SuperCollider-3.6.6-Source-linux~repack/0000775000000000000000000000000012245452763016773 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/INSTALL0000664000000000000000000000025512014636263020017 0ustar rootroot See the platform specific build and install instructions in: README_IPHONE.txt README_JAILBROKEN_IPHONE.txt README_LINUX.txt README_OS_X.txt README_WINDOWS.txt README.txt SuperCollider-3.6.6-Source-linux~repack/lang/0000775000000000000000000000000012245452763017714 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/lang/LangSource/0000775000000000000000000000000012245452763021756 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/lang/LangSource/PyrMathSupport.cpp0000664000000000000000000013345112237772705025454 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SCBase.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "MiscInlineMath.h" #include "SC_RGen.h" #include #include #ifdef __FreeBSD__ # include #endif float centsRatio[128]; float semitoneFreq[128]; /* host function : (move to separate file) */ void pyrmath_init_globs(); void pyrmath_init_globs() { int i; for (i=0; i<128; ++i) { semitoneFreq[i] = 440. * pow(2., (i - 69)/12.); centsRatio[i] = pow(2., i/(12. * 128.)); } } // 1/440 = 0.0022727272727 1/12 = 0.083333333333 #define SQRT2M1 0.41421356f double hypotx(double x, double y); double hypotx(double x, double y) { double minxy; x = fabs(x); y = fabs(y); minxy = sc_min(x,y); return x + y - SQRT2M1 * minxy; } unsigned short primeslist[NUMPRIMES] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, 18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, 18517, 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, 19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, 19603, 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, 20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, 20983, 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, 21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, 21841, 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, 22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, 22871, 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, 23029, 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, 23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, 24169, 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, 25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, 25183, 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, 25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, 26249, 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, 26399, 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, 27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, 27691, 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, 28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, 28579, 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, 29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, 29611, 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, 29819, 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, 31091, 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, 31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, 32063, 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, 32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, 33053, 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, 33211, 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, 33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, 34457, 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, 35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, 35401, 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, 36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, 36541, 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, 36691, 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, 37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, 37951, 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, 38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, 38921, 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, 39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, 40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, 41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, 42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, 42379, 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, 43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, 43499, 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, 43661, 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, 44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, 44953, 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, 45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, 45979, 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, 46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, 47143, 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, 47317, 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, 48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, 48611, 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, 49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, 49537, 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, 50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, 50651, 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, 50867, 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, 51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, 52127, 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, 52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, 53117, 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, 53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, 54311, 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, 54443, 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, 55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, 55793, 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, 56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, 56711, 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, 57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, 57787, 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, 57947, 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, 58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, 59233, 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, 60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, 60251, 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, 61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, 61483, 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, 61631, 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, 62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, 62989, 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, 63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, 63929, 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, 64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, 65179, 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, 65519, 65521 }; long nthPrime(int n) { if (n<0 || n>=NUMPRIMES) return 0; return primeslist[n]; } long findPrime(int n) { // binary search of primes table int i, p, lo = 0, hi = NUMPRIMES-1; while (hi>=lo) { i = (lo + hi) >> 1; p = nthPrime(i); if (n==p) return i; if (n=lo) { i = (lo + hi) >> 1; p = nthPrime(i); if (n==p) return i; if (n=lo) { i = (lo + hi) >> 1; p = nthPrime(i); if (n==p) return i; if (n #include #include "InitAlloc.h" #include "VMGlobals.h" #include "Hash.h" SC_DLLEXPORT_C PyrSymbol* getsym(const char *name) { PyrSymbol* symbol = gMainVMGlobals->symbolTable->Make(name); if (!symbol) { fprintf(stderr, "getsym failed '%s'\n", name); exit(-1); } return symbol; } SC_DLLEXPORT_C PyrSymbol* getmetasym(const char *name) { char str[256]; strcpy(str, "Meta_"); strcat(str, name); return getsym(str); } SC_DLLEXPORT_C PyrSymbol* findsym(const char *name) { PyrSymbol* symbol = gMainVMGlobals->symbolTable->Find(name); return symbol; } SymbolSpace::SymbolSpace(AllocPool *inPool) { mPool = inPool; mStringPool.Init(inPool, STRINGCHUNK, STRINGCHUNK, STRINGCHUNK/5); mSymbolPool.Init(inPool, SYMBOLCHUNK, SYMBOLCHUNK, SYMBOLCHUNK/5); } PyrSymbol* SymbolSpace::NewSymbol(const char *inName, int inHash, int inLength) { PyrSymbol *sym; sym = (PyrSymbol*)mSymbolPool.Alloc(sizeof(PyrSymbol)); MEMFAIL(sym); sym->name = (char*)mStringPool.Alloc(inLength+1); MEMFAIL(sym->name); strcpy(sym->name, inName); sym->hash = inHash; sym->length = inLength; sym->specialIndex = -1; sym->flags = 0; if (inName[0] >= 'A' && inName[0] <= 'Z') sym->flags |= sym_Class; if (inLength > 1 && inName[0] == '_') sym->flags |= sym_Primitive; if (inLength > 1 && inName[inLength-1] == '_') sym->flags |= sym_Setter; sym->u.index = 0; sym->classdep = NULL; return sym; } SymbolTable::SymbolTable(AllocPool *inPool, int inSize) : mPool(inPool), mSpace(inPool), mMaxItems(inSize) { assert(ISPOWEROFTWO(inSize)); AllocTable(); } void SymbolTable::CopyFrom(SymbolTable& inTable) { MakeEmpty(); Rehash(inTable.mTable, inTable.mMaxItems); } int SymbolTable::StrHash(const char *inName, size_t *outLength) { return Hash(inName, outLength); } PyrSymbol* SymbolTable::Find(const char *inName) { size_t length; int hash = StrHash(inName, &length); return Find(inName, hash); } PyrSymbol* SymbolTable::Find(const char *inName, int inHash) { int index = inHash & mMask; PyrSymbol* sym = mTable[index]; while (sym && (sym->hash != inHash || strcmp(inName, sym->name)!=0)) { index = (index+1) & mMask; sym = mTable[index]; } return sym; } void SymbolTable::Add(PyrSymbol* inSymbol) { if (mNumItems + 1 > (mMaxItems>>1)) Grow(); int index = inSymbol->hash & mMask; PyrSymbol *testSymbol = mTable[index]; while (testSymbol && testSymbol != inSymbol) { index = (index + 1) & mMask; testSymbol = mTable[index]; } if (!testSymbol) { // if it is not already in the table. mTable[index] = inSymbol; mNumItems ++ ; } } PyrSymbol* SymbolTable::MakeNew(const char *inName, int inHash, int inLength) { PyrSymbol* symbol = mSpace.NewSymbol(inName, inHash, inLength); Add(symbol); return symbol; } PyrSymbol* SymbolTable::Make(const char *inName) { size_t length; int hash = StrHash(inName, &length); PyrSymbol* symbol = Find(inName, hash); if (!symbol) symbol = MakeNew(inName, hash, length); return symbol; } void SymbolTable::MakeEmpty() { int size = mMaxItems * sizeof(PyrSymbol*); memset(mTable, 0, size); mNumItems = 0 ; } void SymbolTable::AllocTable() { int size = mMaxItems * sizeof(PyrSymbol*); mTable = (PyrSymbol**)mPool->Alloc(size); MEMFAIL(mTable); MakeEmpty(); mMask = mMaxItems - 1; } void SymbolTable::Rehash(PyrSymbol** inTable, int inSize) { // rehash all entries from inTable into the new table for (int i=0; iFree(oldtable); } void SymbolTable::CheckSymbols() { for (int i=0; iu.index == 0) { int c; c = symbol->name[0]; if (c == '_') { post("WARNING: Primitive '%s' used but not bound\n", symbol->name); } else if (c >= 'A' && c <= 'Z') { post("WARNING: Symbol '%s' used but not defined as a Class\n", symbol->name); } else if ((symbol->flags & sym_Called) && !(symbol->flags & sym_Selector)) { post("WARNING: Method '%s' called but not defined\n", symbol->name); } } } } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/Bison/0000775000000000000000000000000012245452763023030 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/lang/LangSource/Bison/lang11d_tab.cpp0000664000000000000000000050346512161364457025625 0ustar rootroot /* A Bison parser, made by GNU Bison 2.4.1. */ /* Skeleton implementation for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "2.4.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Using locations. */ #define YYLSP_NEEDED 0 /* Copy the first part of user declarations. */ /* Line 189 of yacc.c */ #line 16 "lang11d" #include #include #include "PyrLexer.h" #include "PyrParseNode.h" #include "SC_Constants.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "InitAlloc.h" #include "PredefinedSymbols.h" #include "SimpleStack.h" void bcopy(void *src, void *dst, size_t size) ; int yyparse(); extern bool compilingCmdLine; extern LongStack generatorStack; /* Line 189 of yacc.c */ #line 95 "lang11d_tab.cpp" /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 1 #endif /* Enabling the token table. */ #ifndef YYTOKEN_TABLE # define YYTOKEN_TABLE 0 #endif /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { NAME = 258, INTEGER = 259, SC_FLOAT = 260, ACCIDENTAL = 261, SYMBOL = 262, STRING = 263, ASCII = 264, PRIMITIVENAME = 265, CLASSNAME = 266, CURRYARG = 267, VAR = 268, ARG = 269, CLASSVAR = 270, SC_CONST = 271, NILOBJ = 272, TRUEOBJ = 273, FALSEOBJ = 274, PSEUDOVAR = 275, ELLIPSIS = 276, DOTDOT = 277, PIE = 278, BEGINCLOSEDFUNC = 279, BADTOKEN = 280, INTERPRET = 281, BEGINGENERATOR = 282, LEFTARROW = 283, WHILE = 284, READWRITEVAR = 285, KEYBINOP = 286, BINOP = 287, UMINUS = 288 }; #endif #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef int YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif /* Copy the second part of user declarations. */ /* Line 264 of yacc.c */ #line 170 "lang11d_tab.cpp" #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ # define YY_(msgid) msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(e) ((void) (e)) #else # define YYUSE(e) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int yyi) #else static int YYID (yyi) int yyi; #endif { return yyi; } #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (YYID (0)) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (YYID (0)) #endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 67 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 1945 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 55 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 101 /* YYNRULES -- Number of rules. */ #define YYNRULES 292 /* YYNRULES -- Number of states. */ #define YYNSTATES 534 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 288 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 54, 2, 2, 2, 2, 50, 51, 35, 36, 49, 32, 41, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 30, 48, 33, 31, 34, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 46, 2, 47, 52, 2, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 44, 37, 45, 53, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 38, 39, 40, 43 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint16 yyprhs[] = { 0, 0, 3, 5, 7, 10, 11, 14, 16, 19, 26, 36, 42, 43, 45, 46, 49, 50, 53, 57, 61, 65, 66, 69, 77, 86, 94, 103, 104, 106, 107, 109, 110, 112, 114, 117, 122, 125, 127, 129, 132, 133, 136, 137, 141, 142, 146, 148, 151, 153, 155, 156, 158, 161, 166, 171, 178, 185, 194, 200, 208, 213, 216, 221, 228, 235, 241, 247, 255, 264, 272, 279, 286, 295, 303, 308, 309, 317, 318, 326, 327, 330, 335, 341, 347, 350, 355, 360, 362, 364, 366, 368, 370, 372, 376, 379, 383, 387, 392, 396, 398, 403, 405, 411, 417, 424, 432, 440, 449, 456, 463, 471, 480, 489, 499, 502, 505, 509, 515, 520, 523, 526, 530, 535, 541, 543, 545, 547, 549, 555, 558, 563, 567, 572, 578, 586, 591, 598, 606, 607, 610, 613, 618, 620, 624, 627, 628, 631, 633, 637, 640, 644, 649, 655, 657, 661, 664, 669, 671, 675, 678, 680, 684, 686, 690, 692, 696, 698, 700, 702, 704, 706, 708, 710, 712, 714, 716, 718, 720, 722, 724, 726, 728, 730, 732, 734, 736, 738, 740, 742, 744, 746, 748, 750, 752, 754, 756, 758, 764, 770, 771, 774, 776, 779, 783, 784, 788, 794, 798, 804, 806, 810, 815, 816, 818, 820, 824, 826, 830, 836, 837, 839, 841, 845, 847, 851, 856, 860, 863, 865, 869, 870, 873, 875, 879, 882, 887, 891, 895, 898, 900, 904, 905, 908, 913, 919, 923, 928, 929, 932, 934, 938, 939, 941, 943, 945, 946, 948, 950, 953, 955, 958, 960, 963, 965, 967, 969, 972, 975, 977, 980, 982, 984, 986, 988, 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1016, 1018, 1020, 1022, 1024 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { 56, 0, -1, 57, -1, 58, -1, 26, 71, -1, -1, 57, 59, -1, 60, -1, 58, 60, -1, 143, 62, 44, 63, 65, 45, -1, 143, 46, 61, 47, 62, 44, 63, 65, 45, -1, 36, 143, 44, 65, 45, -1, -1, 142, -1, -1, 30, 143, -1, -1, 63, 64, -1, 15, 125, 48, -1, 13, 125, 48, -1, 16, 114, 48, -1, -1, 65, 66, -1, 142, 44, 113, 110, 73, 72, 45, -1, 35, 142, 44, 113, 110, 73, 72, 45, -1, 152, 44, 113, 110, 73, 72, 45, -1, 35, 152, 44, 113, 110, 73, 72, 45, -1, -1, 48, -1, -1, 49, -1, -1, 31, -1, 75, -1, 94, 75, -1, 50, 111, 70, 51, -1, 111, 70, -1, 70, -1, 74, -1, 94, 74, -1, -1, 144, 67, -1, -1, 52, 91, 67, -1, -1, 52, 91, 67, -1, 77, -1, 76, 77, -1, 105, -1, 80, -1, -1, 76, -1, 142, 76, -1, 50, 154, 51, 76, -1, 142, 50, 51, 76, -1, 142, 50, 97, 101, 51, 78, -1, 50, 154, 51, 50, 51, 76, -1, 50, 154, 51, 50, 97, 101, 51, 78, -1, 142, 50, 98, 101, 51, -1, 50, 154, 51, 50, 98, 101, 51, -1, 143, 46, 95, 47, -1, 143, 76, -1, 143, 50, 51, 78, -1, 143, 50, 99, 68, 51, 78, -1, 143, 50, 97, 101, 51, 78, -1, 143, 50, 98, 101, 51, -1, 91, 41, 50, 51, 78, -1, 91, 41, 50, 99, 68, 51, 78, -1, 91, 41, 142, 50, 99, 68, 51, 78, -1, 91, 41, 50, 97, 101, 51, 78, -1, 91, 41, 50, 98, 101, 51, -1, 91, 41, 142, 50, 51, 78, -1, 91, 41, 142, 50, 97, 101, 51, 78, -1, 91, 41, 142, 50, 98, 101, 51, -1, 91, 41, 142, 78, -1, -1, 44, 30, 94, 81, 49, 84, 45, -1, -1, 44, 48, 94, 82, 49, 84, 45, -1, -1, 49, 84, -1, 142, 28, 94, 83, -1, 142, 142, 28, 94, 83, -1, 13, 142, 31, 94, 83, -1, 94, 83, -1, 30, 30, 94, 83, -1, 30, 29, 94, 83, -1, 107, -1, 105, -1, 80, -1, 106, -1, 155, -1, 79, -1, 50, 94, 51, -1, 53, 142, -1, 46, 95, 47, -1, 50, 89, 51, -1, 50, 30, 90, 51, -1, 50, 124, 51, -1, 151, -1, 85, 46, 97, 47, -1, 86, -1, 85, 46, 97, 22, 47, -1, 85, 46, 22, 94, 47, -1, 85, 46, 97, 22, 94, 47, -1, 85, 46, 97, 22, 47, 31, 91, -1, 85, 46, 22, 94, 47, 31, 91, -1, 85, 46, 97, 22, 94, 47, 31, 91, -1, 91, 41, 46, 97, 22, 47, -1, 91, 41, 46, 22, 94, 47, -1, 91, 41, 46, 97, 22, 94, 47, -1, 91, 41, 46, 97, 22, 47, 31, 91, -1, 91, 41, 46, 22, 94, 47, 31, 91, -1, 91, 41, 46, 97, 22, 94, 47, 31, 91, -1, 94, 22, -1, 22, 94, -1, 94, 22, 94, -1, 94, 49, 94, 22, 94, -1, 94, 49, 94, 22, -1, 22, 94, -1, 94, 22, -1, 94, 22, 94, -1, 94, 49, 94, 22, -1, 94, 49, 94, 22, 94, -1, 85, -1, 88, -1, 87, -1, 143, -1, 91, 41, 46, 97, 47, -1, 42, 91, -1, 91, 154, 92, 91, -1, 142, 31, 91, -1, 53, 142, 31, 91, -1, 91, 41, 142, 31, 91, -1, 142, 50, 97, 101, 51, 31, 91, -1, 54, 102, 31, 91, -1, 85, 46, 97, 47, 31, 91, -1, 91, 41, 46, 97, 47, 31, 91, -1, -1, 41, 142, -1, 41, 137, -1, 41, 50, 94, 51, -1, 91, -1, 93, 48, 91, -1, 93, 67, -1, -1, 96, 68, -1, 94, -1, 94, 30, 94, -1, 153, 94, -1, 96, 49, 94, -1, 96, 49, 153, 94, -1, 96, 49, 94, 30, 94, -1, 94, -1, 97, 49, 94, -1, 35, 94, -1, 97, 49, 35, 94, -1, 100, -1, 99, 49, 100, -1, 153, 94, -1, 68, -1, 49, 99, 68, -1, 103, -1, 103, 21, 142, -1, 142, -1, 103, 49, 142, -1, 137, -1, 141, -1, 148, -1, 150, -1, 149, -1, 145, -1, 146, -1, 147, -1, 131, -1, 109, -1, 142, -1, 137, -1, 141, -1, 148, -1, 150, -1, 149, -1, 145, -1, 146, -1, 147, -1, 131, -1, 137, -1, 141, -1, 148, -1, 150, -1, 149, -1, 142, -1, 145, -1, 146, -1, 147, -1, 132, -1, 127, -1, 44, 113, 110, 70, 45, -1, 24, 113, 110, 70, 45, -1, -1, 110, 112, -1, 112, -1, 111, 112, -1, 13, 120, 48, -1, -1, 14, 120, 48, -1, 14, 119, 21, 142, 48, -1, 37, 117, 37, -1, 37, 116, 21, 142, 37, -1, 115, -1, 114, 68, 115, -1, 136, 142, 31, 104, -1, -1, 117, -1, 118, -1, 117, 68, 118, -1, 142, -1, 142, 69, 104, -1, 142, 69, 50, 94, 51, -1, -1, 120, -1, 121, -1, 120, 49, 121, -1, 142, -1, 142, 31, 91, -1, 142, 50, 94, 51, -1, 94, 30, 94, -1, 153, 94, -1, 122, -1, 123, 49, 122, -1, -1, 123, 68, -1, 126, -1, 125, 49, 126, -1, 135, 142, -1, 135, 142, 31, 104, -1, 50, 130, 51, -1, 108, 30, 108, -1, 153, 108, -1, 128, -1, 129, 49, 128, -1, -1, 129, 68, -1, 54, 46, 133, 47, -1, 54, 143, 46, 133, 47, -1, 46, 133, 47, -1, 143, 46, 133, 47, -1, -1, 134, 68, -1, 108, -1, 134, 49, 108, -1, -1, 33, -1, 38, -1, 34, -1, -1, 33, -1, 4, -1, 32, 4, -1, 5, -1, 32, 5, -1, 6, -1, 32, 6, -1, 23, -1, 138, -1, 139, -1, 138, 140, -1, 137, 140, -1, 140, -1, 32, 140, -1, 3, -1, 29, -1, 11, -1, 10, -1, 18, -1, 19, -1, 17, -1, 9, -1, 7, -1, 8, -1, 20, -1, 40, -1, 38, -1, 33, -1, 34, -1, 32, -1, 35, -1, 36, -1, 37, -1, 39, -1, 152, -1, 153, -1, 12, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 39, 39, 41, 43, 47, 48, 52, 53, 57, 61, 68, 74, 75, 78, 79, 83, 84, 88, 90, 92, 96, 97, 101, 104, 107, 110, 115, 116, 119, 120, 123, 124, 127, 128, 132, 134, 136, 140, 141, 145, 146, 151, 152, 157, 158, 162, 163, 169, 170, 173, 174, 177, 181, 185, 189, 194, 198, 203, 221, 234, 236, 247, 258, 269, 282, 303, 312, 321, 326, 339, 359, 363, 369, 387, 393, 393, 403, 403, 410, 431, 435, 469, 507, 521, 532, 536, 561, 562, 563, 564, 565, 566, 567, 573, 583, 585, 587, 589, 591, 593, 606, 609, 636, 654, 681, 709, 728, 756, 783, 801, 826, 854, 873, 901, 920, 939, 956, 970, 991, 1010, 1028, 1045, 1061, 1077, 1078, 1079, 1080, 1081, 1094, 1108, 1113, 1117, 1128, 1133, 1143, 1148, 1162, 1178, 1179, 1180, 1181, 1184, 1185, 1191, 1194, 1195, 1199, 1200, 1202, 1207, 1209, 1216, 1224, 1225, 1229, 1231, 1235, 1236, 1240, 1244, 1245, 1248, 1250, 1254, 1255, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1271, 1274, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1301, 1304, 1309, 1310, 1314, 1315, 1319, 1323, 1324, 1328, 1332, 1336, 1342, 1343, 1347, 1351, 1352, 1355, 1356, 1360, 1362, 1364, 1372, 1373, 1376, 1377, 1381, 1383, 1385, 1393, 1395, 1402, 1403, 1407, 1408, 1411, 1412, 1416, 1418, 1422, 1426, 1428, 1435, 1436, 1440, 1441, 1446, 1448, 1452, 1454, 1458, 1459, 1462, 1463, 1467, 1468, 1470, 1472, 1476, 1477, 1481, 1482, 1491, 1492, 1501, 1502, 1513, 1516, 1517, 1518, 1524, 1532, 1539, 1548, 1549, 1552, 1555, 1558, 1561, 1564, 1567, 1570, 1573, 1576, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1589, 1592, 1593, 1596 }; #endif #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "NAME", "INTEGER", "SC_FLOAT", "ACCIDENTAL", "SYMBOL", "STRING", "ASCII", "PRIMITIVENAME", "CLASSNAME", "CURRYARG", "VAR", "ARG", "CLASSVAR", "SC_CONST", "NILOBJ", "TRUEOBJ", "FALSEOBJ", "PSEUDOVAR", "ELLIPSIS", "DOTDOT", "PIE", "BEGINCLOSEDFUNC", "BADTOKEN", "INTERPRET", "BEGINGENERATOR", "LEFTARROW", "WHILE", "':'", "'='", "'-'", "'<'", "'>'", "'*'", "'+'", "'|'", "READWRITEVAR", "KEYBINOP", "BINOP", "'.'", "'`'", "UMINUS", "'{'", "'}'", "'['", "']'", "';'", "','", "'('", "')'", "'^'", "'~'", "'#'", "$accept", "root", "classes", "classextensions", "classdef", "classextension", "optname", "superclass", "classvardecls", "classvardecl", "methods", "methoddef", "optsemi", "optcomma", "optequal", "funcbody", "cmdlinecode", "methbody", "primitive", "retval", "funretval", "blocklist1", "blocklistitem", "blocklist", "msgsend", "generator", "$@1", "$@2", "nextqual", "qual", "expr1", "valrangex1", "valrangeassign", "valrangexd", "valrange2", "valrange3", "expr", "adverb", "exprn", "exprseq", "arrayelems", "arrayelems1", "arglist1", "arglistv1", "keyarglist1", "keyarg", "optkeyarglist", "mavars", "mavarlist", "slotliteral", "blockliteral", "pushname", "pushliteral", "listliteral", "block", "funcvardecls", "funcvardecls1", "funcvardecl", "argdecls", "constdeflist", "constdef", "slotdeflist0", "slotdeflist", "slotdef", "vardeflist0", "vardeflist", "vardef", "dictslotdef", "dictslotlist1", "dictslotlist", "rwslotdeflist", "rwslotdef", "dictlit2", "litdictslotdef", "litdictslotlist1", "litdictslotlist", "listlit", "listlit2", "literallistc", "literallist1", "rwspec", "rspec", "integer", "floatr", "accidental", "pie", "floatp", "name", "classname", "primname", "trueobj", "falseobj", "nilobj", "ascii", "symbol", "string", "pseudovar", "binop", "keybinop", "binop2", "curryarg", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 58, 61, 45, 60, 62, 42, 43, 124, 285, 286, 287, 46, 96, 288, 123, 125, 91, 93, 59, 44, 40, 41, 94, 126, 35 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 55, 56, 56, 56, 57, 57, 58, 58, 59, 59, 60, 61, 61, 62, 62, 63, 63, 64, 64, 64, 65, 65, 66, 66, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 81, 80, 82, 80, 83, 83, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 86, 86, 86, 87, 87, 87, 88, 88, 88, 88, 88, 88, 89, 89, 89, 89, 89, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 94, 95, 95, 96, 96, 96, 96, 96, 96, 97, 97, 98, 98, 99, 99, 100, 101, 101, 102, 102, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 104, 105, 106, 107, 107, 107, 107, 107, 107, 107, 107, 107, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 109, 109, 110, 110, 111, 111, 112, 113, 113, 113, 113, 113, 114, 114, 115, 116, 116, 117, 117, 118, 118, 118, 119, 119, 120, 120, 121, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, 126, 126, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, 135, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 141, 141, 141, 141, 141, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 152, 152, 152, 152, 152, 152, 152, 153, 154, 154, 155 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 1, 2, 0, 2, 1, 2, 6, 9, 5, 0, 1, 0, 2, 0, 2, 3, 3, 3, 0, 2, 7, 8, 7, 8, 0, 1, 0, 1, 0, 1, 1, 2, 4, 2, 1, 1, 2, 0, 2, 0, 3, 0, 3, 1, 2, 1, 1, 0, 1, 2, 4, 4, 6, 6, 8, 5, 7, 4, 2, 4, 6, 6, 5, 5, 7, 8, 7, 6, 6, 8, 7, 4, 0, 7, 0, 7, 0, 2, 4, 5, 5, 2, 4, 4, 1, 1, 1, 1, 1, 1, 3, 2, 3, 3, 4, 3, 1, 4, 1, 5, 5, 6, 7, 7, 8, 6, 6, 7, 8, 8, 9, 2, 2, 3, 5, 4, 2, 2, 3, 4, 5, 1, 1, 1, 1, 5, 2, 4, 3, 4, 5, 7, 4, 6, 7, 0, 2, 2, 4, 1, 3, 2, 0, 2, 1, 3, 2, 3, 4, 5, 1, 3, 2, 4, 1, 3, 2, 1, 3, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 0, 2, 1, 2, 3, 0, 3, 5, 3, 5, 1, 3, 4, 0, 1, 1, 3, 1, 3, 5, 0, 1, 1, 3, 1, 3, 4, 3, 2, 1, 3, 0, 2, 1, 3, 2, 4, 3, 3, 2, 1, 3, 0, 2, 4, 5, 3, 4, 0, 2, 1, 3, 0, 1, 1, 1, 0, 1, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint16 yydefact[] = { 5, 44, 0, 0, 2, 3, 7, 270, 257, 259, 261, 278, 279, 277, 272, 292, 0, 276, 274, 275, 280, 263, 204, 271, 0, 0, 204, 145, 230, 0, 0, 0, 37, 4, 33, 92, 89, 124, 101, 126, 125, 142, 27, 44, 88, 90, 87, 175, 44, 201, 185, 177, 264, 265, 268, 178, 176, 127, 182, 183, 184, 179, 181, 180, 99, 91, 0, 1, 6, 14, 8, 0, 221, 223, 219, 212, 199, 258, 260, 262, 269, 230, 129, 0, 0, 199, 289, 147, 0, 29, 0, 0, 0, 285, 283, 284, 286, 287, 288, 282, 281, 0, 0, 44, 228, 29, 0, 290, 291, 0, 27, 94, 247, 0, 162, 164, 0, 0, 285, 0, 291, 138, 28, 144, 34, 36, 202, 267, 266, 0, 0, 52, 46, 49, 48, 145, 0, 61, 21, 0, 12, 0, 203, 0, 0, 0, 0, 220, 0, 29, 214, 31, 44, 75, 77, 44, 0, 95, 30, 146, 149, 115, 0, 0, 0, 96, 114, 0, 0, 93, 0, 30, 231, 98, 227, 0, 28, 45, 0, 247, 241, 249, 196, 195, 0, 29, 186, 187, 191, 0, 192, 193, 194, 188, 190, 189, 0, 0, 0, 247, 0, 153, 0, 0, 0, 50, 0, 0, 143, 131, 0, 0, 29, 29, 47, 0, 50, 29, 29, 29, 157, 0, 0, 15, 0, 13, 16, 222, 224, 0, 0, 205, 0, 207, 30, 0, 32, 0, 0, 200, 0, 0, 0, 148, 150, 0, 119, 97, 120, 0, 116, 226, 0, 35, 0, 229, 0, 0, 53, 132, 0, 0, 239, 29, 0, 0, 243, 30, 248, 247, 135, 163, 165, 0, 0, 0, 100, 0, 0, 0, 50, 29, 29, 29, 0, 0, 51, 74, 0, 0, 140, 139, 130, 155, 54, 30, 160, 0, 30, 0, 60, 62, 0, 0, 30, 0, 159, 286, 11, 22, 0, 0, 14, 21, 225, 0, 0, 215, 0, 0, 217, 174, 166, 167, 171, 172, 173, 168, 170, 169, 198, 0, 0, 197, 0, 151, 121, 0, 118, 0, 29, 29, 245, 0, 30, 242, 236, 238, 250, 0, 244, 103, 102, 0, 0, 154, 0, 0, 128, 66, 0, 0, 0, 133, 50, 29, 29, 29, 0, 0, 29, 50, 58, 50, 65, 158, 50, 0, 0, 204, 204, 0, 251, 251, 255, 17, 0, 206, 208, 0, 0, 0, 0, 79, 176, 0, 152, 122, 117, 56, 0, 0, 237, 240, 246, 0, 0, 104, 136, 109, 108, 0, 0, 50, 70, 50, 71, 0, 0, 0, 141, 156, 161, 0, 55, 64, 63, 204, 204, 199, 199, 16, 252, 254, 253, 0, 232, 0, 0, 256, 29, 209, 0, 9, 218, 0, 0, 0, 76, 0, 84, 0, 0, 78, 123, 50, 59, 106, 105, 0, 0, 0, 110, 137, 69, 67, 50, 73, 50, 134, 199, 199, 40, 40, 21, 19, 251, 234, 18, 20, 255, 0, 0, 79, 79, 80, 79, 0, 57, 107, 112, 111, 0, 72, 68, 40, 40, 273, 42, 27, 42, 0, 233, 0, 210, 0, 79, 86, 85, 81, 79, 113, 42, 42, 0, 0, 38, 42, 41, 0, 10, 235, 211, 83, 82, 0, 0, 27, 23, 39, 25, 24, 26, 43 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 3, 4, 5, 68, 6, 224, 141, 313, 385, 222, 309, 123, 296, 237, 32, 33, 515, 498, 516, 34, 286, 132, 287, 35, 36, 240, 241, 450, 392, 37, 38, 39, 40, 101, 163, 41, 207, 42, 201, 88, 89, 202, 213, 370, 220, 297, 113, 114, 320, 44, 45, 46, 181, 47, 152, 48, 239, 76, 440, 441, 148, 149, 150, 146, 71, 72, 104, 105, 106, 435, 436, 182, 262, 263, 264, 50, 183, 184, 185, 437, 442, 51, 52, 53, 54, 55, 56, 57, 499, 58, 59, 60, 61, 62, 63, 64, 107, 120, 121, 65 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -358 static const yytype_int16 yypact[] = { 6, 1013, 28, 131, 28, 57, -358, -358, -358, -358, -358, -358, -358, -358, -358, -358, 17, -358, -358, -358, -358, -358, 64, -358, 236, 1689, 40, 1325, 733, 1689, 17, 147, -358, -358, -358, -358, -358, 89, -358, -358, -358, 1904, 90, 104, -358, -358, -358, -358, 1065, -358, -358, 118, 118, -358, -358, -358, 163, 93, -358, -358, -358, -358, -358, -358, -358, -358, 120, -358, -358, 38, -358, -24, -358, 68, 17, 17, -358, -358, -358, -358, -358, 857, -358, 1689, 1689, -358, -358, 154, 150, 151, 1689, 1689, 1377, 236, -358, -358, -358, -358, -358, -358, -358, 160, 15, 1065, -358, 174, 183, -358, 1689, 184, 1887, 196, 1818, 221, 12, -358, 197, 1429, -358, 19, -358, 213, 1689, -358, -358, -358, -358, -358, -358, 1689, 1117, 92, -358, -358, -358, 1325, 793, 92, -358, 28, 17, 218, -358, 17, 1689, 1689, 243, -18, 247, 74, -358, 200, 1065, -358, -358, 1065, 1689, -358, 1325, -358, -358, -358, 1689, 224, 18, -358, 1689, 1689, 1689, -358, 229, 1325, -358, -358, -358, 188, -358, -358, 1689, 1818, 1770, -358, -358, -358, 235, 246, 118, -358, -358, 252, -358, -358, -358, -358, -358, -358, 1689, 17, 17, 1818, 1689, -358, 51, 1481, 909, 186, 47, 1689, 1904, 1904, 1689, 92, 260, 261, -358, 245, 92, 260, 261, 262, -358, 1689, 1825, -358, 254, -358, -358, -358, 1904, 264, 17, -358, 17, -358, -358, 17, -358, 1740, 267, -358, 269, 270, 271, -358, 290, 1689, -358, -358, 1689, 1689, -358, -358, 299, -358, 292, -358, 1689, 1169, 92, 1904, 278, 296, -358, 279, 276, 1818, -358, 1818, -358, 1818, 1904, -358, -358, 282, 285, 1533, 303, 1689, 1689, 83, 92, 260, 261, 262, 1689, 961, 92, -358, 335, 1689, -358, -358, 307, -358, 92, 1221, -358, 293, 312, 313, -358, -358, 314, 318, 312, 319, -358, 1878, -358, -358, 310, 311, 342, 176, -358, 325, 338, -358, 1689, 7, -358, -358, 118, -358, -358, -358, -358, -358, -358, -358, -358, 1273, 1273, -358, 1689, -358, -358, 356, 1689, 92, 260, 261, -358, 1818, 1770, -358, -358, -358, -358, 336, -358, 351, 357, 337, 1689, -358, 345, 1585, 358, -358, 343, 344, 346, 1904, 92, 260, 261, 262, 347, 1689, 262, 202, -358, 92, -358, -358, 92, 355, 363, 64, 64, 364, 266, 266, 377, -358, 1840, -358, -358, 350, 17, 116, 367, 370, 31, 372, -358, 1689, -358, 92, 369, 371, -358, -358, -358, 1689, 1689, 392, 1904, 393, 394, 379, 1689, 92, -358, 92, -358, 378, 380, 382, -358, -358, -358, 1689, -358, -358, -358, 64, 64, -358, -358, -358, -358, -358, -358, 212, -358, 17, 230, -358, 257, -358, 17, -358, -358, 397, 1689, 1689, -358, 1273, -358, 1689, 408, -358, -358, 92, -358, 1904, 1904, 1689, 1689, 1689, 406, 1904, -358, -358, 92, -358, 92, 1904, -358, -358, 96, 96, 176, -358, 266, 412, -358, -358, 377, 413, 1689, 370, 370, -358, 370, 1689, -358, 1904, 1904, 1904, 1689, -358, -358, 96, 96, -358, 1637, 391, 1637, 1863, -358, 647, -358, 647, 370, -358, -358, -358, 370, 1904, 1637, 1637, 1689, 402, -358, 400, -358, 404, -358, -358, -358, -358, -358, 411, 414, 1887, -358, -358, -358, -358, -358, -358 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -358, -358, -358, -358, -358, 448, -358, 145, 27, -358, -311, -358, -109, -77, -358, -40, -358, -255, -271, -57, 418, -42, -96, 263, -358, 91, -358, -358, -357, -327, -358, -358, -358, -358, -358, -358, -19, -358, -358, -1, 328, -358, -117, -133, -100, 165, -161, -358, -358, -289, 216, -358, -358, -171, -358, -68, 443, 10, -22, -358, -3, -358, -358, 237, -358, 415, 339, 320, -358, -358, 95, 22, -358, 149, -358, -358, -214, -358, -150, -358, -358, -358, 2, -358, -358, -8, 16, 144, 511, -358, 71, 201, 255, 304, 353, 368, -358, -215, 523, -7, -358 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -217 static const yytype_int16 yytable[] = { 43, 177, 386, 218, 85, 395, 82, 311, 125, 261, 110, 49, 159, 212, 131, 137, 80, 155, 14, 217, 7, 109, 7, 321, 142, 143, 87, 102, 172, 260, 231, 143, 1, 197, 7, 214, 219, 166, 49, 14, 248, 214, 2, 127, 128, 167, 23, 43, 23, 273, 7, 8, 299, 112, 74, 22, 302, 303, 126, 451, 23, 198, 129, 170, 168, 203, 169, 249, 139, 204, 83, 282, 235, 275, 109, 26, 23, 75, 74, 288, 102, 130, 153, 154, 140, 80, 279, 281, 84, 160, 161, 164, 378, 2, 347, -213, 348, 289, 276, 144, 277, 75, 43, 208, 283, 357, 497, 174, 268, 16, 209, 233, 238, 126, 186, 242, 22, 22, 145, 349, 360, 361, 485, 234, 341, 228, 507, 508, 187, 509, 358, 67, 277, 258, 87, 117, 26, 26, 122, 135, 340, 21, 305, 136, 229, 446, 447, 133, 133, 523, 7, 43, 366, 524, 43, 243, 29, 244, 14, 259, 73, 246, 214, 501, 138, 250, 251, 252, 365, 294, 254, 311, 402, 261, 111, 115, 23, 270, 127, 400, 401, 186, 186, 190, 156, 367, 345, 22, 292, 382, 214, 383, 384, 112, 129, 187, 187, 157, 214, 274, 158, 186, 500, -216, 417, 418, 362, 26, 290, 293, 22, 165, 22, 130, 521, 187, 522, 284, 73, 151, 306, -216, 133, 171, 512, 513, 22, 178, 133, -216, 26, 236, 26, 423, 173, 175, 285, -216, 257, 322, 77, 78, 79, 199, 335, 519, 26, 336, 337, -216, 190, 190, 196, 323, 206, 174, 188, 525, 526, 21, 475, 476, 226, 205, 230, 363, 133, 186, 232, 186, 190, 186, 134, 134, 353, 247, 355, 356, 478, 476, 253, 187, 266, 187, 225, 187, 311, 73, 368, 321, 419, 321, 300, 422, 355, 267, 133, 399, 269, 432, 433, 312, 133, 214, 434, 479, 234, 133, 324, 295, 298, 304, 330, 191, 127, 314, 333, 389, 331, 332, 334, 338, 167, 188, 188, 342, 343, 346, 344, 350, 393, 393, 351, 396, 354, 408, 190, 398, 190, 77, 190, 271, 272, 188, 371, 186, 186, 134, 119, 133, 291, 86, 131, 134, 379, 380, 411, 429, 430, 187, 187, 472, 473, 480, 372, 373, 310, 192, 421, 374, 376, 133, 139, 387, 315, 388, 316, 133, 397, 151, 191, 191, 405, 404, 407, 133, 457, 458, 406, 412, 518, 134, 409, 463, 413, 414, 454, 415, 420, 427, 191, 444, 495, 496, 469, 470, 471, 428, 431, 188, 439, 188, 448, 188, 190, 190, 193, 453, 533, 449, 455, 134, 456, 459, 460, 461, 462, 134, 482, 466, 133, 467, 134, 468, 192, 192, 487, 492, 325, 176, 489, 490, 491, 503, 505, 483, 484, 528, 393, 530, 486, 377, 514, 70, 192, 133, 531, 381, 474, 532, 529, 124, 133, 215, 133, 194, 191, 133, 191, 375, 191, 103, 317, 511, 134, 394, 394, 504, 438, 301, 195, 506, 227, 193, 193, 133, 510, 188, 188, 147, 133, 255, 326, 403, 0, 527, 134, 517, 502, 517, 0, 0, 134, 193, 133, 322, 133, 322, 0, 0, 134, 517, 517, 66, 0, 69, 0, 0, 0, 323, 192, 323, 192, 0, 192, 0, 0, 0, 0, 0, 310, 0, 194, 194, 445, 0, 0, 0, 452, 0, 0, 327, 116, 359, 191, 191, 133, 195, 195, 0, 90, 108, 194, 0, 0, 134, 0, 133, 0, 133, 0, 0, 0, 0, 0, 0, 0, 195, 0, 193, 0, 193, 0, 193, 324, 0, 324, 0, 0, 0, 134, 477, 0, 0, 0, 0, 481, 134, 0, 134, 328, 0, 134, 394, 0, 0, 0, 0, 192, 192, 0, 0, 0, 0, 108, 329, 0, 0, 0, 0, 134, 0, 0, 0, 0, 134, 0, 0, 194, 0, 194, 0, 194, 189, 0, 0, 0, 416, 0, 134, 0, 134, 0, 195, 424, 195, 425, 195, 0, 426, 0, 0, 0, 0, 0, 310, 0, 193, 193, 0, 223, 8, 9, 10, 11, 12, 13, 0, 90, 221, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 21, 134, 0, 0, 0, 0, 464, 0, 465, 24, 0, 245, 134, 0, 134, 0, 0, 0, 0, 0, 189, 189, 0, 0, 256, 0, 194, 194, 0, 0, 0, 319, 0, 265, 325, 0, 325, 0, 0, 0, 189, 195, 195, 0, 0, 0, 0, 0, 488, 0, 0, 0, 0, 0, 0, 0, 0, 221, 0, 493, 0, 494, 0, 0, 0, 0, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 16, 0, 0, 0, 17, 18, 19, 20, 0, 91, 21, 22, 326, 0, 326, 0, 23, 92, 0, 93, 94, 95, 96, 97, 98, 99, 86, 100, 0, 25, 189, 26, 189, 27, 189, 0, 0, 81, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 327, 221, 327, 17, 18, 19, 20, 0, 0, 21, 22, 221, 0, 0, 221, 23, 0, 0, 24, 0, 221, 210, 0, 116, 0, 86, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 216, 0, 30, 31, 0, 0, 0, 0, 0, 0, 189, 189, 328, 0, 328, 0, 7, 8, 9, 10, 11, 12, 13, 265, 14, 15, 0, 329, 0, 329, 17, 18, 19, 20, 0, 91, 21, 22, 0, 0, 0, 0, 23, 92, 0, 93, 94, 95, 96, 97, 98, 99, 86, 100, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 210, 0, 0, 0, 86, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 280, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 210, 0, 0, 0, 86, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 364, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 16, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 28, 0, 29, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 16, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 29, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 210, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 211, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 210, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 339, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 369, 0, 0, 0, 86, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 390, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 391, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 86, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 162, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 200, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 278, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 352, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 410, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 514, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 24, 7, 8, 9, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 17, 18, 19, 318, 0, 0, 21, 319, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 180, 7, 8, 9, 10, 11, 12, 13, 7, 14, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 21, 0, 7, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 23, 0, 0, 118, 94, 95, 307, 97, 98, 99, 179, 100, 7, 0, 180, 23, 308, 0, 118, 94, 95, 307, 97, 98, 99, 0, 100, 7, 0, 0, 0, 443, 0, 0, 0, 0, 0, 0, 23, 0, 0, 118, 94, 95, 307, 97, 98, 99, 0, 100, 0, 0, 0, 23, 520, 0, 118, 94, 95, 96, 97, 98, 99, 0, 100, 118, 94, 95, 96, 97, 98, 99, 86, 100, 119, 0, 0, 0, 0, 0, 0, 176, 118, 94, 95, 96, 97, 98, 99, 86, 100, 119 }; static const yytype_int16 yycheck[] = { 1, 110, 313, 136, 26, 332, 25, 222, 48, 180, 29, 1, 89, 130, 56, 57, 24, 85, 11, 136, 3, 28, 3, 237, 48, 49, 27, 28, 105, 179, 48, 49, 26, 21, 3, 131, 136, 22, 28, 11, 22, 137, 36, 51, 52, 30, 29, 48, 29, 199, 3, 4, 213, 46, 14, 24, 217, 218, 48, 28, 29, 49, 31, 103, 49, 46, 51, 49, 30, 50, 30, 204, 149, 22, 81, 44, 29, 37, 14, 32, 81, 50, 83, 84, 46, 93, 203, 204, 48, 90, 91, 92, 307, 36, 265, 21, 267, 50, 47, 31, 49, 37, 103, 122, 204, 22, 10, 108, 185, 13, 129, 37, 152, 103, 112, 155, 24, 24, 50, 269, 281, 282, 449, 49, 257, 144, 483, 484, 112, 486, 47, 0, 49, 175, 135, 46, 44, 44, 48, 46, 257, 23, 219, 50, 145, 29, 30, 56, 57, 506, 3, 152, 285, 510, 155, 156, 52, 158, 11, 178, 16, 162, 258, 474, 44, 166, 167, 168, 285, 211, 171, 386, 343, 344, 30, 31, 29, 196, 186, 340, 341, 179, 180, 112, 30, 285, 263, 24, 207, 13, 286, 15, 16, 46, 31, 179, 180, 47, 294, 200, 49, 199, 473, 3, 365, 366, 283, 44, 206, 210, 24, 51, 24, 50, 503, 199, 505, 31, 74, 75, 221, 21, 131, 49, 495, 496, 24, 31, 137, 29, 44, 31, 44, 31, 51, 51, 50, 37, 50, 237, 4, 5, 6, 46, 245, 500, 44, 248, 249, 49, 179, 180, 31, 237, 41, 256, 112, 512, 513, 23, 48, 49, 44, 119, 21, 284, 175, 265, 21, 267, 199, 269, 56, 57, 275, 51, 277, 278, 48, 49, 51, 265, 47, 267, 140, 269, 501, 143, 289, 503, 367, 505, 47, 370, 295, 49, 205, 339, 46, 33, 34, 47, 211, 399, 38, 48, 49, 216, 237, 49, 49, 49, 45, 112, 322, 51, 45, 318, 49, 49, 30, 22, 30, 179, 180, 47, 30, 51, 49, 47, 331, 332, 47, 334, 31, 354, 265, 338, 267, 4, 269, 197, 198, 199, 51, 343, 344, 131, 41, 258, 206, 39, 394, 137, 44, 44, 357, 379, 380, 343, 344, 429, 430, 440, 51, 51, 222, 112, 369, 51, 51, 280, 30, 48, 230, 37, 232, 286, 22, 235, 179, 180, 31, 47, 47, 294, 405, 406, 31, 31, 499, 175, 47, 412, 51, 51, 397, 51, 51, 44, 199, 51, 470, 471, 423, 427, 428, 44, 44, 265, 33, 267, 45, 269, 343, 344, 112, 45, 527, 49, 51, 205, 51, 31, 31, 31, 47, 211, 31, 51, 339, 51, 216, 51, 179, 180, 28, 31, 237, 48, 459, 460, 461, 31, 31, 446, 447, 45, 449, 45, 451, 307, 52, 5, 199, 364, 45, 312, 431, 45, 517, 43, 371, 135, 373, 112, 265, 376, 267, 304, 269, 28, 235, 492, 258, 331, 332, 480, 383, 216, 112, 482, 143, 179, 180, 394, 487, 343, 344, 74, 399, 171, 237, 344, -1, 514, 280, 498, 476, 500, -1, -1, 286, 199, 413, 503, 415, 505, -1, -1, 294, 512, 513, 2, -1, 4, -1, -1, -1, 503, 265, 505, 267, -1, 269, -1, -1, -1, -1, -1, 386, -1, 179, 180, 390, -1, -1, -1, 394, -1, -1, 237, 31, 280, 343, 344, 455, 179, 180, -1, 27, 28, 199, -1, -1, 339, -1, 466, -1, 468, -1, -1, -1, -1, -1, -1, -1, 199, -1, 265, -1, 267, -1, 269, 503, -1, 505, -1, -1, -1, 364, 437, -1, -1, -1, -1, 442, 371, -1, 373, 237, -1, 376, 449, -1, -1, -1, -1, 343, 344, -1, -1, -1, -1, 81, 237, -1, -1, -1, -1, 394, -1, -1, -1, -1, 399, -1, -1, 265, -1, 267, -1, 269, 112, -1, -1, -1, 364, -1, 413, -1, 415, -1, 265, 371, 267, 373, 269, -1, 376, -1, -1, -1, -1, -1, 501, -1, 343, 344, -1, 139, 4, 5, 6, 7, 8, 9, -1, 135, 136, -1, -1, -1, -1, 17, 18, 19, -1, -1, -1, 23, 455, -1, -1, -1, -1, 413, -1, 415, 32, -1, 158, 466, -1, 468, -1, -1, -1, -1, -1, 179, 180, -1, -1, 171, -1, 343, 344, -1, -1, -1, 54, -1, 180, 503, -1, 505, -1, -1, -1, 199, 343, 344, -1, -1, -1, -1, -1, 455, -1, -1, -1, -1, -1, -1, -1, -1, 204, -1, 466, -1, 468, -1, -1, -1, -1, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, 13, -1, -1, -1, 17, 18, 19, 20, -1, 22, 23, 24, 503, -1, 505, -1, 29, 30, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, -1, 42, 265, 44, 267, 46, 269, -1, -1, 50, -1, -1, 53, 54, -1, -1, -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, 503, 285, 505, 17, 18, 19, 20, -1, -1, 23, 24, 295, -1, -1, 298, 29, -1, -1, 32, -1, 304, 35, -1, 319, -1, 39, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, 51, -1, 53, 54, -1, -1, -1, -1, -1, -1, 343, 344, 503, -1, 505, -1, 3, 4, 5, 6, 7, 8, 9, 344, 11, 12, -1, 503, -1, 505, 17, 18, 19, 20, -1, 22, 23, 24, -1, -1, -1, -1, 29, 30, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, 35, -1, -1, -1, 39, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, 51, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, 35, -1, -1, -1, 39, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, 51, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, 13, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, 52, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, 13, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, 52, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, 35, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, 51, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, 35, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, 51, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, 35, -1, -1, -1, 39, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, 13, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, 30, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, 39, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, 22, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, 22, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, 22, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, 47, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, 47, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, 52, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, 32, 3, 4, 5, 6, 7, 8, 9, -1, 11, -1, -1, -1, -1, -1, 17, 18, 19, 50, -1, -1, 23, 54, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, 39, -1, -1, -1, -1, -1, -1, 46, -1, -1, -1, 50, 3, 4, 5, 6, 7, 8, 9, 3, 11, -1, -1, -1, -1, -1, 17, 18, 19, -1, -1, -1, 23, -1, 3, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, 29, -1, -1, 32, 33, 34, 35, 36, 37, 38, 46, 40, 3, -1, 50, 29, 45, -1, 32, 33, 34, 35, 36, 37, 38, -1, 40, 3, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, 29, -1, -1, 32, 33, 34, 35, 36, 37, 38, -1, 40, -1, -1, -1, 29, 45, -1, 32, 33, 34, 35, 36, 37, 38, -1, 40, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, -1, -1, -1, -1, -1, -1, 48, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 26, 36, 56, 57, 58, 60, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 17, 18, 19, 20, 23, 24, 29, 32, 42, 44, 46, 50, 52, 53, 54, 70, 71, 75, 79, 80, 85, 86, 87, 88, 91, 93, 94, 105, 106, 107, 109, 111, 112, 131, 137, 138, 139, 140, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 155, 143, 0, 59, 143, 60, 120, 121, 142, 14, 37, 113, 4, 5, 6, 140, 50, 91, 30, 48, 113, 39, 94, 95, 96, 153, 22, 30, 32, 33, 34, 35, 36, 37, 38, 40, 89, 94, 111, 122, 123, 124, 152, 153, 154, 91, 142, 46, 102, 103, 142, 143, 46, 32, 41, 153, 154, 48, 67, 75, 70, 112, 140, 140, 31, 50, 76, 77, 80, 105, 46, 50, 76, 44, 30, 46, 62, 48, 49, 31, 50, 119, 120, 116, 117, 118, 142, 110, 94, 94, 110, 30, 47, 49, 68, 94, 94, 22, 90, 94, 51, 22, 30, 49, 51, 70, 49, 68, 51, 94, 51, 48, 67, 31, 46, 50, 108, 127, 132, 133, 134, 137, 141, 142, 143, 145, 146, 147, 148, 149, 150, 31, 21, 49, 46, 22, 94, 97, 46, 50, 142, 41, 92, 91, 91, 35, 51, 97, 98, 77, 95, 51, 97, 98, 99, 100, 153, 65, 143, 61, 142, 44, 121, 91, 94, 21, 48, 21, 37, 49, 68, 31, 69, 70, 112, 81, 82, 70, 94, 94, 153, 94, 51, 22, 49, 94, 94, 94, 51, 94, 122, 153, 50, 76, 91, 133, 108, 128, 129, 130, 153, 47, 49, 68, 46, 91, 142, 142, 133, 94, 22, 47, 49, 22, 97, 51, 97, 98, 99, 31, 50, 76, 78, 32, 50, 137, 142, 91, 94, 76, 49, 68, 101, 49, 101, 47, 78, 101, 101, 49, 68, 94, 35, 45, 66, 142, 152, 47, 63, 51, 142, 142, 118, 50, 54, 104, 131, 137, 141, 145, 146, 147, 148, 149, 150, 45, 49, 49, 45, 30, 94, 94, 94, 22, 51, 97, 98, 47, 30, 49, 68, 51, 108, 108, 133, 47, 47, 47, 94, 31, 94, 94, 22, 47, 78, 101, 101, 68, 91, 51, 97, 98, 99, 94, 35, 99, 51, 51, 51, 51, 100, 51, 142, 152, 44, 44, 62, 13, 15, 16, 64, 65, 48, 37, 94, 13, 30, 84, 94, 142, 84, 94, 22, 94, 76, 101, 101, 108, 128, 47, 31, 31, 47, 91, 47, 47, 94, 31, 51, 51, 51, 78, 101, 101, 68, 51, 94, 68, 31, 78, 78, 78, 44, 44, 113, 113, 44, 33, 34, 38, 125, 126, 135, 125, 33, 114, 115, 136, 45, 51, 142, 29, 30, 45, 49, 83, 28, 142, 45, 94, 51, 51, 91, 91, 31, 31, 31, 47, 91, 78, 78, 51, 51, 51, 91, 113, 113, 110, 110, 63, 48, 49, 142, 48, 48, 68, 142, 31, 94, 94, 84, 94, 28, 78, 91, 91, 91, 31, 78, 78, 110, 110, 10, 73, 144, 73, 65, 126, 31, 115, 31, 94, 83, 83, 83, 94, 91, 73, 73, 52, 72, 74, 94, 67, 72, 45, 104, 104, 83, 83, 72, 72, 91, 45, 74, 45, 45, 45, 67 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (YYID (N)) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (YYID (0)) #endif /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if YYLTYPE_IS_TRIVIAL # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ (Loc).first_line, (Loc).first_column, \ (Loc).last_line, (Loc).last_column) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else # define YYLEX yylex () #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (YYID (0)) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void yy_stack_print (yybottom, yytop) yytype_int16 *yybottom; yytype_int16 *yytop; #endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else static void yy_reduce_print (yyvsp, yyrule) YYSTYPE *yyvsp; int yyrule; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, Rule); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into YYRESULT an error message about the unexpected token YYCHAR while in state YYSTATE. Return the number of bytes copied, including the terminating null byte. If YYRESULT is null, do not copy anything; just return the number of bytes that would be copied. As a special case, return 0 if an ordinary "syntax error" message will do. Return YYSIZE_MAXIMUM if overflow occurs during size calculation. */ static YYSIZE_T yysyntax_error (char *yyresult, int yystate, int yychar) { int yyn = yypact[yystate]; if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) return 0; else { int yytype = YYTRANSLATE (yychar); YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; int yysize_overflow = 0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; int yyx; # if 0 /* This is so xgettext sees the translatable formats that are constructed on the fly. */ YY_("syntax error, unexpected %s"); YY_("syntax error, unexpected %s, expecting %s"); YY_("syntax error, unexpected %s, expecting %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); # endif char *yyfmt; char const *yyf; static char const yyunexpected[] = "syntax error, unexpected %s"; static char const yyexpecting[] = ", expecting %s"; static char const yyor[] = " or %s"; char yyformat[sizeof yyunexpected + sizeof yyexpecting - 1 + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) * (sizeof yyor - 1))]; char const *yyprefix = yyexpecting; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yycount = 1; yyarg[0] = yytname[yytype]; yyfmt = yystpcpy (yyformat, yyunexpected); for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; yyformat[sizeof yyunexpected - 1] = '\0'; break; } yyarg[yycount++] = yytname[yyx]; yysize1 = yysize + yytnamerr (0, yytname[yyx]); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; yyfmt = yystpcpy (yyfmt, yyprefix); yyprefix = yyor; } yyf = YY_(yyformat); yysize1 = yysize + yystrlen (yyf); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; if (yysize_overflow) return YYSIZE_MAXIMUM; if (yyresult) { /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ char *yyp = yyresult; int yyi = 0; while ((*yyp = *yyf) != '\0') { if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyf += 2; } else { yyp++; yyf++; } } } return yysize; } } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yymsg, yytype, yyvaluep) const char *yymsg; int yytype; YYSTYPE *yyvaluep; #endif { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*-------------------------. | yyparse or yypush_parse. | `-------------------------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else int yyparse () #endif #endif { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: `yyss': related to states. `yyvs': related to semantic values. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yytoken = 0; yyss = yyssa; yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYPACT_NINF) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yyn == 0 || yyn == YYTABLE_NINF) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: /* Line 1455 of yacc.c */ #line 40 "lang11d" { gRootParseNode = (PyrParseNode*)(yyvsp[(1) - (1)]); gParserResult = 1; ;} break; case 3: /* Line 1455 of yacc.c */ #line 42 "lang11d" { gRootParseNode = (PyrParseNode*)(yyvsp[(1) - (1)]); gParserResult = 1; ;} break; case 4: /* Line 1455 of yacc.c */ #line 44 "lang11d" { gRootParseNode = (PyrParseNode*)(yyvsp[(2) - (2)]); gParserResult = 2; ;} break; case 5: /* Line 1455 of yacc.c */ #line 47 "lang11d" { (yyval) = 0; ;} break; case 6: /* Line 1455 of yacc.c */ #line 49 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 8: /* Line 1455 of yacc.c */ #line 54 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 9: /* Line 1455 of yacc.c */ #line 58 "lang11d" { (yyval) = (long)newPyrClassNode((PyrSlotNode*)(yyvsp[(1) - (6)]), (PyrSlotNode*)(yyvsp[(2) - (6)]), (PyrVarListNode*)(yyvsp[(4) - (6)]), (PyrMethodNode*)(yyvsp[(5) - (6)]), 0); ;} break; case 10: /* Line 1455 of yacc.c */ #line 62 "lang11d" { (yyval) = (long)newPyrClassNode((PyrSlotNode*)(yyvsp[(1) - (9)]), (PyrSlotNode*)(yyvsp[(5) - (9)]), (PyrVarListNode*)(yyvsp[(7) - (9)]), (PyrMethodNode*)(yyvsp[(8) - (9)]), (PyrSlotNode*)(yyvsp[(3) - (9)])); ;} break; case 11: /* Line 1455 of yacc.c */ #line 69 "lang11d" { (yyval) = (long)newPyrClassExtNode((PyrSlotNode*)(yyvsp[(2) - (5)]), (PyrMethodNode*)(yyvsp[(4) - (5)])); ;} break; case 12: /* Line 1455 of yacc.c */ #line 74 "lang11d" { (yyval) = 0; ;} break; case 14: /* Line 1455 of yacc.c */ #line 78 "lang11d" { (yyval) = 0; ;} break; case 15: /* Line 1455 of yacc.c */ #line 80 "lang11d" { (yyval) = (yyvsp[(2) - (2)]); ;} break; case 16: /* Line 1455 of yacc.c */ #line 83 "lang11d" { (yyval) = 0; ;} break; case 17: /* Line 1455 of yacc.c */ #line 85 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 18: /* Line 1455 of yacc.c */ #line 89 "lang11d" { (yyval) = (long)newPyrVarListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), varClass); ;} break; case 19: /* Line 1455 of yacc.c */ #line 91 "lang11d" { (yyval) = (long)newPyrVarListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), varInst); ;} break; case 20: /* Line 1455 of yacc.c */ #line 93 "lang11d" { (yyval) = (long)newPyrVarListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), varConst); ;} break; case 21: /* Line 1455 of yacc.c */ #line 96 "lang11d" { (yyval) = 0; ;} break; case 22: /* Line 1455 of yacc.c */ #line 98 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 23: /* Line 1455 of yacc.c */ #line 102 "lang11d" { (yyval) = (long)newPyrMethodNode((PyrSlotNode*)(yyvsp[(1) - (7)]), (PyrSlotNode*)(yyvsp[(5) - (7)]), (PyrArgListNode*)(yyvsp[(3) - (7)]), (PyrVarListNode*)(yyvsp[(4) - (7)]), (PyrParseNode*)(yyvsp[(6) - (7)]), 0); ;} break; case 24: /* Line 1455 of yacc.c */ #line 105 "lang11d" { (yyval) = (long)newPyrMethodNode((PyrSlotNode*)(yyvsp[(2) - (8)]), (PyrSlotNode*)(yyvsp[(6) - (8)]), (PyrArgListNode*)(yyvsp[(4) - (8)]), (PyrVarListNode*)(yyvsp[(5) - (8)]), (PyrParseNode*)(yyvsp[(7) - (8)]), 1); ;} break; case 25: /* Line 1455 of yacc.c */ #line 108 "lang11d" { (yyval) = (long)newPyrMethodNode((PyrSlotNode*)(yyvsp[(1) - (7)]), (PyrSlotNode*)(yyvsp[(5) - (7)]), (PyrArgListNode*)(yyvsp[(3) - (7)]), (PyrVarListNode*)(yyvsp[(4) - (7)]), (PyrParseNode*)(yyvsp[(6) - (7)]), 0); ;} break; case 26: /* Line 1455 of yacc.c */ #line 111 "lang11d" { (yyval) = (long)newPyrMethodNode((PyrSlotNode*)(yyvsp[(2) - (8)]), (PyrSlotNode*)(yyvsp[(6) - (8)]), (PyrArgListNode*)(yyvsp[(4) - (8)]), (PyrVarListNode*)(yyvsp[(5) - (8)]), (PyrParseNode*)(yyvsp[(7) - (8)]), 1); ;} break; case 34: /* Line 1455 of yacc.c */ #line 129 "lang11d" { (yyval) = (long)newPyrDropNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 35: /* Line 1455 of yacc.c */ #line 133 "lang11d" { (yyval) = (long)newPyrBlockNode(NULL, (PyrVarListNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)]), false); ;} break; case 36: /* Line 1455 of yacc.c */ #line 135 "lang11d" { (yyval) = (long)newPyrBlockNode(NULL, (PyrVarListNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)]), false); ;} break; case 37: /* Line 1455 of yacc.c */ #line 137 "lang11d" { (yyval) = (long)newPyrBlockNode(NULL, NULL, (PyrParseNode*)(yyvsp[(1) - (1)]), false); ;} break; case 39: /* Line 1455 of yacc.c */ #line 142 "lang11d" { (yyval) = (long)newPyrDropNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 40: /* Line 1455 of yacc.c */ #line 145 "lang11d" { (yyval) = 0; ;} break; case 41: /* Line 1455 of yacc.c */ #line 147 "lang11d" { (yyval) = (yyvsp[(1) - (2)]); ;} break; case 42: /* Line 1455 of yacc.c */ #line 151 "lang11d" { (yyval) = (long)newPyrReturnNode(NULL); ;} break; case 43: /* Line 1455 of yacc.c */ #line 153 "lang11d" { (yyval) = (long)newPyrReturnNode((PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 44: /* Line 1455 of yacc.c */ #line 157 "lang11d" { (yyval) = (long)newPyrBlockReturnNode(); ;} break; case 45: /* Line 1455 of yacc.c */ #line 159 "lang11d" { (yyval) = (long)newPyrReturnNode((PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 47: /* Line 1455 of yacc.c */ #line 164 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 50: /* Line 1455 of yacc.c */ #line 173 "lang11d" { (yyval) = 0; ;} break; case 52: /* Line 1455 of yacc.c */ #line 178 "lang11d" { (yyval) = (long)newPyrCallNode((PyrSlotNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)]), 0, 0); ;} break; case 53: /* Line 1455 of yacc.c */ #line 182 "lang11d" { (yyval) = (long)newPyrCallNode((PyrSlotNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)]), 0, 0); ;} break; case 54: /* Line 1455 of yacc.c */ #line 186 "lang11d" { (yyval) = (long)newPyrCallNode((PyrSlotNode*)(yyvsp[(1) - (4)]), NULL, NULL, (PyrParseNode*)(yyvsp[(4) - (4)])); ;} break; case 55: /* Line 1455 of yacc.c */ #line 190 "lang11d" { (yyval) = (long)newPyrCallNode((PyrSlotNode*)(yyvsp[(1) - (6)]), (PyrParseNode*)(yyvsp[(3) - (6)]), (PyrParseNode*)(yyvsp[(4) - (6)]), (PyrParseNode*)(yyvsp[(6) - (6)])); ;} break; case 56: /* Line 1455 of yacc.c */ #line 195 "lang11d" { (yyval) = (long)newPyrCallNode((PyrSlotNode*)(yyvsp[(2) - (6)]), NULL, NULL, (PyrParseNode*)(yyvsp[(6) - (6)])); ;} break; case 57: /* Line 1455 of yacc.c */ #line 199 "lang11d" { (yyval) = (long)newPyrCallNode((PyrSlotNode*)(yyvsp[(2) - (8)]), (PyrParseNode*)(yyvsp[(5) - (8)]), (PyrParseNode*)(yyvsp[(6) - (8)]), (PyrParseNode*)(yyvsp[(8) - (8)])); ;} break; case 58: /* Line 1455 of yacc.c */ #line 204 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)(yyvsp[(3) - (5)]))) { SetRaw(&((PyrPushNameNode*)(yyvsp[(3) - (5)]))->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } selectornode = newPyrSlotNode(&slot); args = linkAfterHead( (PyrParseNode*)(yyvsp[(3) - (5)]), newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (5)]), NULL)); (yyval) = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(4) - (5)]), 0); ;} break; case 59: /* Line 1455 of yacc.c */ #line 222 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_performList); selectornode = newPyrSlotNode(&slot); args = linkAfterHead( (PyrParseNode*)(yyvsp[(5) - (7)]), newPyrPushLitNode((PyrSlotNode*)(yyvsp[(2) - (7)]), NULL)); (yyval) = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(6) - (7)]), 0); ;} break; case 60: /* Line 1455 of yacc.c */ #line 235 "lang11d" { (yyval) = (long)newPyrDynListNode((PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); ;} break; case 61: /* Line 1455 of yacc.c */ #line 237 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (2)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 62: /* Line 1455 of yacc.c */ #line 248 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (4)])); (yyval) = (long)newPyrCallNode(selectornode, args, NULL, (PyrParseNode*)(yyvsp[(4) - (4)])); ;} break; case 63: /* Line 1455 of yacc.c */ #line 259 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (6)])); (yyval) = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(3) - (6)]), (PyrParseNode*)(yyvsp[(6) - (6)])); ;} break; case 64: /* Line 1455 of yacc.c */ #line 270 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (6)])), (PyrParseNode*)(yyvsp[(3) - (6)])); (yyval) = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(4) - (6)]), (PyrParseNode*)(yyvsp[(6) - (6)])); ;} break; case 65: /* Line 1455 of yacc.c */ #line 283 "lang11d" { PyrSlotNode *selectornode, *selectornode2; PyrSlot slot, slot2; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)(yyvsp[(1) - (5)]))) { SetRaw(&((PyrPushNameNode*)(yyvsp[(1) - (5)]))->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } SetSymbol(&slot2, s_new); selectornode = newPyrSlotNode(&slot); selectornode2 = newPyrSlotNode(&slot2); args = linkNextNode( (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (5)])), newPyrPushLitNode(selectornode2, NULL)); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(3) - (5)])); (yyval) = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(5) - (5)]), 0); ;} break; case 66: /* Line 1455 of yacc.c */ #line 304 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); (yyval) = (long)newPyrCallNode(selectornode, (PyrParseNode*)(yyvsp[(1) - (5)]), NULL, (PyrParseNode*)(yyvsp[(5) - (5)])); ;} break; case 67: /* Line 1455 of yacc.c */ #line 313 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); (yyval) = (long)newPyrCallNode(selectornode, (PyrParseNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(4) - (7)]), (PyrParseNode*)(yyvsp[(7) - (7)])); ;} break; case 68: /* Line 1455 of yacc.c */ #line 322 "lang11d" { (yyval) = (long)newPyrCallNode((PyrSlotNode*)(yyvsp[(3) - (8)]), (PyrParseNode*)(yyvsp[(1) - (8)]), (PyrParseNode*)(yyvsp[(5) - (8)]), (PyrParseNode*)(yyvsp[(8) - (8)])); ;} break; case 69: /* Line 1455 of yacc.c */ #line 327 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(4) - (7)])); (yyval) = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(5) - (7)]), (PyrParseNode*)(yyvsp[(7) - (7)])); ;} break; case 70: /* Line 1455 of yacc.c */ #line 340 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot, slot2; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)(yyvsp[(1) - (6)]))) { SetRaw(&((PyrPushNameNode*)(yyvsp[(1) - (6)]))->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } SetSymbol(&slot2, s_value); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (6)]), newPyrPushLitNode(newPyrSlotNode(&slot2), NULL)); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(4) - (6)])); (yyval) = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(5) - (6)]), 0); ;} break; case 71: /* Line 1455 of yacc.c */ #line 360 "lang11d" { (yyval) = (long)newPyrCallNode((PyrSlotNode*)(yyvsp[(3) - (6)]), (PyrParseNode*)(yyvsp[(1) - (6)]), NULL, (PyrParseNode*)(yyvsp[(6) - (6)])); ;} break; case 72: /* Line 1455 of yacc.c */ #line 364 "lang11d" { PyrParseNode* args; args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (8)]), (PyrParseNode*)(yyvsp[(5) - (8)])); (yyval) = (long)newPyrCallNode((PyrSlotNode*)(yyvsp[(3) - (8)]), args, (PyrParseNode*)(yyvsp[(6) - (8)]), (PyrParseNode*)(yyvsp[(8) - (8)])); ;} break; case 73: /* Line 1455 of yacc.c */ #line 370 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)(yyvsp[(1) - (7)]))) { SetRaw(&((PyrPushNameNode*)(yyvsp[(1) - (7)]))->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } selectornode = newPyrSlotNode(&slot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (7)]), newPyrPushLitNode((PyrSlotNode*)(yyvsp[(3) - (7)]), NULL)); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (7)])); (yyval) = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(6) - (7)]), 0); ;} break; case 74: /* Line 1455 of yacc.c */ #line 388 "lang11d" { (yyval) = (long)newPyrCallNode((PyrSlotNode*)(yyvsp[(3) - (4)]), (PyrParseNode*)(yyvsp[(1) - (4)]), 0, (PyrParseNode*)(yyvsp[(4) - (4)])); ;} break; case 75: /* Line 1455 of yacc.c */ #line 393 "lang11d" { pushls(&generatorStack, (yyvsp[(3) - (3)])); pushls(&generatorStack, 1); ;} break; case 76: /* Line 1455 of yacc.c */ #line 394 "lang11d" { PyrSlot slot; SetSymbol(&slot, getsym("r")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)(yyvsp[(6) - (7)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); (yyval) = (long)newPyrCallNode(selectornode, (PyrParseNode*)blocklit, 0, 0); ;} break; case 77: /* Line 1455 of yacc.c */ #line 403 "lang11d" { pushls(&generatorStack, (yyvsp[(3) - (3)])); pushls(&generatorStack, 2); ;} break; case 78: /* Line 1455 of yacc.c */ #line 404 "lang11d" { (yyval) = (yyvsp[(6) - (7)]); ;} break; case 79: /* Line 1455 of yacc.c */ #line 410 "lang11d" { // innermost part int action = popls(&generatorStack); PyrParseNode* expr = (PyrParseNode*)popls(&generatorStack); switch (action) { case 1 : { PyrSlot slot; SetSymbol(&slot, getsym("yield")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); (yyval) = (long)newPyrCallNode(selectornode, expr, 0, 0); } break; case 2 : { (yyval) = (long)expr; } break; } ;} break; case 80: /* Line 1455 of yacc.c */ #line 432 "lang11d" { (yyval) = (yyvsp[(2) - (2)]); ;} break; case 81: /* Line 1455 of yacc.c */ #line 436 "lang11d" { // later should check if exprseq is a series and optimize it to for loop PyrParseNode *exprseq = (PyrParseNode*)(yyvsp[(3) - (4)]); if (exprseq->mClassno == pn_CallNode) { PyrCallNode *callnode = (PyrCallNode*)exprseq; if (slotRawSymbol(&callnode->mSelector->mSlot) == s_series) { SetSymbol(&callnode->mSelector->mSlot, getsym("forSeries")); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (4)]), NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)(yyvsp[(4) - (4)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); callnode->mArglist = linkNextNode(callnode->mArglist, blocklit); (yyval) = (long)callnode; } else goto notoptimized1; } else { notoptimized1: PyrSlot slot; SetSymbol(&slot, getsym("do")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (4)]), NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)(yyvsp[(4) - (4)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = linkNextNode(exprseq, blocklit); (yyval) = (long)newPyrCallNode(selectornode, args2, 0, 0); } ;} break; case 82: /* Line 1455 of yacc.c */ #line 470 "lang11d" { // later should check if exprseq is a series and optimize it to for loop PyrParseNode *exprseq = (PyrParseNode*)(yyvsp[(4) - (5)]); if (exprseq->mClassno == pn_CallNode) { PyrCallNode *callnode = (PyrCallNode*)exprseq; if (slotRawSymbol(&callnode->mSelector->mSlot) == s_series) { SetSymbol(&callnode->mSelector->mSlot, getsym("forSeries")); PyrVarDefNode* var1 = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (5)]), NULL, 0); PyrVarDefNode* var2 = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (5)]), NULL, 0); PyrVarDefNode* vars = (PyrVarDefNode*)linkNextNode(var1, var2); PyrArgListNode* args = newPyrArgListNode(vars, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)(yyvsp[(5) - (5)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); callnode->mArglist = linkNextNode(callnode->mArglist, blocklit); (yyval) = (long)callnode; } else goto notoptimized2; } else { notoptimized2: PyrSlot slot; SetSymbol(&slot, getsym("do")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var1 = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (5)]), NULL, 0); PyrVarDefNode* var2 = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (5)]), NULL, 0); PyrVarDefNode* vars = (PyrVarDefNode*)linkNextNode(var1, var2); PyrArgListNode* args = newPyrArgListNode(vars, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)(yyvsp[(5) - (5)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = linkNextNode(exprseq, blocklit); (yyval) = (long)newPyrCallNode(selectornode, args2, 0, 0); } ;} break; case 83: /* Line 1455 of yacc.c */ #line 508 "lang11d" { PyrSlot slot; SetSymbol(&slot, s_value); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (5)]), NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)(yyvsp[(5) - (5)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = (PyrParseNode*)linkNextNode(blocklit, (PyrParseNode*)(yyvsp[(4) - (5)])); (yyval) = (long)newPyrCallNode(selectornode, args2, 0, 0); ;} break; case 84: /* Line 1455 of yacc.c */ #line 522 "lang11d" { PyrSlot slot; SetSymbol(&slot, getsym("if")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)(yyvsp[(2) - (2)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = (PyrParseNode*)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), blocklit); (yyval) = (long)newPyrCallNode(selectornode, args2, 0, 0); ;} break; case 85: /* Line 1455 of yacc.c */ #line 533 "lang11d" { (yyval) = (long)newPyrDropNode((PyrParseNode*)(yyvsp[(3) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)])); ;} break; case 86: /* Line 1455 of yacc.c */ #line 537 "lang11d" { PyrSlot slot; SetSymbol(&slot, getsym("alwaysYield")); PyrSlotNode* selectornode1 = newPyrSlotNode(&slot); SetSymbol(&slot, getsym("if")); PyrSlotNode* selectornode2 = newPyrSlotNode(&slot); SetNil(&slot); PyrParseNode *pushnil = (PyrParseNode*)newPyrPushLitNode(newPyrSlotNode(&slot), NULL); PyrParseNode *yieldNil = (PyrParseNode*)newPyrCallNode(selectornode1, pushnil, 0, 0); PyrParseNode *block1 = (PyrParseNode*)newPyrBlockNode(0, 0, yieldNil, false); PyrParseNode *blocklit1 = (PyrParseNode*)newPyrPushLitNode(NULL, block1); PyrParseNode *block2 = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)(yyvsp[(4) - (4)]), false); PyrParseNode *blocklit2 = (PyrParseNode*)newPyrPushLitNode(NULL, block2); PyrParseNode* args2 = (PyrParseNode*)linkNextNode((PyrParseNode*)(yyvsp[(3) - (4)]), blocklit2); PyrParseNode* args3 = (PyrParseNode*)linkNextNode(args2, blocklit1); (yyval) = (long)newPyrCallNode(selectornode2, args3, 0, 0); ;} break; case 93: /* Line 1455 of yacc.c */ #line 568 "lang11d" { PyrParseNode* node = (PyrParseNode*)(yyvsp[(2) - (3)]); node->mParens = 1; (yyval) = (yyvsp[(2) - (3)]); ;} break; case 94: /* Line 1455 of yacc.c */ #line 574 "lang11d" { PyrParseNode* argnode; PyrSlotNode* selectornode; PyrSlot slot; argnode = (PyrParseNode*)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(2) - (2)]), NULL); SetSymbol(&slot, s_envirGet); selectornode = newPyrSlotNode(&slot); (yyval) = (long)newPyrCallNode(selectornode, argnode, 0, 0); ;} break; case 95: /* Line 1455 of yacc.c */ #line 584 "lang11d" { (yyval) = (long)newPyrDynListNode(0, (PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 96: /* Line 1455 of yacc.c */ #line 586 "lang11d" { (yyval) = (yyvsp[(2) - (3)]); ;} break; case 97: /* Line 1455 of yacc.c */ #line 588 "lang11d" { (yyval) = (yyvsp[(3) - (4)]); ;} break; case 98: /* Line 1455 of yacc.c */ #line 590 "lang11d" { (yyval) = (long)newPyrDynDictNode((PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 99: /* Line 1455 of yacc.c */ #line 592 "lang11d" { (yyval) = (long)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (1)])); ;} break; case 100: /* Line 1455 of yacc.c */ #line 594 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_at); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 102: /* Line 1455 of yacc.c */ #line 610 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(3) - (5)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (5)])); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (5)]), (PyrParseNode*)(yyvsp[(3) - (5)])); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 103: /* Line 1455 of yacc.c */ #line 637 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (5)]), nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(4) - (5)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 104: /* Line 1455 of yacc.c */ #line 655 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(3) - (6)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (6)])); compileErrors++; } SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (6)]), (PyrParseNode*)(yyvsp[(3) - (6)])); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (6)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 105: /* Line 1455 of yacc.c */ #line 682 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(3) - (7)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (7)])); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(3) - (7)])); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(7) - (7)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 106: /* Line 1455 of yacc.c */ #line 710 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (7)]), nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(4) - (7)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(7) - (7)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 107: /* Line 1455 of yacc.c */ #line 729 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(3) - (8)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (8)])); compileErrors++; } SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (8)]), (PyrParseNode*)(yyvsp[(3) - (8)])); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (8)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(8) - (8)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 108: /* Line 1455 of yacc.c */ #line 757 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(4) - (6)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (6)])); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (6)]), (PyrParseNode*)(yyvsp[(4) - (6)])); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 109: /* Line 1455 of yacc.c */ #line 784 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (6)]), nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (6)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 110: /* Line 1455 of yacc.c */ #line 802 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(4) - (7)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (7)])); compileErrors++; } SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(4) - (7)])); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)(yyvsp[(6) - (7)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 111: /* Line 1455 of yacc.c */ #line 827 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(4) - (8)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (8)])); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (8)]), (PyrParseNode*)(yyvsp[(4) - (8)])); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(8) - (8)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 112: /* Line 1455 of yacc.c */ #line 855 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (8)]), nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (8)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(8) - (8)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 113: /* Line 1455 of yacc.c */ #line 874 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(4) - (9)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (9)])); compileErrors++; } SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (9)]), (PyrParseNode*)(yyvsp[(4) - (9)])); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)(yyvsp[(6) - (9)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(9) - (9)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 114: /* Line 1455 of yacc.c */ #line 902 "lang11d" { // if this is not used in a 'do' or list comprehension, then should return an error. PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), nilnode); args = linkNextNode(args, nilnode2); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 115: /* Line 1455 of yacc.c */ #line 921 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *zeronode; PyrSlot selectorSlot, nilSlot, zeroSlot; PyrParseNode* args; SetInt(&zeroSlot, 0); SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); zeronode = newPyrPushLitNode(newPyrSlotNode(&zeroSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode(zeronode, nilnode); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(2) - (2)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 116: /* Line 1455 of yacc.c */ #line 940 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), nilnode); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(3) - (3)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 117: /* Line 1455 of yacc.c */ #line 957 "lang11d" { PyrSlotNode *selectornode; PyrSlot selectorSlot; PyrParseNode* args; SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (5)]), (PyrParseNode*)(yyvsp[(3) - (5)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (5)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 118: /* Line 1455 of yacc.c */ #line 971 "lang11d" { // if this is not used in a 'do' or list comprehension, then should return an error. PyrSlotNode *selectornode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; PyrPushLitNode *nilnode; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); args = linkNextNode(args, nilnode); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 119: /* Line 1455 of yacc.c */ #line 992 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *zeronode; PyrSlot selectorSlot, nilSlot, zeroSlot; PyrParseNode* args; SetInt(&zeroSlot, 0); SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); zeronode = newPyrPushLitNode(newPyrSlotNode(&zeroSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode(zeronode, nilnode); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(2) - (2)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 120: /* Line 1455 of yacc.c */ #line 1011 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), nilnode); args = linkNextNode(args, nilnode2); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 121: /* Line 1455 of yacc.c */ #line 1029 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), nilnode); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(3) - (3)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 122: /* Line 1455 of yacc.c */ #line 1046 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); args = linkNextNode(args, nilnode); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 123: /* Line 1455 of yacc.c */ #line 1062 "lang11d" { PyrSlotNode *selectornode; PyrSlot selectorSlot; PyrParseNode* args; SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (5)]), (PyrParseNode*)(yyvsp[(3) - (5)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (5)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 127: /* Line 1455 of yacc.c */ #line 1080 "lang11d" { (yyval) = (long)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (1)])); ;} break; case 128: /* Line 1455 of yacc.c */ #line 1082 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_at); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (5)]), (PyrParseNode*)(yyvsp[(4) - (5)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 129: /* Line 1455 of yacc.c */ #line 1095 "lang11d" { PyrParseNode *node, *args; PyrSlotNode *slotnode; PyrSlot slot; SetSymbol(&slot, s_ref); slotnode = newPyrSlotNode(&slot); node = (PyrParseNode*)newPyrPushNameNode(slotnode); args = linkNextNode(node, (PyrParseNode*)(yyvsp[(2) - (2)])); SetSymbol(&slot, s_new); slotnode = newPyrSlotNode(&slot); (yyval) = (long)newPyrCallNode(slotnode, args, 0, 0); ;} break; case 130: /* Line 1455 of yacc.c */ #line 1109 "lang11d" { (yyval) = (long)newPyrBinopCallNode((PyrSlotNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); ;} break; case 131: /* Line 1455 of yacc.c */ #line 1114 "lang11d" { (yyval) = (long)newPyrAssignNode((PyrSlotNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)]), 0); ;} break; case 132: /* Line 1455 of yacc.c */ #line 1118 "lang11d" { PyrParseNode *argnode, *args; PyrSlotNode* selectornode; PyrSlot slot; argnode = (PyrParseNode*)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(2) - (4)]), NULL); args = linkNextNode(argnode, (PyrParseNode*)(yyvsp[(4) - (4)])); SetSymbol(&slot, s_envirPut); selectornode = newPyrSlotNode(&slot); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 133: /* Line 1455 of yacc.c */ #line 1129 "lang11d" { (yyval) = (long)newPyrSetterNode((PyrSlotNode*)(yyvsp[(3) - (5)]), (PyrParseNode*)(yyvsp[(1) - (5)]), (PyrParseNode*)(yyvsp[(5) - (5)])); ;} break; case 134: /* Line 1455 of yacc.c */ #line 1134 "lang11d" { if ((yyvsp[(4) - (7)]) != 0) { error("Setter method called with keyword arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(4) - (7)])); compileErrors++; } (yyval) = (long)newPyrSetterNode((PyrSlotNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(3) - (7)]), (PyrParseNode*)(yyvsp[(7) - (7)])); ;} break; case 135: /* Line 1455 of yacc.c */ #line 1144 "lang11d" { (yyval) = (long)newPyrMultiAssignNode((PyrMultiAssignVarListNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)]), 0); ;} break; case 136: /* Line 1455 of yacc.c */ #line 1149 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_put); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (6)]), (PyrParseNode*)(yyvsp[(3) - (6)])); args = linkNextNode( args, (PyrParseNode*)(yyvsp[(6) - (6)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 137: /* Line 1455 of yacc.c */ #line 1163 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_put); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(4) - (7)])); args = linkNextNode( args, (PyrParseNode*)(yyvsp[(7) - (7)])); (yyval) = (long)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 138: /* Line 1455 of yacc.c */ #line 1178 "lang11d" { (yyval) = 0; ;} break; case 139: /* Line 1455 of yacc.c */ #line 1179 "lang11d" { (yyval) = (long)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(2) - (2)]), NULL); ;} break; case 140: /* Line 1455 of yacc.c */ #line 1180 "lang11d" { (yyval) = (long)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(2) - (2)]), NULL); ;} break; case 141: /* Line 1455 of yacc.c */ #line 1181 "lang11d" { (yyval) = (yyvsp[(3) - (4)]); ;} break; case 143: /* Line 1455 of yacc.c */ #line 1186 "lang11d" { (yyval) = (long)newPyrDropNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 145: /* Line 1455 of yacc.c */ #line 1194 "lang11d" { (yyval) = 0; ;} break; case 146: /* Line 1455 of yacc.c */ #line 1196 "lang11d" { (yyval) = (yyvsp[(1) - (2)]); ;} break; case 148: /* Line 1455 of yacc.c */ #line 1201 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 149: /* Line 1455 of yacc.c */ #line 1203 "lang11d" { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (2)]), NULL); (yyval) = (long)linkNextNode(key, (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 150: /* Line 1455 of yacc.c */ #line 1208 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 151: /* Line 1455 of yacc.c */ #line 1210 "lang11d" { PyrParseNode* elems; PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)(yyvsp[(3) - (4)]), NULL); elems = (PyrParseNode*)linkNextNode(key, (PyrParseNode*)(yyvsp[(4) - (4)])); (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (4)]), elems); ;} break; case 152: /* Line 1455 of yacc.c */ #line 1217 "lang11d" { PyrParseNode* elems; elems = (PyrParseNode*)linkNextNode((PyrParseNode*)(yyvsp[(3) - (5)]), (PyrParseNode*)(yyvsp[(5) - (5)])); (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (5)]), elems); ;} break; case 154: /* Line 1455 of yacc.c */ #line 1226 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 155: /* Line 1455 of yacc.c */ #line 1230 "lang11d" { (yyval) = (yyvsp[(2) - (2)]); ;} break; case 156: /* Line 1455 of yacc.c */ #line 1232 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)])); ;} break; case 158: /* Line 1455 of yacc.c */ #line 1237 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 159: /* Line 1455 of yacc.c */ #line 1241 "lang11d" { (yyval) = (long)newPyrPushKeyArgNode((PyrSlotNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 160: /* Line 1455 of yacc.c */ #line 1244 "lang11d" { (yyval) = 0; ;} break; case 161: /* Line 1455 of yacc.c */ #line 1245 "lang11d" { (yyval) = (yyvsp[(2) - (3)]); ;} break; case 162: /* Line 1455 of yacc.c */ #line 1249 "lang11d" { (yyval) = (long)newPyrMultiAssignVarListNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 163: /* Line 1455 of yacc.c */ #line 1251 "lang11d" { (yyval) = (long)newPyrMultiAssignVarListNode((PyrSlotNode*)(yyvsp[(1) - (3)]), (PyrSlotNode*)(yyvsp[(3) - (3)])); ;} break; case 165: /* Line 1455 of yacc.c */ #line 1256 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 166: /* Line 1455 of yacc.c */ #line 1260 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 167: /* Line 1455 of yacc.c */ #line 1261 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 168: /* Line 1455 of yacc.c */ #line 1262 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 169: /* Line 1455 of yacc.c */ #line 1263 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 170: /* Line 1455 of yacc.c */ #line 1264 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 171: /* Line 1455 of yacc.c */ #line 1265 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 172: /* Line 1455 of yacc.c */ #line 1266 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 173: /* Line 1455 of yacc.c */ #line 1267 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 174: /* Line 1455 of yacc.c */ #line 1268 "lang11d" { (yyval) = (long)newPyrLiteralNode(NULL, (PyrParseNode*)(yyvsp[(1) - (1)])); ;} break; case 175: /* Line 1455 of yacc.c */ #line 1271 "lang11d" { (yyval) = (long)newPyrPushLitNode(NULL, (PyrParseNode*)(yyvsp[(1) - (1)])); ;} break; case 176: /* Line 1455 of yacc.c */ #line 1274 "lang11d" { (yyval) = (long)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (1)])); ;} break; case 177: /* Line 1455 of yacc.c */ #line 1277 "lang11d" { (yyval) = (long)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 178: /* Line 1455 of yacc.c */ #line 1278 "lang11d" { (yyval) = (long)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 179: /* Line 1455 of yacc.c */ #line 1279 "lang11d" { (yyval) = (long)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 180: /* Line 1455 of yacc.c */ #line 1280 "lang11d" { (yyval) = (long)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 181: /* Line 1455 of yacc.c */ #line 1281 "lang11d" { (yyval) = (long)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 182: /* Line 1455 of yacc.c */ #line 1282 "lang11d" { (yyval) = (long)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 183: /* Line 1455 of yacc.c */ #line 1283 "lang11d" { (yyval) = (long)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 184: /* Line 1455 of yacc.c */ #line 1284 "lang11d" { (yyval) = (long)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 185: /* Line 1455 of yacc.c */ #line 1285 "lang11d" { (yyval) = (long)newPyrPushLitNode(NULL, (PyrParseNode*)(yyvsp[(1) - (1)])); ;} break; case 186: /* Line 1455 of yacc.c */ #line 1288 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 187: /* Line 1455 of yacc.c */ #line 1289 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 188: /* Line 1455 of yacc.c */ #line 1290 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 189: /* Line 1455 of yacc.c */ #line 1291 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 190: /* Line 1455 of yacc.c */ #line 1292 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 191: /* Line 1455 of yacc.c */ #line 1293 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 192: /* Line 1455 of yacc.c */ #line 1294 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 193: /* Line 1455 of yacc.c */ #line 1295 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 194: /* Line 1455 of yacc.c */ #line 1296 "lang11d" { (yyval) = (long)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 195: /* Line 1455 of yacc.c */ #line 1297 "lang11d" { (yyval) = (long)newPyrLiteralNode(NULL, (PyrParseNode*)(yyvsp[(1) - (1)])); ;} break; case 196: /* Line 1455 of yacc.c */ #line 1298 "lang11d" { (yyval) = (long)newPyrLiteralNode(NULL, (PyrParseNode*)(yyvsp[(1) - (1)])); ;} break; case 197: /* Line 1455 of yacc.c */ #line 1302 "lang11d" { (yyval) = (long)newPyrBlockNode((PyrArgListNode*)(yyvsp[(2) - (5)]), (PyrVarListNode*)(yyvsp[(3) - (5)]), (PyrParseNode*)(yyvsp[(4) - (5)]), false); ;} break; case 198: /* Line 1455 of yacc.c */ #line 1305 "lang11d" { (yyval) = (long)newPyrBlockNode((PyrArgListNode*)(yyvsp[(2) - (5)]), (PyrVarListNode*)(yyvsp[(3) - (5)]), (PyrParseNode*)(yyvsp[(4) - (5)]), true); ;} break; case 199: /* Line 1455 of yacc.c */ #line 1309 "lang11d" { (yyval) = 0; ;} break; case 200: /* Line 1455 of yacc.c */ #line 1311 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 202: /* Line 1455 of yacc.c */ #line 1316 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 203: /* Line 1455 of yacc.c */ #line 1320 "lang11d" { (yyval) = (long)newPyrVarListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), varLocal); ;} break; case 204: /* Line 1455 of yacc.c */ #line 1323 "lang11d" { (yyval) = 0; ;} break; case 205: /* Line 1455 of yacc.c */ #line 1325 "lang11d" { (yyval) = (long)newPyrArgListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), NULL); ;} break; case 206: /* Line 1455 of yacc.c */ #line 1329 "lang11d" { (yyval) = (long)newPyrArgListNode((PyrVarDefNode*)(yyvsp[(2) - (5)]), (PyrSlotNode*)(yyvsp[(4) - (5)])); ;} break; case 207: /* Line 1455 of yacc.c */ #line 1333 "lang11d" { (yyval) = (long)newPyrArgListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), NULL); ;} break; case 208: /* Line 1455 of yacc.c */ #line 1337 "lang11d" { (yyval) = (long)newPyrArgListNode((PyrVarDefNode*)(yyvsp[(2) - (5)]), (PyrSlotNode*)(yyvsp[(4) - (5)])); ;} break; case 210: /* Line 1455 of yacc.c */ #line 1344 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 211: /* Line 1455 of yacc.c */ #line 1348 "lang11d" { (yyval) = (long)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)]), (yyvsp[(1) - (4)])); ;} break; case 212: /* Line 1455 of yacc.c */ #line 1351 "lang11d" { (yyval) = 0; ;} break; case 215: /* Line 1455 of yacc.c */ #line 1357 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 216: /* Line 1455 of yacc.c */ #line 1361 "lang11d" { (yyval) = (long)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL, 0); ;} break; case 217: /* Line 1455 of yacc.c */ #line 1363 "lang11d" { (yyval) = (long)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)]), 0); ;} break; case 218: /* Line 1455 of yacc.c */ #line 1365 "lang11d" { PyrParseNode* node = (PyrParseNode*)(yyvsp[(4) - (5)]); node->mParens = 1; (yyval) = (long)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (5)]), node, 0); ;} break; case 219: /* Line 1455 of yacc.c */ #line 1372 "lang11d" { (yyval) = 0; ;} break; case 222: /* Line 1455 of yacc.c */ #line 1378 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 223: /* Line 1455 of yacc.c */ #line 1382 "lang11d" { (yyval) = (long)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL, 0); ;} break; case 224: /* Line 1455 of yacc.c */ #line 1384 "lang11d" { (yyval) = (long)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)]), 0); ;} break; case 225: /* Line 1455 of yacc.c */ #line 1386 "lang11d" { PyrParseNode* node = (PyrParseNode*)(yyvsp[(3) - (4)]); node->mParens = 1; (yyval) = (long)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (4)]), node, 0); ;} break; case 226: /* Line 1455 of yacc.c */ #line 1394 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 227: /* Line 1455 of yacc.c */ #line 1396 "lang11d" { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (2)]), NULL); (yyval) = (long)linkNextNode(key, (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 229: /* Line 1455 of yacc.c */ #line 1404 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 230: /* Line 1455 of yacc.c */ #line 1407 "lang11d" { (yyval) = 0; ;} break; case 233: /* Line 1455 of yacc.c */ #line 1413 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 234: /* Line 1455 of yacc.c */ #line 1417 "lang11d" { (yyval) = (long)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - (2)])); ;} break; case 235: /* Line 1455 of yacc.c */ #line 1419 "lang11d" { (yyval) = (long)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)]), (yyvsp[(1) - (4)])); ;} break; case 236: /* Line 1455 of yacc.c */ #line 1423 "lang11d" { (yyval) = (long)newPyrLitDictNode((PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 237: /* Line 1455 of yacc.c */ #line 1427 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 238: /* Line 1455 of yacc.c */ #line 1429 "lang11d" { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (2)]), NULL); (yyval) = (long)linkNextNode(key, (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 240: /* Line 1455 of yacc.c */ #line 1437 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 241: /* Line 1455 of yacc.c */ #line 1440 "lang11d" { (yyval) = 0; ;} break; case 243: /* Line 1455 of yacc.c */ #line 1447 "lang11d" { (yyval) = (long)newPyrLitListNode(0, (PyrParseNode*)(yyvsp[(3) - (4)])); ;} break; case 244: /* Line 1455 of yacc.c */ #line 1449 "lang11d" { (yyval) = (long)newPyrLitListNode((PyrParseNode*)(yyvsp[(2) - (5)]), (PyrParseNode*)(yyvsp[(4) - (5)])); ;} break; case 245: /* Line 1455 of yacc.c */ #line 1453 "lang11d" { (yyval) = (long)newPyrLitListNode(0, (PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 246: /* Line 1455 of yacc.c */ #line 1455 "lang11d" { (yyval) = (long)newPyrLitListNode((PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); ;} break; case 247: /* Line 1455 of yacc.c */ #line 1458 "lang11d" { (yyval) = 0; ;} break; case 250: /* Line 1455 of yacc.c */ #line 1464 "lang11d" { (yyval) = (long)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 251: /* Line 1455 of yacc.c */ #line 1467 "lang11d" { (yyval) = rwPrivate; ;} break; case 252: /* Line 1455 of yacc.c */ #line 1469 "lang11d" { (yyval) = rwReadOnly; ;} break; case 253: /* Line 1455 of yacc.c */ #line 1471 "lang11d" { (yyval) = rwReadWrite; ;} break; case 254: /* Line 1455 of yacc.c */ #line 1473 "lang11d" { (yyval) = rwWriteOnly; ;} break; case 255: /* Line 1455 of yacc.c */ #line 1476 "lang11d" { (yyval) = rwPrivate; ;} break; case 256: /* Line 1455 of yacc.c */ #line 1478 "lang11d" { (yyval) = rwReadOnly; ;} break; case 257: /* Line 1455 of yacc.c */ #line 1481 "lang11d" { (yyval) = zzval; ;} break; case 258: /* Line 1455 of yacc.c */ #line 1483 "lang11d" { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetRaw(&node->mSlot, -slotRawInt(&node->mSlot)); (yyval) = zzval; ;} break; case 259: /* Line 1455 of yacc.c */ #line 1491 "lang11d" { (yyval) = zzval; ;} break; case 260: /* Line 1455 of yacc.c */ #line 1493 "lang11d" { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetRaw(&node->mSlot, -slotRawFloat(&node->mSlot)); (yyval) = zzval; ;} break; case 261: /* Line 1455 of yacc.c */ #line 1501 "lang11d" { (yyval) = zzval; ;} break; case 262: /* Line 1455 of yacc.c */ #line 1503 "lang11d" { PyrSlotNode *node; double intval, fracval; node = (PyrSlotNode*)zzval; intval = floor(slotRawFloat(&node->mSlot) + 0.5); fracval = slotRawFloat(&node->mSlot) - intval; SetRaw(&node->mSlot, -intval + fracval); (yyval) = zzval; ;} break; case 263: /* Line 1455 of yacc.c */ #line 1513 "lang11d" { (yyval) = zzval; ;} break; case 266: /* Line 1455 of yacc.c */ #line 1519 "lang11d" { PyrSlotNode *node; node = (PyrSlotNode*)(yyvsp[(1) - (2)]); SetRaw(&node->mSlot, slotRawFloat(&node->mSlot) * pi); ;} break; case 267: /* Line 1455 of yacc.c */ #line 1525 "lang11d" { PyrSlotNode *node; double ival; node = (PyrSlotNode*)(yyvsp[(1) - (2)]); ival = slotRawInt(&node->mSlot); SetFloat(&node->mSlot, ival * pi); ;} break; case 268: /* Line 1455 of yacc.c */ #line 1533 "lang11d" { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetFloat(&node->mSlot, pi); (yyval) = zzval; ;} break; case 269: /* Line 1455 of yacc.c */ #line 1540 "lang11d" { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetFloat(&node->mSlot, -pi); (yyval) = zzval; ;} break; case 270: /* Line 1455 of yacc.c */ #line 1548 "lang11d" { (yyval) = zzval; ;} break; case 271: /* Line 1455 of yacc.c */ #line 1549 "lang11d" { (yyval) = zzval; ;} break; case 272: /* Line 1455 of yacc.c */ #line 1552 "lang11d" { (yyval) = zzval; ;} break; case 273: /* Line 1455 of yacc.c */ #line 1555 "lang11d" { (yyval) = zzval; ;} break; case 274: /* Line 1455 of yacc.c */ #line 1558 "lang11d" { (yyval) = zzval; ;} break; case 275: /* Line 1455 of yacc.c */ #line 1561 "lang11d" { (yyval) = zzval; ;} break; case 276: /* Line 1455 of yacc.c */ #line 1564 "lang11d" { (yyval) = zzval; ;} break; case 277: /* Line 1455 of yacc.c */ #line 1567 "lang11d" { (yyval) = zzval; ;} break; case 278: /* Line 1455 of yacc.c */ #line 1570 "lang11d" { (yyval) = zzval; ;} break; case 279: /* Line 1455 of yacc.c */ #line 1573 "lang11d" { (yyval) = zzval; ;} break; case 280: /* Line 1455 of yacc.c */ #line 1576 "lang11d" { (yyval) = zzval; ;} break; case 281: /* Line 1455 of yacc.c */ #line 1579 "lang11d" { (yyval) = zzval; ;} break; case 282: /* Line 1455 of yacc.c */ #line 1580 "lang11d" { (yyval) = zzval; ;} break; case 283: /* Line 1455 of yacc.c */ #line 1581 "lang11d" { (yyval) = zzval; ;} break; case 284: /* Line 1455 of yacc.c */ #line 1582 "lang11d" { (yyval) = zzval; ;} break; case 285: /* Line 1455 of yacc.c */ #line 1583 "lang11d" { (yyval) = zzval; ;} break; case 286: /* Line 1455 of yacc.c */ #line 1584 "lang11d" { (yyval) = zzval; ;} break; case 287: /* Line 1455 of yacc.c */ #line 1585 "lang11d" { (yyval) = zzval; ;} break; case 288: /* Line 1455 of yacc.c */ #line 1586 "lang11d" { (yyval) = zzval; ;} break; case 289: /* Line 1455 of yacc.c */ #line 1589 "lang11d" { (yyval) = zzval; ;} break; case 292: /* Line 1455 of yacc.c */ #line 1596 "lang11d" { (yyval) = zzval; ;} break; /* Line 1455 of yacc.c */ #line 4778 "lang11d_tab.cpp" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else { YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) { YYSIZE_T yyalloc = 2 * yysize; if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) yyalloc = YYSTACK_ALLOC_MAXIMUM; if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yyalloc); if (yymsg) yymsg_alloc = yyalloc; else { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; } } if (0 < yysize && yysize <= yymsg_alloc) { (void) yysyntax_error (yymsg, yystate, yychar); yyerror (yymsg); } else { yyerror (YY_("syntax error")); if (yysize != 0) goto yyexhaustedlab; } } #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } *++yyvsp = yylval; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined(yyoverflow) || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif /* Make sure YYID is used. */ return YYID (yyresult); } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/Bison/lang11d0000664000000000000000000013642012161364457024207 0ustar rootroot%token NAME INTEGER SC_FLOAT ACCIDENTAL SYMBOL STRING ASCII PRIMITIVENAME CLASSNAME CURRYARG %token VAR ARG CLASSVAR SC_CONST %token NILOBJ TRUEOBJ FALSEOBJ %token PSEUDOVAR %token ELLIPSIS DOTDOT PIE BEGINCLOSEDFUNC %token BADTOKEN INTERPRET %token BEGINGENERATOR LEFTARROW WHILE %left ':' %right '=' %left BINOP KEYBINOP '-' '<' '>' '*' '+' '|' READWRITEVAR %left '.' %right '`' %right UMINUS %start root %{ #include #include #include "PyrLexer.h" #include "PyrParseNode.h" #include "SC_Constants.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "InitAlloc.h" #include "PredefinedSymbols.h" #include "SimpleStack.h" void bcopy(void *src, void *dst, size_t size) ; int yyparse(); extern bool compilingCmdLine; extern LongStack generatorStack; %} %error-verbose %% root : classes { gRootParseNode = (PyrParseNode*)$1; gParserResult = 1; } | classextensions { gRootParseNode = (PyrParseNode*)$1; gParserResult = 1; } | INTERPRET cmdlinecode { gRootParseNode = (PyrParseNode*)$2; gParserResult = 2; } ; classes : { $$ = 0; } | classes classdef { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; classextensions : classextension | classextensions classextension { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; classdef : classname superclass '{' classvardecls methods '}' { $$ = (long)newPyrClassNode((PyrSlotNode*)$1, (PyrSlotNode*)$2, (PyrVarListNode*)$4, (PyrMethodNode*)$5, 0); } | classname '[' optname ']' superclass '{' classvardecls methods '}' { $$ = (long)newPyrClassNode((PyrSlotNode*)$1, (PyrSlotNode*)$5, (PyrVarListNode*)$7, (PyrMethodNode*)$8, (PyrSlotNode*)$3); } ; classextension : '+' classname '{' methods '}' { $$ = (long)newPyrClassExtNode((PyrSlotNode*)$2, (PyrMethodNode*)$4); } ; optname : { $$ = 0; } | name ; superclass : { $$ = 0; } | ':' classname { $$ = $2; } ; classvardecls : { $$ = 0; } | classvardecls classvardecl { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; classvardecl : CLASSVAR rwslotdeflist ';' { $$ = (long)newPyrVarListNode((PyrVarDefNode*)$2, varClass); } | VAR rwslotdeflist ';' { $$ = (long)newPyrVarListNode((PyrVarDefNode*)$2, varInst); } | SC_CONST constdeflist ';' { $$ = (long)newPyrVarListNode((PyrVarDefNode*)$2, varConst); } ; methods : { $$ = 0; } | methods methoddef { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; methoddef : name '{' argdecls funcvardecls primitive methbody '}' { $$ = (long)newPyrMethodNode((PyrSlotNode*)$1, (PyrSlotNode*)$5, (PyrArgListNode*)$3, (PyrVarListNode*)$4, (PyrParseNode*)$6, 0); } | '*' name '{' argdecls funcvardecls primitive methbody '}' { $$ = (long)newPyrMethodNode((PyrSlotNode*)$2, (PyrSlotNode*)$6, (PyrArgListNode*)$4, (PyrVarListNode*)$5, (PyrParseNode*)$7, 1); } | binop '{' argdecls funcvardecls primitive methbody '}' { $$ = (long)newPyrMethodNode((PyrSlotNode*)$1, (PyrSlotNode*)$5, (PyrArgListNode*)$3, (PyrVarListNode*)$4, (PyrParseNode*)$6, 0); } | '*' binop '{' argdecls funcvardecls primitive methbody '}' { $$ = (long)newPyrMethodNode((PyrSlotNode*)$2, (PyrSlotNode*)$6, (PyrArgListNode*)$4, (PyrVarListNode*)$5, (PyrParseNode*)$7, 1); } ; optsemi : | ';' ; optcomma : | ',' ; optequal : | '=' ; funcbody : funretval | exprseq funretval { $$ = (long)newPyrDropNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; cmdlinecode : '(' funcvardecls1 funcbody ')' { $$ = (long)newPyrBlockNode(NULL, (PyrVarListNode*)$2, (PyrParseNode*)$3, false); } | funcvardecls1 funcbody { $$ = (long)newPyrBlockNode(NULL, (PyrVarListNode*)$1, (PyrParseNode*)$2, false); } | funcbody { $$ = (long)newPyrBlockNode(NULL, NULL, (PyrParseNode*)$1, false); } ; methbody : retval | exprseq retval { $$ = (long)newPyrDropNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; primitive : { $$ = 0; } | primname optsemi { $$ = $1; } ; retval : { $$ = (long)newPyrReturnNode(NULL); } | '^' expr optsemi { $$ = (long)newPyrReturnNode((PyrParseNode*)$2); } ; funretval : { $$ = (long)newPyrBlockReturnNode(); } | '^' expr optsemi { $$ = (long)newPyrReturnNode((PyrParseNode*)$2); } ; blocklist1 : blocklistitem | blocklist1 blocklistitem { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; blocklistitem : blockliteral | generator ; blocklist : { $$ = 0; } | blocklist1 ; msgsend : name blocklist1 { $$ = (long)newPyrCallNode((PyrSlotNode*)$1, (PyrParseNode*)$2, 0, 0); } | '(' binop2 ')' blocklist1 { $$ = (long)newPyrCallNode((PyrSlotNode*)$2, (PyrParseNode*)$4, 0, 0); } | name '(' ')' blocklist1 { $$ = (long)newPyrCallNode((PyrSlotNode*)$1, NULL, NULL, (PyrParseNode*)$4); } | name '(' arglist1 optkeyarglist ')' blocklist { $$ = (long)newPyrCallNode((PyrSlotNode*)$1, (PyrParseNode*)$3, (PyrParseNode*)$4, (PyrParseNode*)$6); } | '(' binop2 ')' '(' ')' blocklist1 { $$ = (long)newPyrCallNode((PyrSlotNode*)$2, NULL, NULL, (PyrParseNode*)$6); } | '(' binop2 ')' '(' arglist1 optkeyarglist ')' blocklist { $$ = (long)newPyrCallNode((PyrSlotNode*)$2, (PyrParseNode*)$5, (PyrParseNode*)$6, (PyrParseNode*)$8); } | name '(' arglistv1 optkeyarglist ')' { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)$3)) { SetRaw(&((PyrPushNameNode*)$3)->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } selectornode = newPyrSlotNode(&slot); args = linkAfterHead( (PyrParseNode*)$3, newPyrPushLitNode((PyrSlotNode*)$1, NULL)); $$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$4, 0); } | '(' binop2 ')' '(' arglistv1 optkeyarglist ')' { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_performList); selectornode = newPyrSlotNode(&slot); args = linkAfterHead( (PyrParseNode*)$5, newPyrPushLitNode((PyrSlotNode*)$2, NULL)); $$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$6, 0); } | classname '[' arrayelems ']' { $$ = (long)newPyrDynListNode((PyrParseNode*)$1, (PyrParseNode*)$3); } | classname blocklist1 { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1); $$ = (long)newPyrCallNode(selectornode, args, 0, (PyrParseNode*)$2); } | classname '(' ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1); $$ = (long)newPyrCallNode(selectornode, args, NULL, (PyrParseNode*)$4); } | classname '(' keyarglist1 optcomma ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1); $$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$3, (PyrParseNode*)$6); } | classname '(' arglist1 optkeyarglist ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1), (PyrParseNode*)$3); $$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$4, (PyrParseNode*)$6); } | classname '(' arglistv1 optkeyarglist ')' { PyrSlotNode *selectornode, *selectornode2; PyrSlot slot, slot2; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)$1)) { SetRaw(&((PyrPushNameNode*)$1)->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } SetSymbol(&slot2, s_new); selectornode = newPyrSlotNode(&slot); selectornode2 = newPyrSlotNode(&slot2); args = linkNextNode( (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1), newPyrPushLitNode(selectornode2, NULL)); args = linkNextNode(args, (PyrParseNode*)$3); $$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$5, 0); } | expr '.' '(' ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); $$ = (long)newPyrCallNode(selectornode, (PyrParseNode*)$1, NULL, (PyrParseNode*)$5); } | expr '.' '(' keyarglist1 optcomma ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); $$ = (long)newPyrCallNode(selectornode, (PyrParseNode*)$1, (PyrParseNode*)$4, (PyrParseNode*)$7); } | expr '.' name '(' keyarglist1 optcomma ')' blocklist { $$ = (long)newPyrCallNode((PyrSlotNode*)$3, (PyrParseNode*)$1, (PyrParseNode*)$5, (PyrParseNode*)$8); } | expr '.' '(' arglist1 optkeyarglist ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$4); $$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$5, (PyrParseNode*)$7); } | expr '.' '(' arglistv1 optkeyarglist ')' { PyrSlotNode *selectornode; PyrSlot slot, slot2; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)$1)) { SetRaw(&((PyrPushNameNode*)$1)->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } SetSymbol(&slot2, s_value); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, newPyrPushLitNode(newPyrSlotNode(&slot2), NULL)); args = linkNextNode(args, (PyrParseNode*)$4); $$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$5, 0); } | expr '.' name '(' ')' blocklist { $$ = (long)newPyrCallNode((PyrSlotNode*)$3, (PyrParseNode*)$1, NULL, (PyrParseNode*)$6); } | expr '.' name '(' arglist1 optkeyarglist ')' blocklist { PyrParseNode* args; args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$5); $$ = (long)newPyrCallNode((PyrSlotNode*)$3, args, (PyrParseNode*)$6, (PyrParseNode*)$8); } | expr '.' name '(' arglistv1 optkeyarglist ')' { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)$1)) { SetRaw(&((PyrPushNameNode*)$1)->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } selectornode = newPyrSlotNode(&slot); args = linkNextNode((PyrParseNode*)$1, newPyrPushLitNode((PyrSlotNode*)$3, NULL)); args = linkNextNode(args, (PyrParseNode*)$5); $$ = (long)newPyrCallNode(selectornode, args, (PyrParseNode*)$6, 0); } | expr '.' name blocklist { $$ = (long)newPyrCallNode((PyrSlotNode*)$3, (PyrParseNode*)$1, 0, (PyrParseNode*)$4); } ; generator : '{' ':' exprseq { pushls(&generatorStack, $3); pushls(&generatorStack, 1); } ',' qual '}' { PyrSlot slot; SetSymbol(&slot, getsym("r")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)$6, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); $$ = (long)newPyrCallNode(selectornode, (PyrParseNode*)blocklit, 0, 0); } | '{' ';' exprseq { pushls(&generatorStack, $3); pushls(&generatorStack, 2); } ',' qual '}' { $$ = $6; } ; nextqual : { // innermost part int action = popls(&generatorStack); PyrParseNode* expr = (PyrParseNode*)popls(&generatorStack); switch (action) { case 1 : { PyrSlot slot; SetSymbol(&slot, getsym("yield")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); $$ = (long)newPyrCallNode(selectornode, expr, 0, 0); } break; case 2 : { $$ = (long)expr; } break; } } | ',' qual { $$ = $2; } ; qual : name LEFTARROW exprseq nextqual { // later should check if exprseq is a series and optimize it to for loop PyrParseNode *exprseq = (PyrParseNode*)$3; if (exprseq->mClassno == pn_CallNode) { PyrCallNode *callnode = (PyrCallNode*)exprseq; if (slotRawSymbol(&callnode->mSelector->mSlot) == s_series) { SetSymbol(&callnode->mSelector->mSlot, getsym("forSeries")); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$4, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); callnode->mArglist = linkNextNode(callnode->mArglist, blocklit); $$ = (long)callnode; } else goto notoptimized1; } else { notoptimized1: PyrSlot slot; SetSymbol(&slot, getsym("do")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$4, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = linkNextNode(exprseq, blocklit); $$ = (long)newPyrCallNode(selectornode, args2, 0, 0); } } | name name LEFTARROW exprseq nextqual { // later should check if exprseq is a series and optimize it to for loop PyrParseNode *exprseq = (PyrParseNode*)$4; if (exprseq->mClassno == pn_CallNode) { PyrCallNode *callnode = (PyrCallNode*)exprseq; if (slotRawSymbol(&callnode->mSelector->mSlot) == s_series) { SetSymbol(&callnode->mSelector->mSlot, getsym("forSeries")); PyrVarDefNode* var1 = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); PyrVarDefNode* var2 = newPyrVarDefNode((PyrSlotNode*)$2, NULL, 0); PyrVarDefNode* vars = (PyrVarDefNode*)linkNextNode(var1, var2); PyrArgListNode* args = newPyrArgListNode(vars, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$5, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); callnode->mArglist = linkNextNode(callnode->mArglist, blocklit); $$ = (long)callnode; } else goto notoptimized2; } else { notoptimized2: PyrSlot slot; SetSymbol(&slot, getsym("do")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var1 = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); PyrVarDefNode* var2 = newPyrVarDefNode((PyrSlotNode*)$2, NULL, 0); PyrVarDefNode* vars = (PyrVarDefNode*)linkNextNode(var1, var2); PyrArgListNode* args = newPyrArgListNode(vars, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$5, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = linkNextNode(exprseq, blocklit); $$ = (long)newPyrCallNode(selectornode, args2, 0, 0); } } | VAR name '=' exprseq nextqual { PyrSlot slot; SetSymbol(&slot, s_value); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)$2, NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$5, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = (PyrParseNode*)linkNextNode(blocklit, (PyrParseNode*)$4); $$ = (long)newPyrCallNode(selectornode, args2, 0, 0); } | exprseq nextqual { PyrSlot slot; SetSymbol(&slot, getsym("if")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)$2, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = (PyrParseNode*)linkNextNode((PyrParseNode*)$1, blocklit); $$ = (long)newPyrCallNode(selectornode, args2, 0, 0); } | ':' ':' exprseq nextqual { $$ = (long)newPyrDropNode((PyrParseNode*)$3, (PyrParseNode*)$4); } | ':' WHILE exprseq nextqual { PyrSlot slot; SetSymbol(&slot, getsym("alwaysYield")); PyrSlotNode* selectornode1 = newPyrSlotNode(&slot); SetSymbol(&slot, getsym("if")); PyrSlotNode* selectornode2 = newPyrSlotNode(&slot); SetNil(&slot); PyrParseNode *pushnil = (PyrParseNode*)newPyrPushLitNode(newPyrSlotNode(&slot), NULL); PyrParseNode *yieldNil = (PyrParseNode*)newPyrCallNode(selectornode1, pushnil, 0, 0); PyrParseNode *block1 = (PyrParseNode*)newPyrBlockNode(0, 0, yieldNil, false); PyrParseNode *blocklit1 = (PyrParseNode*)newPyrPushLitNode(NULL, block1); PyrParseNode *block2 = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)$4, false); PyrParseNode *blocklit2 = (PyrParseNode*)newPyrPushLitNode(NULL, block2); PyrParseNode* args2 = (PyrParseNode*)linkNextNode((PyrParseNode*)$3, blocklit2); PyrParseNode* args3 = (PyrParseNode*)linkNextNode(args2, blocklit1); $$ = (long)newPyrCallNode(selectornode2, args3, 0, 0); } ; expr1 : pushliteral | blockliteral | generator | pushname | curryarg | msgsend | '(' exprseq ')' { PyrParseNode* node = (PyrParseNode*)$2; node->mParens = 1; $$ = $2; } | '~' name { PyrParseNode* argnode; PyrSlotNode* selectornode; PyrSlot slot; argnode = (PyrParseNode*)newPyrPushLitNode((PyrSlotNode*)$2, NULL); SetSymbol(&slot, s_envirGet); selectornode = newPyrSlotNode(&slot); $$ = (long)newPyrCallNode(selectornode, argnode, 0, 0); } | '[' arrayelems ']' { $$ = (long)newPyrDynListNode(0, (PyrParseNode*)$2); } | '(' valrange2 ')' { $$ = $2; } | '(' ':' valrange3 ')' { $$ = $3; } | '(' dictslotlist ')' { $$ = (long)newPyrDynDictNode((PyrParseNode*)$2); } | pseudovar { $$ = (long)newPyrPushNameNode((PyrSlotNode*)$1); } | expr1 '[' arglist1 ']' { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_at); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$3); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | valrangex1 ; valrangex1 : expr1 '[' arglist1 DOTDOT ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$3); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr1 '[' DOTDOT exprseq ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$4); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr1 '[' arglist1 DOTDOT exprseq ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$3); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)$5); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } ; valrangeassign : expr1 '[' arglist1 DOTDOT ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$3); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$7); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr1 '[' DOTDOT exprseq ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$4); args = linkNextNode(args, (PyrParseNode*)$7); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr1 '[' arglist1 DOTDOT exprseq ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$3); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)$5); args = linkNextNode(args, (PyrParseNode*)$8); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } ; valrangexd : expr '.' '[' arglist1 DOTDOT ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$4); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' DOTDOT exprseq ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$5); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' arglist1 DOTDOT exprseq ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$4); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)$6); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' arglist1 DOTDOT ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$4); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$8); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' DOTDOT exprseq ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$5); args = linkNextNode(args, (PyrParseNode*)$8); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' arglist1 DOTDOT exprseq ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$4); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)$6); args = linkNextNode(args, (PyrParseNode*)$9); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } ; valrange2 : exprseq DOTDOT { // if this is not used in a 'do' or list comprehension, then should return an error. PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode); args = linkNextNode(args, nilnode2); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | DOTDOT exprseq { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *zeronode; PyrSlot selectorSlot, nilSlot, zeroSlot; PyrParseNode* args; SetInt(&zeroSlot, 0); SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); zeronode = newPyrPushLitNode(newPyrSlotNode(&zeroSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode(zeronode, nilnode); args = linkNextNode(args, (PyrParseNode*)$2); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | exprseq DOTDOT exprseq { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode); args = linkNextNode(args, (PyrParseNode*)$3); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | exprseq ',' exprseq DOTDOT exprseq { PyrSlotNode *selectornode; PyrSlot selectorSlot; PyrParseNode* args; SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$3); args = linkNextNode(args, (PyrParseNode*)$5); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | exprseq ',' exprseq DOTDOT { // if this is not used in a 'do' or list comprehension, then should return an error. PyrSlotNode *selectornode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; PyrPushLitNode *nilnode; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$3); args = linkNextNode(args, nilnode); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } ; valrange3 : DOTDOT exprseq { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *zeronode; PyrSlot selectorSlot, nilSlot, zeroSlot; PyrParseNode* args; SetInt(&zeroSlot, 0); SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); zeronode = newPyrPushLitNode(newPyrSlotNode(&zeroSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode(zeronode, nilnode); args = linkNextNode(args, (PyrParseNode*)$2); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | exprseq DOTDOT { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode); args = linkNextNode(args, nilnode2); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | exprseq DOTDOT exprseq { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode); args = linkNextNode(args, (PyrParseNode*)$3); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | exprseq ',' exprseq DOTDOT { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); args = linkNextNode(args, nilnode); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | exprseq ',' exprseq DOTDOT exprseq { PyrSlotNode *selectornode; PyrSlot selectorSlot; PyrParseNode* args; SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$3); args = linkNextNode(args, (PyrParseNode*)$5); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } ; expr : expr1 | valrangexd | valrangeassign | classname { $$ = (long)newPyrPushNameNode((PyrSlotNode*)$1); } | expr '.' '[' arglist1 ']' { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_at); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$4); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | '`' expr { PyrParseNode *node, *args; PyrSlotNode *slotnode; PyrSlot slot; SetSymbol(&slot, s_ref); slotnode = newPyrSlotNode(&slot); node = (PyrParseNode*)newPyrPushNameNode(slotnode); args = linkNextNode(node, (PyrParseNode*)$2); SetSymbol(&slot, s_new); slotnode = newPyrSlotNode(&slot); $$ = (long)newPyrCallNode(slotnode, args, 0, 0); } | expr binop2 adverb expr %prec BINOP { $$ = (long)newPyrBinopCallNode((PyrSlotNode*)$2, (PyrParseNode*)$1, (PyrParseNode*)$4, (PyrParseNode*)$3); } | name '=' expr { $$ = (long)newPyrAssignNode((PyrSlotNode*)$1, (PyrParseNode*)$3, 0); } | '~' name '=' expr { PyrParseNode *argnode, *args; PyrSlotNode* selectornode; PyrSlot slot; argnode = (PyrParseNode*)newPyrPushLitNode((PyrSlotNode*)$2, NULL); args = linkNextNode(argnode, (PyrParseNode*)$4); SetSymbol(&slot, s_envirPut); selectornode = newPyrSlotNode(&slot); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' name '=' expr { $$ = (long)newPyrSetterNode((PyrSlotNode*)$3, (PyrParseNode*)$1, (PyrParseNode*)$5); } | name '(' arglist1 optkeyarglist ')' '=' expr { if ($4 != 0) { error("Setter method called with keyword arguments.\n"); nodePostErrorLine((PyrParseNode*)$4); compileErrors++; } $$ = (long)newPyrSetterNode((PyrSlotNode*)$1, (PyrParseNode*)$3, (PyrParseNode*)$7); } | '#' mavars '=' expr { $$ = (long)newPyrMultiAssignNode((PyrMultiAssignVarListNode*)$2, (PyrParseNode*)$4, 0); } | expr1 '[' arglist1 ']' '=' expr { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_put); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$3); args = linkNextNode( args, (PyrParseNode*)$6); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' arglist1 ']' '=' expr { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_put); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$4); args = linkNextNode( args, (PyrParseNode*)$7); $$ = (long)newPyrCallNode(selectornode, args, 0, 0); } ; adverb : { $$ = 0; } | '.' name { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$2, NULL); } | '.' integer { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$2, NULL); } | '.' '(' exprseq ')' { $$ = $3; } ; exprn : expr | exprn ';' expr { $$ = (long)newPyrDropNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; exprseq : exprn optsemi ; arrayelems : { $$ = 0; } | arrayelems1 optcomma { $$ = $1; } ; arrayelems1 : exprseq | exprseq ':' exprseq { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } | keybinop exprseq { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$1, NULL); $$ = (long)linkNextNode(key, (PyrParseNode*)$2); } | arrayelems1 ',' exprseq { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } | arrayelems1 ',' keybinop exprseq { PyrParseNode* elems; PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$3, NULL); elems = (PyrParseNode*)linkNextNode(key, (PyrParseNode*)$4); $$ = (long)linkNextNode((PyrParseNode*)$1, elems); } | arrayelems1 ',' exprseq ':' exprseq { PyrParseNode* elems; elems = (PyrParseNode*)linkNextNode((PyrParseNode*)$3, (PyrParseNode*)$5); $$ = (long)linkNextNode((PyrParseNode*)$1, elems); } ; arglist1 : exprseq | arglist1 ',' exprseq { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; arglistv1 : '*' exprseq { $$ = $2; } | arglist1 ',' '*' exprseq { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); } ; keyarglist1 : keyarg | keyarglist1 ',' keyarg { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; keyarg : keybinop exprseq { $$ = (long)newPyrPushKeyArgNode((PyrSlotNode*)$1, (PyrParseNode*)$2); } ; optkeyarglist : optcomma { $$ = 0; } | ',' keyarglist1 optcomma { $$ = $2; } ; mavars : mavarlist { $$ = (long)newPyrMultiAssignVarListNode((PyrSlotNode*)$1, NULL); } | mavarlist ELLIPSIS name { $$ = (long)newPyrMultiAssignVarListNode((PyrSlotNode*)$1, (PyrSlotNode*)$3); } ; mavarlist : name | mavarlist ',' name { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; slotliteral : integer { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | floatp { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | ascii { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | string { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | symbol { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | trueobj { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | falseobj { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | nilobj { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | listlit { $$ = (long)newPyrLiteralNode(NULL, (PyrParseNode*)$1); } ; blockliteral : block { $$ = (long)newPyrPushLitNode(NULL, (PyrParseNode*)$1); } ; pushname : name { $$ = (long)newPyrPushNameNode((PyrSlotNode*)$1); } ; pushliteral : integer { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | floatp { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | ascii { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | string { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | symbol { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | trueobj { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | falseobj { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | nilobj { $$ = (long)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | listlit { $$ = (long)newPyrPushLitNode(NULL, (PyrParseNode*)$1); } ; listliteral : integer { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | floatp { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | ascii { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | string { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | symbol { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | name { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | trueobj { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | falseobj { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | nilobj { $$ = (long)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | listlit2 { $$ = (long)newPyrLiteralNode(NULL, (PyrParseNode*)$1); } | dictlit2 { $$ = (long)newPyrLiteralNode(NULL, (PyrParseNode*)$1); } ; block : '{' argdecls funcvardecls funcbody '}' { $$ = (long)newPyrBlockNode((PyrArgListNode*)$2, (PyrVarListNode*)$3, (PyrParseNode*)$4, false); } | BEGINCLOSEDFUNC argdecls funcvardecls funcbody '}' { $$ = (long)newPyrBlockNode((PyrArgListNode*)$2, (PyrVarListNode*)$3, (PyrParseNode*)$4, true); } ; funcvardecls : { $$ = 0; } | funcvardecls funcvardecl { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; funcvardecls1 : funcvardecl | funcvardecls1 funcvardecl { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; funcvardecl : VAR vardeflist ';' { $$ = (long)newPyrVarListNode((PyrVarDefNode*)$2, varLocal); } ; argdecls : { $$ = 0; } | ARG vardeflist ';' { $$ = (long)newPyrArgListNode((PyrVarDefNode*)$2, NULL); } | ARG vardeflist0 ELLIPSIS name ';' { $$ = (long)newPyrArgListNode((PyrVarDefNode*)$2, (PyrSlotNode*)$4); } | '|' slotdeflist '|' { $$ = (long)newPyrArgListNode((PyrVarDefNode*)$2, NULL); } | '|' slotdeflist0 ELLIPSIS name '|' { $$ = (long)newPyrArgListNode((PyrVarDefNode*)$2, (PyrSlotNode*)$4); } ; constdeflist : constdef | constdeflist optcomma constdef { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; constdef : rspec name '=' slotliteral { $$ = (long)newPyrVarDefNode((PyrSlotNode*)$2, (PyrParseNode*)$4, $1); } ; slotdeflist0 : { $$ = 0; } | slotdeflist ; slotdeflist : slotdef | slotdeflist optcomma slotdef { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; slotdef : name { $$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); } | name optequal slotliteral { $$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, (PyrParseNode*)$3, 0); } | name optequal '(' exprseq ')' { PyrParseNode* node = (PyrParseNode*)$4; node->mParens = 1; $$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, node, 0); } ; vardeflist0 : { $$ = 0; } | vardeflist ; vardeflist : vardef | vardeflist ',' vardef { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; vardef : name { $$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); } | name '=' expr { $$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, (PyrParseNode*)$3, 0); } | name '(' exprseq ')' { PyrParseNode* node = (PyrParseNode*)$3; node->mParens = 1; $$ = (long)newPyrVarDefNode((PyrSlotNode*)$1, node, 0); } ; dictslotdef : exprseq ':' exprseq { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } | keybinop exprseq { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$1, NULL); $$ = (long)linkNextNode(key, (PyrParseNode*)$2); } ; dictslotlist1 : dictslotdef | dictslotlist1 ',' dictslotdef { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; dictslotlist : { $$ = 0; } | dictslotlist1 optcomma ; rwslotdeflist : rwslotdef | rwslotdeflist ',' rwslotdef { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; rwslotdef : rwspec name { $$ = (long)newPyrVarDefNode((PyrSlotNode*)$2, NULL, $1); } | rwspec name '=' slotliteral { $$ = (long)newPyrVarDefNode((PyrSlotNode*)$2, (PyrParseNode*)$4, $1); } ; dictlit2 : '(' litdictslotlist ')' { $$ = (long)newPyrLitDictNode((PyrParseNode*)$2); } ; litdictslotdef : listliteral ':' listliteral { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } | keybinop listliteral { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$1, NULL); $$ = (long)linkNextNode(key, (PyrParseNode*)$2); } ; litdictslotlist1 : litdictslotdef | litdictslotlist1 ',' litdictslotdef { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; litdictslotlist : { $$ = 0; } | litdictslotlist1 optcomma ; listlit : '#' '[' literallistc ']' { $$ = (long)newPyrLitListNode(0, (PyrParseNode*)$3); } | '#' classname '[' literallistc ']' { $$ = (long)newPyrLitListNode((PyrParseNode*)$2, (PyrParseNode*)$4); } ; listlit2 : '[' literallistc ']' { $$ = (long)newPyrLitListNode(0, (PyrParseNode*)$2); } | classname '[' literallistc ']' { $$ = (long)newPyrLitListNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; literallistc : { $$ = 0; } | literallist1 optcomma ; literallist1 : listliteral | literallist1 ',' listliteral { $$ = (long)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; rwspec : { $$ = rwPrivate; } | '<' { $$ = rwReadOnly; } | READWRITEVAR { $$ = rwReadWrite; } | '>' { $$ = rwWriteOnly; } ; rspec : { $$ = rwPrivate; } | '<' { $$ = rwReadOnly; } ; integer : INTEGER { $$ = zzval; } | '-'INTEGER %prec UMINUS { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetRaw(&node->mSlot, -slotRawInt(&node->mSlot)); $$ = zzval; } ; floatr : SC_FLOAT { $$ = zzval; } | '-' SC_FLOAT %prec UMINUS { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetRaw(&node->mSlot, -slotRawFloat(&node->mSlot)); $$ = zzval; } ; accidental : ACCIDENTAL { $$ = zzval; } | '-' ACCIDENTAL %prec UMINUS { PyrSlotNode *node; double intval, fracval; node = (PyrSlotNode*)zzval; intval = floor(slotRawFloat(&node->mSlot) + 0.5); fracval = slotRawFloat(&node->mSlot) - intval; SetRaw(&node->mSlot, -intval + fracval); $$ = zzval; } pie : PIE { $$ = zzval; } ; floatp : floatr | accidental | floatr pie { PyrSlotNode *node; node = (PyrSlotNode*)$1; SetRaw(&node->mSlot, slotRawFloat(&node->mSlot) * pi); } | integer pie { PyrSlotNode *node; double ival; node = (PyrSlotNode*)$1; ival = slotRawInt(&node->mSlot); SetFloat(&node->mSlot, ival * pi); } | pie { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetFloat(&node->mSlot, pi); $$ = zzval; } | '-' pie { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetFloat(&node->mSlot, -pi); $$ = zzval; } ; name : NAME { $$ = zzval; } | WHILE { $$ = zzval; } ; classname : CLASSNAME { $$ = zzval; } ; primname : PRIMITIVENAME { $$ = zzval; } ; trueobj : TRUEOBJ { $$ = zzval; } ; falseobj : FALSEOBJ { $$ = zzval; } ; nilobj : NILOBJ { $$ = zzval; } ; ascii : ASCII { $$ = zzval; } ; symbol : SYMBOL { $$ = zzval; } ; string : STRING { $$ = zzval; } ; pseudovar : PSEUDOVAR { $$ = zzval; } ; binop : BINOP { $$ = zzval; } | READWRITEVAR { $$ = zzval; } | '<' { $$ = zzval; } | '>' { $$ = zzval; } | '-' { $$ = zzval; } | '*' { $$ = zzval; } | '+' { $$ = zzval; } | '|' { $$ = zzval; } ; keybinop : KEYBINOP { $$ = zzval; } ; binop2 : binop | keybinop ; curryarg : CURRYARG { $$ = zzval; } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/Bison/make_parser.sh0000775000000000000000000000005412014636264025651 0ustar rootroot#!/bin/sh bison -o lang11d_tab.cpp lang11d SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/Bison/lang11d_tab.h0000664000000000000000000000130312014636264025245 0ustar rootroot#ifndef YYSTYPE #define YYSTYPE int #endif #define NAME 258 #define INTEGER 259 #define SC_FLOAT 260 #define ACCIDENTAL 261 #define SYMBOL 262 #define STRING 263 #define ASCII 264 #define PRIMITIVENAME 265 #define CLASSNAME 266 #define CURRYARG 267 #define VAR 268 #define ARG 269 #define CLASSVAR 270 #define SC_CONST 271 #define NILOBJ 272 #define TRUEOBJ 273 #define FALSEOBJ 274 #define PSEUDOVAR 275 #define ELLIPSIS 276 #define DOTDOT 277 #define PIE 278 #define BEGINCLOSEDFUNC 279 #define BADTOKEN 280 #define INTERPRET 281 #define BEGINGENERATOR 282 #define LEFTARROW 283 #define WHILE 284 #define READWRITEVAR 285 #define KEYBINOP 286 #define BINOP 287 #define UMINUS 288 extern YYSTYPE yylval; SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/PyrMessage.cpp0000664000000000000000000012157312161364457024551 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrMessage.h" #include "PyrPrimitiveProto.h" #include "PyrInterpreter.h" #include "PyrPrimitive.h" #include "PyrListPrim.h" #include "PyrSymbol.h" #include "GC.h" #include #include #include "PredefinedSymbols.h" #include "PyrObjectProto.h" #include "SCBase.h" #define DEBUGMETHODS 0 #define METHODMETER 0 PyrMethod **gRowTable; PyrSlot keywordstack[MAXKEYSLOTS]; bool gKeywordError = true; extern bool gTraceInterpreter; long cvxUniqueMethods; extern int ivxIdentDict_array; void StoreToImmutableB(VMGlobals *g, PyrSlot *& sp, unsigned char *& ip); void initUniqueMethods() { PyrClass *dummyclass; cvxUniqueMethods = classVarOffset("Object", "uniqueMethods", &dummyclass); } HOT void sendMessageWithKeys(VMGlobals *g, PyrSymbol *selector, long numArgsPushed, long numKeyArgsPushed) { PyrMethod *meth = NULL; PyrMethodRaw *methraw; PyrSlot *recvrSlot, *sp; PyrClass *classobj; long index; PyrObject *obj; //postfl("->sendMessage\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessageWithKeys"); #endif recvrSlot = g->sp - numArgsPushed + 1; classobj = classOfSlot(recvrSlot); lookup_again: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); } else { methraw = METHRAW(meth); //postfl("methraw->methType %d\n", methraw->methType); switch (methraw->methType) { case methNormal : /* normal msg send */ executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); break; case methReturnSelf : /* return self */ g->sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; g->sp -= numArgsPushed - 1; sp = g->sp; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(recvrSlot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { SetNil(&obj->slots[index]); } slotCopy(sp, recvrSlot); } break; case methReturnClassVar : /* return class var */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp = g->sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else { SetNil(&g->classvars->slots[methraw->specialIndex]); } slotCopy(sp, recvrSlot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); goto lookup_again; case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto lookup_again; case methForwardInstVar : /* forward to an instance variable */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methForwardClassVar : /* forward to a class variable */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methPrimitive : /* primitive */ doPrimitiveWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif break; } } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessage\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessage"); #endif recvrSlot = g->sp - numArgsPushed + 1; classobj = classOfSlot(recvrSlot); lookup_again: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { doesNotUnderstand(g, selector, numArgsPushed); } else { methraw = METHRAW(meth); //postfl("methraw->methType %d\n", methraw->methType); switch (methraw->methType) { case methNormal : /* normal msg send */ executeMethod(g, meth, numArgsPushed); break; case methReturnSelf : /* return self */ g->sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(recvrSlot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { SetNil(&obj->slots[index]); } slotCopy(sp, recvrSlot); } break; case methReturnClassVar : /* return class var */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp = g->sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else { SetNil(&g->classvars->slots[methraw->specialIndex]); } slotCopy(sp, recvrSlot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); goto lookup_again; case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto lookup_again; case methForwardInstVar : /* forward to an instance variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methForwardClassVar : /* forward to a class variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methPrimitive : /* primitive */ doPrimitive(g, meth, numArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif break; /* case methMultDispatchByClass : { index = methraw->specialIndex; if (index < numArgsPushed) { classobj = slotRawObject(sp + index)->classptr; selector = slotRawSymbol(&meth->selectors); goto lookup_again; } else { doesNotUnderstand(g, selector, numArgsPushed); } } break; case methMultDispatchByValue : { index = methraw->specialIndex; if (index < numArgsPushed) { index = arrayAtIdentityHashInPairs(array, b); meth = slotRawObject(&meth->selectors)->slots[index + 1].uom; goto meth_select_again; } else { doesNotUnderstand(g, selector, numArgsPushed); } } break; */ } } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessage\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendSuperMessageWithKeys"); #endif recvrSlot = g->sp - numArgsPushed + 1; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; //assert(isKindOfSlot(recvrSlot, classobj)); lookup_again: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); } else { methraw = METHRAW(meth); //postfl("methraw->methType %d\n", methraw->methType); switch (methraw->methType) { case methNormal : /* normal msg send */ executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); break; case methReturnSelf : /* return self */ g->sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; g->sp -= numArgsPushed - 1; sp = g->sp; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(recvrSlot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { SetNil(&obj->slots[index]); } slotCopy(sp, recvrSlot); } break; case methReturnClassVar : /* return class var */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp = g->sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else { SetNil(&g->classvars->slots[methraw->specialIndex]); } slotCopy(sp, recvrSlot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); goto lookup_again; case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto lookup_again; case methForwardInstVar : /* forward to an instance variable */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methForwardClassVar : /* forward to a class variable */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methPrimitive : /* primitive */ doPrimitiveWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif break; } } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessage\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendSuperMessage"); #endif recvrSlot = g->sp - numArgsPushed + 1; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; //assert(isKindOfSlot(recvrSlot, classobj)); lookup_again: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { doesNotUnderstand(g, selector, numArgsPushed); } else { methraw = METHRAW(meth); //postfl("methraw->methType %d\n", methraw->methType); switch (methraw->methType) { case methNormal : /* normal msg send */ executeMethod(g, meth, numArgsPushed); break; case methReturnSelf : /* return self */ g->sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(recvrSlot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { SetNil(&obj->slots[index]); } slotCopy(sp, recvrSlot); } break; case methReturnClassVar : /* return class var */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp = g->sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else { SetNil(&g->classvars->slots[methraw->specialIndex]); } slotCopy(sp, recvrSlot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); goto lookup_again; case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto lookup_again; case methForwardInstVar : /* forward to an instance variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methForwardClassVar : /* forward to a class variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methPrimitive : /* primitive */ doPrimitive(g, meth, numArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif break; /* case methMultDispatchByClass : { index = methraw->specialIndex; if (index < numArgsPushed) { classobj = slotRawObject(sp + index)->classptr; selector = slotRawSymbol(&meth->selectors); goto lookup_again; } else { doesNotUnderstand(g, selector, numArgsPushed); } } break; case methMultDispatchByValue : { index = methraw->specialIndex; if (index < numArgsPushed) { index = arrayAtIdentityHashInPairs(array, b); meth = slotRawObject(&meth->selectors)->slots[index + 1].uom; goto meth_select_again; } else { doesNotUnderstand(g, selector, numArgsPushed); } } break; */ } } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "gc->SanityCheck(); #endif // move args up by one to make room for selector qslot = g->sp + 1; pslot = g->sp + 2; pend = pslot - numArgsPushed + 1; while (pslot > pend) *--pslot = *--qslot; selSlot = g->sp - numArgsPushed + 2; SetSymbol(selSlot, selector); g->sp++; recvrSlot = selSlot - 1; classobj = classOfSlot(recvrSlot); index = slotRawInt(&classobj->classIndex) + s_nocomprendo->u.index; meth = gRowTable[index]; if (slotRawClass(&meth->ownerclass) == class_object) { // lookup instance specific method uniqueMethodSlot = &g->classvars->slots[cvxUniqueMethods]; if (isKindOfSlot(uniqueMethodSlot, class_identdict)) { arraySlot = slotRawObject(uniqueMethodSlot)->slots + ivxIdentDict_array; if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) { i = arrayAtIdentityHashInPairs(array, recvrSlot); if (i >= 0) { slot = array->slots + i; if (NotNil(slot)) { ++slot; if (isKindOfSlot(slot, class_identdict)) { arraySlot = slotRawObject(slot)->slots + ivxIdentDict_array; if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) { i = arrayAtIdentityHashInPairs(array, selSlot); if (i >= 0) { slot = array->slots + i; if (NotNil(slot)) { ++slot; slotCopy(selSlot, recvrSlot); slotCopy(recvrSlot, slot); blockValueWithKeys(g, numArgsPushed+1, numKeyArgsPushed); return; } } } } } } } } } executeMethodWithKeys(g, meth, numArgsPushed+1, numKeyArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } int blockValue(struct VMGlobals *g, int numArgsPushed); void doesNotUnderstand(VMGlobals *g, PyrSymbol *selector, long numArgsPushed) { PyrSlot *qslot, *pslot, *pend; long i, index; PyrSlot *uniqueMethodSlot, *arraySlot, *recvrSlot, *selSlot, *slot; PyrClass *classobj; PyrMethod *meth; PyrObject *array; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif // move args up by one to make room for selector qslot = g->sp + 1; pslot = g->sp + 2; pend = pslot - numArgsPushed + 1; while (pslot > pend) *--pslot = *--qslot; selSlot = g->sp - numArgsPushed + 2; SetSymbol(selSlot, selector); g->sp++; recvrSlot = selSlot - 1; classobj = classOfSlot(recvrSlot); index = slotRawInt(&classobj->classIndex) + s_nocomprendo->u.index; meth = gRowTable[index]; if (slotRawClass(&meth->ownerclass) == class_object) { // lookup instance specific method uniqueMethodSlot = &g->classvars->slots[cvxUniqueMethods]; if (isKindOfSlot(uniqueMethodSlot, class_identdict)) { arraySlot = slotRawObject(uniqueMethodSlot)->slots + ivxIdentDict_array; if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) { i = arrayAtIdentityHashInPairs(array, recvrSlot); if (i >= 0) { slot = array->slots + i; if (NotNil(slot)) { ++slot; if (isKindOfSlot(slot, class_identdict)) { arraySlot = slotRawObject(slot)->slots + ivxIdentDict_array; if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) { i = arrayAtIdentityHashInPairs(array, selSlot); if (i >= 0) { slot = array->slots + i; if (NotNil(slot)) { ++slot; slotCopy(selSlot, recvrSlot); slotCopy(recvrSlot, slot); blockValue(g, numArgsPushed+1); return; } } } } } } } } } executeMethod(g, meth, numArgsPushed+1); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } HOT void executeMethodWithKeys(VMGlobals *g, PyrMethod *meth, long allArgsPushed, long numKeyArgsPushed) { PyrMethodRaw *methraw; PyrFrame *frame; PyrFrame *caller; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrSlot *vars; PyrObject *proto; long i, j, m, mmax, numtemps, numargs, numArgsPushed; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "executeMethodWithKeys"); #endif #if DEBUGMETHODS if (gTraceInterpreter) { if (g->method) { postfl(" %s:%s -> %s:%s\n", slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } else { postfl(" top -> %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } } #endif #if METHODMETER if (gTraceInterpreter) { slotRawInt(&meth->callMeter)++; } #endif #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 10; proto = slotRawObject(&meth->prototypeFrame); methraw = METHRAW(meth); numtemps = methraw->numtemps; numargs = methraw->numargs; caller = g->frame; numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1); //DumpStack(g, g->sp); //postfl("executeMethod allArgsPushed %d numKeyArgsPushed %d\n", allArgsPushed, numKeyArgsPushed); frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + proto->size; SetObject(&frame->method, meth); SetObject(&frame->homeContext, frame); SetObject(&frame->context, frame); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, caller); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->method = meth; g->ip = slotRawInt8Array(&meth->code)->b - 1; g->frame = frame; g->block = (PyrBlock*)meth; g->sp -= allArgsPushed; qslot = g->sp; pslot = vars; if (numArgsPushed <= numargs) { /* not enough args pushed */ /* push all args to frame */ for (m=0,mmax=numArgsPushed; mslots + numArgsPushed - 1; for (m=0, mmax=numtemps - numArgsPushed; mvarargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ for (m=0,mmax=numargs; mgc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + numargs + 1, list); /* put extra args into list */ lslot = (list->slots - 1); // fixed and raw sizes are zero for (m=0,mmax=i; mnumvars) { /* push default keyword and var values */ pslot = vars + numargs + 1; qslot = proto->slots + numargs; for (m=0,mmax=methraw->numvars; mnumvars) { /* push default keyword and var values */ pslot = vars + numargs; qslot = proto->slots + numargs - 1; for (m=0,mmax=methraw->numvars; mposargs) { PyrSymbol **name0, **name; PyrSlot *key; name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1; key = g->sp + numArgsPushed + 1; for (i=0; iposargs; ++j, ++name) { if (*name == slotRawSymbol(key)) { slotCopy(&vars[j+1], &key[1]); goto found1; } } if (gKeywordError) { post("WARNING: keyword arg '%s' not found in call to %s:%s\n", slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } found1: ; } } slotCopy(&g->receiver, &vars[1]); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "gc->SanityCheck(); CallStackSanity(g, "executeMethod"); #endif #if DEBUGMETHODS if (gTraceInterpreter) { if (g->method) { postfl(" %s:%s -> %s:%s\n", slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } else { postfl(" top -> %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } } #endif #if METHODMETER if (gTraceInterpreter) { slotRawInt(&meth->callMeter)++; } #endif #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 20; proto = slotRawObject(&meth->prototypeFrame); methraw = METHRAW(meth); numtemps = methraw->numtemps; numargs = methraw->numargs; caller = g->frame; //postfl("executeMethod allArgsPushed %d numKeyArgsPushed %d\n", allArgsPushed, numKeyArgsPushed); frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + proto->size; SetObject(&frame->method, meth); SetObject(&frame->homeContext, frame); SetObject(&frame->context, frame); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, caller); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->method = meth; g->ip = slotRawInt8Array(&meth->code)->b - 1; g->frame = frame; g->block = (PyrBlock*)meth; g->sp -= numArgsPushed; qslot = g->sp; pslot = vars; if (numArgsPushed <= numargs) { /* not enough args pushed */ /* push all args to frame */ for (m=0,mmax=numArgsPushed; mslots + numArgsPushed - 1; for (m=0, mmax=numtemps - numArgsPushed; mvarargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ for (m=0,mmax=numargs; mgc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + numargs + 1, list); /* put extra args into list */ lslot = (list->slots - 1); // fixed and raw sizes are zero for (m=0,mmax=i; mnumvars) { /* push default keyword and var values */ pslot = vars + numargs + 1; qslot = proto->slots + numargs; for (m=0,mmax=methraw->numvars; mnumvars) { /* push default keyword and var values */ pslot = vars + numargs; qslot = proto->slots + numargs - 1; for (m=0,mmax=methraw->numvars; mreceiver, &vars[1]); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "returnFromBlock\n"); //printf("->returnFromBlock\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "returnFromBlock"); #endif curframe = g->frame; //again: returnFrame = slotRawFrame(&curframe->caller); if (returnFrame) { block = slotRawBlock(&curframe->method); blockraw = METHRAW(block); g->frame = returnFrame; g->ip = (unsigned char *)slotRawPtr(&returnFrame->ip); g->block = slotRawBlock(&returnFrame->method); homeContext = slotRawFrame(&returnFrame->homeContext); meth = slotRawMethod(&homeContext->method); methraw = METHRAW(meth); slotCopy(&g->receiver, &homeContext->vars[0]); //?? g->method = meth; meth = slotRawMethod(&curframe->method); methraw = METHRAW(meth); if (!methraw->needsHeapContext) { g->gc->Free(curframe); } else { SetInt(&curframe->caller, 0); } } else { ////// this should never happen . error("return from Function at top of call stack.\n"); g->method = NULL; g->block = NULL; g->frame = NULL; g->sp = g->gc->Stack()->slots - 1; longjmp(g->escapeInterpreter, 1); } //if (gTraceInterpreter) postfl("<-returnFromBlock\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "returnFromBlock"); #endif } HOT void returnFromMethod(VMGlobals *g) { PyrFrame *returnFrame, *curframe, *homeContext; PyrMethod *meth; PyrMethodRaw *methraw; curframe = g->frame; //assert(slotRawFrame(&curframe->context) == NULL); /*if (gTraceInterpreter) { post("returnFromMethod %s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name); post("tailcall %d\n", g->tailCall); }*/ #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif homeContext = slotRawFrame(&slotRawFrame(&curframe->context)->homeContext); if (homeContext == NULL) { null_return: #if TAILCALLOPTIMIZE if (g->tailCall) return; // do nothing. #endif /* static bool once = true; if (once || gTraceInterpreter) { once = false; post("return all the way out. sd %d\n", g->sp - g->gc->Stack()->slots); postfl("%s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name ); post("tailcall %d\n", g->tailCall); post("homeContext %p\n", homeContext); post("returnFrame %p\n", returnFrame); dumpObjectSlot(&homeContext->caller); DumpStack(g, g->sp); DumpBackTrace(g); } gTraceInterpreter = false; */ //if (IsNil(&homeContext->caller)) return; // do nothing. // return all the way out. PyrSlot *bottom = g->gc->Stack()->slots; slotCopy(bottom, g->sp); g->sp = bottom; // ??!! pop everybody g->method = NULL; g->block = NULL; g->frame = NULL; longjmp(g->escapeInterpreter, 2); } else { returnFrame = slotRawFrame(&homeContext->caller); if (returnFrame == NULL) goto null_return; // make sure returnFrame is a caller and find earliest stack frame { PyrFrame *tempFrame = curframe; while (tempFrame != returnFrame) { tempFrame = slotRawFrame(&tempFrame->caller); if (!tempFrame) { if (isKindOf((PyrObject*)g->thread, class_routine) && NotNil(&g->thread->parent)) { // not found, so yield to parent thread and continue searching. PyrSlot value; slotCopy(&value, g->sp); int numArgsPushed = 1; switchToThread(g, slotRawThread(&g->thread->parent), tSuspended, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. g->sp -= numArgsPushed - 1; slotCopy(g->sp, &value); curframe = tempFrame = g->frame; } else { slotCopy(&g->sp[2], &g->sp[0]); slotCopy(g->sp, &g->receiver); g->sp++; SetObject(g->sp, g->method); g->sp++; sendMessage(g, getsym("outOfContextReturn"), 3); return; } } } } { PyrFrame *tempFrame = curframe; while (tempFrame != returnFrame) { meth = slotRawMethod(&tempFrame->method); methraw = METHRAW(meth); PyrFrame *nextFrame = slotRawFrame(&tempFrame->caller); if (!methraw->needsHeapContext) { SetInt(&tempFrame->caller, 0); } else { if (tempFrame != homeContext) SetInt(&tempFrame->caller, 0); } tempFrame = nextFrame; } } // return to it g->ip = (unsigned char *)slotRawPtr(&returnFrame->ip); g->frame = returnFrame; g->block = slotRawBlock(&returnFrame->method); homeContext = slotRawFrame(&returnFrame->homeContext); meth = slotRawMethod(&homeContext->method); methraw = METHRAW(meth); #if DEBUGMETHODS if (gTraceInterpreter) { postfl("%s:%s <- %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name, slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name ); } #endif g->method = meth; slotCopy(&g->receiver, &homeContext->vars[0]); } #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } int keywordFixStack(VMGlobals *g, PyrMethod *meth, PyrMethodRaw *methraw, long allArgsPushed, long numKeyArgsPushed) { PyrSlot *pslot, *qslot; long i, j, m, diff, numArgsPushed, numArgsNeeded; if (numKeyArgsPushed) { // evacuate keyword args to separate area pslot = keywordstack + (numKeyArgsPushed<<1); qslot = g->sp + 1; for (m=0; msp - allArgsPushed + 1; numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1); numArgsNeeded = methraw->numargs; diff = numArgsNeeded - numArgsPushed; if (diff > 0) { // not enough args pslot = vars + numArgsPushed - 1; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0; mposargs) { PyrSymbol **name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1; PyrSlot *key = keywordstack; for (i=0; iposargs; ++j, ++name) { if (*name == slotRawSymbol(key)) { slotCopy(&vars[j], &key[1]); goto found; } } if (gKeywordError) { post("WARNING: keyword arg '%s' not found in call to %s:%s\n", slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } found: ; } } g->sp += numArgsPushed - allArgsPushed; return numArgsPushed; } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/PyrSignal.cpp0000664000000000000000000010337512245365552024402 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* compound formulas : amclip out = B<=0 ? 0 : A*B; // two quadrant amplitude modulation ring1 out = A*(B+1) = A*B + A; // amplitude modulation of a by b. ring2 out = A*B + A + B; // ring modulation plus both original signals ring3 out = A*A*B; // ring modulation variant ring4 out = A*A*B - A*B*B; // ring modulation variant difsqr out = A*A - B*B; // difference of squares sumsqr out = A*A + B*B; // sum of squares sqrdif out = (A - B)^2 // square of the difference = a^2 + b^2 - 2ab sqrsum out = (A + B)^2 // square of the sum = a^2 + b^2 + 2ab */ #include #include #include #include "PyrSignal.h" #include "PyrKernel.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "SCBase.h" #include "InitAlloc.h" //double log2 ( double x ); //double hypot ( double x, double y ); float gSlopeFactor[32]; long gWrapMask[32]; float *sineCycle; float *invSineCycle; float *pmSineCycle; float *gFracTable; double phaseToSineIndex; double sineIndexToPhase; void signal_init_globs() { int i; double phaseoffset, d, pmf; long sz, sz2; /* setup slopes and wrap masks */ for (i=0; i<32; ++i) { long length = 1L<Alloc((SINESIZE+1) * sizeof(float)); MEMFAIL(sineCycle); invSineCycle = (float*)pyr_pool_runtime->Alloc((SINESIZE+1) * sizeof(float)); MEMFAIL(invSineCycle); pmSineCycle = (float*)pyr_pool_runtime->Alloc((SINESIZE+1) * sizeof(float)); MEMFAIL(pmSineCycle); //gFracTable = (float*)pyr_pool_runtime->Alloc(FRACTABLESIZE * sizeof(float)); //MEMFAIL(gFracTable); sineIndexToPhase = 2. * 3.1415926535897932384626433832795 / SINESIZE; phaseToSineIndex = 1. / sineIndexToPhase; phaseoffset = sineIndexToPhase * 0.5; pmf = (1L << 29) / twopi; for (i=0; i<=SINESIZE; ++i) { double phase; phase = i * sineIndexToPhase; sineCycle[i] = d = sin(phase); invSineCycle[i] = 1. / d; pmSineCycle[i] = d * pmf; } // fix 1/0 values to a special large number invSineCycle[0] = invSineCycle[SINESIZE/2] = invSineCycle[SINESIZE] = VERY_BIG_FLOAT; sz = SINESIZE; sz2 = sz>>1; for (i=1; i<=8; ++i) { //for (i=1; i<=0; ++i) { //ie. none //postfl("%d %f %f\n", i, invSineCycle[i], sineCycle[i]); invSineCycle[i] = invSineCycle[sz-i] = VERY_BIG_FLOAT; invSineCycle[sz2-i] = invSineCycle[sz2+i] = VERY_BIG_FLOAT; } /*fracscale = 1./FRACTABLESIZE; for (i=0; igc->New(numbytes, 0, obj_float, true); if (signal) { signal->classptr = class_signal; signal->size = size; } // note: signal is filled with garbage return signal; } /*PyrObject* newPyrSignalFrom(VMGlobals *g, PyrObject* inSignal, long size) { PyrObject *signal; double *pslot, *qslot, *endptr; long set, m, mmax; long numbytes = size * sizeof(float); signal = (PyrObject*)g->gc->New(numbytes, 0, obj_float, true); signal->classptr = inSignal->classptr; signal->size = size; return signal; } */ PyrObject* signal_fill(PyrObject *outSignal, float inValue) { float *out = (float*)(outSignal->slots) - 1; UNROLL_CODE(outSignal->size, out, *++out = inValue;); return outSignal; } PyrObject* signal_scale(PyrObject *outSignal, float inValue) { if (inValue != 1.f) { float *out = (float*)(outSignal->slots) - 1; UNROLL_CODE(outSignal->size, out, *++out *= inValue;) } return outSignal; } PyrObject* signal_offset(PyrObject *outSignal, float inValue) { if (inValue != 0.f) { float *out = (float*)(outSignal->slots) - 1; UNROLL_CODE(outSignal->size, out, *++out += inValue;) } return outSignal; } PyrObject* signal_add_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP1(+); } PyrObject* signal_mul_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP1(*); } PyrObject* signal_sub_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( *++c = *++a - *++b; ); } PyrObject* signal_ring1_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; *++c = *a * *++b + *a; ); } PyrObject* signal_ring2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a * *b + *a + *b; ); } PyrObject* signal_ring3_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; *++c = *a * *a * *++b; ); } PyrObject* signal_ring4_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a * *a * *b - *a * *b * *b; ); } PyrObject* signal_thresh_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a < *b ? 0.f : *a; ); } PyrObject* signal_amclip_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *b <= 0.f ? 0.f : *a * *b; ); } PyrObject* signal_div_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( *++c = *++a / *++b; ); } PyrObject* signal_difsqr_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *c = *a * *a - *b * *b; ); } PyrObject* signal_sumsqr_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *c = *a * *a + *b * *b; ); } PyrObject* signal_sqrsum_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { float z; BINOP_LOOP2( z = *++a + *++b; *++c = z * z; ); } PyrObject* signal_sqrdif_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { float z; BINOP_LOOP2( z = *++a - *++b; *++c = z * z; ); } PyrObject* signal_absdif_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( *++c = fabs(*++a - *++b); ); } PyrObject* signal_add_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); if (inb == 0.f) { float *a = (float*)(ina->slots); memcpy((float*)(outc->slots), a, ina->size * sizeof(float)); } else { float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = *++a + inb;) } return outc; } PyrObject* signal_sub_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); if (inb == 0.f) { float *a = (float*)(ina->slots); memcpy((float*)(outc->slots), a, ina->size * sizeof(float)); } else { float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = *++a - inb;) } return outc; } PyrObject* signal_mul_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); if (inb == 1.f) { float *a = (float*)(ina->slots); memcpy((float*)(outc->slots), a, ina->size * sizeof(float)); } else { float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = *++a * inb;) } return outc; } PyrObject* signal_ring1_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++a; *++c = *a * inb + *a;) return outc; } PyrObject* signal_ring2_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++a; *++c = *a * inb + *a + inb;) return outc; } PyrObject* signal_ring3_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++a; *++c = *a * *a * inb;) return outc; } PyrObject* signal_ring4_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; float inb2 = inb * inb; UNROLL_CODE(outc->size, c, ++a; *++c = *a * *a * inb + *a * inb2;) return outc; } PyrObject* signal_thresh_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; float inb2 = inb * inb; UNROLL_CODE(outc->size, c, ++a; *++c = *a < inb2 ? 0.f : *a;) return outc; } PyrObject* signal_amclip_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *res; PyrObject *outc = newPyrSignal(g, ina->size); if (inb <= 0.f) res = signal_fill(outc, 0.f); else res = signal_scale(outc, inb); return res; } PyrObject* signal_div_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); if (inb == 1.f) { float *a = (float*)(ina->slots); memcpy((float*)(outc->slots), a, ina->size * sizeof(float)); } else { float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; inb = 1.f/inb; UNROLL_CODE(outc->size, c, *++c = *++a * inb;) } return outc; } PyrObject* signal_difsqr_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; inb = inb * inb; UNROLL_CODE(outc->size, c, ++a; *++c = *a * *a - inb;) return outc; } PyrObject* signal_sumsqr_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; inb = inb * inb; UNROLL_CODE(outc->size, c, ++a; *++c = *a * *a + inb;) return outc; } PyrObject* signal_sqrsum_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; float temp; UNROLL_CODE(outc->size, c, ++a; temp = *a + inb; *++c = temp * temp;) return outc; } PyrObject* signal_sqrdif_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; float temp; UNROLL_CODE(outc->size, c, ++a; temp = *a - inb; *++c = temp * temp;) return outc; } PyrObject* signal_absdif_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++a; *++c = fabs(*a - inb); ) return outc; } PyrObject* signal_ring1_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = ina * *++b + ina;) return outc; } PyrObject* signal_ring2_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++b; *++c = ina * *b + ina + *b;) return outc; } PyrObject* signal_ring3_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; float ina2 = ina * ina; UNROLL_CODE(outc->size, c, *++c = ina2 * *++b;) return outc; } PyrObject* signal_ring4_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; float ina2 = ina * ina; UNROLL_CODE(outc->size, c, ++b; *++c = ina2 * *b - ina * *b * *b;) return outc; } PyrObject* signal_thresh_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = ina < *b ? 0.f : ina;) return outc; } PyrObject* signal_amclip_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = *b <= 0.f ? 0.f : ina * *b;) return outc; } PyrObject* signal_sub_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = ina - *++b;) return outc; } PyrObject* signal_div_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = ina / *++b;) return outc; } PyrObject* signal_difsqr_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; ina = ina * ina; UNROLL_CODE(outc->size, c, ++b; *++c = ina - *b * *b;) return outc; } PyrObject* signal_sumsqr_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; ina = ina * ina; UNROLL_CODE(outc->size, c, ++b; *++c = ina + *b * *b;) return outc; } PyrObject* signal_sqrsum_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float temp; float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++b; temp = ina + *b; *++c = temp * temp;) return outc; } PyrObject* signal_sqrdif_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float temp; float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++b; temp = ina - *b; *++c = temp * temp;) return outc; } PyrObject* signal_absdif_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++b; *++c = fabs(ina - *b);) return outc; } PyrObject* signal_min_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a < *b ? *a : *b; ); } PyrObject* signal_max_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a > *b ? *a : *b; ); } PyrObject* signal_scaleneg_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a < 0.f ? *a * *b : *a; ); } PyrObject* signal_clip2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a > *b ? *b : (*a < -*b ? -*b : *a); ); } PyrObject* signal_fold2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = sc_fold(*a, -*b, *b); ); } PyrObject* signal_wrap2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = sc_wrap(*a, -*b, *b); ); } PyrObject* signal_excess_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a > *b ? *a - *b : (*a < -*b ? *a + *b : 0.f); ); } bool signal_equal_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { float *a = (float*)(ina->slots) - 1; float *b = (float*)(inb->slots) - 1; float *endptr = a + ina->size; if (ina->size != inb->size) return false; if (slotRawSymbol(&ina->slots[ kSignalRate ]) != slotRawSymbol(&inb->slots[ kSignalRate ])) return false; while (a < endptr) { if (*a++ != *b++) return false; } return true; } PyrObject* signal_min_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = *a < inb ? *a : inb;) return outc; } PyrObject* signal_max_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = *a > inb ? *a : inb;) return outc; } PyrObject* signal_scaleneg_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = *a < 0.f ? *a * inb : *a;) return outc; } PyrObject* signal_clip2_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = *a > inb ? inb : (*a < -inb ? -inb : *a);) return outc; } PyrObject* signal_fold2_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = sc_fold(*a, -inb, inb);) return outc; } PyrObject* signal_wrap2_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = sc_wrap(*a, -inb, inb);) return outc; } PyrObject* signal_excess_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = *a > inb ? *a - inb : (*a < -inb ? *a + inb : 0.f);) return outc; } PyrObject* signal_scaleneg_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; if (ina < 0.f) { UNROLL1_CODE(outc->size, c, *++c = ina * *++b;); } else { UNROLL1_CODE(outc->size, c, *++c = ina;); } return outc; } PyrObject* signal_clip2_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = ina > *b ? *b : (ina < -*b ? -*b : ina);) return outc; } PyrObject* signal_fold2_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = sc_fold(ina, -*b, *b);) return outc; } PyrObject* signal_wrap2_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = sc_wrap(ina, -*b, *b);) return outc; } PyrObject* signal_excess_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = ina > *b ? ina - *b : (ina < -*b ? ina + *b : 0.f);) return outc; } PyrObject* signal_invert(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL_CODE(inPyrSignal->size, out, *++out = -*++in;) return outc; } PyrObject* signal_recip(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL_CODE(inPyrSignal->size, out, *++out = 1.f / *++in;) return outc; } PyrObject* signal_squared(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL_CODE(inPyrSignal->size, out, ++in; *++out = *in * *in;) return outc; } PyrObject* signal_cubed(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL_CODE(inPyrSignal->size, out, ++in; *++out = *in * *in * *in;) return outc; } // PowerPC has a fast fabs instruction PyrObject* signal_abs(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL_CODE(inPyrSignal->size, out, *++out = fabs(*++in);) return outc; } float signal_findpeak(PyrObject *inPyrSignal) { float *out = (float*)(inPyrSignal->slots) - 1; float peak = 0.f; float z; UNROLL1_CODE(inPyrSignal->size, out, ++out; z = fabs(*out); peak = z>peak ? z : peak;) return peak; } PyrObject* signal_normalize_transfer_fn(PyrObject *inPyrSignal) { float *out, scale, offset, x, maxval; long length, halflength; maxval = 0.0; out = (float*)(inPyrSignal->slots) - 1; length = inPyrSignal->size; halflength = length >> 1; offset = (out[halflength-1] + out[halflength]) * 0.5; UNROLL1_CODE(inPyrSignal->size, out, ++out; x = *out - offset; x = (x < 0.) ? -x : x; if (x > maxval) maxval = x; ); if (maxval) { out = (float*)(inPyrSignal->slots) - 1; scale = 1.0 / maxval; UNROLL1_CODE(inPyrSignal->size, out, ++out; *out = (*out - offset) * scale; ); } return inPyrSignal; } float signal_integral(PyrObject *inPyrSignal) { float *out = (float*)(inPyrSignal->slots) - 1; float sum = 0.f; UNROLL1_CODE(inPyrSignal->size, out, sum += *++out;) return sum; } PyrObject* signal_sign(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, ++in; *++out = *in < 0.f ? -1.f : (*in > 0.f ? 1.f : 0.f);) return outc; } PyrObject* signal_negative(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = *++in < 0.f ? 1.f : 0.f;) return outc; } PyrObject* signal_positive(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = *++in >= 0.f ? 1.f : 0.f;) return outc; } PyrObject* signal_strictly_positive(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = *++in > 0.f ? 1.f : 0.f;) return outc; } PyrObject* signal_nyqring(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; float *endptr = out + inPyrSignal->size; switch (inPyrSignal->size & 3) { while (out < endptr) { *++out = -*++in; case 3 : *++out = *++in; case 2 : *++out = -*++in; case 1 : *++out = *++in; case 0 : ; } } return outc; } PyrObject* signal_clip_f(VMGlobals *g, PyrObject *inPyrSignal, float lo, float hi) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; float *endptr = out + inPyrSignal->size; while (out < endptr) { ++in; *++out = *in < lo ? lo : (*in > hi ? hi : *in); } return outc; } PyrObject* signal_clip_x(VMGlobals *g, PyrObject *ina, PyrObject *inb, PyrObject *inc) { PyrObject *outd; float *a, *b, *c, *d, *endptr; long minsize = sc_min(ina->size, inb->size); minsize = sc_min(minsize, inc->size); outd = newPyrSignal(g, minsize); a = (float*)(ina->slots) - 1; b = (float*)(inb->slots) - 1; c = (float*)(inc->slots) - 1; d = (float*)(outd->slots) - 1; endptr = a + minsize; UNROLL1_CODE(outd->size, d, ++a; ++b; ++c; *++d = *a < *b ? *b : (*a > *c ? *c : *a);); return outd; } /// WRAP AND FOLD ARE STILL INCORRECT ! PyrObject* signal_wrap_f(VMGlobals *g, PyrObject *inPyrSignal, float lo, float hi) { float *out = (float*)(inPyrSignal->slots) - 1; float *endptr = out + inPyrSignal->size; while (out < endptr) { ++out; *out = sc_wrap(*out, lo, hi); } return inPyrSignal; } PyrObject* signal_wrap_x(VMGlobals *g, PyrObject *ina, PyrObject *inb, PyrObject *inc) { PyrObject *outd; float *a, *b, *c, *d, *endptr; long minsize = sc_min(ina->size, inb->size); minsize = sc_min(minsize, inc->size); outd = newPyrSignal(g, minsize); a = (float*)(ina->slots) - 1; b = (float*)(inb->slots) - 1; c = (float*)(inc->slots) - 1; d = (float*)(outd->slots) - 1; endptr = d + outd->size; while (d < endptr) { a++; b++; c++; d++; ++d; *d = sc_wrap(*a, *b, *c); } return outd; } PyrObject* signal_fold_f(VMGlobals *g, PyrObject *inPyrSignal, float lo, float hi) { float *out = (float*)(inPyrSignal->slots) - 1; float *endptr = out + inPyrSignal->size; while (out < endptr) { ++out; *out = sc_fold(*out, lo, hi); } return inPyrSignal; } PyrObject* signal_fold_x(VMGlobals *g, PyrObject *ina, PyrObject *inb, PyrObject *inc) { PyrObject *outd; float *a, *b, *c, *d, *endptr; long minsize = sc_min(ina->size, inb->size); minsize = sc_min(minsize, inc->size); outd = newPyrSignal(g, minsize); a = (float*)(ina->slots) - 1; b = (float*)(inb->slots) - 1; c = (float*)(inc->slots) - 1; d = (float*)(outd->slots) - 1; endptr = d + outd->size; while (d < endptr) { a++; b++; c++; d++; *d = sc_fold(*a, *b, *c); } return outd; } PyrObject* signal_log(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = log(*++in);) return outc; } #ifdef SC_WIN32 // in PyrMathSupport.cpp double log2(double x); #elif defined(__FreeBSD__) double log2(double x); #endif PyrObject* signal_log2(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = log2(*++in);) return outc; } PyrObject* signal_log10(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = log10(*++in);) return outc; } PyrObject* signal_sin(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = sin(*++in);) return outc; } PyrObject* signal_cos(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = cos(*++in);) return outc; } PyrObject* signal_tan(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = tan(*++in);) return outc; } PyrObject* signal_sinh(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = sinh(*++in);) return outc; } PyrObject* signal_cosh(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = cosh(*++in);) return outc; } PyrObject* signal_tanh(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = tanh(*++in);) return outc; } PyrObject* signal_tanh_ds(PyrObject *inPyrSignal) { float *out = (float*)(inPyrSignal->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, ++out; *out = tanh(*out);) return inPyrSignal; } PyrObject* signal_asin(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = asin(*++in);) return outc; } PyrObject* signal_acos(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = acos(*++in);) return outc; } PyrObject* signal_atan(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = atan(*++in);) return outc; } PyrObject* signal_exp(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = exp(*++in);) return outc; } PyrObject* signal_sqrt(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = sqrt(*++in);) return outc; } PyrObject* signal_distort(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; float *endptr = out + inPyrSignal->size; while (out < endptr) { float z = *++in; if (z < 0.f) *++out = z/(1.f - z); else *++out = z/(1.f + z); } return outc; } PyrObject* signal_softclip(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; float *endptr = out + inPyrSignal->size; while (out < endptr) { float z = *++in; if (z < -0.5f) *++out = (-z - .25f)/z; else if (z > 0.5f) *++out = (z - .25f)/z; else *++out = z; } return outc; } PyrObject* signal_rotate(VMGlobals *g, PyrObject* ina, int rot) { long i, j; PyrObject *outc = newPyrSignal(g, ina->size); float *a0 = (float*)(ina->slots) - 1; // float *a = a0 + sc_mod(rot, ina->size); float *a = a0 + sc_mod(0 - rot, ina->size); float *aend = a0 + ina->size; float *c = (float*)(outc->slots) - 1; long nsmps = outc->size; for (i=0,j=rot; i= aend) a = a0; } return outc; } PyrObject* signal_reverse_range(PyrObject* ina, long start, long end) { long size = ina->size; long size2; long i; start = sc_max(0, start); end = sc_min(end + 1, size); size = end - start; size2 = size>>1; float *a = (float*)(ina->slots) - 1 + start; // float *b = (float*)(ina->slots) - 1 + end; float *b = (float*)(ina->slots) + end; float temp; for (i=0; isize; long i; float z, scale, maxlevel; float *a0, *a; start = sc_max(0, start); end = sc_min(end + 1, size); size = end - start; a0 = (float*)(ina->slots) - 1 + start; a = a0; maxlevel = 0.f; for (i=0; i maxlevel) maxlevel = z; } a = a0; if (maxlevel != 0.f) { scale = 1./maxlevel; for (i=0; isize; long i; float z; start = sc_max(0, start); end = sc_min(end, size); size = end - start + 1; float *a = (float*)(ina->slots) - 1 + start; for (i=0; isize; long i; float z, level, slope; start = sc_max(0, start); end = sc_min(end + 1, size); size = end - start; float *a = (float*)(ina->slots) - 1 + start; slope = (lvl1 - lvl0) / size; level = lvl0; for (i=0; i 0) { a = (float*)(ina->slots) + index - 1; b = (float*)(inb->slots) - 1; len = sc_min(inb->size, ina->size - index); } else { a = (float*)(ina->slots) - 1; b = (float*)(inb->slots) - index - 1; len = sc_min(ina->size, inb->size + index); } UNROLL_CODE(len, a, *++a += *++b;); return ina; } PyrObject* signal_overwrite(VMGlobals *g, PyrObject* ina, PyrObject* inb, long index) { float *a, *b; long len; if (index > 0) { a = (float*)(ina->slots) + index - 1; b = (float*)(inb->slots) - 1; len = sc_min(inb->size, ina->size - index); } else { a = (float*)(ina->slots) - 1; b = (float*)(inb->slots) - index - 1; len = sc_min(ina->size, inb->size + index); } UNROLL_CODE(len, a, *++a = *++b;); return ina; } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/GC.cpp0000664000000000000000000007422112245365552022760 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "GC.h" #include "PyrKernel.h" #include "PyrObjectProto.h" #include "PyrSymbol.h" #include "InitAlloc.h" #include #include #define PAUSETIMES 0 double pauseBeginTime = 0.; double totalPauseTime = 0.; double maxPauseTime = 0.; double minPauseTime = 1e9; int pauseCount = 0; int numPausesGreaterThanOneMillisecond = 0; int maxPauseStackScans = 0; int maxPauseFlips = 0; int maxPauseScans = 0; int maxPausePartialScans = 0; int maxPauseNumToScan = 0; int maxPauseSlotsScanned = 0; int checkStackScans = 0; int checkFlips = 0; int checkNumToScan = 0; int checkScans = 0; int checkPartialScans = 0; int checkSlotsScanned = 0; double elapsedTime(); inline void PyrGC::beginPause() { checkStackScans = mStackScans; checkFlips = mFlips; checkScans = mScans; checkNumToScan = mNumToScan; checkPartialScans = mNumPartialScans; checkSlotsScanned = mSlotsScanned; pauseBeginTime = elapsedTime(); } inline void PyrGC::endPause() { double pauseTime = elapsedTime() - pauseBeginTime; if (pauseTime > 0.001) numPausesGreaterThanOneMillisecond++; if (pauseTime > maxPauseTime) { maxPauseTime = pauseTime; maxPauseStackScans = mStackScans - checkStackScans; maxPauseFlips = mFlips - checkFlips; maxPauseScans = mScans - checkScans; maxPauseNumToScan = checkNumToScan; maxPausePartialScans = mNumPartialScans - checkPartialScans; maxPauseSlotsScanned = mSlotsScanned - checkSlotsScanned; } if (pauseTime < minPauseTime) minPauseTime = pauseTime; totalPauseTime += pauseTime; pauseCount ++; } void PyrGC::reportPause() { post("pauses %d\n", pauseCount); post("total pause time %g\n", totalPauseTime); post("num pauses > 1 ms %d\n", numPausesGreaterThanOneMillisecond); post("avg pause time %g\n", totalPauseTime / pauseCount); post("min pause time %g\n", minPauseTime); post("max pause time %g\n", maxPauseTime); post("max pause scans %d\n", maxPauseScans); post("max pause partial obj scans %d\n", maxPausePartialScans); post("max pause num to scan %d\n", maxPauseNumToScan); post("max pause flips %d\n", maxPauseFlips); post("max pause stack scans %d\n", maxPauseStackScans); post("max pause slots scanned %d\n", maxPauseSlotsScanned); pauseBeginTime = 0.; totalPauseTime = 0.; maxPauseTime = 0.; minPauseTime = 1e9; pauseCount = 0; numPausesGreaterThanOneMillisecond = 0; } #if PAUSETIMES #define BEGINPAUSE beginPause(); #define ENDPAUSE endPause(); #define REPORTPAUSE reportPause(); #else #define BEGINPAUSE #define ENDPAUSE #define REPORTPAUSE #endif /* --- list segments: black gray white free sweep scan phase: clear list of new nonlocal reached objects. when a non local object is reached, mark it, and put it on the list if not retained. sweep phase: send any new retained objects to other system send any no longer reatined objects to the other system. send this list to enqueue finalization messages finalize: call finalize method, move from sweep area to free area list of nonlocal objects. list of nonlocal reached objects. */ void fatalerror(const char*str); void fatalerror(const char*str) { fputs(str, stderr); postfl(str); throw std::runtime_error(str); //exit(-1); } inline int ScanSize(PyrObjectHdr *obj) { return obj->obj_format <= obj_slot ? obj->size : 0; } HOT void PyrGC::ScanSlots(PyrSlot *inSlots, long inNumToScan) { if (inNumToScan == 0) return; unsigned char whiteColor = mWhiteColor; unsigned char greyColor = mGreyColor; mSlotsScanned += inNumToScan; int foundGreyObjects = 0; PyrObjectHdr * grey = &mGrey; PyrObjectHdr * greyNext = grey->next; PyrSlot *slot = inSlots; PyrSlot *endslot = inSlots + inNumToScan; do { if (IsObj(slot)) { PyrObject *obj = slotRawObject(slot); if (obj->gc_color == whiteColor) { /* used to be ToGrey2(obj), but rearranged for slightly better performance * * move obj from white to grey */ PyrObjectHdr * objPrev = obj->prev; PyrObjectHdr * objNext = obj->next; /* link in grey set */ greyNext->prev = obj; grey->next = obj; obj->prev = grey; obj->next = greyNext; greyNext = obj; // remove from old set objNext->prev = objPrev; objPrev->next = objNext; obj->gc_color = greyColor; foundGreyObjects++; } } ++slot; } while (slot != endslot); mNumGrey += foundGreyObjects; } void GCSet::Init(int inGCSet) { mBlack.classptr = NULL; mBlack.obj_sizeclass = inGCSet; mBlack.size = 0; mBlack.gc_color = obj_gcmarker; mWhite.classptr = NULL; mWhite.obj_sizeclass = inGCSet; mWhite.size = 0; mWhite.gc_color = obj_gcmarker; mFree = &mBlack; mBlack.next = &mWhite; mWhite.next = &mBlack; mBlack.prev = &mWhite; mWhite.prev = &mBlack; } void GCSet::MajorFlip() { // move all white items to beginning of free list mFree = mWhite.next; if (!PyrGC::IsMarker(mBlack.next)) { // move all black items to white list mWhite.next = mBlack.next; mFree->prev = mWhite.prev; mBlack.next->prev = &mWhite; mWhite.prev->next = mFree; // black list empty mBlack.next = &mWhite; mWhite.prev = &mBlack; } } void GCSet::MinorFlip() { // move all white items to beginning of free list mFree = mWhite.next; } PyrProcess* newPyrProcess(VMGlobals *g, PyrClass *procclassobj); PyrGC::PyrGC(VMGlobals *g, AllocPool *inPool, PyrClass *mainProcessClass, long poolSize) { mVMGlobals = g; mPool = inPool; //mCurSet = 0; mNumToScan = 0; mFlips = 0; mCollects = 0; mAllocTotal = 0; mNumAllocs = 0; mScans = 0; mStackScans = 0; mNumPartialScans = 0; mSlotsScanned = 0; mGreyColor = 3<<2; mBlackColor = 2<<2; mWhiteColor = 1<<2; mFreeColor = 0; mRunning = false; mCanSweep = false; mPartialScanObj = NULL; mPartialScanSlot = 0; mUncollectedAllocations = 0; mGrey.classptr = NULL; mGrey.obj_sizeclass = 0; mGrey.size = 0; mGrey.gc_color = obj_gcmarker; mGrey.prev = &mGrey; mGrey.next = &mGrey; mNumGrey = 0; mNewPool.Init(mPool, poolSize, poolSize, 9000); // initialize treadmills for (int i=0; iprocess = NULL; // initPyrThread checks to see if process has been started mProcess = newPyrProcess(g, mainProcessClass); mStack = slotRawObject(&slotRawThread(&mProcess->mainThread)->stack); ToBlack(mStack); SetNil(&slotRawThread(&mProcess->mainThread)->stack); mNumGrey = 0; ToGrey2(mProcess); g->sp = mStack->slots - 1; g->process = mProcess; mRunning = true; SanityCheck(); //assert(SanityCheck()); } PyrObject *PyrGC::NewPermanent(size_t inNumBytes, long inFlags, long inFormat) { // obtain size info int32 alignedSize = (inNumBytes + kAlignMask) & ~kAlignMask; // 16 byte align int32 numSlots = alignedSize / sizeof(PyrSlot); numSlots = numSlots < 1 ? 1 : numSlots; int32 sizeclass = LOG2CEIL(numSlots); sizeclass = sc_min(sizeclass, kNumGCSizeClasses-1); int32 allocSize = sizeof(PyrObjectHdr) + (sizeof(PyrSlot) << sizeclass); // allocate permanent objects PyrObject* obj = (PyrObject*)pyr_pool_runtime->Alloc(allocSize); obj->gc_color = obj_permanent; obj->next = obj->prev = NULL; obj->obj_sizeclass = sizeclass; obj->obj_format = inFormat; obj->obj_flags = inFlags; obj->size = 0; obj->classptr = class_object; return obj; } void PyrGC::BecomePermanent(PyrObject *inObject) { if (IsGrey(inObject)) mNumGrey--; DLRemove(inObject); inObject->gc_color = obj_permanent; inObject->obj_flags |= obj_immutable; inObject->next = inObject->prev = inObject; } void PyrGC::BecomeImmutable(PyrObject *inObject) { inObject->obj_flags |= obj_immutable; } void DumpBackTrace(VMGlobals *g); HOT PyrObject *PyrGC::New(size_t inNumBytes, long inFlags, long inFormat, bool inCollect) { PyrObject *obj = NULL; if (inFlags & obj_permanent) { return NewPermanent(inNumBytes, inFlags, inFormat); } #ifdef GC_SANITYCHECK SanityCheck(); #endif // obtain size info int32 alignedSize = (inNumBytes + kAlignMask) & ~kAlignMask; // 16 byte align int32 numSlots = alignedSize / sizeof(PyrSlot); numSlots = numSlots < 1 ? 1 : numSlots; int32 sizeclass = LOG2CEIL(numSlots); sizeclass = sc_min(sizeclass, kNumGCSizeClasses-1); int32 credit = 1L << sizeclass; mAllocTotal += credit; mNumAllocs++; mNumToScan += credit; obj = Allocate(inNumBytes, sizeclass, inCollect); obj->obj_format = inFormat; obj->obj_flags = inFlags & 255; obj->size = 0; obj->classptr = class_object; obj->gc_color = mWhiteColor; #ifdef GC_SANITYCHECK SanityCheck(); #endif return obj; } HOT PyrObject *PyrGC::NewFrame(size_t inNumBytes, long inFlags, long inFormat, bool inAccount) { PyrObject *obj = NULL; #ifdef GC_SANITYCHECK SanityCheck(); #endif // obtain size info int32 alignedSize = (inNumBytes + kAlignMask) & ~kAlignMask; // 16 byte align int32 numSlots = alignedSize / sizeof(PyrSlot); numSlots = numSlots < 1 ? 1 : numSlots; int32 sizeclass = LOG2CEIL(numSlots); sizeclass = sc_min(sizeclass, kNumGCSizeClasses-1); int32 credit = 1L << sizeclass; mAllocTotal += credit; mNumAllocs++; mNumToScan += credit; obj = Allocate(inNumBytes, sizeclass, inAccount); obj->obj_format = inFormat; obj->obj_flags = inFlags; obj->size = 0; obj->classptr = class_frame; obj->gc_color = mWhiteColor; #ifdef GC_SANITYCHECK SanityCheck(); #endif return obj; } PyrObject *PyrGC::NewFinalizer(ObjFuncPtr finalizeFunc, PyrObject *inObject, bool inCollect) { PyrObject *obj = NULL; #ifdef GC_SANITYCHECK SanityCheck(); #endif // obtain size info int32 sizeclass = 1; int32 credit = 1L << sizeclass; mNumToScan += credit; mAllocTotal += credit; mNumAllocs++; if (inCollect && mNumToScan >= kScanThreshold) { Collect(); } GCSet *gcs = mSets + kFinalizerSet; obj = (PyrObject*)gcs->mFree; if (!IsMarker(obj)) { // from free list gcs->mFree = obj->next; } else { if (sizeclass > kMaxPoolSet) { SweepBigObjects(); int32 allocSize = sizeof(PyrObjectHdr) + (sizeof(PyrSlot) << sizeclass); obj = (PyrObject*)mPool->Alloc(allocSize); } else { int32 allocSize = sizeof(PyrObjectHdr) + (sizeof(PyrSlot) << sizeclass); obj = (PyrObject*)mNewPool.Alloc(allocSize); } if (!obj) { post("Finalizer alloc failed.\n"); MEMFAILED; } DLInsertAfter(&gcs->mWhite, obj); } obj->obj_sizeclass = sizeclass; obj->obj_format = obj_slot; obj->obj_flags = 0; obj->size = 2; obj->classptr = class_finalizer; obj->gc_color = mWhiteColor; SetPtr(obj->slots+0, (void*)finalizeFunc); SetObject(obj->slots+1, inObject); #ifdef GC_SANITYCHECK SanityCheck(); #endif return obj; } void PyrGC::SweepBigObjects() { if (!mCanSweep) return; for (int i=kMaxPoolSet+1; imFree; if (!IsMarker(obj)) { // unlink chain of free objects gcs->mFree = obj->prev->next = &gcs->mBlack; gcs->mBlack.prev = obj->prev; do { PyrObjectHdr *nextobj = obj->next; void* ptr = (void*)obj; mPool->Free(ptr); obj = nextobj; } while (!IsMarker(obj)); } } mCanSweep = false; } void PyrGC::CompletePartialScan(PyrObject *obj) { if (mPartialScanObj == obj) { int32 remain = obj->size - mPartialScanSlot; ScanSlots(mPartialScanObj->slots + mPartialScanSlot, remain); } } HOT void PyrGC::DoPartialScan(int32 inObjSize) { int32 remain = inObjSize - mPartialScanSlot; mNumPartialScans++; if (remain <= 0) { mPartialScanObj = NULL; mNumToScan -= 4; if (mNumToScan<0) mNumToScan = 0; return; } int32 numtoscan = sc_min(remain, mNumToScan); ScanSlots(mPartialScanObj->slots + mPartialScanSlot, numtoscan); if (numtoscan == remain) { mPartialScanObj = NULL; mNumToScan -= numtoscan + 4; } else { mPartialScanSlot += numtoscan; mNumToScan -= numtoscan; } if (mNumToScan < 0) mNumToScan = 0; //post("partial %5d xx %4d %2d %s\n", mScans, mNumToScan, mNumGrey); //post("partial %5d %2d %4d %2d %s\n", mScans, i, mNumToScan, mNumGrey, slotRawSymbol(&obj->classptr->name)->name); } HOT bool PyrGC::ScanOneObj() { // Find a set that has a grey object PyrObject* obj; obj = (PyrObject*)mGrey.next; if (IsMarker(obj)) { if (mNumGrey) fatalerror("grey count error\n"); return false; } /*if (!IsGrey(obj)) { postfl("Object on grey list not grey %d %d\n", obj->gc_color, mGreyColor); fatalerror("C1"); }*/ mScans++; //post("-> scan %d %d %d\n", mNumGrey, IsGrey(obj), mNumToScan); // Found a grey object // move obj from grey to black ToBlack(obj); int32 size = ScanSize(obj); //post("<- scan %d %d %d %d\n", mNumGrey, IsGrey(obj), mNumToScan, size); if (size > mNumToScan + 32) { mPartialScanObj = obj; mPartialScanSlot = 0; DoPartialScan(size); } else if (size > 0) { ScanSlots(obj->slots, size); mNumToScan -= 1L << obj->obj_sizeclass; if (mNumToScan < 0) mNumToScan = 0; } else { mNumToScan -= 1L << obj->obj_sizeclass; if (mNumToScan < 0) mNumToScan = 0; } return true; } void PyrGC::ScanStack() { // scan the stack PyrObject* obj = mStack; VMGlobals *g = mVMGlobals; PyrSlot* slot = obj->slots; int32 size = obj->size = g->sp - slot + 1; ScanSlots(slot, size); } void PyrGC::ScanFrames() { VMGlobals *g = mVMGlobals; PyrFrame* frame = g->frame; while (frame) { #if 1 // this is more incremental if (IsWhite(frame)) { ToGrey2(frame); } #else // this is more efficient if (!IsBlack(frame)) { ToBlack(frame); int32 size = ScanSize(frame); PyrSlot *slots = ((PyrObject*)frame)->slots; ScanSlots(slots, size); } #endif frame = slotRawFrame(&frame->caller); } } void PyrGC::Flip() { #ifdef GC_SANITYCHECK SanityCheck(); #endif ScanFinalizers(); GCSet *gcs = mSets; if ((mFlips & 3) == 0) { // major flip for (int i=0; iMajorFlip(); } // advance colors mBlackColor += 4; mWhiteColor += 4; mGreyColor += 4; mFreeColor += 4; } else { // minor flip for (int i=0; iMinorFlip(); } } // move root to grey area mNumGrey = 0; ToGrey2(mProcess); ToBlack(mStack); // reset counts mNumToScan = 0; mCanSweep = true; mFlips++; //post("flips %d collects %d nalloc %d alloc %d grey %d\n", mFlips, mCollects, mNumAllocs, mAllocTotal, mNumGrey); #ifdef GC_SANITYCHECK SanityCheck(); #endif } void PyrGC::FullCollection() { Collect(100000000); // collect space SweepBigObjects(); } void PyrGC::Collect(int32 inNumToScan) { mNumToScan = sc_max(mNumToScan, inNumToScan); Collect(); // collect space } HOT void PyrGC::Collect() { BEGINPAUSE bool stackScanned = false; mCollects++; #ifdef GC_SANITYCHECK SanityCheck(); #endif if (mNumToScan > 0) { //post("->Collect ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans); //DumpInfo(); mNumToScan += mNumToScan >> 3; //post("->Collect2 ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans); //mCurSet = 0; while (mNumToScan > 0) { while (mNumToScan > 0 && (mNumGrey > 0 || mPartialScanObj)) { if (mPartialScanObj) { DoPartialScan(ScanSize(mPartialScanObj)); } else { if (!ScanOneObj()) break; } } if (mNumGrey == 0 && mPartialScanObj == NULL) { if (!stackScanned) { stackScanned = true; mStackScans++; ScanStack(); ScanFrames(); } if (mNumGrey == 0 && mPartialScanObj == NULL && stackScanned) { Flip(); break; } } } //post("<-Collect ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans); //DumpInfo(); //post("size9:\n"); //TraceAnyPathToObjsOfSize(9); //post("greys:\n"); //TraceAnyPathToAllGrey(); } //post("mNumToScan %d\n", mNumToScan); mUncollectedAllocations = 0; #ifdef GC_SANITYCHECK SanityCheck(); #endif ENDPAUSE } void PyrGC::Finalize(PyrObject *finalizer) { if (!IsPtr(finalizer->slots+0)) return; if (!IsObj(finalizer->slots+1)) return; ObjFuncPtr func = (ObjFuncPtr)slotRawPtr(&finalizer->slots[0]); PyrObject *obj = slotRawObject(&finalizer->slots[1]); //post("FINALIZE %s %p\n", slotRawSymbol(&obj->classptr->name)->name, obj); (func)(mVMGlobals, obj); SetNil(obj->slots+0); SetNil(obj->slots+1); } void PyrGC::ScanFinalizers() { GCSet *gcs = &mSets[kFinalizerSet]; PyrObjectHdr *obj = gcs->mWhite.next; PyrObjectHdr *firstFreeObj = gcs->mFree; while (obj != firstFreeObj) { Finalize((PyrObject*)obj); obj = obj->next; } } void PyrGC::RunAllFinalizers() { GCSet *gcs = &mSets[kFinalizerSet]; PyrObjectHdr *obj = gcs->mBlack.next; while (!IsMarker(obj)) { Finalize((PyrObject*)obj); obj = obj->next; } obj = gcs->mWhite.next; PyrObjectHdr *firstFreeObj = gcs->mFree; while (obj != firstFreeObj) { Finalize((PyrObject*)obj); obj = obj->next; } obj = mGrey.next; while (!IsMarker(obj)) { if (obj->classptr == class_finalizer) Finalize((PyrObject*)obj); obj = obj->next; } } bool PyrGC::SanityCheck2() { int numgrey = 0; PyrObjectHdr *grey = mGrey.next; while (!IsMarker(grey)) { numgrey++; if (!IsGrey(grey)) { postfl("sc Object on grey list not grey %d %d %d\n", grey->gc_color, mGreyColor, numgrey); return false; } grey = grey->next; } //postfl("sc %d %d\n", mNumGrey, numgrey); return mNumGrey == numgrey; } #ifdef SC_DARWIN #include #endif bool PyrGC::SanityCheck() { if (!mRunning) return true; //postfl("PyrGC::SanityCheck\n"); bool res = LinkSanity() && ListSanity() // && SanityMarkObj((PyrObject*)mProcess,NULL,0) && SanityMarkObj(mStack,NULL,0) // && SanityClearObj((PyrObject*)mProcess,0) && SanityClearObj(mStack,0) && SanityCheck2() ; //if (!res) DumpInfo(); //if (!res) Debugger(); return res; } bool PyrGC::ListSanity() { bool found; if (StackDepth() < 0) { fprintf(stderr, "stack underflow %d\n", (int)StackDepth()); return false; } //postfl("PyrGC::ListSanity\n"); for (int i=0; imBlack; if (!IsMarker(obj)) { //debugf("set %d black marker color wrong %d %p\n", i, obj->gc_color, obj); fprintf(stderr, "set %d black marker color wrong %d %p\n", i, obj->gc_color, obj); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); return false; } // check white marker obj = &set->mWhite; if (!IsMarker(obj)) { //debugf("set %d white marker color wrong %d %p\n", i, obj->gc_color, obj); fprintf(stderr, "set %d white marker color wrong %d %p\n", i, obj->gc_color, obj); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); return false; } // check free pointer between white and black marker if (set->mFree != &set->mBlack) { obj = set->mWhite.next; found = false; while (!IsMarker(obj)) { if (obj == set->mFree) { found = true; break; } obj = obj->next; } if (!found) { //debugf("set %d free pointer not between white and black\n", i); fprintf(stderr, "set %d free pointer not between white and black\n", i); fprintf(stderr, "set->mFree %p\n", set->mFree); fprintf(stderr, "set->mWhite %p\n", &set->mWhite); fprintf(stderr, "set->mBlack %p\n", &set->mBlack); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)set->mFree); fprintf(stderr, "black %d white %d grey %d\n", mBlackColor, mWhiteColor, mGreyColor); obj = &set->mWhite; int count = 0; do { if (obj == set->mFree) fprintf(stderr, "%4d %p %3d %d FREE\n", count, obj, obj->gc_color, obj->obj_sizeclass); else if (obj == &set->mWhite) fprintf(stderr, "%4d %p %3d %d WHITE\n", count, obj, obj->gc_color, obj->obj_sizeclass); else if (obj == &set->mBlack) fprintf(stderr, "%4d %p %3d %d BLACK\n", count, obj, obj->gc_color, obj->obj_sizeclass); else fprintf(stderr, "%4d %p %3d %d\n", count, obj, obj->gc_color, obj->obj_sizeclass); obj = obj->next; count++; } while (obj != &set->mWhite); return false; } } // scan black list obj = set->mBlack.next; while (!IsMarker(obj)) { if (obj->gc_color != mBlackColor) { //debugf("set %d black list obj color wrong %d (%d, %d, %d) %p\n", // i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj); fprintf(stderr, "set %d black list obj color wrong %d (%d, %d, %d) %p\n", i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); return false; } if (GetGCSet(obj) != set) { //debugf("set %d black obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); fprintf(stderr, "set %d black obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); setPostFile(stderr); dumpBadObject((PyrObject*)obj); return false; } if (obj->next->prev != obj) { fprintf(stderr, "set %d black obj->next->prev != obj\n", i); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); } // scan for refs to white. if (!BlackToWhiteCheck((PyrObject*)obj)) return false; obj = obj->next; } // scan white list obj = set->mWhite.next; while (obj != set->mFree) { if (obj->gc_color != mWhiteColor) { //debugf("set %d white list obj color wrong %d (%d, %d, %d) %p\n", // i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj); //debugf("hmmm free %p black %p\n", set->mFree, set->black); fprintf(stderr, "set %d white list obj color wrong %d (%d, %d, %d) %p\n", i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj); fprintf(stderr, "hmmm free %p black %p\n", set->mFree, &set->mBlack); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); return false; } if (GetGCSet(obj) != set) { //debugf("set %d white obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); fprintf(stderr, "set %d white obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); return false; } if (obj->next->prev != obj) { fprintf(stderr, "set %d white obj->next->prev != obj\n", i); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); } obj = obj->next; } // mark all free list items free obj = set->mFree; while (!IsMarker(obj)) { /*if (obj->gc_color == mGreyColor) { //debugf("grey obj on free list\n"); fprintf(stderr, "grey obj on free list\n"); return false; }*/ //post("FREE\n"); //dumpObject((PyrObject*)(PyrObject*)obj); obj->gc_color = mFreeColor; if (GetGCSet(obj) != set) { //debugf("set %d free obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); fprintf(stderr, "set %d free obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); //dumpObject((PyrObject*)obj); return false; } if (obj->next->prev != obj) { fprintf(stderr, "set %d free obj->next->prev != obj\n", i); //dumpObject((PyrObject*)obj); } obj = obj->next; } } int numgrey = 0; PyrObjectHdr *grey = mGrey.next; while (!IsMarker(grey)) { numgrey++; if (!IsGrey(grey)) { fprintf(stderr, "sc Object on grey list not grey %d %d %d\n", grey->gc_color, mGreyColor, numgrey); fprintf(stderr, "%p <- %p -> %p grey %p process %p\n", mGrey.prev, &mGrey, mGrey.next, grey, mProcess); return false; } grey = grey->next; } if (numgrey != mNumGrey) { fprintf(stderr, "grey count off %d %d\n", numgrey, mNumGrey); DumpInfo(); fprintf(stderr, "."); return false; } return true; } bool PyrGC::LinkSanity() { //postfl("PyrGC::LinkSanity\n"); for (int i=0; imBlack; do { if (obj->next->prev != obj) { fprintf(stderr, "set %d black obj->next->prev != obj\n", i); //dumpObject((PyrObject*)obj); return false; } if (obj->prev->next != obj) { fprintf(stderr, "set %d black obj->prev->next != obj\n", i); //dumpObject((PyrObject*)obj); return false; } obj = obj->next; } while (obj != &set->mBlack); } return true; } #define DUMPINSANITY 1 bool PyrGC::BlackToWhiteCheck(PyrObject *objA) { if (objA->obj_format > obj_slot) return true; // scan it int size = objA->size; if (size > 0) { PyrSlot *slot = objA->slots; for (int j=size; j--; ++slot) { PyrObject * objB = NULL; if (IsObj(slot) && slotRawObject(slot)) { objB = slotRawObject(slot); } if (objB && (unsigned long)objB < 100) { fprintf(stderr, "weird obj ptr\n"); return false; } if (objB) { if (objA == mStack) continue; if (objA->gc_color == mBlackColor && objA != mPartialScanObj) { if (objB->gc_color == mWhiteColor) { if (objA->classptr == class_frame) { // jmc: black stack frames pointing to white nodes can be ignore PyrFrame * frameA = (PyrFrame*)objA; PyrMethod * meth = slotRawMethod(&frameA->method); PyrMethodRaw * methraw = METHRAW(meth); if (methraw->needsHeapContext) continue; } #if DUMPINSANITY fprintf(stderr, "black frame to white ref %p %p\n", objA, objB); dumpBadObject(objA); dumpBadObject(objB); fprintf(stderr, "\n"); #endif return false; } } } } } return true; } bool PyrGC::SanityMarkObj(PyrObject *objA, PyrObject *fromObj, int level) { if (objA->IsPermanent()) return true; if (objA->IsMarked()) return true; if (objA->size > MAXINDEXSIZE(objA)) { fprintf(stderr, "obj indexed size larger than max: %d > %ld\n", objA->size, MAXINDEXSIZE(objA)); //dumpObject((PyrObject*)objA); return false; } objA->SetMark(); // mark it if (!BlackToWhiteCheck(objA)) return false; if (objA->obj_format <= obj_slot) { // scan it int size = objA->size; if (size > 0) { PyrSlot *slot = objA->slots; for (int j=size; j--; ++slot) { PyrObject * objB = NULL; int tag = GetTag(slot); if (tag == tagObj && slotRawObject(slot)) objB = slotRawObject(slot); if (objB) { /* if (level > 40) { fprintf(stderr, "40 levels deep!\n"); dumpBadObject(objA); dumpBadObject(objB); return false; } */ bool err = SanityMarkObj(objB, objA, level + 1); if (!err) return false; } } } } return true; } bool PyrGC::SanityClearObj(PyrObject *objA, int level) { if (!(objA->IsMarked())) return true; if (objA->IsPermanent()) return true; objA->ClearMark(); // unmark it if (objA->obj_format <= obj_slot) { // scan it int size = objA->size; if (size > 0) { PyrSlot *slot = objA->slots; for (int j=size; j--; ++slot) { PyrObject *objB = NULL; if (IsObj(slot) && slotRawObject(slot)) { objB = slotRawObject(slot); } if (objB) { /*if (level > 40) { fprintf(stderr, "40 levels deep!\n"); dumpBadObject(objA); //dumpObject((PyrObject*)objB); //newPyrFrame return errFailed; }*/ bool err = SanityClearObj(objB, level+1); if (!err) return false; } } } } return true; } void PyrGC::DumpInfo() { int i; PyrObjectHdr *obj; int numblack, numwhite, numfree, settotal, setsiztotal; int totblack, totgrey, totwhite, totfree, totref, total, siztotal; REPORTPAUSE post("flips %d collects %d nalloc %d alloc %d grey %d\n", mFlips, mCollects, mNumAllocs, mAllocTotal, mNumGrey); totblack = 0; totgrey = 0; totwhite = 0; totfree = 0; totref = 0; total = 0; siztotal = 0; for (i=0; imBlack.next; while (!IsMarker(obj)) { numblack++; obj = obj->next; } // scan white list numwhite = 0; obj = set->mWhite.next; while (obj != set->mFree) { numwhite++; obj = obj->next; } // scan free list numfree = 0; obj = set->mFree; while (!IsMarker(obj)) { numfree++; obj = obj->next; } settotal = numblack + numwhite + numfree; setsiztotal = settotal << (i + 3); siztotal += setsiztotal; totblack += numblack; totwhite += numwhite; totfree += numfree; total += settotal; if (settotal) { post("%2d bwf t sz: %6d %6d %6d %6d %8d\n", i, numblack, numwhite, numfree, settotal, setsiztotal); } } post("tot bwf t sz: %6d %6d %6d %6d %8d\n", totblack, totwhite, totfree, total, siztotal); } void PyrGC::DumpGrey() { // scan grey list PyrObjectHdr *obj = mGrey.next; while (!IsMarker(obj)) { post("grey %s %d %d\n", slotRawSymbol(&obj->classptr->name)->name, obj->obj_sizeclass, obj->size); obj = obj->next; } } void PyrGC::DumpSet(int i) { GCSet *set = mSets + i; // scan black list PyrObjectHdr *obj = set->mBlack.next; while (!IsMarker(obj)) { post("black %s %d %d\n", slotRawSymbol(&obj->classptr->name)->name, obj->obj_sizeclass, obj->size); obj = obj->next; } // scan white list obj = set->mWhite.next; while (obj != set->mFree) { post("white %s %d %d\n", slotRawSymbol(&obj->classptr->name)->name, obj->obj_sizeclass, obj->size); obj = obj->next; } // scan free list obj = set->mFree; while (!IsMarker(obj)) { post("free %s %d %d\n", slotRawSymbol(&obj->classptr->name)->name, obj->obj_sizeclass, obj->size); obj = obj->next; } } void PyrGC::ClearMarks() { for (int i=0; imBlack.next; while (!IsMarker(obj)) { obj->ClearMark(); // unmark it obj = obj->next; } // scan grey list obj = mGrey.next; while (!IsMarker(obj)) { obj->ClearMark(); // unmark it obj = obj->next; } // scan white list obj = set->mWhite.next; while (obj != set->mFree) { obj->ClearMark(); // unmark it obj = obj->next; } // scan free list obj = set->mFree; while (!IsMarker(obj)) { obj->ClearMark(); // unmark it obj = obj->next; } } } void PyrGC::throwMemfailed(size_t inNumBytes) { post("alloc failed. size = %d\n", inNumBytes); MEMFAILED; } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/SC_TerminalClient.cpp0000664000000000000000000004457512245365552025777 0ustar rootroot/* Commandline interpreter interface. Copyright (c) 2003-2006 stefan kersten. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_TerminalClient.h" #include #include #ifdef SC_WIN32 # define __GNU_LIBRARY__ # include "getopt.h" # include "SC_Win32Utils.h" # include # include #else # include # include # include #endif #ifdef HAVE_READLINE # include # include # include #endif #include #include #include "GC.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrLexer.h" #include "PyrSlot.h" #include "VMGlobals.h" #include "SC_DirUtils.h" // for gIdeName #include "SC_LanguageConfig.hpp" #define STDIN_FD 0 static FILE* gPostDest = stdout; static const int ticks_per_second = 50; // every 20 milliseconds SC_TerminalClient::SC_TerminalClient(const char* name) : SC_LanguageClient(name), mShouldBeRunning(false), mReturnCode(0), mUseReadline(false), mSignals(0) { pthread_cond_init (&mCond, NULL); pthread_mutex_init(&mSignalMutex, NULL); pthread_mutex_init(&mInputMutex, NULL); pthread_cond_init(&mInputCond, NULL); } SC_TerminalClient::~SC_TerminalClient() { pthread_cond_destroy (&mCond); pthread_mutex_destroy(&mSignalMutex); pthread_mutex_destroy(&mInputMutex); pthread_cond_destroy(&mInputCond); } void SC_TerminalClient::postText(const char* str, size_t len) { fwrite(str, sizeof(char), len, gPostDest); } void SC_TerminalClient::postFlush(const char* str, size_t len) { fwrite(str, sizeof(char), len, gPostDest); fflush(gPostDest); } void SC_TerminalClient::postError(const char* str, size_t len) { fprintf(gPostDest, "ERROR: "); fwrite(str, sizeof(char), len, gPostDest); } void SC_TerminalClient::flush() { fflush(gPostDest); } void SC_TerminalClient::printUsage() { Options opt; const size_t bufSize = 128; char memGrowBuf[bufSize]; char memSpaceBuf[bufSize]; snprintMemArg(memGrowBuf, bufSize, opt.mMemGrow); snprintMemArg(memSpaceBuf, bufSize, opt.mMemSpace); fprintf(stdout, "Usage:\n %s [options] [file..] [-]\n\n", getName()); fprintf(stdout, "Options:\n" " -d Set runtime directory\n" " -D Enter daemon mode (no input)\n" " -g [km] Set heap growth (default %s)\n" " -h Display this message and exit\n" " -l Set library configuration file\n" " -m [km] Set initial heap size (default %s)\n" " -r Call Main.run on startup\n" " -s Call Main.stop on shutdown\n" " -u Set UDP listening port (default %d)\n" " -i Specify IDE name (for enabling IDE-specific class code, default \"%s\")\n", memGrowBuf, memSpaceBuf, opt.mPort, gIdeName ); } bool SC_TerminalClient::parseOptions(int& argc, char**& argv, Options& opt) { const char* optstr = ":d:Dg:hl:m:rsu:i:"; int c; // inhibit error reporting opterr = 0; while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { case 'd': opt.mRuntimeDir = optarg; break; case 'D': opt.mDaemon = true; break; case 'g': if (!parseMemArg(optarg, &opt.mMemGrow)) { optopt = c; goto optArgInvalid; } break; case 'h': goto help; case 'l': opt.mLibraryConfigFile = optarg; break; case 'm': if (!parseMemArg(optarg, &opt.mMemSpace)) { optopt = c; goto optArgInvalid; } break; case 'r': opt.mCallRun = true; break; case 's': opt.mCallStop = true; break; case 'u': if (!parsePortArg(optarg, &opt.mPort)) { optopt = c; goto optArgInvalid; } break; case '?': goto optInvalid; break; case ':': goto optArgExpected; break; case 'i': gIdeName = optarg; break; default: ::post("%s: unknown error (getopt)\n", getName()); quit(255); return false; } } argv += optind; argc -= optind; return true; help: printUsage(); quit(0); return false; optInvalid: ::post("%s: invalid option -%c\n", getName(), optopt); quit(1); return false; optArgExpected: ::post("%s: missing argument for option -%c\n", getName(), optopt); quit(1); return false; optArgInvalid: ::post("%s: invalid argument for option -%c -- %s\n", getName(), optopt, optarg); quit(1); return false; } int SC_TerminalClient::run(int argc, char** argv) { Options& opt = mOptions; if (!parseOptions(argc, argv, opt)) { return mReturnCode; } // finish argv processing const char* codeFile = 0; if (argc > 0) { codeFile = argv[0]; opt.mDaemon = true; argv++; argc--; } opt.mArgc = argc; opt.mArgv = argv; // read library configuration file if (opt.mLibraryConfigFile) SC_LanguageConfig::setConfigFile(opt.mLibraryConfigFile); SC_LanguageConfig::readLibraryConfig(); // initialize runtime initRuntime(opt); // startup library mShouldBeRunning = true; compileLibrary(); // enter main loop if (codeFile) executeFile(codeFile); if (opt.mCallRun) runMain(); if (opt.mDaemon) { daemonLoop(); } else { initInput(); if( shouldBeRunning() ) startInput(); if( shouldBeRunning() ) commandLoop(); endInput(); cleanupInput(); } if (opt.mCallStop) stopMain(); // shutdown library shutdownLibrary(); flush(); shutdownRuntime(); return mReturnCode; } void SC_TerminalClient::quit(int code) { mReturnCode = code; mShouldBeRunning = false; } void SC_TerminalClient::interpretCmdLine(PyrSymbol* method, SC_StringBuffer& cmdLine) { setCmdLine(cmdLine); cmdLine.reset(); runLibrary(method); flush(); } void SC_TerminalClient::interpretCmdLine(PyrSymbol* method, const char* cmdLine) { setCmdLine(cmdLine); runLibrary(method); flush(); } void SC_TerminalClient::interpretCmdLine(PyrSymbol* method, const char *cmdLine, size_t size) { setCmdLine(cmdLine, size); runLibrary(method); flush(); } // WARNING: Call with input locked! void SC_TerminalClient::interpretInput() { char *data = mInputBuf.getData(); int c = mInputBuf.getSize(); int i = 0; while( i < c ) { switch (data[i]) { case kInterpretCmdLine: interpretCmdLine(s_interpretCmdLine, data, i); break; case kInterpretPrintCmdLine: interpretCmdLine(s_interpretPrintCmdLine, data, i); break; case kRecompileLibrary: recompileLibrary(); break; default: ++i; continue; } data += i+1; c -= i+1; i = 0; } mInputBuf.reset(); if( mUseReadline ) pthread_cond_signal( &mInputCond ); } void SC_TerminalClient::onLibraryStartup() { SC_LanguageClient::onLibraryStartup(); int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_Argv", &SC_TerminalClient::prArgv, 1, 0); definePrimitive(base, index++, "_Exit", &SC_TerminalClient::prExit, 1, 0); definePrimitive(base, index++, "_AppClock_SchedNotify", &SC_TerminalClient::prScheduleChanged, 1, 0); definePrimitive(base, index++, "_Recompile", &SC_TerminalClient::prRecompile, 1, 0); } void SC_TerminalClient::sendSignal( Signal sig ) { lockSignal(); mSignals |= sig; pthread_cond_signal( &mCond ); unlockSignal(); } void SC_TerminalClient::onQuit( int exitCode ) { lockSignal(); postfl("main: quit request %i\n", exitCode); quit( exitCode ); pthread_cond_signal( &mCond ); unlockSignal(); } extern void ElapsedTimeToTimespec(double elapsed, struct timespec *spec); void SC_TerminalClient::commandLoop() { bool haveNext = false; struct timespec nextAbsTime; lockSignal(); while( shouldBeRunning() ) { while ( mSignals ) { int sig = mSignals; mSignals = 0; unlockSignal(); if (sig & sig_input) { //postfl("input\n"); lockInput(); interpretInput(); unlockInput(); } if (sig & sig_sched) { //postfl("tick\n"); double secs; lock(); haveNext = tickLocked( &secs ); unlock(); flush(); //postfl("tick -> next time = %f\n", haveNext ? secs : -1); ElapsedTimeToTimespec( secs, &nextAbsTime ); } if (sig & sig_stop) { stopMain(); } if (sig & sig_recompile) { recompileLibrary(); } lockSignal(); } if( !shouldBeRunning() ) { break; } else if( haveNext ) { int result = pthread_cond_timedwait( &mCond, &mSignalMutex, &nextAbsTime ); if( result == ETIMEDOUT ) mSignals |= sig_sched; } else { pthread_cond_wait( &mCond, &mSignalMutex ); } } unlockSignal(); } void SC_TerminalClient::daemonLoop() { commandLoop(); } #ifdef HAVE_READLINE static void sc_rl_cleanlf(void) { rl_reset_line_state(); rl_crlf(); rl_redisplay(); } static void sc_rl_signalhandler(int sig) { // ensure ctrl-C clears line rather than quitting (ctrl-D will quit nicely) rl_replace_line("", 0); sc_rl_cleanlf(); } static int sc_rl_mainstop(int i1, int i2) { static_cast(SC_LanguageClient::instance()) ->sendSignal( SC_TerminalClient::sig_stop ); sc_rl_cleanlf(); // We also push a newline so that there's some UI feedback return 0; } /* // Completion from sclang dictionary TODO char ** sc_rl_completion (const char *text, int start, int end); char ** sc_rl_completion (const char *text, int start, int end){ char **matches = (char **)NULL; printf("sc_rl_completion(%s, %i, %i)\n", text, start, end); return matches; } */ int SC_TerminalClient::readlineRecompile(int i1, int i2) { static_cast(SC_LanguageClient::instance())->sendSignal(sig_recompile); sc_rl_cleanlf(); return 0; } void SC_TerminalClient::readlineCmdLine( char *cmdLine ) { SC_TerminalClient *client = static_cast(instance()); if( cmdLine == NULL ) { postfl("\nExiting sclang (ctrl-D)\n"); client->onQuit(0); return; } if(*cmdLine!=0){ // If line wasn't empty, store it so that uparrow retrieves it add_history(cmdLine); int len = strlen(cmdLine); client->lockInput(); client->mInputBuf.append(cmdLine, len); client->mInputBuf.append(kInterpretPrintCmdLine); client->sendSignal(sig_input); // Wait for input to be processed, // so that its output is displayed before readline prompt. if (client->mInputShouldBeRunning) pthread_cond_wait( &client->mInputCond, &client->mInputMutex ); client->unlockInput(); } } void SC_TerminalClient::readlineInit() { // Setup readline rl_readline_name = "sclang"; rl_basic_word_break_characters = " \t\n\"\\'`@><=;|&{}()."; //rl_attempted_completion_function = sc_rl_completion; rl_bind_key(CTRL('t'), &sc_rl_mainstop); rl_bind_key(CTRL('x'), &readlineRecompile); rl_callback_handler_install( "sc3> ", &readlineCmdLine ); // FIXME: Implement the code below on Windows #ifndef _WIN32 // Set our handler for SIGINT that will clear the line instead of terminating. // NOTE: We prevent readline from setting its own signal handlers, // to not override ours. rl_catch_signals = 0; struct sigaction sact; memset( &sact, 0, sizeof(struct sigaction) ); sact.sa_handler = &sc_rl_signalhandler; sigaction( SIGINT, &sact, 0 ); #endif } #ifndef _WIN32 void *SC_TerminalClient::readlineFunc( void *arg ) { readlineInit(); SC_TerminalClient *client = static_cast(arg); fd_set fds; FD_ZERO(&fds); while(true) { FD_SET(STDIN_FD, &fds); FD_SET(client->mInputCtlPipe[0], &fds); if( select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0 ) { if( errno == EINTR ) continue; postfl("readline: select() error:\n%s\n", strerror(errno)); client->onQuit(1); break; } if( FD_ISSET(client->mInputCtlPipe[0], &fds) ) { postfl("readline: quit requested\n"); break; } if( FD_ISSET(STDIN_FD, &fds) ) { rl_callback_read_char(); } } postfl("readline: stopped.\n"); return NULL; } #else void *SC_TerminalClient::readlineFunc( void *arg ) { readlineInit(); SC_TerminalClient *client = static_cast(arg); HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); HANDLE hnds[] = { client->mQuitInputEvent, hStdIn }; bool shouldRun = true; while (shouldRun) { DWORD result = WaitForMultipleObjects( 2, hnds, false, INFINITE ); if( result == WAIT_FAILED ) { postfl("readline: wait error.\n"); client->onQuit(1); break; } int hIndex = result - WAIT_OBJECT_0; if( hIndex == 0 ) { postfl("readline: quit requested.\n"); break; } if( hIndex == 1 ) { rl_callback_read_char(); } } postfl("readline: stopped.\n"); return NULL; } #endif // !_WIN32 #endif // HAVE_READLINE #ifndef _WIN32 void *SC_TerminalClient::pipeFunc( void *arg ) { SC_TerminalClient *client = static_cast(arg); ssize_t bytes; const size_t toRead = 256; char buf[toRead]; SC_StringBuffer stack; fd_set fds; FD_ZERO(&fds); bool shouldRead = true; while(shouldRead) { FD_SET(STDIN_FD, &fds); FD_SET(client->mInputCtlPipe[0], &fds); if( select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0 ) { if( errno == EINTR ) continue; postfl("pipe-in: select() error: %s\n", strerror(errno)); client->onQuit(1); break; } if( FD_ISSET(client->mInputCtlPipe[0], &fds) ) { postfl("pipe-in: quit requested\n"); break; } if( FD_ISSET(STDIN_FD, &fds) ) { while(true) { bytes = read( STDIN_FD, buf, toRead ); if( bytes > 0 ) { client->pushCmdLine( stack, buf, bytes ); } else if( bytes == 0 ) { postfl("pipe-in: EOF. Will quit.\n"); client->onQuit(0); shouldRead = false; break; } else { if( errno == EAGAIN ) { break; // no more to read this time; } else if( errno != EINTR ){ postfl("pipe-in: read() error: %s\n", strerror(errno)); client->onQuit(1); shouldRead = false; break; } } } } } postfl("pipe-in: stopped.\n"); return NULL; } #else void *SC_TerminalClient::pipeFunc( void *arg ) { SC_TerminalClient *client = static_cast(arg); SC_StringBuffer stack; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); char buf[256]; while(1) { DWORD n; BOOL ok = ReadFile( hStdIn, &buf, 256, &n, NULL ); if(ok) { client->pushCmdLine( stack, buf, n ); } else { postfl("pipe-in: ERROR (ReadFile): %i\n", GetLastError()); client->onQuit(1); break; } } return NULL; } #endif void SC_TerminalClient::pushCmdLine( SC_StringBuffer &buf, const char *newData, size_t size) { lockInput(); bool signal = false; while (size--) { char c = *newData++; switch (c) { case kRecompileLibrary: case kInterpretCmdLine: case kInterpretPrintCmdLine: mInputBuf.append( buf.getData(), buf.getSize() ); mInputBuf.append(c); signal = true; buf.reset(); break; default: buf.append(c); } } if(signal) sendSignal(sig_input); unlockInput(); } void SC_TerminalClient::initInput() { #ifndef _WIN32 if( pipe( mInputCtlPipe ) == -1 ) { postfl("Error creating pipe for input thread control:\n%s\n", strerror(errno)); quit(1); } #else mQuitInputEvent = CreateEvent( NULL, false, false, NULL ); if( mQuitInputEvent == NULL ) { postfl("Error creating event for input thread control.\n"); quit(1); } #endif #ifdef HAVE_READLINE if (strcmp(gIdeName, "none") == 0) { // Other clients (emacs, vim, ...) won't want to interact through rl mUseReadline = true; return; } #endif #ifndef _WIN32 if( fcntl( STDIN_FD, F_SETFL, O_NONBLOCK ) == -1 ) { postfl("Error setting up non-blocking pipe reading:\n%s\n", strerror(errno)); quit(1); } #endif // !_WIN32 } void SC_TerminalClient::startInput() { mInputShouldBeRunning = true; #ifdef HAVE_READLINE if( mUseReadline ) pthread_create( &mInputThread, NULL, &SC_TerminalClient::readlineFunc, this ); else #endif pthread_create( &mInputThread, NULL, &SC_TerminalClient::pipeFunc, this ); } void SC_TerminalClient::endInput() { // NOTE: On Windows, there is no way to safely interrupt // the pipe-reading thread. So just quit and let it die. #ifdef _WIN32 if (mUseReadline) { #endif // wake up the input thread in case it is waiting // for input to be processed lockInput(); mInputShouldBeRunning = false; pthread_cond_signal( &mInputCond ); unlockInput(); #ifndef _WIN32 char c = 'q'; ssize_t bytes = write( mInputCtlPipe[1], &c, 1 ); if( bytes < 1 ) postfl("WARNING: could not send quit command to input thread.\n"); #else SetEvent( mQuitInputEvent ); #endif postfl("main: waiting for input thread to join...\n"); pthread_join( mInputThread, NULL ); #ifdef _WIN32 } // if (mUseReadline) #endif postfl("main: quitting...\n"); } void SC_TerminalClient::cleanupInput() { #ifdef HAVE_READLINE if( mUseReadline ) rl_callback_handler_remove(); #endif } int SC_TerminalClient::prArgv(struct VMGlobals* g, int) { int argc = ((SC_TerminalClient*)SC_TerminalClient::instance())->options().mArgc; char** argv = ((SC_TerminalClient*)SC_TerminalClient::instance())->options().mArgv; PyrSlot* argvSlot = g->sp; PyrObject* argvObj = newPyrArray(g->gc, argc * sizeof(PyrObject), 0, true); SetObject(argvSlot, argvObj); for (int i=0; i < argc; i++) { PyrString* str = newPyrString(g->gc, argv[i], 0, true); SetObject(argvObj->slots+i, str); argvObj->size++; g->gc->GCWrite(argvObj, (PyrObject*)str); } return errNone; } int SC_TerminalClient::prExit(struct VMGlobals* g, int) { int code; int err = slotIntVal(g->sp, &code); if (err) return err; ((SC_TerminalClient*)SC_LanguageClient::instance())->onQuit( code ); return errNone; } int SC_TerminalClient::prScheduleChanged( struct VMGlobals *g, int numArgsPushed) { static_cast(instance())->sendSignal(sig_sched); return errNone; } int SC_TerminalClient::prRecompile(struct VMGlobals *, int) { static_cast(instance())->sendSignal(sig_recompile); return errNone; } // EOF SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/PyrLexer.cpp0000664000000000000000000014222412245365552024240 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #ifdef SC_WIN32 # include #else # include #endif #include #include "PyrParseNode.h" #include "Bison/lang11d_tab.h" #include "SCBase.h" #include "PyrObject.h" #include "PyrObjectProto.h" #include "PyrLexer.h" #include "PyrSched.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "GC.h" #include "SimpleStack.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "InitAlloc.h" #include "PredefinedSymbols.h" #ifdef SC_WIN32 #else # include "dirent.h" #endif #include #include "SC_LanguageConfig.hpp" #include "SC_DirUtils.h" #include "SC_TextUtils.hpp" int yyparse(); int processaccidental1(char *s); int processaccidental2(char *s); extern bool gFullyFunctional; double compileStartTime; int gNumCompiledFiles; /* thisProcess.interpreter.executeFile("Macintosh HD:score").size.postln; */ PyrSymbol *gCompilingFileSym = 0; VMGlobals *gCompilingVMGlobals = 0; static char gCompileDir[MAXPATHLEN]; //#define DEBUGLEX 1 bool gDebugLexer = false; bool gShowWarnings = false; LongStack brackets; LongStack closedFuncCharNo; LongStack generatorStack; int lastClosedFuncCharNo = 0; const char *binopchars = "!@%&*-+=|<>?/"; char yytext[MAXYYLEN]; char curfilename[PATH_MAX]; int yylen; int lexCmdLine = 0; bool compilingCmdLine = false; bool compilingCmdLineErrorWindow = false; long zzval; int lineno, charno, linepos; int *linestarts; int maxlinestarts; char *text; int textlen; int textpos; int errLineOffset, errCharPosOffset; int parseFailed = 0; bool compiledOK = false; std::set compiledDirectories; /* so the text editor's dumb paren matching will work */ #define OPENPAREN '(' #define OPENCURLY '{' #define OPENSQUAR '[' #define CLOSSQUAR ']' #define CLOSCURLY '}' #define CLOSPAREN ')' int sc_strtoi(const char *str, int n, int base) { int z = 0; for (int i=0; i= '0' && c <= '0' + sc_min(10,base) - 1) z = z * base + c - '0'; else if (c >= 'a' && c <= 'a' + sc_min(36,base) - 11) z = z * base + c - 'a' + 10; else if (c >= 'A' && c <= 'A' + sc_min(36,base) - 11) z = z * base + c - 'A' + 10; } return z; } double sc_strtof(const char *str, int n, int base) { double z = 0.; int decptpos = 0; for (int i=0; i= '0' && c <= '0' + sc_min(10,base) - 1) z = z * base + c - '0'; else if (c >= 'a' && c <= 'a' + sc_min(36,base) - 11) z = z * base + c - 'a' + 10; else if (c >= 'A' && c <= 'A' + sc_min(36,base) - 11) z = z * base + c - 'A' + 10; else if (c == '.') decptpos = i; } //calculation previously included decimal point in count of columns (was n-decptpos); there are 1 less than n characters which are columns in the number contribution z = z / pow((double)base, n -1- decptpos); return z; } static void sc_InitCompileDirectory(void) { // main class library folder: only used for relative path resolution sc_GetResourceDirectory(gCompileDir, MAXPATHLEN-32); sc_AppendToPath(gCompileDir, MAXPATHLEN, "SCClassLibrary"); } extern void asRelativePath(char *inPath, char *outPath) { uint32 len = strlen(gCompileDir); if (strlen(inPath) < len || memcmp(inPath, gCompileDir, len) != 0) { // gCompileDir is not the prefix. strcpy(outPath, inPath); return; } strcpy(outPath, inPath + len); } static bool getFileText(char* filename, char **text, int *length) { FILE *file; char *ltext; int llength; #ifdef SC_WIN32 file = fopen(filename, "rb"); #else file = fopen(filename, "r"); #endif if (!file) return false; fseek(file, 0L, SEEK_END); llength = ftell(file); fseek(file, 0L, SEEK_SET); ltext = (char*)pyr_pool_compile->Alloc((llength+1) * sizeof(char)); #ifdef SC_WIN32 // win32 isprint( ) doesn't like the 0xcd after the end of file when // there is a mismatch in lengths due to line endings.... memset(ltext,0,(llength+1) * sizeof(char)); #endif //SC_WIN32 MEMFAIL(ltext); size_t size = fread(ltext, 1, llength, file); if (size != llength) { error("error when reading file"); fclose(file); return false; } ltext[llength] = 0; //ltext[llength] = 0; *length = llength; fclose(file); *text = ltext; return true; } int bugctr = 0; bool startLexer(PyrSymbol *fileSym, int startPos, int endPos, int lineOffset) { char *filename = fileSym->name; textlen = -1; if(!fileSym->u.source) { if (!getFileText(filename, &text, &textlen)) return false; fileSym->u.source = text; rtf2txt(text); } else text = fileSym->u.source; if((startPos >= 0) && (endPos > 0)) { textlen = endPos - startPos; text += startPos; } else if(textlen == -1) textlen = strlen(text); if(lineOffset > 0) errLineOffset = lineOffset; else errLineOffset = 0; if(startPos > 0) errCharPosOffset = startPos; else errCharPosOffset = 0; initLongStack(&brackets); initLongStack(&closedFuncCharNo); initLongStack(&generatorStack); lastClosedFuncCharNo = 0; textpos = 0; linepos = 0; lineno = 1; charno = 0; yylen = 0; zzval = 0; parseFailed = 0; lexCmdLine = 0; strcpy(curfilename, filename); maxlinestarts = 1000; linestarts = (int*)pyr_pool_compile->Alloc(maxlinestarts * sizeof(int*)); linestarts[0] = 0; linestarts[1] = 0; return true; } void startLexerCmdLine(char *textbuf, int textbuflen) { // pyrmalloc: // lifetime: kill after compile. (this one gets killed anyway) text = (char*)pyr_pool_compile->Alloc((textbuflen+2) * sizeof(char)); MEMFAIL(text); memcpy(text, textbuf, textbuflen); text[textbuflen] = ' '; text[textbuflen+1] = 0; textlen = textbuflen + 1; rtf2txt(text); initLongStack(&brackets); initLongStack(&closedFuncCharNo); initLongStack(&generatorStack); lastClosedFuncCharNo = 0; textpos = 0; linepos = 0; lineno = 1; charno = 0; yylen = 0; zzval = 0; parseFailed = 0; lexCmdLine = 1; strcpy(curfilename, "selected text"); maxlinestarts = 1000; linestarts = (int*)pyr_pool_compile->Alloc(maxlinestarts * sizeof(int*)); linestarts[0] = 0; linestarts[1] = 0; errLineOffset = 0; errCharPosOffset = 0; } void finiLexer() { pyr_pool_compile->Free(linestarts); freeLongStack(&brackets); freeLongStack(&closedFuncCharNo); freeLongStack(&generatorStack); } void initLexer() { //strcpy(binopchars, "!@%&*-+=|:<>?/"); } int input() { int c; if (textpos >= textlen) { c = 0; } else { c = text[textpos++]; charno++; } if (c == '\n' || c == '\r') { lineno++; linepos = textpos; if (linestarts) { if (lineno >= maxlinestarts) { maxlinestarts += maxlinestarts; linestarts = (int*)pyr_pool_compile->Realloc( linestarts, maxlinestarts * sizeof(int*)); } linestarts[lineno] = linepos; } charno = 0; } if (c != 0 && yylen < MAXYYLEN-2) yytext[yylen++] = c; //if (gDebugLexer) postfl("input '%c' %d\n",c,c); return c; } int input0() { int c; if (textpos >= textlen) { c = 0; textpos++; // so unput will work properly } else { c = text[textpos++]; charno++; } if (c == '\n' || c == '\r') { lineno++; linepos = textpos; if (linestarts) { if (lineno >= maxlinestarts) { maxlinestarts += maxlinestarts; linestarts = (int*)pyr_pool_compile->Realloc( linestarts, maxlinestarts * sizeof(int*)); } linestarts[lineno] = linepos; } charno = 0; } //if (gDebugLexer) postfl("input0 '%c' %d\n",c,c); return c; } void unput(int c) { if (textpos>0) textpos--; if (c) { if (yylen) --yylen; if (charno) --charno; if (c == '\n' || c == '\r') { --lineno; } } } void unput0(int c) { if (textpos>0) textpos--; if (charno) --charno; if (c == '\n' || c == '\r') { --lineno; } } int yylex() { int r, c, c2, d; int radix; char extPath[MAXPATHLEN]; // for error reporting yylen = 0; // finite state machine to parse input stream into tokens if (lexCmdLine == 1) { lexCmdLine = 2; r = INTERPRET; goto leave; } start: c = input(); if (c == 0) { r = 0; goto leave; } else if (c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f') { yylen = 0; goto start; } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') goto ident; else if (c == '/') { c = input(); if (c == '/') goto comment1; else if (c == '*') goto comment2; else { unput(c); goto binop; } } else if (c >= '0' && c <= '9') goto digits_1; else if (c == OPENPAREN || c == OPENSQUAR || c == OPENCURLY) { pushls(&brackets, (int)c); if (c == OPENCURLY) { pushls(&closedFuncCharNo, linestarts[lineno] + charno - 1); } r = c; goto leave; } else if (c == CLOSSQUAR) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != OPENSQUAR) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error2; } } else { fatal(); post("unmatched '%c'\n",c); goto error2; } r = c; goto leave; } else if (c == CLOSPAREN) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != OPENPAREN) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error2; } } else { fatal(); post("unmatched '%c'\n",c); goto error2; } r = c; goto leave; } else if (c == CLOSCURLY) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != OPENCURLY) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error2; } lastClosedFuncCharNo = popls(&closedFuncCharNo); } else { fatal(); post("unmatched '%c'\n",c); goto error2; } r = c; goto leave; } else if (c == '^') { r = c; goto leave; } else if (c == '~') { r = c; goto leave; } else if (c == ';') { r = c; goto leave; } else if (c == ':') { r = c; goto leave; } else if (c == '`') { r = c; goto leave; } else if (c == '\\') goto symbol1; else if (c == '\'') goto symbol3; else if (c == '"') goto string1; else if (c == '.') { if ((c = input()) == '.') { if ((c = input()) == '.') { r = ELLIPSIS; goto leave; } else { r = DOTDOT; unput(c); goto leave; } } else { unput(c); r = '.'; goto leave; } } else if (c == '#') { if ((c = input()) == OPENCURLY) { pushls(&brackets, OPENCURLY); pushls(&closedFuncCharNo, linestarts[lineno] + charno - 2); r = BEGINCLOSEDFUNC; } else { unput(c); r = '#'; } goto leave; } else if (c == '$') { c = input(); if (c == '\\') { c = input(); switch (c) { case 'n' : c = '\n'; break; case 'r' : c = '\r'; break; case 't' : c = '\t'; break; case 'f' : c = '\f'; break; case 'v' : c = '\v'; break; } } r = processchar(c); goto leave; } else if (c == ',') { r = c; goto leave; } else if (c == '=') { c = input(); if (strchr(binopchars, c)) goto binop; else { unput(c); r = '='; goto leave; } } else if (strchr(binopchars, c)) goto binop; else if(!(isprint(c) || isspace(c) || c == 0)) { yylen = 0; goto start; } else goto error1; ident: c = input(); if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) goto ident; else if (c == ':') { yytext[yylen] = 0; r = processkeywordbinop(yytext) ; goto leave; } else { unput(c); yytext[yylen] = 0; r = processident(yytext) ; goto leave; } symbol1: c = input(); if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') goto symbol2; else if (c >= '0' && c <= '9') goto symbol4; else { unput(c); yytext[yylen] = 0; r = processsymbol(yytext) ; goto leave; } symbol2: c = input(); if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) goto symbol2; else { unput(c); yytext[yylen] = 0; r = processsymbol(yytext) ; goto leave; } symbol4: c = input(); if (c >= '0' && c <= '9') goto symbol4; else { unput(c); yytext[yylen] = 0; r = processsymbol(yytext) ; goto leave; } binop: c = input(); if (c == 0) goto binop2; if (strchr(binopchars, c)) goto binop; else { binop2: unput(c); yytext[yylen] = 0; r = processbinop(yytext) ; goto leave; } radix_digits_1: c = input(); if (c >= '0' && c <= '0' + sc_min(10,radix) - 1) goto radix_digits_1; if (c >= 'a' && c <= 'a' + sc_min(36,radix) - 11) goto radix_digits_1; if (c >= 'A' && c <= 'A' + sc_min(36,radix) - 11) goto radix_digits_1; if (c == '.') { goto radix_digits_2; } unput(c); yytext[yylen] = 0; r = processintradix(yytext, yylen, radix); goto leave; radix_digits_2: c = input(); if (c >= '0' && c <= '0' + sc_min(10,radix) - 1) goto radix_digits_2; if (c >= 'A' && c <= 'A' + sc_min(36,radix) - 11) goto radix_digits_2; // do not allow lower case after decimal point. unput(c); yytext[yylen] = 0; r = processfloatradix(yytext, yylen, radix); goto leave; hexdigits: c = input(); if (c >= '0' && c <= '9') goto hexdigits; if (c >= 'a' && c <= 'f') goto hexdigits; if (c >= 'A' && c <= 'F') goto hexdigits; unput(c); yytext[yylen] = 0; r = processhex(yytext); goto leave; digits_1: /* number started with digits */ c = input(); if (c >= '0' && c <= '9') goto digits_1; else if (c == 'r') { radix = sc_strtoi(yytext, yylen-1, 10); yylen = 0; goto radix_digits_1; } else if (c == 'e' || c == 'E') goto expon_1; else if (c == '.') { c2 = input(); if (c2 >= '0' && c2 <= '9') goto digits_2; else { unput(c2); unput(c); yytext[yylen] = 0; r = processint(yytext); goto leave; } } else if (c == 'b' || c == 's') { d = input(); if (d >= '0' && d <= '9') goto accidental1; if (d == c) goto accidental2; goto accidental3; accidental1: d = input(); if (d >= '0' && d <= '9') goto accidental1; unput(d); yytext[yylen] = 0; r = processaccidental1(yytext); goto leave; accidental2: d = input(); if (d == c) goto accidental2; accidental3: unput(d); yytext[yylen] = 0; r = processaccidental2(yytext); goto leave; } else if (c == 'x') { yylen = 0; goto hexdigits; } else { unput(c); yytext[yylen] = 0; r = processint(yytext); goto leave; } digits_2: c = input(); if (c >= '0' && c <= '9') goto digits_2; else if (c == 'e' || c == 'E') goto expon_1; // else if (c == 'π' || c == '∏') { // --yylen; // yytext[yylen] = 0; // r = processfloat(yytext, 1); // goto leave; // } else { unput(c); yytext[yylen] = 0; r = processfloat(yytext, 0); goto leave; } expon_1: /* e has been seen, need digits */ c = input(); if (c >= '0' && c <= '9') goto expon_3; else if (c == '+' || c == '-') goto expon_2; else goto error1; expon_2: /* + or - seen but still need digits */ c = input(); if (c >= '0' && c <= '9') goto expon_3; else goto error1; expon_3: c = input(); if (c >= '0' && c <= '9') goto expon_3; // else if (c == 'π' || c == '∏') { // --yylen; // yytext[yylen] = 0; // r = processfloat(yytext, 1); // goto leave; // } else { unput(c); yytext[yylen] = 0; r = processfloat(yytext, 0); goto leave; } symbol3 : { int startline, endchar; startline = lineno; endchar = '\''; /*do { c = input(); } while (c != endchar && c != 0);*/ for (;yylen0) postfl("yylex: %d '%s'\n",r,yytext); return r; } int processbinop(char *token) { PyrSymbol *sym; PyrSlot slot; PyrSlotNode *node; #if DEBUGLEX if (gDebugLexer) postfl("processbinop: '%s'\n",token); #endif sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (long)node; if (strcmp(token, "<-")==0) return LEFTARROW; if (strcmp(token, "<>")==0) return READWRITEVAR; if (strcmp(token, "|")==0) return '|'; if (strcmp(token, "<")==0) return '<'; if (strcmp(token, ">")==0) return '>'; if (strcmp(token, "-")==0) return '-'; if (strcmp(token, "*")==0) return '*'; if (strcmp(token, "+")==0) return '+'; return BINOP; } int processkeywordbinop(char *token) { PyrSymbol *sym; PyrSlot slot; PyrSlotNode *node; //post("'%s' file '%s'\n", token, curfilename); #if DEBUGLEX if (gDebugLexer) postfl("processkeywordbinop: '%s'\n",token); #endif token[strlen(token)-1] = 0; // strip off colon sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (long)node; return KEYBINOP; } int processident(char *token) { char c; PyrSymbol *sym; PyrSlot slot; PyrParseNode *node; c = token[0]; zzval = -1; #if DEBUGLEX if (gDebugLexer) postfl("word: '%s'\n",token); #endif /* strcpy(uptoken, token); for (str = uptoken; *str; ++str) { if (*str >= 'a' && *str <= 'z') *str += 'A' - 'a'; }*/ if (token[0] == '_') { if (token[1] == 0) { node = newPyrCurryArgNode(); zzval = (long)node; return CURRYARG; } else { sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (long)node; return PRIMITIVENAME; } } if (token[0] >= 'A' && token[0] <= 'Z') { sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (long)node; #if DEBUGLEX if (gDebugLexer) postfl("CLASSNAME: '%s'\n",token); #endif return CLASSNAME; } if (strcmp("var",token) ==0) return VAR; if (strcmp("arg",token) ==0) return ARG; if (strcmp("classvar",token) ==0) return CLASSVAR; if (strcmp("const",token) ==0) return SC_CONST; if (strcmp("while",token) ==0) { sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (long)node; return WHILE; } if (strcmp("pi",token) ==0) { SetFloat(&slot, pi); node = newPyrSlotNode(&slot); zzval = (long)node; return PIE; } if (strcmp("true",token) ==0) { SetTrue(&slot); node = newPyrSlotNode(&slot); zzval = (long)node; return TRUEOBJ; } if (strcmp("false",token) ==0) { SetFalse(&slot); node = newPyrSlotNode(&slot); zzval = (long)node; return FALSEOBJ; } if (strcmp("nil",token) ==0) { SetNil(&slot); node = newPyrSlotNode(&slot); zzval = (long)node; return NILOBJ; } if (strcmp("inf",token) ==0) { SetFloat(&slot, std::numeric_limits::infinity()); node = newPyrSlotNode(&slot); zzval = (long)node; return SC_FLOAT; } sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (long)node; return NAME; } int processhex(char *s) { PyrSlot slot; PyrSlotNode *node; char *c; int val; #if DEBUGLEX if (gDebugLexer) postfl("processhex: '%s'\n",s); #endif c = s; val = 0; while (*c) { if (*c >= '0' && *c <= '9') val = val*16 + *c - '0'; else if (*c >= 'a' && *c <= 'z') val = val*16 + *c - 'a' + 10; else if (*c >= 'A' && *c <= 'Z') val = val*16 + *c - 'A' + 10; c++; } SetInt(&slot, val); node = newPyrSlotNode(&slot); zzval = (long)node; return INTEGER; } int processintradix(char *s, int n, int radix) { PyrSlot slot; PyrSlotNode *node; #if DEBUGLEX if (gDebugLexer) postfl("processintradix: '%s'\n",s); #endif SetInt(&slot, sc_strtoi(s, n, radix)); node = newPyrSlotNode(&slot); zzval = (long)node; return INTEGER; } int processfloatradix(char *s, int n, int radix) { PyrSlot slot; PyrSlotNode *node; #if DEBUGLEX if (gDebugLexer) postfl("processfloatradix: '%s'\n",s); #endif SetFloat(&slot, sc_strtof(s, n, radix)); node = newPyrSlotNode(&slot); zzval = (long)node; return INTEGER; } int processint(char *s) { PyrSlot slot; PyrSlotNode *node; #if DEBUGLEX if (gDebugLexer) postfl("processint: '%s'\n",s); #endif SetInt(&slot, atoi(s)); node = newPyrSlotNode(&slot); zzval = (long)node; return INTEGER; } int processchar(int c) { PyrSlot slot; PyrSlotNode *node; #if DEBUGLEX if (gDebugLexer) postfl("processhex: '%c'\n",c); #endif SetChar(&slot, c); node = newPyrSlotNode(&slot); zzval = (long)node; return ASCII; } int processfloat(char *s, int sawpi) { PyrSlot slot; PyrSlotNode *node; double z; #if DEBUGLEX if (gDebugLexer) postfl("processfloat: '%s'\n",s); #endif if (sawpi) { z = atof(s)*pi; SetFloat(&slot, z); } else { SetFloat(&slot, atof(s)); } node = newPyrSlotNode(&slot); zzval = (long)node; return SC_FLOAT; } int processaccidental1(char *s) { PyrSlot slot; PyrSlotNode *node; char *c; double degree=0.; double cents=0.; double centsdiv=1000.; #if 0 printf("processaccidental1: '%s'\n",s); #endif c = s; while (*c) { if (*c >= '0' && *c <= '9') degree = degree*10. + *c - '0'; else break; c++; } if (*c == 'b') centsdiv = -1000.; else if (*c == 's') centsdiv = 1000.; c++; while (*c) { if (*c >= '0' && *c <= '9') { cents = cents*10. + *c - '0'; } else break; c++; } if (cents > 499.) cents = 499.; SetFloat(&slot, degree + cents/centsdiv); node = newPyrSlotNode(&slot); zzval = (long)node; return ACCIDENTAL; } int processaccidental2(char *s) { PyrSlot slot; PyrSlotNode *node; char *c; double degree=0.; double semitones=0.; #if 0 printf("processaccidental2: '%s'\n",s); #endif c = s; while (*c) { if (*c >= '0' && *c <= '9') degree = degree*10. + *c - '0'; else break; c++; } while (*c) { if (*c == 'b') semitones -= 1.; else if (*c == 's') semitones += 1.; c++; } if (semitones > 4.) semitones = 4.; SetFloat(&slot, degree + semitones/10.); node = newPyrSlotNode(&slot); zzval = (long)node; return ACCIDENTAL; } int processsymbol(char *s) { PyrSlot slot; PyrSlotNode *node; PyrSymbol *sym; #if DEBUGLEX if (gDebugLexer) postfl("processsymbol: '%s'\n",s); #endif sym = getsym(s+1); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (long)node; return SYMBOL; } int processstring(char *s) { PyrSlot slot; PyrSlotNode *node; PyrString *string; #if DEBUGLEX if (gDebugLexer) postfl("processstring: '%s'\n",s); #endif int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; string = newPyrString(gMainVMGlobals->gc, s+1, flags, false); SetObject(&slot, string); node = newPyrSlotNode(&slot); zzval = (long)node; return STRING; } void yyerror(const char *s) { parseFailed = 1; yytext[yylen] = 0; error("%s\n",s); postErrorLine(lineno, linepos, charno); //Debugger(); } void fatal() { parseFailed = 1; yytext[yylen] = 0; error("Parse error\n"); postErrorLine(lineno, linepos, charno); //Debugger(); } #if 0 void postErrorLine() { int i, j, start, end; char str[256]; parseFailed = true; for (i=textpos-1; i>=0; --i) { if (text[i] == '\r' || text[i] == '\n') break; } start = i+1; for (i=textpos; i < textlen; ++i) { if (text[i] == '\r' || text[i] == '\n') break; } end=i; for (i=start, j=0; i s2[i]) return 1; } if (len1 < len2) return -1; if (len1 > len2) return 1; return 0; } bool scanForClosingBracket() { int r, c, d, startLevel; bool res = true; // finite state machine to parse input stream into tokens #if DEBUGLEX if (gDebugLexer) postfl("->scanForClosingBracket\n"); #endif startLevel = brackets.num; start: c = input0(); if (c == 0) goto leave; else if (c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f') { goto start; } else if (c == '\'') goto symbol3; else if (c == '"') goto string1; else if (c == '/') { c = input0(); if (c == '/') goto comment1; else if (c == '*') goto comment2; else { unput(c); goto start; } } else if (c == '$') { c = input0(); if (c == '\\') { c = input0(); switch (c) { case 'n' : c = '\n'; break; case 'r' : c = '\r'; break; case 't' : c = '\t'; break; case 'f' : c = '\f'; break; case 'v' : c = '\v'; break; } } goto start; } else if (c == OPENPAREN || c == OPENSQUAR || c == OPENCURLY) { pushls(&brackets, (int)c); r = c; goto start; } else if (c == CLOSSQUAR) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != OPENSQUAR) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error1; } } else { fatal(); post("unmatched '%c'\n",c); goto error1; } r = c; if (brackets.num < startLevel) goto leave; else goto start; } else if (c == CLOSPAREN) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != OPENPAREN) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error1; } } else { fatal(); post("unmatched '%c'\n",c); goto error1; } if (brackets.num < startLevel) goto leave; else goto start; } else if (c == CLOSCURLY) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != OPENCURLY) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error1; } } else { fatal(); post("unmatched '%c'\n",c); goto error1; } if (brackets.num < startLevel) goto leave; else goto start; } else { goto start; } symbol3 : { int startline, endchar; startline = lineno; endchar = '\''; do { c = input0(); if (c == '\\') { c = input0(); } } while (c != endchar && c != 0); if (c == 0) { char extPath[MAXPATHLEN]; asRelativePath(curfilename, extPath); post("Open ended symbol ... started on line %d in file '%s'\n", startline, extPath); goto error2; } goto start; } string1 : { int startline, endchar; startline = lineno; endchar = '\"'; do { c = input0(); if (c == '\\') { c = input0(); } } while (c != endchar && c != 0); if (c == 0) { char extPath[MAXPATHLEN]; asRelativePath(curfilename, extPath); post("Open ended string ... started on line %d in file '%s'\n", startline, extPath); goto error2; } goto start; } comment1: /* comment -- to end of line */ do { c = input0(); } while (c != '\n' && c != '\r' && c != 0); if (c == 0) { goto leave; } else goto start; comment2 : { int startline, clevel, prevc; startline = lineno; prevc = 0; clevel = 1; do { c = input0(); if (c == '/' && prevc == '*') { if (--clevel <= 0) break; } else if (c == '*' && prevc == '/') clevel++; prevc = c; } while (c != 0); if (c == 0) { char extPath[MAXPATHLEN]; asRelativePath(curfilename, extPath); post("Open ended comment ... started on line %d in file '%s'\n", startline, extPath); goto error2; } goto start; } error1: char extPath[MAXPATHLEN]; asRelativePath(curfilename, extPath); post(" in file '%s' line %d char %d\n", extPath, lineno, charno); res = false; goto leave; error2: res = false; goto leave; leave: #if DEBUGLEX if (gDebugLexer) postfl("<-scanForClosingBracket\n"); #endif return res; } int numClassDeps; static ClassExtFile* sClassExtFiles; static ClassExtFile* eClassExtFiles; ClassExtFile* newClassExtFile(PyrSymbol *fileSym, int startPos, int endPos); ClassExtFile* newClassExtFile(PyrSymbol *fileSym, int startPos, int endPos) { ClassExtFile* classext; classext = (ClassExtFile*)pyr_pool_compile->Alloc(sizeof(ClassExtFile)); classext->fileSym = fileSym; classext->next = 0; classext->startPos = startPos; classext->endPos = endPos; if (!sClassExtFiles) sClassExtFiles = classext; else eClassExtFiles->next = classext; eClassExtFiles = classext; return classext; } ClassDependancy* newClassDependancy(PyrSymbol *className, PyrSymbol *superClassName, PyrSymbol *fileSym, int startPos, int endPos, int lineOffset) { ClassDependancy* classdep; //post("classdep '%s' '%s' '%s' %d %d\n", className->name, superClassName->name, // fileSym->name, className, superClassName); // pyrmalloc: // lifetime: kill after compile. numClassDeps++; if (className->classdep) { error("duplicate Class found: '%s' \n", className->name); post("%s\n",className->classdep->fileSym->name); postfl("%s\n\n",fileSym->name); return className->classdep; } classdep = (ClassDependancy*)pyr_pool_compile->Alloc(sizeof(ClassDependancy)); MEMFAIL(text); classdep->className = className; classdep->superClassName = superClassName; classdep->fileSym = fileSym; classdep->superClassDep = NULL; classdep->next = NULL; classdep->subclasses = NULL; classdep->startPos = startPos; classdep->endPos = endPos; classdep->lineOffset = lineOffset; className->classdep = classdep; return classdep; } void buildDepTree() { ClassDependancy *next; SymbolTable* symbolTable = gMainVMGlobals->symbolTable; //postfl("->buildDepTree\n"); fflush(stdout); for (int i=0; iTableSize(); ++i) { PyrSymbol *sym = symbolTable->Get(i); if (sym && (sym->flags & sym_Class)) { if (sym->classdep) { if (sym->classdep->superClassName->classdep) { next = sym->classdep->superClassName->classdep->subclasses; sym->classdep->superClassName->classdep->subclasses = sym->classdep; sym->classdep->next = next; } else if (sym->classdep->superClassName != s_none) { error("Superclass '%s' of class '%s' is not defined in any file.\n%s\n", sym->classdep->superClassName->name, sym->classdep->className->name,sym->classdep->fileSym->name); } } } } //postfl("<-buildDepTree\n"); fflush(stdout); } extern PyrClass *gClassList; ClassDependancy **gClassCompileOrder; int gClassCompileOrderNum = 0; int gClassCompileOrderSize = 1000; void compileDepTree(); void traverseFullDepTree() { //postfl("->traverseFullDepTree\n"); fflush(stdout); gClassCompileOrderNum = 0; gClassCompileOrder = (ClassDependancy**)pyr_pool_compile->Alloc( gClassCompileOrderSize * sizeof(ClassDependancy)); MEMFAIL(gClassCompileOrder); // parse and compile all files initParser(); // sets compiler errors to 0 gParserResult = -1; traverseDepTree(s_object->classdep, 0); compileDepTree(); // compiles backwards using the order defined in gClassCompileOrder compileClassExtensions(); pyr_pool_compile->Free(gClassCompileOrder); finiParser(); //postfl("<-traverseFullDepTree\n"); fflush(stdout); } void traverseDepTree(ClassDependancy *classdep, int level) { ClassDependancy *subclassdep; if (!classdep) return; subclassdep = classdep->subclasses; for (; subclassdep; subclassdep = subclassdep->next) { traverseDepTree(subclassdep, level+1); } if (gClassCompileOrderNum > gClassCompileOrderSize) { gClassCompileOrderSize *= 2; gClassCompileOrder = (ClassDependancy**)pyr_pool_compile->Realloc(gClassCompileOrder, gClassCompileOrderSize * sizeof(ClassDependancy)); MEMFAIL(gClassCompileOrder); } /* postfl("traverse level:%d, gClassCompileOrderNum:%d, '%s' '%s' '%s'\n", level, gClassCompileOrderNum, classdep->className->name, classdep->superClassName->name, classdep->fileSym->name); fflush(stdout); */ gClassCompileOrder[gClassCompileOrderNum++] = classdep; } void compileClass(PyrSymbol *fileSym, int startPos, int endPos, int lineOffset) { //fprintf(stderr, "compileClass: %d\n", fileSym->u.index); gCompilingFileSym = fileSym; gCompilingVMGlobals = 0; gRootParseNode = NULL; initParserPool(); if (startLexer(fileSym, startPos, endPos, lineOffset)) { //postfl("->Parsing %s\n", fileSym->name); fflush(stdout); parseFailed = yyparse(); //postfl("<-Parsing %s %d\n", fileSym->name, parseFailed); fflush(stdout); //post("parseFailed %d\n", parseFailed); fflush(stdout); if (!parseFailed && gRootParseNode) { //postfl("Compiling nodes %p\n", gRootParseNode);fflush(stdout); compilingCmdLine = false; compileNodeList(gRootParseNode, true); //postfl("done compiling\n");fflush(stdout); } else { compileErrors++; char extPath[MAXPATHLEN]; asRelativePath(fileSym->name, extPath); error("file '%s' parse failed\n", extPath); postfl("error parsing\n"); } finiLexer(); } else { error("file '%s' open failed\n", fileSym->name); } freeParserPool(); } void compileDepTree() { ClassDependancy *classdep; int i; for (i=gClassCompileOrderNum-1; i>=0; --i) { classdep = gClassCompileOrder[i]; /*postfl("compile %d '%s' '%s' '%s'...%d/%d/%d\n", i, classdep->className->name, classdep->superClassName->name, classdep->fileSym->name, classdep->startLine, classdep->endLine, classDep->lineOffset);*/ compileClass(classdep->fileSym, classdep->startPos, classdep->endPos, classdep->lineOffset); } //postfl("startPos, classext->endPos); compileClass(classext->fileSym, classext->startPos, classext->endPos, -1); classext = classext->next; } while (classext); } } void findDiscrepancy(); void traverseFullDepTree2() { // assign a class index to all classes if (!parseFailed && !compileErrors) { buildClassTree(); gNumClasses = 0; // now I index them during pass one indexClassTree(class_object, 0); setSelectorFlags(); if (2*numClassDeps != gNumClasses) { error("There is a discrepancy.\n"); /* not always correct if(2*numClassDeps < gNumClasses) { post("Duplicate files may exist in the directory structure.\n"); } else { post("Some class files may be missing.\n"); } */ post("numClassDeps %d gNumClasses %d\n", numClassDeps, gNumClasses); findDiscrepancy(); compileErrors++; } else { double elapsed; buildBigMethodMatrix(); SymbolTable* symbolTable = gMainVMGlobals->symbolTable; post("\tNumber of Symbols %d\n", symbolTable->NumItems()); post("\tByte Code Size %d\n", totalByteCodes); //elapsed = TickCount() - compileStartTime; //elapsed = 0; elapsed = elapsedTime() - compileStartTime; post("\tcompiled %d files in %.2f seconds\n", gNumCompiledFiles, elapsed ); if(numOverwrites == 1){ post("\nInfo: One method is currently overwritten by an extension. To see which, execute:\nMethodOverride.printAll\n\n"); } else if(numOverwrites > 1){ post("\nInfo: %i methods are currently overwritten by extensions. To see which, execute:\nMethodOverride.printAll\n\n", numOverwrites); } post("compile done\n"); } } } bool parseOneClass(PyrSymbol *fileSym) { int token; PyrSymbol *className, *superClassName; ClassDependancy *classdep; bool res; int startPos, startLineOffset; res = true; startPos = textpos; startLineOffset = lineno - 1; token = yylex(); if (token == CLASSNAME) { className = slotRawSymbol(&((PyrSlotNode*)zzval)->mSlot); // I think this is wrong: zzval is space pool alloced //pyrfree((PyrSlot*)zzval); token = yylex(); if (token == 0) return false; if (token == OPENSQUAR) { scanForClosingBracket(); // eat indexing spec token = yylex(); if (token == 0) return false; } if (token == ':') { token = yylex(); // get super class if (token == 0) return false; if (token == CLASSNAME) { superClassName = slotRawSymbol(&((PyrSlotNode*)zzval)->mSlot); // I think this is wrong: zzval is space pool alloced //pyrfree((PyrSlot*)zzval); token = yylex(); if (token == 0) return false; if (token == OPENCURLY) { scanForClosingBracket(); // eat class body classdep = newClassDependancy(className, superClassName, fileSym, startPos, textpos, startLineOffset); } else { compileErrors++; postfl("Expected %c. got token: '%s' %d\n", OPENCURLY, yytext, token); postErrorLine(lineno, linepos, charno); return false; } } else { compileErrors++; post("Expected superclass name. got token: '%s' %d\n", yytext, token); postErrorLine(lineno, linepos, charno); return false; } } else if (token == OPENCURLY) { if (className == s_object) superClassName = s_none; else superClassName = s_object; scanForClosingBracket(); // eat class body classdep = newClassDependancy(className, superClassName, fileSym, startPos, textpos, startLineOffset); } else { compileErrors++; post("Expected ':' or %c. got token: '%s' %d\n", OPENCURLY, yytext, token); postErrorLine(lineno, linepos, charno); return false; } } else if (token == '+') { token = yylex(); if (token == 0) return false; scanForClosingBracket(); newClassExtFile(fileSym, startPos, textpos); return false; } else { if (token != 0) { compileErrors++; post("Expected class name. got token: '%s' %d\n", yytext, token); postErrorLine(lineno, linepos, charno); return false; } else { res = false; } } return res; } //void ClearLibMenu(); void aboutToFreeRuntime(); void aboutToFreeRuntime() { //ClearLibMenu(); } //void init_graph_compile(); //void tellPlugInsAboutToCompile(); void pyrmath_init_globs(); void initPassOne() { aboutToFreeRuntime(); //dump_pool_histo(pyr_pool_runtime); pyr_pool_runtime->FreeAllInternal(); //dump_pool_histo(pyr_pool_runtime); //gPermanentObjPool.Init(pyr_pool_runtime, PERMOBJCHUNK); sClassExtFiles = 0; void *ptr = pyr_pool_runtime->Alloc(sizeof(SymbolTable)); gMainVMGlobals->symbolTable = new (ptr) SymbolTable(pyr_pool_runtime, 8192); //gFileSymbolTable = newSymbolTable(512); pyrmath_init_globs(); initSymbols(); // initialize symbol globals //init_graph_compile(); initSpecialSelectors(); initSpecialClasses(); initClasses(); initParserPool(); initParseNodes(); initPrimitives(); //tellPlugInsAboutToCompile(); initLexer(); compileErrors = 0; numClassDeps = 0; compiledOK = false; compiledDirectories.clear(); sc_InitCompileDirectory(); } void finiPassOne() { //postfl("->finiPassOne\n"); freeParserPool(); //postfl("<-finiPassOne\n"); } static bool passOne_ProcessDir(const char *dirname, int level) { if (!sc_DirectoryExists(dirname)) return true; if (compiledDirectories.find(std::string(dirname)) != compiledDirectories.end()) // already compiled return true; bool success = true; if (gLanguageConfig && gLanguageConfig->pathIsExcluded(dirname)) { post("\texcluding dir: '%s'\n", dirname); return success; } if (level == 0) post("\tcompiling dir: '%s'\n", dirname); SC_DirHandle *dir = sc_OpenDir(dirname); if (!dir) { error("open directory failed '%s'\n", dirname); fflush(stdout); return false; } for (;;) { char diritem[MAXPATHLEN]; bool skipItem = true; bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem); if (!validItem) break; if (skipItem) continue; if (sc_DirectoryExists(diritem)) { success = passOne_ProcessDir(diritem, level + 1); } else { success = passOne_ProcessOneFile(diritem, level + 1); } if (!success) break; } compiledDirectories.insert(std::string(dirname)); sc_CloseDir(dir); return success; } bool passOne() { initPassOne(); if (sc_IsStandAlone()) { /// FIXME: this should be moved to the LibraryConfig file if (!passOne_ProcessDir(gCompileDir, 0)) return false; } else if (!gLanguageConfig->forEachIncludedDirectory(passOne_ProcessDir)) return false; finiPassOne(); return true; } // true if filename ends in ".sc" bool isValidSourceFileName(char *filename) { int len = strlen(filename); bool validExtension = (len>3 && strncmp(filename+len-3, ".sc", 3) == 0) || (len>7 && strncmp(filename+len-7, ".sc.rtf", 7) == 0); if (!validExtension) return false; boost::filesystem::path pathname(filename); if (pathname.filename().c_str()[0] == '.') // hidden filename return false; return true; } // sekhar's replacement bool passOne_ProcessOneFile(const char * filenamearg, int level) { bool success = true; bool isAlias = false; char filename[MAXPATHLEN]; int status = sc_ResolveIfAlias(filenamearg, filename, isAlias, MAXPATHLEN); if (status<0) { printf("WARNING: skipping invalid symbolic link: %s\n", filenamearg); return success; } if (gLanguageConfig && gLanguageConfig->pathIsExcluded(filename)) { post("\texcluding file: '%s'\n", filename); return success; } if (isValidSourceFileName(filename)) { gNumCompiledFiles++; PyrSymbol * fileSym = getsym(filename); fileSym->u.source = NULL; if (startLexer(fileSym, -1, -1, -1)) { while (parseOneClass(fileSym)) { }; finiLexer(); } else { error("file '%s' open failed\n", filename); success = false; } } else { if (sc_DirectoryExists(filename)) success = passOne_ProcessDir(filename, level); } return success; } void schedRun(); void compileSucceeded(); void compileSucceeded() { compiledOK = !(parseFailed || compileErrors); if (compiledOK) { compiledOK = true; compiledOK = initRuntime(gMainVMGlobals, 128*1024, pyr_pool_runtime); if (compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; //++g->sp; SetObject(g->sp, g->process); //runInterpreter(g, s_hardwaresetup, 1); ++g->sp; SetObject(g->sp, g->process); runInterpreter(g, s_startup, 1); g->canCallOS = false; schedRun(); } flushPostBuf(); } } void aboutToCompileLibrary(); void aboutToCompileLibrary() { //printf("->aboutToCompileLibrary\n"); pthread_mutex_lock (&gLangMutex); if (compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, g->process); runInterpreter(g, s_shutdown, 1); g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); //printf("<-aboutToCompileLibrary\n"); } void closeAllGUIScreens(); void TempoClock_stopAll(void); void closeAllCustomPorts(); void shutdownLibrary() { closeAllGUIScreens(); schedStop(); aboutToCompileLibrary(); TempoClock_stopAll(); pthread_mutex_lock (&gLangMutex); closeAllCustomPorts(); if (compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; g->gc->RunAllFinalizers(); g->canCallOS = false; } pyr_pool_runtime->FreeAll(); compiledOK = false; pthread_mutex_unlock (&gLangMutex); SC_LanguageConfig::freeLibraryConfig(); } SC_DLLEXPORT_C bool compileLibrary() { //printf("->compileLibrary\n"); shutdownLibrary(); pthread_mutex_lock (&gLangMutex); gNumCompiledFiles = 0; compiledOK = false; SC_LanguageConfig::readLibraryConfig(); compileStartTime = elapsedTime(); totalByteCodes = 0; #ifdef NDEBUG postfl("compiling class library...\n"); #else postfl("compiling class library (debug build)...\n"); #endif bool res = passOne(); if (res) { postfl("\tpass 1 done\n"); if (!compileErrors) { buildDepTree(); traverseFullDepTree(); traverseFullDepTree2(); flushPostBuf(); if (!compileErrors && gShowWarnings) { SymbolTable* symbolTable = gMainVMGlobals->symbolTable; symbolTable->CheckSymbols(); } } pyr_pool_compile->FreeAll(); flushPostBuf(); compileSucceeded(); } else { compiledOK = false; } pthread_mutex_unlock (&gLangMutex); //printf("<-compileLibrary\n"); return compiledOK; } void signal_init_globs(); void dumpByteCodes(PyrBlock *theBlock); SC_DLLEXPORT_C void runLibrary(PyrSymbol* selector) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; try { if (compiledOK) { ++g->sp; SetObject(g->sp, g->process); runInterpreter(g, selector, 1); } else { postfl("Library has not been compiled successfully.\n"); } } catch (std::exception &ex) { PyrMethod *meth = g->method; if (meth) { int ip = slotRawInt8Array(&meth->code) ? g->ip - slotRawInt8Array(&meth->code)->b : -1; post("caught exception in runLibrary %s:%s %3d\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name, ip ); dumpByteCodes(meth); } else { post("caught exception in runLibrary\n"); } error(ex.what()); } catch (...) { postfl("DANGER: OUT of MEMORY. Operation failed.\n"); } g->canCallOS = false; } void interpretCmdLine(const char *textbuf, int textlen, char *methodname) { PyrString *string; if (compiledOK) { PyrSlot slot; string = newPyrStringN(gMainVMGlobals->gc, textlen, 0, false); memcpy(string->s, textbuf, textlen); SetObject(&slotRawInterpreter(&gMainVMGlobals->process->interpreter)->cmdLine, string); gMainVMGlobals->gc->GCWrite(slotRawObject(&gMainVMGlobals->process->interpreter), string); SetObject(&slot, gMainVMGlobals->process); //#if __profile__ // ProfilerInit(collectSummary, microsecondsTimeBase, 500, 100); //#endif slotCopy((++gMainVMGlobals->sp), &slot); runInterpreter(gMainVMGlobals, getsym(methodname), 1); //#if __profile__ // ProfilerDump("\pErase2.prof"); // ProfilerTerm(); //#endif } else { postfl("Library has not been compiled successfully.\n"); } } void init_SuperCollider() { } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/ByteCodeArray.cpp0000664000000000000000000001155012161364457025160 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "SCBase.h" #include "InitAlloc.h" #include "ByteCodeArray.h" #include "Opcodes.h" ByteCodes gCompilingByteCodes; long totalByteCodes = 0; void initByteCodes() { if (gCompilingByteCodes) { freeByteCodes(gCompilingByteCodes); gCompilingByteCodes = NULL; } } int compileOpcode(long opcode, long operand1) { int retc; if (operand1 <= 15) { compileByte((opcode<<4) | operand1); retc = 1; } else { compileByte(opcode); compileByte(operand1); if (opcode == opSendMsg || opcode == opSendSpecialMsg || opcode == opSendSuper) { // these expect numKeyArgsPushed to be passed. compileByte(0); } retc = 2; } return retc; } void compileJump(long opcode, long jumplen) { compileByte((opSpecialOpcode<<4) | opcode); compileByte((jumplen >> 8) & 0xFF); compileByte(jumplen & 0xFF); } void compileByte(long byte) { if (gCompilingByteCodes == NULL) { gCompilingByteCodes = allocByteCodes(); } if ((gCompilingByteCodes->ptr - gCompilingByteCodes->bytes) >= gCompilingByteCodes->size) { reallocByteCodes(gCompilingByteCodes); } totalByteCodes++; *gCompilingByteCodes->ptr++ = byte; } int compileNumber(unsigned long value) { compileByte((value >> 24) & 0xFF); compileByte((value >> 16) & 0xFF); compileByte((value >> 8) & 0xFF); compileByte(value & 0xFF); return 4; } int compileNumber24(unsigned long value) { compileByte((value >> 16) & 0xFF); compileByte((value >> 8) & 0xFF); compileByte(value & 0xFF); return 4; } void compileAndFreeByteCodes(ByteCodes byteCodes) { compileByteCodes(byteCodes); freeByteCodes(byteCodes); } void copyByteCodes(Byte *dest, ByteCodes byteCodes) { memcpy(dest, byteCodes->bytes, byteCodeLength(byteCodes)); } ByteCodes getByteCodes() { ByteCodes curByteCodes; curByteCodes = gCompilingByteCodes; gCompilingByteCodes = NULL; return curByteCodes; } ByteCodes saveByteCodeArray() { ByteCodes curByteCodes; curByteCodes = gCompilingByteCodes; gCompilingByteCodes = NULL; return curByteCodes; } void restoreByteCodeArray(ByteCodes byteCodes) { gCompilingByteCodes = byteCodes; } size_t byteCodeLength(ByteCodes byteCodes) { if (!byteCodes) return 0; return (byteCodes->ptr - byteCodes->bytes); } /*********************************************************************** * * Internal routines. * ***********************************************************************/ void compileByteCodes(ByteCodes byteCodes) { Byte *ptr; int i; if (byteCodes == NULL) return; //postfl("[%d]\n", byteCodes->ptr - byteCodes->bytes); for (i=0, ptr = byteCodes->bytes; ptr < byteCodes->ptr; ptr++, ++i) { compileByte(*ptr); //postfl("%02X ", *ptr); //if ((i & 15) == 15) postfl("\n"); } //postfl("\n\n"); } ByteCodes allocByteCodes() { ByteCodes newByteCodes; // pyrmalloc: I think that all bytecodes are copied to objects // lifetime: kill after compile newByteCodes = (ByteCodes)pyr_pool_compile->Alloc(sizeof(ByteCodeArray)); MEMFAIL(newByteCodes); newByteCodes->bytes = (Byte *)pyr_pool_compile->Alloc(BYTE_CODE_CHUNK_SIZE); MEMFAIL(newByteCodes->bytes); newByteCodes->ptr = newByteCodes->bytes; newByteCodes->size = BYTE_CODE_CHUNK_SIZE; //postfl("allocByteCodes %0X\n", newByteCodes); return newByteCodes; } void reallocByteCodes(ByteCodes byteCodes) { Byte *newBytes; if (byteCodes->size != (byteCodes->ptr - byteCodes->bytes)) { error("reallocByteCodes called with size != byteCode len"); } size_t newLen = byteCodes->size << 1; // pyrmalloc: I think that all bytecodes are copied to objects // lifetime: kill after compile newBytes = (Byte *)pyr_pool_compile->Alloc(newLen); MEMFAIL(newBytes); memcpy(newBytes, byteCodes->bytes, byteCodes->size); pyr_pool_compile->Free(byteCodes->bytes); byteCodes->bytes = newBytes; byteCodes->ptr = newBytes + byteCodes->size; byteCodes->size = newLen; } void freeByteCodes(ByteCodes byteCodes) { //postfl("freeByteCodes %0X\n", byteCodes); if (byteCodes != NULL) { pyr_pool_compile->Free(byteCodes->bytes); pyr_pool_compile->Free(byteCodes); } } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/cmdLineFuncs.cpp0000664000000000000000000000664612245365552025047 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // #ifdef SC_DARWIN // # define USE_SC_TERMINAL_CLIENT 0 // #else // # define USE_SC_TERMINAL_CLIENT 1 // #endif #if USE_SC_TERMINAL_CLIENT #include "SC_TerminalClient.h" #ifdef SC_QT # include "QtCollider.h" #endif #include int main(int argc, char** argv) { #ifdef SC_QT return QtCollider::run(argc, argv); #else SC_TerminalClient app("sclang"); return app.run(argc, argv); #endif } #else // !USE_SC_TERMINAL_CLIENT #include "PyrSymbol.h" #include "PyrObject.h" #include "InitAlloc.h" #include #include "SCBase.h" static FILE *postfile = stdout; void setPostFile(FILE *file) { postfile = file; } void postfl(const char *fmt, ...); void postfl(const char *fmt, ...) { va_list vargs; va_start(vargs, fmt); vfprintf(postfile, fmt, vargs); fflush(postfile); } extern "C" { int vpost(const char *fmt, va_list vargs); } int vpost(const char *fmt, va_list vargs) { return vfprintf(postfile, fmt, vargs); fflush(postfile); } void post(const char *fmt, ...); void post(const char *fmt, ...) { va_list vargs; va_start(vargs, fmt); vfprintf(postfile, fmt, vargs); //fflush(postfile); } void error(const char *fmt, ...); void error(const char *fmt, ...) { fprintf(postfile, "ERROR: "); va_list vargs; va_start(vargs, fmt); vfprintf(postfile, fmt, vargs); fflush(postfile); } void postText(const char *text, long length); void postText(const char *text, long length) { fwrite(text, sizeof(char), length, postfile); } void postChar(char c); void postChar(char c) { fputc(c, postfile); } void flushPostBuf(); void flushPostBuf() { fflush(postfile); } long scMIDIout(int port, int len, int statushi, int chan, int data1, int data2); long scMIDIout(int port, int len, int statushi, int chan, int data1, int data2) { return 0; } /* void tellPlugInsAboutToCompile(); void tellPlugInsAboutToCompile() { } void tellPlugInsAboutToRun(); void tellPlugInsAboutToRun() { } */ void closeAllGUIScreens(); void closeAllGUIScreens() { } void initGUI(); void initGUI() { } #ifndef PYSCLANG void initGUIPrimitives(); void initGUIPrimitives() { } #endif void initSCViewPrimitives(); void initSCViewPrimitives() { } void initCocoaFilePrimitives(); void initCocoaFilePrimitives() { } void initCocoaBridgePrimitives(); void initCocoaBridgePrimitives() { } // CR ADDED void initRendezvousPrimitives(); void initRendezvousPrimitives() { } int main(); int main() { pyr_init_mem_pools(2*1024*1024, 256*1024); init_OSC(57120); schedInit(); compileLibrary(); runLibrary(s_run); fflush(postfile); cleanup_OSC(); return 0; } #endif // USE_SC_TERMINAL_CLIENT SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/SimpleStack.cpp0000664000000000000000000000436112014636264024677 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include //#include #include "SCBase.h" #include "SimpleStack.h" #include "InitAlloc.h" void initLongStack(LongStack *self) { //dbg("initLongStack"); self->maxsize = 0; self->stak = NULL; self->num = 0; } void freeLongStack(LongStack *self) { //dbg("freeLongStack"); self->maxsize = 0; self->num = 0; if (self->stak) { pyr_pool_compile->Free((void*)self->stak); self->stak = NULL; } } void growLongStack(LongStack *self) { if (self->maxsize) { long *oldstak; self->maxsize += self->maxsize >> 1; // grow by 50% oldstak = self->stak; // pyrmalloc: // lifetime: kill after compile. self->stak = (long*)pyr_pool_compile->Alloc(self->maxsize * sizeof(long)); MEMFAIL(self->stak); //BlockMoveData(oldstak, self->stak, self->num * sizeof(long)); memcpy(self->stak, oldstak, self->num * sizeof(long)); pyr_pool_compile->Free((void*)oldstak); } else { self->maxsize = 32; self->stak = (long*)pyr_pool_compile->Alloc(self->maxsize * sizeof(long)); MEMFAIL(self->stak); } } void pushls(LongStack *self, long value) { //dbg2("pushls %lX", value); if (self->num+1 > self->maxsize) { growLongStack(self); } self->stak[self->num++] = value; } long popls(LongStack *self) { if (self->num > 0) return self->stak[--self->num]; else { error("stack empty! (pop)\n"); return 0; } } int emptyls(LongStack *self) { return self->num <= 0; } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/PyrObject.cpp0000664000000000000000000024577712245365552024410 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "GC.h" #include "PyrMessage.h" #include "PyrInterpreter.h" #include "PyrSymbolTable.h" #include "PyrObjectProto.h" #include "PyrKernelProto.h" #include "PyrLexer.h" #include "InitAlloc.h" #include "Hash.h" #include "SC_Constants.h" #include "SC_Alloca.h" #include #include PyrClass *gClassList = NULL; int gNumSelectors = 0; int gNumClasses = 0; int gNumClassVars = 0; int gFormatElemSize[NUMOBJFORMATS]; int gFormatElemCapc[NUMOBJFORMATS]; int gFormatElemTag[NUMOBJFORMATS]; PyrMethod *gNullMethod; // used to fill row table PyrClass* gTagClassTable[16]; PyrClass *class_object; PyrClass *class_dict; PyrClass *class_array; PyrClass *class_list, *class_method, *class_fundef, *class_frame, *class_class; PyrClass *class_symbol, *class_nil; PyrClass *class_boolean, *class_true, *class_false; PyrClass *class_int, *class_char, *class_float, *class_complex; PyrClass *class_rawptr; PyrClass *class_string; PyrClass *class_magnitude, *class_number, *class_collection, *class_ordered_collection; PyrClass *class_arrayed_collection; PyrClass *class_sequenceable_collection; PyrClass *class_simple_number; PyrClass *class_rawarray; PyrClass *class_signal; PyrClass *class_wavetable; PyrClass *class_floatarray; PyrClass *class_int8array; PyrClass *class_int16array; PyrClass *class_int32array; PyrClass *class_symbolarray; PyrClass *class_doublearray; PyrClass *class_func, *class_absfunc; PyrClass *class_stream; PyrClass *class_process; PyrClass *class_interpreter; PyrClass *class_thread; PyrClass *class_routine; PyrClass *class_finalizer; PyrClass *class_server_shm_interface; PyrSymbol *s_none; PyrSymbol *s_object; PyrSymbol *s_bag; PyrSymbol *s_set; PyrSymbol *s_identityset; PyrSymbol *s_dictionary; PyrSymbol *s_identitydictionary; PyrSymbol *s_linkedlist; PyrSymbol *s_sortedlist; PyrSymbol *s_array; PyrSymbol *s_list, *s_method, *s_fundef, *s_frame, *s_class; PyrSymbol *s_symbol, *s_nil; PyrSymbol *s_boolean, *s_true, *s_false; PyrSymbol *s_int, *s_char, *s_color, *s_float, *s_complex; PyrSymbol *s_rawptr, *s_objptr; PyrSymbol *s_string; PyrSymbol *s_magnitude, *s_number, *s_collection, *s_ordered_collection; PyrSymbol *s_arrayed_collection; PyrSymbol *s_sequenceable_collection; PyrSymbol *s_simple_number; PyrSymbol *s_signal; PyrSymbol *s_wavetable; PyrSymbol *s_rawarray; PyrSymbol *s_int8array; PyrSymbol *s_int16array; PyrSymbol *s_int32array; PyrSymbol *s_symbolarray; PyrSymbol *s_doublearray; PyrSymbol *s_floatarray; PyrSymbol *s_point; PyrSymbol *s_rect; PyrSymbol *s_func, *s_absfunc; PyrSymbol *s_stream; PyrSymbol *s_process; PyrSymbol *s_main; PyrSymbol *s_thread; PyrSymbol *s_routine; PyrSymbol *s_task; PyrSymbol *s_prstart; PyrSymbol *s_interpreter; PyrSymbol *s_finalizer; PyrSymbol *s_awake; PyrSymbol *s_appclock; PyrSymbol *s_systemclock; PyrSymbol *s_server_shm_interface; PyrSymbol *s_nocomprendo; PyrSymbol *s_curProcess, *s_curMethod, *s_curBlock, *s_curClosure, *s_curThread; //PyrSymbol *s_sampleRate; //PyrSymbol *s_audioClock, *s_logicalClock; PyrSymbol *s_run; PyrSymbol *s_startup; PyrSymbol *s_docmdline; PyrSymbol *s_audio; PyrSymbol *s_control; PyrSymbol *s_scalar; PyrSymbol *s_next; PyrSymbol *s_env; PyrSymbol *s_ugen, *s_outputproxy; PyrSymbol *s_new, *s_ref, *s_value, *s_at, *s_put; PyrSymbol *s_performList, *s_superPerformList; PyrSymbol *s_series, *s_copyseries, *s_putseries; PyrSymbol *s_envirGet, *s_envirPut; PyrSymbol *s_synth, *s_spawn, *s_environment, *s_event; PyrSymbol *s_hardwaresetup, *s_shutdown; PyrSymbol *s_linear, *s_exponential, *s_gate; PyrSymbol *s_super, *s_this; PyrSlot o_nil, o_true, o_false, o_end; PyrSlot o_pi, o_twopi; PyrSlot o_fhalf, o_fnegone, o_fzero, o_fone, o_ftwo, o_inf; PyrSlot o_negtwo, o_negone, o_zero, o_one, o_two; PyrSlot o_nullframe, o_none; PyrSlot o_emptyarray, o_onenilarray, o_argnamethis; void initSymbols() { s_new = getsym("new"); s_ref = getsym("Ref"); s_none = getsym("none"); s_object = getsym("Object"); s_this = getsym("this"); s_super = getsym("super"); s_dictionary = getsym("Dictionary"); s_bag = getsym("Bag"); s_set = getsym("Set"); s_identityset = getsym("IdentitySet"); s_identitydictionary = getsym("IdentityDictionary"); s_linkedlist = getsym("LinkedList"); s_sortedlist = getsym("SortedList"); s_array = getsym("Array"); s_list = getsym("List"); s_method = getsym("Method"); s_fundef = getsym("FunctionDef"); s_frame = getsym("Frame"); s_class = getsym("Class"); s_symbol = getsym("Symbol"); s_nil = getsym("Nil"); s_true = getsym("True"); s_false = getsym("False"); s_int = getsym("Integer"); s_float = getsym("Float"); s_char = getsym("Char"); s_color = getsym("Color"); s_rawptr = getsym("RawPointer"); s_objptr = getsym("ObjectPointer"); s_string = getsym("String"); s_magnitude = getsym("Magnitude"); s_number = getsym("Number"); s_simple_number = getsym("SimpleNumber"); s_collection = getsym("Collection"); //s_ordered_collection = getsym("OrderedCollection"); s_arrayed_collection = getsym("ArrayedCollection"); s_sequenceable_collection = getsym("SequenceableCollection"); s_boolean = getsym("Boolean"); s_signal = getsym("Signal"); s_wavetable = getsym("Wavetable"); //s_signalnode = getsym("SignalNode"); s_rawarray = getsym("RawArray"); s_int8array = getsym("Int8Array"); s_int16array = getsym("Int16Array"); s_int32array = getsym("Int32Array"); s_symbolarray = getsym("SymbolArray"); s_floatarray = getsym("FloatArray"); s_doublearray = getsym("DoubleArray"); s_complex = getsym("Complex"); s_point = getsym("Point"); s_rect = getsym("Rect"); s_absfunc = getsym("AbstractFunction"); s_func = getsym("Function"); s_stream = getsym("Stream"); s_process = getsym("Process"); s_main = getsym("Main"); s_thread = getsym("Thread"); s_routine = getsym("Routine"); s_task = getsym("Task"); s_prstart = getsym("prStart"); s_interpreter = getsym("Interpreter"); s_finalizer = getsym("Finalizer"); s_awake = getsym("awake"); s_appclock = getsym("AppClock"); s_systemclock = getsym("SystemClock"); s_server_shm_interface = getsym("ServerShmInterface"); s_linear = getsym("linear"); s_exponential = getsym("exponential"); s_gate = getsym("gate"); //s_dsp = getsym("DSP"); //s_dspsettings = getsym("DSPSettings"); s_synth = getsym("Synth"); s_spawn = getsym("BasicSpawn"); s_environment = getsym("Environment"); s_event = getsym("Event"); s_hardwaresetup = getsym("hardwareSetup"); s_shutdown = getsym("shutdown"); s_nocomprendo = getsym("doesNotUnderstand"); s_curProcess = getsym("thisProcess"); s_curThread = getsym("thisThread"); s_curMethod = getsym("thisMethod"); s_curBlock = getsym("thisFunctionDef"); s_curClosure = getsym("thisFunction"); //s_sampleRate = getsym("gSR"); //s_logicalClock = getsym("gTime"); //s_audioClock = getsym("gAudioTime"); s_audio = getsym("audio"); s_control = getsym("control"); s_scalar = getsym("scalar"); s_run = getsym("run"); s_startup = getsym("startup"); s_docmdline = getsym("doCmdLine"); s_next = getsym("next"); s_value = getsym("value"); s_performList = getsym("performList"); s_superPerformList = getsym("superPerformList"); s_at = getsym("at"); s_put = getsym("put"); s_series = getsym("prSimpleNumberSeries"); s_copyseries = getsym("copySeries"); s_putseries = getsym("putSeries"); s_ugen = getsym("UGen"); s_outputproxy = getsym("OutputProxy"); s_env = getsym("Env"); s_envirGet = getsym("envirGet"); s_envirPut = getsym("envirPut"); SetNil(&o_nil); SetFalse(&o_false); SetTrue(&o_true); SetFloat(&o_pi, pi); SetFloat(&o_twopi, twopi); SetFloat(&o_fhalf, .5); SetFloat(&o_fnegone, -1.); SetFloat(&o_fzero, 0.); SetFloat(&o_fone, 1.); SetFloat(&o_ftwo, 2.); SetInt(&o_negtwo, -2); SetInt(&o_negone, -1); SetInt(&o_zero, 0); SetInt(&o_one, 1); SetInt(&o_two, 2); SetSymbol(&o_none, s_none); SetFloat(&o_inf, std::numeric_limits::infinity()); slotCopy(&gSpecialValues[svNil], &o_nil); slotCopy(&gSpecialValues[svFalse], &o_false); slotCopy(&gSpecialValues[svTrue], &o_true); slotCopy(&gSpecialValues[svNegOne], &o_negone); slotCopy(&gSpecialValues[svZero], &o_zero); slotCopy(&gSpecialValues[svOne], &o_one); slotCopy(&gSpecialValues[svTwo], &o_two); slotCopy(&gSpecialValues[svFHalf], &o_fhalf); slotCopy(&gSpecialValues[svFNegOne], &o_fnegone); slotCopy(&gSpecialValues[svFZero], &o_fzero); slotCopy(&gSpecialValues[svFOne], &o_fone); slotCopy(&gSpecialValues[svFTwo], &o_ftwo); slotCopy(&gSpecialValues[svInf], &o_inf); gFormatElemSize[obj_notindexed] = sizeof(PyrSlot); gFormatElemSize[obj_slot ] = sizeof(PyrSlot); gFormatElemSize[obj_double] = sizeof(double); gFormatElemSize[obj_float ] = sizeof(float); gFormatElemSize[obj_int32 ] = sizeof(int32); gFormatElemSize[obj_int16 ] = sizeof(int16); gFormatElemSize[obj_int8 ] = sizeof(int8); gFormatElemSize[obj_char ] = sizeof(char); gFormatElemSize[obj_symbol ] = sizeof(PyrSymbol*); gFormatElemCapc[obj_notindexed] = sizeof(PyrSlot) / sizeof(PyrSlot); gFormatElemCapc[obj_slot ] = sizeof(PyrSlot) / sizeof(PyrSlot); gFormatElemCapc[obj_double] = sizeof(PyrSlot) / sizeof(double); gFormatElemCapc[obj_float ] = sizeof(PyrSlot) / sizeof(float); gFormatElemCapc[obj_int32 ] = sizeof(PyrSlot) / sizeof(int32); gFormatElemCapc[obj_int16 ] = sizeof(PyrSlot) / sizeof(int16); gFormatElemCapc[obj_int8 ] = sizeof(PyrSlot) / sizeof(int8); gFormatElemCapc[obj_char ] = sizeof(PyrSlot) / sizeof(char); gFormatElemCapc[obj_symbol] = sizeof(PyrSlot) / sizeof(PyrSymbol*); gFormatElemTag[obj_notindexed] = -1; gFormatElemTag[obj_slot ] = -1; gFormatElemTag[obj_double] = 0; gFormatElemTag[obj_float ] = 0; gFormatElemTag[obj_int32 ] = tagInt; gFormatElemTag[obj_int16 ] = tagInt; gFormatElemTag[obj_int8 ] = tagInt; gFormatElemTag[obj_char ] = tagChar; gFormatElemTag[obj_symbol] = tagSym; } const char *slotSymString(PyrSlot* slot) { switch (GetTag(slot)) { case tagObj : return slotRawSymbol(&slotRawObject(slot)->classptr->name)->name; case tagInt : return "Integer"; case tagChar : return "Char"; case tagSym : return slotRawSymbol(slot)->name; case tagNil : return "Nil"; case tagFalse : return "False"; case tagTrue : return "True"; default : return ""; } } PyrClass* newClassObj(PyrClass *classObjSuperClass, PyrSymbol* className, PyrSymbol* superClassName, int numInstVars, int numClassVars, int numConsts, int numInstMethods, int instFormat, int instFlags) { PyrClass* classobj, *superclassobj; PyrObject* array; PyrSymbolArray *symarray; int classFlags; /*{ int c; c = className->name[0]; if (!(c >= 'A' && c <= 'Z')) Debugger(); }*/ // pyrmalloc: // lifetime: kill upon recompiling library classobj = (PyrClass*)pyr_pool_runtime->Alloc(sizeof(PyrClass)); MEMFAIL(classobj); classobj->size = (sizeof(PyrClass) - sizeof(PyrObjectHdr))/sizeof(PyrSlot); classobj->prev = classobj->next = NULL; classobj->obj_flags = obj_immutable ; classobj->obj_format = obj_notindexed ; classobj->gc_color = obj_permanent ; classobj->obj_sizeclass = LOG2CEIL(classobj->size); classobj->classptr = classObjSuperClass; // append to the list of classes if (gClassList) SetObject(&classobj->nextclass, gClassList); else SetNil(&classobj->nextclass); gClassList = classobj; className->u.classobj = classobj; //postfl("> '%s' %d %d\n", className->name, className, classobj); SetSymbol(&classobj->name, className); if (superClassName) { SetSymbol(&classobj->superclass, superClassName); superclassobj = superClassName->u.classobj; } else { SetSymbol(&classobj->superclass, s_none); superclassobj = NULL; } SetInt(&classobj->subclasses, 0); // to be filled with subclasses later // in the meantime it is used as a tally of subclasses so that its allocation // size can be known if (numInstMethods) { array = newPyrArray(NULL, numInstMethods, obj_permanent | obj_immutable, false); SetObject(&classobj->methods, array); } else { SetNil(&classobj->methods); } if (numInstVars) { symarray = newPyrSymbolArray(NULL, numInstVars, obj_permanent | obj_immutable, false); SetObject(&classobj->instVarNames, symarray); array = newPyrArray(NULL, numInstVars, obj_permanent | obj_immutable, false); SetObject(&classobj->iprototype, array); nilSlots(array->slots, numInstVars); } else { SetNil(&classobj->instVarNames); SetNil(&classobj->iprototype); } if (numClassVars) { symarray = newPyrSymbolArray(NULL, numClassVars, obj_permanent | obj_immutable, false); SetObject(&classobj->classVarNames, symarray); array = newPyrArray(NULL, numClassVars, obj_permanent | obj_immutable, false); SetObject(&classobj->cprototype, array); nilSlots(array->slots, numClassVars); } else { SetNil(&classobj->classVarNames); SetNil(&classobj->cprototype); } if (numConsts) { symarray = newPyrSymbolArray(NULL, numConsts, obj_permanent | obj_immutable, false); SetObject(&classobj->constNames, symarray); array = newPyrArray(NULL, numConsts, obj_permanent | obj_immutable, false); SetObject(&classobj->constValues, array); nilSlots(array->slots, numConsts); } else { SetNil(&classobj->constNames); SetNil(&classobj->constValues); } classFlags = 0; if (instFormat != obj_notindexed) { classFlags |= classHasIndexableInstances; } SetInt(&classobj->instanceFormat, instFormat); SetInt(&classobj->instanceFlags, instFlags); SetInt(&classobj->classIndex, -1); SetInt(&classobj->classFlags, classFlags); SetInt(&classobj->maxSubclassIndex, 0); SetNil(&classobj->filenameSym); SetInt(&classobj->charPos, 0); SetInt(&classobj->classVarIndex, gNumClassVars); //if (numClassVars) post("%16s %4d %4d\n", className->name, gNumClassVars, numClassVars); gNumClassVars += numClassVars; return classobj; } void reallocClassObj(PyrClass* classobj, int numInstVars, int numClassVars, int numConsts, int numMethods, int instFormat, int instFlags) { PyrObject* array; PyrSymbolArray *symarray; PyrClass *superclassobj; freePyrSlot(&classobj->methods); freePyrSlot(&classobj->instVarNames); freePyrSlot(&classobj->classVarNames); freePyrSlot(&classobj->iprototype); freePyrSlot(&classobj->cprototype); freePyrSlot(&classobj->constNames); freePyrSlot(&classobj->constValues); if (numMethods) { array = newPyrArray(NULL, numMethods, obj_permanent | obj_immutable, false); SetObject(&classobj->methods, array); } else { SetNil(&classobj->methods); } if (numInstVars) { //post("reallocClassObj %s numInstVars %d\n", slotRawSymbol(&classobj->name)->name, numInstVars); symarray = newPyrSymbolArray(NULL, numInstVars, obj_permanent | obj_immutable, false); SetObject(&classobj->instVarNames, symarray); array = newPyrArray(NULL, numInstVars, obj_permanent | obj_immutable, false); SetObject(&classobj->iprototype, array); nilSlots(array->slots, numInstVars); } else { SetNil(&classobj->instVarNames); SetNil(&classobj->iprototype); } if (numClassVars) { //post("reallocClassObj %s numClassVars %d\n", slotRawSymbol(&classobj->name)->name, numClassVars); symarray = newPyrSymbolArray(NULL, numClassVars, obj_permanent | obj_immutable, false); SetObject(&classobj->classVarNames, symarray); nilSlots(array->slots, numClassVars); array = newPyrArray(NULL, numClassVars, obj_permanent | obj_immutable, false); SetObject(&classobj->cprototype, array); nilSlots(array->slots, numClassVars); } else { SetNil(&classobj->classVarNames); SetNil(&classobj->cprototype); } if (numConsts) { //post("reallocClassObj %s numConsts %d\n", slotRawSymbol(&classobj->name)->name, numConsts); symarray = newPyrSymbolArray(NULL, numConsts, obj_permanent | obj_immutable, false); SetObject(&classobj->constNames, symarray); array = newPyrArray(NULL, numConsts, obj_permanent | obj_immutable, false); SetObject(&classobj->constValues, array); nilSlots(array->slots, numConsts); } else { SetNil(&classobj->constNames); SetNil(&classobj->constValues); } superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj; SetInt(&classobj->instanceFormat, instFormat); SetInt(&classobj->instanceFlags, instFlags); SetInt(&classobj->classIndex, -1); } void fixClassArrays(PyrClass *classobj); void fixClassArrays(PyrClass *classobj) { if (IsObj(&classobj->methods)) slotRawObject(&classobj->methods)->classptr = class_array; if (IsObj(&classobj->instVarNames)) slotRawObject(&classobj->instVarNames)->classptr = class_symbolarray; if (IsObj(&classobj->classVarNames)) slotRawObject(&classobj->classVarNames)->classptr = class_symbolarray; if (IsObj(&classobj->iprototype)) slotRawObject(&classobj->iprototype)->classptr = class_array; if (IsObj(&classobj->cprototype)) slotRawObject(&classobj->cprototype)->classptr = class_array; } int numInstVars(PyrClass* classobj) { int res; if (IsNil(&classobj->instVarNames)) res = 0; else res = slotRawObject(&classobj->instVarNames)->size; return res; } int numClassVars(PyrClass* classobj) { int res; if (IsNil(&classobj->classVarNames)) res = 0; else res = slotRawObject(&classobj->classVarNames)->size; return res; } void objAddIndexedSlotGrow(PyrSlot *arraySlot, PyrSlot *addSlot); void objAddIndexedSlotGrow(PyrSlot *arraySlot, PyrSlot *addSlot) { PyrObject *obj; if (IsNil(arraySlot)) { PyrObject *newobj = (PyrObject*)newPyrArray(NULL, 1, obj_permanent | obj_immutable, false); SetObject(arraySlot, newobj); obj = newobj; } else { obj = slotRawObject(arraySlot); if (obj->size >= ARRAYMAXINDEXSIZE(obj)) { //post("objAddIndexedSlotGrow\n"); PyrObject *newobj = (PyrObject*)newPyrArray(NULL, obj->size * 2, obj_permanent | obj_immutable, false); memcpy(newobj->slots, obj->slots, obj->size * sizeof(PyrSlot)); newobj->size = obj->size; SetObject(arraySlot, newobj); pyr_pool_runtime->Free((void*)obj); obj = newobj; } } slotCopy(&obj->slots[obj->size++], addSlot); } void addMethod(PyrClass *classobj, PyrMethod *method) { PyrSlot slot; SetObject(&slot, method); objAddIndexedSlotGrow(&classobj->methods, &slot); } PyrMethod* classFindDirectMethod(PyrClass* classobj, PyrSymbol *name) { PyrMethod *method; PyrSlot *methods; int i, numMethods; if (IsNil(&classobj->methods)) return NULL; methods = slotRawObject(&classobj->methods)->slots; numMethods = slotRawObject(&classobj->methods)->size; for (i=0; iname) == name) break; } if (i>=numMethods) method = NULL; return method; } int numSuperInstVars(PyrClass *superclassobj) { int superinstvars = 0; if (superclassobj) { if (IsObj(&superclassobj->iprototype)) { superinstvars = slotRawObject(&superclassobj->iprototype)->size; } } return superinstvars; } bool classFindInstVar(PyrClass* classobj, PyrSymbol *name, int *index) { PyrSymbolArray *ivnames; PyrSymbol *ivname; int i; if (NotNil(&classobj->instVarNames)) { ivnames = slotRawSymbolArray(&classobj->instVarNames); if (ivnames) { for (i=0; isize; ++i) { ivname = ivnames->symbols[i]; if (ivname == name) { //numsupervars = numSuperInstVars(slotRawSymbol(&classobj->superclass)->u.classobj); //*index = numsupervars + i; *index = i; return true; } } } } return false; } int instVarOffset(const char *classname, const char *instvarname) { PyrSymbol *instvarsymbol, *classsymbol; PyrClass* classobj; int index; char c; classsymbol = getsym(classname); instvarsymbol = getsym(instvarname); c = classname[0]; if (!(c >= 'A' && c <= 'Z')) return -1; classobj = classsymbol->u.classobj; if (!classobj) return -1; if (!classFindInstVar(classobj, instvarsymbol, &index)) return -1; return index; } int classVarOffset(const char *classname, const char *classvarname, PyrClass** classobj) { PyrSymbol *classvarsymbol, *classsymbol; int index; char c; classsymbol = getsym(classname); classvarsymbol = getsym(classvarname); c = classname[0]; if (!(c >= 'A' && c <= 'Z')) return -1; *classobj = classsymbol->u.classobj; if (!*classobj) return -1; if (!classFindClassVar(classobj, classvarsymbol, &index)) return -1; return index; } bool classFindClassVar(PyrClass** classobj, PyrSymbol *name, int *index) { PyrSymbolArray *cvnames; PyrSymbol *cvname; int i, j; char *classname; PyrClass* localclassobj = *classobj; // if this is a Metaclass then we need to search its normal Class for // the class vars classname = slotRawSymbol(&localclassobj->name)->name; if (strncmp(classname, "Meta_", 5) == 0) { localclassobj = getsym(classname+5)->u.classobj; } for (j=0; localclassobj; ++j) { if (NotNil(&localclassobj->classVarNames)) { cvnames = slotRawSymbolArray(&localclassobj->classVarNames); if (cvnames) { for (i=0; isize; ++i) { cvname = cvnames->symbols[i]; if (cvname == name) { *classobj = localclassobj; *index = i; return true; } } } } if (IsSym(&localclassobj->superclass)) { localclassobj = slotRawSymbol(&localclassobj->superclass)->u.classobj; } else { localclassobj = NULL; } } return false; } bool classFindConst(PyrClass** classobj, PyrSymbol *name, int *index) { PyrSymbolArray *knames; PyrSymbol *kname; int i, j; char *classname; PyrClass* localclassobj = *classobj; // if this is a Metaclass then we need to search its normal Class for // the class vars classname = slotRawSymbol(&localclassobj->name)->name; if (strncmp(classname, "Meta_", 5) == 0) { localclassobj = getsym(classname+5)->u.classobj; } for (j=0; localclassobj; ++j) { if (NotNil(&localclassobj->constNames)) { knames = slotRawSymbolArray(&localclassobj->constNames); if (knames) { for (i=0; isize; ++i) { kname = knames->symbols[i]; if (kname == name) { *classobj = localclassobj; *index = i; return true; } } } } if (IsSym(&localclassobj->superclass)) { localclassobj = slotRawSymbol(&localclassobj->superclass)->u.classobj; } else { localclassobj = NULL; } } return false; } struct compareByName { bool operator()(PyrClass * lhs, PyrClass * rhs) const { return strcmp(slotRawSymbol(&lhs->name)->name, slotRawSymbol(&rhs->name)->name) < 0; } }; template class pyr_pool_compile_allocator { public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef pyr_pool_compile_allocator other; }; pyr_pool_compile_allocator(void) {} template pyr_pool_compile_allocator(pyr_pool_compile_allocator const &) {} pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } pointer allocate(size_type n, const void* hint = 0) { return (pointer)pyr_pool_compile->Alloc(n*sizeof(T)); } void deallocate(pointer p, size_type n) { pyr_pool_compile->Free(p); } void construct(pointer p, const T& val) { ::new(p) T(val); } void destroy(pointer p) { p->~T(); } }; /* sort list of classes: * we fill a binary search tree * */ static PyrClass * sortClasses(PyrClass * aClassList) { typedef std::set > classSetType; classSetType classSet; PyrClass * insertHead = aClassList; do { assert(classSet.find(insertHead) == classSet.end()); classSet.insert(insertHead); insertHead = slotRawClass(&insertHead->nextclass); } while (insertHead); classSetType::iterator it = classSet.begin(); PyrClass * sortedClasses = *it; ++it; PyrClass * lastClass = sortedClasses; for (; it != classSet.end(); ++it) { PyrClass * current = *it; SetObject(&lastClass->nextclass, (PyrObject*)current); lastClass = current; } SetNil(&lastClass->nextclass); return sortedClasses; } #include static int cpuCount = boost::thread::hardware_concurrency(); static int helperThreadCount = cpuCount - 1; static boost::threadpool::fifo_pool compileThreadPool; void buildClassTree() { // the first time we use the pool compileThreadPool.size_controller().resize(helperThreadCount); // after all classes are compiled this function builds the tree and // indexes the classes // count subclasses //postfl("count subclasses\n"); PyrClass *classobj = gClassList; while (classobj) { PyrClass * superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj; if (superclassobj) { //postfl(" superclassobj %s\n", slotRawSymbol(&superclassobj->name)->name); SetRaw(&superclassobj->subclasses, slotRawInt(&superclassobj->subclasses) + 1); } classobj = slotRawClass(&classobj->nextclass); } // allocate subclass arrays //postfl("allocate subclass arrays\n"); classobj = gClassList; while (classobj) { int numSubclasses; numSubclasses = slotRawInt(&classobj->subclasses); //postfl(" %s %d\n", slotRawSymbol(&classobj->name)->name, numSubclasses); if (numSubclasses) { SetObject(&classobj->subclasses, (PyrObject*)newPyrArray(NULL, numSubclasses, obj_permanent | obj_immutable, false)); slotRawObject(&classobj->subclasses)->size = 0; } else { SetNil(&classobj->subclasses); } classobj = slotRawClass(&classobj->nextclass); } // fill in subclass arrays //postfl("fill in subclass arrays\n"); classobj = gClassList; while (classobj) { //postfl(" %s\n", slotRawSymbol(&classobj->name)->name); PyrClass *superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj; if (superclassobj) { objAddIndexedObject(slotRawObject(&superclassobj->subclasses), (PyrObject*)classobj); //postfl(" superclassobj %s %d\n", slotRawSymbol(&superclassobj->name)->name, // slotRawObject(&superclassobj->subclasses)->size); } classobj = slotRawClass(&classobj->nextclass); } // alpha sort the classes via insertion sort gClassList = sortClasses(gClassList); } void indexClassTree(PyrClass *classobj, int numSuperMethods) { int i, numMethods; if (!classobj) return; SetInt(&classobj->classIndex, gNumClasses); gNumClasses ++; if (IsObj(&classobj->methods)) { PyrObject * methods = slotRawObject(&classobj->methods); numMethods = methods->size; } else numMethods = 0; numMethods = numSuperMethods + numMethods; if (IsObj(&classobj->subclasses)) { PyrObject * subclasses = slotRawObject(&classobj->subclasses); for (i=0; isize; ++i) indexClassTree(slotRawClass(&subclasses->slots[i]), numMethods); } SetInt(&classobj->maxSubclassIndex, gNumClasses - 1); } void findDiscrepancy(); void findDiscrepancy() { PyrClass *classobjA, *classobjB; classobjA = gClassList; while (classobjA) { classobjB = slotRawClass(&classobjA->nextclass);; while (classobjB) { if (slotRawSymbol(&classobjA->name) == slotRawSymbol(&classobjB->name)) { post("duplicate %s\n", slotRawSymbol(&classobjA->name)->name); } classobjB = slotRawClass(&classobjB->nextclass); } classobjA = slotRawClass(&classobjA->nextclass); } } static void indent(int n) { for (int i=0; iclassIndex)); indent(level); post("%s\n", slotRawSymbol(&classobj->name)->name); if (classobj == class_class) { indent(level+1); post(" [.. all metaclasses ..]\n"); } else { if (IsNil(&classobj->subclasses)) return; // FIXME: can we initialize subclasses with a NULL pointer? subclasses = slotRawObject(&classobj->subclasses); if (subclasses) { // determine if can put on one line bool oneline = subclasses->size <= 5; for (i=0; oneline && isize; ++i) { PyrClass *subclassobj = slotRawClass(&subclasses->slots[i]); if (IsObj(&subclassobj->subclasses)) // FIXME: shall we do a null-pointer check? oneline = false; } if (oneline) { indent(level+1); post("["); for (i=0; isize; ++i) { PyrClass *subclassobj = slotRawClass(&subclasses->slots[i]); post(" %s", slotRawSymbol(&subclassobj->name)->name); } post(" ]\n"); } else { indent(level); post("[\n"); for (i=0; isize; ++i) { postClassTree(slotRawClass(&subclasses->slots[i]), level+1); } indent(level); post("]\n"); } } } } void setSelectorFlags() { int i; PyrClass * classobj = gClassList; while (classobj) { if (IsObj(&classobj->methods)) { PyrObject *methods = slotRawObject(&classobj->methods); for (i=0; isize; ++i) { PyrMethod * method = slotRawMethod(&methods->slots[i]); slotRawSymbol(&method->name)->flags |= sym_Selector; //if (method->methType == methRedirect) { // post("rd: %3d %s:%s\n", k++, slotRawSymbol(&classobj->name)->name, // slotRawSymbol(&method->name)->name); //} } } classobj = slotRawClass(&classobj->nextclass); } // count selectors gNumSelectors = 0; SymbolTable* symbolTable = gMainVMGlobals->symbolTable; for (int i=0; iTableSize(); ++i) { PyrSymbol *sym = symbolTable->Get(i); if (sym && (sym->flags & sym_Selector)) { sym->u.index = gNumSelectors++; } } //post("gNumSelectors %d\n", gNumSelectors); } // the chunky stuff can be commented back in for implementing a better // compression scheme. The Q&D method works fine for my small class tree for now. typedef struct { PyrSymbol *selector; int minClassIndex; int maxClassIndex; int rowWidth; //int largestChunk; //int chunkOffset; int selectorIndex; int population; int rowOffset; } ColumnDescriptor; int compareColDescs(const void *va, const void *vb); int compareColDescs(const void *va, const void *vb) { ColumnDescriptor *a = (ColumnDescriptor*)va; ColumnDescriptor *b = (ColumnDescriptor*)vb; int diff; //diff = b->largestChunk - a->largestChunk; //if (diff != 0) return diff; diff = b->rowWidth - a->rowWidth; if (diff != 0) return diff; //diff = b->chunkOffset - a->chunkOffset; diff = b->minClassIndex - a->minClassIndex; return diff; } #define CHECK_METHOD_LOOKUP_TABLE_BUILD_TIME 0 #if CHECK_METHOD_LOOKUP_TABLE_BUILD_TIME double elapsedTime(); #endif static size_t fillClassRow(PyrClass *classobj, PyrMethod** bigTable); static void updateSelectorRowWidth(ColumnDescriptor* sels, size_t begin, size_t end) { for (int i=begin; i sels[i].largestChunk) { // sels[i].largestChunk = chunkSize; // sels[i].chunkOffset = chunkOffset; //} sels[i].rowWidth = sels[i].maxClassIndex - sels[i].minClassIndex + 1; } } static void binsortClassRows(PyrMethod ** bigTable, const ColumnDescriptor* sels, size_t numSelectors, size_t begin, size_t end) { // bin sort the class rows to the new ordering //post("reorder rows\n"); const int allocaThreshold = 4096; PyrMethod** temprow = (numSelectors < allocaThreshold) ? (PyrMethod**)alloca(numSelectors * sizeof(PyrMethod*)) : (PyrMethod**)malloc(numSelectors * sizeof(PyrMethod*)); for (int j=begin; j= allocaThreshold) free(temprow); } static void prepareColumnTable(ColumnDescriptor * sels, int numSelectors) { // fill selector table //post("fill selector table\n"); SymbolTable* symbolTable = gMainVMGlobals->symbolTable; for (int i=0, j=0; iTableSize(); ++i) { PyrSymbol *sym = symbolTable->Get(i); if (sym && (sym->flags & sym_Selector)) sels[j++].selector = sym; } for (int i=0; iname); sels[i].minClassIndex = INT_MAX; sels[i].maxClassIndex = 0; //sels[i].largestChunk = 0; //sels[i].chunkOffset = 0; sels[i].selectorIndex = i; sels[i].population = 0; } } static void calcRowStats(PyrMethod** bigTable, ColumnDescriptor * sels, int numClasses, int numSelectors, int begin, int end) { //chunkSize = 0; //chunkOffset = 0; for (int j=0; jownerclass.uoc; if (j > sels[i].maxClassIndex) { sels[i].maxClassIndex = j; } if (j < sels[i].minClassIndex) { sels[i].minClassIndex = j; } sels[i].population ++; //if (chunkSize == 0) chunkOffset = j; //chunkSize++; //postfl(" %8s %3d %3d %3d %3d\n", slotRawSymbol(&classobj->name)->name, i, j, // chunkSize, slotRawInt(&classobj->classIndex)); //} else { //if (chunkSize > sels[i].largestChunk) { // sels[i].largestChunk = chunkSize; // sels[i].chunkOffset = chunkOffset; //} //chunkSize = 0; } } } } void buildBigMethodMatrix() { PyrMethod **bigTable, **row; PyrClass *classobj, **classes; int i, j, k; int popSum, widthSum; int rowOffset, freeIndex; int rowTableSize; int bigTableSize; const int numSelectors = gNumSelectors; const int numClasses = gNumClasses; //post("allocate arrays\n"); #if CHECK_METHOD_LOOKUP_TABLE_BUILD_TIME double t0 = elapsedTime(); #endif // pyrmalloc: // lifetime: kill after compile bigTableSize = numSelectors * numClasses; //post("bigTableSize %d %d %d\n", bigTableSize, numSelectors, numClasses); ColumnDescriptor *sels = (ColumnDescriptor*)pyr_pool_compile->Alloc(numSelectors * sizeof(ColumnDescriptor)); MEMFAIL(sels); if (helperThreadCount) compileThreadPool.schedule(boost::bind(&prepareColumnTable, sels, numSelectors)); else prepareColumnTable(sels, numSelectors); bigTable = (PyrMethod**)pyr_pool_compile->Alloc(bigTableSize * sizeof(PyrMethod*)); MEMFAIL(bigTable); classes = (PyrClass**)pyr_pool_compile->Alloc(numClasses * sizeof(PyrClass*)); MEMFAIL(classes); classobj = gClassList; while (classobj) { classes[slotRawInt(&classobj->classIndex)] = classobj; classobj = slotRawClass(&classobj->nextclass); } size_t numentries = fillClassRow(class_object, bigTable); post("\tnumentries = %lu / %d = %.2g\n", numentries, bigTableSize, (double)numentries/(double)bigTableSize); // no need to wait for the theadpool, because it is done in fillClassRow // calc row stats //post("calc row stats\n"); const int classesPerThread = numClasses/cpuCount; const int selectorsPerThread = numSelectors/cpuCount; for (i = 0; i != helperThreadCount; ++i) compileThreadPool.schedule(boost::bind(&calcRowStats, bigTable, sels, numClasses, numSelectors, selectorsPerThread * i, selectorsPerThread * (i+1))); calcRowStats(bigTable, sels, numClasses, numSelectors, helperThreadCount*selectorsPerThread, numSelectors); if (helperThreadCount) compileThreadPool.wait(); for (i = 0; i != helperThreadCount; ++i) compileThreadPool.schedule(boost::bind(&updateSelectorRowWidth, sels, selectorsPerThread * i, selectorsPerThread * (i+1))); updateSelectorRowWidth(sels, helperThreadCount*selectorsPerThread, numSelectors); if (helperThreadCount) compileThreadPool.wait(); //post("qsort\n"); // sort rows by largest chunk, then by width, then by chunk offset //qsort(sels, numSelectors, sizeof(ColumnDescriptor), (std::_compare_function)compareColDescs); qsort(sels, numSelectors, sizeof(ColumnDescriptor), compareColDescs); // bin sort the class rows to the new ordering //post("reorder rows\n"); for (i = 0; i != helperThreadCount; ++i) compileThreadPool.schedule(boost::bind(&binsortClassRows, bigTable, sels, numSelectors, classesPerThread * i, classesPerThread * (i+1))); binsortClassRows(bigTable, sels, numSelectors, helperThreadCount*classesPerThread, numClasses); if (helperThreadCount) compileThreadPool.wait(); //post("calc row offsets %d\n", numSelectors); widthSum = 0; popSum = 0; freeIndex = 0; rowOffset = -1; for (i=0; iu.index = rowOffset; //post("%3d %24s %3d %5d %5d\n", i, sels[i].selector->name, // sels[i].rowWidth, rowOffset, freeIndex); } //post("alloc row table %d\n", freeIndex); rowTableSize = (freeIndex + numClasses) * sizeof(PyrMethod*); gRowTable = (PyrMethod**)pyr_pool_runtime->Alloc(rowTableSize); MEMFAIL(gRowTable); // having the method ptr always be valid saves a branch in SendMessage() for (i=0; iFree(classes); pyr_pool_compile->Free(bigTable); pyr_pool_compile->Free(sels); */ compileThreadPool.size_controller().resize(0); // terminate threads } #include static void fillClassRowSubClasses(PyrObject * subclasses, int begin, int end, PyrMethod** bigTable, boost::atomic * rCount); static void fillClassRow(PyrClass *classobj, PyrMethod** bigTable, boost::atomic * rCount) { size_t count = 0; PyrMethod ** myrow = bigTable + slotRawInt(&classobj->classIndex) * gNumSelectors; PyrClass* superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj; if (superclassobj) { PyrMethod ** superrow = bigTable + slotRawInt(&superclassobj->classIndex) * gNumSelectors; for (int i = 0; i != gNumSelectors; ++i) { myrow[i] = superrow[i]; if (superrow[i]) ++count; } } else { memset(myrow, 0, gNumSelectors * sizeof(PyrMethod*)); } if (IsObj(&classobj->methods)) { PyrObject * methods = slotRawObject(&classobj->methods); //postfl(" %d\n", methods->size); for (int i=0; isize; ++i) { PyrMethod* method = slotRawMethod(&methods->slots[i]); int selectorIndex = slotRawSymbol(&method->name)->u.index; if (myrow[selectorIndex] == 0) ++count; myrow[selectorIndex] = method; } } *rCount += count; if (IsObj(&classobj->subclasses)) { PyrObject * subclasses = slotRawObject(&classobj->subclasses); size_t numSubclasses = subclasses->size; if (numSubclasses > 4*cpuCount) { int subclassesPerThread = numSubclasses / cpuCount; for (int i = 0; i != helperThreadCount; ++i) compileThreadPool.schedule(boost::bind(&fillClassRowSubClasses, subclasses, subclassesPerThread * i, subclassesPerThread * (i+1), bigTable, rCount)); fillClassRowSubClasses(subclasses, subclassesPerThread * helperThreadCount, numSubclasses, bigTable, rCount); } else fillClassRowSubClasses(subclasses, 0, numSubclasses, bigTable, rCount); } } static void fillClassRowSubClasses(PyrObject * subclasses, int begin, int end, PyrMethod** bigTable, boost::atomic * rCount) { for (int i = begin; i != end; ++i) fillClassRow(slotRawClass(&subclasses->slots[i]), bigTable, rCount); } static size_t fillClassRow(PyrClass *classobj, PyrMethod** bigTable) { boost::atomic ret (0); fillClassRow(classobj, bigTable, &ret); if (helperThreadCount) compileThreadPool.wait(); return ret.load(boost::memory_order_acquire); } bool funcFindArg(PyrBlock* func, PyrSymbol *name, int *index) { int i; for (i=0; iargNames)->size; ++i) { if (slotRawSymbolArray(&func->argNames)->symbols[i] == name) { *index = i; return true; } } return false; } bool funcFindVar(PyrBlock* func, PyrSymbol *name, int *index) { int i; for (i=0; ivarNames)->size; ++i) { if (slotRawSymbolArray(&func->varNames)->symbols[i] == name) { *index = i; return true; } } return false; } PyrClass* makeIntrinsicClass(PyrSymbol *className, PyrSymbol *superClassName, int numInstVars, int numClassVars) { PyrClass *superClass = NULL; PyrClass *metaSuperClass = NULL; PyrSymbol *metaClassName = NULL; PyrSymbol *metaSuperClassName = NULL; PyrClass *classobj = NULL; PyrClass *metaclassobj = NULL; int superInstVars; //postfl("makeIntrinsicClass '%s'\n", className->name); if (superClassName) { superClass = superClassName->u.classobj; if (!superClass) { error("Can't find superclass '%s' of '%s'\n", superClassName->name, className->name); return NULL; } metaSuperClassName = getmetasym(superClassName->name); metaSuperClass = metaSuperClassName->u.classobj; superInstVars = numSuperInstVars(superClass); } else { // else it must be Object and so has no superclass metaSuperClassName = NULL; superInstVars = 0; } metaClassName = getmetasym(className->name); metaClassName->flags |= sym_MetaClass; metaclassobj = newClassObj( class_class, metaClassName, metaSuperClassName, classClassNumInstVars, 0, 0, 0, obj_notindexed, 0); SetInt(&metaclassobj->classFlags, slotRawInt(&metaclassobj->classFlags) | classIsIntrinsic); if (metaSuperClassName && classClassNumInstVars) { memcpy(slotRawObject(&metaclassobj->iprototype)->slots, slotRawObject(&metaSuperClass->iprototype)->slots, sizeof(PyrSlot) * classClassNumInstVars); memcpy(slotRawSymbolArray(&metaclassobj->instVarNames)->symbols, slotRawSymbolArray(&metaSuperClass->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars); slotRawObject(&metaclassobj->iprototype)->size = classClassNumInstVars; slotRawObject(&metaclassobj->instVarNames)->size = classClassNumInstVars; //dumpObject((PyrObject*)metaclassobj); } classobj = newClassObj(metaclassobj, className, superClassName, numInstVars + superInstVars, numClassVars, 0, 0, obj_notindexed, 0); SetInt(&classobj->classFlags, slotRawInt(&classobj->classFlags) | classIsIntrinsic); //postfl("%s:%s : %d\n", className->name, superClassName->name, superInstVars); if (superClass && superInstVars) { memcpy(slotRawObject(&classobj->iprototype)->slots, slotRawObject(&superClass->iprototype)->slots, sizeof(PyrSlot) * superInstVars); memcpy(slotRawSymbolArray(&classobj->instVarNames)->symbols, slotRawSymbolArray(&superClass->instVarNames)->symbols, sizeof(PyrSymbol*) * superInstVars); slotRawObject(&classobj->iprototype)->size = superInstVars; slotRawObject(&classobj->instVarNames)->size = superInstVars; } return classobj; } void addIntrinsicVar(PyrClass *classobj, const char *varName, PyrSlot *slot) { //postfl("%s %s %d\n", slotRawSymbol(&classobj->name)->name, varName, // slotRawObject(&classobj->instVarNames)->size); objAddIndexedSymbol(slotRawSymbolArray(&classobj->instVarNames), getsym(varName)); objAddIndexedSlot(slotRawObject(&classobj->iprototype), slot); } void addIntrinsicClassVar(PyrClass *classobj, const char *varName, PyrSlot *slot); void addIntrinsicClassVar(PyrClass *classobj, const char *varName, PyrSlot *slot) { //postfl("%s %s %d\n", slotRawSymbol(&classobj->name)->name, varName, // slotRawObject(&classobj->instVarNames)->size); objAddIndexedSymbol(slotRawSymbolArray(&classobj->classVarNames), getsym(varName)); objAddIndexedSlot(slotRawObject(&classobj->cprototype), slot); } void initClasses() { PyrClass *class_object_meta; PyrMethodRaw *methraw; // BOOTSTRAP THE OBJECT HIERARCHY gNumClassVars = 0; gClassList = NULL; gNullMethod = newPyrMethod(); SetSymbol(&gNullMethod->name, (PyrSymbol*)NULL); methraw = METHRAW(gNullMethod); methraw->methType = methNormal; // build intrinsic classes class_class = NULL; class_object = makeIntrinsicClass(s_object, 0, 0, 4); class_class = makeIntrinsicClass(s_class, s_object, classClassNumInstVars, 1); // now fix class_class ptrs that were just previously installed erroneously class_object->classptr->classptr = class_class; class_class->classptr->classptr = class_class; class_object_meta = class_object->classptr; class_object_meta->superclass = class_class->name; addIntrinsicClassVar(class_object, "dependantsDictionary", &o_nil); addIntrinsicClassVar(class_object, "currentEnvironment", &o_nil); addIntrinsicClassVar(class_object, "topEnvironment", &o_nil); addIntrinsicClassVar(class_object, "uniqueMethods", &o_nil); // declare varNames for Class addIntrinsicVar(class_class, "name", &o_nil); addIntrinsicVar(class_class, "nextclass", &o_nil); addIntrinsicVar(class_class, "superclass", &o_nil); addIntrinsicVar(class_class, "subclasses", &o_nil); addIntrinsicVar(class_class, "methods", &o_nil); addIntrinsicVar(class_class, "instVarNames", &o_nil); addIntrinsicVar(class_class, "classVarNames", &o_nil); addIntrinsicVar(class_class, "iprototype", &o_nil); addIntrinsicVar(class_class, "cprototype", &o_nil); addIntrinsicVar(class_class, "constNames", &o_nil); addIntrinsicVar(class_class, "constValues", &o_nil); addIntrinsicVar(class_class, "instanceFormat", &o_nil); addIntrinsicVar(class_class, "instanceFlags", &o_zero); addIntrinsicVar(class_class, "classIndex", &o_zero); addIntrinsicVar(class_class, "classFlags", &o_zero); addIntrinsicVar(class_class, "maxSubclassIndex", &o_zero); addIntrinsicVar(class_class, "filenameSymbol", &o_nil); addIntrinsicVar(class_class, "charPos", &o_zero); addIntrinsicVar(class_class, "classVarIndex", &o_zero); addIntrinsicClassVar(class_class, "classesInited", &o_nil); // class_object_meta's inst var names need to be copied from class_class // because class_class didn't exist when it was created memcpy(slotRawObject(&class_object_meta->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots, sizeof(PyrSlot) * classClassNumInstVars); memcpy(slotRawSymbolArray(&class_object_meta->instVarNames)->symbols, slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars); memcpy(slotRawObject(&class_class->classptr->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots, sizeof(PyrSlot) * classClassNumInstVars); memcpy(slotRawSymbolArray(&class_class->classptr->instVarNames)->symbols, slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars); // OK the next thing I need is arrays.. class_collection = makeIntrinsicClass(s_collection, s_object, 0, 0); class_sequenceable_collection = makeIntrinsicClass(s_sequenceable_collection, s_collection, 0, 0); class_arrayed_collection = makeIntrinsicClass(s_arrayed_collection, s_sequenceable_collection, 0, 0); class_array = makeIntrinsicClass(s_array, s_arrayed_collection, 0, 0); SetInt(&class_array->instanceFormat, obj_slot); SetInt(&class_array->classFlags, slotRawInt(&class_array->classFlags) | classHasIndexableInstances); // now fix array classptrs in already created classes fixClassArrays(class_class); fixClassArrays(class_class->classptr); fixClassArrays(class_object_meta); fixClassArrays(class_collection); fixClassArrays(class_sequenceable_collection); fixClassArrays(class_arrayed_collection); fixClassArrays(class_array); class_fundef = makeIntrinsicClass(s_fundef, s_object, 10, 0); // declare varNames for Block addIntrinsicVar(class_fundef, "raw1", &o_nil); addIntrinsicVar(class_fundef, "raw2", &o_nil); addIntrinsicVar(class_fundef, "code", &o_nil); addIntrinsicVar(class_fundef, "selectors", &o_nil); addIntrinsicVar(class_fundef, "constants", &o_nil); addIntrinsicVar(class_fundef, "prototypeFrame", &o_nil); addIntrinsicVar(class_fundef, "context", &o_nil); addIntrinsicVar(class_fundef, "argNames", &o_nil); addIntrinsicVar(class_fundef, "varNames", &o_nil); addIntrinsicVar(class_fundef, "sourceCode", &o_nil); class_method = makeIntrinsicClass(s_method, s_fundef, 5, 0); addIntrinsicVar(class_method, "ownerClass", &o_nil); addIntrinsicVar(class_method, "name", &o_nil); addIntrinsicVar(class_method, "primitiveName", &o_nil); addIntrinsicVar(class_method, "filenameSymbol", &o_nil); addIntrinsicVar(class_method, "charPos", &o_zero); //addIntrinsicVar(class_method, "byteMeter", &o_zero); //addIntrinsicVar(class_method, "callMeter", &o_zero); class_frame = makeIntrinsicClass(s_frame, s_object, 0, 0); SetInt(&class_frame->classFlags, slotRawInt(&class_frame->classFlags) | classHasIndexableInstances); //addIntrinsicVar(class_frame, "method", &o_nil); //addIntrinsicVar(class_frame, "caller", &o_nil); //addIntrinsicVar(class_frame, "context", &o_nil); //addIntrinsicVar(class_frame, "homeContext", &o_nil); //addIntrinsicVar(class_frame, "ip", &o_nil); class_process = makeIntrinsicClass(s_process, s_object, 6, 0); addIntrinsicVar(class_process, "classVars", &o_nil); addIntrinsicVar(class_process, "interpreter", &o_nil); addIntrinsicVar(class_process, "curThread", &o_nil); addIntrinsicVar(class_process, "mainThread", &o_nil); addIntrinsicVar(class_process, "schedulerQueue", &o_nil); addIntrinsicVar(class_process, "nowExecutingPath", &o_nil); class_interpreter = makeIntrinsicClass(s_interpreter, s_object, 29, 0); addIntrinsicVar(class_interpreter, "cmdLine", &o_nil); addIntrinsicVar(class_interpreter, "context", &o_nil); for (int i=0; i<26; ++i) { char name[2]; name[0] = 'a' + i; name[1] = 0; addIntrinsicVar(class_interpreter, name, &o_nil); } addIntrinsicVar(class_interpreter, "codeDump", &o_nil); addIntrinsicVar(class_interpreter, "preProcessor", &o_nil); class_absfunc = makeIntrinsicClass(s_absfunc, s_object, 0, 0); class_stream = makeIntrinsicClass(s_stream, s_absfunc, 0, 0); class_thread = makeIntrinsicClass(s_thread, s_stream, 27, 0); addIntrinsicVar(class_thread, "state", &o_nil); addIntrinsicVar(class_thread, "func", &o_nil); addIntrinsicVar(class_thread, "stack", &o_nil); addIntrinsicVar(class_thread, "method", &o_nil); addIntrinsicVar(class_thread, "block", &o_nil); addIntrinsicVar(class_thread, "frame", &o_nil); addIntrinsicVar(class_thread, "ip", &o_zero); addIntrinsicVar(class_thread, "sp", &o_zero); addIntrinsicVar(class_thread, "numpop", &o_zero); addIntrinsicVar(class_thread, "receiver", &o_nil); addIntrinsicVar(class_thread, "numArgsPushed", &o_zero); addIntrinsicVar(class_thread, "parent", &o_nil); addIntrinsicVar(class_thread, "terminalValue", &o_nil); addIntrinsicVar(class_thread, "primitiveError", &o_zero); addIntrinsicVar(class_thread, "primitiveIndex", &o_zero); addIntrinsicVar(class_thread, "randData", &o_zero); addIntrinsicVar(class_thread, "beats", &o_fzero); addIntrinsicVar(class_thread, "seconds", &o_fzero); addIntrinsicVar(class_thread, "clock", &o_nil); addIntrinsicVar(class_thread, "nextBeat", &o_nil); addIntrinsicVar(class_thread, "endBeat", &o_nil); addIntrinsicVar(class_thread, "endValue", &o_nil); addIntrinsicVar(class_thread, "environment", &o_nil); addIntrinsicVar(class_thread, "exceptionHandler", &o_nil); addIntrinsicVar(class_thread, "threadPlayer", &o_nil); addIntrinsicVar(class_thread, "executingPath", &o_nil); addIntrinsicVar(class_thread, "oldExecutingPath", &o_nil); class_finalizer = makeIntrinsicClass(s_finalizer, s_object, 2, 0); addIntrinsicVar(class_finalizer, "cFunction", &o_nil); addIntrinsicVar(class_finalizer, "object", &o_nil); class_routine = makeIntrinsicClass(s_routine, s_thread, 0, 0); class_symbol = makeIntrinsicClass(s_symbol, s_object, 0, 0); class_nil = makeIntrinsicClass(s_nil, s_object, 0, 0); class_boolean = makeIntrinsicClass(s_boolean, s_object, 0, 0); class_true = makeIntrinsicClass(s_true, s_boolean, 0, 0); class_false = makeIntrinsicClass(s_false, s_boolean, 0, 0); class_magnitude = makeIntrinsicClass(s_magnitude, s_object, 0, 0); class_char = makeIntrinsicClass(s_char, s_magnitude, 0, 0); class_number = makeIntrinsicClass(s_number, s_magnitude, 0, 0); class_simple_number = makeIntrinsicClass(s_simple_number, s_number, 0, 0); class_int = makeIntrinsicClass(s_int, s_simple_number, 0, 0); class_float = makeIntrinsicClass(s_float, s_simple_number, 0, 0); class_rawptr = makeIntrinsicClass(s_rawptr, s_object, 0, 0); /* class_complex = makeIntrinsicClass(s_complex, s_number, 2, 0); addIntrinsicVar(class_complex, "real", &o_nil); addIntrinsicVar(class_complex, "imag", &o_nil); */ class_rawarray = makeIntrinsicClass(s_rawarray, s_arrayed_collection, 0, 0); //SetInt(&class_rawarray->instanceFormat, obj_int8); //slotRawInt(&class_rawarray->classFlags) |= classHasIndexableInstances; class_int8array = makeIntrinsicClass(s_int8array, s_rawarray, 0, 0); SetInt(&class_int8array->instanceFormat, obj_int8); SetInt(&class_int8array->classFlags, slotRawInt(&class_int8array->classFlags) | classHasIndexableInstances); class_int16array = makeIntrinsicClass(s_int16array, s_rawarray, 0, 0); SetInt(&class_int16array->instanceFormat, obj_int16); SetInt(&class_int16array->classFlags, slotRawInt(&class_int16array->classFlags) | classHasIndexableInstances); class_int32array = makeIntrinsicClass(s_int32array, s_rawarray, 0, 0); SetInt(&class_int32array->instanceFormat, obj_int32); SetInt(&class_int32array->classFlags, slotRawInt(&class_int32array->classFlags) | classHasIndexableInstances); class_symbolarray = makeIntrinsicClass(s_symbolarray, s_rawarray, 0, 0); SetInt(&class_symbolarray->instanceFormat, obj_symbol); SetInt(&class_symbolarray->classFlags, slotRawInt(&class_symbolarray->classFlags) | classHasIndexableInstances); class_string = makeIntrinsicClass(s_string, s_rawarray, 0, 1); addIntrinsicClassVar(class_string, "unixCmdActions", &o_nil); SetInt(&class_string->instanceFormat, obj_char); SetInt(&class_string->classFlags, slotRawInt(&class_string->classFlags) | classHasIndexableInstances); class_floatarray = makeIntrinsicClass(s_floatarray, s_rawarray, 0, 0); SetInt(&class_floatarray->instanceFormat, obj_float); SetInt(&class_floatarray->classFlags, slotRawInt(&class_floatarray->classFlags) | classHasIndexableInstances); class_signal = makeIntrinsicClass(s_signal, s_floatarray, 0, 0); SetInt(&class_signal->instanceFormat, obj_float); SetInt(&class_signal->classFlags, slotRawInt(&class_signal->classFlags) | classHasIndexableInstances); class_wavetable = makeIntrinsicClass(s_wavetable, s_floatarray, 0, 0); SetInt(&class_wavetable->instanceFormat, obj_float); SetInt(&class_wavetable->classFlags, slotRawInt(&class_wavetable->classFlags) | classHasIndexableInstances); //addIntrinsicVar(class_signal, "rate", &o_nil); class_doublearray = makeIntrinsicClass(s_doublearray, s_rawarray, 0, 0); SetInt(&class_doublearray->instanceFormat, obj_double); SetInt(&class_doublearray->classFlags, slotRawInt(&class_doublearray->classFlags) | classHasIndexableInstances); class_list = makeIntrinsicClass(s_list, s_sequenceable_collection, 1, 0); addIntrinsicVar(class_list, "array", &o_nil); //addIntrinsicVar(class_list, "size", &o_zero); class_func = makeIntrinsicClass(s_func, s_absfunc, 2, 0); addIntrinsicVar(class_func, "def", &o_nil); addIntrinsicVar(class_func, "context", &o_nil); class_server_shm_interface = makeIntrinsicClass(s_server_shm_interface, s_object, 2, 0); addIntrinsicVar(class_server_shm_interface, "ptr", &o_nil); addIntrinsicVar(class_server_shm_interface, "finalizer", &o_nil); gTagClassTable[ 0] = NULL; gTagClassTable[ 1] = NULL; gTagClassTable[ 2] = class_int; gTagClassTable[ 3] = class_symbol; gTagClassTable[ 4] = class_char; gTagClassTable[ 5] = class_nil; gTagClassTable[ 6] = class_false; gTagClassTable[ 7] = class_true; gTagClassTable[ 8] = class_rawptr; gTagClassTable[ 9] = class_float; gTagClassTable[10] = class_float; gTagClassTable[11] = class_float; gTagClassTable[12] = class_float; SetObject(&o_emptyarray, newPyrArray(NULL, 0, obj_permanent | obj_immutable, false)); SetObject(&o_onenilarray, newPyrArray(NULL, 1, obj_permanent | obj_immutable, false)); slotRawObject(&o_onenilarray)->size = 1; SetNil(slotRawObject(&o_onenilarray)->slots); SetObject(&o_argnamethis, newPyrSymbolArray(NULL, 1, obj_permanent | obj_immutable, false)); slotRawSymbolArray(&o_argnamethis)->size = 1; slotRawSymbolArray(&o_argnamethis)->symbols[0] = s_this; /* post("array %p '%s'\n", class_array, class_array->name.us->name); post("o_emptyarray %p '%s'\n", slotRawObject(&o_emptyarray)->classptr, slotRawObject(&o_emptyarray)->classptr->name.us->name); post("o_argnamethis %p '%s'\n", slotRawObject(&o_argnamethis)->classptr, slotRawObject(&o_argnamethis)->classptr->name.us->name); post("o_onenilarray %p '%s'\n", slotRawObject(&o_onenilarray)->classptr, slotRawObject(&o_onenilarray)->classptr->name.us->name); dumpObjectSlot(&o_emptyarray); dumpObjectSlot(&o_argnamethis); dumpObjectSlot(&o_onenilarray); */ } PyrObject* instantiateObject(class PyrGC *gc, PyrClass* classobj, int size, bool fill, bool collect) { PyrObject *newobj, *proto; int numbytes, format, flags; format = slotRawInt(&classobj->instanceFormat); flags = slotRawInt(&classobj->instanceFlags); if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) { // create an indexable object numbytes = size * gFormatElemSize[format]; newobj = gc->New(numbytes, flags, format, collect); if (fill) { newobj->size = size; if (format == obj_slot) { nilSlots(newobj->slots, size); } else { memset(newobj->slots, format == obj_char ? ' ' : 0, size * gFormatElemSize[format]); } } else { newobj->size = 0; } } else { if (IsObj(&classobj->iprototype)) { proto = slotRawObject(&classobj->iprototype); size = proto->size; numbytes = size * sizeof(PyrSlot); newobj = gc->New(numbytes, flags, format, collect); newobj->size = size; if (size) { memcpy(newobj->slots, proto->slots, numbytes); } } else { numbytes = 0; newobj = gc->New(numbytes, flags, format, collect); newobj->size = 0; } } newobj->classptr = classobj; return newobj; } PyrObject* instantiateObjectLight(class PyrGC *gc, PyrClass* classobj, int size, bool collect); PyrObject* instantiateObjectLight(class PyrGC *gc, PyrClass* classobj, int size, bool collect) { PyrObject *newobj, *proto; int numbytes, format, flags; format = slotRawInt(&classobj->instanceFormat); flags = slotRawInt(&classobj->instanceFlags); if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) { numbytes = size * gFormatElemSize[format]; } else { if (IsObj(&classobj->iprototype)) { proto = slotRawObject(&classobj->iprototype); size = proto->size; numbytes = size * sizeof(PyrSlot); } else { size = 0; numbytes = 0; } } newobj = gc->New(numbytes, flags, format, collect); newobj->size = size; newobj->classptr = classobj; return newobj; } PyrObject* copyObject(class PyrGC *gc, PyrObject *inobj, bool collect) { PyrObject *newobj; int flags = ~(obj_immutable) & inobj->obj_flags; int elemsize = gFormatElemSize[inobj->obj_format]; int numbytes = inobj->size * elemsize; newobj = gc->New(numbytes, flags, inobj->obj_format, collect); newobj->size = inobj->size; newobj->classptr = inobj->classptr; memcpy(newobj->slots, inobj->slots, inobj->size * elemsize); return newobj; } PyrObject* copyObjectRange(class PyrGC *gc, PyrObject *inobj, int start, int end, bool collect) { PyrObject *newobj; if (start < 0) start = 0; if (end >= inobj->size) end = inobj->size - 1; int length = end - start + 1; if (length < 0) length = 0; int elemsize = gFormatElemSize[inobj->obj_format]; int numbytes = length * elemsize; int flags = ~(obj_immutable) & inobj->obj_flags; newobj = gc->New(numbytes, flags, inobj->obj_format, collect); newobj->size = length; newobj->classptr = inobj->classptr; if (length > 0) { memcpy(newobj->slots, (char*)(inobj->slots) + start * elemsize, length * elemsize); } return newobj; } void dumpObject(PyrObject *obj) { char str[256]; PyrClass *classobj; int i; if (obj == NULL) { postfl("NULL object pointer\n"); return; } classobj = obj->classptr; if (isKindOf(obj, class_class)) { post("class %s (%p) {\n", slotRawSymbol(&((PyrClass*)obj)->name)->name, obj); } else { //post("Instance of %s (%p) {\n", slotRawSymbol(&classobj->name)->name, obj); post("Instance of %s { (%p, gc=%02X, fmt=%02X, flg=%02X, set=%02X)\n", slotRawSymbol(&classobj->name)->name, obj, obj->gc_color, obj->obj_format, obj->obj_flags, obj->obj_sizeclass); } //flushPostBuf(); if (obj->obj_format == obj_notindexed) { post(" instance variables [%d]\n", obj->size); for (i=0; isize; ++i) { slotString(obj->slots + i, str); post(" %s : %s\n", slotRawSymbolArray(&classobj->instVarNames)->symbols[i]->name, str); } } else { int maxsize; post(" indexed slots [%d]\n", obj->size); maxsize = sc_min(32, obj->size); switch (obj->obj_format) { case obj_slot : for (i=0; islots + i, str); post(" %3d : %s\n", i, str); } break; case obj_double : for (i=0; islots[i])); } break; case obj_float : for (i=0; islots))[i]; post(" %3d : %g\n", i, val); } break; case obj_int32 : for (i=0; islots))[i]; post(" %3d : %d\n", i, val); } break; case obj_int16 : for (i=0; islots))[i]; post(" %3d : %d\n", i, val); } break; case obj_int8 : for (i=0; islots))[i]; post(" %3d : %4d %4u 0x%02X\n", i, val, val&255, val&255); } break; case obj_char : for (i=0; islots))[i]; post(" %3d : %c\n", i, val); } break; case obj_symbol : for (i=0; islots))[i]; post(" %3d : '%s'\n", i, sym->name); } break; default : post("unknown obj_format %X\n", obj->obj_format); } if (obj->size > maxsize) { post(" ...\n"); } } post("}\n"); } void dumpBadObject(PyrObject *obj) { char str[128]; PyrClass *classobj; int i; if (obj == NULL) { postfl("NULL object pointer\n"); return; } classobj = obj->classptr; if (isKindOf(obj, class_class)) { postfl("class %s (%p) {\n", slotRawSymbol(&((PyrClass*)obj)->name)->name, obj); } else { //postfl("Instance of %s (%p) {\n", slotRawSymbol(&classobj->name)->name, obj); postfl("Instance of %s { (%p, gc=%02X, fmt=%02X, flg=%02X, set=%02X)\n", slotRawSymbol(&classobj->name)->name, obj, obj->gc_color, obj->obj_format, obj->obj_flags, obj->obj_sizeclass); } if (obj->obj_format == obj_notindexed) { postfl(" instance variables [%d]\n", obj->size); for (i=0; isize; ++i) { slotString(obj->slots + i, str); postfl(" %s : %s\n", slotRawSymbolArray(&classobj->instVarNames)->symbols[i]->name, str); } } else { int maxsize; postfl(" indexed slots [%d]\n", obj->size); maxsize = obj->size; maxsize = sc_min(32, maxsize); switch (obj->obj_format) { case obj_slot : for (i=0; islots + i, str); postfl(" %3d : %s\n", i, str); } break; case obj_double : for (i=0; islots[i])); } break; case obj_float : for (i=0; islots))[i]; postfl(" %3d : %g\n", i, val); } break; case obj_int32 : for (i=0; islots))[i]; postfl(" %3d : %d\n", i, val); } break; case obj_int16 : for (i=0; islots))[i]; postfl(" %3d : %d\n", i, val); } break; case obj_int8 : for (i=0; islots))[i]; postfl(" %3d : %4d %4u 0x%02X\n", i, val, val&255, val&255); } break; case obj_char : for (i=0; islots))[i]; postfl(" %3d : %c\n", i, val); } break; case obj_symbol : for (i=0; islots))[i]; post(" %3d : '%s'\n", i, sym->name); } break; default : postfl("unknown obj_format %X\n", obj->obj_format); } if (obj->size > maxsize) { postfl(" ...\n"); } } postfl("}\n"); } void dumpObjectSlot(PyrSlot *slot) { if (IsObj(slot)) { dumpObject(slotRawObject(slot)); } else { dumpPyrSlot(slot); } } void dumpSlotOneWord(const char *tagstr, PyrSlot *slot) { char str[256]; slotOneWord(slot, str); post("%s %s\n", tagstr, str); } void CallStackSanity(VMGlobals *g, const char *tagstr); void CallStackSanity(VMGlobals *g, const char *tagstr) { PyrFrame *frame; frame = g->frame; while (frame) { if (FrameSanity(frame, tagstr)) { DumpBackTrace(g); //Debugger(); break; } frame = slotRawFrame(&frame->caller); } } bool FrameSanity(PyrFrame *frame, const char *tagstr); bool FrameSanity(PyrFrame *frame, const char *tagstr) { bool failed = false; if (frame==NULL) return false; if (NotObj(&frame->method)) { postfl("Frame %p method tag wrong %p\n", frame, GetTag(&frame->method)); failed = true; //} else if (!isKindOf((PyrObject*)slotRawObject(&frame->method)->classptr, class_fundef)) { } else if (slotRawObject(&frame->method)->classptr != class_method && slotRawObject(&frame->method)->classptr != class_fundef) { postfl("Frame %p method class wrong %p\n", frame, slotRawObject(&frame->method)->classptr); failed = true; //if (slotRawObject(&frame->method)->classptr->classptr == class_class) { postfl("class: '%s'\n", slotRawSymbol(&slotRawObject(&frame->method)->classptr->name)->name); ///} else { // postfl("not even a class\n"); //} } else if (NotObj(&slotRawBlock(&frame->method)->code)) { postfl("Method %p code tag wrong %p\n", slotRawBlock(&frame->method), GetTag(&slotRawBlock(&frame->method)->code)); failed = true; } else if (slotRawObject(&slotRawBlock(&frame->method)->code)->classptr != class_int8array) { postfl("Code %p class wrong %p\n", slotRawObject(&slotRawBlock(&frame->method)->code), slotRawObject(&slotRawBlock(&frame->method)->code)->classptr); postfl("class: '%s'\n", slotRawSymbol(&slotRawObject(&slotRawBlock(&frame->method)->code)->classptr->name)->name); failed = true; } /* if (frame->caller.utag != tagHFrame && frame->caller.utag != tagNil) { postfl("Frame %p caller tag wrong %p\n", frame, frame->caller.utag); failed = true; } if (frame->context.utag != tagHFrame && frame->context.utag != tagNil) { postfl("Frame %p context tag wrong %p\n", frame, frame->context.utag); failed = true; } if (frame->homeContext.utag != tagHFrame && frame->homeContext.utag != tagNil) { postfl("Frame %p homeContext tag wrong %p\n", frame, frame->homeContext.utag); failed = true; } */ if (!IsPtr(&frame->ip)) { postfl("Frame %p ip tag wrong %p\n", frame, GetTag(&frame->ip)); failed = true; } return failed; } void DumpFrame(PyrFrame *frame) { char str[256]; int i, numargs; PyrMethod *meth; PyrMethodRaw *methraw; if (FrameSanity(frame, "DumpFrame")) { post("FRAME CORRUPTED\n"); return; } slotOneWord(&frame->method, str); //slotString(&frame->method, str); meth = slotRawMethod(&frame->method); methraw = METHRAW(meth); if (methraw->numtemps) { post("\t%s %p\n", str, frame); numargs = methraw->numargs + methraw->varargs; for (i=0; inumtemps; ++i) { slotOneWord(frame->vars + i, str); //slotString(frame->vars + i, str); if (i < numargs) { post("\t\targ %s = %s\n", slotRawSymbolArray(&meth->argNames)->symbols[i]->name, str); } else { post("\t\tvar %s = %s\n", slotRawSymbolArray(&meth->varNames)->symbols[i - numargs]->name, str); } } } else { post("\t%s (no arguments or variables)\n", str); } } void dumpByteCodes(PyrBlock *theBlock); void DumpDetailedFrame(PyrFrame *frame); void DumpDetailedFrame(PyrFrame *frame) { char mstr[256]; char str[256]; int i, numargs; PyrMethod *meth; PyrMethodRaw *methraw; if (FrameSanity(frame, "DumpDetailedFrame")) { post("FRAME CORRUPTED\n"); return; } slotOneWord(&frame->method, mstr); //slotString(&frame->method, str); meth = slotRawMethod(&frame->method); methraw = METHRAW(meth); if (methraw->numtemps) { post("\t%s\n", mstr); numargs = methraw->numargs + methraw->varargs; for (i=0; inumtemps; ++i) { slotOneWord(frame->vars + i, str); //slotString(frame->vars + i, str); if (i < numargs) { post("\t\targ %s = %s\n", slotRawSymbolArray(&meth->argNames)->symbols[i]->name, str); } else { post("\t\tvar %s = %s\n", slotRawSymbolArray(&meth->varNames)->symbols[i - numargs]->name, str); } } } else { post("\t%s (no arguments or variables)\n", mstr); } post("\t....%s details:\n", mstr); post("\t\tneedsHeapContext = %d\n", methraw->needsHeapContext); post("\t\tnumtemps = %d\n", methraw->numtemps); post("\t\tpopSize = %d\n", methraw->popSize); slotString(&frame->method, str); post("\t\tmethod = %s\n", str); slotString(&frame->caller, str); post("\t\tcaller = %s\n", str); slotString(&frame->context, str); post("\t\tcontext = %s\n", str); slotString(&frame->homeContext, str); post("\t\thomeCtx = %s\n", str); slotString(&frame->ip, str); post("\t\tip = %s\n", str); if (IsPtr(&frame->ip)) { post("ipoffset = %d\n", (char*)slotRawPtr(&frame->ip) - (char*)slotRawInt8Array(&meth->code)->b); dumpByteCodes(meth); } } bool respondsTo(PyrSlot *slot, PyrSymbol *selector) { PyrClass *classobj; PyrMethod *meth; int index; classobj = classOfSlot(slot); index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; return slotRawSymbol(&meth->name) == selector; } PyrMethod* methodLookup(PyrSlot *slot, PyrSymbol *selector); PyrMethod* methodLookup(PyrSlot *slot, PyrSymbol *selector) { PyrClass *classobj; PyrMethod *meth; int index; classobj = classOfSlot(slot); index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; return meth; } bool isSubclassOf(PyrClass *classobj, PyrClass *testclass) { while (classobj) { if (classobj == testclass) { return true; } classobj = slotRawSymbol(&classobj->superclass)->u.classobj; } return false; } /*bool isKindOf(PyrObjectHdr *obj, PyrClass *testclass) { int objClassIndex = slotRawInt(&obj->classptr->classIndex); return objClassIndex >= slotRawInt(&testclass->classIndex) && objClassIndex <= slotRawInt(&testclass->maxSubclassIndex); }*/ bool objAddIndexedSlot(PyrObject *obj, PyrSlot *slot) { if (obj->size < ARRAYMAXINDEXSIZE(obj)) { slotCopy(&obj->slots[obj->size++], slot); return true; } else { return false; } } bool objAddIndexedSymbol(PyrSymbolArray *obj, PyrSymbol *symbol) { if (obj->size < MAXINDEXSIZE((PyrObject*)obj)) { obj->symbols[obj->size++] = symbol; return true; } else { return false; } } bool objAddIndexedObject(PyrObject *obj, PyrObject *obj2) { if (obj->size < ARRAYMAXINDEXSIZE(obj)) { SetObject(obj->slots + obj->size, obj2); obj->size++; return true; } else { return false; } } void fillSlots(PyrSlot* slot, int size, PyrSlot* fillslot) { for (int i = 0; i != size; ++i) slotCopy(&slot[i], fillslot); } void nilSlots(PyrSlot* slot, int size) { fillSlots(slot, size, &o_nil); } void zeroSlots(PyrSlot* slot, int size) { PyrSlot zero; SetTagRaw(&zero, 0); SetRaw(&zero, 0.0); fillSlots(slot, size, &zero); } PyrObject* newPyrObject(class PyrGC *gc, size_t inNumBytes, int inFlags, int inFormat, bool inCollect) { return gc->New(inNumBytes, inFlags, inFormat, inCollect); } PyrObject* newPyrArray(class PyrGC *gc, int size, int flags, bool collect) { PyrObject* array; int numbytes = size * sizeof(PyrSlot); if (!gc) array = PyrGC::NewPermanent(numbytes, flags, obj_slot); else array = gc->New(numbytes, flags, obj_slot, collect); array->classptr = class_array; return array; } PyrSymbolArray* newPyrSymbolArray(class PyrGC *gc, int size, int flags, bool collect) { PyrSymbolArray* array; int numbytes = size * sizeof(PyrSymbol*); if (!gc) array = (PyrSymbolArray*)PyrGC::NewPermanent(numbytes, flags, obj_symbol); else array = (PyrSymbolArray*)gc->New(numbytes, flags, obj_symbol, collect); array->classptr = class_symbolarray; return array; } PyrInt8Array* newPyrInt8Array(class PyrGC *gc, int size, int flags, bool collect) { PyrInt8Array* array; if (!gc) array = (PyrInt8Array*)PyrGC::NewPermanent(size, flags, obj_int8); else array = (PyrInt8Array*)gc->New(size, flags, obj_int8, collect); array->classptr = class_int8array; return array; } PyrInt32Array* newPyrInt32Array(class PyrGC *gc, int size, int flags, bool collect) { PyrInt32Array* array; int numbytes = size * sizeof(int32); if (!gc) array = (PyrInt32Array*)PyrGC::NewPermanent(numbytes, flags, obj_int32); else array = (PyrInt32Array*)gc->New(numbytes, flags, obj_int32, collect); array->classptr = class_int32array; return array; } PyrDoubleArray* newPyrDoubleArray(class PyrGC *gc, int size, int flags, bool collect) { PyrDoubleArray* array; int numbytes = size * sizeof(double); if (!gc) array = (PyrDoubleArray*)PyrGC::NewPermanent(numbytes, flags, obj_double); else array = (PyrDoubleArray*)gc->New(size, flags, obj_double, collect); array->classptr = class_doublearray; return array; } PyrString* newPyrString(class PyrGC *gc, const char *s, int flags, bool collect) { PyrString* string; int length = strlen(s); if (!gc) string = (PyrString*)PyrGC::NewPermanent(length, flags, obj_char); else string = (PyrString*)gc->New(length, flags, obj_char, collect); string->classptr = class_string; string->size = length; memcpy(string->s, s, length); return string; } PyrString* newPyrStringN(class PyrGC *gc, int length, int flags, bool collect) { PyrString* string; if (!gc) string = (PyrString*)PyrGC::NewPermanent(length, flags, obj_char); else string = (PyrString*)gc->New(length, flags, obj_char, collect); string->classptr = class_string; string->size = length; // filled with garbage! return string; } PyrBlock* newPyrBlock(int flags) { PyrBlock* block; PyrMethodRaw *methraw; int32 numbytes = sizeof(PyrBlock) - sizeof(PyrObjectHdr); int32 numSlots = numbytes / sizeof(PyrSlot); if (!compilingCmdLine) block = (PyrBlock*)PyrGC::NewPermanent(numbytes, flags, obj_notindexed); else block = (PyrBlock*)gMainVMGlobals->gc->New(numbytes, flags, obj_notindexed, false); block->classptr = class_fundef; block->size = numSlots; // clear out raw area methraw = METHRAW(block); methraw->specialIndex = 0; methraw->methType = methBlock; methraw->needsHeapContext = 0; methraw->frameSize = 0; methraw->varargs = 0; methraw->numargs = 0; methraw->numvars = 0; methraw->numtemps = 0; methraw->popSize = 0; nilSlots(&block->rawData1, numSlots); return block; } SC_DLLEXPORT_C struct VMGlobals* scGlobals() { return gMainVMGlobals; } PyrMethod* initPyrMethod(PyrMethod* method) { int32 numbytes = sizeof(PyrMethod) - sizeof(PyrObjectHdr); int32 numSlots = numbytes / sizeof(PyrSlot); method->classptr = class_method; method->size = 0; method->size = numSlots; SetFloat(&method->rawData1, 0.0); SetFloat(&method->rawData2, 0.0); nilSlots(&method->code, numSlots-2); //slotCopy(&method->byteMeter, &o_zero); //slotCopy(&method->callMeter, &o_zero); //post("<- newPyrMethod %p %p\n", method, methraw); return method; } PyrMethod* newPyrMethod() { int32 numbytes = sizeof(PyrMethod) - sizeof(PyrObjectHdr); PyrMethod* method = (PyrMethod*)PyrGC::NewPermanent(numbytes, obj_permanent | obj_immutable, obj_notindexed); return initPyrMethod(method); } void freePyrSlot(PyrSlot *slot) { if (IsObj(slot)) { PyrObject *obj = slotRawObject(slot); if (obj && obj->IsPermanent()) { // don't deallocate these if (obj != slotRawObject(&o_emptyarray) && obj != slotRawObject(&o_onenilarray) && obj != slotRawObject(&o_argnamethis)) pyr_pool_runtime->Free((void*)obj); SetNil(slot); } } } void freePyrObject(PyrObject *obj) { if (obj->IsPermanent()) { pyr_pool_runtime->Free((void*)obj); } } int getIndexedInt(PyrObject *obj, int index, int *value) { PyrSlot *slot; int err = errNone; if (index < 0 || index >= obj->size) return errIndexOutOfRange; switch (obj->obj_format) { case obj_slot : slot = obj->slots + index; if (IsFloat(slot)) { *value = (int)slotRawFloat(slot); } else if (IsInt(slot)) { *value = slotRawInt(slot); } else { err = errWrongType; } break; case obj_double : *value = (int)((double*)(obj->slots))[index]; break; case obj_float : *value = (int)((float*)(obj->slots))[index]; break; case obj_int32 : *value = ((int32*)(obj->slots))[index]; break; case obj_int16 : *value = ((int16*)(obj->slots))[index]; break; case obj_int8 : *value = ((int8*)(obj->slots))[index]; break; default : err = errWrongType; } return err; } int getIndexedFloat(PyrObject *obj, int index, float *value) { PyrSlot *slot; int err = errNone; if (index < 0 || index >= obj->size) return errIndexOutOfRange; switch (obj->obj_format) { case obj_slot : slot = obj->slots + index; if (IsFloat(slot)) { *value = slotRawFloat(slot); } else if (IsInt(slot)) { *value = slotRawInt(slot); } else { err = errWrongType; } break; case obj_double : *value = ((double*)(obj->slots))[index]; break; case obj_float : *value = ((float*)(obj->slots))[index]; break; case obj_int32 : *value = ((int32*)(obj->slots))[index]; break; case obj_int16 : *value = ((int16*)(obj->slots))[index]; break; case obj_int8 : *value = ((int8*)(obj->slots))[index]; break; default : err = errWrongType; } return err; } int getIndexedDouble(PyrObject *obj, int index, double *value) { PyrSlot *slot; int err = errNone; if (index < 0 || index >= obj->size) return errIndexOutOfRange; switch (obj->obj_format) { case obj_slot : slot = obj->slots + index; if (IsFloat(slot)) { *value = slotRawFloat(slot); } else if (IsInt(slot)) { *value = slotRawInt(slot); } else { err = errWrongType; } break; case obj_double : *value = ((double*)(obj->slots))[index]; break; case obj_float : *value = ((float*)(obj->slots))[index]; break; case obj_int32 : *value = ((int32*)(obj->slots))[index]; break; case obj_int16 : *value = ((int16*)(obj->slots))[index]; break; case obj_int8 : *value = ((int8*)(obj->slots))[index]; break; default : err = errWrongType; } return err; } void getIndexedSlot(PyrObject *obj, PyrSlot *a, int index) { // postfl("getIndexedSlot %s %X %d\n", slotRawSymbol(&obj->classptr->name)->name, // obj, index); switch (obj->obj_format) { case obj_slot : slotCopy(a, &obj->slots[index]); break; case obj_double : SetFloat(a, ((double*)(obj->slots))[index]); break; case obj_float : SetFloat(a, ((float*)(obj->slots))[index]); break; case obj_int32 : SetInt(a, ((int32*)(obj->slots))[index]); break; case obj_int16 : SetInt(a, ((int16*)(obj->slots))[index]); break; case obj_int8 : SetInt(a, ((int8*)(obj->slots))[index]); break; case obj_symbol : SetSymbol(a, (PyrSymbol*)((int**)(obj->slots))[index]); break; case obj_char : SetChar(a, ((unsigned char*)(obj->slots))[index]); break; } } int putIndexedSlot(VMGlobals *g, PyrObject *obj, PyrSlot *c, int index) { PyrSlot *slot; switch (obj->obj_format) { case obj_slot : if (obj->IsImmutable()) return errImmutableObject; slot = obj->slots + index; slotCopy(slot, c); g->gc->GCWrite(obj, slot); break; case obj_double : if (NotFloat(c)) { if (NotInt(c)) return errWrongType; else { ((double*)(obj->slots))[index] = slotRawInt(c); } } else ((double*)(obj->slots))[index] = slotRawFloat(c); break; case obj_float : if (NotFloat(c)) { if (NotInt(c)) return errWrongType; else { ((float*)(obj->slots))[index] = slotRawInt(c); } } else ((float*)(obj->slots))[index] = slotRawFloat(c); break; case obj_int32 : if (NotInt(c)) return errWrongType; ((int32*)(obj->slots))[index] = slotRawInt(c); break; case obj_int16 : if (NotInt(c)) return errWrongType; ((int16*)(obj->slots))[index] = slotRawInt(c); break; case obj_int8 : if (NotInt(c)) return errWrongType; ((int8*)(obj->slots))[index] = slotRawInt(c); break; case obj_symbol : if (NotSym(c)) return errWrongType; ((PyrSymbol**)(obj->slots))[index] = slotRawSymbol(c); break; case obj_char : if (NotChar(c)) return errWrongType; ((unsigned char*)(obj->slots))[index] = slotRawChar(c); break; } return errNone; } int putIndexedFloat(PyrObject *obj, double val, int index) { PyrSlot *slot; switch (obj->obj_format) { case obj_slot : if (obj->IsImmutable()) return errImmutableObject; slot = obj->slots + index; SetFloat(slot, val); break; case obj_double : ((double*)(obj->slots))[index] = val; break; case obj_float : ((float*)(obj->slots))[index] = (float)val; break; case obj_int32 : ((int32*)(obj->slots))[index] = (int32)val; break; case obj_int16 : ((int16*)(obj->slots))[index] = (int16)val; break; case obj_int8 : ((int8*)(obj->slots))[index] = (int8)val; break; } return errNone; } static int hashPtr(void* ptr) { int32 hashed_part = int32((size_t)ptr&0xffffffff); return Hash(hashed_part); } int calcHash(PyrSlot *a); int calcHash(PyrSlot *a) { int hash; switch (GetTag(a)) { case tagObj : hash = hashPtr(slotRawObject(a)); break; case tagInt : hash = Hash(slotRawInt(a)); break; case tagChar : hash = Hash(slotRawChar(a) & 255); break; case tagSym : hash = slotRawSymbol(a)->hash; break; case tagNil : hash = 0xA5A5A5A5; break; case tagFalse : hash = 0x55AA55AA; break; case tagTrue : hash = 0x69696969; break; case tagPtr : hash = hashPtr(slotRawPtr(a)); break; default : // hash for a double union { int32 i[2]; double d; } u; u.d = slotRawFloat(a); hash = Hash(u.i[0] + Hash(u.i[1])); } return hash; } void InstallFinalizer(VMGlobals* g, PyrObject *inObj, int slotIndex, ObjFuncPtr inFunc) { PyrObject *finalizer = g->gc->NewFinalizer(inFunc, inObj, false); SetObject(inObj->slots + slotIndex, finalizer); g->gc->GCWrite(inObj, finalizer); } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/DumpParseNode.cpp0000664000000000000000000003605512161364457025200 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SCBase.h" #include "PyrParseNode.h" #include "PyrLexer.h" #include "PyrKernel.h" #include "Opcodes.h" #include "PyrPrimitive.h" #include #include #include #include #ifdef _WIN32 # define snprintf _snprintf # define PATH_MAX _MAX_PATH #endif extern int textpos; void dumpNodeList(PyrParseNode *node) { for (; node; node = node->mNext) { DUMPNODE(node, 0); } } void PyrCurryArgNode::dump(int level) { postfl("%2d CurryArg %d\n", level, mArgNum); } void PyrSlotNode::dump(int level) { if (mClassno == pn_PushLitNode) dumpPushLit(level); else if (mClassno == pn_PushNameNode) postfl("%2d PushName '%s'\n", level, slotRawSymbol(&mSlot)->name); else if (mClassno == pn_LiteralNode) dumpLiteral(level); else { postfl("%2d SlotNode\n", level); dumpPyrSlot(&mSlot); } DUMPNODE(mNext, level); } void PyrPushKeyArgNode::dump(int level) { postfl("%2d PushKeyArgNode\n", level); DUMPNODE(mSelector, level+1); DUMPNODE(mExpr, level+1); DUMPNODE(mNext, level); } void PyrClassExtNode::dump(int level) { postfl("%2d ClassExt '%s'\n", level, slotRawSymbol(&mClassName->mSlot)->name); DUMPNODE(mMethods, level+1); DUMPNODE(mNext, level); } void PyrClassNode::dump(int level) { postfl("%2d Class '%s'\n", level, slotRawSymbol(&mClassName->mSlot)->name); DUMPNODE(mSuperClassName, level+1); DUMPNODE(mVarlists, level+1); DUMPNODE(mMethods, level+1); DUMPNODE(mNext, level); } void PyrMethodNode::dump(int level) { postfl("%2d MethodNode '%s' %s\n", level, slotRawSymbol(&mMethodName->mSlot)->name, mPrimitiveName ? slotRawSymbol(&mPrimitiveName->mSlot)->name:""); DUMPNODE(mArglist, level+1); DUMPNODE(mBody, level+1); DUMPNODE(mNext, level); } void PyrArgListNode::dump(int level) { postfl("%2d ArgList\n", level); DUMPNODE(mVarDefs, level+1); DUMPNODE(mRest, level+1); DUMPNODE(mNext, level); } void PyrVarListNode::dump(int level) { postfl("%2d VarList\n", level); DUMPNODE(mVarDefs, level+1); DUMPNODE(mNext, level); } void PyrVarDefNode::dump(int level) { postfl("%2d VarDef '%s'\n", level, slotRawSymbol(&mVarName->mSlot)->name); DUMPNODE(mDefVal, level); DUMPNODE(mNext, level); } void PyrCallNode::dump(int level) { postfl("%2d Call '%s'\n", level, slotRawSymbol(&mSelector->mSlot)->name); DUMPNODE(mArglist, level+1); DUMPNODE(mKeyarglist, level+1); DUMPNODE(mNext, level); } void PyrBinopCallNode::dump(int level) { postfl("%2d BinopCall '%s'\n", level, slotRawSymbol(&mSelector->mSlot)->name); DUMPNODE(mArglist, level+1); DUMPNODE(mNext, level); } void PyrDropNode::dump(int level) { postfl("%2d Drop (\n", level); DUMPNODE(mExpr1, level+1); postfl(" -> %2d Drop\n", level); DUMPNODE(mExpr2, level+1); postfl(") %2d Drop\n", level); DUMPNODE(mNext, level); } void PyrSlotNode::dumpPushLit(int level) { postfl("%2d PushLit\n", level); if (!IsPtr(&mSlot)) dumpPyrSlot(&mSlot); else { DUMPNODE((PyrParseNode*)slotRawObject(&mSlot), level); } } void PyrSlotNode::dumpLiteral(int level) { postfl("%2d Literal\n", level); if (!IsPtr(&mSlot)) dumpPyrSlot(&mSlot); else { DUMPNODE((PyrParseNode*)slotRawObject(&mSlot), level); } } void PyrReturnNode::dump(int level) { postfl("%2d Return (\n", level); DUMPNODE(mExpr, level+1); postfl(") %2d Return \n", level); DUMPNODE(mNext, level); } void PyrBlockReturnNode::dump(int level) { postfl("%2d FuncReturn\n", level); DUMPNODE(mNext, level); } void PyrAssignNode::dump(int level) { postfl("%2d Assign '%s'\n", level, slotRawSymbol(&mVarName->mSlot)->name); DUMPNODE(mVarName, level+1); DUMPNODE(mExpr, level+1); DUMPNODE(mNext, level); } void PyrSetterNode::dump(int level) { //postfl("%2d Assign '%s'\n", level, slotRawSymbol(&mVarName->mSlot)->name); DUMPNODE(mSelector, level+1); DUMPNODE(mExpr1, level+1); DUMPNODE(mExpr2, level+1); } void PyrMultiAssignNode::dump(int level) { postfl("%2d MultiAssign\n", level); DUMPNODE(mVarList, level+1); DUMPNODE(mExpr, level+1); DUMPNODE(mNext, level); } void PyrMultiAssignVarListNode::dump(int level) { postfl("%2d MultiAssignVarList\n", level); DUMPNODE(mVarNames, level+1); DUMPNODE(mRest, level+1); DUMPNODE(mNext, level); } void PyrDynDictNode::dump(int level) { postfl("%2d DynDict\n", level); DUMPNODE(mElems, level+1); DUMPNODE(mNext, level); } void PyrDynListNode::dump(int level) { postfl("%2d DynList\n", level); DUMPNODE(mElems, level+1); DUMPNODE(mNext, level); } void PyrLitListNode::dump(int level) { postfl("%2d LitList\n", level); postfl(" %2d mElems\n", level); DUMPNODE(mElems, level+1); postfl(" %2d mNext\n", level); DUMPNODE(mNext, level); } void PyrBlockNode::dump(int level) { postfl("%2d Func\n", level); DUMPNODE(mArglist, level+1); DUMPNODE(mBody, level+1); DUMPNODE(mNext, level); } void dumpPyrSlot(PyrSlot* slot) { char str[1024]; slotString(slot, str); post(" %s\n", str); } void slotString(PyrSlot *slot, char *str) { switch (GetTag(slot)) { case tagInt : sprintf(str, "Integer %d", slotRawInt(slot)); break; case tagChar : sprintf(str, "Character %d '%c'", static_cast(slotRawChar(slot)), static_cast(slotRawChar(slot))); break; case tagSym : if (strlen(slotRawSymbol(slot)->name) > 240) { char str2[256]; memcpy(str2, slotRawSymbol(slot)->name, 240); str2[240] = 0; snprintf(str, 256, "Symbol '%s...'", str2); } else { snprintf(str, 256, "Symbol '%s'", slotRawSymbol(slot)->name); } break; case tagObj : if (slotRawObject(slot)) { PyrClass * classptr = slotRawObject(slot)->classptr; if (classptr == class_class) { sprintf(str, "class %s (%p)", slotRawSymbol(&((PyrClass*)slotRawObject(slot))->name)->name, slotRawObject(slot)); } else if (classptr == class_string) { char str2[48]; int len; if (slotRawObject(slot)->size > 47) { memcpy(str2, (char*)slotRawObject(slot)->slots, 44); str2[44] = '.'; str2[45] = '.'; str2[46] = '.'; str2[47] = 0; } else { len = sc_min(47, slotRawObject(slot)->size); memcpy(str2, (char*)slotRawObject(slot)->slots, len); str2[len] = 0; } sprintf(str, "\"%s\"", str2); } else if (classptr == class_method) { sprintf(str, "instance of Method %s:%s (%p)", slotRawSymbol(&slotRawClass(&slotRawMethod(slot)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(slot)->name)->name, slotRawMethod(slot)); } else if (classptr == class_fundef) { PyrSlot *context, *nextcontext; // find function's method nextcontext = &slotRawBlock(slot)->contextDef; if (NotNil(nextcontext)) { do { context = nextcontext; nextcontext = &slotRawBlock(context)->contextDef; } while (NotNil(nextcontext)); if (isKindOf(slotRawObject(context), class_method)) { sprintf(str, "instance of FunctionDef in Method %s:%s", slotRawSymbol(&slotRawClass(&slotRawMethod(context)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(context)->name)->name); } else { sprintf(str, "instance of FunctionDef in closed FunctionDef"); } } else { sprintf(str, "instance of FunctionDef - closed"); } } else if (classptr == class_frame) { if (!slotRawFrame(slot)) { sprintf(str, "Frame (%0X)", slotRawInt(slot)); } else if (slotRawBlock(&slotRawFrame(slot)->method)->classptr == class_method) { sprintf(str, "Frame (%p) of %s:%s", slotRawObject(slot), slotRawSymbol(&slotRawClass(&slotRawMethod(&slotRawFrame(slot)->method)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(&slotRawFrame(slot)->method)->name)->name); } else { sprintf(str, "Frame (%p) of Function", slotRawFrame(slot)); } } else { sprintf(str, "instance of %s (%p, size=%d, set=%d)", slotRawSymbol(&classptr->name)->name, slotRawObject(slot), slotRawObject(slot)->size, slotRawObject(slot)->obj_sizeclass); } } else { sprintf(str, "NULL Object Pointer"); } break; case tagNil : sprintf(str, "nil"); break; case tagFalse : sprintf(str, "false"); break; case tagTrue : sprintf(str, "true"); break; case tagPtr : sprintf(str, "RawPointer %p", slotRawPtr(slot)); break; default : { union { int32 i[2]; double f; } u; u.f = slotRawFloat(slot); sprintf(str, "Float %f %08X %08X", u.f, u.i[0], u.i[1]); break; } } } static void printObject(PyrSlot * slot, PyrObject * obj, char *str) { assert(obj); PyrClass * classptr = obj->classptr; if (classptr == class_class) { sprintf(str, "class %s", slotRawSymbol(&((PyrClass*)obj)->name)->name); } else if (classptr == class_string) { char str2[32]; int len; if (obj->size > 31) { memcpy(str2, (char*)obj->slots, 28); str2[28] = '.'; str2[29] = '.'; str2[30] = '.'; str2[31] = 0; } else { len = sc_min(31, obj->size); memcpy(str2, (char*)obj->slots, len); str2[len] = 0; } sprintf(str, "\"%s\"", str2); } else if (classptr == class_method) { sprintf(str, "%s:%s", slotRawSymbol(&slotRawClass(&slotRawMethod(slot)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(slot)->name)->name); } else if (classptr == class_fundef) { PyrSlot *context, *nextcontext; // find function's method nextcontext = &slotRawBlock(slot)->contextDef; if (NotNil(nextcontext)) { do { context = nextcontext; nextcontext = &slotRawBlock(context)->contextDef; } while (NotNil(nextcontext)); if (isKindOf(slotRawObject(context), class_method)) { sprintf(str, "< FunctionDef in Method %s:%s >", slotRawSymbol(&slotRawClass(&slotRawMethod(context)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(context)->name)->name); } else { sprintf(str, "< FunctionDef in closed FunctionDef >"); } } else { sprintf(str, "< closed FunctionDef >"); } } else if (classptr == class_frame) { if (!slotRawFrame(slot)) { sprintf(str, "Frame (null)"); } else if (!slotRawBlock(&slotRawFrame(slot)->method)) { sprintf(str, "Frame (null method)"); } else if (slotRawBlock(&slotRawFrame(slot)->method)->classptr == class_method) { sprintf(str, "Frame (%p) of %s:%s", obj, slotRawSymbol(&slotRawClass(&slotRawMethod(&slotRawFrame(slot)->method)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(&slotRawFrame(slot)->method)->name)->name); } else { sprintf(str, "Frame (%p) of Function", obj); } } else if (classptr == class_array) { sprintf(str, "[*%d]", obj->size); } else { sprintf(str, "", slotRawSymbol(&classptr->name)->name); } } void slotOneWord(PyrSlot *slot, char *str) { str[0] = 0; switch (GetTag(slot)) { case tagInt : sprintf(str, "%d", slotRawInt(slot)); break; case tagChar : sprintf(str, "$%c", static_cast(slotRawChar(slot))); break; case tagSym : if (strlen(slotRawSymbol(slot)->name) > 240) { char str2[256]; memcpy(str2, slotRawSymbol(slot)->name, 240); str2[240] = 0; snprintf(str, 256, "'%s...'", str2); } else { snprintf(str, 256, "'%s'", slotRawSymbol(slot)->name); } break; case tagObj : { PyrObject * slotObj = slotRawObject(slot); if (slotObj) printObject(slot, slotObj, str); else sprintf(str, "NULL Object Pointer"); break; } case tagNil : sprintf(str, "nil"); break; case tagFalse : sprintf(str, "false"); break; case tagTrue : sprintf(str, "true"); break; case tagPtr : sprintf(str, "ptr%p", slotRawPtr(slot)); break; default : sprintf(str, "%.14g", slotRawFloat(slot)); break; } } bool postString(PyrSlot *slot, char *str) { bool res = true; switch (GetTag(slot)) { case tagInt : sprintf(str, "%d", slotRawInt(slot)); break; case tagChar : sprintf(str, "%c", slotRawChar(slot)); break; case tagSym : str[0] = 0; res = false; break; case tagObj : { PyrObject * slotObj = slotRawObject(slot); if (slotObj) { PyrClass * classptr = slotRawObject(slot)->classptr; if (classptr == class_class || classptr == class_method || classptr == class_fundef || classptr == class_frame) printObject(slot, slotObj, str); else { str[0] = 0; res = false; } } else sprintf(str, "NULL Object Pointer"); break; } case tagNil : sprintf(str, "nil"); break; case tagFalse : sprintf(str, "false"); break; case tagTrue : sprintf(str, "true"); break; case tagPtr : sprintf(str, "%p", slotRawPtr(slot)); break; default : sprintf(str, "%.14g", slotRawFloat(slot)); break; } return res; } int asCompileString(PyrSlot *slot, char *str) { switch (GetTag(slot)) { case tagInt : sprintf(str, "%d", slotRawInt(slot)); break; case tagChar : { int c = slotRawChar(slot); if (isprint(c)) { sprintf(str, "$%c", c); } else { switch (c) { case '\n' : strcpy(str, "$\\n"); break; case '\r' : strcpy(str, "$\\r"); break; case '\t' : strcpy(str, "$\\t"); break; case '\f' : strcpy(str, "$\\f"); break; case '\v' : strcpy(str, "$\\v"); break; default: sprintf(str, "%d.asAscii", c); } } break; } case tagSym : return errFailed; case tagObj : return errFailed; case tagNil : sprintf(str, "nil"); break; case tagFalse : sprintf(str, "false"); break; case tagTrue : sprintf(str, "true"); break; case tagPtr : strcpy(str, "/*Ptr*/ nil"); break; default : sprintf(str, "%f", slotRawFloat(slot)); break; } return errNone; } void stringFromPyrString(PyrString *obj, char *str, int maxlength); void stringFromPyrString(PyrString *obj, char *str, int maxlength) { if (obj->classptr == class_string) { int len; if (obj->size > maxlength-4) { memcpy(str, obj->s, maxlength-4); str[maxlength-4] = '.'; str[maxlength-3] = '.'; str[maxlength-2] = '.'; str[maxlength-1] = 0; } else { len = sc_min(maxlength-1, obj->size); memcpy(str, obj->s, len); str[len] = 0; } } else { sprintf(str, "not a string"); } } void pstrncpy(unsigned char *s1, unsigned char *s2, int n); void pstringFromPyrString(PyrString *obj, unsigned char *str, int maxlength) { static const char not_a_string[] = "not a string"; const char * src; int len; if (obj && obj->classptr == class_string) { len = sc_min(maxlength-1, obj->size); src = obj->s; } else { len = sizeof(not_a_string); src = not_a_string; } memcpy(str+1, src, len); str[0] = len; } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/SC_LanguageConfig.cpp0000664000000000000000000001755612161364457025735 0ustar rootroot/* * Copyright 2003 Maurizio Umberto Puxeddu * Copyright 2011 Jakob Leben * * This file is part of SuperCollider. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA * */ #include "SC_LanguageConfig.hpp" #include "SCBase.h" #include "SC_DirUtils.h" #include #include #include #include #include #include #ifdef SC_WIN32 # include "SC_Win32Utils.h" #else # include # include # include #endif #include #include #include "yaml-cpp/yaml.h" using namespace std; SC_LanguageConfig *gLanguageConfig = 0; string SC_LanguageConfig::gConfigFile; static bool findPath( SC_LanguageConfig::DirVector & vec, const char * path, bool addIfMissing) { char standardPath[PATH_MAX]; sc_StandardizePath(path, standardPath); for ( SC_LanguageConfig::DirVector::iterator it = vec.begin(); it != vec.end(); ++it) { typedef boost::filesystem::path Path; Path stdPath(standardPath), thisPath(it->c_str()); stdPath = stdPath / "."; thisPath = thisPath / "."; if (boost::filesystem::absolute(stdPath) == boost::filesystem::absolute(thisPath)) return true; } if (addIfMissing) vec.push_back(string(standardPath)); return false; } SC_LanguageConfig::SC_LanguageConfig() { char classLibraryDir[MAXPATHLEN]; char systemExtensionDir[MAXPATHLEN]; char userExtensionDir[MAXPATHLEN]; sc_GetResourceDirectory(classLibraryDir, MAXPATHLEN-32); sc_AppendToPath(classLibraryDir, MAXPATHLEN, "SCClassLibrary"); findPath(mDefaultClassLibraryDirectories, classLibraryDir, true); if (!sc_IsStandAlone()) { sc_GetSystemExtensionDirectory(systemExtensionDir, MAXPATHLEN); findPath(mDefaultClassLibraryDirectories, systemExtensionDir, true); sc_GetUserExtensionDirectory(userExtensionDir, MAXPATHLEN); findPath(mDefaultClassLibraryDirectories, userExtensionDir, true); } } void SC_LanguageConfig::postExcludedDirectories(void) { DirVector &vec = mExcludedDirectories; DirVector::iterator it; for (it=vec.begin(); it!=vec.end(); ++it) { post("\texcluding dir: '%s'\n", it->c_str()); } } bool SC_LanguageConfig::forEachIncludedDirectory(bool (*func)(const char *, int)) { for (DirVector::iterator it=mDefaultClassLibraryDirectories.begin(); it!=mDefaultClassLibraryDirectories.end(); ++it) { if (!pathIsExcluded(it->c_str())) { if (!func(it->c_str(), 0)) return false; } } for (DirVector::iterator it=mIncludedDirectories.begin(); it!=mIncludedDirectories.end(); ++it) { if (!pathIsExcluded(it->c_str())) { if (!func(it->c_str(), 0)) return false; } } return true; } bool SC_LanguageConfig::pathIsExcluded(const char *path) { return findPath(mExcludedDirectories, path, false); } void SC_LanguageConfig::addIncludedDirectory(const char *path) { if (path == 0) return; findPath(mIncludedDirectories, path, true); } void SC_LanguageConfig::addExcludedDirectory(const char *path) { if (path == 0) return; findPath(mExcludedDirectories, path, true); } void SC_LanguageConfig::removeIncludedDirectory(const char *path) { char standardPath[PATH_MAX]; sc_StandardizePath(path, standardPath); string str(standardPath); DirVector::iterator end = std::remove(mIncludedDirectories.begin(), mIncludedDirectories.end(), str); mIncludedDirectories.erase(end, mIncludedDirectories.end()); } void SC_LanguageConfig::removeExcludedDirectory(const char *path) { string str(path); DirVector::iterator end = std::remove(mExcludedDirectories.begin(), mExcludedDirectories.end(), str); mExcludedDirectories.erase(end, mExcludedDirectories.end()); } extern bool gPostInlineWarnings; bool SC_LanguageConfig::readLibraryConfigYAML(const char* fileName) { freeLibraryConfig(); gLanguageConfig = new SC_LanguageConfig(); using namespace YAML; try { std::ifstream fin(fileName); Parser parser(fin); Node doc; while(parser.GetNextDocument(doc)) { const Node * includePaths = doc.FindValue("includePaths"); if (includePaths && includePaths->Type() == NodeType::Sequence) { for (Iterator it = includePaths->begin(); it != includePaths->end(); ++it) { Node const & pathNode = *it; if (pathNode.Type() != NodeType::Scalar) continue; string path; pathNode.GetScalar(path); gLanguageConfig->addIncludedDirectory(path.c_str()); } } const Node * excludePaths = doc.FindValue("excludePaths"); if (excludePaths && excludePaths->Type() == NodeType::Sequence) { for (Iterator it = excludePaths->begin(); it != excludePaths->end(); ++it) { Node const & pathNode = *it; if (pathNode.Type() != NodeType::Scalar) continue; string path; pathNode.GetScalar(path); gLanguageConfig->addExcludedDirectory(path.c_str()); } } const Node * inlineWarnings = doc.FindValue("postInlineWarnings"); if (inlineWarnings) { try { gPostInlineWarnings = inlineWarnings->to(); } catch(...) { postfl("Warning: Cannot parse config file entry \"postInlineWarnings\"\n"); } } } return true; } catch (std::exception & e) { postfl("Exception when parsing YAML config file: %s\n", e.what()); freeLibraryConfig(); return false; } } bool SC_LanguageConfig::writeLibraryConfigYAML(const char* fileName) { using namespace YAML; Emitter out; out.SetIndent(4); out.SetMapFormat(Block); out.SetSeqFormat(Block); out.SetBoolFormat(TrueFalseBool); out << BeginMap; out << Key << "includePaths"; out << Value << BeginSeq; for (DirVector::iterator it = gLanguageConfig->mIncludedDirectories.begin(); it != gLanguageConfig->mIncludedDirectories.end(); ++it) out << *it; out << EndSeq; out << Key << "excludePaths"; out << Value << BeginSeq; for (DirVector::iterator it = gLanguageConfig->mExcludedDirectories.begin(); it != gLanguageConfig->mExcludedDirectories.end(); ++it) out << *it; out << EndSeq; out << Key << "postInlineWarnings"; out << Value << gPostInlineWarnings; out << EndMap; ofstream fout(fileName); fout << out.c_str(); return true; } bool SC_LanguageConfig::defaultLibraryConfig(void) { freeLibraryConfig(); gLanguageConfig = new SC_LanguageConfig(); return true; } static bool file_exists(const char * fileName) { FILE * fp = fopen(fileName, "r"); if (fp) fclose(fp); return fp != NULL; } static bool file_exists(std::string const & fileName) { return file_exists(fileName.c_str()); } bool SC_LanguageConfig::readLibraryConfig() { bool configured = false; if (!gConfigFile.empty() && file_exists(gConfigFile)) { configured = readLibraryConfigYAML(gConfigFile.c_str()); if (configured) return true; } char config_dir[PATH_MAX]; sc_GetUserConfigDirectory(config_dir, PATH_MAX); std::string user_yaml_config_file = std::string(config_dir) + SC_PATH_DELIMITER + "sclang_conf.yaml"; if (file_exists(user_yaml_config_file)) configured = readLibraryConfigYAML(user_yaml_config_file.c_str()); if (!configured) { char global_yaml_config_file[] = "/etc/sclang_conf.yaml"; if (file_exists(global_yaml_config_file)) configured = readLibraryConfigYAML(global_yaml_config_file); } if (configured) return true; SC_LanguageConfig::defaultLibraryConfig(); return false; } void SC_LanguageConfig::freeLibraryConfig() { if (gLanguageConfig) { delete gLanguageConfig; gLanguageConfig = 0; } } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/InitAlloc.cpp0000664000000000000000000000411312245365552024336 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "InitAlloc.h" AllocPool *pyr_pool_compile = 0; AllocPool *pyr_pool_runtime = 0; #define HOST_ALLOC(size) malloc(size) #define HOST_FREE(ptr) free((void*)(ptr)) #define AREASIZE 65536L void* pyr_new_area(size_t size); void* pyr_new_area(size_t size) { #ifdef SC_WIN32 size += kAlign; char* ptr = (char*)malloc(size); return (ptr + kAlign); #else return (char*)HOST_ALLOC(size); #endif } void pyr_free_area(void *ptr); void pyr_free_area(void *ptr) { #ifdef SC_WIN32 free((void*)((char*)ptr - kAlign)); #else HOST_FREE(ptr); #endif } void* pyr_new_area_from_runtime(size_t size); void* pyr_new_area_from_runtime(size_t size) { void *ptr = pyr_pool_runtime->Alloc(size); MEMFAIL(ptr); return ptr; } void pyr_free_area_from_runtime(void *ptr); void pyr_free_area_from_runtime(void *ptr) { pyr_pool_runtime->Free(ptr); } SC_DLLEXPORT_C bool pyr_init_mem_pools(int runtime_space, int runtime_grow) { pyr_pool_runtime = new AllocPool(pyr_new_area, pyr_free_area, runtime_space, runtime_grow); if (!pyr_pool_runtime) return false; pyr_pool_compile = new AllocPool(pyr_new_area_from_runtime, pyr_free_area_from_runtime, 0L, AREASIZE); if (!pyr_pool_compile) return false; //pyr_pool_runtime->DoCheckPool(); return true; } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/Samp.cpp0000664000000000000000000000465312245365552023371 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "Samp.h" #include "SC_Constants.h" #include #include float32 gSine[kSineSize+1]; float32 gPMSine[kSineSize+1]; float32 gInvSine[kSineSize+1]; float32 gSineWavetable[2*kSineSize]; void SignalAsWavetable(float32* signal, float32* wavetable, long inSize) { float32 val1, val2; float32* in = signal; float32* out = wavetable - 1; for (int i=0; i>1; for (int i=1; i<=8; ++i) { gInvSine[i] = gInvSine[sz-i] = kBadValue; gInvSine[sz2-i] = gInvSine[sz2+i] = kBadValue; } //SignalAsWavetable(gInvSine, gInvSineWavetable, kSineSize); } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/PyrInterpreter3.cpp0000664000000000000000000024001612245365552025545 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "Opcodes.h" #include "PyrInterpreter.h" #include "PyrPrimitive.h" #include "PyrPrimitiveProto.h" #include "PyrMathPrim.h" #include "PyrListPrim.h" #include "PyrKernel.h" #include "PyrMessage.h" #include "PyrParseNode.h" #include "PyrSignal.h" #include "PyrSched.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrKernelProto.h" #include "PyrSymbolTable.h" #include #include #include # include #ifdef SC_WIN32 # include "SC_Win32Utils.h" #else # include #endif #include #define kBigBigFloat DBL_MAX #define kSmallSmallFloat DBL_MIN #include #include "InitAlloc.h" #include "function_attributes.h" //void tellPlugInsAboutToRun(); double timeNow(); int32 timeseed() { struct timeval tv; gettimeofday(&tv, 0); return tv.tv_sec ^ tv.tv_usec; } VMGlobals gVMGlobals; VMGlobals *gMainVMGlobals = &gVMGlobals; extern PyrObject *gSynth; void debugf(char *fmt, ...) ; #define DEBUGINTERPRETER 0 #define METHODMETER 0 #define BCSTAT 0 #define CHECK_MAX_STACK_USE 0 #if CHECK_MAX_STACK_USE int gMaxStackDepth = 0; #endif unsigned char* dumpOneByteCode(PyrBlock *theBlock, PyrClass* theClass, unsigned char *ip); void dumpSlotOneWord(const char *tagstr, PyrSlot *slot); //bool checkAllObjChecksum(PyrObject* obj); bool gTraceInterpreter = false; //bool gTraceInterpreter = true; const char* byteCodeString(int code); extern int gNumClasses; extern PyrClass *gClassList; // runInterpreter has 7 call sites: // compileLibrary (4) // runLibrary // interpretCmdLine static void endInterpreter(VMGlobals *g); SC_DLLEXPORT_C void runInterpreter(VMGlobals *g, PyrSymbol *selector, int numArgsPushed) { //postfl("->runInterpreter\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif //postfl(" >initInterpreter\n"); if (initInterpreter(g, selector, numArgsPushed)) { #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif // if (strcmp(selector->name, "tick") != 0) post("%s %d execMethod %d\n", selector->name, numArgsPushed, g->execMethod); //post("->Interpret thread %p\n", g->thread); if (g->execMethod) Interpret(g); //post("<-Interpret thread %p\n", g->thread); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } //postfl(" >endInterpreter\n"); endInterpreter(g); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif //postfl("<-runInterpreter\n"); //dumpGCStats(g->gc); } static bool initAwakeMessage(VMGlobals *g); void runAwakeMessage(VMGlobals *g) { if (initAwakeMessage(g)) { if (g->execMethod) Interpret(g); } endInterpreter(g); } void initPyrThread(VMGlobals *g, PyrThread *thread, PyrSlot *func, int stacksize, PyrInt32Array* rgenArray, double beats, double seconds, PyrSlot* clock, bool collect); int32 timeseed(); PyrProcess* newPyrProcess(VMGlobals *g, PyrClass *procclassobj) { PyrGC* gc = g->gc; PyrProcess * proc = (PyrProcess*)instantiateObject(gc, procclassobj, 0, true, false); PyrObject *sysSchedulerQueue = newPyrArray(gc, 4096, 0, false); sysSchedulerQueue->size = 1; SetInt(sysSchedulerQueue->slots + 0, 0); // stability count SetObject(&proc->sysSchedulerQueue, sysSchedulerQueue); PyrObject *classVars = newPyrArray(gc, gNumClassVars, 0, false); classVars->size = gNumClassVars; nilSlots(classVars->slots, gNumClassVars); SetObject(&proc->classVars, classVars); g->classvars = classVars; // fill class vars from prototypes: PyrClass * classobj = gClassList; while (classobj) { if (IsObj(&classobj->cprototype)) { int numClassVars = slotRawObject(&classobj->cprototype)->size; if (numClassVars > 0) { memcpy(g->classvars->slots + slotRawInt(&classobj->classVarIndex), slotRawObject(&classobj->cprototype)->slots, numClassVars * sizeof(PyrSlot)); } } classobj = slotRawClass(&classobj->nextclass); } SetNil(&proc->nowExecutingPath); class_thread = getsym("Thread")->u.classobj; if (class_thread) { SetNil(&proc->curThread); PyrThread * thread = (PyrThread*)instantiateObject(gc, class_thread, 0, true, false); //SetObject(&threadsArray->slots[0], thread); SetObject(&proc->mainThread, thread); PyrInt32Array *rgenArray = newPyrInt32Array(gc, 4, 0, false); rgenArray->size = 4; rgenArray->i[0] = 0; rgenArray->i[1] = 0; rgenArray->i[2] = 0; rgenArray->i[3] = 0; ((RGen*)(rgenArray->i))->init(timeseed()); PyrSlot clockSlot; SetObject(&clockSlot, s_systemclock->u.classobj); initPyrThread(g, thread, &o_nil, EVALSTACKDEPTH, rgenArray, 0., 0., &clockSlot, false); //postfl("elapsedTime %.6f\n", elapsedTime()); } else { error("Class Thread not found.\n"); } PyrSymbol * contextsym = getsym("functionCompileContext"); size_t index = slotRawInt(&class_interpreter->classIndex) + contextsym->u.index; PyrMethod * meth = gRowTable[index]; if (!meth || slotRawSymbol(&meth->name) != contextsym) { error("compile context method 'functionCompileContext' not found.\n"); //SetNil(&proc->interpreter); } else { PyrObject *proto; PyrFrame *frame; PyrMethodRaw *methraw; PyrInterpreter * interpreter = (PyrInterpreter*)instantiateObject(gc, class_interpreter, 0, true, false); SetObject(&proc->interpreter, interpreter); proto = slotRawObject(&meth->prototypeFrame); methraw = METHRAW(meth); frame = (PyrFrame*)gc->New(methraw->frameSize, 0, obj_slot, false); frame->classptr = class_frame; frame->size = FRAMESIZE + proto->size; /// <- IS THIS WRONG ?? SetObject(&frame->method, meth); SetObject(&frame->homeContext, frame); SetInt(&frame->caller, 0); SetNil(&frame->context); SetPtr(&frame->ip, 0); SetObject(&frame->vars[0], interpreter); SetObject(&interpreter->context, frame); } return proc; } #if BCSTAT int prevop = 0; int bcstat[256]; int bcpair[256][256]; void clearbcstat(); void clearbcstat() { int i, j; for (i=0; i<256; ++i) { bcstat[i] = 0; for (j=0; j<256; ++j) { bcpair[i][j] = 0; } } } void dumpbcstat(); void dumpbcstat() { FILE *file; int i, j, k, total; file = fopen("bcstat", "w"); if (file) { fprintf(file, "----------\n"); total = 0; for (i=0; i<256; ++i) { total += bcstat[i]; if (bcstat[i]) fprintf(file, "%3d %8d %-32s\n", i, bcstat[i], byteCodeString(i)); } fprintf(file, "\ntotal %d\n", total); fprintf(file, "-----cur,next-----\n"); for (i=0, k=0; i<256; ++i) { for (j=0; j<256; j++) { if (bcpair[i][j] > 0) { fprintf(file, "%4d %3d %3d %8d %-32s %-32s\n", k++, i, j, bcpair[i][j], byteCodeString(i), byteCodeString(j)); } } } fprintf(file, "-----cur,prev-----\n"); for (i=0, k=0; i<256; ++i) { for (j=0; j<256; j++) { if (bcpair[j][i] > 0) { fprintf(file, "%4d %3d %3d %8d %-32s %-32s\n", k++, i, j, bcpair[j][i], byteCodeString(i), byteCodeString(j)); } } } } fclose(file); } #endif void initPatterns(); void initThreads(); void initGUI(); #ifndef SC_WIN32 bool running = true; static void handleSigUsr1(int param) { printf("handleSigUsr1()...\n"); running = false; } #endif bool initRuntime(VMGlobals *g, int poolSize, AllocPool *inPool) { /* create a GC environment create a vmachine instance of main initialize VMGlobals */ PyrClass * class_main = s_main->u.classobj; if (!class_main) { error("Class 'Main' not defined.\n"); return false; } if (!isSubclassOf(class_main, class_process)) { error("Class Main is not a subclass of Process.\n"); return false; } // create GC environment, process g->allocPool = inPool; g->gc = (PyrGC*)g->allocPool->Alloc(sizeof(PyrGC)); new (g->gc) PyrGC(g, g->allocPool, class_main, poolSize); g->thread = slotRawThread(&g->process->mainThread); SetObject(&g->receiver, g->process); // these will be set up when the run method is called g->method = NULL; g->block = NULL; g->frame = NULL; g->ip = NULL; // initialize process random number generator g->rgen = (RGen*)(slotRawObject(&g->thread->randData)->slots); //initUGenFuncs(); signal_init_globs(); initThreads(); initPatterns(); initUniqueMethods(); initGUI(); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif //tellPlugInsAboutToRun(); #ifndef SC_WIN32 signal(SIGUSR1,handleSigUsr1); #endif assert((g->gc->SanityCheck())); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif return true; } static bool initAwakeMessage(VMGlobals *g) { //post("initAwakeMessage %p %p\n", g->thread, slotRawThread(&g->process->mainThread)); slotCopy(&g->process->curThread, &g->process->mainThread); //?? g->thread = slotRawThread(&g->process->mainThread); //?? // these will be set up when the run method is called g->method = NULL; g->block = NULL; g->frame = NULL; g->ip = NULL; g->execMethod = 0; // set process as the receiver PyrSlot *slot = g->sp - 3; slotCopy(&g->receiver, slot); SetFloat(&g->thread->beats, slotRawFloat(&slot[1])); SetFloat(&g->thread->seconds, slotRawFloat(&slot[2])); slotCopy(&g->thread->clock, &slot[3]); g->gc->GCWrite(g->thread, slot+3); // start it sendMessage(g, s_awake, 4); return g->method != NULL; } bool initInterpreter(VMGlobals *g, PyrSymbol *selector, int numArgsPushed) { slotCopy(&g->process->curThread, &g->process->mainThread); g->thread = slotRawThread(&g->process->mainThread); // these will be set up when the run method is called #if TAILCALLOPTIMIZE g->tailCall = 0; #endif g->method = NULL; g->block = NULL; g->frame = NULL; g->ip = NULL; g->execMethod = 0; double elapsed = elapsedTime(); SetFloat(&g->thread->beats, elapsed); SetFloat(&g->thread->seconds, elapsed); SetObject(&g->thread->clock, s_systemclock->u.classobj); g->gc->GCWrite(g->thread, s_systemclock->u.classobj); // set process as the receiver PyrSlot *slot = g->sp - numArgsPushed + 1; slotCopy(&g->receiver, slot); // start it sendMessage(g, selector, numArgsPushed); return g->method != NULL; } static void endInterpreter(VMGlobals *g) { slotCopy(&g->result, g->sp); // dumpObjectSlot(&g->result); g->gc->Stack()->size = 0; g->sp = g->gc->Stack()->slots - 1; g->gc->LazyCollect(); } static void StoreToImmutableA(VMGlobals *g, PyrSlot *& sp, unsigned char *& ip) { // only the value is on the stack slotCopy(sp + 1, sp); // copy value up one slotCopy(sp, &g->receiver); // put receiver in place sp++; g->sp = sp; g->ip = ip; post("StoreToImmutableA\n"); dumpObjectSlot(sp-1); dumpObjectSlot(sp); sendMessage(g, getsym("immutableError"), 2); sp = g->sp; ip = g->ip; } void StoreToImmutableB(VMGlobals *g, PyrSlot *& sp, unsigned char *& ip) { // receiver and value are on the stack. sp++; g->sp = sp; g->ip = ip; post("StoreToImmutableB\n"); dumpObjectSlot(sp-1); dumpObjectSlot(sp); PyrSymbol *selector = getsym("immutableError"); sendMessage(g, selector, 2); sp = g->sp; ip = g->ip; } void dumpByteCodes(PyrBlock *theBlock); static inline void handlePushClassVar(VMGlobals* g, PyrSlot *& sp, unsigned char *& ip, unsigned char op2) { unsigned char op3 = ip[1]; ++ip; // get class var index slotCopy(++sp, &g->classvars->slots[(op2<<8)|op3]); } static inline void handleStoreInstVar(VMGlobals* g, PyrSlot *& sp, unsigned char *& ip, unsigned int index) { PyrObject* obj = slotRawObject(&g->receiver); if (obj->IsImmutable()) StoreToImmutableA(g, sp, ip); else { PyrSlot * slot = obj->slots + index; slotCopy(slot, sp--); g->gc->GCWrite(obj, slot); } } static inline void handleSendSpecialUnaryArithMsg(VMGlobals* g, PyrSlot *& sp, unsigned char *& ip, unsigned char op1) { g->sp = sp; g->ip = ip; g->primitiveIndex = op1 & 15; doSpecialUnaryArithMsg(g, -1); sp = g->sp; ip = g->ip; } static inline void handleSendSpecialBinaryArithMsg(VMGlobals* g, PyrSlot *& sp, unsigned char *& ip, unsigned char op1) { g->sp = sp; g->ip = ip; g->primitiveIndex = op1 & 15; doSpecialBinaryArithMsg(g, 2, false); sp = g->sp; ip = g->ip; } static inline bool checkStackOverflow(VMGlobals* g, PyrSlot * sp) { PyrObject * stack = g->gc->Stack(); int depth = sp - stack->slots; return depth < slotRawInt(&g->thread->stackSize); } static inline void checkStackDepth(VMGlobals* g, PyrSlot * sp) { #if CHECK_MAX_STACK_USE int stackDepth = sp - g->sp + 1; if (stackDepth > gMaxStackDepth) { gMaxStackDepth = stackDepth; printf("gMaxStackDepth %d\n", gMaxStackDepth); } #endif } #if defined(__GNUC__) || defined(__INTEL_COMPILER) #define LABELS_AS_VALUES #endif #ifdef LABELS_AS_VALUES #define dispatch_opcode \ op1 = ip[1]; \ ++ip; \ checkStackDepth(g, sp); \ assert(checkStackOverflow(g, sp)); \ goto *opcode_labels[op1] #else #define dispatch_opcode break #endif #if defined(__GNUC__) #define LIKELY(x) __builtin_expect((x),1) #define UNLIKELY(x) __builtin_expect((x),0) #else #define LIKELY(x) x #define UNLIKELY(x) x #endif HOT void Interpret(VMGlobals *g) { // byte code values unsigned char *ip; unsigned char op1; size_t index; int op2, op3, tag; // interpreter globals // temporary variables used in the interpreter int ival, jmplen, numArgsPushed, numKeyArgsPushed; PyrFrame *tframe; PyrSymbol *selector; PyrClass *classobj; PyrSlot *slot, *vars; PyrSlot *sp, *pslot; PyrObject *obj; PyrClosure *closure; PyrMethod *meth; int m,mmax; #ifdef LABELS_AS_VALUES static void * opcode_labels[] = { &&handle_op_0, &&handle_op_1, &&handle_op_2, &&handle_op_3, &&handle_op_4, &&handle_op_5, &&handle_op_6, &&handle_op_7, &&handle_op_8, &&handle_op_9, &&handle_op_10, &&handle_op_11, &&handle_op_12, &&handle_op_13, &&handle_op_14, &&handle_op_15, &&handle_op_16, &&handle_op_17, &&handle_op_18, &&handle_op_19, &&handle_op_20, &&handle_op_21, &&handle_op_22, &&handle_op_23, &&handle_op_24, &&handle_op_25, &&handle_op_26, &&handle_op_27, &&handle_op_28, &&handle_op_29, &&handle_op_30, &&handle_op_31, &&handle_op_32, &&handle_op_33, &&handle_op_34, &&handle_op_35, &&handle_op_36, &&handle_op_37, &&handle_op_38, &&handle_op_39, &&handle_op_40, &&handle_op_41, &&handle_op_42, &&handle_op_43, &&handle_op_44, &&handle_op_45, &&handle_op_46, &&handle_op_47, &&handle_op_48, &&handle_op_49, &&handle_op_50, &&handle_op_51, &&handle_op_52, &&handle_op_53, &&handle_op_54, &&handle_op_55, &&handle_op_56, &&handle_op_57, &&handle_op_58, &&handle_op_59, &&handle_op_60, &&handle_op_61, &&handle_op_62, &&handle_op_63, &&handle_op_64, &&handle_op_65, &&handle_op_66, &&handle_op_67, &&handle_op_68, &&handle_op_69, &&handle_op_70, &&handle_op_71, &&handle_op_72, &&handle_op_73, &&handle_op_74, &&handle_op_75, &&handle_op_76, &&handle_op_77, &&handle_op_78, &&handle_op_79, &&handle_op_80, &&handle_op_81, &&handle_op_82, &&handle_op_83, &&handle_op_84, &&handle_op_85, &&handle_op_86, &&handle_op_87, &&handle_op_88, &&handle_op_89, &&handle_op_90, &&handle_op_91, &&handle_op_92, &&handle_op_93, &&handle_op_94, &&handle_op_95, &&handle_op_96, &&handle_op_97, &&handle_op_98, &&handle_op_99, &&handle_op_100, &&handle_op_101, &&handle_op_102, &&handle_op_103, &&handle_op_104, &&handle_op_105, &&handle_op_106, &&handle_op_107, &&handle_op_108, &&handle_op_109, &&handle_op_110, &&handle_op_111, &&handle_op_112, &&handle_op_113, &&handle_op_114, &&handle_op_115, &&handle_op_116, &&handle_op_117, &&handle_op_118, &&handle_op_119, &&handle_op_120, &&handle_op_121, &&handle_op_122, &&handle_op_123, &&handle_op_124, &&handle_op_125, &&handle_op_126, &&handle_op_127, &&handle_op_128, &&handle_op_129, &&handle_op_130, &&handle_op_131, &&handle_op_132, &&handle_op_133, &&handle_op_134, &&handle_op_135, &&handle_op_136, &&handle_op_137, &&handle_op_138, &&handle_op_139, &&handle_op_140, &&handle_op_141, &&handle_op_142, &&handle_op_143, &&handle_op_144, &&handle_op_145, &&handle_op_146, &&handle_op_147, &&handle_op_148, &&handle_op_149, &&handle_op_150, &&handle_op_151, &&handle_op_152, &&handle_op_153, &&handle_op_154, &&handle_op_155, &&handle_op_156, &&handle_op_157, &&handle_op_158, &&handle_op_159, &&handle_op_160, &&handle_op_161, &&handle_op_162, &&handle_op_163, &&handle_op_164, &&handle_op_165, &&handle_op_166, &&handle_op_167, &&handle_op_168, &&handle_op_169, &&handle_op_170, &&handle_op_171, &&handle_op_172, &&handle_op_173, &&handle_op_174, &&handle_op_175, &&handle_op_176, &&handle_op_177, &&handle_op_178, &&handle_op_179, &&handle_op_180, &&handle_op_181, &&handle_op_182, &&handle_op_183, &&handle_op_184, &&handle_op_185, &&handle_op_186, &&handle_op_187, &&handle_op_188, &&handle_op_189, &&handle_op_190, &&handle_op_191, &&handle_op_192, &&handle_op_193, &&handle_op_194, &&handle_op_195, &&handle_op_196, &&handle_op_197, &&handle_op_198, &&handle_op_199, &&handle_op_200, &&handle_op_201, &&handle_op_202, &&handle_op_203, &&handle_op_204, &&handle_op_205, &&handle_op_206, &&handle_op_207, &&handle_op_208, &&handle_op_209, &&handle_op_210, &&handle_op_211, &&handle_op_212, &&handle_op_213, &&handle_op_214, &&handle_op_215, &&handle_op_216, &&handle_op_217, &&handle_op_218, &&handle_op_219, &&handle_op_220, &&handle_op_221, &&handle_op_222, &&handle_op_223, &&handle_op_224, &&handle_op_225, &&handle_op_226, &&handle_op_227, &&handle_op_228, &&handle_op_229, &&handle_op_230, &&handle_op_231, &&handle_op_232, &&handle_op_233, &&handle_op_234, &&handle_op_235, &&handle_op_236, &&handle_op_237, &&handle_op_238, &&handle_op_239, &&handle_op_240, &&handle_op_241, &&handle_op_242, &&handle_op_243, &&handle_op_244, &&handle_op_245, &&handle_op_246, &&handle_op_247, &&handle_op_248, &&handle_op_249, &&handle_op_250, &&handle_op_251, &&handle_op_252, &&handle_op_253, &&handle_op_254, &&handle_op_255 }; #endif #if 0 unsigned char *bzero; PyrSlot *szero; char str[80]; #endif #if BCSTAT //clearbcstat(); op1 = 0; prevop = 0; #endif #if 0 bzero = g->ip; szero = g->sp; //SetSymbol(g->sp, getsym("STACK TOP")); // just for debugging //g->sp++; // just for debugging #endif // Codewarrior puts them in registers. take advantage.. sp = g->sp; ip = g->ip; numKeyArgsPushed = 0; if (setjmp(g->escapeInterpreter) != 0) { return; } #ifndef SC_WIN32 while (running) { // not going to indent body to save line space #else while (true) { #endif checkStackDepth(g, sp); #if BCSTAT prevop = op1; #endif op1 = ip[1]; ++ip; assert(checkStackOverflow(g, sp)); #if BCSTAT ++bcstat[op1]; ++bcpair[prevop][op1]; prevop = op1; #endif //printf("op1 %d\n", op1); //postfl("sp %p frame %p caller %p ip %p\n", sp, g->frame, g->frame->caller.uof, slotRawInt(&g->frame->caller.uof->ip)); //postfl("sp %p frame %p diff %d caller %p\n", sp, g->frame, ((int)sp - (int)g->frame)>>3, g->frame->caller.uof); #if DEBUGINTERPRETER if (gTraceInterpreter) { //DumpStack(g, sp); if (FrameSanity(g->frame, "dbgint")) { //Debugger(); } //g->gc->SanityCheck(); //assert(g->gc->SanityCheck()); g->sp = sp; g->ip = ip; g->gc->FullCollection(); sp = g->sp; ip = g->ip; postfl("[%3d] %20s-%-16s ", (sp - g->gc->Stack()->slots) + 1, slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name); dumpOneByteCode(g->block, NULL, ip); } #endif #ifdef GC_SANITYCHECK // gcLinkSanity(g->gc); g->gc->SanityCheck(); // do_check_pool(pyr_pool_runtime); // do_check_pool(pyr_pool_compile); #endif #if METHODMETER if (gTraceInterpreter) { slotRawInt(&g->method->byteMeter)++; } #endif switch (op1) { case 0 : // push class handle_op_0: op2 = ip[1]; ++ip; // get literal index classobj = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2])->u.classobj; if (classobj) { ++sp; SetObject(sp, classobj); } else { postfl("Execution warning: Class '%s' not found\n", slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2])->name); slotCopy(++sp, &gSpecialValues[svNil]); } dispatch_opcode; case 1 : // opExtended, opPushInstVar handle_op_1: op2 = ip[1]; ++ip; // get inst var index slotCopy(++sp, &slotRawObject(&g->receiver)->slots[op2]); dispatch_opcode; case 2 : // opExtended, opPushTempVar handle_op_2: op2 = ip[1]; // get temp var level op3 = ip[2]; // get temp var index ip += 2; for (tframe = g->frame; --op2; tframe = slotRawFrame(&tframe->context)) { /* noop */ } slotCopy(++sp, &tframe->vars[op3]); dispatch_opcode; case 3 : // opExtended, opPushTempZeroVar handle_op_3: op2 = ip[1]; ++ip; // get temp var index slotCopy(++sp, &g->frame->vars[op2]); dispatch_opcode; case 4 : // opExtended, opPushLiteral handle_op_4: op2 = ip[1]; ++ip; // get literal index // push a block as a closure if it is one slot = slotRawObject(&g->block->selectors)->slots + op2; if (IsObj(slot) && slotRawObject(slot)->classptr == gSpecialClasses[op_class_fundef]->u.classobj) { // push a closure g->sp = sp; // gc may push the stack closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, true); sp = g->sp; closure->classptr = gSpecialClasses[op_class_func]->u.classobj; closure->size = 2; slotCopy(&closure->block, slot); if (IsNil(&slotRawBlock(slot)->contextDef)) { slotCopy(&closure->context, &slotRawInterpreter(&g->process->interpreter)->context); } else { SetObject(&closure->context, g->frame); } ++sp; SetObject(sp, closure); } else { slotCopy(++sp, slot); } dispatch_opcode; case 5 : // opExtended, opPushClassVar handle_op_5: op2 = ip[1]; // get class op3 = ip[2]; // get class var index ip += 2; slotCopy(++sp, &g->classvars->slots[(op2<<8)|op3]); dispatch_opcode; case 6 : // opExtended, opPushSpecialValue == push a special class handle_op_6: op2 = ip[1]; ++ip; // get class name index classobj = gSpecialClasses[op2]->u.classobj; if (classobj) { ++sp; SetObject(sp, classobj); } else { slotCopy(++sp, &gSpecialValues[svNil]); } dispatch_opcode; case 7 : // opExtended, opStoreInstVar handle_op_7: op2 = ip[1]; ++ip; // get inst var index obj = slotRawObject(&g->receiver); if (obj->IsImmutable()) { StoreToImmutableA(g, sp, ip); } else { slot = obj->slots + op2; slotCopy(slot, sp); g->gc->GCWrite(obj, slot); } dispatch_opcode; case 8 : // opExtended, opStoreTempVar handle_op_8: op2 = ip[1]; // get temp var level op3 = ip[2]; // get temp var index ip += 2; for (tframe = g->frame; op2--; tframe = slotRawFrame(&tframe->context)) { /* noop */ } slot = tframe->vars + op3; slotCopy(slot, sp); g->gc->GCWrite(tframe, slot); dispatch_opcode; case 9 : // opExtended, opStoreClassVar handle_op_9: op2 = ip[1]; // get index of class name literal op3 = ip[2]; // get class var index ip += 2; slotCopy(&g->classvars->slots[(op2<<8)|op3], sp); g->gc->GCWrite(g->classvars, sp); dispatch_opcode; case 10 : // opExtended, opSendMsg handle_op_10: numArgsPushed = ip[1]; // get num args numKeyArgsPushed = ip[2]; // get num keyword args op3 = ip[3]; // get selector index ip += 3; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op3]); slot = sp - numArgsPushed + 1; if (numKeyArgsPushed) goto key_class_lookup; else goto class_lookup; case 11 : // opExtended, opSendSuper handle_op_11: numArgsPushed = ip[1]; // get num args numKeyArgsPushed = ip[2]; // get num keyword args op3 = ip[3]; // get selector index ip += 3; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op3]); slot = g->sp - numArgsPushed + 1; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; if (numKeyArgsPushed) goto key_msg_lookup; else goto msg_lookup; case 12 : // opExtended, opSendSpecialMsg handle_op_12: numArgsPushed = ip[1]; // get num args numKeyArgsPushed = ip[2]; // get num keyword args op3 = ip[3]; // get selector index ip += 3; selector = gSpecialSelectors[op3]; slot = sp - numArgsPushed + 1; if (numKeyArgsPushed) goto key_class_lookup; else goto class_lookup; case 13 : // opExtended, opSendSpecialUnaryArithMsg handle_op_13: op2 = ip[1]; ++ip; // get selector index g->sp = sp; g->ip = ip; g->primitiveIndex = op2; doSpecialUnaryArithMsg(g, -1); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif sp = g->sp; ip = g->ip; dispatch_opcode; case 14 : // opExtended, opSendSpecialBinaryArithMsg handle_op_14: op2 = ip[1]; ++ip; // get selector index g->sp = sp; g->ip = ip; g->primitiveIndex = op2; doSpecialBinaryArithMsg(g, 2, false); sp = g->sp; ip = g->ip; dispatch_opcode; case 15 : // opExtended, opSpecialOpcode (none yet) handle_op_15: op2 = ip[1]; ++ip; // get extended special opcode switch (op2) { case opgProcess : // push thisProcess ++sp; SetObject(sp, g->process); break; case opgThread : // push thisProcess ++sp; SetObject(sp, g->thread); break; case opgMethod : // push thisMethod ++sp; SetObject(sp, g->method); break; case opgFunctionDef : // push thisFunctionDef ++sp; SetObject(sp, g->block); break; case opgFunction : // push thisFunc // push a closure g->sp = sp; // gc may push the stack closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, true); sp = g->sp; closure->classptr = gSpecialClasses[op_class_func]->u.classobj; closure->size = 2; SetObject(&closure->block, g->block); SetObject(&closure->context, slotRawFrame(&g->frame->context)); ++sp; SetObject(sp, closure); break; default : slotCopy(++sp, &gSpecialValues[svNil]); break; } dispatch_opcode; // opPushInstVar, 0..15 case 16 : handle_op_16: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 0]); dispatch_opcode; case 17 : handle_op_17: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 1]); dispatch_opcode; case 18 : handle_op_18: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 2]); dispatch_opcode; case 19 : handle_op_19: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 3]); dispatch_opcode; case 20 : handle_op_20: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 4]); dispatch_opcode; case 21 : handle_op_21: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 5]); dispatch_opcode; case 22 : handle_op_22: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 6]); dispatch_opcode; case 23 : handle_op_23: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 7]); dispatch_opcode; case 24 : handle_op_24: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 8]); dispatch_opcode; case 25 : handle_op_25: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 9]); dispatch_opcode; case 26 : handle_op_26: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[10]); dispatch_opcode; case 27 : handle_op_27: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[11]); dispatch_opcode; case 28 : handle_op_28: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[12]); dispatch_opcode; case 29 : handle_op_29: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[13]); dispatch_opcode; case 30 : handle_op_30: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[14]); dispatch_opcode; case 31 : handle_op_31: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[15]); dispatch_opcode; case 32 : // JumpIfTrue handle_op_32: // cannot compare with o_false because it is NaN if ( IsTrue(sp) ) { jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else if ( IsFalse(sp)) { ip+=2; } else { numArgsPushed = 1; selector = gSpecialSelectors[opmNonBooleanError]; slot = sp; goto class_lookup; } --sp; dispatch_opcode; // opPushTempVar, levels 1..7 case 33 : handle_op_33: slotCopy(++sp, &slotRawFrame(&g->frame->context)->vars[ip[1]]); ++ip; dispatch_opcode; case 34 : handle_op_34: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&g->frame->context)->context)->vars[ip[1]]); ++ip; dispatch_opcode; case 35 : handle_op_35: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)->context)->context)->vars[ip[1]]); ++ip; dispatch_opcode; case 36 : handle_op_36: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)->context)->context)-> context)->vars[ip[1]]); ++ip; dispatch_opcode; case 37 : handle_op_37: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)-> context)->context)->context)->context)->vars[ip[1]]); ++ip; dispatch_opcode; case 38 : handle_op_38: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)-> context)->context)->context)->context)->context)->vars[ip[1]]); ++ip; dispatch_opcode; case 39 : handle_op_39: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)-> context)->context)->context)->context)->context)->context)->vars[ip[1]]); ++ip; dispatch_opcode; // push literal constants. case 40 : handle_op_40: ival = ip[1]; ip+=1; slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ival]); dispatch_opcode; case 41 : handle_op_41: ival = (ip[1] << 8) | ip[2]; ip+=2; slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ival]); dispatch_opcode; case 42 : handle_op_42: ival = (ip[1] << 16) | (ip[2] << 8) | ip[3]; ip+=3; slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ival]); dispatch_opcode; case 43 : handle_op_43: ival = (ip[1] << 24) | (ip[2] << 16) | (ip[3] << 8) | ip[4]; ip+=4; slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ival]); dispatch_opcode; // push integers. case 44 : handle_op_44: ival = (int32)(ip[1] << 24) >> 24; ip+=1; ++sp; SetInt(sp, ival); dispatch_opcode; case 45 : handle_op_45: ival = (int32)((ip[1] << 24) | (ip[2] << 16)) >> 16; ip+=2; ++sp; SetInt(sp, ival); dispatch_opcode; case 46 : handle_op_46: ival = (int32)((ip[1] << 24) | (ip[2] << 16) | (ip[3] << 8)) >> 8; ip+=3; ++sp; SetInt(sp, ival); dispatch_opcode; case 47 : handle_op_47: ival = (int32)((ip[1] << 24) | (ip[2] << 16) | (ip[3] << 8) | ip[4]); ip+=4; ++sp; SetInt(sp, ival); dispatch_opcode; // opPushTempZeroVar case 48 : handle_op_48: slotCopy(++sp, &g->frame->vars[ 0]); dispatch_opcode; case 49 : handle_op_49: slotCopy(++sp, &g->frame->vars[ 1]); dispatch_opcode; case 50 : handle_op_50: slotCopy(++sp, &g->frame->vars[ 2]); dispatch_opcode; case 51 : handle_op_51: slotCopy(++sp, &g->frame->vars[ 3]); dispatch_opcode; case 52 : handle_op_52: slotCopy(++sp, &g->frame->vars[ 4]); dispatch_opcode; case 53 : handle_op_53: slotCopy(++sp, &g->frame->vars[ 5]); dispatch_opcode; case 54 : handle_op_54: slotCopy(++sp, &g->frame->vars[ 6]); dispatch_opcode; case 55 : handle_op_55: slotCopy(++sp, &g->frame->vars[ 7]); dispatch_opcode; case 56 : handle_op_56: slotCopy(++sp, &g->frame->vars[ 8]); dispatch_opcode; case 57 : handle_op_57: slotCopy(++sp, &g->frame->vars[ 9]); dispatch_opcode; case 58 : handle_op_58: slotCopy(++sp, &g->frame->vars[10]); dispatch_opcode; case 59 : handle_op_59: slotCopy(++sp, &g->frame->vars[11]); dispatch_opcode; case 60 : handle_op_60: slotCopy(++sp, &g->frame->vars[12]); dispatch_opcode; case 61 : handle_op_61: slotCopy(++sp, &g->frame->vars[13]); dispatch_opcode; case 62 : handle_op_62: slotCopy(++sp, &g->frame->vars[14]); dispatch_opcode; case 63 : handle_op_63: slotCopy(++sp, &g->frame->vars[15]); dispatch_opcode; // case opPushLiteral case 64 : handle_op_64: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 0]); dispatch_opcode; case 65 : handle_op_65: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 1]); dispatch_opcode; case 66 : handle_op_66: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 2]); dispatch_opcode; case 67 : handle_op_67: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 3]); dispatch_opcode; case 68 : handle_op_68: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 4]); dispatch_opcode; case 69 : handle_op_69: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 5]); dispatch_opcode; case 70 : handle_op_70: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 6]); dispatch_opcode; case 71 : handle_op_71: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 7]); dispatch_opcode; case 72 : handle_op_72: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 8]); dispatch_opcode; case 73 : handle_op_73: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 9]); dispatch_opcode; case 74 : handle_op_74: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[10]); dispatch_opcode; case 75 : handle_op_75: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[11]); dispatch_opcode; case 76 : handle_op_76: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[12]); dispatch_opcode; case 77 : handle_op_77: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[13]); dispatch_opcode; case 78 : handle_op_78: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[14]); dispatch_opcode; case 79 : handle_op_79: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[15]); dispatch_opcode; // opPushClassVar case 80: handle_op_80: handlePushClassVar(g, sp, ip, 0); dispatch_opcode; case 81: handle_op_81: handlePushClassVar(g, sp, ip, 1); dispatch_opcode; case 82: handle_op_82: handlePushClassVar(g, sp, ip, 2); dispatch_opcode; case 83: handle_op_83: handlePushClassVar(g, sp, ip, 3); dispatch_opcode; case 84: handle_op_84: handlePushClassVar(g, sp, ip, 4); dispatch_opcode; case 85: handle_op_85: handlePushClassVar(g, sp, ip, 5); dispatch_opcode; case 86: handle_op_86: handlePushClassVar(g, sp, ip, 6); dispatch_opcode; case 87: handle_op_87: handlePushClassVar(g, sp, ip, 7); dispatch_opcode; case 88: handle_op_88: handlePushClassVar(g, sp, ip, 8); dispatch_opcode; case 89: handle_op_89: handlePushClassVar(g, sp, ip, 9); dispatch_opcode; case 90: handle_op_90: handlePushClassVar(g, sp, ip, 10); dispatch_opcode; case 91: handle_op_91: handlePushClassVar(g, sp, ip, 11); dispatch_opcode; case 92: handle_op_92: handlePushClassVar(g, sp, ip, 12); dispatch_opcode; case 93: handle_op_93: handlePushClassVar(g, sp, ip, 13); dispatch_opcode; case 94: handle_op_94: handlePushClassVar(g, sp, ip, 14); dispatch_opcode; case 95: handle_op_95: handlePushClassVar(g, sp, ip, 15); dispatch_opcode; // opPushSpecialValue case 96 : handle_op_96: slotCopy(++sp, &g->receiver); dispatch_opcode; case 97 : // push one and subtract handle_op_97: if (IsInt(sp)) { SetRaw(sp, slotRawInt(sp) - 1); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else { slotCopy(++sp, &gSpecialValues[svOne]); g->sp = sp; g->ip = ip; g->primitiveIndex = opSub; prSubNum(g, -1); sp = g->sp; ip = g->ip; } dispatch_opcode; case 98 : handle_op_98: slotCopy(++sp, &gSpecialValues[svNegOne]); dispatch_opcode; case 99 : handle_op_99: slotCopy(++sp, &gSpecialValues[svZero]); dispatch_opcode; case 100 : handle_op_100: slotCopy(++sp, &gSpecialValues[svOne]); dispatch_opcode; case 101 : handle_op_101: slotCopy(++sp, &gSpecialValues[svTwo]); dispatch_opcode; case 102 : handle_op_102: slotCopy(++sp, &gSpecialValues[svFHalf]); dispatch_opcode; case 103 : handle_op_103: slotCopy(++sp, &gSpecialValues[svFNegOne]); dispatch_opcode; case 104 : handle_op_104: slotCopy(++sp, &gSpecialValues[svFZero]); dispatch_opcode; case 105 : handle_op_105: slotCopy(++sp, &gSpecialValues[svFOne]); dispatch_opcode; case 106 : handle_op_106: slotCopy(++sp, &gSpecialValues[svFTwo]); dispatch_opcode; case 107 : // push one and add handle_op_107: if (IsInt(sp)) { SetRaw(sp, slotRawInt(sp) + 1); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else { slotCopy(++sp, &gSpecialValues[svOne]); g->sp = sp; g->ip = ip; g->primitiveIndex = opAdd; prAddNum(g, -1); sp = g->sp; ip = g->ip; } dispatch_opcode; case 108 : handle_op_108: slotCopy(++sp, &gSpecialValues[svTrue]); dispatch_opcode; case 109 : handle_op_109: slotCopy(++sp, &gSpecialValues[svFalse]); dispatch_opcode; case 110 : handle_op_110: slotCopy(++sp, &gSpecialValues[svNil]); dispatch_opcode; case 111 : handle_op_111: slotCopy(++sp, &gSpecialValues[svInf]); dispatch_opcode; // opStoreInstVar, 0..15 case 112 : handle_op_112: handleStoreInstVar(g, sp, ip, 0); dispatch_opcode; case 113 : handle_op_113: handleStoreInstVar(g, sp, ip, 1); dispatch_opcode; case 114 : handle_op_114: handleStoreInstVar(g, sp, ip, 2); dispatch_opcode; case 115 : handle_op_115: handleStoreInstVar(g, sp, ip, 3); dispatch_opcode; case 116 : handle_op_116: handleStoreInstVar(g, sp, ip, 4); dispatch_opcode; case 117 : handle_op_117: handleStoreInstVar(g, sp, ip, 5); dispatch_opcode; case 118 : handle_op_118: handleStoreInstVar(g, sp, ip, 6); dispatch_opcode; case 119 : handle_op_119: handleStoreInstVar(g, sp, ip, 7); dispatch_opcode; case 120 : handle_op_120: handleStoreInstVar(g, sp, ip, 8); dispatch_opcode; case 121 : handle_op_121: handleStoreInstVar(g, sp, ip, 9); dispatch_opcode; case 122 : handle_op_122: handleStoreInstVar(g, sp, ip, 10); dispatch_opcode; case 123 : handle_op_123: handleStoreInstVar(g, sp, ip, 11); dispatch_opcode; case 124 : handle_op_124: handleStoreInstVar(g, sp, ip, 12); dispatch_opcode; case 125 : handle_op_125: handleStoreInstVar(g, sp, ip, 13); dispatch_opcode; case 126 : handle_op_126: handleStoreInstVar(g, sp, ip, 14); dispatch_opcode; case 127 : handle_op_127: handleStoreInstVar(g, sp, ip, 15); dispatch_opcode; // opStoreTempVar case 128 : handle_op_128: op3 = ip[1]; ++ip; // get temp var index tframe = g->frame; // zero level slot = tframe->vars + op3; slotCopy(slot, sp--); g->gc->GCWrite(tframe, slot); dispatch_opcode; case 129 : handle_op_129: op3 = ip[1]; ++ip; // get temp var index tframe = slotRawFrame(&g->frame->context); // one level slot = tframe->vars + op3; slotCopy(slot, sp--); g->gc->GCWrite(tframe, slot); dispatch_opcode; case 130 : handle_op_130: op3 = ip[1]; ++ip; // get temp var index tframe = slotRawFrame(&slotRawFrame(&g->frame->context)->context); // two levels slot = tframe->vars + op3; slotCopy(slot, sp--); g->gc->GCWrite(tframe, slot); dispatch_opcode; case 131 : handle_op_131: op3 = ip[1]; ++ip; // get temp var index tframe = slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)->context)->context); // three levels slot = tframe->vars + op3; slotCopy(slot, sp--); g->gc->GCWrite(tframe, slot); dispatch_opcode; case 132 : handle_op_132: op3 = ip[1]; ++ip; // get temp var index tframe = slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)->context)->context)->context); // four levels slot = tframe->vars + op3; slotCopy(slot, sp--); g->gc->GCWrite(tframe, slot); dispatch_opcode; case 133 : case 134 : case 135 : handle_op_133: handle_op_134: handle_op_135: op2 = op1 & 15; op3 = ip[1]; ++ip; // get temp var index for (tframe = g->frame; op2--; tframe = slotRawFrame(&tframe->context)) { /* noop */ } slot = tframe->vars + op3; slotCopy(slot, sp); g->gc->GCWrite(tframe, slot); dispatch_opcode; case 136 : // push inst var, send special selector handle_op_136: op2 = ip[1]; // get inst var index op3 = ip[2]; // get selector ip+=2; slotCopy(++sp, &slotRawObject(&g->receiver)->slots[op2]); numArgsPushed = 1; selector = gSpecialSelectors[op3]; slot = sp; goto class_lookup; case 137 : // push all args, send msg handle_op_137: numArgsPushed = METHRAW(g->block)->numargs; pslot = g->frame->vars - 1; for (m=0,mmax=numArgsPushed; mblock->selectors)->slots[op2]); slot = sp - numArgsPushed + 1; goto class_lookup; case 138 : // push all but first arg, send msg handle_op_138: numArgsPushed = METHRAW(g->block)->numargs; pslot = g->frame->vars; for (m=0,mmax=numArgsPushed-1; mblock->selectors)->slots[op2]); slot = sp - numArgsPushed + 1; goto class_lookup; case 139 : // push all args, send special handle_op_139: numArgsPushed = METHRAW(g->block)->numargs; pslot = g->frame->vars - 1; for (m=0,mmax=numArgsPushed; mblock)->numargs; pslot = g->frame->vars; for (m=0,mmax=numArgsPushed-1; mblock)->numargs + 1; pslot = g->frame->vars; for (m=0,mmax=numArgsPushed-2; mblock->selectors)->slots[op2]); slot = sp - numArgsPushed + 1; goto class_lookup; case 142 : // one arg pushed, push all but first arg, send special handle_op_142: numArgsPushed = METHRAW(g->block)->numargs + 1; pslot = g->frame->vars; for (m=0,mmax=numArgsPushed-2; mframe->vars; if (slotRawInt(&vars[2]) < slotRawInt(&g->receiver)) { slotCopy(++sp, &vars[1]); // push function slotCopy(++sp, &vars[2]); // push i slotCopy(++sp, &vars[2]); // push i // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; case 1 : -- sp ; // Drop SetRaw(&g->frame->vars[2], slotRawInt(&g->frame->vars[2]) + 1); // inc i ip -= 4; dispatch_opcode; // Integer-reverseDo : 143 2, 143 3, 143 4 case 2 : SetRaw(&g->frame->vars[2], slotRawInt(&g->receiver) - 1); dispatch_opcode; case 3 : vars = g->frame->vars; if (slotRawInt(&vars[2]) >= 0) { slotCopy(++sp, &vars[1]); // push function slotCopy(++sp, &vars[2]); // push i slotCopy(++sp, &vars[3]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; case 4 : -- sp ; // Drop vars = g->frame->vars; SetRaw(&vars[2], slotRawInt(&vars[2]) - 1); // dec i SetRaw(&vars[3], slotRawInt(&vars[3]) + 1); // inc j ip -= 4; dispatch_opcode; // Integer-for : 143 5, 143 6, 143 16 case 5 : vars = g->frame->vars; tag = GetTag(&vars[1]); if (tag != tagInt) { if (IsFloat(&vars[1])) { // coerce to int SetInt(&vars[1], (int32)(slotRawFloat(&vars[1]))); } else { error("Integer-for : endval not a SimpleNumber.\n"); slotCopy(++sp, &g->receiver); numArgsPushed = 1; selector = gSpecialSelectors[opmPrimitiveFailed]; slot = sp; goto class_lookup; } } if (slotRawInt(&g->receiver) <= slotRawInt(&vars[1])) { SetRaw(&vars[5], 1); } else { SetRaw(&vars[5], -1); } slotCopy(&vars[3], &g->receiver); dispatch_opcode; case 6 : vars = g->frame->vars; if ((slotRawInt(&vars[5]) > 0 && slotRawInt(&vars[3]) <= slotRawInt(&vars[1])) || (slotRawInt(&vars[5]) < 0 && slotRawInt(&vars[3]) >= slotRawInt(&vars[1]))) { slotCopy(++sp, &vars[2]); // push function slotCopy(++sp, &vars[3]); // push i slotCopy(++sp, &vars[4]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; // Integer-forBy : 143 7, 143 8, 143 9 case 7 : vars = g->frame->vars; if (IsFloat(vars+1)) { SetInt(&vars[1], (int32)(slotRawFloat(&vars[1]))); } if (IsFloat(vars+2)) { SetInt(&vars[2], (int32)(slotRawFloat(&vars[2]))); } tag = GetTag(&vars[1]); if ((tag != tagInt) || NotInt(&vars[2])) { error("Integer-forBy : endval or stepval not an Integer.\n"); slotCopy(++sp, &g->receiver); numArgsPushed = 1; selector = gSpecialSelectors[opmPrimitiveFailed]; slot = sp; goto class_lookup; } slotCopy(&vars[4], &g->receiver); dispatch_opcode; case 8 : vars = g->frame->vars; if ((slotRawInt(&vars[2]) >= 0 && slotRawInt(&vars[4]) <= slotRawInt(&vars[1])) || (slotRawInt(&vars[2]) < 0 && slotRawInt(&vars[4]) >= slotRawInt(&vars[1]))) { slotCopy(++sp, &vars[3]); // push function slotCopy(++sp, &vars[4]); // push i slotCopy(++sp, &vars[5]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; case 9 : --sp ; // Drop vars = g->frame->vars; SetRaw(&vars[4], slotRawInt(&vars[4]) + slotRawInt(&vars[2])); // inc i SetRaw(&vars[5], slotRawInt(&vars[5]) + 1); // inc j ip -= 4; dispatch_opcode; // ArrayedCollection-do : 143 10, 143 1 case 10 : // 0 this, 1 func, 2 i vars = g->frame->vars; if (slotRawInt(&vars[2]) < slotRawObject(&g->receiver)->size) { slotCopy(++sp, &vars[1]); // push function getIndexedSlot(slotRawObject(&g->receiver), ++sp, slotRawInt(&vars[2])); // push this.at(i) slotCopy(++sp, &vars[2]); // push i // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; // ArrayedCollection-reverseDo : 143 11, 143 12, 143 4 case 11 : SetRaw(&g->frame->vars[2], slotRawObject(&g->receiver)->size - 1); dispatch_opcode; case 12 : vars = g->frame->vars; if (slotRawInt(&vars[2]) >= 0) { slotCopy(++sp, &vars[1]); // push function getIndexedSlot(slotRawObject(&g->receiver), ++sp, slotRawInt(&vars[2])); // push this.at(i) slotCopy(++sp, &vars[3]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; // class_lookup: } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; // Dictionary-keysValuesArrayDo case 13 : vars = g->frame->vars; m = slotRawInt(&vars[3]); obj = slotRawObject(&vars[1]); if ( m < obj->size ) { slot = obj->slots + m; // key while (IsNil(slot)) { m += 2; if ( m >= obj->size ) { SetRaw(&vars[3], m); goto keysValuesArrayDo_return; } slot = obj->slots + m; // key } SetRaw(&vars[3], m); slotCopy(++sp, &vars[2]); // function slotCopy(++sp, &slot[0]); // key slotCopy(++sp, &slot[1]); // val slotCopy(++sp, &vars[4]); // j SetRaw(&vars[4], slotRawInt(&vars[4]) + 1); // SendSpecialMsg value numArgsPushed = 4; selector = gSpecialSelectors[opmValue]; slot = sp - 3; goto class_lookup; // class_lookup: } else { keysValuesArrayDo_return: slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; case 14 : -- sp; // Drop SetRaw(&g->frame->vars[3], slotRawInt(&g->frame->vars[3]) + 2); // inc i ip -= 4; dispatch_opcode; case 15 : // unused opcode. break; case 16 : -- sp ; // Drop vars = g->frame->vars; SetRaw(&vars[3], slotRawInt(&vars[3]) + slotRawInt(&vars[5])); // inc i by stepval SetRaw(&vars[4], slotRawInt(&vars[4]) + 1); // inc j ip -= 4; dispatch_opcode; // Float-do : 143 17, 143 18 case 17 : vars = g->frame->vars; if (slotRawFloat(&vars[2]) + 0.5 < slotRawFloat(&g->receiver)) { slotCopy(++sp, &vars[1]); // push function slotCopy(++sp, &vars[2]); // push i slotCopy(++sp, &vars[2]); // push i // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; case 18 : -- sp ; // Drop SetRaw(&g->frame->vars[2], slotRawFloat(&g->frame->vars[2]) + 1.0); // inc i ip -= 4; dispatch_opcode; // Float-reverseDo : 143 19, 143 20, 143 21 case 19 : SetFloat(&g->frame->vars[2], slotRawFloat(&g->receiver) - 1.0); dispatch_opcode; case 20 : vars = g->frame->vars; if (slotRawFloat(&vars[2]) + 0.5 >= 0.0) { slotCopy(++sp, &vars[1]); // push function slotCopy(++sp, &vars[2]); // push i slotCopy(++sp, &vars[3]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; case 21 : -- sp ; // Drop vars = g->frame->vars; SetRaw(&g->frame->vars[2], slotRawFloat(&g->frame->vars[2]) - 1.0); // dec i SetRaw(&g->frame->vars[3], slotRawFloat(&g->frame->vars[3]) - 1.0); // inc j ip -= 4; dispatch_opcode; case 22 : // ? question mark method --sp; if (IsNil(sp)) { *sp = *(sp+1); } dispatch_opcode; case 23 : // if not nil push this and jump. used to implement ?? if (NotNil(sp)) { jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else { --sp; ip+=2; } dispatch_opcode; case 24 : // ifNil if ( NotNil(sp) ) { jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else { ip+=2; } --sp; dispatch_opcode; case 25 : // ifNotNil if ( IsNil(sp) ) { jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else { ip+=2; } --sp; dispatch_opcode; case 26 : // ifNotNilPushNil if ( NotNil(sp) ) { jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; slotCopy(sp, &gSpecialValues[svNil]); } else { ip+=2; --sp; } dispatch_opcode; case 27 : // ifNilPushNil if ( IsNil(sp) ) { jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else { ip+=2; --sp; } dispatch_opcode; case 28 : // switch obj = slotRawObject(sp); op2 = 1 + arrayAtIdentityHashInPairs(obj, (sp-1)); sp-=2; ip += slotRawInt(&obj->slots[op2]); dispatch_opcode; // Number-forSeries : 143 29, 143 30, 143 31 case 29 : vars = g->frame->vars; // 0 receiver, 1 step, 2 last, 3 function, 4 i, 5 j if (IsInt(vars+0) && (IsInt(vars+1) || IsNil(vars+1)) && (IsInt(vars+2) || IsNil(vars+2))) { if (IsNil(vars+1)) { if (IsNil(vars+2)) SetInt(vars+2, 0x7FFFFFFF); if (slotRawInt(&vars[0]) < slotRawInt(&vars[2])) SetInt(vars+1, 1); else SetInt(vars+1, -1); } else { if (IsNil(vars+2)) { if (slotRawInt(&vars[1]) < slotRawInt(&vars[0])) SetInt(vars+2, 0x80000000); else SetInt(vars+2, 0x7FFFFFFF); } SetInt(vars+1, slotRawInt(&vars[1]) - slotRawInt(&vars[0])); } slotCopy(&vars[4], &vars[0]); } else { if (IsInt(vars+0)) { SetFloat(&vars[4], slotRawInt(&vars[0])); } else if (IsFloat(vars+0)) { SetFloat(&vars[4], slotRawFloat(&vars[0])); } else { bailFromNumberSeries: error("Number-forSeries : first, second or last not an Integer or Float.\n"); slotCopy(++sp, &g->receiver); numArgsPushed = 1; selector = gSpecialSelectors[opmPrimitiveFailed]; slot = sp; goto class_lookup; } if (IsNil(vars+1)) { if (IsNil(vars+2)) SetFloat(vars+2, kBigBigFloat); else if (IsInt(vars+2)) SetFloat(&vars[2], slotRawInt(&vars[2])); else if (!IsFloat(vars+2)) goto bailFromNumberSeries; if (slotRawFloat(&vars[4]) < slotRawFloat(&vars[2])) SetFloat(vars+1, 1.); else SetFloat(vars+1, -1.); } else { if (IsInt(vars+1)) SetFloat(&vars[1], slotRawInt(&vars[1])); else if (!IsFloat(vars+1)) goto bailFromNumberSeries; if (IsNil(vars+2)) { if (slotRawFloat(&vars[1]) < slotRawFloat(&vars[4])) SetFloat(vars+2, kSmallSmallFloat); else SetFloat(vars+2, kBigBigFloat); } else if (IsInt(vars+2)) SetFloat(&vars[2], slotRawInt(&vars[2])); else if (!IsFloat(vars+2)) goto bailFromNumberSeries; SetFloat(vars+1, slotRawFloat(&vars[1]) - slotRawFloat(&vars[4])); } } dispatch_opcode; case 30 : vars = g->frame->vars; tag = GetTag(&vars[1]); if (tag == tagInt) { if ((slotRawInt(&vars[1]) >= 0 && slotRawInt(&vars[4]) <= slotRawInt(&vars[2])) || (slotRawInt(&vars[1]) < 0 && slotRawInt(&vars[4]) >= slotRawInt(&vars[2]))) { slotCopy(++sp, &vars[3]); // push function slotCopy(++sp, &vars[4]); // push i slotCopy(++sp, &vars[5]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } } else { if ((slotRawFloat(&vars[1]) >= 0. && slotRawFloat(&vars[4]) <= slotRawFloat(&vars[2])) || (slotRawFloat(&vars[1]) < 0. && slotRawFloat(&vars[4]) >= slotRawFloat(&vars[2]))) { slotCopy(++sp, &vars[3]); // push function slotCopy(++sp, &vars[4]); // push i slotCopy(++sp, &vars[5]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } } dispatch_opcode; case 31 : -- sp ; // Drop vars = g->frame->vars; tag = GetTag(&vars[1]); if (tag == tagInt) { SetRaw(&vars[4], slotRawInt(&vars[4]) + slotRawInt(&vars[1])); // inc i } else { SetRaw(&vars[4], slotRawFloat(&vars[4]) + slotRawFloat(&vars[1])); // inc i } SetRaw(&vars[5], slotRawInt(&vars[5]) + 1); // inc j ip -= 4; dispatch_opcode; } dispatch_opcode; // opStoreClassVar case 144 : case 145 : case 146 : case 147 : case 148 : case 149 : case 150 : case 151 : case 152 : case 153 : case 154 : case 155 : case 156 : case 157 : case 158 : case 159 : handle_op_144: handle_op_145: handle_op_146: handle_op_147: handle_op_148: handle_op_149: handle_op_150: handle_op_151: handle_op_152: handle_op_153: handle_op_154: handle_op_155: handle_op_156: handle_op_157: handle_op_158: handle_op_159: op2 = op1 & 15; op3 = ip[1]; ++ip; // get class var index slotCopy(&g->classvars->slots[(op2<<8)|op3], sp--); g->gc->GCWrite(g->classvars, (sp+1)); dispatch_opcode; // opSendMsg case 160 : handle_op_160: // special case for this as only arg op2 = ip[1]; ++ip; // get selector index slotCopy(++sp, &g->receiver); numArgsPushed = 1; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2]); slot = sp; goto class_lookup; case 161 : case 162 : case 163 : case 164 : case 165 : case 166 : case 167 : case 168 : case 169 : case 170 : case 171 : case 172 : case 173 : case 174 : case 175 : handle_op_161: handle_op_162: handle_op_163: handle_op_164: handle_op_165: handle_op_166: handle_op_167: handle_op_168: handle_op_169: handle_op_170: handle_op_171: handle_op_172: handle_op_173: handle_op_174: handle_op_175: op2 = ip[1]; ++ip; // get selector index numArgsPushed = op1 & 15; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2]); slot = sp - numArgsPushed + 1; goto class_lookup; case 176 : // opcTailCallReturnFromFunction handle_op_176: #if TAILCALLOPTIMIZE g->tailCall = 2; #endif dispatch_opcode; // opSuperMsg case 177 : handle_op_177: // special case for this as only arg op2 = ip[1]; ++ip; // get selector index slotCopy(++sp, &g->receiver); numArgsPushed = 1; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2]); slot = sp; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; goto msg_lookup; case 178 : case 179 : case 180 : case 181 : case 182 : case 183 : case 184 : case 185 : case 186 : case 187 : case 188 : case 189 : case 190 : case 191 : handle_op_178: handle_op_179: handle_op_180: handle_op_181: handle_op_182: handle_op_183: handle_op_184: handle_op_185: handle_op_186: handle_op_187: handle_op_188: handle_op_189: handle_op_190: handle_op_191: op2 = ip[1]; ++ip; // get selector index numArgsPushed = op1 & 15; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2]); slot = sp - numArgsPushed + 1; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; goto msg_lookup; // opSendSpecialMsg case 192 : handle_op_192: slotCopy(++sp, &g->receiver); op2 = ip[1]; ++ip; // get selector index numArgsPushed = 1; selector = gSpecialSelectors[op2]; slot = sp; goto class_lookup; case 193 : case 194 : case 195 : case 196 : case 197 : case 198 : case 199 : case 200 : case 201 : case 202 : case 203 : case 204 : case 205 : case 206 : case 207 : handle_op_193: handle_op_194: handle_op_195: handle_op_196: handle_op_197: handle_op_198: handle_op_199: handle_op_200: handle_op_201: handle_op_202: handle_op_203: handle_op_204: handle_op_205: handle_op_206: handle_op_207: op2 = ip[1]; ++ip; // get selector index numArgsPushed = op1 & 15; selector = gSpecialSelectors[op2]; slot = sp - numArgsPushed + 1; goto class_lookup; // opSendSpecialUnaryArithMsg case 208 : // opNeg handle_op_208: if (IsFloat(sp)) { SetFloat(sp, -slotRawFloat(sp)); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else if (IsInt(sp)) { SetRaw(sp, -slotRawInt(sp)); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 209 : // opNot handle_op_209: if (IsTrue(sp)) { SetTagRaw(sp, tagFalse); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else if (IsFalse(sp)) { SetTagRaw(sp, tagTrue); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 210 : // opIsNil handle_op_210: if (IsNil(sp)) { SetTagRaw(sp, tagTrue); } else { slotCopy(sp, &gSpecialValues[svFalse]); } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif dispatch_opcode; case 211 : // opNotNil handle_op_211: if (NotNil(sp)) { slotCopy(sp, &gSpecialValues[svTrue]); } else { SetTagRaw(sp, tagFalse); } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif dispatch_opcode; case 212 : handle_op_212: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 213 : handle_op_213: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 214 : handle_op_214: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 215 : handle_op_215: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 216 : handle_op_216: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 217 : handle_op_217: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 218 : handle_op_218: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 219 : handle_op_219: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 220 : handle_op_220: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 221 : handle_op_221: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 222 : handle_op_222: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 223 : handle_op_223: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; // opSendSpecialBinaryArithMsg case 224 : // add handle_op_224: if (IsInt(sp - 1)) { if (IsInt(sp)) { --sp; SetRaw(sp, slotRawInt(sp) + slotRawInt(sp + 1)); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opAdd; prAddInt(g, -1); sp = g->sp; ip = g->ip; } } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opAdd; prAddNum(g, -1); sp = g->sp; ip = g->ip; } dispatch_opcode; case 225 : // subtract handle_op_225: if (IsInt(sp - 1)) { if (IsInt(sp)) { --sp; SetRaw(sp, slotRawInt(sp) - slotRawInt(sp + 1)); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opSub; prSubInt(g, -1); sp = g->sp; ip = g->ip; } } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opSub; prSubNum(g, -1); sp = g->sp; ip = g->ip; } dispatch_opcode; case 226 : // multiply handle_op_226: if (IsInt(sp - 1)) { if (IsInt(sp)) { --sp; SetRaw(sp, slotRawInt(sp) * slotRawInt(sp + 1)); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opMul; prMulInt(g, -1); sp = g->sp; ip = g->ip; } } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opMul; prMulNum(g, -1); sp = g->sp; ip = g->ip; } dispatch_opcode; case 227 : handle_op_227: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 228 : handle_op_228: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 229 : handle_op_229: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 230 : handle_op_230: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 231 : handle_op_231: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 232 : handle_op_232: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 233 : handle_op_233: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 234 : handle_op_234: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 235 : handle_op_235: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 236 : handle_op_236: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 237 : handle_op_237: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 238 : handle_op_238: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 239 : handle_op_239: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; // opSpecialOpcodes case 240 : handle_op_240: --sp; dispatch_opcode; // opDrop case 241 : handle_op_241: ++sp; *sp = sp[-1]; dispatch_opcode; // opDup case 242 : // opcFunctionReturn handle_op_242: g->sp = sp; g->ip = ip; returnFromBlock(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 243 : // opcReturn handle_op_243: g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 244 : // opcReturnSelf handle_op_244: slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 245 : // opcReturnTrue handle_op_245: slotCopy(++sp, &gSpecialValues[svTrue]); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 246 : // opcReturnFalse handle_op_246: slotCopy(++sp, &gSpecialValues[svFalse]); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 247 : // opcReturnNil handle_op_247: slotCopy(++sp, &gSpecialValues[svNil]); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 248 : // opcJumpIfFalse handle_op_248: // cannot compare with o_false because it is NaN if ( IsFalse(sp) ) { jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else if ( IsTrue(sp)) { ip+=2; } else { numArgsPushed = 1; selector = gSpecialSelectors[opmNonBooleanError]; slot = sp; goto class_lookup; } --sp; dispatch_opcode; case 249 : // opcJumpIfFalsePushNil handle_op_249: if ( IsFalse(sp)) { jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; slotCopy(sp, &gSpecialValues[svNil]); } else if ( IsTrue(sp)) { --sp; ip+=2; } else { numArgsPushed = 1; selector = gSpecialSelectors[opmNonBooleanError]; slot = sp; goto class_lookup; } dispatch_opcode; case 250 : // opcJumpIfFalsePushFalse handle_op_250: if (IsFalse(sp)) { jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; //*sp = r_false; } else if (IsTrue(sp)) { --sp; ip+=2; } else { numArgsPushed = 1; selector = gSpecialSelectors[opmNonBooleanError]; slot = sp; goto class_lookup; } dispatch_opcode; case 251 : // opcJumpIfTruePushTrue handle_op_251: if (IsFalse(sp)) { --sp; ip+=2; } else if (IsTrue(sp)) { jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; slotCopy(sp, &gSpecialValues[svTrue]); } else { numArgsPushed = 1; selector = gSpecialSelectors[opmNonBooleanError]; slot = sp; goto class_lookup; } dispatch_opcode; case 252 : // opcJumpFwd handle_op_252: jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; dispatch_opcode; case 253 : // opcJumpBak handle_op_253: --sp; // also drops the stack. This saves an opcode in the while loop // which is the only place this opcode is used. jmplen = (ip[1]<<8) | ip[2]; ip -= jmplen; //assert(g->gc->SanityCheck()); dispatch_opcode; case 254 : // opcSpecialBinaryOpWithAdverb handle_op_254: op2 = ip[1]; ++ip; // get selector index g->sp = sp; g->ip = ip; g->primitiveIndex = op2; doSpecialBinaryArithMsg(g, 3, false); sp = g->sp; ip = g->ip; dispatch_opcode; case 255 : // opcTailCallReturnFromMethod handle_op_255: #if TAILCALLOPTIMIZE g->tailCall = 1; #endif dispatch_opcode; //////////////////////////////////// class_lookup: // normal class lookup classobj = classOfSlot(slot); // message sends handled here: msg_lookup: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (UNLIKELY(slotRawSymbol(&meth->name) != selector)) { g->sp = sp; g->ip = ip; doesNotUnderstand(g, selector, numArgsPushed); sp = g->sp; ip = g->ip; } else { PyrMethodRaw *methraw; methraw = METHRAW(meth); switch (methraw->methType) { case methNormal : /* normal msg send */ g->sp = sp; g->ip = ip; executeMethod(g, meth, numArgsPushed); sp = g->sp; ip = g->ip; break; case methReturnSelf : /* return self */ sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ sp -= numArgsPushed - 1; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(slot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(slot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { slotCopy(&obj->slots[index], &gSpecialValues[svNil]); } slotCopy(sp, slot); } break; case methReturnClassVar : /* return class var */ sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else slotCopy(&g->classvars->slots[methraw->specialIndex], &gSpecialValues[svNil]); slotCopy(sp, slot); break; case methRedirect : /* send a different selector to self */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *qslot; int m, mmax; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; } selector = slotRawSymbol(&meth->selectors); goto msg_lookup; case methRedirectSuper : /* send a different selector to self */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *qslot; int m, mmax; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; } selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto msg_lookup; case methForwardInstVar : /* forward to an instance variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *qslot; int m, mmax; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; } selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(slot, &slotRawObject(slot)->slots[index]); classobj = classOfSlot(slot); goto msg_lookup; case methForwardClassVar : /* forward to an instance variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *qslot; int m, mmax; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; } selector = slotRawSymbol(&meth->selectors); slotCopy(slot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(slot); goto msg_lookup; case methPrimitive : /* primitive */ g->sp = sp; g->ip = ip; doPrimitive(g, meth, numArgsPushed); sp = g->sp; ip = g->ip; break; } // switch (meth->methType) } // end handle message #if TAILCALLOPTIMIZE g->tailCall = 0; #endif dispatch_opcode; //////////////////////////////////// key_class_lookup: // normal class lookup classobj = classOfSlot(slot); // message sends handled here: key_msg_lookup: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (UNLIKELY(slotRawSymbol(&meth->name) != selector)) { g->sp = sp; g->ip = ip; doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); sp = g->sp; ip = g->ip; } else { PyrMethodRaw *methraw; methraw = METHRAW(meth); switch (methraw->methType) { case methNormal : /* normal msg send */ g->sp = sp; g->ip = ip; executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); sp = g->sp; ip = g->ip; break; case methReturnSelf : /* return self */ sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ g->sp = sp; numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; sp = g->sp; sp -= numArgsPushed - 1; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(slot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp -= numArgsPushed - 1; numArgsPushed -= numKeyArgsPushed << 1; index = methraw->specialIndex; obj = slotRawObject(slot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else slotCopy(&obj->slots[index], &gSpecialValues[svNil]); slotCopy(sp, slot); } break; case methReturnClassVar : /* return class var */ sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else slotCopy(&g->classvars->slots[methraw->specialIndex], &gSpecialValues[svNil]); slotCopy(sp, slot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ g->sp = sp; numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; sp = g->sp; selector = slotRawSymbol(&meth->selectors); goto msg_lookup; case methRedirectSuper : /* send a different selector to super */ g->sp = sp; numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; sp = g->sp; selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto msg_lookup; case methForwardInstVar : /* forward to an instance variable */ g->sp = sp; numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; sp = g->sp; selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(slot, &slotRawObject(slot)->slots[index]); classobj = classOfSlot(slot); goto msg_lookup; case methForwardClassVar : /* forward to an instance variable */ g->sp = sp; numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; sp = g->sp; selector = slotRawSymbol(&meth->selectors); slotCopy(slot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(slot); goto msg_lookup; case methPrimitive : /* primitive */ g->sp = sp; g->ip = ip; doPrimitiveWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); sp = g->sp; ip = g->ip; break; } // switch (meth->methType) } // end handle message numKeyArgsPushed = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif dispatch_opcode; } // switch(op1) } // end while(running) #ifndef SC_WIN32 running = true; // reset the signal #endif g->sp = sp; g->ip = ip; } void DumpSimpleBackTrace(VMGlobals *g); void DumpSimpleBackTrace(VMGlobals *g) { int i; PyrFrame *frame; post("CALL STACK:\n"); // print the variables and arguments for the most recent frames in the // call graph frame = g->frame; for (i=0; i<16; ++i) { char str[256]; slotOneWord(&frame->method, str); post("%s ip %d\n", str, (char*)slotRawPtr(&frame->ip) - (char*)slotRawObject(&slotRawMethod(&frame->method)->code)->slots); frame = slotRawFrame(&frame->caller); if (!frame) break; } if (frame) { post("...\n"); } //DumpStack(g, g->sp); } void DumpBackTrace(VMGlobals *g) { int i; PyrFrame *frame; post("CALL STACK:\n"); // print the variables and arguments for the most recent frames in the // call graph frame = g->frame; for (i=0; i<16; ++i) { if (FrameSanity(frame, "DumpBackTrace")) { post("FRAME CORRUPTED\n"); return; } DumpFrame(frame); frame = slotRawFrame(&frame->caller); if (!frame) break; } if (frame) { post("...\n"); } //DumpStack(g, g->sp); } void DumpDetailedFrame(PyrFrame *frame); void DumpDetailedBackTrace(VMGlobals *g); void DumpDetailedBackTrace(VMGlobals *g) { int i; PyrFrame *frame; post("CALL STACK:\n"); // print the variables and arguments for the most recent frames in the // call graph frame = g->frame; for (i=0; i<16; ++i) { if (FrameSanity(frame, "DumpDetailedBackTrace")) { post("FRAME CORRUPTED\n"); return; } DumpDetailedFrame(frame); frame = slotRawFrame(&frame->caller); if (!frame) break; } if (frame) { post("...\n"); } //DumpStack(g, g->sp); } void DumpStack(VMGlobals *g, PyrSlot *sp) { PyrSlot *slot; char str[128]; #if BCSTAT dumpbcstat(); #endif postfl("STACK:\n"); slot = sp - 64; if (slot < g->gc->Stack()->slots) slot = g->gc->Stack()->slots; for (size_t i=slot - g->gc->Stack()->slots; slot<=sp; slot++, ++i) { slotString(slot, str); post(" %2d %s\n", i, str); } } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/dumpByteCodes.cpp0000664000000000000000000010614212014636264025227 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrKernel.h" #include "PyrParseNode.h" #include "PyrSymbol.h" #include "SCBase.h" void numBlockTemps(PyrBlock *block, long level, long *numArgNames, long *numVarNames); void numBlockTemps(PyrBlock *block, long level, long *numArgNames, long *numVarNames) { long i; for (i=0; icontextDef); } *numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; *numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; } unsigned char* dumpOneByteCode(PyrBlock *theBlock, PyrClass* theClass, unsigned char *ip); unsigned char* dumpOneByteCode(PyrBlock *theBlock, PyrClass* theClass, unsigned char *ip) { PyrClass *classobj; PyrBlock *block; PyrSlot *slot; PyrSymbol *selector; char str[256]; long op1, op2, op3, op4, op5; long i, n, ival, jmplen; long numArgNames, numVarNames, numTemps; unsigned char *ipbeg; if (theClass == NULL) { block = theBlock; theClass = 0; while (block) { //dumpObject((PyrObject*)block); //post("block->classptr %d class_method %d %d\n", // block->classptr, class_method, isKindOf((PyrObject*)block, class_method)); //if (block->classptr == class_method) { if (isKindOf((PyrObject*)block, class_method)) { theClass = slotRawClass(&((PyrMethod*)block)->ownerclass); break; } block = slotRawBlock(&block->contextDef); } if (theClass == NULL) { theClass = s_interpreter->u.classobj; //error("dumpByteCodes: no Class found.\n"); //return NULL; } } ipbeg = slotRawInt8Array(&theBlock->code)->b; n = ip - ipbeg; op1 = *ip++; post("%3d %02X", n, op1); switch (op1) { case 0 : // push class op2 = *ip++; // get literal index post(" %02X PushClassX '%s'\n", op2, slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2])->name); break; case 1 : // Extended, PushInstVar op2 = *ip++; // get inst var index post(" %02X PushInstVarX '%s'\n", op2, slotRawSymbolArray(&theClass->instVarNames)->symbols[op2]->name); break; case 2 : // Extended, PushTempVar op2 = *ip++; // get temp var level block = theBlock; for (i=op2; i--; block = slotRawBlock(&block->contextDef)) { /* noop */ } numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; op3 = numTemps - *ip++ - 1; // get temp var index if (op3 < numArgNames) { post(" %02X %02X PushTempVarX '%s'\n", op2, op3, slotRawSymbolArray(&block->argNames)->symbols[op3]->name); } else { post(" %02X %02X PushTempVarX '%s'\n", op2, op3, slotRawSymbolArray(&block->varNames)->symbols[op3-numArgNames]->name); } break; case 3 : // Extended, PushTempZeroVar block = theBlock; numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; op2 = numTemps - *ip++ - 1; // get temp var index if (op2 < numArgNames) { post(" %02X PushTempZeroVarX '%s'\n", op2, slotRawSymbolArray(&theBlock->argNames)->symbols[op2]->name); } else { post(" %02X PushTempZeroVarX '%s'\n", op2, slotRawSymbolArray(&theBlock->varNames)->symbols[op2-numArgNames]->name); } break; case 4 : // Extended, PushLiteral op2 = *ip++; // get literal index // push a block if it is one slot = slotRawObject(&theBlock->selectors)->slots + op2; slotString(slot, str); post(" %02X PushLiteralX %s\n", op2, str); break; case 5 : // Extended, PushClassVar op2 = *ip++; // get class var literal index op3 = *ip++; // get class var index post(" %02X %02X PushClassVarX\n", op2, op3); break; case 6 : // Extended, PushSpecialValue == push a special class op2 = *ip++; // get class name index classobj = gSpecialClasses[op2]->u.classobj; post(" %02X PushSpecialClass '%s'\n", op2, slotRawSymbol(&classobj->name)->name); break; case 7 : // Extended, StoreInstVar op2 = *ip++; // get inst var index post(" %02X StoreInstVarX '%s'\n", op2, slotRawSymbolArray(&theClass->instVarNames)->symbols[op2]->name); break; case 8 : // Extended, StoreTempVar op2 = *ip++; // get temp var level block = theBlock; for (i=op2; i--; block = slotRawBlock(&block->contextDef)) { /* noop */ } numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; op3 = *ip++; // get temp var index if (op3 < numArgNames) { post(" %02X %02X StoreTempVarX '%s'\n", op2, op3, slotRawSymbolArray(&block->argNames)->symbols[op3]->name); } else { post(" %02X %02X StoreTempVarX '%s'\n", op2, op3, slotRawSymbolArray(&block->varNames)->symbols[op3-numArgNames]->name); } break; case 9 : // Extended, StoreClassVar op2 = *ip++; // get class var literal index op3 = *ip++; // get class var index post(" %02X %02X StoreClassVarX\n", op2, op3); break; case 10 : // Extended, SendMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op4]); post(" %02X %02X %02X SendMsgX '%s'\n", op2, op3, op4, selector->name); break; case 11 : // Extended, SuperMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op4]); post(" %02X %02X %02X SuperMsgX '%s'\n", op2, op3, op4, selector->name); break; case 12 : // Extended, SendSpecialMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index post(" %02X %02X %02X SendSpecialMsgX '%s'\n", op2, op3, op4, gSpecialSelectors[op4]->name); break; case 13 : // Extended, SendSpecialUnaryArithMsg op2 = *ip++; // get selector index post(" %02X SendSpecialUnaryArithMsgX '%s'\n", op2, gSpecialUnarySelectors[op2]->name); break; case 14 : // Extended, SendSpecialBinaryArithMsg op2 = *ip++; // get selector index post(" %02X SendSpecialBinaryArithMsgX '%s'\n", op2, gSpecialBinarySelectors[op2]->name); break; case 15 : // Extended, SpecialOpcode (none yet) op2 = *ip++; // get extended special opcode switch (op2) { case opgProcess : // push thisProcess post(" %02X opgProcess\n", op1, op2); break; case opgThread : // push thisThread post(" %02X opgThread\n", op1, op2); break; case opgMethod : // push thisMethod post(" %02X opgMethod\n", op1, op2); break; case opgFunctionDef : // push thisBlock post(" %02X opgFunctionDef\n", op1, op2); break; case opgFunction : // push thisClosure post(" %02X opgFunction\n", op1, op2); break; } break; // PushInstVar, 0..15 case 16 : case 17 : case 18 : case 19 : case 20 : case 21 : case 22 : case 23 : case 24 : case 25 : case 26 : case 27 : case 28 : case 29 : case 30 : case 31 : post(" PushInstVar '%s'\n", slotRawSymbolArray(&theClass->instVarNames)->symbols[op1&15]->name); break; case 32 : op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpIfTrue %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 33 : case 34 : case 35 : case 36 : case 37 : case 38 : case 39 : op2 = op1 & 15; // get temp var level block = theBlock; for (i=op2; i--; block = slotRawBlock(&block->contextDef)) { /* noop */ } numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; op3 = numTemps - *ip++ - 1; // get temp var index if (op3 >= 0 && op3 < numArgNames) { post(" %02X PushTempVar '%s'\n", op3, slotRawSymbolArray(&block->argNames)->symbols[op3]->name); } else if (op3 >= 0) { post(" %02X PushTempVar '%s'\n", op3, slotRawSymbolArray(&block->varNames)->symbols[op3-numArgNames]->name); } break; case 40 : op5 = *ip++; ival = op5; slot = slotRawObject(&theBlock->constants)->slots + ival; slotString(slot, str); post(" %02X PushConstant %s\n", op5, str); break; case 41 : op4 = *ip++; op5 = *ip++; ival = (op4 << 8) | op5; slot = slotRawObject(&theBlock->constants)->slots + ival; slotString(slot, str); post(" %02X %02X PushConstant %s\n", op4, op5, str); break; case 42 : op3 = *ip++; op4 = *ip++; op5 = *ip++; ival = (op3 << 16) | (op4 << 8) | op5; slot = slotRawObject(&theBlock->constants)->slots + ival; slotString(slot, str); post(" %02X %02X %02X PushConstant %s\n", op3, op4, op5, str); break; case 43 : op2 = *ip++; op3 = *ip++; op4 = *ip++; op5 = *ip++; ival = (op2 << 24) | (op3 << 16) | (op4 << 8) | op5; slot = slotRawObject(&theBlock->constants)->slots + ival; slotString(slot, str); post(" %02X %02X %02X %02X PushConstant %s\n", op2, op3, op4, op5, str); break; case 44 : op5 = *ip++; ival = (int32)(op5 << 24) >> 24; post(" %02X PushInt %d\n", op5, ival); break; case 45 : op4 = *ip++; op5 = *ip++; ival = (int32)((op4 << 24) | (op5 << 16)) >> 16; post(" %02X %02X PushInt %d\n", op4, op5, ival); break; case 46 : op3 = *ip++; op4 = *ip++; op5 = *ip++; ival = (int32)((op3 << 24) | (op4 << 16) | (op5 << 8)) >> 8; post(" %02X %02X %02X PushInt %d\n", op3, op4, op5, ival); break; case 47 : op2 = *ip++; op3 = *ip++; op4 = *ip++; op5 = *ip++; ival = (int32)((op2 << 24) | (op3 << 16) | (op4 << 8) | op5); post(" %02X %02X %02X %02X PushInt %d\n", op2, op3, op4, op5, ival); break; case 48 : case 49 : case 50 : case 51 : case 52 : case 53 : case 54 : case 55 : case 56 : case 57 : case 58 : case 59 : case 60 : case 61 : case 62 : case 63 : op2 = op1 & 15; // get temp var index block = theBlock; numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; if (op2 < numArgNames) { post(" PushTempZeroVar '%s'\n", slotRawSymbolArray(&theBlock->argNames)->symbols[op2]->name); } else { post(" PushTempZeroVar '%s'\n", slotRawSymbolArray(&theBlock->varNames)->symbols[op2-numArgNames]->name); } break; case 64 : case 65 : case 66 : case 67 : case 68 : case 69 : case 70 : case 71 : case 72 : case 73 : case 74 : case 75 : case 76 : case 77 : case 78 : case 79 : op2 = op1 & 15; // get temp var level slot = slotRawObject(&theBlock->constants)->slots + op2; slotString(slot, str); post(" PushLiteral %s\n", str); break; // PushClassVar case 80 : case 81 : case 82 : case 83 : case 84 : case 85 : case 86 : case 87 : case 88 : case 89 : case 90 : case 91 : case 92 : case 93 : case 94 : case 95 : op2 = op1 & 15; op3 = *ip++; // get class var index post(" %02X %02X PushClassVar\n", op2, op3); break; // PushSpecialValue case 96 : post(" PushSpecialValue this\n"); break; case 97 : post(" PushOneAndSubtract\n"); break; case 98 : post(" PushSpecialValue -1\n"); break; case 99 : post(" PushSpecialValue 0\n"); break; case 100 : post(" PushSpecialValue 1\n"); break; case 101 : post(" PushSpecialValue 2\n"); break; case 102 : post(" PushSpecialValue 0.5\n"); break; case 103 : post(" PushSpecialValue -1.0\n"); break; case 104 : post(" PushSpecialValue 0.0\n"); break; case 105 : post(" PushSpecialValue 1.0\n"); break; case 106 : post(" PushSpecialValue 2.0\n"); break; case 107 : post(" PushOneAndAdd\n"); break; case 108 : post(" PushSpecialValue true\n"); break; case 109 : post(" PushSpecialValue false\n"); break; case 110 : post(" PushSpecialValue nil\n"); break; case 111 : post(" PushSpecialValue 'end'\n"); break; // StoreInstVar, 0..15 case 112 : case 113 : case 114 : case 115 : case 116 : case 117 : case 118 : case 119 : case 120 : case 121 : case 122 : case 123 : case 124 : case 125 : case 126 : case 127 : post(" StoreInstVar '%s'\n", slotRawSymbolArray(&theClass->instVarNames)->symbols[op1 & 15]->name); break; // StoreTempVar case 128 : case 129 : case 130 : case 131 : case 132 : case 133 : case 134 : case 135 : op2 = op1 & 15; // get temp var level block = theBlock; for (i=op2; i--; block = slotRawBlock(&block->contextDef)) { /* noop */ } numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; op3 = *ip++; // get temp var index if (op3 < numArgNames) { post(" %02X StoreTempVar '%s'\n", op3, slotRawSymbolArray(&block->argNames)->symbols[op3]->name); } else { post(" %02X StoreTempVar '%s'\n", op3, slotRawSymbolArray(&block->varNames)->symbols[op3-numArgNames]->name); } break; case 136 : op2 = *ip++; // get inst var index op3 = *ip++; // get selector index selector = gSpecialSelectors[op3]; post(" %02X %02X PushInstVarAndSendSpecialMsg '%s' '%s'\n", op2, op3, slotRawSymbolArray(&theClass->instVarNames)->symbols[op2]->name, selector->name); break; case 137 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); post(" %02X PushAllArgs+SendMsg '%s'\n", op2, selector->name); break; case 138 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); post(" %02X PushAllButFirstArg+SendMsg '%s'\n", op2, selector->name); break; case 139 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; post(" %02X PushAllArgs+SendSpecialMsg '%s'\n", op2, selector->name); break; case 140 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; post(" %02X PushAllButFirstArg+SendSpecialMsg '%s'\n", op2, selector->name); break; case 141 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); post(" %02X PushAllButFirstTwoArgs+SendMsg '%s'\n", op2, selector->name); break; case 142 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; post(" %02X PushAllButFirstTwoArgs+SendSpecialMsg '%s'\n", op2, selector->name); break; case 143 : op2 = *ip++; // get loop opcode if (op2 < 23 || op2 > 27) { post(" %02X ControlOpcode\n", op2); break; } else { op3 = *ip++; // jump op4 = *ip++; // jump jmplen = ((op3 & 0xFF)<<8) | (op4 & 0xFF); post(" %02X %02X %02X ControlOpcode %d (%d)\n", op2, op3, op4, jmplen, n + jmplen + 3); break; } break; // StoreClassVar case 144 : case 145 : case 146 : case 147 : case 148 : case 149 : case 150 : case 151 : case 152 : case 153 : case 154 : case 155 : case 156 : case 157 : case 158 : case 159 : op2 = op1 & 15; op3 = *ip++; // get class var index post(" %02X StoreClassVar\n", op3); break; // SendMsg case 160 : case 161 : case 162 : case 163 : case 164 : case 165 : case 166 : case 167 : case 168 : case 169 : case 170 : case 171 : case 172 : case 173 : case 174 : case 175 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); post(" %02X SendMsg '%s'\n", op2, selector->name); break; // TailCallReturnFromFunction case 176 : post(" TailCallReturnFromFunction\n"); break; // SuperMsg case 177 : case 178 : case 179 : case 180 : case 181 : case 182 : case 183 : case 184 : case 185 : case 186 : case 187 : case 188 : case 189 : case 190 : case 191 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); post(" %02X SuperMsg '%s'\n", op2, selector->name); break; // SendSpecialMsg case 192 : case 193 : case 194 : case 195 : case 196 : case 197 : case 198 : case 199 : case 200 : case 201 : case 202 : case 203 : case 204 : case 205 : case 206 : case 207 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; post(" %02X SendSpecialMsg '%s'\n", op2, selector->name); break; // SendSpecialUnaryArithMsg case 208 : case 209 : case 210 : case 211 : case 212 : case 213 : case 214 : case 215 : case 216 : case 217 : case 218 : case 219 : case 220 : case 221 : case 222 : case 223 : op2 = op1 & 15; selector = gSpecialUnarySelectors[op2]; post(" SendSpecialUnaryArithMsg '%s'\n", selector->name); break; // SendSpecialBinaryArithMsg case 224 : case 225 : case 226 : case 227 : case 228 : case 229 : case 230 : case 231 : case 232 : case 233 : case 234 : case 235 : case 236 : case 237 : case 238 : case 239 : op2 = op1 & 15; selector = gSpecialBinarySelectors[op2]; post(" SendSpecialBinaryArithMsg '%s'\n", selector->name); break; // SpecialOpcodes case 240 : post(" Drop\n"); break; case 241 : post(" Dup\n"); break; // Dup case 242 : post(" BlockReturn\n"); break; // BlockReturn case 243 : post(" Return\n"); break; // Return case 244 : post(" ReturnSelf\n"); break; // ReturnSelf case 245 : post(" ReturnTrue\n"); break; // ReturnTrue case 246 : post(" ReturnFalse\n"); break; // ReturnFalse case 247 : post(" ReturnNil\n"); break; // ReturnNil case 248 : // JumpIfFalse op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpIfFalse %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 249 : // JumpIfFalsePushNil op2 = *ip++; op3 = *ip++; jmplen = ((op2 & 0xFF)<<8) | (op3 & 0xFF); post(" %02X %02X JumpIfFalsePushNil %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 250 : // JumpIfFalsePushFalse op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpIfFalsePushFalse %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 251 : // JumpIfTruePushTrue op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpIfTruePushTrue %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 252 : // JumpFwd op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpFwd %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 253 : // JumpBak op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpBak %d (%d)\n", op2, op3, jmplen, n - jmplen + 1); break; case 254 : op2 = *ip++; post(" %02X SpecialBinaryOpWithAdverb\n", op2); break; case 255 : post(" TailCallReturnFromMethod\n"); break; } return ip; } bool detectSendSelector(PyrBlock *theBlock, PyrClass* theClass, unsigned char **ipp, PyrSymbol *testSelector); bool detectSendSelector(PyrBlock *theBlock, PyrClass* theClass, unsigned char **ipp, PyrSymbol *testSelector) { PyrBlock *block; PyrSymbol *selector = 0; long op1, op2, op3, op4, op5, op6; unsigned char *ip = *ipp; if (theClass == NULL) { block = theBlock; theClass = 0; while (block) { if (isKindOf((PyrObject*)block, class_method)) { theClass = slotRawClass(&((PyrMethod*)block)->ownerclass); break; } block = slotRawBlock(&block->contextDef); } if (theClass == NULL) { theClass = s_interpreter->u.classobj; } } op1 = *ip++; switch (op1) { case 0 : // push class op2 = *ip++; // get literal index break; case 1 : // Extended, PushInstVar op2 = *ip++; // get inst var index break; case 2 : // Extended, PushTempVar op2 = *ip++; // get temp var level op3 = *ip++; // get temp var index break; case 3 : // Extended, PushTempZeroVar op2 = *ip++; // get temp var level break; case 4 : // Extended, PushLiteral op2 = *ip++; // get literal index break; case 5 : // Extended, PushClassVar op2 = *ip++; // get class var literal index op3 = *ip++; // get class var index break; case 6 : // Extended, PushSpecialValue == push a special class op2 = *ip++; // get class name index break; case 7 : // Extended, StoreInstVar op2 = *ip++; // get inst var index break; case 8 : // Extended, StoreTempVar op2 = *ip++; // get temp var level op3 = *ip++; // get class var index break; case 9 : // Extended, StoreClassVar op2 = *ip++; // get class var literal index op3 = *ip++; // get class var index break; case 10 : // Extended, SendMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op4]); break; case 11 : // Extended, SuperMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op4]); break; case 12 : // Extended, SendSpecialMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index selector = gSpecialSelectors[op4]; break; case 13 : // Extended, SendSpecialUnaryArithMsg op2 = *ip++; // get selector index selector = gSpecialUnarySelectors[op2]; break; case 14 : // Extended, SendSpecialBinaryArithMsg op2 = *ip++; // get selector index selector = gSpecialBinarySelectors[op2]; break; case 15 : // Extended, SpecialOpcode (none yet) op2 = *ip++; // get extended special opcode break; // PushInstVar, 0..15 case 16 : case 17 : case 18 : case 19 : case 20 : case 21 : case 22 : case 23 : case 24 : case 25 : case 26 : case 27 : case 28 : case 29 : case 30 : case 31 : break; case 32 : case 33 : case 34 : case 35 : case 36 : case 37 : case 38 : case 39 : case 40 : case 41 : case 42 : case 43 : case 44 : case 45 : case 46 : case 47 : op2 = op1 & 15; // get temp var level op3 = *ip++; // get num key args break; case 48 : case 49 : case 50 : case 51 : case 52 : case 53 : case 54 : case 55 : case 56 : case 57 : case 58 : case 59 : case 60 : case 61 : case 62 : case 63 : break; case 64 : case 65 : case 66 : case 67 : case 68 : case 69 : case 70 : case 71 : case 72 : case 73 : case 74 : case 75 : case 76 : case 77 : case 78 : case 79 : break; // PushClassVar case 80 : case 81 : case 82 : case 83 : case 84 : case 85 : case 86 : case 87 : case 88 : case 89 : case 90 : case 91 : case 92 : case 93 : case 94 : case 95 : op2 = op1 & 15; op3 = *ip++; // get class var index break; // PushSpecialValue case 96 : case 97 : case 98 : case 99 : case 100 : case 101 : case 102 : case 103 : case 104 : case 105 : case 106 : case 107 : case 108 : case 109 : case 110 : case 111 : break; // StoreInstVar, 0..15 case 112 : case 113 : case 114 : case 115 : case 116 : case 117 : case 118 : case 119 : case 120 : case 121 : case 122 : case 123 : case 124 : case 125 : case 126 : case 127 : break; // StoreTempVar case 128 : case 129 : case 130 : case 131 : case 132 : case 133 : case 134 : case 135 : op2 = op1 & 15; // get temp var level op3 = *ip++; // get class var index break; case 136 : op2 = *ip++; // get inst var index op3 = *ip++; // get selector index selector = gSpecialSelectors[op3]; break; case 137 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); break; case 138 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); break; case 139 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; break; case 140 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; break; case 141 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); break; case 142 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; break; case 143 : op2 = *ip++; // get selector index break; // StoreClassVar case 144 : case 145 : case 146 : case 147 : case 148 : case 149 : case 150 : case 151 : case 152 : case 153 : case 154 : case 155 : case 156 : case 157 : case 158 : case 159 : op2 = op1 & 15; op3 = *ip++; // get class var index break; // SendMsg case 160 : case 161 : case 162 : case 163 : case 164 : case 165 : case 166 : case 167 : case 168 : case 169 : case 170 : case 171 : case 172 : case 173 : case 174 : case 175 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); break; // SuperMsg case 176 : case 177 : case 178 : case 179 : case 180 : case 181 : case 182 : case 183 : case 184 : case 185 : case 186 : case 187 : case 188 : case 189 : case 190 : case 191 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); break; // SendSpecialMsg case 192 : case 193 : case 194 : case 195 : case 196 : case 197 : case 198 : case 199 : case 200 : case 201 : case 202 : case 203 : case 204 : case 205 : case 206 : case 207 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; break; // SendSpecialUnaryArithMsg case 208 : case 209 : case 210 : case 211 : case 212 : case 213 : case 214 : case 215 : case 216 : case 217 : case 218 : case 219 : case 220 : case 221 : case 222 : case 223 : op2 = op1 & 15; selector = gSpecialUnarySelectors[op2]; break; // SendSpecialBinaryArithMsg case 224 : case 225 : case 226 : case 227 : case 228 : case 229 : case 230 : case 231 : case 232 : case 233 : case 234 : case 235 : case 236 : case 237 : case 238 : case 239 : op2 = op1 & 15; selector = gSpecialBinarySelectors[op2]; break; // SpecialOpcodes case 240 : case 241 : case 242 : case 243 : case 244 : case 245 : case 246 : case 247 : break; case 248 : // JumpIfFalse case 249 : // JumpIfFalsePushNil case 250 : // JumpIfFalsePushFalse case 251 : // JumpIfTruePushTrue case 252 : // JumpFwd case 253 : // JumpBak op2 = *ip++; op3 = *ip++; break; case 254 : // PushPosInt case 255 : // PushNegInt op2 = *ip++; if (op2 & 0x80) { op3 = *ip++; if (op3 & 0x80) { op4 = *ip++; if (op4 & 0x80) { op5 = *ip++; if (op5 & 0x80) { op6 = *ip++; } } } } break; } *ipp = ip; return testSelector == selector; } void dumpByteCodes(PyrBlock *theBlock); void dumpByteCodes(PyrBlock *theBlock) { PyrClass *theClass; PyrBlock *block; long size; unsigned char *ip, *ipbeg, *ipend; if (slotRawInt8Array(&theBlock->code) == NULL) { post("Code empty.\n"); return; } block = theBlock; theClass = 0; while (block) { if (isKindOf((PyrObject*)block, class_method)) { theClass = slotRawClass(&((PyrMethod*)block)->ownerclass); break; } block = slotRawBlock(&block->contextDef); } if (theClass == NULL) { theClass = s_interpreter->u.classobj; } ip = ipbeg = slotRawInt8Array(&theBlock->code)->b; size = slotRawInt8Array(&theBlock->code)->size; ipend = ip + size; post("BYTECODES: (%d)\n", size); while (ipcode) == NULL) { PyrMethodRaw* methraw = METHRAW(theBlock); switch (methraw->methType) { case methRedirect : case methRedirectSuper : case methForwardInstVar : case methForwardClassVar : selector = slotRawSymbol(&theBlock->selectors); return selector == testSelector; default : return false; } } block = theBlock; theClass = 0; while (block) { if (isKindOf((PyrObject*)block, class_method)) { theClass = slotRawClass(&((PyrMethod*)block)->ownerclass); break; } block = slotRawBlock(&block->contextDef); } if (theClass == NULL) { theClass = s_interpreter->u.classobj; } ip = ipbeg = slotRawInt8Array(&theBlock->code)->b; size = slotRawInt8Array(&theBlock->code)->size; ipend = ip + size; bool res = false; while (ip * Copyright 2011 Jakob Leben * * This file is part of SuperCollider. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA * */ #ifndef SC_LANGUAGECONFIG_HPP_INCLUDED #define SC_LANGUAGECONFIG_HPP_INCLUDED #include #include class SC_LanguageConfig { public: typedef std::vector DirVector; SC_LanguageConfig(); const DirVector& includedDirectories() { return mIncludedDirectories; } const DirVector& excludedDirectories() { return mExcludedDirectories; } void postExcludedDirectories(void); bool forEachIncludedDirectory(bool (*func)(const char *, int)); bool pathIsExcluded(const char *path); void addIncludedDirectory(const char *name); void addExcludedDirectory(const char *name); void removeIncludedDirectory(const char *name); void removeExcludedDirectory(const char *name); // convenience functions to access the global library config static void setConfigFile(std::string const & fileName) { gConfigFile = fileName; } static bool readLibraryConfigYAML(const char* fileName); static bool writeLibraryConfigYAML(const char* fileName); static void freeLibraryConfig(); static bool defaultLibraryConfig(void); static bool readLibraryConfig(); private: DirVector mIncludedDirectories; DirVector mExcludedDirectories; DirVector mDefaultClassLibraryDirectories; static std::string gConfigFile; }; extern SC_LanguageConfig* gLanguageConfig; #endif // SC_LANGUAGECONFIG_HPP_INCLUDED SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/PyrMathOps.cpp0000664000000000000000000012753412014636264024536 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "Opcodes.h" #include "PyrInterpreter.h" #include "PyrPrimitive.h" #include "PyrPrimitiveProto.h" #include "PyrMathPrim.h" #include "PyrKernel.h" #include "PyrMessage.h" #include "PyrParseNode.h" #include "PyrSignal.h" #include "PyrSched.h" #include "PyrSymbol.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "MiscInlineMath.h" #include "PyrKernelProto.h" #include double hypotx(double x, double y); #define IS_BINARY_BOOL_OP(op) ((op)>=opEQ && (op)<=opGE) int doSpecialUnaryArithMsg(VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrSymbol *msg; int opcode = g->primitiveIndex; a = g->sp; switch (GetTag(a)) { case tagInt : switch (opcode) { case opNeg : SetRaw(a, -slotRawInt(a)); break; //case opNot : goto send_normal_1; case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; case opBitNot : SetRaw(a, ~slotRawInt(a)); break; case opAbs : SetRaw(a, sc_abs(slotRawInt(a))); break; case opAsFloat : SetFloat(a, (double)slotRawInt(a)); break; case opAsInt : SetRaw(a, (int)slotRawInt(a)); break; case opCeil : SetRaw(a, slotRawInt(a)); break; case opFloor : SetRaw(a, slotRawInt(a)); break; case opFrac : SetRaw(a, 0); break; case opSign : SetRaw(a, slotRawInt(a) > 0 ? 1 : (slotRawInt(a) == 0 ? 0 : -1)); break; case opSquared : SetRaw(a, slotRawInt(a) * slotRawInt(a)); break; case opCubed : SetRaw(a, slotRawInt(a) * slotRawInt(a) * slotRawInt(a)); break; case opSqrt : SetFloat(a, sqrt((double)slotRawInt(a))); break; case opExp : SetFloat(a, exp((double)slotRawInt(a))); break; case opRecip : SetFloat(a, 1. / slotRawInt(a)); break; case opMIDICPS : SetFloat(a, sc_midicps((double)slotRawInt(a))); break; case opCPSMIDI : SetFloat(a, sc_cpsmidi((double)slotRawInt(a))); break; case opMIDIRatio : SetFloat(a, sc_midiratio((double)slotRawInt(a))); break; case opRatioMIDI : SetFloat(a, sc_ratiomidi((double)slotRawInt(a))); break; case opAmpDb : SetFloat(a, sc_ampdb((double)slotRawInt(a))); break; case opDbAmp : SetFloat(a, sc_dbamp((double)slotRawInt(a))); break; case opOctCPS : SetFloat(a, sc_octcps((double)slotRawInt(a))); break; case opCPSOct : SetFloat(a, sc_cpsoct((double)slotRawInt(a))); break; case opLog : SetFloat(a, log((double)slotRawInt(a))); break; case opLog2 : SetFloat(a, sc_log2((double)slotRawInt(a))); break; case opLog10 : SetFloat(a, log10((double)slotRawInt(a))); break; case opSin : SetFloat(a, sin((double)slotRawInt(a))); break; case opCos : SetFloat(a, cos((double)slotRawInt(a))); break; case opTan : SetFloat(a, tan((double)slotRawInt(a))); break; case opArcSin : SetFloat(a, asin((double)slotRawInt(a))); break; case opArcCos : SetFloat(a, acos((double)slotRawInt(a))); break; case opArcTan : SetFloat(a, atan((double)slotRawInt(a))); break; case opSinH : SetFloat(a, sinh((double)slotRawInt(a))); break; case opCosH : SetFloat(a, cosh((double)slotRawInt(a))); break; case opTanH : SetFloat(a, tanh((double)slotRawInt(a))); break; case opRand : SetRaw(a, g->rgen->irand(slotRawInt(a))); break; case opRand2 : SetRaw(a, g->rgen->irand2(slotRawInt(a))); break; case opLinRand : SetRaw(a, g->rgen->ilinrand(slotRawInt(a))); break; case opBiLinRand : SetRaw(a, g->rgen->ibilinrand(slotRawInt(a))); break; // case opExpRand : SetFloat(a, g->rgen->exprand(slotRawInt(a))); break; // case opBiExpRand : SetFloat(a, g->rgen->biexprand(slotRawInt(a))); break; case opSum3Rand : SetFloat(a, g->rgen->sum3rand(slotRawInt(a))); break; // case opGammaRand : SetFloat(a, g->rgen->gammarand(slotRawInt(a))); break; // case opGaussRand : SetFloat(a, g->rgen->gaussrand(slotRawInt(a))); break; // case opPoiRand : SetFloat(a, g->rgen->poirand(slotRawInt(a))); break; case opDistort : SetFloat(a, sc_distort((double)slotRawInt(a))); break; case opSoftClip : SetFloat(a, sc_softclip((double)slotRawInt(a))); break; case opCoin : SetBool(a, (slotRawInt(a))); break; case opRectWindow : SetFloat(a, sc_rectwindow((double)slotRawInt(a))); break; case opHanWindow : SetFloat(a, sc_hanwindow((double)slotRawInt(a))); break; case opWelchWindow : SetFloat(a, sc_welwindow((double)slotRawInt(a))); break; case opTriWindow : SetFloat(a, sc_triwindow((double)slotRawInt(a))); break; case opSCurve : SetFloat(a, sc_scurve((double)slotRawInt(a))); break; case opRamp : SetFloat(a, sc_ramp((double)slotRawInt(a))); break; default : goto send_normal_1; } break; case tagChar : switch (opcode) { //case opNot : goto send_normal_1; case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; case opAsInt : SetTagRaw(a, tagInt); break; case opDigitValue : if (slotRawInt(a) >= '0' && slotRawInt(a) <= '9') SetInt(a, slotRawInt(a) - '0'); else if (slotRawInt(a) >= 'A' && slotRawInt(a) <= 'Z') SetInt(a, slotRawInt(a) - 'A'); else if (slotRawInt(a) >= 'a' && slotRawInt(a) <= 'z') SetInt(a, slotRawInt(a) - 'a'); else SetInt(a, 0); break; default : goto send_normal_1; } break; case tagPtr : switch (opcode) { case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; default : goto send_normal_1; } break; case tagNil : switch (opcode) { case opIsNil : SetTrue(a); break; case opNotNil : SetFalse(a); break; default : goto send_normal_1; } break; case tagFalse : switch (opcode) { case opNot : SetTrue(a); break; case opIsNil : /*SetFalse(a);*/ break; case opNotNil : SetTrue(a); break; default : goto send_normal_1; } break; case tagTrue : switch (opcode) { case opNot : SetFalse(a); break; case opIsNil : SetFalse(a); break; case opNotNil : /*SetTrue(a);*/ break; default : goto send_normal_1; } break; case tagSym : switch (opcode) { case opAsFloat : case opAsInt : goto send_normal_1; case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; default : /* SetSymbol(a, slotRawSymbol(a)); */ break; } break; case tagObj : if (isKindOf(slotRawObject(a), class_signal)) { switch (opcode) { case opNeg : SetRaw(a, signal_invert(g, slotRawObject(a))); break; case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; case opAbs : SetRaw(a, signal_abs(g, slotRawObject(a))); break; case opSign : SetRaw(a, signal_sign(g, slotRawObject(a))); break; case opSquared : SetRaw(a, signal_squared(g, slotRawObject(a))); break; case opCubed : SetRaw(a, signal_cubed(g, slotRawObject(a))); break; case opSqrt : SetRaw(a, signal_sqrt(g, slotRawObject(a))); break; case opExp : SetRaw(a, signal_exp(g, slotRawObject(a))); break; case opRecip : SetRaw(a, signal_recip(g, slotRawObject(a))); break; case opLog : SetRaw(a, signal_log(g, slotRawObject(a))); break; case opLog2 : SetRaw(a, signal_log2(g, slotRawObject(a))); break; case opLog10 : SetRaw(a, signal_log10(g, slotRawObject(a))); break; case opSin : SetRaw(a, signal_sin(g, slotRawObject(a))); break; //case opSin : SetRaw(a, signal_fsin(g, slotRawObject(a))); break; case opCos : SetRaw(a, signal_cos(g, slotRawObject(a))); break; case opTan : SetRaw(a, signal_tan(g, slotRawObject(a))); break; case opArcSin : SetRaw(a, signal_asin(g, slotRawObject(a))); break; case opArcCos : SetRaw(a, signal_acos(g, slotRawObject(a))); break; case opArcTan : SetRaw(a, signal_atan(g, slotRawObject(a))); break; case opSinH : SetRaw(a, signal_sinh(g, slotRawObject(a))); break; case opCosH : SetRaw(a, signal_cosh(g, slotRawObject(a))); break; case opTanH : SetRaw(a, signal_tanh(g, slotRawObject(a))); break; case opDistort : SetRaw(a, signal_distort(g, slotRawObject(a))); break; case opSoftClip : SetRaw(a, signal_softclip(g, slotRawObject(a))); break; default : goto send_normal_1; } } else { goto send_normal_1; } break; default : // double switch (opcode) { case opNeg : SetRaw(a, -slotRawFloat(a)); break; case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; case opBitNot : SetRaw(a, ~(int)slotRawFloat(a)); break; case opAbs : SetRaw(a, sc_abs(slotRawFloat(a))); break; case opAsFloat : SetRaw(a, (double)slotRawFloat(a)); break; case opAsInt : { double val = slotRawFloat(a); if (val == std::numeric_limits::infinity()) SetInt(a, std::numeric_limits::max()); else SetInt(a, (int)val); break; } case opCeil : SetRaw(a, ceil(slotRawFloat(a))); break; case opFloor : SetRaw(a, floor(slotRawFloat(a))); break; case opFrac : SetRaw(a, sc_frac(slotRawFloat(a))); break; case opSign : SetRaw(a, slotRawFloat(a) > 0. ? 1.0 : (slotRawFloat(a) == 0 ? 0.0 : -1.0)); break; case opSquared : SetRaw(a, slotRawFloat(a) * slotRawFloat(a)); break; case opCubed : SetRaw(a, slotRawFloat(a) * slotRawFloat(a) * slotRawFloat(a)); break; case opSqrt : SetRaw(a, sqrt(slotRawFloat(a))); break; case opExp : SetRaw(a, exp(slotRawFloat(a))); break; case opRecip : SetRaw(a, 1./slotRawFloat(a)); break; case opMIDICPS : SetRaw(a, sc_midicps(slotRawFloat(a))); break; case opCPSMIDI : SetRaw(a, sc_cpsmidi(slotRawFloat(a))); break; case opMIDIRatio : SetRaw(a, sc_midiratio((double)slotRawFloat(a))); break; case opRatioMIDI : SetRaw(a, sc_ratiomidi((double)slotRawFloat(a))); break; case opAmpDb : SetRaw(a, sc_ampdb(slotRawFloat(a))); break; case opDbAmp : SetRaw(a, sc_dbamp(slotRawFloat(a))); break; case opOctCPS : SetRaw(a, sc_octcps(slotRawFloat(a))); break; case opCPSOct : SetRaw(a, sc_cpsoct(slotRawFloat(a))); break; case opLog : SetRaw(a, log(slotRawFloat(a))); break; case opLog2 : SetRaw(a, sc_log2(slotRawFloat(a))); break; case opLog10 : SetRaw(a, log10(slotRawFloat(a))); break; case opSin : SetRaw(a, sin(slotRawFloat(a))); break; case opCos : SetRaw(a, cos(slotRawFloat(a))); break; case opTan : SetRaw(a, tan(slotRawFloat(a))); break; case opArcSin : SetRaw(a, asin(slotRawFloat(a))); break; case opArcCos : SetRaw(a, acos(slotRawFloat(a))); break; case opArcTan : SetRaw(a, atan(slotRawFloat(a))); break; case opSinH : SetRaw(a, sinh(slotRawFloat(a))); break; case opCosH : SetRaw(a, cosh(slotRawFloat(a))); break; case opTanH : SetRaw(a, tanh(slotRawFloat(a))); break; case opRand : SetRaw(a, g->rgen->frand() * slotRawFloat(a)); break; case opRand2 : SetRaw(a, g->rgen->frand2() * slotRawFloat(a)); break; case opLinRand : SetRaw(a, g->rgen->linrand(slotRawFloat(a))); break; case opBiLinRand : SetRaw(a, g->rgen->bilinrand(slotRawFloat(a))); break; // case opExpRand : SetRaw(a, g->rgen->exprand(slotRawFloat(a))); break; // case opBiExpRand : SetRaw(a, g->rgen->biexprand(slotRawFloat(a))); break; case opSum3Rand : SetRaw(a, g->rgen->sum3rand(slotRawFloat(a))); break; // case opGammaRand : SetRaw(a, g->rgen->gammarand(slotRawFloat(a))); break; // case opGaussRand : SetRaw(a, g->rgen->gaussrand(slotRawFloat(a))); break; // case opPoiRand : SetRaw(a, g->rgen->poirand(slotRawFloat(a))); break; case opDistort : SetRaw(a, sc_distort(slotRawFloat(a))); break; case opSoftClip : SetRaw(a, sc_softclip(slotRawFloat(a))); break; case opCoin : SetBool(a, g->rgen->frand() < slotRawFloat(a)); break; case opRectWindow : SetRaw(a, sc_rectwindow(slotRawFloat(a))); break; case opHanWindow : SetRaw(a, sc_hanwindow(slotRawFloat(a))); break; case opWelchWindow : SetRaw(a, sc_welwindow(slotRawFloat(a))); break; case opTriWindow : SetRaw(a, sc_triwindow(slotRawFloat(a))); break; case opSCurve : SetRaw(a, sc_scurve(slotRawFloat(a))); break; case opRamp : SetRaw(a, sc_ramp(slotRawFloat(a))); break; default : goto send_normal_1; } break; } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_1: if (numArgsPushed != -1) // special case flag meaning it is a primitive return errFailed; msg = gSpecialUnarySelectors[opcode]; sendMessage(g, msg, 1); return errNone; } int prSpecialBinaryArithMsg(VMGlobals *g, int numArgsPushed) { return doSpecialBinaryArithMsg(g, numArgsPushed, true); } int doSpecialBinaryArithMsg(VMGlobals *g, int numArgsPushed, bool isPrimitive) { PyrSlot *a, *b; PyrSymbol *msg; int opcode = g->primitiveIndex; a = g->sp - (numArgsPushed - 1); b = a + 1; switch (GetTag(a)) { case tagInt : { switch (GetTag(b)) { case tagInt : switch (opcode) { case opAdd : SetRaw(a, slotRawInt(a) + slotRawInt(b)); break; case opSub : SetRaw(a, slotRawInt(a) - slotRawInt(b)); break; case opMul : SetRaw(a, slotRawInt(a) * slotRawInt(b)); break; case opIDiv : SetRaw(a, sc_div(slotRawInt(a), slotRawInt(b))); break; case opFDiv : SetFloat(a, (double)slotRawInt(a) / (double)slotRawInt(b)); break; case opMod : SetRaw(a, sc_mod((int)slotRawInt(a), (int)slotRawInt(b))); break; case opEQ : SetBool(a, slotRawInt(a) == slotRawInt(b)); break; case opNE : SetBool(a, slotRawInt(a) != slotRawInt(b)); break; case opLT : SetBool(a, slotRawInt(a) < slotRawInt(b)); break; case opGT : SetBool(a, slotRawInt(a) > slotRawInt(b)); break; case opLE : SetBool(a, slotRawInt(a) <= slotRawInt(b)); break; case opGE : SetBool(a, slotRawInt(a) >= slotRawInt(b)); break; //case opIdentical : SetBool(a, slotRawInt(a) == slotRawInt(b)); break; //case opNotIdentical : SetBool(a, slotRawInt(a) != slotRawInt(b)); break; case opMin : SetRaw(a, sc_min(slotRawInt(a), slotRawInt(b))); break; case opMax : SetRaw(a, sc_max(slotRawInt(a), slotRawInt(b))); break; case opBitAnd : SetRaw(a, slotRawInt(a) & slotRawInt(b)); break; case opBitOr : SetRaw(a, slotRawInt(a) | slotRawInt(b)); break; case opBitXor : SetRaw(a, slotRawInt(a) ^ slotRawInt(b)); break; case opLCM : SetRaw(a, sc_lcm(slotRawInt(a), slotRawInt(b))); break; case opGCD : SetRaw(a, sc_gcd(slotRawInt(a), slotRawInt(b))); break; case opRound : SetRaw(a, sc_round((int)slotRawInt(a), (int)slotRawInt(b))); break; case opRoundUp :SetRaw(a, sc_roundUp((int)slotRawInt(a), (int)slotRawInt(b))); break; case opTrunc : SetRaw(a, sc_trunc((int)slotRawInt(a), (int)slotRawInt(b))); break; case opAtan2 : SetFloat(a, atan2((double)slotRawInt(a), (double)slotRawInt(b))); break; case opHypot : SetFloat(a, hypot((double)slotRawInt(a), (double)slotRawInt(b))); break; case opHypotx : SetFloat(a, hypotx((double)slotRawInt(a), (double)slotRawInt(b))); break; case opPow : SetFloat(a, pow((double)slotRawInt(a), (double)slotRawInt(b))); break; case opShiftLeft : { long ia = slotRawInt(a); long ib = slotRawInt(b); if (ib>0) ia <<= ib; else if (ib<0) ia >>= -ib; SetRaw(a, ia); } break; case opShiftRight : { long ia = slotRawInt(a); long ib = slotRawInt(b); if (ib>0) ia >>= ib; else if (ib<0) ia <<= -ib; SetRaw(a, ia); } break; case opUnsignedShift : { unsigned long ia = slotRawInt(a); long ib = slotRawInt(b); if (ib>0) ia >>= ib; else if (ib<0) ia <<= -ib; SetRaw(a, (long)ia); } break; case opRing1 : SetRaw(a, sc_ring1(slotRawInt(a), slotRawInt(b))); break; case opRing2 : SetRaw(a, sc_ring2(slotRawInt(a), slotRawInt(b))); break; case opRing3 : SetRaw(a, sc_ring3(slotRawInt(a), slotRawInt(b))); break; case opRing4 : SetRaw(a, sc_ring4(slotRawInt(a), slotRawInt(a))); break; case opDifSqr : SetRaw(a, sc_difsqr(slotRawInt(a), slotRawInt(b))); break; case opSumSqr : SetRaw(a, sc_sumsqr(slotRawInt(a), slotRawInt(b))); break; case opSqrSum : SetRaw(a, sc_sqrsum(slotRawInt(a), slotRawInt(b))); break; case opSqrDif : SetRaw(a, sc_sqrdif(slotRawInt(a), slotRawInt(b))); break; case opAbsDif : SetRaw(a, sc_abs(slotRawInt(a) - slotRawInt(b))); break; case opThresh : SetRaw(a, sc_thresh(slotRawInt(a), slotRawInt(b))); break; case opAMClip : SetRaw(a, sc_amclip(slotRawInt(a), slotRawInt(b))); break; case opScaleNeg : SetRaw(a, sc_scaleneg(slotRawInt(a), slotRawInt(b))); break; case opClip2 : SetRaw(a, sc_clip2(slotRawInt(a), slotRawInt(b))); break; case opFold2 : SetRaw(a, sc_fold2(slotRawInt(a), slotRawInt(b))); break; case opWrap2 : SetRaw(a, sc_wrap2(slotRawInt(a), slotRawInt(b))); break; case opExcess : SetRaw(a, sc_excess(slotRawInt(a), slotRawInt(b))); break; case opFirstArg : SetRaw(a, slotRawInt(a)); break; case opRandRange : SetRaw(a, slotRawInt(b) > slotRawInt(a) ? slotRawInt(a) + g->rgen->irand(slotRawInt(b) - slotRawInt(a) + 1) : slotRawInt(b) + g->rgen->irand(slotRawInt(a) - slotRawInt(b) + 1)); break; case opExpRandRange : SetFloat(a, g->rgen->exprandrng(slotRawInt(a), slotRawInt(b))); break; default : goto send_normal_2; } break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : if (IS_BINARY_BOOL_OP(opcode)) SetBool(a, opcode == opNE); else SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) { switch (opcode) { case opAdd : SetObject(a, signal_add_xf(g, slotRawObject(b), slotRawInt(a))); break; case opSub : SetObject(a, signal_sub_fx(g, slotRawInt(a), slotRawObject(b))); break; case opMul : SetObject(a, signal_mul_xf(g, slotRawObject(b), slotRawInt(a))); break; case opIDiv : SetObject(a, signal_div_fx(g, slotRawInt(a), slotRawObject(b))); break; case opFDiv : SetObject(a, signal_div_fx(g, slotRawInt(a), slotRawObject(b))); break; case opEQ : SetFalse(a); break; case opNE : SetTrue(a); break; case opMin : SetObject(a, signal_min_xf(g, slotRawObject(b), slotRawInt(a))); break; case opMax : SetObject(a, signal_max_xf(g, slotRawObject(b), slotRawInt(a))); break; case opRing1 : SetObject(a, signal_ring1_fx(g, slotRawInt(a), slotRawObject(b))); break; case opRing2 : SetObject(a, signal_ring2_fx(g, slotRawInt(a), slotRawObject(b))); break; case opRing3 : SetObject(a, signal_ring3_fx(g, slotRawInt(a), slotRawObject(b))); break; case opRing4 : SetObject(a, signal_ring4_fx(g, slotRawInt(a), slotRawObject(b))); break; case opDifSqr : SetObject(a, signal_difsqr_fx(g, slotRawInt(a), slotRawObject(b))); break; case opSumSqr : SetObject(a, signal_sumsqr_fx(g, slotRawInt(a), slotRawObject(b))); break; case opSqrSum : SetObject(a, signal_sqrsum_fx(g, slotRawInt(a), slotRawObject(b))); break; case opSqrDif : SetObject(a, signal_sqrdif_fx(g, slotRawInt(a), slotRawObject(b))); break; case opAbsDif : SetObject(a, signal_absdif_fx(g, slotRawInt(a), slotRawObject(b))); break; case opThresh : SetObject(a, signal_thresh_fx(g, slotRawInt(a), slotRawObject(b))); break; case opAMClip : SetObject(a, signal_amclip_fx(g, slotRawInt(a), slotRawObject(b))); break; case opScaleNeg : SetObject(a, signal_scaleneg_fx(g, slotRawInt(a), slotRawObject(b))); break; case opClip2 : SetObject(a, signal_clip2_fx(g, slotRawInt(a), slotRawObject(b))); break; case opFold2 : SetObject(a, signal_fold2_fx(g, slotRawInt(a), slotRawObject(b))); break; case opWrap2 : SetObject(a, signal_wrap2_fx(g, slotRawInt(a), slotRawObject(b))); break; case opExcess : SetObject(a, signal_excess_fx(g, slotRawInt(a), slotRawObject(b))); break; case opFirstArg : SetObject(a, slotRawObject(a)); break; default : goto send_normal_2; } } else { goto send_normal_2; } break; default : switch (opcode) { case opAdd : SetFloat(a, slotRawInt(a) + slotRawFloat(b)); break; case opSub : SetFloat(a, slotRawInt(a) - slotRawFloat(b)); break; case opMul : SetFloat(a, slotRawInt(a) * slotRawFloat(b)); break; case opIDiv : SetRaw(a, (long)floor(slotRawInt(a) / slotRawFloat(b))); break; case opFDiv : SetFloat(a, slotRawInt(a) / slotRawFloat(b)); break; case opMod : SetFloat(a, sc_mod((double)slotRawInt(a), slotRawFloat(b))); break; case opEQ : SetBool(a, slotRawInt(a) == slotRawFloat(b)); break; case opNE : SetBool(a, slotRawInt(a) != slotRawFloat(b)); break; case opLT : SetBool(a, slotRawInt(a) < slotRawFloat(b)); break; case opGT : SetBool(a, slotRawInt(a) > slotRawFloat(b)); break; case opLE : SetBool(a, slotRawInt(a) <= slotRawFloat(b)); break; case opGE : SetBool(a, slotRawInt(a) >= slotRawFloat(b)); break; //case opIdentical : SetFalse(a); break; //case opNotIdentical : SetTrue(a); break; case opMin : SetFloat(a, sc_min((double)slotRawInt(a), slotRawFloat(b))); break; case opMax : SetFloat(a, sc_max((double)slotRawInt(a), slotRawFloat(b))); break; case opRound : SetFloat(a, sc_round((double)slotRawInt(a), slotRawFloat(b))); break; case opRoundUp : SetFloat(a, sc_roundUp((double)slotRawInt(a), slotRawFloat(b))); break; case opTrunc : SetFloat(a, sc_trunc((double)slotRawInt(a), slotRawFloat(b))); break; case opAtan2 : SetFloat(a, atan2(slotRawInt(a), slotRawFloat(b))); break; case opHypot : SetFloat(a, hypot(slotRawInt(a), slotRawFloat(b))); break; case opHypotx : SetFloat(a, hypotx(slotRawInt(a), slotRawFloat(b))); break; case opPow : SetFloat(a, pow((double)slotRawInt(a), slotRawFloat(b))); break; case opRing1 : SetFloat(a, sc_ring1((double)slotRawInt(a), slotRawFloat(b))); break; case opRing2 : SetFloat(a, sc_ring2((double)slotRawInt(a), slotRawFloat(b))); break; case opRing3 : SetFloat(a, sc_ring3((double)slotRawInt(a), slotRawFloat(b))); break; case opRing4 : SetFloat(a, sc_ring4((double)slotRawInt(a), slotRawFloat(b))); break; case opDifSqr : SetFloat(a, sc_difsqr((double)slotRawInt(a), slotRawFloat(b))); break; case opSumSqr : SetFloat(a, sc_sumsqr((double)slotRawInt(a), slotRawFloat(b))); break; case opSqrSum : SetFloat(a, sc_sqrsum((double)slotRawInt(a), slotRawFloat(b))); break; case opSqrDif : SetFloat(a, sc_sqrdif((double)slotRawInt(a), slotRawFloat(b))); break; case opAbsDif : SetFloat(a, sc_abs(slotRawInt(a) - slotRawFloat(b))); break; case opThresh : SetRaw(a, sc_thresh(slotRawInt(a), slotRawFloat(b))); break; case opAMClip : SetFloat(a, sc_amclip((double)slotRawInt(a), slotRawFloat(b))); break; case opScaleNeg : SetFloat(a, sc_scaleneg((double)slotRawInt(a), slotRawFloat(b))); break; case opClip2 : SetFloat(a, sc_clip2((double)slotRawInt(a), slotRawFloat(b))); break; case opFold2 : SetFloat(a, sc_fold2((double)slotRawInt(a), slotRawFloat(b))); break; case opWrap2 : SetFloat(a, sc_wrap2((double)slotRawInt(a), -slotRawFloat(b))); break; case opExcess : SetFloat(a, sc_excess((double)slotRawInt(a), slotRawFloat(b))); break; case opFirstArg : SetInt(a, slotRawInt(a)); break; case opRandRange : SetFloat(a, slotRawInt(a) + g->rgen->frand() * (slotRawFloat(b) - slotRawInt(a))); break; case opExpRandRange : SetFloat(a, g->rgen->exprandrng(slotRawInt(a), slotRawFloat(b))); break; default : goto send_normal_2; } break; } } break; case tagChar : { if (IsChar(b)) { switch (opcode) { case opEQ : SetBool(a, slotRawChar(a) == slotRawChar(b)); break; case opNE : SetBool(a, slotRawChar(a) != slotRawChar(b)); break; case opLT : SetBool(a, slotRawChar(a) < slotRawChar(b)); break; case opGT : SetBool(a, slotRawChar(a) > slotRawChar(b)); break; case opLE : SetBool(a, slotRawChar(a) <= slotRawChar(b)); break; case opGE : SetBool(a, slotRawChar(a) >= slotRawChar(b)); break; //case opIdentical : SetBool(a, slotRawChar(a) == slotRawChar(b)); break; //case opNotIdentical : SetBool(a, slotRawChar(a) != slotRawChar(b)); break; case opMin : SetRawChar(a, sc_min(slotRawChar(a), slotRawChar(b))); break; case opMax : SetRawChar(a, sc_max(slotRawChar(a), slotRawChar(b))); break; default : goto send_normal_2; } } else { goto send_normal_2; } } break; case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : if (IsSym(b)) { switch (opcode) { case opEQ : SetBool(a, slotRawSymbol(a) == slotRawSymbol(b)); break; case opNE : SetBool(a, slotRawSymbol(a) != slotRawSymbol(b)); break; case opLT : SetBool(a, strcmp(slotRawSymbol(a)->name, slotRawSymbol(b)->name) < 0); break; case opGT : SetBool(a, strcmp(slotRawSymbol(a)->name, slotRawSymbol(b)->name) > 0); break; case opLE : SetBool(a, strcmp(slotRawSymbol(a)->name, slotRawSymbol(b)->name) <= 0); break; case opGE : SetBool(a, strcmp(slotRawSymbol(a)->name, slotRawSymbol(b)->name) >= 0); break; //default : leave first operand on stack } } else { if (IS_BINARY_BOOL_OP(opcode)) SetBool(a, opcode == opNE); } break; case tagObj : { if (isKindOf(slotRawObject(a), class_signal)) { switch (GetTag(b)) { case tagInt : switch (opcode) { case opAdd : SetRaw(a, signal_add_xf(g, slotRawObject(a), slotRawInt(b))); break; case opSub : SetRaw(a, signal_sub_xf(g, slotRawObject(a), slotRawInt(b))); break; case opMul : SetRaw(a, signal_mul_xf(g, slotRawObject(a), slotRawInt(b))); break; case opIDiv : SetRaw(a, signal_div_xf(g, slotRawObject(a), slotRawInt(b))); break; case opFDiv : SetRaw(a, signal_div_xf(g, slotRawObject(a), slotRawInt(b))); break; case opEQ : SetFalse(a); break; case opNE : SetTrue(a); break; case opMin : SetRaw(a, signal_min_xf(g, slotRawObject(a), slotRawInt(b))); break; case opMax : SetRaw(a, signal_max_xf(g, slotRawObject(a), slotRawInt(b))); break; case opFill : SetRaw(a, signal_fill(slotRawObject(a), slotRawInt(b))); break; case opRing1 : SetRaw(a, signal_ring1_xf(g, slotRawObject(a), slotRawInt(b))); break; case opRing2 : SetRaw(a, signal_ring2_xf(g, slotRawObject(a), slotRawInt(b))); break; case opRing3 : SetRaw(a, signal_ring3_xf(g, slotRawObject(a), slotRawInt(b))); break; case opRing4 : SetRaw(a, signal_ring4_xf(g, slotRawObject(a), slotRawInt(b))); break; case opDifSqr : SetRaw(a, signal_difsqr_xf(g, slotRawObject(a), slotRawInt(b))); break; case opSumSqr : SetRaw(a, signal_sumsqr_xf(g, slotRawObject(a), slotRawInt(b))); break; case opSqrSum : SetRaw(a, signal_sqrsum_xf(g, slotRawObject(a), slotRawInt(b))); break; case opSqrDif : SetRaw(a, signal_sqrdif_xf(g, slotRawObject(a), slotRawInt(b))); break; case opAbsDif : SetRaw(a, signal_absdif_xf(g, slotRawObject(a), slotRawInt(b))); break; case opThresh : SetRaw(a, signal_thresh_xf(g, slotRawObject(a), slotRawInt(b))); break; case opAMClip : SetRaw(a, signal_amclip_xf(g, slotRawObject(a), slotRawInt(b))); break; case opScaleNeg : SetRaw(a, signal_scaleneg_xf(g, slotRawObject(a), slotRawInt(b))); break; case opClip2 : SetRaw(a, signal_clip2_xf(g, slotRawObject(a), slotRawInt(b))); break; case opFold2 : SetRaw(a, signal_fold2_xf(g, slotRawObject(a), slotRawInt(b))); break; case opWrap2 : SetRaw(a, signal_wrap2_xf(g, slotRawObject(a), slotRawInt(b))); break; case opExcess : SetRaw(a, signal_excess_xf(g, slotRawObject(a), slotRawInt(b))); break; case opFirstArg : SetRaw(a, slotRawObject(a)); break; default : goto send_normal_2; } break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : if (IS_BINARY_BOOL_OP(opcode)) SetBool(a, opcode == opNE); else SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) { switch (opcode) { case opAdd : SetRaw(a, signal_add_xx(g, slotRawObject(a), slotRawObject(b))); break; case opSub : SetRaw(a, signal_sub_xx(g, slotRawObject(a), slotRawObject(b))); break; case opMul : SetRaw(a, signal_mul_xx(g, slotRawObject(a), slotRawObject(b))); break; case opIDiv : SetRaw(a, signal_div_xx(g, slotRawObject(a), slotRawObject(b))); break; case opFDiv : SetRaw(a, signal_div_xx(g, slotRawObject(a), slotRawObject(b))); break; case opEQ : SetBool(a, signal_equal_xx(g, slotRawObject(a), slotRawObject(b))); break; case opNE : SetBool(a, !signal_equal_xx(g, slotRawObject(a), slotRawObject(b))); break; case opMin : SetRaw(a, signal_min_xx(g, slotRawObject(a), slotRawObject(b))); break; case opMax : SetRaw(a, signal_max_xx(g, slotRawObject(a), slotRawObject(b))); break; case opRing1 : SetRaw(a, signal_ring1_xx(g, slotRawObject(a), slotRawObject(b))); break; case opRing2 : SetRaw(a, signal_ring2_xx(g, slotRawObject(a), slotRawObject(b))); break; case opRing3 : SetRaw(a, signal_ring3_xx(g, slotRawObject(a), slotRawObject(b))); break; case opRing4 : SetRaw(a, signal_ring4_xx(g, slotRawObject(a), slotRawObject(b))); break; case opDifSqr : SetRaw(a, signal_difsqr_xx(g, slotRawObject(a), slotRawObject(b))); break; case opSumSqr : SetRaw(a, signal_sumsqr_xx(g, slotRawObject(a), slotRawObject(b))); break; case opSqrSum : SetRaw(a, signal_sqrsum_xx(g, slotRawObject(a), slotRawObject(b))); break; case opSqrDif : SetRaw(a, signal_sqrdif_xx(g, slotRawObject(a), slotRawObject(b))); break; case opAbsDif : SetRaw(a, signal_absdif_xx(g, slotRawObject(a), slotRawObject(b))); break; case opThresh : SetRaw(a, signal_thresh_xx(g, slotRawObject(a), slotRawObject(b))); break; case opAMClip : SetRaw(a, signal_amclip_xx(g, slotRawObject(a), slotRawObject(b))); break; case opScaleNeg : SetRaw(a, signal_scaleneg_xx(g, slotRawObject(a), slotRawObject(b))); break; case opClip2 : SetRaw(a, signal_clip2_xx(g, slotRawObject(a), slotRawObject(b))); break; case opFold2 : SetRaw(a, signal_fold2_xx(g, slotRawObject(a), slotRawObject(b))); break; case opWrap2 : SetRaw(a, signal_wrap2_xx(g, slotRawObject(a), slotRawObject(b))); break; case opExcess : SetRaw(a, signal_excess_xx(g, slotRawObject(a), slotRawObject(b))); break; case opFirstArg : SetRaw(a, slotRawObject(a)); break; default : goto send_normal_2; } } else goto send_normal_2; break; default : // double switch (opcode) { case opAdd : SetRaw(a, signal_add_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opSub : SetRaw(a, signal_sub_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opMul : SetRaw(a, signal_mul_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opIDiv : SetRaw(a, signal_div_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opFDiv : SetRaw(a, signal_div_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opEQ : SetFalse(a); break; case opNE : SetTrue(a); break; case opMin : SetRaw(a, signal_min_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opMax : SetRaw(a, signal_max_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opFill : SetRaw(a, signal_fill(slotRawObject(a), slotRawFloat(b))); break; case opRing1 : SetRaw(a, signal_ring1_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opRing2 : SetRaw(a, signal_ring2_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opRing3 : SetRaw(a, signal_ring3_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opRing4 : SetRaw(a, signal_ring4_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opDifSqr : SetRaw(a, signal_difsqr_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opSumSqr : SetRaw(a, signal_sumsqr_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opSqrSum : SetRaw(a, signal_sqrsum_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opSqrDif : SetRaw(a, signal_sqrdif_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opAbsDif : SetRaw(a, signal_absdif_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opThresh : SetRaw(a, signal_thresh_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opAMClip : SetRaw(a, signal_amclip_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opScaleNeg : SetRaw(a, signal_scaleneg_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opClip2 : SetRaw(a, signal_clip2_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opFold2 : SetRaw(a, signal_fold2_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opWrap2 : SetRaw(a, signal_wrap2_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opExcess : SetRaw(a, signal_excess_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opFirstArg : SetRaw(a, slotRawObject(a)); break; default : goto send_normal_2; } break; } } else { goto send_normal_2; } } break; default : { // double switch (GetTag(b)) { case tagInt : switch (opcode) { case opAdd : SetRaw(a, slotRawFloat(a) + slotRawInt(b)); break; case opSub : SetRaw(a, slotRawFloat(a) - slotRawInt(b)); break; case opMul : SetRaw(a, slotRawFloat(a) * slotRawInt(b)); break; case opIDiv : SetInt(a, (long)floor(slotRawFloat(a) / slotRawInt(b))); break; case opFDiv : SetRaw(a, slotRawFloat(a) / slotRawInt(b)); break; case opMod : SetRaw(a, sc_mod(slotRawFloat(a), (double)slotRawInt(b))); break; case opEQ : SetBool(a, slotRawFloat(a) == slotRawInt(b)); break; case opNE : SetBool(a, slotRawFloat(a) != slotRawInt(b)); break; case opLT : SetBool(a, slotRawFloat(a) < slotRawInt(b)); break; case opGT : SetBool(a, slotRawFloat(a) > slotRawInt(b)); break; case opLE : SetBool(a, slotRawFloat(a) <= slotRawInt(b)); break; case opGE : SetBool(a, slotRawFloat(a) >= slotRawInt(b)); break; //case opIdentical : SetFalse(a); break; //case opNotIdentical : SetTrue(a); break; case opMin : SetRaw(a, sc_min(slotRawFloat(a), (double)slotRawInt(b))); break; case opMax : SetRaw(a, sc_max(slotRawFloat(a), (double)slotRawInt(b))); break; case opRound : SetRaw(a, sc_round(slotRawFloat(a), (double)slotRawInt(b))); break; case opRoundUp : SetRaw(a, sc_roundUp(slotRawFloat(a), (double)slotRawInt(b))); break; case opTrunc : SetRaw(a, sc_trunc(slotRawFloat(a), (double)slotRawInt(b))); break; case opAtan2 : SetRaw(a, atan2(slotRawFloat(a), slotRawInt(b))); break; case opHypot : SetRaw(a, hypot(slotRawFloat(a), slotRawInt(b))); break; case opHypotx : SetRaw(a, hypotx(slotRawFloat(a), slotRawInt(b))); break; case opPow : SetRaw(a, pow(slotRawFloat(a), (double)slotRawInt(b))); break; case opRing1 : SetRaw(a, sc_ring1(slotRawFloat(a), (double)slotRawInt(b))); break; case opRing2 : SetRaw(a, sc_ring2(slotRawFloat(a), (double)slotRawInt(b))); break; case opRing3 : SetRaw(a, sc_ring3(slotRawFloat(a), (double)slotRawInt(b))); break; case opRing4 : SetRaw(a, sc_ring4(slotRawFloat(a), (double)slotRawInt(b))); break; case opDifSqr : SetRaw(a, sc_difsqr(slotRawFloat(a), (double)slotRawInt(b))); break; case opSumSqr : SetRaw(a, sc_sumsqr(slotRawFloat(a), (double)slotRawInt(b))); break; case opSqrSum : SetRaw(a, sc_sqrsum(slotRawFloat(a), (double)slotRawInt(b))); break; case opSqrDif : SetRaw(a, sc_sqrdif(slotRawFloat(a), (double)slotRawInt(b))); break; case opAbsDif : SetRaw(a, sc_abs(slotRawFloat(a) - slotRawInt(b))); break; case opThresh : SetRaw(a, sc_thresh(slotRawFloat(a), slotRawInt(b))); break; case opAMClip : SetRaw(a, sc_amclip(slotRawFloat(a), (double)slotRawInt(b))); break; case opScaleNeg : SetRaw(a, sc_scaleneg(slotRawFloat(a), (double)slotRawInt(b))); break; case opClip2 : SetRaw(a, sc_clip2(slotRawFloat(a), (double)slotRawInt(b))); break; case opFold2 : SetRaw(a, sc_fold2(slotRawFloat(a), (double)slotRawInt(b))); break; case opWrap2 : SetRaw(a, sc_wrap2(slotRawFloat(a), (double)slotRawInt(b))); break; case opExcess : SetRaw(a, sc_excess(slotRawFloat(a), (double)slotRawInt(b))); break; case opFirstArg : SetRaw(a, slotRawFloat(a)); break; case opRandRange : SetRaw(a, slotRawFloat(a) + g->rgen->frand() * (slotRawInt(b) - slotRawFloat(a))); break; case opExpRandRange : SetRaw(a, g->rgen->exprandrng(slotRawFloat(a), slotRawInt(b))); break; default : goto send_normal_2; } break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : if (IS_BINARY_BOOL_OP(opcode)) SetBool(a, opcode == opNE); else SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) { switch (opcode) { case opAdd : SetObject(a, signal_add_xf(g, slotRawObject(b), slotRawFloat(a))); break; case opSub : SetObject(a, signal_sub_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opMul : SetObject(a, signal_mul_xf(g, slotRawObject(b), slotRawFloat(a))); break; case opIDiv : SetObject(a, signal_div_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opFDiv : SetObject(a, signal_div_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opEQ : SetFalse(a); break; case opNE : SetTrue(a); break; case opMin : SetObject(a, signal_min_xf(g, slotRawObject(b), slotRawFloat(a))); break; case opMax : SetObject(a, signal_max_xf(g, slotRawObject(b), slotRawFloat(a))); break; case opRing1 : SetObject(a, signal_ring1_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opRing2 : SetObject(a, signal_ring2_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opRing3 : SetObject(a, signal_ring3_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opRing4 : SetObject(a, signal_ring4_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opDifSqr : SetObject(a, signal_difsqr_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opSumSqr : SetObject(a, signal_sumsqr_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opSqrSum : SetObject(a, signal_sqrsum_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opSqrDif : SetObject(a, signal_sqrdif_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opAbsDif : SetObject(a, signal_absdif_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opThresh : SetObject(a, signal_thresh_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opAMClip : SetObject(a, signal_amclip_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opScaleNeg : SetObject(a, signal_scaleneg_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opClip2 : SetObject(a, signal_clip2_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opFold2 : SetObject(a, signal_fold2_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opWrap2 : SetObject(a, signal_wrap2_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opExcess : SetObject(a, signal_excess_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opFirstArg : SetObject(a, slotRawObject(a)); break; default : goto send_normal_2; } } else goto send_normal_2; break; default : // double switch (opcode) { case opAdd : SetRaw(a, slotRawFloat(a) + slotRawFloat(b)); break; case opSub : SetRaw(a, slotRawFloat(a) - slotRawFloat(b)); break; case opMul : SetRaw(a, slotRawFloat(a) * slotRawFloat(b)); break; case opIDiv : SetInt(a, (long)floor(slotRawFloat(a) / slotRawFloat(b))); break; case opFDiv : SetRaw(a, slotRawFloat(a) / slotRawFloat(b)); break; case opMod : SetRaw(a, sc_mod(slotRawFloat(a), slotRawFloat(b))); break; case opEQ : SetBool(a, slotRawFloat(a) == slotRawFloat(b)); break; case opNE : SetBool(a, slotRawFloat(a) != slotRawFloat(b)); break; case opLT : SetBool(a, slotRawFloat(a) < slotRawFloat(b)); break; case opGT : SetBool(a, slotRawFloat(a) > slotRawFloat(b)); break; case opLE : SetBool(a, slotRawFloat(a) <= slotRawFloat(b)); break; case opGE : SetBool(a, slotRawFloat(a) >= slotRawFloat(b)); break; //case opIdentical : SetBool(a, slotRawFloat(a) == slotRawFloat(b)); break; //case opNotIdentical : SetBool(a, slotRawFloat(a) != slotRawFloat(b)); break; case opMin : SetRaw(a, sc_min(slotRawFloat(a), slotRawFloat(b))); break; case opMax : SetRaw(a, sc_max(slotRawFloat(a), slotRawFloat(b))); break; case opRound : SetRaw(a, sc_round(slotRawFloat(a), slotRawFloat(b))); break; case opRoundUp : SetRaw(a, sc_roundUp(slotRawFloat(a), slotRawFloat(b))); break; case opTrunc : SetRaw(a, sc_trunc(slotRawFloat(a), slotRawFloat(b))); break; case opAtan2 : SetRaw(a, atan2(slotRawFloat(a), slotRawFloat(b))); break; case opHypot : SetRaw(a, hypot(slotRawFloat(a), slotRawFloat(b))); break; case opHypotx : SetRaw(a, hypotx(slotRawFloat(a), slotRawFloat(b))); break; case opPow : SetRaw(a, pow(slotRawFloat(a), slotRawFloat(b))); break; case opRing1 : SetRaw(a, sc_ring1(slotRawFloat(a), slotRawFloat(b))); break; case opRing2 : SetRaw(a, sc_ring2(slotRawFloat(a), slotRawFloat(b))); break; case opRing3 : SetRaw(a, sc_ring3(slotRawFloat(a), slotRawFloat(b))); break; case opRing4 : SetRaw(a, sc_ring4(slotRawFloat(a), slotRawFloat(b))); break; case opDifSqr : SetRaw(a, sc_difsqr(slotRawFloat(a), slotRawFloat(b))); break; case opSumSqr : SetRaw(a, sc_sumsqr(slotRawFloat(a), slotRawFloat(b))); break; case opSqrSum : SetRaw(a, sc_sqrsum(slotRawFloat(a), slotRawFloat(b))); break; case opSqrDif : SetRaw(a, sc_sqrdif(slotRawFloat(a), slotRawFloat(b))); break; case opAbsDif : SetRaw(a, sc_abs(slotRawFloat(a) - slotRawFloat(b))); break; case opThresh : SetRaw(a, sc_thresh(slotRawFloat(a), slotRawFloat(b))); break; case opAMClip : SetRaw(a, sc_amclip(slotRawFloat(a), slotRawFloat(b))); break; case opScaleNeg : SetRaw(a, sc_scaleneg(slotRawFloat(a), slotRawFloat(b))); break; case opClip2 : SetRaw(a, sc_clip2(slotRawFloat(a), slotRawFloat(b))); break; case opFold2 : SetRaw(a, sc_fold2(slotRawFloat(a), slotRawFloat(b))); break; case opWrap2 : SetRaw(a, sc_wrap2(slotRawFloat(a), slotRawFloat(b))); break; case opExcess : SetRaw(a, sc_excess(slotRawFloat(a), slotRawFloat(b))); break; case opFirstArg : SetRaw(a, slotRawFloat(a)); break; case opRandRange : SetRaw(a, slotRawFloat(a) + g->rgen->frand() * (slotRawFloat(b) - slotRawFloat(a))); break; case opExpRandRange : SetRaw(a, g->rgen->exprandrng(slotRawFloat(a), slotRawFloat(b))); break; default : goto send_normal_2; } break; } } break; } g->sp = a; // drop g->numpop = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_2: if (isPrimitive) // special case flag meaning it is a primitive return errFailed; // arguments remain on the stack msg = gSpecialBinarySelectors[opcode]; sendMessage(g, msg, numArgsPushed); return errNone; } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/VMGlobals.cpp0000664000000000000000000000220112014636264024275 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "VMGlobals.h" VMGlobals::VMGlobals() : allocPool(0), process(0), gc(0), classvars(0), canCallOS(false), thread(0), method(0), block(0), frame(0), primitiveMethod(0), ip(0), sp(0), numpop(0), primitiveIndex(0), execMethod(0) { SetNil(&receiver); SetNil(&result); } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/SC_LanguageClient.cpp0000664000000000000000000002335412245365552025737 0ustar rootroot/* Abstract interpreter interface. Copyright (c) 2003 2004 stefan kersten. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_LanguageClient.h" #include "SC_LanguageConfig.hpp" #include #include #include #ifdef SC_WIN32 # include # include # define snprintf _snprintf # ifndef PATH_MAX # define PATH_MAX _MAX_PATH # endif #else # include #endif #include "PyrObject.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "GC.h" #include "VMGlobals.h" #include "SC_DirUtils.h" #include "SCBase.h" void closeAllGUIScreens(); void initGUI(); void initGUIPrimitives(); extern PyrString* newPyrStringN(class PyrGC *gc, long length, long flags, long collect); // ===================================================================== // SC_LanguageClient // ===================================================================== SC_LanguageClient* SC_LanguageClient::gInstance = 0; SC_Lock SC_LanguageClient::gInstanceMutex; PyrSymbol* SC_LanguageClient::s_interpretCmdLine = 0; PyrSymbol* SC_LanguageClient::s_interpretPrintCmdLine = 0; PyrSymbol* SC_LanguageClient::s_run = 0; PyrSymbol* SC_LanguageClient::s_stop = 0; static PyrSymbol* s_tick = 0; SC_LanguageClient::SC_LanguageClient(const char* name) : mName(0), mPostFile(0), mScratch(0), mRunning(false) { lockInstance(); if (gInstance) { unlockInstance(); fprintf(stderr, "SC_LanguageClient already running\n"); abort(); } mName = strdup(name); gInstance = this; unlockInstance(); } SC_LanguageClient::~SC_LanguageClient() { lockInstance(); free(mName); gInstance = 0; unlockInstance(); } void SC_LanguageClient::initRuntime(const Options& opt) { // start virtual machine if (!mRunning) { #ifdef __linux__ char deprecatedSupportDirectory[PATH_MAX]; sc_GetUserHomeDirectory(deprecatedSupportDirectory, PATH_MAX); sc_AppendToPath(deprecatedSupportDirectory, PATH_MAX, "share/SuperCollider"); if (sc_DirectoryExists(deprecatedSupportDirectory)) { char supportDirectory[PATH_MAX]; sc_GetUserAppSupportDirectory(supportDirectory, PATH_MAX); postfl("WARNING: Deprecated support directory detected: %s\n" "Extensions and other contents in this directory will not be available until you move them to the new support directory:\n" "%s\n" "Quarks will need to be reinstalled due to broken symbolic links.\n\n", deprecatedSupportDirectory, supportDirectory); } #endif mRunning = true; if (opt.mRuntimeDir) { int err = chdir(opt.mRuntimeDir); if (err) error("Cannot change to runtime directory: %s", strerror(errno)); } pyr_init_mem_pools(opt.mMemSpace, opt.mMemGrow); init_OSC(opt.mPort); schedInit(); onInitRuntime(); } } void SC_LanguageClient::shutdownRuntime() { cleanup_OSC(); } void SC_LanguageClient::compileLibrary() { ::compileLibrary(); } extern void shutdownLibrary(); void SC_LanguageClient::shutdownLibrary() { ::shutdownLibrary(); flush(); } void SC_LanguageClient::recompileLibrary() { compileLibrary(); } void SC_LanguageClient::setCmdLine(const char* buf, size_t size) { if (isLibraryCompiled()) { lock(); if (isLibraryCompiled()) { VMGlobals *g = gMainVMGlobals; PyrString* strobj = newPyrStringN(g->gc, size, 0, true); memcpy(strobj->s, buf, size); SetObject(&slotRawInterpreter(&g->process->interpreter)->cmdLine, strobj); g->gc->GCWrite(slotRawObject(&g->process->interpreter), strobj); } unlock(); } } void SC_LanguageClient::setCmdLine(const char* str) { setCmdLine(str, strlen(str)); } void SC_LanguageClient::setCmdLine(const SC_StringBuffer& strBuf) { setCmdLine(strBuf.getData(), strBuf.getSize()); } void SC_LanguageClient::setCmdLinef(const char* fmt, ...) { va_list ap; va_start(ap, fmt); mScratch.reset(); mScratch.vappendf(fmt, ap); va_end(ap); setCmdLine(mScratch); } void SC_LanguageClient::runLibrary(PyrSymbol* symbol) { lock(); ::runLibrary(symbol); unlock(); } void SC_LanguageClient::runLibrary(const char* methodName) { lock(); ::runLibrary(getsym(methodName)); unlock(); } void SC_LanguageClient::executeFile(const char* fileName) { std::string escaped_file_name(fileName); int i = 0; while (i < escaped_file_name.size()) { if (escaped_file_name[i] == '\\') escaped_file_name.insert(++i, 1, '\\'); ++i; } setCmdLinef("thisProcess.interpreter.executeFile(\"%s\")", escaped_file_name.c_str()); runLibrary(s_interpretCmdLine); } void SC_LanguageClient::snprintMemArg(char* dst, size_t size, int arg) { int rem = arg; int mod = 0; const char* modstr = ""; while (((rem % 1024) == 0) && (mod < 4)) { rem /= 1024; mod++; } switch (mod) { case 0: modstr = ""; break; case 1: modstr = "k"; break; case 2: modstr = "m"; break; case 3: modstr = "g"; break; default: rem = arg; modstr = ""; break; } snprintf(dst, size, "%d%s", rem, modstr); } bool SC_LanguageClient::parseMemArg(const char* arg, int* res) { long value, factor = 1; char* endPtr = 0; if (*arg == '\0') return false; value = strtol(arg, &endPtr, 0); char spec = *endPtr++; if (spec != '\0') { if (*endPtr != '\0') // trailing characters return false; switch (spec) { case 'k': factor = 1024; break; case 'm': factor = 1024 * 1024; break; default: // invalid mem spec return false; } } *res = value * factor; return true; } bool SC_LanguageClient::parsePortArg(const char* arg, int* res) { long value; char* endPtr; if (*arg == '\0') return false; value = strtol(arg, &endPtr, 0); if ((*endPtr != '\0') || (value < 0) || (value > 65535)) return false; *res = value; return true; } void SC_LanguageClient::tick() { if (trylock()) { if (isLibraryCompiled()) { ::runLibrary(s_tick); } unlock(); } flush(); } bool SC_LanguageClient::tickLocked( double * nextTime ) { if (isLibraryCompiled()) { ::runLibrary(s_tick); } return slotDoubleVal( &gMainVMGlobals->result, nextTime ) == errNone; } void SC_LanguageClient::onInitRuntime() { } void SC_LanguageClient::onLibraryStartup() { } void SC_LanguageClient::onLibraryShutdown() { } void SC_LanguageClient::onInterpStartup() { } // ===================================================================== // library functions // ===================================================================== // this is defined in PySCLang #ifndef PYSCLANG void setPostFile(FILE* file) { SC_LanguageClient::instance()->setPostFile(file); } int vpost(const char *fmt, va_list ap) { char buf[512]; int n = vsnprintf(buf, sizeof(buf), fmt, ap); if (n > 0) { SC_LanguageClient *client = SC_LanguageClient::lockedInstance(); if (client) client->postText(buf, sc_min(n, sizeof(buf) - 1)); SC_LanguageClient::unlockInstance(); } return 0; } void post(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vpost(fmt, ap); } void postfl(const char *fmt, ...) { char buf[512]; va_list ap; va_start(ap, fmt); int n = vsnprintf(buf, sizeof(buf), fmt, ap); if (n > 0) { SC_LanguageClient *client = SC_LanguageClient::lockedInstance(); if (client) client->postFlush(buf, sc_min(n, sizeof(buf) - 1)); SC_LanguageClient::unlockInstance(); } } void postText(const char *str, long len) { SC_LanguageClient *client = SC_LanguageClient::lockedInstance(); if (client) client->postFlush(str, len); SC_LanguageClient::unlockInstance(); } void postChar(char c) { SC_LanguageClient *client = SC_LanguageClient::lockedInstance(); if (client) client->postFlush(&c, sizeof(char)); SC_LanguageClient::unlockInstance(); } void error(const char *fmt, ...) { char buf[512]; va_list ap; va_start(ap, fmt); int n = vsnprintf(buf, sizeof(buf), fmt, ap); if (n > 0) { SC_LanguageClient *client = SC_LanguageClient::lockedInstance(); if (client) client->postError(buf, sc_min(n, sizeof(buf) - 1)); SC_LanguageClient::unlockInstance(); } } void flushPostBuf(void) { SC_LanguageClient::instance()->flush(); } void closeAllGUIScreens() { SC_LanguageClient::instance()->onLibraryShutdown(); } void initGUI() { SC_LanguageClient::instance()->onInterpStartup(); } void initGUIPrimitives() { SC_LanguageClient::s_interpretCmdLine = getsym("interpretCmdLine"); SC_LanguageClient::s_interpretPrintCmdLine = getsym("interpretPrintCmdLine"); SC_LanguageClient::s_run = getsym("run"); SC_LanguageClient::s_stop = getsym("stop"); s_tick = getsym("tick"); SC_LanguageClient::instance()->onLibraryStartup(); } void initSCViewPrimitives(); void initSCViewPrimitives() { } void initCocoaFilePrimitives(); void initCocoaFilePrimitives() { } void initCocoaBridgePrimitives(); void initCocoaBridgePrimitives() { } void initRendezvousPrimitives(); void initRendezvousPrimitives() { } #if !defined(HAVE_SPEECH) void initSpeechPrimitives(); void initSpeechPrimitives() { } #endif // HAVE_SPEECH long scMIDIout(int port, int len, int statushi, int chan, int data1, int data2); long scMIDIout(int port, int len, int statushi, int chan, int data1, int data2) { return 0; } #endif // EOF SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/AdvancingAllocPool.cpp0000664000000000000000000000616612014636264026164 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "AdvancingAllocPool.h" #include "SC_AllocPool.h" //#include AdvancingAllocPool::AdvancingAllocPool() { mAllocPool = 0; mInitSize = 0; mGrowSize = 0; mTooBig = 0; mCurSize = 0; mChunks = NULL; mFatties = NULL; } void AdvancingAllocPool::Init(AllocPool *inAllocPool, size_t initSize, size_t growSize, size_t tooBigSize) { mAllocPool = inAllocPool; mInitSize = initSize; mGrowSize = growSize; mTooBig = tooBigSize; mChunks = NULL; AddChunk(initSize); mFatties = NULL; //assert(SanityCheck()); } void AdvancingAllocPool::AddChunk(size_t inSize) { size_t chunkSize = sizeof(AdvancingAllocPoolChunkHdr) + inSize; AdvancingAllocPoolChunk* chunk = (AdvancingAllocPoolChunk*)mAllocPool->Alloc(chunkSize); FailNil(chunk); chunk->mNext = mChunks; mChunks = chunk; chunk->mSize = mGrowSize; mCurSize = 0; } void* AdvancingAllocPool::Alloc(size_t reqsize) { //assert(SanityCheck()); //assert(mAllocPool); size_t size = (reqsize + 15) & ~15; // round up to 16 byte alignment if (size < mTooBig) { if (!mChunks) AddChunk(mInitSize); else if (mCurSize + size > mChunks->mSize) AddChunk(mGrowSize); char* space = mChunks->mSpace + mCurSize; mCurSize += size; //assert(SanityCheck()); return (void*)space; } else { size_t chunkSize = sizeof(AdvancingAllocPoolChunkHdr) + size; AdvancingAllocPoolChunk* fatty = (AdvancingAllocPoolChunk*)mAllocPool->Alloc(chunkSize); FailNil(fatty); fatty->mNext = mFatties; mFatties = fatty; fatty->mSize = size; //assert(SanityCheck()); return (void*)fatty->mSpace; } } void AdvancingAllocPool::FreeAll() { //assert(SanityCheck()); AdvancingAllocPoolChunk *chunk, *next; for (chunk = mChunks; chunk; chunk = next) { next = chunk->mNext; mAllocPool->Free(chunk); } for (chunk = mFatties; chunk; chunk = next) { next = chunk->mNext; mAllocPool->Free(chunk); } mChunks = NULL; mFatties = NULL; mCurSize = 0; //assert(SanityCheck()); } bool AdvancingAllocPool::SanityCheck() { AdvancingAllocPoolChunk *chunk, *next; for (chunk = mChunks; chunk; chunk = next) { next = chunk->mNext; mAllocPool->DoCheckInUseChunk(AllocPool::MemToChunk(chunk)); } for (chunk = mFatties; chunk; chunk = next) { next = chunk->mNext; mAllocPool->DoCheckInUseChunk(AllocPool::MemToChunk(chunk)); } return true; } SuperCollider-3.6.6-Source-linux~repack/lang/LangSource/PyrParseNode.cpp0000664000000000000000000042261012014636264025034 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SCBase.h" #include "PyrParseNode.h" #include "PyrLexer.h" #include "PyrKernel.h" #include "PyrListPrim.h" #include "PyrSymbolTable.h" #include "Opcodes.h" #include "PyrKernelProto.h" #include "PyrObjectProto.h" #include "GC.h" #include #include #include #include #include #include "InitAlloc.h" #include "PredefinedSymbols.h" #include "SimpleStack.h" #include "PyrPrimitive.h" #include "SC_Win32Utils.h" AdvancingAllocPool gParseNodePool; PyrSymbol *gSpecialUnarySelectors[opNumUnarySelectors]; PyrSymbol *gSpecialBinarySelectors[opNumBinarySelectors]; PyrSymbol *gSpecialSelectors[opmNumSpecialSelectors]; PyrSymbol* gSpecialClasses[op_NumSpecialClasses]; PyrSlot gSpecialValues[svNumSpecialValues]; PyrParseNode* gRootParseNode; int gParserResult; int conjureConstantIndex(PyrParseNode *node, PyrBlock* func, PyrSlot *slot); void compilePushConstant(PyrParseNode* node, PyrSlot *slot); PyrClass *gCurrentClass = NULL; PyrClass *gCurrentMetaClass = NULL; PyrClass *gCompilingClass = NULL; PyrMethod *gCompilingMethod = NULL; PyrBlock *gCompilingBlock = NULL; PyrBlock *gPartiallyAppliedFunction = NULL; bool gIsTailCodeBranch = false; bool gTailIsMethodReturn = false; int gFunctionHighestExternalRef = 1; bool gFunctionCantBeClosed = true; #if TAILCALLOPTIMIZE bool gGenerateTailCallByteCodes = true; #else bool gGenerateTailCallByteCodes = false; #endif long gInliningLevel; int compileErrors = 0; int numOverwrites = 0; std::string overwriteMsg; extern bool compilingCmdLine; extern int errLineOffset, errCharPosOffset; bool gPostInlineWarnings = false; const char* nodename[] = { "ClassNode", "ClassExtNode", "MethodNode", "BlockNode", "SlotNode", /* variable declarations */ "VarListNode", "VarDefNode", "DynDictNode", "DynListNode", "LitListNode", "LitDictNode", "StaticVarListNode", "InstVarListNode", "PoolVarListNode", "ArgListNode", "SlotDefNode", /* selectors */ "LiteralNode", /* code */ "PushLitNode", "PushNameNode", "PushKeyArgNode", "CallNode", "BinopCallNode", "DropNode", "AssignNode", "MultiAssignNode", "MultiAssignVarListNode", "SetterNode", "CurryArgNode", "ReturnNode", "BlockReturnNode" }; void compileTail() { if (gGenerateTailCallByteCodes && gIsTailCodeBranch) { //if (gCompilingClass && gCompilingMethod) post("tail call %s:%s ismethod %d\n", // slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, gTailIsMethodReturn); if (gTailIsMethodReturn) compileByte(255); else compileByte(176); } } PyrGC* compileGC(); PyrGC* compileGC() { return gCompilingVMGlobals ? gCompilingVMGlobals->gc : 0; } void initParser() { compileErrors = 0; numOverwrites = 0; overwriteMsg.clear(); } void finiParser() { } void initParseNodes() { } void initParserPool() { //postfl("initPool gParseNodePool pyr_pool_compile\n"); gParseNodePool.Init(pyr_pool_compile, 32000, 32000, 2000); } void freeParserPool() { //postfl("freePool gParseNodePool pyr_pool_compile\n"); gParseNodePool.FreeAll(); } PyrParseNode::PyrParseNode(int inClassNo) { mClassno = inClassNo; mNext = 0; mTail = this; mCharno = ::charno; mLineno = ::lineno; mParens = 0; } void compileNodeList(PyrParseNode *node, bool onTailBranch) { PyrSlot dummy; //postfl("->compileNodeList\n"); for (; node; node = node->mNext) { //postfl("-->compileNodeList %p\n", node); COMPILENODE(node, &dummy, onTailBranch); //postfl("<--compileNodeList %p\n", node); } //postfl("<-compileNodeList\n"); } void nodePostErrorLine(PyrParseNode* node) { postErrorLine(node->mLineno, linestarts[node->mLineno], node->mCharno); } PyrPushNameNode* newPyrPushNameNode(PyrSlotNode *slotNode) { slotNode->mClassno = pn_PushNameNode; return (PyrPushNameNode*)slotNode; } void compilePushVar(PyrParseNode *node, PyrSymbol *varName) { int level, index, vindex, varType; PyrBlock *tempfunc; PyrClass *classobj; //postfl("compilePushVar\n"); classobj = gCompilingClass; if (varName->name[0] >= 'A' && varName->name[0] <= 'Z') { if (compilingCmdLine && varName->u.classobj == NULL) { error("Class not defined.\n"); nodePostErrorLine(node); compileErrors++; } else { if (findSpecialClassName(varName, &index)) { compileOpcode(opExtended, opPushSpecialValue); // special op for pushing a class compileByte(index); } else { PyrSlot slot; SetSymbol(&slot, varName); index = conjureLiteralSlotIndex(node, gCompilingBlock, &slot); compileOpcode(opExtended, opExtended); // special op for pushing a class compileByte(index); } } } else if (varName == s_this || varName == s_super) { gFunctionCantBeClosed = true; compileOpcode(opPushSpecialValue, opsvSelf); } else if (varName == s_true) { compileOpcode(opPushSpecialValue, opsvTrue); } else if (varName == s_false) { compileOpcode(opPushSpecialValue, opsvFalse); } else if (varName == s_nil) { compileOpcode(opPushSpecialValue, opsvNil); } else if (findVarName(gCompilingBlock, &classobj, varName, &varType, &level, &index, &tempfunc)) { switch (varType) { case varInst : compileOpcode(opPushInstVar, index); break; case varClass : { index += slotRawInt(&classobj->classVarIndex); if (index < 4096) { compileByte((opPushClassVar<<4) | ((index >> 8) & 15)); compileByte(index & 255); } else { compileByte(opPushClassVar); compileByte((index >> 8) & 255); compileByte(index & 255); } } break; case varConst : { PyrSlot *slot = slotRawObject(&classobj->constValues)->slots + index; compilePushConstant(node, slot); } break; case varTemp : vindex = index; if (level == 0) { compileOpcode(opPushTempZeroVar, vindex); } else if (level < 8) { compileOpcode(opPushTempVar, level); compileByte(vindex); } else { compileByte(opPushTempVar); compileByte(level); compileByte(vindex); } break; case varPseudo : compileOpcode(opExtended, opSpecialOpcode); compileByte(index); break; } } else { error("Variable '%s' not defined.\n", varName->name); nodePostErrorLine(node); compileErrors++; //Debugger(); } } PyrCurryArgNode* newPyrCurryArgNode() { PyrCurryArgNode* node = ALLOCNODE(PyrCurryArgNode); return node; } void PyrCurryArgNode::compile(PyrSlot *result) { if (gPartiallyAppliedFunction) { compileOpcode(opPushTempZeroVar, mArgNum); } else { error("found _ argument outside of a call.\n"); nodePostErrorLine((PyrParseNode*)this); compileErrors++; } } PyrSlotNode* newPyrSlotNode(PyrSlot *slot) { PyrSlotNode* node = ALLOCNODE(PyrSlotNode); node->mSlot = *slot; return node; } void PyrSlotNode::compile(PyrSlot *result) { if (mClassno == pn_LiteralNode) compileLiteral(result); else if (mClassno == pn_PushLitNode) compilePushLit(result); else if (mClassno == pn_PushNameNode) compilePushVar((PyrParseNode*)this, slotRawSymbol(&mSlot)); else { error("compilePyrSlotNode: shouldn't get here.\n"); dumpObjectSlot(&mSlot); nodePostErrorLine((PyrParseNode*)this); compileErrors++; //Debugger(); } } PyrClassExtNode* newPyrClassExtNode(PyrSlotNode* className, PyrMethodNode* methods) { PyrClassExtNode* node = ALLOCNODE(PyrClassExtNode); node->mClassName = className; node->mMethods = methods; return node; } void PyrClassExtNode::compile(PyrSlot *result) { PyrClass *classobj = slotRawSymbol(&mClassName->mSlot)->u.classobj; if (!classobj) { char extPath[1024]; asRelativePath(gCompilingFileSym->name, extPath); error("Class extension for nonexistent class '%s'\n In file:'%s'\n", slotRawSymbol(&mClassName->mSlot)->name, extPath ); return; } gCurrentClass = classobj; gCurrentMetaClass = classobj->classptr; compileExtNodeMethods(this); } void compileExtNodeMethods(PyrClassExtNode* node) { PyrMethodNode *method; method = node->mMethods; for (; method; method = (PyrMethodNode*)method->mNext) { PyrSlot dummy; //post("compile ext %s:%s\n", method->mExtension = true; compilePyrMethodNode(method, &dummy); } gCompilingMethod = NULL; gCompilingBlock = NULL; gPartiallyAppliedFunction = NULL; gInliningLevel = 0; } PyrClassNode* newPyrClassNode(PyrSlotNode* className, PyrSlotNode* superClassName, PyrVarListNode* varlists, PyrMethodNode* methods, PyrSlotNode* indexType) { PyrClassNode* node = ALLOCNODE(PyrClassNode); node->mClassName = className; node->mIndexType = indexType; node->mSuperClassName = superClassName; node->mVarlists = varlists; node->mMethods = methods; node->mVarTally[varInst] = 0; node->mVarTally[varClass] = 0; node->mVarTally[varTemp] = 0; node->mVarTally[varConst] = 0; //node->mVarTally[varPool] = 0; return node; } bool compareVarDefs(PyrClassNode* node, PyrClass* classobj) { int numinstvars, numclassvars; int i, xinst, xclass; PyrVarListNode* varlist; PyrVarDefNode *vardef; PyrParseNode *errnode; PyrSymbol **varNames; bool isIntrinsic; isIntrinsic = slotRawInt(&classobj->classFlags) & classIsIntrinsic; numinstvars = numInstVars(classobj); numclassvars = numClassVars(classobj); if (numinstvars == node->mVarTally[varInst] + node->mNumSuperInstVars && numclassvars == node->mVarTally[varClass]) { xclass = 0; xinst = node->mNumSuperInstVars; varlist = node->mVarlists; for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) { int type = varlist->mFlags; if (type == varInst) { vardef = varlist->mVarDefs; varNames = slotRawSymbolArray(&classobj->instVarNames)->symbols; for (i=0; vardef; vardef = (PyrVarDefNode*)vardef->mNext, xinst++, ++i) { if (slotRawSymbol(&vardef->mVarName->mSlot) != varNames[xinst]) { errnode = (PyrParseNode*)vardef; //post("A %s %d %d %d\n", vardef->mVarName->slotRawSymbol(&mSlot)->name, // vardef->mVarName->slotRawSymbol(&mSlot), varNames[xinst].us, xinst); //post("A %s %s %d\n", vardef->mVarName->slotRawSymbol(&mSlot)->name, // varNames[xinst].us->name, xinst); goto differExit; } } } else if (type == varClass) { vardef = varlist->mVarDefs; varNames = slotRawSymbolArray(&classobj->classVarNames)->symbols; for (i=0; vardef && xclass < numclassvars; vardef = (PyrVarDefNode*)vardef->mNext, xclass++, ++i) { if (slotRawSymbol(&vardef->mVarName->mSlot) != varNames[xclass]) { errnode = (PyrParseNode*)vardef; //post("B %d %d %d\n", vardef->mVarName->slotRawSymbol(&mSlot), varNames[xclass].us, xclass); goto differExit; } } } } } else { //post("C %d %d %d %d %d\n", numinstvars, node->mVarTally[varInst], node->mNumSuperInstVars, // numclassvars, node->mVarTally[varClass]); errnode = (node->mVarlists ? (PyrParseNode*)node->mVarlists : (PyrParseNode*)node->mClassName); goto differExit; } return false; differExit: if (isIntrinsic) { error("You may not change variable definitions of intrinsic classes.\n"); nodePostErrorLine(errnode); compileErrors++; } return true; } void countClassVarDefs(PyrClassNode* node, int *numClassMethods, int *numInstMethods) { PyrVarListNode* varlist; PyrVarDefNode *vardef; //*numClassMethods = 0; //*numInstMethods = 0; node->mVarTally[varInst] = 0; node->mVarTally[varClass] = 0; node->mVarTally[varTemp] = 0; node->mVarTally[varConst] = 0; // count number of variables of each type varlist = node->mVarlists; for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) { int type = varlist->mFlags; vardef = varlist->mVarDefs; for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { node->mVarTally[type]++; if (type == varClass) { if (vardef->mFlags & rwReadOnly) { *numClassMethods = *numClassMethods + 1; } if (vardef->mFlags & rwWriteOnly) { *numClassMethods = *numClassMethods + 1; } } else if (type == varInst) { if (vardef->mFlags & rwReadOnly) { *numInstMethods = *numInstMethods + 1; } if (vardef->mFlags & rwWriteOnly) { *numInstMethods = *numInstMethods + 1; } } } } } void countNodeMethods(PyrClassNode* node, int *numClassMethods, int *numInstMethods) { // count methods PyrMethodNode *method; //*numClassMethods = 0; //*numInstMethods = 0; method = node->mMethods; for (; method; method = (PyrMethodNode*)method->mNext) { if (method->mIsClassMethod) *numClassMethods = *numClassMethods + 1; else *numInstMethods = *numInstMethods + 1; } } void compileNodeMethods(PyrClassNode* node) { PyrMethodNode *method; method = node->mMethods; for (; method; method = (PyrMethodNode*)method->mNext) { PyrSlot dummy; method->mExtension = false; compilePyrMethodNode(method, &dummy); } gCompilingMethod = NULL; gCompilingBlock = NULL; gPartiallyAppliedFunction = NULL; gInliningLevel = 0; } PyrClass* getNodeSuperclass(PyrClassNode *node) { PyrClass *superclassobj = NULL; // postfl("getNodeSuperclass node %d\n", node); // postfl("getNodeSuperclass node->mSuperClassName %d\n", node->mSuperClassName); // postfl("getNodeSuperclass node->mSuperClassName->mSlot.utag %d\n", // node->mSuperClassName->mSlot.utag); if (node->mSuperClassName && IsSym(&node->mSuperClassName->mSlot)) { superclassobj = slotRawSymbol(&node->mSuperClassName->mSlot)->u.classobj; if (superclassobj == NULL) { error("Cannot find superclass '%s' for class '%s'\n", slotSymString(&node->mSuperClassName->mSlot), slotSymString(&node->mClassName->mSlot)); nodePostErrorLine((PyrParseNode*)node->mSuperClassName); superclassobj = (PyrClass*)-1; compileErrors++; } } else { if (slotRawSymbol(&node->mClassName->mSlot) != s_object) { superclassobj = class_object; } // else this is object and there is no superclass } return superclassobj; } void fillClassPrototypes(PyrClassNode *node, PyrClass *classobj, PyrClass *superclassobj) { PyrVarListNode* varlist; PyrVarDefNode *vardef; PyrSlot *islot, *cslot, *kslot; PyrSymbol **inameslot, **cnameslot, **knameslot; PyrClass *metaclassobj; PyrMethod *method; PyrMethodRaw *methraw; int instVarIndex, classVarIndex; // copy superclass's prototype to here if (superclassobj && NotNil(&superclassobj->iprototype) && slotRawObject(&superclassobj->iprototype)->size) { memcpy(slotRawObject(&classobj->iprototype)->slots, slotRawObject(&superclassobj->iprototype)->slots, sizeof(PyrSlot)* slotRawObject(&superclassobj->iprototype)->size); //slotRawObject(&classobj->iprototype)->size = slotRawObject(&superclassobj->iprototype)->size; slotRawObject(&classobj->iprototype)->size = node->mNumSuperInstVars; memcpy(slotRawSymbolArray(&classobj->instVarNames)->symbols, slotRawSymbolArray(&superclassobj->instVarNames)->symbols, sizeof(PyrSymbol*)* slotRawObject(&superclassobj->instVarNames)->size); //slotRawObject(&classobj->instVarNames)->size = slotRawObject(&superclassobj->iprototype)->size; slotRawObject(&classobj->instVarNames)->size = node->mNumSuperInstVars; } // fill the class' own part of prototypes metaclassobj = classobj->classptr; varlist = node->mVarlists; if (NotNil(&classobj->iprototype)) { islot = slotRawObject(&classobj->iprototype)->slots + node->mNumSuperInstVars; } if (NotNil(&classobj->cprototype)) { cslot = slotRawObject(&classobj->cprototype)->slots; } if (NotNil(&classobj->constValues)) { kslot = slotRawObject(&classobj->constValues)->slots; } if (NotNil(&classobj->instVarNames)) { inameslot = slotRawSymbolArray(&classobj->instVarNames)->symbols + node->mNumSuperInstVars; } if (NotNil(&classobj->classVarNames)) { cnameslot = slotRawSymbolArray(&classobj->classVarNames)->symbols; } if (NotNil(&classobj->constNames)) { knameslot = slotRawSymbolArray(&classobj->constNames)->symbols; } instVarIndex = node->mNumSuperInstVars; classVarIndex = 0; for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) { int type = varlist->mFlags; switch (type) { case varInst : vardef = varlist->mVarDefs; for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { PyrSlot litslot; compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litslot); *islot++ = litslot; slotRawObject(&classobj->iprototype)->size++; *inameslot++ = slotRawSymbol(&vardef->mVarName->mSlot); slotRawSymbolArray(&classobj->instVarNames)->size++; if (vardef->mFlags & rwReadOnly) { // create getter method method = newPyrMethod(); methraw = METHRAW(method); methraw->unused1 = 0; methraw->unused2 = 0; methraw->numargs = 1; methraw->numvars = 0; methraw->posargs = 1; methraw->varargs = 0; methraw->numtemps = 1; methraw->popSize = 0; SetNil(&method->contextDef); SetNil(&method->varNames); SetObject(&method->ownerclass, classobj); if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset); slotCopy(&method->name, &vardef->mVarName->mSlot); methraw->methType = methReturnInstVar; methraw->specialIndex = instVarIndex; addMethod(classobj, method); } if (vardef->mFlags & rwWriteOnly) { char setterName[256]; PyrSymbol *setterSym; sprintf(setterName, "%s_", slotRawSymbol(&vardef->mVarName->mSlot)->name); //underscore = strcpy(setterName, slotRawSymbol(&vardef->mVarName->mSlot)->name); //underscore[0] = '_'; //underscore[1] = 0; setterSym = getsym(setterName); // create setter method method = newPyrMethod(); methraw = METHRAW(method); methraw->unused1 = 0; methraw->unused2 = 0; methraw->numargs = 2; methraw->numvars = 0; methraw->posargs = 2; methraw->varargs = 0; methraw->numtemps = 2; methraw->popSize = 1; SetNil(&method->contextDef); SetNil(&method->varNames); SetObject(&method->ownerclass, classobj); SetSymbol(&method->name, setterSym); if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset); methraw->methType = methAssignInstVar; methraw->specialIndex = instVarIndex; addMethod(classobj, method); } instVarIndex++; } break; case varClass : vardef = varlist->mVarDefs; for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { PyrSlot litslot; compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litslot); *cslot++ = litslot; slotRawObject(&classobj->cprototype)->size++; *cnameslot++ = slotRawSymbol(&vardef->mVarName->mSlot); slotRawSymbolArray(&classobj->classVarNames)->size++; if (vardef->mFlags & rwReadOnly) { // create getter method method = newPyrMethod(); methraw = METHRAW(method); methraw->unused1 = 0; methraw->unused2 = 0; methraw->numargs = 1; methraw->numvars = 0; methraw->posargs = 1; methraw->varargs = 0; methraw->numtemps = 1; methraw->popSize = 0; SetNil(&method->contextDef); SetNil(&method->varNames); SetObject(&method->ownerclass, metaclassobj); slotCopy(&method->name, &vardef->mVarName->mSlot); SetSymbol(&method->selectors, slotRawSymbol(&classobj->name)); if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset); methraw->methType = methReturnClassVar; methraw->specialIndex = classVarIndex + slotRawInt(&classobj->classVarIndex); addMethod(metaclassobj, method); } if (vardef->mFlags & rwWriteOnly) { char setterName[256]; PyrSymbol *setterSym; sprintf(setterName, "%s_", slotRawSymbol(&vardef->mVarName->mSlot)->name); //underscore = strcpy(setterName, slotRawSymbol(&vardef->mVarName->mSlot)->name); //underscore[0] = '_'; //underscore[1] = 0; setterSym = getsym(setterName); // create setter method method = newPyrMethod(); methraw = METHRAW(method); methraw->numargs = 2; methraw->numvars = 0; methraw->posargs = 2; methraw->varargs = 0; methraw->numtemps = 2; methraw->popSize = 1; SetNil(&method->contextDef); SetNil(&method->varNames); SetObject(&method->ownerclass, metaclassobj); SetSymbol(&method->name, setterSym); SetSymbol(&method->selectors, slotRawSymbol(&classobj->name)); if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset); methraw->methType = methAssignClassVar; methraw->specialIndex = classVarIndex + slotRawInt(&classobj->classVarIndex); addMethod(metaclassobj, method); } classVarIndex++; } break; case varConst : vardef = varlist->mVarDefs; for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { PyrSlot litslot; compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litslot); *kslot++ = litslot; slotRawObject(&classobj->constValues)->size++; *knameslot++ = slotRawSymbol(&vardef->mVarName->mSlot); slotRawSymbolArray(&classobj->constNames)->size++; if (vardef->mFlags & rwReadOnly) { // create getter method method = newPyrMethod(); methraw = METHRAW(method); methraw->unused1 = 0; methraw->unused2 = 0; methraw->numargs = 1; methraw->numvars = 0; methraw->posargs = 1; methraw->varargs = 0; methraw->numtemps = 1; methraw->popSize = 0; SetNil(&method->contextDef); SetNil(&method->varNames); SetObject(&method->ownerclass, metaclassobj); slotCopy(&method->name, &vardef->mVarName->mSlot); if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset); methraw->methType = methReturnLiteral; slotCopy(&method->selectors, &litslot); addMethod(metaclassobj, method); } } break; } } } int getIndexType(PyrClassNode *classnode) { PyrSlotNode *node; int res; node = classnode->mIndexType; if (node == NULL) res = obj_notindexed; else { char *name; name = slotRawSymbol(&node->mSlot)->name; if (strcmp(name, "slot") == 0) res = obj_slot; else if (strcmp(name, "double") == 0) res = obj_double; else if (strcmp(name, "float") == 0) res = obj_float; else if (strcmp(name, "int32") == 0) res = obj_int32; else if (strcmp(name, "int16") == 0) res = obj_int16; else if (strcmp(name, "int8") == 0) res = obj_int8; else if (strcmp(name, "char") == 0) res = obj_char; else if (strcmp(name, "symbol") == 0) res = obj_symbol; else { error("Illegal indexed type. Must be one of:\n" " slot, double, float, int8, int16, int32, char\n"); res = obj_slot; compileErrors++; } } return res; } void PyrClassNode::compile(PyrSlot *result) { PyrClass *classobj, *superclassobj, *metaclassobj; int numClassMethods, numInstMethods; bool isIntrinsic; bool varsDiffer, superclassesDiffer, indexTypesDiffer; bool shouldRecompileSubclasses = false; int indexType; // find num instvars in superclass //postfl("class '%s'\n", slotRawSymbol(&mClassName->mSlot)->name); superclassobj = getNodeSuperclass(this); indexType = getIndexType(this); //postfl("%s %d\n", slotRawSymbol(&mClassName->mSlot)->name, indexType); if ((size_t)superclassobj == -1) { // redundant error message removed: //error("Can't find superclass of '%s'\n", slotRawSymbol(&mClassName->mSlot)->name); //nodePostErrorLine(node); return; // can't find superclass } mNumSuperInstVars = numSuperInstVars(superclassobj); numClassMethods = 0; numInstMethods = 0; countClassVarDefs(this, &numClassMethods, &numInstMethods); //postfl("accessor methods %d %d\n", numClassMethods, numInstMethods); countNodeMethods(this, &numClassMethods, &numInstMethods); //postfl("total methods %d %d\n", numClassMethods, numInstMethods); // get or make a class object // see if it already exists classobj = slotRawSymbol(&mClassName->mSlot)->u.classobj; if (classobj) { // deal with intrinsic classes or other classes being recompiled here. // recompile of subclasses not necessary if inst and class vars are // unchanged. metaclassobj = (PyrClass*)classobj->classptr; isIntrinsic = slotRawInt(&classobj->classFlags) & classIsIntrinsic; varsDiffer = compareVarDefs(this, classobj); if (varsDiffer) { if (isIntrinsic) { //error("Class '%s' declaration doesn't match intrinsic definition.\n", // slotRawSymbol(&mClassName->mSlot)->name); return; } else { shouldRecompileSubclasses = true; } } superclassesDiffer = superclassobj != slotRawSymbol(&classobj->superclass)->u.classobj; indexTypesDiffer = indexType != slotRawInt(&classobj->instanceFormat); //postfl("%d %d %d\n", indexType, slotRawInt(&classobj->instanceFormat)); //if (varsDiffer || superclassesDiffer || indexTypesDiffer) { if (varsDiffer || superclassesDiffer || indexTypesDiffer) { if (isIntrinsic) { if (superclassesDiffer) { error("Superclass of '%s' does not match intrinsic definition.\n", slotRawSymbol(&mClassName->mSlot)->name); nodePostErrorLine((PyrParseNode*)(mSuperClassName ? mSuperClassName : mClassName)); compileErrors++; } if (indexTypesDiffer) { error("Index type of '%s' does not match intrinsic definition.\n", slotRawSymbol(&mClassName->mSlot)->name); nodePostErrorLine((indexType ? (PyrParseNode*)mIndexType : (PyrParseNode*)mClassName)); compileErrors++; } error("Class '%s' declaration doesn't match intrinsic definition.\n", slotRawSymbol(&mClassName->mSlot)->name); return; } else { shouldRecompileSubclasses = true; } } // reallocate fields in the class object reallocClassObj(metaclassobj, classClassNumInstVars, 0, 0, numClassMethods, indexType, 0); //postfl("^3 %d %d\n", metaclassobj, class_class); //postfl("^4 %d %d\n", slotRawObject(&metaclassobj->iprototype), slotRawObject(&class_class->iprototype)); memcpy(slotRawObject(&metaclassobj->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots, sizeof(PyrSlot) * classClassNumInstVars); memcpy(slotRawSymbolArray(&metaclassobj->instVarNames)->symbols, slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars); slotRawObject(&metaclassobj->iprototype)->size = classClassNumInstVars; slotRawSymbolArray(&metaclassobj->instVarNames)->size = classClassNumInstVars; reallocClassObj(classobj, mVarTally[varInst] + mNumSuperInstVars, mVarTally[varClass], mVarTally[varConst], numInstMethods, indexType, 0); } else { PyrSymbol *superClassName, *metaClassName, *metaSuperClassName; superClassName = superclassobj ? slotRawSymbol(&superclassobj->name) : NULL; metaClassName = getmetasym(slotRawSymbol(&mClassName->mSlot)->name); metaClassName->flags |= sym_MetaClass; metaSuperClassName = superClassName ? getmetasym(superClassName->name) : NULL; metaclassobj = newClassObj(class_class, metaClassName, metaSuperClassName, classClassNumInstVars, 0, 0, numClassMethods, indexType, 0); // test //postfl("^1 %d %d\n", metaclassobj, class_class); //postfl("^2 %d %d\n", slotRawObject(&metaclassobj->iprototype), slotRawObject(&class_class->iprototype)); memcpy(slotRawObject(&metaclassobj->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots, sizeof(PyrSlot) * classClassNumInstVars); memcpy(slotRawSymbolArray(&metaclassobj->instVarNames)->symbols, slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars); slotRawObject(&metaclassobj->iprototype)->size = classClassNumInstVars; slotRawObject(&metaclassobj->instVarNames)->size = classClassNumInstVars; // end test classobj = newClassObj(metaclassobj, slotRawSymbol(&mClassName->mSlot), superClassName, mVarTally[varInst] + mNumSuperInstVars, mVarTally[varClass], mVarTally[varConst], numInstMethods, indexType, 0); } gCurrentClass = classobj; gCurrentMetaClass = metaclassobj; if (gCompilingFileSym) { SetSymbol(&classobj->filenameSym, gCompilingFileSym); SetInt(&classobj->charPos, linestarts[mClassName->mLineno] + errCharPosOffset); SetSymbol(&metaclassobj->filenameSym, gCompilingFileSym); SetInt(&metaclassobj->charPos, linestarts[mClassName->mLineno] + errCharPosOffset); } else { SetNil(&classobj->filenameSym); SetNil(&metaclassobj->filenameSym); } // fill inst and class prototypes fillClassPrototypes(this, classobj, superclassobj); // compile methods compileNodeMethods(this); // recompileSubclasses if (shouldRecompileSubclasses) { recompileSubclasses(classobj); } } void recompileSubclasses(PyrClass* classobj) { } #if 0 void catVarLists(PyrVarListNode *varlist); void catVarLists(PyrVarListNode *varlist) { PyrVarListNode *prevvarlist; PyrVarDefNode *vardef, *lastvardef; if (varlist) { // find end of this list vardef = varlist->mVarDefs; for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { lastvardef = vardef; } prevvarlist = varlist; varlist = (PyrVarListNode*)varlist->mNext; for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) { vardef = varlist->mVarDefs; if (lastvardef) { lastvardef->mNext = (PyrParseNode*)vardef; } else { prevvarlist->mVarDefs = vardef; } // find end of this list for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { lastvardef = vardef; } } } } #else void catVarLists(PyrVarListNode *varlist); void catVarLists(PyrVarListNode *varlist) { PyrVarListNode *prevvarlist; PyrVarDefNode *vardef, *lastvardef; if (varlist) { // find end of this list vardef = varlist->mVarDefs; lastvardef = (PyrVarDefNode*)vardef->mTail; prevvarlist = varlist; varlist = (PyrVarListNode*)varlist->mNext; for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) { vardef = varlist->mVarDefs; lastvardef->mNext = (PyrParseNode*)vardef; // find end of this list lastvardef = (PyrVarDefNode*)vardef->mTail; } } } #endif PyrMethodNode* newPyrMethodNode(PyrSlotNode* methodName, PyrSlotNode* primitiveName, PyrArgListNode* arglist, PyrVarListNode *varlist, PyrParseNode* body, int isClassMethod) { PyrMethodNode* node = ALLOCNODE(PyrMethodNode); node->mMethodName = methodName; node->mPrimitiveName = primitiveName; node->mArglist = arglist; catVarLists(varlist); node->mVarlist = varlist; node->mBody = body; node->mIsClassMethod = isClassMethod; return node; } enum { push_Normal, push_AllArgs, push_AllButFirstArg, push_AllButFirstArg2 }; int checkPushAllArgs(PyrParseNode *actualArg, int numArgs); int checkPushAllArgs(PyrParseNode *actualArg, int numArgs) { PyrBlock *block; PyrPushNameNode *nameNode; block = gCompilingBlock; int i; //if (strcmp("ar", slotRawSymbol(&gCompilingMethod->name)->name)==0) Debugger(); if (actualArg->mClassno != pn_PushNameNode) { if (numArgs < 3) { return push_Normal; } actualArg = actualArg->mNext; for (i=1; imClassno != pn_PushNameNode) { return push_Normal; } nameNode = (PyrPushNameNode*)actualArg; if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbolArray(&block->argNames)->symbols[i]) { return push_Normal; } actualArg = actualArg->mNext; } return push_AllButFirstArg; } else { for (i=0; imClassno != pn_PushNameNode) { return push_Normal; } nameNode = (PyrPushNameNode*)actualArg; if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbolArray(&block->argNames)->symbols[i]) { return push_Normal; } actualArg = actualArg->mNext; } return push_AllArgs; } } int checkPushAllButFirstTwoArgs(PyrParseNode *actualArg, int numArgs); int checkPushAllButFirstTwoArgs(PyrParseNode *actualArg, int numArgs) { PyrBlock *block; PyrPushNameNode *nameNode; block = gCompilingBlock; int i; if (numArgs >= 2) { actualArg = actualArg->mNext; actualArg = actualArg->mNext; for (i=1; imClassno != pn_PushNameNode) { return push_Normal; } nameNode = (PyrPushNameNode*)actualArg; /*if (slotRawSymbol(&gCompilingClass->name) == s_ugen) { post("check meth %s %d '%s' '%s'\n", slotRawSymbol(&gCompilingMethod->name)->name, i, slotRawSymbol(&nameNode->mSlot)->name, block->argNames.uosym->symbols[i]->name); }*/ if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbolArray(&block->argNames)->symbols[i]) { return push_Normal; } actualArg = actualArg->mNext; } return push_AllButFirstArg2; } return push_Normal; } int compareCallArgs(PyrMethodNode* node, PyrCallNode *cnode, int *varIndex, PyrClass **specialClass) { int i, numFormalArgs, numActualArgs; int special, varType, varLevel; PyrParseNode *actualArg; PyrVarDefNode *formalArg; PyrPushNameNode *nameNode; // fail if has a rest arg .. too much trouble? if (node->mArglist && node->mArglist->mRest) { return methNormal; } // check first actual arg is 'this' actualArg = cnode->mArglist; if (actualArg->mClassno != pn_PushNameNode) { return methNormal; } nameNode = (PyrPushNameNode*)actualArg; if (slotRawSymbol(&nameNode->mSlot) == s_this) { special = methRedirect; } else if (slotRawSymbol(&nameNode->mSlot) == s_super) { special = methRedirectSuper; } else { bool varFound; PyrClass *classobj; classobj = gCompilingClass; varFound = findVarName(gCompilingBlock, &classobj, slotRawSymbol(&nameNode->mSlot), &varType, &varLevel, varIndex, NULL); if (!varFound ) return methNormal; if (varType == varInst) special = methForwardInstVar; else if (varType == varClass) { special = methForwardClassVar; *varIndex += slotRawInt(&classobj->classVarIndex); *specialClass = classobj; } else return methNormal; } actualArg = actualArg->mNext; numActualArgs = nodeListLength((PyrParseNode*)cnode->mArglist); if (!node->mArglist) { numFormalArgs = 1; if (numActualArgs != numFormalArgs) { return methNormal; } } else { numFormalArgs = 1 + nodeListLength((PyrParseNode*)node->mArglist->mVarDefs); if (numActualArgs != numFormalArgs) { return methNormal; } formalArg = node->mArglist->mVarDefs; for (i=0; imClassno != pn_PushNameNode) { return methNormal; } nameNode = (PyrPushNameNode*)actualArg; if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbol(&formalArg->mVarName->mSlot)) { return methNormal; } formalArg = (PyrVarDefNode*)formalArg->mNext; actualArg = actualArg->mNext; } } /* if (special == methForwardInstVar) { postfl("methForwardInstVar %s:%s formal %d actual %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, numFormalArgs, numActualArgs); } if (special == methForwardClassVar) { postfl("methForwardClassVar %s:%s formal %d actual %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, numFormalArgs, numActualArgs); } if (special == methRedirectSuper) { postfl("methRedirectSuper %s:%s formal %d actual %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, numFormalArgs, numActualArgs); } */ // if (special == methTempDelegate) { // postfl("methTempDelegate %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); // } return special; } void installByteCodes(PyrBlock *block) { PyrInt8Array *byteArray; long length, flags; ByteCodes byteCodes; byteCodes = getByteCodes(); if (byteCodes) { length = byteCodeLength(byteCodes); if (length) { flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; byteArray = newPyrInt8Array(compileGC(), length, flags, false); copyByteCodes(byteArray->b, byteCodes); byteArray->size = length; freeByteCodes(byteCodes); SetObject(&block->code, byteArray); } else { error("installByteCodes: zero length byte codes\n"); } } else { error("installByteCodes: NULL byte codes\n"); } } PyrMethod* initPyrMethod(PyrMethod* method); void compilePyrMethodNode(PyrMethodNode *node, PyrSlot *result) { node->compile(result); } void PyrMethodNode::compile(PyrSlot *result) { PyrMethod *method, *oldmethod; PyrMethodRaw *methraw; int i, j, numArgs, numVars, methType, funcVarArgs, firstKeyIndex; int index, numSlots, numArgNames; bool hasPrimitive = false; bool hasVarExprs = false; PyrVarDefNode *vardef; PyrObject *proto; PyrSymbolArray *argNames, *varNames; SetTailBranch branch(false); //postfl("->method '%s'\n", slotRawSymbol(&mMethodName->mSlot)->name); gCompilingClass = mIsClassMethod ? gCurrentMetaClass : gCurrentClass; oldmethod = classFindDirectMethod(gCompilingClass, slotRawSymbol(&mMethodName->mSlot)); if (oldmethod && !mExtension) { error("Method %s:%s already defined.\n", slotRawSymbol(&slotRawClass(&oldmethod->ownerclass)->name)->name, slotRawSymbol(&oldmethod->name)->name); nodePostErrorLine((PyrParseNode*)mMethodName); compileErrors++; return; } if (oldmethod) { ++numOverwrites; // accumulate overwrite message onto the string buffer overwriteMsg .append(slotRawSymbol(&slotRawClass(&oldmethod->ownerclass)->name)->name) .append(":") .append(slotRawSymbol(&oldmethod->name)->name) .append("\t") .append(gCompilingFileSym->name) .append("\t") .append(slotRawSymbol(&oldmethod->filenameSym)->name) .append("\n"); method = oldmethod; freePyrSlot(&method->code); freePyrSlot(&method->selectors); freePyrSlot(&method->prototypeFrame); freePyrSlot(&method->argNames); freePyrSlot(&method->varNames); initPyrMethod(method); } else { method = newPyrMethod(); } SetObject(&method->ownerclass, gCompilingClass); methraw = METHRAW(method); methraw->unused1 = 0; methraw->unused2 = 0; //postfl("method %p raw %p\n", method, methraw); method->contextDef = o_nil; method->name = mMethodName->mSlot; if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[mMethodName->mLineno] + errCharPosOffset); if (mPrimitiveName) { hasPrimitive = true; method->primitiveName = mPrimitiveName->mSlot; methraw->specialIndex = slotRawSymbol(&mPrimitiveName->mSlot)->u.index; } gCompilingBlock = (PyrBlock*)method; gCompilingMethod = (PyrMethod*)method; gPartiallyAppliedFunction = NULL; gInliningLevel = 0; methraw->needsHeapContext = 0; methraw->varargs = funcVarArgs = (mArglist && mArglist->mRest) ? 1 : 0; numArgs = mArglist ? nodeListLength((PyrParseNode*)mArglist->mVarDefs) + 1 : 1; numVars = mVarlist ? nodeListLength((PyrParseNode*)mVarlist->mVarDefs) : 0; numSlots = numArgs + funcVarArgs + numVars; methraw->frameSize = (numSlots + FRAMESIZE) * sizeof(PyrSlot); methraw->numargs = numArgs; methraw->numvars = numVars; methraw->posargs = numArgs + funcVarArgs; methraw->numtemps = numSlots; methraw->popSize = numSlots - 1; firstKeyIndex = numArgs + funcVarArgs; numArgNames = methraw->posargs; if (numSlots == 1) { slotCopy(&method->argNames, &o_argnamethis); slotCopy(&method->prototypeFrame, &o_onenilarray); } else { argNames = newPyrSymbolArray(NULL, numArgNames, obj_permanent | obj_immutable, false); argNames->size = numArgNames; SetObject(&method->argNames, argNames); proto = newPyrArray(NULL, numSlots, obj_permanent | obj_immutable, false); proto->size = numSlots; SetObject(&method->prototypeFrame, proto); // declare args slotRawSymbolArray(&method->argNames)->symbols[0] = s_this; if (mArglist) { PyrSymbol **methargs; methargs = slotRawSymbolArray(&method->argNames)->symbols; vardef = mArglist->mVarDefs; for (i=1; imNext) { PyrSlot *varslot; varslot = &vardef->mVarName->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in arglist methargs[i] = slotRawSymbol(varslot); //postfl("defarg %d '%s'\n", i, slotRawSymbol(slot)->name); /*if (slotRawSymbol(varslot)->name[0] == 'a' && slotRawSymbol(varslot)->name[1] == 'r' && slotRawSymbol(varslot)->name[2] == 'g') { post("%d %s:%s '%s'\n", i, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, slotRawSymbol(varslot)->name); }*/ } if (funcVarArgs) { PyrSlot *varslot; varslot = &mArglist->mRest->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in arglist methargs[i] = slotRawSymbol(varslot); //postfl("defrest '%s'\n", slotRawSymbol(slot)->name); } } // fill prototype args if (NotNil(&method->prototypeFrame)) { SetNil(&slotRawObject(&method->prototypeFrame)->slots[0]); } if (mArglist) { vardef = mArglist->mVarDefs; for (i=1; imNext) { PyrSlot *slot, litval; slot = slotRawObject(&method->prototypeFrame)->slots + i; //compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litval); if (vardef->hasExpr(&litval)) hasVarExprs = true; *slot = litval; } if (funcVarArgs) { slotCopy(&slotRawObject(&method->prototypeFrame)->slots[numArgs], &o_emptyarray); } } } if (numVars) { varNames = newPyrSymbolArray(NULL, numVars, obj_permanent | obj_immutable, false); varNames->size = numVars; SetObject(&method->varNames, varNames); } else { SetNil(&method->varNames); } // declare vars if (mVarlist) { PyrSymbol **methargs, **methvars; methargs = slotRawSymbolArray(&method->argNames)->symbols; methvars = slotRawSymbolArray(&method->varNames)->symbols; vardef = mVarlist->mVarDefs; for (i=0; imNext) { PyrSlot *varslot; varslot = &vardef->mVarName->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // already declared as var? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in mVarlist methvars[i] = slotRawSymbol(varslot); //postfl("defvar %d '%s'\n", i, slotRawSymbol(slot)->name); } } if (mVarlist) { vardef = mVarlist->mVarDefs; for (i=0; imNext) { PyrSlot *slot, litval; slot = slotRawObject(&method->prototypeFrame)->slots + i + numArgs + funcVarArgs; if (vardef->hasExpr(&litval)) hasVarExprs = true; //compilePyrLiteralNode(vardef->mDefVal, &litval); *slot = litval; } } methType = methNormal; if (hasVarExprs) { methType = methNormal; } else if (hasPrimitive) { methType = methPrimitive; /* if (getPrimitiveNumArgs(methraw->specialIndex) != numArgs) { post("warning: number of arguments for method %s:%s does not match primitive %s. %d vs %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, getPrimitiveName(methraw->specialIndex)->name, numArgs, getPrimitiveNumArgs(methraw->specialIndex)); } */ } else if (slotRawSymbol(&gCompilingMethod->name) == s_nocomprendo) { methType = methNormal; } else { int bodyType = mBody->mClassno; if (bodyType == pn_ReturnNode) { PyrReturnNode *rnode; PyrParseNode *xnode; int rtype; PyrSlot rslot; rnode = (PyrReturnNode*)mBody; xnode = (PyrParseNode*)rnode->mExpr; if (xnode) { rtype = xnode->mClassno; if (rtype == pn_PushLitNode) { // return literal ? compilePyrLiteralNode((PyrLiteralNode*)xnode, &rslot); if (IsObj(&rslot) && slotRawObject(&rslot)->classptr == class_fundef) { methType = methNormal; } else { methType = methReturnLiteral; method->selectors = rslot; } } else if (rtype == pn_PushNameNode) { PyrSlot *rslot; rslot = &((PyrPushNameNode*)xnode)->mSlot; if (slotRawSymbol(rslot) == s_this) { // return this methType = methReturnSelf; } else { if (funcFindArg((PyrBlock*)method, slotRawSymbol(rslot), &index)) { // return arg ? // eliminate the case where its an ellipsis or keyword argument if (index < methraw->numargs) { methType = methReturnArg; methraw->specialIndex = index; // when you change sp to sp - 1 //methraw->specialIndex = index - 1; } } else if (classFindInstVar(gCompilingClass, slotRawSymbol(rslot), &index)) { // return inst var methType = methReturnInstVar; methraw->specialIndex = index; } } } else if (rtype == pn_CallNode) { // need to do this for binary opcodes too.. int specialIndex; PyrCallNode *cnode; PyrClass *specialClass = 0; cnode = (PyrCallNode*)xnode; methType = compareCallArgs(this, cnode, &specialIndex, &specialClass); if (methType != methNormal) { methraw->specialIndex = specialIndex; method->selectors = cnode->mSelector->mSlot; if (specialClass) method->constants = specialClass->name; } } } else { methType = methReturnSelf; } } else if (bodyType == pn_AssignNode && numArgs == 2) { // assign inst var ? PyrAssignNode *anode; //post("methAssignInstVar 1 %s:%s\n", // slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); anode = (PyrAssignNode*)mBody; if (anode->mNext && anode->mNext->mClassno == pn_ReturnNode && ((PyrReturnNode*)anode->mNext)->mExpr == NULL) { //post("methAssignInstVar 2 %s:%s\n", // slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); if (classFindInstVar(gCompilingClass, slotRawSymbol(&anode->mVarName->mSlot), &index)) { methType = methAssignInstVar; methraw->specialIndex = index; //post("methAssignInstVar 3 %s:%s\n", // slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); } } } } methraw->methType = methType; // set primitive // optimize common cases if (methType == methNormal || methType == methPrimitive) { PyrSlot dummy; PyrSymbol *name; // compile body initByteCodes(); if (gCompilingClass == class_int) { // handle some special cases name = slotRawSymbol(&method->name); if (name == gSpecialSelectors[opmDo]) { compileByte(143); compileByte(0); compileByte(143); compileByte(1); } else if (name == gSpecialSelectors[opmReverseDo]) { compileByte(143); compileByte(2); compileByte(143); compileByte(3); compileByte(143); compileByte(4); } else if (name == gSpecialSelectors[opmFor]) { compileByte(143); compileByte(5); compileByte(143); compileByte(6); compileByte(143); compileByte(16); } else if (name == gSpecialSelectors[opmForBy]) { compileByte(143); compileByte(7); compileByte(143); compileByte(8); compileByte(143); compileByte(9); } else goto compile_body; } else if (gCompilingClass == class_arrayed_collection) { name = slotRawSymbol(&method->name); if (name == gSpecialSelectors[opmDo]) { compileByte(143); compileByte(10); compileByte(143); compileByte(1); } else if (name == gSpecialSelectors[opmReverseDo]) { compileByte(143); compileByte(11); compileByte(143); compileByte(12); compileByte(143); compileByte(4); } else goto compile_body; } else if (slotRawSymbol(&gCompilingClass->name) == s_dictionary) { name = slotRawSymbol(&method->name); if (name == getsym("keysValuesArrayDo")) { compileByte(143); compileByte(13); compileByte(143); compileByte(14); } else goto compile_body; } else if (gCompilingClass == class_number) { name = slotRawSymbol(&method->name); if (name == gSpecialSelectors[opmForSeries]) { compileByte(143); compileByte(29); compileByte(143); compileByte(30); compileByte(143); compileByte(31); } else goto compile_body; } else if (gCompilingClass == class_float) { // handle some special cases name = slotRawSymbol(&method->name); if (name == gSpecialSelectors[opmDo]) { compileByte(143); compileByte(17); compileByte(143); compileByte(18); } else if (name == gSpecialSelectors[opmReverseDo]) { compileByte(143); compileByte(19); compileByte(143); compileByte(20); compileByte(143); compileByte(21); } else goto compile_body; } else { compile_body: SetTailIsMethodReturn mr(false); if (mArglist) { vardef = mArglist->mVarDefs; for (i=1; imNext) { vardef->compileArg(&dummy); } } if (mVarlist) { vardef = mVarlist->mVarDefs; for (i=0; imNext) { vardef->compile(&dummy); } } COMPILENODE(mBody, &dummy, true); } installByteCodes((PyrBlock*)method); } if (!oldmethod) { addMethod(gCompilingClass, method); } gCompilingMethod = NULL; gCompilingBlock = NULL; gPartiallyAppliedFunction = NULL; //postfl("<-method '%s'\n", slotRawSymbol(&mMethodName->mSlot)->name); } PyrArgListNode* newPyrArgListNode(PyrVarDefNode* varDefs, PyrSlotNode* rest) { PyrArgListNode* node = ALLOCNODE(PyrArgListNode); node->mVarDefs = varDefs; node->mRest = rest; return node; } void PyrArgListNode::compile(PyrSlot *result) { error("compilePyrArgListNode: shouldn't get here.\n"); compileErrors++; } PyrVarListNode* newPyrVarListNode(PyrVarDefNode* vardefs, int flags) { PyrVarListNode* node = ALLOCNODE(PyrVarListNode); node->mVarDefs = vardefs; node->mFlags = flags; return node; } void PyrVarListNode::compile(PyrSlot *result) { error("compilePyrVarListNode: shouldn't get here.\n"); compileErrors++; } PyrVarDefNode* newPyrVarDefNode(PyrSlotNode* varName, PyrParseNode* defVal, int flags) { PyrVarDefNode* node = ALLOCNODE(PyrVarDefNode); node->mVarName = varName; node->mDefVal = defVal; node->mFlags = flags; node->mDrop = true; return node; } bool PyrVarDefNode::hasExpr(PyrSlot *result) { if (result) SetNil(result); if (!mDefVal) return false; if (mDefVal->mClassno != pn_PushLitNode && mDefVal->mClassno != pn_LiteralNode) { //post("hasExpr A %s:%s %s %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, mVarName->slotRawSymbol(&mSlot)->name, mDefVal->mClassno); return true; } PyrPushLitNode *node = (PyrPushLitNode*)mDefVal; if (IsPtr(&node->mSlot)) { PyrParseNode* litnode = (PyrParseNode*)slotRawPtr(&node->mSlot); if (litnode) { if (litnode->mClassno == pn_BlockNode) { //post("hasExpr B %s:%s %s %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, mVarName->slotRawSymbol(&mSlot)->name, node->mClassno); return true; } else { if (result) node->compileLiteral(result); } } } else if (result) *result = node->mSlot; if (node->mParens) return true; return false; } void PyrVarDefNode::compile(PyrSlot *result) { if (hasExpr(NULL)) { COMPILENODE(mDefVal, result, false); compileAssignVar((PyrParseNode*)this, slotRawSymbol(&mVarName->mSlot), mDrop); } //error("compilePyrVarDefNode: shouldn't get here.\n"); //compileErrors++; } void PyrVarDefNode::compileArg(PyrSlot *result) { if (hasExpr(NULL)) { ByteCodes trueByteCodes; compilePushVar((PyrParseNode*)this, slotRawSymbol(&mVarName->mSlot)); mDrop = false; trueByteCodes = compileBodyWithGoto(this, 0, true); int jumplen = byteCodeLength(trueByteCodes); compileByte(143); // special opcodes compileByte(26); compileByte((jumplen >> 8) & 0xFF); compileByte(jumplen & 0xFF); compileAndFreeByteCodes(trueByteCodes); compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean } //error("compilePyrVarDefNode: shouldn't get here.\n"); //compileErrors++; } PyrCallNode* newPyrCallNode(PyrSlotNode* selector, PyrParseNode* arglist, PyrParseNode* keyarglist, PyrParseNode* blocklist) { PyrCallNode* node = ALLOCNODE(PyrCallNode); node->mSelector = selector; arglist = linkNextNode(arglist, blocklist); node->mArglist = arglist; node->mKeyarglist = keyarglist; return node; } int PyrCallNode::isPartialApplication() { int sum = 0; PyrParseNode* argnode = mArglist; for (; argnode; argnode = argnode->mNext) { if (argnode->mClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)argnode)->mArgNum = sum; sum ++; } } PyrParseNode* keynode = mKeyarglist; for (; keynode; keynode = keynode->mNext) { if (keynode->mClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)keynode)->mArgNum = sum; sum ++; } } return sum; } void PyrCallNodeBase::compilePartialApplication(int numCurryArgs, PyrSlot *result) { // create a function // compile the call ByteCodes savedBytes = saveByteCodeArray(); int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; PyrBlock* block = newPyrBlock(flags); PyrSlot blockSlot; SetObject(&blockSlot, block); int prevFunctionHighestExternalRef = gFunctionHighestExternalRef; bool prevFunctionCantBeClosed = gFunctionCantBeClosed; gFunctionHighestExternalRef = 0; gFunctionCantBeClosed = false; PyrClass* prevClass = gCompilingClass; PyrBlock* prevBlock = gCompilingBlock; gCompilingBlock = block; PyrBlock* prevPartiallyAppliedFunction = gPartiallyAppliedFunction; gPartiallyAppliedFunction = block; PyrMethodRaw* methraw = METHRAW(block); methraw->unused1 = 0; methraw->unused2 = 0; methraw->needsHeapContext = 0; SetObject(&block->contextDef, prevBlock); //// methraw->varargs = 0; methraw->frameSize = (numCurryArgs + FRAMESIZE) * sizeof(PyrSlot); PyrObject* proto = newPyrArray(compileGC(), numCurryArgs, flags, false); proto->size = numCurryArgs; SetObject(&block->prototypeFrame, proto); PyrSymbolArray* argNames = newPyrSymbolArray(compileGC(), numCurryArgs, flags, false); argNames->size = numCurryArgs; SetObject(&block->argNames, argNames); SetNil(&block->varNames); methraw->numargs = numCurryArgs; methraw->numvars = 0; methraw->posargs = numCurryArgs; methraw->numtemps = numCurryArgs; methraw->popSize = numCurryArgs; methraw->methType = methBlock; { PyrSymbol* s_empty = getsym("_"); PyrSymbol **blockargs = slotRawSymbolArray(&block->argNames)->symbols; for (int i=0; islots + i); } } initByteCodes(); { SetTailBranch branch(true); SetTailIsMethodReturn mr(false); PyrSlot body; compileCall(&body); } compileOpcode(opSpecialOpcode, opcFunctionReturn); installByteCodes(block); gCompilingBlock = prevBlock; gPartiallyAppliedFunction = prevPartiallyAppliedFunction; restoreByteCodeArray(savedBytes); int index = conjureLiteralSlotIndex(this, gCompilingBlock, &blockSlot); compileOpcode(opExtended, opPushLiteral); compileByte(index); if (!gFunctionCantBeClosed && gFunctionHighestExternalRef == 0) { SetNil(&block->contextDef); } else { METHRAW(prevBlock)->needsHeapContext = 1; } gCompilingBlock = prevBlock; gCompilingClass = prevClass; gPartiallyAppliedFunction = prevPartiallyAppliedFunction; gFunctionCantBeClosed = gFunctionCantBeClosed || prevFunctionCantBeClosed; gFunctionHighestExternalRef = sc_max(gFunctionHighestExternalRef - 1, prevFunctionHighestExternalRef); } void PyrCallNodeBase::compile(PyrSlot *result) { int numCurryArgs = isPartialApplication(); if (numCurryArgs) { compilePartialApplication(numCurryArgs, result); } else { compileCall(result); } } bool isSeries(PyrParseNode* node, PyrParseNode** args) { if (node->mClassno != pn_CallNode) return false; PyrCallNode *callnode = (PyrCallNode*)node; if (slotRawSymbol(&callnode->mSelector->mSlot) != s_series) return false; if (callnode->mKeyarglist) return false; *args = callnode->mArglist; return true; } void PyrCallNode::compileCall(PyrSlot *result) { int index, selType; PyrSlot dummy; bool varFound; PyrParseNode *argnode2; //postfl("compilePyrCallNode\n"); PyrParseNode* argnode = mArglist; PyrParseNode* keynode = mKeyarglist; int numArgs = nodeListLength(argnode); int numKeyArgs = nodeListLength(keynode); int isSuper = isSuperObjNode(argnode); int numBlockArgs = METHRAW(gCompilingBlock)->numargs; slotRawSymbol(&mSelector->mSlot)->flags |= sym_Called; index = conjureSelectorIndex((PyrParseNode*)mSelector, gCompilingBlock, isSuper, slotRawSymbol(&mSelector->mSlot), &selType); if (numKeyArgs > 0 || (numArgs > 15 && !(selType == selSwitch || selType == selCase))) { for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } for (; keynode; keynode = keynode->mNext) { COMPILENODE(keynode, &dummy, false); } if (isSuper) { compileTail(); compileByte(opSendSuper); compileByte(numArgs + 2*numKeyArgs); compileByte(numKeyArgs); compileByte(index); } else { switch (selType) { case selNormal : compileTail(); compileByte(opSendMsg); compileByte(numArgs + 2*numKeyArgs); compileByte(numKeyArgs); compileByte(index); break; case selSpecial : compileTail(); compileByte(opSendSpecialMsg); compileByte(numArgs + 2*numKeyArgs); compileByte(numKeyArgs); compileByte(index); break; case selUnary : case selBinary : index = conjureLiteralSlotIndex((PyrParseNode*)mSelector, gCompilingBlock, &mSelector->mSlot); // fall through default: compileTail(); compileByte(opSendMsg); compileByte(numArgs + 2*numKeyArgs); compileByte(numKeyArgs); compileByte(index); break; } } } else if (isSuper) { if (numArgs == 1) { // pushes this as well, don't compile arg gFunctionCantBeClosed = true; compileTail(); compileOpcode(opSendSuper, numArgs); compileByte(index); } else { for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSuper, numArgs); compileByte(index); } } else { PyrSymbol *varname; if (argnode->mClassno == pn_PushNameNode) { varname = slotRawSymbol(&((PyrPushNameNode*)argnode)->mSlot); } else { varname = NULL; } if (varname == s_this) { gFunctionCantBeClosed = true; } switch (selType) { case selNormal : if (numArgs == 1 && varname == s_this) { compileTail(); compileOpcode(opSendMsg, 0); compileByte(index); //} else if (numArgs>1 && numArgs == numBlockArgs) { } else if (numArgs>1 && numArgs == numBlockArgs) { // try for multiple push optimization int code; code = checkPushAllArgs(argnode, numArgs); if (code == push_Normal) goto normal; else if (code == push_AllArgs) { compileTail(); compileByte(137); // push all args, send msg compileByte(index); //post("137 pushAllArgs %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else if (code == push_AllButFirstArg) { COMPILENODE(argnode, &dummy, false); compileTail(); compileByte(138); // push all but first arg, send msg compileByte(index); //post("138 pushAllButFirstArg %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else goto normal; } else if (numArgs>2 && numArgs == numBlockArgs+1) { int code; code = checkPushAllButFirstTwoArgs(argnode, numBlockArgs); if (code == push_Normal) goto normal; else if (code == push_AllButFirstArg2) { COMPILENODE(argnode, &dummy, false); COMPILENODE(argnode->mNext, &dummy, false); compileTail(); compileByte(141); // one arg pushed, push all but first arg, send msg compileByte(index); //post("141 pushAllButFirstArg2 %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else goto normal; } else { normal: for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendMsg, numArgs); compileByte(index); } break; case selSpecial : if (numArgs == 1) { if (varname == s_this) { compileTail(); compileOpcode(opSendSpecialMsg, 0); compileByte(index); } else if (varname) { PyrClass *classobj; PyrBlock *tempFunc; int varType, varLevel, varIndex; classobj = gCompilingClass; varFound = findVarName(gCompilingBlock, &classobj, varname, &varType, &varLevel, &varIndex, &tempFunc); if (varFound && varType == varInst) { //post("136 pushInstVar(sp) %s:%s '%s' %d %d\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name, varname->name, varIndex, index); compileTail(); compileByte(136); compileByte(varIndex); compileByte(index); } else goto special; } else goto special; } else if (index == opmDo && isSeries(argnode, &argnode)) { index = opmForSeries; mArglist = linkNextNode(argnode, mArglist->mNext); numArgs = nodeListLength(mArglist); goto special; } else if (numArgs>1 && numArgs == numBlockArgs) { //} else if (numArgs>1 && numArgs == numBlockArgs) { // try for multiple push optimization int code; code = checkPushAllArgs(argnode, numArgs); if (code == push_Normal) goto special; else if (code == push_AllArgs) { compileTail(); compileByte(139); // push all args, send special msg compileByte(index); //post("139 pushAllArgs(sp) %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else if (code == push_AllButFirstArg) { COMPILENODE(argnode, &dummy, false); compileTail(); compileByte(140); // push all but first arg, send special msg compileByte(index); //post("140 pushAllButFirstArg(sp) %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else goto special; } else if (numArgs>2 && numArgs == numBlockArgs+1) { int code; code = checkPushAllButFirstTwoArgs(argnode, numBlockArgs); if (code == push_Normal) goto special; else if (code == push_AllButFirstArg2) { COMPILENODE(argnode, &dummy, false); COMPILENODE(argnode->mNext, &dummy, false); compileTail(); compileByte(142); // one arg pushed, push all but first arg, send msg compileByte(index); //post("142 pushAllButFirstArg2(sp) %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else goto special; } else { int i; special: for (i=0; argnode; argnode = argnode->mNext,i++) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(index); } break; case selUnary : if (numArgs != 1) { index = conjureLiteralSlotIndex((PyrParseNode*)mSelector, gCompilingBlock, &mSelector->mSlot); goto defaultCase; } for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialUnaryArithMsg, index); break; case selBinary : if (numArgs != 2) { index = conjureLiteralSlotIndex((PyrParseNode*)mSelector, gCompilingBlock, &mSelector->mSlot); goto defaultCase; } //for (; argnode; argnode = argnode->mNext) { // COMPILENODE(argnode, &dummy, false); //} argnode2 = argnode->mNext; if (index == opAdd && argnode2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)argnode2)->mSlot) && slotRawInt(&((PyrPushLitNode*)argnode2)->mSlot) == 1) { COMPILENODE(argnode, &dummy, false); compileOpcode(opPushSpecialValue, opsvPlusOne); } else if (index == opSub && argnode2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)argnode2)->mSlot) && slotRawInt(&((PyrPushLitNode*)argnode2)->mSlot) == 1) { COMPILENODE(argnode, &dummy, false); compileOpcode(opPushSpecialValue, opsvMinusOne); } else { COMPILENODE(argnode, &dummy, false); COMPILENODE(argnode->mNext, &dummy, false); compileTail(); compileOpcode(opSendSpecialBinaryArithMsg, index); } break; case selIf : compileAnyIfMsg(this); break; case selCase : compileCaseMsg(this); break; case selSwitch : compileSwitchMsg(this); break; case selWhile : compileWhileMsg(this); break; case selLoop : compileLoopMsg(this); break; case selAnd : if (numArgs == 2) compileAndMsg(argnode, argnode->mNext); else goto special; break; case selOr : if (numArgs == 2) compileOrMsg(argnode, argnode->mNext); else goto special; break; case selQuestionMark : if (numArgs == 2) compileQMsg(argnode, argnode->mNext); break; case selDoubleQuestionMark : if (numArgs == 2) compileQQMsg(argnode, argnode->mNext); break; case selExclamationQuestionMark : if (numArgs == 2) compileXQMsg(argnode, argnode->mNext); break; default : defaultCase: if (numArgs == 1 && varname == s_this) { compileTail(); compileOpcode(opSendMsg, 0); compileByte(index); } else { for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendMsg, numArgs); compileByte(index); } break; } } } ByteCodes compileSubExpression(PyrPushLitNode* litnode, bool onTailBranch) { return compileSubExpressionWithGoto(litnode, 0, onTailBranch); } ByteCodes compileSubExpressionWithGoto(PyrPushLitNode* litnode, int branchLen, bool onTailBranch) { PyrBlockNode *bnode = (PyrBlockNode*)slotRawPtr(&litnode->mSlot); return compileBodyWithGoto(bnode->mBody, branchLen, onTailBranch); } ByteCodes compileBodyWithGoto(PyrParseNode* body, int branchLen, bool onTailBranch) { ByteCodes currentByteCodes, subExprByteCodes; PyrSlot dummy; PyrBlock* prevPartiallyAppliedFunction = gPartiallyAppliedFunction; gPartiallyAppliedFunction = NULL; currentByteCodes = saveByteCodeArray(); COMPILENODE(body, &dummy, onTailBranch); if (branchLen) { if (!byteCodeLength(gCompilingByteCodes)) { compileOpcode(opPushSpecialValue, opsvNil); // push nil } compileJump(opcJumpFwd, branchLen); } subExprByteCodes = getByteCodes(); restoreByteCodeArray(currentByteCodes); gPartiallyAppliedFunction = prevPartiallyAppliedFunction; return subExprByteCodes; } #if 0 ByteCodes compileDefaultValue(int litIndex, int realExprLen) { ByteCodes currentByteCodes, defaultByteCodes; currentByteCodes = saveByteCodeArray(); compileOpcode(opPushSpecialValue, litIndex); compileJump(realExprLen, unconditionalJump); defaultByteCodes = getByteCodes(); restoreByteCodeArray(currentByteCodes); return (defaultByteCodes); } #endif bool isAnInlineableBlock(PyrParseNode *node) { bool res = false; if (node->mClassno == pn_PushLitNode) { PyrPushLitNode *anode; PyrBlockNode *bnode; anode = (PyrPushLitNode*)node; if (IsPtr(&anode->mSlot) && (bnode = (PyrBlockNode*)(slotRawPtr(&anode->mSlot)))->mClassno == pn_BlockNode) { if (bnode->mArglist || bnode->mVarlist) { if (gPostInlineWarnings) { post("WARNING: FunctionDef contains variable declarations and so" " will not be inlined.\n"); if (bnode->mArglist) nodePostErrorLine((PyrParseNode*)bnode->mArglist); else nodePostErrorLine((PyrParseNode*)bnode->mVarlist); } } else res = true; } } return res; } bool isAnInlineableAtomicLiteralBlock(PyrParseNode *node) { bool res = false; if (node->mClassno == pn_PushLitNode) { PyrPushLitNode *anode; PyrBlockNode *bnode; anode = (PyrPushLitNode*)node; if (IsPtr(&anode->mSlot) && (bnode = (PyrBlockNode*)(slotRawPtr(&anode->mSlot)))->mClassno == pn_BlockNode) { if (bnode->mArglist || bnode->mVarlist) { if (gPostInlineWarnings) { post("WARNING: FunctionDef contains variable declarations and so" " will not be inlined.\n"); if (bnode->mArglist) nodePostErrorLine((PyrParseNode*)bnode->mArglist); else nodePostErrorLine((PyrParseNode*)bnode->mVarlist); } } else { if (bnode->mBody->mClassno == pn_DropNode && ((PyrDropNode*)bnode->mBody)->mExpr2->mClassno == pn_BlockReturnNode) res = isAtomicLiteral(((PyrDropNode*)bnode->mBody)->mExpr1); else res = false; } } } return res; } bool isAtomicLiteral(PyrParseNode *node) { bool res = false; if (node->mClassno == pn_PushLitNode) { PyrPushLitNode *anode; anode = (PyrPushLitNode*)node; if (NotObj(&anode->mSlot) && !IsPtr(&anode->mSlot)) res = true; } return res; } bool isWhileTrue(PyrParseNode *node) { bool res = false; if (node->mClassno == pn_PushLitNode) { PyrPushLitNode *anode; PyrBlockNode *bnode; anode = (PyrPushLitNode*)node; if (IsPtr(&anode->mSlot) && (bnode = (PyrBlockNode*)(slotRawPtr(&anode->mSlot)))->mClassno == pn_BlockNode) { if (bnode->mArglist || bnode->mVarlist) { /* post("WARNING: FunctionDef contains variable declarations and so" " will not be inlined.\n"); if (bnode->mArglist) nodePostErrorLine((PyrParseNode*)bnode->mArglist); else nodePostErrorLine((PyrParseNode*)bnode->mVarlist); */ } else { if (bnode->mBody->mClassno == pn_PushLitNode && IsTrue(&((PyrPushLitNode*)bnode->mBody)->mSlot)) { res = true; } } } else if (IsTrue(&anode->mSlot)) { res = true; } } return res; } void compileAndMsg(PyrParseNode* arg1, PyrParseNode* arg2) { PyrSlot dummy; ByteCodes trueByteCodes; COMPILENODE(arg1, &dummy, false); if (isAnInlineableBlock(arg2)) { trueByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); compileJump(opcJumpIfFalsePushFalse, byteCodeLength(trueByteCodes)); compileAndFreeByteCodes(trueByteCodes); } else { COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, 2); compileByte(opmAnd); } } void compileOrMsg(PyrParseNode* arg1, PyrParseNode* arg2) { PyrSlot dummy; ByteCodes falseByteCodes; COMPILENODE(arg1, &dummy, false); if (isAnInlineableBlock(arg2)) { falseByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); compileJump(opcJumpIfTruePushTrue, byteCodeLength(falseByteCodes)); compileAndFreeByteCodes(falseByteCodes); } else { COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, 2); compileByte(opmOr); } } void compileQMsg(PyrParseNode* arg1, PyrParseNode* arg2) { // question mark. PyrSlot dummy; COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); compileByte(143); // special opcodes compileByte(22); // ?? } void compileQQMsg(PyrParseNode* arg1, PyrParseNode* arg2) { // double question mark. ?? {|obj| ^if (this.notNil, this, func) } PyrSlot dummy; COMPILENODE(arg1, &dummy, false); if (isAnInlineableBlock(arg2)) { ByteCodes nilByteCodes; nilByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); int jumplen = byteCodeLength(nilByteCodes); compileByte(143); // special opcodes compileByte(23); // ?? compileByte((jumplen >> 8) & 0xFF); compileByte(jumplen & 0xFF); compileAndFreeByteCodes(nilByteCodes); } else { COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, 2); compileByte(opmDoubleQuestionMark); } } void compileXQMsg(PyrParseNode* arg1, PyrParseNode* arg2) { // double question mark. !? {|obj| ^if (this.isNil, this, func) } PyrSlot dummy; COMPILENODE(arg1, &dummy, false); if (isAnInlineableBlock(arg2)) { ByteCodes nilByteCodes; nilByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); int jumplen = byteCodeLength(nilByteCodes); compileByte(143); // special opcodes compileByte(27); // !? compileByte((jumplen >> 8) & 0xFF); compileByte(jumplen & 0xFF); compileAndFreeByteCodes(nilByteCodes); } else { COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, 2); compileByte(opmExclamationQuestionMark); } } void compileAnyIfMsg(PyrCallNodeBase2* node) { PyrParseNode* arg1 = node->mArglist; if (arg1->mClassno == pn_CallNode) { PyrCallNode* callNode = (PyrCallNode*)arg1; int numCallArgs = nodeListLength(callNode->mArglist); int numCallKeyArgs = nodeListLength(callNode->mKeyarglist); if (numCallArgs == 1 && numCallKeyArgs == 0) { if (slotRawSymbol(&callNode->mSelector->mSlot) == gSpecialUnarySelectors[opIsNil]) { compileIfNilMsg(node, true); return; } else if (slotRawSymbol(&callNode->mSelector->mSlot) == gSpecialUnarySelectors[opNotNil]) { compileIfNilMsg(node, false); return; } } } compileIfMsg(node); } void compileIfMsg(PyrCallNodeBase2* node) { PyrSlot dummy; ByteCodes trueByteCodes, falseByteCodes; int numArgs = nodeListLength(node->mArglist); PyrParseNode* arg1 = node->mArglist; PyrParseNode *arg2, *arg3; if (numArgs == 2) { arg2 = arg1->mNext; if (isAnInlineableBlock(arg2)) { COMPILENODE(arg1, &dummy, false); trueByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); if (byteCodeLength(trueByteCodes)) { compileJump(opcJumpIfFalsePushNil, byteCodeLength(trueByteCodes)); compileAndFreeByteCodes(trueByteCodes); } else { compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean compileOpcode(opPushSpecialValue, opsvNil); // push nil } } else goto unoptimized; } else if (numArgs == 3) { arg2 = arg1->mNext; arg3 = arg2->mNext; if (isAnInlineableBlock(arg2) && isAnInlineableBlock(arg3)) { COMPILENODE(arg1, &dummy, false); falseByteCodes = compileSubExpression((PyrPushLitNode*)arg3, true); trueByteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)arg2, byteCodeLength(falseByteCodes), true); if (byteCodeLength(falseByteCodes)) { compileJump(opcJumpIfFalse, byteCodeLength(trueByteCodes)); compileAndFreeByteCodes(trueByteCodes); compileAndFreeByteCodes(falseByteCodes); } else if (byteCodeLength(trueByteCodes)) { compileJump(opcJumpIfFalsePushNil, byteCodeLength(trueByteCodes)); compileAndFreeByteCodes(trueByteCodes); } else { compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean compileOpcode(opPushSpecialValue, opsvNil); // push nil } } else goto unoptimized; } else { unoptimized: for (; arg1; arg1 = arg1->mNext) { COMPILENODE(arg1, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmIf); } } void compileIfNilMsg(PyrCallNodeBase2* node, bool flag) { PyrSlot dummy; ByteCodes trueByteCodes, falseByteCodes; PyrParseNode *arg2, *arg3; int numArgs = nodeListLength(node->mArglist); PyrParseNode* arg1 = node->mArglist; if (numArgs < 2) { COMPILENODE(arg1, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmIf); } else if (numArgs == 2) { arg2 = arg1->mNext; if (isAnInlineableBlock(arg2)) { PyrCallNode* callNode = (PyrCallNode*)arg1; COMPILENODE(callNode->mArglist, &dummy, false); trueByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); int jumplen = byteCodeLength(trueByteCodes); if (jumplen) { compileByte(143); // special opcodes compileByte(flag ? 26 : 27); compileByte((jumplen >> 8) & 0xFF); compileByte(jumplen & 0xFF); compileAndFreeByteCodes(trueByteCodes); } else { compileOpcode(opSpecialOpcode, opcDrop); // drop the value compileOpcode(opPushSpecialValue, opsvNil); // push nil } } else { COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmIf); } } else if (numArgs == 3) { arg2 = arg1->mNext; arg3 = arg2->mNext; if (isAnInlineableBlock(arg2) && isAnInlineableBlock(arg3)) { PyrCallNode* callNode = (PyrCallNode*)arg1; COMPILENODE(callNode->mArglist, &dummy, false); falseByteCodes = compileSubExpression((PyrPushLitNode*)arg3, true); int falseLen = byteCodeLength(falseByteCodes); trueByteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)arg2, falseLen, true); int trueLen = byteCodeLength(trueByteCodes); if (falseLen) { compileByte(143); // special opcodes compileByte(flag ? 24 : 25); compileByte((trueLen >> 8) & 0xFF); compileByte(trueLen & 0xFF); compileAndFreeByteCodes(trueByteCodes); compileAndFreeByteCodes(falseByteCodes); } else if (trueLen) { compileByte(143); // special opcodes compileByte(flag ? 26 : 27); compileByte((trueLen >> 8) & 0xFF); compileByte(trueLen & 0xFF); compileAndFreeByteCodes(trueByteCodes); } else { compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean compileOpcode(opPushSpecialValue, opsvNil); // push nil } } else { COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmIf); } } else { for (; arg1; arg1 = arg1->mNext) { COMPILENODE(arg1, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmIf); } } PyrParseNode* reverseNodeList(PyrParseNode** list) { PyrParseNode* temp1 = *list; PyrParseNode* temp2 = NULL; PyrParseNode* temp3 = NULL; while (temp1) { *list = temp1; temp2 = temp1->mNext; temp1->mNext = temp3; temp3 = temp1; temp1 = temp2; } return *list; } PyrCallNode* buildCase(PyrParseNode *arg1) { // transform case statement into nested if statements. //int numArgs = nodeListLength(arg1); //post("->buildCase %d\n", numArgs); PyrParseNode *arg2 = arg1->mNext; PyrPushLitNode *litnode = (PyrPushLitNode*)arg1; PyrBlockNode *bnode = (PyrBlockNode*)slotRawPtr(&litnode->mSlot); PyrParseNode *bbody = bnode->mBody; if (bbody->mClassno == pn_DropNode) { PyrDropNode* dropNode = (PyrDropNode*)bbody; if (dropNode->mExpr2->mClassno == pn_BlockReturnNode) { arg1 = dropNode->mExpr1; } else { arg1 = dropNode; } } else { arg1 = bbody; } arg1->mNext = arg2; PyrParseNode *arg3 = 0; if (arg2) { arg3 = arg2->mNext; if (arg3) { PyrParseNode *arg4 = arg3->mNext; if (arg4) { arg3 = buildCase(arg3); PyrBlockNode* bnode = newPyrBlockNode(NULL, NULL, arg3, false); arg3 = newPyrPushLitNode(NULL, bnode); arg2->mNext = arg3; arg3->mNext = NULL; arg1->mTail = arg3; } } else { arg1->mTail = arg2; } } else { arg1->mTail = arg1; } /* post("arg1->mNext %p arg2 %p\n", arg1->mNext, arg2); if (arg2) { post("arg2->mNext %p arg3 %p\n", arg2->mNext, arg3); post("isAnInlineableBlock arg2 %d\n", isAnInlineableBlock(arg2)); } if (arg3) { post("isAnInlineableBlock arg3 %d\n", isAnInlineableBlock(arg3)); post("arg3->mNext %p\n", arg3->mNext); } DUMPNODE(arg1, 0); */ PyrSlot selector; SetSymbol(&selector, gSpecialSelectors[opmIf]); PyrSlotNode* selectorNode = newPyrSlotNode(&selector); PyrCallNode *callNode = newPyrCallNode(selectorNode, arg1, NULL, NULL); //post("<-buildCase %d\n", numArgs); return callNode; } void compileCaseMsg(PyrCallNodeBase2* node) { PyrParseNode *argnode = node->mArglist; bool canInline = true; for (; argnode; argnode = argnode->mNext) { if (!isAnInlineableBlock(argnode)) { canInline = false; break; } } PyrSlot dummy; if (canInline) { PyrCallNode* callNode = buildCase(node->mArglist); callNode->compile(&dummy); } else { int numArgs = 0; argnode = node->mArglist; for (; argnode; argnode = argnode->mNext, ++numArgs) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmCase); } } void compileSwitchMsg(PyrCallNode* node) { PyrSlot dummy; bool canInline = true; int numArgs; { PyrParseNode *argnode = node->mArglist; numArgs = nodeListLength(argnode); argnode = argnode->mNext; // skip first arg. PyrParseNode* nextargnode = 0; for (; argnode; argnode = nextargnode) { nextargnode = argnode->mNext; if (nextargnode != NULL) { if (!isAtomicLiteral(argnode) && !isAnInlineableAtomicLiteralBlock(argnode)) { canInline = false; break; } if (!isAnInlineableBlock(nextargnode)) { canInline = false; break; } nextargnode = nextargnode->mNext; } else { if (!isAnInlineableBlock(argnode)) { canInline = false; } break; } } } if (canInline) { PyrParseNode *argnode = node->mArglist; int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; int arraySize = NEXTPOWEROFTWO(numArgs * 2); PyrObject* array = newPyrArray(compileGC(), arraySize, flags, false); array->size = arraySize; nilSlots(array->slots, arraySize); PyrSlot slot; SetObject(&slot, array); COMPILENODE(argnode, &dummy, false); compilePushConstant(node, &slot); compileByte(143); // lookup slot in dictionary and jump to offset. compileByte(28); argnode = argnode->mNext; // skip first arg. PyrParseNode* nextargnode = 0; int absoluteOffset = byteCodeLength(gCompilingByteCodes); int offset = 0; int lastOffset = 0; for (; argnode; argnode = nextargnode) { nextargnode = argnode->mNext; if (nextargnode != NULL) { ByteCodes byteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)nextargnode, 0x6666, true); PyrSlot *key; PyrSlot value; SetInt(&value, offset); PyrPushLitNode* keyargnode = (PyrPushLitNode*)argnode; if (isAtomicLiteral(argnode)) { key = &keyargnode->mSlot; } else { PyrBlockNode *bnode = (PyrBlockNode*)slotRawPtr(&keyargnode->mSlot); PyrDropNode *dropnode = (PyrDropNode*)bnode->mBody; PyrPushLitNode* litnode = (PyrPushLitNode*)dropnode->mExpr1; key = &litnode->mSlot; } int index = arrayAtIdentityHashInPairs(array, key); PyrSlot *slot = array->slots + index; slotCopy(slot, key); SetInt(slot+1, offset); if (byteCodes) { offset += byteCodeLength(byteCodes); compileAndFreeByteCodes(byteCodes); } else { compileOpcode(opPushSpecialValue, opsvNil); offset += 1; } nextargnode = nextargnode->mNext; if (nextargnode == NULL) { compileOpcode(opPushSpecialValue, opsvNil); lastOffset = offset; offset += 1; } } else { ByteCodes byteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)argnode, 0, true); lastOffset = offset; if (byteCodes) { offset += byteCodeLength(byteCodes); compileAndFreeByteCodes(byteCodes); } else { compileOpcode(opPushSpecialValue, opsvNil); lastOffset = offset; offset += 1; } } } Byte *bytes = gCompilingByteCodes->bytes + absoluteOffset; PyrSlot *slots = array->slots; { int jumplen = offset - lastOffset; bytes[lastOffset-2] = (jumplen >> 8) & 255; bytes[lastOffset-1] = jumplen & 255; } for (int i=0; i> 8) & 255; bytes[offsetToHere-1] = jumplen & 255; } } } } else { PyrParseNode *argnode = node->mArglist; for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmSwitch); } } void compileWhileMsg(PyrCallNodeBase2* node) { int numArgs; PyrParseNode *argnode; PyrSlot dummy; ByteCodes whileByteCodes, exprByteCodes; int whileByteCodeLen, exprByteCodeLen; numArgs = nodeListLength(node->mArglist); if (numArgs == 1 && isAnInlineableBlock(node->mArglist)) { whileByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist, false); whileByteCodeLen = byteCodeLength(whileByteCodes); compileAndFreeByteCodes(whileByteCodes); exprByteCodeLen = 1; compileJump(opcJumpIfFalsePushNil, exprByteCodeLen + 3); // opcJumpBak does a drop.. compileOpcode(opPushSpecialValue, opsvNil); compileJump(opcJumpBak, exprByteCodeLen + whileByteCodeLen + 4); } else if (numArgs == 2 && isWhileTrue(node->mArglist) && isAnInlineableBlock(node->mArglist->mNext)) { exprByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist->mNext, false); exprByteCodeLen = byteCodeLength(exprByteCodes); compileAndFreeByteCodes(exprByteCodes); compileJump(opcJumpBak, exprByteCodeLen + 1); } else if (numArgs == 2 && isAnInlineableBlock(node->mArglist) && isAnInlineableBlock(node->mArglist->mNext)) { whileByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist, false); exprByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist->mNext, false); whileByteCodeLen = byteCodeLength(whileByteCodes); compileAndFreeByteCodes(whileByteCodes); if (exprByteCodes) { exprByteCodeLen = byteCodeLength(exprByteCodes); compileJump(opcJumpIfFalsePushNil, exprByteCodeLen + 3); compileAndFreeByteCodes(exprByteCodes); } else { exprByteCodeLen = 1; compileJump(opcJumpIfFalsePushNil, exprByteCodeLen + 3); // opcJumpBak does a drop.. compileOpcode(opPushSpecialValue, opsvNil); } compileJump(opcJumpBak, exprByteCodeLen + whileByteCodeLen + 4); } else { argnode = node->mArglist; for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmWhile); } } void compileLoopMsg(PyrCallNodeBase2* node) { int numArgs; PyrParseNode *argnode; PyrSlot dummy; ByteCodes exprByteCodes; int exprByteCodeLen; numArgs = nodeListLength(node->mArglist); if (numArgs == 1 && isAnInlineableBlock(node->mArglist)) { exprByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist, false); exprByteCodeLen = byteCodeLength(exprByteCodes); compileAndFreeByteCodes(exprByteCodes); compileJump(opcJumpBak, exprByteCodeLen + 1); } else { argnode = node->mArglist; for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmLoop); } } PyrBinopCallNode* newPyrBinopCallNode(PyrSlotNode* selector, PyrParseNode* arg1, PyrParseNode* arg2, PyrParseNode* arg3) { PyrBinopCallNode* node = ALLOCNODE(PyrBinopCallNode); node->mSelector = selector; node->mArglist = arg1; arg1->mNext = arg2; arg2->mNext = arg3; return node; } int PyrBinopCallNode::isPartialApplication() { int sum = 0; PyrParseNode* argnode = mArglist; for (; argnode; argnode = argnode->mNext) { if (argnode->mClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)argnode)->mArgNum = sum; sum ++; } } return sum; } void PyrBinopCallNode::compileCall(PyrSlot *result) { int index, selType, isSuper, numArgs; PyrSlot dummy; PyrParseNode *arg1 = mArglist; PyrParseNode *arg2 = arg1->mNext; PyrParseNode *arg3 = arg2->mNext; //postfl("compilePyrBinopCallNode\n"); isSuper = isSuperObjNode(arg1); slotRawSymbol(&mSelector->mSlot)->flags |= sym_Called; index = conjureSelectorIndex((PyrParseNode*)mSelector, gCompilingBlock, isSuper, slotRawSymbol(&mSelector->mSlot), &selType); numArgs = arg3 ? 3 : 2; if (isSuper) { COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); if (arg3) COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSendSuper, numArgs); compileByte(index); } else { switch (selType) { case selNormal : COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); if (arg3) COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSendMsg, numArgs); compileByte(index); break; case selSpecial : COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); if (arg3) COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(index); break; case selUnary : COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); if (arg3) COMPILENODE(arg3, &dummy, false); compileTail(); if (arg3) compileOpcode(opSpecialOpcode, opcDrop); // drop third argument compileOpcode(opSpecialOpcode, opcDrop); // drop second argument compileOpcode(opSendSpecialUnaryArithMsg, index); break; case selBinary : if (arg3) { COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSpecialOpcode, opcSpecialBinaryOpWithAdverb); compileByte(index); } else if (index == opAdd && arg2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)arg2)->mSlot) && slotRawInt(&((PyrPushLitNode*)arg2)->mSlot) == 1) { COMPILENODE(arg1, &dummy, false); compileOpcode(opPushSpecialValue, opsvPlusOne); } else if (index == opSub && arg2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)arg2)->mSlot) && slotRawInt(&((PyrPushLitNode*)arg2)->mSlot) == 1) { COMPILENODE(arg1, &dummy, false); compileTail(); compileOpcode(opPushSpecialValue, opsvMinusOne); } else { COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialBinaryArithMsg, index); } break; case selIf : compileAnyIfMsg(this); break; case selCase : compileCaseMsg(this); break; case selWhile : compileWhileMsg(this); break; case selLoop : compileLoopMsg(this); break; case selAnd : compileAndMsg(arg1, arg2); break; case selOr : compileOrMsg(arg1, arg2); break; case selQuestionMark : compileQMsg(arg1, arg2); break; case selDoubleQuestionMark : compileQQMsg(arg1, arg2); break; case selExclamationQuestionMark : compileXQMsg(arg1, arg2); break; default : COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); if (arg3) COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSendMsg, numArgs); compileByte(index); break; } } } PyrPushKeyArgNode* newPyrPushKeyArgNode(PyrSlotNode* selector, PyrParseNode* expr) { PyrPushKeyArgNode* node = ALLOCNODE(PyrPushKeyArgNode); node->mSelector = selector; node->mExpr = expr; return node; } void PyrPushKeyArgNode::compile(PyrSlot *result) { PyrSlot dummy; //postfl("->compilePyrPushKeyArgNode\n"); compilePushConstant((PyrParseNode*)this, &mSelector->mSlot); COMPILENODE(mExpr, &dummy, false); } PyrDropNode* newPyrDropNode(PyrParseNode* expr1, PyrParseNode* expr2) { PyrDropNode* node = ALLOCNODE(PyrDropNode); node->mExpr1 = expr1; node->mExpr2 = expr2; return node; } void PyrDropNode::compile(PyrSlot *result) { //postfl("->compilePyrDropNode\n"); PyrSlot dummy; // eliminate as many drops as possible if (!mExpr2) { post("DROP EXPR2 NULL\n"); COMPILENODE(mExpr1, &dummy, true); } else if (mExpr2->mClassno == pn_BlockReturnNode) { // no drop before a block return COMPILENODE(mExpr1, &dummy, true); } else if (mExpr1 && mExpr1->mClassno == pn_AssignNode) { // let the store do the drop ((PyrAssignNode*)mExpr1)->mDrop = 1; COMPILENODE(mExpr1, &dummy, false); COMPILENODE(mExpr2, &dummy, true); } else if (mExpr1 && mExpr1->mClassno == pn_DropNode) { PyrDropNode *znode; // let the store do the drop, a bit more complex. // find the ultimate expression in the left subtree before the drop. znode = (PyrDropNode*)mExpr1; while (znode->mExpr2 && znode->mExpr2->mClassno == pn_DropNode) { znode = (PyrDropNode*)znode->mExpr2; } if (znode->mExpr2->mClassno == pn_AssignNode) { ((PyrAssignNode*)znode->mExpr2)->mDrop = 1; COMPILENODE(mExpr1, &dummy, false); COMPILENODE(mExpr2, &dummy, true); } else { COMPILENODE(mExpr1, &dummy, false); compileOpcode(opSpecialOpcode, opcDrop); COMPILENODE(mExpr2, &dummy, true); } } else { COMPILENODE(mExpr1, &dummy, false); compileOpcode(opSpecialOpcode, opcDrop); COMPILENODE(mExpr2, &dummy, true); } //postfl("<-compilePyrDropNode\n"); } PyrPushLitNode* newPyrPushLitNode(PyrSlotNode* literalSlot, PyrParseNode* literalObj) { PyrPushLitNode* node; if (literalSlot) { node = literalSlot; node->mClassno = pn_PushLitNode; } else { node = ALLOCSLOTNODE(PyrSlotNode, pn_PushLitNode); SetPtr(&node->mSlot, (PyrObject*)literalObj); } return node; } void compilePushConstant(PyrParseNode* node, PyrSlot *slot) { int index = conjureConstantIndex(node, gCompilingBlock, slot); if (index < (1<<4)) { compileByte((opPushLiteral << 4) | index); } else if (index < (1<<8)) { compileByte(40); compileByte(index & 0xFF); } else if (index < (1<<16)) { compileByte(41); compileByte((index >> 8) & 0xFF); compileByte(index & 0xFF); } else if (index < (1<<24)) { compileByte(42); compileByte((index >> 16) & 0xFF); compileByte((index >> 8) & 0xFF); compileByte(index & 0xFF); } else { compileByte(43); compileByte((index >> 24) & 0xFF); compileByte((index >> 16) & 0xFF); compileByte((index >> 8) & 0xFF); compileByte(index & 0xFF); } } void compilePushInt(int value) { //postfl("compilePushInt\n"); if (value >= -1 && value <= 2) { compileOpcode(opPushSpecialValue, opsvZero + value); } else{ //printf("int %d\n", value); if (value >= -(1<<7) && value <= ((1<<7)-1)) { compileByte(44); compileByte(value & 0xFF); } else if (value >= -(1<<15) && value <= ((1<<15)-1)) { compileByte(45); compileByte((value >> 8) & 0xFF); compileByte(value & 0xFF); } else if (value >= -(1<<23) && value <= ((1<<23)-1)) { compileByte(46); compileByte((value >> 16) & 0xFF); compileByte((value >> 8) & 0xFF); compileByte(value & 0xFF); } else { compileByte(47); compileByte((value >> 24) & 0xFF); compileByte((value >> 16) & 0xFF); compileByte((value >> 8) & 0xFF); compileByte(value & 0xFF); } } } void PyrSlotNode::compilePushLit(PyrSlot *result) { int index; PyrSlot slot; ByteCodes savedBytes; //postfl("compilePyrPushLitNode\n"); if (IsPtr(&mSlot)) { PyrParseNode *literalObj = (PyrParseNode*)slotRawPtr(&mSlot); //index = conjureLiteralObjIndex(gCompilingBlock, literalObj); if (literalObj->mClassno == pn_BlockNode) { savedBytes = saveByteCodeArray(); COMPILENODE(literalObj, &slot, false); restoreByteCodeArray(savedBytes); index = conjureLiteralSlotIndex(literalObj, gCompilingBlock, &slot); compileOpcode(opExtended, opPushLiteral); compileByte(index); PyrBlock *block = slotRawBlock(&slot); if (NotNil(&block->contextDef)) { METHRAW(gCompilingBlock)->needsHeapContext = 1; } } else { COMPILENODE(literalObj, &slot, false); compilePushConstant((PyrParseNode*)literalObj, &slot); } } else { slot = mSlot; if (IsInt(&slot)) { compilePushInt(slotRawInt(&slot)); } else if (SlotEq(&slot, &o_nil)) { compileOpcode(opPushSpecialValue, opsvNil); } else if (SlotEq(&slot, &o_true)) { compileOpcode(opPushSpecialValue, opsvTrue); } else if (SlotEq(&slot, &o_false)) { compileOpcode(opPushSpecialValue, opsvFalse); } else if (SlotEq(&slot, &o_fhalf)) { compileOpcode(opPushSpecialValue, opsvFHalf); } else if (SlotEq(&slot, &o_fnegone)) { compileOpcode(opPushSpecialValue, opsvFNegOne); } else if (SlotEq(&slot, &o_fzero)) { compileOpcode(opPushSpecialValue, opsvFZero); } else if (SlotEq(&slot, &o_fone)) { compileOpcode(opPushSpecialValue, opsvFOne); } else if (SlotEq(&slot, &o_ftwo)) { compileOpcode(opPushSpecialValue, opsvFTwo); } else if (SlotEq(&slot, &o_inf)) { compileOpcode(opPushSpecialValue, opsvInf); } else if (IsFloat(&slot)) { compilePushConstant((PyrParseNode*)this, &slot); } else if (IsSym(&slot)) { compilePushConstant((PyrParseNode*)this, &slot); } else { compilePushConstant((PyrParseNode*)this, &slot); } } } PyrLiteralNode* newPyrLiteralNode(PyrSlotNode* literalSlot, PyrParseNode* literalObj) { PyrLiteralNode* node; if (literalSlot) { node = literalSlot; node->mClassno = pn_LiteralNode; } else { node = ALLOCSLOTNODE(PyrSlotNode, pn_LiteralNode); SetPtr(&node->mSlot, (PyrObject*)literalObj); } return node; } void compilePyrLiteralNode(PyrLiteralNode *node, PyrSlot *result) { if (!node) { SetNil(result); } else { node->compileLiteral(result); } } void PyrSlotNode::compileLiteral(PyrSlot *result) { ByteCodes savedBytes; if (IsPtr(&mSlot)) { PyrParseNode* literalObj = (PyrParseNode*)slotRawPtr(&mSlot); if (literalObj->mClassno == pn_BlockNode) { savedBytes = saveByteCodeArray(); COMPILENODE(literalObj, result, false); restoreByteCodeArray(savedBytes); PyrBlock *block = slotRawBlock(result); if (NotNil(&block->contextDef)) { METHRAW(gCompilingBlock)->needsHeapContext = 1; } } else { COMPILENODE(literalObj, result, false); } } else { *(PyrSlot*)result = mSlot; } } PyrReturnNode* newPyrReturnNode(PyrParseNode* expr) { PyrReturnNode* node = ALLOCNODE(PyrReturnNode); node->mExpr = expr; return node; } void PyrReturnNode::compile(PyrSlot *result) { PyrPushLitNode *lit; PyrSlot dummy; //post("->compilePyrReturnNode\n"); gFunctionCantBeClosed = true; if (!mExpr) { compileOpcode(opSpecialOpcode, opcReturnSelf); } else if (mExpr->mClassno == pn_PushLitNode) { lit = (PyrPushLitNode*)mExpr; if (IsSym(&(lit->mSlot)) && slotRawSymbol(&lit->mSlot) == s_this) { compileOpcode(opSpecialOpcode, opcReturnSelf); } else if (IsNil(&lit->mSlot)) { compileOpcode(opSpecialOpcode, opcReturnNil); } else if (IsTrue(&lit->mSlot)) { compileOpcode(opSpecialOpcode, opcReturnTrue); } else if (IsFalse(&lit->mSlot)) { compileOpcode(opSpecialOpcode, opcReturnFalse); } else { COMPILENODE(lit, &dummy, false); compileOpcode(opSpecialOpcode, opcReturn); } } else { SetTailBranch branch(true); SetTailIsMethodReturn mr(true); COMPILENODE(mExpr, &dummy, true); compileOpcode(opSpecialOpcode, opcReturn); } //post("<-compilePyrReturnNode\n"); } PyrBlockReturnNode* newPyrBlockReturnNode() { PyrBlockReturnNode* node = ALLOCNODE(PyrBlockReturnNode); return node; } void PyrBlockReturnNode::compile(PyrSlot *result) { //postfl("compilePyrBlockReturnNode\n"); //compileOpcode(opSpecialOpcode, opcFunctionReturn); } PyrAssignNode* newPyrAssignNode(PyrSlotNode* varName, PyrParseNode* expr, int flags) { PyrAssignNode* node = ALLOCNODE(PyrAssignNode); node->mVarName = varName; node->mExpr = expr; node->mDrop = 0; return node; } PyrSetterNode* newPyrSetterNode(PyrSlotNode* selector, PyrParseNode* expr1, PyrParseNode* expr2) { PyrSetterNode* node = ALLOCNODE(PyrSetterNode); node->mSelector = selector; node->mExpr1 = expr1; node->mExpr2 = expr2; return node; } PyrMultiAssignNode* newPyrMultiAssignNode(PyrMultiAssignVarListNode* varList, PyrParseNode* expr, int flags) { PyrMultiAssignNode* node = ALLOCNODE(PyrMultiAssignNode); node->mVarList = varList; node->mExpr = expr; node->mDrop = 0; return node; } PyrMultiAssignVarListNode* newPyrMultiAssignVarListNode(PyrSlotNode* varNames, PyrSlotNode* rest) { PyrMultiAssignVarListNode* node = ALLOCNODE(PyrMultiAssignVarListNode); node->mVarNames = varNames; node->mRest = rest; return node; } void compileAssignVar(PyrParseNode* node, PyrSymbol* varName, bool drop) { int level, index, vindex, varType; PyrBlock *tempfunc; PyrClass *classobj; //postfl("compileAssignVar\n"); classobj = gCompilingClass; if (varName == s_this || varName == s_super || varName == s_curProcess || varName == s_curThread || varName == s_curMethod || varName == s_curBlock || varName == s_curClosure) { error("You may not assign to '%s'.", varName->name); nodePostErrorLine(node); compileErrors++; } else if (varName->name[0] >= 'A' && varName->name[0] <= 'Z') { // actually this shouldn't even parse, so you won't get here. error("You may not assign to a class name."); nodePostErrorLine(node); compileErrors++; } else if (findVarName(gCompilingBlock, &classobj, varName, &varType, &level, &index, &tempfunc)) { switch (varType) { case varInst : if (drop) { if (index <= 15) { compileByte((opStoreInstVar<<4) | index); } else { compileByte(opStoreInstVar); compileByte(index); compileByte((opSpecialOpcode<<4) | opcDrop); } } else { compileByte(opStoreInstVar); compileByte(index); } break; case varClass : { index += slotRawInt(&classobj->classVarIndex); if (drop) { if (index < 4096) { compileByte((opStoreClassVar<<4) | ((index>>8) & 15)); compileByte(index & 255); } else { compileByte(opStoreClassVar); assert(false); compileByte(vindex); // FIXME: vindex is not initalized!!!! compileByte(index); compileByte((opSpecialOpcode<<4) | opcDrop); } } else { compileByte(opStoreClassVar); compileByte((index >> 8) & 255); compileByte(index & 255); } } break; case varConst : { error("You may not assign to a constant."); nodePostErrorLine(node); compileErrors++; } break; case varTemp : //compileOpcode(opStoreTempVar, level); //compileByte(index); if (drop) { if (index <= 15 && level < 8) { compileByte((opStoreTempVar<<4) | level); compileByte(index); } else { compileByte(opStoreTempVar); compileByte(level); compileByte(index); compileByte((opSpecialOpcode<<4) | opcDrop); } } else { compileByte(opStoreTempVar); compileByte(level); compileByte(index); } break; } } else { error("Variable '%s' not defined.\n", varName->name); nodePostErrorLine(node); compileErrors++; //Debugger(); } } void PyrAssignNode::compile(PyrSlot* result) { PyrSlot dummy; //postfl("compilePyrAssignNode\n"); COMPILENODE(mExpr, &dummy, false); compileAssignVar((PyrParseNode*)this, slotRawSymbol(&mVarName->mSlot), mDrop); } int PyrSetterNode::isPartialApplication() { int sum = 0; if (mExpr1->mClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)mExpr1)->mArgNum = sum; sum ++; } if (mExpr2->mClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)mExpr2)->mArgNum = sum; sum ++; } return sum; } void PyrSetterNode::compileCall(PyrSlot* result) { int index, selType, isSuper; PyrSlot dummy; char setterName[128]; PyrSymbol *setterSym; //postfl("compilePyrSetterNode\n"); if (nodeListLength(mExpr1) > 1) { error("Setter method called with too many arguments.\n"); nodePostErrorLine(mExpr1); compileErrors++; } else { COMPILENODE(mExpr1, &dummy, false); COMPILENODE(mExpr2, &dummy, false); //postfl("compilePyrCallNode\n"); isSuper = isSuperObjNode(mExpr1); sprintf(setterName, "%s_", slotRawSymbol(&mSelector->mSlot)->name); setterSym = getsym(setterName); slotRawSymbol(&mSelector->mSlot)->flags |= sym_Called; index = conjureSelectorIndex((PyrParseNode*)mSelector, gCompilingBlock, isSuper, setterSym, &selType); if (isSuper) { compileTail(); compileOpcode(opSendSuper, 2); compileByte(index); } else { compileTail(); compileOpcode(opSendMsg, 2); compileByte(index); } } } void PyrMultiAssignNode::compile(PyrSlot* result) { PyrSlot dummy; //postfl("compilePyrMultiAssignNode\n"); COMPILENODE(mExpr, &dummy, false); COMPILENODE(mVarList, &dummy, false); } void PyrMultiAssignVarListNode::compile(PyrSlot* result) { int i, numAssigns; PyrSlotNode *varname; //postfl("compilePyrMultiAssignVarListNode\n"); numAssigns = nodeListLength((PyrParseNode*)mVarNames); varname = mVarNames; for (i=0; imNext) { compileOpcode(opSpecialOpcode, opcDup); compilePushInt(i); compileOpcode(opSendSpecialMsg, 2); compileByte(opmAt); compileAssignVar((PyrParseNode*)varname, slotRawSymbol(&varname->mSlot), 1); //compileOpcode(opSpecialOpcode, opcDrop); } if (mRest) { compileOpcode(opSpecialOpcode, opcDup); compilePushInt(i); compileOpcode(opSendSpecialMsg, 2); compileByte(opmCopyToEnd); compileAssignVar((PyrParseNode*)mRest, slotRawSymbol(&mRest->mSlot), 1); //compileOpcode(opSpecialOpcode, opcDrop); } } PyrDynDictNode* newPyrDynDictNode(PyrParseNode *elems) { PyrDynDictNode* node; //if (compilingCmdLine) post("newPyrDynDictNode\n"); node = ALLOCNODE(PyrDynDictNode); node->mElems = elems; return node; } int PyrDynDictNode::isPartialApplication() { int sum = 0; int numItems = nodeListLength(mElems); PyrParseNode* inode = mElems; for (int i=0; imClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)inode)->mArgNum = sum; sum ++; } inode = (PyrParseNode*)inode->mNext; } return sum; } void PyrDynDictNode::compileCall(PyrSlot* result) { int i, numItems; PyrParseNode *inode; PyrSlot dummy; //postfl("compilePyrDynDictNode\n"); numItems = nodeListLength(mElems) >> 1; compilePushVar((PyrParseNode*)this, s_event); compilePushInt(numItems); compileByte(110); // push nil for proto compileByte(110); // push nil for parent compileByte(108); // push true for know compileOpcode(opSendSpecialMsg, 5); compileByte(opmNew); inode = mElems; for (i=0; isize); COMPILENODE(inode, &dummy, false); inode = (PyrParseNode*)inode->mNext; COMPILENODE(inode, &dummy, false); inode = (PyrParseNode*)inode->mNext; compileOpcode(opSendSpecialMsg, 3); compileByte(opmPut); } } PyrDynListNode* newPyrDynListNode(PyrParseNode *classname, PyrParseNode *elems) { PyrDynListNode* node; //if (compilingCmdLine) post("newPyrDynListNode\n"); node = ALLOCNODE(PyrDynListNode); node->mClassname = classname; node->mElems = elems; return node; } int PyrDynListNode::isPartialApplication() { int sum = 0; int numItems = nodeListLength(mElems); PyrParseNode* inode = mElems; for (int i=0; imClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)inode)->mArgNum = sum; sum ++; } inode = (PyrParseNode*)inode->mNext; } return sum; } void PyrDynListNode::compileCall(PyrSlot* result) { int i, numItems; PyrParseNode *inode; PyrSlot dummy; //postfl("compilePyrDynListNode\n"); numItems = nodeListLength(mElems); if (mClassname) { compilePushVar((PyrParseNode*)this, slotRawSymbol(&((PyrSlotNode*)mClassname)->mSlot)); } else { compilePushVar((PyrParseNode*)this, s_array); } //compileOpcode(opExtended, opPushSpecialValue); //compileByte(op_class_list); compilePushInt(numItems); compileOpcode(opSendSpecialMsg, 2); compileByte(opmNew); inode = mElems; for (i=0; imNext) { //if (compilingCmdLine) post("+ %d %d\n", i, gCompilingByteCodes->size); COMPILENODE(inode, &dummy, false); compileOpcode(opSendSpecialMsg, 2); compileByte(opmAdd); } } PyrLitListNode* newPyrLitListNode(PyrParseNode *classname, PyrParseNode *elems) { PyrLitListNode* node = ALLOCNODE(PyrLitListNode); node->mClassname = classname; node->mElems = elems; return node; } void PyrLitListNode::compile(PyrSlot* result) { PyrSlot *resultSlot; PyrSlot itemSlot; PyrObject *array; PyrParseNode *inode; int i, numItems, flags; //postfl("->compilePyrLitListNode\n"); if (mClassname && slotRawSymbol(&((PyrSlotNode*)mClassname)->mSlot) != s_array) { error("Only Array is supported as literal type.\n"); post("Compiling as an Array.\n"); } resultSlot = (PyrSlot*)result; numItems = mElems ? nodeListLength(mElems) : 0; flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; array = newPyrArray(compileGC(), numItems, flags, false); inode = mElems; for (i=0; imNext) { COMPILENODE(inode, &itemSlot, false); array->slots[i] = itemSlot; } array->size = numItems; SetObject(resultSlot, array); //postfl("<-compilePyrLitListNode\n"); } PyrLitDictNode* newPyrLitDictNode(PyrParseNode *elems) { PyrLitDictNode* node = ALLOCNODE(PyrLitDictNode); node->mElems = elems; return node; } int litDictPut(PyrObject *dict, PyrSlot *key, PyrSlot *value); int litDictPut(PyrObject *dict, PyrSlot *key, PyrSlot *value) { #if 0 PyrSlot *slot, *newslot; int i, index, size; PyrObject *array; bool knows = IsTrue(dict->slots + ivxIdentDict_know); if (knows && IsSym(key)) { if (slotRawSymbol(key) == s_parent) { slotCopy(&dict->slots[ivxIdentDict_parent], value); return errNone; } if (slotRawSymbol(key) == s_proto) { slotCopy(&dict->slots[ivxIdentDict_proto], value); return errNone; } } array = slotRawObject(&dict->slots[ivxIdentDict_array]); if (!isKindOf((PyrObject*)array, class_array)) return errFailed; index = arrayAtIdentityHashInPairs(array, key); slot = array->slots + index; slotCopy(&slot[1], value); if (IsNil(slot)) { slotCopy(slot, key); } #endif return errNone; } void PyrLitDictNode::dump(int level) { } void PyrLitDictNode::compile(PyrSlot* result) { #if 0 PyrSlot *resultSlot; PyrSlot itemSlot; PyrObject *array; PyrParseNode *inode; int i, numItems, flags; //postfl("->compilePyrLitDictNode\n"); if (mClassname && slotRawSymbol(&((PyrSlotNode*)mClassname)->mSlot) != s_array) { error("Only Array is supported as literal type.\n"); post("Compiling as an Array.\n"); } resultSlot = (PyrSlot*)result; numItems = mElems ? nodeListLength(mElems) : 0; int numSlots = NEXTPOWEROFTWO(numItems*2); PyrObject *obj = instantiateObject(g->gc, class_event->u.classobj, 0, true, false); PyrSlot *slots = obj->slots; flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; array = newPyrArray(compileGC(), numSlots, flags, false); nilSlots(array->slots, numSlots); inode = mElems; for (i=0; imNext) { COMPILENODE(inode, &itemSlot, false); array->slots[i] = itemSlot; } array->size = numItems; SetObject(resultSlot, array); //postfl("<-compilePyrLitListNode\n"); #endif } extern LongStack closedFuncCharNo; extern int lastClosedFuncCharNo; PyrBlockNode* newPyrBlockNode(PyrArgListNode *arglist, PyrVarListNode *varlist, PyrParseNode *body, bool isTopLevel) { PyrBlockNode* node = ALLOCNODE(PyrBlockNode); node->mArglist = arglist; catVarLists(varlist); node->mVarlist = varlist; node->mBody = body; node->mIsTopLevel = isTopLevel; node->mBeginCharNo = lastClosedFuncCharNo; return node; } void PyrBlockNode::compile(PyrSlot* slotResult) { PyrBlock *block, *prevBlock; PyrMethodRaw *methraw; int i, j, numArgs, numVars, funcVarArgs; int numSlots, numArgNames, flags; PyrVarDefNode *vardef; PyrObject *proto; PyrSymbolArray *argNames, *varNames; PyrSlot dummy; bool hasVarExprs = false; //postfl("->block\n"); // create a new block object flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; block = newPyrBlock(flags); SetObject(slotResult, block); int prevFunctionHighestExternalRef = gFunctionHighestExternalRef; bool prevFunctionCantBeClosed = gFunctionCantBeClosed; gFunctionHighestExternalRef = 0; gFunctionCantBeClosed = false; prevBlock = gCompilingBlock; PyrClass* prevClass = gCompilingClass; gCompilingBlock = block; PyrBlock* prevPartiallyAppliedFunction = gPartiallyAppliedFunction; gPartiallyAppliedFunction = NULL; methraw = METHRAW(block); methraw->unused1 = 0; methraw->unused2 = 0; int endCharNo = linestarts[mLineno] + mCharno; int stringLength = endCharNo - mBeginCharNo; int lastChar = text[mBeginCharNo + stringLength - 1]; if (lastChar == 0) stringLength--; methraw->needsHeapContext = 0; if (mIsTopLevel) { gCompilingClass = class_interpreter; SetNil(&block->contextDef); } else { SetObject(&block->contextDef, prevBlock); } methraw->varargs = funcVarArgs = (mArglist && mArglist->mRest) ? 1 : 0; numArgs = mArglist ? nodeListLength((PyrParseNode*)mArglist->mVarDefs) : 0; numVars = mVarlist ? nodeListLength((PyrParseNode*)mVarlist->mVarDefs) : 0; numSlots = numArgs + funcVarArgs + numVars; methraw->frameSize = (numSlots + FRAMESIZE) * sizeof(PyrSlot); if (numSlots) { proto = newPyrArray(compileGC(), numSlots, flags, false); proto->size = numSlots; SetObject(&block->prototypeFrame, proto); } else { SetNil(&block->prototypeFrame); } numArgNames = numArgs + funcVarArgs; if (numArgNames) { argNames = newPyrSymbolArray(compileGC(), numArgNames, flags, false); argNames->size = numArgNames; SetObject(&block->argNames, argNames); } else { SetNil(&block->argNames); } if (numVars) { varNames = newPyrSymbolArray(compileGC(), numVars, flags, false); varNames->size = numVars; SetObject(&block->varNames, varNames); } else { SetNil(&block->varNames); } methraw->numargs = numArgs; methraw->numvars = numVars; methraw->posargs = numArgs + funcVarArgs; methraw->numtemps = numSlots; methraw->popSize = numSlots; // declare args if (numArgs) { PyrSymbol **blockargs; blockargs = slotRawSymbolArray(&block->argNames)->symbols; vardef = mArglist->mVarDefs; for (i=0; imNext) { PyrSlot *varslot; varslot = &vardef->mVarName->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in mArglist blockargs[i] = slotRawSymbol(varslot); //postfl("defarg %d '%s'\n", i, slotRawSymbol(slot)->name); } } if (funcVarArgs) { PyrSlot *varslot; PyrSymbol **blockargs; blockargs = slotRawSymbolArray(&block->argNames)->symbols; varslot = &mArglist->mRest->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in mArglist blockargs[numArgs] = slotRawSymbol(varslot); //postfl("defrest '%s'\n", slotRawSymbol(slot)->name); } // declare vars if (numVars) { PyrSymbol **blockargs, **blockvars; blockargs = slotRawSymbolArray(&block->argNames)->symbols; blockvars = slotRawSymbolArray(&block->varNames)->symbols; vardef = mVarlist->mVarDefs; for (i=0; imNext) { PyrSlot *varslot; varslot = &vardef->mVarName->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // already declared as var? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in varlist blockvars[i] = slotRawSymbol(varslot); //postfl("defvar %d '%s'\n", i, slotRawSymbol(slot)->name); } } if (numArgs) { vardef = mArglist->mVarDefs; for (i=0; imNext) { PyrSlot *slot, litval; slot = slotRawObject(&block->prototypeFrame)->slots + i; if (vardef->hasExpr(&litval)) hasVarExprs = true; //compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litval); *slot = litval; } } if (funcVarArgs) { //SetNil(&slotRawObject(&block->prototypeFrame)->slots[numArgs]); slotCopy(&slotRawObject(&block->prototypeFrame)->slots[numArgs], &o_emptyarray); } if (numVars) { vardef = mVarlist->mVarDefs; for (i=0; imNext) { PyrSlot *slot, litval; slot = slotRawObject(&block->prototypeFrame)->slots + i + numArgs + funcVarArgs; if (vardef->hasExpr(&litval)) hasVarExprs = true; //compilePyrLiteralNode(vardef->mDefVal, &litval); *slot = litval; } } methraw->methType = methBlock; // compile body initByteCodes(); { SetTailBranch branch(true); /*if (compilingCmdLine) { post("block %d\n", gIsTailCodeBranch); DUMPNODE(mBody, 0); }*/ SetTailIsMethodReturn mr(false); if (hasVarExprs) { if (mArglist) { vardef = mArglist->mVarDefs; for (i=0; imNext) { vardef->compileArg(&dummy); } } if (mVarlist) { vardef = mVarlist->mVarDefs; for (i=0; imNext) { vardef->compile(&dummy); } } } if (mBody->mClassno == pn_BlockReturnNode) { compileOpcode(opPushSpecialValue, opsvNil); } else { COMPILENODE(mBody, &dummy, true); } } compileOpcode(opSpecialOpcode, opcFunctionReturn); installByteCodes(block); if ((!gFunctionCantBeClosed && gFunctionHighestExternalRef == 0) || mIsTopLevel) { SetNil(&block->contextDef); PyrString* string = newPyrStringN(compileGC(), stringLength, flags, false); memcpy(string->s, text+mBeginCharNo, stringLength); SetObject(&block->sourceCode, string); //static int totalLength = 0, totalStrings = 0; //totalLength += stringLength; //totalStrings++; //post("cf %4d %4d %6d %s:%s \n", totalStrings, stringLength, totalLength, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); } gCompilingBlock = prevBlock; gCompilingClass = prevClass; gPartiallyAppliedFunction = prevPartiallyAppliedFunction; gFunctionCantBeClosed = gFunctionCantBeClosed || prevFunctionCantBeClosed; gFunctionHighestExternalRef = sc_max(gFunctionHighestExternalRef - 1, prevFunctionHighestExternalRef); } PyrParseNode* linkNextNode(PyrParseNode* a, PyrParseNode* b) { if (a == NULL) return b; if (b) { a->mTail->mNext = b; a->mTail = b->mTail; } return a; } PyrParseNode* linkAfterHead(PyrParseNode* a, PyrParseNode* b) { b->mNext = a->mNext; if (!a->mNext) a->mTail = b; a->mNext = b; return a; } bool isSuperObjNode(PyrParseNode *node) { return node->mClassno == pn_PushNameNode && slotRawSymbol(&((PyrPushNameNode*)node)->mSlot) == s_super; } bool isThisObjNode(PyrParseNode *node) { return node->mClassno == pn_PushNameNode && slotRawSymbol(&((PyrPushNameNode*)node)->mSlot) == s_this; } int nodeListLength(PyrParseNode *node) { int length = 0; for (; node; node=node->mNext) length++; return length; } int conjureSelectorIndex(PyrParseNode *node, PyrBlock* func, bool isSuper, PyrSymbol *selector, int *selType) { int i; PyrObject *selectors; PyrSlot *slot; int newsize, flags; flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; if (!isSuper) { if (selector == gSpecialSelectors[opmIf]) { *selType = selIf; return opmIf; } else if (selector == gSpecialSelectors[opmWhile]) { *selType = selWhile; return opmWhile; } else if (selector == gSpecialSelectors[opmAnd]) { *selType = selAnd; return opmAnd; } else if (selector == gSpecialSelectors[opmOr]) { *selType = selOr; return opmOr; } else if (selector == gSpecialSelectors[opmCase]) { *selType = selCase; return opmCase; } else if (selector == gSpecialSelectors[opmSwitch]) { *selType = selSwitch; return opmSwitch; } else if (selector == gSpecialSelectors[opmLoop]) { *selType = selLoop; return opmLoop; } else if (selector == gSpecialSelectors[opmQuestionMark]) { *selType = selQuestionMark; return opmAnd; } else if (selector == gSpecialSelectors[opmDoubleQuestionMark]) { *selType = selDoubleQuestionMark; return opmAnd; } else if (selector == gSpecialSelectors[opmExclamationQuestionMark]) { *selType = selExclamationQuestionMark; return opmAnd; } for (i=0; iselectors)) { selectors = slotRawObject(&func->selectors); for (i=0; isize; ++i) { if (IsSym(&selectors->slots[i]) && slotRawSymbol(&selectors->slots[i]) == selector) { *selType = selNormal; return i; } } } else { selectors = (PyrObject*)newPyrArray(compileGC(), 2, flags, false); SetObject(&func->selectors, selectors); } // otherwise add it to the selectors table if (selectors->size+1 >= 256) { error("Selector table too big: too many classes, method selectors or function definitions in this function. Simplify the function.\n"); post("Next selector was: %s\n", selector->name); nodePostErrorLine(node); compileErrors++; return 0; } if (selectors->size+1 > ARRAYMAXINDEXSIZE(selectors)) { // resize literal table newsize = ARRAYMAXINDEXSIZE(selectors) * 2; SetRaw(&func->selectors, (PyrObject*)newPyrArray(compileGC(), newsize, flags, false)); memcpy(slotRawObject(&func->selectors)->slots, selectors->slots, selectors->size * sizeof(PyrSlot)); slotRawObject(&func->selectors)->size = selectors->size; freePyrObject(selectors); selectors = slotRawObject(&func->selectors); } slot = selectors->slots + selectors->size++; SetSymbol(slot, selector); *selType = selNormal; return selectors->size-1; } int conjureLiteralSlotIndex(PyrParseNode *node, PyrBlock* func, PyrSlot *slot) { int i; PyrObject *selectors; PyrSlot *slot2; int newsize, flags; flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; // lookup slot in selectors table if (IsObj(&func->selectors)) { selectors = slotRawObject(&func->selectors); /*if (selectors->classptr != class_array) { post("compiling %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); post("selectors is a '%s'\n", selectors->classptr->name.us->name); dumpObjectSlot(slot); Debugger(); }*/ for (i=0; isize; ++i) if (SlotEq(&selectors->slots[i], slot)) return i; } else { selectors = (PyrObject*)newPyrArray(compileGC(), 4, flags, false); SetObject(&func->selectors, selectors); } // otherwise add it to the selectors table if (selectors->size+1 >= 256) { error("Selector table too big: too many classes, method selectors or function definitions in this function. Simplify the function.\n"); post("Next literal was:\n"); dumpPyrSlot(slot); nodePostErrorLine(node); compileErrors++; return 0; } if (selectors->size+1 > ARRAYMAXINDEXSIZE(selectors)) { // resize literal table newsize = ARRAYMAXINDEXSIZE(selectors) * 2; // resize literal table SetRaw(&func->selectors, (PyrObject*)newPyrArray(compileGC(), newsize, flags, false)); memcpy(slotRawObject(&func->selectors)->slots, selectors->slots, selectors->size * sizeof(PyrSlot)); slotRawObject(&func->selectors)->size = selectors->size; freePyrObject(selectors); selectors = slotRawObject(&func->selectors); } slot2 = selectors->slots + selectors->size++; slotCopy(slot2, slot); return selectors->size-1; } int conjureConstantIndex(PyrParseNode *node, PyrBlock* func, PyrSlot *slot) { int i; PyrObject *constants; int newsize, flags; flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; // lookup slot in constants table if (IsObj(&func->constants)) { constants = slotRawObject(&func->constants); for (i=0; isize; ++i) if (SlotEq(&constants->slots[i], slot)) return i; } else { constants = (PyrObject*)newPyrArray(compileGC(), 4, flags, false); SetObject(&func->constants, constants); } // otherwise add it to the constants table if (constants->size+1 > ARRAYMAXINDEXSIZE(constants)) { // resize literal table newsize = ARRAYMAXINDEXSIZE(constants) * 2; // resize literal table SetRaw(&func->constants, (PyrObject*)newPyrArray(compileGC(), newsize, flags, false)); memcpy(slotRawObject(&func->constants)->slots, constants->slots, constants->size * sizeof(PyrSlot)); slotRawObject(&func->constants)->size = constants->size; freePyrObject((PyrObject*)constants); constants = slotRawObject(&func->constants); } slotCopy(&constants->slots[constants->size++], slot); return constants->size-1; } bool findVarName(PyrBlock* func, PyrClass **classobj, PyrSymbol *name, int *varType, int *level, int *index, PyrBlock** tempfunc) { int i, j, k; int numargs; PyrSymbol *argname, *varname; PyrMethodRaw *methraw; //postfl("->findVarName %s\n", name->name); // find var in enclosing blocks, instance, class if (name == s_super) { gFunctionCantBeClosed = true; name = s_this; } if (name->name[0] >= 'A' && name->name[0] <= 'Z') return false; for (j=0; func; func = slotRawBlock(&func->contextDef), ++j) { methraw = METHRAW(func); numargs = methraw->posargs; for (i=0; iargNames)->symbols[i]; //postfl(" %d %d arg '%s' '%s'\n", j, i, argname->name, name->name); if (argname == name) { *level = j; *index = i; *varType = varTemp; if (tempfunc) *tempfunc = func; if (j > gFunctionHighestExternalRef) gFunctionHighestExternalRef = j; return true; } } for (i=0, k=numargs; inumvars; ++i,++k) { varname = slotRawSymbolArray(&func->varNames)->symbols[i]; //postfl(" %d %d %d var '%s' '%s'\n", j, i, k, varname->name, name->name); if (varname == name) { *level = j; *index = k; *varType = varTemp; if (tempfunc) *tempfunc = func; if (j > gFunctionHighestExternalRef) gFunctionHighestExternalRef = j; return true; } } } if (classFindInstVar(*classobj, name, index)) { *level = 0; *varType = varInst; if (gCompilingClass != class_interpreter) gFunctionCantBeClosed = true; return true; } if (classFindClassVar(classobj, name, index)) { *varType = varClass; if (gCompilingClass != class_interpreter) gFunctionCantBeClosed = true; return true; } if (classFindConst(classobj, name, index)) { *varType = varConst; //if (gCompilingClass != class_interpreter) gFunctionCantBeClosed = true; return true; } if (name == s_curProcess) { *varType = varPseudo; *index = opgProcess; return true; } if (name == s_curThread) { *varType = varPseudo; *index = opgThread; return true; } if (name == s_curMethod) { *varType = varPseudo; *index = opgMethod; return true; } if (name == s_curBlock) { *varType = varPseudo; *index = opgFunctionDef; return true; } if (name == s_curClosure) { *varType = varPseudo; *index = opgFunction; return true; } return false; } extern PyrSymbol *s_env; void initSpecialClasses() { gSpecialClasses[op_class_object] = s_object; gSpecialClasses[op_class_symbol] = s_symbol; gSpecialClasses[op_class_nil] = s_nil; gSpecialClasses[op_class_boolean] = s_boolean; gSpecialClasses[op_class_true] = s_true; gSpecialClasses[op_class_false] = s_false; gSpecialClasses[op_class_magnitude] = s_magnitude; gSpecialClasses[op_class_char] = s_char; gSpecialClasses[op_class_number] = s_number; gSpecialClasses[op_class_complex] = s_complex; gSpecialClasses[op_class_simple_number] = s_simple_number; gSpecialClasses[op_class_int] = s_int; gSpecialClasses[op_class_float] = s_float; gSpecialClasses[op_class_method] = s_method; gSpecialClasses[op_class_fundef] = s_fundef; gSpecialClasses[op_class_stream] = s_stream; gSpecialClasses[op_class_func] = s_func; gSpecialClasses[op_class_frame] = s_frame; gSpecialClasses[op_class_process] = s_process; gSpecialClasses[op_class_main] = s_main; gSpecialClasses[op_class_class] = s_class; gSpecialClasses[op_class_string] = s_string; gSpecialClasses[op_class_collection] = s_collection; gSpecialClasses[op_class_sequenceable_collection] = s_sequenceable_collection; gSpecialClasses[op_class_arrayed_collection] = s_arrayed_collection; gSpecialClasses[op_class_array] = s_array; gSpecialClasses[op_class_int8array] = s_int8array; gSpecialClasses[op_class_int16array] = s_int16array; gSpecialClasses[op_class_int32array] = s_int32array; gSpecialClasses[op_class_floatarray] = s_floatarray; gSpecialClasses[op_class_signal] = s_signal; gSpecialClasses[op_class_doublearray] = s_doublearray; gSpecialClasses[op_class_symbolarray] = s_symbolarray; gSpecialClasses[op_class_list] = s_list; gSpecialClasses[op_class_linkedlist] = s_linkedlist; gSpecialClasses[op_class_bag] = s_bag; gSpecialClasses[op_class_set] = s_set; gSpecialClasses[op_class_identityset] = s_identityset; gSpecialClasses[op_class_dictionary] = s_dictionary; gSpecialClasses[op_class_identitydictionary] = s_identitydictionary; gSpecialClasses[op_class_sortedlist] = s_sortedlist; gSpecialClasses[op_class_synth] = s_synth; gSpecialClasses[op_class_ref] = s_ref; gSpecialClasses[op_class_environment] = s_environment; gSpecialClasses[op_class_event] = s_event; gSpecialClasses[op_class_wavetable] = s_wavetable; gSpecialClasses[op_class_env] = s_env; gSpecialClasses[op_class_routine] = s_routine; gSpecialClasses[op_class_color] = s_color; gSpecialClasses[op_class_rect] = s_rect; //Infinitum, Point, Rect, ?? } void initSpecialSelectors() { PyrSymbol **sel; long i; sel = gSpecialUnarySelectors; sel[opNeg] = getsym("neg"); sel[opRecip] = getsym("reciprocal"); sel[opNot] = getsym("not"); sel[opIsNil] = getsym("isNil"); sel[opNotNil] = getsym("notNil"); sel[opBitNot] = getsym("bitNot"); sel[opAbs] = getsym("abs"); sel[opAsFloat] = getsym("asFloat"); sel[opAsInt] = getsym("asInt"); sel[opCeil] = getsym("ceil"); //5 sel[opFloor] = getsym("floor"); sel[opFrac] = getsym("frac"); sel[opSign] = getsym("sign"); sel[opSquared] = getsym("squared"); sel[opCubed] = getsym("cubed"); //10 sel[opSqrt] = getsym("sqrt"); sel[opExp] = getsym("exp"); sel[opMIDICPS] = getsym("midicps"); sel[opCPSMIDI] = getsym("cpsmidi"); sel[opMIDIRatio] = getsym("midiratio"); sel[opRatioMIDI] = getsym("ratiomidi"); sel[opAmpDb] = getsym("ampdb"); //15 sel[opDbAmp] = getsym("dbamp"); sel[opOctCPS] = getsym("octcps"); sel[opCPSOct] = getsym("cpsoct"); sel[opLog] = getsym("log"); sel[opLog2] = getsym("log2"); //20 sel[opLog10] = getsym("log10"); sel[opSin] = getsym("sin"); sel[opCos] = getsym("cos"); sel[opTan] = getsym("tan"); sel[opArcSin] = getsym("asin"); //25 sel[opArcCos] = getsym("acos"); sel[opArcTan] = getsym("atan"); sel[opSinH] = getsym("sinh"); sel[opCosH] = getsym("cosh"); sel[opTanH] = getsym("tanh"); //30 sel[opRand] = getsym("rand"); sel[opRand2] = getsym("rand2"); sel[opLinRand] = getsym("linrand"); sel[opBiLinRand] = getsym("bilinrand"); sel[opSum3Rand] = getsym("sum3rand"); /* sel[opExpRand] = getsym("exprand"); sel[opBiExpRand] = getsym("biexprand"); sel[opGammaRand] = getsym("gammarand"); sel[opGaussRand] = getsym("gaussrand"); sel[opPoiRand] = getsym("poirand"); */ sel[opDistort] = getsym("distort"); sel[opSoftClip] = getsym("softclip"); sel[opCoin] = getsym("coin"); sel[opRectWindow] = getsym("rectWindow"); sel[opHanWindow] = getsym("hanWindow"); sel[opWelchWindow] = getsym("welWindow"); sel[opTriWindow] = getsym("triWindow"); sel[opSCurve] = getsym("scurve"); sel[opRamp] = getsym("ramp"); sel[opDigitValue] = getsym("digitValue"); sel[opSilence] = getsym("silence"); sel[opThru] = getsym("thru"); sel = gSpecialBinarySelectors; sel[opAdd] = getsym("+"); sel[opSub] = getsym("-"); sel[opMul] = getsym("*"); sel[opFDiv] = getsym("/"); sel[opIDiv] = getsym("div"); sel[opMod] = getsym("mod"); sel[opEQ] = getsym("=="); sel[opNE] = getsym("!="); sel[opLT] = getsym("<"); sel[opGT] = getsym(">"); sel[opLE] = getsym("<="); sel[opGE] = getsym(">="); //sel[opIdentical] = getsym("==="); //sel[opNotIdentical] = getsym("!=="); sel[opMin] = getsym("min"); sel[opMax] = getsym("max"); sel[opBitAnd] = getsym("bitAnd"); sel[opBitOr] = getsym("bitOr"); sel[opBitXor] = getsym("bitXor"); sel[opLCM] = getsym("lcm"); sel[opGCD] = getsym("gcd"); sel[opRound] = getsym("round"); sel[opRoundUp] = getsym("roundUp"); sel[opTrunc] = getsym("trunc"); sel[opAtan2] = getsym("atan2"); sel[opHypot] = getsym("hypot"); sel[opHypotx] = getsym("hypotApx"); sel[opPow] = getsym("pow"); sel[opShiftLeft] = getsym("leftShift"); sel[opShiftRight] = getsym("rightShift"); sel[opUnsignedShift] = getsym("unsignedRightShift"); sel[opFill] = getsym("fill"); sel[opRing1] = getsym("ring1"); // a * (b + 1) == a * b + a sel[opRing2] = getsym("ring2"); // a * b + a + b sel[opRing3] = getsym("ring3"); // a*a*b sel[opRing4] = getsym("ring4"); // a*a*b - a*b*b sel[opDifSqr] = getsym("difsqr"); // a*a - b*b sel[opSumSqr] = getsym("sumsqr"); // a*a + b*b sel[opSqrSum] = getsym("sqrsum"); // (a + b)^2 sel[opSqrDif] = getsym("sqrdif"); // (a - b)^2 sel[opAbsDif] = getsym("absdif"); // sel[opThresh] = getsym("thresh"); // sel[opAMClip] = getsym("amclip"); // sel[opScaleNeg] = getsym("scaleneg"); // sel[opClip2] = getsym("clip2"); sel[opFold2] = getsym("fold2"); sel[opWrap2] = getsym("wrap2"); sel[opExcess] = getsym("excess"); sel[opFirstArg] = getsym("firstArg"); sel[opRandRange] = getsym("rrand"); sel[opExpRandRange] = getsym("exprand"); sel = gSpecialSelectors; sel[opmNew] = getsym("new"); sel[opmNewClear] = getsym("newClear"); sel[opmNewCopyArgs] = getsym("newCopyArgs"); sel[opmInit] = getsym("init"); sel[opmAt] = getsym("at"); sel[opmPut] = getsym("put"); sel[opmNext] = getsym("next"); sel[opmReset] = getsym("reset"); sel[opmValue] = getsym("value"); sel[opmCopyToEnd] = getsym("copyToEnd"); // used by multiple assignment //sel[opmIsNil] = getsym("isNil"); //sel[opmNotNil] = getsym("notNil"); sel[opmSize] = getsym("size"); sel[opmClass] = getsym("class"); sel[opmIf] = getsym("if"); sel[opmWhile] = getsym("while"); sel[opmFor] = getsym("for"); sel[opmAnd] = getsym("and"); sel[opmOr] = getsym("or"); sel[opmCase] = getsym("case"); sel[opmSwitch] = getsym("switch"); sel[opmIdentical] = getsym("==="); sel[opmNotIdentical] = getsym("!=="); sel[opmPrint] = getsym("print"); sel[opmAdd] = getsym("add"); sel[opmRemove] = getsym("remove"); sel[opmIndexOf] = getsym("indexOf"); sel[opmWrapAt] = getsym("wrapAt"); sel[opmClipAt] = getsym("clipAt"); sel[opmFoldAt] = getsym("foldAt"); sel[opmWrapPut] = getsym("wrapPut"); sel[opmClipPut] = getsym("clipPut"); sel[opmFoldPut] = getsym("foldPut"); sel[opmDo] = getsym("do"); sel[opmCollect] = getsym("collect"); sel[opmSelect] = getsym("select"); sel[opmReject] = getsym("reject"); sel[opmAny] = getsym("any"); sel[opmEvery] = getsym("every"); sel[opmFind] = getsym("find"); sel[opmChoose] = getsym("choose"); sel[opmValueList] = getsym("valueList"); sel[opmAddFirst] = getsym("addFirst"); sel[opmPrimitiveFailed] = getsym("primitiveFailed"); sel[opmSubclassResponsibility] = getsym("subclassResponsibility"); sel[opmShouldNotImplement] = getsym("shouldNotImplement"); sel[opmDoesNotUnderstand] = getsym("doesNotUnderstand"); // not really needed sel[opmNotYetImplemented] = getsym("notYetImplemented"); sel[opmAtSign] = getsym("@"); sel[opmWrapAtSign] = getsym("@@"); sel[opmClipAtSign] = getsym("|@|"); sel[opmFoldAtSign] = getsym("@|@"); sel[opmMultiNew] = getsym("multiNew"); // UGens sel[opmMultiNewList] = getsym("multiNewList"); // UGens sel[opmAR] = getsym("ar"); // UGens sel[opmKR] = getsym("kr"); // UGens sel[opmIR] = getsym("ir"); // UGens sel[opmEnvirGet] = getsym("envirGet"); sel[opmEnvirPut] = getsym("envirPut"); sel[opmHalt] = getsym("halt"); sel[opmForBy] = getsym("forBy"); sel[opmForSeries] = getsym("forSeries"); sel[opmReverseDo] = getsym("reverseDo"); sel[opmLoop] = getsym("loop"); sel[opmNonBooleanError] = getsym("mustBeBoolean"); sel[opmCopy] = getsym("copy"); sel[opmPerformList] = getsym("performList"); sel[opmIsKindOf] = getsym("isKindOf"); sel[opmPostln] = getsym("postln"); sel[opmAsString] = getsym("asString"); sel[opmPlusPlus] = getsym("++"); sel[opmLTLT] = getsym("<<"); sel[opmQuestionMark] = getsym("?"); sel[opmDoubleQuestionMark] = getsym("??"); sel[opmExclamationQuestionMark] = getsym("!?"); sel[opmYield] = getsym("yield"); sel[opmName] = getsym("name"); sel[opmMulAdd] = getsym("madd"); sel[opmSeries] = getsym("series"); for (i=0; ispecialIndex = i; } for (i=0; ispecialIndex = i; } } bool findSpecialClassName(PyrSymbol *className, int *index) { int i; for (i=0; i #include "InitAlloc.h" #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #import #import #import #import #import #import //comment the following line to use cocoa speech #define useCarbonSpeech ///////////////////// const int kMaxSpeechChannels = 32; PyrSymbol * s_speech; PyrSymbol * s_speechwordAction; PyrSymbol * s_speechdoneAction; #ifdef useCarbonSpeech SpeechChannel fCurSpeechChannel[kMaxSpeechChannels]; char *speechStrings[kMaxSpeechChannels]; #else //NSSpeechSynthesizer* speechSynths[kMaxSpeechChannels]; NSArray * speechSynthsArray; #endif pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon ); pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon ) { //call action here; // post("text done"); #ifdef useCarbonSpeech pthread_mutex_lock (&gLangMutex); VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, s_speech->u.classobj); // Set the class //set arguments: ++g->sp;SetInt(g->sp, (int) inRefCon); //src runInterpreter(g, s_speechdoneAction, 2); if(speechStrings[(int) inRefCon] != NULL){ free(speechStrings[(int) inRefCon]); speechStrings[(int) inRefCon] = NULL; } g->canCallOS = false; pthread_mutex_unlock (&gLangMutex); #endif } pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen); pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen) { //post("word done"); #ifdef useCarbonSpeech pthread_mutex_lock (&gLangMutex); VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, s_speech->u.classobj); //set arguments: ++g->sp; SetInt(g->sp, (int) inRefCon); //src runInterpreter(g, s_speechwordAction, 2); g->canCallOS = false; pthread_mutex_unlock (&gLangMutex); #endif } int prInitSpeech(struct VMGlobals *g, int numArgsPushed); int prInitSpeech(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-1; PyrSlot *b = g->sp; int chan; slotIntVal(b, &chan); if (chan < 0 || chan >= kMaxSpeechChannels) return errIndexOutOfRange; #ifdef useCarbonSpeech for (int i=0; isp-1; PyrSlot *str = g->sp; int chan; slotIntVal(a, &chan); chan = sc_clip(chan, 0, kMaxSpeechChannels); #ifdef useCarbonSpeech chan = sc_clip(chan, 0, kMaxSpeechChannels); if(speechStrings[chan] != NULL) { post("voice %i already speaking\n", chan); return errNone; } else { // speechStrings[chan] = (char*)pyr_pool_compile->Alloc((a->uo->size + 1)* sizeof(char)); speechStrings[chan] = (char*) malloc((slotRawObject(str)->size + 1)* sizeof(char)); MEMFAIL(speechStrings[chan]); slotStrVal(str, speechStrings[chan], slotRawObject(str)->size+1); //if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SpeakText( fCurSpeechChannel[chan], speechStrings[chan], strlen(speechStrings[chan])); } #else // pthread_mutex_lock (&gLangMutex); NSAutoreleasePool *autoreleasepool= [[NSAutoreleasePool alloc] init]; NSSpeechSynthesizer * spsynth = [speechSynthsArray objectAtIndex: chan]; char cstr [str->uo->size+1]; slotStrVal(str, cstr, str->uo->size+1); // if([spsynth isSpeaking]) [spsynth stopSpeaking]; // NSString * nsstring = [NSString stringWithCString: cstr encoding: NSASCIIStringEncoding]; [spsynth startSpeakingString: [NSString stringWithCString: cstr encoding: NSASCIIStringEncoding]]; // [nsstring release]; // [nsstring release]; [autoreleasepool release]; // pthread_mutex_unlock (&gLangMutex); #endif return errNone; } int prSetSpeechRate(struct VMGlobals *g, int numArgsPushed); int prSetSpeechRate(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); #ifdef useCarbonSpeech Fixed newRate = (Fixed)(val * 65536.0); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soRate, &newRate); #else // NSSpeechSynthesizer * spsynth = speechSynths[chan]; // if(!spsynth) return errNone; // [spsynth setRate: val]; #endif return errNone; } int prSetSpeechPitch(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPitch(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); #ifdef useCarbonSpeech Fixed newVal = (Fixed)(val * 65536.0); //if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechPitch (fCurSpeechChannel[chan], newVal); #else NSSpeechSynthesizer * spsynth = [speechSynthsArray objectAtIndex: chan]; NSError * err; if(!spsynth) return errNone; // 10.5 only ... ;-( // [spsynth setObject: val forProperty: NSSpeechPitchBaseProperty error: &err]; #endif return errNone; } int prSetSpeechPitchMod(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPitchMod(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); #ifdef useCarbonSpeech Fixed newVal = (Fixed)(val * 65536.0); // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soPitchMod, &newVal); #endif return errNone; } int prSetSpeechVolume(struct VMGlobals *g, int numArgsPushed); int prSetSpeechVolume(struct VMGlobals *g, int numArgsPushed) { OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); #ifdef useCarbonSpeech Fixed newVal = (Fixed)(val * 65536.0); // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soVolume, &newVal); #else // 10.5 :-( // NSSpeechSynthesizer * spsynth = speechSynths[chan]; // if(!spsynth) return errNone; // [spsynth setVolume: val]; #endif return errNone; } // theErr = PauseSpeechAt (fCurSpeechChannel, kImmediate); // theErr = ContinueSpeech (fCurSpeechChannel); int prSetSpeechPause(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPause(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int val; int chan; slotIntVal(b, &chan); slotIntVal(c, &val); #ifdef useCarbonSpeech if(val) { theErr = ContinueSpeech(fCurSpeechChannel[chan] ); } else { theErr = PauseSpeechAt(fCurSpeechChannel[chan], kImmediate); } #else // NSSpeechSynthesizer * spsynth = speechSynths[chan]; // if(!spsynth) return errNone; // [spsynth setRate: val]; #endif return errNone; } int prSetSpeechStop(struct VMGlobals *g, int numArgsPushed); int prSetSpeechStop(struct VMGlobals *g, int numArgsPushed){ //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int selector [3] = {kImmediate, kEndOfWord, kEndOfWord}; int val; int chan; slotIntVal(b, &chan); slotIntVal(c, &val); #ifdef useCarbonSpeech StopSpeechAt(fCurSpeechChannel[chan], selector[val]); if(speechStrings[chan] != NULL) { free(speechStrings[chan]); speechStrings[chan] = NULL; } #else NSSpeechSynthesizer * spsynth = [speechSynthsArray objectAtIndex: chan]; if(!spsynth) return errNone; [spsynth stopSpeaking]; #endif return errNone; } int prSetSpeechVoice(struct VMGlobals *g, int numArgsPushed); int prSetSpeechVoice(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int val; int chan; slotIntVal(b, &chan); slotIntVal(c, &val); #ifdef useCarbonSpeech VoiceSpec theVoiceSpec; theErr = GetIndVoice (val, &theVoiceSpec); if (SetSpeechInfo (fCurSpeechChannel[chan], soCurrentVoice, &theVoiceSpec) == incompatibleVoice) return (!errNone); #else NSSpeechSynthesizer * spsynth = [speechSynthsArray objectAtIndex: chan]; if(!spsynth) return errNone; [spsynth setVoice: [[NSSpeechSynthesizer availableVoices] objectAtIndex: val]]; #endif return errNone; } #ifndef useCarbonSpeech int prGetSpeechVoiceNames(struct VMGlobals *g, int numArgsPushed); int prGetSpeechVoiceNames(struct VMGlobals *g, int numArgsPushed){ PyrSlot *a = g->sp-1; PyrSlot *b = g->sp; NSAutoreleasePool *autoreleasepool= [[NSAutoreleasePool alloc] init]; NSString * aVoice = NULL; NSEnumerator * voiceEnumerator = [[NSSpeechSynthesizer availableVoices] objectEnumerator]; PyrObject* allVoices = newPyrArray(g->gc, (int) [[NSSpeechSynthesizer availableVoices] count] * sizeof(PyrObject), 0 , true); while(aVoice = [voiceEnumerator nextObject]) { NSDictionary * dictionaryOfVoiceAttributes = [NSSpeechSynthesizer attributesForVoice:aVoice]; NSString * voiceDisplayName = [dictionaryOfVoiceAttributes objectForKey:NSVoiceName]; PyrString *namestring = newPyrString(g->gc, [voiceDisplayName cStringUsingEncoding:[NSString defaultCStringEncoding]], 0, true); SetObject(allVoices->slots+allVoices->size++, namestring); g->gc->GCWrite(allVoices, (PyrObject*) namestring); } [autoreleasepool release]; SetObject(a, allVoices); return errNone; } #endif int prSpeechVoiceIsSpeaking(struct VMGlobals *g, int numArgsPushed); int prSpeechVoiceIsSpeaking(struct VMGlobals *g, int numArgsPushed){ PyrSlot *out = g->sp-1; PyrSlot *b = g->sp; int chan; slotIntVal(b, &chan); #ifdef useCarbonSpeech if(speechStrings[chan] != NULL) SetTrue(out); else SetFalse(out); #else NSSpeechSynthesizer * spsynth = [speechSynthsArray objectAtIndex: chan]; if(!spsynth) return errNone; if([spsynth isSpeaking]) SetTrue(out); else SetFalse(out); #endif return errNone; } void initSpeechPrimitives () { int base, index; base = nextPrimitiveIndex(); index = 0; s_speechwordAction = getsym("doWordAction"); s_speechdoneAction = getsym("doSpeechDoneAction"); s_speech = getsym("Speech"); definePrimitive(base, index++, "_SpeakText", prSpeakText, 3, 0); definePrimitive(base, index++, "_InitSpeech", prInitSpeech, 2, 0); definePrimitive(base, index++, "_SetSpeechRate", prSetSpeechRate, 3, 0); definePrimitive(base, index++, "_SetSpeechPitch", prSetSpeechPitch, 3, 0); definePrimitive(base, index++, "_SetSpeechPitchMod", prSetSpeechPitchMod, 3, 0); definePrimitive(base, index++, "_SetSpeechVoice", prSetSpeechVoice, 3, 0); definePrimitive(base, index++, "_SetSpeechVolume", prSetSpeechVolume, 3, 0); definePrimitive(base, index++, "_SetSpeechPause", prSetSpeechPause, 3, 0); //0 pause, 1 continue definePrimitive(base, index++, "_SetSpeechStopAt", prSetSpeechStop, 3, 0); //0 kImmediate, 1 kEndOfWord, 2 kEndOfSentence definePrimitive(base, index++, "_SpeechVoiceIsSpeaking", prSpeechVoiceIsSpeaking, 2, 0); #ifndef useCarbonSpeech definePrimitive(base, index++, "_GetSpeechVoiceNames", prGetSpeechVoiceNames, 2, 0); #endif #ifdef useCarbonSpeech for(int i=0; isp; PyrArchiver arch(g); int err = arch.prepareToWriteArchive(a); if (err) return err; int32 size = arch.calcArchiveSize(); PyrInt8Array *obj = newPyrInt8Array(g->gc, size, 0, true); obj->size = size; arch.setStream((char*)obj->b); err = arch.writeArchive(); if (err == errNone) SetObject(a, obj); else SetNil(a); return err; } int prUnarchive(struct VMGlobals *g, int numArgsPushed); int prUnarchive(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (!isKindOfSlot(a, class_int8array)) return errWrongType; PyrArchiver arch(g); arch.setStream((char*)slotRawObject(a)->slots); int err = arch.readArchive(a); return err; } int prWriteArchive(struct VMGlobals *g, int numArgsPushed); int prWriteArchive(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (!isKindOfSlot(b, class_string)) return errWrongType; char pathname[PATH_MAX]; memcpy(pathname, slotRawString(b)->s, slotRawObject(b)->size); pathname[slotRawString(b)->size] = 0; PyrArchiver arch(g); FILE *file = fopen(pathname, "wb"); int err = errNone; if (file) { err = arch.prepareToWriteArchive(a); if (!err) { arch.setStream(file); err = arch.writeArchive(); } fclose(file); } else { error("file open failed\n"); err = errFailed; } return err; } int prReadArchive(struct VMGlobals *g, int numArgsPushed); int prReadArchive(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (!isKindOfSlot(b, class_string)) return errWrongType; char pathname[PATH_MAX]; memcpy(pathname, slotRawString(b)->s, slotRawObject(b)->size); pathname[slotRawString(b)->size] = 0; PyrArchiver arch(g); FILE *file = fopen(pathname, "rb"); int err; if (file) { arch.setStream(file); err = arch.readArchive(a); fclose(file); } else { error("file open failed\n"); err = errFailed; } return err; } void initArchiverPrimitives(); void initArchiverPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_AsArchive", prAsArchive, 1, 0); definePrimitive(base, index++, "_Unarchive", prUnarchive, 1, 0); definePrimitive(base, index++, "_WriteArchive", prWriteArchive, 2, 0); definePrimitive(base, index++, "_ReadArchive", prReadArchive, 2, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" // export the function that SC will call to load the plug in. #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initArchiverPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/SC_ComPort.cpp0000664000000000000000000004426212245365552025271 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_BoundsMacros.h" #include "SC_ComPort.h" #include "SC_Endian.h" #include #include #include #include "SCBase.h" #include #ifndef SC_WIN32 # include #else #include "SC_Win32Utils.h" #endif #ifdef __linux__ # include #endif #ifdef __FreeBSD__ # include #endif #if defined(SC_DARWIN) || defined(SC_IPHONE) #include #endif // sk: determine means of blocking SIGPIPE for send(2) (implementation // dependent) #define HAVE_SO_NOSIGPIPE 0 #define HAVE_MSG_NOSIGNAL 0 #if defined(SO_NOSIGPIPE) # undef HAVE_SO_NOSIGPIPE # define HAVE_SO_NOSIGPIPE 1 #elif defined(MSG_NOSIGNAL) # undef HAVE_MSG_NOSIGNAL # define HAVE_MSG_NOSIGNAL 1 #endif int recvall(int socket, void *msg, size_t len); int recvallfrom(int socket, void *msg, size_t len, struct sockaddr *fromaddr, int addrlen); int sendallto(int socket, const void *msg, size_t len, struct sockaddr *toaddr, int addrlen); int sendall(int socket, const void *msg, size_t len); void ProcessOSCPacket(OSC_Packet *inPacket, int inPortNum); static void dumpOSCmsg(int inSize, char* inData) { int size; const char *data; if (inData[0]) { char *addr = inData; data = OSCstrskip(inData); size = inSize - (data - inData); printf("[ \"%s\",", addr); } else { printf("[ %d,", OSCint(inData)); data = inData + 4; size = inSize - 4; } sc_msg_iter msg(size, data); while (msg.remain()) { char c = msg.nextTag('i'); switch(c) { case 'i' : printf(" %d", msg.geti()); break; case 'f' : printf(" %g", msg.getf()); break; case 'd' : printf(" %g", msg.getd()); break; case 's' : printf(" \"%s\"", msg.gets()); break; case 'b' : printf(" DATA[%zu]", msg.getbsize()); msg.skipb(); break; default : printf(" !unknown tag '%c' 0x%02x !", isprint(c)?c:'?', (unsigned char)c & 255); goto leave; } if (msg.remain()) printf(","); } leave: printf(" ]"); } static void hexdump(int size, char* data) { char ascii[20]; int padsize = (size + 15) & -16; printf("size %d\n", size); for (int i=0; i= size) { printf(" "); ascii[i&15] = 0; } else { printf("%02x ", (unsigned char)data[i] & 255); if (isprint(data[i])) ascii[i&15] = data[i]; else ascii[i&15] = '.'; } if ((i&15)==15) { ascii[16] = 0; printf(" |%s|\n", ascii); } else if ((i&3)==3) { printf(" "); } } printf("\n"); } void dumpOSC(int mode, int size, char* inData) { if (mode & 1) { if (strcmp(inData, "#bundle") == 0) { char* data = inData + 8; printf("[ \"#bundle\", %lld, ", OSCtime(data)); data += 8; char* dataEnd = inData + size; while (data < dataEnd) { int32 msgSize = OSCint(data); data += sizeof(int32); printf("\n "); dumpOSCmsg(msgSize, data); data += msgSize; if (data < dataEnd) printf(","); } printf("\n]\n"); } else { dumpOSCmsg(size, inData); printf("\n"); } } if (mode & 2) hexdump(size, inData); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_CmdPort::SC_CmdPort() { } SC_CmdPort::~SC_CmdPort() { } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_ComPort::SC_ComPort(int inPortNum) : mPortNum(inPortNum), mSocket(-1) { } SC_ComPort::~SC_ComPort() { #ifdef SC_WIN32 if (mSocket != -1) closesocket(mSocket); #else if (mSocket != -1) close(mSocket); #endif } static void* com_thread_func(void* arg) { SC_CmdPort *thread = (SC_CmdPort*)arg; void* result = thread->Run(); return result; } void SC_CmdPort::Start() { pthread_create (&mThread, NULL, com_thread_func, (void*)this); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_UdpInPort::SC_UdpInPort(int inPortNum) : SC_ComPort(inPortNum) { if ((mSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { throw std::runtime_error("failed to create udp socket\n"); } { int bufsize = 65536; #ifdef SC_WIN32 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize)); #else setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); #endif } bzero((char *)&mBindSockAddr, sizeof(mBindSockAddr)); mBindSockAddr.sin_family = AF_INET; mBindSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); bool bound = false; for (int i=0; i<10 && !bound; ++i) { mPortNum = mPortNum+i; mBindSockAddr.sin_port = htons(mPortNum); if (bind(mSocket, (struct sockaddr *)&mBindSockAddr, sizeof(mBindSockAddr)) >= 0) { bound = true; } } if (!bound) throw std::runtime_error("unable to bind udp socket\n"); Start(); } SC_UdpInPort::~SC_UdpInPort() { #ifdef SC_WIN32 if (mSocket != -1) closesocket(mSocket); #else if (mSocket != -1) close(mSocket); #endif } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_UdpCustomInPort::SC_UdpCustomInPort(int inPortNum) : SC_ComPort(inPortNum) { if ((mSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { throw std::runtime_error("failed to create udp socket\n"); } { int bufsize = 65536; #ifdef SC_WIN32 setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize)); #else setsockopt(mSocket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); #endif } bzero((char *)&mBindSockAddr, sizeof(mBindSockAddr)); mBindSockAddr.sin_family = AF_INET; mBindSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); bool bound = false; mBindSockAddr.sin_port = htons(mPortNum); if (bind(mSocket, (struct sockaddr *)&mBindSockAddr, sizeof(mBindSockAddr)) >= 0) { bound = true; } if (!bound) throw std::runtime_error("unable to bind udp socket\n"); Start(); } SC_UdpCustomInPort::~SC_UdpCustomInPort() { mRunning.store(false); pthread_join(mThread, NULL); #ifdef SC_WIN32 if (mSocket != -1) closesocket(mSocket); #else if (mSocket != -1) close(mSocket); #endif } ////////////////////////////////////////////////////////////////////////////////////////////////////////// static void DumpReplyAddress(ReplyAddress *inReplyAddress) { printf("mSockAddrLen %d\n", inReplyAddress->mSockAddrLen); printf("mSocket %d\n", inReplyAddress->mSocket); #ifdef SC_DARWIN printf("mSockAddr.sin_len %d\n", inReplyAddress->mSockAddr.sin_len); #endif printf("mSockAddr.sin_family %d\n", inReplyAddress->mSockAddr.sin_family); printf("mSockAddr.sin_port %d\n", inReplyAddress->mSockAddr.sin_port); printf("mSockAddr.sin_addr.s_addr %d\n", inReplyAddress->mSockAddr.sin_addr.s_addr); printf("mReplyFunc %p\n", inReplyAddress->mReplyFunc); } /* int32 Hash(ReplyAddress *inReplyAddress) { int32 hash; int32 *word = (int32*)&inReplyAddress->mSockAddr; hash = Hash(inReplyAddress->mSockAddr.sin_addr.s_addr); hash += inReplyAddress->mSockAddr.sin_len << 24 | inReplyAddress->mSockAddr.sin_family << 16 | inReplyAddress->mSockAddr.sin_port; hash = Hash(hash); return hash; } */ void udp_reply_func(struct ReplyAddress *addr, char* msg, int size); void udp_reply_func(struct ReplyAddress *addr, char* msg, int size) { printf("->udp_reply_func\n"); int total = sendallto(addr->mSocket, msg, size, (sockaddr*)&addr->mSockAddr, addr->mSockAddrLen); printf("<-udp_reply_func %d of %d\n", total, size); if (total < size) DumpReplyAddress(addr); } ReplyFunc SC_UdpInPort::GetReplyFunc() { return udp_reply_func; } void* SC_UdpInPort::Run() { OSC_Packet *packet = 0; //printf("SC_UdpInPort::Run\n"); fflush(stdout); while (true) { if (!packet) { packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); } packet->mReplyAddr.mSockAddrLen = sizeof(sockaddr_in); int size = recvfrom(mSocket, buf, kTextBufSize , 0, (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen); if (size > 0) { //dumpOSC(3, size, buf); //fflush(stdout); char *data = (char*)malloc(size); packet->mReplyAddr.mReplyFunc = udp_reply_func; packet->mSize = size; packet->mData = data; packet->mReplyAddr.mSocket = mSocket; memcpy(data, buf, size); ProcessOSCPacket(packet, mPortNum); packet = 0; } } return 0; } ReplyFunc SC_UdpCustomInPort::GetReplyFunc() { return udp_reply_func; } void* SC_UdpCustomInPort::Run() { OSC_Packet *packet = 0; const int fd = mSocket; const int max_fd = fd+1; mRunning.store(true); while (mRunning.load(boost::memory_order_consume)) { fd_set rfds; FD_ZERO( &rfds); FD_SET(fd, &rfds); struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 500000; int n = select(max_fd, &rfds, 0, 0, &timeout); if ((n > 0) && FD_ISSET(fd, &rfds)) { if (!packet) { packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); } packet->mReplyAddr.mSockAddrLen = sizeof(sockaddr_in); int size = recvfrom(mSocket, buf, kTextBufSize , 0, (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen); if (size > 0 && mRunning.load(boost::memory_order_consume)) { //dumpOSC(3, size, buf); //fflush(stdout); char *data = (char*)malloc(size); packet->mReplyAddr.mReplyFunc = udp_reply_func; packet->mSize = size; packet->mData = data; packet->mReplyAddr.mSocket = mSocket; memcpy(data, buf, size); ProcessOSCPacket(packet, mPortNum); packet = 0; } } } FreeOSCPacket(packet); // just in case return 0; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_TcpInPort::SC_TcpInPort(int inPortNum, int inMaxConnections, int inBacklog) : SC_ComPort(inPortNum), mConnectionAvailable(inMaxConnections), mBacklog(inBacklog) { if((mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { throw std::runtime_error("failed to create tcp socket\n"); } //setsockopt(mSocket, SOL_SOCKET, TCP_NODELAY); bzero((char *)&mBindSockAddr, sizeof(mBindSockAddr)); mBindSockAddr.sin_family = AF_INET; mBindSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); mBindSockAddr.sin_port = htons(mPortNum); if(bind(mSocket, (struct sockaddr *)&mBindSockAddr, sizeof(mBindSockAddr)) < 0) { throw std::runtime_error("unable to bind tcp socket\n"); } if(listen(mSocket, mBacklog) < 0) { throw std::runtime_error("unable to listen tcp socket\n"); } Start(); } void* SC_TcpInPort::Run() { while (true) { mConnectionAvailable.Acquire(); struct sockaddr_in address; /* Internet socket address stuct */ int addressSize=sizeof(struct sockaddr_in); int socket = accept(mSocket,(struct sockaddr*)&address,(socklen_t*)&addressSize); if (socket < 0) { mConnectionAvailable.Release(); } else { new SC_TcpConnectionPort(this, socket); } } return 0; } void SC_TcpInPort::ConnectionTerminated() { mConnectionAvailable.Release(); } ReplyFunc SC_TcpInPort::GetReplyFunc() { return null_reply_func; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_TcpConnectionPort::SC_TcpConnectionPort(SC_TcpInPort *inParent, int inSocket) : SC_ComPort(0), mParent(inParent) { mSocket = inSocket; Start(); } SC_TcpConnectionPort::~SC_TcpConnectionPort() { #ifdef SC_WIN32 closesocket(mSocket); #else close(mSocket); #endif mParent->ConnectionTerminated(); } void tcp_reply_func(struct ReplyAddress *addr, char* msg, int size); void tcp_reply_func(struct ReplyAddress *addr, char* msg, int size) { sendall(addr->mSocket, msg, size); } ReplyFunc SC_TcpConnectionPort::GetReplyFunc() { return tcp_reply_func; } extern const char* gPassword; void* SC_TcpConnectionPort::Run() { OSC_Packet *packet = 0; // wait for login message int32 size; int32 msglen; while (true) { if (!packet) { packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); } size = recvall(mSocket, &msglen, sizeof(int32)); if (size < 0) goto leave; // sk: msglen is in network byte order msglen = ntohl(msglen); char *data = (char*)malloc(msglen); size = recvall(mSocket, data, msglen); if (size < msglen) goto leave; packet->mReplyAddr.mReplyFunc = tcp_reply_func; packet->mSize = msglen; packet->mData = data; packet->mReplyAddr.mSocket = mSocket; ProcessOSCPacket(packet, mPortNum); packet = 0; } leave: delete this; // ohh this could cause a crash if a reply tries to access it.. return 0; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef SC_WIN32 # include #endif //SC_WIN32 SC_TcpClientPort::SC_TcpClientPort(int inSocket, ClientNotifyFunc notifyFunc, void *clientData) : SC_ComPort(0), mClientNotifyFunc(notifyFunc), mClientData(clientData) { mSocket = inSocket; socklen_t sockAddrLen = sizeof(mReplySockAddr); if (getpeername(mSocket, (struct sockaddr*)&mReplySockAddr, &sockAddrLen) == -1) { memset(&mReplySockAddr, 0, sizeof(mReplySockAddr)); mReplySockAddr.sin_family = AF_INET; mReplySockAddr.sin_addr.s_addr = htonl(INADDR_NONE); mReplySockAddr.sin_port = htons(0); } #if HAVE_SO_NOSIGPIPE int sockopt = 1; setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &sockopt, sizeof(sockopt)); #endif // HAVE_SO_NOSIGPIPE if (pipe(mCmdFifo) == -1) { mCmdFifo[0] = mCmdFifo[1] = -1; } Start(); } SC_TcpClientPort::~SC_TcpClientPort() { #ifdef SC_WIN32 closesocket(mCmdFifo[0]); closesocket(mCmdFifo[1]); closesocket(mSocket); #else close(mCmdFifo[0]); close(mCmdFifo[1]); close(mSocket); #endif } void* SC_TcpClientPort::Run() { OSC_Packet *packet = 0; int32 size; int32 msglen; int cmdfd = mCmdFifo[0]; int sockfd = mSocket; int nfds = sc_max(cmdfd, sockfd) + 1; bool cmdClose = false; pthread_detach(mThread); while (true) { fd_set rfds; FD_ZERO(&rfds); FD_SET(cmdfd, &rfds); FD_SET(sockfd, &rfds); if ((select(nfds, &rfds, 0, 0, 0) == -1) || (cmdClose = FD_ISSET(cmdfd, &rfds))) goto leave; if (!FD_ISSET(sockfd, &rfds)) continue; packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); if (!packet) goto leave; packet->mData = 0; size = recvall(sockfd, &msglen, sizeof(int32)); if (size < (int32)sizeof(int32)) goto leave; // msglen is in network byte order msglen = ntohl(msglen); packet->mData = (char*)malloc(msglen); if (!packet->mData) goto leave; size = recvall(sockfd, packet->mData, msglen); if (size < msglen) goto leave; memcpy(&packet->mReplyAddr.mSockAddr, &mReplySockAddr, sizeof(mReplySockAddr)); packet->mReplyAddr.mSockAddrLen = sizeof(mReplySockAddr); packet->mReplyAddr.mSocket = sockfd; packet->mReplyAddr.mReplyFunc = tcp_reply_func; packet->mSize = msglen; ProcessOSCPacket(packet, mPortNum); packet = 0; } leave: if (packet) { free(packet->mData); free(packet); } // Only call notify function when not closed explicitly if (!cmdClose && mClientNotifyFunc) { (*mClientNotifyFunc)(mClientData); } delete this; return 0; } void SC_TcpClientPort::Close() { char cmd = 0; #ifdef SC_WIN32 win32_pipewrite(mCmdFifo[1], &cmd, sizeof(cmd)); #else size_t written = write(mCmdFifo[1], &cmd, sizeof(cmd)); if (written != sizeof(cmd)) post("warning: invalid write in SC_TcpClientPort::Close"); #endif } ReplyFunc SC_TcpClientPort::GetReplyFunc() { return tcp_reply_func; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// int recvall(int socket, void *msg, size_t len) { size_t total = 0; while (total < len) { #ifdef SC_WIN32 int numbytes = recv(socket, reinterpret_cast(msg), len - total, 0); #else int numbytes = recv(socket, msg, len - total, 0); #endif if (numbytes <= 0) return total; total += numbytes; msg = (void*)((char*)msg + numbytes); } return total; } int recvallfrom(int socket, void *msg, size_t len, struct sockaddr *fromaddr, int addrlen) { size_t total = 0; while (total < len) { socklen_t addrlen2 = addrlen; #ifdef SC_WIN32 int numbytes = recvfrom(socket, reinterpret_cast(msg), len - total, 0, fromaddr, &addrlen2); #else int numbytes = recvfrom(socket, msg, len - total, 0, fromaddr, &addrlen2); #endif if (numbytes < 0) return total; total += numbytes; msg = (void*)((char*)msg + numbytes); } return total; } int sendallto(int socket, const void *msg, size_t len, struct sockaddr *toaddr, int addrlen) { size_t total = 0; while (total < len) { #ifdef SC_WIN32 int numbytes = sendto(socket, reinterpret_cast(msg), len - total, 0, toaddr, addrlen); #else int numbytes = sendto(socket, msg, len - total, 0, toaddr, addrlen); #endif //printf("numbytes %d total %d len %d\n", numbytes, total, len); if (numbytes < 0) { printf("******* errno %d %s\n", errno, strerror(errno)); return total; } total += numbytes; msg = (void*)((char*)msg + numbytes); } return total; } int sendall(int socket, const void *msg, size_t len) { size_t total = 0; while (total < len) { #if HAVE_MSG_NOSIGNAL int flags = MSG_NOSIGNAL; #else int flags = 0; #endif // HAVE_MSG_NOSIGNAL #ifdef SC_WIN32 int numbytes = send(socket, reinterpret_cast(msg), len - total, flags); #else int numbytes = send(socket, msg, len - total, flags); #endif if (numbytes < 0) return total; total += numbytes; msg = (void*)((char*)msg + numbytes); } return total; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/SC_HID.cpp0000664000000000000000000006446612245365552024322 0ustar rootroot/* * SC_HID.cpp * SC3lang * * Created by Jan Truetzschler v. Falkenstein on Tue Sep 30 2003. * Copyright (c) 2003 jan.t. All rights reserved. * modifications by Marije Baalman in May 2007 * part of ... SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef SC_DARWIN #include #include "HID_Utilities_External.h" /* #include #include #include #include */ #include #include #include #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" // Backward compatibility for the older (10.4) way of doing things: #if (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4) #define SC_MAC_HIDSTYLE_10_4 1 #define IOHIDDeviceRef pRecDevice #define IOHIDElementRef pRecElement #define IOHIDDevice_GetLocationID(x) (x->locID) #define IOHIDElementGetType(x) ((IOHIDElementType) x->type) #define IOHIDElementGetCookie(x) (x->cookie) #define IOHIDElementGetLogicalMin(x) (x->min) #define IOHIDElementGetLogicalMax(x) (x->max) #define IOHIDElementGetUsagePage(x) (x->usagePage) #define IOHIDElementGetUsage(x) (x->usage) #define IOHIDDevice_GetManufacturer(x) (x->manufacturer) #define IOHIDDevice_GetProduct(x) (x->product) #define IOHIDDevice_GetUsagePage(x) (x->usagePage) #define IOHIDDevice_GetUsage(x) (x->usage) #define IOHIDDevice_GetVendorID(x) (x->vendorID) #define IOHIDDevice_GetProductID(x) (x->productID) #define IOHIDDevice_GetLocationID(x) (x->locID) #define IOHIDDevice_GetVersionNumber(x) (x->version) #define IOHIDDevice_GetSerialNumber(x) (x->serial) #endif PyrSymbol * s_readError; PyrSymbol * s_hidAction; PyrSymbol * s_hid; extern bool compiledOK; int gNumberOfHIDDevices = 0; EventLoopTimerRef gTimer = NULL; // timer for element data updates void releaseHIDDevices (); void releaseHIDDevices () { if (gTimer) { RemoveEventLoopTimer(gTimer); gTimer = NULL; } HIDReleaseAllDeviceQueues(); HIDReleaseDeviceList(); gNumberOfHIDDevices = 0; } int prHIDGetElementListSize(VMGlobals *g, int numArgsPushed); int prHIDGetElementListSize(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; //class PyrSlot *b = g->sp; //locID device int locID; int err = slotIntVal(b, &locID); if (err) return err; IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && ((uint32)IOHIDDevice_GetLocationID(pCurrentHIDDevice) != (uint32)locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; UInt32 numElements = HIDCountDeviceElements (pCurrentHIDDevice, kHIDElementTypeAll ); SetInt(a, numElements); return errNone; } int prHIDBuildElementList(VMGlobals *g, int numArgsPushed); int prHIDBuildElementList(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; //class PyrSlot *b = g->sp - 1; //locID device PyrSlot *c = g->sp; //array int locID; int err = slotIntVal(b, &locID); if (err) return err; //look for the right device: IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && ((uint32)IOHIDDevice_GetLocationID(pCurrentHIDDevice) !=(uint32)locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; IOHIDElementRef devElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll ); UInt32 numElements = HIDCountDeviceElements (pCurrentHIDDevice, kHIDElementTypeAll ); // PyrObject* devAllElementsArray = newPyrArray(g->gc, numElements * sizeof(PyrObject), 0 , true); PyrObject *devAllElementsArray = slotRawObject(c); // post("numElements: %d\n", numElements); numElements = sc_clip(numElements, 0, devAllElementsArray->size); for(uint i=0; igc, 8 * sizeof(PyrObject), 0 , true); // type name (1) HIDGetTypeName(IOHIDElementGetType(devElement), cstrElementName); PyrString *devstring = newPyrString(g->gc, cstrElementName, 0, true); SetObject(devElementArray->slots+devElementArray->size++, devstring); //g->gc->GCWrite(devElementArray, (PyrObject*) devstring); //usage (2) HIDGetUsageName (IOHIDElementGetUsagePage(devElement), IOHIDElementGetUsage(devElement), cstrElementName); PyrString *usestring = newPyrString(g->gc, cstrElementName, 0, true); SetObject(devElementArray->slots+devElementArray->size++, usestring); //g->gc->GCWrite(devElementArray, (PyrObject*) usestring); //cookie (3) SetInt(devElementArray->slots+devElementArray->size++, (long) IOHIDElementGetCookie(devElement)); // min (4) SetInt(devElementArray->slots+devElementArray->size++, (long) IOHIDElementGetLogicalMin(devElement)); // max (5) SetInt(devElementArray->slots+devElementArray->size++, (long) IOHIDElementGetLogicalMax(devElement)); // IO type as int: (6) SetInt(devElementArray->slots+devElementArray->size++, (int) IOHIDElementGetType(devElement)); // Usage page as int: (7) SetInt(devElementArray->slots+devElementArray->size++, (long) IOHIDElementGetUsagePage(devElement)); // Usage type as int: (8) SetInt(devElementArray->slots+devElementArray->size++, (long) IOHIDElementGetUsage(devElement)); SetObject(devAllElementsArray->slots+i, devElementArray); //g->gc->GCWrite(devAllElementsArray, (PyrObject*) devElementArray); } devElement = HIDGetNextDeviceElement (devElement, kHIDElementTypeAll); } SetObject(a, devAllElementsArray); return errNone; } int prHIDBuildDeviceList(VMGlobals *g, int numArgsPushed); int prHIDBuildDeviceList(VMGlobals *g, int numArgsPushed) { //build a device list PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; //usagePage PyrSlot *c = g->sp; //usage int usagePage, usage, err; if(IsNil(b)) usagePage = 0; else { err = slotIntVal(b, &usagePage); if (err) return err; } if(IsNil(c)) usage = 0; else { err = slotIntVal(c, &usage); if (err) return err; } //pass in usage & usagepage //kHIDUsage_GD_Joystick kHIDUsage_GD_GamePad //UInt32 usagePage = kHIDPage_GenericDesktop; //UInt32 usage = NULL; Boolean result = HIDBuildDeviceList ((uint32)usagePage, (uint32)usage); /* #if(SC_MAC_HIDSTYLE_10_4) // on 10.4, this should return false (!) result = !result; #endif */ if(!result) post("no HID devices found\n"); int numdevs = HIDCountDevices(); gNumberOfHIDDevices = numdevs; if(!numdevs){ SetNil(a); return errNone; } //post("number of devices: %d", numdevs); IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); PyrObject* allDevsArray = newPyrArray(g->gc, numdevs * sizeof(PyrObject), 0 , true); for(int i=0; igc, 8 * sizeof(PyrObject), 0 , true); //manufacturer: //#if(SC_MAC_HIDSTYLE_10_4) // PyrString *devstring = newPyrString(g->gc, pCurrentHIDDevice->manufacturer, 0, true); //#else *tmp = 0; stringref = IOHIDDevice_GetManufacturer(pCurrentHIDDevice); if (stringref) { CFStringGetCString(stringref, tmp, 256, kCFStringEncodingASCII); CFRelease(stringref); } PyrString *devstring = newPyrString(g->gc, tmp, 0, true); //#endif SetObject(devNameArray->slots+devNameArray->size++, devstring); g->gc->GCWrite(devNameArray, (PyrObject*) devstring); //product name: //#if(SC_MAC_HIDSTYLE_10_4) // devstring = newPyrString(g->gc, pCurrentHIDDevice->product, 0, true); //#else *tmp = 0; stringref = IOHIDDevice_GetProduct(pCurrentHIDDevice); if (stringref) { CFStringGetCString(stringref, tmp, 256, kCFStringEncodingASCII); CFRelease(stringref); } devstring = newPyrString(g->gc, tmp, 0, true); //#endif SetObject(devNameArray->slots+devNameArray->size++, devstring); g->gc->GCWrite(devNameArray, (PyrObject*) devstring); //usage //#if(SC_MAC_HIDSTYLE_10_4) // HIDGetUsageName (pCurrentHIDDevice->usagePage, pCurrentHIDDevice->usage, tmp); // devstring = newPyrString(g->gc, tmp, 0, true); //#else *tmp = 0; HIDGetUsageName (IOHIDDevice_GetPrimaryUsagePage(pCurrentHIDDevice), IOHIDDevice_GetPrimaryUsage(pCurrentHIDDevice), tmp); devstring = newPyrString(g->gc, tmp, 0, true); //#endif SetObject(devNameArray->slots+devNameArray->size++, devstring); g->gc->GCWrite(devNameArray, (PyrObject*) devstring); //vendor id SetInt(devNameArray->slots+devNameArray->size++, (int)IOHIDDevice_GetVendorID(pCurrentHIDDevice)); //product id SetInt(devNameArray->slots+devNameArray->size++, (int)IOHIDDevice_GetProductID(pCurrentHIDDevice)); //locID SetInt(devNameArray->slots+devNameArray->size++, (int)IOHIDDevice_GetLocationID(pCurrentHIDDevice)); //version SetInt(devNameArray->slots+devNameArray->size++, (int)IOHIDDevice_GetVersionNumber(pCurrentHIDDevice)); //serial //#if(SC_MAC_HIDSTYLE_10_4) // devstring = newPyrString(g->gc, pCurrentHIDDevice->serial, 0, true); //#else *tmp = 0; stringref = IOHIDDevice_GetSerialNumber(pCurrentHIDDevice); if (stringref) { CFStringGetCString(stringref, tmp, 256, kCFStringEncodingASCII); CFRelease(stringref); } devstring = newPyrString(g->gc, tmp, 0, true); //#endif SetObject(devNameArray->slots+devNameArray->size++, devstring); g->gc->GCWrite(devNameArray, (PyrObject*) devstring); SetObject(allDevsArray->slots+allDevsArray->size++, devNameArray); g->gc->GCWrite(allDevsArray, (PyrObject*) devNameArray); pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); } //UInt32 outnum = HIDCountDeviceElements (pCurrentHIDDevice, kHIDElementTypeOutput); //post("number of outputs: %d \n", outnum); SetObject(a, allDevsArray); return errNone; } int prHIDGetValue(VMGlobals *g, int numArgsPushed); int prHIDGetValue(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; //class PyrSlot *b = g->sp - 1; //locID device PyrSlot *c = g->sp; //element cookie int locID, cookieNum; int err = slotIntVal(b, &locID); if (err) return err; err = slotIntVal(c, &cookieNum); if (err) return err; IOHIDElementCookie cookie = (IOHIDElementCookie) cookieNum; //look for the right device: IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && ((uint32)IOHIDDevice_GetLocationID(pCurrentHIDDevice) != (uint32)locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; //look for the right element: IOHIDElementRef pCurrentHIDElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll); // use gElementCookie to find current element while (pCurrentHIDElement && (IOHIDElementGetCookie(pCurrentHIDElement) != cookie)) pCurrentHIDElement = HIDGetNextDeviceElement (pCurrentHIDElement, kHIDElementTypeAll); if (pCurrentHIDElement) { //#if(SC_MAC_HIDSTYLE_10_4) // SInt32 value = HIDGetElementValue (pCurrentHIDDevice, pCurrentHIDElement); // // if it's not a button and it's not a hatswitch then calibrate // if(( pCurrentHIDElement->type != kIOHIDElementTypeInput_Button ) && // ( pCurrentHIDElement->usagePage == 0x01 && pCurrentHIDElement->usage != kHIDUsage_GD_Hatswitch)) // value = HIDCalibrateValue ( value, pCurrentHIDElement ); //#else SInt32 value; // if it's not a button and it's not a hatswitch then calibrate if(( IOHIDElementGetType(pCurrentHIDElement) != kIOHIDElementTypeInput_Button ) && ( IOHIDElementGetUsagePage(pCurrentHIDElement) == 0x01 && IOHIDElementGetUsage(pCurrentHIDElement) != kHIDUsage_GD_Hatswitch)) { value = IOHIDElement_GetValue(pCurrentHIDElement, kIOHIDValueScaleTypeCalibrated); } else { value = IOHIDElement_GetValue(pCurrentHIDElement, kIOHIDValueScaleTypePhysical); } //#endif SetInt(a, value); } else SetNil(a); return errNone; } int prHIDSetValue(VMGlobals *g, int numArgsPushed); int prHIDSetValue(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 3; //class PyrSlot *b = g->sp - 2; //locID PyrSlot *c = g->sp - 1; //element device PyrSlot *d = g->sp; //value cookie int locID, cookieNum, value; int err = slotIntVal(b, &locID); if (err) return err; err = slotIntVal(c, &cookieNum); if (err) return err; IOHIDElementCookie cookie = (IOHIDElementCookie) cookieNum; err = slotIntVal(d, &value); if (err) return err; //look for the right device: IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && ((uint32)IOHIDDevice_GetLocationID(pCurrentHIDDevice) !=(uint32)locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; //look for the right element: IOHIDElementRef pCurrentHIDElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll); // use gElementCookie to find current element while (pCurrentHIDElement && (IOHIDElementGetCookie(pCurrentHIDElement) != cookie)) pCurrentHIDElement = HIDGetNextDeviceElement (pCurrentHIDElement, kHIDElementTypeAll); //struct IOHIDEventStruct //{ // IOHIDElementType type; // IOHIDElementCookie elementCookie; // SInt32 value; // AbsoluteTime timestamp; // UInt32 longValueSize; // void * longValue; //}; if (pCurrentHIDElement) { //#if(SC_MAC_HIDSTYLE_10_4) // IOHIDEventStruct event = // { // kIOHIDElementTypeOutput, // pCurrentHIDElement->cookie, // value, // {0}, // sizeof(int), // NULL // }; // SInt32 value = HIDSetElementValue (pCurrentHIDDevice, pCurrentHIDElement, &event); // // if it's not a button and it's not a hatswitch then calibrate // // if(( pCurrentHIDElement->type != kIOHIDElementTypeInput_Button ) && // // ( pCurrentHIDElement->usagePage == 0x01 && pCurrentHIDElement->usage != kHIDUsage_GD_Hatswitch)) // // value = HIDCalibrateValue ( value, pCurrentHIDElement ); //#else IOHIDValueRef valueref = IOHIDValueCreateWithIntegerValue(0, pCurrentHIDElement, 0, value); IOHIDDeviceSetValue(pCurrentHIDDevice, pCurrentHIDElement, valueref); CFRelease(valueref); //#endif SetInt(a, value); } else SetNil(a); return errNone; } void PushQueueEvents_RawValue (); void PushQueueEvents_RawValue (){ //#if(SC_MAC_HIDSTYLE_10_4) // IOHIDEventStruct event; //#else IOHIDValueRef value_ref = 0; //#endif IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); int numdevs = gNumberOfHIDDevices; unsigned char result; for(int i=0; i< numdevs; i++){ //#if(SC_MAC_HIDSTYLE_10_4) // result = HIDGetEvent(pCurrentHIDDevice, (void*) &event); //#else result = HIDGetEvent(pCurrentHIDDevice, &value_ref); //#endif if(result && compiledOK) { //#if(SC_MAC_HIDSTYLE_10_4) // SInt32 value = event.value; //#else SInt32 value = IOHIDValueGetIntegerValue(value_ref); //#endif int vendorID = IOHIDDevice_GetVendorID(pCurrentHIDDevice);; int productID = IOHIDDevice_GetProductID(pCurrentHIDDevice); uint32 locID = (uint32)IOHIDDevice_GetLocationID(pCurrentHIDDevice); //#if(SC_MAC_HIDSTYLE_10_4) // IOHIDElementCookie cookie = (IOHIDElementCookie) event.elementCookie; //#else IOHIDElementCookie cookie = IOHIDElementGetCookie(IOHIDValueGetElement(value_ref)); CFRelease(value_ref); //#endif VMGlobals *g = gMainVMGlobals; pthread_mutex_lock (&gLangMutex); g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_hid->u.classobj); // Set the class HIDService //set arguments: ++g->sp;SetInt(g->sp, vendorID); ++g->sp;SetInt(g->sp, productID); ++g->sp;SetInt(g->sp, (int)locID); ++g->sp;SetInt(g->sp, (int) cookie); ++g->sp;SetInt(g->sp, value); runInterpreter(g, s_hidAction, 6); g->canCallOS = false; // cannot call the OS pthread_mutex_unlock (&gLangMutex); } /* FIXME: this does not seem to be working if ( !HIDIsValidDevice(pCurrentHIDDevice) ) { // readError post("HID: read Error\n"); int locID = pCurrentHIDDevice->locID; VMGlobals *g = gMainVMGlobals; pthread_mutex_lock (&gLangMutex); g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_hid->u.classobj); // Set the class HIDService ++g->sp;SetInt(g->sp, locID); runInterpreter(g, s_readError, 2); g->canCallOS = false; // cannot call the OS pthread_mutex_unlock (&gLangMutex); } */ pCurrentHIDDevice = HIDGetNextDevice(pCurrentHIDDevice); } } void PushQueueEvents_CalibratedValue (); void PushQueueEvents_CalibratedValue (){ //#if(SC_MAC_HIDSTYLE_10_4) // IOHIDEventStruct event; //#else IOHIDValueRef value_ref = 0; //#endif IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); int numdevs = gNumberOfHIDDevices; unsigned char result; for(int i=0; i< numdevs; i++){ //#if(SC_MAC_HIDSTYLE_10_4) // result = HIDGetEvent(pCurrentHIDDevice, (void*) &event); //#else result = HIDGetEvent(pCurrentHIDDevice, &value_ref); //#endif printf("result is %d\n", (int)result); if(result && compiledOK) { //#if(SC_MAC_HIDSTYLE_10_4) // SInt32 value = event.value; //#else SInt32 value = IOHIDValueGetScaledValue(value_ref, kIOHIDValueScaleTypeCalibrated); //#endif int vendorID = IOHIDDevice_GetVendorID(pCurrentHIDDevice);; int productID = IOHIDDevice_GetProductID(pCurrentHIDDevice); uint32 locID = (uint32)IOHIDDevice_GetLocationID(pCurrentHIDDevice); //#if(SC_MAC_HIDSTYLE_10_4) // IOHIDElementCookie cookie = (IOHIDElementCookie) event.elementCookie; //#else IOHIDElementCookie cookie = IOHIDElementGetCookie(IOHIDValueGetElement(value_ref)); CFRelease(value_ref); //#endif IOHIDElementRef pCurrentHIDElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll); // use gElementCookie to find current element while (pCurrentHIDElement && ( (IOHIDElementGetCookie(pCurrentHIDElement)) != cookie)) pCurrentHIDElement = HIDGetNextDeviceElement (pCurrentHIDElement, kHIDElementTypeAll); if (pCurrentHIDElement) { //#if(SC_MAC_HIDSTYLE_10_4) // value = HIDCalibrateValue(value, pCurrentHIDElement); //#endif //find element to calibrate VMGlobals *g = gMainVMGlobals; pthread_mutex_lock (&gLangMutex); g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_hid->u.classobj); // Set the class HIDService //set arguments: ++g->sp;SetInt(g->sp, vendorID); ++g->sp;SetInt(g->sp, productID); ++g->sp;SetInt(g->sp, (int)locID); ++g->sp;SetInt(g->sp, (int) cookie); ++g->sp;SetInt(g->sp, value); runInterpreter(g, s_hidAction, 6); g->canCallOS = false; // cannot call the OS pthread_mutex_unlock (&gLangMutex); } } /* FIXME: this does not seem to be working! if ( !HIDIsValidDevice(pCurrentHIDDevice) ) { // readError post("HID: read Error\n"); int locID = pCurrentHIDDevice->locID; VMGlobals *g = gMainVMGlobals; pthread_mutex_lock (&gLangMutex); g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_hid->u.classobj); // Set the class HIDService ++g->sp;SetInt(g->sp, locID); runInterpreter(g, s_readError, 2); g->canCallOS = false; // cannot call the OS pthread_mutex_unlock (&gLangMutex); }*/ pCurrentHIDDevice = HIDGetNextDevice(pCurrentHIDDevice); } } static pascal void IdleTimer (EventLoopTimerRef inTimer, void* userData); static pascal void IdleTimer (EventLoopTimerRef inTimer, void* userData) { #pragma unused (inTimer, userData) PushQueueEvents_CalibratedValue (); } int prHIDReleaseDeviceList(VMGlobals *g, int numArgsPushed); int prHIDReleaseDeviceList(VMGlobals *g, int numArgsPushed) { releaseHIDDevices(); return errNone; } static EventLoopTimerUPP GetTimerUPP (void); static EventLoopTimerUPP GetTimerUPP (void) { static EventLoopTimerUPP sTimerUPP = NULL; if (sTimerUPP == NULL) sTimerUPP = NewEventLoopTimerUPP (IdleTimer); return sTimerUPP; } /* typedef void (*IOHIDCallbackFunction) (void * target, IOReturn result, void * refcon, void * sender); */ /* void callback (void * target, IOReturn result, void * refcon, void * sender); void callback (void * target, IOReturn result, void * refcon, void * sender) { } */ int prHIDRunEventLoop(VMGlobals *g, int numArgsPushed); int prHIDRunEventLoop(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; //class PyrSlot *b = g->sp; //num double eventtime; int err = slotDoubleVal(b, &eventtime); if (err) return err; if(gTimer) { RemoveEventLoopTimer(gTimer); gTimer = NULL; } InstallEventLoopTimer (GetCurrentEventLoop(), 0, (EventTimerInterval) eventtime, GetTimerUPP (), 0, &gTimer); //HIDSetQueueCallback(pCurrentHIDDevice, callback); return errNone; } int prHIDQueueDevice(VMGlobals *g, int numArgsPushed); int prHIDQueueDevice(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; //class PyrSlot *b = g->sp; //locID device int locID; int err = slotIntVal(b, &locID); if (err) return err; //look for the right device: IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && ((uint32)IOHIDDevice_GetLocationID(pCurrentHIDDevice) != (uint32)locID)){ printf("current device wasn't found\n"); pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); } if(!pCurrentHIDDevice) return errFailed; int thisreturn = HIDQueueDevice(pCurrentHIDDevice); printf("%d the return\n", thisreturn); return errNone; } int prHIDQueueElement(VMGlobals *g, int numArgsPushed); int prHIDQueueElement(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; //class PyrSlot *b = g->sp - 1; //locID device PyrSlot *c = g->sp; //element cookie int locID, cookieNum; int err = slotIntVal(b, &locID); if (err) return err; err = slotIntVal(c, &cookieNum); if (err) return err; IOHIDElementCookie cookie = (IOHIDElementCookie) cookieNum; //look for the right device: IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && ((uint32)IOHIDDevice_GetLocationID(pCurrentHIDDevice) !=(uint32)locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; //look for the right element: IOHIDElementRef pCurrentHIDElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll); // use gElementCookie to find current element while (pCurrentHIDElement && (IOHIDElementGetCookie(pCurrentHIDElement) != cookie)) pCurrentHIDElement = HIDGetNextDeviceElement (pCurrentHIDElement, kHIDElementTypeAll); if(!pCurrentHIDElement) return errFailed; HIDQueueElement(pCurrentHIDDevice, pCurrentHIDElement); return errNone; } int prHIDDequeueElement(VMGlobals *g, int numArgsPushed); int prHIDDequeueElement(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; //class PyrSlot *b = g->sp - 1; //locID device PyrSlot *c = g->sp; //element cookie int locID, cookieNum; int err = slotIntVal(b, &locID); if (err) return err; err = slotIntVal(c, &cookieNum); if (err) return err; IOHIDElementCookie cookie = (IOHIDElementCookie) cookieNum; //look for the right device: IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && ((uint32)IOHIDDevice_GetLocationID(pCurrentHIDDevice) !=(uint32)locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; //look for the right element: IOHIDElementRef pCurrentHIDElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll); while (pCurrentHIDElement && (IOHIDElementGetCookie(pCurrentHIDElement) != cookie)) pCurrentHIDElement = HIDGetNextDeviceElement (pCurrentHIDElement, kHIDElementTypeAll); if(!pCurrentHIDElement) return errFailed; HIDDequeueElement(pCurrentHIDDevice, pCurrentHIDElement); return errNone; } int prHIDDequeueDevice(VMGlobals *g, int numArgsPushed); int prHIDDequeueDevice(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; //class PyrSlot *b = g->sp; //locID device int locID; int err = slotIntVal(b, &locID); if (err) return err; //look for the right device: IOHIDDeviceRef pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && ((uint32)IOHIDDevice_GetLocationID(pCurrentHIDDevice) !=(uint32)locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; HIDDequeueDevice(pCurrentHIDDevice); return errNone; } int prHIDStopEventLoop(VMGlobals *g, int numArgsPushed); int prHIDStopEventLoop(VMGlobals *g, int numArgsPushed) { if (gTimer) { RemoveEventLoopTimer(gTimer); gTimer = NULL; } return errNone; } void initHIDPrimitives() { int base, index; releaseHIDDevices(); s_hid = getsym("HIDDeviceService"); s_hidAction = getsym("prHidAction"); s_readError = getsym("prReadError"); base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_HIDBuildDeviceList", prHIDBuildDeviceList, 3, 0); definePrimitive(base, index++, "_HIDGetElementListSize", prHIDGetElementListSize, 2, 0); definePrimitive(base, index++, "_HIDBuildElementList", prHIDBuildElementList, 3, 0); definePrimitive(base, index++, "_HIDGetValue", prHIDGetValue, 3, 0); definePrimitive(base, index++, "_HIDSetValue", prHIDSetValue, 4, 0); definePrimitive(base, index++, "_HIDReleaseDeviceList", prHIDReleaseDeviceList, 1, 0); definePrimitive(base, index++, "_HIDRunEventLoop", prHIDRunEventLoop, 2, 0); definePrimitive(base, index++, "_HIDStopEventLoop", prHIDStopEventLoop, 1, 0); definePrimitive(base, index++, "_HIDQueueDevice", prHIDQueueDevice, 2, 0); definePrimitive(base, index++, "_HIDDequeueDevice", prHIDDequeueDevice, 2, 0); definePrimitive(base, index++, "_HIDDequeueElement", prHIDDequeueElement, 3, 0); definePrimitive(base, index++, "_HIDQueueElement", prHIDQueueElement, 3, 0); } #else // !SC_DARWIN void initHIDPrimitives() { //other platforms? } #endif // SC_DARWIN SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrMathPrim.cpp0000664000000000000000000006145512245365552025540 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrMathPrim.h" #include "MiscInlineMath.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSignal.h" #include "PyrParseNode.h" #include "PyrMessage.h" #include "clz.h" #include #include #include #include "SC_Endian.h" #include "SCBase.h" #include "boost/math/special_functions.hpp" const int INT_MAX_BY_PyrSlot = INT_MAX / sizeof(PyrSlot); inline bool IsSignal(PyrSlot* slot) { return (IsObj(slot) && slotRawObject(slot)->classptr == class_signal); } inline bool NotSignal(PyrSlot* slot) { return (NotObj(slot) || slotRawObject(slot)->classptr != class_signal); } /* functors for dispatching template code */ struct addNum { static inline double run(double lhs, double rhs) { return lhs + rhs; } static inline int run(int lhs, int rhs) { return lhs + rhs; } static inline PyrObject* signal_xf(VMGlobals *g, PyrObject* ina, float inb) { return signal_add_xf(g, ina, inb); } static inline PyrObject* signal_fx(VMGlobals *g, float ina, PyrObject* inb) { return signal_xf(g, inb, ina); } static inline PyrObject* signal_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { return signal_add_xx(g, ina, inb); } }; struct mulNum { static inline double run(double lhs, double rhs) { return lhs * rhs; } static inline int run(int lhs, int rhs) { return lhs * rhs; } static inline PyrObject* signal_xf(VMGlobals *g, PyrObject* ina, float inb) { return signal_mul_xf(g, ina, inb); } static inline PyrObject* signal_fx(VMGlobals *g, float ina, PyrObject* inb) { return signal_xf(g, inb, ina); } static inline PyrObject* signal_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { return signal_mul_xx(g, ina, inb); } }; struct subNum { static inline double run(double lhs, double rhs) { return lhs - rhs; } static inline int run(int lhs, int rhs) { return lhs - rhs; } static inline PyrObject* signal_xf(VMGlobals *g, PyrObject* ina, float inb) { return signal_sub_xf(g, ina, inb); } static inline PyrObject* signal_fx(VMGlobals *g, float ina, PyrObject* inb) { return signal_sub_fx(g, ina, inb); } static inline PyrObject* signal_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { return signal_sub_xx(g, ina, inb); } }; template inline int prOpNum(VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrSymbol *msg; a = g->sp - 1; b = g->sp; switch (GetTag(a)) { case tagInt : switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::run(slotRawInt(a), slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) SetObject(a, Functor::signal_fx(g, slotRawInt(a), slotRawObject(b))); else goto send_normal_2; break; default : SetFloat(a, slotRawInt(a) + slotRawFloat(b)); break; } break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : // leave self in 'a' break; case tagObj : if (isKindOf(slotRawObject(a), class_signal)) { switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::signal_xf(g, slotRawObject(a), slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) { SetRaw(a, Functor::signal_xx(g, slotRawObject(a), slotRawObject(b))); } else goto send_normal_2; break; default : // double SetRaw(a, Functor::signal_xf(g, slotRawObject(a), slotRawFloat(b))); break; } } else goto send_normal_2; break; default : // double switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::run(slotRawFloat(a), (double)slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) SetObject(a, Functor::signal_fx(g, slotRawFloat(a), slotRawObject(b))); else goto send_normal_2; break; default : // double SetRaw(a, Functor::run(slotRawFloat(a), slotRawFloat(b))); break; } break; } g->sp-- ; // drop g->numpop = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_2: if (numArgsPushed != -1) // special case flag meaning it is a primitive return errFailed; // arguments remain on the stack msg = gSpecialBinarySelectors[g->primitiveIndex]; sendMessage(g, msg, 2); return errNone; } template inline int prOpInt(VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrSymbol *msg; a = g->sp - 1; b = g->sp; switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::run(slotRawInt(a), slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) SetObject(a, Functor::signal_fx(g, slotRawInt(a), slotRawObject(b))); else goto send_normal_2; break; default : SetFloat(a, Functor::run((double)slotRawInt(a), slotRawFloat(b))); break; } g->sp-- ; // drop g->numpop = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_2: if (numArgsPushed != -1) // special case flag meaning it is a primitive return errFailed; // arguments remain on the stack msg = gSpecialBinarySelectors[g->primitiveIndex]; sendMessage(g, msg, 2); return errNone; } template inline int prOpFloat(VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrSymbol *msg; a = g->sp - 1; b = g->sp; switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::run(slotRawFloat(a), (double)slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) SetObject(a, Functor::signal_fx(g, slotRawFloat(a), slotRawObject(b))); else goto send_normal_2; break; default : SetRaw(a, Functor::run(slotRawFloat(a), slotRawFloat(b))); break; } g->sp-- ; // drop g->numpop = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_2: if (numArgsPushed != -1) // special case flag meaning it is a primitive return errFailed; // arguments remain on the stack msg = gSpecialBinarySelectors[g->primitiveIndex]; sendMessage(g, msg, 2); return errNone; } int prAddNum(VMGlobals *g, int numArgsPushed) { return prOpNum(g, numArgsPushed); } int prSubNum(VMGlobals *g, int numArgsPushed) { return prOpNum(g, numArgsPushed); } int prMulNum(VMGlobals *g, int numArgsPushed) { return prOpNum(g, numArgsPushed); } int prAddFloat(VMGlobals *g, int numArgsPushed) { return prOpFloat(g, numArgsPushed); } int prSubFloat(VMGlobals *g, int numArgsPushed) { return prOpFloat(g, numArgsPushed); } int prMulFloat(VMGlobals *g, int numArgsPushed) { return prOpFloat(g, numArgsPushed); } int prAddInt(VMGlobals *g, int numArgsPushed) { return prOpInt(g, numArgsPushed); } int prSubInt(VMGlobals *g, int numArgsPushed) { return prOpInt(g, numArgsPushed); } int prMulInt(VMGlobals *g, int numArgsPushed) { return prOpInt(g, numArgsPushed); } int prNthPrime(VMGlobals *g, int numArgsPushed); int prNthPrime(VMGlobals *g, int numArgsPushed) { PyrSlot *a; int n, p; a = g->sp; n = slotRawInt(a); p = nthPrime(n); if (p == 0) { SetNil(a); } else { SetInt(a, p); } return errNone; } int prPrevPrime(VMGlobals *g, int numArgsPushed); int prPrevPrime(VMGlobals *g, int numArgsPushed) { PyrSlot *a; int n, p, i; a = g->sp; n = slotRawInt(a); i = prevPrime(n); p = nthPrime(i); if (p == 0) { SetNil(a); } else { SetInt(a, p); } return errNone; } int prNextPrime(VMGlobals *g, int numArgsPushed); int prNextPrime(VMGlobals *g, int numArgsPushed) { PyrSlot *a; int n, p, i; a = g->sp; n = slotRawInt(a); i = nextPrime(n); p = nthPrime(i); if (p == 0) { SetNil(a); } else { SetInt(a, p); } return errNone; } int prIsPrime(VMGlobals *g, int numArgsPushed); int prIsPrime(VMGlobals *g, int numArgsPushed) { PyrSlot *a; int n, p, sqrtn, i; a = g->sp; n = slotRawInt(a); SetNil(a); if (n <= 2) { if (n == 2) { SetTrue(a); } else { SetFalse(a); } } else if (n <= nthPrime(NUMPRIMES-1)) { // do a search of the primes table i = findPrime(n); if (i >= 0) { SetTrue(a); } else { SetFalse(a); } } else { #ifdef SC_WIN32 sqrtn = (int)sqrt(static_cast(n)); #else sqrtn = (int)sqrt(n); #endif for (i=0; i= sqrtn) { SetTrue(a); break; } } } return errNone; } int prIndexOfPrime(VMGlobals *g, int numArgsPushed); int prIndexOfPrime(VMGlobals *g, int numArgsPushed) { PyrSlot *a; int n, p; a = g->sp; n = slotRawInt(a); if (n <= 2) { if (n == 2) { SetInt(a, 0); } else { SetNil(a); } } else if (n <= nthPrime(NUMPRIMES-1)) { p = findPrime(n); if (p < 0) { SetNil(a); } else { SetInt(a, p); } } else { SetNil(a); } return errNone; } int prAs32Bits(VMGlobals *g, int numArgsPushed); int prAs32Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; // return an integer that is a bit pattern for the 32 bit float representation union { float f; int32 i; } u; u.f = slotRawFloat(a); SetInt(a, u.i); return errNone; } int prHigh32Bits(VMGlobals *g, int numArgsPushed); int prHigh32Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; #if BYTE_ORDER == BIG_ENDIAN union { struct { uint32 hi, lo; } i; double f; } du; #else union { struct { uint32 lo, hi; } i; double f; } du; #endif du.f = slotRawFloat(a); SetInt(a, du.i.hi); return errNone; } int prLow32Bits(VMGlobals *g, int numArgsPushed); int prLow32Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; #if BYTE_ORDER == BIG_ENDIAN union { struct { uint32 hi, lo; } i; double f; } du; #else union { struct { uint32 lo, hi; } i; double f; } du; #endif du.f = slotRawFloat(a); SetInt(a, du.i.lo); return errNone; } int prFrom32Bits(VMGlobals *g, int numArgsPushed); int prFrom32Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; int err, word; err = slotIntVal(b, &word); if (err) return err; union { float f; int32 i; } u; u.i = word; SetFloat(a, u.f); return errNone; } int prFrom64Bits(VMGlobals *g, int numArgsPushed); int prFrom64Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, hi, lo; err = slotIntVal(b, &hi); if (err) return err; err = slotIntVal(c, &lo); if (err) return err; #if BYTE_ORDER == BIG_ENDIAN union { struct { uint32 hi, lo; } i; double f; } du; #else union { struct { uint32 lo, hi; } i; double f; } du; #endif du.i.hi = hi; du.i.lo = lo; SetFloat(a, du.f); return errNone; } int mathClipInt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; double lo, hi; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsInt(b) && IsInt(c)) { SetRaw(a, sc_clip(slotRawInt(a), slotRawInt(b), slotRawInt(c))); } else { err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetFloat(a, sc_clip((double)slotRawInt(a), lo, hi)); } return errNone; } int mathClipFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; double lo, hi; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else { err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetRaw(a, sc_clip(slotRawFloat(a), lo, hi)); } return errNone; } int mathClipSignal(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; float lo, hi; int err; PyrObject *sig; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsSignal(b) && IsSignal(c)) { sig = signal_clip_x(g, slotRawObject(a), slotRawObject(b), slotRawObject(c)); SetObject(a, sig); } else { err = slotFloatVal(b, &lo); if (err) return err; err = slotFloatVal(c, &hi); if (err) return err; sig = signal_clip_f(g, slotRawObject(a), lo, hi); SetObject(a, sig); } return errNone; } int mathWrapInt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsInt(b) && IsInt(c)) { SetRaw(a, sc_mod((int)(slotRawInt(a) - slotRawInt(b)), (int)(slotRawInt(c) - slotRawInt(b) + 1)) + slotRawInt(b)); } else { double x, lo, hi; x = slotRawInt(a); err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetFloat(a, sc_mod(x - lo, hi - lo) + lo); } return errNone; } int mathWrapFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; double lo, hi; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else { err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetRaw(a, sc_mod(slotRawFloat(a) - lo, hi - lo) + lo); } return errNone; } int mathWrapSignal(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; float lo, hi; int err; PyrObject *sig; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsSignal(b) && IsSignal(c)) { sig = signal_wrap_x(g, slotRawObject(a), slotRawObject(b), slotRawObject(c)); SetObject(a, sig); } else { err = slotFloatVal(b, &lo); if (err) return err; err = slotFloatVal(c, &hi); if (err) return err; sig = signal_wrap_f(g, slotRawObject(a), lo, hi); SetObject(a, sig); } return errNone; } int mathFoldInt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsInt(b) && IsInt(c)) { SetRaw(a, sc_fold(slotRawInt(a), slotRawInt(b), slotRawInt(c))); } else { double x, lo, hi; x = slotRawInt(a); err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetFloat(a, sc_fold(x, lo, hi)); } return errNone; } int mathFoldFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; double lo, hi; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else { err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetRaw(a, sc_fold(slotRawFloat(a), lo, hi)); } return errNone; } int mathFoldSignal(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; float lo, hi; int err; PyrObject *sig; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsSignal(b) && IsSignal(c)) { sig = signal_fold_x(g, slotRawObject(a), slotRawObject(b), slotRawObject(c)); SetObject(a, sig); } else { err = slotFloatVal(b, &lo); if (err) return err; err = slotFloatVal(c, &hi); if (err) return err; sig = signal_fold_f(g, slotRawObject(a), lo, hi); SetObject(a, sig); } return errNone; } int prSimpleNumberSeries(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, size; if (IsInt(a) && (IsInt(b) || IsNil(b)) && IsInt(c)) { int first, second, last, step; first = slotRawInt(a); last = slotRawInt(c); second = IsInt(b) ? slotRawInt(b) : (first < last ? first + 1 : first - 1); step = second - first; if ( step == 0 ) size = 1; else size = ((last - first) / step) + 1; if(size<1 || size > INT_MAX_BY_PyrSlot){ post("prSimpleNumberSeries: array size %i exceeds limit (%i)\n", size, INT_MAX_BY_PyrSlot); return errFailed; } PyrObject *obj = newPyrArray(g->gc, size, 0, true); obj->size = size; PyrSlot *slots = obj->slots; if(step==1){ // Faster iteration for common case if(first==0){ for (int i=0; i INT_MAX_BY_PyrSlot){ post("prSimpleNumberSeries: array size %i exceeds limit (%i)\n", size, INT_MAX_BY_PyrSlot); return errFailed; } PyrObject *obj = newPyrArray(g->gc, size, 0, true); obj->size = size; PyrSlot *slots = obj->slots; if(first==0. && step==1.){ // Faster iteration for common case for (long i=0; i mediant[0] } { if (maxDenominator < mediant[1]) {^upper}; d = upper[0] - (this * upper[1]); if (d == 0) {^upper}; lower = mediant; k = floor(((this * lower[1]) - lower[0]) / d); k1 = k + 1; temp = [lower[0] + (k1 * upper[0]), lower[1] + (k1 * upper[1])]; lower = [lower[0] + (k * upper[0]), lower[1] + (k * upper[1])]; upper = temp; } { (this * mediant[1]) == mediant[0] } { if (maxDenominator >= mediant[1]) {^mediant}; if (lower[1] < upper[1]) {^lower}; ^upper } { if (maxDenominator < mediant[1]) {^lower}; d = lower[0] - (this * lower[1]); if (d == 0) {^lower}; upper = mediant; k = floor(((this * upper[1]) - upper[0]) / d); k1 = k + 1; temp = [(k1 * lower[0]) + upper[0], (k1 * lower[1]) + upper[1]]; upper = [(k * lower[0]) + upper[0], (k * lower[1]) + upper[1]]; lower = temp; }; } } */ int prAsFraction(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; double mediant_num, lower_num, upper_num, temp_num; double mediant_den, lower_den, upper_den, temp_den; double x, d; int k, k1; int maxDenominator; int err; bool neg = false; err = slotDoubleVal(a, &x); if (err) return err; err = slotIntVal(b, &maxDenominator); if (err) return err; bool faster = IsTrue(c); PyrObject *obj = newPyrArray(g->gc, 2, 0, true); obj->size = 2; PyrSlot *slots = obj->slots; SetObject(a, obj); if (x < 0.0) { x = -x; neg = true; } if (x == 0.0) { SetInt(slots+0, 0); SetInt(slots+1, 1); return errNone; } if (x < 1.0) { upper_num = 1.0; upper_den = floor(1./x); lower_num = 1.0; lower_den = upper_den + 1.; } else { lower_num = floor(x); lower_den = 1.0; upper_num = lower_num + 1.; upper_den = 1.0; } while (true) { mediant_num = lower_num + upper_num; mediant_den = lower_den + upper_den; //post(" md %g %g %g %g %g %g\n", mediant_num, mediant_den, lower_num, lower_den, upper_num, upper_den); if (x * mediant_den > mediant_num) { d = upper_num - (x * upper_den); if (maxDenominator < mediant_den || fabs(d) < 1e-5) { if (neg) upper_num = -upper_num; SetInt(slots+0, (int)upper_num); SetInt(slots+1, (int)upper_den); return errNone; } lower_num = mediant_num; lower_den = mediant_den; if (faster) { k = (int)floor(((x * lower_den) - lower_num) / d); if (k < 10000) { k1 = k + 1; temp_num = lower_num + (k1 * upper_num); temp_den = lower_den + (k1 * upper_den); lower_num = lower_num + (k * upper_num); lower_den = lower_den + (k * upper_den); upper_num = temp_num; upper_den = temp_den; } } } else if (x * mediant_den == mediant_num) { if (maxDenominator >= mediant_den) { if (neg) mediant_num = -mediant_num; SetInt(slots+0, (int)mediant_num); SetInt(slots+1, (int)mediant_den); return errNone; } else if (lower_den < upper_den) { if (neg) lower_num = -lower_num; SetInt(slots+0, (int)lower_num); SetInt(slots+1, (int)lower_den); return errNone; } else { if (neg) upper_num = -upper_num; SetInt(slots+0, (int)upper_num); SetInt(slots+1, (int)upper_den); return errNone; } } else { d = lower_num - (x * lower_den); if (maxDenominator < mediant_den || fabs(d) < 1e-5) { if (neg) lower_num = -lower_num; SetInt(slots+0, (int)lower_num); SetInt(slots+1, (int)lower_den); return errNone; } upper_num = mediant_num; upper_den = mediant_den; if (faster) { k = (int)floor(((x * upper_den) - upper_num) / d); if (k < 10000) { k1 = k + 1; temp_num = (k1 * lower_num) + upper_num; temp_den = (k1 * lower_den) + upper_den; upper_num = (k * lower_num) + upper_num; upper_den = (k * lower_den) + upper_den; lower_num = temp_num; lower_den = temp_den; } } } } } void initMathPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_AddInt", prAddInt, 2, 0); definePrimitive(base, index++, "_SubInt", prSubInt, 2, 0); definePrimitive(base, index++, "_MulInt", prMulInt, 2, 0); definePrimitive(base, index++, "_AddFloat", prAddFloat, 2, 0); definePrimitive(base, index++, "_SubFloat", prSubFloat, 2, 0); definePrimitive(base, index++, "_MulFloat", prMulFloat, 2, 0); definePrimitive(base, index++, "_NthPrime", prNthPrime, 1, 0); definePrimitive(base, index++, "_PrevPrime", prPrevPrime, 1, 0); definePrimitive(base, index++, "_NextPrime", prNextPrime, 1, 0); definePrimitive(base, index++, "_IsPrime", prIsPrime, 1, 0); definePrimitive(base, index++, "_IndexOfPrime", prIndexOfPrime, 1, 0); definePrimitive(base, index++, "_As32Bits", prAs32Bits, 1, 0); definePrimitive(base, index++, "_High32Bits", prHigh32Bits, 1, 0); definePrimitive(base, index++, "_Low32Bits", prLow32Bits, 1, 0); definePrimitive(base, index++, "_From32Bits", prFrom32Bits, 2, 0); definePrimitive(base, index++, "_From64Bits", prFrom64Bits, 3, 0); definePrimitive(base, index++, "_ClipInt", mathClipInt, 3, 0); definePrimitive(base, index++, "_ClipFloat", mathClipFloat, 3, 0); definePrimitive(base, index++, "_ClipSignal", mathClipSignal, 3, 0); definePrimitive(base, index++, "_WrapInt", mathWrapInt, 3, 0); definePrimitive(base, index++, "_WrapFloat", mathWrapFloat, 3, 0); definePrimitive(base, index++, "_WrapSignal", mathWrapSignal, 3, 0); definePrimitive(base, index++, "_FoldInt", mathFoldInt, 3, 0); definePrimitive(base, index++, "_FoldFloat", mathFoldFloat, 3, 0); definePrimitive(base, index++, "_FoldSignal", mathFoldSignal, 3, 0); definePrimitive(base, index++, "_SimpleNumberSeries", prSimpleNumberSeries, 3, 0); definePrimitive(base, index++, "_AsFraction", prAsFraction, 3, 0); } SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrFilePrim.cpp0000664000000000000000000013031212245365552025513 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for File i/o. */ #include "GC.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrSymbol.h" #include "PyrFilePrim.h" #include "ReadWriteMacros.h" #include "SCBase.h" #include "SC_DirUtils.h" #include "sc_popen.h" #include #include #include #include #include "../../common/SC_SndFileHelpers.hpp" #ifdef NOCLASSIC #include #include #endif #ifndef _WIN32 # include #else # include # include #endif #ifdef _WIN32 #include #include "SC_Win32Utils.h" #include "SC_DirUtils.h" #endif #include #include #include #if defined(__APPLE__) || defined(SC_IPHONE) #ifndef _SC_StandAloneInfo_ # include "SC_StandAloneInfo_Darwin.h" #endif # include # include #ifndef SC_IPHONE # include #endif #endif #define DELIMITOR ':' int prFileDelete(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1, *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; int err = unlink(filename); SetBool(a, err == 0); return errNone; } int prFileMTime(struct VMGlobals * g, int numArgsPushed) { PyrSlot *a = g->sp - 1, *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; time_t mtime = boost::filesystem::last_write_time(filename); SetInt(a, mtime); return errNone; } int prFileExists(struct VMGlobals * g, int numArgsPushed) { PyrSlot *a = g->sp - 1, *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; bool res = boost::filesystem::exists(filename); SetBool(a, res); return errNone; } int prFileRealPath(struct VMGlobals* g, int numArgsPushed ) { PyrSlot *a = g->sp - 1, *b = g->sp; char ipath[PATH_MAX]; char opath[PATH_MAX]; int err; err = slotStrVal(b, ipath, PATH_MAX); if (err) return err; bool isAlias = false; if(sc_ResolveIfAlias(ipath, opath, isAlias, PATH_MAX)!=0) { return errFailed; } boost::system::error_code error_code; boost::filesystem::path p = boost::filesystem::canonical(opath,error_code); if(error_code) { SetNil(a); return errNone; } strcpy(opath,p.string().c_str()); #if SC_DARWIN CFStringRef cfstring = CFStringCreateWithCString(NULL, opath, kCFStringEncodingUTF8); err = !CFStringGetFileSystemRepresentation(cfstring, opath, PATH_MAX); CFRelease(cfstring); if (err) return errFailed; #endif // SC_DARWIN PyrString* pyrString = newPyrString(g->gc, opath, 0, true); SetObject(a, pyrString); return errNone; } int prFileMkDir(struct VMGlobals * g, int numArgsPushed) { PyrSlot *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; boost::system::error_code error_code; boost::filesystem::create_directories(filename, error_code); if (error_code) postfl("Warning: %s (\"%s\")\n", error_code.message().c_str(), filename); return errNone; } int prFileCopy(struct VMGlobals * g, int numArgsPushed) { PyrSlot *b = g->sp - 1, *c = g->sp; char filename1[PATH_MAX]; char filename2[PATH_MAX]; int error; error = slotStrVal(b, filename1, PATH_MAX); if (error != errNone) return error; error = slotStrVal(c, filename2, PATH_MAX); if (error != errNone) return error; boost::filesystem::copy(filename1, filename2); return errNone; } int prFileType(struct VMGlobals * g, int numArgsPushed) { PyrSlot *a = g->sp - 1, *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; boost::filesystem::file_status s(boost::filesystem::symlink_status(filename)); SetInt(a, s.type()); return errNone; } int prFileSize(struct VMGlobals * g, int numArgsPushed) { PyrSlot *a = g->sp - 1, *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; uintmax_t sz = boost::filesystem::file_size(filename); SetInt(a, sz); return errNone; } int prFileOpen(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; char filename[PATH_MAX]; char mode[12]; PyrFile *pfile; FILE *file; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(c) || !isKindOf(slotRawObject(c), class_string) || NotObj(b) || !isKindOf(slotRawObject(b), class_string)) return errWrongType; if (slotRawObject(b)->size > PATH_MAX - 1) return errFailed; if (slotRawObject(c)->size > 11) return errFailed; pfile = (PyrFile*)slotRawObject(a); memcpy(filename, slotRawString(b)->s, slotRawObject(b)->size); filename[slotRawString(b)->size] = 0; memcpy(mode, slotRawString(c)->s, slotRawObject(c)->size); mode[slotRawString(c)->size] = 0; #ifdef SC_WIN32 win32_ReplaceCharInString(filename,PATH_MAX,'/','\\'); if(strcmp(mode,"w") == 0) strcpy(mode,"wb"); if(strcmp(mode,"r") == 0) strcpy(mode,"rb"); #endif //SC_WIN32 file = fopen(filename, mode); if (file) { SetPtr(&pfile->fileptr, file); SetTrue(a); } else { #ifdef SC_WIN32 // check if directory exisits // create a temporary file (somewhere) for a handle // the file is deleted automatically when closed if (sc_DirectoryExists(filename)) { int err; #ifdef _MSC_VER err = tmpfile_s(&file); if (!err) { SetPtr(&pfile->fileptr, file); SetTrue(a); return errNone; } #elif defined(__MINGW32__) file = tmpfile(); if (file) { SetPtr(&pfile->fileptr, file); SetTrue(a); return errNone; } #else #error compiler unsupported #endif } #endif SetNil(a); SetFalse(a); } return errNone; } int prFileClose(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errNone; SetPtr(&pfile->fileptr, NULL); if (fclose(file)) return errFailed; return errNone; } int prFileFlush(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file != NULL) fflush(file); return errNone; } int prFilePos(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; fpos_t pos; int length; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (fgetpos(file, &pos)) return errFailed; #ifdef __linux__ // sk: hack alert! length = pos.__pos; #else length = pos; #endif SetInt(a, length); return errNone; } int prFileLength(struct VMGlobals *g, int numArgsPushed) { PyrSlot * a = g->sp; PyrFile *pfile = (PyrFile*)slotRawObject(a); FILE *file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; // preserve file position fpos_t pos; if (fgetpos(file, &pos)) return errFailed; if (fseek(file, 0, SEEK_END)) return errFailed; size_t length; length = ftell(file); if (fsetpos(file, &pos)) return errFailed; SetInt(a, length); return errNone; } int prFileSeek(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; PyrFile *pfile; FILE *file; size_t offset; int origin; static int originTable[3] = { SEEK_SET, SEEK_CUR, SEEK_END }; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotInt(b)) return errWrongType; if (NotInt(c)) return errWrongType; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; offset = slotRawInt(b); origin = slotRawInt(c); if (origin < 0 || origin > 2) return errIndexOutOfRange; origin = originTable[origin]; // translate in case ANSI constants ever change.. if (fseek(file, offset, origin)) return errFailed; return errNone; } int prFileWrite(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *ptr; PyrFile *pfile; FILE *file; PyrObject *obj; char chr; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; switch (GetTag(b)) { case tagInt : { SC_IOStream scio(file); scio.writeInt32_be(slotRawInt(b)); break; } case tagSym : fwrite(slotRawSymbol(b)->name, sizeof(char), slotRawSymbol(b)->length, file); break; case tagChar : chr = slotRawChar(b); fwrite(&chr, sizeof(char), 1, file); break; case tagNil : case tagFalse : case tagTrue : case tagPtr : return errWrongType; case tagObj : { // writes the indexable part of any non obj_slot format object obj = slotRawObject(b); if (!isKindOf(obj, class_rawarray) || isKindOf(obj, class_symbolarray)) return errWrongType; if (obj->size) { ptr = obj->slots; int elemSize = gFormatElemSize[obj->obj_format]; int numElems = obj->size; #if BYTE_ORDER != BIG_ENDIAN switch (elemSize) { case 1: fwrite(ptr, elemSize, numElems, file); break; case 2: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*2; for (; ptr < ptrend; ptr+=2) { fputc(ptr[1], file); fputc(ptr[0], file); } break; } case 4: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*4; for (; ptr < ptrend; ptr+=4) { fputc(ptr[3], file); fputc(ptr[2], file); fputc(ptr[1], file); fputc(ptr[0], file); } break; } case 8: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*8; for (; ptr < ptrend; ptr+=8) { fputc(ptr[7], file); fputc(ptr[6], file); fputc(ptr[5], file); fputc(ptr[4], file); fputc(ptr[3], file); fputc(ptr[2], file); fputc(ptr[1], file); fputc(ptr[0], file); } break; } } #else fwrite(ptr, elemSize, numElems, file); #endif } break; } default : // double { SC_IOStream scio(file); scio.writeDouble_be(slotRawFloat(b)); break; } } return errNone; } int prFileWriteLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *ptr; PyrFile *pfile; FILE *file; PyrObject *obj; char chr; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; switch (GetTag(b)) { case tagInt : { SC_IOStream scio(file); scio.writeInt32_le(slotRawInt(b)); break; } case tagSym : fwrite(slotRawSymbol(b)->name, sizeof(char), slotRawSymbol(b)->length, file); break; case tagChar : chr = slotRawInt(b); fwrite(&chr, sizeof(char), 1, file); break; case tagNil : case tagFalse : case tagTrue : case tagPtr : return errWrongType; case tagObj : { // writes the indexable part of any non obj_slot format object obj = slotRawObject(b); if (!isKindOf(obj, class_rawarray) || isKindOf(obj, class_symbolarray)) return errWrongType; if (obj->size) { ptr = obj->slots; int elemSize = gFormatElemSize[obj->obj_format]; int numElems = obj->size; #if BYTE_ORDER == BIG_ENDIAN switch (elemSize) { case 1: fwrite(ptr, elemSize, numElems, file); break; case 2: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*2; for (; ptr < ptrend; ptr+=2) { fputc(ptr[1], file); fputc(ptr[0], file); } break; } case 4: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*4; for (; ptr < ptrend; ptr+=4) { fputc(ptr[3], file); fputc(ptr[2], file); fputc(ptr[1], file); fputc(ptr[0], file); } break; } case 8: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*8; for (; ptr < ptrend; ptr+=8) { fputc(ptr[7], file); fputc(ptr[6], file); fputc(ptr[5], file); fputc(ptr[4], file); fputc(ptr[3], file); fputc(ptr[2], file); fputc(ptr[1], file); fputc(ptr[0], file); } break; } } #else fwrite(ptr, elemSize, numElems, file); #endif } break; } default : // double { SC_IOStream scio(file); scio.writeDouble_le(slotRawFloat(b)); break; } } return errNone; } int prFileReadLine(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; // receiver(a File), string PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; char* result = fgets(slotRawString(b)->s, MAXINDEXSIZE(slotRawObject(b)) - 1, file); if (!result) { SetNil(a); } else { slotRawString(b)->size = strlen(slotRawString(b)->s); if (slotRawString(b)->s[slotRawString(b)->size-1] == '\n') slotRawString(b)->size--; slotCopy(a,b); } return errNone; } int prFilePutInt32(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int val; int err = slotIntVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeInt32_be(val); return errNone; } int prFilePutInt16(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int val; int err = slotIntVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeInt16_be(val); return errNone; } int prFilePutInt32LE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int val; int err = slotIntVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeInt32_le(val); return errNone; } int prFilePutInt16LE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int val; int err = slotIntVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeInt16_le(val); return errNone; } int prFilePutInt8(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int val; int err = slotIntVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeInt8(val); return errNone; } int prFilePutChar(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; char z; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (NotChar(b)) return errWrongType; z = slotRawChar(b); SC_IOStream scio(file); scio.writeInt8(z); return errNone; } int prFilePutFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) { dumpObjectSlot(a); return errFailed; } float val; int err = slotFloatVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeFloat_be(val); return errNone; } int prFilePutDouble(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; double val; int err = slotDoubleVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeDouble_be(val); return errNone; } int prFilePutFloatLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) { dumpObjectSlot(a); return errFailed; } float val; int err = slotFloatVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeFloat_le(val); return errNone; } int prFilePutDoubleLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; double val; int err = slotDoubleVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeDouble_le(val); return errNone; } int prFilePutString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; PyrString *string; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (NotObj(b) || slotRawObject(b)->classptr != class_string) return errWrongType; string = slotRawString(b); if (string->size) { fwrite(string->s, 1, string->size, file); } return errNone; } int prFileGetDouble(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetFloat(a, scio.readDouble_be()); } return errNone; } int prFileGetFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetFloat(a, scio.readFloat_be()); } return errNone; } int prFileGetDoubleLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetFloat(a, scio.readDouble_le()); } return errNone; } int prFileGetFloatLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetFloat(a, scio.readFloat_le()); } return errNone; } int prFileGetChar(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; char z; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int count = fread(&z, sizeof(char), 1, file); if (count==0) SetNil(a); else SetChar(a, z); return errNone; } int prFileGetInt8(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; int8 z; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int count = fread(&z, sizeof(int8), 1, file); if (count==0) SetNil(a); else SetInt(a, z); return errNone; } int prFileGetInt16(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetInt(a, scio.readInt16_be()); } return errNone; } int prFileGetInt32(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetInt(a, scio.readInt32_be()); } return errNone; } int prFileGetInt16LE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetInt(a, scio.readInt16_le()); } return errNone; } int prFileGetInt32LE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetInt(a, scio.readInt32_le()); } return errNone; } int prFileReadRaw(struct VMGlobals *g, int numArgsPushed) { PyrFile *pfile; FILE *file; PyrSlot* a = g->sp - 1; PyrSlot* b = g->sp; if (!isKindOfSlot(b, class_rawarray) || isKindOfSlot(b, class_symbolarray)) return errWrongType; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int elemSize = gFormatElemSize[slotRawObject(b)->obj_format]; int numElems = slotRawObject(b)->size; numElems = fread(slotRawString(b)->s, elemSize, numElems, file); slotRawObject(b)->size = numElems; #if BYTE_ORDER != BIG_ENDIAN switch (elemSize) { case 1: break; case 2: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*2; for (; ptr < ptrend; ptr+=2) { char temp = ptr[0]; ptr[0] = ptr[1]; ptr[1] = temp; } break; } case 4: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*4; for (; ptr < ptrend; ptr+=4) { char temp = ptr[0]; ptr[0] = ptr[3]; ptr[3] = temp; temp = ptr[1]; ptr[1] = ptr[2]; ptr[2] = temp; } break; } case 8: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*8; for (; ptr < ptrend; ptr+=8) { char temp = ptr[0]; ptr[0] = ptr[7]; ptr[7] = temp; temp = ptr[1]; ptr[1] = ptr[6]; ptr[6] = temp; temp = ptr[2]; ptr[2] = ptr[5]; ptr[5] = temp; temp = ptr[3]; ptr[3] = ptr[4]; ptr[4] = temp; } break; } } #endif if (slotRawObject(b)->size==0) SetNil(a); else slotCopy(a,b); return errNone; } int prFileReadRawLE(struct VMGlobals *g, int numArgsPushed) { PyrFile *pfile; FILE *file; PyrSlot* a = g->sp - 1; PyrSlot* b = g->sp; if (!isKindOfSlot(b, class_rawarray) || isKindOfSlot(b, class_symbolarray)) return errWrongType; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int elemSize = gFormatElemSize[slotRawObject(b)->obj_format]; int numElems = slotRawObject(b)->size; numElems = fread(slotRawString(b)->s, elemSize, numElems, file); slotRawObject(b)->size = numElems; #if BYTE_ORDER == BIG_ENDIAN switch (elemSize) { case 1: break; case 2: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*2; for (; ptr < ptrend; ptr+=2) { char temp = ptr[0]; ptr[0] = ptr[1]; ptr[1] = temp; } break; } case 4: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*4; for (; ptr < ptrend; ptr+=4) { char temp = ptr[0]; ptr[0] = ptr[3]; ptr[3] = temp; temp = ptr[1]; ptr[1] = ptr[2]; ptr[2] = temp; } break; } case 8: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*8; for (; ptr < ptrend; ptr+=8) { char temp = ptr[0]; ptr[0] = ptr[7]; ptr[7] = temp; temp = ptr[1]; ptr[1] = ptr[6]; ptr[6] = temp; temp = ptr[2]; ptr[2] = ptr[5]; ptr[5] = temp; temp = ptr[3]; ptr[3] = ptr[4]; ptr[4] = temp; } break; } } #endif if (slotRawObject(b)->size==0) SetNil(a); else slotCopy(a,b); return errNone; } int prFileGetcwd(struct VMGlobals *g, int numArgsPushed) { //PyrSlot* a = g->sp - 1; // File PyrSlot* string = g->sp; if (!isKindOfSlot(string, class_string)) return errWrongType; char * cwd = getcwd(slotRawString(string)->s,255); if (cwd == NULL) { error(strerror(errno)); return errFailed; } slotRawString(string)->size = strlen(slotRawString(string)->s); return errNone; } //////// int prPipeOpen(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; char mode[12]; PyrFile *pfile; FILE *file; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(c) || !isKindOf(slotRawObject(c), class_string) || NotObj(b) || !isKindOf(slotRawObject(b), class_string)) return errWrongType; if (slotRawObject(c)->size > 11) return errFailed; pfile = (PyrFile*)slotRawObject(a); char *commandLine = (char*)malloc(slotRawObject(b)->size + 1); memcpy(commandLine, slotRawString(b)->s, slotRawObject(b)->size); commandLine[slotRawString(b)->size] = 0; memcpy(mode, slotRawString(c)->s, slotRawObject(c)->size); mode[slotRawString(c)->size] = 0; pid_t pid; file = sc_popen(commandLine, &pid, mode); free(commandLine); if (file) { SetPtr(&pfile->fileptr, file); SetInt(a, pid); } else { SetNil(a); } return errNone; } int prPipeClose(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrSlot *b; PyrFile *pfile; FILE *file; pid_t pid; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errNone; pid = (pid_t) slotRawInt(b); SetPtr(&pfile->fileptr, NULL); int perr = sc_pclose(file, pid); SetInt(a, perr); if (perr == -1) return errFailed; return errNone; } //////// #ifndef NO_LIBSNDFILE #include int sampleFormatToString(struct SF_INFO *info, const char **string); int sampleFormatToString(struct SF_INFO *info, const char **string) { unsigned int format = info->format & SF_FORMAT_SUBMASK; switch (format) { case SF_FORMAT_DPCM_8: case SF_FORMAT_PCM_S8: *string = "int16"; break; case SF_FORMAT_DPCM_16: case SF_FORMAT_PCM_16: case SF_FORMAT_DWVW_16: *string = "int16"; break; case SF_FORMAT_PCM_24: case SF_FORMAT_DWVW_24: *string = "int24"; break; case SF_FORMAT_PCM_32: *string = "int32"; break; case SF_FORMAT_FLOAT: *string = "float"; break; case SF_FORMAT_DOUBLE: *string = "double"; break; case SF_FORMAT_ULAW: *string = "ulaw"; break; case SF_FORMAT_ALAW: *string = "alaw"; break; default: *string = "float"; break; } return errNone; } int headerFormatToString(struct SF_INFO *info, const char **string); int headerFormatToString(struct SF_INFO *info, const char **string){ switch (info->format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV : *string = "WAV"; break; case SF_FORMAT_AIFF : *string = "AIFF"; break ; case SF_FORMAT_AU : *string = "SUN"; break ; case SF_FORMAT_IRCAM : *string = "IRCAM"; break ; case SF_FORMAT_RAW : *string = "raw"; break ; case SF_FORMAT_W64 : *string = "WAV"; break ; case SF_FORMAT_FLAC : *string = "FLAC"; break ; // TODO allow other platforms to know vorbis once libsndfile 1.0.18 is established #if SC_DARWIN || SC_WIN32 || LIBSNDFILE_1018 case SF_FORMAT_VORBIS : *string = "vorbis"; break ; #endif /* case SF_FORMAT_PAF : break ; case SF_FORMAT_SVX : break ; case SF_FORMAT_NIST : break ; case SF_FORMAT_VOC : break ; case SF_FORMAT_MAT4 : break ; case SF_FORMAT_MAT5 : break ; case SF_FORMAT_PVF : break ; case SF_FORMAT_XI : break ; case SF_FORMAT_HTK : break ; case SF_FORMAT_SDS : break ; */ default : *string = " "; break ; } return errNone; } int sndfileFormatInfoToStrings(struct SF_INFO *info, const char **stringHead, const char **stringSample); int sndfileFormatInfoToStrings(struct SF_INFO *info, const char **stringHead, const char **stringSample) { int error = 0; error = headerFormatToString(info, stringHead); error = sampleFormatToString(info, stringSample); return error; } int prSFOpenRead(struct VMGlobals *g, int numArgsPushed); int prSFOpenRead(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; char filename[PATH_MAX]; SNDFILE *file; SF_INFO info; const char *headerstr; const char *sampleformatstr; a = g->sp - 1; b = g->sp; if (!isKindOfSlot(b, class_string)) return errWrongType; if (slotRawObject(b)->size > PATH_MAX - 1) return errFailed; memcpy(filename, slotRawString(b)->s, slotRawObject(b)->size); filename[slotRawString(b)->size] = 0; info.format = 0; file = sf_open(filename, SFM_READ, &info); if (file) { SetPtr(slotRawObject(a)->slots + 0, file); sndfileFormatInfoToStrings(&info, &headerstr, &sampleformatstr); //headerFormatToString(&info, &headerstr); PyrString *hpstr = newPyrString(g->gc, headerstr, 0, true); SetObject(slotRawObject(a)->slots+1, hpstr); PyrString *smpstr = newPyrString(g->gc, sampleformatstr, 0, true); SetObject(slotRawObject(a)->slots+2, smpstr); SetInt(slotRawObject(a)->slots + 3, info.frames); SetInt(slotRawObject(a)->slots + 4, info.channels); SetInt(slotRawObject(a)->slots + 5, info.samplerate); SetTrue(a); } else { SetNil(a); SetFalse(a); } return errNone; } int prSFOpenWrite(struct VMGlobals *g, int numArgsPushed); int prSFOpenWrite(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; char filename[PATH_MAX]; SNDFILE *file; SF_INFO info; PyrSlot *headerSlot; PyrSlot *formatSlot; int error; a = g->sp - 1; b = g->sp; headerSlot = (slotRawObject(a)->slots + 1); formatSlot = (slotRawObject(a)->slots + 2); if (!isKindOfSlot(headerSlot, class_string)) return errWrongType; if (!isKindOfSlot(formatSlot, class_string)) return errWrongType; if (!isKindOfSlot(b, class_string)) return errWrongType; if (slotRawObject(b)->size > PATH_MAX - 1) return errFailed; memcpy(filename, slotRawString(b)->s, slotRawObject(b)->size); filename[slotRawString(b)->size] = 0; #ifdef SC_WIN32 char* headerFormat = (char *)malloc(slotRawObject(headerSlot)->size); #else char headerFormat[slotRawString(headerSlot)->size]; #endif memcpy(headerFormat, slotRawString(headerSlot)->s, slotRawObject(headerSlot)->size); headerFormat[slotRawString(headerSlot)->size] = 0; #ifdef SC_WIN32 char* sampleFormat = (char *)malloc(slotRawString(formatSlot)->size); #else char sampleFormat[slotRawString(formatSlot)->size]; #endif memcpy(sampleFormat, slotRawString(formatSlot)->s, slotRawObject(formatSlot)->size); sampleFormat[slotRawString(formatSlot)->size] = 0; error = sndfileFormatInfoFromStrings(&info, headerFormat, sampleFormat); if(error) { #ifdef SC_WIN32 free(sampleFormat); free(headerFormat); #endif return errFailed; } if(error) return errFailed; //slotIntVal(slotRawObject(a)->slots + 3, &info.frames); slotIntVal(slotRawObject(a)->slots + 4, &info.channels); slotIntVal(slotRawObject(a)->slots + 5, &info.samplerate); file = sf_open(filename, SFM_WRITE, &info); sf_command(file, SFC_SET_CLIPPING, NULL, SF_TRUE); if (file) { SetPtr(slotRawObject(a)->slots+0, file); SetTrue(a); } else { SetNil(a); SetFalse(a); } return errNone; } int prSFClose(struct VMGlobals *g, int numArgsPushed); int prSFClose(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SNDFILE *file = (SNDFILE*)slotRawPtr(&slotRawObject(a)->slots[0]); if (file) { sf_close(file); SetNil(slotRawObject(a)->slots + 0); } return errNone; } int prSFRead(struct VMGlobals *g, int numArgsPushed); int prSFRead(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; a = g->sp - 1; b = g->sp; SNDFILE *file = (SNDFILE*)slotRawPtr(&slotRawObject(a)->slots[0]); if (!isKindOfSlot(b, class_rawarray)) return errWrongType; switch (slotRawObject(b)->obj_format) { case obj_int16 : slotRawObject(b)->size = sf_read_short(file, (short*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_int32 : slotRawObject(b)->size = sf_read_int(file, (int*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_float : slotRawObject(b)->size = sf_read_float(file, (float*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_double : slotRawObject(b)->size = sf_read_double(file, (double*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; default: error("sample format not supported.\n"); return errFailed; } return errNone; } int prSFWrite(struct VMGlobals *g, int numArgsPushed); int prSFWrite(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; a = g->sp - 1; b = g->sp; SNDFILE *file = (SNDFILE*)slotRawPtr(&slotRawObject(a)->slots[0]); if (!isKindOfSlot(b, class_rawarray)) return errWrongType; switch (slotRawObject(b)->obj_format) { case obj_int16 : sf_write_short(file, (short*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_int32 : sf_write_int(file, (int*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_float : sf_write_float(file, (float*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_double : sf_write_double(file, (double*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; default: error("sample format not supported.\n"); return errFailed; } return errNone; } int prSFSeek(struct VMGlobals *g, int numArgsPushed); int prSFSeek(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; a = g->sp - 2; b = g->sp - 1; c = g->sp; SNDFILE *file = (SNDFILE*)slotRawPtr(&slotRawObject(a)->slots[0]); int origin, offset; int err = slotIntVal(b, &offset); if (err) return err; err = slotIntVal(c, &origin); if (err) return err; sf_seek(file, offset, origin); return errNone; } int prSFHeaderInfoString(struct VMGlobals *g, int numArgsPushed); int prSFHeaderInfoString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SNDFILE *file = (SNDFILE*)slotRawPtr(&slotRawObject(a)->slots[0]); if(file){ static char strbuffer [(1 << 16)] ; sf_command (file, SFC_GET_LOG_INFO, strbuffer, (1 << 16)) ; PyrString *pstring = newPyrString(g->gc, strbuffer, 0, true); // post(strbuffer); SetObject(a, pstring); return errNone; } return errFailed; } #else // !NO_LIBSNDFILE int prSFOpenRead(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFOpenWrite(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFClose(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFWrite(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFRead(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFSeek(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFHeaderInfoString(struct VMGlobals *g, int numArgsPushed) { return errFailed; } #endif // !NO_LIBSNDFILE ////////// #ifdef NOCLASSIC int dir_Lookup(char *pathString, int pathStringLength, int index, /* outputs: */ char *name, int *nameLength, int *creationDate, int *modificationDate, int *isDirectory, int *isVisible, int *sizeIfFile); int prDirectory_At(struct VMGlobals *g, int numArgsPushed); int prDirectory_At(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; PyrSlot *dirPathSlot = slotRawObject(a)->slots + 0; int err, index; err = slotIntVal(c, &index); if (err) { SetNil(a); return err; } char name[256], fullPathName[256]; int nameLength, creationDate, modificationDate, isDirectory, isVisible, sizeIfFile; int dirPathLength = slotRawObject(dirPathSlot)->size; err = dir_Lookup(slotRawObject(dirPathSlot)s->s, dirPathLength, index+1, name, &nameLength, &creationDate, &modificationDate, &isDirectory, &isVisible, &sizeIfFile); if (err == 1) { SetNil(a); return errNone; } if (err) { error("Invalid path\n"); SetNil(a); return errFailed; } if (dirPathLength + nameLength + 1 > 255) { error("Full path name too long.\n"); SetNil(a); return errFailed; } PyrSlot *entryName = slotRawObject(b)->slots + 0; PyrSlot *entryPath = slotRawObject(b)->slots + 1; PyrSlot *entryIsDir = slotRawObject(b)->slots + 2; PyrSlot *entryIsVisible = slotRawObject(b)->slots + 3; PyrString *nameString = newPyrString(g->gc, name, 0, true); SetObject(entryName, nameString); g->gc->GCWrite(slotRawObject(b), (PyrObject*)nameString); memcpy(fullPathName, slotRawObject(dirPathSlot)s->s, dirPathLength); fullPathName[dirPathLength] = DELIMITOR; strcpy(fullPathName + dirPathLength + 1, name); PyrString *pathString = newPyrString(g->gc, fullPathName, 0, true); SetObject(entryPath, pathString); g->gc->GCWrite(slotRawObject(b), (PyrObject*)pathString); if (isDirectory) { SetTrue(entryIsDir); } else { SetFalse(entryIsDir); } if (isVisible) { SetTrue(entryIsVisible); } else { SetFalse(entryIsVisible); } slotCopy(a,b); return errNone; } Boolean GetFullPathname(const FSSpec* aSpec, Str255 pathname); void pstrncpy(unsigned char *s1, unsigned char *s2, int n); int prFile_GetFile(struct VMGlobals *g, int numArgsPushed); int prFile_GetFile(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; NavDialogOptions options; int err = NavGetDefaultDialogOptions(&options); if (err) return errFailed; options.dialogOptionFlags |= kNavNoTypePopup; options.dialogOptionFlags |= kNavDontAutoTranslate; options.dialogOptionFlags |= kNavDontAddTranslateItems; options.dialogOptionFlags |= kNavSelectDefaultLocation; options.dialogOptionFlags &= ~kNavAllowPreviews; options.dialogOptionFlags &= ~kNavAllowMultipleFiles; if (isKindOfSlot(b, class_string)) { pstringFromPyrString((PyrString*)slotRawObject(b), options.message, 256); } NavReplyRecord reply; err = NavGetFile(0, &reply, &options, 0, 0, 0, 0, 0); if (err == noErr && reply.validRecord) { AEKeyword keyword; DescType actualType; Size actualSize; FSSpec fsspec; err = AEGetNthPtr(&reply.selection, 1, typeFSS, &keyword, &actualType, &fsspec, sizeof(FSSpec), &actualSize); if (err == noErr) { Str255 pathname; GetFullPathname(&fsspec, pathname); p2cstr(pathname); PyrString *string = newPyrString(g->gc, (char*)pathname, 0, true); SetObject(a, string); } else { SetNil(a); } err = NavDisposeReply(&reply); } else { SetNil(a); } return errNone; } int prFile_PutFile(struct VMGlobals *g, int numArgsPushed); int prFile_PutFile(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; NavDialogOptions options; int err = NavGetDefaultDialogOptions(&options); if (err) return errFailed; options.dialogOptionFlags |= kNavNoTypePopup; options.dialogOptionFlags |= kNavDontAutoTranslate; options.dialogOptionFlags |= kNavDontAddTranslateItems; options.dialogOptionFlags |= kNavSelectDefaultLocation; options.dialogOptionFlags &= ~kNavAllowPreviews; options.dialogOptionFlags &= ~kNavAllowMultipleFiles; if (isKindOfSlot(b, class_string)) { pstringFromPyrString((PyrString*)slotRawObject(b), options.message, 256); } if (isKindOfSlot(c, class_string)) { pstringFromPyrString((PyrString*)slotRawObject(c), options.savedFileName, 256); } else { //pstrncpy(options.savedFileName, "\pUntitled", 255); } NavReplyRecord reply; err = NavPutFile(0, &reply, &options, 0, 'TEXT', 'SCjm', 0); if (err == noErr && reply.validRecord) { AEKeyword keyword; DescType actualType; Size actualSize; FSSpec fsspec; err = AEGetNthPtr(&reply.selection, 1, typeFSS, &keyword, &actualType, &fsspec, sizeof(FSSpec), &actualSize); if (err == noErr) { Str255 pathname; GetFullPathname(&fsspec, pathname); p2cstr(pathname); PyrString *string = newPyrString(g->gc, (char*)pathname, 0, true); SetObject(a, string); err = NavCompleteSave(&reply, kNavTranslateInPlace); } else { SetNil(a); } err = NavDisposeReply(&reply); } else { SetNil(a); } return errNone; } #endif ///////////// void initFilePrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_SFOpenRead", prSFOpenRead, 2, 0); definePrimitive(base, index++, "_SFOpenWrite", prSFOpenWrite, 2, 0); definePrimitive(base, index++, "_SFClose", prSFClose, 1, 0); definePrimitive(base, index++, "_SFWrite", prSFWrite, 2, 0); definePrimitive(base, index++, "_SFRead", prSFRead, 2, 0); definePrimitive(base, index++, "_SFSeek", prSFSeek, 3, 0); definePrimitive(base, index++, "_SFHeaderInfoString", prSFHeaderInfoString, 1, 0); definePrimitive(base, index++, "_PipeOpen", prPipeOpen, 3, 0); definePrimitive(base, index++, "_PipeClose", prPipeClose, 2, 0); definePrimitive(base, index++, "_FileDelete", prFileDelete, 2, 0); definePrimitive(base, index++, "_FileMTime", prFileMTime, 2, 0); definePrimitive(base, index++, "_FileExists", prFileExists, 2, 0); definePrimitive(base, index++, "_FileRealPath", prFileRealPath, 2, 0); definePrimitive(base, index++, "_FileMkDir", prFileMkDir, 2, 0); definePrimitive(base, index++, "_FileCopy", prFileCopy, 3, 0); definePrimitive(base, index++, "_FileType", prFileType, 2, 0); definePrimitive(base, index++, "_FileSize", prFileSize, 2, 0); definePrimitive(base, index++, "_FileOpen", prFileOpen, 3, 0); definePrimitive(base, index++, "_FileClose", prFileClose, 1, 0); definePrimitive(base, index++, "_FileFlush", prFileFlush, 1, 0); definePrimitive(base, index++, "_FileSeek", prFileSeek, 3, 0); definePrimitive(base, index++, "_FilePos", prFilePos, 1, 0); definePrimitive(base, index++, "_FileLength", prFileLength, 1, 0); definePrimitive(base, index++, "_FileWrite", prFileWrite, 2, 0); definePrimitive(base, index++, "_FileWriteLE", prFileWriteLE, 2, 0); definePrimitive(base, index++, "_FileReadLine", prFileReadLine, 2, 0); definePrimitive(base, index++, "_File_getcwd", prFileGetcwd, 2, 0); definePrimitive(base, index++, "_FilePutChar", prFilePutChar, 2, 0); definePrimitive(base, index++, "_FilePutInt8", prFilePutInt8, 2, 0); definePrimitive(base, index++, "_FilePutInt16", prFilePutInt16, 2, 0); definePrimitive(base, index++, "_FilePutInt32", prFilePutInt32, 2, 0); definePrimitive(base, index++, "_FilePutFloat", prFilePutFloat, 2, 0); definePrimitive(base, index++, "_FilePutDouble", prFilePutDouble, 2, 0); definePrimitive(base, index++, "_FilePutInt16LE", prFilePutInt16LE, 2, 0); definePrimitive(base, index++, "_FilePutInt32LE", prFilePutInt32LE, 2, 0); definePrimitive(base, index++, "_FilePutFloatLE", prFilePutFloatLE, 2, 0); definePrimitive(base, index++, "_FilePutDoubleLE", prFilePutDoubleLE, 2, 0); definePrimitive(base, index++, "_FileGetChar", prFileGetChar, 1, 0); definePrimitive(base, index++, "_FileGetInt8", prFileGetInt8, 1, 0); definePrimitive(base, index++, "_FileGetInt16", prFileGetInt16, 1, 0); definePrimitive(base, index++, "_FileGetInt32", prFileGetInt32, 1, 0); definePrimitive(base, index++, "_FileGetFloat", prFileGetFloat, 1, 0); definePrimitive(base, index++, "_FileGetDouble", prFileGetDouble, 1, 0); definePrimitive(base, index++, "_FileGetInt16LE", prFileGetInt16LE, 1, 0); definePrimitive(base, index++, "_FileGetInt32LE", prFileGetInt32LE, 1, 0); definePrimitive(base, index++, "_FileGetFloatLE", prFileGetFloatLE, 1, 0); definePrimitive(base, index++, "_FileGetDoubleLE", prFileGetDoubleLE, 1, 0); definePrimitive(base, index++, "_FilePutString", prFilePutString, 2, 0); definePrimitive(base, index++, "_FileReadRaw", prFileReadRaw, 2, 0); definePrimitive(base, index++, "_FileReadRawLE", prFileReadRawLE, 2, 0); #ifdef NOCLASSIC definePrimitive(base, index++, "_Directory_At", prDirectory_At, 3, 0); definePrimitive(base, index++, "_File_GetFile", prFile_GetFile, 2, 0); definePrimitive(base, index++, "_File_PutFile", prFile_PutFile, 3, 0); #endif } SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/SC_CoreMIDI.cpp0000664000000000000000000005663512245365552025250 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* changes by charles picasso 14/april/2008 (sysex parsing + added running status) changes by jan trutzschler v. f. 9/9/2002 the midiReadProc calls doAction in the class MIDIIn. with the arguments: inUid, status, chan, val1, val2 added prDisposeMIDIClient added prRestartMIDI 19/9 call different actions,disconnect midiInPort, midiout: sendmidi 04/feb/03 prListMIDIEndpoints modification by Ron Kuivila added jt. */ #if SC_IPHONE #include #else #include #include #endif #include #include #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" PyrSymbol* s_domidiaction; PyrSymbol* s_midiNoteOnAction; PyrSymbol* s_midiNoteOffAction; PyrSymbol* s_midiTouchAction; PyrSymbol* s_midiControlAction; PyrSymbol* s_midiPolyTouchAction; PyrSymbol* s_midiProgramAction; PyrSymbol* s_midiBendAction; PyrSymbol* s_midiSysexAction; PyrSymbol* s_midiInvalidSysexAction; PyrSymbol* s_midiSysrtAction; PyrSymbol* s_midiSMPTEAction; //jt PyrSymbol * s_midiin; PyrSymbol * s_numMIDIDev; PyrSymbol * s_midiclient; const int kMaxMidiPorts = 16; MIDIClientRef gMIDIClient = 0; MIDIPortRef gMIDIInPort[kMaxMidiPorts], gMIDIOutPort[kMaxMidiPorts]; int gNumMIDIInPorts = 0, gNumMIDIOutPorts = 0; bool gMIDIInitialized = false; //cp static bool gSysexFlag = false; static Byte gRunningStatus = 0; std::vector gSysexData; void midiNotifyProc(const MIDINotification *msg, void* refCon) { } extern bool compiledOK; #if 0 static void dumpSysexData() { if(gSysexData.size() <= 0) return; std::vector::const_iterator iter = gSysexData.begin(), end = gSysexData.end(); int i=0; while(iter != end) { if((i % 16) == 0 && (i > 0)) printf("\n"); ++i; printf("%02X ", *iter++); } printf("\n"); printf("sysex data dump size: %i bytes.\n", gSysexData.size()); } #endif static void sysexBegin() { gRunningStatus = 0; // clear running status gSysexData.clear(); gSysexFlag = true; } static void scCallSysexAction(PyrSymbol* action, int recoverFromUID) { VMGlobals *g = gMainVMGlobals; if(recoverFromUID) { // rebuild the VM so sc won't crash with two following calls ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // Set the class MIDIIn ++g->sp; SetInt(g->sp, recoverFromUID); //src ++g->sp; } PyrInt8Array* sysexArray = newPyrInt8Array(g->gc, gSysexData.size(), 0, true); sysexArray->size = gSysexData.size(); std::copy(gSysexData.begin(), gSysexData.end(), sysexArray->b); SetObject(g->sp, (PyrObject*) sysexArray); // chan argument unneeded as there runInterpreter(g, action, 3 ); // special sysex action in the lang } static void sysexEnd(int lastUID) { gSysexFlag = false; scCallSysexAction(s_midiSysexAction, lastUID); } static void sysexEndInvalid() { gSysexFlag = false; scCallSysexAction(s_midiInvalidSysexAction, 0); } static int midiProcessSystemPacket(MIDIPacket *pkt, int chan) { int index, data; VMGlobals *g = gMainVMGlobals; switch (chan) { case 7: // added cp: Sysex EOX must be taken into account if first on data packet case 0: { int last_uid = 0; int m = pkt->length; Byte* p_pkt = pkt->data; Byte pktval; while(m--) { pktval = *p_pkt++; if(pktval & 0x80) { // status byte if(pktval == 0xF7) { // end packet gSysexData.push_back(pktval); // add EOX if(gSysexFlag) sysexEnd(last_uid); // if last_uid != 0 rebuild the VM. else sysexEndInvalid(); // invalid 1 byte with only EOX can happen break; } else if(pktval == 0xF0) { // new packet if(gSysexFlag) {// invalid new one/should not happen -- but handle in case // store the last uid value previous to invalid data to rebuild VM after sysexEndInvalid call // since it may call sysexEnd() just after it ! if(slotIntVal(g->sp-1, &last_uid)) { post("error: failed retrieving uid value !"); last_uid = -1; } sysexEndInvalid(); } sysexBegin(); // new sysex in gSysexData.push_back(pktval); // add SOX } else {// abnormal data in middle of sysex packet gSysexData.push_back(pktval); // add it as an abort message sysexEndInvalid(); // flush invalid m = 0; // discard all packet break; } } else if(gSysexFlag) gSysexData.push_back(pktval); // add Byte else // garbage - handle in case - discard it break; } return (pkt->length-m); } break; case 1 : index = pkt->data[1] >> 4; data = pkt->data[1] & 0xf; switch (index) { case 1: case 3: case 5: case 7: { data = data << 4; } } SetInt(g->sp, index); // chan unneeded ++g->sp; SetInt(g->sp, data); // special smpte action in the lang runInterpreter(g, s_midiSMPTEAction, 4 ); return 2; case 2 : //songptr ++g->sp; SetInt(g->sp, (pkt->data[2] << 7) | pkt->data[1]); //val1 runInterpreter(g, s_midiSysrtAction, 4); return 3; case 3 : // song select ++g->sp; SetInt(g->sp, pkt->data[1]); //val1 runInterpreter(g, s_midiSysrtAction, 4); return 2; case 8 : //clock case 10: //start case 11: //continue case 12: //stop case 15: //reset gRunningStatus = 0; // clear running status runInterpreter(g, s_midiSysrtAction, 3); return 1; default: g->sp -= 3; // nevermind break; } return (1); } static void midiProcessPacket(MIDIPacket *pkt, size_t uid) { //jt if(pkt) { pthread_mutex_lock (&gLangMutex); //dont know if this is really needed/seems to be more stable.. // it is needed -jamesmcc if (compiledOK) { VMGlobals *g = gMainVMGlobals; int i = 0; //cp : changed uint8 to int if packet->length >= 256 bug:(infinite loop) while (i < pkt->length) { uint8 status = pkt->data[i] & 0xF0; uint8 chan = pkt->data[i] & 0x0F; g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // Set the class MIDIIn //set arguments: ++g->sp; SetInt(g->sp, uid); //src // ++g->sp; SetInt(g->sp, status); //status ++g->sp; SetInt(g->sp, chan); //chan if(status & 0x80) // set the running status for voice messages gRunningStatus = ((status >> 4) == 0xF) ? 0 : pkt->data[i]; // keep also additional info L: switch (status) { case 0x80 : //noteOff ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, s_midiNoteOffAction, 5); i += 3; break; case 0x90 : //noteOn ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, pkt->data[i+2] ? s_midiNoteOnAction : s_midiNoteOffAction, 5); i += 3; break; case 0xA0 : //polytouch ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, s_midiPolyTouchAction, 5); i += 3; break; case 0xB0 : //control ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, s_midiControlAction, 5); i += 3; break; case 0xC0 : //program ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 runInterpreter(g, s_midiProgramAction, 4); i += 2; break; case 0xD0 : //touch ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 runInterpreter(g, s_midiTouchAction, 4); i += 2; break; case 0xE0 : //bend ++g->sp; SetInt(g->sp, (pkt->data[i+2] << 7) | pkt->data[i+1]); //val1 runInterpreter(g, s_midiBendAction, 4); i += 3; break; case 0xF0 : i += midiProcessSystemPacket(pkt, chan); break; default : // data byte => continuing sysex message if(gRunningStatus && !gSysexFlag) { // modified cp: handling running status. may be we should here status = gRunningStatus & 0xF0; // accept running status only inside a packet beginning chan = gRunningStatus & 0x0F; // with a valid status byte ? SetInt(g->sp, chan); --i; goto L; // parse again with running status set } chan = 0; i += midiProcessSystemPacket(pkt, chan); break; } } g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); } } static void midiReadProc(const MIDIPacketList *pktlist, void* readProcRefCon, void* srcConnRefCon) { MIDIPacket *pkt = (MIDIPacket*)pktlist->packet; size_t uid = (size_t) srcConnRefCon; for (uint32 i=0; inumPackets; ++i) { midiProcessPacket(pkt, uid); pkt = MIDIPacketNext(pkt); } } int midiCleanUp(); int initMIDI(int numIn, int numOut) { midiCleanUp(); numIn = sc_clip(numIn, 1, kMaxMidiPorts); numOut = sc_clip(numOut, 1, kMaxMidiPorts); int enc = kCFStringEncodingMacRoman; CFAllocatorRef alloc = CFAllocatorGetDefault(); CFStringRef clientName = CFStringCreateWithCString(alloc, "SuperCollider", enc); OSStatus err = MIDIClientCreate(clientName, midiNotifyProc, nil, &gMIDIClient); if (err) { post("Could not create MIDI client. error %d\n", err); return errFailed; } CFRelease(clientName); for (int i=0; isp; int numSrc = MIDIGetNumberOfSources(); int numDst = MIDIGetNumberOfDestinations(); PyrObject* idarray = newPyrArray(g->gc, 6 * sizeof(PyrObject), 0 , true); SetObject(a, idarray); PyrObject* idarraySo = newPyrArray(g->gc, numSrc * sizeof(SInt32), 0 , true); SetObject(idarray->slots+idarray->size++, idarraySo); g->gc->GCWrite(idarray, idarraySo); PyrObject* devarraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarraySo); g->gc->GCWrite(idarray, devarraySo); PyrObject* namearraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearraySo); g->gc->GCWrite(idarray, namearraySo); PyrObject* idarrayDe = newPyrArray(g->gc, numDst * sizeof(SInt32), 0 , true); SetObject(idarray->slots+idarray->size++, idarrayDe); g->gc->GCWrite(idarray, idarrayDe); PyrObject* namearrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearrayDe); g->gc->GCWrite(idarray, namearrayDe); PyrObject* devarrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarrayDe); g->gc->GCWrite(idarray, devarrayDe); for (int i=0; igc, cendname, 0, true); SetObject(namearraySo->slots+i, string); namearraySo->size++; g->gc->GCWrite(namearraySo, (PyrObject*)string); PyrString *devstring = newPyrString(g->gc, cdevname, 0, true); SetObject(devarraySo->slots+i, devstring); devarraySo->size++; g->gc->GCWrite(devarraySo, (PyrObject*)devstring); SetInt(idarraySo->slots+i, id); idarraySo->size++; CFRelease(devname); CFRelease(endname); } // post("numDst %d\n", numDst); for (int i=0; igc, cendname, 0, true); SetObject(namearrayDe->slots+namearrayDe->size++, string); g->gc->GCWrite(namearrayDe, (PyrObject*)string); PyrString *devstring = newPyrString(g->gc, cdevname, 0, true); SetObject(devarrayDe->slots+devarrayDe->size++, devstring); g->gc->GCWrite(devarrayDe, (PyrObject*)devstring); SetInt(idarrayDe->slots+idarrayDe->size++, id); CFRelease(devname); CFRelease(endname); } return errNone; } int prConnectMIDIIn(struct VMGlobals *g, int numArgsPushed); int prConnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return errWrongType; if (inputIndex < 0 || inputIndex >= gNumMIDIInPorts) return errIndexOutOfRange; err = slotIntVal(c, &uid); if (err) return errWrongType; MIDIEndpointRef src=0; MIDIObjectType mtype; MIDIObjectFindByUniqueID(uid, (MIDIObjectRef*)&src, &mtype); if (mtype != kMIDIObjectType_Source) return errFailed; //pass the uid to the midiReadProc to identify the src MIDIPortConnectSource(gMIDIInPort[inputIndex], src, (void*)uid); return errNone; } int prDisconnectMIDIIn(struct VMGlobals *g, int numArgsPushed); int prDisconnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; if (inputIndex < 0 || inputIndex >= gNumMIDIInPorts) return errIndexOutOfRange; err = slotIntVal(c, &uid); if (err) return err; MIDIEndpointRef src=0; MIDIObjectType mtype; MIDIObjectFindByUniqueID(uid, (MIDIObjectRef*)&src, &mtype); if (mtype != kMIDIObjectType_Source) return errFailed; MIDIPortDisconnectSource(gMIDIInPort[inputIndex], src); return errNone; } int prInitMIDI(struct VMGlobals *g, int numArgsPushed); int prInitMIDI(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, numIn, numOut; err = slotIntVal(b, &numIn); if (err) return errWrongType; err = slotIntVal(c, &numOut); if (err) return errWrongType; return initMIDI(numIn, numOut); } int prDisposeMIDIClient(VMGlobals *g, int numArgsPushed); int prDisposeMIDIClient(VMGlobals *g, int numArgsPushed) { return midiCleanUp(); } int prRestartMIDI(VMGlobals *g, int numArgsPushed); int prRestartMIDI(VMGlobals *g, int numArgsPushed) { MIDIRestart(); return errNone; } void freeSysex(MIDISysexSendRequest* pk); void freeSysex(MIDISysexSendRequest* pk) { free(pk); } int prSendSysex(VMGlobals *g, int numArgsPushed); int prSendSysex(VMGlobals *g, int numArgsPushed) { int err, uid, size; if( !isKindOfSlot(g->sp, s_int8array->u.classobj) ) return errWrongType; PyrInt8Array* packet = slotRawInt8Array(g->sp); size = packet->size; PyrSlot *u = g->sp - 1; err = slotIntVal(u, &uid); if (err) return err; MIDIEndpointRef dest; MIDIObjectType mtype; MIDIObjectFindByUniqueID(uid, (MIDIObjectRef*)&dest, &mtype); if (mtype != kMIDIObjectType_Destination) return errFailed; if (!dest) return errFailed; MIDISysexSendRequest *pk = (MIDISysexSendRequest*) malloc (sizeof(MIDISysexSendRequest) + size); Byte *data = (Byte *)pk + sizeof(MIDISysexSendRequest); memcpy(data,packet->b, size); pk->complete = false; pk -> destination = dest; pk -> data = data; pk -> bytesToSend = size; pk->completionProc = freeSysex; pk->completionRefCon = 0; return ((MIDISendSysex(pk) == (OSStatus)0) ? errNone : errFailed); } #if SC_IPHONE static struct mach_timebase_info machTimebaseInfo() { struct mach_timebase_info info; mach_timebase_info(&info); return info; } static MIDITimeStamp midiTime(float latencySeconds) { // add the latency expressed in seconds, to the current host time base. static struct mach_timebase_info info = machTimebaseInfo(); // cache the timebase info. Float64 latencyNanos = 1000000000 * latencySeconds; MIDITimeStamp latencyMIDI = (latencyNanos / (Float64)info.numer) * (Float64)info.denom; return (MIDITimeStamp)mach_absolute_time() + latencyMIDI; } #else static MIDITimeStamp midiTime(float latencySeconds) { // add the latency expressed in seconds, to the current host time base. UInt64 latencyNanos = 1000000000 * latencySeconds ; //secs to nano return (MIDITimeStamp)AudioGetCurrentHostTime() + AudioConvertNanosToHostTime(latencyNanos); } #endif void sendmidi(int port, MIDIEndpointRef dest, int length, int hiStatus, int loStatus, int aval, int bval, float late); void sendmidi(int port, MIDIEndpointRef dest, int length, int hiStatus, int loStatus, int aval, int bval, float late) { MIDIPacketList mpktlist; MIDIPacketList * pktlist = &mpktlist; MIDIPacket * pk = MIDIPacketListInit(pktlist); ByteCount nData = (ByteCount) length; pk->data[0] = (Byte) (hiStatus & 0xF0) | (loStatus & 0x0F); pk->data[1] = (Byte) aval; pk->data[2] = (Byte) bval; pk = MIDIPacketListAdd(pktlist, sizeof(struct MIDIPacketList) , pk, midiTime(late), nData, pk->data); /*OSStatus error =*/ MIDISend(gMIDIOutPort[port], dest, pktlist ); } int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed); int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed) { //port, uid, len, hiStatus, loStatus, a, b, latency //PyrSlot *m = g->sp - 8; PyrSlot *p = g->sp - 7; PyrSlot *u = g->sp - 6; PyrSlot *l = g->sp - 5; PyrSlot *his = g->sp - 4; PyrSlot *los = g->sp - 3; PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *plat = g->sp; int err, outputIndex, uid, length, hiStatus, loStatus, aval, bval; float late; err = slotIntVal(p, &outputIndex); if (err) return err; if (outputIndex < 0 || outputIndex >= gNumMIDIInPorts) return errIndexOutOfRange; err = slotIntVal(u, &uid); if (err) return err; err = slotIntVal(l, &length); if (err) return err; err = slotIntVal(his, &hiStatus); if (err) return err; err = slotIntVal(los, &loStatus); if (err) return err; err = slotIntVal(a, &aval); if (err) return err; err = slotIntVal(b, &bval); if (err) return err; err = slotFloatVal(plat, &late); if (err) return err; MIDIEndpointRef dest; MIDIObjectType mtype; MIDIObjectFindByUniqueID(uid, (MIDIObjectRef*)&dest, &mtype); if (mtype != kMIDIObjectType_Destination) return errFailed; if (!dest) return errFailed; sendmidi(outputIndex, dest, length, hiStatus, loStatus, aval, bval, late); return errNone; } // not needed in CoreMIDI: int initMIDIClient() { return errNone; } int prInitMIDIClient(struct VMGlobals *g, int numArgsPushed); int prInitMIDIClient(struct VMGlobals *g, int numArgsPushed) { return initMIDIClient(); } //-------------- void initMIDIPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; gSysexData.reserve(1024); s_midiin = getsym("MIDIIn"); s_domidiaction = getsym("doAction"); s_midiNoteOnAction = getsym("doNoteOnAction"); s_midiNoteOffAction = getsym("doNoteOffAction"); s_midiTouchAction = getsym("doTouchAction"); s_midiControlAction = getsym("doControlAction"); s_midiPolyTouchAction = getsym("doPolyTouchAction"); s_midiProgramAction = getsym("doProgramAction"); s_midiBendAction = getsym("doBendAction"); s_midiSysexAction = getsym("doSysexAction"); s_midiInvalidSysexAction = getsym("doInvalidSysexAction"); // client can handle incorrect case s_midiSysrtAction = getsym("doSysrtAction"); s_midiSMPTEAction = getsym("doSMPTEaction"); s_numMIDIDev = getsym("prSetNumberOfDevices"); s_midiclient = getsym("MIDIClient"); definePrimitive(base, index++, "_ListMIDIEndpoints", prListMIDIEndpoints, 1, 0); definePrimitive(base, index++, "_InitMIDI", prInitMIDI, 3, 0); definePrimitive(base, index++, "_InitMIDIClient", prInitMIDIClient, 1, 0); definePrimitive(base, index++, "_ConnectMIDIIn", prConnectMIDIIn, 3, 0); definePrimitive(base, index++, "_DisconnectMIDIIn", prDisconnectMIDIIn, 3, 0); definePrimitive(base, index++, "_DisposeMIDIClient", prDisposeMIDIClient, 1, 0); definePrimitive(base, index++, "_RestartMIDI", prRestartMIDI, 1, 0); definePrimitive(base, index++, "_SendMIDIOut", prSendMIDIOut, 9, 0); definePrimitive(base, index++, "_SendSysex", prSendSysex, 3, 0); if(gMIDIClient) midiCleanUp(); } SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrStringPrim.cpp0000664000000000000000000006212012161364457026103 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for String. */ #include "PyrPrimitive.h" #include "PyrKernel.h" #include "GC.h" #include "Hash.h" #include #include #include #include "PyrLexer.h" #include "SC_DirUtils.h" #ifdef SC_WIN32 # include # include "SC_Win32Utils.h" #else # include #endif #include #include #include #include #include "yaml-cpp/yaml.h" #include #include using namespace std; int prStringAsSymbol(struct VMGlobals *g, int numArgsPushed); int prStringAsSymbol(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; char str[1024], *strp=0; int len; a = g->sp; len = slotRawObject(a)->size; strp = len > 1023 ? (char*)malloc(len+1) : str; memcpy(strp, slotRawString(a)->s, len); strp[len] = 0; SetSymbol(a, getsym(strp)); if (len > 1023) free(strp); return errNone; } int prString_AsInteger(struct VMGlobals *g, int numArgsPushed); int prString_AsInteger(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char str[256]; int err = slotStrVal(a, str, 255); if (err) return err; SetInt(a, atoi(str)); return errNone; } int prString_AsFloat(struct VMGlobals *g, int numArgsPushed); int prString_AsFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char str[256]; int err = slotStrVal(a, str, 255); if (err) return err; SetFloat(a, atof(str)); return errNone; } int prString_AsCompileString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrString* scstr = slotRawString(a); char *chars1 = scstr->s; int newSize = scstr->size + 2; for (int i=0; isize; ++i) { if (chars1[i] == '"' || chars1[i] == '\\') newSize++; } PyrString *newString = newPyrStringN(g->gc, newSize, 0, true); char *chars2 = newString->s; chars2[0] = '"'; chars2[newSize - 1] = '"'; int k = 1; for (int i=0; isize; ++i) { int c = chars1[i]; if (c == '"' || c == '\\') chars2[k++] = '\\'; chars2[k++] = c; } SetObject(a, newString); return errNone; } int prString_Format(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (!isKindOfSlot(b, class_array)) return errWrongType; char *fmt = slotRawString(a)->s; int asize = slotRawObject(a)->size; int bsize = slotRawObject(b)->size; int csize = asize; PyrSlot *slots = slotRawObject(b)->slots; for (int i=0; isize; } PyrString *newString = newPyrStringN(g->gc, csize, 0, true); char* buf = newString->s; int k=0; int index = 0; for (int i=0; is, bstring->size); k += bstring->size; index++; } } else if (ch == '\\') { if (i >= asize) break; ch = fmt[i++]; if (ch == '%') { buf[k++] = '%'; } else { i--; } } else { buf[k++] = ch; } } newString->size = k; SetObject(a, newString); return errNone; }; namespace detail { namespace bin = boost::intrusive; class regex_lru_cache { int regex_flags; struct regex_node: bin::list_base_hook<>, bin::unordered_set_base_hook<> { public: regex_node(const char * str, size_t size, int regex_flags): pattern(str, size, regex_flags) {} boost::regex const & get (void) const { return pattern; } private: boost::regex pattern; }; struct regex_equal { bool operator()(regex_node const & lhs, regex_node const & rhs) const { return lhs.get() == rhs.get(); } bool operator()(const char * lhs, regex_node const & rhs) const { return strcmp(lhs, rhs.get().str().c_str()) == 0; } }; static inline std::size_t string_hash(const char * str) { std::size_t ret = 0; // sdbm hash int c; while ((c = *str++)) ret = c + (ret << 6) + (ret << 16) - ret; return ret; } struct regex_hash { size_t operator()(regex_node const & arg) const { return string_hash(arg.get().str().c_str()); } size_t operator()(const char * arg) const { return string_hash(arg); } }; typedef bin::unordered_set, bin::hash, bin::power_2_buckets, bin::constant_time_size > re_set_t; typedef re_set_t::bucket_type bucket_type; typedef re_set_t::bucket_traits bucket_traits; bucket_type buckets[128]; re_set_t re_set; bin::list re_list; void pop_lru() { regex_node & rlu = re_list.back(); re_list.pop_back(); re_set.erase(rlu); delete &rlu; } public: regex_lru_cache(int regex_flags = boost::regex_constants::ECMAScript): re_set(bucket_traits(buckets, 128)) {} ~regex_lru_cache() { while (!re_list.empty()) { pop_lru(); } } boost::regex const & get_regex(const char * str, size_t size) { re_set_t::iterator re_in_cache = re_set.find(str, regex_hash(), regex_equal()); if (re_in_cache != re_set.end()) { regex_node & node = *re_in_cache; bin::list::iterator re_in_list = bin::list::s_iterator_to(node); re_list.splice(re_list.begin(), re_list, re_in_list); // move to the begin of the list assert(&re_list.front() == &node); return node.get(); } if (re_list.size() >= 64) pop_lru(); regex_node * new_node = new regex_node(str, size, regex_flags); re_set.insert(*new_node); re_list.push_front(*new_node); return new_node->get(); } }; } int prString_Regexp(struct VMGlobals *g, int numArgsPushed) { /* not reentrant */ static detail::regex_lru_cache regex_lru_cache(boost::regex_constants::ECMAScript | boost::regex_constants::nosubs); using namespace boost; int start, end, len; PyrSlot *a = g->sp - 3; PyrSlot *b = g->sp - 2; PyrSlot *c = g->sp - 1; PyrSlot *d = g->sp; if (!isKindOfSlot(b, class_string)) return errWrongType; if (NotInt(c) || (NotInt(d) && NotNil(d))) return errWrongType; start = slotRawInt(c); len = slotRawObject(b)->size; // last char index instead of size if(IsNil(d)) { end = len; } else { end = slotRawInt(d); } if(end > len) end = len; if(end - start <= 0) { SetFalse(a); return errNone; } int stringlen = end - start; try { regex const & pattern = regex_lru_cache.get_regex(slotRawString(a)->s, slotRawObject(a)->size); match_flag_type flags = match_nosubs | match_any; const char * stringStart = slotRawString(b)->s + start; const char * stringEnd = stringStart + stringlen; bool res = regex_search(stringStart, stringEnd, pattern, flags); if(res) SetTrue(a); else SetFalse(a); return errNone; } catch (std::exception const & e) { postfl("Warning: Exception in _String_Regexp - %s\n", e.what()); return errFailed; } } struct sc_regexp_match { int pos; int len; }; static int prString_FindRegexp(struct VMGlobals *g, int numArgsPushed) { /* not reentrant */ static detail::regex_lru_cache regex_lru_cache(boost::regex_constants::ECMAScript); using namespace boost; PyrSlot *a = g->sp - 2; // source string PyrSlot *b = g->sp - 1; // pattern PyrSlot *c = g->sp; // offset if (!isKindOfSlot(b, class_string) || (NotInt(c))) return errWrongType; int offset = slotRawInt(c); int stringlen = std::max(slotRawObject(a)->size - offset, 0); std::vector matches; const char* const stringBegin = slotRawString(a)->s + offset; try { regex const & pattern = regex_lru_cache.get_regex(slotRawString(b)->s, slotRawObject(b)->size); match_flag_type flags = match_default; match_results what; const char* start = stringBegin; const char* end = start + stringlen; while (start <= end && regex_search(start, end, what, pattern, flags)) { for (int i = 0; i < what.size(); ++i ) { sc_regexp_match match; if (what[i].matched) { match.pos = what[i].first - stringBegin; match.len = what[i].second - what[i].first; } else { match.pos = 0; match.len = 0; } matches.push_back(match); } start = what[0].second; if(what[0].first == what[0].second) ++start; } } catch (std::exception const & e) { postfl("Warning: Exception in _String_FindRegexp - %s\n", e.what()); return errFailed; } int match_count = matches.size(); PyrObject *result_array = newPyrArray(g->gc, match_count, 0, true); result_array->size = 0; SetObject(a, result_array); if( !match_count ) return errNone; for (int i = 0; i < match_count; ++i ) { int pos = matches[i].pos; int len = matches[i].len; PyrObject *array = newPyrArray(g->gc, 2, 0, true); SetObject(result_array->slots + i, array); result_array->size++; g->gc->GCWrite(result_array, array); PyrString *matched_string = newPyrStringN(g->gc, len, 0, true); memcpy(matched_string->s, stringBegin + pos, len); array->size = 2; SetInt(array->slots, pos + offset); SetObject(array->slots+1, matched_string); g->gc->GCWrite(array, matched_string); }; return errNone; } int memcmpi(char *a, char *b, int len) { for (int i=0; i bb) return 1; } return 0; } int prStringCompare(struct VMGlobals *g, int numArgsPushed); int prStringCompare(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int cmp, length; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(b) || !isKindOf(slotRawObject(b), class_string)) { SetNil(a); return errNone; } length = sc_min(slotRawObject(a)->size, slotRawObject(b)->size); if (IsTrue(c)) cmp = memcmpi(slotRawString(a)->s, slotRawString(b)->s, length); else cmp = memcmp(slotRawString(a)->s, slotRawString(b)->s, length); if (cmp == 0) { if (slotRawObject(a)->size < slotRawObject(b)->size) cmp = -1; else if (slotRawObject(a)->size > slotRawObject(b)->size) cmp = 1; } SetInt(a, cmp); return errNone; } int prStringHash(struct VMGlobals *g, int numArgsPushed); int prStringHash(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; int hash = Hash(slotRawString(a)->s, slotRawString(a)->size); SetInt(a, hash); return errNone; } #ifndef SC_WIN32 #include int prStringPathMatch(struct VMGlobals *g, int numArgsPushed); int prStringPathMatch(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char pattern[1024]; int err = slotStrVal(a, pattern, 1023); if (err) return err; glob_t pglob; int gflags = GLOB_MARK | GLOB_TILDE; #ifdef SC_DARWIN gflags |= GLOB_QUOTE; #endif int gerr = glob(pattern, gflags, NULL, &pglob); if (gerr) { pglob.gl_pathc = 0; } PyrObject* array = newPyrArray(g->gc, pglob.gl_pathc, 0, true); SetObject(a, array); if (gerr) return errNone; for (unsigned int i=0; igc, pglob.gl_pathv[i], 0, true); SetObject(array->slots+i, string); g->gc->GCWrite(array, string); array->size++; } globfree(&pglob); return errNone; } #else //#ifndef SC_WIN32 int prStringPathMatch(struct VMGlobals *g, int numArgsPushed); int prStringPathMatch(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char pattern[1024]; int err = slotStrVal(a, pattern, 1023); if (err) return err; win32_ReplaceCharInString(pattern,1024,'/','\\'); // Remove trailing slash if found, to allow folders to be matched if(pattern[strlen(pattern)-1]=='\\'){ pattern[strlen(pattern)-1] = 0; } // extract the containing folder, including backslash char folder[1024]; win32_ExtractContainingFolder(folder,pattern,1024); ///////// PASS 1 WIN32_FIND_DATA findData; HANDLE hFind; int nbPaths = 0; hFind = ::FindFirstFile(pattern, &findData); if (hFind == INVALID_HANDLE_VALUE) { nbPaths = 0; } if (hFind == INVALID_HANDLE_VALUE) { // This is what happens when no matches. So we create an empty array to return. PyrObject* array = newPyrArray(g->gc, 0, 0, true); SetObject(a, array); return errNone; } do { if(strcmp(findData.cFileName, "..")!=0 && strcmp(findData.cFileName, "..")!=0){ nbPaths++; } } while( ::FindNextFile(hFind, &findData)); ::FindClose(hFind); // PASS 2 hFind = ::FindFirstFile(pattern, &findData); if (hFind == INVALID_HANDLE_VALUE) { nbPaths = 0; } PyrObject* array = newPyrArray(g->gc, nbPaths , 0, true); SetObject(a, array); if (hFind == INVALID_HANDLE_VALUE) { return errNone; } int i = 0; do { if(strcmp(findData.cFileName, "..")!=0 && strcmp(findData.cFileName, ".")!=0){ std::string strPath(folder); strPath += std::string(findData.cFileName); if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){ strPath += std::string("\\"); // Append trailing slash, to match behaviour on unix (used by sclang to detect folderness) } const char* fullPath = strPath.c_str(); PyrObject *string = (PyrObject*)newPyrString(g->gc, fullPath, 0, true); SetObject(array->slots+i, string); g->gc->GCWrite(array, string); array->size++; i++; } } while( ::FindNextFile(hFind, &findData)); ::FindClose(hFind); return errNone; } #endif //#ifndef SC_WIN32 int prString_Getenv(struct VMGlobals* g, int numArgsPushed); int prString_Getenv(struct VMGlobals* g, int /* numArgsPushed */) { PyrSlot* arg = g->sp; char key[256]; char* value; int err; err = slotStrVal(arg, key, 256); if (err) return err; #ifdef _WIN32 char buf[1024]; DWORD size = GetEnvironmentVariable(key, buf, 1024); if (size == 0 || size > 1024) value = 0; else value = buf; #else value = getenv(key); #endif if (value) { PyrString* pyrString = newPyrString(g->gc, value, 0, true); if (!pyrString) return errFailed; SetObject(arg, pyrString); } else { SetNil(arg); } return errNone; } int prString_Setenv(struct VMGlobals* g, int numArgsPushed); int prString_Setenv(struct VMGlobals* g, int /* numArgsPushed */) { PyrSlot* args = g->sp - 1; char key[256]; int err; err = slotStrVal(args+0, key, 256); if (err) return err; if (IsNil(args+1)) { #ifdef SC_WIN32 SetEnvironmentVariable(key,NULL); #else unsetenv(key); #endif } else { char value[1024]; err = slotStrVal(args+1, value, 1024); if (err) return err; #ifdef SC_WIN32 SetEnvironmentVariable(key, value); #else setenv(key, value, 1); #endif } return errNone; } int prStripRtf(struct VMGlobals *g, int numArgsPushed); int prStripRtf(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; int len = slotRawObject(a)->size; char * chars = (char*)malloc(len + 1); memcpy(chars, slotRawString(a)->s, len); chars[len] = 0; rtf2txt(chars); PyrString* string = newPyrString(g->gc, chars, 0, false); SetObject(a, string); free(chars); return errNone; } int prStripHtml(struct VMGlobals *g, int numArgsPushed); int prStripHtml(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; int len = slotRawObject(a)->size; char * chars = (char*)malloc(len + 1); memcpy(chars, slotRawString(a)->s, len); chars[len] = 0; html2txt(chars); PyrString* string = newPyrString(g->gc, chars, 0, false); SetObject(a, string); free(chars); return errNone; } int prString_Find(struct VMGlobals *g, int numArgsPushed); int prString_Find(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 3; // source string PyrSlot *b = g->sp - 2; // search string PyrSlot *c = g->sp - 1; // ignoreCase PyrSlot *d = g->sp; // offset int offset; int err = slotIntVal(d, &offset); if (err) return err; if (!isKindOfSlot(b, class_string)) { SetNil(a); return errNone; } int alength = slotRawObject(a)->size - offset; int blength = slotRawObject(b)->size; if ((alength <= 0) || (blength == 0) // should also return nil if search string is longer than source || (blength > alength)) { SetNil(a); return errNone; } int cmp = 1; // assume contains will be false char *achar = slotRawString(a)->s + offset; char *bchar = slotRawString(b)->s; char bchar0 = bchar[0]; int scanlength = alength - blength; if (IsTrue(c)) { bchar0 = toupper(bchar0); for (int i=0; i <= scanlength; ++i, ++achar) { if (toupper(*achar) == bchar0) { cmp = memcmpi(achar+1, bchar+1, blength-1); if (cmp == 0) break; } } } else { for (int i=0; i <= scanlength; ++i, ++achar) { if (*achar == bchar0) { cmp = memcmp(achar+1, bchar+1, blength-1); if (cmp == 0) break; } } } if (cmp == 0) { SetInt(a, achar - slotRawString(a)->s); } else { SetNil(a); } return errNone; } int prString_FindBackwards(struct VMGlobals *g, int numArgsPushed); int prString_FindBackwards(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 3; // source string PyrSlot *b = g->sp - 2; // search string PyrSlot *c = g->sp - 1; // ignoreCase PyrSlot *d = g->sp; // offset int offset; int err = slotIntVal(d, &offset); if (err) return err; if (!isKindOfSlot(b, class_string)) { SetNil(a); return errNone; } int alength = sc_min(offset + 1, slotRawObject(a)->size); int blength = slotRawObject(b)->size; if ((alength <= 0) || (blength == 0) // should also return nil if search string is longer than source || (blength > alength)) { SetNil(a); return errNone; } int cmp = 1; // assume contains will be false char *achar = slotRawString(a)->s + (alength - blength); char *bchar = slotRawString(b)->s; char bchar0 = bchar[0]; int scanlength = alength - blength; if (IsTrue(c)) { bchar0 = toupper(bchar0); for (int i=scanlength; i >= 0; --i, --achar) { if (toupper(*achar) == bchar0) { cmp = memcmpi(achar+1, bchar+1, blength-1); if (cmp == 0) break; } } } else { for (int i=scanlength; i >= 0; --i, --achar) { if (*achar == bchar0) { cmp = memcmp(achar+1, bchar+1, blength-1); if (cmp == 0) break; } } } if (cmp == 0) { SetInt(a, achar - slotRawString(a)->s); } else { SetNil(a); } return errNone; } #if SC_DARWIN # include #endif // SC_DARWIN int prString_StandardizePath(struct VMGlobals* g, int numArgsPushed); int prString_StandardizePath(struct VMGlobals* g, int /* numArgsPushed */) { PyrSlot* arg = g->sp; char ipath[PATH_MAX]; char opathbuf[PATH_MAX]; char* opath = opathbuf; int err; err = slotStrVal(arg, ipath, PATH_MAX); if (err) return err; if (!sc_StandardizePath(ipath, opath)) { opath = ipath; } #if SC_DARWIN CFStringRef cfstring = CFStringCreateWithCString(NULL, opath, kCFStringEncodingUTF8); err = !CFStringGetFileSystemRepresentation(cfstring, opath, PATH_MAX); CFRelease(cfstring); if (err) return errFailed; #endif // SC_DARWIN PyrString* pyrString = newPyrString(g->gc, opath, 0, true); SetObject(arg, pyrString); return errNone; } int prString_EscapeChar(struct VMGlobals* g, int numArgsPushed) { PyrSlot* arg = g->sp - 1; PyrSlot* charToEscapeSlot = g->sp; assert (isKindOfSlot(arg, class_string)); if (!IsChar(charToEscapeSlot)) return errWrongType; char charToEscape = slotRawChar(charToEscapeSlot); PyrString* argString = slotRawString(arg); int length = argString->size; PyrString* resultString = newPyrStringN(g->gc, length*2 + 1, 0, 1); // pressimize char * original = argString->s; char * result = resultString->s; int resultLength = length; for (int i = 0; i != length; ++i) { char current = *original++; if (current == charToEscape) { *result++ = '\\'; resultLength += 1; } *result++ = current; } *result = 0; resultString->size = resultLength; SetRaw(arg, (PyrObject*)resultString); return errNone; } static void yaml_traverse(struct VMGlobals* g, const YAML::Node & node, PyrObject *parent, PyrSlot *slot) { YAML::NodeType::value type = node.Type(); string out; PyrObject *result = NULL; switch (type) { case YAML::NodeType::Scalar: node >> out; result = (PyrObject*)newPyrString(g->gc, out.c_str(), 0, true); SetObject(slot, result); if(parent) g->gc->GCWrite(parent, result); break; case YAML::NodeType::Sequence: result = newPyrArray(g->gc, node.size(), 0, true); result->size = 0; SetObject(slot, result); if(parent) g->gc->GCWrite(parent, result); for (unsigned int i = 0; i < node.size(); i++) { const YAML::Node & subnode = node[i]; result->size++; yaml_traverse(g, subnode, result, result->slots+i); } break; case YAML::NodeType::Map: { result = instantiateObject( g->gc, s_dictionary->u.classobj, 0, false, true ); SetObject(slot, result); if(parent) g->gc->GCWrite(parent, result); PyrObject *array = newPyrArray(g->gc, node.size()*2, 0, true); array->size = 0; result->size = 2; // ? SetObject(result->slots, array); // array SetInt(result->slots+1, node.size()); // size g->gc->GCWrite(result, array); int j = 0; for (YAML::Iterator i = node.begin(); i != node.end(); ++i) { const YAML::Node & key = i.first(); const YAML::Node & value = i.second(); key >> out; PyrObject *pkey = (PyrObject*)newPyrString(g->gc, out.c_str(), 0, true); SetObject(array->slots+j, pkey); array->size++; g->gc->GCWrite(array, pkey); array->size++; yaml_traverse(g, value, array, array->slots+j+1); j += 2; } break; } case YAML::NodeType::Null: SetNil(slot); break; default: postfl("WARNING: yaml_traverse(): unknown/unsupported node type\n"); SetNil(slot); } } int prString_ParseYAML(struct VMGlobals* g, int numArgsPushed) { PyrSlot* arg = g->sp; if (!isKindOfSlot(arg, class_string)) return errWrongType; string str((const char*)slotRawString(arg)->s,slotRawString(arg)->size); std::istringstream fin(str); YAML::Parser parser(fin); YAML::Node doc; // while(parser.GetNextDocument(doc)) { // yaml_traverse(doc, 0); // } parser.GetNextDocument(doc); yaml_traverse(g, doc, NULL, arg); return errNone; } int prString_ParseYAMLFile(struct VMGlobals* g, int numArgsPushed) { PyrSlot* arg = g->sp; if (!isKindOfSlot(arg, class_string)) return errWrongType; string str((const char*)slotRawString(arg)->s,slotRawString(arg)->size); std::ifstream fin(str.c_str()); YAML::Parser parser(fin); YAML::Node doc; // while(parser.GetNextDocument(doc)) { // yaml_traverse(doc, 0); // } parser.GetNextDocument(doc); yaml_traverse(g, doc, NULL, arg); return errNone; } void initStringPrimitives(); void initStringPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_StringCompare", prStringCompare, 3, 0); definePrimitive(base, index++, "_StringHash", prStringHash, 1, 0); definePrimitive(base, index++, "_StringPathMatch", prStringPathMatch, 1, 0); definePrimitive(base, index++, "_StringAsSymbol", prStringAsSymbol, 1, 0); definePrimitive(base, index++, "_String_AsInteger", prString_AsInteger, 1, 0); definePrimitive(base, index++, "_String_AsFloat", prString_AsFloat, 1, 0); definePrimitive(base, index++, "_String_AsCompileString", prString_AsCompileString, 1, 0); definePrimitive(base, index++, "_String_Getenv", prString_Getenv, 1, 0); definePrimitive(base, index++, "_String_Setenv", prString_Setenv, 2, 0); definePrimitive(base, index++, "_String_Find", prString_Find, 4, 0); definePrimitive(base, index++, "_String_FindBackwards", prString_FindBackwards, 4, 0); definePrimitive(base, index++, "_String_Format", prString_Format, 2, 0); definePrimitive(base, index++, "_String_Regexp", prString_Regexp, 4, 0); definePrimitive(base, index++, "_String_FindRegexp", prString_FindRegexp, 3, 0); definePrimitive(base, index++, "_StripRtf", prStripRtf, 1, 0); definePrimitive(base, index++, "_StripHtml", prStripHtml, 1, 0); definePrimitive(base, index++, "_String_StandardizePath", prString_StandardizePath, 1, 0); definePrimitive(base, index++, "_String_EscapeChar", prString_EscapeChar, 2, 0); definePrimitive(base, index++, "_String_ParseYAML", prString_ParseYAML, 1, 0); definePrimitive(base, index++, "_String_ParseYAMLFile", prString_ParseYAMLFile, 1, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" // export the function that SC will call to load the plug in. #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initStringPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrPlatformPrim.cpp0000664000000000000000000000727312237772705026434 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for platform dependent directories, constants etc. */ #include "SC_DirUtils.h" #include "PyrPrimitive.h" #include "PyrKernel.h" #ifdef _WIN32 # include "SC_Win32Utils.h" # include "Shlobj.h" #endif #define PATH_CONSTANT_PRIM_BODY(func) \ PyrSlot *a = g->sp; \ char path[PATH_MAX]; \ func(path, PATH_MAX); \ PyrString* string = newPyrString(g->gc, path, 0, true); \ SetObject(a, string); \ return errNone static int prPlatform_userHomeDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetUserHomeDirectory); } static int prPlatform_systemAppSupportDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetSystemAppSupportDirectory); } static int prPlatform_userAppSupportDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetUserAppSupportDirectory); } static int prPlatform_systemExtensionDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetSystemExtensionDirectory); } static int prPlatform_userExtensionDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetUserExtensionDirectory); } static int prPlatform_userConfigDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetUserConfigDirectory); } static int prPlatform_resourceDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetResourceDirectory); } #ifdef _WIN32 static int prWinPlatform_myDocumentsDir(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char path[PATH_MAX]; win32_GetKnownFolderPath(CSIDL_PERSONAL, path, PATH_MAX); \ PyrString* string = newPyrString(g->gc, path, 0, true); \ SetObject(a, string); return errNone; } #endif static int prPlatform_ideName(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrString* string = newPyrString(g->gc, gIdeName, 0, true); SetObject(a, string); return errNone; } void initPlatformPrimitives(); void initPlatformPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_Platform_userHomeDir", prPlatform_userHomeDir, 1, 0); definePrimitive(base, index++, "_Platform_systemAppSupportDir", prPlatform_systemAppSupportDir, 1, 0); definePrimitive(base, index++, "_Platform_userAppSupportDir", prPlatform_userAppSupportDir, 1, 0); definePrimitive(base, index++, "_Platform_systemExtensionDir", prPlatform_systemExtensionDir, 1, 0); definePrimitive(base, index++, "_Platform_userExtensionDir", prPlatform_userExtensionDir, 1, 0); definePrimitive(base, index++, "_Platform_userConfigDir", prPlatform_userConfigDir, 1, 0); definePrimitive(base, index++, "_Platform_resourceDir", prPlatform_resourceDir, 1, 0); definePrimitive(base, index++, "_Platform_ideName", prPlatform_ideName, 1, 0); #ifdef _WIN32 definePrimitive(base, index++, "_WinPlatform_myDocumentsDir", prWinPlatform_myDocumentsDir, 1, 0); #endif } // EOF SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/SC_Speech.cpp0000664000000000000000000002325612245365552025115 0ustar rootroot/* * SC_Speech.h * SC3lang * * Created by jan truetzschler v. falkenstein on Wed Apr 16 2003. * Copyright (c) 2003 sampleAndHold.org. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "InitAlloc.h" #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" ///////////////////// const int kMaxSpeechChannels = 32; PyrSymbol * s_speech; PyrSymbol * s_speechwordAction; PyrSymbol * s_speechdoneAction; SpeechChannel fCurSpeechChannel[kMaxSpeechChannels]; char *speechStrings[kMaxSpeechChannels]; pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon ); pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon ) { //call action here; // post("text done"); pthread_mutex_lock (&gLangMutex); VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, s_speech->u.classobj); // Set the class //set arguments: ++g->sp;SetInt(g->sp, (int) inRefCon); //src runInterpreter(g, s_speechdoneAction, 2); if(speechStrings[(int) inRefCon] != NULL){ free(speechStrings[(int) inRefCon]); speechStrings[(int) inRefCon] = NULL; } g->canCallOS = false; pthread_mutex_unlock (&gLangMutex); } pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen); pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen) { //post("word done"); pthread_mutex_lock (&gLangMutex); VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, s_speech->u.classobj); //set arguments: ++g->sp; SetInt(g->sp, (int) inRefCon); //src runInterpreter(g, s_speechwordAction, 2); g->canCallOS = false; pthread_mutex_unlock (&gLangMutex); } int prInitSpeech(struct VMGlobals *g, int numArgsPushed); int prInitSpeech(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-1; PyrSlot *b = g->sp; int chan; slotIntVal(b, &chan); if (chan < 0 || chan >= kMaxSpeechChannels) return errIndexOutOfRange; for (int i=0; isp-2; PyrSlot *a = g->sp-1; PyrSlot *str = g->sp; int chan; slotIntVal(a, &chan); chan = sc_clip(chan, 0, kMaxSpeechChannels); if(speechStrings[chan] != NULL) { post("voice %i already speaking\n", chan); return errNone; } else { // speechStrings[chan] = (char*)pyr_pool_compile->Alloc((slotRawObject(a)->size + 1)* sizeof(char)); speechStrings[chan] = (char*) malloc((slotRawObject(str)->size + 1)* sizeof(char)); MEMFAIL(speechStrings[chan]); slotStrVal(str, speechStrings[chan], slotRawObject(str)->size+1); //if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SpeakText( fCurSpeechChannel[chan], speechStrings[chan], strlen(speechStrings[chan])); //should be freed only after the text was spoken! // todo move this bit to the callback! // pyr_pool_compile->Free(theTextToSpeak); } return errNone; } int prSetSpeechRate(struct VMGlobals *g, int numArgsPushed); int prSetSpeechRate(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); Fixed newRate = (Fixed)(val * 65536.0); // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soRate, &newRate); return errNone; } int prSetSpeechPitch(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPitch(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); Fixed newVal = (Fixed)(val * 65536.0); //if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechPitch (fCurSpeechChannel[chan], newVal); return errNone; } int prSetSpeechPitchMod(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPitchMod(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); Fixed newVal = (Fixed)(val * 65536.0); // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soPitchMod, &newVal); return errNone; } int prSetSpeechVolume(struct VMGlobals *g, int numArgsPushed); int prSetSpeechVolume(struct VMGlobals *g, int numArgsPushed) { OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); Fixed newVal = (Fixed)(val * 65536.0); // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soVolume, &newVal); return errNone; } // theErr = PauseSpeechAt (fCurSpeechChannel, kImmediate); // theErr = ContinueSpeech (fCurSpeechChannel); int prSetSpeechPause(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPause(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int val; int chan; slotIntVal(b, &chan); slotIntVal(c, &val); //Fixed newVal = (Fixed)(val * 65536.0); if(val) { theErr = ContinueSpeech(fCurSpeechChannel[chan] ); } else { theErr = PauseSpeechAt(fCurSpeechChannel[chan], kImmediate); } return errNone; } int prSetSpeechStop(struct VMGlobals *g, int numArgsPushed); int prSetSpeechStop(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int selector [3] = {kImmediate, kEndOfWord, kEndOfWord}; int val; int chan; slotIntVal(b, &chan); slotIntVal(c, &val); StopSpeechAt(fCurSpeechChannel[chan], selector[val]); if(speechStrings[chan] != NULL) { free(speechStrings[chan]); speechStrings[chan] = NULL; } return errNone; } int prSetSpeechVoice(struct VMGlobals *g, int numArgsPushed); int prSetSpeechVoice(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int val; int chan; VoiceSpec theVoiceSpec; slotIntVal(b, &chan); slotIntVal(c, &val); theErr = GetIndVoice (val, &theVoiceSpec); if (SetSpeechInfo (fCurSpeechChannel[chan], soCurrentVoice, &theVoiceSpec) == incompatibleVoice) return (!errNone); return errNone; } int prSpeechVoiceIsSpeaking(struct VMGlobals *g, int numArgsPushed); int prSpeechVoiceIsSpeaking(struct VMGlobals *g, int numArgsPushed){ PyrSlot *out = g->sp-1; PyrSlot *b = g->sp; int chan; slotIntVal(b, &chan); if(speechStrings[chan] != NULL) SetTrue(out); else SetFalse(out); return errNone; } void initSpeechPrimitives () { int base, index; base = nextPrimitiveIndex(); index = 0; s_speechwordAction = getsym("doWordAction"); s_speechdoneAction = getsym("doSpeechDoneAction"); s_speech = getsym("Speech"); definePrimitive(base, index++, "_SpeakText", prSpeakText, 3, 0); definePrimitive(base, index++, "_InitSpeech", prInitSpeech, 2, 0); definePrimitive(base, index++, "_SetSpeechRate", prSetSpeechRate, 3, 0); definePrimitive(base, index++, "_SetSpeechPitch", prSetSpeechPitch, 3, 0); definePrimitive(base, index++, "_SetSpeechPitchMod", prSetSpeechPitchMod, 3, 0); definePrimitive(base, index++, "_SetSpeechVoice", prSetSpeechVoice, 3, 0); definePrimitive(base, index++, "_SetSpeechVolume", prSetSpeechVolume, 3, 0); definePrimitive(base, index++, "_SetSpeechPause", prSetSpeechPause, 3, 0); //0 pause, 1 continue definePrimitive(base, index++, "_SetSpeechStopAt", prSetSpeechStop, 3, 0); //0 kImmediate, 1 kEndOfWord, 2 kEndOfSentence definePrimitive(base, index++, "_SpeechVoiceIsSpeaking", prSpeechVoiceIsSpeaking, 2, 0); for(int i=0; i #include #include #include #include #ifdef SC_WIN32 # include typedef int socklen_t; # define bzero( ptr, count ) memset( ptr, 0, count ) #else # include # include # include #endif #include #include "scsynthsend.h" #include "sc_msg_iter.h" #include "SC_ComPort.h" #include "SC_WorldOptions.h" #include "SC_SndBuf.h" #include "SC_Endian.h" #ifndef SC_DARWIN # ifndef SC_WIN32 # include # endif #endif #include "../../../common/server_shm.hpp" struct InternalSynthServerGlobals { struct World *mWorld; int mNumSharedControls; float *mSharedControls; }; const int kNumDefaultSharedControls = 1024; float gDefaultSharedControls[kNumDefaultSharedControls]; bool gUseDoubles = false; InternalSynthServerGlobals gInternalSynthServer = { 0, kNumDefaultSharedControls, gDefaultSharedControls }; SC_UdpInPort* gUDPport = 0; PyrString* newPyrString(VMGlobals *g, char *s, int flags, bool collect); PyrSymbol *s_call, *s_write, *s_recvoscmsg, *s_recvoscbndl, *s_netaddr; const char* gPassword; extern bool compiledOK; std::vector gCustomUdpPorts; /////////// inline bool IsBundle(char* ptr) { return strcmp(ptr, "#bundle") == 0; } /////////// const int ivxNetAddr_Hostaddr = 0; const int ivxNetAddr_PortID = 1; const int ivxNetAddr_Hostname = 2; const int ivxNetAddr_Socket = 3; void makeSockAddr(struct sockaddr_in &toaddr, int32 addr, int32 port); int sendallto(int socket, const void *msg, size_t len, struct sockaddr *toaddr, int addrlen); int sendall(int socket, const void *msg, size_t len); static int makeSynthMsgWithTags(big_scpacket *packet, PyrSlot *slots, int size); int makeSynthBundle(big_scpacket *packet, PyrSlot *slots, int size, bool useElapsed); static int addMsgSlot(big_scpacket *packet, PyrSlot *slot) { switch (GetTag(slot)) { case tagInt : packet->addi(slotRawInt(slot)); break; case tagSym : packet->adds(slotRawSymbol(slot)->name); break; case tagObj : if (isKindOf(slotRawObject(slot), class_string)) { PyrString *stringObj = slotRawString(slot); packet->adds(stringObj->s, stringObj->size); } else if (isKindOf(slotRawObject(slot), class_int8array)) { PyrInt8Array *arrayObj = slotRawInt8Array(slot); packet->addb(arrayObj->b, arrayObj->size); } else if (isKindOf(slotRawObject(slot), class_array)) { PyrObject *arrayObj = slotRawObject(slot); big_scpacket packet2; if (arrayObj->size > 1 && isKindOfSlot(arrayObj->slots+1, class_array)) { makeSynthBundle(&packet2, arrayObj->slots, arrayObj->size, true); } else { int error = makeSynthMsgWithTags(&packet2, arrayObj->slots, arrayObj->size); if (error != errNone) return error; } packet->addb((uint8*)packet2.data(), packet2.size()); } break; case tagNil : case tagTrue : case tagFalse : case tagChar : case tagPtr : break; default : if (gUseDoubles) packet->addd(slotRawFloat(slot)); else packet->addf(slotRawFloat(slot)); break; } return errNone; } static int addMsgSlotWithTags(big_scpacket *packet, PyrSlot *slot) { switch (GetTag(slot)) { case tagInt : packet->addtag('i'); packet->addi(slotRawInt(slot)); break; case tagSym : packet->addtag('s'); packet->adds(slotRawSymbol(slot)->name); break; case tagObj : if (isKindOf(slotRawObject(slot), class_string)) { PyrString *stringObj = slotRawString(slot); packet->addtag('s'); packet->adds(stringObj->s, stringObj->size); } else if (isKindOf(slotRawObject(slot), class_int8array)) { PyrInt8Array *arrayObj = slotRawInt8Array(slot); packet->addtag('b'); packet->addb(arrayObj->b, arrayObj->size); } else if (isKindOf(slotRawObject(slot), class_array)) { PyrObject *arrayObj = slotRawObject(slot); if (arrayObj->size) { packet->addtag('b'); big_scpacket packet2; if (arrayObj->size > 1 && isKindOfSlot(arrayObj->slots+1, class_array)) { makeSynthBundle(&packet2, arrayObj->slots, arrayObj->size, true); } else { int error = makeSynthMsgWithTags(&packet2, arrayObj->slots, arrayObj->size); if (error != errNone) return error; } packet->addb((uint8*)packet2.data(), packet2.size()); } else { packet->addtag('i'); packet->addi(0); } } break; case tagTrue : packet->addtag('i'); packet->addi(1); break; case tagChar : packet->addtag(slotRawChar(slot)); break; case tagFalse : case tagNil : case tagPtr : packet->addtag('i'); packet->addi(0); break; default : if (gUseDoubles) { packet->addtag('d'); packet->addd(slotRawFloat(slot)); } else { packet->addtag('f'); packet->addf(slotRawFloat(slot)); } break; } return errNone; } static int makeSynthMsgWithTags(big_scpacket *packet, PyrSlot *slots, int size) { packet->BeginMsg(); // First component: OSC Address Pattern. // For convenience, we allow the user to omit the initial '/', when // expressing it as a symbol (e.g. \g_new) - we add it back on here, for OSC compliance. if(GetTag(slots) == tagSym && slotRawSymbol(slots)->name[0]!='/'){ packet->adds_slpre(slotRawSymbol(slots)->name); } else { int error = addMsgSlot(packet, slots); if (error != errNone) return error; } // skip space for tags packet->maketags(size); packet->addtag(','); try { for (int i=1; iEndMsg(); return errNone; } void PerformOSCBundle(int inSize, char *inData, PyrObject *inReply, int inPortNum); void PerformOSCMessage(int inSize, char *inData, PyrObject *inReply, int inPortNum); PyrObject* ConvertReplyAddress(ReplyAddress *inReply); void localServerReplyFunc(struct ReplyAddress *inReplyAddr, char* inBuf, int inSize); void localServerReplyFunc(struct ReplyAddress *inReplyAddr, char* inBuf, int inSize) { bool isBundle = IsBundle(inBuf); pthread_mutex_lock (&gLangMutex); if (compiledOK) { PyrObject *replyObj = ConvertReplyAddress(inReplyAddr); if (isBundle) { PerformOSCBundle(inSize, inBuf, replyObj, gUDPport->RealPortNum()); } else { PerformOSCMessage(inSize, inBuf, replyObj, gUDPport->RealPortNum()); } } pthread_mutex_unlock (&gLangMutex); } int makeSynthBundle(big_scpacket *packet, PyrSlot *slots, int size, bool useElapsed) { double time; int err; int64 oscTime; err = slotDoubleVal(slots, &time); if (!err) { if (useElapsed) { oscTime = ElapsedTimeToOSC(time); } else { oscTime = (int64)(time * kSecondsToOSC); } } else { oscTime = 1; // immediate } packet->OpenBundle(oscTime); for (int i=1; islots, obj->size); if (error != errNone) return error; } } packet->CloseBundle(); return errNone; } int netAddrSend(PyrObject *netAddrObj, int msglen, char *bufptr, bool sendMsgLen=true); int netAddrSend(PyrObject *netAddrObj, int msglen, char *bufptr, bool sendMsgLen) { int err, port, addr; if (IsPtr(netAddrObj->slots + ivxNetAddr_Socket)) { SC_TcpClientPort* comPort = (SC_TcpClientPort*)slotRawPtr(netAddrObj->slots + ivxNetAddr_Socket); // send TCP int tcpSocket = comPort->Socket(); if (sendMsgLen) { // send length of message in network byte-order int32 sizebuf = htonl(msglen); sendall(tcpSocket, &sizebuf, sizeof(int32)); } sendall(tcpSocket, bufptr, msglen); } else { if (gUDPport == 0) return errFailed; // send UDP err = slotIntVal(netAddrObj->slots + ivxNetAddr_Hostaddr, &addr); if (err) return err; if (addr == 0) { #ifndef NO_INTERNAL_SERVER if (gInternalSynthServer.mWorld) { World_SendPacket(gInternalSynthServer.mWorld, msglen, bufptr, &localServerReplyFunc); } #endif return errNone; } err = slotIntVal(netAddrObj->slots + ivxNetAddr_PortID, &port); if (err) return err; struct sockaddr_in toaddr; makeSockAddr(toaddr, addr, port); sendallto(gUDPport->Socket(), bufptr, msglen, (sockaddr*)&toaddr, sizeof(toaddr)); } return errNone; } /////////// inline size_t OSCStrLen(char *str) { return (strlen(str) + 4) & ~3; } int makeSynthBundle(big_scpacket *packet, PyrSlot *slots, int size, bool useElapsed); static void netAddrTcpClientNotifyFunc(void *clientData); void netAddrTcpClientNotifyFunc(void *clientData) { extern bool compiledOK; pthread_mutex_lock(&gLangMutex); if (compiledOK) { PyrObject* netAddrObj = (PyrObject*)clientData; VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, netAddrObj); runInterpreter(g, getsym("prConnectionClosed"), 1); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } int prNetAddr_Connect(VMGlobals *g, int numArgsPushed); int prNetAddr_Connect(VMGlobals *g, int numArgsPushed) { PyrSlot* netAddrSlot = g->sp; PyrObject* netAddrObj = slotRawObject(netAddrSlot); int err, port, addr; err = slotIntVal(netAddrObj->slots + ivxNetAddr_PortID, &port); if (err) return err; err = slotIntVal(netAddrObj->slots + ivxNetAddr_Hostaddr, &addr); if (err) return err; struct sockaddr_in toaddr; makeSockAddr(toaddr, addr, port); int aSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (aSocket == -1) { //post("\nCould not create socket\n"); return errFailed; } const int on = 1; #ifdef SC_WIN32 if (setsockopt( aSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on)) != 0) { #else if (setsockopt( aSocket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) { #endif //post("\nCould not setsockopt TCP_NODELAY\n"); #ifdef SC_WIN32 closesocket(aSocket); #else close(aSocket); #endif return errFailed; }; if(connect(aSocket,(struct sockaddr*)&toaddr,sizeof(toaddr)) != 0) { //post("\nCould not connect socket\n"); #ifdef SC_WIN32 closesocket(aSocket); #else close(aSocket); #endif return errFailed; } SC_TcpClientPort *comPort = new SC_TcpClientPort(aSocket, netAddrTcpClientNotifyFunc, netAddrObj); SetPtr(netAddrObj->slots + ivxNetAddr_Socket, comPort); return errNone; } int prNetAddr_Disconnect(VMGlobals *g, int numArgsPushed); int prNetAddr_Disconnect(VMGlobals *g, int numArgsPushed) { PyrSlot* netAddrSlot = g->sp; PyrObject* netAddrObj = slotRawObject(netAddrSlot); SC_TcpClientPort *comPort = (SC_TcpClientPort*)slotRawPtr(netAddrObj->slots + ivxNetAddr_Socket); if (comPort) comPort->Close(); return errNone; } int prNetAddr_SendMsg(VMGlobals *g, int numArgsPushed); int prNetAddr_SendMsg(VMGlobals *g, int numArgsPushed) { PyrSlot* netAddrSlot = g->sp - numArgsPushed + 1; PyrSlot* args = netAddrSlot + 1; big_scpacket packet; int numargs = numArgsPushed - 1; int error = makeSynthMsgWithTags(&packet, args, numargs); if (error != errNone) return error; //for (int i=0; isp - numArgsPushed + 1; PyrSlot* args = netAddrSlot + 1; big_scpacket packet; double time; int err = slotDoubleVal(args, &time); if (!err) { time += slotRawFloat(&g->thread->seconds); SetFloat(args, time); } int numargs = numArgsPushed - 1; makeSynthBundle(&packet, args, numargs, true); //for (int i=0; isp - 1; PyrSlot* arraySlot = g->sp; PyrObject* netAddrObj = slotRawObject(netAddrSlot); if (!IsObj(arraySlot) || !isKindOf(slotRawObject(arraySlot), class_rawarray)) { error("sendRaw arg must be a kind of RawArray.\n"); return errWrongType; } PyrObject *array = slotRawObject(arraySlot); char *bufptr = (char*)array->slots; int32 msglen = array->size * gFormatElemSize[array->obj_format]; return netAddrSend(netAddrObj, msglen, bufptr, false); } int prNetAddr_GetBroadcastFlag(VMGlobals *g, int numArgsPushed); int prNetAddr_GetBroadcastFlag(VMGlobals *g, int numArgsPushed) { if (gUDPport == 0) return errFailed; int opt; socklen_t optlen = sizeof(opt); #ifdef SC_WIN32 if (getsockopt(gUDPport->Socket(), SOL_SOCKET, SO_BROADCAST, (char *)&opt, &optlen) == -1) #else if (getsockopt(gUDPport->Socket(), SOL_SOCKET, SO_BROADCAST, &opt, &optlen) == -1) #endif return errFailed; SetBool(g->sp, opt); return errNone; } int prNetAddr_SetBroadcastFlag(VMGlobals *g, int numArgsPushed); int prNetAddr_SetBroadcastFlag(VMGlobals *g, int numArgsPushed) { if (gUDPport == 0) return errFailed; int opt = IsTrue(g->sp); #ifdef SC_WIN32 if (setsockopt(gUDPport->Socket(), SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt)) == -1) #else if (setsockopt(gUDPport->Socket(), SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) == -1) #endif return errFailed; return errNone; } int prNetAddr_BundleSize(VMGlobals *g, int numArgsPushed); int prNetAddr_BundleSize(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; big_scpacket packet; int numargs = slotRawObject(args)->size; if (numargs < 1) return errFailed; makeSynthBundle(&packet, slotRawObject(args)->slots, numargs, true); SetInt(args, packet.size()); return errNone; } int prNetAddr_MsgSize(VMGlobals *g, int numArgsPushed); int prNetAddr_MsgSize(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; big_scpacket packet; int numargs = slotRawObject(args)->size; if (numargs < 1) return errFailed; int error = makeSynthMsgWithTags(&packet, slotRawObject(args)->slots, numargs); if (error != errNone) return error; SetInt(args, packet.size()); return errNone; } int prNetAddr_UseDoubles(VMGlobals *g, int numArgsPushed); int prNetAddr_UseDoubles(VMGlobals *g, int numArgsPushed) { //PyrSlot* netAddrSlot = g->sp - 1; PyrSlot* flag = g->sp; gUseDoubles = IsTrue(flag); return errNone; } int prArray_OSCBytes(VMGlobals *g, int numArgsPushed); int prArray_OSCBytes(VMGlobals *g, int numArgsPushed) { PyrSlot* a = g->sp; PyrObject *array = slotRawObject(a); PyrSlot* args = array->slots; int numargs = array->size; if (numargs < 1) return errFailed; big_scpacket packet; if (IsFloat(args) || IsNil(args) || IsInt(args)) { makeSynthBundle(&packet, args, numargs, false); } else if (IsSym(args) || isKindOfSlot(args, class_string)) { int error = makeSynthMsgWithTags(&packet, args, numargs); if (error != errNone) return error; } else { return errWrongType; } int size = packet.size(); PyrInt8Array* obj = newPyrInt8Array(g->gc, size, 0, true); obj->size = size; memcpy(obj->b, packet.data(), size); SetObject(a, (PyrObject*)obj); //for (int i=0; i object and copy data from `msg.getb'. // Bytes are properly untyped, but there is no type. static PyrInt8Array* MsgToInt8Array ( sc_msg_iter msg ) ; static PyrInt8Array* MsgToInt8Array ( sc_msg_iter msg ) { int size = msg.getbsize() ; VMGlobals *g = gMainVMGlobals ; PyrInt8Array *obj = newPyrInt8Array ( g->gc , size , 0 , true ) ; obj->size = size ; msg.getb ( (char *)obj->b , obj->size ) ; return obj ; } PyrObject* ConvertOSCMessage(int inSize, char *inData) { char *cmdName = inData; int cmdNameLen = OSCstrlen(cmdName); sc_msg_iter msg(inSize - cmdNameLen, inData + cmdNameLen); int numElems; if (inSize == cmdNameLen) { numElems = 0; } else { if (!msg.tags) { numElems = 0; error("OSC messages must have type tags. %s\n", cmdName); } else { numElems = strlen(msg.tags); } } //post("tags %s %d\n", msg.tags, numElems); VMGlobals *g = gMainVMGlobals; PyrObject *obj = newPyrArray(g->gc, numElems + 1, 0, false); PyrSlot *slots = obj->slots; SetSymbol(slots+0, getsym(cmdName)); for (int i=0; iname); break; case 'b' : SetObject(slots+i+1, (PyrObject*)MsgToInt8Array(msg)); break; case 'c': SetChar(slots+i+1, (char)msg.geti()); break; // else add the type tag as a char (jrhb 2009) default: SetChar(slots+i+1, tag); msg.gets(); } } obj->size = numElems + 1; return obj; } PyrObject* ConvertReplyAddress(ReplyAddress *inReply) { VMGlobals *g = gMainVMGlobals; PyrObject *obj = instantiateObject(g->gc, s_netaddr->u.classobj, 2, true, false); PyrSlot *slots = obj->slots; SetInt(slots+0, ntohl(inReply->mSockAddr.sin_addr.s_addr)); SetInt(slots+1, ntohs(inReply->mSockAddr.sin_port)); return obj; } void PerformOSCBundle(int inSize, char* inData, PyrObject *replyObj, int inPortNum) { // convert all data to arrays int64 oscTime = OSCtime(inData + 8); double seconds = OSCToElapsedTime(oscTime); VMGlobals *g = gMainVMGlobals; ++g->sp; SetObject(g->sp, g->process); ++g->sp; SetFloat(g->sp, seconds); ++g->sp; SetObject(g->sp, replyObj); ++g->sp; SetInt(g->sp, inPortNum); PyrSlot *stackBase = g->sp; char *data = inData + 16; char* dataEnd = inData + inSize; while (data < dataEnd) { int32 msgSize = OSCint(data); data += sizeof(int32); PyrObject *arrayObj = ConvertOSCMessage(msgSize, data); ++g->sp; SetObject(g->sp, arrayObj); data += msgSize; } int numMsgs = g->sp - stackBase; runInterpreter(g, s_recvoscbndl, 4+numMsgs); } void ConvertOSCBundle(int inSize, char* inData, PyrObject *replyObj) { // convert all data to arrays //int64 oscTime = OSCtime(inData + 8); //double seconds = OSCToElapsedTime(oscTime); VMGlobals *g = gMainVMGlobals; int numMsgs = 0; char *data = inData + 16; char* dataEnd = inData + inSize; while (data < dataEnd) { int32 msgSize = OSCint(data); data += sizeof(int32); PyrObject *arrayObj = ConvertOSCMessage(msgSize, data); ++g->sp; SetObject(g->sp, arrayObj); numMsgs++; data += msgSize; } } void PerformOSCMessage(int inSize, char *inData, PyrObject *replyObj, int inPortNum) { PyrObject *arrayObj = ConvertOSCMessage(inSize, inData); // call virtual machine to handle message VMGlobals *g = gMainVMGlobals; ++g->sp; SetObject(g->sp, g->process); ++g->sp; SetFloat(g->sp, elapsedTime()); // time ++g->sp; SetObject(g->sp, replyObj); ++g->sp; SetInt(g->sp, inPortNum); ++g->sp; SetObject(g->sp, arrayObj); runInterpreter(g, s_recvoscmsg, 5); } void FreeOSCPacket(OSC_Packet *inPacket) { //post("->FreeOSCPacket %p\n", inPacket); if (inPacket) { free(inPacket->mData); free(inPacket); } } void ProcessOSCPacket(OSC_Packet* inPacket, int inPortNum) { //post("recv '%s' %d\n", inPacket->mData, inPacket->mSize); inPacket->mIsBundle = IsBundle(inPacket->mData); pthread_mutex_lock (&gLangMutex); if (compiledOK) { PyrObject *replyObj = ConvertReplyAddress(&inPacket->mReplyAddr); if (compiledOK) { if (inPacket->mIsBundle) { PerformOSCBundle(inPacket->mSize, inPacket->mData, replyObj, inPortNum); } else { PerformOSCMessage(inPacket->mSize, inPacket->mData, replyObj, inPortNum); } } } pthread_mutex_unlock (&gLangMutex); FreeOSCPacket(inPacket); } void init_OSC(int port); void init_OSC(int port) { postfl("init_OSC\n"); #ifdef _WIN32 WSAData wsaData; int nCode; if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) { error( "sclang: init_OSC: WSAStartup() failed with error code %d.\n", nCode ); } #endif try { gUDPport = new SC_UdpInPort(port); } catch (...) { postfl("No networking."); } } int prOpenUDPPort(VMGlobals *g, int numArgsPushed); int prOpenUDPPort(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; int port; int err = slotIntVal(b, &port); if (err) return err; SC_UdpCustomInPort* newUDPport; try { SetTrue(a); newUDPport = new SC_UdpCustomInPort(port); gCustomUdpPorts.push_back(newUDPport); } catch (...) { SetFalse(a); postfl("Could not bind to requested port. This may mean it is in use already by another application.\n"); } return errNone; } void closeAllCustomPorts(); void closeAllCustomPorts() { // close all custom sockets if(gCustomUdpPorts.empty()) postfl("empty\n"); for(int i=0; isp; char hostname[256]; int err = slotStrVal(a, hostname, 255); if (err) return err; struct hostent *he = gethostbyname(hostname); if (!he) { #ifdef _WIN32 int err = WSAGetLastError(); error("gethostbyname(\"%s\") failed with error code %i.\n", hostname, err); #endif return errFailed; } SetInt(a, ntohl(*(int*)he->h_addr)); return errNone; } int prGetLangPort(VMGlobals *g, int numArgsPushed); int prGetLangPort(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (!gUDPport) return errFailed; SetInt(a, gUDPport->RealPortNum()); return errNone; } int prExit(VMGlobals *g, int numArgsPushed); int prExit(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; exit(slotRawInt(a)); //post("exit %d\n", slotRawInt(a)); //DumpBackTrace(g); return errNone; } extern "C" { int vpost(const char *fmt, va_list vargs); } #ifndef NO_INTERNAL_SERVER int prBootInProcessServer(VMGlobals *g, int numArgsPushed); int prBootInProcessServer(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (!gInternalSynthServer.mWorld) { SetPrintFunc(&vpost); WorldOptions options = kDefaultWorldOptions; PyrObject *optionsObj = slotRawObject(a); PyrSlot *optionsSlots = optionsObj->slots; static char mInputStreamsEnabled[512], mOutputStreamsEnabled[512], mDeviceName[512]; int err; err = slotIntVal(optionsSlots + 0, (int*)&options.mNumAudioBusChannels); if (err) return err; err = slotIntVal(optionsSlots + 1, (int*)&options.mNumControlBusChannels); if (err) return err; err = slotIntVal(optionsSlots + 2, (int*)&options.mNumInputBusChannels); if (err) return err; err = slotIntVal(optionsSlots + 3, (int*)&options.mNumOutputBusChannels); if (err) return err; err = slotIntVal(optionsSlots + 4, (int*)&options.mNumBuffers); if (err) return err; err = slotIntVal(optionsSlots + 5, (int*)&options.mMaxNodes); if (err) return err; err = slotIntVal(optionsSlots + 6, (int*)&options.mMaxGraphDefs); if (err) return err; err = slotIntVal(optionsSlots + 8, (int*)&options.mBufLength); if (err) return err; if (NotNil(optionsSlots + 9)) { err = slotIntVal(optionsSlots + 9, (int*)&options.mPreferredHardwareBufferFrameSize); if (err) return err; } err = slotIntVal(optionsSlots + 10, (int*)&options.mRealTimeMemorySize); if (err) return err; err = slotIntVal(optionsSlots + 11, (int*)&options.mNumRGens); if (err) return err; err = slotIntVal(optionsSlots + 12, (int*)&options.mMaxWireBufs); if (err) return err; if (NotNil(optionsSlots + 13)) { err = slotIntVal(optionsSlots + 13, (int*)&options.mPreferredSampleRate); if (err) return err; } options.mLoadGraphDefs = IsTrue(optionsSlots + 14) ? 1 : 0; #ifdef SC_DARWIN err = slotStrVal(optionsSlots+15, mInputStreamsEnabled, 512); if(err) options.mInputStreamsEnabled = NULL; else options.mInputStreamsEnabled = mInputStreamsEnabled; err = slotStrVal(optionsSlots+16, mOutputStreamsEnabled, 512); if(err) options.mOutputStreamsEnabled = NULL; else options.mOutputStreamsEnabled = mOutputStreamsEnabled; #endif err = slotStrVal(optionsSlots+17, mDeviceName, 512); if(err) options.mInDeviceName = options.mOutDeviceName = NULL; else options.mInDeviceName = options.mOutDeviceName = mDeviceName; options.mNumSharedControls = gInternalSynthServer.mNumSharedControls; options.mSharedControls = gInternalSynthServer.mSharedControls; // internal servers use the PID to identify the shared memory region #if defined(SC_IPHONE) options.mSharedMemoryID = 0; #elif !defined(_WIN32) options.mSharedMemoryID = getpid(); #else options.mSharedMemoryID = GetCurrentProcessId(); #endif gInternalSynthServer.mWorld = World_New(&options); } return errNone; } int getScopeBuf(uint32 index, SndBuf *buf, bool& didChange) { if (gInternalSynthServer.mWorld) { int serverErr = World_CopySndBuf(gInternalSynthServer.mWorld, index, buf, true, &didChange); if (serverErr) return errFailed; } else { didChange = false; } return errNone; } void* wait_for_quit(void* thing); void* wait_for_quit(void* thing) { World *world = (World*)thing; World_WaitForQuit(world); return 0; } int prQuitInProcessServer(VMGlobals *g, int numArgsPushed); int prQuitInProcessServer(VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp; if (gInternalSynthServer.mWorld) { World *world = gInternalSynthServer.mWorld; gInternalSynthServer.mWorld = 0; pthread_t thread; pthread_create(&thread, NULL, wait_for_quit, (void*)world); pthread_detach(thread); } return errNone; } #else // is windows int prQuitInProcessServer(VMGlobals *g, int numArgsPushed); int prQuitInProcessServer(VMGlobals *g, int numArgsPushed) { // no-op. Better to have this than to overwrite in lang. return errNone; } #endif //#ifndef SC_WIN32 inline int32 BUFMASK(int32 x) { return (1 << (31 - CLZ(x))) - 1; } int prAllocSharedControls(VMGlobals *g, int numArgsPushed); int prAllocSharedControls(VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (gInternalSynthServer.mWorld) { post("can't allocate while internal server is running\n"); return errNone; } if (gInternalSynthServer.mSharedControls != gDefaultSharedControls) { free(gInternalSynthServer.mSharedControls); gInternalSynthServer.mSharedControls = gDefaultSharedControls; } int numSharedControls; int err = slotIntVal(b, &numSharedControls); if (err) return err; if (numSharedControls <= 0) { gInternalSynthServer.mNumSharedControls = 0; } else if (numSharedControls < kNumDefaultSharedControls) { gInternalSynthServer.mNumSharedControls = numSharedControls; } else { gInternalSynthServer.mNumSharedControls = numSharedControls; gInternalSynthServer.mSharedControls = (float*)calloc(numSharedControls, sizeof(float)); } return errNone; } int prGetSharedControl(VMGlobals *g, int numArgsPushed); int prGetSharedControl(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; int index; int err = slotIntVal(b, &index); if (err) return err; if (index < 0 || index >= gInternalSynthServer.mNumSharedControls) { SetFloat(a, 0.); return errNone; } float val = gInternalSynthServer.mSharedControls[index]; SetFloat(a, val); return errNone; } int prSetSharedControl(VMGlobals *g, int numArgsPushed); int prSetSharedControl(VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int index; int err = slotIntVal(b, &index); if (err) return err; float val; err = slotFloatVal(c, &val); if (err) return err; if (index < 0 || index >= gInternalSynthServer.mNumSharedControls) { return errNone; } gInternalSynthServer.mSharedControls[index] = val; return errNone; } static int disconnectSharedMem(VMGlobals *g, PyrObject * object) { int ptrIndex = 0; PyrSlot * ptrSlot = object->slots + ptrIndex; if (IsNil(ptrSlot)) // already disconnected return errNone; assert(IsPtr(ptrSlot)); server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot); delete client; SetNil(ptrSlot); return errNone; } int prConnectSharedMem(VMGlobals *g, int numArgsPushed) { #if !defined(SC_IPHONE) PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); int portNumber = slotRawInt(b); int ptrIndex = 0; int finalizerIndex = 1; try { server_shared_memory_client * client = new server_shared_memory_client(portNumber); SetPtr(self->slots + ptrIndex, client); InstallFinalizer(g, self, finalizerIndex, disconnectSharedMem); postfl("Shared memory server interface initialized\n"); } catch (std::exception & e) { postfl("Cannot connect to shared memory: %s\n", e.what()); return errFailed; } #else postfl("Warning: Shared memory server interface disabled on iphone\n"); #endif return errNone; } int prDisconnectSharedMem(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); return disconnectSharedMem(g, self); } int prGetControlBusValue(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); int ptrIndex = 0; PyrSlot * ptrSlot = self->slots + ptrIndex; if (NotPtr(ptrSlot)) return errFailed; if (!IsInt(b)) return errFailed; int busIndex = slotRawInt(b); if (NotPtr(ptrSlot)) return errFailed; server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot); float value = client->get_control_busses()[busIndex]; SetFloat(a, value); return errNone; } int prGetControlBusValues(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); int ptrIndex = 0; PyrSlot * ptrSlot = self->slots + ptrIndex; if (NotPtr(ptrSlot)) return errFailed; if (!IsInt(b)) return errFailed; int busIndex = slotRawInt(b); if (!IsInt(c)) return errFailed; int numberOfChannels = slotRawInt(c); server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot); PyrObject * ret = newPyrArray(g->gc, numberOfChannels, 0, 1); ret->size = numberOfChannels; for (int i = 0; i != numberOfChannels; ++i) { float value = client->get_control_busses()[busIndex + i]; SetFloat(ret->slots+i, value); } SetObject(a, ret); return errNone; } int prSetControlBusValue(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); int ptrIndex = 0; PyrSlot * ptrSlot = self->slots + ptrIndex; if (NotPtr(ptrSlot)) return errFailed; if (!IsInt(b)) return errFailed; int busIndex = slotRawInt(b); if (NotPtr(ptrSlot)) return errFailed; float value; int error = slotFloatVal(c, &value); if (error != errNone) return error; server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot); client->get_control_busses()[busIndex] = value; return errNone; } int prSetControlBusValues(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); int ptrIndex = 0; PyrSlot * ptrSlot = self->slots + ptrIndex; if (NotPtr(ptrSlot)) return errFailed; if (!IsInt(b)) return errFailed; int busIndex = slotRawInt(b); if (!IsObj(c)) return errFailed; PyrObject * values = slotRawObject(c); server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot); float * control_busses = client->get_control_busses() + busIndex; for (int i = 0; i != values->size; ++i) { float value; int error = slotFloatVal(values->slots + i, &value); if (error != errNone) return error; control_busses[i] = value; } return errNone; } void init_OSC_primitives(); void init_OSC_primitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_NetAddr_Connect", prNetAddr_Connect, 1, 0); definePrimitive(base, index++, "_NetAddr_Disconnect", prNetAddr_Disconnect, 1, 0); definePrimitive(base, index++, "_NetAddr_SendMsg", prNetAddr_SendMsg, 1, 1); definePrimitive(base, index++, "_NetAddr_SendBundle", prNetAddr_SendBundle, 2, 1); definePrimitive(base, index++, "_NetAddr_SendRaw", prNetAddr_SendRaw, 2, 0); definePrimitive(base, index++, "_NetAddr_GetBroadcastFlag", prNetAddr_GetBroadcastFlag, 1, 0); definePrimitive(base, index++, "_NetAddr_SetBroadcastFlag", prNetAddr_SetBroadcastFlag, 2, 0); definePrimitive(base, index++, "_NetAddr_BundleSize", prNetAddr_BundleSize, 1, 0); definePrimitive(base, index++, "_NetAddr_MsgSize", prNetAddr_MsgSize, 1, 0); definePrimitive(base, index++, "_NetAddr_UseDoubles", prNetAddr_UseDoubles, 2, 0); definePrimitive(base, index++, "_Array_OSCBytes", prArray_OSCBytes, 1, 0); definePrimitive(base, index++, "_GetHostByName", prGetHostByName, 1, 0); definePrimitive(base, index++, "_GetLangPort", prGetLangPort, 1, 0); definePrimitive(base, index++, "_Exit", prExit, 1, 0); #ifndef NO_INTERNAL_SERVER definePrimitive(base, index++, "_BootInProcessServer", prBootInProcessServer, 1, 0); #endif definePrimitive(base, index++, "_QuitInProcessServer", prQuitInProcessServer, 1, 0); definePrimitive(base, index++, "_AllocSharedControls", prAllocSharedControls, 2, 0); definePrimitive(base, index++, "_SetSharedControl", prSetSharedControl, 3, 0); definePrimitive(base, index++, "_GetSharedControl", prGetSharedControl, 2, 0); definePrimitive(base, index++, "_OpenUDPPort", prOpenUDPPort, 2, 0); // server shared memory interface definePrimitive(base, index++, "_ServerShmInterface_connectSharedMem", prConnectSharedMem, 2, 0); definePrimitive(base, index++, "_ServerShmInterface_disconnectSharedMem", prDisconnectSharedMem, 1, 0); definePrimitive(base, index++, "_ServerShmInterface_getControlBusValue", prGetControlBusValue, 2, 0); definePrimitive(base, index++, "_ServerShmInterface_getControlBusValues", prGetControlBusValues, 3, 0); definePrimitive(base, index++, "_ServerShmInterface_setControlBusValue", prSetControlBusValue, 3, 0); definePrimitive(base, index++, "_ServerShmInterface_setControlBusValues", prSetControlBusValues, 3, 0); //post("initOSCRecs###############\n"); s_call = getsym("call"); s_write = getsym("write"); s_recvoscmsg = getsym("recvOSCmessage"); s_recvoscbndl = getsym("recvOSCbundle"); s_netaddr = getsym("NetAddr"); } SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrSignalPrim.cpp0000664000000000000000000003512512014636264026052 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrSymbol.h" #include "PyrKernel.h" #include "PyrObject.h" #include "PyrPrimitive.h" #include "PyrSignal.h" #include "PyrSignalPrim.h" #include "PyrMessage.h" #include "SC_Constants.h" #include "SCBase.h" #include "clz.h" extern "C" { #include "fftlib.h" } #include #include #include int prSignalFill(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int err; float value; a = g->sp - 1; b = g->sp; err = slotFloatVal(b, &value); if (err != errNone) return err; signal_fill(slotRawObject(a), value); return errNone; } int prSignalScale(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int err; float value; a = g->sp - 1; b = g->sp; err = slotFloatVal(b, &value); if (err != errNone) return err; signal_scale(slotRawObject(a), value); return errNone; } int prSignalOffset(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int err; float value; a = g->sp - 1; b = g->sp; err = slotFloatVal(b, &value); if (err != errNone) return err; signal_offset(slotRawObject(a), value); return errNone; } int prSignalString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrString *string; PyrObject *signal; float *x; char str[128]; a = g->sp; slotString(a, str); signal = slotRawObject(a); if (signal->size) { x = (float*)(signal->slots); sprintf(str, "%s[%g .. %g]", slotRawSymbol(&signal->classptr->name)->name, x[0], x[signal->size-1]); } else { sprintf(str, "%s[none]", slotRawSymbol(&signal->classptr->name)->name); } string = newPyrString(g->gc, str, 0, true); SetObject(a, string); return errNone; } int prSignalPeak(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetFloat(a, signal_findpeak(slotRawObject(a))); return errNone; } int prSignalNormalize(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err, start, end; a = g->sp - 2; b = g->sp - 1; c = g->sp; err = slotIntVal(b, &start); if (err) { if (IsNil(c)) start = 0; else return err; } err = slotIntVal(c, &end); if (err) { if (IsNil(c)) end = slotRawObject(a)->size; else return err; } signal_normalize_range(slotRawObject(a), start, end); return errNone; } int prSignalNormalizeTransferFn(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; signal_normalize_transfer_fn(slotRawObject(a)); return errNone; } int prSignalIntegral(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetFloat(a, signal_integral(slotRawObject(a))); return errNone; } int prSignalInvert(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err, start, end; a = g->sp - 2; b = g->sp - 1; c = g->sp; err = slotIntVal(b, &start); if (err) { if (IsNil(c)) start = 0; else return err; } err = slotIntVal(c, &end); if (err) { if (IsNil(c)) end = slotRawObject(a)->size; else return err; } signal_invert_range(slotRawObject(a), start, end); return errNone; } int prSignalReverse(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err, start, end; a = g->sp - 2; b = g->sp - 1; c = g->sp; err = slotIntVal(b, &start); if (err) { if (IsNil(b)) start = 0; else return err; } err = slotIntVal(c, &end); if (err) { if (IsNil(c)) end = slotRawObject(a)->size; else return err; } signal_reverse_range(slotRawObject(a), start, end); return errNone; } int prSignalRotate(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int err, rot; a = g->sp - 1; b = g->sp; err = slotIntVal(b, &rot); if (err) return err; SetRaw(a, signal_rotate(g, slotRawObject(a), rot)); return errNone; } int prSignalOverDub(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err; int index; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(b) || !isKindOf(slotRawObject(b), class_signal)) return errWrongType; err = slotIntVal(c, &index); if (err) return errWrongType; signal_overdub(g, slotRawObject(a), slotRawObject(b), index); return errNone; } int prSignalOverWrite(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err; int index; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(b) || !isKindOf(slotRawObject(b), class_signal)) return errWrongType; err = slotIntVal(c, &index); if (err) return errWrongType; signal_overwrite(g, slotRawObject(a), slotRawObject(b), index); return errNone; } int prSignalFade(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *d, *e; int err; int start, end; float lvl0, lvl1; a = g->sp - 4; b = g->sp - 3; c = g->sp - 2; d = g->sp - 1; e = g->sp; err = slotIntVal(b, &start); if (err) { if (IsNil(b)) start = 0; else return err; } err = slotIntVal(c, &end); if (err) { if (IsNil(c)) end = slotRawObject(a)->size; else return err; } err = slotFloatVal(d, &lvl0); if (err) return err; err = slotFloatVal(e, &lvl1); if (err) return err; signal_fade_range(slotRawObject(a), start, end, lvl0, lvl1); return errNone; } int prSignalAddHarmonic(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *d; int err; float harmonic, amp; double phase, step; PyrObject *signal; float *out; a = g->sp - 3; b = g->sp - 2; c = g->sp - 1; d = g->sp; err = slotFloatVal(b, &harmonic); if (err) return errWrongType; err = slotFloatVal(c, &); if (err) return errWrongType; err = slotDoubleVal(d, &phase); if (err) return errWrongType; signal = slotRawObject(a); out = (float*)(signal->slots) - 1; step = twopi * harmonic / signal->size; UNROLL_CODE(signal->size, out, *++out += sin(phase) * amp; phase += step; ); return errNone; } int prSignalAddChebyshev(struct VMGlobals *g, int numArgsPushed); int prSignalAddChebyshev(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err; float harmonic, amp; double x, step; PyrObject *signal; float *out; a = g->sp - 2; b = g->sp - 1; c = g->sp; err = slotFloatVal(b, &harmonic); if (err) return errWrongType; err = slotFloatVal(c, &); if (err) return errWrongType; signal = slotRawObject(a); out = (float*)(signal->slots) - 1; x = -1.0; step = 2.0 / (signal->size - 1); UNROLL_CODE(signal->size, out, *++out += cos(harmonic * acos(x)) * amp; x += step; ); return errNone; } ////////////////////////////////////////////////////////////////////////////// void signalAsWavetable(float *signal, float *wavetable, int size) { int i, imax; float *in, *out; float val1, val2; in = signal; out = wavetable - 1; imax = size-1; for (i=0; isp; signal = slotRawObject(a); size = signal->size; if ((size & (size - 1)) != 0) { error("Signal size not a power of two.\n"); return errFailed; } wavetable = newPyrSignal(g, signal->size * 2); wavetable->classptr = class_wavetable; signalAsWavetable((float*)signal->slots, (float*)wavetable->slots, signal->size); SetObject(a, wavetable); return errNone; } int prWavetableAsSignal(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrObject *signal, *wavetable; a = g->sp; wavetable = slotRawObject(a); signal = newPyrSignal(g, wavetable->size / 2); wavetableAsSignal((float*)wavetable->slots, (float*)signal->slots, signal->size); SetObject(a, signal); return errNone; } //class_signal #if 1 int prSignal_FFT(struct VMGlobals *g, int numArgsPushed); int prSignal_FFT(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int i, M, fftsize, fftbufsize, asize; float *inreal, *inimag, *fftbuf, *costable, *outreal, *outimag; PyrObject *fftoutobj, *complexobj, *realobj, *imagobj; a = g->sp - 2; b = g->sp - 1; c = g->sp; asize = slotRawObject(a)->size; if (NotNil(b) && !(isKindOfSlot(b, class_signal) && slotRawObject(b)->size == asize)) { error("Signal::fft imaginary part wrong type or length.\n"); return errFailed; } M = LOG2CEIL(asize); fftsize = 1L << M; if (!(isKindOfSlot(c, class_floatarray))) { error("Signal::fft must be provided a table containing 1/4 cycle of a cosine.\n"); return errFailed; } if (slotRawObject(c)->size != fftsize/4+1) { error("Signal::fft cosine table wrong size (%d), expected %d.\n", slotRawObject(c)->size, fftsize/4+1); return errFailed; } costable = (float*)slotRawObject(c)->slots; fftbufsize = fftsize * 2; fftoutobj = newPyrSignal(g, fftbufsize); fftoutobj->size = fftbufsize; ++g->sp; SetObject(g->sp, fftoutobj); complexobj = instantiateObject(g->gc, s_complex->u.classobj, 0, false, true); ++g->sp; SetObject(g->sp, complexobj); realobj = newPyrSignal(g, fftbufsize); SetObject(complexobj->slots + 0, realobj); g->gc->GCWriteNew(complexobj, realobj); imagobj = newPyrSignal(g, fftbufsize); SetObject(complexobj->slots + 1, imagobj); g->gc->GCWriteNew(complexobj, imagobj); inreal = (float*)slotRawObject(a)->slots - 1; if (IsNil(b)) { fftbuf = (float*)fftoutobj->slots - 1; for (i=0; islots; rffts(fftbuf, M, 1, costable); } else { inimag = (float*)slotRawObject(b)->slots - 1; fftbuf = (float*)fftoutobj->slots - 1; for (i=0; islots; ffts(fftbuf, M, 1, costable); } outreal = (float*)realobj->slots - 1; outimag = (float*)imagobj->slots - 1; fftbuf = (float*)fftoutobj->slots - 1; for (i=0; isize = fftsize; imagobj->size = fftsize; g->sp -= 2; SetRaw(a, complexobj); return errNone; } int prSignal_IFFT(struct VMGlobals *g, int numArgsPushed); int prSignal_IFFT(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int i, M, fftsize, fftbufsize, asize; float *inreal, *inimag, *fftbuf, *costable, *outreal, *outimag; PyrObject *fftoutobj, *complexobj, *realobj, *imagobj; a = g->sp - 2; b = g->sp - 1; c = g->sp; asize = slotRawObject(a)->size; if (!(isKindOfSlot(b, class_signal) && slotRawObject(b)->size == asize)) { error("Signal::ifft imaginary part wrong type or length.\n"); return errFailed; } M = LOG2CEIL(asize); fftsize = 1L << M; if (!(isKindOfSlot(c, class_floatarray))) { error("Signal::ifft must be provided a table containing 1/4 cycle of a cosine.\n"); return errFailed; } if (slotRawObject(c)->size != fftsize/4+1) { error("Signal::ifft cosine table wrong size (%d), expected %d.\n", slotRawObject(c)->size, fftsize/4+1); return errFailed; } costable = (float*)slotRawObject(c)->slots; fftbufsize = fftsize * 2; fftoutobj = newPyrSignal(g, fftbufsize); fftoutobj->size = fftbufsize; ++g->sp; SetObject(g->sp, fftoutobj); complexobj = instantiateObject(g->gc, s_complex->u.classobj, 0, false, true); ++g->sp; SetObject(g->sp, complexobj); realobj = newPyrSignal(g, fftbufsize); SetObject(complexobj->slots + 0, realobj); g->gc->GCWriteNew(complexobj, realobj); imagobj = newPyrSignal(g, fftbufsize); SetObject(complexobj->slots + 1, imagobj); g->gc->GCWriteNew(complexobj, imagobj); inreal = (float*)slotRawObject(a)->slots - 1; inimag = (float*)slotRawObject(b)->slots - 1; fftbuf = (float*)fftoutobj->slots - 1; for (i=0; islots; iffts(fftbuf, M, 1, costable); outreal = (float*)realobj->slots - 1; outimag = (float*)imagobj->slots - 1; fftbuf = (float*)fftoutobj->slots - 1; for (i=0; isize = fftsize; imagobj->size = fftsize; g->sp -= 2; SetRaw(a, complexobj); return errNone; } #endif void initSignalPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_SignalPeak", prSignalPeak, 1, 0); definePrimitive(base, index++, "_SignalNormalize", prSignalNormalize, 3, 0); definePrimitive(base, index++, "_SignalNormalizeTransferFn", prSignalNormalizeTransferFn, 1, 0); definePrimitive(base, index++, "_SignalIntegral", prSignalIntegral, 1, 0); definePrimitive(base, index++, "_SignalReverse", prSignalReverse, 3, 0); definePrimitive(base, index++, "_SignalInvert", prSignalInvert, 3, 0); definePrimitive(base, index++, "_SignalRotate", prSignalRotate, 2, 0); definePrimitive(base, index++, "_SignalFill", prSignalFill, 2, 0); definePrimitive(base, index++, "_SignalScale", prSignalScale, 2, 0); definePrimitive(base, index++, "_SignalOffset", prSignalOffset, 2, 0); definePrimitive(base, index++, "_SignalOverDub", prSignalOverDub, 3, 0); definePrimitive(base, index++, "_SignalOverWrite", prSignalOverWrite, 3, 0); definePrimitive(base, index++, "_SignalFade", prSignalFade, 5, 0); definePrimitive(base, index++, "_SignalAddHarmonic", prSignalAddHarmonic, 4, 0); definePrimitive(base, index++, "_SignalAddChebyshev", prSignalAddChebyshev, 3, 0); definePrimitive(base, index++, "_SignalString", prSignalString, 1, 0); definePrimitive(base, index++, "_SignalAsWavetable", prSignalAsWavetable, 1, 0); definePrimitive(base, index++, "_WavetableAsSignal", prWavetableAsSignal, 1, 0); definePrimitive(base, index++, "_Signal_FFT", prSignal_FFT, 3, 0); definePrimitive(base, index++, "_Signal_IFFT", prSignal_IFFT, 3, 0); } SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrBitPrim.cpp0000664000000000000000000001061612014636264025351 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for some bit operations. */ #include "PyrPrimitive.h" #include "VMGlobals.h" #include "clz.h" int prNumBits(VMGlobals *g, int numArgsPushed); int prNumBits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetRaw(a, NUMBITS(slotRawInt(a))); return errNone; } int prLog2Ceil(VMGlobals *g, int numArgsPushed); int prLog2Ceil(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetRaw(a, LOG2CEIL(slotRawInt(a))); return errNone; } int prCLZ(VMGlobals *g, int numArgsPushed); int prCLZ(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetRaw(a, CLZ(slotRawInt(a))); return errNone; } int prCTZ(VMGlobals *g, int numArgsPushed); int prCTZ(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetRaw(a, CTZ(slotRawInt(a))); return errNone; } int prNextPowerOfTwo(VMGlobals *g, int numArgsPushed); int prNextPowerOfTwo(VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetRaw(a, NEXTPOWEROFTWO(slotRawInt(a))); return errNone; } int prIsPowerOfTwo(VMGlobals *g, int numArgsPushed); int prIsPowerOfTwo(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetBool(a, ISPOWEROFTWO(slotRawInt(a))); return errNone; } int prBinaryGrayCode(VMGlobals *g, int numArgsPushed); int prBinaryGrayCode(VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetRaw(a, GRAYCODE(slotRawInt(a))); return errNone; } int prSetBit(VMGlobals *g, int numArgsPushed); int prSetBit(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int32 bit, mask; int err = slotIntVal(b, &bit); if (err) return err; bit = bit & 31; mask = 1L << bit; if (IsFalse(c)) { SetRaw(a, slotRawInt(a) & ~mask); } else { SetRaw(a, slotRawInt(a) | mask); } return errNone; } int prHammingDistance(VMGlobals *g, int numArgsPushed); int prHammingDistance(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (NotInt(a) || NotInt(b)) return errWrongType; int aInt = slotRawInt(a); int bInt = slotRawInt(b); int count = 0, mask = 1; for(int i = 0; i < 32; i++) { if((aInt & mask) != (bInt & mask)) count = count + 1; mask = mask << 1; } SetRaw(a, count); return errNone; } void initBitPrimitives(); void initBitPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_NextPowerOfTwo", prNextPowerOfTwo, 1, 0); definePrimitive(base, index++, "_IsPowerOfTwo", prIsPowerOfTwo, 1, 0); definePrimitive(base, index++, "_CLZ", prCLZ, 1, 0); definePrimitive(base, index++, "_CTZ", prCTZ, 1, 0); definePrimitive(base, index++, "_NumBits", prNumBits, 1, 0); definePrimitive(base, index++, "_Log2Ceil", prLog2Ceil, 1, 0); definePrimitive(base, index++, "_SetBit", prSetBit, 3, 0); definePrimitive(base, index++, "_BinaryGrayCode", prBinaryGrayCode, 1, 0); definePrimitive(base, index++, "_HammingDistance", prHammingDistance, 2, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" // export the function that SC will call to load the plug in. #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initBitPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/SC_LID.cpp0000664000000000000000000004547112245365552024321 0ustar rootroot/* Linux Input Device support. Copyright (c) 2004 stefan kersten. modifications by Marije Baalman 2006-9 ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Linux Input Device interface, 2004 */ #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #include #include "SC_LanguageClient.h" #if HAVE_LID #include #include #include #include #include #include #include #include #define BITS_PER_LONG (sizeof(long) * 8) #define NBITS(x) ((((x) - 1) / BITS_PER_LONG) + 1) #define OFF(x) ((x) % BITS_PER_LONG) #define BIT(x) (1UL << OFF(x)) #define LONG(x) ((x) / BITS_PER_LONG) #define TEST_BIT(array, bit) (((array)[LONG(bit)] >> OFF(bit)) & 1) extern bool compiledOK; static PyrSymbol* s_inputDeviceClass = 0; static PyrSymbol* s_inputDeviceInfoClass = 0; static PyrSymbol* s_absInfoClass = 0; static PyrSymbol* s_handleEvent = 0; static PyrSymbol* s_readError = 0; // ===================================================================== // SC_LID struct SC_LID { SC_LID(PyrObject *obj); ~SC_LID(); int open(const char *path); int close(); bool isEventTypeSupported(int evtType); bool isEventCodeSupported(int evtType, int evtCode); int getName(char* buf, size_t size); int getInfo(struct input_id *info, char *bufPhys, size_t sizePhys, char *bufUniq, size_t sizeUniq); int getKeyState(int evtCode); int getAbsInfo(int evtCode, struct input_absinfo *info); int setLedState( int evtCode, int evtValue, int evtType ); int grab(int flag); void handleEvent(struct input_event& evt, boost::atomic const & shouldBeRunning); void readError(boost::atomic const & shouldBeRunning); static PyrObject* getObject(PyrSlot* slot) { return isKindOfSlot(slot, s_inputDeviceClass->u.classobj) ? slotRawObject(slot) : 0; } static SC_LID* getDevice(PyrObject* obj) { return (SC_LID*)slotRawPtr(&obj->slots[0]); } SC_LID* m_next; PyrObject* m_obj; int m_fd; int m_lastEventType; unsigned long m_eventTypeCaps[NBITS(EV_MAX)]; unsigned long m_eventCodeCaps[NBITS(KEY_MAX)]; unsigned long m_keyState[NBITS(KEY_MAX)]; }; // ===================================================================== // SC_LIDManager struct SC_LIDManager { public: static SC_LIDManager& instance(); int start(); int stop(); int add(SC_LID *dev); int remove(SC_LID *dev); private: SC_LIDManager(); ~SC_LIDManager(); enum { kStop, kAdd, kRemove }; struct Command { int id; union { SC_LID* dev; } arg; }; int sendCommand(const Command& cmd); void devicesChanged(); bool asyncAddDevice(SC_LID *dev); bool asyncRemoveDevice(SC_LID *dev); void loop(); static void* threadFunc(void*); pthread_t m_thread; pthread_mutex_t m_mutex; boost::atomic m_running; boost::atomic mShouldBeRunning; int m_cmdFifo[2]; int m_nfds; fd_set m_fds; SC_LID* m_devices; }; // ===================================================================== // SC_LID SC_LID::SC_LID(PyrObject* obj) : m_next(0), m_obj(obj), m_fd(-1), m_lastEventType(-1) { SetPtr(obj->slots+0, this); } SC_LID::~SC_LID() { if (m_fd != -1) ::close(m_fd); } int SC_LID::open(const char* path) { m_fd = ::open(path, O_RDWR); if (m_fd == -1) { error("LID (1): %s\n", strerror(errno)); return errFailed; } memset(m_eventTypeCaps, 0, sizeof(m_eventTypeCaps)); if (ioctl(m_fd, EVIOCGBIT(0, EV_MAX), m_eventTypeCaps) == -1) { error("LID (2): %s\n", strerror(errno)); return errFailed; } memset(m_keyState, 0, sizeof(m_keyState)); if (ioctl(m_fd, EVIOCGKEY(sizeof(m_keyState)), m_keyState) == -1) { error("LID (3): %s\n", strerror(errno)); return errFailed; } return SC_LIDManager::instance().add(this); } int SC_LID::close() { SetNil(m_obj->slots+0); return SC_LIDManager::instance().remove(this); } bool SC_LID::isEventTypeSupported(int evtType) { return TEST_BIT(m_eventTypeCaps, evtType); } bool SC_LID::isEventCodeSupported(int evtType, int evtCode) { if (evtType != m_lastEventType) { m_lastEventType = evtType; memset(m_eventCodeCaps, 0, sizeof(m_eventCodeCaps)); if (ioctl(m_fd, EVIOCGBIT(evtType, KEY_MAX), m_eventCodeCaps) == -1) { post("LID failed to check event code (error %s)\n", strerror(errno)); return false; } } return TEST_BIT(m_eventCodeCaps, evtCode); } int SC_LID::getName(char* buf, size_t size) { if (ioctl(m_fd, EVIOCGNAME(size), buf) == -1) { error("LID (5): %s\n", strerror(errno)); return errFailed; } return errNone; } int SC_LID::getInfo(struct input_id *info, char *bufPhys, size_t sizePhys, char *bufUniq, size_t sizeUniq) { if (ioctl(m_fd, EVIOCGID, info) == -1) { error("LID (6): %s\n", strerror(errno)); return errFailed; } if (ioctl(m_fd, EVIOCGPHYS(sizePhys), bufPhys) == -1) { // strcpy( sizePhys, strerror(errno)); post("LID could not retrieve physical location (error: %s)\n", strerror(errno)); // return errFailed; } if (ioctl(m_fd, EVIOCGUNIQ(sizeUniq), bufUniq) == -1) { // strcpy( strerror(errno), sizeof( strerror(errno)), sizeUniq ); post("LID could not get unique identifier (error: %s)\n", strerror(errno)); // return errFailed; } return errNone; } int SC_LID::getKeyState(int evtCode) { return TEST_BIT(m_keyState, evtCode); } int SC_LID::getAbsInfo(int evtCode, struct input_absinfo* info) { if (ioctl(m_fd, EVIOCGABS(evtCode), info) == -1) { error("LID (9): %s\n", strerror(errno)); return errFailed; } return errNone; } int SC_LID::setLedState( int evtCode, int evtValue, int evtType ) { // added by marije baalman struct input_event ev; // post( "set led state called, putting event" ); ev.code = evtCode; ev.value = evtValue; ev.type = evtType; // post( "m_fd %i", m_fd ); // post( "code %i, value %i ", evtCode, evtValue ); if ( write(m_fd, &ev, sizeof(struct input_event)) == -1 ) { // post( "error writing event" ); return errFailed; } return errNone; } int SC_LID::grab(int flag) { if (ioctl(m_fd, EVIOCGRAB, flag) == -1) { error("LID (10): %s\n", strerror(errno)); return errFailed; } return errNone; } void SC_LID::handleEvent(struct input_event& evt, boost::atomic const & shouldBeRunning) { if (evt.type != EV_SYN) { int status = lockLanguageOrQuit(shouldBeRunning); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetInt(g->sp, evt.type); ++g->sp; SetInt(g->sp, evt.code); ++g->sp; SetInt(g->sp, evt.value); runInterpreter(g, s_handleEvent, 4); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } } void SC_LID::readError(boost::atomic const & shouldBeRunning) { int status = lockLanguageOrQuit(shouldBeRunning); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, s_readError, 1); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } // ===================================================================== // SC_LIDManager SC_LIDManager& SC_LIDManager::instance() { static SC_LIDManager instance; return instance; } SC_LIDManager::SC_LIDManager() : m_running(false), m_devices(0) { if (pipe(m_cmdFifo) == -1) { m_cmdFifo[0] = m_cmdFifo[1] = -1; } devicesChanged(); } SC_LIDManager::~SC_LIDManager() { close(m_cmdFifo[0]); close(m_cmdFifo[1]); } int SC_LIDManager::start() { mShouldBeRunning = true; int err = pthread_create(&m_thread, 0, &threadFunc, this); if (err != 0) return errFailed; return errNone; } int SC_LIDManager::stop() { if (m_running == false) return errNone; Command cmd; cmd.id = kStop; int err = sendCommand(cmd); if (err) return err; mShouldBeRunning = false; err = pthread_join(m_thread, 0); if (err != 0) return errFailed; return errNone; } int SC_LIDManager::add(SC_LID* dev) { Command cmd; cmd.id = kAdd; cmd.arg.dev = dev; return sendCommand(cmd); } int SC_LIDManager::remove(SC_LID* dev) { Command cmd; cmd.id = kRemove; cmd.arg.dev = dev; return sendCommand(cmd); } int SC_LIDManager::sendCommand(const Command& cmd) { return write(m_cmdFifo[1], &cmd, sizeof(cmd)) == sizeof(cmd) ? errNone : errFailed; } void SC_LIDManager::devicesChanged() { int fdMax = m_cmdFifo[0]; FD_ZERO(&m_fds); FD_SET(fdMax, &m_fds); SC_LID *dev = m_devices; while (dev) { int fd = dev->m_fd; if (fd != -1) { FD_SET(fd, &m_fds); if (fd > fdMax) fdMax = fd; } dev = dev->m_next; } m_nfds = fdMax + 1; } bool SC_LIDManager::asyncAddDevice(SC_LID* dev) { if (dev->m_next) return false; dev->m_next = m_devices; m_devices = dev; devicesChanged(); return true; } bool SC_LIDManager::asyncRemoveDevice(SC_LID* dev) { SC_LID *prev = 0, *cur = m_devices; while (cur) { if (cur == dev) { if (prev) prev->m_next = dev->m_next; else m_devices = dev->m_next; dev->m_next = 0; delete dev; devicesChanged(); return true; } prev = cur; cur = cur->m_next; } return false; } void* SC_LIDManager::threadFunc(void* arg) { ((SC_LIDManager*)arg)->loop(); return 0; } void SC_LIDManager::loop() { m_running = true; post("LID: event loop started\n"); while (true) { fd_set fds; memcpy(&fds, &m_fds, sizeof(fd_set)); int n = select(m_nfds, &fds, 0, 0, 0); if (n == -1) { if( errno == EINTR ) continue; post("LID: error in input handler: %s\n", strerror(errno)); goto quit; } else if (n > 0) { if (FD_ISSET(m_cmdFifo[0], &fds)) { Command cmd; --n; int err = read(m_cmdFifo[0], &cmd, sizeof(cmd)); if (err == -1) { if( errno != EINTR ) { post("LID: error in input handler: %s\n", strerror(errno)); goto quit; } } else { switch (cmd.id) { case kStop: goto quit; case kAdd: if (asyncAddDevice(cmd.arg.dev)) { post("LID: added device %p\n", cmd.arg); } else { post("LID: cannot add device\n"); } break; case kRemove: if (asyncRemoveDevice(cmd.arg.dev)) { post("LID: removed device %p\n", cmd.arg); } else { post("LID: couldn't remove device\n"); } break; default: post("LID: unknown command in input handler\n"); } } } if (n > 0) { SC_LID *dev = m_devices; while (dev) { int fd = dev->m_fd; if (FD_ISSET(fd, &fds)) { struct input_event evt; if (read(fd, &evt, sizeof(evt)) == sizeof(evt)) { dev->handleEvent(evt, mShouldBeRunning); } else { dev->readError(mShouldBeRunning); } } if (!mShouldBeRunning) goto quit; dev = dev->m_next; } } } } quit: m_running = false; post("LID: event loop stopped\n"); } // ===================================================================== // Primitive Interface int prLID_Open(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; char path[PATH_MAX]; err = slotStrVal(args+1, path, sizeof(path)); if (err) return err; SC_LID* dev = new SC_LID(obj); err = dev->open(path); if (err) { delete dev; return err; } return errNone; } int prLID_Close(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; return dev->close(); } int prLID_EventTypeSupported(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int evtType; int err; if (!g->canCallOS) return errCantCallOS; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtType); if (err) return err; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; SetBool(args, dev->isEventTypeSupported(evtType)); return errNone; } int prLID_EventCodeSupported(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 2; int evtType, evtCode; int err; if (!g->canCallOS) return errCantCallOS; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtType); if (err) return err; err = slotIntVal(args+2, &evtCode); if (err) return err; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; SetBool(args, dev->isEventCodeSupported(evtType, evtCode)); return errNone; } int prLID_GetInfo(VMGlobals* g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; if (!isKindOfSlot(args+1, s_inputDeviceInfoClass->u.classobj)) return errWrongType; PyrObject* infoObj = slotRawObject(&args[1]); SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; char name[128]; err = dev->getName(name, sizeof(name)); if (err) return err; struct input_id info; char namePhys[128]; char nameUniq[128]; err = dev->getInfo(&info, namePhys, sizeof( namePhys ), nameUniq, sizeof( nameUniq ) ); if (err) return err; SetSymbol(infoObj->slots+0, getsym(name)); SetInt(infoObj->slots+1, info.bustype); SetInt(infoObj->slots+2, info.vendor); SetInt(infoObj->slots+3, info.product); SetInt(infoObj->slots+4, info.version); SetSymbol(infoObj->slots+5, getsym(namePhys)); SetSymbol(infoObj->slots+6, getsym(nameUniq)); slotCopy(&args[0], &args[1]); return errNone; } int prLID_GetKeyState(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int evtCode; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtCode); if (err) return err; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; SetInt(args, dev->getKeyState(evtCode)); return errNone; } int prLID_GetAbsInfo(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 2; int evtCode; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtCode); if (err) return err; if (!isKindOfSlot(args+2, s_absInfoClass->u.classobj)) return errWrongType; PyrObject* infoObj = slotRawObject(&args[2]); SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; struct input_absinfo info; err = dev->getAbsInfo(evtCode, &info); if (err) return err; SetInt(infoObj->slots+0, info.value); SetInt(infoObj->slots+1, info.minimum); SetInt(infoObj->slots+2, info.maximum); SetInt(infoObj->slots+3, info.fuzz); SetInt(infoObj->slots+4, info.flat); slotCopy(&args[0], &args[2]); return errNone; } int prLID_Grab(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; return dev->grab(IsTrue(args+1)); } int prLID_Start(VMGlobals* g, int numArgsPushed) { // if (!g->canCallOS) return errCantCallOS; return SC_LIDManager::instance().start(); } int prLID_Stop(VMGlobals* g, int numArgsPushed) { // if (!g->canCallOS) return errCantCallOS; return SC_LIDManager::instance().stop(); } int prLID_SetLedState(VMGlobals *g, int numArgsPushed) { // post( "set led state primitive called" ); PyrSlot* args = g->sp - 2; int evtCode, evtValue; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtCode); if (err) return err; err = slotIntVal(args+2, &evtValue); if (err) return err; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; SetInt(args, dev->setLedState(evtCode,evtValue, EV_LED)); return errNone; } int prLID_SetMscState(VMGlobals *g, int numArgsPushed) { // post( "set msc state primitive called\n" ); PyrSlot* args = g->sp - 2; int evtCode, evtValue; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtCode); if (err) return err; err = slotIntVal(args+2, &evtValue); if (err) return err; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; SetInt(args, dev->setLedState(evtCode,evtValue, EV_MSC)); return errNone; } void SC_LIDInit() { int base, index; s_inputDeviceClass = getsym("LID"); s_inputDeviceInfoClass = getsym("LIDInfo"); s_absInfoClass = getsym("LIDAbsInfo"); s_handleEvent = getsym("prHandleEvent"); s_readError = getsym("prReadError"); base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_LID_Open", prLID_Open, 2, 0); definePrimitive(base, index++, "_LID_Close", prLID_Close, 1, 0); definePrimitive(base, index++, "_LID_EventTypeSupported", prLID_EventTypeSupported, 2, 0); definePrimitive(base, index++, "_LID_EventCodeSupported", prLID_EventCodeSupported, 3, 0); definePrimitive(base, index++, "_LID_GetInfo", prLID_GetInfo, 2, 0); definePrimitive(base, index++, "_LID_GetKeyState", prLID_GetKeyState, 2, 0); definePrimitive(base, index++, "_LID_GetAbsInfo", prLID_GetAbsInfo, 3, 0); definePrimitive(base, index++, "_LID_Grab", prLID_Grab, 2, 0); definePrimitive(base, index++, "_LID_Start", prLID_Start, 1, 0); definePrimitive(base, index++, "_LID_Stop", prLID_Stop, 1, 0); definePrimitive(base, index++, "_LID_SetLedState", prLID_SetLedState, 3, 0); // added by Marije Baalman definePrimitive(base, index++, "_LID_SetMscState", prLID_SetMscState, 3, 0); } #else // !HAVE_LID int prLID_Start(VMGlobals* g, int numArgsPushed) { return errNone; } int prLID_Stop(VMGlobals* g, int numArgsPushed) { return errNone; } void SC_LIDInit() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_LID_Start", prLID_Start, 1, 0); definePrimitive(base, index++, "_LID_Stop", prLID_Stop, 1, 0); } #endif // HAVE_LID void initHIDPrimitives() { SC_LIDInit(); } // EOF SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrCharPrim.cpp0000664000000000000000000001416112161364457025514 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for Char. */ #include #include "PyrPrimitive.h" #include "VMGlobals.h" int prToLower(struct VMGlobals *g, int numArgsPushed); int prToLower(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetRawChar(a, tolower(slotRawChar(a))); return errNone; } int prToUpper(struct VMGlobals *g, int numArgsPushed); int prToUpper(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetRawChar(a, toupper(slotRawChar(a))); return errNone; } int prIsLower(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (islower(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsUpper(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (isupper(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsAlpha(struct VMGlobals *g, int numArgsPushed); int prIsAlpha(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (isalpha(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsAlphaNum(struct VMGlobals *g, int numArgsPushed); int prIsAlphaNum(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (isalnum(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsControl(struct VMGlobals *g, int numArgsPushed); int prIsControl(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (iscntrl(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsDigit(struct VMGlobals *g, int numArgsPushed); int prIsDigit(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (isdigit(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsPrint(struct VMGlobals *g, int numArgsPushed); int prIsPrint(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (isprint(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsPunct(struct VMGlobals *g, int numArgsPushed); int prIsPunct(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (ispunct(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsSpace(struct VMGlobals *g, int numArgsPushed); int prIsSpace(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (isspace(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prAsciiValue(struct VMGlobals *g, int numArgsPushed); int prAsciiValue(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetTagRaw(a, tagInt); return errNone; } int prDigitValue(struct VMGlobals *g, int numArgsPushed); int prDigitValue(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; char c; a = g->sp; c = slotRawChar(a); if (c >= '0' && c <= '9') { SetInt(a, c - '0'); } else if (c >= 'a' && c <= 'z') { SetInt(a, c - 'a' + 10); } else if (c >= 'A' && c <= 'Z') { SetInt(a, c - 'A' + 10); } else { return errFailed; } return errNone; } int prAsAscii(struct VMGlobals *g, int numArgsPushed); int prAsAscii(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetChar(a, slotRawInt(a) & 255); return errNone; } int prAsDigit(struct VMGlobals *g, int numArgsPushed); int prAsDigit(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; int c; a = g->sp; c = slotRawInt(a); if (c >= 0 && c <= 9) { SetChar(a, slotRawInt(a) + '0'); } else if (c >= 10 && c <= 35) { SetChar(a, slotRawInt(a) + 'A' - 10); } else { return errFailed; } return errNone; } void initCharPrimitives(); void initCharPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_AsciiValue", prAsciiValue, 1, 0); definePrimitive(base, index++, "_DigitValue", prDigitValue, 1, 0); definePrimitive(base, index++, "_AsAscii", prAsAscii, 1, 0); definePrimitive(base, index++, "_AsDigit", prAsDigit, 1, 0); definePrimitive(base, index++, "_ToLower", prToLower, 1, 0); definePrimitive(base, index++, "_ToUpper", prToUpper, 1, 0); definePrimitive(base, index++, "_IsLower", prIsLower, 1, 0); definePrimitive(base, index++, "_IsUpper", prIsUpper, 1, 0); definePrimitive(base, index++, "_IsAlpha", prIsAlpha, 1, 0); definePrimitive(base, index++, "_IsAlphaNum", prIsAlphaNum, 1, 0); definePrimitive(base, index++, "_IsPrint", prIsPrint, 1, 0); definePrimitive(base, index++, "_IsPunct", prIsPunct, 1, 0); definePrimitive(base, index++, "_IsControl", prIsControl, 1, 0); definePrimitive(base, index++, "_IsSpace", prIsSpace, 1, 0); definePrimitive(base, index++, "_IsDecDigit", prIsDigit, 1, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" // export the function that SC will call to load the plug in. #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initCharPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrUnixPrim.cpp0000664000000000000000000002347612245365552025573 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for Unix. */ #include #include #include #include #include "PyrPrimitive.h" #include "PyrObject.h" #include "PyrKernel.h" #include "PyrSched.h" #include "VMGlobals.h" #include "GC.h" #include "SC_RGen.h" #include "SC_DirUtils.h" #include "sc_popen.h" #include "SCBase.h" #ifdef SC_WIN32 #include "SC_Win32Utils.h" #else #include #endif extern bool compiledOK; PyrSymbol* s_unixCmdAction; int prString_System(struct VMGlobals *g, int numArgsPushed); int prString_System(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char cmdline[1024]; int err = slotStrVal(a, cmdline, 1023); if (err) return err; int res = system(cmdline); SetInt(a, res); return errNone; } int prString_Basename(struct VMGlobals *g, int numArgsPushed); int prString_Basename(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char path[PATH_MAX]; int err = slotStrVal(a, path, PATH_MAX); if (err) return err; char *basename0 = basename(path); int size = strlen(basename0); PyrString *strobj = newPyrStringN(g->gc, size, 0, true); memcpy(strobj->s, basename0, size); SetObject(a, strobj); return errNone; } int prString_Dirname(struct VMGlobals *g, int numArgsPushed); int prString_Dirname(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char path[PATH_MAX]; int err = slotStrVal(a, path, PATH_MAX); if (err) return err; char *dirname0 = dirname(path); int size = strlen(dirname0); PyrString *strobj = newPyrStringN(g->gc, size, 0, true); memcpy(strobj->s, dirname0, size); SetObject(a, strobj); return errNone; } struct sc_process { pid_t pid; FILE *stream; bool postOutput; }; void* string_popen_thread_func(void *data); void* string_popen_thread_func(void *data) { struct sc_process *process = (struct sc_process *)data; FILE *stream = process->stream; pid_t pid = process->pid; char buf[1024]; while (process->postOutput) { char *string = fgets(buf, 1024, stream); if (!string) break; postText(string, strlen(string)); } int res; res = sc_pclose(stream, pid); res = WEXITSTATUS(res); if(process->postOutput) postfl("RESULT = %d\n", res); free(process); pthread_mutex_lock (&gLangMutex); if(compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, class_string); ++g->sp; SetInt(g->sp, res); ++g->sp; SetInt(g->sp, pid); runInterpreter(g, s_unixCmdAction, 3); g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); return 0; } int prString_POpen(struct VMGlobals *g, int numArgsPushed); int prString_POpen(struct VMGlobals *g, int numArgsPushed) { struct sc_process *process; PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; int err; if (!isKindOfSlot(a, class_string)) return errWrongType; char *cmdline = (char*)malloc(slotRawObject(a)->size + 1); err = slotStrVal(a, cmdline, slotRawObject(a)->size + 1); if(err) { free(cmdline); return errFailed; } #ifdef SC_IPHONE SetInt(a, 0); return errNone; #endif process = (struct sc_process *)malloc(sizeof(struct sc_process)); process->stream = sc_popen(cmdline, &process->pid, "r"); setvbuf(process->stream, 0, _IONBF, 0); process->postOutput = IsTrue(b); free(cmdline); if(process->stream == NULL) { free(process); return errFailed; } pthread_t thread; pthread_create(&thread, NULL, string_popen_thread_func, (void*)process); pthread_detach(thread); SetInt(a, process->pid); return errNone; } int prPidRunning(VMGlobals *g, int numArgsPushed); int prPidRunning(VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; #ifdef SC_WIN32 HANDLE handle; handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, slotRawInt(a)); if(handle) { unsigned long exitCode; if(GetExitCodeProcess(handle, &exitCode) == 0) SetFalse(a); else if(exitCode == STILL_ACTIVE) SetTrue(a); CloseHandle(handle); } else SetFalse(a); #else if(kill(slotRawInt(a), 0) == 0) SetTrue(a); else SetFalse(a); #endif return errNone; } int prUnix_Errno(struct VMGlobals *g, int numArgsPushed); int prUnix_Errno(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, errno); return errNone; } #include #ifndef SC_WIN32 #include #endif double bootSeconds(); int prLocalTime(struct VMGlobals *g, int numArgsPushed); int prLocalTime(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrSlot *slots = slotRawObject(a)->slots; struct timeval tv; gettimeofday(&tv, 0); struct tm* tm = localtime((const time_t*)&tv.tv_sec); SetInt(slots+0, tm->tm_year + 1900); SetInt(slots+1, tm->tm_mon + 1); // 0 based month ?? SetInt(slots+2, tm->tm_mday); SetInt(slots+3, tm->tm_hour); SetInt(slots+4, tm->tm_min); SetInt(slots+5, tm->tm_sec); SetInt(slots+6, tm->tm_wday); SetFloat(slots+7, tv.tv_sec + 1e-6 * tv.tv_usec); SetFloat(slots+8, bootSeconds()); return errNone; } int prGMTime(struct VMGlobals *g, int numArgsPushed); int prGMTime(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrSlot *slots = slotRawObject(a)->slots; struct timeval tv; gettimeofday(&tv, 0); struct tm* tm = gmtime((const time_t*)&tv.tv_sec); SetInt(slots+0, tm->tm_year + 1900); SetInt(slots+1, tm->tm_mon + 1); SetInt(slots+2, tm->tm_mday); SetInt(slots+3, tm->tm_hour); SetInt(slots+4, tm->tm_min); SetInt(slots+5, tm->tm_sec); SetInt(slots+6, tm->tm_wday); SetFloat(slots+7, tv.tv_sec + 1e-6 * tv.tv_usec); SetFloat(slots+8, bootSeconds()); return errNone; } int prAscTime(struct VMGlobals *g, int numArgsPushed); int prAscTime(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrSlot *slots = slotRawObject(a)->slots; if (IsNil(slots + 0)) { SetNil(a); return errNone; } struct tm tm0; if (slotIntVal(slots+0, &tm0.tm_year)) return errWrongType; tm0.tm_year -= 1900; if (slotIntVal(slots+1, &tm0.tm_mon)) return errWrongType; tm0.tm_mon -- ; if (slotIntVal(slots+2, &tm0.tm_mday)) return errWrongType; if (slotIntVal(slots+3, &tm0.tm_hour)) return errWrongType; if (slotIntVal(slots+4, &tm0.tm_min)) return errWrongType; if (slotIntVal(slots+5, &tm0.tm_sec)) return errWrongType; if (slotIntVal(slots+6, &tm0.tm_wday)) return errWrongType; const char *text = asctime(&tm0); int size = strlen(text) - 1; // Discard trailing newline PyrString *strobj = newPyrStringN(g->gc, size, 0, true); memcpy(strobj->s, text, size); SetObject(a, strobj); return errNone; } int prStrFTime(struct VMGlobals *g, int numArgsPushed); int prStrFTime(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; PyrSlot *slots = slotRawObject(a)->slots; if (IsNil(slots + 0)) { SetNil(a); return errNone; } struct tm tm0; if (slotIntVal(slots+0, &tm0.tm_year)) return errWrongType; tm0.tm_year -= 1900; if (slotIntVal(slots+1, &tm0.tm_mon)) return errWrongType; tm0.tm_mon --; if (slotIntVal(slots+2, &tm0.tm_mday)) return errWrongType; if (slotIntVal(slots+3, &tm0.tm_hour)) return errWrongType; if (slotIntVal(slots+4, &tm0.tm_min)) return errWrongType; if (slotIntVal(slots+5, &tm0.tm_sec)) return errWrongType; if (slotIntVal(slots+6, &tm0.tm_wday)) return errWrongType; char format[1024]; if (slotStrVal(b, format, 1024)) return errWrongType; char buffer[1024]; if (strftime(buffer, 1024, format, &tm0) != 0) { int size = strlen(buffer); PyrString *strobj = newPyrStringN(g->gc, size, 0, true); memcpy(strobj->s, buffer, size); SetObject(a, strobj); } else { error("could not convert the date to string with the give format"); return errFailed; } return errNone; } int32 timeseed(); int prTimeSeed(struct VMGlobals *g, int numArgsPushed); int prTimeSeed(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, timeseed()); return errNone; } int prGetPid(VMGlobals *g, int numArgsPushed); int prGetPid(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, #ifndef SC_WIN32 getpid() #else GetCurrentProcessId() #endif ); return errNone; } void initUnixPrimitives(); void initUnixPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); s_unixCmdAction = getsym("doUnixCmdAction"); definePrimitive(base, index++, "_String_System", prString_System, 1, 0); definePrimitive(base, index++, "_String_Basename", prString_Basename, 1, 0); definePrimitive(base, index++, "_String_Dirname", prString_Dirname, 1, 0); definePrimitive(base, index++, "_String_POpen", prString_POpen, 2, 0); definePrimitive(base, index++, "_Unix_Errno", prUnix_Errno, 1, 0); definePrimitive(base, index++, "_LocalTime", prLocalTime, 1, 0); definePrimitive(base, index++, "_GMTime", prGMTime, 1, 0); definePrimitive(base, index++, "_AscTime", prAscTime, 1, 0); definePrimitive(base, index++, "_prStrFTime", prStrFTime, 2, 0); definePrimitive(base, index++, "_TimeSeed", prTimeSeed, 1, 0); definePrimitive(base, index++, "_PidRunning", prPidRunning, 1, 0); definePrimitive(base, index++, "_GetPid", prGetPid, 1, 0); } SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/SC_AlsaMIDI.cpp0000664000000000000000000007313712245365552025234 0ustar rootroot/* Alsa MIDI/Sequencer support. Copyright (c) 2004 stefan kersten. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #include "SC_LanguageClient.h" PyrSymbol* s_midiin; PyrSymbol* s_domidiaction; PyrSymbol* s_midiNoteOnAction; PyrSymbol* s_midiNoteOffAction; PyrSymbol* s_midiTouchAction; PyrSymbol* s_midiControlAction; PyrSymbol* s_midiPolyTouchAction; PyrSymbol* s_midiProgramAction; PyrSymbol* s_midiBendAction; PyrSymbol* s_midiSysexAction; PyrSymbol* s_midiSysrtAction; PyrSymbol* s_midiSMPTEAction; const int kMaxMidiPorts = 16; bool gMIDIInitialized = false; extern bool compiledOK; // ===================================================================== // Platform declarations (interface routines) // ===================================================================== static int initClient(); static int initMIDI(int numIn, int numOut); static int disposeMIDI(); static int restartMIDI(); static void cleanUpMIDI(); static int listMIDIEndpoints(struct VMGlobals *g, PyrSlot *a); static int connectMIDIIn(int inputIndex, int uid); static int disconnectMIDIIn(int inputIndex, int uid); static int connectMIDIOut(int outputIndex, int uid); static int disconnectMIDIOut(int outputIndex, int uid); static int sendMIDI(int port, int destId, int length, int hiStatus, int loStatus, int aval, int bval, float late); static int sendMIDISysex(int port, int destId, int length, uint8* data); // ===================================================================== // Platform declarations (ALSA) // ===================================================================== #include #include #include #include static const size_t kAlsaMaxPacketSize = 3; static const size_t kAlsaMaxPortNameLen = 256; // MIDI packet struct SC_AlsaMidiPacket { uint8 data[kAlsaMaxPacketSize]; }; // MIDI client state struct SC_AlsaMidiClient { snd_seq_t* mHandle; int mQueue; int mNumInPorts; int mInPorts[kMaxMidiPorts]; int mNumOutPorts; int mOutPorts[kMaxMidiPorts]; snd_midi_event_t* mEventToMidi; snd_midi_event_t* mMidiToEvent; pthread_t mInputThread; bool mShouldBeRunning; static void* inputThreadFunc(void*); void processEvent(snd_seq_event_t* evt); int connectInput(int inputIndex, int uid, int (*action)(snd_seq_t*, snd_seq_port_subscribe_t*), const char* actionName); int connectOutput(int outputIndex, int uid, int (*action)(snd_seq_t*, snd_seq_port_subscribe_t*), const char* actionName); int sendEvent(int outputIndex, int uid, snd_seq_event_t* evt, float late=0.f); }; static SC_AlsaMidiClient gMIDIClient; // Port description struct SC_AlsaMidiPort { SC_AlsaMidiPort() : uid(0) { *name = 0; } char name[kAlsaMaxPortNameLen]; int32 uid; }; // ===================================================================== // Platform implementation (ALSA) // ===================================================================== static inline int SC_AlsaMakeUID(int clientID, int portID) { return (clientID << 16) | (portID & 0xFFFF); } static inline void SC_AlsaParseUID(int uid, int& clientID, int& portID) { clientID = uid >> 16; portID = uid & 0xFFFF; } void SC_AlsaMidiClient::processEvent(snd_seq_event_t* evt) { int status = lockLanguageOrQuit(mShouldBeRunning); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; PyrInt8Array* sysexArray; SC_AlsaMidiPacket pkt; g->canCallOS = false; // cannot call the OS // class MIDIIn ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // source ++g->sp; SetInt(g->sp, SC_AlsaMakeUID(evt->source.client, evt->source.port)); switch (evt->type) { // midi events case SND_SEQ_EVENT_NOTEOFF: // noteOff ++g->sp; SetInt(g->sp, evt->data.note.channel); ++g->sp; SetInt(g->sp, evt->data.note.note); ++g->sp; SetInt(g->sp, evt->data.note.velocity); runInterpreter(g, s_midiNoteOffAction, 5); break; case SND_SEQ_EVENT_NOTEON: // noteOn ++g->sp; SetInt(g->sp, evt->data.note.channel); ++g->sp; SetInt(g->sp, evt->data.note.note); ++g->sp; SetInt(g->sp, evt->data.note.velocity); runInterpreter(g, evt->data.note.velocity ? s_midiNoteOnAction : s_midiNoteOffAction, 5); break; case SND_SEQ_EVENT_KEYPRESS: // polytouch ++g->sp; SetInt(g->sp, evt->data.note.channel); ++g->sp; SetInt(g->sp, evt->data.note.note); ++g->sp; SetInt(g->sp, evt->data.note.velocity); runInterpreter(g, s_midiPolyTouchAction, 5); break; case SND_SEQ_EVENT_CONTROLLER: // control ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, evt->data.control.param); ++g->sp; SetInt(g->sp, evt->data.control.value); runInterpreter(g, s_midiControlAction, 5); break; case SND_SEQ_EVENT_PGMCHANGE: // program ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, evt->data.control.value); runInterpreter(g, s_midiProgramAction, 4); break; case SND_SEQ_EVENT_CHANPRESS: // touch ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, evt->data.control.value); runInterpreter(g, s_midiTouchAction, 4); break; case SND_SEQ_EVENT_PITCHBEND: // bend ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, evt->data.control.value + 8192); runInterpreter(g, s_midiBendAction, 4); break; // system common events case SND_SEQ_EVENT_QFRAME: // mtc quarter frame { int index = evt->data.control.value >> 4; int data = evt->data.control.value & 0xf; #if 0 post( "mtc qframe: byte 0x%x index 0x%x data 0x%x\n", evt->data.control.value, index, data ); #endif switch (index) { case 1: case 3: case 5: case 7: data = data << 4; } ++g->sp; SetInt(g->sp, index); ++g->sp; SetInt(g->sp, data); } runInterpreter(g, s_midiSMPTEAction, 4); break; case SND_SEQ_EVENT_SONGPOS: // song ptr ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, (evt->data.control.value << 7) | evt->data.control.param); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_SONGSEL: // song sel ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, evt->data.control.param); runInterpreter(g, s_midiSysrtAction, 4); break; // system realtime events case SND_SEQ_EVENT_CLOCK: // clock ++g->sp; SetInt(g->sp, 0x8); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_START: // start ++g->sp; SetInt(g->sp, 0xA); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_CONTINUE: // continue ++g->sp; SetInt(g->sp, 0xB); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_STOP: // stop ++g->sp; SetInt(g->sp, 0xC); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_SENSING: // active sensing ++g->sp; SetInt(g->sp, 0xE); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_RESET: // system reset ++g->sp; SetInt(g->sp, 0xF); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; // sysex events case SND_SEQ_EVENT_SYSEX: // sysex sysexArray = newPyrInt8Array(g->gc, evt->data.ext.len, 0, true); memcpy(sysexArray->b, evt->data.ext.ptr, evt->data.ext.len); sysexArray->size = evt->data.ext.len; ++g->sp; SetObject(g->sp, (PyrObject*)sysexArray); runInterpreter(g, s_midiSysexAction, 3); break; default: // unknown: convert to midi packet snd_midi_event_reset_decode(mEventToMidi); memset(pkt.data, 0, kAlsaMaxPacketSize); if (snd_midi_event_decode(mEventToMidi, pkt.data, kAlsaMaxPacketSize, evt) > 0) { for (size_t i=0; i < kAlsaMaxPacketSize; i++) { ++g->sp; SetInt(g->sp, pkt.data[i]); } runInterpreter(g, s_domidiaction, 2+kAlsaMaxPacketSize); } else { g->sp -= 2; } } g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); } void* SC_AlsaMidiClient::inputThreadFunc(void* arg) { SC_AlsaMidiClient* client = (SC_AlsaMidiClient*)arg; snd_seq_t* handle = client->mHandle; int npfd = snd_seq_poll_descriptors_count(handle, POLLIN); struct pollfd pfd[npfd]; snd_seq_poll_descriptors(handle, pfd, npfd, POLLIN); while (client->mShouldBeRunning) { if (poll(pfd, npfd, 2000) > 0) { // 2s timeout for (int i=0; i < npfd; i++) { if (pfd[i].revents > 0) { do { snd_seq_event_t* evt; snd_seq_event_input(handle, &evt); client->processEvent(evt); snd_seq_free_event(evt); } while (snd_seq_event_input_pending(handle, 0) > 0); } } } } return 0; } int SC_AlsaMidiClient::connectInput(int inputIndex, int uid, int (*action)(snd_seq_t*, snd_seq_port_subscribe_t*), const char* actionName) { snd_seq_t* seq = mHandle; snd_seq_client_info_t* cinfo; snd_seq_port_subscribe_t* subs; snd_seq_addr_t src, dst; int cid, pid; if ((inputIndex < 0) || (inputIndex >= mNumInPorts)) return errIndexOutOfRange; snd_seq_client_info_alloca(&cinfo); if (snd_seq_get_client_info(seq, cinfo) < 0) { post("MIDI (ALSA): could not get client info: %s\n", snd_strerror(errno)); return errFailed; } dst.client = snd_seq_client_info_get_client(cinfo); dst.port = mInPorts[inputIndex]; SC_AlsaParseUID(uid, cid, pid); src.client = cid; src.port = pid; //post("MIDI (ALSA): connect ndx %d uid %u dst %d:%d src %d:%d\n", inputIndex, uid, dst.client, dst.port, src.client, src.port); snd_seq_port_subscribe_alloca(&subs); snd_seq_port_subscribe_set_sender(subs, &src); snd_seq_port_subscribe_set_dest(subs, &dst); if ((*action)(seq, subs) < 0) { post("MIDI (ALSA): %s failed (%s)\n", actionName, snd_strerror(errno)); return errFailed; } return errNone; } int SC_AlsaMidiClient::connectOutput(int outputIndex, int uid, int (*action)(snd_seq_t*, snd_seq_port_subscribe_t*), const char* actionName) { snd_seq_t* seq = mHandle; snd_seq_client_info_t* cinfo; snd_seq_port_subscribe_t* subs; snd_seq_addr_t src, dst; int cid, pid; if ((outputIndex < 0) || (outputIndex >= mNumOutPorts)) return errIndexOutOfRange; snd_seq_client_info_alloca(&cinfo); if (snd_seq_get_client_info(seq, cinfo) < 0) { post("MIDI (ALSA): could not get client info: %s\n", snd_strerror(errno)); return errFailed; } src.client = snd_seq_client_info_get_client(cinfo); src.port = mOutPorts[outputIndex]; SC_AlsaParseUID(uid, cid, pid); dst.client = cid; dst.port = pid; // post("MIDI (ALSA): connect ndx %d uid %u dst %d:%d src %d:%d\n", outputIndex, uid, dst.client, dst.port, src.client, src.port); snd_seq_port_subscribe_alloca(&subs); snd_seq_port_subscribe_set_sender(subs, &src); snd_seq_port_subscribe_set_dest(subs, &dst); if ((*action)(seq, subs) < 0) { post("MIDI (ALSA): %s failed (%s)\n", actionName, snd_strerror(errno)); return errFailed; } return errNone; } int SC_AlsaMidiClient::sendEvent(int outputIndex, int uid, snd_seq_event_t* evt, float late) { snd_seq_real_time time; if ((outputIndex < 0) || (outputIndex >= mNumOutPorts)) return errIndexOutOfRange; snd_seq_ev_set_source(evt, mOutPorts[outputIndex]); if (uid == 0) { // send to all subscribed ports snd_seq_ev_set_subs(evt); } else { // send to specific port int cid, pid; SC_AlsaParseUID(uid, cid, pid); snd_seq_ev_set_dest(evt, cid, pid); } // long latelong; if (late > 0.f) { // latelong = (long) (late * 1000000000); // new time calculation. The old one was not correct // time.tv_sec = (long)(latelong / 1000000000); // seconds // time.tv_nsec = (long)(latelong % 1000000000); // nanoseconds time.tv_sec = (long)(floorf (late)); time.tv_nsec = (long)((late - time.tv_sec) * 1e9f); } else { time.tv_sec = time.tv_nsec = 0; } // evt->flags = evt->flags | SND_SEQ_TIME_STAMP_REAL; // post("MIDI (ALSA): sending event, time %i, %i, late %f, latelong %i\n", time.tv_sec, time.tv_nsec, late, latelong); snd_seq_ev_schedule_real(evt, mQueue, 1, &time); snd_seq_event_output_direct(mHandle, evt); // snd_seq_event_output(mHandle, evt); // snd_seq_continue_queue(mHandle, mQueue, 0); // snd_seq_drain_output(mHandle); return errNone; } int initMIDI(int numIn, int numOut) { SC_AlsaMidiClient* client = &gMIDIClient; int i; if (client->mHandle) cleanUpMIDI(); numIn = sc_clip(numIn, 1, kMaxMidiPorts); numOut = sc_clip(numOut, 1, kMaxMidiPorts); // initialize client handle if (snd_seq_open(&client->mHandle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) { client->mHandle = 0; post("MIDI (ALSA): could not open ALSA sequencer: %s\n", snd_strerror(errno)); return errFailed; } snd_seq_set_client_name(client->mHandle, "SuperCollider"); // allocate i/o ports for (i=0; i < numIn; i++) { char str[32]; int port; sprintf(str, "in%d", i); port = snd_seq_create_simple_port( client->mHandle, str, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION); if (port < 0) { post("MIDI (ALSA): could not create MIDI in port %d: %s\n", i, snd_strerror(errno)); break; } client->mInPorts[i] = port; } client->mNumInPorts = i; for (i=0; i < numOut; i++) { char str[32]; int port; sprintf(str, "out%d", i); port = snd_seq_create_simple_port( client->mHandle, str, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION); if (port < 0) { post("MIDI (ALSA): could not create MIDI out port %d: %s\n", i, snd_strerror(errno)); break; } client->mOutPorts[i] = port; } client->mNumOutPorts = i; // initialize queue client->mQueue = snd_seq_alloc_queue(client->mHandle); snd_seq_start_queue(client->mHandle, client->mQueue, 0); snd_seq_drain_output(client->mHandle); // snd_seq_set_client_pool_output(seqHandle, ??); // initialize event en-/decoders if (snd_midi_event_new(32, &client->mEventToMidi) < 0) { client->mEventToMidi = 0; post("MIDI (ALSA): could not create MIDI decoder\n"); return errFailed; } if (snd_midi_event_new(32, &client->mMidiToEvent) < 0) { client->mMidiToEvent = 0; post("MIDI (ALSA): could not create MIDI encoder\n"); return errFailed; } snd_midi_event_no_status(client->mEventToMidi, 1); snd_midi_event_no_status(client->mMidiToEvent, 1); // start input thread client->mShouldBeRunning = true; if (pthread_create(&client->mInputThread, 0, &SC_AlsaMidiClient::inputThreadFunc, client) != 0) { post("MIDI (ALSA): could not start input thread\n"); return errFailed; } return errNone; } int initMIDIClient() { SC_AlsaMidiClient* client = &gMIDIClient; if (client->mHandle) return errNone; // initialize client handle if (snd_seq_open(&client->mHandle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) { client->mHandle = 0; post("MIDI (ALSA): could not open ALSA sequencer: %s\n", snd_strerror(errno)); return errFailed; } snd_seq_set_client_name(client->mHandle, "SuperCollider"); // initialize queue client->mQueue = snd_seq_alloc_queue(client->mHandle); snd_seq_start_queue(client->mHandle, client->mQueue, 0); snd_seq_drain_output(client->mHandle); // snd_seq_set_client_pool_output(seqHandle, ??); // initialize event en-/decoders if (snd_midi_event_new(32, &client->mEventToMidi) < 0) { client->mEventToMidi = 0; post("MIDI (ALSA): could not create MIDI decoder\n"); return errFailed; } if (snd_midi_event_new(32, &client->mMidiToEvent) < 0) { client->mMidiToEvent = 0; post("MIDI (ALSA): could not create MIDI encoder\n"); return errFailed; } snd_midi_event_no_status(client->mEventToMidi, 1); snd_midi_event_no_status(client->mMidiToEvent, 1); // start input thread client->mShouldBeRunning = true; if (pthread_create(&client->mInputThread, 0, &SC_AlsaMidiClient::inputThreadFunc, client) != 0) { post("MIDI (ALSA): could not start input thread\n"); return errFailed; } return errNone; } int disposeMIDI() { cleanUpMIDI(); return errNone; } int restartMIDI() { return errNone; } void cleanUpMIDI() { SC_AlsaMidiClient* client = &gMIDIClient; if (client->mHandle) { client->mShouldBeRunning = false; pthread_join(client->mInputThread, 0); snd_seq_remove_events_t *revt; snd_seq_remove_events_malloc(&revt); snd_seq_remove_events_set_queue(revt, client->mQueue); snd_seq_remove_events_set_condition(revt, SND_SEQ_REMOVE_OUTPUT|SND_SEQ_REMOVE_IGNORE_OFF); snd_seq_remove_events(client->mHandle, revt); snd_seq_remove_events_free(revt); snd_seq_stop_queue(client->mHandle, client->mQueue, 0); snd_seq_free_queue(client->mHandle, client->mQueue); if (client->mEventToMidi) { snd_midi_event_free(client->mEventToMidi); } if (client->mMidiToEvent) { snd_midi_event_free(client->mMidiToEvent); } snd_seq_close(client->mHandle); client->mHandle = 0; } } inline static bool SC_AlsaCheckPerm(snd_seq_port_info_t* pinfo, int bits) { int cap = snd_seq_port_info_get_capability(pinfo); return ((cap & bits) == bits) && !(cap & SND_SEQ_PORT_CAP_NO_EXPORT); } int listMIDIEndpoints(struct VMGlobals *g, PyrSlot* a) { snd_seq_t* seq; snd_seq_client_info_t* cinfo; snd_seq_port_info_t* pinfo; if (!gMIDIClient.mHandle) return errFailed; seq = gMIDIClient.mHandle; snd_seq_client_info_alloca(&cinfo); snd_seq_port_info_alloca(&pinfo); snd_seq_client_info_set_client(cinfo, -1); std::vector srcPorts; std::vector dstPorts; while (snd_seq_query_next_client(seq, cinfo) >= 0) { int cid = snd_seq_client_info_get_client(cinfo); const char* cname = snd_seq_client_info_get_name(cinfo); if ((cid < 0) || (cid > 0xffff)) { post("MIDI (ALSA): client ID out of range.\n"); return errFailed; } snd_seq_port_info_set_client(pinfo, cid); snd_seq_port_info_set_port(pinfo, -1); while (snd_seq_query_next_port(seq, pinfo) >= 0) { int pid = snd_seq_port_info_get_port(pinfo); const char* pname = snd_seq_port_info_get_name(pinfo); if ((pid < 0) || (pid > 0xffff)) { post("MIDI (ALSA): port ID out of range.\n"); return errFailed; } if (SC_AlsaCheckPerm(pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ)) { // src port srcPorts.push_back(SC_AlsaMidiPort()); snprintf(srcPorts.back().name, kAlsaMaxPortNameLen, "%s-%s", cname, pname); srcPorts.back().uid = SC_AlsaMakeUID(cid, pid); //post("MIDI (ALSA): src %s-%s %d:%d %u\n", cname, pname, cid, pid, srcPorts.back().uid); } if (SC_AlsaCheckPerm(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) { // dst port dstPorts.push_back(SC_AlsaMidiPort()); snprintf(dstPorts.back().name, kAlsaMaxPortNameLen, "%s-%s", cname, pname); dstPorts.back().uid = SC_AlsaMakeUID(cid, pid); //post("MIDI (ALSA): dst %s-%s %d:%d %u\n", cname, pname, cid, pid, srcPorts.back().uid); } } } int numSrc = srcPorts.size(); int numDst = dstPorts.size(); PyrObject* idarray = newPyrArray(g->gc, 6 * sizeof(PyrObject), 0 , true); SetObject(a, idarray); PyrObject* idarraySo = newPyrArray(g->gc, numSrc * sizeof(int32), 0 , true); SetObject(idarray->slots+idarray->size++, idarraySo); g->gc->GCWrite(idarray, idarraySo); PyrObject* devarraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarraySo); g->gc->GCWrite(idarray, devarraySo); PyrObject* namearraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearraySo); g->gc->GCWrite(idarray, namearraySo); PyrObject* idarrayDe = newPyrArray(g->gc, numDst * sizeof(int32), 0 , true); SetObject(idarray->slots+idarray->size++, idarrayDe); g->gc->GCWrite(idarray, idarrayDe); PyrObject* namearrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearrayDe); g->gc->GCWrite(idarray, namearrayDe); PyrObject* devarrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarrayDe); g->gc->GCWrite(idarray, devarrayDe); for (int i=0; igc, name, 0, true); SetObject(namearraySo->slots+i, string); namearraySo->size++; g->gc->GCWrite(namearraySo, (PyrObject*)string); PyrString *devstring = newPyrString(g->gc, name, 0, true); SetObject(devarraySo->slots+i, devstring); devarraySo->size++; g->gc->GCWrite(devarraySo, (PyrObject*)devstring); SetInt(idarraySo->slots+i, srcPorts[i].uid); idarraySo->size++; } for (int i=0; igc, name, 0, true); SetObject(namearrayDe->slots+namearrayDe->size++, string); g->gc->GCWrite(namearrayDe, (PyrObject*)string); PyrString *devstring = newPyrString(g->gc, name, 0, true); SetObject(devarrayDe->slots+i, devstring); devarrayDe->size++; g->gc->GCWrite(devarrayDe, (PyrObject*)devstring); SetInt(idarrayDe->slots+i, dstPorts[i].uid); idarrayDe->size++; } return errNone; } int connectMIDIIn(int inputIndex, int uid) { if (!gMIDIClient.mHandle) return errFailed; return gMIDIClient.connectInput(inputIndex, uid, &snd_seq_subscribe_port, "connect"); } int disconnectMIDIIn(int inputIndex, int uid) { if (!gMIDIClient.mHandle) return errFailed; return gMIDIClient.connectInput(inputIndex, uid, &snd_seq_unsubscribe_port, "disconnect"); } int connectMIDIOut(int outputIndex, int uid) { if (!gMIDIClient.mHandle) return errFailed; return gMIDIClient.connectOutput(outputIndex, uid, &snd_seq_subscribe_port, "connect"); } int disconnectMIDIOut(int outputIndex, int uid) { if (!gMIDIClient.mHandle) return errFailed; return gMIDIClient.connectOutput(outputIndex, uid, &snd_seq_unsubscribe_port, "disconnect"); } int sendMIDI(int port, int uid, int length, int hiStatus, int loStatus, int aval, int bval, float late) { if (!gMIDIClient.mHandle) return errFailed; // post("MIDI (ALSA): send %x %x %d %d %i\n", hiStatus>>4, loStatus, aval, bval, gMIDIClient.mMidiToEvent); snd_seq_event_t evt; SC_AlsaMidiPacket pkt; snd_seq_ev_clear(&evt); pkt.data[0] = (hiStatus & 0xF0) | (loStatus & 0x0F); pkt.data[1] = (uint8)aval; pkt.data[2] = (uint8)bval; snd_midi_event_reset_encode(gMIDIClient.mMidiToEvent); if (snd_midi_event_encode(gMIDIClient.mMidiToEvent, pkt.data, length, &evt) < 0) { post("MIDI (ALSA): could not encode midi data: %s\n", snd_strerror(errno)); return errFailed; } return gMIDIClient.sendEvent(port, uid, &evt, late); } int sendMIDISysex(int port, int uid, int length, uint8* data) { if (!gMIDIClient.mHandle) return errFailed; snd_seq_event_t evt; evt.type = SND_SEQ_EVENT_SYSEX; // MIDIOut.sysex patch 2007-01-16 snd_seq_ev_set_variable(&evt, length, data); return gMIDIClient.sendEvent(port, uid, &evt, 0.f); } // ===================================================================== // Primitives // ===================================================================== int prInitMIDI(struct VMGlobals *g, int numArgsPushed); int prInitMIDI(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, numIn, numOut; err = slotIntVal(b, &numIn); if (err) return errWrongType; err = slotIntVal(c, &numOut); if (err) return errWrongType; return initMIDI(numIn, numOut); } int prInitMIDIClient(struct VMGlobals *g, int numArgsPushed); int prInitMIDIClient(struct VMGlobals *g, int numArgsPushed) { return initMIDIClient(); } int prDisposeMIDIClient(VMGlobals *g, int numArgsPushed); int prDisposeMIDIClient(VMGlobals *g, int numArgsPushed) { return disposeMIDI(); } int prRestartMIDI(VMGlobals *g, int numArgsPushed); int prRestartMIDI(VMGlobals *g, int numArgsPushed) { return restartMIDI(); } int prListMIDIEndpoints(struct VMGlobals *g, int numArgsPushed); int prListMIDIEndpoints(struct VMGlobals *g, int numArgsPushed) { return listMIDIEndpoints(g, g->sp); } int prConnectMIDIIn(struct VMGlobals *g, int numArgsPushed); int prConnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; err = slotIntVal(c, &uid); if (err) return err; return connectMIDIIn(inputIndex, uid); } int prDisconnectMIDIIn(struct VMGlobals *g, int numArgsPushed); int prDisconnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; err = slotIntVal(c, &uid); if (err) return err; return disconnectMIDIIn(inputIndex, uid); } int prConnectMIDIOut(struct VMGlobals *g, int numArgsPushed); int prConnectMIDIOut(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; err = slotIntVal(c, &uid); if (err) return err; return connectMIDIOut(inputIndex, uid); } int prDisconnectMIDIOut(struct VMGlobals *g, int numArgsPushed); int prDisconnectMIDIOut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; err = slotIntVal(c, &uid); if (err) return err; return disconnectMIDIOut(inputIndex, uid); } int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed); int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed) { //port, uid, len, hiStatus, loStatus, a, b, latency //PyrSlot *m = g->sp - 8; PyrSlot *p = g->sp - 7; PyrSlot *u = g->sp - 6; PyrSlot *l = g->sp - 5; PyrSlot *his = g->sp - 4; PyrSlot *los = g->sp - 3; PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *plat = g->sp; int err, outputIndex, uid, length, hiStatus, loStatus, aval, bval; float late; err = slotIntVal(p, &outputIndex); if (err) return err; err = slotIntVal(u, &uid); if (err) return err; err = slotIntVal(l, &length); if (err) return err; err = slotIntVal(his, &hiStatus); if (err) return err; err = slotIntVal(los, &loStatus); if (err) return err; err = slotIntVal(a, &aval); if (err) return err; err = slotIntVal(b, &bval); if (err) return err; err = slotFloatVal(plat, &late); if (err) return err; return sendMIDI(outputIndex, uid, length, hiStatus, loStatus, aval, bval, late); } int prSendSysex(VMGlobals *g, int numArgsPushed) { int err, uid, outputIndex; PyrInt8Array* packet; // rcvr, uid, packet PyrSlot* args = g->sp - 2; int MIDIOut_port_index = instVarOffset("MIDIOut", "port"); err = slotIntVal(slotRawObject(args)->slots + MIDIOut_port_index, &outputIndex); if (err) return err; err = slotIntVal(args+1, &uid); if (err) return err; if( !isKindOfSlot(args+2, s_int8array->u.classobj) ) return errWrongType; packet = slotRawInt8Array(&args[2]); return sendMIDISysex(outputIndex, uid, packet->size, packet->b); } void initMIDIPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; s_midiin = getsym("MIDIIn"); s_domidiaction = getsym("doAction"); s_midiNoteOnAction = getsym("doNoteOnAction"); s_midiNoteOffAction = getsym("doNoteOffAction"); s_midiTouchAction = getsym("doTouchAction"); s_midiControlAction = getsym("doControlAction"); s_midiPolyTouchAction = getsym("doPolyTouchAction"); s_midiProgramAction = getsym("doProgramAction"); s_midiBendAction = getsym("doBendAction"); s_midiSysexAction = getsym("doSysexAction"); s_midiSysrtAction = getsym("doSysrtAction"); s_midiSMPTEAction = getsym("doSMPTEaction"); definePrimitive(base, index++, "_InitMIDI", prInitMIDI, 3, 0); definePrimitive(base, index++, "_InitMIDIClient", prInitMIDIClient, 1, 0); definePrimitive(base, index++, "_RestartMIDI", prRestartMIDI, 1, 0); definePrimitive(base, index++, "_DisposeMIDIClient", prDisposeMIDIClient, 1, 0); definePrimitive(base, index++, "_ListMIDIEndpoints", prListMIDIEndpoints, 1, 0); definePrimitive(base, index++, "_ConnectMIDIIn", prConnectMIDIIn, 3, 0); definePrimitive(base, index++, "_DisconnectMIDIIn", prDisconnectMIDIIn, 3, 0); definePrimitive(base, index++, "_ConnectMIDIOut", prConnectMIDIOut, 3, 0); definePrimitive(base, index++, "_DisconnectMIDIOut", prDisconnectMIDIOut, 3, 0); definePrimitive(base, index++, "_SendMIDIOut", prSendMIDIOut, 9, 0); definePrimitive(base, index++, "_SendSysex", prSendSysex, 3, 0); // MIDIOut.sysex patch 2007-01-16 cleanUpMIDI(); } // EOF SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/SC_CoreAudioPrim.cpp0000775000000000000000000001036012161364457026403 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "SCBase.h" #include "VMGlobals.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "GC.h" enum { OUT = 0, IN, BOTH }; int listDevices(struct VMGlobals *g, int type) { int numDevices, num = 0; PyrSlot *a = g->sp-2; AudioObjectPropertyAddress propertyAddress; propertyAddress.mSelector = kAudioHardwarePropertyDevices; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; // unsigned long count; UInt32 count; // OSStatus err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0); OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count); AudioDeviceID *devices = (AudioDeviceID*)malloc(count); // err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices); err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count, devices); if (err!=kAudioHardwareNoError) { free(devices); return 0; } numDevices = count / sizeof(AudioDeviceID); int i; if (typegc, num * sizeof(PyrObject), 0, true); SetObject(a, devArray); int j = 0; for (i=0; igc, name, 0, true); SetObject(devArray->slots+j, string); devArray->size++; g->gc->GCWrite(devArray, (PyrObject*)string); free(name); j++; } free(devices); return 1; } int prListAudioDevices(struct VMGlobals *g, int numArgsPushed) { int in = 0; int out = 0; slotIntVal(g->sp, &out); slotIntVal(g->sp-1, &in); int type; if (in && out) type = BOTH; else if (in) type = IN; else type = OUT; if (listDevices(g, type)) return errNone; return errFailed; } void initCoreAudioPrimitives() { definePrimitive(nextPrimitiveIndex(), 0, "_ListAudioDevices", prListAudioDevices, 3, 0); }SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrSymbolPrim.cpp0000664000000000000000000001756612245365552026120 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for Symbol. */ #include #include #include "PyrPrimitive.h" #include "PyrSymbol.h" #include "VMGlobals.h" #include "PyrKernel.h" #include "SCBase.h" /* int prSymbolString(struct VMGlobals *g, int numArgsPushed); int prSymbolString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrString *string; a = g->sp; if (NotSym(a)) return errWrongType; string = newPyrString(g->gc, slotRawSymbol(a)->name, 0, true); SetObject(a, string); return errNone; } */ int prSymbolIsPrefix(struct VMGlobals *g, int numArgsPushed); int prSymbolIsPrefix(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int length; a = g->sp - 1; b = g->sp; if (!IsSym(a) || !IsSym(b)) return errWrongType; int32 alen = slotRawSymbol(a)->length; int32 blen = slotRawSymbol(b)->length; length = sc_min(alen, blen); if (memcmp(slotRawSymbol(a)->name, slotRawSymbol(b)->name, length) == 0) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prSymbolClass(struct VMGlobals *g, int numArgsPushed); int prSymbolClass(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrClass *classobj; //char firstChar; a = g->sp; if (slotRawSymbol(a)->flags & sym_Class) { //firstChar = slotRawSymbol(a)->name[0]; //if (firstChar >= 'A' && firstChar <= 'Z') { classobj = slotRawSymbol(a)->u.classobj; if (classobj) { SetObject(a, classobj); } else { SetNil(a); } } else { SetNil(a); } return errNone; } int prSymbolIsSetter(struct VMGlobals *g, int numArgsPushed); int prSymbolIsSetter(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (slotRawSymbol(a)->flags & sym_Setter) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prSymbolAsSetter(struct VMGlobals *g, int numArgsPushed); int prSymbolAsSetter(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; char str[256]; int len; a = g->sp; if (!(slotRawSymbol(a)->flags & sym_Setter)) { if ((slotRawSymbol(a)->flags & sym_Class) || (slotRawSymbol(a)->flags & sym_Primitive)) { error("Cannot convert class names or primitive names to setters.\n"); return errFailed; } if (strlen(slotRawSymbol(a)->name)>255) { error("symbol name too long.\n"); return errFailed; } strcpy(str, slotRawSymbol(a)->name); len = strlen(str); str[len] = '_'; str[len+1] = 0; //postfl("prSymbolAsSetter %s\n", str); SetRaw(a, getsym(str)); } return errNone; } int prSymbolAsGetter(struct VMGlobals *g, int numArgsPushed); int prSymbolAsGetter(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; char str[256]; a = g->sp; if ((slotRawSymbol(a)->flags & sym_Setter)) { if ((slotRawSymbol(a)->flags & sym_Class) || (slotRawSymbol(a)->flags & sym_Primitive)) { error("Cannot convert class names or primitive names to getters.\n"); return errFailed; } strcpy(str, slotRawSymbol(a)->name); str[strlen(str)-1] = 0; //postfl("prSymbolAsGetter %s\n", str); SetRaw(a, getsym(str)); } return errNone; } int prSymbolIsClassName(struct VMGlobals *g, int numArgsPushed); int prSymbolIsClassName(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (slotRawSymbol(a)->flags & sym_Class) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prSymbolIsMetaClassName(struct VMGlobals *g, int numArgsPushed); int prSymbolIsMetaClassName(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (slotRawSymbol(a)->flags & sym_MetaClass) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prSymbol_AsInteger(struct VMGlobals *g, int numArgsPushed); int prSymbol_AsInteger(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char *str = slotRawSymbol(a)->name; SetInt(a, atoi(str)); return errNone; } int prSymbol_PrimitiveIndex(struct VMGlobals *g, int numArgsPushed); int prSymbol_PrimitiveIndex(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, slotRawSymbol(a)->u.index); return errNone; } int prSymbol_SpecialIndex(struct VMGlobals *g, int numArgsPushed); int prSymbol_SpecialIndex(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, slotRawSymbol(a)->specialIndex); return errNone; } int prSymbol_AsFloat(struct VMGlobals *g, int numArgsPushed); int prSymbol_AsFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char *str = slotRawSymbol(a)->name; SetFloat(a, atof(str)); return errNone; } int prSymbol_matchOSCPattern(struct VMGlobals *g, int numArgsPushed); int prSymbol_matchOSCPattern(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; a = g->sp - 1; b = g->sp; if (!IsSym(a) || !IsSym(b)) return errWrongType; // int32 alen = slotRawSymbol(a)->length; // int32 blen = slotRawSymbol(b)->length; // length = sc_min(alen, blen); if (lo_pattern_match(slotRawSymbol(a)->name, slotRawSymbol(b)->name)) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prSymbol_isMap(struct VMGlobals *g, int numArgsPushed); int prSymbol_isMap(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char *str = slotRawSymbol(a)->name; if(strlen(str)>1 && (str[0]=='a' || str[0]=='c') && str[1]>='0' && str[1]<='9') SetTrue(a); else SetFalse(a); return errNone; } void initSymbolPrimitives(); void initSymbolPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_SymbolIsPrefix", prSymbolIsPrefix, 2, 0); //definePrimitive(base, index++, "_SymbolString", prSymbolString, 1, 0); definePrimitive(base, index++, "_SymbolClass", prSymbolClass, 1, 0); definePrimitive(base, index++, "_SymbolIsClassName", prSymbolIsClassName, 1, 0); definePrimitive(base, index++, "_SymbolIsMetaClassName", prSymbolIsMetaClassName, 1, 0); definePrimitive(base, index++, "_SymbolIsSetter", prSymbolIsSetter, 1, 0); definePrimitive(base, index++, "_SymbolAsSetter", prSymbolAsSetter, 1, 0); definePrimitive(base, index++, "_SymbolAsGetter", prSymbolAsGetter, 1, 0); definePrimitive(base, index++, "_Symbol_AsInteger", prSymbol_AsInteger, 1, 0); definePrimitive(base, index++, "_Symbol_PrimitiveIndex", prSymbol_PrimitiveIndex, 1, 0); definePrimitive(base, index++, "_Symbol_SpecialIndex", prSymbol_SpecialIndex, 1, 0); definePrimitive(base, index++, "_Symbol_AsFloat", prSymbol_AsFloat, 1, 0); definePrimitive(base, index++, "_Symbol_matchOSCPattern", prSymbol_matchOSCPattern, 2, 0); definePrimitive(base, index++, "_Symbol_IsMap", prSymbol_isMap, 1, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" // export the function that SC will call to load the plug in. #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initSymbolPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/SC_Wii.cpp0000664000000000000000000017022212245365552024432 0ustar rootroot// problem: communication with the event loop // pipe cannot be read // on MacOSX, I could use the EventLoopTimer instead, like in HID // to try: put discovery within thread (so extra command in manager) /* * SC_Wii.cpp * SC3lang * * Created by Marije Baalman on Fri 18 May 2007. * Copyright (c) 2007 Marije Baalman All rights reserved. * part of ... SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef SC_DARWIN #include #endif #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #ifdef HAVE_WII #ifdef SC_DARWIN #include #include extern "C"{ #include "WiiMote_OSX/wiiremote.h" } #endif // SC_DARWIN #ifdef __linux__ #include #include #include #include extern "C"{ #include // #include // #include // #include // #include } #endif // __linux__ // common: #include #include //--------- PyrSymbols ------------ PyrSymbol * s_wiiDisconnected; PyrSymbol * s_wiiConnected; PyrSymbol * s_handleEvent; PyrSymbol * s_handleBatteryEvent; PyrSymbol * s_handleExtensionEvent; PyrSymbol * s_handleNunchukEvent; PyrSymbol * s_handleClassicEvent; PyrSymbol * s_handleIREvent; PyrSymbol * s_handleAccEvent; PyrSymbol * s_handleButtonEvent; static PyrSymbol* s_wii = 0; static PyrSymbol* s_wiiCalibrationInfoClass = 0; static PyrSymbol* s_wiiLEDStateClass = 0; static PyrSymbol* s_readError = 0; extern bool compiledOK; //int gNumberOfWiiDevices = 0; #ifdef SC_DARWIN EventLoopTimerRef gWiiTimer = NULL; // timer for element data updates #endif // --------------- SC_WII structure -------------- struct SC_WII { SC_WII(PyrObject *obj); ~SC_WII(); bool open(); bool close(); bool wii_connect(); bool wii_disconnect(); int enable( bool enab ); void disconnected(); void connected(); void get_address(); // void set_address( char * addr ); // void speaker_init( int format ); bool update(); #ifdef __linux__ void handleBatteryEvent( uint8_t battery ); void handleButtonEvent( uint16_t buttons ); void handleAccEvent( uint8_t acc[3] ); void handleIREvent( int id, cwiid_ir_src ir ); void handleNunchukEvent( struct cwiid_nunchuk_mesg nunchuk ); void handleClassicEvent( struct cwiid_classic_mesg classic ); void handleExtensionEvent( int ext_type ); #endif #ifdef SC_DARWIN // void handleBatteryEvent( ); // void handleButtonEvent( ); // void handleAccEvent( ); // void handleIREvent( ); // void handleNunchukEvent( ); // void handleClassicEvent( ); void handleEvent(); #endif void readError(); static PyrObject* getObject(PyrSlot* slot) { return isKindOfSlot(slot, s_wii->u.classobj) ? slotRawObject(slot) : 0; } static SC_WII* getDevice(PyrObject* obj) { return (SC_WII*)slotRawPtr(obj->slots); } #ifdef SC_DARWIN WiiRemoteRef m_wiiremote; char m_address[32]; #endif #ifdef __linux__ cwiid_wiimote_t *m_wiiremote; int id; unsigned char rpt_mode; unsigned char led_state; char m_address[19]; #endif bool m_connected; int m_searching; SC_WII* m_next; PyrObject* m_obj; }; // ---------------- SC_WIIManager structure -------------- struct SC_WIIManager { public: static SC_WIIManager& instance(); int start( float updtime ); int stop(); #ifdef __linux__ cwiid_wiimote_t * discover(); #endif #ifdef SC_DARWIN WiiRemoteRef discover(); #endif int add(SC_WII *dev); int remove(SC_WII *dev); /// kind of private, but used in callback function and getWiiData SC_WII* m_devices; private: SC_WIIManager(); ~SC_WIIManager(); void loop(); bool m_running; float m_updatetime; }; #ifdef __linux__ /// linux specific cwiid functions #define toggle_bit(bf,b) \ (bf) = ((bf) & b) \ ? ((bf) & ~(b)) \ : ((bf) | (b)) void set_bit( unsigned char * bf, unsigned char b ) { if (!(*bf & b) ) toggle_bit( *bf, b ); } void clear_bit( unsigned char * bf, unsigned char b ) { if ((*bf & b) ) toggle_bit( *bf, b ); } cwiid_mesg_callback_t cwiid_callback; void set_led_state(cwiid_wiimote_t *wiimote, unsigned char led_state); void set_rpt_mode(cwiid_wiimote_t *wiimote, unsigned char rpt_mode); cwiid_err_t err; void err(cwiid_wiimote_t *wiimote, const char *s, va_list ap) { if (wiimote) printf("%d:", cwiid_get_id(wiimote)); else printf("-1:"); vprintf(s, ap); printf("\n"); } void set_led_state(cwiid_wiimote_t *wiimotet, unsigned char led_state) { // printf( "set_led_state %i\n", led_state ); if (cwiid_set_led(wiimotet, led_state)) { post( "WII Error: Unable to set led state\n"); } } void set_rpt_mode(cwiid_wiimote_t *wiimotet, unsigned char rpt_mode) { if (cwiid_set_rpt_mode(wiimotet, rpt_mode)) { post( "WII Error: Unable to set report mode\n"); } } #endif #ifdef SC_DARWIN void GetWii_Events(); static pascal void IdleTimerWii (EventLoopTimerRef inTimer, void* userData); static EventLoopTimerUPP GetTimerUPPWii (void); static pascal void IdleTimerWii (EventLoopTimerRef inTimer, void* userData) { #pragma unused (inTimer, userData) GetWii_Events (); } static EventLoopTimerUPP GetTimerUPPWii (void) { static EventLoopTimerUPP sTimerUPP = NULL; if (sTimerUPP == NULL) sTimerUPP = NewEventLoopTimerUPP (IdleTimerWii); return sTimerUPP; } #endif //------------ SC_WIIManager functions -------- SC_WIIManager& SC_WIIManager::instance() { static SC_WIIManager instance; return instance; } SC_WIIManager::SC_WIIManager() : m_running(false), m_devices(0) { #ifdef __linux__ cwiid_set_err(err); #endif #ifdef SC_DARWIN NumVersion outSoftwareVersion; BluetoothHCIVersionInfo outHardwareVersion; // post("aka.wiiremote 1.0B6-UB by Masayuki Akamatsu"); if (IOBluetoothGetVersion(&outSoftwareVersion, &outHardwareVersion)==kIOReturnSuccess) { if (outSoftwareVersion.majorRev < 1 && outSoftwareVersion.minorAndBugRev < 0x63) { error("WII: requires Bluetooth version 1.6.3 or later."); return; } } else { error("WII: can't get Bluetooth version."); return; } #endif } SC_WIIManager::~SC_WIIManager() { #ifdef SC_DARWIN if (gWiiTimer) { RemoveEventLoopTimer(gWiiTimer); gWiiTimer = NULL; } #endif } int SC_WIIManager::start( float updtime ) { /// nothing to do for Linux #ifdef SC_DARWIN m_updatetime = (updtime / 1000); // convert to seconds post( "WII: eventloop updatetime %f\n", m_updatetime ); //double eventtime = (double) updtime; if(gWiiTimer) { RemoveEventLoopTimer(gWiiTimer); gWiiTimer = NULL; } InstallEventLoopTimer (GetCurrentEventLoop(), 0, (EventTimerInterval) m_updatetime, GetTimerUPPWii (), 0, &gWiiTimer); #endif return errNone; } #ifdef __linux__ cwiid_wiimote_t * SC_WIIManager::discover() { bdaddr_t bdaddr = {0, 0, 0, 0, 0, 0}; cwiid_wiimote_t* wiimotediscovered; if ( (wiimotediscovered = cwiid_open(&bdaddr, 0)) == NULL ) { return NULL; } if (cwiid_set_mesg_callback(wiimotediscovered, cwiid_callback)) { post("ERROR: WII: Unable to set message callback\n"); if ( cwiid_close(wiimotediscovered) ){ post("ERROR: WII: Unable to close Wii\n"); } return NULL; } /// adding these as devices in the primitive! this is the only way to be able to connect, as the connection uses much more info than I thought! return( wiimotediscovered ); } #endif #ifdef SC_DARWIN WiiRemoteRef SC_WIIManager::discover() { /* WiiRemoteRef newwii; char address[32]; newwii = (WiiRemoteRef)malloc(sizeof(WiiRemoteRec)); if (newwii != NULL) { wiiremote_init(newwii); bool result; result = wiiremote_search( newwii, address); // start searching the device // m_searching++; post("WII: searching wiimote %i\n",result); } return( newwii ); */ } #endif int SC_WIIManager::stop() { /// nothing to do on LINUX #ifdef SC_DARWIN if (gWiiTimer) { RemoveEventLoopTimer(gWiiTimer); gWiiTimer = NULL; } #endif return errNone; } int SC_WIIManager::add(SC_WII* dev) { // post("WII: SC_WIIManager::add\n"); if (dev->m_next) return false; if (m_devices == dev ) { m_devices = dev; } else { dev->m_next = m_devices; m_devices = dev; } #ifdef __linux__ dev->id = cwiid_get_id( dev->m_wiiremote ); if (cwiid_enable(dev->m_wiiremote, CWIID_FLAG_MESG_IFC)) { post("ERROR: WII: Unable to enable Wii\n"); } dev->rpt_mode = CWIID_RPT_STATUS; dev->led_state = 0; set_rpt_mode( dev->m_wiiremote, dev->rpt_mode ); set_led_state( dev->m_wiiremote, dev->led_state ); #endif //#ifdef SC_DARWIN // dev->wii_connect(); //#endif return true; } int SC_WIIManager::remove(SC_WII* dev) { SC_WII *prev = 0, *cur = m_devices; while (cur) { if (cur == dev) { if (prev) prev->m_next = dev->m_next; else m_devices = dev->m_next; dev->m_next = 0; delete dev; return errNone; } prev = cur; cur = cur->m_next; } return errFailed; } #ifdef __linux__ void cwiid_callback(cwiid_wiimote_t *wiimotet, int mesg_count, union cwiid_mesg mesg[], struct timespec *timestamp) { int i, j; int valid_source; int thisid, id; SC_WII *dev = SC_WIIManager::instance().m_devices; id = 0; thisid = cwiid_get_id( wiimotet ); while (dev) { if ( thisid == dev->id ) { break; } dev = dev->m_next; } for (i=0; i < mesg_count; i++) { switch (mesg[i].type) { case CWIID_MESG_STATUS: dev->handleBatteryEvent( mesg[i].status_mesg.battery ); dev->handleExtensionEvent( mesg[i].status_mesg.ext_type ); break; case CWIID_MESG_BTN: dev->handleButtonEvent( mesg[i].btn_mesg.buttons ); break; case CWIID_MESG_ACC: dev->handleAccEvent( mesg[i].acc_mesg.acc ); break; case CWIID_MESG_IR: for (j = 0; j < CWIID_IR_SRC_COUNT; j++) { dev->handleIREvent( j, mesg[i].ir_mesg.src[j] ); } break; case CWIID_MESG_NUNCHUK: dev->handleNunchukEvent( mesg[i].nunchuk_mesg ); break; case CWIID_MESG_CLASSIC: dev->handleClassicEvent( mesg[i].classic_mesg ); break; case CWIID_MESG_ERROR: dev->disconnected(); dev->readError(); break; default: post("WII: Unknown Report"); break; } } } #endif #ifdef SC_DARWIN void GetWii_Events (){ SC_WII *dev = SC_WIIManager::instance().m_devices; // m_devices; int debugcnt = 0; while (dev) { bool connection; // post( "WII: device %i, t %p, w %p, n %p\n", debugcnt, dev, dev->m_wiiremote, dev->m_next); debugcnt++; if ( dev->m_wiiremote != NULL ) { connection = wiiremote_isconnected(dev->m_wiiremote); if ( dev->m_connected == false && connection == true) // if the device is connected, but wasn't before { // post( "WII: wiimote got connected\n"); wiiremote_getstatus(dev->m_wiiremote); dev->connected(); } else if (dev->m_connected == true && connection == false) // if device was disconnected { // post( "WII: wiimote got disconnected\n"); dev->disconnected(); } else if ( dev->m_searching > 0 ) { dev->wii_connect(); } if ( dev->m_connected ) { // post( "WII: wiimote is connected\n"); wiiremote_getstatus(dev->m_wiiremote); dev->handleEvent(); } else { // post("WII: wiimote not connected\n"); } } else { // post("WII: read error\n"); dev->readError(); } dev = dev->m_next; } } #endif //---------------- SC_WII functions ----------------- SC_WII::SC_WII(PyrObject* obj) : m_next(0), m_obj(obj) { // #ifdef __linux__ // m_report = nil; // #endif m_wiiremote = NULL; m_searching = 0; m_connected = false; // m_address; SetPtr(obj->slots+0, this); } SC_WII::~SC_WII() { close(); } bool SC_WII::open() { #ifdef SC_DARWIN m_wiiremote = (WiiRemoteRef)malloc(sizeof(WiiRemoteRec)); if (m_wiiremote != NULL) { wiiremote_init(m_wiiremote); m_wiiremote->isMotionSensorEnabled = true; m_wiiremote->isIRSensorEnabled = false; m_wiiremote->isVibrationEnabled = false; m_wiiremote->isExpansionPortEnabled = false; m_wiiremote->isLED1Illuminated = false; m_wiiremote->isLED2Illuminated = false; m_wiiremote->isLED3Illuminated = false; m_wiiremote->isLED4Illuminated = false; m_connected = false; // return SC_WIIManager::instance().add(this); } #endif #ifdef __linux__ // m_wiiremote = (wiimote_t*)malloc(sizeof(wiimote_t)); // m_report = (wiimote_report_t)malloc(sizeof(wiimote_report_t)); // if ( m_wiiremote != NULL ) // { // *m_wiiremote = WIIMOTE_INIT; // m_report = WIIMOTE_REPORT_INIT; // m_connected = false; // return SC_WIIManager::instance().add(this); // } #endif return( false ); } bool SC_WII::close() { if (m_wiiremote != NULL) { #ifdef SC_DARWIN if (wiiremote_isconnected(m_wiiremote)) wiiremote_disconnect(m_wiiremote); ; //m_wiiremote, sizeof(WiiRemoteRec)); m_wiiremote = NULL; m_searching = 0; #endif #ifdef __linux__ if ( cwiid_close( m_wiiremote ) ){ // m_wiiremote = NULL; post( "error closing device\n" ); fflush( stdout ); return errFailed; } m_wiiremote = NULL; // return errNone; // if (wiimote_is_open(m_wiiremote)) // wiimote_disconnect(m_wiiremote); #endif } // SetNil(m_obj->slots+0); return SC_WIIManager::instance().remove(this); } bool SC_WII::wii_connect() { #ifdef SC_DARWIN if (wiiremote_isconnected(m_wiiremote)) { post("WII: wiimote is already connected\n"); m_connected = true; } else { bool result; result = wiiremote_search( m_wiiremote, m_address); // start searching the device m_searching++; post("WII: searching wiimote %i\n",result); if ( result ) m_connected = true; else m_connected = false; } #endif #ifdef __linux__ // if (wiimote_connect(m_wiiremote, m_address) < 0) { // post("WII: unable to open wiimote: %s at address %s\n", wiimote_get_error(), m_address); // post("WII: unable to open wiimote at address %s\n",m_address); // m_connected = false; // } // else m_connected = true; #endif return( m_connected ); } void SC_WII::connected() { bool result; m_connected = true; m_searching = 0; #ifdef SC_DARWIN result = wiiremote_led( m_wiiremote, 0, 0, 0, 0); // if ( !result ) // wii_disconnect(); #endif // post("WII: wiiremote connected\n"); pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, s_wiiConnected, 1); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } bool SC_WII::wii_disconnect() { bool result; m_searching = 0; /// TODO: remove from wii_manager #ifdef SC_DARWIN wiiremote_stopsearch( m_wiiremote ); result = wiiremote_disconnect( m_wiiremote); #endif #ifdef __linux__ // result = wiimote_disconnect(m_wiiremote); #endif // call disconnect action if ( result ) disconnected(); return( result ); } int SC_WII::enable( bool enab ) { #ifdef __linux__ if ( enab ) { if (cwiid_enable(m_wiiremote, CWIID_FLAG_MESG_IFC)) { return errFailed; } } else { if (cwiid_disable(m_wiiremote, CWIID_FLAG_MESG_IFC)) { return errFailed; } } return errNone; #endif return errNone; } void SC_WII::disconnected() { m_connected = false; m_searching = 0; pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, s_wiiDisconnected, 1); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } // void SC_WII::speaker_init( int format ) // { // if ( format == 4 ) // wiimote_speaker_init(m_wiiremote, WIIMOTE_FMT_S4, 0xff); // else if ( format == 8 ) // wiimote_speaker_init(m_wiiremote, WIIMOTE_FMT_S8, 0xff); // } void SC_WII::get_address() { #ifdef SC_DARWIN if (m_wiiremote->device == NULL) { return; } else { char str[32]; wiiremote_getaddress(m_wiiremote, str); strcpy(m_address, str); } #endif } // bool SC_WII::update() // { // if (wiimote_update(m_wiiremote) < 0) { // wiimote_disconnect(m_wiiremote); // post( "WII: wiimote got disconnected\n"); // disconnected(); // return( false ); // } // return( true ); // } // void SC_WII::set_address( char * addr ) // { // strcpy( m_address, addr ); // // post( "WII: addr %s, m_address %s\n", addr, m_address ); // } #ifdef SC_DARWIN void SC_WII::handleEvent() { if (m_wiiremote->device == NULL) return; // do nothing pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); // buttons // post( "buttondata %i\n", m_wiiremote->buttonData); // ++g->sp; SetInt(g->sp, m_wiiremote->buttonData); PyrObject *butArray = newPyrArray(g->gc, 11 * sizeof(int), 0, true); PyrSlot *butArraySlots = butArray->slots; SetInt(butArray->slots+butArray->size++, (int) ((0x0008 & m_wiiremote->buttonData) > 0) ); //A SetInt(butArray->slots+butArray->size++, (int) ((0x0004 & m_wiiremote->buttonData) > 0) ); //B SetInt(butArray->slots+butArray->size++, (int) ((0x0002 & m_wiiremote->buttonData) > 0) ); //1 SetInt(butArray->slots+butArray->size++, (int) ((0x0001 & m_wiiremote->buttonData) > 0) ); //2 SetInt(butArray->slots+butArray->size++, (int) ((0x0010 & m_wiiremote->buttonData) > 0) ); //minus SetInt(butArray->slots+butArray->size++, (int) ((0x0080 & m_wiiremote->buttonData) > 0) ); //home SetInt(butArray->slots+butArray->size++, (int) ((0x1000 & m_wiiremote->buttonData) > 0) ); // plus SetInt(butArray->slots+butArray->size++, (int) ((0x0800 & m_wiiremote->buttonData) > 0) ); // up SetInt(butArray->slots+butArray->size++, (int) ((0x0400 & m_wiiremote->buttonData) > 0) ); // down SetInt(butArray->slots+butArray->size++, (int) ((0x0100 & m_wiiremote->buttonData) > 0) ); // left SetInt(butArray->slots+butArray->size++, (int) ((0x0200 & m_wiiremote->buttonData) > 0) ); // right butArray->size = 11; ++g->sp; SetObject(g->sp, butArray); if (m_wiiremote->isIRSensorEnabled) {// IR sensor ++g->sp; SetFloat(g->sp, m_wiiremote->posX); ++g->sp; SetFloat(g->sp, m_wiiremote->posY); ++g->sp; SetFloat(g->sp, m_wiiremote->angle); ++g->sp; SetInt(g->sp, m_wiiremote->tracking); } else { ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetInt(g->sp, 0); } if (m_wiiremote->isMotionSensorEnabled) { // motion sensor ++g->sp; SetFloat(g->sp, (float) m_wiiremote->accX / 256); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->accY / 256); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->accZ / 256); ++g->sp; SetInt(g->sp, m_wiiremote->orientation); } else { ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetInt(g->sp, 0); } if (m_wiiremote->isExpansionPortAttached && m_wiiremote->isExpansionPortEnabled) { ++g->sp; SetInt(g->sp, m_wiiremote->expType); // Classic Controller if (m_wiiremote->expType == WiiClassicController) { // buttons //++g->sp; SetInt(g->sp, m_wiiremote->cButtonData); PyrObject *outArray = newPyrArray(g->gc, 15 * sizeof(char), 0, true); PyrSlot *outArraySlots = outArray->slots; SetInt(outArray->slots+outArray->size++, (int) ((0x0008 & m_wiiremote->cButtonData) > 0) ); //X SetInt(outArray->slots+outArray->size++, (int) ((0x0020 & m_wiiremote->cButtonData) > 0) ); //Y SetInt(outArray->slots+outArray->size++, (int) ((0x0010 & m_wiiremote->cButtonData) > 0) ); //A SetInt(outArray->slots+outArray->size++, (int) ((0x0040 & m_wiiremote->cButtonData) > 0) ); //B SetInt(outArray->slots+outArray->size++, (int) ((0x2000 & m_wiiremote->cButtonData) > 0) ); //L SetInt(outArray->slots+outArray->size++, (int) ((0x0200 & m_wiiremote->cButtonData) > 0) ); //R SetInt(outArray->slots+outArray->size++, (int) ((0x0080 & m_wiiremote->cButtonData) > 0) ); //ZL SetInt(outArray->slots+outArray->size++, (int) ((0x0004 & m_wiiremote->cButtonData) > 0) ); //ZR SetInt(outArray->slots+outArray->size++, (int) ((0x0001 & m_wiiremote->cButtonData) > 0) ); //Up SetInt(outArray->slots+outArray->size++, (int) ((0x4000 & m_wiiremote->cButtonData) > 0) ); //Down SetInt(outArray->slots+outArray->size++, (int) ((0x0002 & m_wiiremote->cButtonData) > 0) ); //Left SetInt(outArray->slots+outArray->size++, (int) ((0x8000 & m_wiiremote->cButtonData) > 0) );//Right SetInt(outArray->slots+outArray->size++, (int) ((0x1000 & m_wiiremote->cButtonData) > 0) );//Minus SetInt(outArray->slots+outArray->size++, (int) ((0x0800 & m_wiiremote->cButtonData) > 0) );//Home SetInt(outArray->slots+outArray->size++, (int) ((0x0400 & m_wiiremote->cButtonData) > 0) );//Plus outArray->size = 15; ++g->sp; SetObject(g->sp, outArray); // Joystick 1 ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cStickX1 / 0x3F); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cStickY1 / 0x3F); // Joystick 2 ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cStickX2 / 0x1F); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cStickY2 / 0x1F); // Analog ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cAnalogL / 0x1F); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cAnalogR / 0x1F); } // Nunchuk if (m_wiiremote->expType == WiiNunchuk) { // Buttons //++g->sp; SetInt(g->sp, m_wiiremote->nButtonData); PyrObject *butArrayN = newPyrArray(g->gc, 2 * sizeof(int), 0, true); PyrSlot *butArraySlotsN = butArrayN->slots; SetInt(butArrayN->slots+butArrayN->size++, (int) ((0x01 & m_wiiremote->nButtonData) < 1) ); SetInt(butArrayN->slots+butArrayN->size++, (int) ((0x02 & m_wiiremote->nButtonData) < 1) ); butArrayN->size = 2; ++g->sp; SetObject(g->sp, butArrayN); // Joystick ++g->sp; SetFloat(g->sp, (float) m_wiiremote->nStickX / 256); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->nStickY / 256); // Motion Sensor if (m_wiiremote->isMotionSensorEnabled) { ++g->sp; SetFloat(g->sp, (float) m_wiiremote->nAccX / 256); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->nAccY / 256); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->nAccZ / 256); ++g->sp; SetInt(g->sp, m_wiiremote->nOrientation); } else { ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetInt(g->sp, 0); } } } else { ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); } ++g->sp; SetFloat(g->sp, m_wiiremote->batteryLevel); runInterpreter(g, s_handleEvent, 19); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } #endif #ifdef __linux__ void SC_WII::handleBatteryEvent( uint8_t battery ){ pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetFloat(g->sp, (float) battery / CWIID_BATTERY_MAX ); runInterpreter(g, s_handleBatteryEvent, 2); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } #endif #ifdef __linux__ void SC_WII::handleExtensionEvent( int ext_type ){ pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetInt(g->sp, ext_type ); runInterpreter(g, s_handleExtensionEvent, 2); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } #endif #ifdef __linux__ void SC_WII::handleButtonEvent( uint16_t buttons ){ pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); // post( "handle Button Event\n" ); // fflush( stdout ); // ++g->sp; SetInt(g->sp, (int) buttons ); PyrObject *outArray = newPyrArray(g->gc, 11 * sizeof(int), 0, true); PyrSlot *outArraySlots = outArray->slots; SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_A & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_B & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_1 & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_2 & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_MINUS & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_HOME & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_PLUS & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_UP & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_DOWN & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_LEFT & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_RIGHT & buttons) > 0) ); outArray->size = 11; ++g->sp; SetObject(g->sp, outArray); runInterpreter(g, s_handleButtonEvent, 2); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } #endif #ifdef __linux__ void SC_WII::handleAccEvent( uint8_t acc[3] ){ pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetFloat(g->sp, (float) acc[CWIID_X]/CWIID_ACC_MAX ); ++g->sp; SetFloat(g->sp, (float) acc[CWIID_Y]/CWIID_ACC_MAX ); ++g->sp; SetFloat(g->sp, (float) acc[CWIID_Z]/CWIID_ACC_MAX ); runInterpreter(g, s_handleAccEvent, 4); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } #endif #ifdef __linux__ void SC_WII::handleNunchukEvent( struct cwiid_nunchuk_mesg nunchuk ){ pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); PyrObject *outArray = newPyrArray(g->gc, 2 * sizeof(int), 0, true); PyrSlot *outArraySlots = outArray->slots; SetInt(outArray->slots+outArray->size++, (int) ((CWIID_NUNCHUK_BTN_Z & nunchuk.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_NUNCHUK_BTN_C & nunchuk.buttons) > 0) ); outArray->size = 2; ++g->sp; SetObject(g->sp, outArray); // ++g->sp; SetInt(g->sp, (int) nunchuk.buttons); ++g->sp; SetFloat(g->sp, (float) nunchuk.stick[CWIID_X]/256); ++g->sp; SetFloat(g->sp, (float) nunchuk.stick[CWIID_Y]/256); ++g->sp; SetFloat(g->sp, (float) nunchuk.acc[CWIID_X]/CWIID_ACC_MAX ); ++g->sp; SetFloat(g->sp, (float) nunchuk.acc[CWIID_Y]/CWIID_ACC_MAX ); ++g->sp; SetFloat(g->sp, (float) nunchuk.acc[CWIID_Z]/CWIID_ACC_MAX ); runInterpreter(g, s_handleNunchukEvent, 7); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } #endif #ifdef __linux__ void SC_WII::handleClassicEvent( struct cwiid_classic_mesg classic ){ pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); PyrObject *outArray = newPyrArray(g->gc, 15 * sizeof(char), 0, true); PyrSlot *outArraySlots = outArray->slots; SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_X & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_Y & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_A & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_B & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_L & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_R & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_ZL & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_ZR & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_UP & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_DOWN & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_LEFT & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_RIGHT & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_MINUS & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_HOME & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_PLUS & classic.buttons) > 0) ); outArray->size = 15; ++g->sp; SetObject(g->sp, outArray); // ++g->sp; SetInt(g->sp, (int) classic.buttons); ++g->sp; SetFloat(g->sp, (float) classic.l_stick[CWIID_X]/CWIID_CLASSIC_L_STICK_MAX ); ++g->sp; SetFloat(g->sp, (float) classic.l_stick[CWIID_Y]/CWIID_CLASSIC_L_STICK_MAX ); ++g->sp; SetFloat(g->sp, (float) classic.r_stick[CWIID_X]/CWIID_CLASSIC_R_STICK_MAX ); ++g->sp; SetFloat(g->sp, (float) classic.r_stick[CWIID_Y]/CWIID_CLASSIC_R_STICK_MAX ); ++g->sp; SetFloat(g->sp, (float) classic.l/CWIID_CLASSIC_LR_MAX ); ++g->sp; SetFloat(g->sp, (float) classic.r/CWIID_CLASSIC_LR_MAX ); runInterpreter(g, s_handleClassicEvent, 8); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } #endif #ifdef __linux__ void SC_WII::handleIREvent( int id, cwiid_ir_src ir ){ pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetInt(g->sp, id); ++g->sp; SetInt(g->sp, ir.valid); ++g->sp; SetFloat(g->sp, (float) ir.pos[CWIID_X]/CWIID_IR_X_MAX); ++g->sp; SetFloat(g->sp, (float) ir.pos[CWIID_Y]/CWIID_IR_Y_MAX); ++g->sp; SetFloat(g->sp, (float) ir.size/256); runInterpreter(g, s_handleIREvent, 6); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); } #endif void SC_WII::readError() { pthread_mutex_lock(&gLangMutex); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, s_readError, 1); g->canCallOS = false; } pthread_mutex_unlock(&gLangMutex); // SC_WIIManager::instance().remove( this ); } //------------ primitives --------------- int prWii_Start(VMGlobals* g, int numArgsPushed) { float updtime; int err; PyrSlot* args = g->sp - 1; // PyrSlot* args = g->sp; err = slotFloatVal(args+1, &updtime); if (err) return err; post( "update time %f", updtime ); // if (!g->canCallOS) return errCantCallOS; // return SC_WIIManager::instance().start(); return SC_WIIManager::instance().start(updtime); } int prWii_Stop(VMGlobals* g, int numArgsPushed) { // if (!g->canCallOS) return errCantCallOS; return SC_WIIManager::instance().stop(); } int prWii_Discover(VMGlobals* g, int numArgsPushed) { int curid, nmotes; int err; PyrSlot* args = g->sp - 1; err = slotIntVal(args, &curid); if (err) return err; if (!isKindOfSlot(args+1, class_array)) return errWrongType; PyrObject* allDevsArray = slotRawObject(&args[1]); PyrSlot* slotsArray = allDevsArray->slots; #ifdef __linux__ cwiid_wiimote_t * thiswii; thiswii = SC_WIIManager::instance().discover(); if ( thiswii == NULL ){ SetFalse(g->sp-2); post( "no device found\n" ); return errNone; } #endif if ( !isKindOfSlot(slotsArray+curid, s_wii->u.classobj ) ) { SetFalse(g->sp-2); return errWrongType; } PyrObject* obj = SC_WII::getObject(slotsArray+curid); SC_WII* dev = SC_WII::getDevice(obj); #ifdef SC_DARWIN dev->wii_connect(); #endif // post( "dev %p, wii %p\n", dev, dev->m_wiiremote ); // if (!dev) return errFailed; // free( dev->m_wiiremote ); #ifdef __linux__ dev->m_wiiremote = thiswii; #endif if ( SC_WIIManager::instance().add( dev ) ) { post( "device added\n" ); SetTrue(g->sp-2); } else { SetFalse(g->sp-2); post( "device was already added\n" ); } return errNone; } int prWii_Open(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; int err; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = new SC_WII(obj); err = dev->open(); if (err) { delete dev; return err; } return errNone; } int prWii_Close(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; return dev->close(); } int prWiiAddress(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; int err; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; dev->get_address(); SetSymbol(args, getsym(dev->m_address)); return errNone; } // int prWiiSetAddress(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // #ifdef __linux__ // char path[19]; // #endif // #ifdef SC_DARWIN // char path[32]; // #endif // err = slotStrVal(args+1, path, sizeof(path)); // if (err) return err; // // post( "WII: address %s\n", path ); // // dev->set_address( path ); // // return errNone; // } int prWiiConnect(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; int err; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; dev->wii_connect(); return errNone; } int prWiiDisconnect(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; int err; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; dev->wii_disconnect(); return errNone; } int prWiiCalibration(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; if (!isKindOfSlot(args+1, s_wiiCalibrationInfoClass->u.classobj)) return errWrongType; PyrObject* infoObj = slotRawObject(&args[1]); SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef SC_DARWIN SetFloat(infoObj->slots+0, dev->m_wiiremote->wiiCalibData.accX_zero); SetFloat(infoObj->slots+1, dev->m_wiiremote->wiiCalibData.accY_zero); SetFloat(infoObj->slots+2, dev->m_wiiremote->wiiCalibData.accZ_zero); SetFloat(infoObj->slots+3, dev->m_wiiremote->wiiCalibData.accX_1g); SetFloat(infoObj->slots+4, dev->m_wiiremote->wiiCalibData.accY_1g); SetFloat(infoObj->slots+5, dev->m_wiiremote->wiiCalibData.accZ_1g); if (dev->m_wiiremote->isExpansionPortAttached) { SetFloat(infoObj->slots+6, dev->m_wiiremote->nunchukCalibData.accX_zero); SetFloat(infoObj->slots+7, dev->m_wiiremote->nunchukCalibData.accY_zero); SetFloat(infoObj->slots+8, dev->m_wiiremote->nunchukCalibData.accZ_zero); SetFloat(infoObj->slots+9, dev->m_wiiremote->nunchukCalibData.accX_1g); SetFloat(infoObj->slots+10, dev->m_wiiremote->nunchukCalibData.accY_1g); SetFloat(infoObj->slots+11, dev->m_wiiremote->nunchukCalibData.accZ_1g); SetFloat(infoObj->slots+12, dev->m_wiiremote->nunchukJoyStickCalibData.x_max); SetFloat(infoObj->slots+13, dev->m_wiiremote->nunchukJoyStickCalibData.x_min); SetFloat(infoObj->slots+14, dev->m_wiiremote->nunchukJoyStickCalibData.x_center); SetFloat(infoObj->slots+15, dev->m_wiiremote->nunchukJoyStickCalibData.y_max); SetFloat(infoObj->slots+16, dev->m_wiiremote->nunchukJoyStickCalibData.y_min); SetFloat(infoObj->slots+17, dev->m_wiiremote->nunchukJoyStickCalibData.y_center); } #endif #ifdef __linux__ /* SetInt(infoObj->slots+0, dev->m_wiiremote->cal.x_zero); SetInt(infoObj->slots+1, dev->m_wiiremote->cal.y_zero); SetInt(infoObj->slots+2, dev->m_wiiremote->cal.z_zero); SetInt(infoObj->slots+3, dev->m_wiiremote->cal.x_scale); SetInt(infoObj->slots+4, dev->m_wiiremote->cal.y_scale); SetInt(infoObj->slots+5, dev->m_wiiremote->cal.z_scale); if (dev->m_wiiremote->mode.ext == 1) { SetInt(infoObj->slots+6, dev->m_wiiremote->ext.nunchuk.cal.x_zero); SetInt(infoObj->slots+7, dev->m_wiiremote->ext.nunchuk.cal.y_zero); SetInt(infoObj->slots+8, dev->m_wiiremote->ext.nunchuk.cal.z_zero); SetInt(infoObj->slots+9, dev->m_wiiremote->ext.nunchuk.cal.x_scale); SetInt(infoObj->slots+10, dev->m_wiiremote->ext.nunchuk.cal.y_scale); SetInt(infoObj->slots+11, dev->m_wiiremote->ext.nunchuk.cal.z_scale); SetInt(infoObj->slots+12, dev->m_wiiremote->ext.nunchuk.cal.joyx_max); SetInt(infoObj->slots+13, dev->m_wiiremote->ext.nunchuk.cal.joyx_min); SetInt(infoObj->slots+14, dev->m_wiiremote->ext.nunchuk.cal.joyx_center); SetInt(infoObj->slots+15, dev->m_wiiremote->ext.nunchuk.cal.joyy_max); SetInt(infoObj->slots+16, dev->m_wiiremote->ext.nunchuk.cal.joyy_min); SetInt(infoObj->slots+17, dev->m_wiiremote->ext.nunchuk.cal.joyy_center); }*/ #endif } slotCopy(&args[0], &args[1]); return errNone; } // int prWiiGetLED(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* leds = slotRawObject(&args[1]); // PyrSlot* bslots = leds->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef SC_DARWIN // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->led.one); // SetInt(bslots+1, dev->m_wiiremote->led.two); // SetInt(bslots+2, dev->m_wiiremote->led.three); // SetInt(bslots+3, dev->m_wiiremote->led.four); // #endif // } // // return errNone; // } // // int prWiiGetButtons(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef SC_DARWIN // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->keys.left); // SetInt(bslots+1, dev->m_wiiremote->keys.right); // SetInt(bslots+2, dev->m_wiiremote->keys.down); // SetInt(bslots+3, dev->m_wiiremote->keys.up); // SetInt(bslots+4, dev->m_wiiremote->keys.plus); // SetInt(bslots+5, dev->m_wiiremote->keys.two); // SetInt(bslots+6, dev->m_wiiremote->keys.one); // SetInt(bslots+7, dev->m_wiiremote->keys.b); // SetInt(bslots+8, dev->m_wiiremote->keys.a); // SetInt(bslots+9, dev->m_wiiremote->keys.minus); // SetInt(bslots+10, dev->m_wiiremote->keys.home); // #endif // } // // return errNone; // } // // int prWiiGetMotion(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef SC_DARWIN // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->axis.x); // SetInt(bslots+1, dev->m_wiiremote->axis.y); // SetInt(bslots+2, dev->m_wiiremote->axis.z); // #endif // } // // return errNone; // } // // int prWiiGetIR(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef SC_DARWIN // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->ir1.x); // SetInt(bslots+1, dev->m_wiiremote->ir1.y); // SetInt(bslots+2, dev->m_wiiremote->ir1.size); // #endif // } // // return errNone; // } // // int prWiiGetNunchukButtons(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef SC_DARWIN // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->ext.nunchuk.keys.z); // SetInt(bslots+1, dev->m_wiiremote->ext.nunchuk.keys.c); // #endif // } // // return errNone; // } // // int prWiiGetNunchukJoy(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef SC_DARWIN // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->ext.nunchuk.joyx); // SetInt(bslots+1, dev->m_wiiremote->ext.nunchuk.joyy); // #endif // } // // return errNone; // } // // int prWiiGetNunchukMotion(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef SC_DARWIN // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->ext.nunchuk.axis.x); // SetInt(bslots+1, dev->m_wiiremote->ext.nunchuk.axis.y); // SetInt(bslots+2, dev->m_wiiremote->ext.nunchuk.axis.z); // #endif // } // // return errNone; // } // // int prWiiGetExpansion(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef SC_DARWIN // if (dev->m_wiiremote->isExpansionPortAttached) // SetInt( args, dev->m_wiiremote->expType ); // else // SetInt( args, 0 ); // #endif // // #ifdef __linux__ // // if ( dev->m_wiiremote->mode.ext == 1 ) // // SetInt( args, dev->m_wiiremote->ext.id ); // // else // // SetInt( args, 0 ); // // #endif // } // // return errNone; // } // // int prWiiGetBattery(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef SC_DARWIN // if (dev->m_wiiremote->batteryLevel) // SetFloat( args, dev->m_wiiremote->batteryLevel ); // else // SetFloat( args, 0 ); // #endif // // #ifdef __linux__ // // SetFloat( args, dev->m_wiiremote->battery ); // // #endif // } // // return errNone; // } int prWiiSetLED(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; bool result; int enable1, enable2, enable3, enable4; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; if (!isKindOfSlot(args+1, class_array)) return errWrongType; PyrObject* leds = slotRawObject(&args[1]); PyrSlot* bslots = leds->slots; err = slotIntVal( bslots+0, &enable1 ); if (err) return err; err = slotIntVal( bslots+1, &enable2 ); if (err) return err; err = slotIntVal( bslots+2, &enable3 ); if (err) return err; err = slotIntVal( bslots+3, &enable4 ); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef SC_DARWIN result = wiiremote_led( dev->m_wiiremote, enable1, enable2, enable3, enable4); // if ( !result ) // dev->wii_disconnect(); #endif #ifdef __linux__ if ( enable1 ) set_bit(&dev->led_state, CWIID_LED1_ON); else clear_bit(&dev->led_state, CWIID_LED1_ON); if ( enable2 ) set_bit(&dev->led_state, CWIID_LED2_ON); else clear_bit(&dev->led_state, CWIID_LED2_ON); if ( enable3 ) set_bit(&dev->led_state, CWIID_LED3_ON); else clear_bit(&dev->led_state, CWIID_LED3_ON); if ( enable4 ) set_bit(&dev->led_state, CWIID_LED4_ON); else clear_bit(&dev->led_state, CWIID_LED4_ON); set_led_state(dev->m_wiiremote, dev->led_state); // post( "WII: led %i %i %i %i", dev->m_wiiremote->led.one, dev->m_wiiremote->led.two, dev->m_wiiremote->led.three, dev->m_wiiremote->led.four ); // dev->update(); #endif } return errNone; } int prWiiSetVibration(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef SC_DARWIN result = wiiremote_vibration( dev->m_wiiremote, enable1 ); // if ( !result ) // dev->wii_disconnect(); // post( "WII: rumble %i %i", enable1, result ); #endif #ifdef __linux__ if (cwiid_set_rumble(dev->m_wiiremote, (unsigned char) enable1)) { return errFailed; } // post( "WII: rumble %i %i", dev->m_wiiremote->rumble, enable1 ); #endif } return errNone; } int prWiiSetExpansion(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef SC_DARWIN result = wiiremote_expansion( dev->m_wiiremote, enable1 ); // if ( !result ) // dev->wii_disconnect(); #endif #ifdef __linux__ if ( enable1 ) set_bit(&dev->rpt_mode, CWIID_RPT_EXT); else clear_bit(&dev->rpt_mode, CWIID_RPT_EXT); set_rpt_mode(dev->m_wiiremote, dev->rpt_mode); // post( "WII: expansion %i %i", dev->m_wiiremote->mode.ext, enable1 ); #endif } return errNone; } int prWiiSetIRSensor(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef SC_DARWIN result = wiiremote_irsensor( dev->m_wiiremote, enable1 ); // if ( !result ) // dev->wii_disconnect(); #endif #ifdef __linux__ if ( enable1 ) set_bit(&dev->rpt_mode, CWIID_RPT_IR); else clear_bit(&dev->rpt_mode, CWIID_RPT_IR); set_rpt_mode(dev->m_wiiremote, dev->rpt_mode); // post( "WII: ir sensor %i %i", dev->m_wiiremote->mode.ir, enable1 ); #endif } return errNone; } int prWiiSetMotionSensor(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef SC_DARWIN result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); // if ( !result ) // dev->wii_disconnect(); #endif #ifdef __linux__ if ( enable1 ) set_bit(&dev->rpt_mode, CWIID_RPT_ACC); else clear_bit(&dev->rpt_mode, CWIID_RPT_ACC); set_rpt_mode(dev->m_wiiremote, dev->rpt_mode); #endif } return errNone; } int prWiiSetButtons(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef SC_DARWIN // buttons are always enabled // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); #endif #ifdef __linux__ if ( enable1 ) set_bit(&dev->rpt_mode, CWIID_RPT_BTN); else clear_bit(&dev->rpt_mode, CWIID_RPT_BTN); set_rpt_mode(dev->m_wiiremote, dev->rpt_mode); #endif } return errNone; } int prWiiEnable(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef SC_DARWIN // is always enabled // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); #endif #ifdef __linux__ dev->enable( enable1 ); #endif } return errNone; } // int prWiiPlaySpeaker(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 4; // int err; // int enable1; // int freq, vol; // bool result; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // err = slotIntVal(args+1, &enable1); // if (err) return err; // // err = slotIntVal(args+2, &freq); // if (err) return err; // // err = slotIntVal(args+3, &vol); // if (err) return err; // // // err = slotIntVal(args+4, &sample); // // if (err) return err; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // // #ifdef SC_DARWIN // // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); // // #endif // #ifdef __linux__ // uint8_t sample[20] = { // 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, // 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c // }; // wiimote_speaker_freq( dev->m_wiiremote, (uint8_t) freq); // wiimote_speaker_volume( dev->m_wiiremote, (uint8_t) vol ); // if ( enable1 ) // wiimote_speaker_play( dev->m_wiiremote, sample, 20); // // // post( "WII: speaker %i %i", freq, vol ); // #endif // } // // return errNone; // } // int prWiiEnableSpeaker(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // int enable1; // bool result; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // err = slotIntVal(args+1, &enable1); // if (err) return err; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // // #ifdef SC_DARWIN // // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); // // #endif // #ifdef __linux__ // if ( enable1 ) // wiimote_speaker_enable(dev->m_wiiremote); // else // wiimote_speaker_disable(dev->m_wiiremote); // // // post( "WII: speaker enable %i", enable1 ); // // #endif // } // // return errNone; // } // // int prWiiInitSpeaker(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // int enable1; // bool result; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // err = slotIntVal(args+1, &enable1); // if (err) return err; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // // #ifdef SC_DARWIN // // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); // // #endif // #ifdef __linux__ // if ( enable1 ) // dev->speaker_init( 4 ); // else // dev->speaker_init( 8 ); // // // post( "WII: speaker init %i", enable1 ); // // #endif // } // // return errNone; // } // // int prWiiMuteSpeaker(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // int enable1; // bool result; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // err = slotIntVal(args+1, &enable1); // if (err) return err; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // // #ifdef SC_DARWIN // // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); // // #endif // #ifdef __linux__ // if ( enable1 ) // wiimote_speaker_mute(dev->m_wiiremote); // else // wiimote_speaker_unmute(dev->m_wiiremote); // // // post( "WII: mute %i", enable1 ); // #endif // } // // return errNone; // } void initWiiPrimitives() { int base, index; s_wii = getsym("WiiMote"); s_wiiCalibrationInfoClass = getsym("WiiCalibrationInfo"); // has calibration date for all axes // s_wiiLEDStateClass = getsym("WiiLEDState"); // has the four LED states // s_wiiRemoteClass = getsym("WiiRemote"); // Remote // s_wiiNunChuckClass = getsym("WiiNunChuck"); // NunChuck // s_wiiClassicClass = getsym("WiiClassic"); // Classic // s_wiiAction = getsym("prWiiMoteAction"); s_wiiDisconnected = getsym("prDisconnectAction"); s_wiiConnected = getsym("prConnectAction"); s_readError = getsym("prReadError"); /// general event on MacOSX s_handleEvent = getsym("prHandleEvent"); /// separate events on Linux: s_handleBatteryEvent = getsym("prHandleBatteryEvent"); s_handleExtensionEvent = getsym("prHandleExtensionEvent"); s_handleButtonEvent = getsym("prHandleButtonEvent"); s_handleNunchukEvent = getsym("prHandleNunchukEvent"); s_handleClassicEvent = getsym("prHandleClassicEvent"); s_handleIREvent = getsym("prHandleIREvent"); s_handleAccEvent = getsym("prHandleAccEvent"); base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_Wii_Start", prWii_Start, 2, 0); // starts the eventloop definePrimitive(base, index++, "_Wii_Discover", prWii_Discover, 3, 0); // discovers a new device definePrimitive(base, index++, "_Wii_Stop", prWii_Stop, 1, 0); // stops the eventloop definePrimitive(base, index++, "_Wii_Open", prWii_Open, 1, 0 ); // definePrimitive(base, index++, "_Wii_Update", prWii_Update, 1, 0 ); // definePrimitive(base, index++, "_Wii_UpdateData", prWii_UpdateData, 9, 0 ); definePrimitive(base, index++, "_Wii_Close", prWii_Close, 1, 0 ); definePrimitive(base, index++, "_Wii_Address", prWiiAddress, 1, 0); // definePrimitive(base, index++, "_Wii_SetAddress", prWiiSetAddress, 2, 0); definePrimitive(base, index++, "_Wii_Connect", prWiiConnect, 1, 0); definePrimitive(base, index++, "_Wii_Disconnect", prWiiDisconnect, 1, 0); definePrimitive(base, index++, "_Wii_Calibration", prWiiCalibration, 2, 0); // definePrimitive(base, index++, "_Wii_GetExpansion", prWiiGetExpansion, 1, 0); // definePrimitive(base, index++, "_Wii_GetBattery", prWiiGetBattery, 1, 0); // // definePrimitive(base, index++, "_Wii_GetButtons", prWiiGetButtons, 2, 0); // definePrimitive(base, index++, "_Wii_GetMotion", prWiiGetMotion, 2, 0); // definePrimitive(base, index++, "_Wii_GetIR", prWiiGetIR, 2, 0); // // definePrimitive(base, index++, "_Wii_GetNunchukButtons", prWiiGetNunchukButtons, 2, 0); // definePrimitive(base, index++, "_Wii_GetNunchukJoy", prWiiGetNunchukJoy, 2, 0); // definePrimitive(base, index++, "_Wii_GetNunchukMotion", prWiiGetNunchukMotion, 2, 0); // definePrimitive(base, index++, "_Wii_GetClassicButtons", prWiiGetClassicButtons, 2, 0); // definePrimitive(base, index++, "_Wii_GetClassicJoy", prWiiGetClassicJoy, 2, 0); // definePrimitive(base, index++, "_Wii_GetClassicAnalog", prWiiGetClassicAnalog, 2, 0); // definePrimitive(base, index++, "_Wii_GetLED", prWiiGetLED, 2, 0); definePrimitive(base, index++, "_Wii_SetLED", prWiiSetLED, 2, 0); definePrimitive(base, index++, "_Wii_SetVibration", prWiiSetVibration, 2, 0); // definePrimitive(base, index++, "_Wii_InitSpeaker", prWiiInitSpeaker, 2, 0); // definePrimitive(base, index++, "_Wii_PlaySpeaker", prWiiPlaySpeaker, 5, 0); // definePrimitive(base, index++, "_Wii_MuteSpeaker", prWiiMuteSpeaker, 2, 0); // definePrimitive(base, index++, "_Wii_EnableSpeaker", prWiiEnableSpeaker, 2, 0); definePrimitive(base, index++, "_Wii_Enable", prWiiEnable, 2, 0); definePrimitive(base, index++, "_Wii_EnableButtons", prWiiSetButtons, 2, 0); definePrimitive(base, index++, "_Wii_EnableIRSensor", prWiiSetIRSensor, 2, 0); definePrimitive(base, index++, "_Wii_EnableMotionSensor", prWiiSetMotionSensor, 2, 0); definePrimitive(base, index++, "_Wii_EnableExpansion", prWiiSetExpansion, 2, 0); } #else // NOT HAVE_WII void initWiiPrimitives() { //other platforms? } #endif SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrPrimitive.cpp0000664000000000000000000036044012245365552025763 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "PyrKernel.h" #include "PyrObject.h" #include "PyrPrimitive.h" #include "PyrPrimitiveProto.h" #include "PyrSignal.h" #include "PyrSched.h" #include "PyrSignalPrim.h" #include "PyrFilePrim.h" #include "PyrMathPrim.h" #include "PyrListPrim.h" #include "Opcodes.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrMessage.h" #include "PyrParseNode.h" #include "PyrLexer.h" #include "PyrKernelProto.h" #include "PyrInterpreter.h" #include "PyrObjectProto.h" #include "PyrArchiverT.h" #include "PyrDeepCopier.h" #include "PyrDeepFreezer.h" //#include "Wacom.h" #include "InitAlloc.h" #include "../LangSource/SC_LanguageConfig.hpp" #include "SC_DirUtils.h" #include "SC_Version.hpp" #ifdef SC_WIN32 # include #else # include #endif #ifdef SC_QT # include "QtCollider.h" #endif #include "SCDocPrim.h" int yyparse(); extern bool gTraceInterpreter; PyrSymbol *s_recvmsg; void initPatternPrimitives(); typedef struct { PrimitiveHandler func; PyrSymbol* name; unsigned short base; unsigned char numArgs; unsigned char varArgs; unsigned char keyArgs; } PrimitiveDef; typedef struct { int size, maxsize; PrimitiveDef *table; } PrimitiveTable; extern PrimitiveTable gPrimitiveTable; extern PyrSlot o_nullframe; int getPrimitiveNumArgs(int index) { return gPrimitiveTable.table[index].numArgs; } PyrSymbol* getPrimitiveName(int index) { return gPrimitiveTable.table[index].name; } int slotStrLen(PyrSlot *slot) { if (IsSym(slot)) return slotRawSymbol(slot)->length; if (isKindOfSlot(slot, class_string)) return slotRawObject(slot)->size; return -1; } int slotStrVal(PyrSlot *slot, char *str, int maxlen) { if (IsSym(slot)) { strncpy(str, slotRawSymbol(slot)->name, maxlen); return errNone; } else if (isKindOfSlot(slot, class_string)) { int len; len = sc_min(maxlen-1, slotRawObject(slot)->size); memcpy(str, slotRawString(slot)->s, len); str[len] = 0; return errNone; } return errWrongType; } int slotPStrVal(PyrSlot *slot, unsigned char *str) { if (IsSym(slot)) { strncpy((char*)str+1, slotRawSymbol(slot)->name, 255); str[0] = slotRawSymbol(slot)->length; return errNone; } else if (isKindOfSlot(slot, class_string)) { int len; len = sc_min(255, slotRawObject(slot)->size); memcpy(str+1, slotRawString(slot)->s, len); str[0] = len; return errNone; } return errWrongType; } int instVarAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; PyrObject *obj = slotRawObject(a); if (IsInt(b)) { index = slotRawInt(b); if (index < 0 || index >= obj->size) return errIndexOutOfRange; slotCopy(a,&obj->slots[index]); } else if (IsSym(b)) { PyrSlot *instVarNamesSlot = &obj->classptr->instVarNames; if (!isKindOfSlot(instVarNamesSlot, class_symbolarray)) return errFailed; PyrSymbolArray *instVarNames = slotRawSymbolArray(instVarNamesSlot); PyrSymbol **names = instVarNames->symbols; PyrSymbol *name = slotRawSymbol(b); for (int i=0; isize; ++i) { if (names[i] == name) { slotCopy(a,&obj->slots[i]); return errNone; } } return errFailed; } else return errWrongType; return errNone; } int instVarPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *slot; int index; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (IsInt(b)) { index = slotRawInt(b); if (index < 0 || index >= obj->size) return errIndexOutOfRange; slot = obj->slots + index; slotCopy(slot,c); g->gc->GCWrite(obj, slot); } else if (IsSym(b)) { PyrSlot *instVarNamesSlot = &obj->classptr->instVarNames; if (!IsObj(instVarNamesSlot)) return errFailed; PyrSymbolArray *instVarNames = slotRawSymbolArray(instVarNamesSlot); PyrSymbol **names = instVarNames->symbols; PyrSymbol *name = slotRawSymbol(b); for (int i=0; isize; ++i) { if (names[i] == name) { slot = obj->slots + i; slotCopy(slot,c); g->gc->GCWrite(obj, slot); return errNone; } } post("WARNING: %s instVarPut '%s' failed.\n", slotRawSymbol(&obj->classptr->name)->name, name->name); return errNone; } else return errWrongType; return errNone; } int instVarSize(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrObject *obj; a = g->sp; if (NotObj(a)) { SetInt(a, 0); return errNone; } obj = slotRawObject(a); if (obj->obj_format == obj_notindexed) { SetInt(a, obj->size); } else { SetInt(a, 0); } return errNone; } int objectHash(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; int hash; a = g->sp; hash = calcHash(a); SetInt(a, hash); return errNone; } int objectClass(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrClass *classobj; a = g->sp; classobj = classOfSlot(a); SetObject(a, classobj); return errNone; } int prPrimitiveError(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; slotCopy(a,&g->thread->primitiveError); return errNone; } int prStackDepth(struct VMGlobals *g, int numArgsPushed); int prStackDepth(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetInt(a, g->gc->StackDepth()); return errNone; } extern void DumpStack(VMGlobals *g, PyrSlot *sp); int prDumpStack(struct VMGlobals *g, int numArgsPushed) { DumpStack(g, g->sp); return errNone; } void DumpDetailedBackTrace(VMGlobals *g); int prDumpDetailedBackTrace(struct VMGlobals *g, int numArgsPushed); int prDumpDetailedBackTrace(struct VMGlobals *g, int numArgsPushed) { DumpDetailedBackTrace(g); return errNone; } int prPrimitiveErrorString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrString *string; const char *str; a = g->sp; switch (slotRawInt(&g->thread->primitiveError)) { case errReturn : str = "Return (not an error)."; break; case errNone : str = "No Error"; break; case errFailed : str = "Failed."; break; case errBadPrimitive : str = "Bad Primitive."; break; case errWrongType : str = "Wrong type."; break; case errIndexNotAnInteger : str = "Index not an Integer"; break; case errIndexOutOfRange : str = "Index out of range."; break; case errImmutableObject : str = "Attempted write to immutable object."; break; case errNotAnIndexableObject : str = "Not an indexable object."; break; case errStackOverflow : str = "Stack overflow."; break; case errOutOfMemory : str = "Out of memory."; break; case errCantCallOS : str = "Operation cannot be called from this Process. Try using AppClock instead of SystemClock."; break; default : str = "Failed."; } string = newPyrString(g->gc, str, 0, true); SetObject(a, string); return errNone; } int prPostString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; //if (NotObj(a)) return errWrongType; // assume it is a string! postText(slotRawString(a)->s, slotRawString(a)->size); return errNone; } int prPostLine(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; //if (NotObj(a)) return errWrongType; // assume it is a string! postText(slotRawString(a)->s, slotRawString(a)->size); postChar('\n'); return errNone; } int prDebugger(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; //Debugger(); return errNone; } int prObjectString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrString *string; char str[256]; a = g->sp; if (IsSym(a)) { string = newPyrString(g->gc, slotRawSymbol(a)->name, 0, true); SetObject(a, string); return errNone; } else if (postString(a, str)) { string = newPyrString(g->gc, str, 0, true); SetObject(a, string); return errNone; } else { return errFailed; } } int prFloat_AsStringPrec(struct VMGlobals *g, int numArgsPushed); int prFloat_AsStringPrec(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; int precision; int err = slotIntVal(b, &precision); if (err) return err; char fmt[8], str[256]; sprintf(fmt, "%%.%dg", precision); sprintf(str, fmt, slotRawFloat(a)); PyrString *string = newPyrString(g->gc, str, 0, true); SetObject(a, string); return errNone; } int prAsCompileString(struct VMGlobals *g, int numArgsPushed); int prAsCompileString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrString *string; int err = errNone; a = g->sp; if (IsSym(a)) { int len = strlen(slotRawSymbol(a)->name) + 1; if (len < 255) { char str[256]; sprintf(str, "'%s'", slotRawSymbol(a)->name); string = newPyrString(g->gc, str, 0, true); } else { char *str = (char*)malloc(len+2); sprintf(str, "'%s'", slotRawSymbol(a)->name); string = newPyrString(g->gc, str, 0, true); free(str); } } else { char str[256]; err = asCompileString(a, str); if (err) return err; string = newPyrString(g->gc, str, 0, true); } SetObject(a, string); return err; } int prClassString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrClass *classobj; PyrString *string; a = g->sp; classobj = classOfSlot(a); string = newPyrString(g->gc, slotRawSymbol(&classobj->name)->name, 0, true); SetObject(a, string); return errNone; } int prPrimName(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrThread *thread; a = g->sp; thread = slotRawThread(a); if (slotRawInt(&thread->primitiveIndex) <= gPrimitiveTable.size) { SetSymbol(a, gPrimitiveTable.table[slotRawInt(&thread->primitiveIndex)].name); } else { SetSymbol(a, s_none); } return errNone; } int objectIsKindOf(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrClass *classobj, *testclass; int objClassIndex, testClassIndex, maxSubclassIndex; a = g->sp - 1; b = g->sp; if (NotObj(b)) return errWrongType; testclass = (PyrClass*)slotRawObject(b); classobj = classOfSlot(a); #if 0 while (classobj) { if (classobj == testclass) { SetTrue(a); return errNone; } classobj = slotRawSymbol(&classobj->superclass)->u.classobj; } SetFalse(a); #else // constant time lookup method: objClassIndex = slotRawInt(&classobj->classIndex); testClassIndex = slotRawInt(&testclass->classIndex); maxSubclassIndex = slotRawInt(&testclass->maxSubclassIndex); /*post("%s %s\n", slotRawSymbol(&classobj->name)->name, testclass->name.us->name); post("objClassIndex %d\n", objClassIndex); post("testClassIndex %d\n", testClassIndex); post("maxSubclassIndex %d\n", maxSubclassIndex);*/ if (objClassIndex >= testClassIndex && objClassIndex <= maxSubclassIndex) { SetTrue(a); return errNone; } else { SetFalse(a); return errNone; } #endif return errNone; } int objectIsMemberOf(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrClass *classobj, *testclass; a = g->sp - 1; b = g->sp; if (NotObj(b)) return errWrongType; testclass = (PyrClass*)slotRawObject(b); classobj = classOfSlot(a); if (classobj == testclass) { SetTrue(a); } else { SetFalse(a); } return errNone; } int objectIdentical(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; a = g->sp - 1; b = g->sp; if (SlotEq(a, b)) SetTrue(a); else SetFalse(a); return errNone; } int objectNotIdentical(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; a = g->sp - 1; b = g->sp; if ( !SlotEq(a, b) ) SetTrue(a); else SetFalse(a); return errNone; } int basicNewClear(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int size; PyrClass *classobj; PyrObject *newobj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; classobj = (PyrClass*)slotRawObject(a); if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) { // create an indexable object if (NotInt(b)) { if (IsFloat(b)) { size = (int)slotRawFloat(b); } else if (NotNil(b)) return errIndexNotAnInteger; else size = 8; } else { size = slotRawInt(b); } if (size < 0) size = 0; } else { size = 0; } newobj = instantiateObject(g->gc, classobj, size, true, true); SetObject(a, newobj); return errNone; } int basicNewCopyArgsToInstanceVars(struct VMGlobals *g, int numArgsPushed); int basicNewCopyArgsToInstanceVars(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrClass *classobj; PyrObject *newobj; a = g->sp - numArgsPushed + 1; b = a + 1; if (NotObj(a)) return errWrongType; classobj = (PyrClass*)slotRawObject(a); if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) { error("CopyArgs : object has no instance variables.\n"); return errFailed; } newobj = instantiateObject(g->gc, classobj, 0, true, true); SetObject(a, newobj); int length = sc_min(numArgsPushed-1, newobj->size); for (int i=0; islots[i],&b[i]); } return errNone; } int basicNew(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int size; PyrClass *classobj; PyrObject *newobj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; classobj = (PyrClass*)slotRawObject(a); if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) { // create an indexable object if (NotInt(b)) { if (IsFloat(b)) { size = (int)slotRawFloat(b); } else if (NotNil(b)) return errIndexNotAnInteger; else size = 8; } else { size = slotRawInt(b); } if (size < 0) size = 0; } else { size = 0; } newobj = instantiateObject(g->gc, classobj, size, false, true); SetObject(a, newobj); return errNone; } bool isClosed(PyrBlock* fundef); bool isClosed(PyrBlock* fundef) { return IsNil(&fundef->contextDef) && fundef->classptr == class_fundef; } bool isWithinClosed(PyrBlock* fundef); bool isWithinClosed(PyrBlock* fundef) { while (fundef) { if (isClosed(fundef)) return true; fundef = slotRawBlock(&fundef->contextDef); } return false; } int prFunctionDefAsFunction(struct VMGlobals *g, int numArgsPushed); int prFunctionDefAsFunction(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (!isClosed(slotRawBlock(a))) { dumpObjectSlot(a); error("Only closed FunctionDef may be converted to a Function using asFunction.\n"); return errFailed; } PyrClosure* closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, true); closure->classptr = gSpecialClasses[op_class_func]->u.classobj; closure->size = 2; slotCopy(&closure->block,a); slotCopy(&closure->context,&slotRawInterpreter(&g->process->interpreter)->context); SetObject(a, closure); return errNone; } int prFunctionDefDumpContexts(struct VMGlobals *g, int numArgsPushed); int prFunctionDefDumpContexts(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; int i=0; while (slotRawBlock(a)) { post("%2d context %s %p\n", i++, slotRawSymbol(&slotRawObject(a)->classptr->name)->name, slotRawInt(&slotRawBlock(a)->contextDef)); a = &slotRawBlock(a)->contextDef; } return errNone; } int prFunctionDefIsClosed(struct VMGlobals *g, int numArgsPushed); int prFunctionDefIsClosed(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrBlock *block = slotRawBlock(a); SetBool(a, isClosed(block)); return errNone; } int prFunctionDefIsWithinClosed(struct VMGlobals *g, int numArgsPushed); int prFunctionDefIsWithinClosed(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrBlock *block = slotRawBlock(a); SetBool(a, isWithinClosed(block)); return errNone; } void reallocStack(struct VMGlobals *g, int stackNeeded, int stackDepth) { //PyrThread *thread = g->thread; PyrGC *gc = g->gc; int newStackSize = NEXTPOWEROFTWO(stackNeeded); PyrObject* array = newPyrArray(gc, newStackSize, 0, false); memcpy(array->slots, gc->Stack()->slots, stackDepth * sizeof(PyrSlot)); gc->SetStack(array); gc->ToBlack(gc->Stack()); g->sp = array->slots + stackDepth - 1; } int blockValueArray(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b; PyrObject *array; PyrList *list; PyrSlot *pslot, *qslot; int m, size; //a = g->sp - numArgsPushed + 1; b = g->sp; if (IsObj(b)) { if (slotRawObject(b)->classptr == class_array) { array = (PyrObject*)slotRawObject(b); above: size = array->size; PyrObject *stack = g->gc->Stack(); int stackDepth = g->sp - stack->slots + 1; int stackSize = ARRAYMAXINDEXSIZE(stack); int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations. if (stackNeeded > stackSize) { reallocStack(g, stackNeeded, stackDepth); b = g->sp; } pslot = array->slots - 1; qslot = b - 1; //pend = (double*)(pslot + size); //while (pslotsp += size - 1; return blockValue(g, size+numArgsPushed-1); } else if (slotRawObject(b)->classptr == class_list) { list = slotRawList(b); if (NotObj(&list->array)) return errWrongType; array = slotRawObject(&list->array); if (array->classptr != class_array) return errWrongType; goto above; } else { // last arg is not a list or array, so pass as normal return blockValue(g, numArgsPushed); } } else { return blockValue(g, numArgsPushed); } } int blockValueEnvir(struct VMGlobals *g, int numArgsPushed); int blockValueArrayEnvir(struct VMGlobals *g, int numArgsPushed); int blockValueArrayEnvir(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b; PyrObject *array; PyrList *list; PyrSlot *pslot, *qslot; int m, size; //a = g->sp - numArgsPushed + 1; b = g->sp; if (IsObj(b)) { if (slotRawObject(b)->classptr == class_array) { array = (PyrObject*)slotRawObject(b); above: size = array->size; PyrObject *stack = g->gc->Stack(); int stackDepth = g->sp - stack->slots + 1; int stackSize = ARRAYMAXINDEXSIZE(stack); int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations. if (stackNeeded > stackSize) { reallocStack(g, stackNeeded, stackDepth); b = g->sp; } pslot = array->slots - 1; qslot = b - 1; //pend = (double*)(pslot + size); //while (pslotsp += size - 1; return blockValueEnvir(g, size+numArgsPushed-1); } else if (slotRawObject(b)->classptr == class_list) { list = slotRawList(b); if (NotObj(&list->array)) return errWrongType; array = slotRawObject(&list->array); if (array->classptr != class_array) return errWrongType; goto above; } else { // last arg is not a list or array, so pass as normal return blockValueEnvir(g, numArgsPushed); } } else { return blockValueEnvir(g, numArgsPushed); } } HOT int blockValue(struct VMGlobals *g, int numArgsPushed) { PyrSlot *args; PyrSlot *vars; PyrFrame *frame; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrObject *proto; int i, m, mmax, numtemps; PyrBlock *block; PyrFrame *context; PyrFrame *caller; PyrFrame *homeContext; PyrClosure *closure; PyrMethodRaw *methraw; #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 30; args = g->sp - numArgsPushed + 1; numArgsPushed -- ; g->numpop = 0; closure = (PyrClosure*)slotRawObject(args); block = slotRawBlock(&closure->block); context = slotRawFrame(&closure->context); proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL; methraw = METHRAW(block); numtemps = methraw->numtemps; caller = g->frame; frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + numtemps; SetObject(&frame->method, block); slotCopy(&frame->homeContext,&context->homeContext); slotCopy(&frame->context,&closure->context); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, g->frame); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->sp = args - 1; g->ip = slotRawInt8Array(&block->code)->b - 1; g->frame = frame; g->block = block; if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */ /* push all args to frame */ qslot = args; pslot = vars; for (m=0; mslots + numArgsPushed - 1; for (m=0; mvarargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumargs; list = newPyrArray(g->gc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + methraw->numargs + 1, list); /* put extra args into list */ lslot = list->slots - 1; // fixed and raw sizes are zero for (m=0; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs + 1; qslot = proto->slots + methraw->numargs; for (m=0,mmax=methraw->numvars; mnumargs) { /* push all args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs; qslot = proto->slots + methraw->numargs - 1; for (m=0,mmax=methraw->numvars; mhomeContext); if (homeContext) { PyrMethodRaw *methraw; g->method = slotRawMethod(&homeContext->method); methraw = METHRAW(g->method); slotCopy(&g->receiver,&homeContext->vars[0]); } else { slotCopy(&g->receiver,&g->process->interpreter); } return errNone; } int blockValueWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed); int blockValueWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed) { PyrSlot *args; PyrSlot *vars; PyrFrame *frame; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrObject *proto; int i, j, m, mmax, numtemps, numArgsPushed; PyrBlock *block; PyrFrame *context; PyrFrame *caller; PyrFrame *homeContext; PyrClosure *closure; PyrMethodRaw *methraw; #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 40; args = g->sp - allArgsPushed + 1; allArgsPushed -- ; g->numpop = 0; closure = (PyrClosure*)slotRawObject(args); block = slotRawBlock(&closure->block); context = slotRawFrame(&closure->context); proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL; methraw = METHRAW(block); numtemps = methraw->numtemps; caller = g->frame; numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1); frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + numtemps; SetObject(&frame->method, block); slotCopy(&frame->homeContext,&context->homeContext); slotCopy(&frame->context,&closure->context); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, g->frame); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->sp = args - 1; g->ip = slotRawInt8Array(&block->code)->b - 1; g->frame = frame; g->block = block; if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */ /* push all args to frame */ qslot = args; pslot = vars; for (m=0; mslots + numArgsPushed - 1; for (m=0; mvarargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumargs; list = newPyrArray(g->gc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + methraw->numargs + 1, list); /* put extra args into list */ lslot = list->slots - 1; // fixed and raw sizes are zero //lend = lslot + i; //while (lslot < lend) slotCopy(++lslot, ++qslot); for (m=0; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs + 1; qslot = proto->slots + methraw->numargs; for (m=0,mmax=methraw->numvars; mnumargs) { /* push all args to frame */ qslot = args; pslot = vars; //pend = pslot + methraw->numargs; //while (pslot < pend) slotCopy(++pslot, ++qslot); for (m=0,mmax=methraw->numargs; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs; qslot = proto->slots + methraw->numargs - 1; //pend = pslot + methraw->numvars; //while (pslotnumvars; mposargs) { PyrSlot *key; PyrSymbol **name0, **name; name0 = slotRawSymbolArray(&block->argNames)->symbols; key = args + numArgsPushed + 1; for (i=0; iposargs; ++j, ++name) { if (*name == slotRawSymbol(key)) { slotCopy(&vars[j+1],&key[1]); goto found1; } } if (gKeywordError) { post("WARNING: keyword arg '%s' not found in call to function.\n", slotRawSymbol(key)->name); } found1: ; } } homeContext = slotRawFrame(&frame->homeContext); if (homeContext) { PyrMethodRaw *methraw; g->method = slotRawMethod(&homeContext->method); methraw = METHRAW(g->method); slotCopy(&g->receiver,&homeContext->vars[0]); } else { slotCopy(&g->receiver,&g->process->interpreter); } return errNone; } bool identDict_lookupNonNil(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result); int blockValueEnvir(struct VMGlobals *g, int numArgsPushed) { PyrSlot *args; PyrSlot *vars; PyrFrame *frame; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrObject *proto; int i, m, mmax, numtemps; PyrBlock *block; PyrFrame *context; PyrFrame *caller; PyrFrame *homeContext; PyrClosure *closure; PyrMethodRaw *methraw; PyrSlot *curEnvirSlot; #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 50; args = g->sp - numArgsPushed + 1; numArgsPushed -- ; g->numpop = 0; closure = (PyrClosure*)slotRawObject(args); block = slotRawBlock(&closure->block); context = slotRawFrame(&closure->context); proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL; methraw = METHRAW(block); numtemps = methraw->numtemps; caller = g->frame; frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + numtemps; SetObject(&frame->method, block); slotCopy(&frame->homeContext,&context->homeContext); slotCopy(&frame->context,&closure->context); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, g->frame); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->sp = args - 1; g->ip = slotRawInt8Array(&block->code)->b - 1; g->frame = frame; g->block = block; if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */ /* push all args to frame */ qslot = args; pslot = vars; for (m=0; mslots + numArgsPushed - 1; for (m=0; mclassvars->slots[1]; // currentEnvironment is the second class var. if (isKindOfSlot(curEnvirSlot, s_identitydictionary->u.classobj)) { PyrSymbol **argNames; argNames = slotRawSymbolArray(&block->argNames)->symbols; for (m=numArgsPushed; mnumargs; ++m) { // replace the args with values from the environment if they exist PyrSlot keyslot; SetSymbol(&keyslot, argNames[m]); identDict_lookupNonNil(slotRawObject(curEnvirSlot), &keyslot, calcHash(&keyslot), vars+m+1); } } } else if (methraw->varargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumargs; list = newPyrArray(g->gc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + methraw->numargs + 1, list); /* put extra args into list */ lslot = list->slots - 1; // fixed and raw sizes are zero for (m=0; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs + 1; qslot = proto->slots + methraw->numargs; for (m=0,mmax=methraw->numvars; mnumargs) { /* push all args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs; qslot = proto->slots + methraw->numargs - 1; for (m=0,mmax=methraw->numvars; mhomeContext); if (homeContext) { PyrMethodRaw *methraw; g->method = slotRawMethod(&homeContext->method); methraw = METHRAW(g->method); slotCopy(&g->receiver,&homeContext->vars[0]); } else { slotCopy(&g->receiver,&g->process->interpreter); } return errNone; } int blockValueEnvirWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed); int blockValueEnvirWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed) { PyrSlot *args; PyrSlot *vars; PyrFrame *frame; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrObject *proto; int i, j, m, mmax, numtemps, numArgsPushed; PyrBlock *block; PyrFrame *context; PyrFrame *caller; PyrFrame *homeContext; PyrClosure *closure; PyrMethodRaw *methraw; PyrSlot *curEnvirSlot; #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 60; args = g->sp - allArgsPushed + 1; allArgsPushed -- ; g->numpop = 0; closure = (PyrClosure*)slotRawObject(args); block = slotRawBlock(&closure->block); context = slotRawFrame(&closure->context); proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL; methraw = METHRAW(block); numtemps = methraw->numtemps; caller = g->frame; numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1); frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + numtemps; SetObject(&frame->method, block); slotCopy(&frame->homeContext,&context->homeContext); slotCopy(&frame->context,&closure->context); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, g->frame); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->sp = args - 1; g->ip = slotRawInt8Array(&block->code)->b - 1; g->frame = frame; g->block = block; if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */ /* push all args to frame */ qslot = args; pslot = vars; for (m=0; mslots + numArgsPushed - 1; for (m=0; mclassvars->slots[1]; // currentEnvironment is the second class var. if (isKindOfSlot(curEnvirSlot, s_identitydictionary->u.classobj)) { PyrSymbol **argNames; argNames = slotRawSymbolArray(&block->argNames)->symbols; for (m=numArgsPushed; mnumargs; ++m) { // replace the args with values from the environment if they exist PyrSlot keyslot; SetSymbol(&keyslot, argNames[m]); identDict_lookupNonNil(slotRawObject(curEnvirSlot), &keyslot, calcHash(&keyslot), vars+m+1); } } } else if (methraw->varargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumargs; list = newPyrArray(g->gc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + methraw->numargs + 1, list); /* put extra args into list */ lslot = list->slots - 1; // fixed and raw sizes are zero //lend = lslot + i; //while (lslot < lend) slotCopy(++lslot, ++qslot); for (m=0; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs + 1; qslot = proto->slots + methraw->numargs; for (m=0,mmax=methraw->numvars; mnumargs) { /* push all args to frame */ qslot = args; pslot = vars; //pend = pslot + methraw->numargs; //while (pslot < pend) slotCopy(++pslot, ++qslot); for (m=0,mmax=methraw->numargs; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs; qslot = proto->slots + methraw->numargs - 1; //pend = pslot + methraw->numvars; //while (pslotnumvars; mposargs) { PyrSymbol **name0, **name; PyrSlot *key; name0 = slotRawSymbolArray(&block->argNames)->symbols; key = args + numArgsPushed + 1; for (i=0; iposargs; ++j, ++name) { if (*name == slotRawSymbol(key)) { slotCopy(&vars[j+1],&key[1]); goto found1; } } if (gKeywordError) { post("WARNING: keyword arg '%s' not found in call to function.\n", slotRawSymbol(key)->name); } found1: ; } } homeContext = slotRawFrame(&frame->homeContext); if (homeContext) { PyrMethodRaw *methraw; g->method = slotRawMethod(&homeContext->method); methraw = METHRAW(g->method); slotCopy(&g->receiver,&homeContext->vars[0]); } else { slotCopy(&g->receiver,&g->process->interpreter); } return errNone; } int objectPerform(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax; recvrSlot = g->sp - numArgsPushed + 1; selSlot = recvrSlot + 1; if (IsSym(selSlot)) { selector = slotRawSymbol(selSlot); // move args down one to fill selector's position pslot = selSlot - 1; qslot = selSlot; for (m=0; msp -- ; numArgsPushed -- ; // now the stack looks just like it would for a normal message send } else if (IsObj(selSlot)) { listSlot = selSlot; if (slotRawObject(listSlot)->classptr == class_list) { listSlot = slotRawObject(listSlot)->slots; } if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { goto badselector; } PyrObject *array = slotRawObject(listSlot); if (array->size < 1) { error("Array must have a selector.\n"); return errFailed; } selSlot = array->slots; selector = slotRawSymbol(selSlot); if (numArgsPushed>2) { qslot = recvrSlot + numArgsPushed; pslot = recvrSlot + numArgsPushed + array->size - 2; for (m=0; msize-1; msp += array->size - 2; numArgsPushed += array->size - 2; // now the stack looks just like it would for a normal message send } else { badselector: error("perform selector not a Symbol or Array.\n"); dumpObjectSlot(selSlot); return errWrongType; } sendMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int objectPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed); int objectPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax; recvrSlot = g->sp - numArgsPushed + 1; selSlot = recvrSlot + 1; if (IsSym(selSlot)) { selector = slotRawSymbol(selSlot); // move args down one to fill selector's position pslot = selSlot - 1; qslot = selSlot; for (m=0; msp -- ; numArgsPushed -- ; // now the stack looks just like it would for a normal message send } else if (IsObj(selSlot)) { listSlot = selSlot; if (slotRawObject(listSlot)->classptr == class_list) { listSlot = slotRawObject(listSlot)->slots; } if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { goto badselector; } PyrObject *array = slotRawObject(listSlot); if (array->size < 1) { error("Array must have a selector.\n"); return errFailed; } selSlot = array->slots; selector = slotRawSymbol(selSlot); if (numArgsPushed>2) { qslot = recvrSlot + numArgsPushed; pslot = recvrSlot + numArgsPushed + array->size - 2; for (m=0; msize-1; msp += array->size - 2; numArgsPushed += array->size - 2; // now the stack looks just like it would for a normal message send } else { badselector: error("perform selector not a Symbol or Array.\n"); dumpObjectSlot(selSlot); return errWrongType; } sendMessageWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); g->numpop = 0; return errNone; } int objectPerformList(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax, numargslots; PyrObject *array; recvrSlot = g->sp - numArgsPushed + 1; selSlot = recvrSlot + 1; listSlot = g->sp; numargslots = numArgsPushed - 3; if (NotSym(selSlot)) { error("Selector not a Symbol :\n"); return errWrongType; } selector = slotRawSymbol(selSlot); if (NotObj(listSlot)) { return objectPerform(g, numArgsPushed); } if (slotRawObject(listSlot)->classptr == class_array) { doarray: array = slotRawObject(listSlot); PyrObject *stack = g->gc->Stack(); int stackDepth = g->sp - stack->slots + 1; int stackSize = ARRAYMAXINDEXSIZE(stack); int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations. if (stackNeeded > stackSize) { reallocStack(g, stackNeeded, stackDepth); recvrSlot = g->sp - numArgsPushed + 1; selSlot = recvrSlot + 1; } pslot = recvrSlot; if (numargslots>0) { qslot = selSlot; for (m=0; mslots - 1; for (m=0,mmax=array->size; mclassptr == class_list) { listSlot = slotRawObject(listSlot)->slots; if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { error("List array not an Array.\n"); dumpObjectSlot(listSlot); return errWrongType; } goto doarray; } else { return objectPerform(g, numArgsPushed); } g->sp += array->size - 2; numArgsPushed = numargslots + array->size + 1; // now the stack looks just like it would for a normal message send sendMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int objectSuperPerform(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax; recvrSlot = g->sp - numArgsPushed + 1; PyrClass* classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; if (!isKindOfSlot(recvrSlot, classobj)) { error("superPerform must be called with 'this' as the receiver.\n"); return errFailed; } selSlot = recvrSlot + 1; if (IsSym(selSlot)) { selector = slotRawSymbol(selSlot); // move args down one to fill selector's position pslot = selSlot - 1; qslot = selSlot; for (m=0; msp -- ; numArgsPushed -- ; // now the stack looks just like it would for a normal message send } else if (IsObj(selSlot)) { listSlot = selSlot; if (slotRawObject(listSlot)->classptr == class_list) { listSlot = slotRawObject(listSlot)->slots; } if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { goto badselector; } PyrObject *array = slotRawObject(listSlot); if (array->size < 1) { error("Array must have a selector.\n"); return errFailed; } selSlot = array->slots; selector = slotRawSymbol(selSlot); if (numArgsPushed>2) { qslot = recvrSlot + numArgsPushed; pslot = recvrSlot + numArgsPushed + array->size - 2; for (m=0; msize-1; msp += array->size - 2; numArgsPushed += array->size - 2; // now the stack looks just like it would for a normal message send } else { badselector: error("perform selector not a Symbol or Array.\n"); dumpObjectSlot(selSlot); return errWrongType; } sendSuperMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int objectSuperPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed); int objectSuperPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax; recvrSlot = g->sp - numArgsPushed + 1; PyrClass* classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; if (!isKindOfSlot(recvrSlot, classobj)) { error("superPerform must be called with 'this' as the receiver.\n"); return errFailed; } selSlot = recvrSlot + 1; if (IsSym(selSlot)) { selector = slotRawSymbol(selSlot); // move args down one to fill selector's position pslot = selSlot - 1; qslot = selSlot; for (m=0; msp -- ; numArgsPushed -- ; // now the stack looks just like it would for a normal message send } else if (IsObj(selSlot)) { listSlot = selSlot; if (slotRawObject(listSlot)->classptr == class_list) { listSlot = slotRawObject(listSlot)->slots; } if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { goto badselector; } PyrObject *array = slotRawObject(listSlot); if (array->size < 1) { error("Array must have a selector.\n"); return errFailed; } selSlot = array->slots; selector = slotRawSymbol(selSlot); if (numArgsPushed>2) { qslot = recvrSlot + numArgsPushed; pslot = recvrSlot + numArgsPushed + array->size - 2; for (m=0; msize-1; msp += array->size - 2; numArgsPushed += array->size - 2; // now the stack looks just like it would for a normal message send } else { badselector: error("perform selector not a Symbol or Array.\n"); dumpObjectSlot(selSlot); return errWrongType; } sendSuperMessageWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); g->numpop = 0; return errNone; } int objectSuperPerformList(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax, numargslots; PyrObject *array; recvrSlot = g->sp - numArgsPushed + 1; selSlot = recvrSlot + 1; listSlot = g->sp; numargslots = numArgsPushed - 3; if (NotSym(selSlot)) { error("Selector not a Symbol :\n"); return errWrongType; } selector = slotRawSymbol(selSlot); if (NotObj(listSlot)) { return objectPerform(g, numArgsPushed); } if (slotRawObject(listSlot)->classptr == class_array) { doarray: pslot = recvrSlot; if (numargslots>0) { qslot = selSlot; for (m=0; mslots - 1; for (m=0,mmax=array->size; mclassptr == class_list) { listSlot = slotRawObject(listSlot)->slots; if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { error("List array not an Array.\n"); dumpObjectSlot(listSlot); return errWrongType; } goto doarray; } else { return objectSuperPerform(g, numArgsPushed); } g->sp += array->size - 2; numArgsPushed = numargslots + array->size + 1; // now the stack looks just like it would for a normal message send sendSuperMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int objectPerformSelList(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax; PyrObject *array; recvrSlot = g->sp - 1; listSlot = g->sp; if (NotObj(listSlot)) { error("Expected Array or List.. Got :\n"); dumpObjectSlot(listSlot); return errWrongType; } if (slotRawObject(listSlot)->classptr == class_array) { doarray: array = slotRawObject(listSlot); selSlot = array->slots; if (NotSym(selSlot)) { error("Selector not a Symbol :\n"); return errWrongType; } selector = slotRawSymbol(selSlot); pslot = recvrSlot; qslot = selSlot; for (m=0,mmax=array->size-1; mclassptr == class_list) { listSlot = slotRawObject(listSlot)->slots; if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { error("List array not an Array.\n"); dumpObjectSlot(listSlot); return errWrongType; } goto doarray; } else { error("Expected Array or List.. Got :\n"); dumpObjectSlot(listSlot); return errWrongType; } g->sp += array->size - 2; numArgsPushed = array->size; // now the stack looks just like it would for a normal message send sendMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int arrayPerformMsg(struct VMGlobals *g, int numArgsPushed); int arrayPerformMsg(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *arraySlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax, numargslots; PyrObject *array; arraySlot = g->sp - numArgsPushed + 1; array = slotRawObject(arraySlot); if (array->size < 2) { error("Array must contain a receiver and a selector.\n"); return errFailed; } recvrSlot = array->slots; selSlot = recvrSlot + 1; numargslots = numArgsPushed - 1; if (NotSym(selSlot)) { error("Selector not a Symbol :\n"); return errWrongType; } selector = slotRawSymbol(selSlot); slotCopy(arraySlot,recvrSlot); if (numargslots>0) { qslot = arraySlot + numargslots + 1; pslot = arraySlot + numargslots + array->size - 1; for (m=0; msize-2; msp += array->size - 2; numArgsPushed = numargslots + array->size - 1; // now the stack looks just like it would for a normal message send sendMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int objectDump(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; dumpObjectSlot(a); return errNone; } int prTotalFree(struct VMGlobals *g, int numArgsPushed); int prTotalFree(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, g->allocPool->TotalFree()); return errNone; } int prLargestFreeBlock(struct VMGlobals *g, int numArgsPushed); int prLargestFreeBlock(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, g->allocPool->LargestFreeChunk()); return errNone; } int dumpGCinfo(struct VMGlobals *g, int numArgsPushed); int dumpGCinfo(struct VMGlobals *g, int numArgsPushed) { g->gc->DumpInfo(); return errNone; } int dumpGCdumpGrey(struct VMGlobals *g, int numArgsPushed); int dumpGCdumpGrey(struct VMGlobals *g, int numArgsPushed) { g->gc->DumpGrey(); return errNone; } int dumpGCdumpSet(struct VMGlobals *g, int numArgsPushed); int dumpGCdumpSet(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b = g->sp; int set; int err = slotIntVal(b, &set); if (err) return err; g->gc->DumpSet(set); return errNone; } int prGCSanity(struct VMGlobals *g, int numArgsPushed); int prGCSanity(struct VMGlobals *g, int numArgsPushed) { g->gc->SanityCheck(); return errNone; } #if GCDEBUG int prTraceAllPathsTo(struct VMGlobals *g, int numArgsPushed); int prTraceAllPathsTo(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; g->gc->TracePathsTo(slotRawObject(a), false); return errNone; } int prTraceAnyPathsTo(struct VMGlobals *g, int numArgsPushed); int prTraceAnyPathsTo(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; g->gc->TracePathsTo(slotRawObject(a), true); return errNone; } int prTraceAnyPathToAllInstancesOf(struct VMGlobals *g, int numArgsPushed); int prTraceAnyPathToAllInstancesOf(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; g->gc->TraceAnyPathToAllInstancesOf(slotRawClass(a)->name.us); return errNone; } #endif extern PyrClass *gClassList; int prAllClasses(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrClass *classobj; PyrObject *array; int i; a = g->sp; array = newPyrArray(g->gc, gNumClasses, 0, true); classobj = gClassList; for (i=0; classobj; ++i) { SetObject(array->slots + i, classobj); classobj = slotRawClass(&classobj->nextclass); } array->size = gNumClasses; SetObject(a, array); return errNone; } int prPostClassTree(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; postClassTree(slotRawClass(a), 0); return errNone; } int prDumpBackTrace(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; DumpBackTrace(g); return errNone; } /* the DebugFrameConstructor uses a work queue in order to avoid recursions, which could lead to stack overflows */ struct DebugFrameConstructor { void makeDebugFrame (VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot) { workQueue.push_back(std::make_pair(frame, outSlot)); run_queue(g); } private: void run_queue(VMGlobals *g) { while (!workQueue.empty()) { WorkQueueItem work = workQueue.back(); workQueue.pop_back(); fillDebugFrame(g, work.first, work.second); } } void fillDebugFrame(VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot) { PyrMethod *meth = slotRawMethod(&frame->method); PyrMethodRaw * methraw = METHRAW(meth); PyrObject* debugFrameObj = instantiateObject(g->gc, getsym("DebugFrame")->u.classobj, 0, false, true); SetObject(outSlot, debugFrameObj); SetObject(debugFrameObj->slots + 0, meth); SetPtr(debugFrameObj->slots + 5, meth); int numargs = methraw->numargs; int numvars = methraw->numvars; if (numargs) { PyrObject* argArray = (PyrObject*)newPyrArray(g->gc, numargs, 0, false); SetObject(debugFrameObj->slots + 1, argArray); for (int i=0; islots[i], &frame->vars[i]); argArray->size = numargs; } else SetNil(debugFrameObj->slots + 1); if (numvars) { PyrObject* varArray = (PyrObject*)newPyrArray(g->gc, numvars, 0, false); SetObject(debugFrameObj->slots + 2, varArray); for (int i=0, j=numargs; islots[i], &frame->vars[j]); varArray->size = numvars; } else SetNil(debugFrameObj->slots + 2); if (slotRawFrame(&frame->caller)) { WorkQueueItem newWork = std::make_pair(slotRawFrame(&frame->caller), debugFrameObj->slots + 3); workQueue.push_back(newWork); } else SetNil(debugFrameObj->slots + 3); if (IsObj(&frame->context) && slotRawFrame(&frame->context) == frame) SetObject(debugFrameObj->slots + 4, debugFrameObj); else if (NotNil(&frame->context)) { WorkQueueItem newWork = std::make_pair(slotRawFrame(&frame->context), debugFrameObj->slots + 4); workQueue.push_back(newWork); } else SetNil(debugFrameObj->slots + 4); } typedef std::pair WorkQueueItem; typedef std::vector WorkQueueType; WorkQueueType workQueue; }; static void MakeDebugFrame(VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot) { DebugFrameConstructor constructor; constructor.makeDebugFrame(g, frame, outSlot); } int prGetBackTrace(VMGlobals *g, int numArgsPushed); int prGetBackTrace(VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; MakeDebugFrame(g, g->frame, a); return errNone; } int prObjectShallowCopy(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; switch (GetTag(a)) { case tagObj : SetRaw(a, copyObject(g->gc, slotRawObject(a), true)); break; // the default case is to leave the argument unchanged on the stack } return errNone; } int prObjectCopyImmutable(struct VMGlobals *g, int numArgsPushed); int prObjectCopyImmutable(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; switch (GetTag(a)) { case tagObj : if (slotRawObject(a)->obj_flags & obj_immutable) { SetRaw(a, copyObject(g->gc, slotRawObject(a), true)); } break; } return errNone; } int prObjectIsMutable(struct VMGlobals *g, int numArgsPushed); int prObjectIsMutable(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (IsObj(a)) { if (slotRawObject(a)->obj_flags & obj_immutable) { SetFalse(a); } else { SetTrue(a); } } else { SetFalse(a); } return errNone; } int prObjectIsPermanent(struct VMGlobals *g, int numArgsPushed); int prObjectIsPermanent(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (IsObj(a)) { if (slotRawObject(a)->gc_color == obj_permanent) { SetTrue(a); } else { SetFalse(a); } } else { SetTrue(a); } return errNone; } int prDeepFreeze(struct VMGlobals *g, int numArgsPushed); int prDeepFreeze(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; PyrDeepFreezer freezer(g); int err = freezer.doDeepFreeze(a); return err; } int prDeepCopy(struct VMGlobals *g, int numArgsPushed); int prDeepCopy(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; PyrDeepCopier copier(g); int err = copier.doDeepCopy(a); return err; } bool IsSimpleLiteralSlot(PyrSlot* slot); bool IsSimpleLiteralSlot(PyrSlot* slot) { switch (GetTag(slot)) { case tagObj : return slotRawObject(slot)->IsPermanent(); case tagInt : return true; case tagSym : return true; case tagChar : return true; case tagNil : return true; case tagFalse : return true; case tagTrue : return true; case tagPtr : return false; default : return true; } } int prObjectCopyRange(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(a)) return errWrongType; if (NotInt(b)) return errWrongType; if (NotInt(c)) return errWrongType; SetRaw(a, copyObjectRange(g->gc, slotRawObject(a), slotRawInt(b), slotRawInt(c), true)); return errNone; } int prObjectCopySeries(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *d; a = g->sp - 3; b = g->sp - 2; c = g->sp - 1; d = g->sp; PyrObject *inobj = slotRawObject(a); PyrObject *newobj; int size = inobj->size; int flags = ~(obj_immutable) & inobj->obj_flags; int first, second, last; if (IsInt(b)) first = slotRawInt(b); else if (IsNil(b)) first = 0; else return errWrongType; if (IsInt(d)) { last = slotRawInt(d); if (last < 0 && IsNil(b)) { zerolength: newobj = g->gc->New(0, flags, inobj->obj_format, true); newobj->size = 0; newobj->classptr = inobj->classptr; SetRaw(a, newobj); return errNone; } } else if (IsNil(d)) { if (first >= size) goto zerolength; last = size - 1; } else return errWrongType; if (IsInt(c)) second = slotRawInt(c); else if (IsNil(c)) second = first < last ? first + 1 : first - 1; else return errWrongType; int step = second - first; int elemsize = gFormatElemSize[inobj->obj_format]; int length; if (step > 0) { length = (last - first) / step + 1; } else if (step < 0) { length = (first - last) / -step + 1; } else return errFailed; int numbytes = length * elemsize; newobj = g->gc->New(numbytes, flags, inobj->obj_format, true); newobj->size = 0; newobj->classptr = inobj->classptr; for (int i=first, j=0; j= 0 && i < inobj->size) { getIndexedSlot(inobj, &slot, i); int err = putIndexedSlot(g, newobj, &slot, newobj->size++); if (err) return err; } } SetRaw(a, newobj); return errNone; } void switchToThread(struct VMGlobals *g, struct PyrThread *newthread, int oldstate, int *numArgsPushed); int haltInterpreter(struct VMGlobals *g, int numArgsPushed) { switchToThread(g, slotRawThread(&g->process->mainThread), tDone, &numArgsPushed); // return all the way out. //PyrSlot *bottom = g->gc->Stack()->slots; //slotCopy(bottom,g->sp); //g->sp = bottom; // ??!! pop everybody g->method = NULL; g->block = NULL; g->frame = NULL; SetNil(g->sp); longjmp(g->escapeInterpreter, 3); //hmm need to fix this to work only on main thread. //!!! //g->sp = g->gc->Stack()->slots - 1; return errReturn; } int prCanCallOS(struct VMGlobals *g, int numArgsPushed); int prCanCallOS(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetBool(a, g->canCallOS); return errNone; } extern bool gGenerateTailCallByteCodes; int prGetTailCallOptimize(struct VMGlobals *g, int numArgsPushed); int prGetTailCallOptimize(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetBool(a, gGenerateTailCallByteCodes); return errNone; } int prSetTailCallOptimize(struct VMGlobals *g, int numArgsPushed); int prSetTailCallOptimize(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 1; #if TAILCALLOPTIMIZE PyrSlot *b = g->sp; if (IsTrue(b)) { gGenerateTailCallByteCodes = true; } else if (IsFalse(b)) { gGenerateTailCallByteCodes = false; } else return errWrongType; #endif return errNone; } int prTraceOn(struct VMGlobals *g, int numArgsPushed); int prTraceOn(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; gTraceInterpreter = IsTrue(a); return errNone; } int prKeywordError(struct VMGlobals *g, int numArgsPushed); int prKeywordError(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; gKeywordError = IsTrue(a); return errNone; } int prFunDef_NumArgs(struct VMGlobals *g, int numArgsPushed); int prFunDef_NumArgs(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrMethodRaw *methraw; a = g->sp; methraw = METHRAW(slotRawBlock(a)); SetInt(a, methraw->numargs); return errNone; } int prFunDef_NumVars(struct VMGlobals *g, int numArgsPushed); int prFunDef_NumVars(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrMethodRaw *methraw; a = g->sp; methraw = METHRAW(slotRawBlock(a)); SetInt(a, methraw->numvars); return errNone; } int prFunDef_VarArgs(struct VMGlobals *g, int numArgsPushed); int prFunDef_VarArgs(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrMethodRaw *methraw; a = g->sp; methraw = METHRAW(slotRawBlock(a)); if (methraw->varargs) { SetTrue(a); } else { SetFalse(a); } return errNone; } int undefinedPrimitive(struct VMGlobals *g, int numArgsPushed) { error("A primitive was not bound. %d %d\n", g->primitiveIndex, gPrimitiveTable.size); dumpObject((PyrObject*)g->primitiveMethod); return errFailed; } void dumpByteCodes(PyrBlock *theBlock); int prDumpByteCodes(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; dumpByteCodes(slotRawBlock(a)); return errNone; } int prObjectPointsTo(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, temp; PyrObject *obj; int i; a = g->sp - 1; b = g->sp; if (NotObj(a)) slotCopy(a,&o_false); else { obj = slotRawObject(a); for (i=0; isize; ++i) { getIndexedSlot(obj, &temp, i); if (SlotEq(&temp, b)) { slotCopy(a,&o_true); return errNone; } } slotCopy(a,&o_false); } return errNone; } int prObjectRespondsTo(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrClass *classobj; PyrMethod *meth; PyrSymbol *selector; int index; a = g->sp - 1; b = g->sp; classobj = classOfSlot(a); if (IsSym(b)) { selector = slotRawSymbol(b); index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { slotCopy(a,&o_false); } else { slotCopy(a,&o_true); } } else if (isKindOfSlot(b, class_array)) { int size = slotRawObject(b)->size; PyrSlot *slot = slotRawObject(b)->slots; for (int i=0; iclassIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { slotCopy(a,&o_false); return errNone; } } slotCopy(a,&o_true); } else return errWrongType; return errNone; } PyrMethod* GetFunctionCompileContext(VMGlobals* g); PyrMethod* GetFunctionCompileContext(VMGlobals* g) { PyrClass *classobj; PyrSymbol *classsym, *contextsym; PyrMethod *meth; // lookup interpreter class classsym = getsym("Interpreter"); classobj = classsym->u.classobj; if (!classobj) { error("There is no Interpreter class.\n"); return 0; } // lookup functionCompileContext method contextsym = getsym("functionCompileContext"); int index = slotRawInt(&classobj->classIndex) + contextsym->u.index; meth = gRowTable[index]; if (!meth || slotRawSymbol(&meth->name) != contextsym) { error("compile context method 'functionCompileContext' not found.\n"); return 0; } gCompilingClass = classobj; gCompilingMethod = meth; gCompilingBlock = (PyrBlock*)meth; return meth; } #if !SCPLAYER int prCompileString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrString *string; PyrMethod *meth; a = g->sp - 1; b = g->sp; // check b is a string if (NotObj(b)) return errWrongType; if (!isKindOf(slotRawObject(b), class_string)) return errWrongType; string = slotRawString(b); gRootParseNode = NULL; initParserPool(); //assert(g->gc->SanityCheck()); startLexerCmdLine(string->s, string->size); compileErrors = 0; compilingCmdLine = true; gCompilingVMGlobals = g; compilingCmdLineErrorWindow = false; //assert(g->gc->SanityCheck()); parseFailed = yyparse(); //assert(g->gc->SanityCheck()); if (!parseFailed && gRootParseNode) { PyrSlot slotResult; meth = GetFunctionCompileContext(g); if (!meth) return errFailed; ((PyrBlockNode*)gRootParseNode)->mIsTopLevel = true; SetNil(&slotResult); COMPILENODE(gRootParseNode, &slotResult, true); if (NotObj(&slotResult) || slotRawObject(&slotResult)->classptr != class_fundef) { compileErrors++; error("Compile did not return a FunctionDef..\n"); } if (compileErrors) { SetNil(a); } else { PyrBlock *block; PyrClosure *closure; block = slotRawBlock(&slotResult); // create a closure closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, false); closure->classptr = class_func; closure->size = 2; SetObject(&closure->block, block); slotCopy(&closure->context,&slotRawInterpreter(&g->process->interpreter)->context); SetObject(a, closure); } } else { if (parseFailed) { compileErrors++; error("Command line parse failed\n"); } else { postfl("\n"); } SetNil(a); } finiLexer(); freeParserPool(); pyr_pool_compile->FreeAll(); //flushErrors(); compilingCmdLine = false; return !(parseFailed || compileErrors) ? errNone : errFailed; } #endif char sCodeStringIn[8192]; char sCodeStringOut[8192]; int prUGenCodeString(struct VMGlobals *g, int numArgsPushed); int prUGenCodeString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *aa, *bb, *cc, *dd, *ee; char *out = sCodeStringOut; char ugenPrefix[16]; int err; aa = g->sp - 4; // code string bb = g->sp - 3; // ugen prefix ee = g->sp - 2; // isDecl cc = g->sp - 1; // input names dd = g->sp; // input value strings int ugenIndex; err = slotIntVal(bb, &ugenIndex); if (err) return err; if (!isKindOfSlot(cc, class_array) && !isKindOfSlot(cc, class_symbolarray)) return errWrongType; if (!isKindOfSlot(dd, class_array)) return errWrongType; bool isDecl = IsTrue(ee); PyrObject *inputNamesObj = slotRawObject(cc); PyrObject *inputStringsObj = slotRawObject(dd); sprintf(ugenPrefix, "u%d", ugenIndex); int ugenPrefixSize = strlen(ugenPrefix); PyrString* codeStringObj = slotRawString(aa); int codeStringSize = codeStringObj->size; if (codeStringSize > 8000) { error("input string too int.\n"); return errFailed; } memcpy(sCodeStringIn, codeStringObj->s, codeStringSize); sCodeStringIn[codeStringSize] = 0; char* in = sCodeStringIn; int c; while ((c = *in++) != 0) { if (c == '@') { if (!isDecl) { if (*in != '@') { *out++ = 's'; *out++ = '-'; *out++ = '>'; } else in++; } for (int j=0; j= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))) { --in; break; } name[j++] = c; } while (c); bool found = false; int nameSize = j; int slotIndex = -1; for (int j=0; jsize; ++j) { PyrSlot inputNameSlot; getIndexedSlot(inputNamesObj, &inputNameSlot, j); if (!IsSym(&inputNameSlot)) return errWrongType; PyrSymbol* inputSym = slotRawSymbol(&inputNameSlot); char *inputName = inputSym->name; int inputNameSize = inputSym->length; if (inputNameSize == nameSize && strncmp(inputName, name, nameSize)==0) { found = true; slotIndex = j; break; } } if (slotIndex >= 0) { PyrSlot *inputStringSlot = inputStringsObj->slots + slotIndex; if (!isKindOfSlot(inputStringSlot, class_string)) return errWrongType; PyrString *inputStringObj = slotRawString(inputStringSlot); char *input = inputStringObj->s; int inputStringSize = inputStringObj->size; for (int j=0; j 8000) { *out++ = '\n'; *out++ = '.'; *out++ = '.'; *out++ = '.'; *out++ = '\n'; break; } } *out++ = 0; PyrString* outString = newPyrString(g->gc, sCodeStringOut, 0, true); SetObject(aa, outString); return errNone; } /*void threadSanity(VMGlobals *g, PyrThread *thread); void threadSanity(VMGlobals *g, PyrThread *thread) { int state; g->gc->numToScan = 1000000; doGC(g, 0); assert(g->gc->SanityCheck()); state = slotRawInt(&thread->state); if (state == tYield) { if (!IsObj(&thread->method)) { error("thread method not an Object\n"); } else if (!isKindOf(slotRawObject(&thread->method), class_method)) { error("thread method not a Method\n"); } else if (slotRawObject(&thread->method)->gc_color == gcColor.gcFree) { error("thread method is FREE\n"); } if (!IsObj(&thread->block)) { error("thread block not an Object\n"); } else if (!isKindOf(slotRawObject(&thread->block), class_func)) { error("thread block not a Function\n"); } else if (slotRawObject(&thread->block)->gc_color == gcColor.gcFree) { error("thread block is FREE\n"); } if (IsObj(&thread->receiver) &slotRawObject(&& thread->receiver)->gc_color == gcColor.gcFree) { error("thread receiver is FREE\n"); } FrameSanity(thread->frame.uof); oldthread->method.uom = g->method; oldthread->block.uoblk = g->block; SetObject(&oldthread->frame, g->frame); slotRawInt(&oldthread->ip) = (int)g->ip; slotRawInt(&oldthread->sp) = (int)g->sp; } else if (state == tInit) { } else { postfl("bad state\n"); } }*/ PyrSymbol *s_prready; PyrSymbol *s_prrunnextthread; void switchToThread(VMGlobals *g, PyrThread *newthread, int oldstate, int *numArgsPushed); void switchToThread(VMGlobals *g, PyrThread *newthread, int oldstate, int *numArgsPushed) { PyrThread *oldthread; PyrGC *gc; PyrFrame *frame; #if TAILCALLOPTIMIZE g->tailCall = 0; // ?? prevent a crash. is there a way to allow a TCO ? #endif oldthread = g->thread; if (newthread == oldthread) return; //postfl("->switchToThread %d %p -> %p\n", oldstate, oldthread, newthread); //post("->switchToThread from %s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name); //post("->stack %p g->sp %p [%d] g->top %p [%d]\n", // g->gc->Stack()->slots, g->sp, g->sp - g->gc->Stack()->slots, g->top, g->top - g->gc->Stack()->slots); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "switchToThreadA"); //gcDumpInfo(g->gc); gc = g->gc; // save environment in oldthread PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1]; slotCopy(&oldthread->environment,currentEnvironmentSlot); gc->GCWrite(oldthread, currentEnvironmentSlot); SetRaw(&oldthread->state, oldstate); if (oldstate == tDone) { SetObject(&oldthread->stack, gc->Stack()); gc->ToWhite(gc->Stack()); gc->Stack()->size = 0; gc->GCWrite(oldthread, gc->Stack()); SetNil(&oldthread->method); SetNil(&oldthread->block); SetNil(&oldthread->receiver); SetNil(&oldthread->frame); SetRaw(&oldthread->ip, (void*)0); SetRaw(&oldthread->sp, (void*)0); SetRaw(&oldthread->numArgsPushed, 0); SetRaw(&oldthread->numpop, 0); SetNil(&oldthread->parent); } else if (oldstate == tInit) { SetObject(&oldthread->stack, gc->Stack()); gc->ToWhite(gc->Stack()); gc->Stack()->size = 0; gc->GCWrite(oldthread, gc->Stack()); SetNil(&oldthread->method); SetNil(&oldthread->block); SetNil(&oldthread->receiver); SetNil(&oldthread->frame); SetRaw(&oldthread->ip, (void*)0); SetRaw(&oldthread->sp, (void*)0); SetRaw(&oldthread->numArgsPushed, 0); SetRaw(&oldthread->numpop, 0); SetNil(&oldthread->parent); } else { // save old thread's state SetObject(&oldthread->stack, gc->Stack()); gc->ToWhite(gc->Stack()); gc->Stack()->size = g->sp - gc->Stack()->slots + 1; //post("else %p %p\n", slotRawObject(&oldthread->stack), gc->Stack()); SetObject(&oldthread->method, g->method); SetObject(&oldthread->block, g->block); SetObject(&oldthread->frame, g->frame); SetPtr(&oldthread->ip, g->ip); SetPtr(&oldthread->sp, g->sp); slotCopy(&oldthread->receiver,&g->receiver); SetRaw(&oldthread->numArgsPushed, *numArgsPushed); SetRaw(&oldthread->numpop, g->numpop); //gc->ToGrey(oldthread); if (gc->ObjIsBlack(oldthread)) { gc->GCWriteBlack(gc->Stack()); gc->GCWriteBlack(g->method); gc->GCWriteBlack(g->block); frame = slotRawFrame(&oldthread->frame); gc->GCWriteBlack(frame); gc->GCWriteBlack(&g->receiver); } } // restore new thread's state g->thread = newthread; SetObject(&g->process->curThread, newthread); gc->GCWrite(g->process, newthread); gc->SetStack(slotRawObject(&newthread->stack)); gc->ToBlack(gc->Stack()); SetNil(&newthread->stack); g->method = slotRawMethod(&newthread->method); g->block = slotRawBlock(&newthread->block); g->frame = slotRawFrame(&newthread->frame); g->ip = (unsigned char *)slotRawPtr(&newthread->ip); g->sp = (PyrSlot*)slotRawPtr(&newthread->sp); slotCopy(&g->receiver,&newthread->receiver); g->rgen = (RGen*)(slotRawObject(&newthread->randData)->slots); *numArgsPushed = slotRawInt(&newthread->numArgsPushed); // these are perhaps unecessary because a thread may not // legally block within a C primitive g->numpop = slotRawInt(&newthread->numpop); g->execMethod = 99; //post("switchToThread ip %p\n", g->ip); //post(slotRawInt(&"switchToThread newthread->ip) %d\n", slotRawInt(&newthread->ip)); //post(slotRawInt(&"switchToThread oldthread->ip) %d\n", slotRawInt(&oldthread->ip)); // wipe out values which will become stale as new thread executes: SetNil(&newthread->method); SetNil(&newthread->block); SetNil(&newthread->frame); SetRaw(&newthread->ip, (void*)0); SetRaw(&newthread->sp, (void*)0); SetNil(&newthread->receiver); SetRaw(&newthread->state, tRunning); // set new environment slotCopy(currentEnvironmentSlot,&g->thread->environment); g->gc->GCWrite(g->classvars, currentEnvironmentSlot); //post("old thread %p stack %p\n", oldthread, slotRawObject(&oldthread->stack)); //post("new thread %p stack %p\n", g->thread, slotRawObject(&g->thread->stack)); //post("main thread %p stack %p\n", slotRawThread(&g->process->mainThread), slotRawObject(&slotRawThread(&g->process->mainThread)->stack)); //postfl("<-switchToThread\n"); //post("<-stack %p g->sp %p [%d] g->top %p [%d]\n", // g->gc->Stack()->slots, g->sp, g->sp - g->gc->Stack()->slots, g->top, g->top - g->gc->Stack()->slots); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "switchToThreadB"); //post("switchToThread ip2 %p\n", g->ip); } void initPyrThread(VMGlobals *g, PyrThread *thread, PyrSlot *func, int stacksize, PyrInt32Array* rgenArray, double beats, double seconds, PyrSlot* clock, bool collect); void initPyrThread(VMGlobals *g, PyrThread *thread, PyrSlot *func, int stacksize, PyrInt32Array* rgenArray, double beats, double seconds, PyrSlot* clock, bool collect) { PyrObject *array; PyrGC* gc = g->gc; slotCopy(&thread->func, func); gc->GCWrite(thread, func); array = newPyrArray(gc, stacksize, 0, collect); SetObject(&thread->stack, array); gc->GCWrite(thread, array); SetInt(&thread->state, tInit); SetPtr(&thread->ip, 0); SetPtr(&thread->sp, 0); SetObject(&thread->randData, rgenArray); gc->GCWrite(thread, rgenArray); SetFloat(&thread->beats, beats); SetFloat(&thread->seconds, seconds); SetInt(&thread->numArgsPushed, 0); SetInt(&thread->numpop, 0); if (IsNil(clock)) { SetObject(&thread->clock, s_systemclock->u.classobj); } else { slotCopy(&thread->clock,clock); gc->GCWrite(thread, clock); } PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1]; slotCopy(&thread->environment,currentEnvironmentSlot); gc->GCWrite(thread, currentEnvironmentSlot); if(g->process) { // check we're not just starting up slotCopy(&thread->executingPath,&g->process->nowExecutingPath); gc->GCWrite(thread, &g->process->nowExecutingPath); } SetInt(&thread->stackSize, stacksize); } extern PyrSymbol *s_prstart; int prThreadInit(struct VMGlobals *g, int numArgsPushed); int prThreadInit(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int stacksize, err; PyrThread *thread; //postfl("->prThreadInit\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prThreadInit"); a = g->sp - 2; // thread b = g->sp - 1; // function c = g->sp; // stacksize thread = slotRawThread(a); if (NotObj(b) || !isKindOf(slotRawObject(b), class_func)) { error("Thread function arg not a Function.\n"); return errWrongType; } err = slotIntVal(c, &stacksize); if (err) return err; stacksize = std::max(stacksize, EVALSTACKDEPTH); double beats, seconds; err = slotDoubleVal(&g->thread->beats, &beats); if (err) return err; err = slotDoubleVal(&g->thread->seconds, &seconds); if (err) return err; initPyrThread(g, thread, b, stacksize, (PyrInt32Array*)(slotRawObject(&g->thread->randData)), beats, seconds, &g->thread->clock, true); //postfl("<-prThreadInit\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "sp - 1; // thread PyrSlot *b = g->sp; // rand seed PyrThread *thread = slotRawThread(a); int32 seed; int err = slotIntVal(b, &seed); if (err) return err; PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, true); rgenArray->size = 4; ((RGen*)(rgenArray->i))->init(seed); if (thread == g->thread) { g->rgen = (RGen*)(rgenArray->i); } SetObject(&thread->randData, rgenArray); g->gc->GCWrite(thread, rgenArray); return errNone; } int prThreadGetRandData(struct VMGlobals *g, int numArgsPushed); int prThreadGetRandData(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; // thread PyrThread *thread = slotRawThread(a); RGen* rgen = (RGen*)slotRawObject(&thread->randData)->slots; PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, false); rgenArray->size = 3; rgenArray->i[0] = rgen->s1; rgenArray->i[1] = rgen->s2; rgenArray->i[2] = rgen->s3; SetObject(a, rgenArray); return errNone; } int prThreadSetRandData(struct VMGlobals *g, int numArgsPushed); int prThreadSetRandData(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; // thread PyrSlot *b = g->sp; // rand data array if (!isKindOfSlot(b, class_int32array)) return errWrongType; if (slotRawObject(b)->size < 3) return errWrongType; PyrThread *thread = slotRawThread(a); RGen* rgen = (RGen*)slotRawObject(&thread->randData)->slots; PyrInt32Array *rgenArray = (PyrInt32Array*)slotRawObject(b); rgen->s1 = rgenArray->i[0]; rgen->s2 = rgenArray->i[1]; rgen->s3 = rgenArray->i[2]; return errNone; } #if 0 int32 timeseed(); int transformMainThreadToRoutine(VMGlobals *g) { PyrProcess* process = g->process; if (g->thread != process->mainThread.uot) return errFailed; //if (g->thread != process->curThread.uot) return errFailed; PyrThread* curthread = (PyrThread*)slotRawObject(&process->mainThread); // create a new main thread PyrThread* newthread = (PyrThread*)instantiateObject(g->gc, class_thread, 0, true, false); PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, false); rgenArray->size = 4; ((RGen*)(rgenArray->i))->init(timeseed()); PyrSlot clockSlot; SetObject(&clockSlot, s_systemclock->u.classobj); initPyrThread(g, newthread, &o_nil, EVALSTACKDEPTH, rgenArray, 0., 0., &clockSlot, false); slotRawInt(&newthread->sp) = (int)slotRawObject(&newthread->stack)->slots - 1; SetObject(&process->mainThread, newthread); g->gc->GCWrite(process, newthread); curthread->classptr = class_routine; PyrSlot *cmdFunc = &process->interpreter.uoi->cmdFunc; slotCopy(&curthread->func,cmdFunc); g->gc->GCWrite(curthread, cmdFunc); return errNone; } void schedAdd(VMGlobals *g, PyrObject* inQueue, double inSeconds, PyrSlot* inTask); #endif int prRoutineYield(struct VMGlobals *g, int numArgsPushed); int prRoutineYield(struct VMGlobals *g, int numArgsPushed) { PyrSlot value; //postfl("->prRoutineYield %p\n", g->thread); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineYield"); //postfl("->numArgsPushed %d\n", numArgsPushed); slotCopy(&value,g->sp); if (!isKindOf((PyrObject*)g->thread, class_routine)) { error ("yield was called outside of a Routine.\n"); return errFailed; } PyrThread *parent = slotRawThread(&g->thread->parent); SetNil(&g->thread->parent); slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath); //debugf("yield from thread %p to parent %p\n", g->thread, slotRawThread(&g->thread->parent)); switchToThread(g, parent, tSuspended, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. slotCopy((g->sp - numArgsPushed + 1),&value); //postfl("<-numArgsPushed %d\n", numArgsPushed); //postfl("<-prRoutineYield\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineAlwaysYield ip %p\n", g->ip); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineAlwaysYield"); if (!isKindOf((PyrObject*)g->thread, class_routine)) { error ("alwaysYield was called outside of a Routine.\n"); return errFailed; } slotCopy(&value,g->sp); slotCopy(&g->thread->terminalValue,&value); g->gc->GCWrite(g->thread, g->sp); PyrThread *parent = slotRawThread(&g->thread->parent); SetNil(&g->thread->parent); slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath); //post("alwaysYield from thread %p to parent %p\n", g->thread, parent); switchToThread(g, parent, tDone, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. slotCopy((g->sp - numArgsPushed + 1),&value); //postfl("<-prRoutineAlwaysYield ip %p\n", g->ip); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "gc->SanityCheck()); //CallStackSanity(g, "prRoutineResume"); a = g->sp - 1; b = g->sp; thread = slotRawThread(a); state = slotRawInt(&thread->state); //postfl("->prRoutineResume %d\n", state); slotCopy(&thread->oldExecutingPath,&g->process->nowExecutingPath); slotCopy(&g->process->nowExecutingPath, &thread->executingPath); if (state == tInit) { slotCopy(&threadSlot,a); slotCopy(&value,b); //post("g->thread %p\n", g->thread); //post("thread %p\n", thread); SetObject(&thread->parent, g->thread); g->gc->GCWrite(thread, g->thread); slotCopy(&thread->beats, &g->thread->beats); slotCopy(&thread->seconds, &g->thread->seconds); slotCopy(&thread->clock, &g->thread->clock); g->gc->GCWrite(thread, &g->thread->beats); g->gc->GCWrite(thread, &g->thread->seconds); g->gc->GCWrite(thread, &g->thread->clock); //postfl("start into thread %p from parent %p\n", thread, g->thread); switchToThread(g, thread, tSuspended, &numArgsPushed); // set stack //post("set stack %p %p\n", g->sp, g->gc->Stack()->slots - 1); g->sp = g->gc->Stack()->slots - 1; slotCopy((++g->sp), &threadSlot); slotCopy(&g->receiver, &threadSlot); slotCopy((++g->sp),&value); sendMessage(g, s_prstart, 2); } else if (state == tSuspended) { if (IsNil(&thread->parent)) { SetObject(&thread->parent, g->thread); } g->gc->GCWrite(thread, g->thread); slotCopy(&thread->beats, &g->thread->beats); slotCopy(&thread->seconds, &g->thread->seconds); slotCopy(&thread->clock,&g->thread->clock); g->gc->GCWrite(thread, &g->thread->beats); g->gc->GCWrite(thread, &g->thread->seconds); g->gc->GCWrite(thread, &g->thread->clock); slotCopy(&value,b); //debugf("resume into thread %p from parent %p\n", thread, g->thread); switchToThread(g, thread, tSuspended, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. slotCopy((g->sp - numArgsPushed + 1),&value); } else if (state == tDone) { slotCopy(a,&thread->terminalValue); } else if (state == tRunning) { error("Tried to resume the running thread.\n"); return errFailed; } else { error("Thread in strange state: %d\n", state); return errFailed; } //postfl("<-prRoutineResume\n"); //CallStackSanity(g); return errNone; } int prRoutineReset(struct VMGlobals *g, int numArgsPushed); int prRoutineReset(struct VMGlobals *g, int numArgsPushed) { PyrThread *thread; int state; //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineReset"); thread = slotRawThread(g->sp); state = slotRawInt(&thread->state); //post("->prRoutineReset %d\n", state); if (state == tSuspended) { SetRaw(&thread->state, tInit); slotRawObject(&thread->stack)->size = 0; SetNil(&thread->method); SetNil(&thread->block); SetNil(&thread->receiver); SetNil(&thread->frame); SetRaw(&thread->ip, (void*)0); SetRaw(&thread->sp, (void*)0); SetRaw(&thread->numArgsPushed, 0); SetRaw(&thread->numpop, 0); SetNil(&thread->parent); } else if (state == tDone) { SetRaw(&thread->state, tInit); slotRawObject(&thread->stack)->size = 0; SetNil(&thread->method); SetNil(&thread->block); SetNil(&thread->receiver); SetNil(&thread->frame); SetRaw(&thread->ip, (void*)0); SetRaw(&thread->sp, (void*)0); SetRaw(&thread->numArgsPushed, 0); SetRaw(&thread->numpop, 0); SetNil(&thread->parent); } else if (state == tInit) { // do nothing } else if (state == tRunning) { error("A Routine cannot reset itself except by yieldAndReset.\n"); return errFailed; } else { error("Routine in unknown state. %d\n", state); return errFailed; } //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineStop\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineStop"); thread = slotRawThread(g->sp); state = slotRawInt(&thread->state); if (state == tSuspended || state == tInit) { slotCopy(&g->process->nowExecutingPath, &thread->oldExecutingPath); SetNil(&g->thread->terminalValue); SetRaw(&thread->state, tDone); slotRawObject(&thread->stack)->size = 0; } else if (state == tDone) { // do nothing } else if (state == tRunning) { error("Do not call .stop from within the Routine.\n"); post("A Routine should stop itself using nil.alwaysYield.\n"); return errFailed; } else { error("Routine in unknown state. %d\n", state); return errFailed; } //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineYieldAndReset\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineYieldAndReset"); a = g->sp - 1; b = g->sp; if (!isKindOf((PyrObject*)g->thread, class_routine)) { error ("yieldAndReset was called outside of a Routine.\n"); return errFailed; } /*if (!slotRawThread(&g->thread->parent)) { error ("yieldAndReset was called from a thread with no parent.\n"); return errFailed; }*/ slotCopy(&value,a); if (IsFalse(b)) state = tSuspended; else state = tInit; PyrThread *parent = slotRawThread(&g->thread->parent); SetNil(&g->thread->parent); switchToThread(g, parent, state, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. slotCopy((g->sp - numArgsPushed + 1),&value); //slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath); //post("<-prRoutineYieldAndReset\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineYieldAndReset"); return errNone; } bool gBlork = false; int prBlork(struct VMGlobals *g, int numArgsPushed); int prBlork(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (IsTrue(a)) gBlork = true; else gBlork = false; return errNone; } int prOverwriteMsg(struct VMGlobals *g, int numArgsPushed); int prOverwriteMsg(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrString* string = newPyrString(g->gc, overwriteMsg.c_str(), 0, false); SetObject(a, string); return errNone; } int prAppClockSchedNotify(struct VMGlobals *g, int numArgsPushed) { //NOTE: the _AppClock_SchedNotify primitive shall be redefined by language clients // if they wish to respond to AppClock scheduling notifications return errNone; } enum {includePaths, excludePaths}; static int prLanguageConfig_getLibraryPaths(struct VMGlobals * g, int numArgsPushed, int pathType) { PyrSlot *result = g->sp; typedef SC_LanguageConfig::DirVector DirVector; DirVector const & dirVector = (pathType == includePaths) ? gLanguageConfig->includedDirectories() : gLanguageConfig->excludedDirectories(); size_t numberOfPaths = dirVector.size(); PyrObject * resultArray = newPyrArray(g->gc, numberOfPaths, 0, true); SetObject(result, resultArray); resultArray->size = numberOfPaths; for (size_t i = 0; i != numberOfPaths; ++i) SetObject(resultArray->slots + i, newPyrString(g->gc, dirVector[i].c_str(), 0, true)); return errNone; } static int prLanguageConfig_getIncludePaths(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_getLibraryPaths(g, numArgsPushed, includePaths); } static int prLanguageConfig_getExcludePaths(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_getLibraryPaths(g, numArgsPushed, excludePaths); } static int prLanguageConfig_addLibraryPath(struct VMGlobals * g, int numArgsPushed, int pathType) { PyrSlot *removeString = g->sp; char path[MAXPATHLEN]; bool error = slotStrVal(removeString, path, MAXPATHLEN); if (error) return errWrongType; if (pathType == includePaths) gLanguageConfig->addIncludedDirectory(path); else gLanguageConfig->addExcludedDirectory(path); return errNone; } static int prLanguageConfig_addIncludePath(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_addLibraryPath(g, numArgsPushed, includePaths); } static int prLanguageConfig_addExcludePath(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_addLibraryPath(g, numArgsPushed, excludePaths); } static int prLanguageConfig_removeLibraryPath(struct VMGlobals * g, int numArgsPushed, int pathType) { PyrSlot *dirString = g->sp; char path[MAXPATHLEN]; bool error = slotStrVal(dirString, path, MAXPATHLEN); if (error) return errWrongType; if (pathType == includePaths) gLanguageConfig->removeIncludedDirectory(path); else gLanguageConfig->removeExcludedDirectory(path); return errNone; } static int prLanguageConfig_removeIncludePath(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_removeLibraryPath(g, numArgsPushed, includePaths); } static int prLanguageConfig_removeExcludePath(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_removeLibraryPath(g, numArgsPushed, excludePaths); } static int prLanguageConfig_writeConfigFile(struct VMGlobals * g, int numArgsPushed) { PyrSlot *fileString = g->sp; char path[MAXPATHLEN]; if (NotNil(fileString)) { bool error = slotStrVal(fileString, path, MAXPATHLEN); if (error) return errWrongType; } else { sc_GetUserConfigDirectory(path, PATH_MAX); sc_AppendToPath(path, MAXPATHLEN, "sclang_conf.yaml"); } gLanguageConfig->writeLibraryConfigYAML(path); return errNone; } extern bool gPostInlineWarnings; static int prLanguageConfig_getPostInlineWarnings(struct VMGlobals * g, int numArgsPushed) { PyrSlot *result = g->sp; SetBool(result, gPostInlineWarnings); return errNone; } static int prLanguageConfig_setPostInlineWarnings(struct VMGlobals * g, int numArgsPushed) { PyrSlot *arg = g->sp; if (IsTrue(arg)) gPostInlineWarnings = true; else if (IsFalse(arg)) gPostInlineWarnings = false; else return errWrongType; return errNone; } static int prVersionMajor(struct VMGlobals * g, int numArgsPushed) { PyrSlot *result = g->sp; SetInt(result, SC_VersionMajor); return errNone; } static int prVersionMinor(struct VMGlobals * g, int numArgsPushed) { PyrSlot *result = g->sp; SetInt(result, SC_VersionMinor); return errNone; } static int prVersionPatch(struct VMGlobals * g, int numArgsPushed) { PyrSlot *result = g->sp; SetObject(result, newPyrString(g->gc, SC_VersionPatch, 0, 1)); return errNone; } #define PRIMGROWSIZE 480 PrimitiveTable gPrimitiveTable; void initPrimitiveTable() { int i; gPrimitiveTable.maxsize = PRIMGROWSIZE; gPrimitiveTable.size = 0; // pyrmalloc: // lifetime: runtime. primitives are reloaded when library is compiled. gPrimitiveTable.table = (PrimitiveDef*)pyr_pool_runtime->Alloc(gPrimitiveTable.maxsize * sizeof(PrimitiveDef)); MEMFAIL(gPrimitiveTable.table); for (i=0; iAlloc(gPrimitiveTable.maxsize * sizeof(PrimitiveDef)); MEMFAIL(gPrimitiveTable.table); memcpy(gPrimitiveTable.table, oldtable, oldsize * sizeof(PrimitiveDef)); for (i=oldsize; iFree(oldtable); } int definePrimitive(int base, int index, const char *name, PrimitiveHandler handler, int numArgs, int varArgs) { int tableIndex; PyrSymbol *sym; if (name[0] != '_') { error("*** Primitive Name must begin with an underscore ***\n"); postfl("name: '%s' index: %d\n", name, index); return -1; } tableIndex = base + index; if (tableIndex < 0) { error("*** Negative Primitive Index ***\n"); postfl("name: '%s' index: %d\n", name, tableIndex); return -1; } if (tableIndex >= gPrimitiveTable.maxsize) { growPrimitiveTable(tableIndex + PRIMGROWSIZE); } if (gPrimitiveTable.table[tableIndex].func != undefinedPrimitive) { error("*** Duplicate Primitive Index ***\n"); postfl("name: '%s' index: %d\n", name, tableIndex); return -1; } sym = getsym(name); gPrimitiveTable.table[tableIndex].func = handler; gPrimitiveTable.table[tableIndex].name = sym; gPrimitiveTable.table[tableIndex].base = base; gPrimitiveTable.table[tableIndex].numArgs = numArgs; gPrimitiveTable.table[tableIndex].varArgs = varArgs; gPrimitiveTable.table[tableIndex].keyArgs = 0; if (tableIndex > gPrimitiveTable.size) gPrimitiveTable.size = tableIndex; sym->u.index = tableIndex; return tableIndex; } int definePrimitiveWithKeys(int base, int index, const char *name, PrimitiveHandler handler, PrimitiveWithKeysHandler keyhandler, int numArgs, int varArgs) { int tableIndex; PyrSymbol *sym; if (name[0] != '_') { error("*** Primitive Name must begin with an underscore ***\n"); postfl("name: '%s' index: %d\n", name, index); return -1; } tableIndex = base + index; if (tableIndex < 0) { error("*** Negative Primitive Index ***\n"); postfl("name: '%s' index: %d\n", name, tableIndex); return -1; } if (tableIndex+1 >= gPrimitiveTable.maxsize) { growPrimitiveTable(tableIndex + PRIMGROWSIZE); } if (gPrimitiveTable.table[tableIndex].func != undefinedPrimitive) { error("*** Duplicate Primitive Index ***\n"); postfl("name: '%s' index: %d\n", name, tableIndex); return -1; } sym = getsym(name); gPrimitiveTable.table[tableIndex].func = handler; gPrimitiveTable.table[tableIndex].name = sym; gPrimitiveTable.table[tableIndex].base = base; gPrimitiveTable.table[tableIndex].numArgs = numArgs; gPrimitiveTable.table[tableIndex].varArgs = varArgs; gPrimitiveTable.table[tableIndex].keyArgs = 1; sym->u.index = tableIndex; tableIndex++; gPrimitiveTable.table[tableIndex].func = (PrimitiveHandler)keyhandler; gPrimitiveTable.table[tableIndex].name = sym; gPrimitiveTable.table[tableIndex].base = base; gPrimitiveTable.table[tableIndex].numArgs = numArgs; gPrimitiveTable.table[tableIndex].varArgs = varArgs; gPrimitiveTable.table[tableIndex].keyArgs = 1; if (tableIndex > gPrimitiveTable.size) gPrimitiveTable.size = tableIndex; return tableIndex; } int nextPrimitiveIndex() { return gPrimitiveTable.size + 1; } void doPrimitive(VMGlobals* g, PyrMethod* meth, int numArgsPushed) { #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif //post("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); PyrMethodRaw *methraw = METHRAW(meth); int primIndex = methraw->specialIndex; PrimitiveDef *def = gPrimitiveTable.table + primIndex; int numArgsNeeded = def->numArgs; int diff = numArgsNeeded - numArgsPushed; if (diff != 0) { // incorrect num of args if (diff > 0) { // not enough args PyrSlot* pslot = g->sp; PyrSlot* qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (int m=0; msp += diff; } else if (def->varArgs) { // has var args numArgsNeeded = numArgsPushed; } else { g->sp += diff; // remove excess args } } g->numpop = numArgsNeeded - 1; g->primitiveIndex = primIndex - def->base; g->primitiveMethod = meth; g->args = g->sp - numArgsNeeded; int err; try { #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif err = (*def->func)(g, numArgsNeeded); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } catch (std::exception& ex) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); error(ex.what()); err = errException; } catch (...) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); err = errException; } if (err <= errNone) g->sp -= g->numpop; else { //post("primitive failed %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); SetInt(&g->thread->primitiveIndex, methraw->specialIndex); SetInt(&g->thread->primitiveError, err); executeMethod(g, meth, numArgsNeeded); } #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } void doPrimitiveWithKeys(VMGlobals* g, PyrMethod* meth, int allArgsPushed, int numKeyArgsPushed) { int i, j, m, diff, err; PyrSlot *pslot, *qslot; int numArgsNeeded, numArgsPushed; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif //post("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); //printf("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); PyrMethodRaw *methraw = METHRAW(meth); int primIndex = methraw->specialIndex; PrimitiveDef *def = gPrimitiveTable.table + primIndex; g->primitiveIndex = primIndex - def->base; g->primitiveMethod = meth; if (def->keyArgs && numKeyArgsPushed) { g->numpop = allArgsPushed - 1; try { err = ((PrimitiveWithKeysHandler)def[1].func)(g, allArgsPushed, numKeyArgsPushed); } catch (std::exception& ex) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); error(ex.what()); err = errException; } catch (...) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); err = errException; } if (err <= errNone) g->sp -= g->numpop; else { //post("primerr %d\n", err); SetInt(&g->thread->primitiveIndex, methraw->specialIndex); SetInt(&g->thread->primitiveError, err); executeMethodWithKeys(g, meth, allArgsPushed, numKeyArgsPushed); } } else { numArgsNeeded = def->numArgs; numArgsPushed = allArgsPushed - (numKeyArgsPushed << 1); if (numKeyArgsPushed) { // evacuate keyword args to separate area pslot = keywordstack + (numKeyArgsPushed<<1); qslot = g->sp + 1; for (m=0; m 0) { // not enough args g->sp += numArgsNeeded - allArgsPushed; // remove excess args pslot = g->sp - diff; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0; mvarArgs) { // has var args numArgsNeeded = numArgsPushed; g->sp += numArgsNeeded - allArgsPushed; // remove excess args } else { g->sp += numArgsNeeded - allArgsPushed; // remove excess args } } // do keyword lookup: if (numKeyArgsPushed && methraw->posargs) { PyrSymbol **name0, **name; PyrSlot *key, *vars; name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1; key = keywordstack; vars = g->sp - numArgsNeeded + 1; for (i=0; iposargs; ++j, ++name) { if (*name == slotRawSymbol(key)) { slotCopy(&vars[j],&key[1]); goto found; } } if (gKeywordError) { post("WARNING: keyword arg '%s' not found in call to %s:%s\n", slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } found: ; } } g->numpop = numArgsNeeded - 1; try { err = (*def->func)(g, numArgsNeeded); } catch (std::exception& ex) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); error(ex.what()); err = errException; } catch (...) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); err = errException; } if (err <= errNone) g->sp -= g->numpop; else { //post("primerr %d\n", err); SetInt(&g->thread->primitiveIndex, methraw->specialIndex); SetInt(&g->thread->primitiveError, err); executeMethod(g, meth, numArgsNeeded); } } #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } void initPrimitives() { int base, index; initPrimitiveTable(); // unary operators base = nextPrimitiveIndex(); definePrimitive(base, opNeg, "_Neg", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opBitNot, "_BitNot", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opAbs, "_Abs", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opAsFloat, "_AsFloat", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opAsInt, "_AsInt", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCeil, "_Ceil", doSpecialUnaryArithMsg, 1, 0); // 5 definePrimitive(base, opFloor, "_Floor", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opFrac, "_Frac", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSign, "_Sign", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSquared, "_Squared", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCubed, "_Cubed", doSpecialUnaryArithMsg, 1, 0); //10 definePrimitive(base, opSqrt, "_Sqrt", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opExp, "_Exp", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRecip, "_Recip", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opMIDICPS, "_MIDICPS", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCPSMIDI, "_CPSMIDI", doSpecialUnaryArithMsg, 1, 0); //15 definePrimitive(base, opMIDIRatio, "_MIDIRatio", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRatioMIDI, "_RatioMIDI", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opDbAmp, "_DbAmp", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opAmpDb, "_AmpDb", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opOctCPS, "_OctCPS", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCPSOct, "_CPSOct", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opLog, "_Log", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opLog2, "_Log2", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opLog10, "_Log10", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSin, "_Sin", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCos, "_Cos", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opTan, "_Tan", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opArcSin, "_ArcSin", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opArcCos, "_ArcCos", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opArcTan, "_ArcTan", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSinH, "_SinH", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCosH, "_CosH", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opTanH, "_TanH", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRand, "_Rand", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRand2, "_Rand2", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opLinRand, "_LinRand", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opBiLinRand, "_BiLinRand", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSum3Rand, "_Sum3Rand", doSpecialUnaryArithMsg, 1, 0); // definePrimitive(base, opExpRand, "_ExpRand", doSpecialUnaryArithMsg, 1, 0); // definePrimitive(base, opBiExpRand, "_BiExpRand", doSpecialUnaryArithMsg, 1, 0); // definePrimitive(base, opGammaRand, "_GammaRand", doSpecialUnaryArithMsg, 1, 0); // definePrimitive(base, opGaussRand, "_GaussRand", doSpecialUnaryArithMsg, 1, 0); // definePrimitive(base, opPoiRand, "_PoiRand", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opDistort, "_Distort", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSoftClip, "_SoftClip", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCoin, "_Coin", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRectWindow, "_RectWindow", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opHanWindow, "_HanWindow", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opWelchWindow, "_WelchWindow", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opTriWindow, "_TriWindow", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSCurve, "_SCurve", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRamp, "_Ramp", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opDigitValue, "_DigitValue", doSpecialUnaryArithMsg, 1, 0); // binary operators base = nextPrimitiveIndex(); definePrimitive(base, opAdd, "_Add", prAddNum, 2, 0); definePrimitive(base, opSub, "_Sub", prSubNum, 2, 0); definePrimitive(base, opMul, "_Mul", prMulNum, 2, 0); definePrimitive(base, opIDiv, "_IDiv", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opFDiv, "_FDiv", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opMod, "_Mod", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opEQ, "_EQ", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opNE, "_NE", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opLT, "_LT", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opGT, "_GT", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opLE, "_LE", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opGE, "_GE", prSpecialBinaryArithMsg, 3, 0); //definePrimitive(base, opIdentical, "_Identical", prSpecialBinaryArithMsg, 3, 0); //definePrimitive(base, opNotIdentical, "_NotIdentical", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opMin, "_Min", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opMax, "_Max", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opBitAnd, "_BitAnd", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opBitOr, "_BitOr", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opBitXor, "_BitXor", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opLCM, "_LCM", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opGCD, "_GCD", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opRound, "_Round", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opRoundUp, "_RoundUp", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opTrunc, "_Trunc", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opAtan2, "_Atan2", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opHypot, "_Hypot", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opHypotx, "_HypotApx", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opPow, "_Pow", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opShiftLeft, "_ShiftLeft", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opShiftRight, "_ShiftRight", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opUnsignedShift, "_UnsignedShift", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opFill, "_Fill", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opRing1, "_Ring1", prSpecialBinaryArithMsg, 3, 0); // a * (b + 1) == a * b + a definePrimitive(base, opRing2, "_Ring2", prSpecialBinaryArithMsg, 3, 0); // a * b + a + b definePrimitive(base, opRing3, "_Ring3", prSpecialBinaryArithMsg, 3, 0); // a*a*b definePrimitive(base, opRing4, "_Ring4", prSpecialBinaryArithMsg, 3, 0); // a*a*b - a*b*b definePrimitive(base, opDifSqr, "_DifSqr", prSpecialBinaryArithMsg, 3, 0); // a*a - b*b definePrimitive(base, opSumSqr, "_SumSqr", prSpecialBinaryArithMsg, 3, 0); // a*a + b*b definePrimitive(base, opSqrSum, "_SqrSum", prSpecialBinaryArithMsg, 3, 0); // (a + b)^2 definePrimitive(base, opSqrDif, "_SqrDif", prSpecialBinaryArithMsg, 3, 0); // (a - b)^2 definePrimitive(base, opAbsDif, "_AbsDif", prSpecialBinaryArithMsg, 3, 0); // abs(a - b) definePrimitive(base, opThresh, "_Thresh", prSpecialBinaryArithMsg, 3, 0); // a * max(0,b) definePrimitive(base, opAMClip, "_AMClip", prSpecialBinaryArithMsg, 3, 0); // a * max(0,b) definePrimitive(base, opScaleNeg, "_ScaleNeg", prSpecialBinaryArithMsg, 3, 0); // a < 0 ? a*b : a definePrimitive(base, opClip2, "_Clip2", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opFold2, "_Fold2", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opWrap2, "_Wrap2", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opExcess, "_Excess", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opFirstArg, "_FirstArg", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opRandRange, "_RandRange", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opExpRandRange, "_ExpRandRange", prSpecialBinaryArithMsg, 3, 0); // general primitives base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_Halt", haltInterpreter, 1, 0); definePrimitive(base, index++, "_InstVarAt", instVarAt, 2, 0); definePrimitive(base, index++, "_InstVarPut", instVarPut, 3, 0); definePrimitive(base, index++, "_InstVarSize", instVarSize, 1, 0); definePrimitive(base, index++, "_ObjectHash", objectHash, 1, 0); definePrimitive(base, index++, "_ObjectClass", objectClass, 1, 0); definePrimitive(base, index++, "_BasicNew", basicNew, 2, 0); definePrimitive(base, index++, "_BasicNewClear", basicNewClear, 2, 0); definePrimitive(base, index++, "_BasicNewCopyArgsToInstVars", basicNewCopyArgsToInstanceVars, 1, 1); //definePrimitive(base, index++, "_BasicNewCopyArgsByName", basicNewCopyArgsByName, 1, 1); definePrimitiveWithKeys(base, index, "_FunctionValue", blockValue, blockValueWithKeys, 1, 1); index+=2; definePrimitiveWithKeys(base, index, "_FunctionValueEnvir", blockValueEnvir, blockValueEnvirWithKeys, 1, 1); index+=2; definePrimitive(base, index++, "_FunctionValueArray", blockValueArray, 1, 1); definePrimitive(base, index++, "_FunctionValueArrayEnvir", blockValueArrayEnvir, 1, 1); definePrimitive(base, index++, "_FunctionDefAsFunction", prFunctionDefAsFunction, 1, 0); definePrimitive(base, index++, "_FunctionDefDumpContexts", prFunctionDefDumpContexts, 1, 0); definePrimitive(base, index++, "_FunctionDefIsClosed", prFunctionDefIsClosed, 1, 0); definePrimitive(base, index++, "_FunctionDefIsWithinClosed", prFunctionDefIsWithinClosed, 1, 0); definePrimitive(base, index++, "_ObjectIsKindOf", objectIsKindOf, 2, 0); definePrimitive(base, index++, "_ObjectIsMemberOf", objectIsMemberOf, 2, 0); definePrimitive(base, index++, "_ObjectDump", objectDump, 1, 0); definePrimitive(base, index++, "_TotalFree", prTotalFree, 1, 0); definePrimitive(base, index++, "_LargestFreeBlock", prLargestFreeBlock, 1, 0); definePrimitive(base, index++, "_GCInfo", dumpGCinfo, 1, 0); definePrimitive(base, index++, "_GCDumpGrey", dumpGCdumpGrey, 1, 0); definePrimitive(base, index++, "_GCDumpSet", dumpGCdumpSet, 2, 0); definePrimitive(base, index++, "_GCSanity", prGCSanity, 1, 0); #if GCDEBUG definePrimitive(base, index++, "_TraceAllPathsTo", prTraceAllPathsTo, 1, 0); definePrimitive(base, index++, "_TraceAnyPathsTo", prTraceAnyPathsTo, 1, 0); definePrimitive(base, index++, "_TraceAnyPathToAllInstancesOf", prTraceAnyPathToAllInstancesOf, 1, 0); #endif definePrimitive(base, index++, "_Identical", objectIdentical, 2, 0); definePrimitive(base, index++, "_NotIdentical", objectNotIdentical, 2, 0); definePrimitiveWithKeys(base, index, "_ObjectPerform", objectPerform, objectPerformWithKeys, 2, 1); index+=2; definePrimitive(base, index++, "_ObjectPerformList", objectPerformList, 2, 1); definePrimitiveWithKeys(base, index, "_SuperPerform", objectSuperPerform, objectSuperPerformWithKeys, 2, 1); index+=2; definePrimitive(base, index++, "_SuperPerformList", objectSuperPerformList, 2, 1); definePrimitive(base, index++, "_ObjectPerformMsg", objectPerformSelList, 2, 0); //definePrimitive(base, index++, "_ArrayPerformMsg", arrayPerformMsg, 1, 1); definePrimitive(base, index++, "_ObjectString", prObjectString, 1, 0); definePrimitive(base, index++, "_Float_AsStringPrec", prFloat_AsStringPrec, 2, 0); definePrimitive(base, index++, "_ObjectCompileString", prAsCompileString, 1, 0); definePrimitive(base, index++, "_ClassString", prClassString, 1, 0); definePrimitive(base, index++, "_PostString", prPostString, 1, 0); definePrimitive(base, index++, "_PostLine", prPostLine, 1, 0); definePrimitive(base, index++, "_HostDebugger", prDebugger, 1, 0); definePrimitive(base, index++, "_Trace", prTraceOn, 1, 0); definePrimitive(base, index++, "_CanCallOS", prCanCallOS, 1, 0); definePrimitive(base, index++, "_KeywordError", prKeywordError, 1, 0); definePrimitive(base, index++, "_GetTailCallOptimize", prGetTailCallOptimize, 1, 0); definePrimitive(base, index++, "_SetTailCallOptimize", prSetTailCallOptimize, 2, 0); definePrimitive(base, index++, "_PrimitiveError", prPrimitiveError, 1, 0); definePrimitive(base, index++, "_PrimitiveErrorString", prPrimitiveErrorString, 1, 0); definePrimitive(base, index++, "_DumpStack", prDumpStack, 1, 0); definePrimitive(base, index++, "_DumpDetailedBackTrace", prDumpDetailedBackTrace, 1, 0); definePrimitive(base, index++, "_StackDepth", prStackDepth, 1, 0); definePrimitive(base, index++, "_PrimName", prPrimName, 1, 0); definePrimitive(base, index++, "_ObjectShallowCopy", prObjectShallowCopy, 1, 0); definePrimitive(base, index++, "_ObjectCopyImmutable", prObjectCopyImmutable, 1, 0); definePrimitive(base, index++, "_ObjectCopyRange", prObjectCopyRange, 3, 0); definePrimitive(base, index++, "_ObjectCopySeries", prObjectCopySeries, 4, 0); definePrimitive(base, index++, "_ObjectPointsTo", prObjectPointsTo, 2, 0); definePrimitive(base, index++, "_ObjectRespondsTo", prObjectRespondsTo, 2, 0); definePrimitive(base, index++, "_ObjectIsMutable", prObjectIsMutable, 1, 0); definePrimitive(base, index++, "_ObjectIsPermanent", prObjectIsPermanent, 1, 0); definePrimitive(base, index++, "_ObjectDeepFreeze", prDeepFreeze, 1, 0); definePrimitive(base, index++, "_ObjectDeepCopy", prDeepCopy, 1, 0); #if !SCPLAYER definePrimitive(base, index++, "_CompileExpression", prCompileString, 2, 0); #endif definePrimitive(base, index++, "_GetBackTrace", prGetBackTrace, 1, 0); definePrimitive(base, index++, "_DumpBackTrace", prDumpBackTrace, 1, 0); definePrimitive(base, index++, "_DumpByteCodes", prDumpByteCodes, 1, 0); definePrimitive(base, index++, "_AllClasses", prAllClasses, 1, 0); definePrimitive(base, index++, "_DumpClassSubtree", prPostClassTree, 1, 0); // definePrimitive(base, index++, "_TabletTracking", prTabletTracking, 1, 0); definePrimitive(base, index++, "_FunDef_NumArgs", prFunDef_NumArgs, 1, 0); definePrimitive(base, index++, "_FunDef_NumVars", prFunDef_NumVars, 1, 0); definePrimitive(base, index++, "_FunDef_VarArgs", prFunDef_VarArgs, 1, 0); definePrimitive(base, index++, "_Thread_Init", prThreadInit, 3, 0); definePrimitive(base, index++, "_Thread_RandSeed", prThreadRandSeed, 2, 0); definePrimitive(base, index++, "_Thread_GetRandData", prThreadGetRandData, 1, 0); definePrimitive(base, index++, "_Thread_SetRandData", prThreadSetRandData, 2, 0); // definePrimitive(base, index++, "_ThreadRun", prThreadRun, 2, 0); // definePrimitive(base, index++, "_RunNextThread", prRunNextThread, 1, 0); definePrimitive(base, index++, "_RoutineYield", prRoutineYield, 1, 0); definePrimitive(base, index++, "_RoutineAlwaysYield", prRoutineAlwaysYield, 1, 0); definePrimitive(base, index++, "_RoutineResume", prRoutineResume, 2, 0); definePrimitive(base, index++, "_RoutineReset", prRoutineReset, 1, 0); definePrimitive(base, index++, "_RoutineYieldAndReset", prRoutineYieldAndReset, 2, 0); definePrimitive(base, index++, "_RoutineStop", prRoutineStop, 1, 0); // definePrimitive(base, index++, "_IsDemo", prIsDemo, 1, 0); definePrimitive(base, index++, "_Blork", prBlork, 1, 0); definePrimitive(base, index++, "_UGenCodeString", prUGenCodeString, 5, 0); definePrimitive(base, index++, "_MainOverwriteMsg", prOverwriteMsg, 1, 0); definePrimitive(base, index++, "_AppClock_SchedNotify", prAppClockSchedNotify, 1, 0); definePrimitive(base, index++, "_LanguageConfig_getIncludePaths", prLanguageConfig_getIncludePaths, 1, 0); definePrimitive(base, index++, "_LanguageConfig_getExcludePaths", prLanguageConfig_getExcludePaths, 1, 0); definePrimitive(base, index++, "_LanguageConfig_addIncludePath", prLanguageConfig_addIncludePath, 2, 0); definePrimitive(base, index++, "_LanguageConfig_addExcludePath", prLanguageConfig_addExcludePath, 2, 0); definePrimitive(base, index++, "_LanguageConfig_removeIncludePath", prLanguageConfig_removeIncludePath, 2, 0); definePrimitive(base, index++, "_LanguageConfig_removeExcludePath", prLanguageConfig_removeExcludePath, 2, 0); definePrimitive(base, index++, "_LanguageConfig_writeConfigFile", prLanguageConfig_writeConfigFile, 2, 0); definePrimitive(base, index++, "_LanguageConfig_getPostInlineWarnings", prLanguageConfig_getPostInlineWarnings, 1, 0); definePrimitive(base, index++, "_LanguageConfig_setPostInlineWarnings", prLanguageConfig_setPostInlineWarnings, 2, 0); definePrimitive(base, index++, "_SC_VersionMajor", prVersionMajor, 1, 0); definePrimitive(base, index++, "_SC_VersionMinor", prVersionMinor, 1, 0); definePrimitive(base, index++, "_SC_VersionPatch", prVersionPatch, 1, 0); //void initOscilPrimitives(); //void initControllerPrimitives(); //initOscilPrimitives(); //initControllerPrimitives(); initMathPrimitives(); initSignalPrimitives(); initArrayPrimitives(); void initSymbolPrimitives(); initSymbolPrimitives(); void initArchiverPrimitives(); initArchiverPrimitives(); void initArrayPrimitives(); initArrayPrimitives(); void initBitPrimitives(); initBitPrimitives(); void initCharPrimitives(); initCharPrimitives(); void initFilePrimitives(); initFilePrimitives(); void initPlatformPrimitives(); initPlatformPrimitives(); void initStringPrimitives(); initStringPrimitives(); void initListPrimitives(); initListPrimitives(); void initUnixPrimitives(); initUnixPrimitives(); void init_OSC_primitives(); init_OSC_primitives(); /* these probably should be moved out of the Lang code into an App init primitives section */ void initGUIPrimitives(); initGUIPrimitives(); void initSCViewPrimitives(); initSCViewPrimitives(); void initSchedPrimitives(); initSchedPrimitives(); #if defined(__APPLE__) || defined(HAVE_ALSA) || defined(HAVE_PORTMIDI) void initMIDIPrimitives(); initMIDIPrimitives(); #endif #if !defined(SC_WIN32) && !defined(SC_IPHONE) void initHIDPrimitives(); initHIDPrimitives(); void initSpeechPrimitives(); initSpeechPrimitives(); void initCocoaFilePrimitives(); initCocoaFilePrimitives(); void initCocoaBridgePrimitives(); initCocoaBridgePrimitives(); void initSerialPrimitives(); initSerialPrimitives(); void initWiiPrimitives(); initWiiPrimitives(); #endif #ifdef SC_DARWIN void initCoreAudioPrimitives(); initCoreAudioPrimitives(); #endif // CR ADDED void initRendezvousPrimitives(); initRendezvousPrimitives(); #ifdef SCOGL_COMPILE void initOpenGLPrimitives(); initOpenGLPrimitives(); #endif #ifdef SC_QT QtCollider::initPrimitives(); #endif #ifdef SC_IDE void initScIDEPrimitives(); initScIDEPrimitives(); #endif initSCDocPrimitives(); s_recvmsg = getsym("receiveMsg"); post("\tNumPrimitives = %d\n", nextPrimitiveIndex()); } void initThreads(); void initThreads() { s_prrunnextthread = getsym("prRunNextThread"); s_prready = getsym("prReady"); } SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrListPrim.cpp0000664000000000000000000005003412161364457025551 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrKernel.h" #include "PyrKernelProto.h" #include "PyrPrimitive.h" #include "PyrPrimitiveProto.h" #include "PyrSymbol.h" #include "PyrListPrim.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSignal.h" #include "PyrMessage.h" #include "PyrSched.h" #include "SC_RGen.h" #include "SCBase.h" #include #include int objectPerform(VMGlobals *g, int numArgsPushed); int ivxIdentDict_array, ivxIdentDict_size, ivxIdentDict_parent, ivxIdentDict_proto, ivxIdentDict_know; int class_array_index, class_array_maxsubclassindex; int class_identdict_index, class_identdict_maxsubclassindex; PyrClass *class_identdict; PyrSymbol *s_proto, *s_parent; PyrSymbol *s_delta, *s_dur, *s_stretch; #define HASHSYMBOL(sym) (sym >> 5) #define ISKINDOF(obj, lo, hi) (\ objClassIndex = slotRawInt(&obj->classptr->classIndex), \ objClassIndex >= lo && objClassIndex <= hi) int prArrayMultiChanExpand(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slot, *slots1, *slots2, *slots3, *slots4; PyrObject *obj1, *obj2, *obj3, *obj4; int i, j, size, len, maxlen; a = g->sp; obj1 = slotRawObject(a); size = obj1->size; slots1 = obj1->slots; maxlen = 1; for (j=0; jclassptr == class_array) { len = slotRawObject(slot)->size; maxlen = len > maxlen ? len : maxlen; } else if (isKindOf(slotRawObject(slot), class_sequenceable_collection) && (slotRawObject(slot)->classptr != class_string)) { return errFailed; // this primitive only handles Arrays. } } } obj2 = newPyrArray(g->gc, maxlen, 0, true); obj2->size = maxlen; slots2 = obj2->slots; for (i=0; igc, size, 0, false); obj3->size = size; SetObject(slots2 + i, obj3); slots1 = obj1->slots; slots3 = obj3->slots; for (j=0; jclassptr == class_array && slotRawObject(slot)->size > 0) { obj4 = slotRawObject(slot); slots4 = obj4->slots; slotCopy(&slots3[j],&slots4[i % obj4->size]); } else { slotCopy(&slots3[j],slot); } } else { slotCopy(&slots3[j],slot); } } } SetObject(a, obj2); return errNone; } int arrayAtIdentityHash(PyrObject *array, PyrSlot *key) { PyrSlot *slots, *test; unsigned int i, start, end, hash, maxHash; hash = calcHash(key); maxHash = array->size; start = hash % maxHash; end = array->size; slots = array->slots; for (i=start; isp - 1; // array b = g->sp; // key array = slotRawObject(a); if(array->size == 0) return errFailed; index = arrayAtIdentityHash(array, b); SetInt(a, index); return errNone; } int arrayAtIdentityHashInPairs(PyrObject *array, PyrSlot *key) { PyrSlot *slots, *test; unsigned int i, start, end, hash, maxHash; hash = calcHash(key); maxHash = array->size >> 1; start = (hash % maxHash) << 1; end = array->size; slots = array->slots; for (i=start; isize >> 1; start = (hash % maxHash) << 1; end = array->size; slots = array->slots; for (i=start; islots + ivxIdentDict_know); if (knows && IsSym(key)) { if (slotRawSymbol(key) == s_parent) { slotCopy(&dict->slots[ivxIdentDict_parent],value); g->gc->GCWrite(dict, value); return errNone; } if (slotRawSymbol(key) == s_proto) { slotCopy(&dict->slots[ivxIdentDict_proto],value); g->gc->GCWrite(dict, value); return errNone; } } array = slotRawObject(&dict->slots[ivxIdentDict_array]); if (!isKindOf((PyrObject*)array, class_array)) return errFailed; index = arrayAtIdentityHashInPairs(array, key); slot = array->slots + index; slotCopy(&slot[1],value); g->gc->GCWrite(array, value); if (IsNil(slot)) { slotCopy(slot,key); g->gc->GCWrite(array, key); size = slotRawInt(&dict->slots[ivxIdentDict_size]) + 1; SetRaw(&dict->slots[ivxIdentDict_size], size); if (array->size < size*3) { PyrObject *newarray; newarray = newPyrArray(g->gc, size*3, 0, false); newarray->size = ARRAYMAXINDEXSIZE(newarray); nilSlots(newarray->slots, newarray->size); slot = array->slots; for (i=0; isize; i+=2, slot+=2) { if (NotNil(slot)) { index = arrayAtIdentityHashInPairs(newarray, slot); newslot = newarray->slots + index; slotCopy(&newslot[0],&slot[0]); slotCopy(&newslot[1],&slot[1]); } } SetRaw(&dict->slots[ivxIdentDict_array], newarray); g->gc->GCWrite(dict, newarray); } } return errNone; } int prIdentDict_Put(struct VMGlobals *g, int numArgsPushed); int prIdentDict_Put(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; a = g->sp - 2; // dict b = g->sp - 1; // key c = g->sp; // value if(IsNil(b)) return errWrongType; if(IsNil(c)) return errFailed; // will call removeAt return identDictPut(g, slotRawObject(a), b, c); } int prIdentDict_PutGet(struct VMGlobals *g, int numArgsPushed); int prIdentDict_PutGet(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *d, *slot, *newslot; int i, index, size; PyrObject *dict; PyrObject *array; a = g->sp - 2; // dict b = g->sp - 1; // key c = g->sp; // value d = ++g->sp; // push the stack to save the receiver slotCopy(d,a); dict = slotRawObject(d); array = slotRawObject(&dict->slots[ivxIdentDict_array]); if (!isKindOf((PyrObject*)array, class_array)) { SetNil(a); --g->sp; return errFailed; } index = arrayAtIdentityHashInPairs(array, b); slot = array->slots + index; slotCopy(a,&slot[1]); slotCopy(&slot[1],c); g->gc->GCWrite(array, c); if (IsNil(slot)) { slotCopy(slot,b); g->gc->GCWrite(array, b); size = slotRawInt(&dict->slots[ivxIdentDict_size]) + 1; SetRaw(&dict->slots[ivxIdentDict_size], size); if (array->size < size*3) { PyrObject *newarray; newarray = newPyrArray(g->gc, size*3, 0, true); newarray->size = ARRAYMAXINDEXSIZE(newarray); nilSlots(newarray->slots, newarray->size); slot = array->slots; for (i=0; isize; i+=2, slot+=2) { if (NotNil(slot)) { index = arrayAtIdentityHashInPairs(newarray, slot); newslot = newarray->slots + index; slotCopy(&newslot[0],&slot[0]); slotCopy(&newslot[1],&slot[1]); } } SetRaw(&dict->slots[ivxIdentDict_array], newarray); g->gc->GCWrite(dict, newarray); } } --g->sp; return errNone; } int prArray_AtIdentityHashInPairs(struct VMGlobals *g, int numArgsPushed); int prArray_AtIdentityHashInPairs(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; unsigned int i; a = g->sp - 1; // array b = g->sp; // key if(slotRawObject(a)->size < 2) return errFailed; i = arrayAtIdentityHashInPairs(slotRawObject(a), b); SetInt(a, i); return errNone; } bool identDict_lookupNonNil(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result); bool identDict_lookupNonNil(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result) { again: PyrSlot *dictslots = dict->slots; PyrSlot *arraySlot = dictslots + ivxIdentDict_array; if (isKindOfSlot(arraySlot, class_array)) { PyrObject *array = slotRawObject(arraySlot); int index = arrayAtIdentityHashInPairsWithHash(array, key, hash); if (SlotEq(key, array->slots + index)) { slotCopy(result,&array->slots[index + 1]); return true; } } PyrClass *identDictClass = s_identitydictionary->u.classobj; PyrSlot *parentSlot = dictslots + ivxIdentDict_parent; PyrSlot * protoSlot = dictslots + ivxIdentDict_proto; if (isKindOfSlot(parentSlot, identDictClass)) { if (isKindOfSlot(protoSlot, identDictClass)) { // recursive call. if (identDict_lookupNonNil(slotRawObject(protoSlot), key, hash, result)) return true; } dict = slotRawObject(parentSlot); goto again; // tail call } else { if (isKindOfSlot(protoSlot, identDictClass)) { dict = slotRawObject(protoSlot); goto again; // tail call } } return false; } bool identDict_lookup(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result); bool identDict_lookup(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result) { again: PyrSlot *dictslots = dict->slots; PyrSlot *arraySlot = dictslots + ivxIdentDict_array; if (isKindOfSlot(arraySlot, class_array)) { PyrObject *array = slotRawObject(arraySlot); int index = arrayAtIdentityHashInPairsWithHash(array, key, hash); if (SlotEq(key, array->slots + index)) { slotCopy(result,&array->slots[index + 1]); return true; } } PyrClass *identDictClass = s_identitydictionary->u.classobj; PyrSlot *parentSlot = dictslots + ivxIdentDict_parent; PyrSlot * protoSlot = dictslots + ivxIdentDict_proto; if (isKindOfSlot(parentSlot, identDictClass)) { if (isKindOfSlot(protoSlot, identDictClass)) { // recursive call. if (identDict_lookup(slotRawObject(protoSlot), key, hash, result)) return true; } dict = slotRawObject(parentSlot); goto again; // tail call } else { if (isKindOfSlot(protoSlot, identDictClass)) { dict = slotRawObject(protoSlot); goto again; // tail call } } SetNil(result); return false; } int prIdentDict_At(struct VMGlobals *g, int numArgsPushed); int prIdentDict_At(struct VMGlobals *g, int numArgsPushed) { PyrSlot* a = g->sp - 1; // dict PyrSlot* key = g->sp; // key PyrObject *dict = slotRawObject(a); bool knows = IsTrue(dict->slots + ivxIdentDict_know); if (knows && IsSym(key)) { if (slotRawSymbol(key) == s_parent) { slotCopy(a,&dict->slots[ivxIdentDict_parent]); return errNone; } if (slotRawSymbol(key) == s_proto) { slotCopy(a,&dict->slots[ivxIdentDict_proto]); return errNone; } } identDict_lookup(dict, key, calcHash(key), a); return errNone; } int prSymbol_envirGet(struct VMGlobals *g, int numArgsPushed); int prSymbol_envirGet(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, result; int objClassIndex; a = g->sp; // key PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1]; PyrObject *dict = slotRawObject(currentEnvironmentSlot); if (!IsObj(currentEnvironmentSlot)) return errFailed; if (!ISKINDOF(dict, class_identdict_index, class_identdict_maxsubclassindex)) return errFailed; identDict_lookup(dict, a, calcHash(a), &result); slotCopy(a,&result); return errNone; } int prSymbol_envirPut(struct VMGlobals *g, int numArgsPushed); int prSymbol_envirPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int objClassIndex; a = g->sp - 1; // key b = g->sp; // value PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1]; PyrObject *dict = slotRawObject(currentEnvironmentSlot); if (!IsObj(currentEnvironmentSlot)) return errFailed; if (!ISKINDOF(dict, class_identdict_index, class_identdict_maxsubclassindex)) return errFailed; int err = identDictPut(g, dict, a, b); if (err) return err; slotCopy(a,b); return errNone; } int prEvent_Delta(struct VMGlobals *g, int numArgsPushed); int prEvent_Delta(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, key, dur, stretch, delta; double fdur, fstretch; int err; a = g->sp; // dict SetSymbol(&key, s_delta); identDict_lookup(slotRawObject(a), &key, calcHash(&key), &delta); if (NotNil(&delta)) { slotCopy(a,&delta); } else { SetSymbol(&key, s_dur); identDict_lookup(slotRawObject(a), &key, calcHash(&key), &dur); err = slotDoubleVal(&dur, &fdur); if (err) { if (NotNil(&dur)) return err; SetNil(a); return errNone; } SetSymbol(&key, s_stretch); identDict_lookup(slotRawObject(a), &key, calcHash(&key), &stretch); err = slotDoubleVal(&stretch, &fstretch); if (err) { if (NotNil(&stretch)) return err; SetFloat(a, fdur); return errNone; } SetFloat(a, fdur * fstretch ); } return errNone; } void PriorityQueueAdd(struct VMGlobals *g, PyrObject* queueobj, PyrSlot* item, double time); void PriorityQueueAdd(struct VMGlobals *g, PyrObject* queueobj, PyrSlot* item, double time) { PyrObject *schedq, *newschedq; int size, maxsize; PyrSlot *schedqSlot = queueobj->slots; if (!IsObj(schedqSlot)) { size = 32; schedq = newPyrArray(g->gc, size, 0, true); schedq->size = 1; SetInt(schedq->slots + 0, 0); // stability count SetObject(schedqSlot, schedq); g->gc->GCWrite(queueobj, schedq); } else { schedq = slotRawObject(schedqSlot); maxsize = ARRAYMAXINDEXSIZE(schedq); size = schedq->size; if (size+3 > maxsize) { newschedq = newPyrArray(g->gc, maxsize*2, 0, true); newschedq->size = size; slotCopy(newschedq->slots, schedq->slots, size); assert(IsInt(newschedq->slots)); SetObject(schedqSlot, newschedq); g->gc->GCWrite(queueobj, newschedq); schedq = newschedq; } } addheap(g, schedq, time, item); } int prPriorityQueueAdd(struct VMGlobals *g, int numArgsPushed); int prPriorityQueueAdd(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; // priority queue PyrSlot *b = g->sp - 1; // time PyrSlot *c = g->sp; // item double time; int err = slotDoubleVal(b, &time); if (err) return errNone; // nil is OK, nothing gets added PriorityQueueAdd(g, slotRawObject(a), c, time); return errNone; } void PriorityQueuePop(VMGlobals *g, PyrObject *queueobj, PyrSlot *result); void PriorityQueuePop(VMGlobals *g, PyrObject *queueobj, PyrSlot *result) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); double time; if (!getheap(g, schedq, &time, result)) { SetNil(result); } } else { SetNil(result); } } void PriorityQueueTop(PyrObject *queueobj, PyrSlot *result); void PriorityQueueTop(PyrObject *queueobj, PyrSlot *result) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); if (schedq->size > 1) { slotCopy(result,&schedq->slots[1]); } else { SetNil(result); } } else { SetNil(result); } } void PriorityQueueClear(PyrObject *queueobj); void PriorityQueueClear(PyrObject *queueobj) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); SetInt(schedq->slots, 0); // stability count schedq->size = 1; } } bool PriorityQueueEmpty(PyrObject *queueobj); bool PriorityQueueEmpty(PyrObject *queueobj) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); if (schedq->size > 1) { return false; } } return true; } int prPriorityQueuePop(struct VMGlobals *g, int numArgsPushed); int prPriorityQueuePop(struct VMGlobals *g, int numArgsPushed) { PyrSlot* a = g->sp; // priority queue PriorityQueuePop(g, slotRawObject(a), a); return errNone; } int prPriorityQueueTop(struct VMGlobals *g, int numArgsPushed); int prPriorityQueueTop(struct VMGlobals *g, int numArgsPushed) { PyrSlot* a = g->sp; // priority queue PriorityQueueTop(slotRawObject(a), a); return errNone; } int prPriorityQueueClear(struct VMGlobals *g, int numArgsPushed); int prPriorityQueueClear(struct VMGlobals *g, int numArgsPushed) { PyrSlot* a = g->sp; // priority queue PriorityQueueClear(slotRawObject(a)); return errNone; } int prPriorityQueueEmpty(struct VMGlobals *g, int numArgsPushed); int prPriorityQueueEmpty(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; // priority queue if (PriorityQueueEmpty(slotRawObject(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } void PriorityQueuePostpone(PyrObject* queueobj, double time); void PriorityQueuePostpone(PyrObject* queueobj, double time) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); PyrSlot* slots = schedq->slots; for (int i=1; i < schedq->size; i+=3) { SetRaw(&slots[i], slotRawFloat(&slots[i]) + time); } } } int prPriorityQueuePostpone(struct VMGlobals *g, int numArgsPushed); int prPriorityQueuePostpone(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; // priority queue PyrSlot *b = g->sp; // time double time; int err = slotDoubleVal(b, &time); if (err) return err; PyrObject *queueobj = slotRawObject(a); PriorityQueuePostpone(queueobj, time); return errNone; } void initListPrimitives(); void initListPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_Array_AtIdentityHash", prArray_AtIdentityHash, 2, 0); definePrimitive(base, index++, "_Array_AtIdentityHashInPairs", prArray_AtIdentityHashInPairs, 2, 0); definePrimitive(base, index++, "_IdentDict_Put", prIdentDict_Put, 3, 0); definePrimitive(base, index++, "_IdentDict_PutGet", prIdentDict_PutGet, 3, 0); definePrimitive(base, index++, "_IdentDict_At", prIdentDict_At, 2, 0); definePrimitive(base, index++, "_Symbol_envirGet", prSymbol_envirGet, 1, 0); definePrimitive(base, index++, "_Symbol_envirPut", prSymbol_envirPut, 2, 0); definePrimitive(base, index++, "_ArrayMultiChannelExpand", prArrayMultiChanExpand, 1, 0); definePrimitive(base, index++, "_PriorityQueueAdd", prPriorityQueueAdd, 3, 0); definePrimitive(base, index++, "_PriorityQueuePop", prPriorityQueuePop, 1, 0); definePrimitive(base, index++, "_PriorityQueueTop", prPriorityQueueTop, 1, 0); definePrimitive(base, index++, "_PriorityQueueClear", prPriorityQueueClear, 1, 0); definePrimitive(base, index++, "_PriorityQueueEmpty", prPriorityQueueEmpty, 1, 0); definePrimitive(base, index++, "_PriorityQueuePostpone", prPriorityQueuePostpone, 2, 0); definePrimitive(base, index++, "_Event_Delta", prEvent_Delta, 1, 0); } void initPatterns(); void initPatterns() { PyrSymbol *sym; ivxIdentDict_array = instVarOffset("IdentityDictionary", "array"); ivxIdentDict_size = instVarOffset("IdentityDictionary", "size"); ivxIdentDict_parent = instVarOffset("IdentityDictionary", "parent"); ivxIdentDict_proto = instVarOffset("IdentityDictionary", "proto"); ivxIdentDict_know = instVarOffset("IdentityDictionary", "know"); sym = getsym("IdentityDictionary"); class_identdict = sym ? sym->u.classobj : NULL; class_identdict_index = slotRawInt(&class_identdict->classIndex); class_identdict_maxsubclassindex = slotRawInt(&class_identdict->maxSubclassIndex); class_array_index = slotRawInt(&class_array->classIndex); class_array_maxsubclassindex = slotRawInt(&class_array->maxSubclassIndex); s_parent = getsym("parent"); s_proto = getsym("proto"); s_delta = getsym("delta"); s_dur = getsym("dur"); s_stretch = getsym("stretch"); } SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrSerialPrim.cpp0000664000000000000000000003372312245365552026063 0ustar rootroot/* Serial port support. Copyright (c) 2006 stefan kersten. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "GC.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "SC_LanguageClient.h" #include "SCBase.h" #include "SC_FIFO.h" class SerialPort { public: enum Parity { kNoParity, kEvenParity, kOddParity }; struct Options { Options() : exclusive(false), baudrate(9600), databits(8), stopbit(true), parity(kNoParity), crtscts(false), xonxoff(false) { } bool exclusive; size_t baudrate; size_t databits; bool stopbit; Parity parity; bool crtscts; bool xonxoff; }; static const int kNumOptions = 7; static const int kBufferSize = 8192; static const int kReadTimeoutMs = 1000; typedef SC_FIFO FIFO; struct Error : std::runtime_error { explicit Error(const char* what) : std::runtime_error(what) { } }; struct SysError : public Error { explicit SysError(int e=errno) : Error(strerror(e)) { } }; static PyrSymbol* s_dataAvailable; static PyrSymbol* s_doneAction; public: SerialPort(PyrObject* obj, const char* serialport, const Options& options); ~SerialPort(); bool isRunning() const { return m_running; } int fd() const { return m_fd; } const Options& options() const { return m_options; } bool put(uint8_t byte); bool get(uint8_t* byte); int rxErrors(); void stop(); void cleanup(); protected: static void* threadFunc(void*); void threadLoop(); void dataAvailable(); void doneAction(); private: // language interface PyrObject* m_obj; boost::atomic m_dodone; // serial interface Options m_options; int m_fd; boost::atomic m_open; struct termios m_termio; struct termios m_oldtermio; // rx buffers int m_rxErrors[2]; FIFO m_rxfifo; uint8_t m_rxbuffer[kBufferSize]; // rx thread boost::atomic m_running; pthread_t m_thread; }; PyrSymbol* SerialPort::s_dataAvailable = 0; PyrSymbol* SerialPort::s_doneAction = 0; SerialPort::SerialPort(PyrObject* obj, const char* serialport, const Options& options) : m_obj(obj), m_options(options), m_fd(-1) { // open non blocking m_fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY); if (m_fd == -1) { throw SysError(errno); } // exclusiveness #if defined(TIOCEXCL) if (m_options.exclusive) { if (ioctl(m_fd, TIOCEXCL) == -1) { throw SysError(errno); } } #endif // TIOCEXCL if (fcntl(m_fd, F_SETFL, O_NONBLOCK) == -1) { int e = errno; close(m_fd); throw SysError(e); } // initialize serial connection // get current settings and remember them struct termios toptions; if (tcgetattr(m_fd, &toptions) < 0) { int e = errno; close(m_fd); throw SysError(e); } memcpy(&m_oldtermio, &toptions, sizeof(toptions)); // baudrate speed_t brate; switch (m_options.baudrate) { case 1200: brate = B1200; break; case 1800: brate = B1800; break; case 2400: brate = B2400; break; case 4800: brate = B4800; break; case 9600: brate = B9600; break; case 19200: brate = B19200; break; case 38400: brate = B38400; break; // #ifndef _POSIX_C_SOURCE #if defined(B7200) case 7200: brate = B7200; break; #endif #if defined(B7200) case 14400: brate = B14400; break; #endif #if defined(B28800) case 28800: brate = B28800; break; #endif #if defined(B57600) case 57600: brate = B57600; break; #endif #if defined(B76800) case 76800: brate = B76800; break; #endif #if defined(B115200) case 115200: brate = B115200; break; #endif #if defined(B230400) case 230400: brate = B230400; break; #endif // #endif // !_POSIX_C_SOURCE default: close(m_fd); throw Error("unsupported baudrate"); } cfsetispeed(&toptions, brate); cfsetospeed(&toptions, brate); // data bits toptions.c_cflag &= ~CSIZE; switch (m_options.databits) { case 5: toptions.c_cflag |= CS5; break; case 6: toptions.c_cflag |= CS6; break; case 7: toptions.c_cflag |= CS7; break; default: m_options.databits = 8; toptions.c_cflag |= CS8; break; } // stop bit if (m_options.stopbit) { toptions.c_cflag |= CSTOPB; } else { toptions.c_cflag &= ~CSTOPB; } // parity switch (m_options.parity) { case kNoParity: toptions.c_cflag &= ~PARENB; break; case kEvenParity: toptions.c_cflag |= PARENB; toptions.c_cflag &= ~PARODD; break; case kOddParity: toptions.c_cflag |= (PARENB | PARODD); break; } // h/w flow control #if !defined(_POSIX_C_SOURCE) || defined(__USE_MISC) if (m_options.crtscts) { toptions.c_cflag &= ~CRTSCTS; } else { toptions.c_cflag |= CRTSCTS; } #endif // !_POSIX_C_SOURCE || __USE_MISC // s/w flow control if (m_options.xonxoff) { toptions.c_iflag |= (IXON | IXOFF | IXANY); } else { toptions.c_iflag &= ~(IXON | IXOFF | IXANY); } // (nescivi) by default carriage returns are translated to line feeds, // we don't want that toptions.c_iflag &= ~ICRNL; // enable READ & ignore ctrl lines toptions.c_cflag |= (CREAD | CLOCAL); // non-canonical (raw) i/o toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // disable post processing toptions.c_oflag &= ~OPOST; // see: http://unixwiz.net/techtips/termios-vmin-vtime.html // NOTE: unused for non-blocking reads // toptions.c_cc[VMIN] = 0; // toptions.c_cc[VTIME] = 20; if (tcsetattr(m_fd, TCSAFLUSH, &toptions) < 0) { int e = errno; close(m_fd); throw SysError(e); } memcpy(&m_termio, &toptions, sizeof(toptions)); m_rxErrors[0] = m_rxErrors[1] = 0; int e = pthread_create(&m_thread, 0, threadFunc, this); if (e != 0) { close(m_fd); throw SysError(e); } m_open = true; m_dodone = true; } SerialPort::~SerialPort() { m_running = false; // m_open = false; if ( m_open ){ tcflush(m_fd, TCIOFLUSH); tcsetattr(m_fd, TCSANOW, &m_oldtermio); close(m_fd); m_open = false; }; pthread_join(m_thread, 0); } void SerialPort::stop(){ m_running = false; } void SerialPort::cleanup(){ m_running = false; m_dodone = false; if ( m_open ){ tcflush(m_fd, TCIOFLUSH); tcsetattr(m_fd, TCSANOW, &m_oldtermio); close(m_fd); m_open = false; }; } bool SerialPort::put(uint8_t byte) { return write(m_fd, &byte, sizeof(byte)) == sizeof(byte); } bool SerialPort::get(uint8_t* byte) { if (m_rxfifo.IsEmpty()) return false; *byte = m_rxfifo.Get() & 0xFF; return true; } int SerialPort::rxErrors() { // errors since last query int x = m_rxErrors[1]; int res = x-m_rxErrors[0]; m_rxErrors[0] = x; return res; } void* SerialPort::threadFunc(void* self) { ((SerialPort*)self)->threadLoop(); return 0; } void SerialPort::dataAvailable() { int status = lockLanguageOrQuit(m_running); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } PyrSymbol *method = s_dataAvailable; if (m_obj) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, method, 1); g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); } void SerialPort::doneAction() { int status = lockLanguageOrQuit(m_dodone); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } PyrSymbol *method = s_doneAction; if (m_obj) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, method, 1); g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); } void SerialPort::threadLoop() { const int fd = m_fd; const int max_fd = fd+1; m_running = true; m_rxErrors[1] = 0; while (true) { fd_set rfds; FD_ZERO( &rfds); FD_SET(fd, &rfds); struct timeval timeout; timeout.tv_sec = kReadTimeoutMs/1000; timeout.tv_usec = (kReadTimeoutMs%1000)*1000; int n = select(max_fd, &rfds, 0, 0, &timeout); // int fdset = FD_ISSET(fd, &rfds); // printf( "fdset %i, n %i, errno %i\n", fdset, n, errno ); if ( m_open ){ if ((n > 0) && FD_ISSET(fd, &rfds)) { // printf("poll input\n"); int nr = 0; // while (true) { if ( m_open ){ int n2 = read(fd, m_rxbuffer, kBufferSize); // printf("read %d, errno %i, errbadf %i, %i, %i\n", n2, errno, EBADF, EAGAIN, EIO); if (n2 > 0) { // write data to ringbuffer for (int i=0; i < n2; ++i) { if (!m_rxfifo.Put(m_rxbuffer[i])) { m_rxErrors[1]++; break; } } nr += n2; } else if ((n2 == 0) && (n == 1) ) { // added by nescivi, to check for disconnected device. In this case the read is 0 all the time and otherwise eats up the CPU // printf( "done\n" ); goto done; } else if ((n2 == 0) || ((n2 == -1) && (errno == EAGAIN))) { // printf( "break\n"); break; } else { #ifndef NDEBUG printf("SerialPort HUP\n"); #endif goto done; } } //} if (!m_running) { // close and cleanup goto done; } if (nr > 0) { dataAvailable(); } } else if (n == -1) { goto done; } } if (!m_running) { // close and cleanup goto done; } } done: // doneAction(); if ( m_open ){ tcflush(fd, TCIOFLUSH); tcsetattr(fd, TCSANOW, &m_oldtermio); close(fd); }; m_open = false; m_running = false; if ( m_dodone ) doneAction(); #ifndef NDEBUG printf("SerialPort closed\n"); #endif } // ===================================================================== // primitives static SerialPort* getSerialPort(PyrSlot* slot) { if (NotPtr(&slotRawObject(slot)->slots[0])) return NULL; return (SerialPort*)slotRawPtr(&slotRawObject(slot)->slots[0]); } static int prSerialPort_Open(struct VMGlobals *g, int numArgsPushed) { PyrSlot *args = g->sp - 1 - SerialPort::kNumOptions; int err; PyrSlot* self = args+0; if (getSerialPort(self) != 0) return errFailed; char portName[PATH_MAX]; err = slotStrVal(args+1, portName, sizeof(portName)); printf("portName %s\n", portName); if (err) return err; SerialPort::Options options; SerialPort* port = 0; options.exclusive = IsTrue(args+2); int baudrate; err = slotIntVal(args+3, &baudrate); if (err) return err; options.baudrate = baudrate; int databits; err = slotIntVal(args+4, &databits); if (err) return err; options.databits = databits; options.stopbit = IsTrue(args+5); int parity; err = slotIntVal(args+6, &parity); if (err) return err; options.parity = (SerialPort::Parity)parity; options.crtscts = IsTrue(args+7); options.xonxoff = IsTrue(args+8); try { port = new SerialPort(slotRawObject(self), portName, options); } catch (SerialPort::Error& e) { std::ostringstream os; os << "SerialPort Error: " << e.what(); post(os.str().c_str()); return errFailed; } SetPtr(slotRawObject(self)->slots+0, port); return errNone; } static int prSerialPort_Close(struct VMGlobals *g, int numArgsPushed) { PyrSlot* self = g->sp; SerialPort* port = (SerialPort*)getSerialPort(self); if (port == 0) return errFailed; port->stop(); return errNone; } static int prSerialPort_Cleanup(struct VMGlobals *g, int numArgsPushed) { PyrSlot* self = g->sp; SerialPort* port = (SerialPort*)getSerialPort(self); if (port == 0) return errFailed; port->cleanup(); post("SerialPort Cleanup\n"); delete port; SetNil(slotRawObject(self)->slots+0); return errNone; } static int prSerialPort_Next(struct VMGlobals *g, int numArgsPushed) { PyrSlot* self = g->sp; SerialPort* port = (SerialPort*)getSerialPort(self); // printf( "port %i", port ); if (port == 0) return errFailed; uint8_t byte; if (port->get(&byte)) { SetInt(self, byte); } else { SetNil(self); } return errNone; } static int prSerialPort_Put(struct VMGlobals *g, int numArgsPushed) { PyrSlot *args = g->sp - 1; PyrSlot* self = args+0; SerialPort* port = (SerialPort*)getSerialPort(self); if (port == 0) return errFailed; PyrSlot* src = args+1; int val; if (IsChar(src)) { val = slotRawChar(src); } else { int err = slotIntVal(src, &val); if (err) return err; } bool res = port->put(val & 0xFF); SetBool(self, res); return errNone; } static int prSerialPort_RXErrors(struct VMGlobals *g, int numArgsPushed) { PyrSlot* self = g->sp; SerialPort* port = (SerialPort*)getSerialPort(self); if (port == 0) return errFailed; SetInt(self, port->rxErrors()); return errNone; } void initSerialPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_SerialPort_Open", prSerialPort_Open, 2+SerialPort::kNumOptions, 0); definePrimitive(base, index++, "_SerialPort_Close", prSerialPort_Close, 1, 0); definePrimitive(base, index++, "_SerialPort_Next", prSerialPort_Next, 1, 0); definePrimitive(base, index++, "_SerialPort_Put", prSerialPort_Put, 2, 0); definePrimitive(base, index++, "_SerialPort_RXErrors", prSerialPort_RXErrors, 1, 0); definePrimitive(base, index++, "_SerialPort_Cleanup", prSerialPort_Cleanup, 1, 0); SerialPort::s_dataAvailable = getsym("prDataAvailable"); SerialPort::s_doneAction = getsym("prDoneAction"); } // EOF SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrSched.cpp0000664000000000000000000011275412245365552025044 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrKernel.h" #include "PyrSched.h" #include "GC.h" #include "PyrPrimitive.h" #include "PyrSymbol.h" #ifdef SC_DARWIN # include #endif #include #include #include #include #ifndef SC_WIN32 #include #endif #include "SC_Win32Utils.h" #include "SCBase.h" static const double dInfinity = std::numeric_limits::infinity(); void runAwakeMessage(VMGlobals *g); // heaps use an integer timestamp to ensure stable heap order struct PyrHeap: PyrObjectHdr { PyrSlot count; // stability count PyrSlot slots[0]; // slots }; bool addheap(VMGlobals *g, PyrObject *heapArg, double schedtime, PyrSlot *task) { PyrHeap * heap = (PyrHeap*)heapArg; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif if (heap->size >= ARRAYMAXINDEXSIZE(heap)) return false; assert(heap->size); // post("->addheap\n"); // dumpheap(heapArg); /* parent and sibling in the heap, not in the task hierarchy */ int mom = heap->size - 1; PyrSlot * pme = heap->slots + mom; int stabilityCount = slotRawInt(&heap->count); SetRaw(&heap->count, stabilityCount + 1); for (; mom>0;) { /* percolate up heap */ int newMom = ((mom - 3) / 2); mom = newMom - newMom % 3; /// LATER: we could avoid the division by using 4 slots per element PyrSlot * pmom = heap->slots + mom; if (schedtime < slotRawFloat(pmom)) { assert(slotRawInt(pmom + 2) < stabilityCount); slotCopy(&pme[0], &pmom[0]); slotCopy(&pme[1], &pmom[1]); slotCopy(&pme[2], &pmom[2]); pme = pmom; } else break; } SetFloat(&pme[0], schedtime); slotCopy(&pme[1], task); SetInt(&pme[2], stabilityCount); g->gc->GCWrite(heap, task); heap->size += 3; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif // dumpheap(heapArg); // post("<-addheap %g\n", schedtime); return true; } bool lookheap(PyrObject *heap, double *schedtime, PyrSlot *task) { if (heap->size > 1) { *schedtime = slotRawFloat(&heap->slots[0]); slotCopy(task, &heap->slots[1]); return true; } else return false; } bool getheap(VMGlobals *g, PyrObject *heapArg, double *schedtime, PyrSlot *task) { PyrHeap * heap = (PyrHeap*)heapArg; PyrGC* gc = g->gc; bool isPartialScanObj = gc->IsPartialScanObject(heapArg); assert(heap->size); // post("->getheap\n"); // dumpheap(heapArg); if (heap->size>1) { *schedtime = slotRawFloat(&heap->slots[0]); slotCopy(task, &heap->slots[1]); heap->size -= 3; int size = heap->size - 1; slotCopy(&heap->slots[0], &heap->slots[size]); slotCopy(&heap->slots[1], &heap->slots[size+1]); slotCopy(&heap->slots[2], &heap->slots[size+2]); /* parent and sibling in the heap, not in the task hierarchy */ int mom = 0; int me = 3; PyrSlot * pmom = heap->slots + mom; PyrSlot * pme = heap->slots + me; PyrSlot * pend = heap->slots + size; double timetemp = slotRawFloat(&pmom[0]); int stabilityCountTemp = slotRawInt(&pmom[2]); PyrSlot tasktemp; slotCopy(&tasktemp, &pmom[1]); for (;pme < pend;) { /* demote heap */ if (pme+3 < pend && ((slotRawFloat(&pme[0]) > slotRawFloat(&pme[3])) || ((slotRawFloat(&pme[0]) == slotRawFloat(&pme[3])) && (slotRawInt(&pme[2]) > slotRawInt(&pme[5])) ))) { me += 3; pme += 3; } if (timetemp > slotRawFloat(&pme[0]) || (timetemp == slotRawFloat(&pme[0]) && stabilityCountTemp > slotRawInt(&pme[2]))) { slotCopy(&pmom[0], &pme[0]); slotCopy(&pmom[1], &pme[1]); slotCopy(&pmom[2], &pme[2]); if (isPartialScanObj) { gc->GCWriteBlack(pmom+1); } pmom = pme; me = ((mom = me) * 2) + 3; pme = heap->slots + me; } else break; } SetRaw(&pmom[0], timetemp); slotCopy(&pmom[1], &tasktemp); SetRaw(&pmom[2], stabilityCountTemp); if (isPartialScanObj) gc->GCWriteBlack(pmom+1); if (size == 0) SetInt(&heap->count, 0); // dumpheap(heapArg); // post("<-getheap true\n"); return true; } else { // post("<-getheap false\n"); return false; } } void offsetheap(VMGlobals *g, PyrObject *heap, double offset) { long i; for (i=0; isize; i+=2) { SetRaw(&heap->slots[i], slotRawFloat(&heap->slots[i]) + offset); //post("%3d %9.2f %9.2f\n", i>>1, heap->slots[i].uf, offset); } } void dumpheap(PyrObject *heapArg) { PyrHeap * heap = (PyrHeap*)heapArg; double mintime = slotRawFloat(&heap->slots[0]); int count = slotRawFloat(&heap->slots[2]); int heapSize = heap->size - 1; post("SCHED QUEUE (%d)\n", heapSize); for (int i=0; islots[i]), slotRawObject(&heap->slots[i+1]), slotRawInt(&heap->slots[i+2])); if ((slotRawFloat(&heap->slots[i]) < mintime) || (slotRawFloat(&heap->slots[i]) == mintime && slotRawInt(&heap->slots[i+2]) < count ) ) post("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); } } bool gRunSched = false; pthread_t gSchedThread; pthread_t gResyncThread; pthread_cond_t gSchedCond; pthread_mutex_t gLangMutex; #ifdef SC_DARWIN int64 gHostOSCoffset = 0; int64 gHostStartNanos = 0; #endif int64 gElapsedOSCoffset = 0; const int32 kSECONDS_FROM_1900_to_1970 = (int32)2208988800UL; /* 17 leap years */ const double fSECONDS_FROM_1900_to_1970 = 2208988800.; /* 17 leap years */ #ifdef SC_DARWIN static void syncOSCOffsetWithTimeOfDay(); void* resyncThread(void* arg); #else // !SC_DARWIN #ifdef SC_WIN32 #else # include #endif inline double GetTimeOfDay(); double GetTimeOfDay() { struct timeval tv; gettimeofday(&tv, 0); return (double)tv.tv_sec + 1.0e-6 * (double)tv.tv_usec; } #endif // SC_DARWIN SC_DLLEXPORT_C void schedInit() { pthread_cond_init (&gSchedCond, NULL); pthread_mutex_init (&gLangMutex, NULL); #ifdef SC_DARWIN syncOSCOffsetWithTimeOfDay(); pthread_create (&gResyncThread, NULL, resyncThread, (void*)0); gHostStartNanos = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); gElapsedOSCoffset = (int64)(gHostStartNanos * kNanosToOSC) + gHostOSCoffset; #else gElapsedOSCoffset = (int64)kSECONDS_FROM_1900_to_1970 << 32; #endif } SC_DLLEXPORT_C void schedCleanup() { pthread_mutex_destroy (&gLangMutex); pthread_cond_destroy (&gSchedCond); } double bootSeconds(); double bootSeconds() { #ifdef SC_DARWIN return 1e-9 * (double)AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); #else return GetTimeOfDay(); #endif } double elapsedTime(); double elapsedTime() { #ifdef SC_DARWIN return 1e-9 * (double)(AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()) - gHostStartNanos); #else return GetTimeOfDay(); #endif } int64 ElapsedTimeToOSC(double elapsed) { return (int64)(elapsed * kSecondsToOSC) + gElapsedOSCoffset; } double OSCToElapsedTime(int64 oscTime) { return (double)(oscTime - gElapsedOSCoffset) * kOSCtoSecs; } void ElapsedTimeToTimespec(double elapsed, struct timespec *spec); void ElapsedTimeToTimespec(double elapsed, struct timespec *spec) { int64 oscTime = ElapsedTimeToOSC(elapsed); spec->tv_sec = (time_t)((oscTime >> 32) - kSECONDS_FROM_1900_to_1970); spec->tv_nsec = (int32)((oscTime & 0xFFFFFFFF) * kOSCtoNanos); } int64 OSCTime() { return ElapsedTimeToOSC(elapsedTime()); } #ifdef SC_DARWIN void syncOSCOffsetWithTimeOfDay() { // generate a value gHostOSCoffset such that // (gHostOSCoffset + systemTimeInOSCunits) // is equal to gettimeofday time in OSCunits. // Then if this machine is synced via NTP, we are synced with the world. // more accurate way to do this?? struct timeval tv; int64 systemTimeBefore, systemTimeAfter, diff; int64 minDiff = 0x7fffFFFFffffFFFFLL; // take best of several tries const int numberOfTries = 8; int64 newOffset = gHostOSCoffset; for (int i=0; isize > 1 ? slotRawFloat(inQueue->slots + 1) : -1e10; bool added = addheap(g, inQueue, inSeconds, inTask); if (!added) post("scheduler queue is full.\n"); else { if (isKindOfSlot(inTask, class_thread)) { SetFloat(&slotRawThread(inTask)->nextBeat, inSeconds); } if (slotRawFloat(inQueue->slots + 1) != prevTime) { //post("pthread_cond_signal\n"); pthread_cond_signal (&gSchedCond); } } } void doubleToTimespec(double secs, struct timespec *spec); void doubleToTimespec(double secs, struct timespec *spec) { double isecs = floor(secs); spec->tv_sec = (long)isecs; spec->tv_nsec = (long)floor(1000000000. * (secs - isecs)); } SC_DLLEXPORT_C void schedStop() { //printf("->schedStop\n"); pthread_mutex_lock (&gLangMutex); if (gRunSched) { gRunSched = false; pthread_cond_signal (&gSchedCond); pthread_mutex_unlock (&gLangMutex); pthread_join(gSchedThread, 0); } else { pthread_mutex_unlock (&gLangMutex); } //printf("<-schedStop\n"); } void schedClearUnsafe(); SC_DLLEXPORT_C void schedClear() { pthread_mutex_lock (&gLangMutex); schedClearUnsafe(); pthread_mutex_unlock (&gLangMutex); } void schedClearUnsafe() { //postfl("->schedClear %d\n", gRunSched); if (gRunSched) { VMGlobals *g = gMainVMGlobals; PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); inQueue->size = 1; pthread_cond_signal (&gSchedCond); //pthread_mutex_unlock (&gLangMutex); } //postfl("<-schedClear %d\n", gRunSched); } void post(const char *fmt, ...); #ifdef SC_DARWIN void* resyncThread(void* arg) { while (true) { sleep(20); syncOSCOffsetWithTimeOfDay(); gElapsedOSCoffset = (int64)(gHostStartNanos * kNanosToOSC) + gHostOSCoffset; } return 0; } #endif extern bool gTraceInterpreter; void* schedRunFunc(void* arg); void* schedRunFunc(void* arg) { pthread_mutex_lock (&gLangMutex); VMGlobals *g = gMainVMGlobals; PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); //dumpObject(inQueue); gRunSched = true; while (true) { assert(inQueue->size); //postfl("wait until there is something in scheduler\n"); // wait until there is something in scheduler while (inQueue->size == 1) { //postfl("wait until there is something in scheduler\n"); pthread_cond_wait (&gSchedCond, &gLangMutex); if (!gRunSched) goto leave; } //postfl("wait until an event is ready\n"); // wait until an event is ready double elapsed; do { elapsed = elapsedTime(); if (elapsed >= slotRawFloat(inQueue->slots + 1)) break; struct timespec abstime; //doubleToTimespec(inQueue->slots->uf, &abstime); ElapsedTimeToTimespec(slotRawFloat(inQueue->slots + 1), &abstime); //postfl("wait until an event is ready\n"); pthread_cond_timedwait (&gSchedCond, &gLangMutex, &abstime); if (!gRunSched) goto leave; //postfl("time diff %g\n", elapsedTime() - inQueue->slots->uf); } while (inQueue->size > 1); //postfl("perform all events that are ready %d %.9f\n", inQueue->size, elapsed); // perform all events that are ready //postfl("perform all events that are ready\n"); while ((inQueue->size > 1) && elapsed >= slotRawFloat(inQueue->slots + 1)) { double schedtime, delta; PyrSlot task; //postfl("while %.6f >= %.6f\n", elapsed, inQueue->slots->uf); getheap(g, inQueue, &schedtime, &task); if (isKindOfSlot(&task, class_thread)) { SetNil(&slotRawThread(&task)->nextBeat); } slotCopy((++g->sp), &task); SetFloat(++g->sp, schedtime); SetFloat(++g->sp, schedtime); ++g->sp; SetObject(g->sp, s_systemclock->u.classobj); runAwakeMessage(g); long err = slotDoubleVal(&g->result, &delta); if (!err) { // add delta time and reschedule double time = schedtime + delta; schedAdd(g, inQueue, time, &task); } } //postfl("loop\n"); } //postfl("exitloop\n"); leave: pthread_mutex_unlock (&gLangMutex); return 0; } #ifdef SC_DARWIN #include #include //Polls a (non-realtime) thread to find out how it is scheduled //Results are undefined of an error is returned. Otherwise, the //priority is returned in the address pointed to by the priority //parameter, and whether or not the thread uses timeshare scheduling //is returned at the address pointed to by the isTimeShare parameter kern_return_t GetStdThreadSchedule( mach_port_t machThread, int *priority, boolean_t *isTimeshare ) { kern_return_t result = 0; thread_extended_policy_data_t timeShareData; thread_precedence_policy_data_t precedenceData; mach_msg_type_number_t structItemCount; boolean_t fetchDefaults = false; memset( &timeShareData, 0, sizeof( thread_extended_policy_data_t )); memset( &precedenceData, 0, sizeof( thread_precedence_policy_data_t )); if( 0 == machThread ) machThread = mach_thread_self(); if( NULL != isTimeshare ) { structItemCount = THREAD_EXTENDED_POLICY_COUNT; result = thread_policy_get( machThread, THREAD_EXTENDED_POLICY, (integer_t*)&timeShareData, &structItemCount, &fetchDefaults ); *isTimeshare = timeShareData.timeshare; if( 0 != result ) return result; } if( NULL != priority ) { fetchDefaults = false; structItemCount = THREAD_PRECEDENCE_POLICY_COUNT; result = thread_policy_get( machThread, THREAD_PRECEDENCE_POLICY, (integer_t*)&precedenceData, &structItemCount, &fetchDefaults ); *priority = precedenceData.importance; } return result; } // Reschedules the indicated thread according to new parameters: // // machThread The mach thread id. Pass 0 for the current thread. // newPriority The desired priority. // isTimeShare false for round robin (fixed) priority, // true for timeshare (normal) priority // // A standard new thread usually has a priority of 0 and uses the // timeshare scheduling scheme. Use pthread_mach_thread_np() to // to convert a pthread id to a mach thread id kern_return_t RescheduleStdThread( mach_port_t machThread, int newPriority, boolean_t isTimeshare ) { kern_return_t result = 0; thread_extended_policy_data_t timeShareData; thread_precedence_policy_data_t precedenceData; //Set up some variables that we need for the task precedenceData.importance = newPriority; timeShareData.timeshare = isTimeshare; if( 0 == machThread ) machThread = mach_thread_self(); //Set the scheduling flavor. We want to do this first, since doing so //can alter the priority result = thread_policy_set( machThread, THREAD_EXTENDED_POLICY, (integer_t*)&timeShareData, THREAD_EXTENDED_POLICY_COUNT ); if( 0 != result ) return result; //Now set the priority return thread_policy_set( machThread, THREAD_PRECEDENCE_POLICY, (integer_t*)&precedenceData, THREAD_PRECEDENCE_POLICY_COUNT ); } #endif // SC_DARWIN #ifdef __linux__ #include static void SC_LinuxSetRealtimePriority(pthread_t thread, int priority) { int policy; struct sched_param param; pthread_getschedparam(thread, &policy, ¶m); policy = SCHED_FIFO; const int minprio = sched_get_priority_min(policy); const int maxprio = sched_get_priority_max(policy); param.sched_priority = sc_clip(priority, minprio, maxprio); int err = pthread_setschedparam(thread, policy, ¶m); if (err != 0) { post("Couldn't set realtime scheduling priority %d: %s\n", param.sched_priority, strerror(err)); } } #endif // __linux__ SC_DLLEXPORT_C void schedRun() { pthread_create (&gSchedThread, NULL, schedRunFunc, (void*)0); #ifdef SC_DARWIN int policy; struct sched_param param; //pthread_t thread = pthread_self (); pthread_getschedparam (gSchedThread, &policy, ¶m); //post("param.sched_priority %d\n", param.sched_priority); policy = SCHED_RR; // round-robin, AKA real-time scheduling int machprio; boolean_t timeshare; GetStdThreadSchedule(pthread_mach_thread_np(gSchedThread), &machprio, ×hare); //post("mach priority %d timeshare %d\n", machprio, timeshare); // what priority should gSchedThread use? RescheduleStdThread(pthread_mach_thread_np(gSchedThread), 62, false); GetStdThreadSchedule(pthread_mach_thread_np(gSchedThread), &machprio, ×hare); //post("mach priority %d timeshare %d\n", machprio, timeshare); //param.sched_priority = 70; // you'll have to play with this to see what it does //pthread_setschedparam (gSchedThread, policy, ¶m); pthread_getschedparam (gSchedThread, &policy, ¶m); //post("param.sched_priority %d\n", param.sched_priority); #endif // SC_DARWIN #ifdef __linux__ SC_LinuxSetRealtimePriority(gSchedThread, 1); #endif // __linux__ } /* unscheduled events: startup, receive OSC, mouse, keyboard, MIDI all these happen in the main thread. */ /* new clock: create destroy wake up at time x. unschedule awake reschedules. */ class TempoClock { public: TempoClock(VMGlobals *inVMGlobals, PyrObject* inTempoClockObj, double inTempo, double inBaseBeats, double inBaseSeconds); ~TempoClock() {} void StopReq(); void Stop(); void* Run(); void Add(double inBeats, PyrSlot* inTask); void SetTempoAtBeat(double inTempo, double inBeats); void SetTempoAtTime(double inTempo, double inSeconds); void SetAll(double inTempo, double inBeats, double inSeconds); double ElapsedBeats(); void Clear(); //void Flush(); double GetTempo() const { return mTempo; } double GetBeatDur() const { return mBeatDur; } double BeatsToSecs(double beats) const { return (beats - mBaseBeats) * mBeatDur + mBaseSeconds; } double SecsToBeats(double secs) const { return (secs - mBaseSeconds) * mTempo + mBaseBeats; } void Dump(); //protected: VMGlobals* g; PyrObject* mTempoClockObj; PyrHeap* mQueue; double mTempo; // beats per second double mBeatDur; // 1/tempo double mBeats; // beats double mBaseSeconds; double mBaseBeats; volatile bool mRun; pthread_t mThread; pthread_cond_t mCondition; TempoClock *mPrev, *mNext; static TempoClock *sAll; }; TempoClock *TempoClock::sAll = 0; void* TempoClock_run_func(void* p) { TempoClock* clock = (TempoClock*)p; return clock->Run(); } void* TempoClock_stop_func(void* p) { //printf("->TempoClock_stop_func\n"); TempoClock* clock = (TempoClock*)p; clock->Stop(); //printf("delete\n"); delete clock; //printf("<-TempoClock_stop_func\n"); return 0; } void TempoClock_stopAll(void) { //printf("->TempoClock_stopAll %p\n", TempoClock::sAll); TempoClock *clock = TempoClock::sAll; while (clock) { TempoClock* next = clock->mNext; clock->Stop(); //printf("delete\n"); delete clock; clock = next; } //printf("<-TempoClock_stopAll %p\n", TempoClock::sAll); TempoClock::sAll = 0; } TempoClock::TempoClock(VMGlobals *inVMGlobals, PyrObject* inTempoClockObj, double inTempo, double inBaseBeats, double inBaseSeconds) : g(inVMGlobals), mTempoClockObj(inTempoClockObj), mTempo(inTempo), mBeatDur(1./inTempo), mBaseSeconds(inBaseSeconds), mBaseBeats(inBaseBeats), mRun(true), mPrev(0), mNext(sAll) { if (sAll) sAll->mPrev = this; sAll = this; mQueue = (PyrHeap*)slotRawObject(&mTempoClockObj->slots[0]); mQueue->size = 1; SetInt(&mQueue->count, 0); pthread_cond_init (&mCondition, NULL); int err = pthread_create (&mThread, NULL, TempoClock_run_func, (void*)this); if (err) { post("Couldn't start thread for TempoClock: %s\n", strerror(err)); return; } #ifdef SC_DARWIN int machprio; boolean_t timeshare; GetStdThreadSchedule(pthread_mach_thread_np(mThread), &machprio, ×hare); //post("mach priority %d timeshare %d\n", machprio, timeshare); // what priority should gSchedThread use? RescheduleStdThread(pthread_mach_thread_np(mThread), 10, false); GetStdThreadSchedule(pthread_mach_thread_np(mThread), &machprio, ×hare); //post("mach priority %d timeshare %d\n", machprio, timeshare); //param.sched_priority = 70; // you'll have to play with this to see what it does //pthread_setschedparam (mThread, policy, ¶m); #endif // SC_DARWIN #ifdef __linux__ SC_LinuxSetRealtimePriority(mThread, 1); #endif // __linux__ } void TempoClock::StopReq() { //printf("->TempoClock::StopReq\n"); pthread_t stopThread; pthread_create (&stopThread, NULL, TempoClock_stop_func, (void*)this); pthread_detach(stopThread); //printf("<-TempoClock::StopReq\n"); } void TempoClock::Stop() { //printf("->TempoClock::Stop\n"); pthread_mutex_lock (&gLangMutex); //printf("Stop mRun %d\n", mRun); if (mRun) { mRun = false; // unlink if (mPrev) mPrev->mNext = mNext; else sAll = mNext; if (mNext) mNext->mPrev = mPrev; //printf("Stop pthread_cond_signal\n"); pthread_cond_signal (&mCondition); //printf("Stop pthread_mutex_unlock\n"); pthread_mutex_unlock (&gLangMutex); //printf("Stop pthread_join\n"); pthread_join(mThread, 0); } else { pthread_mutex_unlock (&gLangMutex); } //printf("Stop pthread_cond_destroy\n"); pthread_cond_destroy (&mCondition); //printf("<-TempoClock::Stop\n"); } void TempoClock::SetAll(double inTempo, double inBeats, double inSeconds) { mBaseSeconds = inSeconds; mBaseBeats = inBeats; mTempo = inTempo; mBeatDur = 1. / mTempo; pthread_cond_signal (&mCondition); } void TempoClock::SetTempoAtBeat(double inTempo, double inBeats) { mBaseSeconds = BeatsToSecs(inBeats); mBaseBeats = inBeats; mTempo = inTempo; mBeatDur = 1. / mTempo; pthread_cond_signal (&mCondition); } void TempoClock::SetTempoAtTime(double inTempo, double inSeconds) { mBaseBeats = SecsToBeats(inSeconds); mBaseSeconds = inSeconds; mTempo = inTempo; mBeatDur = 1. / mTempo; pthread_cond_signal (&mCondition); } double TempoClock::ElapsedBeats() { return SecsToBeats(elapsedTime()); } void* TempoClock::Run() { //printf("->TempoClock::Run\n"); pthread_mutex_lock (&gLangMutex); while (mRun) { assert(mQueue->size); //printf("tempo %g dur %g beats %g\n", mTempo, mBeatDur, mBeats); //printf("wait until there is something in scheduler\n"); // wait until there is something in scheduler while (mQueue->size == 1) { //printf("wait until there is something in scheduler\n"); pthread_cond_wait (&mCondition, &gLangMutex); //printf("mRun a %d\n", mRun); if (!mRun) goto leave; } //printf("wait until an event is ready\n"); // wait until an event is ready double elapsedBeats; do { elapsedBeats = ElapsedBeats(); if (elapsedBeats >= slotRawFloat(mQueue->slots)) break; struct timespec abstime; //doubleToTimespec(mQueue->slots->uf, &abstime); //printf("event ready at %g . elapsed beats %g\n", mQueue->slots->uf, elapsedBeats); double wakeTime = BeatsToSecs(slotRawFloat(mQueue->slots)); ElapsedTimeToTimespec(wakeTime, &abstime); //printf("wait until an event is ready. wake %g now %g\n", wakeTime, elapsedTime()); pthread_cond_timedwait (&mCondition, &gLangMutex, &abstime); //printf("mRun b %d\n", mRun); if (!mRun) goto leave; //printf("time diff %g\n", elapsedTime() - mQueue->slots->uf); } while (mQueue->size > 1); //printf("perform all events that are ready %d %.9f\n", mQueue->size, elapsedBeats); // perform all events that are ready //printf("perform all events that are ready\n"); while (mQueue->size > 1 && elapsedBeats >= slotRawFloat(mQueue->slots)) { double delta; PyrSlot task; //printf("while %.6f >= %.6f\n", elapsedBeats, mQueue->slots->uf); getheap(g, (PyrObject*)mQueue, &mBeats, &task); if (isKindOfSlot(&task, class_thread)) { SetNil(&slotRawThread(&task)->nextBeat); } slotCopy((++g->sp), &task); SetFloat(++g->sp, mBeats); SetFloat(++g->sp, BeatsToSecs(mBeats)); ++g->sp; SetObject(g->sp, mTempoClockObj); runAwakeMessage(g); long err = slotDoubleVal(&g->result, &delta); if (!err) { // add delta time and reschedule double beats = mBeats + delta; Add(beats, &task); } } } leave: //printf("<-TempoClock::Run\n"); pthread_mutex_unlock (&gLangMutex); return 0; } /* void TempoClock::Flush() { while (mQueue->size && elapsedBeats >= mQueue->slots->uf) { double delta; PyrSlot task; //printf("while %.6f >= %.6f\n", elapsedBeats, mQueue->slots->uf); getheap(g, mQueue, &mBeats, &task); slotCopy((++g->sp), &task); (++g->sp)->uf = mBeats; (++g->sp)->uf = BeatsToSecs(mBeats); ++g->sp; SetObject(g->sp, mTempoClockObj); runAwakeMessage(g); long err = slotDoubleVal(&g->result, &delta); if (!err) { // add delta time and reschedule double beats = mBeats + delta; Add(beats, &task); } } } */ void TempoClock::Add(double inBeats, PyrSlot* inTask) { double prevBeats = mQueue->size > 1 ? slotRawFloat(mQueue->slots) : -1e10; bool added = addheap(g, (PyrObject*)mQueue, inBeats, inTask); if (!added) post("scheduler queue is full.\n"); else { if (isKindOfSlot(inTask, class_thread)) { SetFloat(&slotRawThread(inTask)->nextBeat, inBeats); } if (slotRawFloat(mQueue->slots) != prevBeats) { pthread_cond_signal (&mCondition); } } } void TempoClock::Clear() { if (mRun) { mQueue->size = 1; pthread_cond_signal (&mCondition); } } void TempoClock::Dump() { post("mTempo %g\n", mTempo); post("mBeatDur %g\n", mBeatDur); post("mBeats %g\n", mBeats); post("seconds %g\n", BeatsToSecs(mBeats)); post("mBaseSeconds %g\n", mBaseSeconds); post("mBaseBeats %g\n", mBaseBeats); } int prTempoClock_New(struct VMGlobals *g, int numArgsPushed); int prTempoClock_New(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 3; PyrSlot *b = g->sp - 2; PyrSlot *c = g->sp - 1; PyrSlot *d = g->sp; double tempo; int err = slotDoubleVal(b, &tempo); if (err) tempo = 1.; if (tempo <= 0.) { error("invalid tempo %g\n", tempo); SetPtr(slotRawObject(a)->slots+1, NULL); return errFailed; } double beats; err = slotDoubleVal(c, &beats); if (err) beats = 0.; double seconds; err = slotDoubleVal(d, &seconds); if (err) seconds = elapsedTime(); TempoClock* clock = new TempoClock(g, slotRawObject(a), tempo, beats, seconds); SetPtr(slotRawObject(a)->slots+1, clock); return errNone; } int prTempoClock_Free(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Free(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) return errNone; // not running SetNil(slotRawObject(a)->slots + 1); clock->StopReq(); return errNone; } int prTempoClock_Clear(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Clear(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (clock) clock->Clear(); return errNone; } int prTempoClock_Dump(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Dump(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (clock) clock->Dump(); return errNone; } int prTempoClock_Tempo(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Tempo(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } SetFloat(a, clock->mTempo); return errNone; } int prTempoClock_BeatDur(struct VMGlobals *g, int numArgsPushed); int prTempoClock_BeatDur(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } SetFloat(a, clock->mBeatDur); return errNone; } int prTempoClock_ElapsedBeats(struct VMGlobals *g, int numArgsPushed); int prTempoClock_ElapsedBeats(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } SetFloat(a, clock->ElapsedBeats()); return errNone; } int prTempoClock_Beats(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Beats(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; double beats, seconds; if (SlotEq(&g->thread->clock, a)) { int err = slotDoubleVal(&g->thread->beats, &beats); if (err) return errWrongType; } else { TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } int err = slotDoubleVal(&g->thread->seconds, &seconds); if (err) return errWrongType; beats = clock->SecsToBeats(seconds); } SetFloat(a, beats); return errNone; } int prTempoClock_Sched(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Sched(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; double delta, beats; int err; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } if (!SlotEq(&g->thread->clock, a)) { beats = clock->ElapsedBeats(); //post("shouldn't call TempoClock-sched from a different clock. Use schedAbs.\n"); //return errFailed; } else { err = slotDoubleVal(&g->thread->beats, &beats); if (err) return errNone; // return nil OK, just don't schedule } err = slotDoubleVal(b, &delta); if (err) return errNone; // return nil OK, just don't schedule beats += delta; if (beats == dInfinity) return errNone; // return nil OK, just don't schedule clock->Add(beats, c); return errNone; } int prTempoClock_SchedAbs(struct VMGlobals *g, int numArgsPushed); int prTempoClock_SchedAbs(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double beats; int err = slotDoubleVal(b, &beats) || (beats == dInfinity); if (err) return errNone; // return nil OK, just don't schedule clock->Add(beats, c); return errNone; } int prTempoClock_SetTempoAtBeat(struct VMGlobals *g, int numArgsPushed); int prTempoClock_SetTempoAtBeat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double tempo, beat; int err = slotDoubleVal(b, &tempo); if (err) return errFailed; if (tempo <= 0.) { error("invalid tempo %g\n", tempo); return errFailed; } err = slotDoubleVal(c, &beat); if (err) return errFailed; clock->SetTempoAtBeat(tempo, beat); return errNone; } int prTempoClock_SetAll(struct VMGlobals *g, int numArgsPushed); int prTempoClock_SetAll(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 3; PyrSlot *b = g->sp - 2; PyrSlot *c = g->sp - 1; PyrSlot *d = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double tempo, beat, secs; int err = slotDoubleVal(b, &tempo); if (err) return errFailed; err = slotDoubleVal(c, &beat); if (err) return errFailed; err = slotDoubleVal(d, &secs); if (err) return errFailed; clock->SetAll(tempo, beat, secs); return errNone; } int prTempoClock_SetTempoAtTime(struct VMGlobals *g, int numArgsPushed); int prTempoClock_SetTempoAtTime(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double tempo, sec; int err = slotDoubleVal(b, &tempo); if (err) return errFailed; err = slotDoubleVal(c, &sec); if (err) return errFailed; clock->SetTempoAtTime(tempo, sec); return errNone; } int prTempoClock_BeatsToSecs(struct VMGlobals *g, int numArgsPushed); int prTempoClock_BeatsToSecs(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double beats; int err = slotDoubleVal(b, &beats); if (err) return errFailed; SetFloat(a, clock->BeatsToSecs(beats)); return errNone; } int prTempoClock_SecsToBeats(struct VMGlobals *g, int numArgsPushed); int prTempoClock_SecsToBeats(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double secs; int err = slotDoubleVal(b, &secs); if (err) return errFailed; SetFloat(a, clock->SecsToBeats(secs)); return errNone; } int prSystemClock_Clear(struct VMGlobals *g, int numArgsPushed); int prSystemClock_Clear(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp; schedClearUnsafe(); return errNone; } int prSystemClock_Sched(struct VMGlobals *g, int numArgsPushed); int prSystemClock_Sched(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; double delta, seconds; int err = slotDoubleVal(b, &delta); if (err) return errNone; // return nil OK, just don't schedule err = slotDoubleVal(&g->thread->seconds, &seconds); if (err) return errNone; // return nil OK, just don't schedule seconds += delta; if (seconds == dInfinity) return errNone; // return nil OK, just don't schedule PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); schedAdd(g, inQueue, seconds, c); return errNone; } int prSystemClock_SchedAbs(struct VMGlobals *g, int numArgsPushed); int prSystemClock_SchedAbs(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; double time; int err = slotDoubleVal(b, &time) || (time == dInfinity); if (err) return errNone; // return nil OK, just don't schedule PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); schedAdd(g, inQueue, time, c); return errNone; } int prElapsedTime(struct VMGlobals *g, int numArgsPushed); int prElapsedTime(struct VMGlobals *g, int numArgsPushed) { SetFloat(g->sp, elapsedTime()); return errNone; } void initSchedPrimitives() { int base, index=0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_TempoClock_New", prTempoClock_New, 4, 0); definePrimitive(base, index++, "_TempoClock_Free", prTempoClock_Free, 1, 0); definePrimitive(base, index++, "_TempoClock_Clear", prTempoClock_Clear, 1, 0); definePrimitive(base, index++, "_TempoClock_Dump", prTempoClock_Dump, 1, 0); definePrimitive(base, index++, "_TempoClock_Sched", prTempoClock_Sched, 3, 0); definePrimitive(base, index++, "_TempoClock_SchedAbs", prTempoClock_SchedAbs, 3, 0); definePrimitive(base, index++, "_TempoClock_Tempo", prTempoClock_Tempo, 1, 0); definePrimitive(base, index++, "_TempoClock_BeatDur", prTempoClock_BeatDur, 1, 0); definePrimitive(base, index++, "_TempoClock_ElapsedBeats", prTempoClock_ElapsedBeats, 1, 0); definePrimitive(base, index++, "_TempoClock_Beats", prTempoClock_Beats, 1, 0); definePrimitive(base, index++, "_TempoClock_SetTempoAtBeat", prTempoClock_SetTempoAtBeat, 3, 0); definePrimitive(base, index++, "_TempoClock_SetTempoAtTime", prTempoClock_SetTempoAtTime, 3, 0); definePrimitive(base, index++, "_TempoClock_SetAll", prTempoClock_SetAll, 4, 0); definePrimitive(base, index++, "_TempoClock_BeatsToSecs", prTempoClock_BeatsToSecs, 2, 0); definePrimitive(base, index++, "_TempoClock_SecsToBeats", prTempoClock_SecsToBeats, 2, 0); definePrimitive(base, index++, "_SystemClock_Clear", prSystemClock_Clear, 1, 0); definePrimitive(base, index++, "_SystemClock_Sched", prSystemClock_Sched, 3, 0); definePrimitive(base, index++, "_SystemClock_SchedAbs", prSystemClock_SchedAbs, 3, 0); definePrimitive(base, index++, "_ElapsedTime", prElapsedTime, 1, 0); } SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/SC_PortMIDI.cpp0000664000000000000000000004130512245365552025270 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* changes by jan trutzschler v. f. 9/9/2002 the midiReadProc calls doAction in the class MIDIIn. with the arguments: inUid, status, chan, val1, val2 added prDisposeMIDIClient added prRestartMIDI 19/9 call different actions,disconnect midiInPort, midiout: sendmidi 04/feb/03 prListMIDIEndpoints modification by Ron Kuivila added jt. */ #include "PortMIDI.h" #include "PortTime.h" #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #include // symbols to call back into lang PyrSymbol* s_domidiaction; PyrSymbol* s_midiNoteOnAction; PyrSymbol* s_midiNoteOffAction; PyrSymbol* s_midiTouchAction; PyrSymbol* s_midiControlAction; PyrSymbol* s_midiPolyTouchAction; PyrSymbol* s_midiProgramAction; PyrSymbol* s_midiBendAction; PyrSymbol* s_midiSysexAction; PyrSymbol* s_midiInvalidSysexAction; PyrSymbol* s_midiSysrtAction; PyrSymbol* s_midiSMPTEAction; PyrSymbol* s_midiin; PyrSymbol* s_numMIDIDev; PyrSymbol* s_midiclient; const int kMaxMidiPorts = 16; int gNumMIDIInPorts = 0, gNumMIDIOutPorts = 0; bool gMIDIInitialized = false; PmStream* gMIDIInStreams[kMaxMidiPorts]; PmStream* gMIDIOutStreams[kMaxMidiPorts]; std::map gMidiInputIndexToPmDevIndex; std::map gMidiOutputIndexToPmDevIndex; std::map gMidiPmDevIndexToInputIndex; std::map gMidiPmDevIndexToOutputIndex; pthread_mutex_t gPmStreamMutex; struct ScopeMutexLock { pthread_mutex_t* mutex_; ScopeMutexLock(pthread_mutex_t* mutex) : mutex_(mutex) { pthread_mutex_lock(mutex_); } ~ScopeMutexLock( ) { pthread_mutex_unlock(mutex_); } }; /* if INPUT_BUFFER_SIZE is 0, PortMidi uses a default value */ #define PMSTREAM_INPUT_BUFFER_SIZE 0 #define PMSTREAM_OUTPUT_BUFFER_SIZE 100 #define PMSTREAM_DRIVER_INFO NULL #define PMSTREAM_TIME_PROC NULL #define PMSTREAM_TIME_INFO NULL /* use zero latency because we want output to be immediate */ #define LATENCY 0 extern bool compiledOK; inline void TPmErr(PmError err) { if( err != pmNoError) throw err; } /* timer "interrupt" for processing midi data */ static void PMProcessMidi(PtTimestamp timestamp, void *userData) { ScopeMutexLock mulo(&gPmStreamMutex); PmError result; PmEvent buffer; /* just one message at a time */ for( int i = 0 ; i < gNumMIDIInPorts; ++i ) { int pmdid = gMidiInputIndexToPmDevIndex[i]; PmStream* midi_in = gMIDIInStreams[i]; if( midi_in ) { while(result = Pm_Poll(midi_in)) { long Tstatus, data1, data2; if (Pm_Read(midi_in, &buffer, 1) == pmBufferOverflow) continue; // unless there was overflow, we should have a message now Tstatus = Pm_MessageStatus(buffer.message); data1 = Pm_MessageData1(buffer.message); data2 = Pm_MessageData2(buffer.message); // +---------------------------------------------+ // | Lock the interp. mutex and dispatch message | // +---------------------------------------------+ pthread_mutex_lock (&gLangMutex); // it is needed -jamesmcc if (compiledOK) { VMGlobals *g = gMainVMGlobals; uint8 status = static_cast(Tstatus & 0xF0); uint8 chan = static_cast(Tstatus & 0x0F); g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // Set the class MIDIIn //set arguments: ++g->sp; SetInt(g->sp, pmdid); //src // ++g->sp; SetInt(g->sp, status); //status ++g->sp; SetInt(g->sp, chan); //chan //if(status & 0x80) // set the running status for voice messages //gRunningStatus = ((status >> 4) == 0xF) ? 0 : pkt->data[i]; // keep also additional info switch (status) { case 0x80 : //noteOff ++g->sp; SetInt(g->sp, data1); ++g->sp; SetInt(g->sp, data2); runInterpreter(g, s_midiNoteOffAction, 5); break; case 0x90 : //noteOn ++g->sp; SetInt(g->sp, data1); ++g->sp; SetInt(g->sp, data2); runInterpreter(g, data2 ? s_midiNoteOnAction : s_midiNoteOffAction, 5); break; case 0xA0 : //polytouch ++g->sp; SetInt(g->sp, data1); ++g->sp; SetInt(g->sp, data2); runInterpreter(g, s_midiPolyTouchAction, 5); break; case 0xB0 : //control ++g->sp; SetInt(g->sp, data1); ++g->sp; SetInt(g->sp, data2); runInterpreter(g, s_midiControlAction, 5); break; case 0xC0 : //program ++g->sp; SetInt(g->sp, data1); runInterpreter(g, s_midiProgramAction, 4); break; case 0xD0 : //touch ++g->sp; SetInt(g->sp, data1); runInterpreter(g, s_midiTouchAction, 4); break; case 0xE0 : //bend ++g->sp; SetInt(g->sp, (data2 << 7) | data1); runInterpreter(g, s_midiBendAction, 4); break; /*case 0xF0 : // only the first Pm_Event will carry the 0xF0 byte // sysex message will be terminated by the EOX status byte 0xF7 midiProcessSystemPacket(data1, data2, chan); break; default : // data byte => continuing sysex message if(gRunningStatus && !gSysexFlag) { // handle running status status = gRunningStatus & 0xF0; // accept running status only inside a packet beginning chan = gRunningStatus & 0x0F; // with a valid status byte SetInt(g->sp, chan); --i; //goto L; // parse again with running status set // mv - get next byte } chan = 0; i += midiProcessSystemPacket(pkt, chan); // process sysex packet break; */ } g->canCallOS = false; } pthread_mutex_unlock (&gLangMutex); } } // if (midi_in) } // for loop until numMIDIInPorts } /* ------------------------------------------------------------- */ void midiCleanUp(); int initMIDI() { try { midiCleanUp(); TPmErr(Pm_Initialize()); int nbDev = Pm_CountDevices(); int inIndex = 0; int outIndex = 0; int pmdid; for( int i = 0; i < nbDev ; ++i ) { const PmDeviceInfo* devInfo = Pm_GetDeviceInfo(i); if( devInfo->input ) { gNumMIDIInPorts++; gMidiInputIndexToPmDevIndex[inIndex++] = i; gMidiPmDevIndexToInputIndex[i] = inIndex; } if( devInfo->output ) { gNumMIDIOutPorts++; gMidiOutputIndexToPmDevIndex[outIndex++] = i; gMidiPmDevIndexToOutputIndex[i] = outIndex; } } for( int i = 0; i < gNumMIDIOutPorts; i++) { pmdid = gMidiOutputIndexToPmDevIndex[i]; Pm_OpenOutput(&gMIDIOutStreams[i], pmdid, NULL, 512, NULL, NULL, 0); } /* will call our function, PMProcessMidi() every millisecond */ Pt_Start(1, &PMProcessMidi, 0); /* start a timer with millisecond accuracy */ } catch(PmError) { return errFailed; } gMIDIInitialized = true; return errNone; } /* ------------------------------------------------------------- */ void midiCleanUp() { ScopeMutexLock mulo(&gPmStreamMutex); if(gMIDIInitialized) { for (int i=0; isp; int numSrc = gNumMIDIInPorts; int numDst = gNumMIDIOutPorts; PyrObject* idarray = newPyrArray(g->gc, 6 * sizeof(PyrObject), 0 , true); SetObject(a, idarray); // 0 PyrObject* idarraySo = newPyrArray(g->gc, numSrc * sizeof(__int32), 0 , true); SetObject(idarray->slots+idarray->size++, idarraySo); g->gc->GCWrite(idarray, idarraySo); // 1 PyrObject* devarraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarraySo); g->gc->GCWrite(idarray, devarraySo); // 2 PyrObject* namearraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearraySo); g->gc->GCWrite(idarray, namearraySo); // 3 PyrObject* idarrayDe = newPyrArray(g->gc, numDst * sizeof(__int32), 0 , true); SetObject(idarray->slots+idarray->size++, idarrayDe); g->gc->GCWrite(idarray, idarrayDe); // 4 PyrObject* namearrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearrayDe); g->gc->GCWrite(idarray, namearrayDe); // 5 PyrObject* devarrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarrayDe); g->gc->GCWrite(idarray, devarrayDe); for (int i=0; iname,1023); cendname[1023] = 0; strncpy(cdevname,devInfo->name,1023); cdevname[1023] = 0; PyrString *string = newPyrString(g->gc, cendname, 0, true); SetObject(namearraySo->slots+i, string); namearraySo->size++; g->gc->GCWrite(namearraySo, (PyrObject*)string); PyrString *devstring = newPyrString(g->gc, cdevname, 0, true); SetObject(devarraySo->slots+i, devstring); devarraySo->size++; g->gc->GCWrite(devarraySo, (PyrObject*)devstring); SetInt(idarraySo->slots+i, i); idarraySo->size++; } // post("numDst %d\n", numDst); for (int i=0; iname,1023); cendname[1023] = 0; strncpy(cdevname,devInfo->name,1023); cdevname[1023] = 0; PyrString *string = newPyrString(g->gc, cendname, 0, true); SetObject(namearrayDe->slots+namearrayDe->size++, string); g->gc->GCWrite(namearrayDe, (PyrObject*)string); PyrString *devstring = newPyrString(g->gc, cdevname, 0, true); SetObject(devarrayDe->slots+devarrayDe->size++, devstring); g->gc->GCWrite(devarrayDe, (PyrObject*)devstring); SetInt(idarrayDe->slots+idarrayDe->size++, i); } return errNone; } /* ------------------------------------------------------------- */ int prConnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { ScopeMutexLock mulo(&gPmStreamMutex); //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return errWrongType; if (inputIndex < 0 || inputIndex >= gNumMIDIInPorts) return errIndexOutOfRange; err = slotIntVal(c, &uid); if (err) return errWrongType; PmStream* inStream = NULL; int pmdid = gMidiInputIndexToPmDevIndex[uid]; PmError pmerr = Pm_OpenInput( &inStream, pmdid, PMSTREAM_DRIVER_INFO, PMSTREAM_INPUT_BUFFER_SIZE, PMSTREAM_TIME_PROC, PMSTREAM_TIME_INFO ); if(pmerr != pmNoError) return errFailed; gMIDIInStreams[uid] = inStream; return errNone; } /* ------------------------------------------------------------- */ int prDisconnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { ScopeMutexLock mulo(&gPmStreamMutex); PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; if (inputIndex < 0 || inputIndex >= gNumMIDIInPorts) return errIndexOutOfRange; err = slotIntVal(c, &uid); if (err) return err; PmError pmerr = Pm_Close(gMIDIInStreams[uid]); if(pmerr != pmNoError) return errFailed; gMIDIInStreams[uid] = NULL; return errNone; } /* ------------------------------------------------------------- */ int prInitMIDI(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, numIn, numOut; err = slotIntVal(b, &numIn); if (err) return errWrongType; err = slotIntVal(c, &numOut); if (err) return errWrongType; return initMIDI(); } int prDisposeMIDIClient(VMGlobals *g, int numArgsPushed) { midiCleanUp(); return errNone; } int prRestartMIDI(VMGlobals *g, int numArgsPushed) { initMIDI(); return errNone; } /* void freeSysex(MIDISysexSendRequest* pk) { free(pk->data); free(pk); } */ int prSendSysex(VMGlobals *g, int numArgsPushed) { /* int err, uid, size; PyrInt8Array* packet = g->sp->uob; size = packet->size; Byte *data = (Byte *)malloc(size); memcpy(data,packet->b, size); PyrSlot *u = g->sp - 1; err = slotIntVal(u, &uid); if (err) return err; MIDIEndpointRef dest; MIDIObjectType mtype; MIDIObjectFindByUniqueID(uid, (MIDIObjectRef*)&dest, &mtype); if (mtype != kMIDIObjectType_Destination) return errFailed; if (!dest) return errFailed; sendsysex(dest, size, data); return errNone; */ return errFailed; } /* ------------------------------------------------------------- */ int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed) { ScopeMutexLock mulo(&gPmStreamMutex); //port, uid, len, hiStatus, loStatus, a, b, latency //PyrSlot *m = g->sp - 8; PyrSlot *p = g->sp - 7; PyrSlot *u = g->sp - 6; PyrSlot *l = g->sp - 5; PyrSlot *his = g->sp - 4; PyrSlot *los = g->sp - 3; PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *plat = g->sp; int err, outputIndex, uid, length, hiStatus, loStatus, aval, bval; float late; err = slotIntVal(p, &outputIndex); if (err) return err; if (outputIndex < 0 || outputIndex >= gNumMIDIOutPorts) return errIndexOutOfRange; err = slotIntVal(u, &uid); if (err) return err; err = slotIntVal(l, &length); if (err) return err; err = slotIntVal(his, &hiStatus); if (err) return err; err = slotIntVal(los, &loStatus); if (err) return err; err = slotIntVal(a, &aval); if (err) return err; err = slotIntVal(b, &bval); if (err) return err; err = slotFloatVal(plat, &late); if (err) return err; Pm_WriteShort(gMIDIOutStreams[uid], 0, Pm_Message((hiStatus & 0xF0) | (loStatus & 0x0F) , aval, bval)); return errNone; } // not needed in PortMIDI: int initMIDIClient() { return errNone; } int prInitMIDIClient(struct VMGlobals *g, int numArgsPushed) { return initMIDIClient(); } void initMIDIPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; s_midiin = getsym("MIDIIn"); s_domidiaction = getsym("doAction"); s_midiNoteOnAction = getsym("doNoteOnAction"); s_midiNoteOffAction = getsym("doNoteOffAction"); s_midiTouchAction = getsym("doTouchAction"); s_midiControlAction = getsym("doControlAction"); s_midiPolyTouchAction = getsym("doPolyTouchAction"); s_midiProgramAction = getsym("doProgramAction"); s_midiBendAction = getsym("doBendAction"); s_midiSysexAction = getsym("doSysexAction"); s_midiInvalidSysexAction = getsym("doInvalidSysexAction"); // client can handle incorrect case s_midiSysrtAction = getsym("doSysrtAction"); s_midiSMPTEAction = getsym("doSMPTEaction"); s_numMIDIDev = getsym("prSetNumberOfDevices"); s_midiclient = getsym("MIDIClient"); definePrimitive(base, index++, "_ListMIDIEndpoints", prListMIDIEndpoints, 1, 0); definePrimitive(base, index++, "_InitMIDI", prInitMIDI, 3, 0); definePrimitive(base, index++, "_InitMIDIClient", prInitMIDIClient, 1, 0); definePrimitive(base, index++, "_ConnectMIDIIn", prConnectMIDIIn, 3, 0); definePrimitive(base, index++, "_DisconnectMIDIIn", prDisconnectMIDIIn, 3, 0); definePrimitive(base, index++, "_DisposeMIDIClient", prDisposeMIDIClient, 1, 0); definePrimitive(base, index++, "_RestartMIDI", prRestartMIDI, 1, 0); definePrimitive(base, index++, "_SendMIDIOut", prSendMIDIOut, 9, 0); definePrimitive(base, index++, "_SendSysex", prSendSysex, 3, 0); pthread_mutex_init (&gPmStreamMutex, NULL); midiCleanUp(); } SuperCollider-3.6.6-Source-linux~repack/lang/LangPrimSource/PyrArrayPrimitives.cpp0000664000000000000000000017026712161364457027153 0ustar rootroot/* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for Arrays. */ #include "GC.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "SC_InlineBinaryOp.h" #include "SC_Constants.h" #include int basicSize(VMGlobals *g, int numArgsPushed); int basicMaxSize(VMGlobals *g, int numArgsPushed); int basicSwap(struct VMGlobals *g, int numArgsPushed); int basicAt(VMGlobals *g, int numArgsPushed); int basicRemoveAt(VMGlobals *g, int numArgsPushed); int basicClipAt(VMGlobals *g, int numArgsPushed); int basicWrapAt(VMGlobals *g, int numArgsPushed); int basicFoldAt(VMGlobals *g, int numArgsPushed); int basicPut(VMGlobals *g, int numArgsPushed); int basicClipPut(VMGlobals *g, int numArgsPushed); int basicWrapPut(VMGlobals *g, int numArgsPushed); int basicFoldPut(VMGlobals *g, int numArgsPushed); int prArrayAdd(VMGlobals *g, int numArgsPushed); int prArrayFill(VMGlobals *g, int numArgsPushed); int prArrayPop(VMGlobals *g, int numArgsPushed); int prArrayGrow(VMGlobals *g, int numArgsPushed); int prArrayCat(VMGlobals *g, int numArgsPushed); int prArrayReverse(VMGlobals *g, int numArgsPushed); int prArrayScramble(VMGlobals *g, int numArgsPushed); int prArrayRotate(VMGlobals *g, int numArgsPushed); int prArrayStutter(VMGlobals *g, int numArgsPushed); int prArrayMirror(VMGlobals *g, int numArgsPushed); int prArrayMirror1(VMGlobals *g, int numArgsPushed); int prArrayMirror2(VMGlobals *g, int numArgsPushed); int prArrayExtendWrap(VMGlobals *g, int numArgsPushed); int prArrayExtendFold(VMGlobals *g, int numArgsPushed); int prArrayPermute(VMGlobals *g, int numArgsPushed); int prArrayPyramid(VMGlobals *g, int numArgsPushed); int prArraySlide(VMGlobals *g, int numArgsPushed); int prArrayLace(VMGlobals *g, int numArgsPushed); int prArrayContainsSeqColl(VMGlobals *g, int numArgsPushed); int prArrayWIndex(VMGlobals *g, int numArgsPushed); int prArrayNormalizeSum(VMGlobals *g, int numArgsPushed); int prArrayIndexOfGreaterThan(VMGlobals *g, int numArgsPushed); int basicSize(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrObject *obj; a = g->sp; if (NotObj(a)) { SetInt(a, 0); return errNone; } obj = slotRawObject(a); SetInt(a, obj->size); return errNone; } int basicMaxSize(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrObject *obj; int maxsize; a = g->sp; if (NotObj(a)) { SetInt(a, 0); return errNone; } obj = slotRawObject(a); maxsize = MAXINDEXSIZE(obj); SetInt(a, maxsize); return errNone; } int basicSwap(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, tempi, tempj; int i, j; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(a)) return errWrongType; if (NotInt(b)) return errIndexNotAnInteger; if (NotInt(c)) return errIndexNotAnInteger; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; i = slotRawInt(b); j = slotRawInt(c); if (i < 0 || i >= obj->size) return errIndexOutOfRange; if (j < 0 || j >= obj->size) return errIndexOutOfRange; getIndexedSlot(obj, &tempi, i); getIndexedSlot(obj, &tempj, j); putIndexedSlot(g, obj, &tempi, j); putIndexedSlot(g, obj, &tempj, i); // in case it is partial scan obj g->gc->GCWrite(obj, &tempi); g->gc->GCWrite(obj, &tempj); return errNone; } int getIndexedInt(PyrObject *obj, int index, int *value); void DumpBackTrace(VMGlobals *g); int basicAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index; PyrObject *obj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; int err = slotIntVal(b, &index); if (!err) { if (index < 0 || index >= obj->size) { slotCopy(a,&o_nil); } else { getIndexedSlot(obj, a, index); } } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = indexArray->size; PyrObject *outArray = newPyrArray(g->gc, size, 0, true); PyrSlot *outArraySlots = outArray->slots; for (int i=0; i= obj->size) { slotCopy(&outArraySlots[i],&o_nil); } else { getIndexedSlot(obj, outArraySlots + i, index); } } outArray->size = size; SetObject(a, outArray); } else { return errIndexNotAnInteger; } return errNone; } int basicRemoveAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index, length, elemsize; PyrObject *obj; void *ptr; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (err) return errWrongType; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (index < 0 || index >= obj->size) return errIndexOutOfRange; switch (obj->obj_format) { default : case obj_slot : ptr = obj->slots + index; slotCopy(a, (PyrSlot*)ptr); break; case obj_double : ptr = obj->slots + index; SetFloat(a, *(double*)ptr); break; case obj_float : ptr = ((float*)(obj->slots)) + index; SetFloat(a, *(float*)ptr); break; case obj_int32 : ptr = ((int32*)(obj->slots)) + index; SetInt(a, *(int32*)ptr); break; case obj_int16 : ptr = ((int16*)(obj->slots)) + index; SetInt(a, *(int16*)ptr); break; case obj_int8 : ptr = ((int8*)(obj->slots)) + index; SetInt(a, *(int8*)ptr); break; case obj_symbol : ptr = ((int*)(obj->slots)) + index; SetSymbol(a, *(PyrSymbol**)ptr); break; case obj_char : ptr = ((unsigned char*)(obj->slots)) + index; SetChar(a, *(unsigned char*)ptr); break; } length = obj->size - index - 1; if (length > 0) { elemsize = gFormatElemSize[obj->obj_format]; memmove(ptr, (char*)ptr + elemsize, length * elemsize); if (obj->obj_format <= obj_slot) { // might be partial scan object g->gc->GCWrite(obj, obj->slots + index); } } obj->size -- ; return errNone; } int basicTakeAt(struct VMGlobals *g, int numArgsPushed); int basicTakeAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index, lastIndex; PyrObject *obj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (err) return errWrongType; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; lastIndex = obj->size - 1; if (index < 0 || index >= obj->size) return errIndexOutOfRange; switch (obj->obj_format) { case obj_slot : { PyrSlot* ptr = obj->slots + index; PyrSlot* lastptr = obj->slots + lastIndex; slotCopy(a, ptr); *ptr = *lastptr; // might be partial scan obj g->gc->GCWrite(obj, ptr); } break; case obj_double : { PyrSlot* ptr = obj->slots + index; PyrSlot* lastptr = obj->slots + lastIndex; SetFloat(a, *(double*)ptr); *ptr = *lastptr; // might be partial scan obj g->gc->GCWrite(obj, ptr); } break; case obj_float : { float* ptr = ((float*)(obj->slots)) + index; float* lastptr = ((float*)(obj->slots)) + lastIndex; SetFloat(a, *(float*)ptr); *ptr = *lastptr; } break; case obj_int32 : { int32* ptr = ((int32*)(obj->slots)) + index; int32* lastptr = ((int32*)(obj->slots)) + lastIndex; SetInt(a, *(int32*)ptr); *ptr = *lastptr; } break; case obj_int16 : { int16* ptr = ((int16*)(obj->slots)) + index; int16* lastptr = ((int16*)(obj->slots)) + lastIndex; SetInt(a, *(int16*)ptr); *ptr = *lastptr; } break; case obj_int8 : { int8* ptr = ((int8*)(obj->slots)) + index; int8* lastptr = ((int8*)(obj->slots)) + lastIndex; SetInt(a, *(int8*)ptr); *ptr = *lastptr; } break; case obj_symbol : { int32* ptr = ((int32*)(obj->slots)) + index; int32* lastptr = ((int32*)(obj->slots)) + lastIndex; SetSymbol(a, *(PyrSymbol**)ptr); *ptr = *lastptr; } break; case obj_char : { unsigned char* ptr = ((unsigned char*)(obj->slots)) + index; unsigned char* lastptr = ((unsigned char*)(obj->slots)) + lastIndex; SetChar(a, *(unsigned char*)ptr); *ptr = *lastptr; } break; } obj->size -- ; return errNone; } int basicWrapAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index; PyrObject *obj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if(obj->size==0) {SetNil(a); return errNone; } int err = slotIntVal(b, &index); if (!err) { index = sc_mod((int)index, (int)obj->size); getIndexedSlot(obj, a, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = indexArray->size; PyrObject *outArray = newPyrArray(g->gc, size, 0, true); PyrSlot *outArraySlots = outArray->slots; for (int i=0; isize); getIndexedSlot(obj, outArraySlots + i, index); } outArray->size = size; SetObject(a, outArray); } else return errIndexNotAnInteger; return errNone; } int basicFoldAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index; PyrObject *obj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if(obj->size==0) {SetNil(a); return errNone; } int err = slotIntVal(b, &index); if (!err) { index = sc_fold(index, 0, obj->size-1); getIndexedSlot(obj, a, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = indexArray->size; PyrObject *outArray = newPyrArray(g->gc, size, 0, true); PyrSlot *outArraySlots = outArray->slots; for (int i=0; isize-1); getIndexedSlot(obj, outArraySlots + i, index); } outArray->size = size; SetObject(a, outArray); } else return errIndexNotAnInteger; return errNone; } int basicClipAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index; PyrObject *obj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if(obj->size==0) {SetNil(a); return errNone; } int err = slotIntVal(b, &index); if (!err) { index = sc_clip(index, 0, obj->size - 1); getIndexedSlot(obj, a, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = indexArray->size; PyrObject *outArray = newPyrArray(g->gc, size, 0, true); PyrSlot *outArraySlots = outArray->slots; for (int i=0; isize - 1); getIndexedSlot(obj, outArraySlots + i, index); } outArray->size = size; SetObject(a, outArray); } else return errIndexNotAnInteger; return errNone; } int basicPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int index; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (!err) { if (index < 0 || index >= obj->size) return errIndexOutOfRange; return putIndexedSlot(g, obj, c, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = slotRawObject(b)->size; for (int i=0; i= obj->size) return errIndexOutOfRange; err = putIndexedSlot(g, obj, c, index); if (err) return err; } return errNone; } else return errIndexNotAnInteger; } int basicClipPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int index; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (!err) { index = sc_clip(index, 0, obj->size - 1); return putIndexedSlot(g, obj, c, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = slotRawObject(b)->size; for (int i=0; isize - 1); err = putIndexedSlot(g, obj, c, index); if (err) return err; } return errNone; } else return errIndexNotAnInteger; } int basicWrapPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int index; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (!err) { index = sc_mod((int)index, (int)obj->size); return putIndexedSlot(g, obj, c, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = slotRawObject(b)->size; for (int i=0; isize); err = putIndexedSlot(g, obj, c, index); if (err) return err; } return errNone; } else return errIndexNotAnInteger; } int basicFoldPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int index; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (!err) { index = sc_fold(index, 0, obj->size-1); return putIndexedSlot(g, obj, c, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = slotRawObject(b)->size; for (int i=0; isize-1); err = putIndexedSlot(g, obj, c, index); if (err) return err; } return errNone; } else return errIndexNotAnInteger; } int prArrayPutEach(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (!isKindOfSlot(b, class_arrayed_collection)) return errWrongType; if (!isKindOfSlot(c, class_arrayed_collection)) return errWrongType; PyrSlot *indices = slotRawObject(b)->slots; PyrSlot *values = slotRawObject(c)->slots; int size = slotRawObject(b)->size; int valsize = slotRawObject(c)->size; for (int i=0; i= obj->size) return errIndexOutOfRange; int valindex = sc_mod(i, valsize); err = putIndexedSlot(g, obj, values + valindex, index); if (err) return err; } return errNone; } int prArrayAssocAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj; bool found = false; a = g->sp - 1; b = g->sp; obj = slotRawObject(a); int size = obj->size; if (obj->obj_format == obj_slot) { PyrSlot *slots = obj->slots; for (int i=0; i= size) return errFailed; slotCopy(a,&slots[i+1]); found = true; break; } } } else { PyrSlot slot; for (int i=0; i= size) return errFailed; getIndexedSlot(obj, &slot, i+1); slotCopy(a,&slot); found = true; break; } } } if (!found) SetNil(a); return errNone; } int prArrayAssocPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; PyrObject *obj; bool found = false; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; int size = obj->size; if (obj->obj_format == obj_slot) { PyrSlot *slots = obj->slots; for (int i=0; i= size) return errFailed; slotCopy(&slots[i+1],c); g->gc->GCWrite(obj, c); found = true; break; } } } else { PyrSlot slot; for (int i=0; i= size) return errFailed; putIndexedSlot(g, obj, &slot, i+1); g->gc->GCWrite(obj, c); found = true; break; } } } if (!found) SetNil(a); return errNone; } int prArrayIndexOf(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj; bool found = false; a = g->sp - 1; b = g->sp; obj = slotRawObject(a); int size = obj->size; if (obj->obj_format == obj_slot) { PyrSlot *slots = obj->slots; for (int i=0; isp - 4; b = g->sp - 3; c = g->sp - 2; d = g->sp - 1; e = g->sp; PyrObject *inobj = slotRawObject(a); if (inobj->IsImmutable()) return errImmutableObject; int size = inobj->size; if (NotInt(b) && NotNil(b)) return errWrongType; if (NotInt(c) && NotNil(c)) return errWrongType; if (NotInt(d) && NotNil(d)) return errWrongType; int first = IsInt(b) ? slotRawInt(b) : 0; int last = IsInt(d) ? slotRawInt(d) : size - 1; int second = IsInt(c) ? slotRawInt(c) : (first < last ? first + 1 : first - 1); int step = second - first; first = sc_clip(first, 0, size-1); last = sc_clip(last, 0, size-1); int err = errNone; if (step == 0) return errFailed; if (step == 1) { for (int i=first; i<=last; ++i) { err = putIndexedSlot(g, inobj, e, i); if (err) return err; } } else if (step == -1) { for (int i=last; i>=first; --i) { err = putIndexedSlot(g, inobj, e, i); if (err) return err; } } else if (step > 0) { int length = (last - first) / step + 1; for (int i=first, j=0; jsp - 1; b = g->sp; PyrObject *array = slotRawObject(a); if (array->IsImmutable()) return errImmutableObject; format = slotRawObject(a)->obj_format; tag = gFormatElemTag[format]; /*if (tag > 0) { if (GetTag(b) != tag) return errWrongType; } else if (tag == 0) { if (NotFloat(b)) return errWrongType; } // else format is obj_slot, any tag is acceptable*/ elemsize = gFormatElemSize[format]; maxelems = MAXINDEXSIZE(array); if (array->size >= maxelems || array->IsImmutable()) { numbytes = sizeof(PyrSlot) << (array->obj_sizeclass + 1); array = g->gc->New(numbytes, 0, format, true); array->classptr = slotRawObject(a)->classptr; array->size = slotRawObject(a)->size; memcpy(array->slots, slotRawObject(a)->slots, slotRawObject(a)->size * elemsize); SetRaw(a, array); } slots = array->slots; switch (format) { case obj_slot : slotCopy(&slots[array->size++],b); g->gc->GCWrite(array, b); break; case obj_int32 : err = slotIntVal(b, &ival); if (err) return err; ((int32*)slots)[array->size++] = ival; break; case obj_int16 : err = slotIntVal(b, &ival); if (err) return err; ((int16*)slots)[array->size++] = ival; break; case obj_int8 : err = slotIntVal(b, &ival); if (err) return err; ((int8*)slots)[array->size++] = ival; break; case obj_char : if (NotChar(b)) return errWrongType; ((char*)slots)[array->size++] = slotRawChar(b); break; case obj_symbol : if (NotSym(b)) return errWrongType; ((PyrSymbol**)slots)[array->size++] = slotRawSymbol(b); break; case obj_float : err = slotDoubleVal(b, &fval); if (err) return err; ((float*)slots)[array->size++] = fval; break; case obj_double : err = slotDoubleVal(b, &fval); if (err) return err; ((double*)slots)[array->size++] = fval; break; } return errNone; } int prArrayInsert(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *slots1, *slots2; PyrObject *array, *oldarray; int err, ival; double fval; a = g->sp - 2; // array b = g->sp - 1; // index c = g->sp; // value if (NotInt(b)) return errWrongType; array = slotRawObject(a); const int format = slotRawObject(a)->obj_format; const int tag = gFormatElemTag[format]; const int size = array->size; int index = slotRawInt(b); index = sc_clip(index, 0, size); const int remain = size - index; const int elemsize = gFormatElemSize[format]; const int maxelems = MAXINDEXSIZE(array); if (size+1 > maxelems || array->IsImmutable()) { oldarray = array; const int numbytes = sizeof(PyrSlot) << (array->obj_sizeclass + 1); array = g->gc->New(numbytes, 0, format, true); array->classptr = oldarray->classptr; array->size = size+1; SetRaw(a, array); slots1 = array->slots; slots2 = oldarray->slots; if (index) memcpy(slots1, slots2, index * elemsize); switch (format) { case obj_slot : slotCopy(&slots1[index],c); if (remain) memcpy(slots1 + index + 1, slots2 + index, remain * elemsize); if (!g->gc->ObjIsGrey(array)) g->gc->ToGrey(array); break; case obj_int32 : err = slotIntVal(c, &ival); if (err) return err; ((int32*)slots1)[index] = ival; if (remain) { memcpy((int*)slots1 + index + 1, (int*)slots2 + index, remain * elemsize); } break; case obj_int16 : err = slotIntVal(c, &ival); if (err) return err; ((int16*)slots1)[index] = ival; if (remain) { memcpy((short*)slots1 + index + 1, (short*)slots2 + index, remain * elemsize); } break; case obj_int8 : err = slotIntVal(c, &ival); if (err) return err; ((int8*)slots1)[index] = ival; if (remain) { memcpy((char*)slots1 + index + 1, (char*)slots2 + index, remain * elemsize); } break; case obj_char : if (NotChar(c)) return errWrongType; ((char*)slots1)[index] = slotRawInt(c); if (remain) { memcpy((char*)slots1 + index + 1, (char*)slots2 + index, remain * elemsize); } break; case obj_symbol : if (NotSym(c)) return errWrongType; ((PyrSymbol**)slots1)[index] = slotRawSymbol(c); if (remain) { memcpy((int*)slots1 + index + 1, (int*)slots2 + index, remain * elemsize); } break; case obj_float : err = slotDoubleVal(c, &fval); if (err) return err; ((float*)slots1)[index] = fval; if (remain) { memcpy((float*)slots1 + index + 1, (float*)slots2 + index, remain * elemsize); } break; case obj_double : err = slotDoubleVal(c, &fval); if (err) return err; ((double*)slots1)[index] = fval; if (remain) { memcpy((double*)slots1 + index + 1, (double*)slots2 + index, remain * elemsize); } break; } } else { array->size = size+1; slots1 = array->slots; switch (format) { case obj_slot : if (remain) memmove(slots1 + index + 1, slots1 + index, remain * elemsize); slotCopy(&slots1[index],c); if (!g->gc->ObjIsGrey(array)) g->gc->ToGrey(array); break; case obj_int32 : if (remain) { memmove((int*)slots1 + index + 1, (int*)slots1 + index, remain * elemsize); } err = slotIntVal(c, &ival); if (err) return err; ((int32*)slots1)[index] = ival; break; case obj_int16 : if (remain) { memmove((short*)slots1 + index + 1, (short*)slots1 + index, remain * elemsize); } err = slotIntVal(c, &ival); if (err) return err; ((int16*)slots1)[index] = ival; break; case obj_int8 : if (remain) { memmove((char*)slots1 + index + 1, (char*)slots1 + index, remain * elemsize); } err = slotIntVal(c, &ival); if (err) return err; ((int8*)slots1)[index] = ival; break; case obj_char : if (remain) { memmove((char*)slots1 + index + 1, (char*)slots1 + index, remain * elemsize); } if (NotChar(c)) return errWrongType; ((char*)slots1)[index] = slotRawInt(c); break; case obj_symbol : if (remain) { memmove((int*)slots1 + index + 1, (int*)slots1 + index, remain * elemsize); } if (NotSym(c)) return errWrongType; ((PyrSymbol**)slots1)[index] = slotRawSymbol(c); break; case obj_float : if (remain) { memmove((float*)slots1 + index + 1, (float*)slots1 + index, remain * elemsize); } err = slotDoubleVal(c, &fval); if (err) return err; ((float*)slots1)[index] = fval; break; case obj_double : if (remain) { memmove((double*)slots1 + index + 1, (double*)slots1 + index, remain * elemsize); } err = slotDoubleVal(c, &fval); if (err) return err; ((double*)slots1)[index] = fval; break; } } return errNone; } int prArrayFill(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots; PyrObject *array; PyrSymbol *sym; int i; int format, tag; int err, ival; double fval; a = g->sp - 1; b = g->sp; array = slotRawObject(a); format = slotRawObject(a)->obj_format; tag = gFormatElemTag[format]; /*if (tag > 0) { if (GetTag(b) != tag) return errWrongType; } else if (tag == 0) { if (NotFloat(b)) return errWrongType; } // else format is obj_slot, any tag is acceptable*/ slots = array->slots; switch (format) { case obj_slot : if (array->IsImmutable()) return errImmutableObject; for (i=0; isize; ++i) { slotCopy(&slots[i],b); } g->gc->GCWrite(array, b); break; case obj_int32 : err = slotIntVal(b, &ival); if (err) return err; for (i=0; isize; ++i) { ((int32*)slots)[i] = ival; } break; case obj_int16 : err = slotIntVal(b, &ival); if (err) return err; for (i=0; isize; ++i) { ((int16*)slots)[i] = ival; } break; case obj_int8 : err = slotIntVal(b, &ival); if (err) return err; for (i=0; isize; ++i) { ((int8*)slots)[i] = ival; } break; case obj_char : if (NotChar(b)) return errWrongType; ival = slotRawInt(b); for (i=0; isize; ++i) { ((char*)slots)[i] = ival; } break; case obj_symbol : if (NotSym(b)) return errWrongType; sym = slotRawSymbol(b); for (i=0; isize; ++i) { ((PyrSymbol**)slots)[i] = sym; } break; case obj_float : err = slotDoubleVal(b, &fval); if (err) return err; for (i=0; isize; ++i) { ((float*)slots)[i] = fval; } break; case obj_double : err = slotDoubleVal(b, &fval); if (err) return err; for (i=0; isize; ++i) { ((double*)slots)[i] = fval; } break; } return errNone; } int prArrayPop(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots; PyrObject *array; int z; int format; PyrSymbol *sym; a = g->sp; array = slotRawObject(a); if (array->IsImmutable()) return errImmutableObject; if (array->size > 0) { format = array->obj_format; slots = array->slots; switch (format) { case obj_slot : slotCopy(a,&slots[--array->size]); break; case obj_int32 : z = ((int32*)slots)[--array->size]; SetInt(a, z); break; case obj_int16 : z = ((int16*)slots)[--array->size]; SetInt(a, z); break; case obj_int8 : z = ((int8*)slots)[--array->size]; SetInt(a, z); break; case obj_char : z = ((char*)slots)[--array->size]; SetChar(a, z); break; case obj_symbol : sym = ((PyrSymbol**)slots)[--array->size]; SetSymbol(a, sym); break; case obj_float : SetFloat(a, ((float*)slots)[--array->size]); break; case obj_double : SetFloat(a, slotRawFloat(&slots[--array->size])); break; } } else { slotCopy(a,&o_nil); } return errNone; } int prArrayExtend(struct VMGlobals *g, int numArgsPushed) { int numbytes, elemsize, format; int err; PyrSlot *a = g->sp - 2; // array PyrSlot *b = g->sp - 1; // size PyrSlot *c = g->sp; // filler item if (NotInt(b)) return errWrongType; PyrObject* aobj = slotRawObject(a); if (slotRawInt(b) <= aobj->size) { aobj->size = slotRawInt(b); return errNone; } format = aobj->obj_format; if (slotRawInt(b) > MAXINDEXSIZE(aobj) || aobj->IsImmutable()) { elemsize = gFormatElemSize[format]; numbytes = slotRawInt(b) * elemsize; PyrObject *obj = g->gc->New(numbytes, 0, format, true); obj->classptr = aobj->classptr; obj->size = aobj->size; memcpy(obj->slots, aobj->slots, aobj->size * elemsize); aobj = obj; SetRaw(a, aobj); } int fillSize = slotRawInt(b) - aobj->size; int32 ival; float fval; double dval; PyrSlot *slots = aobj->slots; switch (format) { case obj_slot : fillSlots(slots + aobj->size, fillSize, c); g->gc->GCWrite(aobj, c); break; case obj_int32 : { int32* ptr = (int32*)slots + aobj->size; err = slotIntVal(c, &ival); if (err) return err; for (int i=0; isize; err = slotIntVal(c, &ival); if (err) return err; for (int i=0; isize; err = slotIntVal(c, &ival); if (err) return err; for (int i=0; isize; if (NotChar(c)) return errWrongType; ival = slotRawChar(c); for (int i=0; isize; if (NotSym(c)) return errWrongType; PyrSymbol *sym = slotRawSymbol(c); for (int i=0; isize; err = slotFloatVal(c, &fval); for (int i=0; isize; err = slotDoubleVal(c, &dval); for (int i=0; isize = slotRawInt(b); return errNone; } int prArrayGrow(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj, *aobj; int numbytes, elemsize, format; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; if (slotRawInt(b) <= 0) return errNone; aobj = slotRawObject(a); if (aobj->size + slotRawInt(b) <= MAXINDEXSIZE(aobj)) return errNone; format = aobj->obj_format; elemsize = gFormatElemSize[format]; numbytes = ((aobj->size + slotRawInt(b)) * elemsize); obj = g->gc->New(numbytes, 0, format, true); obj->classptr = aobj->classptr; obj->size = aobj->size; memcpy(obj->slots, aobj->slots, aobj->size * elemsize); SetRaw(a, obj); return errNone; } int prArrayGrowClear(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj, *aobj; int numbytes, elemsize, format; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; if (slotRawInt(b) <= 0) return errNone; aobj = slotRawObject(a); if (aobj->size + slotRawInt(b) <= MAXINDEXSIZE(aobj) && aobj->IsMutable()) { obj = aobj; } else { format = aobj->obj_format; elemsize = gFormatElemSize[format]; numbytes = ((aobj->size + slotRawInt(b)) * elemsize); obj = g->gc->New(numbytes, 0, format, true); obj->classptr = aobj->classptr; memcpy(obj->slots, aobj->slots, aobj->size * elemsize); } if (obj->obj_format == obj_slot) { nilSlots(obj->slots + aobj->size, slotRawInt(b)); } else { memset((char*)(obj->slots) + aobj->size * gFormatElemSize[format], 0, slotRawInt(b) * gFormatElemSize[format]); } obj->size = aobj->size + slotRawInt(b); SetRaw(a, obj); return errNone; } int prArrayCat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj, *aobj, *bobj; int elemsize, size; int numbytes, format; a = g->sp - 1; b = g->sp; if (NotObj(b) || slotRawObject(a)->classptr != slotRawObject(b)->classptr) return errWrongType; aobj = slotRawObject(a); bobj = slotRawObject(b); size = aobj->size + bobj->size; format = aobj->obj_format; assert(aobj->obj_format == bobj->obj_format); elemsize = gFormatElemSize[format]; numbytes = (size * elemsize); obj = g->gc->New(numbytes, 0, format, true); obj->classptr = aobj->classptr; obj->size = size; memcpy(obj->slots, aobj->slots, aobj->size * elemsize); memcpy((char*)obj->slots + aobj->size * elemsize, bobj->slots, bobj->size * elemsize); SetObject(a, obj); return errNone; } int prArrayAddAll(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj, *aobj; int elemsize, newindexedsize, newsizebytes, asize, bsize; int format; a = g->sp - 1; b = g->sp; if (NotObj(b) || slotRawObject(a)->classptr != slotRawObject(b)->classptr) return errWrongType; aobj = slotRawObject(a); format = aobj->obj_format; elemsize = gFormatElemSize[format]; asize = aobj->size; bsize = slotRawObject(b)->size; newindexedsize = asize + bsize; newsizebytes = newindexedsize * elemsize; if (newindexedsize > MAXINDEXSIZE(aobj) || aobj->IsImmutable()) { obj = g->gc->New(newsizebytes, 0, format, true); obj->classptr = aobj->classptr; memcpy(obj->slots, aobj->slots, asize * elemsize); SetObject(a, obj); } else { obj = aobj; if (format == obj_slot && !g->gc->ObjIsGrey(obj)) g->gc->ToGrey(obj); } obj->size = newindexedsize; memcpy((char*)obj->slots + asize * elemsize, slotRawObject(b)->slots, bsize * elemsize); return errNone; } int prArrayOverwrite(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; PyrObject *obj, *aobj; int err, elemsize, newindexedsize, newsizebytes, pos, asize, bsize; int format; a = g->sp - 2; b = g->sp - 1; c = g->sp; // pos if (NotObj(b) || slotRawObject(a)->classptr != slotRawObject(b)->classptr) return errWrongType; err = slotIntVal(c, &pos); if (err) return errWrongType; if (pos < 0 || pos > slotRawObject(a)->size) return errIndexOutOfRange; aobj = slotRawObject(a); format = aobj->obj_format; elemsize = gFormatElemSize[format]; asize = aobj->size; bsize = slotRawObject(b)->size; newindexedsize = pos + bsize; newindexedsize = sc_max(asize, newindexedsize); newsizebytes = newindexedsize * elemsize; if (newindexedsize > MAXINDEXSIZE(aobj) || aobj->IsImmutable()) { obj = g->gc->New(newsizebytes, 0, format, true); obj->classptr = aobj->classptr; memcpy(obj->slots, aobj->slots, asize * elemsize); SetObject(a, obj); } else { obj = aobj; if (format == obj_slot && !g->gc->ObjIsGrey(obj)) g->gc->ToGrey(obj); } obj->size = newindexedsize; memcpy((char*)(obj->slots) + pos * elemsize, slotRawObject(b)->slots, bsize * elemsize); return errNone; } int prArrayReverse(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots1, *slots2; PyrObject *obj1, *obj2; int i, j, size; a = g->sp; obj1 = slotRawObject(a); size = obj1->size; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); slots1 = obj1->slots; slots2 = obj2->slots; for (i=0, j=size-1; isize = size; SetRaw(a, obj2); return errNone; } int prArrayScramble(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots1, *slots2, temp; PyrObject *obj1, *obj2; int i, j, k, m, size; a = g->sp; obj1 = slotRawObject(a); size = obj1->size; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); slots1 = obj1->slots; slots2 = obj2->slots; memcpy(slots2, slots1, size * sizeof(PyrSlot)); if (size > 1) { k = size; for (i=0, m=k; irgen->irand(m); slotCopy(&temp,&slots2[i]); slotCopy(&slots2[i],&slots2[j]); slotCopy(&slots2[j],&temp); } } obj2->size = size; SetRaw(a, obj2); return errNone; } int prArrayRotate(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots; PyrObject *obj1, *obj2; int i, j, n, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; obj1 = slotRawObject(a); size = obj1->size; n = sc_mod((int)slotRawInt(b), (int)size); slots = obj1->slots; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); for (i=0, j=n; islots[j],&slots[i]); if (++j >= size) j=0; } obj2->size = size; SetRaw(a, obj2); return errNone; } int prArrayStutter(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots1, *slots2; PyrObject *obj1, *obj2; int i, j, k, m, n, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; obj1 = slotRawObject(a); n = slotRawInt(b); m = obj1->size; size = m * n; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); slots1 = obj1->slots; slots2 = obj2->slots; for (i=0,j=0; isize = size; SetRaw(a, obj2); return errNone; } int prArrayMirror(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots; PyrObject *obj1, *obj2; int i, j, k, size; a = g->sp; obj1 = slotRawObject(a); slots = obj1->slots; size = obj1->size * 2 - 1; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; // copy first part of list memcpy(obj2->slots, slots, obj1->size * sizeof(PyrSlot)); // copy second part k = size/2; for (i=0, j=size-1; islots[j],&slots[i]); } SetRaw(a, obj2); return errNone; } int prArrayMirror1(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots; PyrObject *obj1, *obj2; int i, j, k, size; a = g->sp; obj1 = slotRawObject(a); slots = obj1->slots; size = obj1->size * 2 - 2; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; // copy first part of list memcpy(obj2->slots, slots, obj1->size * sizeof(PyrSlot)); // copy second part k = size/2; for (i=1, j=size-1; islots[j],&slots[i]); } SetRaw(a, obj2); return errNone; } int prArrayMirror2(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots; PyrObject *obj1, *obj2; int i, j, k, size; a = g->sp; obj1 = slotRawObject(a); slots = obj1->slots; size = obj1->size * 2; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; // copy first part of list memcpy(obj2->slots, slots, obj1->size * sizeof(PyrSlot)); // copy second part k = size/2; for (i=0, j=size-1; islots[j],&slots[i]); } SetRaw(a, obj2); return errNone; } int prArrayExtendWrap(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots; PyrObject *obj1, *obj2; int i, j, m, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; size = slotRawInt(b); if (size < 0) return errFailed; obj1 = slotRawObject(a); if(obj1->size > 0) { obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; slots = obj2->slots; // copy first part of list memcpy(slots, obj1->slots, sc_min(size, obj1->size) * sizeof(PyrSlot)); if (size > obj1->size) { // copy second part m = obj1->size; for (i=0,j=m; jgc, obj1->classptr, size, true, true); } SetRaw(a, obj2); return errNone; } int prArrayExtendFold(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots; PyrObject *obj1, *obj2; int i, j, m, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; size = slotRawInt(b); if (size < 0) return errFailed; obj1 = slotRawObject(a); if(obj1->size > 0) { obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; slots = obj2->slots; // copy first part of list memcpy(slots, obj1->slots, sc_min(size, obj1->size) * sizeof(PyrSlot)); if (size > obj1->size) { // copy second part m = obj1->size; for (i=0,j=m; jgc, obj1->classptr, size, true, true); } SetRaw(a, obj2); return errNone; } int prArrayExtendLast(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots, last; PyrObject *obj1, *obj2; int i, j, m, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; size = slotRawInt(b); if (size < 0) return errFailed; obj1 = slotRawObject(a); if(obj1->size > 0) { obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; slots = obj2->slots; // copy first part of list memcpy(slots, obj1->slots, sc_min(size, obj1->size) * sizeof(PyrSlot)); if (size > obj1->size) { // copy second part m = obj1->size; slotCopy(&last,&slots[m-1]); for (i=0,j=m; jgc, obj1->classptr, size, true, true); } SetRaw(a, obj2); return errNone; } int prArrayPermute(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots1, *slots2, temp; PyrObject *obj1, *obj2; int i, j, m, z, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; obj1 = slotRawObject(a); size = obj1->size; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; slots1 = obj1->slots; slots2 = obj2->slots; memcpy(slots2, slots1, size * sizeof(PyrSlot)); z = slotRawInt(b); for (i=0, m=size; isp - 1; b = g->sp; if (NotInt(b)) return errWrongType; int maxSize = slotRawInt(b); obj1 = slotRawObject(a); slots1 = obj1->slots; int newSize = 1; int tupSize = obj1->size; for (int i=0; i < tupSize; ++i) { if (isKindOfSlot(slots1+i, class_array)) { newSize *= slotRawObject(&slots1[i])->size; } } if (newSize > maxSize) newSize = maxSize; obj2 = instantiateObject(g->gc, obj1->classptr, newSize, false, true); slots2 = obj2->slots; SetObject(b, obj2); // store reference on stack, so both source and destination objects can be reached by the gc for (int i=0; i < newSize; ++i) { int k = i; obj3 = instantiateObject(g->gc, obj1->classptr, tupSize, false, true); slots3 = obj3->slots; for (int j=tupSize-1; j >= 0; --j) { if (isKindOfSlot(slots1+j, class_array)) { PyrObject *obj4 = slotRawObject(&slots1[j]); slotCopy(&slots3[j], &obj4->slots[k % obj4->size]); g->gc->GCWrite(obj3, obj4); k /= obj4->size; } else { slotCopy(&slots3[j], &slots1[j]); } } obj3->size = tupSize; SetObject(obj2->slots+i, obj3); g->gc->GCWriteNew(obj2, obj3); obj2->size++; } SetRaw(a, obj2); return errNone; } int prArrayPyramid(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots; PyrObject *obj1, *obj2; int i, j, k, n, m, numslots, x; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; obj1 = slotRawObject(a); slots = obj1->slots; m = sc_clip(slotRawInt(b), 1, 10); x = numslots = obj1->size; switch (m) { case 1 : n = (x*x + x)/2; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } obj2->size = k; break; case 2 : n = (x*x + x)/2; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } obj2->size = k; break; case 3 : n = (x*x + x)/2; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } obj2->size = k; break; case 4 : n = (x*x + x)/2; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } obj2->size = k; break; case 5 : n = x*x; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=0; islots[k],&slots[j]); } } obj2->size = k; break; case 6 : n = x*x; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=0; islots[k],&slots[j]); } } obj2->size = k; break; case 7 : n = x*x + x - 1; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=1; islots[k],&slots[j]); } } obj2->size = k; break; case 8 : n = x*x + x - 1; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=1; islots[k],&slots[j]); } } obj2->size = k; break; case 9 : n = x*x; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=0; islots[k],&slots[j]); } } obj2->size = k; break; case 10 : n = x*x; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=0; islots[k],&slots[j]); } } obj2->size = k; break; } SetRaw(a, obj2); return errNone; } int prArraySlide(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *slots; PyrObject *obj1, *obj2; int h, i, j, k, numslots, numwin; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotInt(b)) return errWrongType; if (NotInt(c)) return errWrongType; obj1 = slotRawObject(a); slots = obj1->slots; int m = slotRawInt(b); int n = slotRawInt(c); if (n <= 0) return errFailed; numwin = (obj1->size + n - m) / n; numslots = numwin * m; obj2 = instantiateObject(g->gc, obj1->classptr, numslots, false, true); for (i=h=k=0; islots[k++],&slots[j]); } obj2->size = k; SetRaw(a, obj2); return errNone; } int prArrayLace(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots, *slot; PyrObject *obj1, *obj2, *obj3; int i, j, k, n, m, numLists, len; a = g->sp - 1; b = g->sp; obj1 = slotRawObject(a); slots = obj1->slots; numLists = obj1->size; if(IsNil(b)) { for (j=0; jsize; if(j==0 || n>len) { n = len; } } else { return errFailed; // this primitive only handles Arrays. } } n = n * numLists; } else if (IsInt(b)) { n = slotRawInt(b); } else { return errWrongType; } n = sc_max(1, n); if(obj1->size > 0) { obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=j=k=0; islots[0]); // get the list's array } if (obj3 && isKindOf(obj3, class_array)) { m = j % obj3->size; slotCopy(&obj2->slots[i],&obj3->slots[m]); } else { slotCopy(&obj2->slots[i],&slots[k]); } } else { slotCopy(&obj2->slots[i],&slots[k]); } k = (k+1) % obj1->size; if (k == 0) j++; } } else { obj2 = instantiateObject(g->gc, obj1->classptr, n, true, true); } obj2->size = n; SetRaw(a, obj2); return errNone; } int prArrayContainsSeqColl(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slot, *endptr; PyrObject *obj; int size; a = g->sp; obj = slotRawObject(a); size = obj->size; slot = obj->slots - 1; endptr = slot + size; while (slot < endptr) { ++slot; if (IsObj(slot)) { if (isKindOf(slotRawObject(slot), class_sequenceable_collection)) { SetTrue(a); return errNone; } } } SetFalse(a); return errNone; } int prArrayNormalizeSum(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots2; PyrObject *obj1, *obj2; int i, size, err; double w, sum, rsum; a = g->sp; obj1 = slotRawObject(a); size = obj1->size; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); slots2 = obj2->slots; sum = 0.0; for (i=0; isize = size; SetRaw(a, obj2); return errNone; } int prArrayWIndex(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots; PyrObject *obj; int i, j, size, err; double r, w, sum; a = g->sp; sum = 0.0; r = g->rgen->frand(); obj = slotRawObject(a); size = obj->size; j = size - 1; slots = obj->slots; for (i=0; i= r) { j = i; break; } } SetInt(a, j); return errNone; } enum { shape_Step, shape_Linear, shape_Exponential, shape_Sine, shape_Welch, shape_Curve, shape_Squared, shape_Cubed }; enum { kEnv_initLevel, kEnv_numStages, kEnv_releaseNode, kEnv_loopNode }; int prArrayEnvAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; PyrObject* env = slotRawObject(a); PyrSlot* slots = env->slots; // Env:asArray always gives at least 8 array elements if(env->size < 8) return errFailed; double time; int err = slotDoubleVal(b, &time); if (err) return err; double begLevel; err = slotDoubleVal(slots + kEnv_initLevel, &begLevel); if (err) return err; int numStages; err = slotIntVal(slots + kEnv_numStages, &numStages); if (err) return err; double begTime = 0.; double endTime = 0.; for (int i=0; isp - 1; b = g->sp; obj = slotRawObject(a); size = obj->size; slots = obj->slots; err = slotDoubleVal(b, &s); if (err) return err; for (i=0; i s) { SetInt(a, i); return errNone; } } SetNil(a); return errNone; } int prArrayUnlace(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *slots, *slots2, *slots3; PyrObject *obj1, *obj2, *obj3; int i, j, k, clump, numLists, size, size3, err; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj1 = slotRawObject(a); slots = obj1->slots; size = obj1->size; err = slotIntVal(b, &numLists); if (err) return err; err = slotIntVal(c, &clump); if (err) return err; obj2 = instantiateObject(g->gc, obj1->classptr, numLists, false, true); obj2->size = numLists; slots2 = obj2->slots; SetObject(b, obj2); // store reference on stack, so both source and destination objects can be reached by the gc size3 = size / numLists; size3 = size3 - (size3 % clump); if(size3 < 1) return errFailed; for(i=0; igc, obj1->classptr, size3, false, true); obj3->size = size3; slots3 = obj3->slots; for(j=0; j -O coff -i -o ") endif(MINGW) if (SC_WII OR APPLE) if(CMAKE_SYSTEM_NAME MATCHES "Linux") find_package(CWiid) find_package(Bluetooth) if (BLUETOOTH_FOUND AND CWIID_FOUND) add_definitions(-DHAVE_WII) include_directories(${CWIID_INCLUDE_DIRS} ${BLUETOOTH_INCLUDE_DIRS}) message(STATUS "Compiling with WiiMote support") else() message(SEND_ERROR "Cannot find libcwiid or libbluetooth.\n (If Wii support is not required, then set SC_WII=no)") endif() elseif(APPLE) add_definitions(-DHAVE_WII) list(APPEND sclang_sources LangPrimSource/WiiMote_OSX/wiiremote.c) include_directories(LangPrimSource/WiiMote_OSX) endif() endif() include(../SCDoc/CMakeLists.txt) list(APPEND sclang_sources ${SCDOC_SRCS}) if(SC_IDE) list(APPEND sclang_sources ../editors/sc-ide/primitives/sc_ipc_client.cpp) endif() if(SC_QT) set(QT_COLLIDER_LANG_CLIENT ON) include(../QtCollider/CMakeLists.txt) list(APPEND sclang_sources ${QT_COLLIDER_SRCS}) endif() if(0 AND FINAL_BUILD) # sclang final-builds are broken CREATE_FINAL_FILE(libsclang_final.cpp ${sclang_sources}) add_library(libsclang STATIC libsclang_final.cpp ${sclang_parser_source}) else() add_library(libsclang STATIC ${sclang_sources} ${sclang_parser_source}) endif() set_property(TARGET libsclang APPEND PROPERTY COMPILE_DEFINITIONS BUILDING_SUPERCOLLIDER) if (SC_WII OR APPLE) if (BLUETOOTH_FOUND AND CWIID_FOUND) target_link_libraries(libsclang ${BLUETOOTH_LIBRARIES} ${CWIID_LIBRARIES}) elseif(APPLE) target_link_libraries(libsclang "-framework IOBluetooth") endif() endif() if (Boost_FOUND) target_link_libraries(libsclang ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_REGEX_LIBRARY} ${Boost_FILESYSTEM_LIBRARY}) endif() if (SCLANG_SERVER) target_link_libraries(libsclang libscsynth) else() set_property(TARGET libsclang APPEND PROPERTY COMPILE_DEFINITIONS NO_INTERNAL_SERVER ) endif() set_property(TARGET libsclang PROPERTY OUTPUT_NAME sclang) ## external libraries if(READLINE_FOUND) message(STATUS "Compiling with Readline support") set_property(TARGET libsclang APPEND PROPERTY COMPILE_DEFINITIONS HAVE_READLINE) include_directories(${READLINE_INCLUDE_DIR}) target_link_libraries(libsclang ${READLINE_LIBRARY}) endif(READLINE_FOUND) if (APPLE) target_link_libraries(libsclang "-framework Carbon") target_link_libraries(libsclang "-framework CoreAudio") target_link_libraries(libsclang "-framework CoreMIDI") target_link_libraries(libsclang "-framework IOKit") target_link_libraries(libsclang "-framework CoreServices") endif() if(ALSA_FOUND) message(STATUS "Compiling with ALSA midi support") set_property(TARGET libsclang APPEND PROPERTY COMPILE_DEFINITIONS HAVE_ALSA=1) target_link_libraries(libsclang ${ALSA_LIBRARY}) endif(ALSA_FOUND) if(SNDFILE_FOUND) include_directories(${SNDFILE_INCLUDE_DIR}) target_link_libraries(libsclang ${SNDFILE_LIBRARIES}) elseif(NOT NO_LIBSNDFILE) message(SEND_ERROR "Cannot find libsndfile") endif(SNDFILE_FOUND) if (FFTW3F_FOUND) include_directories (${FFTW3F_INCLUDE_DIR}) target_link_libraries(libsclang ${FFTW3F_LIBRARY}) endif() if (WIN32) target_link_libraries(libsclang wsock32 ws2_32) if(PORTMIDI_FOUND) target_link_libraries(libsclang ${PORTMIDI_LIBRARIES}) endif() endif() if (GC_SANITYCHECK) add_definitions(-DGC_SANITYCHECK) endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux") target_link_libraries(libsclang rt) endif() target_link_libraries(libsclang ${PTHREADS_LIBRARY} ${YAMLCPP_LIBRARY}) if(SC_QT) target_link_libraries(libsclang ${QT_COLLIDER_LIBS}) endif() if(SC_IDE) add_definitions(-DSC_IDE -DQT_NO_KEYWORDS) find_package( Qt4 4.7 REQUIRED QtCore QtNetwork ) include( ${QT_USE_FILE} ) target_link_libraries( libsclang ${QT_LIBRARIES} ) endif() add_executable(sclang LangSource/cmdLineFuncs.cpp ${RES_FILES}) if (Boost_FOUND) target_link_libraries(sclang libsclang ${Boost_THREAD_LIBRARY}) else() target_link_libraries(sclang libsclang boost_thread) endif() set_property(TARGET sclang APPEND PROPERTY COMPILE_DEFINITIONS USE_SC_TERMINAL_CLIENT BUILDING_SUPERCOLLIDER) if(LTO) set_property(TARGET sclang libsclang APPEND PROPERTY COMPILE_FLAGS "-flto -flto-report") set_property(TARGET sclang libsclang APPEND PROPERTY LINK_FLAGS "-flto -flto-report -fwhole-program") endif() if(APPLE) # determines the app name and app install location (scappbundlename, scappdir): include (${CMAKE_SOURCE_DIR}/cmake_modules/MacAppFolder.cmake) install(TARGETS sclang DESTINATION "${scappauxresourcesdir}" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) elseif(WIN32) install(TARGETS sclang DESTINATION "SuperCollider" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) else() install(TARGETS sclang RUNTIME DESTINATION "bin" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) endif() SuperCollider-3.6.6-Source-linux~repack/package/0000775000000000000000000000000012245452763020366 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/package/package0000775000000000000000000001127012245452737021711 0ustar rootroot#!/bin/bash basename=`basename $PWD` if [ $basename != "package" ]; then echo "This script must be ran from within the Packager directory." exit 1 fi version=`date "+%Y-%m-%d"` include_optionals=false if [ `uname` = 'Darwin' ]; then package_type="osx" else package_type="source" fi while getopts ":v:os" Option do case $Option in v ) version=$OPTARG ;; o ) include_optionals=true ;; s ) package_type="source" ;; esac done shift $(($OPTIND - 1)) revision=`git rev-list HEAD -1 | sed -E 's/([[:alnum:]]{1,10}).*/\1/'` if [ "`git status -s -uno`" != "" ]; then echo "WARNING: The working copy has uncommitted changes which will NOT be included in the package." fi if [ $package_type == "source" ]; then if [ -d SuperCollider-Source ]; then echo "Please remove the ./SuperCollider-Source directory before running this script." exit 1 fi returndir=`pwd` cd ../ python package/git-archive-all.py --prefix SuperCollider-Source/ "$returndir/SuperCollider-Source.tmp.tar" cd "$returndir" # NB we only need one instance of boost, so we exclude one of its two appearances as a submodule in the following tar -x --exclude ".gitignore" --exclude ".gitmodules" \ --exclude "SuperCollider-Source/external_libraries/nova-tt/boost_lockfree" \ -f SuperCollider-Source.tmp.tar if $include_optionals; then cp -Rp optional SuperCollider-Source/optional_installs cp OPTIONALS_README_SOURCE.txt SuperCollider-Source/optional_installs/README.txt filename="SuperCollider-$version-Source-With-Extras.tar.bz2" filenamelinux="SuperCollider-$version-Source-With-Extras-linux.tar.bz2" else filename="SuperCollider-$version-Source.tar.bz2" filenamelinux="SuperCollider-$version-Source-linux.tar.bz2" fi # Here we build a list of (many) files that are useless on linux, so as to build a slimline source.tar.bz2 find SuperCollider-Source -iname windows -or -iname osx -or -name "*.xcodeproj" -or -name scide_scapp -or -iname "iPhone*" \ | grep -v "external_libraries/boost/boost/asio/windows" > LinuxExclusions.txt echo 'SuperCollider-Source/README_OS_X.md SuperCollider-Source/README_WINDOWS.txt SuperCollider-Source/README_IPHONE.txt SuperCollider-Source/external_libraries/libsndfile SuperCollider-Source/external_libraries/curl SuperCollider-Source/external_libraries/icu SuperCollider-Source/platform/mac SuperCollider-Source/platform/iphone SuperCollider-Source/platform/windows SuperCollider-Source/lang/LangPrimSource/HID_Utilities SuperCollider-Source/lang/LangPrimSource/HID_Utilities_10_4 SuperCollider-Source/lang/LangPrimSource/WiiMote_OSX SuperCollider-Source/editors/scapp' >> LinuxExclusions.txt tar cfj "$filename" SuperCollider-Source tar cfjX "$filenamelinux" LinuxExclusions.txt SuperCollider-Source rm -rf SuperCollider-Source SuperCollider-Source.tmp.tar exit else if [ -d SuperCollider ]; then echo "Please remove the ./SuperCollider directory before running this script." exit 1 fi if $include_optionals; then opt_options='--copy dmg_with_optionals.ds_store:/.DS_Store --copy optional/:/Optional\ Installs --copy OPTIONALS_README_OSX.rtf:/Optional\ Installs/README.rtf' filename="SuperCollider-$version-With-Extras.dmg" else opt_options='--copy dmg_without_optionals.ds_store:/.DS_Store' filename="SuperCollider-$version.dmg" fi about_version="$version (Revision $revision)" echo "About box version string:" $about_version mkdir -p SuperCollider/plugins returndir=`pwd` cd ../platform/mac/build git archive $revision | tar -x -C "$returndir/SuperCollider" cp -R SuperCollider.app scsynth sclang "$returndir/SuperCollider/" cp plugins/* "$returndir/SuperCollider/plugins/" cd $returndir cd ../ cp -R ChangeLog COPYING examples Help SCClassLibrary README sounds "$returndir/SuperCollider/" cd $returndir find SuperCollider/Help/ \( -name "*.htm" -or -name "*.html" \) -exec /Developer/Tools/SetFile -c SCjm {} \; defaults write $PWD/SuperCollider/SuperCollider.app/Contents/Info CFBundleVersion -string "$about_version" defaults write $PWD/SuperCollider/SuperCollider.app/Contents/Info CFBundleGetInfoString -string "$version" plutil -convert xml1 $PWD/SuperCollider/SuperCollider.app/Contents/Info.plist # use eval to force any escapes or quotes in $opt_options to be evaluated eval './pkg-dmg --verbosity 0 --source ./SuperCollider --target "$filename" --sourcefile --volname SuperCollider --mkdir /.background --copy background.png:/.background/background.png --symlink /Applications:/Applications '$opt_options rm -rf ./SuperCollider fi SuperCollider-3.6.6-Source-linux~repack/package/dmg_without_optionals.ds_store0000664000000000000000000003000412014636264026543 0ustar rootrootBud1  ob PctB  @ @ @ @ .BKGDblob PctB8.ICVObool.fwi0blobi(1icnv.fwswlong.fwvhshor.icgoblob.icvoblob icv48nonebotm1.icvtshor .pictblob88 SuperColliderIH+background.pngIPNGf8BIM  .backgroundʺʺ0(SuperCollider:.background:background.pngbackground.png SuperCollider/.background/background.png/Volumes/SuperCollider Macintosh HDYhH+tSuperCollider withou#C5FD2C.dmg,Idevrddsk Desktopʺ tf7s?Macintosh HD:Users:ryan:Desktop:SuperCollider withou#C5FD2C.dmgH#SuperCollider without Optionals.dmg Macintosh HD6Users/ryan/Desktop/SuperCollider without Optionals.dmg/ .backgroundfwi0blobdWicnv .backgroundfwvhshor~ ApplicationsIlocblobi2 SuperColliderIlocblob2 E DSDB ` @ @ @SuperCollider-3.6.6-Source-linux~repack/package/USAGE0000664000000000000000000000150712014636264021152 0ustar rootroot./package usage: -v version: Specify a version number. If this option is not specified the default is to use the date (YYYY-MM-DD) as the version. -s: Build a source package. If this option is not specified the default is to build a DMG. -o: Include the optional installs located in the ./optional directory. If this option is not specified the default is to not include the optional installs. ----------------------------------------------------------------------- Typical usage when posting a new release on SourceForge: # Place the mac optional installs in the ./optional directory. ./package -v 3.2 ./package -v 3.2 -o # Place the source optional installs in the ./optional directory. ./package -v 3.2 -s ./package -v 3.2 -s -o -----------------------------------------------------------------------SuperCollider-3.6.6-Source-linux~repack/package/background.png0000664000000000000000000003005212014636264023205 0ustar rootrootPNG  IHDRX)tEXtSoftwareAdobe ImageReadyqe</IDATx}{UUEy5@@!wA0J!EPk8EB$~`GAC &$ Q iYqDnj "i3~ks͵|\7oT5j|@W9_)0Ҥ-Y|OB9gP?_f +gX_ K쨅`B=߭&nu1Bj~2_HQfm 2qu>Djh%}02`im]lZGE  Rʊ00Ro+ވ0gB)3B1+Gn ],:WByXgUh?4m!AAd#Bc0"ܤD$p*qpH;M$ΊgRxWL`tB"@g5H3<_ݰknj28]n,$PmƊ.0P"/5b̪+2Sc-h  TâXtJXhn mvA:BLN1V;5jO߿Pp{n|cle>DU.64ZZ>Sf )͔>'3"4V\9ڟqᳶ]If). AFe qOBqmb8-;5^|bKwWqK*wP.[Z̔Z o F=ɆEpDBY&CL4ǞrtԘrKf*M%]MtCeYƀ"JiVa3ay 5JAtHǾm-֢пߞh@ʶZ~W6-vjLDM%bքYuL}6/qk]奍fgDצ6G\Vh,q,?vnX0s91B "ը,9>;{盅Dr^+[T#O轂D7n&; ,\_l/mDA凃nbDHA0"5N3"jk1aKD&ڐx'ʟ,/BJP",9g-[8nJ-CtzG[\z&ee:9-_0EC\X6ݎł8)1Lf̺,7ٙ(32"ed3 NQ ky琐Sq4 fʞR-d "`ר؂+2V{#8v CըeK{hF<"̈́4fzrl8@vD%C'jYF΋)˔3v;Ocu܏Һ‰P϶M)A,kaq;cEZ;gyvRsb TrF͸E]$ةu҆Ju_|l⍰.2ADbxV1'ipxGK)NQ{w:aA* ;,\-nBxGW'43Y&ڱH' M,yAӅ :}iX5'P/,'.cui%u#¢73c-ja,(i|Iq Ajk4Γ2Fr85jbUq[ӎpʷ+ )_԰r*+**U:kunMG5?|(0p.oG n(F TM-qc߁%ĭ:0[%[uŚe)!  tG>aKLy13fcר%Rޒ(1(&XϑKJAF|a(]E\],ٌe[JYJ\Ͷ?d-&]ءY. ;}2f1нÜp H5Ju wAaQ2'=xq{%|gK:z6=Gw%v2aP۰Z򲧲jrB-5vZڼ׍uؼb0R>MF)j^ m#U'˘)֘t8Σ'QΘW&x#¸BΈԣݍc-6:"rz:B "yΩ%6# Vpk[303+1dXY3i`ݎcv z]62;lyC_)s8%K®Q "pxA*η ι7<9{>Ma⩾FWV " 2iXG\?ם(Ĕr򶍵5L۪ nrd,⻱G[O܁ijFIF{>XFy3.sD -!c{;C$nlHiרCضbSF-d7Lw}Q1ݎhŮQHd0AN6>aY9H/]_h.zQ]*Ykq¾%ӯ Ruj%B:)!/QyƢDAlQ(qk(*=`^{vs,oS)9‰}'˸ZD"BgiK6y5^QeYN #633ckv|Ci$eAs4ÈPDHbdOg1LFGJJ/ KنA}4!A{Al;1DxA |2-2D{8=F0O˶D1x/V6ɶKA8IT CDWϒ!IڒMOcڜo2^-7V &OHB$1 )9Q!+K2(6c%:CDhgw+b۱.HBS-HFM(!wPV ?{(-MN+NN4ae a,XR)%0M=9ceٿI]/oj'j06oxѭȽCdn&l&eGnD)_Gh$;}NcfM tG&9®Q7p}Q: _oCxM OQJA:"H>J pnJvh* [މMm>5jui1!HQDd'26kq)Gl` U{DHsOAXMv&st,⺟DדJdbL ~ tGN:cZ`?c̗TArA B2 2,1 ŝ "BmJ F$A$Bx@~.I <gړdXK5R׬AIN$Bgg.@HRiO՘>]Ɋ¼A0"$#H,Y+,´]Pdk5vFJAt H5*?sj  ADQ !AA0"$ FAA"$ !AA#$ A  HAA"$~4,XSA"$͐ HA"$DH$B HA"$DHXk׮[N~Ϛ5m۶ݟ'{w7,p }G"$a"|Wv}hEݺu۴iӵkWf۝~QУ%KxV[Cu۷W ٿC uOJ|[*+6H."_rw&L~<8z#GlذDx _B 6EPE)Yc^z%$~D#f͚!  h;ӧ'G|j̘1dR< gϞ@rv0 G?F5F8sÇ#D# Ǐ' "uDn!s>,X$r @!Ut*MvD4mڴVZ pY7ƿl_',e!l޼s < +=wo6!A$ Q@7d00LE}Fmƍ+ :#۷ow5{ӧO]Gs=|@Z P=z~ovń@;w?2xצM槊rF=Jʁ7ahBc>hp~zP<s=J5Fd"ٳ3 %1>}DS7%wbQQÐv =l޼Y,f`#<5; (\MO){onݔҢd~!ZP5kt ӌ=Zxbu M+x(}x{[zQX+VV5dC<8X{ nc=7oD6mxԨQ Y>W1b8ux#fηm0P%E3Tzx衇  Ux?F8p\~^z@ȉjT$?x RRzԢ2d ! 0#~L4 NgN+I"R y(|.&Y#B0Rhx6Q\`y9F`z=ks=7|Gz^A&?V@ҽKhU>YLFÎ+3CLM 4\#"3"a귪az*ȧ HޫW/5OVkqz şșg k(O"G[R)x$rlDD@7Q2 v :(&u˖-ArUUM:U폏j#ܹP#Co}I&҇bku,[P(˗oذVZcǎs@BU*/(qd6 ,\S+.]vZh.7 ;6n܈D/|=`}RuE$*p:|$>, J >%X;gh,gO}$vE= "]ve3hΰ!W_}5^>ah/fc_ )p`g"+.\[Q:ŪUo0_$C͙N>}~T\u%^9ș\DU -/'#;)\X2@$ kxv.\w`.a֒ J/x-9^Qxr'+(So$% 8n82Ȫr o[o^+?هaRůGh[pV``Yg%:[E<&B ` 4D`Qdmڴy ( ZeeԐMЩS'8@HS]GVUU95&VD?яxb .*-|eg1I ,5M> "P>@:+Wࣈi0Hb6mo<B1 JԬYk+7og{o|}2^ Jd"*(D>ap )+Uf'W d!G}Lv=J5?;^_9JGp =h3,xb_~ot8d3آh7'` IG"|?s&NGj%$5X+qqQС~Ϟ=pp]csL>] =ꧪHx%-rBpArs\'CxnZ^=ȩl_Cfdޜ ޽{wr*ĉ3f8s2xeTK..)N!EĂ_<8 L<5"@&F R0b胮5jJ HAXf̘ W/eWj+t2zC8&3gԙ~4ڈ"BRgtTQQle':'I믗(#aTVVF*Zfl䛖V'^$G xe@`q 4Sy&nu 7oެDb0` 8V q_*I> 3Y0ov~5dxzjd ίH!gvUHk_( _NB"BFNT߿?J BIvÇ4i ڵk}/νIy_|9@۶mQ=z@h"j5*j)UU[^GfYF_&BC_>QChy=f yDz)t>+Yf)̼^(䌥EQ8 !C~9C}c*[)$E*Y,t9,3_dL>׏Ο?_]у,#q'`ј7oT\rr<8(" D޽;)(54I铼a6n܈I3b9s<z*\me.ņ l@QL׭[{Td!-*5J*g۹sTj+F?f[[)"#ؘ9k|"DK n:#QTA2pt^x>"D9ߤISPGaY7,'Baj /K'XiӦɄسgOaߨDT,rzi9[ҁUht {مO"P1(pժU[lAv>5U⒜-4SZ+jLڵW^,^瞻3s~B\yZ R @կ~ b-[o^\(利>B<~]vDBixbҀRV6M6lrPdnXp$h3+cW%7B=8py3{ DbRqx^W_}u Wz" ڝzːd@$DUweObϳ,nDP>*`e fE.ڦMYOؽ{wmР<&5/U3f%\t.] l׮ͧ.?堰nݺ _-*hJxBg]z'F! ]x ,@ <~ ^{$ȮƠ"_׉̋4h|ܹBIv){xLJ  Ŵo>(# KVPz/"o ґ͙mLqWw'S K&"MiTf͚*P^K:p_s\kTA)(_4 m^yYG+cO>}qSAaNԒޢ'U^X~;7Q}* 4V@"_NGp.\t' ē'zQ_U9[@yyC ,Bc%T {"!p#/IらXjՌ3r4ZXH qev pվW8(σxjwޜ ԩSG K.y9;$[x 1" oD̚SR!X@ 7o~7oٲ*WD?O:YʻF jCz@Twڥʜ-Z*=*;Db : Y]}1g}{ 9Oj#tXi#~aOyZd:g hݺ-\dFg,GI?OWVV]}do#| =d! j֬ C֔l2Z"FA'93y*B)X? A&pɒ%>HJi {إQV>;/_@ƢQt^?cg* ڏ:׭,GlP#H}HAJx@9 0Ee,I])!5N*3p"$ ;bXQH Zbe"!Aiw HXDH HAp HA"L|&84j(]RFC HVUUG$B RD&&2A"$"]DH$B r]wE-A DHA$B  AD*PAA DHA$B H8FHA0"$ FA  HA"SuperCollider-3.5.beta-OSX.dmgOSX2Users/lijon/Desktop/SuperCollider-3.5.beta-OSX.dmg/ #@,#?#?#@#@Tnone #@H)2H_h}%&/1:CLMOTUV_.icvtshor .pictblob22 SuperCollider7ɭH+background.png<*  SuperCollider7<SuperCollider:background.pngbackground.png SuperCollider/background.png/Volumes/SuperCollider Macintosh HDE:H+SuperCollider-3.5beta1-10.5.dmg< Ny mapp 2E<տHHpuLMacintosh HD:Users:ifields:Desktop:Ny mapp 2:SuperCollider-3.5beta1-10.5.dmg@SuperCollider-3.5beta1-10.5.dmg Macintosh HD?Users/ifields/Desktop/Ny mapp 2/SuperCollider-3.5beta1-10.5.dmg/.vstltype .backgroundfwi0blobdWicnv .backgroundfwvhshor~ ApplicationsIlocblob5background.pngIlocblob 4L@ SuperColliderIlocblob4 E DSDB `(0@ @ @top:SuperCollider-3.5.beta-OSX.dmg>SuperCollider-3.5.beta-OSX.dmgOSX2Users/lijon/Desktop/SuperCollider-3.5.beta-OSX.dmg/ #@,#?#?#@#@Tnone #@H)2H_h}%&/1:CLMOTUV_.icvtshor .pictblob22 SuperCollider7ɭH+background.png<*  SuperCollider7<SuperCollider:background.pngbackground.png SuperCollider/background.png/Volumes/SuperCollider Macintosh HDE:H+SuperCollider-3.6.6-Source-linux~repack/package/git-archive-all.py0000664000000000000000000001560412161364457023715 0ustar rootroot#! /usr/bin/env python import sys from os import path, chdir from subprocess import Popen, PIPE from sys import argv, stdout from fnmatch import fnmatch class GitArchiver(object): """ GitArchiver Scan a git repository and export all tracked files, and submodules. Checks for .gitattributes files in each directory and uses 'export-ignore' pattern entries for ignore files in the archive. Automatically detects output format extension: zip, tar, bz2, or gz """ def __init__(self, prefix='', verbose=False, exclude=True, force_sub=False, extra=[]): self.prefix = prefix self.verbose = verbose self.exclude = exclude self.extra = extra self.force_sub = force_sub self._excludes = [] def create(self, output_file): """ create(str output_file) -> None Creates the archive, written to the given output_file Filetype may be one of: gz, zip, bz2, tar, tgz """ # # determine the format # _, _, format = output_file.rpartition(".") format = format.lower() if format == 'zip': from zipfile import ZipFile, ZIP_DEFLATED output_archive = ZipFile(path.abspath(output_file), 'w') add = lambda name, arcname: output_archive.write(name, self.prefix + arcname, ZIP_DEFLATED) elif format in ['tar', 'bz2', 'gz', 'tgz']: import tarfile if format == 'tar': t_mode = 'w' elif format == 'tgz': t_mode = 'w:gz' else: t_mode = ('w:%s' % format) output_archive = tarfile.open(path.abspath(output_file), t_mode) add = lambda name, arcname: output_archive.add(name, self.prefix + arcname) else: raise RuntimeError("Unknown format: '%s'" % format) # # compress # # extra files first (we may change folder later) for name in self.extra: if self.verbose: toPath = '=> %s%s' % (self.prefix, name) if self.prefix else "" print 'Compressing %s %s ...' % (name, toPath) add(name, name) self._excludes = [] for name, arcname in self.listFiles(path.abspath('')): if self.verbose: toPath = '=> %s%s' % (self.prefix, arcname) if self.prefix else "" print 'Compressing %s %s ...' % (arcname, toPath) add(name, arcname) output_archive.close() def listFiles(self, git_repositary_path, baselevel=''): """ listFiles(str git_repository_path, str baselevel='') -> iterator An iterator method that yields a tuple(filepath, fullpath) for each file that should be included in the archive. Skips those that match the exclusion patterns found in any discovered .gitattributes files along the way. Recurses into submodules as well. """ for filepath in self.runShell('git ls-files --cached --full-name --no-empty-directory'): filepath = filepath.decode('string_escape').strip('"') fullpath = path.join(baselevel, filepath) filename = path.basename(filepath) if self.exclude and filename == '.gitattributes': self._excludes = [] fh = open(filepath, 'r') for line in fh: if not line: break tokens = line.strip().split() if 'export-ignore' in tokens[1:]: self._excludes.append(tokens[0]) fh.close() # Only list symlinks and files that don't start with git if not filename.startswith('.git') \ and (path.islink(filepath) or not path.isdir(filepath)): # check the patterns first ignore = False for pattern in self._excludes: if fnmatch(fullpath, pattern) or fnmatch(filename, pattern): if self.verbose: print 'Exclude pattern matched (%s): %s' % (pattern, fullpath) ignore = True break if ignore: continue # baselevel is needed to tell the arhiver where it have to extract file yield filepath, fullpath if self.force_sub : self.runShell("git submodule init") self.runShell("git submodule update") # get paths for every submodule for submodule in self.runShell("git submodule --quiet foreach 'pwd'"): chdir(submodule) # in order to get output path we need to exclude repository path from the submodule path submodule = submodule[len(git_repositary_path)+1:] # recursion allows us to process repositories with more than one level of submodules for git_file in self.listFiles(git_repositary_path, submodule): yield git_file @staticmethod def runShell(cmd): return Popen(cmd, shell=True, stdout=PIPE).stdout.read().splitlines() if __name__ == "__main__": from optparse import OptionParser parser = OptionParser(usage="usage: %prog [-v] [--prefix PREFIX] [--no-exclude] OUTPUT_FILE", version="%prog 1.3") parser.add_option('--prefix', type='string', dest='prefix', default='', help="prepend PREFIX to each filename in the archive") parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='enable verbose mode') parser.add_option('--no-exclude', action='store_false', dest='exclude', default=True, help="Don't read .gitattributes files for patterns containing export-ignore attrib") parser.add_option('--force-submodules', action='store_true', dest='force_sub', help="Force a git submodule init && git submodule update at each level before iterating submodules.") parser.add_option('--extra', action='append', dest='extra', default=[], help="Any additional files to include in the archive.") options, args = parser.parse_args() if len(args) != 1: parser.error('You must specify exactly one output file') outFile = args[0] if path.isdir(outFile): parser.error('You cannot use directory as output') archiver = GitArchiver(options.prefix, options.verbose, options.exclude, options.force_sub, options.extra) try: archiver.create(outFile) except Exception, e: parser.exit(2, "%s\n" % e) sys.exit(0) SuperCollider-3.6.6-Source-linux~repack/package/git-archive-all.sh0000775000000000000000000001324612014636264023675 0ustar rootroot#!/bin/bash - # # File: git-archive-all.sh # # Description: A utility script that builds an archive file(s) of all # git repositories and submodules in the current path. # Useful for creating a single tarfile of a git super- # project that contains other submodules. # # Examples: Use git-archive-all.sh to create archive distributions # from git repositories. To use, simply do: # # cd $GIT_DIR; git-archive-all.sh # # where $GIT_DIR is the root of your git superproject. # DEBUGGING set -e set -C # noclobber # TRAP SIGNALS trap 'cleanup' QUIT EXIT # For security reasons, explicitly set the internal field separator # to newline, space, tab OLD_IFS=$IFS IFS=' ' function cleanup () { rm -f $TMPFILE rm -f $TOARCHIVE IFS="$OLD_IFS" } function usage () { echo "Usage is as follows:" echo echo "$PROGRAM <--version>" echo " Prints the program version number on a line by itself and exits." echo echo "$PROGRAM <--usage|--help|-?>" echo " Prints this usage output and exits." echo echo "$PROGRAM [--format ] [--prefix ] [--separate|-s] [output_file]" echo " Creates an archive for the entire git superproject, and its submodules" echo " using the passed parameters, described below." echo echo " If '--format' is specified, the archive is created with the named" echo " git archiver backend. Obviously, this must be a backend that git-archive" echo " understands. The format defaults to 'tar' if not specified." echo echo " If '--prefix' is specified, the archive's superproject and all submodules" echo " are created with the prefix named. The default is to not use one." echo echo " If '--separate' or '-s' is specified, individual archives will be created" echo " for each of the superproject itself and its submodules. The default is to" echo " concatenate individual archives into one larger archive." echo echo " If 'output_file' is specified, the resulting archive is created as the" echo " file named. This parameter is essentially a path that must be writeable." echo " When combined with '--separate' ('-s') this path must refer to a directory." echo " Without this parameter or when combined with '--separate' the resulting" echo " archive(s) are named with a dot-separated path of the archived directory and" echo " a file extension equal to their format (e.g., 'superdir.submodule1dir.tar')." } function version () { echo "$PROGRAM version $VERSION" } # Internal variables and initializations. readonly PROGRAM=`basename "$0"` readonly VERSION=0.2 OLD_PWD="`pwd`" TMPDIR=${TMPDIR:-/tmp} TMPFILE=`mktemp "$TMPDIR/$PROGRAM.XXXXXX"` # Create a place to store our work's progress TOARCHIVE=`mktemp "$TMPDIR/$PROGRAM.toarchive.XXXXXX"` OUT_FILE=$OLD_PWD # assume "this directory" without a name change by default SEPARATE=0 FORMAT=tar PREFIX= TREEISH=HEAD # RETURN VALUES/EXIT STATUS CODES readonly E_BAD_OPTION=254 readonly E_UNKNOWN=255 # Process command-line arguments. while test $# -gt 0; do case $1 in --format ) shift FORMAT="$1" shift ;; --prefix ) shift PREFIX="$1" shift ;; --separate | -s ) shift SEPARATE=1 ;; --version ) version exit ;; -? | --usage | --help ) usage exit ;; -* ) echo "Unrecognized option: $1" >&2 usage exit $E_BAD_OPTION ;; * ) break ;; esac done if [ ! -z "$1" ]; then OUT_FILE="$1" shift fi # Validate parameters; error early, error often. if [ $SEPARATE -eq 1 -a ! -d $OUT_FILE ]; then echo "When creating multiple archives, your destination must be a directory." echo "If it's not, you risk being surprised when your files are overwritten." exit elif [ `git config -l | grep -q '^core\.bare=false'; echo $?` -ne 0 ]; then echo "$PROGRAM must be run from a git working copy (i.e., not a bare repository)." exit fi # Create the superproject's git-archive git archive --format=$FORMAT --prefix="$PREFIX" $TREEISH > $TMPDIR/$(basename $(pwd)).$FORMAT echo $TMPDIR/$(basename $(pwd)).$FORMAT >| $TMPFILE # clobber on purpose superfile=`head -n 1 $TMPFILE` # find all '.git' dirs, these show us the remaining to-be-archived dirs find . -name '.git' -type d -print | sed -e 's/^\.\///' -e 's/\.git$//' | grep -v '^$' >> $TOARCHIVE while read path; do TREEISH=$(git submodule | grep "^ .*${path%/} " | cut -d ' ' -f 2) # git-submodule does not list trailing slashes in $path cd "$path" git archive --format=$FORMAT --prefix="${PREFIX}$path" ${TREEISH:-HEAD} > "$TMPDIR"/"$(echo "$path" | sed -e 's/\//./g')"$FORMAT if [ $FORMAT == 'zip' ]; then # delete the empty directory entry; zipped submodules won't unzip if we don't do this zip -d "$(tail -n 1 $TMPFILE)" "${PREFIX}${path%/}" >/dev/null # remove trailing '/' fi echo "$TMPDIR"/"$(echo "$path" | sed -e 's/\//./g')"$FORMAT >> $TMPFILE cd "$OLD_PWD" done < $TOARCHIVE # Concatenate archives into a super-archive. if [ $SEPARATE -eq 0 ]; then if [ $FORMAT == 'tar' ]; then sed -e '1d' $TMPFILE | while read file; do tar --concatenate -f "$superfile" "$file" && rm -f "$file" done elif [ $FORMAT == 'zip' ]; then sed -e '1d' $TMPFILE | while read file; do # zip incorrectly stores the full path, so cd and then grow cd `dirname "$file"` zip -g "$superfile" `basename "$file"` && rm -f "$file" done cd "$OLD_PWD" fi echo "$superfile" >| $TMPFILE # clobber on purpose fi while read file; do mv "$file" "$OUT_FILE" done < $TMPFILE SuperCollider-3.6.6-Source-linux~repack/package/pkg-dmg0000775000000000000000000014364412014636264021650 0ustar rootroot#!/usr/bin/perl # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is pkg-dmg, a Mac OS X disk image (.dmg) packager # # The Initial Developer of the Original Code is # Mark Mentovai . # Portions created by the Initial Developer are Copyright (C) 2005 # the Initial Developer. All Rights Reserved. # # Contributor(s): # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # ***** END LICENSE BLOCK ***** use strict; use warnings; =pod =head1 NAME B - Mac OS X disk image (.dmg) packager =head1 SYNOPSIS B B<--source> I B<--target> I [B<--format> I] [B<--volname> I] [B<--tempdir> I] [B<--mkdir> I] [B<--copy> I[:I]] [B<--symlink> I[:I]] [B<--license> I] [B<--resource> I] [B<--icon> I] [B<--attribute> I:I[:I...] [B<--idme>] [B<--sourcefile>] [B<--verbosity> I] [B<--dry-run>] =head1 DESCRIPTION I takes a directory identified by I and transforms it into a disk image stored as I. The disk image will occupy the least space possible for its format, or the least space that the authors have been able to figure out how to achieve. =head1 OPTIONS =over 5 ==item B<--source> I Identifies the directory that will be packaged up. This directory is not touched, a copy will be made in a temporary directory for staging purposes. See B<--tempdir>. ==item B<--target> I The disk image to create. If it exists and is not in use, it will be overwritten. If I already contains a suitable extension, it will be used unmodified. If no extension is present, or the extension is incorrect for the selected format, the proper extension will be added. See B<--format>. ==item B<--format> I The format to create the disk image in. Valid values for I are: - UDZO - zlib-compressed, read-only; extension I<.dmg> - UDBZ - bzip2-compressed, read-only; extension I<.dmg>; create and use on 10.4 ("Tiger") and later only - UDRW - read-write; extension I<.dmg> - UDSP - read-write, sparse; extension I<.sparseimage> UDZO is the default format. See L for a description of these formats. =item B<--volname> I The name of the volume in the disk image. If not specified, I defaults to the name of the source directory from B<--source>. =item B<--tempdir> I A temporary directory to stage intermediate files in. I must have enough space available to accommodate twice the size of the files being packaged. If not specified, defaults to the same directory that the I is to be placed in. B will remove any temporary files it places in I. =item B<--mkdir> I Specifies a directory that should be created in the disk image. I and any ancestor directories will be created. This is useful in conjunction with B<--copy>, when copying files to directories that may not exist in I. B<--mkdir> may appear multiple times. =item B<--copy> I[:I] Additional files to copy into the disk image. If I is specified, I is copied to the location I identifies, otherwise, I is copied to the root of the new volume. B<--copy> provides a way to package up a I by adding files to it without modifying the original I. B<--copy> may appear multiple times. This option is useful for adding .DS_Store files and window backgrounds to disk images. =item B<--symlink> I[:I] Like B<--copy>, but allows symlinks to point out of the volume. Empty symlink destinations are interpreted as "like the source path, but inside the dmg" This option is useful for adding symlinks to external resources, e.g. to /Applications. =item B<--license> I A plain text file containing a license agreement to be displayed before the disk image is mounted. English is the only supported language. To include license agreements in other languages, in multiple languages, or to use formatted text, prepare a resource and use L<--resource>. =item B<--resource> I A resource file to merge into I. If I is UDZO or UDBZ, the disk image will be flattened to a single-fork file that contains the resource but may be freely transferred without any special encodings. I must be in a format suitable for L. See L for a description of the format, and L for a discussion on flattened disk images. B<--resource> may appear multiple times. This option is useful for adding license agreements and other messages to disk images. =item B<--icon> I Specifies an I file that will be used as the icon for the root of the volume. This file will be copied to the new volume and the custom icon attribute will be set on the root folder. =item B<--attribute> I:I[:I...] Sets the attributes of I to the attribute list in I. See L =item B<--idme> Enable IDME to make the disk image "Internet-enabled." The first time the image is mounted, if IDME processing is enabled on the system, the contents of the image will be copied out of the image and the image will be placed in the trash with IDME disabled. =item B<--sourcefile> If this option is present, I is treated as a file, and is placed as a file within the volume's root folder. Without this option, I is treated as the volume root itself. =item B<--verbosity> I Adjusts the level of loudness of B. The possible values for I are: 0 - Only error messages are displayed. 1 - Print error messages and command invocations. 2 - Print everything, including command output. The default I is 2. =item B<--dry-run> When specified, the commands that would be executed are printed, without actually executing them. When commands depend on the output of previous commands, dummy values are displayed. =back =head1 NON-OPTIONS =over 5 =item Resource forks aren't copied. =item The root folder of the created volume is designated as the folder to open when the volume is mounted. See L. =item All files in the volume are set to be world-readable, only writable by the owner, and world-executable when appropriate. All other permissions bits are cleared. =item When possible, disk images are created without any partition tables. This is what L refers to as I<-layout NONE>, and saves a handful of kilobytes. The alternative, I, contains a partition table that is not terribly handy on disk images that are not intended to represent any physical disk. =item Read-write images are created with journaling off. Any read-write image created by this tool is expected to be transient, and the goal of this tool is to create images which consume a minimum of space. =back =head1 EXAMPLE pkg-dmg --source /Applications/DeerPark.app --target ~/DeerPark.dmg --sourcefile --volname DeerPark --icon ~/DeerPark.icns --mkdir /.background --copy DeerParkBackground.png:/.background/background.png --copy DeerParkDSStore:/.DS_Store --symlink /Applications:"/Drag to here" =head1 REQUIREMENTS I has been tested with Mac OS X releases 10.2 ("Jaguar") through 10.4 ("Tiger"). Certain adjustments to behavior are made depending on the host system's release. Mac OS X 10.3 ("Panther") or later are recommended. =head1 LICENSE MPL 1.1/GPL 2.0/LGPL 2.1. Your choice. =head1 AUTHOR Mark Mentovai =head1 SEE ALSO L, L, L, L, L, L, L =cut use Fcntl; use POSIX; use Getopt::Long; sub argumentEscape(@); sub cleanupDie($); sub command(@); sub commandInternal($@); sub commandInternalVerbosity($$@); sub commandOutput(@); sub commandOutputVerbosity($@); sub commandVerbosity($@); sub copyFiles($@); sub diskImageMaker($$$$$$$$); sub giveExtension($$); sub hdidMountImage($@); sub isFormatCompressed($); sub licenseMaker($$); sub pathSplit($); sub setAttributes($@); sub trapSignal($); sub usage(); # Variables used as globals my(@gCleanup, %gConfig, $gDarwinMajor, $gDryRun, $gVerbosity); # Use the commands by name if they're expected to be in the user's # $PATH (/bin:/sbin:/usr/bin:/usr/sbin). Otherwise, go by absolute # path. These may be overridden with --config. %gConfig = ('cmd_bless' => 'bless', 'cmd_chmod' => 'chmod', 'cmd_diskutil' => 'diskutil', 'cmd_du' => 'du', 'cmd_hdid' => 'hdid', 'cmd_hdiutil' => 'hdiutil', 'cmd_mkdir' => 'mkdir', 'cmd_mktemp' => 'mktemp', 'cmd_Rez' => '/Developer/Tools/Rez', 'cmd_rm' => 'rm', 'cmd_rsync' => 'rsync', 'cmd_SetFile' => '/Developer/Tools/SetFile', # create_directly indicates whether hdiutil create supports # -srcfolder and -srcdevice. It does on >= 10.3 (Panther). # This is fixed up for earlier systems below. If false, # hdiutil create is used to create empty disk images that # are manually filled. 'create_directly' => 1, # If hdiutil attach -mountpoint exists, use it to avoid # mounting disk images in the default /Volumes. This reduces # the likelihood that someone will notice a mounted image and # interfere with it. Only available on >= 10.3 (Panther), # fixed up for earlier systems below. # # This is presently turned off for all systems, because there # is an infrequent synchronization problem during ejection. # diskutil eject might return before the image is actually # unmounted. If pkg-dmg then attempts to clean up its # temporary directory, it could remove items from a read-write # disk image or attempt to remove items from a read-only disk # image (or a read-only item from a read-write image) and fail, # causing pkg-dmg to abort. This problem is experienced # under Tiger, which appears to eject asynchronously where # previous systems treated it as a synchronous operation. # Using hdiutil attach -mountpoint didn't always keep images # from showing up on the desktop anyway. 'hdiutil_mountpoint' => 0, # hdiutil makehybrid results in optimized disk images that # consume less space and mount more quickly. Use it when # it's available, but that's only on >= 10.3 (Panther). # If false, hdiutil create is used instead. Fixed up for # earlier systems below. 'makehybrid' => 1, # hdiutil create doesn't allow specifying a folder to open # at volume mount time, so those images are mounted and # their root folders made holy with bless -openfolder. But # only on >= 10.3 (Panther). Earlier systems are out of luck. # Even on Panther, bless refuses to run unless root. # Fixed up below. 'openfolder_bless' => 1, # It's possible to save a few more kilobytes by including the # partition only without any partition table in the image. # This is a good idea on any system, so turn this option off. # # Except it's buggy. "-layout NONE" seems to be creating # disk images with more data than just the partition table # stripped out. You might wind up losing the end of the # filesystem - the last file (or several) might be incomplete. 'partition_table' => 1, # To create a partition table-less image from something # created by makehybrid, the hybrid image needs to be # mounted and a new image made from the device associated # with the relevant partition. This requires >= 10.4 # (Tiger), presumably because earlier systems have # problems creating images from devices themselves attached # to images. If this is false, makehybrid images will # have partition tables, regardless of the partition_table # setting. Fixed up for earlier systems below. 'recursive_access' => 1); # --verbosity $gVerbosity = 2; # --dry-run $gDryRun = 0; # %gConfig fix-ups based on features and bugs present in certain releases. my($ignore, $uname_r, $uname_s); ($uname_s, $ignore, $uname_r, $ignore, $ignore) = POSIX::uname(); if($uname_s eq 'Darwin') { ($gDarwinMajor, $ignore) = split(/\./, $uname_r, 2); # $major is the Darwin major release, which for our purposes, is 4 higher # than the interesting digit in a Mac OS X release. if($gDarwinMajor <= 6) { # <= 10.2 (Jaguar) # hdiutil create does not support -srcfolder or -srcdevice $gConfig{'create_directly'} = 0; # hdiutil attach does not support -mountpoint $gConfig{'hdiutil_mountpoint'} = 0; # hdiutil mkhybrid does not exist $gConfig{'makehybrid'} = 0; } if($gDarwinMajor <= 7) { # <= 10.3 (Panther) # Can't mount a disk image and then make a disk image from the device $gConfig{'recursive_access'} = 0; # bless does not support -openfolder on 10.2 (Jaguar) and must run # as root under 10.3 (Panther) $gConfig{'openfolder_bless'} = 0; } } else { # If it's not Mac OS X, just assume all of those good features are # available. They're not, but things will fail long before they # have a chance to make a difference. # # Now, if someone wanted to document some of these private formats... print STDERR ($0.": warning, not running on Mac OS X, ". "this could be interesting.\n"); } # Non-global variables used in Getopt my(@attributes, @copyFiles, @createSymlinks, $iconFile, $idme, $licenseFile, @makeDirs, $outputFormat, @resourceFiles, $sourceFile, $sourceFolder, $targetImage, $tempDir, $volumeName); # --format $outputFormat = 'UDZO'; # --idme $idme = 0; # --sourcefile $sourceFile = 0; # Leaving this might screw up the Apple tools. delete $ENV{'NEXT_ROOT'}; # This script can get pretty messy, so trap a few signals. $SIG{'INT'} = \&trapSignal; $SIG{'HUP'} = \&trapSignal; $SIG{'TERM'} = \&trapSignal; Getopt::Long::Configure('pass_through'); GetOptions('source=s' => \$sourceFolder, 'target=s' => \$targetImage, 'volname=s' => \$volumeName, 'format=s' => \$outputFormat, 'tempdir=s' => \$tempDir, 'mkdir=s' => \@makeDirs, 'copy=s' => \@copyFiles, 'symlink=s' => \@createSymlinks, 'license=s' => \$licenseFile, 'resource=s' => \@resourceFiles, 'icon=s' => \$iconFile, 'attribute=s' => \@attributes, 'idme' => \$idme, 'sourcefile' => \$sourceFile, 'verbosity=i' => \$gVerbosity, 'dry-run' => \$gDryRun, 'config=s' => \%gConfig); # "hidden" option not in usage() if(@ARGV) { # All arguments are parsed by Getopt usage(); exit(1); } if($gVerbosity<0 || $gVerbosity>2) { usage(); exit(1); } if(!defined($sourceFolder) || $sourceFolder eq '' || !defined($targetImage) || $targetImage eq '') { # --source and --target are required arguments usage(); exit(1); } # Make sure $sourceFolder doesn't contain trailing slashes. It messes with # rsync. while(substr($sourceFolder, -1) eq '/') { chop($sourceFolder); } if(!defined($volumeName)) { # Default volumeName is the name of the source directory. my(@components); @components = pathSplit($sourceFolder); $volumeName = pop(@components); } my(@tempDirComponents, $targetImageFilename); @tempDirComponents = pathSplit($targetImage); $targetImageFilename = pop(@tempDirComponents); if(defined($tempDir)) { @tempDirComponents = pathSplit($tempDir); } else { # Default tempDir is the same directory as what is specified for # targetImage $tempDir = join('/', @tempDirComponents); } # Ensure that the path of the target image has a suitable extension. If # it didn't, hdiutil would add one, and we wouldn't be able to find the # file. # # Note that $targetImageFilename is not being reset. This is because it's # used to build other names below, and we don't need to be adding all sorts # of extra unnecessary extensions to the name. my($originalTargetImage, $requiredExtension); $originalTargetImage = $targetImage; if($outputFormat eq 'UDSP') { $requiredExtension = '.sparseimage'; } else { $requiredExtension = '.dmg'; } $targetImage = giveExtension($originalTargetImage, $requiredExtension); if($targetImage ne $originalTargetImage) { print STDERR ($0.": warning: target image extension is being added\n"); print STDERR (' The new filename is '. giveExtension($targetImageFilename,$requiredExtension)."\n"); } # Make a temporary directory in $tempDir for our own nefarious purposes. my(@output, $tempSubdir, $tempSubdirTemplate); $tempSubdirTemplate=join('/', @tempDirComponents, 'pkg-dmg.'.$$.'.XXXXXXXX'); if(!(@output = commandOutput($gConfig{'cmd_mktemp'}, '-d', $tempSubdirTemplate)) || $#output != 0) { cleanupDie('mktemp failed'); } if($gDryRun) { (@output)=($tempSubdirTemplate); } ($tempSubdir) = @output; push(@gCleanup, sub {commandVerbosity(0, $gConfig{'cmd_rm'}, '-rf', $tempSubdir);}); my($tempMount, $tempRoot, @tempsToMake); $tempRoot = $tempSubdir.'/stage'; $tempMount = $tempSubdir.'/mount'; push(@tempsToMake, $tempRoot); if($gConfig{'hdiutil_mountpoint'}) { push(@tempsToMake, $tempMount); } if(command($gConfig{'cmd_mkdir'}, @tempsToMake) != 0) { cleanupDie('mkdir tempRoot/tempMount failed'); } # This cleanup object is not strictly necessary, because $tempRoot is inside # of $tempSubdir, but the rest of the script relies on this object being # on the cleanup stack and expects to remove it. push(@gCleanup, sub {commandVerbosity(0, $gConfig{'cmd_rm'}, '-rf', $tempRoot);}); # If $sourceFile is true, it means that $sourceFolder is to be treated as # a file and placed as a file within the volume root, as opposed to being # treated as the volume root itself. rsync will do this by default, if no # trailing '/' is present. With a trailing '/', $sourceFolder becomes # $tempRoot, instead of becoming an entry in $tempRoot. if(command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links', $sourceFolder.($sourceFile?'':'/'),$tempRoot) != 0) { cleanupDie('rsync failed'); } if(@makeDirs) { my($makeDir, @tempDirsToMake); foreach $makeDir (@makeDirs) { if($makeDir =~ /^\//) { push(@tempDirsToMake, $tempRoot.$makeDir); } else { push(@tempDirsToMake, $tempRoot.'/'.$makeDir); } } if(command($gConfig{'cmd_mkdir'}, '-p', @tempDirsToMake) != 0) { cleanupDie('mkdir failed'); } } # copy files and/or create symlinks copyFiles($tempRoot, 'copy', @copyFiles); copyFiles($tempRoot, 'symlink', @createSymlinks); if($gConfig{'create_directly'}) { # If create_directly is false, the contents will be rsynced into a # disk image and they would lose their attributes. setAttributes($tempRoot, @attributes); } if(defined($iconFile)) { if(command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links', $iconFile, $tempRoot.'/.VolumeIcon.icns') != 0) { cleanupDie('rsync failed for volume icon'); } # It's pointless to set the attributes of the root when diskutil create # -srcfolder is being used. In that case, the attributes will be set # later, after the image is already created. if(isFormatCompressed($outputFormat) && (command($gConfig{'cmd_SetFile'}, '-a', 'C', $tempRoot) != 0)) { cleanupDie('SetFile failed'); } } if(command($gConfig{'cmd_chmod'}, '-R', 'a+rX,a-st,u+w,go-w', $tempRoot) != 0) { cleanupDie('chmod failed'); } my($unflattenable); if(isFormatCompressed($outputFormat)) { $unflattenable = 1; } else { $unflattenable = 0; } diskImageMaker($tempRoot, $targetImage, $outputFormat, $volumeName, $tempSubdir, $tempMount, $targetImageFilename, defined($iconFile)); if(defined($licenseFile) && $licenseFile ne '') { my($licenseResource); $licenseResource = $tempSubdir.'/license.r'; if(!licenseMaker($licenseFile, $licenseResource)) { cleanupDie('licenseMaker failed'); } push(@resourceFiles, $licenseResource); # Don't add a cleanup object because licenseResource is in tempSubdir. } if(@resourceFiles) { # Add resources, such as a license agreement. # Only unflatten read-only and compressed images. It's not supported # on other image times. if($unflattenable && (command($gConfig{'cmd_hdiutil'}, 'unflatten', $targetImage)) != 0) { cleanupDie('hdiutil unflatten failed'); } # Don't push flatten onto the cleanup stack. If we fail now, we'll be # removing $targetImage anyway. # Type definitions come from Carbon.r. if(command($gConfig{'cmd_Rez'}, 'Carbon.r', @resourceFiles, '-a', '-o', $targetImage) != 0) { cleanupDie('Rez failed'); } # Flatten. This merges the resource fork into the data fork, so no # special encoding is needed to transfer the file. if($unflattenable && (command($gConfig{'cmd_hdiutil'}, 'flatten', $targetImage)) != 0) { cleanupDie('hdiutil flatten failed'); } } # $tempSubdir is no longer needed. It's buried on the stack below the # rm of the fresh image file. Splice in this fashion is equivalent to # pop-save, pop, push-save. splice(@gCleanup, -2, 1); # No need to remove licenseResource separately, it's in tempSubdir. if(command($gConfig{'cmd_rm'}, '-rf', $tempSubdir) != 0) { cleanupDie('rm -rf tempSubdir failed'); } if($idme) { if(command($gConfig{'cmd_hdiutil'}, 'internet-enable', '-yes', $targetImage) != 0) { cleanupDie('hdiutil internet-enable failed'); } } # Done. exit(0); # argumentEscape(@arguments) # # Takes a list of @arguments and makes them shell-safe. sub argumentEscape(@) { my(@arguments); @arguments = @_; my($argument, @argumentsOut); foreach $argument (@arguments) { $argument =~ s%([^A-Za-z0-9_\-/.=+,])%\\$1%g; push(@argumentsOut, $argument); } return @argumentsOut; } # cleanupDie($message) # # Displays $message as an error message, and then runs through the # @gCleanup stack, performing any cleanup operations needed before # exiting. Does not return, exits with exit status 1. sub cleanupDie($) { my($message); ($message) = @_; print STDERR ($0.': '.$message.(@gCleanup?' (cleaning up)':'')."\n"); while(@gCleanup) { my($subroutine); $subroutine = pop(@gCleanup); &$subroutine; } exit(1); } # command(@arguments) # # Runs the specified command at the verbosity level defined by $gVerbosity. # Returns nonzero on failure, returning the exit status if appropriate. # Discards command output. sub command(@) { my(@arguments); @arguments = @_; return commandVerbosity($gVerbosity,@arguments); } # commandInternal($command, @arguments) # # Runs the specified internal command at the verbosity level defined by # $gVerbosity. # Returns zero(!) on failure, because commandInternal is supposed to be a # direct replacement for the Perl system call wrappers, which, unlike shell # commands and C equivalent system calls, return true (instead of 0) to # indicate success. sub commandInternal($@) { my(@arguments, $command); ($command, @arguments) = @_; return commandInternalVerbosity($gVerbosity, $command, @arguments); } # commandInternalVerbosity($verbosity, $command, @arguments) # # Run an internal command, printing a bogus command invocation message if # $verbosity is true. # # If $command is unlink: # Removes the files specified by @arguments. Wraps unlink. # # If $command is symlink: # Creates the symlink specified by @arguments. Wraps symlink. sub commandInternalVerbosity($$@) { my(@arguments, $command, $verbosity); ($verbosity, $command, @arguments) = @_; if($command eq 'unlink') { if($verbosity || $gDryRun) { print(join(' ', 'rm', '-f', argumentEscape(@arguments))."\n"); } if($gDryRun) { return $#arguments+1; } return unlink(@arguments); } elsif($command eq 'symlink') { if($verbosity || $gDryRun) { print(join(' ', 'ln', '-s', argumentEscape(@arguments))."\n"); } if($gDryRun) { return 1; } my($source, $target); ($source, $target) = @arguments; return symlink($source, $target); } } # commandOutput(@arguments) # # Runs the specified command at the verbosity level defined by $gVerbosity. # Output is returned in an array of lines. undef is returned on failure. # The exit status is available in $?. sub commandOutput(@) { my(@arguments); @arguments = @_; return commandOutputVerbosity($gVerbosity, @arguments); } # commandOutputVerbosity($verbosity, @arguments) # # Runs the specified command at the verbosity level defined by the # $verbosity argument. Output is returned in an array of lines. undef is # returned on failure. The exit status is available in $?. # # If an error occurs in fork or exec, an error message is printed to # stderr and undef is returned. # # If $verbosity is 0, the command invocation is not printed, and its # stdout is not echoed back to stdout. # # If $verbosity is 1, the command invocation is printed. # # If $verbosity is 2, the command invocation is printed and the output # from stdout is echoed back to stdout. # # Regardless of $verbosity, stderr is left connected. sub commandOutputVerbosity($@) { my(@arguments, $verbosity); ($verbosity, @arguments) = @_; my($pid); if($verbosity || $gDryRun) { print(join(' ', argumentEscape(@arguments))."\n"); } if($gDryRun) { return(1); } if (!defined($pid = open(*COMMAND, '-|'))) { printf STDERR ($0.': fork: '.$!."\n"); return undef; } elsif ($pid) { # parent my(@lines); while(!eof(*COMMAND)) { my($line); chop($line = ); if($verbosity > 1) { print($line."\n"); } push(@lines, $line); } close(*COMMAND); if ($? == -1) { printf STDERR ($0.': fork: '.$!."\n"); return undef; } elsif ($? & 127) { printf STDERR ($0.': exited on signal '.($? & 127). ($? & 128 ? ', core dumped' : '')."\n"); return undef; } return @lines; } else { # child; this form of exec is immune to shell games if(!exec {$arguments[0]} (@arguments)) { printf STDERR ($0.': exec: '.$!."\n"); exit(-1); } } } # commandVerbosity($verbosity, @arguments) # # Runs the specified command at the verbosity level defined by the # $verbosity argument. Returns nonzero on failure, returning the exit # status if appropriate. Discards command output. sub commandVerbosity($@) { my(@arguments, $verbosity); ($verbosity, @arguments) = @_; if(!defined(commandOutputVerbosity($verbosity, @arguments))) { return -1; } return $?; } # copyFiles($tempRoot, $method, @arguments) # # Copies files or create symlinks in the disk image. # See --copy and --symlink descriptions for details. # If $method is 'copy', @arguments are interpreted as source:target, if $method # is 'symlink', @arguments are interpreted as symlink:target. sub copyFiles($@) { my(@fileList, $method, $tempRoot); ($tempRoot, $method, @fileList) = @_; my($file, $isSymlink); $isSymlink = ($method eq 'symlink'); foreach $file (@fileList) { my($source, $target); ($source, $target) = split(/:/, $file); if(!defined($target) and $isSymlink) { # empty symlink targets would result in an invalid target and fail, # but they shall be interpreted as "like source path, but inside dmg" $target = $source; } if(!defined($target)) { $target = $tempRoot; } elsif($target =~ /^\//) { $target = $tempRoot.$target; } else { $target = $tempRoot.'/'.$target; } my($success); if($isSymlink) { $success = commandInternal('symlink', $source, $target); } else { $success = !command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links', $source, $target); } if(!$success) { cleanupDie('copyFiles failed for method '.$method); } } } # diskImageMaker($source, $destination, $format, $name, $tempDir, $tempMount, # $baseName, $setRootIcon) # # Creates a disk image in $destination of format $format corresponding to the # source directory $source. $name is the volume name. $tempDir is a good # place to write temporary files, which should be empty (aside from the other # things that this script might create there, like stage and mount). # $tempMount is a mount point for temporary disk images. $baseName is the # name of the disk image, and is presently unused. $setRootIcon is true if # a volume icon was added to the staged $source and indicates that the # custom volume icon bit on the volume root needs to be set. sub diskImageMaker($$$$$$$$) { my($baseName, $destination, $format, $name, $setRootIcon, $source, $tempDir, $tempMount); ($source, $destination, $format, $name, $tempDir, $tempMount, $baseName, $setRootIcon) = @_; if(isFormatCompressed($format)) { my($uncompressedImage); if($gConfig{'makehybrid'}) { my($hybridImage); $hybridImage = giveExtension($tempDir.'/hybrid', '.dmg'); if(command($gConfig{'cmd_hdiutil'}, 'makehybrid', '-hfs', '-hfs-volume-name', $name, '-hfs-openfolder', $source, '-ov', $source, '-o', $hybridImage) != 0) { cleanupDie('hdiutil makehybrid failed'); } $uncompressedImage = $hybridImage; # $source is no longer needed and will be removed before anything # else can fail. splice in this form is the same as pop/push. splice(@gCleanup, -1, 1, sub {commandInternalVerbosity(0, 'unlink', $hybridImage);}); if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) { cleanupDie('rm -rf failed'); } if(!$gConfig{'partition_table'} && $gConfig{'recursive_access'}) { # Even if we do want to create disk images without partition tables, # it's impossible unless recursive_access is set. my($rootDevice, $partitionDevice, $partitionMountPoint); if(!(($rootDevice, $partitionDevice, $partitionMountPoint) = hdidMountImage($tempMount, '-readonly', $hybridImage))) { cleanupDie('hdid mount failed'); } push(@gCleanup, sub {commandVerbosity(0, $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);}); my($udrwImage); $udrwImage = giveExtension($tempDir.'/udrw', '.dmg'); if(command($gConfig{'cmd_hdiutil'}, 'create', '-format', 'UDRW', '-ov', '-srcdevice', $partitionDevice, $udrwImage) != 0) { cleanupDie('hdiutil create failed'); } $uncompressedImage = $udrwImage; # Going to eject before anything else can fail. Get the eject off # the stack. pop(@gCleanup); # $hybridImage will be removed soon, but until then, it needs to # stay on the cleanup stack. It needs to wait until after # ejection. $udrwImage is staying around. Make it appear as # though it's been done before $hybridImage. # # splice in this form is the same as popping one element to # @tempCleanup and pushing the subroutine. my(@tempCleanup); @tempCleanup = splice(@gCleanup, -1, 1, sub {commandInternalVerbosity(0, 'unlink', $udrwImage);}); push(@gCleanup, @tempCleanup); if(command($gConfig{'cmd_diskutil'}, 'eject', $rootDevice) != 0) { cleanupDie('diskutil eject failed'); } # Pop unlink of $uncompressedImage pop(@gCleanup); if(commandInternal('unlink', $hybridImage) != 1) { cleanupDie('unlink hybridImage failed: '.$!); } } } else { # makehybrid is not available, fall back to making a UDRW and # converting to a compressed image. It ought to be possible to # create a compressed image directly, but those come out far too # large (journaling?) and need to be read-write to fix up the # volume icon anyway. Luckily, we can take advantage of a single # call back into this function. my($udrwImage); $udrwImage = giveExtension($tempDir.'/udrw', '.dmg'); diskImageMaker($source, $udrwImage, 'UDRW', $name, $tempDir, $tempMount, $baseName, $setRootIcon); # The call back into diskImageMaker already removed $source. $uncompressedImage = $udrwImage; } # The uncompressed disk image is now in its final form. Compress it. # Jaguar doesn't support hdiutil convert -ov, but it always allows # overwriting. # bzip2-compressed UDBZ images can only be created and mounted on 10.4 # and later. The bzip2-level imagekey is only effective when creating # images in 10.5. In 10.4, bzip2-level is harmlessly ignored, and the # default value of 1 is always used. if(command($gConfig{'cmd_hdiutil'}, 'convert', '-format', $format, '-imagekey', ($format eq 'UDBZ' ? 'bzip2-level=9' : 'zlib-level=9'), (defined($gDarwinMajor) && $gDarwinMajor <= 6 ? () : ('-ov')), $uncompressedImage, '-o', $destination) != 0) { cleanupDie('hdiutil convert failed'); } # $uncompressedImage is going to be unlinked before anything else can # fail. splice in this form is the same as pop/push. splice(@gCleanup, -1, 1, sub {commandInternalVerbosity(0, 'unlink', $destination);}); if(commandInternal('unlink', $uncompressedImage) != 1) { cleanupDie('unlink uncompressedImage failed: '.$!); } # At this point, the only thing that the compressed block has added to # the cleanup stack is the removal of $destination. $source has already # been removed, and its cleanup entry has been removed as well. } elsif($format eq 'UDRW' || $format eq 'UDSP') { my(@extraArguments); if(!$gConfig{'partition_table'}) { @extraArguments = ('-layout', 'NONE'); } if($gConfig{'create_directly'}) { # Use -fs HFS+ to suppress the journal. if(command($gConfig{'cmd_hdiutil'}, 'create', '-format', $format, @extraArguments, '-fs', 'HFS+', '-volname', $name, '-ov', '-srcfolder', $source, $destination) != 0) { cleanupDie('hdiutil create failed'); } # $source is no longer needed and will be removed before anything # else can fail. splice in this form is the same as pop/push. splice(@gCleanup, -1, 1, sub {commandInternalVerbosity(0, 'unlink', $destination);}); if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) { cleanupDie('rm -rf failed'); } } else { # hdiutil create does not support -srcfolder or -srcdevice, it only # knows how to create blank images. Figure out how large an image # is needed, create it, and fill it. This is needed for Jaguar. # Use native block size for hdiutil create -sectors. delete $ENV{'BLOCKSIZE'}; my(@duOutput, $ignore, $sizeBlocks, $sizeOverhead, $sizeTotal, $type); if(!(@output = commandOutput($gConfig{'cmd_du'}, '-s', $tempRoot)) || $? != 0) { cleanupDie('du failed'); } ($sizeBlocks, $ignore) = split(' ', $output[0], 2); # The filesystem itself takes up 152 blocks of its own blocks for the # filesystem up to 8192 blocks, plus 64 blocks for every additional # 4096 blocks or portion thereof. $sizeOverhead = 152 + 64 * POSIX::ceil( (($sizeBlocks - 8192) > 0) ? (($sizeBlocks - 8192) / (4096 - 64)) : 0); # The number of blocks must be divisible by 8. my($mod); if($mod = ($sizeOverhead % 8)) { $sizeOverhead += 8 - $mod; } # sectors is taken as the size of a disk, not a filesystem, so the # partition table eats into it. if($gConfig{'partition_table'}) { $sizeOverhead += 80; } # That was hard. Leave some breathing room anyway. Use 1024 sectors # (512kB). These read-write images wouldn't be useful if they didn't # have at least a little free space. $sizeTotal = $sizeBlocks + $sizeOverhead + 1024; # Minimum sizes - these numbers are larger on Jaguar than on later # systems. Just use the Jaguar numbers, since it's unlikely to wind # up here on any other release. if($gConfig{'partition_table'} && $sizeTotal < 8272) { $sizeTotal = 8272; } if(!$gConfig{'partition_table'} && $sizeTotal < 8192) { $sizeTotal = 8192; } # hdiutil create without -srcfolder or -srcdevice will not accept # -format. It uses -type. Fortunately, the two supported formats # here map directly to the only two supported types. if ($format eq 'UDSP') { $type = 'SPARSE'; } else { $type = 'UDIF'; } if(command($gConfig{'cmd_hdiutil'}, 'create', '-type', $type, @extraArguments, '-fs', 'HFS+', '-volname', $name, '-ov', '-sectors', $sizeTotal, $destination) != 0) { cleanupDie('hdiutil create failed'); } push(@gCleanup, sub {commandInternalVerbosity(0, 'unlink', $destination);}); # The rsync will occur shortly. } my($mounted, $rootDevice, $partitionDevice, $partitionMountPoint); $mounted=0; if(!$gConfig{'create_directly'} || $gConfig{'openfolder_bless'} || $setRootIcon) { # The disk image only needs to be mounted if: # create_directly is false, because the content needs to be copied # openfolder_bless is true, because bless -openfolder needs to run # setRootIcon is true, because the root needs its attributes set. if(!(($rootDevice, $partitionDevice, $partitionMountPoint) = hdidMountImage($tempMount, $destination))) { cleanupDie('hdid mount failed'); } $mounted=1; push(@gCleanup, sub {commandVerbosity(0, $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);}); } if(!$gConfig{'create_directly'}) { # Couldn't create and copy directly in one fell swoop. Now that # the volume is mounted, copy the files. --copy-unsafe-links is # unnecessary since it was used to copy everything to the staging # area. There can be no more unsafe links. if(command($gConfig{'cmd_rsync'}, '-a', $source.'/',$partitionMountPoint) != 0) { cleanupDie('rsync to new volume failed'); } # We need to get the rm -rf of $source off the stack, because it's # being cleaned up here. There are two items now on top of it: # removing the target image and, above that, ejecting it. Splice it # out. my(@tempCleanup); @tempCleanup = splice(@gCleanup, -2); # The next splice is the same as popping once and pushing @tempCleanup. splice(@gCleanup, -1, 1, @tempCleanup); if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) { cleanupDie('rm -rf failed'); } } if($gConfig{'openfolder_bless'}) { # On Tiger, the bless docs say to use --openfolder, but only # --openfolder is accepted on Panther. Tiger takes it with a single # dash too. Jaguar is out of luck. if(command($gConfig{'cmd_bless'}, '-openfolder', $partitionMountPoint) != 0) { cleanupDie('bless failed'); } } setAttributes($partitionMountPoint, @attributes); if($setRootIcon) { # When "hdiutil create -srcfolder" is used, the root folder's # attributes are not copied to the new volume. Fix up. if(command($gConfig{'cmd_SetFile'}, '-a', 'C', $partitionMountPoint) != 0) { cleanupDie('SetFile failed'); } } if($mounted) { # Pop diskutil eject pop(@gCleanup); if(command($gConfig{'cmd_diskutil'}, 'eject', $rootDevice) != 0) { cleanupDie('diskutil eject failed'); } } # End of UDRW/UDSP section. At this point, $source has been removed # and its cleanup entry has been removed from the stack. } else { cleanupDie('unrecognized format'); print STDERR ($0.": unrecognized format\n"); exit(1); } } # giveExtension($file, $extension) # # If $file does not end in $extension, $extension is added. The new # filename is returned. sub giveExtension($$) { my($extension, $file); ($file, $extension) = @_; if(substr($file, -length($extension)) ne $extension) { return $file.$extension; } return $file; } # hdidMountImage($mountPoint, @arguments) # # Runs the hdid command with arguments specified by @arguments. # @arguments may be a single-element array containing the name of the # disk image to mount. Returns a three-element array, with elements # corresponding to: # - The root device of the mounted image, suitable for ejection # - The device corresponding to the mounted partition # - The mounted partition's mount point # # If running on a system that supports easy mounting at points outside # of the default /Volumes with hdiutil attach, it is used instead of hdid, # and $mountPoint is used as the mount point. # # The root device will differ from the partition device when the disk # image contains a partition table, otherwise, they will be identical. # # If hdid fails, undef is returned. sub hdidMountImage($@) { my(@arguments, @command, $mountPoint); ($mountPoint, @arguments) = @_; my(@output); if($gConfig{'hdiutil_mountpoint'}) { @command=($gConfig{'cmd_hdiutil'}, 'attach', @arguments, '-mountpoint', $mountPoint); } else { @command=($gConfig{'cmd_hdid'}, @arguments); } if(!(@output = commandOutput(@command)) || $? != 0) { return undef; } if($gDryRun) { return('/dev/diskX','/dev/diskXsY','/Volumes/'.$volumeName); } my($line, $restOfLine, $rootDevice); foreach $line (@output) { my($device, $mountpoint); if($line !~ /^\/dev\//) { # Consider only lines that correspond to /dev entries next; } ($device, $restOfLine) = split(' ', $line, 2); if(!defined($rootDevice) || $rootDevice eq '') { # If this is the first device seen, it's the root device to be # used for ejection. Keep it. $rootDevice = $device; } if($restOfLine =~ /(\/.*)/) { # The first partition with a mount point is the interesting one. It's # usually Apple_HFS and usually the last one in the list, but beware of # the possibility of other filesystem types and the Apple_Free partition. # If the disk image contains no partition table, the partition will not # have a type, so look for the mount point by looking for a slash. $mountpoint = $1; return($rootDevice, $device, $mountpoint); } } # No mount point? This is bad. If there's a root device, eject it. if(defined($rootDevice) && $rootDevice ne '') { # Failing anyway, so don't care about failure commandVerbosity(0, $gConfig{'cmd_diskutil'}, 'eject', $rootDevice); } return undef; } # isFormatCompressed($format) # # Returns true if $format corresponds to a compressed disk image format. # Returns false otherwise. sub isFormatCompressed($) { my($format); ($format) = @_; return $format eq 'UDZO' || $format eq 'UDBZ'; } # licenseMaker($text, $resource) # # Takes a plain text file at path $text and creates a license agreement # resource containing the text at path $license. English-only, and # no special formatting. This is the bare-bones stuff. For more # intricate license agreements, create your own resource. # # ftp://ftp.apple.com/developer/Development_Kits/SLAs_for_UDIFs_1.0.dmg sub licenseMaker($$) { my($resource, $text); ($text, $resource) = @_; if(!sysopen(*TEXT, $text, O_RDONLY)) { print STDERR ($0.': licenseMaker: sysopen text: '.$!."\n"); return 0; } if(!sysopen(*RESOURCE, $resource, O_WRONLY|O_CREAT|O_EXCL)) { print STDERR ($0.': licenseMaker: sysopen resource: '.$!."\n"); return 0; } print RESOURCE << '__EOT__'; // See /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/Script.h for language IDs. data 'LPic' (5000) { // Default language ID, 0 = English $"0000" // Number of entries in list $"0001" // Entry 1 // Language ID, 0 = English $"0000" // Resource ID, 0 = STR#/TEXT/styl 5000 $"0000" // Multibyte language, 0 = no $"0000" }; resource 'STR#' (5000, "English") { { // Language (unused?) = English "English", // Agree "Agree", // Disagree "Disagree", __EOT__ # This stuff needs double-quotes for interpolations to work. print RESOURCE (" // Print, ellipsis is 0xC9\n"); print RESOURCE (" \"Print\xc9\",\n"); print RESOURCE (" // Save As, ellipsis is 0xC9\n"); print RESOURCE (" \"Save As\xc9\",\n"); print RESOURCE (' // Descriptive text, curly quotes are 0xD2 and 0xD3'. "\n"); print RESOURCE (' "If you agree to the terms of this license '. "agreement, click \xd2Agree\xd3 to access the software. If you ". "do not agree, press \xd2Disagree.\xd3\"\n"); print RESOURCE << '__EOT__'; }; }; // Beware of 1024(?) byte (character?) line length limitation. Split up long // lines. // If straight quotes are used ("), remember to escape them (\"). // Newline is \n, to leave a blank line, use two of them. // 0xD2 and 0xD3 are curly double-quotes ("), 0xD4 and 0xD5 are curly // single quotes ('), 0xD5 is also the apostrophe. data 'TEXT' (5000, "English") { __EOT__ while(!eof(*TEXT)) { my($line); chop($line = ); while(defined($line)) { my($chunk); # Rez doesn't care for lines longer than (1024?) characters. Split # at less than half of that limit, in case everything needs to be # backwhacked. if(length($line)>500) { $chunk = substr($line, 0, 500); $line = substr($line, 500); } else { $chunk = $line; $line = undef; } if(length($chunk) > 0) { # Unsafe characters are the double-quote (") and backslash (\), escape # them with backslashes. $chunk =~ s/(["\\])/\\$1/g; print RESOURCE ' "'.$chunk.'"'."\n"; } } print RESOURCE ' "\n"'."\n"; } close(*TEXT); print RESOURCE << '__EOT__'; }; data 'styl' (5000, "English") { // Number of styles following = 1 $"0001" // Style 1. This is used to display the first two lines in bold text. // Start character = 0 $"0000 0000" // Height = 16 $"0010" // Ascent = 12 $"000C" // Font family = 1024 (Lucida Grande) $"0400" // Style bitfield, 0x1=bold 0x2=italic 0x4=underline 0x8=outline // 0x10=shadow 0x20=condensed 0x40=extended $"00" // Style, unused? $"02" // Size = 12 point $"000C" // Color, RGB $"0000 0000 0000" }; __EOT__ close(*RESOURCE); return 1; } # pathSplit($pathname) # # Splits $pathname into an array of path components. sub pathSplit($) { my($pathname); ($pathname) = @_; return split(/\//, $pathname); } # setAttributes($root, @attributeList) # # @attributeList is an array, each element of which must be in the form # :. is a list of attributes, per SetFile. is a file # which is taken as relative to $root (even if it appears as an absolute # path.) SetFile is called to set the attributes on each file in # @attributeList. sub setAttributes($@) { my(@attributes, $root); ($root, @attributes) = @_; my($attribute); foreach $attribute (@attributes) { my($attrList, $file, @fileList, @fixedFileList); ($attrList, @fileList) = split(/:/, $attribute); if(!defined($attrList) || !@fileList) { cleanupDie('--attribute requires :'); } @fixedFileList=(); foreach $file (@fileList) { if($file =~ /^\//) { push(@fixedFileList, $root.$file); } else { push(@fixedFileList, $root.'/'.$file); } } if(command($gConfig{'cmd_SetFile'}, '-a', $attrList, @fixedFileList)) { cleanupDie('SetFile failed to set attributes'); } } return; } sub trapSignal($) { my($signalName); ($signalName) = @_; cleanupDie('exiting on SIG'.$signalName); } sub usage() { print STDERR ( "usage: pkg-dmg --source \n". " --target \n". " [--format ] (default: UDZO)\n". " [--volname ] (default: same name as source)\n". " [--tempdir ] (default: same dir as target)\n". " [--mkdir ] (make directory in image)\n". " [--copy [:]] (extra files to add)\n". " [--symlink [:]] (extra symlinks to add)\n". " [--license ] (plain text license agreement)\n". " [--resource ] (flat .r files to merge)\n". " [--icon ] (volume icon)\n". " [--attribute :] (set file attributes)\n". " [--idme] (make Internet-enabled image)\n". " [--sourcefile] (treat --source as a file)\n". " [--verbosity ] (0, 1, 2; default=2)\n". " [--dry-run] (print what would be done)\n"); return; } SuperCollider-3.6.6-Source-linux~repack/package/OPTIONALS_README_OSX.rtf0000664000000000000000000000355112014636264024217 0ustar rootroot{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf480 {\fonttbl\f0\fnil\fcharset77 LucidaGrande-Bold;\f1\fnil\fcharset77 LucidaGrande;\f2\fnil\fcharset77 Monaco; } {\colortbl;\red255\green255\blue255;} \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural \f0\b\fs36 \cf0 Installation Instructions \f1\b0\fs24 \ \ \f0\b\fs26 Quarks \f1\b0\fs24 \ \ Quarks are the standard method for handling the distribution of class library extensions.\ \ 1) To install for one user move the \f2\fs22 quarks \f1\fs24 directory to \f2\fs22 ~/Library/Application Support/SuperCollider \f1\fs24 . To install for all users, move the \f2\fs22 quarks \f1\fs24 directory to \f2\fs22 /Library/Application Support/SuperCollider \f1\fs24 .\ NOTE: you might see a folder called " \f2\fs22 Extensions \f1\fs24 " but \f0\b DON'T \f1\b0 put the quarks directory directly in there!\ \ 2) From within the SuperCollider application, follow the steps outlined inside the Quarks helpfile to actually install a Quark. You do NOT need to download the quarks (you already have), at this point, you should be able to start installing Quarks by running:\ \ Quarks.gui\ \fs22 \ \ \f0\b\fs26 sc3-plugins \f1\b0\fs22 \ \fs24 \ sc3-plugins are some of the more common extension libraries, maintained at:\ \ {\field{\*\fldinst{HYPERLINK "http://sourceforge.net/projects/sc3-plugins/"}}{\fldrslt http://sourceforge.net/projects/sc3-plugins/}}\ \ 1) Move the \f2\fs22 sc3-plugin-extensions \f1\fs24 folder to \f2\fs22 ~/Library/Application Support/SuperCollider/Extensions \f1\fs24 , creating any necessary directories.\ \ 2) Restart SuperCollider.\ \ \ \f0\b\fs26 SwingOSC\ \ \f1\b0\fs24 SwingOSC is a system for creating graphical user interfaces using Java. To install it, follow the SwingOSC installation instructions in SwingOSC/SuperCollider/readme.html.}SuperCollider-3.6.6-Source-linux~repack/package/dmg_with_optionals.ds_store0000664000000000000000000003000412014636264026013 0ustar rootrootBud1 ob PctB  @ @ @ @.BKGDblob PctB0.ICVObool.fwi0blobY!ricnv.fwswlong.fwvhshor.icgoblob.icvoblob icv48nonebotm1.icvtshor .pictblob00 SuperColliderIH+background.pngIPNGf8BIM  .backgroundʺʺ0(SuperCollider:.background:background.pngbackground.png SuperCollider/.background/background.png/Volumes/SuperCollider Macintosh HDYhH+tSuperCollider with O#C5FCEF.dmgIdevrddsk Desktopʺ tf7s?Macintosh HD:Users:ryan:Desktop:SuperCollider with O#C5FCEF.dmgB SuperCollider with Optionals.dmg Macintosh HD3Users/ryan/Desktop/SuperCollider with Optionals.dmg/ .backgroundfwi0blobdWicnv .backgroundfwvhshor~ ApplicationsIlocblob2Optional InstallsIlocblob2 SuperColliderIlocblobZ2 E DSDB ` @ @ @perColliderIlocblobZ2SuperCollider-3.6.6-Source-linux~repack/package/OPTIONALS_README_SOURCE.txt0000664000000000000000000000227412014636264024573 0ustar rootrootINSTALLATION INSTRUCTIONS ------------------------- QUARKS ------ Quarks are the standard method for handling the distribution of class library extensions. 1) To install for one user move the quarks directory to "~/share/SuperCollider". To install for all users, move the quarks directory to "/usr/local/share/SuperCollider". NOTE: you might see a folder called "Extensions" but DON'T put the quarks directory directly in there! 2) Follow the steps outlined inside the Quarks helpfile to actually install a Quark.You do NOT need to download the quarks (you already have), at this point, you should be able to start installing Quarks by running: Quarks.gui SC3-PLUGINS ----------- sc3-plugins are some of the more common extension libraries, maintained at: http://sourceforge.net/projects/sc3-plugins/ 1) Execute "scons ./distro_linux" in the sc3-plugin-extensions folder and move the "./sc3-plugin-extensions/Extensions" folder to "~/share/SuperCollider/Extensions". 2) Restart SuperCollider. SWINGOSC -------- SwingOSC is a system for creating graphical user interfaces using Java. To install it, follow the SwingOSC installation instructions in "SwingOSC/SuperCollider/readme.html". SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/0000775000000000000000000000000012245452763021613 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/0000775000000000000000000000000012245452763023043 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Quarks/0000775000000000000000000000000012245452763024311 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Quarks/QuarkSVNRepository.sc0000664000000000000000000002046212207047105030402 0ustar rootroot/** * * Subversion based package repository and package manager. * sk & cx & ds & LFSaw * */ QuarkSVNRepository { classvar <>svnpath="/usr/local/bin/svn"; var 0}){ svnpath = "svn"; }; }; } *new { | url, local | QuarkSVNRepository.initSVNDetails; if(svnpath.isNil) { if(thisProcess.platform.name==\windows){ Post << "\tSVN not yet possible on windows. Quarks placed in the directory" << "\n\n\t\t" << Platform.userAppSupportDir << "\\quarks" << "\n\n\t" << "will be available.\n" }{ Post << "\tSVN not found! Quarks placed in the directory" << "\n\n\t\t" << Platform.userAppSupportDir << "/quarks" << "\n\n\t" << "will be available, but you need svn to checkout updated versions." << "\n\n\t" << "svn can be downloaded from:" << "\n\n\t\t" << "http://subversion.tigris.org/project_packages.html\n" } }; ^this.newCopyArgs(url ? "https://svn.code.sf.net/p/quarks/code", local ?? {Quarks.local}) } // returns true if some change was performed checkSVNandBackupIfNeeded{ var res,files; files = (Quarks.local.path ++ "/*").pathMatch; if ( files.size != 0 ) { // there are files in the quarks dir if ( (Quarks.local.path ++ "/.svn").pathMatch.size == 0 ) { // but quarks dir itself is not under version control files.do{ |it| res = ("svn st -q " ++ it ).unixCmdGetStdOut; if ( res == "" ){ // no local modifications, so delete the folder ("rm -r " ++ it ).unixCmd; }{ // local modifications, so copy the folder for backup ("mv" + it + it.drop(-1) ++ "_modified" ).unixCmd; ("You had local modifications in quark folder" + it + "a copy of the folder has been made, so please review your modifications there").inform; }; }; ^true } }; ^false } // easiest to just check out all - BUT may waste your space since the global repos is becoming bigger and bigger! checkoutAll { |localRoot| this.checkSVNandBackupIfNeeded; this.svn("co", this.url ++ "/", localRoot.escapeChar($ ) ++ "/") } // checkout a specific quark (or multiple quarks - first arg can be an array). // NOTE: despite the method name, this actually uses "svn up" rather than "svn co", to ensure the base checkout is the base for this subfolder. // Therefore it can be used to update, equally well as to checkout, a quark. checkout { | q, localRoot, sync = false | var subfolders, fullCheckout, pathSoFar, skeletonCheckout, args; skeletonCheckout = []; fullCheckout = []; q.asArray.do{ |oneq| subfolders = oneq.path.split($/); fullCheckout = fullCheckout ++ [oneq.path.escapeChar($ )]; subfolders.pop; // The final entry is the folder whose entire contents we want pathSoFar = "."; skeletonCheckout = skeletonCheckout ++ subfolders.collect{ |element, index| pathSoFar = pathSoFar ++ "/" ++ element }.collect{|el| el.escapeChar($ )}; }; // Now construct a svn command for the skels, and then a svn command for the fulls args = if(skeletonCheckout.isEmpty){ [] }{ ["update", ["--non-recursive"] ++ skeletonCheckout.collect(_.asSymbol).as(OrderedIdentitySet).collectAs((_.asString), Array)] } ++ ["update", fullCheckout.collect(_.asSymbol).as(OrderedIdentitySet).collectAs((_.asString), Array)]; this.svnMulti(localRoot, sync, *args); } // check if the quarks directory is checked out yet checkDir { var dir; dir = local.path.select{|c| (c != $\\)}; if(File.exists(dir).not, { // This method SHOULD NOT check the dir out on your behalf! That's not what it's for! Use .checkoutDirectory for that. //"Quarks dir is not yet checked out. Execute:".debug; //this.svn("co","--non-recursive",this.url, local.path.escapeChar($ )); //this.svn("up", local.path.escapeChar($ ) +/+ "DIRECTORY"); ^false; }); ^true; } // updateDirectory and checkoutDirectory can be handled by the same function, simplifying the user experience, hopefully. // TODO: deprecate checkoutDirectory methods, simply use updateDirectory whether or not it's the first time. // Then update the help docs to the simpler instructions. checkoutDirectory {|forceSync=false| ^this.updateDirectory(forceSync); } // DIRECTORY contains a quark spec file for each quark regardless if checked out / downloaded or not. updateDirectory { |forceSync=false| if (svnpath.isNil) { "\n\tSince SVN not installed, you cannot checkout Quarks. ".postln.halt; }; // If there's no svn metadata then either there's nothing there at all or there's a non-svn thing in the way if ( File.exists(local.path ++ "/.svn").not) { if( File.exists(local.path).not ) { // Main folder doesn't exist at all, simply check it out this.svnMulti(".", forceSync, "checkout", ["--non-recursive", this.url, local.path.select{|c| (c != $\\)}.escapeChar($ )], // and then do the directory update: "update", [local.path.select{|c| (c != $\\)}.escapeChar($ ) +/+ "DIRECTORY"] ); }{ Post << "\n\tCurrent Quarks are not SVN. Delete the directories \n\t\t " << local.path << "\n\tand\n\t\t" << Platform.userExtensionDir << "/quarks\n" << "\tand recompile before checking out quarks"; nil.halt; }; }{ this.svnMulti(local.path, forceSync, "update", ["DIRECTORY"]); }; } update { this.checkSVNandBackupIfNeeded; if(this.checkDir.not){ this.checkoutDirectory; // ensures that the main folder exists this.svn("update",local.path.escapeChar($ )); }{ // The "checkout" method can do the updating of individual quarks for us this.checkout(local.quarks, local.path); }; } // load all specification quark objects from DIRECTORY // they may or may not be locally checked out quarks { var paths, quarks; paths = (local.path ++ "/*/*.quark").pathMatch; quarks = Dictionary.new; paths.do { |p| try { var q=Quark.fromFile(p, this.local.parent); quarks[q.name] = q; } { |e| e.errorString.postln } }; ^quarks.values; } // search DIRECTORY quark objects to see if quark is in repository findQuark { arg name, version; var matches; matches = this.quarks.select({ |q| q.name == name }); if(version.notNil,{ matches = matches.select({ |q| q.version >= version }); }); ^matches.sort({ |a,b| a.version > b.version }).first } // Can perform multiple svn commands in one call. // Call it with [cmd, args, cmd, args] pairs - e.g. svnMulti(.... "co", ["--quiet", "/some/repo"], "up", ["~/my/repo"]). // "forceSync" is whether or not to force to run in sync (on OSX we like to do it async to avoid certificate-pain) svnMulti { | baseDir, forceSync=(false) ... pairs | var cmd, svnpath = this.class.svnpath.escapeChar($ ); if (svnpath.isNil) { Error("SVN is not installed! Quarks cannot be updated.").throw; }; cmd = "export LANG='' && cd" + baseDir.select{|c| (c != $\\)}.escapeChar($ ); pairs.pairsDo{|onecmd, args| cmd = cmd + "&&" + svnpath + onecmd + args.join(" ") }; cmd = cmd + "2>&1"; "".debug; cmd.debug; "".debug; if(forceSync.not and: {thisProcess.platform.name == \osx}){ // asynchronous but user-friendly execution - on OSX we // run it in a terminal window to minimise the risk of people getting stuck without a certificate ("echo " ++ $" ++ " -------------------------------------------------------------- SuperCollider Quarks: accessing remote repository. If this is the first time, you may be asked to accept a security certificate. If you can trust it, please do so! The command being run is: " ++ cmd.escapeChar($") ++ " -------------------------------------------------------------- " ++ $" ++ cmd).runInTerminal }{ // synchronous execution: cmd.unixCmdGetStdOut.postln; }; } svn { | cmd ... args | ^this.svnMulti(".", false, cmd, args); } // Allows to wait for command to complete svnSync { | cmd ... args | ^this.svnMulti(".", true, cmd, args); } // just post svnp { |cmd ... args| cmd = ("svn" + cmd + args.join(" ")); "".debug; cmd.debug; "".debug; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Quarks/Quarks.sc0000664000000000000000000005132312207047105026076 0ustar rootroot/** * * Subversion based package repository and package manager * sk, cx, danstowell, LFSaw * * this is the interface class for * accessing the SVN repository, (eg. the sourceforge quarks project) * downloading those to the local quarks folder (Platform.userAppSupportDir/quarks) * installing individual quarks by symlinking from the local quark folder into the [Platform dependent]/Extensions folder * */ Quarks { classvar global, (Platform.userAppSupportDir +/+ "quarks"), "https://svn.sonenvir.at/svnroot/SonEnvir/trunk/src/quarks-sonenvir" -> (Platform.userAppSupportDir +/+ "quarks-sonenvir"), "https://sc3-plugins.svn.sourceforge.net/svnroot/sc3-plugins/build" -> (Platform.userAppSupportDir +/+ "SC3plugins") ]; } *forUrl { |url| var q; this.global; // ensure the global one is constructed q = allInstances.detect({|q| q.repos.url == url}); if(q.isNil && this.known[url].isNil.not, { q = Quarks.new(url, this.known[url]); }); ^q; } update { |name| var q; if(name.notNil,{ if((q = local.findQuark(name)).isNil,{ Error("Local Quark "+name+" not found, cannot update from repository").throw; }); repos.svn("update", (local.path+/+q.path).escapeChar($ )); },{ //update all repos.update(local) }); } /*add { |name| // this should create or manage the directory file too if it exists var q; if((q = local.findQuark(name)).isNil,{ Error("Local Quark code not found, cannot add to repository").throw; }); repos.svn("add",local.path++"/"++q.path); }*/ commit { |name,message| var q; if((q = local.findQuark(name)).isNil,{ Error("Local Quark code not found, cannot commit to repository").throw; }); if(message.isNil,{ Error("svn log message required to commit").throw; }); repos.svn("commit","-m",message,"-F",local.path +/+ q.path); } // TODO: Deprecate "checkoutDirectory" - "updateDirectory" can be used whether or not there's an existing one checkoutDirectory { "Please wait for directory to be checked out.".postln; ^this.updateDirectory } updateDirectory { repos.updateDirectory } listCheckedOut { this.checkedOut.do { |q| q.postDesc }; } listAvailable { this.repos.quarks.do { |q| q.postDesc }; } checkoutAll { repos.checkoutAll(local.path) } checkout { |name, version, sync=false| var q; if(local.findQuark(name,version).notNil,{ inform("Quark "++name++" already checked out"); ^this }); q = repos.findQuark(name,version); if(q.isNil,{ Error("Quark not found in repository.").throw; }); repos.checkout(q, local.path, sync); } // DEPRECATED because it has a different and confusing functionality w.r.t. QuarkSVNRepos.checkDir checkDir { var d; "Quarks.checkDir is deprecated".warn; d = (Platform.userExtensionDir +/+ local.name).escapeChar($ ); if(d.pathMatch.isEmpty,{ ("creating: " + d).inform; d.mkdir; }); } checkedOut { ^local.quarks } status { |name| var q; if(name.notNil,{ q = local.findQuark(name); repos.svn("status",(local.path +/+ q.path).escapeChar($ )); },{ repos.svn("status",local.path.escapeChar($ )); }); } installed { // of quarks in local, select those also present in userExtensionDir ^local.quarks.select{|q| (Platform.userExtensionDir.escapeChar($ ) +/+ local.name +/+ q.path ).pathMatch.notEmpty } } install { | name , includeDependencies=true, checkoutIfNeeded=true | var q, deps, installed, dirname, quarksForDep; if(this.isInstalled(name),{ (name + "already installed").inform; ^this }); q = local.findQuark(name); if(q.isNil,{ if(checkoutIfNeeded) { (name.asString + " not found in local quarks; checking out from remote ...").postln; this.checkout(name, sync: true); q = local.reread.findQuark(name); if(q.isNil, { Error("Quark" + name + "install: checkout failed.").throw; }); } { Error(name.asString + "not found in local quarks. Not yet downloaded from the repository ?").throw; }; }); if(q.isCompatible.not,{ (q.name + " reports that it is not compatible with your current class library. See the help file for further information.").inform; ^this }); // create /quarks/ directory if needed if(this.repos.checkDir.not){this.checkoutDirectory}; // Now ensure that the dependencies are installed (if available given the current active reposses) if(includeDependencies, { q.dependencies(true).do({ |dep| quarksForDep = if(dep.repos.isNil, {this}, {Quarks.forUrl(dep.repos)}); if(quarksForDep.isNil, { ("Quarks:install - unable to find repository for dependency '" ++ dep.name ++ "' - you may need to satisfy this dependency manually. No repository detected locally with URL "++dep.repos).warn; }, { if(quarksForDep.isInstalled(dep.name).not, { try({ quarksForDep.install(dep.name, false, checkoutIfNeeded) }, { ("Unable to satisfy dependency of '"++name++"' on '"++dep.name ++"' - you may need to install '"++dep.name++"' manually.").warn; }); }); }); }); }); // Ensure the correct folder-hierarchy exists first dirname = (Platform.userExtensionDir +/+ local.name +/+ q.path).dirname; if(File.exists(dirname).not, { dirname.mkdir }); // install via symlink to Extensions/ ("ln -s " + (local.path +/+ q.path).escapeChar($ ) + (Platform.userExtensionDir +/+ local.name +/+ q.path).escapeChar($ )).systemCmd; (q.name + "installed").inform; } listInstalled { this.installed.do { |q| q.postDesc }; } isInstalled { arg name; ^this.installed.detect{|quark| quark.name == name }.notNil } uninstall { | name | var q, deps, installed; name = name.asString; if(this.isInstalled(name).not,{ ^this }); q = local.findQuark(name); if(q.isNil,{ Error( name + "is not found in Local quarks in order to look up its relative path. You may remove the symlink manually." ).throw; }); // install via symlink to Extensions/Quarks ("rm " + (Platform.userExtensionDir +/+ local.name +/+ q.path).escapeChar($ )).systemCmd; (q.name + "uninstalled").inform; } help { |name| var q; if(name.isNil){ "Quarks".help }{ q = local.findQuark(name); if(q.isNil,{ Error( name.asString + "not found in local quarks. Not yet downloaded from the repository ?" ).throw; }); q.help; } } name { ^local.name } ///// convenience methods for Quarks.global *checkoutAll { this.global.repos.checkoutAll(this.global.local.path) } *checkout { | name, version, sync | this.global.checkout(name,version, sync); } /* return Quark objects for each in App Support/SuperCollider/Quarks (so actually this would list any Quarks that are in local development and not yet checked in) */ *checkedOut { ^this.global.checkedOut } *listCheckedOut { this.checkedOut.do { |q| q.postDesc }; } *listAvailable { this.global.listAvailable } /* download/update only the quark specification files from remote repos and not the quarks themselves */ *updateDirectory { ^this.global.repos.updateDirectory } *checkoutDirectory { ^this.global.checkoutDirectory } *update { |quarkName| this.global.update(quarkName) } /* this symlinks from {App Support}/SuperCollider/Quarks to {App Support}/SuperCollider/Extensions it is then in the SC compile path */ *install { |name, includeDependencies=true, checkoutIfNeeded=true| this.global.install(name, includeDependencies, checkoutIfNeeded) } /* return Quark objects for each installed */ *installed { ^this.global.installed } *listInstalled { ^this.global.listInstalled } *isInstalled { |name| ^this.global.isInstalled(name) } /* removes the symlink */ *uninstall { |name| ^this.global.uninstall(name) } /* add code in {App Support}/SuperCollider/Quarks to the remote repos and also adds the quarks file in DIRECTORY */ //*add { |name| this.global.add(name) } /* you may also use standard svn tools within {App Support}/SuperCollider/Quarks */ *commit { |name,message| this.global.commit(name,message) } // post the SVN status *status { |name| this.global.status(name) } *local { ^this.global.local } *repos { ^this.global.repos } *help {|name| ^this.global.help(name) } *gui { ^this.global.gui } gui { if( GUI.id === \qt ) { ^QuarksViewQt(this) } { ^QuarksView(this) } } } // a gui for Quarks. 2007 by LFSaw.de QuarksView { var quarksCtrl, quarks; var window, caption, explanation, views, resetButton, saveButton, warning, scrollview, scrB, flowLayout, /* quarksflow, */ height, maxPerPage, nextButton, prevButton; *new { |quarksCtrl| ^super.new.init(quarksCtrl) } init { |q| var pageStart = 0, fillPage; quarksCtrl = q; fillPage = { |start| scrollview.visible = false; views.notNil.if({ views.do({ |view| view.remove }); }); scrollview.decorator.reset; views = quarks.sort { |a, b| a.name < b.name } .collect { |quark| var qView = QuarkView.new(scrollview, 500@20, quark, quarksCtrl.installed.detect { |it| it == quark }.notNil ); scrollview.decorator.nextLine; qView; }; scrollview.visible = true; views }; // note, this doesn't actually contact svn // it only reads the DIRECTORY entries you've already checked out quarks = quarksCtrl.repos.quarks.copy; scrB = GUI.window.screenBounds; height = min(quarks.size * 25 + 120, scrB.height - 60); window = GUI.window.new(quarksCtrl.name, Rect.aboutPoint( scrB.center, 250, height.div( 2 ))); flowLayout = FlowLayout( window.view.bounds ); window.view.decorator = flowLayout; caption = GUI.staticText.new(window, Rect(20,15,400,30)); caption.font_( Font.sansSerif( 24 )); caption.string = quarksCtrl.name; window.view.decorator.nextLine; if ( quarks.size == 0 ){ GUI.button.new(window, Rect(0, 0, 229, 20)) .states_([["checkout Quarks DIRECTORY"]]) .action_({ quarksCtrl.checkoutDirectory; }); }{ GUI.button.new(window, Rect(0, 0, 229, 20)) .states_([["update Quarks DIRECTORY"]]) .action_({ quarksCtrl.updateDirectory;}); }; GUI.button.new(window, Rect(0, 0, 200, 20)) .states_([["refresh Quarks listing"]]) .action_({ window.close; quarksCtrl.gui; }); window.view.decorator.nextLine; GUI.button.new(window, Rect(0, 0, 150, 20)) .states_([["browse all help"]]) .action_({ HelpBrowser.openBrowsePage("Quarks") }); GUI.button.new(window, Rect(15,15,150,20)) .states_([["open quark directory"]]) .action_{ arg butt; openOS(quarksCtrl.local.path.escapeChar($ )) }; resetButton = GUI.button.new(window, Rect(15,15,75,20)); resetButton.states = [ ["reset"] ]; resetButton.action = { arg butt; views.do(_.reset); }; saveButton = GUI.button.new(window, Rect(15,15,75,20)); saveButton.states = [ ["save", nil, Color.blue(1, 0.2)] ]; saveButton.action = { arg butt; Task{ warning.string = "Applying changes, please wait"; warning.background_(Color(1.0, 1.0, 0.9)); 0.1.wait; views.do{|qView| qView.toBeInstalled.if({ quarksCtrl.install(qView.quark.name); qView.flush }); qView.toBeDeinstalled.if({ quarksCtrl.uninstall(qView.quark.name); qView.flush; }) }; warning.string = "Done. You should now recompile sclang"; warning.background_(Color(0.9, 1.0, 0.9)); }.play(AppClock); }; window.view.decorator.nextLine; explanation = GUI.staticText.new(window, Rect(20,15,500,20)); explanation.string = "\"+\" -> installed, \"-\" -> not installed, \"*\" -> marked to install, \"x\" -> marked to uninstall"; window.view.decorator.nextLine; warning = GUI.staticText.new(window, Rect(20,15,400,30)); warning.font_( Font.sansSerif( 18 )); window.view.decorator.nextLine; GUI.staticText.new( window, 492 @ 1 ).background_( Color.grey ); window.view.decorator.nextLine; flowLayout.margin_( 0 @0 ).gap_( 0@0 ); scrollview = GUI.scrollView.new(window, 500 @ (height - 165)) .resize_( 5 ) .autohidesScrollers_(true); scrollview.decorator = FlowLayout( Rect( 0, 0, 500, quarks.size * 25 + 20 )); window.front; fillPage.(pageStart); ^window; } } QuarksViewQt { var quarksCtrl; var window, lblCaption, btnUpdate, btnHelp, btnUpdateQuarks, btnOpenDir, btnReset, btnApply, lblStatus, lblExplanation, quarksView, infoView, btnQuarkHelp, btnQuarkOpen, btnQuarkClasses, btnQuarkMethods, txtDescription, btnCloseDetails; var quarks, views, curQuark; var refresh, msgWorking, msgDone; var screen, palette, gizmo; *new { |quarksCtrl| ^super.new.init(quarksCtrl) } init { |q| quarksCtrl = q; refresh = { quarksView.invokeMethod( \clear ); quarks = quarksCtrl.repos.quarks.copy; quarksView.canSort = false; views = quarks.collect{|quark| var qView = QuarkViewQt.new(quarksView, quark, quarksCtrl.installed.detect{|it| it == quark}.notNil); qView; }; quarksView.canSort = true; quarksView.sort( 1 ); quarksView.invokeMethod( \resizeColumnToContents, 0 ); quarksView.invokeMethod( \resizeColumnToContents, 1 ); views }; msgWorking = { arg msg; lblStatus.background = palette.button.blend(Color.yellow,0.2); lblStatus.string = msg; }; msgDone = { arg msg; lblStatus.background = palette.button.blend(Color.green,0.2); lblStatus.string = msg; }; palette = GUI.current.palette; screen = Window.flipY(Window.availableBounds); window = Window( quarksCtrl.name, Rect( 0, 0, 700, screen.height * 0.9 ).center_(screen.center) ); lblCaption = StaticText().font_( GUI.font.new(size:16,usePointSize:true) ).string_(quarksCtrl.name); btnUpdate = Button() .states_([["Update Quark Listing"]]) .toolTip_("Download the latest information and update the Quarks listing") .action_({ quarksView.enabled = false; msgWorking.value("Downloading the latest information..."); AppClock.sched( 0.2, { protect { quarksCtrl.updateDirectory; } { refresh.value; quarksView.enabled = true; msgDone.value("Quarks listing has been updated with the latest information.") } }); nil }); btnUpdateQuarks = Button() .states_([["Update Quarks"]]) .toolTip_("Update installed Quarks") .action_({ quarksView.enabled = false; msgWorking.value("Updating installed Quarks..."); AppClock.sched( 0.2, { protect { quarksCtrl.update; } { refresh.value; quarksView.enabled = true; msgDone.value("Quarks have been updated." + " You should recompile the class library for changes to take effect.") } }); nil }); btnHelp = Button().states_([["Help"]]) .toolTip_("Browse help for all the Quarks") .action_({ HelpBrowser.openBrowsePage("Quarks") }); btnOpenDir = Button().states_([["Directory"]]) .toolTip_("Open the local Quarks directory") .action_({ openOS(quarksCtrl.local.path) }); btnReset = Button() .states_([["Reset"]]) .toolTip_("Clear the marked changes") .action_({ arg butt; views.do(_.reset) }); btnApply = Button().states_([["Apply",nil,Color.blue.blend(palette.button,0.6)]]) .toolTip_("Apply the marked changes") .action_({ arg butt; quarksView.enabled = false; msgWorking.value("Applying changes, please wait..."); AppClock.sched( 0.2, { protect { views.do{|qView| qView.toBeInstalled.if({ quarksCtrl.install(qView.quark.name); qView.flush }); qView.toBeDeinstalled.if({ quarksCtrl.uninstall(qView.quark.name); qView.flush; }) }; } { msgDone.value("Changes applied." + "You should recompile the class library for changes to take effect." ); quarksView.enabled = true; } }); }); lblExplanation = StaticText().string_( "\"+\" installed, \"-\" not installed, \"*\" to install, \"x\" to uninstall" ); lblStatus = StaticText().font_( GUI.font.new( size:12, usePointSize:true ) ); quarksView = TreeView() .setProperty( \rootIsDecorated, false ) .columns_([nil,"Name","Summary"]) .itemPressedAction_({ |v| infoView.visible = true; }) .onItemChanged_({ |v| var curItem, curView, inst; curItem = v.currentItem; curQuark = nil; if( curItem.notNil ) { curView = views.detect { |view| view.treeItem == curItem }; if( curView.notNil ) { curQuark = curView.quark; txtDescription.string = curQuark.longDesc; btnQuarkOpen.enabled = curQuark.isLocal; inst = quarksCtrl.installed.detect{|it| it == curQuark}.notNil; btnQuarkClasses.enabled = inst; btnQuarkMethods.enabled = inst; } }{ infoView.visible = false } }); txtDescription = TextView(bounds:10@10) .font_( GUI.font.new( size:10, usePointSize:true ) ) .tabWidth_(15) .autohidesScrollers_( true ) .hasVerticalScroller_( true ) .editable_( false ) //.minSize_(Size(0,0)); .minHeight_(50); btnQuarkHelp = Button() .states_([["Help"]]) .toolTip_("Show help for this Quark") .action_({ curQuark.help }); btnQuarkOpen = Button() .states_([["Source"]]) .toolTip_("Open the source directory of this Quark") .action_({ openOS( "%/%".format(Quarks.local.path, curQuark.path) ); }); btnQuarkClasses = Button() .states_([["Classes"]]) .toolTip_("Show list of classes defined by this Quark") .enabled_(false) .action_({ var cls = curQuark.definesClasses; var tree, item, buts = [ Button().states_([["Browse"]]).action_({ cls[item.index].browse; }), Button().states_([["Help"]]).action_({ cls[item.index].help; }), Button().states_([["Source"]]).action_({ cls[item.index].openCodeFile; }) ]; buts.do(_.enabled_(false)); Window("% Classes".format(curQuark.name)).layout_( VLayout( tree = TreeView() .setProperty( \rootIsDecorated, false ) .columns_(["Classes"]) .onItemChanged_({|v| item = v.currentItem}), HLayout(*buts) ) ).front; if(cls.size>0) { cls.do {|c| tree.addItem([c.name.asString])}; tree.itemPressedAction = { buts.do(_.enabled_(true)) } } { tree.addItem(["No classes"]); }; tree.invokeMethod( \resizeColumnToContents, 0 ); }); btnQuarkMethods = Button() .states_([["Ext methods"]]) .toolTip_("Show list of extension methods added by this Quark") .enabled_(false) .action_({ var mets = curQuark.definesExtensionMethods; var tree, item, buts = [ Button().states_([["Browse"]]).action_({ mets[item.index].ownerClass.browse; }), Button().states_([["Help"]]).action_({ mets[item.index].help; }), Button().states_([["Source"]]).action_({ mets[item.index].openCodeFile; }) ]; buts.do(_.enabled_(false)); Window("% Extension Methods".format(curQuark.name)).layout_( VLayout( tree = TreeView() .setProperty( \rootIsDecorated, false ) .columns_(["Class","Method"]) .onItemChanged_({|v| item = v.currentItem}), HLayout(*buts) ) ).front; if(mets.size>0) { mets.collect{|m| var x = m.ownerClass.name; tree.addItem(if(x.isMetaClassName) {[x.asString[5..],"*"++m.name]} {[x.asString,"-"++m.name]}); }; tree.itemPressedAction = { buts.do(_.enabled_(true)) } } { tree.addItem([nil,"No extension methods"]); }; tree.invokeMethod( \resizeColumnToContents, 0 ); tree.invokeMethod( \resizeColumnToContents, 1 ); }); btnCloseDetails = StaticText() .string_("X") .align_(\center) .toolTip_("Hide Quark information panel") .mouseDownAction_({ infoView.visible = false; }); gizmo = btnCloseDetails.sizeHint; gizmo.width = gizmo.width + 20; btnCloseDetails.fixedSize = gizmo; infoView = View(); infoView.layout = VLayout( HLayout( btnCloseDetails, btnQuarkHelp, btnQuarkOpen, btnQuarkClasses, btnQuarkMethods, nil ).margins_(0), txtDescription ).spacing_(0).margins_(0); infoView.visible = false; window.layout = VLayout( lblCaption, HLayout( btnUpdate, btnUpdateQuarks, btnOpenDir, btnHelp, nil ), lblStatus, HLayout( btnReset, btnApply, [lblExplanation, s:1] ).margins_(0), [quarksView, s:5], [infoView, s:2] ); refresh.value; window.front; ^window; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Quarks/LocalQuarks.sc0000664000000000000000000000360312014636263027054 0ustar rootroot/** * * Subversion based package repository and package manager * a work in progress. sk, cx, lfsaw * */ // Local Quarks are those that have been checked out from the repository. // and are stored in build/quarks prior to being actually installed LocalQuarks { classvar >globalPath; // where the "Quarks.global" checkout is stored var = version }); }); ^matches.sort({ |a,b| a.version > b.version }).first } findPath { arg name, version; var q; if((q = this.findQuark(name, version)).isNil,{ Error("Local Quark % not Found.".format(name.quote)).throw; }); ^path ++ "/" ++ q.path; } openFolder { arg name, version; if(name.isNil) { openOS(path) } { openOS(this.findPath(name, version)) } } /// reread local quarks directory reread { all = nil; this.quarks; } // stupid path has to be escaped above??? // well sometimes you need the raw path... simplePath { var out = path.copy; path.findAll("\\").reverseDo({ |i| path.removeAt(i); }); ^path } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Quarks/packages.sc0000664000000000000000000000731412014636263026414 0ustar rootroot+ Main { // a package is either a quark or a folder in SCClassLibrary or extensions folders // a class is in a 'package' determined by where its Class file is // all folders in class library : // Common // JITlib // crucial // your own // all folders in system extension // all folders in user extension // all quarks // any loose files are placed in a packaged calle SCClassLibrary or Extensions // possiblity for error: if you have loose files in user extensions and system extensions // they will both be placed in the same package: Extensions // [ name -> folderPath, name -> folderPath ... ] *packages { var platform,scClassLibrary,looseFiles; var packages,f; // cache packages = Library.at(Quarks,\packages); if(packages.notNil,{ ^packages }); platform = thisProcess.platform; f = { arg dir; var folders,packages,paths,files; dir = dir.withTrailingSlash; paths = (dir++"*").pathMatch; folders = paths.reject({ |p| p.last != $/ or: {p.basename == "quarks"} }); files = paths.select({ |p| p.last != $/ }); packages = folders.collect({ |p| p.basename.asSymbol -> p }); if(files.notEmpty,{ // if there are any loose files then create a package called dir packages = packages.add( dir.basename.asSymbol -> dir ) }); packages }; packages = (f.value(platform.classLibraryDir) ++ f.value(platform.systemExtensionDir) ++ Quarks.installed.collect({ |q| q.name.asSymbol -> (Platform.userExtensionDir +/+ "quarks" +/+ q.path.withTrailingSlash) })) .sort({ |a,b| a.value.size > b.value.size }) // sort longer paths first ++ f.value(platform.userExtensionDir); Library.put(Quarks,\packages,packages); ^packages } } + Class { package { var path; path = this.filenameSymbol.asString; Main.packages.do({ |namepath| if(path.copyRange(0,namepath.value.size-1) == namepath.value,{ ^namepath.key }) }); Error("Discrepancy: Package not found for class !").throw; } } /* method extensions: may not be the package that its class is in */ + Method { package { var path; path = this.filenameSymbol.asString; Main.packages.do({ |namepath| if(path.copyRange(0,namepath.value.size-1) == namepath.value,{ ^namepath.key }) }); Error("Discrepancy: Package not found for method !").throw; } } + Quark { definesClasses { var myPath,end; myPath = Platform.userExtensionDir +/+ "quarks" +/+ this.path; end = myPath.size-1; ^Class.allClasses.reject(_.isMetaClass).select({ |class| class.filenameSymbol.asString.copyRange(0,end) == myPath }) } definesExtensionMethods { // all methods whose path is in this quark folder // where the class is not in this quark var myPath,end; myPath = Platform.userExtensionDir +/+ "quarks" +/+ this.path; end = myPath.size-1; ^Class.allClasses.collect({ |c| c.methods }).reject(_.isNil).flat .select({ |method| method.filenameSymbol.asString.copyRange(0,end) == myPath and: { method.ownerClass.filenameSymbol.asString.copyRange(0,end) != myPath } }) } // of the classes you defined, what packages are the superclasses in ? // of the extension methods you defined, what packages are the super classes in ? /* checkDependencies { }*/ } + Quarks { // the equivalent to Quark-definesClasses // but works for non-quarks like Quarks.classesInPackage("JITlib") *classesInPackage { |packageName| var myPath,end,package; package = Main.packages.detect({ |pk| pk.key == packageName }); if(package.isNil,{ Error("Package not found:"+packageName).throw }); myPath = package.value; end = myPath.size-1; ^Class.allClasses.select({ |class| class.isMetaClass.not and: { class.filenameSymbol.asString.copyRange(0,end) == myPath } }) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Quarks/Quark.sc0000664000000000000000000002420412161364457025724 0ustar rootroot/** * * Subversion based package repository and package manager * sk, cx, LFSaw, danstowell * */ // quarks are much worse than opiates, you should have been more careful ! // now you have a quark dependency QuarkDependency { // Note: "repos" should be nil if dependency is in same repos; otherwise the base URL of the repos. var path, <>status; var "++name); ^this; }; p = info.helpdoc; if(p.notNil) { HelpBrowser.goTo(URI.fromLocalPath(parent.local.path +/+ path +/+ p).asString) ^this }; HelpBrowser.openBrowsePage("Quarks>"++name); } printOn { arg stream; stream << "Quark: " << name; if(version.notNil,{ stream << " [" << version << "]"; }); } longDesc { var string; string = name; if(version.notNil) { string = string + "[" ++ version ++ "]" }; string = string ++ "\n(by " ++ (author ? "anonymous") ++ ")" ++ "\n\n" ++ summary ++ "\n\n" ++ "Status: " ++ (status ? "unknown") ++ "\n" ++ "Checked out: " ++ if(isLocal, "yes", "no"); if(dependencies.notEmpty) { string = string ++ "\nDepends on"; dependencies.do{|dep| string = string ++ "\n - " ++ dep.name; }; }; string = string ++ "\n"; ^string; } postDesc { this.longDesc.postln; } == { arg that; ^this.compareObject(that, [\name, \summary, \version, \author, \dependencies, \tags, \path, \status]); } hash { arg that; ^this.instVarHash([\name, \summary, \version, \author, \dependencies, \tags, \path, \status]); } dependencies { |recursive = false, knownList| var deps, quark, selfasdep; deps = dependencies; if(recursive, { if(knownList.isNil.not, { deps = dependencies.select({|d| knownList.indexOfEqual(d).isNil}); // To avoid infinite recursion traps }); deps.do({|dep| quark = dep.asQuark(parent); if(quark.notNil) { deps = deps ++ quark.dependencies(recursive: true, knownList: ([QuarkDependency(name, version)] ++ knownList)); }; }); }); ^deps } isCompatible { ^info['isCompatible'].value !== false } } QuarkView { var 0; }; },{ // Quark is currently not installed installButton.states = [ // never installed ["-", nil, ], // selected to install ["*", nil, if(c.notNil){Color.blue.blend(c,0.5)}{Color.blue(1, 0.5)}] ]; installButton.action = { arg butt; toBeInstalled = butt.value>0; }; }); this.reset; } reset { installButton.valueAction = 0; } flush { toBeInstalled.if {isInstalled = true; toBeInstalled = false}; toBeDeinstalled.if{isInstalled = false; toBeDeinstalled = false}; this.updateButtonStates; } fullDescription { var window; window = GUI.window.new(quark.name, Rect(100, 100, 400, 200)).front; GUI.textView.new( window, Rect(4, 4, 392, 192)) .font_( Font.sansSerif( 12 ) ) .resize_( 5 ) .autohidesScrollers_( true ) .hasVerticalScroller_( true ) .string_( quark.longDesc ) .editable_( false ); GUI.button.new(window, Rect(125, 176, 150, 20)) .resize_(8) .states_([["Open quark help"]]) .action_({ quark.help }); } remove { [installButton, nameView, infoButton, srcButton].do(_.remove); } } QuarkViewQt { var 0; }; },{ // Quark is currently not installed installButton.states = [ // never installed ["-", nil, ], // selected to install ["*", nil, if(c.notNil){Color.blue.blend(c,0.5)}{Color.blue(1, 0.5)}] ]; installButton.action = { arg butt; toBeInstalled = butt.value>0; }; }); this.reset; } reset { installButton.valueAction = 0; } flush { toBeInstalled.if {isInstalled = true; toBeInstalled = false}; toBeDeinstalled.if{isInstalled = false; toBeDeinstalled = false}; this.updateButtonStates; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Unix/0000775000000000000000000000000012245452763023766 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Unix/Unix.sc0000664000000000000000000000007412014636263025232 0ustar rootrootUnix { *errno { _Unix_Errno ^this.primitiveFailed } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Unix/UnixFILE.sc0000664000000000000000000000712512014636263025676 0ustar rootrootUnixFILE : IOStream { // abstract class. Use File or Pipe. classvar a - b if (b.descendants.size == 1) { buildSynthDef.removeUGen(b); } { b.descendants.remove(this); }; ^(a - b.inputs[0]) }; if (a.isKindOf(UnaryOpUGen) and: { a.operator == 'neg' }) { // a.neg + b -> b - a if (a.descendants.size == 1) { buildSynthDef.removeUGen(a); } { a.descendants.remove(this); }; ^(b - a.inputs[0]) }; ^nil } optimizeToMulAdd { var a, b; #a, b = inputs; if (a.isKindOf(BinaryOpUGen) and: { a.operator == '*' and: { a.descendants.size == 1 }}) { if (MulAdd.canBeMulAdd(a.inputs[0], a.inputs[1], b)) { buildSynthDef.removeUGen(a); ^MulAdd.new(a.inputs[0], a.inputs[1], b); }; if (MulAdd.canBeMulAdd(a.inputs[1], a.inputs[0], b)) { buildSynthDef.removeUGen(a); ^MulAdd.new(a.inputs[1], a.inputs[0], b) }; }; if (b.isKindOf(BinaryOpUGen) and: { b.operator == '*' and: { b.descendants.size == 1 }}) { if (MulAdd.canBeMulAdd(b.inputs[0], b.inputs[1], a)) { buildSynthDef.removeUGen(b); ^MulAdd.new(b.inputs[0], b.inputs[1], a) }; if (MulAdd.canBeMulAdd(b.inputs[1], b.inputs[0], a)) { buildSynthDef.removeUGen(b); ^MulAdd.new(b.inputs[1], b.inputs[0], a) }; }; ^nil } optimizeToSum3 { var a, b; #a, b = inputs; if (a.isKindOf(BinaryOpUGen) and: { a.operator == '+' and: { a.descendants.size == 1 }}) { buildSynthDef.removeUGen(a); ^Sum3(a.inputs[0], a.inputs[1], b); }; if (b.isKindOf(BinaryOpUGen) and: { b.operator == '+' and: { b.descendants.size == 1 }}) { buildSynthDef.removeUGen(b); ^Sum3(b.inputs[0], b.inputs[1], a); }; ^nil } optimizeToSum4 { var a, b; #a, b = inputs; if (a.isKindOf(Sum3) and: { a.descendants.size == 1 }) { buildSynthDef.removeUGen(a); ^Sum4(a.inputs[0], a.inputs[1], a.inputs[2], b); }; if (b.isKindOf(Sum3) and: { b.descendants.size == 1 }) { buildSynthDef.removeUGen(b); ^Sum4(b.inputs[0], b.inputs[1], b.inputs[2], a); }; ^nil } optimizeSub { var a, b, replacement; #a, b = inputs; if (b.isKindOf(UnaryOpUGen) and: { b.operator == 'neg' }) { // a - b.neg -> a + b if (b.descendants.size == 1) { buildSynthDef.removeUGen(b); } { b.descendants.remove(this); }; replacement = BinaryOpUGen('+', a, b.inputs[0]); synthDef.replaceUGen(this, replacement); replacement.optimizeGraph }; ^nil } constantFolding { var a, b, aa, bb, cc, dd, temp, ac_ops, value; // associative & commutative operators ac_ops = #['+','*','min','max','&&','||']; if (ac_ops.includes(operator).not) { ^this }; #a, b = inputs; if (a.isKindOf(BinaryOpUGen) and: { operator == a.operator and: { b.isKindOf(BinaryOpUGen) and: { operator == b.operator } }}) { #aa, bb = a.inputs; #cc, dd = b.inputs; if (aa.isKindOf(SimpleNumber)) { if (cc.isKindOf(SimpleNumber)) { b.inputs[0] = bb; this.inputs[0] = aa.perform(operator, cc); synthDef.removeUGen(a); }{ if (dd.isKindOf(SimpleNumber)) { b.inputs[1] = bb; this.inputs[0] = aa.perform(operator, dd); synthDef.removeUGen(a); }} }{ if (bb.isKindOf(SimpleNumber)) { if (cc.isKindOf(SimpleNumber)) { b.inputs[0] = aa; this.inputs[0] = bb.perform(operator, cc); synthDef.removeUGen(a); }{ if (dd.isKindOf(SimpleNumber)) { b.inputs[1] = aa; this.inputs[0] = bb.perform(operator, dd); synthDef.removeUGen(a); }} }}; }; #a, b = inputs; if (a.isKindOf(BinaryOpUGen) and: { operator == a.operator }) { #aa, bb = a.inputs; if (b.isKindOf(SimpleNumber)) { if (aa.isKindOf(SimpleNumber)) { buildSynthDef.removeUGen(a); this.inputs[0] = aa.perform(operator, b); this.inputs[1] = bb; ^this }; if (bb.isKindOf(SimpleNumber)) { buildSynthDef.removeUGen(a); this.inputs[0] = bb.perform(operator, b); this.inputs[1] = aa; ^this }; }; // percolate constants upward so that a subsequent folding may occur if (aa.isKindOf(SimpleNumber)) { this.inputs[1] = aa; a.inputs[0] = b; }{ if (bb.isKindOf(SimpleNumber)) { this.inputs[1] = bb; a.inputs[1] = b; }}; }; #a, b = inputs; if (b.isKindOf(BinaryOpUGen) and: { operator == b.operator }) { #cc, dd = b.inputs; if (a.isKindOf(SimpleNumber)) { if (cc.isKindOf(SimpleNumber)) { buildSynthDef.removeUGen(b); this.inputs[0] = a.perform(operator, cc); this.inputs[1] = dd; ^this }; if (dd.isKindOf(SimpleNumber)) { buildSynthDef.removeUGen(b); this.inputs[0] = a.perform(operator, dd); this.inputs[1] = cc; ^this }; }; // percolate constants upward so that a subsequent folding may occur if (cc.isKindOf(SimpleNumber)) { this.inputs[0] = cc; b.inputs[0] = a; }{ if (dd.isKindOf(SimpleNumber)) { this.inputs[0] = dd; b.inputs[1] = a; }}; }; #a, b = inputs; if (a.isKindOf(SimpleNumber) and: { b.isKindOf(SimpleNumber) }) { synthDef.replaceUGen(this, a.perform(operator, b)); synthDef.removeUGen(this); }; } } MulAdd : UGen { *new { arg in, mul = 1.0, add = 0.0; var rate = [in, mul, add].rate; ^this.multiNew(rate, in, mul, add) } *new1 { arg rate, in, mul, add; var minus, nomul, noadd; // eliminate degenerate cases if (mul == 0.0, { ^add }); minus = mul == -1.0; nomul = mul == 1.0; noadd = add == 0.0; if (nomul && noadd, { ^in }); if (minus && noadd, { ^in.neg }); if (noadd, { ^in * mul }); if (minus, { ^add - in }); if (nomul, { ^in + add }); if (this.canBeMulAdd(in, mul, add)) { ^super.new1(rate, in, mul, add) }; if (this.canBeMulAdd(mul, in, add)) { ^super.new1(rate, mul, in, add) }; ^( (in * mul) + add) } init { arg in, mul, add; inputs = [in, mul, add]; rate = inputs.rate; } *canBeMulAdd { arg in, mul, add; // see if these inputs satisfy the constraints of a MulAdd ugen. if (in.rate == \audio, { ^true }); if (in.rate == \control and: { mul.rate == \control || { mul.rate == \scalar }} and: { add.rate == \control || { add.rate == \scalar }}, { ^true }); ^false } } Sum3 : UGen { *new { arg in0, in1, in2; ^this.multiNew(nil, in0, in1, in2) } *new1 { arg dummyRate, in0, in1, in2; var argArray, rate, sortedArgs; if (in2 == 0.0) { ^(in0 + in1) }; if (in1 == 0.0) { ^(in0 + in2) }; if (in0 == 0.0) { ^(in1 + in2) }; argArray = [in0, in1, in2]; rate = argArray.rate; sortedArgs = argArray.sort {|a b| a.rate < b.rate}; ^super.new1(rate, *sortedArgs) } } Sum4 : UGen { *new { arg in0, in1, in2, in3; ^this.multiNew(nil, in0, in1, in2, in3) } *new1 { arg dummyRate, in0, in1, in2, in3; var argArray, rate, sortedArgs; if (in0 == 0.0) { ^Sum3.new1(nil, in1, in2, in3) }; if (in1 == 0.0) { ^Sum3.new1(nil, in0, in2, in3) }; if (in2 == 0.0) { ^Sum3.new1(nil, in0, in1, in3) }; if (in3 == 0.0) { ^Sum3.new1(nil, in0, in1, in2) }; argArray = [in0, in1, in2, in3]; rate = argArray.rate; sortedArgs = argArray.sort {|a b| a.rate < b.rate}; ^super.new1(rate, *sortedArgs) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/FFT.sc0000664000000000000000000001012412245365552025047 0ustar rootroot// fft uses a local buffer for holding the buffered audio. // wintypes are defined in the C++ source. 0 is default, Welch; 1 is Hann; -1 is rect. WidthFirstUGen : UGen { addToSynth { synthDef = buildSynthDef; if (synthDef.notNil, { synthDef.addUGen(this); synthDef.widthFirstUGens = synthDef.widthFirstUGens.add(this); }); } } FFT : PV_ChainUGen { *new { | buffer, in = 0.0 , hop = 0.5, wintype = 0 , active = 1, winsize=0| ^this.multiNew('control', buffer, in, hop, wintype, active, winsize) } } IFFT : WidthFirstUGen { *new { | buffer, wintype = 0, winsize=0| ^this.ar(buffer, wintype, winsize) } *ar { | buffer, wintype = 0, winsize=0| ^this.multiNew('audio', buffer, wintype, winsize) } *kr { | buffer, wintype = 0, winsize=0| ^this.multiNew('control', buffer, wintype, winsize) } } PV_MagAbove : PV_ChainUGen { *new { arg buffer, threshold = 0.0; ^this.multiNew('control', buffer, threshold) } } PV_MagBelow : PV_MagAbove {} PV_MagClip : PV_MagAbove {} PV_LocalMax : PV_MagAbove {} PV_MagSmear : PV_ChainUGen { *new { arg buffer, bins = 0.0; ^this.multiNew('control', buffer, bins) } } PV_BinShift : PV_ChainUGen { *new { arg buffer, stretch = 1.0, shift = 0.0, interp = 0; ^this.multiNew('control', buffer, stretch, shift, interp) } } PV_MagShift : PV_ChainUGen { *new { arg buffer, stretch = 1.0, shift = 0.0; ^this.multiNew('control', buffer, stretch, shift) } } PV_MagSquared : PV_ChainUGen { *new { arg buffer; ^this.multiNew('control', buffer) } } PV_MagNoise : PV_MagSquared {} PV_PhaseShift90 : PV_MagSquared {} PV_PhaseShift270 : PV_MagSquared {} PV_Conj : PV_MagSquared {} PV_PhaseShift : PV_ChainUGen { *new { arg buffer, shift, integrate=0; ^this.multiNew('control', buffer, shift, integrate) } } PV_BrickWall : PV_ChainUGen { *new { arg buffer, wipe = 0.0; ^this.multiNew('control', buffer, wipe) } } PV_BinWipe : PV_ChainUGen { *new { arg bufferA, bufferB, wipe = 0.0; ^this.multiNew('control', bufferA, bufferB, wipe) } } PV_MagMul : PV_ChainUGen { *new { arg bufferA, bufferB; ^this.multiNew('control', bufferA, bufferB) } } PV_CopyPhase : PV_MagMul {} PV_Copy : PV_MagMul {} PV_Max : PV_MagMul {} PV_Min : PV_MagMul {} PV_Mul : PV_MagMul {} PV_Div : PV_MagMul {} PV_Add : PV_MagMul {} PV_MagDiv : PV_ChainUGen { *new { arg bufferA, bufferB, zeroed = 0.0001; ^this.multiNew('control', bufferA, bufferB, zeroed) } } PV_RandComb : PV_ChainUGen { *new { arg buffer, wipe = 0.0, trig = 0.0; ^this.multiNew('control', buffer, wipe, trig) } } PV_RectComb : PV_ChainUGen { *new { arg buffer, numTeeth = 0.0, phase = 0.0, width = 0.5; ^this.multiNew('control', buffer, numTeeth, phase, width) } } PV_RectComb2 : PV_ChainUGen { *new { arg bufferA, bufferB, numTeeth = 0.0, phase = 0.0, width = 0.5; ^this.multiNew('control', bufferA, bufferB, numTeeth, phase, width) } } PV_RandWipe : PV_ChainUGen { *new { arg bufferA, bufferB, wipe = 0.0, trig = 0.0; ^this.multiNew('control', bufferA, bufferB, wipe, trig) } } PV_Diffuser : PV_ChainUGen { *new { arg buffer, trig = 0.0; ^this.multiNew('control', buffer, trig) } } PV_MagFreeze : PV_ChainUGen { *new { arg buffer, freeze = 0.0; ^this.multiNew('control', buffer, freeze) } } PV_BinScramble : PV_ChainUGen { *new { arg buffer, wipe = 0.0, width = 0.2, trig = 0.0; ^this.multiNew('control', buffer, wipe, width, trig) } } FFTTrigger : PV_ChainUGen { *new { | buffer, hop = 0.5, polar = 0.0| ^this.multiNew('control', buffer, hop, polar) } } //////////////////////////////////////////////////// /* PV_OscBank : PV_ChainUGen { *new { arg buffer, scale; ^this.multiNew('control', buffer) } } PV_Scope : PV_ChainUGen {} PV_TimeAverageScope : PV_Scope {} PV_MagAllTimeAverage : PV_MagSquared {} PV_MagOnePole : PV_ChainUGen { *new { arg buffer, feedback = 0.0; ^this.multiNew('control', buffer, feedback) } } PV_MagPeakDecay : PV_ChainUGen { *new { arg buffer, decay = 0.0; ^this.multiNew('control', buffer, decay) } } PV_TimeSmear : PV_MagSmear {} PV_LoBitEncoder : PV_ChainUGen { *new { arg buffer, levels = 4.0; ^this.multiNew('control', buffer, levels) } } */ SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/BEQSuite.sc0000664000000000000000000001205212014636263026045 0ustar rootrootBEQSuite : Filter {} BLowPass : BEQSuite { *ar { arg in, freq = 1200.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq).madd(mul, add); } *sc { arg dummy, freq = 1200.0, rq = 1.0; var w0, cos_w0, i, alpha, a0, a1, b0rz, b1, b2, sr; sr = SampleRate.ir; w0 = pi * 2 * freq * SampleDur.ir; cos_w0 = w0.cos; i = 1 - cos_w0; alpha = w0.sin * 0.5 * rq; b0rz = (1 + alpha).reciprocal; a0 = i * 0.5 * b0rz; a1 = i * b0rz; b1 = cos_w0 * 2 * b0rz; b2 = (1 - alpha) * b0rz.neg; ^[a0, a1, a0, b1, b2]; } } BHiPass : BEQSuite { *ar { arg in, freq = 1200.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq).madd(mul, add); } *sc { arg dummy, freq = 1200.0, rq = 1.0; var i, w0, cos_w0, alpha, a0, a1, b0rz, b1, b2, sr; sr = SampleRate.ir; w0 = pi * 2 * freq * SampleDur.ir; cos_w0 = w0.cos; i = 1 + cos_w0; alpha = w0.sin * 0.5 * rq; b0rz = (1 + alpha).reciprocal; a0 = i * 0.5 * b0rz; a1 = i.neg * b0rz; b1 = cos_w0 * 2 * b0rz; b2 = (1 - alpha) * b0rz.neg; ^[a0, a1, a0, b1, b2]; } } BAllPass : BEQSuite { *ar { arg in, freq = 1200.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq).madd(mul, add); } *sc { arg dummy, freq = 1200.0, rq = 1.0; var w0, alpha, a0, b1, b0rz, sr; sr = SampleRate.ir; w0 = pi * 2 * freq * SampleDur.ir; alpha = w0.sin * 0.5 * rq; b0rz = (1 + alpha).reciprocal; a0 = (1 - alpha) * b0rz; b1 = 2.0 * w0.cos * b0rz; ^[a0, b1.neg, 1.0, b1, a0.neg]; } } BBandPass : BEQSuite { *ar {arg in, freq = 1200.0, bw = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, bw).madd(mul, add); } *sc { arg dummy, freq = 1200.0, bw = 1.0; var w0, sin_w0, alpha, a0, b0rz, b1, b2, sr; sr = SampleRate.ir; w0 = pi * 2 * freq * SampleDur.ir; sin_w0 = w0.sin; // alpha = w0.sin * 0.5 * rq; alpha = sin_w0 * sinh(0.34657359027997 * bw * w0 / sin_w0); b0rz = (1 + alpha).reciprocal; a0 = alpha * b0rz; b1 = w0.cos * 2 * b0rz; b2 = (1 - alpha) * b0rz.neg; ^[a0, 0.0, a0.neg, b1, b2]; } } BBandStop : BEQSuite { *ar {arg in, freq = 1200.0, bw = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, bw).madd(mul, add); } *sc { arg dummy, freq = 1200.0, bw = 1.0; var w0, sin_w0, alpha, b1, b2, b0rz, sr; sr = SampleRate.ir; w0 = pi * 2 * freq * SampleDur.ir; sin_w0 = w0.sin; // alpha = w0.sin * 0.5 * rq; alpha = sin_w0 * sinh(0.34657359027997 * bw * w0 / sin_w0); b0rz = (1 + alpha).reciprocal; b1 = 2.0 * w0.cos * b0rz; b2 = (1 - alpha) * b0rz.neg; ^[b0rz, b1.neg, b0rz, b1, b2]; } } BPeakEQ : BEQSuite { *ar {arg in, freq = 1200.0, rq = 1.0, db = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq, db).madd(mul, add); } *sc { arg dummy, freq = 1200.0, rq = 1.0, db = 0.0; var a, w0, alpha, a0, a2, b1, b2, b0rz, sr; sr = SampleRate.ir; a = pow(10, db/40); w0 = pi * 2 * freq * SampleDur.ir; alpha = w0.sin * 0.5 * rq; b0rz = (1 + (alpha / a)).reciprocal; a0 = (1 + (alpha * a)) * b0rz; a2 = (1 - (alpha * a)) * b0rz; b1 = 2.0 * w0.cos * b0rz; b2 = (1 - (alpha / a)) * b0rz.neg; ^[a0, b1.neg, a2, b1, b2]; } } BLowShelf : BEQSuite { *ar {arg in, freq = 1200.0, rs = 1.0, db = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rs, db).madd(mul, add); } *sc { arg dummy, freq = 120.0, rs = 1.0, db = 0.0; var a, w0, sin_w0, cos_w0, alpha, i, j, k, a0, a1, a2, b0rz, b1, b2, sr; sr = SampleRate.ir; a = pow(10, db/40); w0 = pi * 2 * freq * SampleDur.ir; cos_w0 = w0.cos; sin_w0 = w0.sin; alpha = sin_w0 * 0.5 * sqrt((a + a.reciprocal) * (rs - 1) + 2.0); i = (a+1) * cos_w0; j = (a-1) * cos_w0; k = 2 * sqrt(a) * alpha; b0rz = ((a+1) + j + k).reciprocal; a0 = a * ((a+1) - j + k) * b0rz; a1 = 2 * a * ((a-1) - i) * b0rz; a2 = a * ((a+1) - j - k) * b0rz; b1 = 2.0 * ((a-1) + i) * b0rz; b2 = ((a+1) + j - k) * b0rz.neg; ^[a0, a1, a2, b1, b2]; } } BHiShelf : BEQSuite { *ar {arg in, freq = 1200.0, rs = 1.0, db = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rs, db).madd(mul, add); } *sc { arg dummy, freq = 120.0, rs = 1.0, db = 0.0; var a, w0, sin_w0, cos_w0, alpha, i, j, k, a0, a1, a2, b0rz, b1, b2, sr; sr = SampleRate.ir; a = pow(10, db/40); w0 = pi * 2 * freq * SampleDur.ir; cos_w0 = w0.cos; sin_w0 = w0.sin; alpha = sin_w0 * 0.5 * sqrt((a + a.reciprocal) * (rs - 1) + 2.0); i = (a+1) * cos_w0; j = (a-1) * cos_w0; k = 2 * sqrt(a) * alpha; b0rz = ((a+1) - j + k).reciprocal; a0 = a * ((a+1) + j + k) * b0rz; a1 = -2.0 * a * ((a-1) + i) * b0rz; a2 = a * ((a+1) + j - k) * b0rz; b1 = -2.0 * ((a-1) - i) * b0rz; b2 = ((a+1) - j - k) * b0rz.neg; ^[a0, a1, a2, b1, b2]; } } // pseudo UGens BLowPass4 { *ar { arg in, freq = 1200.0, rq = 1.0, mul = 1.0, add = 0.0; var coefs; rq = sqrt(rq); coefs = BLowPass.sc(nil, freq, rq); ^SOS.ar(SOS.ar(in, *coefs), *coefs ++ [mul, add]); } } BHiPass4 { *ar { arg in, freq = 1200.0, rq = 1.0, mul = 1.0, add = 0.0; var coefs; rq = sqrt(rq); coefs = BHiPass.sc(nil, freq, rq); ^SOS.ar(SOS.ar(in, *coefs), *coefs ++ [mul, add]); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/FreeVerb.sc0000775000000000000000000000105412014636263026127 0ustar rootroot// blackrain's freeverb ugen. FreeVerb : Filter { *ar { arg in, mix = 0.33, room = 0.5, damp = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, mix, room, damp).madd(mul, add) } } FreeVerb2 : MultiOutUGen { *ar { arg in, in2, mix = 0.33, room = 0.5, damp = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, in2, mix, room, damp).madd(mul, add) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate, this, 0), OutputProxy(rate, this, 1) ]; ^channels } checkInputs { ^this.checkNInputs(2); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Compander.sc0000664000000000000000000000233512014636263026337 0ustar rootrootAmplitude : UGen { *ar { arg in = 0.0, attackTime = 0.01, releaseTime = 0.01, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, attackTime, releaseTime).madd(mul, add) } *kr { arg in = 0.0, attackTime = 0.01, releaseTime = 0.01, mul = 1.0, add = 0.0; ^this.multiNew('control', in, attackTime, releaseTime).madd(mul, add) } } Compander : UGen { *ar { arg in = 0.0, control = 0.0, thresh = 0.5, slopeBelow = 1.0, slopeAbove = 1.0, clampTime = 0.01, relaxTime = 0.1, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, control, thresh, slopeBelow, slopeAbove, clampTime, relaxTime).madd(mul, add) } } // CompanderD passes the signal directly to the control input, // but adds a delay to the process input so that the lag in the gain // clamping will not lag the attacks in the input sound CompanderD : UGen { *ar { arg in = 0.0, thresh = 0.5, slopeBelow = 1.0, slopeAbove = 1.0, clampTime = 0.01, relaxTime = 0.01, mul = 1.0, add = 0.0; ^Compander.ar(DelayN.ar(in, clampTime, clampTime), in, thresh, slopeBelow, slopeAbove, clampTime, relaxTime).madd(mul, add) } } Normalizer : UGen { var buffer; *ar { arg in = 0.0, level = 1.0, dur = 0.01; ^this.multiNew('audio', in, level, dur) } } Limiter : Normalizer {} SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/MachineListening.sc0000664000000000000000000000417612014636263027655 0ustar rootroot//4 outs BeatTrack : MultiOutUGen { *kr { arg chain, lock=0; if(chain.isKindOf(FFT).not){ // Automatically drop in an FFT, possible now that we have LocalBuf chain = FFT(LocalBuf(if(SampleRate.ir>48000, 2048, 1024)), chain); }; ^this.multiNew('control',chain, lock); } init { arg ... theInputs; inputs = theInputs; ^this.initOutputs(4, rate); } } //loudness output in sones Loudness : UGen { *kr { arg chain, smask=0.25, tmask=1; ^this.multiNew('control',chain, smask, tmask); } } Onsets : UGen { *kr { |chain, threshold=0.5, odftype=\rcomplex, relaxtime=1, floor=0.1, mingap=10, medianspan=11, whtype=1, rawodf=0| if(odftype.class == Symbol){ odftype = #[\power, \magsum, \complex, \rcomplex, \phase, \wphase,\mkl] .indexOf(odftype) }; // mingap of 10 frames, @ 44100 & 512 & 50%, is about 0.058 seconds ^this.multiNew('control', chain, threshold, odftype, relaxtime, floor, mingap, medianspan, whtype, rawodf) } } //transient input not currently used but reserved for future use in downweighting frames which have high transient content KeyTrack : UGen { *kr { arg chain,keydecay=2.0,chromaleak= 0.5; //transient=0.0; ^this.multiNew('control',chain,keydecay,chromaleak); //transient; } } //a bufnum could be added as third argument for passing arbitrary band spacing data MFCC : MultiOutUGen { *kr { arg chain, numcoeff=13; ^this.multiNew('control', chain, numcoeff); } init { arg ... theInputs; inputs = theInputs; ^this.initOutputs(theInputs[1], rate); } } //6 outs BeatTrack2 : MultiOutUGen { *kr { arg busindex, numfeatures, windowsize=2.0, phaseaccuracy=0.02, lock=0, weightingscheme; ^this.multiNew('control',busindex, numfeatures,windowsize, phaseaccuracy, lock, weightingscheme ? (-2.1)); } init { arg ... theInputs; inputs = theInputs; ^this.initOutputs(6, rate); } } SpecFlatness : UGen { *kr { | buffer | ^this.multiNew('control', buffer) } } SpecPcile : UGen { *kr { | buffer, fraction = 0.5, interpolate = 0 | ^this.multiNew('control', buffer, fraction, interpolate) } } SpecCentroid : UGen { *kr { | buffer | ^this.multiNew('control', buffer) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/CheckBadValues.sc0000664000000000000000000000055212014636263027232 0ustar rootrootCheckBadValues : UGen { *ar {arg in = 0.0, id = 0, post = 2; ^this.multiNew('audio', in, id, post); } *kr {arg in = 0.0, id = 0, post = 2; ^this.multiNew('control', in, id, post); } checkInputs { if ((rate==\audio) and:{ inputs.at(0).rate != \audio}) { ^("audio-rate, yet first input is not audio-rate"); }; ^this.checkValidInputs } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/InOut.sc0000664000000000000000000001634512245365552025501 0ustar rootrootControlName { var <>name, <>index, <>rate, <>defaultValue, <>argNum, <>lag; *new { arg name, index, rate, defaultValue, argNum, lag; ^super.newCopyArgs(name.asSymbol, index, rate, defaultValue, argNum, lag ? 0.0) } numChannels { ^defaultValue.asArray.size; } printOn { arg stream; stream << "ControlName P " << index.asString; if (name.notNil) { stream << " " << name; }; if (rate.notNil) { stream << " " << rate; }; if (defaultValue.notNil) { stream << " " << defaultValue; }; //stream << "\n" } } Control : MultiOutUGen { var 0) { // the current control is always the last added, so: lastControl = synthDef.controlNames.last; if(lastControl.defaultValue.isNil) { // only write if not there yet: lastControl.defaultValue_(values.unbubble); } }; synthDef.controlIndex = synthDef.controlIndex + values.size; }; ^this.initOutputs(values.size, rate) } *isControlUGen { ^true } } AudioControl : MultiOutUGen { var > 1; values = stuff[ .. size2-1]; inputs = stuff[size2 .. size-1]; if (synthDef.notNil, { specialIndex = synthDef.controls.size; synthDef.controls = synthDef.controls.addAll(values); synthDef.controlIndex = synthDef.controlIndex + values.size; }); ^this.initOutputs(values.size, rate) } } AbstractIn : MultiOutUGen { *isInputUGen { ^true } } In : AbstractIn { *ar { arg bus = 0, numChannels = 1; ^this.multiNew('audio', numChannels, bus) } *kr { arg bus = 0, numChannels = 1; ^this.multiNew('control', numChannels, bus) } init { arg numChannels ... argBus; inputs = argBus.asArray; ^this.initOutputs(numChannels, rate) } } LocalIn : AbstractIn { *ar { arg numChannels = 1, default = 0.0; ^this.multiNew('audio', numChannels, *default) } *kr { arg numChannels = 1, default = 0.0; ^this.multiNew('control', numChannels, *default) } init { arg numChannels ... default; inputs = default.wrapExtend(numChannels); ^this.initOutputs(numChannels, rate) } } LagIn : AbstractIn { *kr { arg bus = 0, numChannels = 1, lag = 0.1; ^this.multiNew('control', numChannels, bus, lag) } init { arg numChannels ... argInputs; inputs = argInputs.asArray; ^this.initOutputs(numChannels, rate) } } InFeedback : AbstractIn { *ar { arg bus = 0, numChannels = 1; ^this.multiNew('audio', numChannels, bus) } init { arg numChannels ... argBus; inputs = argBus.asArray; ^this.initOutputs(numChannels, rate) } } InTrig : AbstractIn { *kr { arg bus = 0, numChannels = 1; ^this.multiNew('control', numChannels, bus) } init { arg numChannels ... argBus; inputs = argBus.asArray; ^this.initOutputs(numChannels, rate) } } AbstractOut : UGen { numOutputs { ^0 } writeOutputSpecs {} checkInputs { if (rate == 'audio', { for(this.class.numFixedArgs, inputs.size - 1, { arg i; if (inputs.at(i).rate != 'audio', { ^(" input at index " + i + "(" + inputs.at(i) + ") is not audio rate"); }); }); }); ^this.checkValidInputs } *isOutputUGen { ^true } *numFixedArgs { ^this.subclassResponsibility(thisMethod) } numAudioChannels { ^inputs.size - this.class.numFixedArgs } writesToBus { ^this.subclassResponsibility(thisMethod) } } Out : AbstractOut { *ar { arg bus, channelsArray; channelsArray = this.replaceZeroesWithSilence(channelsArray.asArray); this.multiNewList(['audio', bus] ++ channelsArray) ^0.0 // Out has no output } *kr { arg bus, channelsArray; this.multiNewList(['control', bus] ++ channelsArray.asArray) ^0.0 // Out has no output } *numFixedArgs { ^1 } writesToBus { ^true } } ReplaceOut : Out {} OffsetOut : Out { *kr { ^this.shouldNotImplement(thisMethod) } } LocalOut : AbstractOut { *ar { arg channelsArray; channelsArray = this.replaceZeroesWithSilence(channelsArray.asArray); this.multiNewList(['audio'] ++ channelsArray) ^0.0 // LocalOut has no output } *kr { arg channelsArray; this.multiNewList(['control'] ++ channelsArray.asArray) ^0.0 // LocalOut has no output } *numFixedArgs { ^0 } writesToBus { ^false } } XOut : AbstractOut { *ar { arg bus, xfade, channelsArray; channelsArray = this.replaceZeroesWithSilence(channelsArray.asArray); this.multiNewList(['audio', bus, xfade] ++ channelsArray) ^0.0 // Out has no output } *kr { arg bus, xfade, channelsArray; this.multiNewList(['control', bus, xfade] ++ channelsArray.asArray) ^0.0 // Out has no output } *numFixedArgs { ^2 } checkInputs { if (rate == 'audio', { for(2, inputs.size - 1, { arg i; if (inputs.at(i).rate != 'audio', { ^(" input at index " + i + "(" + inputs.at(i) + ") is not audio rate"); }); }); }); ^this.checkValidInputs } writesToBus { ^true } } SharedOut : AbstractOut { *kr { arg bus, channelsArray; warn("SharedOut is deprecated and will be removed. Please use Bus-getSynchronous instead."); this.multiNewList(['control', bus] ++ channelsArray.asArray) ^0.0 // Out has no output } *numFixedArgs { ^1 } writesToBus { ^false } } SharedIn : AbstractIn { *kr { arg bus = 0, numChannels = 1; warn("SharedIn is deprecated and will be removed. Please use Bus-setSynchronous instead."); ^this.multiNew('control', numChannels, bus) } init { arg numChannels ... argBus; inputs = argBus.asArray; ^this.initOutputs(numChannels, rate) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Demand.sc0000664000000000000000000001177412245365552025634 0ustar rootrootDemand : MultiOutUGen { *ar { arg trig, reset, demandUGens; ^this.multiNewList(['audio', trig, reset] ++ demandUGens.asArray) } *kr { arg trig, reset, demandUGens; ^this.multiNewList(['control', trig, reset] ++ demandUGens.asArray) } init { arg ... argInputs; inputs = argInputs; ^this.initOutputs(inputs.size - 2, rate) } checkInputs { ^this.checkSameRateAsFirstInput } } Duty : UGen { *ar { arg dur = 1.0, reset = 0.0, level = 1.0, doneAction = 0; ^this.multiNew('audio', dur, reset, doneAction, level) } *kr { arg dur = 1.0, reset = 0.0, level = 1.0, doneAction = 0; ^this.multiNew('control', dur, reset, doneAction, level) } checkInputs { ^if(inputs.at(0).rate === \demand) { if (inputs.at(1).rate !== \demand and: { inputs.at(1).rate !== \scalar } and: { inputs.at(1).rate !== rate }) { ("reset input is not" + rate + "rate: " + inputs.at(1) + inputs.at(1).rate); } } { this.checkValidInputs } } } TDuty : Duty { *ar { arg dur = 1.0, reset = 0.0, level = 1.0, doneAction = 0, gapFirst = 0; ^this.multiNew('audio', dur, reset, doneAction, level, gapFirst) } *kr { arg dur = 1.0, reset = 0.0, level = 1.0, doneAction = 0, gapFirst = 0; ^this.multiNew('control', dur, reset, doneAction, level, gapFirst) } } // old version with gap first TDuty_old { *ar { arg dur = 1.0, reset = 0.0, level = 1.0, doneAction = 0; ^TDuty.ar(dur, reset, level, doneAction, 1) } *kr { arg dur = 1.0, reset = 0.0, level = 1.0, doneAction = 0; ^TDuty.kr(dur, reset, level, doneAction, 1) } } DemandEnvGen : UGen { *kr { arg level, dur, shape = 1, curve = 0, gate = 1.0, reset = 1.0, levelScale = 1.0, levelBias = 0.0, timeScale = 1.0, doneAction=0; ^this.multiNew('control', level, dur, shape, curve, gate, reset, levelScale, levelBias, timeScale, doneAction) } *ar { arg level, dur, shape = 1, curve = 0, gate = 1.0, reset = 1.0, levelScale = 1.0, levelBias = 0.0, timeScale = 1.0, doneAction=0; if(gate.rate === 'audio' or: { reset.rate === 'audio' }) { if(gate.rate !== 'audio') { gate = K2A.ar(gate) }; if(reset.rate !== 'audio') { reset = K2A.ar(reset) }; }; ^this.multiNew('audio', level, dur, shape, curve, gate, reset, levelScale, levelBias, timeScale, doneAction) } } DUGen : UGen { // some n-ary op special cases linlin { arg inMin, inMax, outMin, outMax, clip=\minmax; ^((this.prune(inMin, inMax, clip)-inMin)/(inMax-inMin) * (outMax-outMin) + outMin); } linexp { arg inMin, inMax, outMin, outMax, clip=\minmax; ^(pow(outMax/outMin, (this-inMin)/(inMax-inMin)) * outMin) .prune(outMin, outMax, clip); } explin { arg inMin, inMax, outMin, outMax, clip=\minmax; ^(log(this.prune(inMin, inMax, clip)/inMin)) / (log(inMax/inMin)) * (outMax-outMin) + outMin } expexp { arg inMin, inMax, outMin, outMax, clip=\minmax; ^pow(outMax/outMin, log(this.prune(inMin, inMax, clip/inMin) / log(inMax/inMin)) * outMin) } } Dseries : DUGen { *new { arg start = 1, step = 1, length = inf; ^this.multiNew('demand', length, start, step) } } Dgeom : DUGen { *new { arg start = 1, grow = 2, length = inf; ^this.multiNew('demand', length, start, grow) } } Dbufrd : DUGen { *new { arg bufnum = 0, phase = 0.0, loop = 1.0; ^this.multiNew('demand', bufnum, phase, loop) } } Dbufwr : DUGen { *new { arg input = 0.0, bufnum = 0, phase = 0.0, loop = 1.0; ^this.multiNew('demand', bufnum, phase, input, loop) } } ListDUGen : DUGen { *new { arg list, repeats = 1; ^this.multiNewList(['demand', repeats] ++ list) } } Dseq : ListDUGen {} Dser : ListDUGen {} Dshuf : ListDUGen {} Drand : ListDUGen {} Dxrand : ListDUGen {} Dwrand : DUGen { *new { arg list, weights, repeats = 1; var size = list.size; weights = weights.extend(size, 0.0); ^this.multiNewList(['demand', repeats, size] ++ weights ++ list) } } Dswitch1 : DUGen { *new { arg list, index; ^this.multiNewList(['demand', index] ++ list) } } Dswitch : Dswitch1 {} Dwhite : DUGen { *new { arg lo = 0.0, hi = 1.0, length = inf; ^this.multiNew('demand', length, lo, hi) } } Diwhite : Dwhite {} Dbrown : DUGen { *new { arg lo = 0.0, hi = 1.0, step = 0.01, length = inf; ^this.multiNew('demand', length, lo, hi, step) } } Dibrown : Dbrown {} Dstutter : DUGen { *new { arg n, in; ^this.multiNew('demand', n, in) } } Donce : DUGen { *new { arg in; ^this.multiNew('demand', in) } } Dreset : DUGen { *new { arg in, reset = 0.0; ^this.multiNew('demand', in, reset) } } Dpoll : DUGen { *new { arg in, label, run = 1, trigid = -1; ^this.multiNew('demand', in, label, run, trigid) } *new1 { arg rate, in, label, run, trigid; label = label ?? { "DemandUGen(%)".format(in.class) }; label = label.ascii; ^super.new.rate_(rate).addToSynth.init(*[in, trigid, run, label.size] ++ label); } } // behave as identical in multiple uses Dunique : UGen { var <>source, stutter, numUses; *new { arg source; ^super.new.source_(source).init } init { numUses = 0; stutter = Dstutter(1, source); } asUGenInput { numUses = numUses + 1; stutter.inputs[0] = numUses; ^stutter } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/InfoUGens.sc0000664000000000000000000000174712245365552026300 0ustar rootrootInfoUGenBase : UGen { *ir { ^this.multiNew('scalar') } } BufInfoUGenBase : UGen { *kr { arg bufnum; ^this.multiNew('control', bufnum) } // the .ir method is not the safest choice. Since a buffer can be reallocated at any time, // using .ir will not track the changes. *ir { arg bufnum; ^this.multiNew('scalar',bufnum) } } SampleRate : InfoUGenBase {} SampleDur : InfoUGenBase {} RadiansPerSample : InfoUGenBase {} ControlRate : InfoUGenBase {} ControlDur : InfoUGenBase {} SubsampleOffset : InfoUGenBase {} NumOutputBuses : InfoUGenBase {} NumInputBuses : InfoUGenBase {} NumAudioBuses : InfoUGenBase {} NumControlBuses : InfoUGenBase {} NumBuffers : InfoUGenBase {} NumRunningSynths : InfoUGenBase { *kr { ^this.multiNew('control') } } BufSampleRate : BufInfoUGenBase {} BufRateScale : BufInfoUGenBase {} BufFrames : BufInfoUGenBase {} BufSamples : BufInfoUGenBase {} BufDur : BufInfoUGenBase {} BufChannels : BufInfoUGenBase {} //////////////////////////////////////////// SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Delays.sc0000664000000000000000000000536012161364457025657 0ustar rootrootDelay1 : PureUGen { *ar { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in).madd(mul, add) } *kr { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in).madd(mul, add) } } Delay2 : Delay1 { } /////////////////////////////////////// // these delays use real time allocated memory. DelayN : PureUGen { *ar { arg in = 0.0, maxdelaytime = 0.2, delaytime = 0.2, mul = 1.0, add = 0.0; ^this.multiNew('audio', in.asAudioRateInput, maxdelaytime, delaytime).madd(mul, add) } *kr { arg in = 0.0, maxdelaytime = 0.2, delaytime = 0.2, mul = 1.0, add = 0.0; ^this.multiNew('control', in, maxdelaytime, delaytime).madd(mul, add) } } DelayL : DelayN { } DelayC : DelayN { } CombN : PureUGen { *ar { arg in = 0.0, maxdelaytime = 0.2, delaytime = 0.2, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in.asAudioRateInput(this), maxdelaytime, delaytime, decaytime).madd(mul, add) } *kr { arg in = 0.0, maxdelaytime = 0.2, delaytime = 0.2, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, maxdelaytime, delaytime, decaytime).madd(mul, add) } } CombL : CombN { } CombC : CombN { } AllpassN : CombN { } AllpassL : CombN { } AllpassC : CombN { } /////////////////////////////////////// // these delays use shared buffers. BufDelayN : UGen { *ar { arg buf = 0, in = 0.0, delaytime = 0.2, mul = 1.0, add = 0.0; ^this.multiNew('audio', buf, in.asAudioRateInput, delaytime).madd(mul, add) } *kr { arg buf = 0, in = 0.0, delaytime = 0.2, mul = 1.0, add = 0.0; ^this.multiNew('control', buf, in, delaytime).madd(mul, add) } } BufDelayL : BufDelayN { } BufDelayC : BufDelayN { } BufCombN : UGen { *ar { arg buf = 0, in = 0.0, delaytime = 0.2, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', buf, in.asAudioRateInput(this), delaytime, decaytime).madd(mul, add) } } BufCombL : BufCombN { } BufCombC : BufCombN { } BufAllpassN : BufCombN { } BufAllpassL : BufCombN { } BufAllpassC : BufCombN { } /////////////////////////////////////// /* GrainTap : MultiOutUGen { *ar { arg grainDur = 0.2, pchRatio = 1.0, pchDispersion = 0.0, timeDispersion = 0.0, overlap = 2.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', grainDur, pchRatio, pchDispersion, timeDispersion, overlap).madd(mul, add) } } */ /////////////////////////////////////// DelTapWr : UGen { *ar {arg buffer, in; ^this.multiNew('audio', buffer, in) } *kr {arg buffer, in; ^this.multiNew('control', buffer, in) } } DelTapRd : UGen { *ar {arg buffer, phase, delTime, interp = 1, mul = 1, add = 0; ^this.multiNew('audio', buffer, phase, delTime, interp).madd(mul, add) } *kr {arg buffer, phase, delTime, interp = 1, mul = 1, add = 0; ^this.multiNew('control', buffer, phase, delTime, interp).madd(mul, add) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/SynthDesc.sc0000664000000000000000000004151412245365552026343 0ustar rootrootIODesc { var <>rate, <>numberOfChannels, <>startingChannel, <>type; *new { arg rate, numberOfChannels, startingChannel="?", type; ^super.newCopyArgs(rate, numberOfChannels, startingChannel, type) } printOn { arg stream; stream << rate.asString << " " << type.name << " " << startingChannel << " " << numberOfChannels } } SynthDesc { classvar <>mdPlugin, <>populateMetadataFunc; var <>name, <>controlNames, <>controlDict; var <>controls, <>inputs, <>outputs; var <>metadata; var <>constants, <>def; var <>msgFunc, <>hasGate = false, <>hasArrayArgs, <>hasVariants, <>canFreeSynth = false; var = 2, { desc = SynthDesc.new.readSynthDef2(stream, keepDefs); },{ desc = SynthDesc.new.readSynthDef(stream, keepDefs); }); dict.put(desc.name.asSymbol, desc); // AbstractMDPlugin dynamically determines the md archive type // from the file extension if(path.notNil) { desc.metadata = AbstractMDPlugin.readMetadata(path); }; this.populateMetadataFunc.value(desc); if(desc.def.notNil and: { stream.isKindOf(CollStream).not }) { desc.def.metadata ?? { desc.def.metadata = () }; desc.def.metadata.put(\shouldNotSend, true) .put(\loadPath, path); }; } ^dict } readSynthDef { arg stream, keepDef=false; var numControls, numConstants, numControlNames, numUGens, numVariants; protect { inputs = []; outputs = []; controlDict = IdentityDictionary.new; name = stream.getPascalString; def = SynthDef.prNew(name); UGen.buildSynthDef = def; numConstants = stream.getInt16; constants = FloatArray.newClear(numConstants); stream.read(constants); numControls = stream.getInt16; def.controls = FloatArray.newClear(numControls); stream.read(def.controls); controls = Array.fill(numControls) { |i| ControlName('?', i, '?', def.controls[i]); }; numControlNames = stream.getInt16; numControlNames.do { var controlName, controlIndex; controlName = stream.getPascalString.asSymbol; controlIndex = stream.getInt16; controls[controlIndex].name = controlName; controlNames = controlNames.add(controlName); controlDict[controlName] = controls[controlIndex]; }; numUGens = stream.getInt16; numUGens.do { this.readUGenSpec(stream); }; controls.inject(nil) {|z,y| if(y.name=='?') { z.defaultValue = z.defaultValue.asArray.add(y.defaultValue); z } { y } }; def.controlNames = controls.select {|x| x.name.notNil }; hasArrayArgs = controls.any { |cn| cn.name == '?' }; numVariants = stream.getInt16; hasVariants = numVariants > 0; // maybe later, read in variant names and values // this is harder than it might seem at first def.constants = Dictionary.new; constants.do {|k,i| def.constants.put(k,i) }; if (keepDef.not) { // throw away unneeded stuff def = nil; constants = nil; }; this.makeMsgFunc; } { UGen.buildSynthDef = nil; } } // synthdef ver 2 readSynthDef2 { arg stream, keepDef=false; var numControls, numConstants, numControlNames, numUGens, numVariants; protect { inputs = []; outputs = []; controlDict = IdentityDictionary.new; name = stream.getPascalString; def = SynthDef.prNew(name); UGen.buildSynthDef = def; numConstants = stream.getInt32; constants = FloatArray.newClear(numConstants); stream.read(constants); numControls = stream.getInt32; def.controls = FloatArray.newClear(numControls); stream.read(def.controls); controls = Array.fill(numControls) { |i| ControlName('?', i, '?', def.controls[i]); }; numControlNames = stream.getInt32; numControlNames.do { var controlName, controlIndex; controlName = stream.getPascalString.asSymbol; controlIndex = stream.getInt32; controls[controlIndex].name = controlName; controlNames = controlNames.add(controlName); controlDict[controlName] = controls[controlIndex]; }; numUGens = stream.getInt32; numUGens.do { this.readUGenSpec2(stream); }; controls.inject(nil) {|z,y| if(y.name=='?') { z.defaultValue = z.defaultValue.asArray.add(y.defaultValue); z } { y } }; def.controlNames = controls.select {|x| x.name.notNil }; hasArrayArgs = controls.any { |cn| cn.name == '?' }; numVariants = stream.getInt16; hasVariants = numVariants > 0; // maybe later, read in variant names and values // this is harder than it might seem at first def.constants = Dictionary.new; constants.do {|k,i| def.constants.put(k,i) }; if (keepDef.not) { // throw away unneeded stuff def = nil; constants = nil; }; this.makeMsgFunc; } { UGen.buildSynthDef = nil; } } readUGenSpec { arg stream; var ugenClass, rateIndex, rate, numInputs, numOutputs, specialIndex; var inputSpecs, outputSpecs; var addIO; var ugenInputs, ugen; var control; ugenClass = stream.getPascalString.asSymbol; if(ugenClass.asClass.isNil,{ Error("No UGen class found for" + ugenClass + "which was specified in synth def file: " + this.name ++ ".scsyndef").throw; }); ugenClass = ugenClass.asClass; rateIndex = stream.getInt8; numInputs = stream.getInt16; numOutputs = stream.getInt16; specialIndex = stream.getInt16; inputSpecs = Int16Array.newClear(numInputs * 2); outputSpecs = Int8Array.newClear(numOutputs); stream.read(inputSpecs); stream.read(outputSpecs); ugenInputs = []; forBy (0,inputSpecs.size-1,2) {|i| var ugenIndex, outputIndex, input, ugen; ugenIndex = inputSpecs[i]; outputIndex = inputSpecs[i+1]; input = if (ugenIndex < 0) { constants[outputIndex] }{ ugen = def.children[ugenIndex]; if (ugen.isKindOf(MultiOutUGen)) { ugen.channels[outputIndex] }{ ugen } }; ugenInputs = ugenInputs.add(input); }; rate = #[\scalar,\control,\audio][rateIndex]; ugen = ugenClass.newFromDesc(rate, numOutputs, ugenInputs, specialIndex).source; ugen.addToSynth(ugen); addIO = {|list, nchan| var b = ugen.inputs[0]; if (b.class == OutputProxy and: {b.source.isKindOf(Control)}) { control = controls.detect {|item| item.index == (b.outputIndex+b.source.specialIndex) }; if (control.notNil) { b = control.name }; }; list.add( IODesc(rate, nchan, b, ugenClass)) }; if (ugenClass.isControlUGen) { // Control.newFromDesc does not set the specialIndex, since it doesn't call Control-init. // Therefore we fill it in here: ugen.specialIndex = specialIndex; numOutputs.do { |i| controls[i+specialIndex].rate = rate; } } { case {ugenClass.isInputUGen} {inputs = addIO.value(inputs, ugen.channels.size)} {ugenClass.isOutputUGen} {outputs = addIO.value(outputs, ugen.numAudioChannels)} { canFreeSynth = canFreeSynth or: { ugen.canFreeSynth }; }; }; } // synthdef ver 2 readUGenSpec2 { arg stream; var ugenClass, rateIndex, rate, numInputs, numOutputs, specialIndex; var inputSpecs, outputSpecs; var addIO; var ugenInputs, ugen; var control; ugenClass = stream.getPascalString.asSymbol; if(ugenClass.asClass.isNil,{ Error("No UGen class found for" + ugenClass + "which was specified in synth def file: " + this.name ++ ".scsyndef").throw; }); ugenClass = ugenClass.asClass; rateIndex = stream.getInt8; numInputs = stream.getInt32; numOutputs = stream.getInt32; specialIndex = stream.getInt16; inputSpecs = Int32Array.newClear(numInputs * 2); outputSpecs = Int8Array.newClear(numOutputs); stream.read(inputSpecs); stream.read(outputSpecs); ugenInputs = []; forBy (0,inputSpecs.size-1,2) {|i| var ugenIndex, outputIndex, input, ugen; ugenIndex = inputSpecs[i]; outputIndex = inputSpecs[i+1]; input = if (ugenIndex < 0) { constants[outputIndex] }{ ugen = def.children[ugenIndex]; if (ugen.isKindOf(MultiOutUGen)) { ugen.channels[outputIndex] }{ ugen } }; ugenInputs = ugenInputs.add(input); }; rate = #[\scalar,\control,\audio][rateIndex]; ugen = ugenClass.newFromDesc(rate, numOutputs, ugenInputs, specialIndex).source; ugen.addToSynth(ugen); addIO = {|list, nchan| var b = ugen.inputs[0]; if (b.class == OutputProxy and: {b.source.isKindOf(Control)}) { control = controls.detect {|item| item.index == (b.outputIndex+b.source.specialIndex) }; if (control.notNil) { b = control.name }; }; list.add( IODesc(rate, nchan, b, ugenClass)) }; if (ugenClass.isControlUGen) { // Control.newFromDesc does not set the specialIndex, since it doesn't call Control-init. // Therefore we fill it in here: ugen.specialIndex = specialIndex; numOutputs.do { |i| controls[i+specialIndex].rate = rate; } } { case {ugenClass.isInputUGen} {inputs = addIO.value(inputs, ugen.channels.size)} {ugenClass.isOutputUGen} {outputs = addIO.value(outputs, ugen.numAudioChannels)} { canFreeSynth = canFreeSynth or: { ugen.canFreeSynth }; }; }; } makeMsgFunc { var string, comma=false; var names = IdentitySet.new, suffix = this.hash.asHexString(8); // if a control name is duplicated, the msgFunc will be invalid // that "shouldn't" happen but it might; better to check for it // and throw a proper error controls.do({ |controlName| var name; if(controlName.name.asString.first.isAlpha) { name = controlName.name.asSymbol; if(names.includes(name)) { "Could not build msgFunc for this SynthDesc: duplicate control name %" .format(name).warn; comma = true; } { names.add(name); }; }; }); // reusing variable to know if I should continue or not if(comma) { "\nYour synthdef has been saved in the library and loaded on the server, if running. Use of this synth in Patterns will not detect argument names automatically because of the duplicate name(s).".postln; msgFunc = nil; ^this }; comma = false; names = 0; // now, count the args actually added to the func string = String.streamContents {|stream| stream << "#{ "; if (controlNames.size > 0) { stream << "arg " ; }; controls.do {|controlName, i| var name, name2; name = controlName.name.asString; if (name != "?") { if (name == "gate") { hasGate = true; if(msgFuncKeepGate) { if (comma) { stream << ", " } { comma = true }; stream << name; names = names + 1; } }{ if (name[1] == $_) { name2 = name.drop(2) } { name2 = name }; if (comma) { stream << ", " } { comma = true }; stream << name2; names = names + 1; }; }; }; if (controlNames.size > 0) { stream << ";\n" ; }; stream << "\tvar\tx" << suffix << " = Array.new(" << (names*2) << ");\n"; comma = false; controls.do {|controlName, i| var name, name2; name = controlName.name.asString; if (name != "?") { if (msgFuncKeepGate or: { name != "gate" }) { if (name[1] == $_) { name2 = name.drop(2) } { name2 = name }; stream << "\t" << name2 << " !? { x" << suffix << ".add('" << name << "').add(" << name2 << ") };\n"; names = names + 1; }; }; }; stream << "\tx" << suffix << "\n}" }; // do not compile the string if no argnames were added if(names > 0) { msgFunc = string.compile.value }; } msgFuncKeepGate_ { |bool = false| if(bool != msgFuncKeepGate) { msgFuncKeepGate = bool; this.makeMsgFunc; } } writeMetadata { arg path, mdPlugin; if(metadata.isNil) { AbstractMDPlugin.clearMetadata(path); ^this }; (mdPlugin ?? { this.class.mdPlugin }).writeMetadata(metadata, def, path); } // parse the def name out of the bytes array sent with /d_recv *defNameFromBytes { arg int8Array; var stream, n, numDefs, size; stream = CollStream(int8Array); stream.getInt32; stream.getInt32; numDefs = stream.getInt16; size = stream.getInt8; n = String.newClear(size); ^Array.fill(size, { stream.getChar.asAscii }).as(String) } outputData { var ugens = def.children; var outs = ugens.select(_.writesToBus); ^outs.collect { |outUgen| (rate: outUgen.rate, numChannels: outUgen.numAudioChannels) } } } SynthDescLib { classvar <>all, <>global; var <>name, <>synthDescs, <>servers; *new { arg name, servers; if (name.isNil) { "SynthDescLib must have a name".error; ^nil } ^super.new.name_(name).init(servers); } init { |inServers| all.put(name.asSymbol, this); synthDescs = IdentityDictionary.new; servers = IdentitySet.with(*inServers ? { Server.default }) } *initClass { Class.initClassTree(Server); all = IdentityDictionary.new; global = this.new(\global); ServerBoot.add { |server| // tryToLoadReconstructedDefs = false: // since this is done automatically, w/o user action, // it should not try to do things that will cause warnings // (or errors, if one of the servers is not local) this.send(server, false) } } *getLib { arg libname; ^all[libname] ?? { Error("library % not found".format(libname)).throw }; } *default { ^global } *send { |server, tryToLoadReconstructedDefs = true| global.send(server, tryToLoadReconstructedDefs); } *read { arg path; global.read(path); } at { arg i; ^synthDescs.at(i) } *at { arg i; ^global.at(i) } add { |synthdesc| synthDescs.put(synthdesc.name.asSymbol, synthdesc); } removeAt { |name| ^synthDescs.removeAt(name.asSymbol); } addServer { |server| servers = servers.add(server); // IdentitySet = one server only once. } removeServer { |server| servers.remove(server); } match { |key| var keyString = key.asString, dotIndex = keyString.indexOf($.), desc; if(dotIndex.isNil) { ^synthDescs.at(key.asSymbol) }; if((desc = synthDescs[keyString[..dotIndex-1].asSymbol]).notNil and: { desc.hasVariants }) { ^desc } { ^synthDescs.at(key.asSymbol) } } *match { |key| ^global.match(key) } send { |aServer, tryToLoadReconstructedDefs = true| // sent to all (aServer ? servers).do { |server| server = server.value; synthDescs.do { |desc| if(desc.def.metadata.trueAt(\shouldNotSend).not) { desc.send(server.value) } { if(tryToLoadReconstructedDefs) { desc.def.loadReconstructed(server); }; }; }; }; } read { arg path; if (path.isNil) { path = SynthDef.synthDefDir ++ "*.scsyndef"; }; synthDescs = SynthDesc.read(path, true, synthDescs); } } // Basic metadata plugins // to disable metadata read/write AbstractMDPlugin { *clearMetadata { |path| ^thisProcess.platform.clearMetadata(path) } *writeMetadata { |metadata, synthdef, path| this.clearMetadata(path); path = this.applyExtension(path); this.writeMetadataFile(metadata, synthdef, path); } *writeMetadataFile {} // clearMetadata should ensure that only one MD file ever exists // therefore we can check the subclasses in turn // and return the first MD found // every subclass should have a unique extension *readMetadata { |path| var pathTmp, classList, i; path = path.splitext[0] ++ "."; classList = this.allSubclasses; // ensure that SynthDescLib.mdPlugin is preferred for reading, // with other plugins as a fallback // it will also be possible to use Events or Protos as plugins this way if((i = classList.indexOf(SynthDesc.mdPlugin)).notNil and: { i > 0 }) { classList = classList.copy.swap(0, i); } { classList = [SynthDesc.mdPlugin] ++ classList; }; classList.do({ |class| if(class.notNil and: { File.exists(pathTmp = path ++ class.mdExtension) }) { ^class.readMetadataFile(pathTmp) } }); ^nil } *readMetadataFile { ^nil } *applyExtension { |path| ^path.splitext[0] ++ "." ++ this.mdExtension } *mdExtension { ^"" } // nothing is written anyway } // simple archiving of the dictionary TextArchiveMDPlugin : AbstractMDPlugin { *writeMetadataFile { |metadata, synthdef, path| metadata.writeArchive(path) } *readMetadataFile { |path| ^Object.readArchive(path) } *mdExtension { ^"txarcmeta" } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/IEnvGen.sc0000664000000000000000000000136112161364457025726 0ustar rootrootIEnvGen : UGen { // envelope index generator *ar { arg envelope, index, mul = 1, add = 0; envelope = this.convertEnv(envelope); ^this.multiNewList(['audio', index, envelope]).madd(mul, add) } *kr { arg envelope, index, mul = 1, add = 0; envelope = this.convertEnv(envelope); ^this.multiNewList(['control', index, envelope]).madd(mul, add) } *convertEnv { arg env; if(env.isSequenceableCollection) { ^env.reference }; // raw envelope data ^env.asArrayForInterpolation.collect(_.reference).unbubble } *new1 { arg rate, index, envArray; ^super.new.rate_(rate).addToSynth.init([index] ++ envArray.dereference) } init { arg theInputs; // store the inputs as an array inputs = theInputs; } argNamesInputsOffset { ^2 } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Chaos.sc0000664000000000000000000000554612014636263025473 0ustar rootroot/* Non-linear Dynamic Sound Generators Lance Putnam 2004 lance@uwalumni.com This is a set of iterative functions and differential equations that are known to exhibit chaotic behavior. Internal calculations are done with 64-bit words to ensure greater accuracy. The name of the function is followed by one of N, L, or C. These represent the interpolation method used between function iterations. N -> None L -> Linear C -> Cubic */ ChaosGen : UGen { } // General Quadratic Map QuadN : ChaosGen { const 1}) and: //doneAction { // it can happen that the gate is 1 and the envelope runs out inputs.at(0).isNumber.not or: //variable gate { inputs.at(7) == -99 } //or self releasing envelope } } } + Linen { canFreeSynth { ^(inputs.at(4).isNumber.not or: { inputs.at(4) > 1 }) and: { inputs.at(0).isNumber.not } } } + Line { canFreeSynth { ^inputs.at(3).isNumber.not or: { inputs.at(3) > 1 } } } + XLine { canFreeSynth { ^inputs.at(3).isNumber.not or: { inputs.at(3) > 1 } } } + Free { canFreeSynth { ^true } } + FreeSelf { canFreeSynth { ^true } } + DetectSilence { canFreeSynth { ^inputs.at(3).isNumber.not or: { inputs.at(3) > 1 } } } + Duty { canFreeSynth { ^inputs.at(2).isNumber.not or: { inputs.at(2) > 1 } } } + DemandEnvGen { canFreeSynth { ^inputs.at(9).isNumber.not or: { inputs.at(9) > 1 } } } + SynthDef { canFreeSynth { ^children.canFreeSynth } canReleaseSynth { ^this.hasGateControl and: { this.canFreeSynth } } hasGateControl { if(allControlNames.isNil) { ^false }; ^allControlNames.any { arg cn; cn.notNil and: { cn.name == 'gate' } and: { cn.rate !== 'scalar' } }; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/FSinOsc.sc0000664000000000000000000001003512161364457025735 0ustar rootroot/* FSinOsc - fixed frequency sine oscillator arguments : freq - frequency in cycles per second. Must be a scalar. mul - multiply by signal or scalar add - add to signal or scalar This unit generator uses a very fast algorithm for generating a sine wave at a fixed frequency. */ FSinOsc : UGen { *ar { arg freq=440.0, iphase = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq, iphase).madd(mul, add) } *kr { arg freq=440.0, iphase = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', freq, iphase).madd(mul, add) } } Klang : UGen { *ar { arg specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0; specificationsArrayRef = specificationsArrayRef.multichannelExpandRef(2); ^this.multiNewList(['audio', freqscale, freqoffset, specificationsArrayRef] ) } *new1 { arg rate, freqscale, freqoffset, arrayRef; var specs, freqs, amps, phases; # freqs, amps, phases = arrayRef.dereference; specs = [freqs, amps ?? {Array.fill(freqs.size,1.0)}, phases ?? {Array.fill(freqs.size,0.0)} ].flop.flat; ^super.new.rate_(rate).addToSynth.init([freqscale,freqoffset] ++ specs); } init { arg theInputs; // store the inputs as an array inputs = theInputs; } argNamesInputsOffset { ^2 } } Klank : UGen { *ar { arg specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0; specificationsArrayRef = specificationsArrayRef.multichannelExpandRef(2); ^this.multiNewList(['audio', input, freqscale, freqoffset, decayscale, specificationsArrayRef] ) } *new1 { arg rate, input, freqscale, freqoffset, decayscale, arrayRef; var specs, freqs, amps, times; # freqs, amps, times = arrayRef.dereference; specs = [freqs, amps ?? {Array.fill(freqs.size,1.0)}, times ?? {Array.fill(freqs.size,1.0)} ].flop.flat; ^super.new.rate_(rate).addToSynth.init([input,freqscale,freqoffset,decayscale] ++ specs); } init { arg theInputs; // store the inputs as an array inputs = theInputs; } argNamesInputsOffset { ^2 } } DynKlank : UGen { *ar { arg specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0; ^this.multiNew(\audio, specificationsArrayRef, input, freqscale, freqoffset, decayscale) } *kr { arg specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0; ^this.multiNew(\control, specificationsArrayRef, input, freqscale, freqoffset, decayscale) } *new1 { arg rate, specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0; var spec = specificationsArrayRef.value; var selector = this.methodSelectorForRate(rate); ^Ringz.perform(selector, input, spec[0] ? #[440.0] * freqscale + freqoffset, spec[2] ? #[1.0] * decayscale, spec[1] ? #[1.0] ).sum } } DynKlang : UGen { *ar { arg specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0; ^this.multiNew(\audio, specificationsArrayRef, freqscale, freqoffset); } *kr { arg specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0; ^this.multiNew(\control, specificationsArrayRef, freqscale, freqoffset); } *new1 { arg rate, specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0; var spec = specificationsArrayRef.value; var selector = this.methodSelectorForRate(rate); ^SinOsc.perform(selector, spec[0] ? #[440.0] * freqscale + freqoffset, spec[2] ? #[0.0], spec[1] ? #[1.0] ).sum } } Blip : UGen { *ar { arg freq=440.0, numharm = 200.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq, numharm).madd(mul, add) } *kr { arg freq=440.0, numharm = 200.0, mul = 1.0, add = 0.0; ^this.multiNew('control', freq, numharm).madd(mul, add) } } Saw : UGen { *ar { arg freq=440.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq).madd(mul, add) } *kr { arg freq=440.0, mul = 1.0, add = 0.0; ^this.multiNew('control', freq).madd(mul, add) } } Pulse : UGen { *ar { arg freq=440.0, width = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq, width).madd(mul, add) } *kr { arg freq=440.0, width = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('control', freq, width).madd(mul, add) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Mix.sc0000664000000000000000000000402712161364457025172 0ustar rootrootMix { *new { arg array; var reducedArray = array.asArray.clump(4); var mixedArray = reducedArray.collect {|a| if (a.size == 4) { Sum4(*a) } { if (a.size == 3) { Sum3(*a) } { a.sum } } }; if (mixedArray.size < 3) { ^mixedArray.sum }; if (mixedArray.size == 3) { ^Sum3(*mixedArray) } { ^Mix(mixedArray) } } // support this common idiom *fill { arg n, function; var array = Array.fill(n, function); ^this.new(array); } // and these common idioms *ar { |array| var result = this.new(array); ^switch(result.rate) { \audio } { result } { \control } { K2A.ar(result) } { \scalar } { DC.ar(result) } { Error("Unsupported rate % for Mix.ar".format(result.rate)).throw }; } *kr { |array| var result; // 'rate' on an array returns the fastest rate // ('audio' takes precedence over 'control' over 'scalar') if(array.rate == \audio) { "Audio rate input(s) to Mix.kr will result in signal degradation.".warn; array.do { |unit| if(unit.rate == \audio) { (unit + unit.rate).postln; unit.dumpArgs; }; }; array = array.collect { |unit| if(unit.rate == \audio) { A2K.kr(unit) } { unit }; }; }; result = this.new(array); ^switch(result.rate) { \control } { result } { \scalar } { DC.kr(result) } { Error("Unsupported rate % for Mix.kr".format(result.rate)).throw }; } *arFill { |n, function| ^this.ar(Array.fill(n, function)) } *krFill { |n, function| ^this.kr(Array.fill(n, function)) } } NumChannels { *ar { arg input, numChannels = 2, mixdown = true; if(input.size > 1) { // collection ^input .clump(input.size / numChannels) .collect { arg chan, i; if(chan.size == 1) { chan.at(0) } { if(mixdown) { Mix.new(chan) } { chan.at(0) } } } } { // single ugen or single item collection if(input.isSequenceableCollection) { input = input.at(0); }; if(numChannels == 1) { ^input } { ^Array.fill(numChannels, input) } } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/MoogFF.sc0000775000000000000000000000121412014636263025542 0ustar rootroot/** "MoogFF" - Moog VCF digital implementation. As described in the paper entitled "Preserving the Digital Structure of the Moog VCF" by Federico Fontana appeared in the Proc. ICMC07, Copenhagen, 25-31 August 2007 Original Java code created by F. Fontana - August 2007 federico.fontana@univr.it Ported to C++ for SuperCollider by Dan Stowell - August 2007 http://www.mcld.co.uk/ */ MoogFF : Filter { *ar { | in, freq=100, gain=2, reset=0, mul=1, add=0 | ^this.multiNew('audio', in, freq, gain, reset).madd(mul, add) } *kr { | in, freq=100, gain=2, reset=0, mul=1, add=0 | ^this.multiNew('control', in, freq, gain, reset).madd(mul, add) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/MacUGens.sc0000664000000000000000000000114412014636263026066 0ustar rootrootMouseX : UGen { // warp 0 = linear // warp 1 = exponential *kr { arg minval=0, maxval=1, warp=0, lag=0.2; if (warp === \linear, { warp = 0 }); if (warp === \exponential, { warp = 1 }); ^this.multiNew('control', minval, maxval, warp, lag) } signalRange { ^\unipolar } } MouseY : MouseX {} MouseButton : UGen { *kr { arg minval=0, maxval=1, lag=0.2; ^this.multiNew('control', minval, maxval, lag) } signalRange { ^\unipolar } } KeyState : UGen { *kr { arg keycode=0, minval=0, maxval=1, lag=0.2; ^this.multiNew('control', keycode, minval, maxval, lag) } signalRange { ^\unipolar } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Env.sc0000664000000000000000000002311412245365552025163 0ustar rootrootEnv { var 0, \lin -> 1, \linear -> 1, \exp -> 2, \exponential -> 2, \sin -> 3, \sine -> 3, \wel -> 4, \welch -> 4, \sqr -> 6, \squared -> 6, \cub -> 7, \cubed -> 7 ]; shapeNames.freeze; } kr { arg doneAction = 0, gate = 1.0, timeScale = 1.0, mul = 1.0, add = 0.0; ^EnvGen.kr(this, gate, mul, add, timeScale, doneAction) } ar { arg doneAction = 0, gate = 1.0, timeScale = 1.0, mul = 1.0, add = 0.0; ^EnvGen.ar(this, gate, mul, add, timeScale, doneAction) } levels_ { arg z; levels = z; array = nil; } times_ { arg z; times = z; array = nil; } curves_ { arg z; curves = z; array = nil; } releaseNode_ { arg z; releaseNode = z; array = nil; } loopNode_ { arg z; loopNode = z; array = nil; } offset_ { arg z; offset = z; array = nil; } duration_ { arg dur; times = times * this.totalDuration.reciprocal * dur } duration { ^times.sum } totalDuration { var duration = times.sum; ^duration.asArray.maxItem; } range { arg lo = 0.0, hi = 1.0; ^this.copy.levels_(levels.linlin(levels.minItem, levels.maxItem, lo, hi)) } exprange { arg lo = 0.01, hi = 1.0; ^this.copy.levels_(levels.linexp(levels.minItem, levels.maxItem, lo, hi)) } // methods to make some typical shapes : // fixed duration envelopes *triangle { arg dur=1.0, level=1.0; dur = dur * 0.5; ^this.new( [0, level, 0], [dur, dur] ) } *sine { arg dur=1.0, level=1.0; dur = dur * 0.5; ^this.new( [0, level, 0], [dur, dur], \sine ) } *perc { arg attackTime=0.01, releaseTime=1.0, level=1.0, curve = -4.0; ^this.new( [0, level, 0], [attackTime, releaseTime], curve ) } *linen { arg attackTime=0.01, sustainTime=1.0, releaseTime=1.0, level=1.0, curve = \lin; ^this.new( [0, level, level, 0], [attackTime, sustainTime, releaseTime], curve ) } *xyc { arg xyc; var times, levels, curves, offset, order; #times, levels, curves = xyc.flop; if(times.containsSeqColl.not) { // sort triplets, if possible. order = times.order; times = times[order]; levels = levels[order]; curves = curves[order]; }; offset = times[0]; times = times.differentiate.drop(1); curves.asArray.drop(-1); ^this.new(levels, times, curves, offset: offset); } *pairs { arg pairs, curve; if(curve.isNil) { ^this.xyc(pairs) }; ^this.xyc(pairs +++ curve); } // envelopes with sustain *cutoff { arg releaseTime = 0.1, level = 1.0, curve = \lin; var curveNo = this.shapeNumber(curve); var releaseLevel = if(curveNo == 2) { -100.dbamp } { 0 }; ^this.new([level, releaseLevel], [releaseTime], curve, 0) } *dadsr { arg delayTime=0.1, attackTime=0.01, decayTime=0.3, sustainLevel=0.5, releaseTime=1.0, peakLevel=1.0, curve = -4.0, bias = 0.0; ^this.new( [0, 0, peakLevel, peakLevel * sustainLevel, 0] + bias, [delayTime, attackTime, decayTime, releaseTime], curve, 3 ) } *adsr { arg attackTime=0.01, decayTime=0.3, sustainLevel=0.5, releaseTime=1.0, peakLevel=1.0, curve = -4.0, bias = 0.0; ^this.new( [0, peakLevel, peakLevel * sustainLevel, 0] + bias, [attackTime, decayTime, releaseTime], curve, 2 ) } *asr { arg attackTime=0.01, sustainLevel=1.0, releaseTime=1.0, curve = -4.0; ^this.new( [0, sustainLevel, 0], [attackTime, releaseTime], curve, 1 ) } *circle { arg levels, times, curve = \lin; times = times.asArray.wrapExtend(levels.size); curve = curve.asArray.wrapExtend(levels.size); ^this.new(levels, times.drop(-1), curve.drop(-1)).circle(times.last, curve.last); } releaseTime { if(releaseNode.isNil) { ^0.0 }; ^times.copyRange(releaseNode, times.size - 1).sum } isSustained { ^releaseNode.notNil } asMultichannelSignal { arg length = 400, class = (Signal); var multiChannelArray = this.asMultichannelArray; var channelCount = multiChannelArray.size; var totalDur = this.totalDuration; length = max(length, levels.size); ^multiChannelArray.collect { |chan| var signal, ratio; ratio = totalDur / (length - 1); signal = class.new(length); length.do { arg i; signal.add(chan.envAt(i * ratio)) }; signal } } asSignal { arg length = 400; ^this.asMultichannelSignal(length).unbubble } discretize { arg n = 1024; ^this.asSignal(n); } storeArgs { ^[levels, times, curves, releaseNode, loopNode] } == { arg that; ^this.compareObject(that, [\levels, \times, \curves, \releaseNode, \loopNode, \offset]) } hash { ^this.instVarHash([\levels, \times, \curves, \releaseNode, \loopNode, \offset]) } at { arg time; var data = this.asMultichannelArray; time = (time - offset).max(0); ^if(time.isSequenceableCollection) { if(data.size <= 1) { data = data[0]; time.collect { |t| data.envAt(t) } } { time.collect { |t| data.collect { |channel| channel.envAt(t) } } } } { if(data.size <= 1) { data[0].envAt(time) } { data.collect { |channel| channel.envAt(time) } } } } embedInStream { arg inval; var startTime = thisThread.endBeat ? thisThread.beats; thisThread.endBeat = this.duration + startTime; loop { inval = yield(this.at(thisThread.beats - startTime)); } } asStream { ^Routine({ arg inval; this.embedInStream(inval) }) } asPseg { var c = if(curves.isSequenceableCollection.not) { curves } { Pseq(curves, inf) }; ^Pseg(Pseq(levels), Pseq(times ++ [1.0]), c) // last time is a dummy } // blend two envelopes blend { arg argAnotherEnv, argBlendFrac=0.5; ^this.class.new( levels.blend(argAnotherEnv.levels, argBlendFrac), times.blend(argAnotherEnv.times, argBlendFrac), curves.blend(argAnotherEnv.curves, argBlendFrac), releaseNode, loopNode ) } // delay the onset of the envelope delay { arg delay; ^Env([levels[0]] ++ levels, [delay] ++ times, if (curves.isArray) { [\lin] ++ curves } { curves }, if(releaseNode.notNil) { releaseNode = releaseNode + 1 }, if(loopNode.notNil) { loopNode = loopNode + 1 } ) } // connect releaseNode (or end) to first node of envelope circle { arg timeFromLastToFirst = 0.0, curve = \lin; var first0Then1; if(UGen.buildSynthDef.isNil) { ^this }; first0Then1 = Latch.kr(1.0, Impulse.kr(0.0)); if(releaseNode.isNil) { levels = [0.0] ++ levels ++ 0.0; curves = [curve] ++ curves.asArray.wrapExtend(times.size) ++ \lin; times = [first0Then1 * timeFromLastToFirst] ++ times ++ inf; releaseNode = levels.size - 2; } { levels = [0.0] ++ levels; curves = [curve] ++ curves.asArray.wrapExtend(times.size); times = [first0Then1 * timeFromLastToFirst] ++ times; releaseNode = releaseNode + 1; }; loopNode = 0; } test { arg releaseTime = 3.0; var s = Server.default; if(s.serverRunning.not) { "Server not running.".warn; ^this }; fork { var synth = { arg gate=1; SinOsc.ar(800, pi/2, 0.3) * EnvGen.ar(this, gate, doneAction:2) }.play; if(this.isSustained) { s.sendBundle(s.latency + releaseTime, [15, synth.nodeID, \gate, 0]) }; }; } *shapeNumber { arg shapeName; ^shapeName.asArray.collect { |name| var shape; if(name.isValidUGenInput) { 5 } { shape = shapeNames.at(name); if(shape.isNil) { Error("Env shape not defined.").throw }; shape } }.unbubble } curveValue { arg curve; ^if(curve.isSequenceableCollection) { curve.collect { |x| if(x.isValidUGenInput) { x } { 0 } } } { if(curve.isValidUGenInput) { curve } { 0 } } } asArray { if (array.isNil) { array = this.prAsArray } ^array.unbubble // keep backward compatibility } asMultichannelArray { if (array.isNil) { array = this.prAsArray } ^array } // this version is for IEnvGen and has a special format. // don't cache this version for now, but instead return it directly. asArrayForInterpolation { var contents, size; var levelArray = levels.asUGenInput; var timeArray = times.asUGenInput; var curvesArray = curves.asArray.asUGenInput; size = timeArray.size; contents = Array.new((size + 1) * 4); contents.add(offset.asUGenInput ? 0); contents.add(levelArray.at(0)); contents.add(size); contents.add(timeArray.sum); curvesArray = curves.asArray; times.size.do { arg i; contents.add(timeArray[i]); contents.add(this.class.shapeNumber(curvesArray.wrapAt(i))); contents.add(this.curveValue(curvesArray.wrapAt(i))); contents.add(levelArray[i+1]); }; ^contents.flop } prAsArray { var contents, size; var levelArray = levels.asUGenInput; var timeArray = times.asUGenInput; var curvesArray = curves.asArray.asUGenInput; size = times.size; contents = Array.new((size + 1) * 4); contents.add(levelArray.at(0)); contents.add(size); contents.add(releaseNode.asUGenInput ? -99); contents.add(loopNode.asUGenInput ? -99); size.do { arg i; contents.add(levelArray.at(i+1)); contents.add(timeArray.at(i)); contents.add(this.class.shapeNumber(curvesArray.wrapAt(i))); contents.add(this.curveValue(curvesArray.wrapAt(i))); }; ^contents.flop; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/GrainUGens.sc0000664000000000000000000000421312014636263026426 0ustar rootrootGrainSin : MultiOutUGen { *ar { arg numChannels = 1, trigger = 0, dur = 1, freq = 440, pan = 0, envbufnum = -1, maxGrains = 512, mul = 1, add = 0; ^this.multiNew('audio', numChannels, trigger, dur, freq, pan, envbufnum, maxGrains) .madd(mul, add); } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } GrainFM : MultiOutUGen { *ar { arg numChannels = 1, trigger = 0, dur = 1, carfreq = 440, modfreq = 200, index = 1, pan = 0, envbufnum = -1, maxGrains = 512, mul = 1, add = 0; ^this.multiNew('audio', numChannels, trigger, dur, carfreq, modfreq, index, pan, envbufnum, maxGrains).madd(mul, add); } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } GrainBuf : MultiOutUGen { *ar { arg numChannels = 1, trigger = 0, dur = 1, sndbuf, rate = 1, pos = 0, interp = 2, pan = 0, envbufnum = -1, maxGrains = 512, mul = 1, add = 0; ^this.multiNew('audio', numChannels, trigger, dur, sndbuf, rate, pos, interp, pan, envbufnum, maxGrains).madd(mul, add); } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } GrainIn : MultiOutUGen { *ar { arg numChannels = 1, trigger = 0, dur = 1, in, pan = 0, envbufnum = -1, maxGrains = 512, mul = 1, add = 0; ^this.multiNew('audio', numChannels, trigger, dur, in, pan, envbufnum, maxGrains) .madd(mul, add); } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } Warp1 : MultiOutUGen { *ar { arg numChannels = 1, bufnum=0, pointer=0, freqScale = 1, windowSize = 0.2, envbufnum = -1, overlaps = 8, windowRandRatio = 0.0, interp=1, mul = 1, add = 0; ^this.multiNew('audio', numChannels, bufnum, pointer, freqScale, windowSize, envbufnum, overlaps, windowRandRatio, interp).madd(mul, add); } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Line.sc0000664000000000000000000000607512245365552025331 0ustar rootrootLine : UGen { *ar { arg start=0.0, end = 1.0, dur = 1.0, mul = 1.0, add = 0.0, doneAction = 0; ^this.multiNew('audio', start, end, dur, doneAction).madd(mul, add) } *kr { arg start=0.0, end = 1.0, dur = 1.0, mul = 1.0, add = 0.0, doneAction = 0; ^this.multiNew('control', start, end, dur, doneAction).madd(mul, add) } } XLine : UGen { *ar { arg start=1.0, end = 2.0, dur = 1.0, mul = 1.0, add = 0.0, doneAction = 0; ^this.multiNew('audio', start, end, dur, doneAction).madd(mul, add) } *kr { arg start=1.0, end = 2.0, dur = 1.0, mul = 1.0, add = 0.0, doneAction = 0; ^this.multiNew('control', start, end, dur, doneAction).madd(mul, add) } } LinExp : PureUGen { checkInputs { ^this.checkSameRateAsFirstInput } *ar { arg in=0.0, srclo = 0.0, srchi = 1.0, dstlo = 1.0, dsthi = 2.0; ^this.multiNew('audio', in, srclo, srchi, dstlo, dsthi) } *kr { arg in=0.0, srclo = 0.0, srchi = 1.0, dstlo = 1.0, dsthi = 2.0; ^this.multiNew('control', in, srclo, srchi, dstlo, dsthi) } } LinLin { *ar { arg in=0.0, srclo = 0.0, srchi = 1.0, dstlo = 1.0, dsthi = 2.0; var scale = (dsthi - dstlo) / (srchi - srclo); var offset = dstlo - (scale * srclo); ^MulAdd(in, scale, offset) } *kr { arg in=0.0, srclo = 0.0, srchi = 1.0, dstlo = 1.0, dsthi = 2.0; var scale = (dsthi - dstlo) / (srchi - srclo); var offset = dstlo - (scale * srclo); ^(in * scale + offset) } } AmpComp : PureUGen { *ir { arg freq = 60.midicps, root = 60.midicps, exp = 0.3333; ^this.multiNew('scalar', freq, root, exp) } *ar { arg freq = 60.midicps, root = 60.midicps, exp = 0.3333; ^this.multiNew('audio', freq, root, exp) } *kr { arg freq = 60.midicps, root = 60.midicps, exp = 0.3333; ^this.multiNew('control', freq, root, exp) } checkInputs { ^if(rate === \audio) { this.checkSameRateAsFirstInput } } } AmpCompA : AmpComp { *ir { arg freq = 1000, root = 0, minAmp = 0.32, rootAmp = 1.0; ^this.multiNew('scalar', freq, root, minAmp, rootAmp) } *ar { arg freq = 1000, root = 0, minAmp = 0.32, rootAmp = 1.0; ^this.multiNew('audio', freq, root, minAmp, rootAmp) } *kr { arg freq = 1000, root = 0, minAmp = 0.32, rootAmp = 1.0; ^this.multiNew('control', freq, root, minAmp, rootAmp) } } K2A : PureUGen { // control rate to audio rate converter *ar { arg in = 0.0; ^this.multiNew('audio', in) } } A2K : PureUGen { // audio rate to control rate converter. only needed in specific cases *kr { arg in = 0.0; ^this.multiNew('control', in) } } T2K : A2K { // audio rate to control rate trigger converter. checkInputs { if(inputs.at(0).rate != \audio) { ^"first input is not audio rate" }; ^nil } } T2A : K2A { // control rate to audio rate trigger converter. *ar { arg in = 0.0, offset = 0; ^this.multiNew('audio', in, offset) } } DC : MultiOutUGen { *ar { arg in=0.0; ^this.multiNew('audio', in) } *kr { arg in=0.0; ^this.multiNew('control', in) } init { arg ... argInputs; inputs = argInputs; ^this.initOutputs(inputs.size, rate) } } Silent { *ar { arg numChannels = 1; var sig = DC.ar(0); if (numChannels == 1) { ^sig } { ^(sig ! numChannels) } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Hilbert.sc0000664000000000000000000000235712014636263026024 0ustar rootrootHilbert : MultiOutUGen { *ar { arg in, mul = 1, add = 0; ^this.multiNew('audio', in).madd(mul, add); } init { arg ... theInputs; inputs = theInputs; ^this.initOutputs(2, rate); } } // class using FFT (with a delay) for better results than the above UGen // buffer should be 2048 or 1024 // 2048, better results, more delay // 1024, less delay, little choppier results HilbertFIR : UGen { *ar { arg in, buffer; var fft, delay; fft = FFT(buffer, in); fft = PV_PhaseShift90(fft); delay = BufDur.kr(buffer); // return [source, shift90] ^[DelayN.ar(in, delay, delay), IFFT(fft)]; } } // single sideband amplitude modulation, using optimized Hilbert phase differencing network // basically coded by Joe Anderson, except Sean Costello changed the word HilbertIIR.ar // to Hilbert.ar FreqShift : UGen { *ar { arg in, // input signal freq = 0.0, // shift, in cps phase = 0.0, // phase of SSB mul = 1.0, add = 0.0; // var shifts; // freq = freq.asArray; // shifts = Array.fill(freq.size, {arg i; // // multiply by quadrature // // and add together. . . // (Hilbert.ar(in) * SinOsc.ar(freq[i], (phase + [ 0.5*pi, 0.0 ]))).sum}); // ^(shifts).madd(mul, add) ^this.multiNew('audio', in, freq, phase).madd(mul, add) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/FFT2.sc0000664000000000000000000000472112113230577025127 0ustar rootroot//third party FFT UGens //sick lincoln remembers complex analysis courses PV_ConformalMap : PV_ChainUGen { *new { arg buffer, areal = 0.0, aimag = 0.0; ^this.multiNew('control', buffer, areal, aimag) } } //in and kernel are both audio rate changing signals Convolution : UGen { *ar { arg in, kernel, framesize=512,mul = 1.0, add = 0.0; ^this.multiNew('audio', in, kernel, framesize).madd(mul, add); } } //fixed kernel convolver with fix by nescivi to update the kernel on receipt of a trigger message Convolution2 : UGen { *ar { arg in, kernel, trigger = 0, framesize=2048,mul = 1.0, add = 0.0; ^this.multiNew('audio', in, kernel, trigger, framesize).madd(mul, add); } } //fixed kernel convolver with linear crossfade Convolution2L : UGen { *ar { arg in, kernel, trigger = 0, framesize=2048, crossfade=1, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, kernel, trigger, framesize, crossfade).madd(mul, add); } } //fixed kernel stereo convolver with linear crossfade StereoConvolution2L : MultiOutUGen { *ar { arg in, kernelL, kernelR, trigger=0, framesize=2048, crossfade=1, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, kernelL, kernelR, trigger, framesize, crossfade).madd(mul, add); } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate, this, 0), OutputProxy(rate, this, 1) ]; ^channels } } //time based convolution by nescivi Convolution3 : UGen { *ar { arg in, kernel, trigger=0, framesize=2048, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, kernel, trigger, framesize).madd(mul, add); } *kr { arg in, kernel, trigger=0, framesize=2048, mul = 1.0, add = 0.0; ^this.multiNew('control', in, kernel, trigger, framesize).madd(mul, add); } } //jensen andersen inspired FFT feature detector PV_JensenAndersen : PV_ChainUGen { *ar { arg buffer, propsc=0.25, prophfe=0.25, prophfc=0.25, propsf=0.25, threshold=1.0, waittime=0.04; ^this.multiNew('audio', buffer, propsc, prophfe, prophfc, propsf, threshold, waittime); } } PV_HainsworthFoote : PV_ChainUGen { *ar { arg buffer, proph=0.0, propf=0.0, threshold=1.0, waittime=0.04; ^this.multiNew('audio', buffer, proph, propf, threshold, waittime); } } //not FFT but useful for time domain onset detection RunningSum : UGen { *ar { arg in, numsamp=40; ^this.multiNew('audio', in, numsamp); } *kr { arg in, numsamp=40; ^this.multiNew('control', in, numsamp); } *rms { arg in, numsamp=40; ^(RunningSum.ar(in.squared,numsamp)*(numsamp.reciprocal)).sqrt; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Pluck.sc0000664000000000000000000000035512014636263025505 0ustar rootrootPluck : UGen { *ar { arg in = 0.0, trig = 1.0, maxdelaytime = 0.2, delaytime = 0.2, decaytime = 1.0, coef = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, trig, maxdelaytime, delaytime, decaytime, coef).madd(mul, add)} } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Filter.sc0000664000000000000000000002240712245365552025664 0ustar rootrootFilter : PureUGen { checkInputs { ^this.checkSameRateAsFirstInput } } Resonz : Filter { *ar { arg in = 0.0, freq = 440.0, bwr = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, bwr).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, bwr = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, bwr).madd(mul, add) } } OnePole : Filter { *ar { arg in = 0.0, coef = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, coef).madd(mul, add) } *kr { arg in = 0.0, coef = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('control', in, coef).madd(mul, add) } } OneZero : OnePole {} TwoPole : Filter { *ar { arg in = 0.0, freq = 440.0, radius = 0.8, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, radius).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, radius = 0.8, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, radius).madd(mul, add) } } TwoZero : TwoPole {} APF : TwoPole {} Integrator : Filter { *ar { arg in = 0.0, coef = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, coef).madd(mul, add) } *kr { arg in = 0.0, coef = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, coef).madd(mul, add) } } Decay : Filter { *ar { arg in = 0.0, decayTime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, decayTime).madd(mul, add) } *kr { arg in = 0.0, decayTime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, decayTime).madd(mul, add) } } Decay2 : Filter { *ar { arg in = 0.0, attackTime = 0.01, decayTime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, attackTime, decayTime).madd(mul, add) } *kr { arg in = 0.0, attackTime = 0.01, decayTime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, attackTime, decayTime).madd(mul, add) } } Lag : Filter { *ar { arg in = 0.0, lagTime = 0.1, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, lagTime).madd(mul, add) } *kr { arg in = 0.0, lagTime = 0.1, mul = 1.0, add = 0.0; ^this.multiNew('control', in, lagTime).madd(mul, add) } } Lag2 : Lag {} Lag3 : Lag {} Ramp : Lag {} /// added by nescivi - 15 may 2007 LagUD : Filter { *ar { arg in = 0.0, lagTimeU = 0.1, lagTimeD = 0.1, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, lagTimeU, lagTimeD).madd(mul, add) } *kr { arg in = 0.0, lagTimeU = 0.1, lagTimeD = 0.1, mul = 1.0, add = 0.0; ^this.multiNew('control', in, lagTimeU, lagTimeD).madd(mul, add) } } Lag2UD : LagUD {} Lag3UD : LagUD {} VarLag : Filter { *ar { arg in = 0.0, time = 0.1, curvature = 0, warp = 5, start, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, time, curvature, warp, start).madd(mul, add); } *kr { arg in = 0.0, time = 0.1, curvature = 0, warp = 5, start, mul = 1.0, add = 0.0; ^this.multiNew('control', in, time, curvature, warp, start).madd(mul, add); } // FIXME: Implement 'curve' input on VLag ugen instead of using EnvGen. // Then \exp warp should probably behave as Lag ugen. *new1 { arg rate, in, time, curvature, warp, start; var e, curve, trig, sel = if(rate==\audio,\ar,\kr); start = start ? in; curve = Env.shapeNames[warp] ? warp; ^if(curve != 1) { e = Env([start, in], [time], warp).asArray; e[6] = curve; e[7] = curvature; trig = Changed.perform(sel, in) + Impulse.perform(sel, 0); if(time.rate != \scalar) { trig = trig + Changed.kr(time) }; EnvGen.perform(sel, e, trig); } { ^super.new.rate_(rate).addToSynth.init(in, time, start); } } } LeakDC : Filter { *ar { arg in = 0.0, coef = 0.995, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, coef).madd(mul, add) } *kr { arg in = 0.0, coef = 0.9, mul = 1.0, add = 0.0; ^this.multiNew('control', in, coef).madd(mul, add) } } RLPF : Filter { *ar { arg in = 0.0, freq = 440.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, rq).madd(mul, add) } } RHPF : RLPF {} LPF : Filter { *ar { arg in = 0.0, freq = 440.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq).madd(mul, add) } } HPF : LPF {} BPF : Filter { *ar { arg in = 0.0, freq = 440.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, rq).madd(mul, add) } } BRF : BPF {} MidEQ : Filter { *ar { arg in = 0.0, freq = 440.0, rq = 1.0, db = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq, db).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, rq = 1.0, db = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, rq, db).madd(mul, add) } } LPZ1 : Filter { *ar { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in).madd(mul, add) } *kr { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in).madd(mul, add) } } HPZ1 : LPZ1 {} Slope : Filter { *ar { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in).madd(mul, add) } *kr { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in).madd(mul, add) } } Changed : Filter { *kr { arg input, threshold = 0; ^HPZ1.kr(input).abs > threshold } *ar { arg input, threshold = 0; ^HPZ1.ar(input).abs > threshold } } LPZ2 : Filter { *ar { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in).madd(mul, add) } *kr { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in).madd(mul, add) } } HPZ2 : LPZ2 {} BPZ2 : LPZ2 {} BRZ2 : LPZ2 {} Median : Filter { *ar { arg length=3, in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', length, in).madd(mul, add) } *kr { arg length=3, in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', length, in).madd(mul, add) } checkInputs { if (rate == 'audio', { if (inputs.at(1).rate != 'audio', { ^"input was not audio rate"; }); }); ^this.checkValidInputs } } //exception in GrafDef_Load: UGen 'AvgAbsAmp' not installed. //AvgAbsAmp : Filter { // // *ar { arg in = 0.0, coef = 0.999, mul = 1.0, add = 0.0; // ^this.multiNew('audio', in, coef).madd(mul, add) // } // *kr { arg in = 0.0, coef = 0.999, mul = 1.0, add = 0.0; // ^this.multiNew('control', in, coef).madd(mul, add) // } //} Slew : Filter { *ar { arg in = 0.0, up = 1.0, dn = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, up, dn).madd(mul, add) } *kr { arg in = 0.0, up = 1.0, dn = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, up, dn).madd(mul, add) } } // not installed //RLPF4 : Filter { // // *ar { arg in = 0.0, freq = 0.5, res = 0.5, mul = 1.0, add = 0.0; // ^this.multiNew('audio', in, freq, res).madd(mul, add) // } //} FOS : Filter { *ar { arg in = 0.0, a0 = 0.0, a1 = 0.0, b1 = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, a0, a1, b1).madd(mul, add) } *kr { arg in = 0.0, a0 = 0.0, a1 = 0.0, b1 = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, a0, a1, b1).madd(mul, add) } } SOS : Filter { *ar { arg in = 0.0, a0 = 0.0, a1 = 0.0, a2 = 0.0, b1 = 0.0, b2 = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, a0, a1, a2, b1, b2).madd(mul, add) } *kr { arg in = 0.0, a0 = 0.0, a1 = 0.0, a2 = 0.0, b1 = 0.0, b2 = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, a0, a1, a2, b1, b2).madd(mul, add) } } Ringz : Filter { *ar { arg in = 0.0, freq = 440.0, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, decaytime).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, decaytime).madd(mul, add) } } Formlet : Filter { *ar { arg in = 0.0, freq = 440.0, attacktime = 1.0, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, attacktime, decaytime).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, attacktime = 1.0, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, attacktime, decaytime).madd(mul, add) } } // the doneAction arg lets you cause the EnvGen to stop or end the // synth without having to use a PauseSelfWhenDone or FreeSelfWhenDone ugen. // It is more efficient to use a doneAction. // doneAction = 0 do nothing when the envelope has ended. // doneAction = 1 pause the synth running, it is still resident. // doneAction = 2 remove the synth and deallocate it. // doneAction = 3 remove and deallocate both this synth and the preceeding node. // doneAction = 4 remove and deallocate both this synth and the following node. // doneAction = 5 remove and deallocate this synth and free all children in the preceeding group (if it is a group). // doneAction = 6 remove and deallocate this synth and free all children in the following group (if it is a group). DetectSilence : Filter { optimizeGraph { } *ar { arg in = 0.0, amp = 0.0001, time = 0.1, doneAction = 0; ^this.multiNew('audio', in, amp, time, doneAction) // ^0.0 // DetectSilence has no output } *kr { arg in = 0.0, amp = 0.0001, time = 0.1, doneAction = 0; ^this.multiNew('control', in, amp, time, doneAction) // ^0.0 // DetectSilence has no output } } //exception in GrafDef_Load: UGen 'FlagNaN' not installed. //FlagNaN : Filter { // // *ar { arg in = 0.0; // ^this.multiNew('audio', in) // } // *kr { arg in = 0.0; // ^this.multiNew('control', in) // } //} SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/DiskIO.sc0000664000000000000000000000200612245365552025552 0ustar rootrootDiskOut : UGen { *ar { arg bufnum, channelsArray; ^this.multiNewList(['audio', bufnum] ++ channelsArray.asArray) //^0.0 // DiskOut has no output // now it does: the number of frames written } // numOutputs { ^1 } // writeOutputSpecs {} checkInputs { if (rate == 'audio', { for(1, inputs.size - 1, { arg i; if (inputs.at(i).rate != 'audio', { ^("input was not audio rate: " + inputs.at(i)); }); }); }); ^this.checkValidInputs } } DiskIn : MultiOutUGen { *ar { arg numChannels, bufnum, loop = 0; ^this.multiNew('audio', numChannels, bufnum, loop) } init { arg numChannels, bufnum, loop = 0; inputs = [bufnum, loop]; ^this.initOutputs(numChannels, rate) } } VDiskIn : MultiOutUGen { *ar { arg numChannels, bufnum, rate = 1, loop = 0, sendID = 0; ^this.multiNew('audio', numChannels, bufnum, rate, loop, sendID) } init { arg numChannels, bufnum, argRate = 1, loop = 0, sendID = 0; inputs = [bufnum, argRate, loop, sendID]; ^this.initOutputs(numChannels, rate) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Poll.sc0000664000000000000000000000222512014636263025333 0ustar rootrootPoll : UGen { *ar { arg trig, in, label, trigid = -1; this.multiNewList(['audio', trig, in, label, trigid]); ^in; } *kr { arg trig, in, label, trigid = -1; this.multiNewList(['control', trig, in, label, trigid]); ^in; } *new { arg trig, in, label, trigid = -1; var rate = in.asArray.collect(_.rate).unbubble; this.multiNewList([rate, trig, in, label, trigid]); ^in; } *new1 { arg rate, trig, in, label, trigid; label = label ?? { "UGen(%)".format(in.class) }; label = label.asString.collectAs(_.ascii, Array); if(rate === \scalar) { rate = \control }; if(trig.isNumber) { trig = Impulse.multiNew(rate, trig, 0) }; ^super.new.rate_(rate).addToSynth.init([trig, in, trigid, label.size] ++ label); } checkInputs { ^this.checkSameRateAsFirstInput } init { arg theInputs; // store the inputs as an array inputs = theInputs; } } /* s.boot; {Poll.ar(Impulse.ar(5), Line.ar(0, 1, 1), \test2)}.play(s); {SinOsc.ar(220, 0, 1).poll(Impulse.ar(15), "test")}.play(s); o = OSCresponderNode(s.addr, '/tr', {arg time, resp, msg; msg.postln; }).add {Poll.ar(Impulse.ar(5), Line.ar(0, 1, 1), \test2, 1234)}.play(s); o.remove; s.quit; */ SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/DelayWr.sc0000664000000000000000000000420712161364457026004 0ustar rootrootPingPong { //your buffer should be the same numChannels as your inputs *ar { arg bufnum=0, inputs, delayTime, feedback=0.7, rotate=1; var delaySamps = max(0, delayTime * SampleRate.ir - ControlDur.ir).round, phase, feedbackChannels, delayedSignals, frames = BufFrames.kr(bufnum); phase = Phasor.ar(0, 1, 0, frames); feedbackChannels = LocalIn.ar(inputs.size) * feedback; delayedSignals = BufRd.ar(inputs.size, bufnum, (phase - delaySamps).wrap(0, frames), 0); LocalOut.ar(delayedSignals); BufWr.ar((inputs + feedbackChannels).rotate(rotate) numChannels = 16; classvar <>tempNamePrefix = "temp__"; classvar tempDefCount = 0; classvar <>maxTempDefNames = 512; *generateTempName { var name = tempNamePrefix ++ tempDefCount; tempDefCount = tempDefCount + 1 % maxTempDefNames; ^name } *initClass { // clean up any written synthdefs starting with "temp__" StartUp.add { var path = SynthDef.synthDefDir ++ tempNamePrefix ++ "*"; if(pathMatch(path).notEmpty) { unixCmd("rm -f" + path.quote) }; (1..numChannels).do { arg i; SynthDef("system_link_audio_" ++ i, { arg out=0, in=16, vol=1, doneAction=2; var env; env = EnvGate( doneAction:doneAction, curve:'sin') * Lag.kr(vol, 0.05); Out.ar(out, InFeedback.ar(in, i) * env) }, [\kr, \ir, \kr, \ir]).add; SynthDef("system_link_control_" ++ i, { arg out=0, in=16, doneAction=2; var env; env = EnvGate( doneAction:doneAction, curve:'lin'); Out.kr(out, In.kr(in, i) * env) }, [\kr, \ir, \kr, \ir]).add; SynthDef("system_diskout_" ++ i, { arg i_in, i_bufNum=0; DiskOut.ar(i_bufNum, InFeedback.ar(i_in, i)); }).add; }; }; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/AudioIn.sc0000664000000000000000000000135312014636263025756 0ustar rootrootSoundIn { *ar { arg bus = 0, mul=1.0, add=0.0; var chanOffset; chanOffset = this.channelOffset; if(bus.isArray.not,{ ^In.ar(chanOffset + bus, 1).madd(mul,add) }); // check to see if channels array is consecutive [n,n+1,n+2...] if(bus.every({arg item, i; (i==0) or: {item == (bus.at(i-1)+1)} }),{ ^In.ar(chanOffset + bus.first, bus.size).madd(mul,add) },{ // allow In to multi channel expand ^In.ar(chanOffset + bus).madd(mul,add) }) } *channelOffset { ^NumOutputBuses.ir } } // backward compatible version. Only difference: starts counting from channel 1 AudioIn : SoundIn { *ar { arg channel = 0, mul=1.0, add=0.0; ^super.ar(channel, mul, add) } *channelOffset { ^NumOutputBuses.ir - 1 } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Gendyn.sc0000664000000000000000000000376312014636263025661 0ustar rootroot//GENDYN by Iannis Xenakis implemented for SC3 by sicklincoln with some refinements Gendy1 : UGen { *ar { arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, minfreq=440, maxfreq=660, ampscale= 0.5, durscale=0.5, initCPs= 12, knum, mul=1.0,add=0.0; ^this.multiNew('audio', ampdist, durdist, adparam, ddparam, minfreq, maxfreq, ampscale, durscale, initCPs, knum ? initCPs).madd( mul, add ) } *kr {arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, minfreq=20, maxfreq=1000, ampscale= 0.5, durscale=0.5, initCPs= 12, knum,mul=1.0,add=0.0; ^this.multiNew('control', ampdist, durdist, adparam, ddparam, minfreq, maxfreq, ampscale, durscale, initCPs, knum ? initCPs).madd( mul, add ) } } Gendy2 : UGen { *ar { arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, minfreq=440, maxfreq=660, ampscale= 0.5, durscale=0.5, initCPs= 12, knum, a=1.17, c=0.31, mul=1.0,add=0.0; ^this.multiNew('audio', ampdist, durdist, adparam, ddparam, minfreq, maxfreq, ampscale, durscale, initCPs, knum ? initCPs, a, c).madd( mul, add ) } *kr {arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, minfreq=20, maxfreq=1000, ampscale= 0.5, durscale=0.5, initCPs= 12, knum, a=1.17, c=0.31, mul=1.0,add=0.0; ^this.multiNew('control', ampdist, durdist, adparam, ddparam, minfreq, maxfreq, ampscale, durscale, initCPs, knum ? initCPs, a, c).madd( mul, add ) } } Gendy3 : UGen { *ar { arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, freq=440, ampscale= 0.5, durscale=0.5, initCPs= 12, knum, mul=1.0,add=0.0; ^this.multiNew('audio', ampdist, durdist, adparam, ddparam, freq, ampscale, durscale, initCPs, knum ? initCPs).madd( mul, add ) } *kr {arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, freq=440, ampscale= 0.5, durscale=0.5, initCPs= 12, knum, mul=1.0,add=0.0; ^this.multiNew('control', ampdist, durdist, adparam, ddparam, freq, ampscale, durscale, initCPs, knum ? initCPs).madd( mul, add ) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/PSinGrain.sc0000664000000000000000000000060212014636263026254 0ustar rootroot/* PSinGrain - fixed frequency sine oscillator arguments : freq - frequency in cycles per second. Must be a scalar. dur - grain duration amp - amplitude of grain This unit generator uses a very fast algorithm for generating a sine wave at a fixed frequency. */ PSinGrain : UGen { *ar { arg freq = 440.0, dur = 0.2, amp = 1.0; ^this.multiNew('audio', freq, dur, amp) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/SynthDef.sc0000664000000000000000000004364112245365552026166 0ustar rootrootSynthDef { var <>name, <>func; var <>controls, <>controlNames; // ugens add to this var <>allControlNames; var <>controlIndex=0; var <>children; var <>constants; var <>constantSet; var <>maxLocalBufs; // topo sort var <>available; var <>variants; var <>widthFirstUGens; var rewriteInProgress; var <>desc, <>metadata; classvar 0) { nonControlNames.do {|cn| arguments[cn.argNum] = cn.defaultValue; }; }; if (irControlNames.size > 0) { values = nil; irControlNames.do {|cn| values = values.add(cn.defaultValue); }; index = controlIndex; controlUGens = Control.ir(values.flat).asArray.reshapeLike(values); irControlNames.do {|cn, i| cn.index = index; index = index + cn.defaultValue.asArray.size; arguments[cn.argNum] = controlUGens[i]; this.setControlNames(controlUGens[i], cn); }; }; if (trControlNames.size > 0) { values = nil; trControlNames.do {|cn| values = values.add(cn.defaultValue); }; index = controlIndex; controlUGens = TrigControl.kr(values.flat).asArray.reshapeLike(values); trControlNames.do {|cn, i| cn.index = index; index = index + cn.defaultValue.asArray.size; arguments[cn.argNum] = controlUGens[i]; this.setControlNames(controlUGens[i], cn); }; }; if (arControlNames.size > 0) { values = nil; arControlNames.do {|cn| values = values.add(cn.defaultValue); }; index = controlIndex; controlUGens = AudioControl.ar(values.flat).asArray.reshapeLike(values); arControlNames.do {|cn, i| cn.index = index; index = index + cn.defaultValue.asArray.size; arguments[cn.argNum] = controlUGens[i]; this.setControlNames(controlUGens[i], cn); }; }; if (krControlNames.size > 0) { values = nil; lags = nil; krControlNames.do {|cn| valsize = cn.defaultValue.asArray.size; values = values.add(cn.defaultValue); lags = lags.addAll(cn.lag.asArray.wrapExtend(valsize)); }; index = controlIndex; if (lags.any {|lag| lag != 0 }) { controlUGens = LagControl.kr(values.flat, lags).asArray.reshapeLike(values); }{ controlUGens = Control.kr(values.flat).asArray.reshapeLike(values); }; krControlNames.do {|cn, i| cn.index = index; index = index + cn.defaultValue.asArray.size; arguments[cn.argNum] = controlUGens[i]; this.setControlNames(controlUGens[i], cn); }; }; controlNames = controlNames.reject {|cn| cn.rate == 'noncontrol' }; ^arguments } setControlNames {arg controlUGens, cn; controlUGens.isArray.if({ controlUGens.do({arg thisCtrl; thisCtrl.name_(cn.name); }) }, { controlUGens.name_(cn.name) }); } finishBuild { this.optimizeGraph; this.collectConstants; this.checkInputs;// will die on error // re-sort graph. reindex. this.topologicalSort; this.indexUGens; UGen.buildSynthDef = nil; } asBytes { var stream = CollStream.on(Int8Array.new(256)); this.asArray.writeDef(stream); ^stream.collection; } writeDefFile { arg dir, overwrite(true), mdPlugin; var desc, defFileExistedBefore; if((metadata.tryPerform(\at, \shouldNotSend) ? false).not) { dir = dir ? SynthDef.synthDefDir; defFileExistedBefore = File.exists(dir +/+ name ++ ".scsyndef"); super.writeDefFile(name, dir, overwrite); if(overwrite or: { defFileExistedBefore.not }) { desc = this.asSynthDesc; desc.metadata = metadata; SynthDesc.populateMetadataFunc.value(desc); desc.writeMetadata(dir +/+ name, mdPlugin); }; } { // actual error, not just warning as in .send and .load, // because you might try to write the file somewhere other than // the default location - could be fatal later, so crash now MethodError("This SynthDef (%) was reconstructed from a .scsyndef file. It does not contain all the required structure to write back to disk. File was not written." .format(name), this).throw } } writeDef { arg file; // This describes the file format for the synthdef files. var allControlNamesTemp, allControlNamesMap; file.putPascalString(name); this.writeConstants(file); //controls have been added by the Control UGens file.putInt32(controls.size); controls.do { | item | file.putFloat(item); }; allControlNamesTemp = allControlNames.reject { |cn| cn.rate == \noncontrol }; file.putInt32(allControlNamesTemp.size); allControlNamesTemp.do { | item | if (item.name.notNil) { file.putPascalString(item.name.asString); file.putInt32(item.index); }; }; file.putInt32(children.size); children.do { | item | item.writeDef(file); }; file.putInt16(variants.size); if (variants.size > 0) { allControlNamesMap = (); allControlNamesTemp.do { |cn| allControlNamesMap[cn.name] = cn; }; variants.keysValuesDo {|varname, pairs| var varcontrols; varname = name ++ "." ++ varname; if (varname.size > 32) { Post << "variant '" << varname << "' name too long.\n"; ^nil }; varcontrols = controls.copy; pairs.pairsDo { |cname, values| var cn, index; cn = allControlNamesMap[cname]; if (cn.notNil) { values = values.asArray; if (values.size > cn.defaultValue.asArray.size) { postf("variant: '%' control: '%' size mismatch.\n", varname, cname); ^nil }{ index = cn.index; values.do {|val, i| varcontrols[index + i] = val; } } }{ postf("variant: '%' control: '%' not found.\n", varname, cname); ^nil } }; file.putPascalString(varname); varcontrols.do { | item | file.putFloat(item); }; }; }; } writeConstants { arg file; var array = FloatArray.newClear(constants.size); constants.keysValuesDo { arg value, index; array[index] = value; }; file.putInt32(constants.size); array.do { | item | file.putFloat(item) }; } checkInputs { var firstErr; children.do { arg ugen; var err; if ((err = ugen.checkInputs).notNil) { err = ugen.class.asString + err; err.postln; ugen.dumpArgs; if(firstErr.isNil) { firstErr = err }; }; }; if(firstErr.notNil) { ("SynthDef" + this.name + "build failed").postln; Error(firstErr).throw }; ^true } // UGens do these addUGen { arg ugen; if (rewriteInProgress.isNil) { // we don't add ugens, if a rewrite operation is in progress ugen.synthIndex = children.size; ugen.widthFirstAntecedents = widthFirstUGens.copy; children = children.add(ugen); } } removeUGen { arg ugen; // lazy removal: clear entry and later remove all nil enties children[ugen.synthIndex] = nil; } replaceUGen { arg a, b; if (b.isKindOf(UGen).not) { Error("replaceUGen assumes a UGen").throw; }; b.widthFirstAntecedents = a.widthFirstAntecedents; b.descendants = a.descendants; b.synthIndex = a.synthIndex; children[a.synthIndex] = b; children.do { arg item, i; if (item.notNil) { item.inputs.do { arg input, j; if (input === a) { item.inputs[j] = b }; }; }; }; } addConstant { arg value; if (constantSet.includes(value).not) { constantSet.add(value); constants[value] = constants.size; }; } // multi channel expansion causes a non optimal breadth-wise ordering of the graph. // the topological sort below follows branches in a depth first order, // so that cache performance of connection buffers is optimized. optimizeGraph { var oldSize; this.initTopoSort; rewriteInProgress = true; children.copy.do { arg ugen; ugen.optimizeGraph; }; rewriteInProgress = nil; // fixup removed ugens oldSize = children.size; children.removeEvery(#[nil]); if (oldSize != children.size) { this.indexUGens }; } collectConstants { children.do { arg ugen; ugen.collectConstants; }; } initTopoSort { available = nil; children.do { arg ugen; ugen.antecedents = Set.new; ugen.descendants = Set.new; }; children.do { arg ugen; // this populates the descendants and antecedents ugen.initTopoSort; }; children.reverseDo { arg ugen; ugen.descendants = ugen.descendants.asArray.sort( { arg a, b; a.synthIndex < b.synthIndex } ); ugen.makeAvailable; // all ugens with no antecedents are made available }; } cleanupTopoSort { children.do { arg ugen; ugen.antecedents = nil; ugen.descendants = nil; ugen.widthFirstAntecedents = nil; }; } topologicalSort { var outStack; this.initTopoSort; while { available.size > 0 } { outStack = available.pop.schedule(outStack); }; children = outStack; this.cleanupTopoSort; } indexUGens { children.do { arg ugen, i; ugen.synthIndex = i; }; } dumpUGens { name.postln; children.do { arg ugen, i; var inputs, ugenName; if (ugen.inputs.notNil) { inputs = ugen.inputs.collect {|in| if (in.respondsTo(\dumpName)) { in.dumpName }{ in }; }; }; [ugen.dumpName, ugen.rate, inputs].postln; }; } // make SynthDef available to all servers add { arg libname, completionMsg, keepDef = true; var servers, desc = this.asSynthDesc(libname ? \global, keepDef); if(libname.isNil) { servers = Server.allRunningServers } { servers = SynthDescLib.getLib(libname).servers }; servers.do { |each| this.doSend(each.value, completionMsg.value(each)) } } *removeAt { arg name, libname = \global; var lib = SynthDescLib.getLib(libname); lib.removeAt(name); lib.servers.do { |each| each.value.sendMsg("/d_free", name) }; } // methods for special optimizations // only send to servers send { arg server, completionMsg; var servers = (server ?? { Server.allRunningServers }).asArray; servers.do { |each| if(each.serverRunning.not) { "Server % not running, could not send SynthDef.".format(server.name).warn }; if(metadata.trueAt(\shouldNotSend)) { this.loadReconstructed(each, completionMsg); } { this.doSend(each, completionMsg); } } } doSend { |server, completionMsg| var bytes = this.asBytes; if (bytes.size < (65535 div: 4)) { server.sendMsg("/d_recv", bytes, completionMsg) } { if (server.isLocal) { "SynthDef % too big for sending. Retrying via synthdef file".format(name).warn; this.writeDefFile(synthDefDir); server.sendMsg("/d_load", synthDefDir ++ name ++ ".scsyndef", completionMsg) } { "SynthDef % too big for sending.".format(name).warn; } } } // send to server and write file load { arg server, completionMsg, dir(synthDefDir); server = server ? Server.default; if(metadata.trueAt(\shouldNotSend)) { this.loadReconstructed(server, completionMsg); } { // should remember what dir synthDef was written to dir = dir ? synthDefDir; this.writeDefFile(dir); server.sendMsg("/d_load", dir ++ name ++ ".scsyndef", completionMsg) }; } // write to file and make synth description store { arg libname=\global, dir(synthDefDir), completionMsg, mdPlugin; var lib = SynthDescLib.getLib(libname); var file, path = dir ++ name ++ ".scsyndef"; if(metadata.falseAt(\shouldNotSend)) { protect { var bytes, desc; file = File(path, "w"); bytes = this.asBytes; file.putAll(bytes); file.close; lib.read(path); lib.servers.do { arg server; this.doSend(server.value, completionMsg) }; desc = lib[this.name.asSymbol]; desc.metadata = metadata; SynthDesc.populateMetadataFunc.value(desc); desc.writeMetadata(path, mdPlugin); } { file.close } } { lib.read(path); lib.servers.do { arg server; this.loadReconstructed(server, completionMsg); }; }; } asSynthDesc { |libname=\global, keepDef = true| var lib, stream = CollStream(this.asBytes); libname ?? { libname = \global }; lib = SynthDescLib.getLib(libname); SynthDesc.readFile(stream, keepDef, lib.synthDescs); desc = lib[name.asSymbol]; if(keepDef) { desc.def = this }; if(metadata.notNil) { desc.metadata = metadata }; ^desc } // this method warns and does not halt // because loading existing def from disk is a viable alternative // to get the synthdef to the server loadReconstructed { arg server, completionMsg; "SynthDef (%) was reconstructed from a .scsyndef file, " "it does not contain all the required structure to send back to the server." .format(name).warn; if(server.isLocal) { "Loading from disk instead.".postln; server.sendBundle(nil, ["/d_load", metadata[\loadPath], completionMsg]); } { MethodError("Server is remote, cannot load from disk.", this).throw; }; } // this method needs a reconsideration storeOnce { arg libname=\global, dir(synthDefDir), completionMsg, mdPlugin; var path = dir ++ name ++ ".scsyndef", lib; if(File.exists(path).not) { this.store(libname, dir, completionMsg, mdPlugin); } { // load synthdesc from disk // because SynthDescLib still needs to have the info lib = SynthDescLib.getLib(libname); lib.read(path); }; } play { arg target,args,addAction=\addToHead; var synth, msg; // this.deprecated(thisMethod, Function.findRespondingMethodFor(\play)); target = target.asTarget; synth = Synth.basicNew(name,target.server); msg = synth.newMsg(target, args, addAction); this.send(target.server, msg); ^synth } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/PhysicalModel.sc0000664000000000000000000000136212014636263027163 0ustar rootrootSpring : UGen { *ar { arg in=0.0, spring=1, damp=0; ^this.multiNew('audio', in, spring, damp) } *kr { arg in=0.0, spring=1, damp=0; ^this.multiNew('control', in, spring, damp) } } //Friction : UGen { // *ar { arg in=0.0, spring=1, thresh=0.5; // ^this.multiNew('audio', in, spring, thresh) // } // //} Ball : UGen { *ar { arg in=0.0, g=1, damp=0, friction=0.01; ^this.multiNew('audio', in, g, damp, friction) } *kr { arg in=0.0, g=1, damp=0, friction=0.01; ^this.multiNew('control', in, g, damp, friction) } } TBall : UGen { *ar { arg in=0.0, g=10, damp=0, friction=0.01; ^this.multiNew('audio', in, g, damp, friction) } *kr { arg in=0.0, g=10, damp=0, friction=0.01; ^this.multiNew('control', in, g, damp, friction) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/PitchShift.sc0000664000000000000000000000046312014636263026474 0ustar rootrootPitchShift : UGen { checkInputs { ^this.checkSameRateAsFirstInput } *ar { arg in = 0.0, windowSize = 0.2, pitchRatio = 1.0, pitchDispersion = 0.0, timeDispersion = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, windowSize, pitchRatio, pitchDispersion, timeDispersion).madd(mul, add) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/UGen.sc0000664000000000000000000003012512245365552025271 0ustar rootrootUGen : AbstractFunction { classvar <>buildSynthDef; // the synth currently under construction var <>synthDef; var <>inputs; var <>rate = 'audio'; var <>synthIndex = -1, <>specialIndex=0; var <>antecedents, <>descendants, <>widthFirstAntecedents; // topo sorting // instance creation *new1 { arg rate ... args; if (rate.isKindOf(Symbol).not) { Error("rate must be Symbol.").throw }; ^super.new.rate_(rate).addToSynth.init( *args ) } *newFromDesc { arg rate, numOutputs, inputs, specialIndex; ^super.new.rate_(rate).inputs_(inputs).specialIndex_(specialIndex) } *multiNew { arg ... args; ^this.multiNewList(args); } *multiNewList { arg args; var size = 0, newArgs, results; args = args.asUGenInput(this); args.do({ arg item; (item.class == Array).if({ size = max(size, item.size) }); }); if (size == 0) { ^this.new1( *args ) }; newArgs = Array.newClear(args.size); results = Array.newClear(size); size.do({ arg i; args.do({ arg item, j; newArgs.put(j, if (item.class == Array, { item.wrapAt(i) },{ item })); }); results.put(i, this.multiNewList(newArgs)); }); ^results } init { arg ... theInputs; // store the inputs as an array inputs = theInputs; } copy { // you can't really copy a UGen without disturbing the Synth. // Usually you want the same object. This makes .dup work ^this } madd { arg mul = 1.0, add = 0.0; ^MulAdd(this, mul, add); } range { arg lo = 0.0, hi = 1.0; var mul, add; if (this.signalRange == \bipolar, { mul = (hi - lo) * 0.5; add = mul + lo; },{ mul = (hi - lo) ; add = lo; }); ^MulAdd(this, mul, add); } exprange { arg lo = 0.01, hi = 1.0; ^if (this.signalRange == \bipolar) { this.linexp(-1, 1, lo, hi, nil) } { this.linexp(0, 1, lo, hi, nil) }; } unipolar { arg mul = 1; ^this.range(0, mul) } bipolar { arg mul = 1; ^this.range(mul.neg, mul) } clip { arg lo = 0.0, hi = 1.0; ^if(rate == \demand){ max(lo, min(hi, this)) }{ Clip.perform(Clip.methodSelectorForRate(rate), this, lo, hi) } } fold { arg lo = 0.0, hi = 0.0; ^if(rate == \demand) { this.notYetImplemented(thisMethod) } { Fold.perform(Fold.methodSelectorForRate(rate), this, lo, hi) } } wrap { arg lo = 0.0, hi = 1.0; ^if(rate == \demand) { this.notYetImplemented(thisMethod) } { Wrap.perform(Wrap.methodSelectorForRate(rate), this, lo, hi) } } blend { arg that, blendFrac = 0.5; var pan; ^if (rate == \demand || that.rate == \demand) { this.notYetImplemented(thisMethod) } { pan = blendFrac.linlin(0.0, 1.0, -1, 1); if (rate == \audio) { ^XFade2.ar(this, that, pan) }; if (that.rate == \audio) { ^XFade2.ar(that, this, pan.neg) }; ^LinXFade2.perform(LinXFade2.methodSelectorForRate(rate), this, that, pan) } } minNyquist { ^min(this, SampleRate.ir * 0.5) } lag { arg t1=0.1, t2; ^if(t2.isNil) { Lag.multiNew(this.rate, this, t1) } { LagUD.multiNew(this.rate, this, t1, t2) } } lag2 { arg t1=0.1, t2; ^if(t2.isNil) { Lag2.multiNew(this.rate, this, t1) } { Lag2UD.multiNew(this.rate, this, t1, t2) } } lag3 { arg t1=0.1, t2; ^if(t2.isNil) { Lag3.multiNew(this.rate, this, t1) } { Lag3UD.multiNew(this.rate, this, t1, t2) } } lagud { arg lagTimeU=0.1, lagTimeD=0.1; ^LagUD.multiNew(this.rate, this, lagTimeU, lagTimeD) } lag2ud { arg lagTimeU=0.1, lagTimeD=0.1; ^Lag2UD.multiNew(this.rate, this, lagTimeU, lagTimeD) } lag3ud { arg lagTimeU=0.1, lagTimeD=0.1; ^Lag3UD.multiNew(this.rate, this, lagTimeU, lagTimeD) } varlag { arg time=0.1, curvature=0, warp=5, start; ^VarLag.multiNew(this.rate, this, time, curvature, warp, start) } slew { arg up = 1, down = 1; ^Slew.multiNew(this.rate, this, up, down) } prune { arg min, max, type; switch(type, \minmax, { ^this.clip(min, max); }, \min, { ^this.max(min); }, \max, { ^this.min(max); } ); ^this } linlin { arg inMin, inMax, outMin, outMax, clip = \minmax; if (this.rate == \audio) { ^LinLin.ar(this.prune(inMin, inMax, clip), inMin, inMax, outMin, outMax) } { ^LinLin.kr(this.prune(inMin, inMax, clip), inMin, inMax, outMin, outMax) } } linexp { arg inMin, inMax, outMin, outMax, clip = \minmax; ^LinExp.multiNew(this.rate, this.prune(inMin, inMax, clip), inMin, inMax, outMin, outMax) } explin { arg inMin, inMax, outMin, outMax, clip = \minmax; ^(log(this.prune(inMin, inMax, clip)/inMin)) / (log(inMax/inMin)) * (outMax-outMin) + outMin; // no separate ugen yet } expexp { arg inMin, inMax, outMin, outMax, clip = \minmax; ^pow(outMax/outMin, log(this.prune(inMin, inMax, clip)/inMin) / log(inMax/inMin)) * outMin; } lincurve { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; var grow, a, b, scaled; if (curve.isNumber and: { abs(curve) < 0.25 }) { ^this.linlin(inMin, inMax, outMin, outMax, clip) }; grow = exp(curve); a = outMax - outMin / (1.0 - grow); b = outMin + a; scaled = (this.prune(inMin, inMax, clip) - inMin) / (inMax - inMin); ^b - (a * pow(grow, scaled)); } curvelin { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; var grow, a, b, scaled; if (curve.isNumber and: { abs(curve) < 0.25 }) { ^this.linlin(inMin, inMax, outMin, outMax, clip) }; grow = exp(curve); a = inMax - inMin / (1.0 - grow); b = inMin + a; ^(log( (b - this.prune(inMin, inMax, clip)) / a ) * (outMax - outMin) / curve + outMin) } signalRange { ^\bipolar } @ { arg y; ^Point.new(this, y) } // dynamic geometry support addToSynth { synthDef = buildSynthDef; if (synthDef.notNil, { synthDef.addUGen(this) }); } collectConstants { inputs.do({ arg input; if (input.isNumber, { synthDef.addConstant(input.asFloat) }); }); } isValidUGenInput { ^true } asUGenInput { ^this } asControlInput { Error("can't set a control to a UGen").throw } numChannels { ^1 } checkInputs { ^this.checkValidInputs } checkValidInputs { inputs.do({arg in,i; var argName; if(in.isValidUGenInput.not,{ argName = this.argNameForInputAt(i) ? i; ^"arg: '" ++ argName ++ "' has bad input:" + in; }) }); ^nil } checkNInputs { arg n; if (rate == 'audio') { n.do {| i | if (inputs.at(i).rate != 'audio') { //"failed".postln; ^("input " ++ i ++ " is not audio rate: " + inputs.at(i) + inputs.at(0).rate); }; }; }; ^this.checkValidInputs } checkSameRateAsFirstInput { if (rate !== inputs.at(0).rate) { ^("first input is not" + rate + "rate: " + inputs.at(0) + inputs.at(0).rate); }; ^this.checkValidInputs } argNameForInputAt { arg i; var method = this.class.class.findMethod(this.methodSelectorForRate); if(method.isNil or: {method.argNames.isNil},{ ^nil }); ^method.argNames.at(i + this.argNamesInputsOffset) } argNamesInputsOffset { ^1 } dumpArgs { " ARGS:".postln; inputs.do({ arg in,ini; (" " ++ (this.argNameForInputAt(ini) ? ini.asString)++":" + in + in.class).postln }); } degreeToKey { arg scale, stepsPerOctave=12; ^DegreeToKey.kr(scale, this, stepsPerOctave) } outputIndex { ^0 } writesToBus { ^false } poll { arg trig = 10, label, trigid = -1; ^Poll(trig, this, label, trigid) } dpoll { arg label, run = 1, trigid = -1; ^Dpoll(this, label, run, trigid) } checkBadValues { arg id = 0, post = 2; // add the UGen to the tree but keep "this" as the output CheckBadValues.perform(this.methodSelectorForRate, this, id, post); } *methodSelectorForRate { arg rate; if(rate == \audio,{ ^\ar }); if(rate == \control, { ^\kr }); if(rate == \scalar, { if(this.respondsTo(\ir),{ ^\ir },{ ^\new }); }); if(rate == \demand, { ^\new }); ^nil } *replaceZeroesWithSilence { arg array; // this replaces zeroes with audio rate silence. // sub collections are deep replaced var numZeroes, silentChannels, pos = 0; numZeroes = array.count({ arg item; item == 0.0 }); if (numZeroes == 0, { ^array }); silentChannels = Silent.ar(numZeroes).asCollection; array.do({ arg item, i; var res; if (item == 0.0, { array.put(i, silentChannels.at(pos)); pos = pos + 1; }, { if(item.isSequenceableCollection, { res = this.replaceZeroesWithSilence(item); array.put(i, res); }); }); }); ^array; } // PRIVATE // function composition composeUnaryOp { arg aSelector; ^UnaryOpUGen.new(aSelector, this) } composeBinaryOp { arg aSelector, anInput; if (anInput.isValidUGenInput, { ^BinaryOpUGen.new(aSelector, this, anInput) },{ anInput.performBinaryOpOnUGen(aSelector, this); }); } reverseComposeBinaryOp { arg aSelector, aUGen; ^BinaryOpUGen.new(aSelector, aUGen, this) } composeNAryOp { arg aSelector, anArgList; ^thisMethod.notYetImplemented } // complex support asComplex { ^Complex.new(this, 0.0) } performBinaryOpOnComplex { arg aSelector, aComplex; ^aComplex.perform(aSelector, this.asComplex) } if { arg trueUGen, falseUGen; ^(this * (trueUGen - falseUGen)) + falseUGen; } rateNumber { if (rate == \audio, { ^2 }); if (rate == \control, { ^1 }); if (rate == \demand, { ^3 }); ^0 // scalar } methodSelectorForRate { if(rate == \audio,{ ^\ar }); if(rate == \control, { ^\kr }); if(rate == \scalar, { if(this.class.respondsTo(\ir),{ ^\ir },{ ^\new }); }); if(rate == \demand, { ^\new }); ^nil } writeInputSpec { arg file, synthDef; file.putInt32(synthIndex); file.putInt32(this.outputIndex); } writeOutputSpec { arg file; file.putInt8(this.rateNumber); } writeOutputSpecs { arg file; this.writeOutputSpec(file); } numInputs { ^inputs.size } numOutputs { ^1 } name { ^this.class.name.asString; } writeDef { arg file; file.putPascalString(this.name); file.putInt8(this.rateNumber); file.putInt32(this.numInputs); file.putInt32(this.numOutputs); file.putInt16(this.specialIndex); // write wire spec indices. inputs.do({ arg input; input.writeInputSpec(file, synthDef); }); this.writeOutputSpecs(file); } /////////////////////////////////////////////////////////////// initTopoSort { inputs.do({ arg input; if (input.isKindOf(UGen), { antecedents.add(input.source); input.source.descendants.add(this); }); }); widthFirstAntecedents.do({ arg ugen; antecedents.add(ugen); ugen.descendants.add(this); }) } makeAvailable { if (antecedents.size == 0, { synthDef.available = synthDef.available.add(this); }); } removeAntecedent { arg ugen; antecedents.remove(ugen); this.makeAvailable; } schedule { arg outStack; descendants.reverseDo({ arg ugen; ugen.removeAntecedent(this); }); ^outStack.add(this); } optimizeGraph {} dumpName { ^synthIndex.asString ++ "_" ++ this.class.name.asString } performDeadCodeElimination { if (descendants.size == 0) { this.inputs.do {|a| if (a.isKindOf(UGen)) { a.descendants.remove(this); a.optimizeGraph } }; buildSynthDef.removeUGen(this); ^true; }; ^false } } // ugen, which has no side effect and can therefore be considered for a dead code elimination // read access to buffers/busses are allowed PureUGen : UGen { optimizeGraph { super.performDeadCodeElimination } } MultiOutUGen : UGen { // a class for UGens with multiple outputs var source, <>outputIndex, <>name; *new { arg rate, itsSourceUGen, index; ^super.new1(rate, itsSourceUGen, index) } addToSynth { synthDef = buildSynthDef; } init { arg argSource, argIndex; source = argSource; outputIndex = argIndex; synthIndex = source.synthIndex; } dumpName { ^this.source.dumpName ++ "[" ++ outputIndex ++ "]" } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/InterplEnv.sc0000664000000000000000000000150412161364457026520 0ustar rootroot // InterplEnvs are a fixed duration // Envelope specification for an IEnvGen, InterplEnv is not a UGen itself InterplEnv { *new { arg levels=#[0,1,0], times=#[1,1], curve='lin', offset = 0.0; "InterplEnv is deprecated, please use Env.new instead.".warn; ^Env.new(levels, times, curve, nil, nil, offset) } } // InterplXYC([0, 0, \lin], [1, 2, \sin], [2, 0]) // at time 0, value 0, lin to time 1, value 2, sin to time 2, value 0 InterplXYC { *new { arg ... xyc; "InterplXYC is deprecated, please use Env.xyc instead.".warn; ^Env.xyc(xyc) } } InterplPairs { *new { arg pairs, curve; "InterplPairs is deprecated, please use Env.pairs instead.".warn; ^Env.pairs(pairs, curve) } } InterplChord { *new { arg pairs; "InterplChord is deprecated, please use Env.pairs instead.".warn; ^Env.pairs(pairs) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/Splay.sc0000664000000000000000000000543212245365552025526 0ustar rootrootSplay : UGen { *new1 { arg rate, spread = 1, level = 1, center = 0.0, levelComp = true ... inArray; var n = max(2, inArray.size); var n1 = n - 1; var positions = ((0 .. n1) * (2 / n1) - 1) * spread + center; if (levelComp) { if(rate == \audio) { level = level * n.reciprocal.sqrt } { level = level / n } }; ^Pan2.perform(this.methodSelectorForRate(rate), inArray, positions).sum * level; } *kr { arg inArray, spread = 1, level = 1, center = 0.0, levelComp = true; ^this.multiNewList([\control, spread, level, center, levelComp] ++ inArray) } *ar { arg inArray, spread = 1, level = 1, center = 0.0, levelComp = true; ^this.multiNewList([\audio, spread, level, center, levelComp] ++ inArray) } /* *ar { arg inArray, spread = 1, level = 1, center = 0.0, levelComp = true; var n = inArray.size.max(2); var n1 = n-1; if (levelComp) { level = level * n.reciprocal.sqrt }; ^Pan2.ar( inArray, ((0 .. n1) * (2 / n1) - 1) * spread + center ).sum * level; } */ *arFill { arg n, function, spread = 1, level = 1, center = 0.0, levelComp = true; ^this.ar((function ! n), spread, level, center, levelComp) } } SplayAz : UGen { *kr { arg numChans = 4, inArray, spread = 1, level = 1, width = 2, center = 0.0, orientation = 0.5, levelComp = true; var n = max(1, inArray.size); var pos = [ center - spread, center + spread ].resamp1(n); if (levelComp) { level = level / n }; ^(PanAz.kr(numChans, inArray, pos, level, width, orientation).flop.collect(_.sum)) } *ar { arg numChans = 4, inArray, spread = 1, level = 1, width = 2, center = 0.0, orientation = 0.5, levelComp = true; var n = max(1, inArray.size); var pos = [ center - spread, center + spread ].resamp1(n); if (levelComp) { level = level * n.reciprocal.sqrt }; ^(PanAz.ar(numChans, inArray, pos, level, width, orientation).flop.collect(_.sum)) } *arFill { arg numChans = 4, n, function, spread = 1, level = 1, width = 2, center = 0.0, orientation = 0.5, levelComp = true; ^this.ar(numChans, function ! n, spread, level, width, center, orientation, levelComp) } } SplayZ { *ar { arg numChans = 4, inArray, spread = 1, level = 1, width = 2, center = 0.0, orientation = 0.5, levelComp = true; var n = inArray.size.max(2); var n1 = n - 1; if (levelComp) { level = level * n.reciprocal.sqrt }; "SplayZ is deprecated, because its geometry is wrong. Please convert to SplayAz.".inform; ^PanAz.ar( numChans, inArray, ((0 .. n1) * (2 / n1) - 1) * spread + center, 1, width, orientation ).sum * level; } *arFill { arg numChans = 4, n, function, spread = 1, level = 1, width = 2, center = 0.0, orientation = 0.5, levelComp = true; ^this.ar(numChans, function ! n, spread, level, width, center, orientation, levelComp) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/BufIO.sc0000664000000000000000000001200612014636263025367 0ustar rootroot/* PlayBuf - sample player */ PlayBuf : MultiOutUGen { *ar { arg numChannels, bufnum=0, rate=1.0, trigger=1.0, startPos=0.0, loop = 0.0, doneAction=0; ^this.multiNew('audio', numChannels, bufnum, rate, trigger, startPos, loop, doneAction) } *kr { arg numChannels, bufnum=0, rate=1.0, trigger=1.0, startPos=0.0, loop = 0.0, doneAction=0; ^this.multiNew('control', numChannels, bufnum, rate, trigger, startPos, loop, doneAction) } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } TGrains : MultiOutUGen { *ar { arg numChannels, trigger=0, bufnum=0, rate=1, centerPos=0, dur=0.1, pan=0, amp=0.1, interp=4; if (numChannels < 2) { "TGrains needs at least two channels.".error; ^nil } ^this.multiNew('audio', numChannels, trigger, bufnum, rate, centerPos, dur, pan, amp, interp) } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } /* // exception in GrafDef_Load: UGen 'SimpleLoopBuf' not installed. SimpleLoopBuf : MultiOutUGen { *ar { arg numChannels, bufnum=0, loopStart=0.0, loopEnd=99999.0, trigger=0.0; ^this.multiNew('audio', numChannels, bufnum, loopStart, loopEnd, trigger) } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } } */ BufRd : MultiOutUGen { *ar { arg numChannels, bufnum=0, phase=0.0, loop=1.0, interpolation=2; ^this.multiNew('audio', numChannels, bufnum, phase, loop, interpolation) } *kr { arg numChannels, bufnum=0, phase=0.0, loop=1.0, interpolation=2; ^this.multiNew('control', numChannels, bufnum, phase, loop, interpolation) } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } checkInputs { if (rate == 'audio' and: {inputs.at(1).rate != 'audio'}, { ^("phase input is not audio rate: " + inputs.at(1) + inputs.at(1).rate); }); ^this.checkValidInputs } } BufWr : UGen { *ar { arg inputArray, bufnum=0, phase=0.0, loop=1.0; ^this.multiNewList(['audio', bufnum, phase, loop] ++ inputArray.asArray) } *kr { arg inputArray, bufnum=0, phase=0.0, loop=1.0; ^this.multiNewList(['control', bufnum, phase, loop] ++ inputArray.asArray) } checkInputs { if (rate == 'audio' and: {inputs.at(1).rate != 'audio'}, { ^("phase input is not audio rate: " + inputs.at(1) + inputs.at(1).rate); }); ^this.checkValidInputs } } RecordBuf : UGen { *ar { arg inputArray, bufnum=0, offset=0.0, recLevel=1.0, preLevel=0.0, run=1.0, loop=1.0, trigger=1.0, doneAction=0; ^this.multiNewList( ['audio', bufnum, offset, recLevel, preLevel, run, loop, trigger, doneAction ] ++ inputArray.asArray ) } *kr { arg inputArray, bufnum=0, offset=0.0, recLevel=1.0, preLevel=0.0, run=1.0, loop=1.0, trigger=1.0, doneAction=0; ^this.multiNewList( ['control', bufnum, offset, recLevel, preLevel, run, loop, trigger, doneAction ] ++ inputArray.asArray ) } } ScopeOut : UGen { *ar { arg inputArray , bufnum=0; this.multiNewList(['audio', bufnum] ++ inputArray.asArray); ^0.0 } *kr { arg inputArray , bufnum=0; this.multiNewList(['control', bufnum] ++ inputArray.asArray); ^0.0 } } ScopeOut2 : UGen { *ar { arg inputArray, scopeNum=0, maxFrames = 4096, scopeFrames; this.multiNewList(['audio', scopeNum, maxFrames, scopeFrames ? maxFrames] ++ inputArray.asArray); ^0.0 } *kr { arg inputArray, scopeNum=0, maxFrames = 4096, scopeFrames; this.multiNewList(['control', scopeNum, maxFrames, scopeFrames ? maxFrames] ++ inputArray.asArray); ^0.0 } } Tap : UGen { *ar { arg bufnum = 0, numChannels = 1, delaytime = 0.2; var n; n = delaytime * SampleRate.ir.neg; // this depends on the session sample rate, not buffer. ^PlayBuf.ar(numChannels, bufnum, 1, 0, n, 1); } } LocalBuf : WidthFirstUGen { *new { arg numFrames = 1, numChannels = 1; ^this.multiNew('scalar', numChannels, numFrames) } *new1 { arg rate ... args; var maxLocalBufs = UGen.buildSynthDef.maxLocalBufs; if(maxLocalBufs.isNil) { maxLocalBufs = MaxLocalBufs.new; UGen.buildSynthDef.maxLocalBufs = maxLocalBufs; }; maxLocalBufs.increment; ^super.new.rate_(rate).addToSynth.init( *args ++ maxLocalBufs ) } *newFrom { arg list; var shape, buf; shape = list.shape; if(shape.size == 1) { shape = [1, list.size] }; if(shape.size > 2) { Error("LocalBuf: list has not the right shape").throw }; buf = this.new(*shape.reverse); buf.set(list.flop.flat); ^buf } numFrames { ^inputs[1] } numChannels { ^inputs[0] } set { arg values, offset = 0; SetBuf(this, values.asArray, offset); } clear { ClearBuf(this); } } MaxLocalBufs : UGen { *new { ^this.multiNew('scalar', 0); } increment { inputs[0] = inputs[0] + 1; } } SetBuf : WidthFirstUGen { *new { arg buf, values, offset = 0; ^this.multiNewList(['scalar', buf, offset, values.size] ++ values) } } ClearBuf : WidthFirstUGen { *new { arg buf; ^this.multiNew('scalar', buf) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Audio/SynthDefOld.sc0000664000000000000000000001111012245365552026607 0ustar rootrootSynthDefOld : SynthDef { *new { arg name, ugenGraphFunc, rates, prependArgs, variants, metadata; ^super.new.name_(name.asSymbol).variants_(variants).metadata_(metadata).children_(Array.new(64)) .build(ugenGraphFunc, rates, prependArgs) } writeDefFile { arg dir, overwrite(true); if((metadata.tryPerform(\at, \shouldNotSend) ? false).not) { super.writeDefFileOld(name, dir, overwrite); } { // actual error, not just warning as in .send and .load, // because you might try to write the file somewhere other than // the default location - could be fatal later, so crash now MethodError("This SynthDef (%) was reconstructed from a .scsyndef file. It does not contain all the required structure to write back to disk. File was not written." .format(name), this).throw } } writeDef { arg file; // This describes the file format for the synthdef files. var allControlNamesTemp, allControlNamesMap; file.putPascalString(name.asString); this.writeConstants(file); //controls have been added by the Control UGens file.putInt16(controls.size); controls.do { | item | file.putFloat(item); }; allControlNamesTemp = allControlNames.reject { |cn| cn.rate == \noncontrol }; file.putInt16(allControlNamesTemp.size); allControlNamesTemp.do { | item | if (item.name.notNil) { file.putPascalString(item.name.asString); file.putInt16(item.index); }; }; file.putInt16(children.size); children.do { | item | item.writeDefOld(file); }; file.putInt16(variants.size); if (variants.size > 0) { allControlNamesMap = (); allControlNamesTemp.do { |cn| allControlNamesMap[cn.name] = cn; }; variants.keysValuesDo {|varname, pairs| var varcontrols; varname = name ++ "." ++ varname; if (varname.size > 32) { Post << "variant '" << varname << "' name too long.\n"; ^nil }; varcontrols = controls.copy; pairs.pairsDo { |cname, values| var cn, index; cn = allControlNamesMap[cname]; if (cn.notNil) { values = values.asArray; if (values.size > cn.defaultValue.asArray.size) { postf("variant: '%' control: '%' size mismatch.\n", varname, cname); ^nil }{ index = cn.index; values.do {|val, i| varcontrols[index + i] = val; } } }{ postf("variant: '%' control: '%' not found.\n", varname, cname); ^nil } }; file.putPascalString(varname); varcontrols.do { | item | file.putFloat(item); }; }; } } writeConstants { arg file; var array = FloatArray.newClear(constants.size); constants.keysValuesDo { arg value, index; array[index] = value; }; file.putInt16(constants.size); array.do { | item | file.putFloat(item) }; } asBytes { var stream = CollStream.on(Int8Array.new(256)); this.asArray.writeDefOld(stream); ^stream.collection; } } + Collection { writeDefOld { | file | file.putString("SCgf"); file.putInt32(1); // file version file.putInt16(this.size); // number of defs in file. this.do { | item | item.writeDef(file); } } writeInputSpecOld { | file, synthDef | this.do { | item | item.writeInputSpecOld(file, synthDef) }; } } + UGen { writeDefOld { arg file; //[\WR, this.class.name, rate, this.numInputs, this.numOutputs].postln; file.putPascalString(this.name); file.putInt8(this.rateNumber); file.putInt16(this.numInputs); file.putInt16(this.numOutputs); file.putInt16(this.specialIndex); // write wire spec indices. inputs.do({ arg input; input.writeInputSpecOld(file, synthDef); }); this.writeOutputSpecs(file); //[this.class.name, file.length].postln; } writeInputSpecOld { arg file, synthDef; file.putInt16(synthIndex); file.putInt16(this.outputIndex); } } + SimpleNumber { writeInputSpecOld { arg file, synth; var constIndex = synth.constants.at(this.asFloat); if (constIndex.isNil) { Error("SimpleNumber-writeInputSpec constant not found: " ++ this.asFloat).throw; }; //[\inpspc, this.class.name, constIndex, this].postln; file.putInt16(-1); file.putInt16(constIndex); } } + Object { writeDefFileOld { arg name, dir, overwrite = (true); StartUp.defer { // make sure the synth defs are written to the right path var file; dir = dir ? SynthDef.synthDefDir; if (name.isNil) { Error("missing SynthDef file name").throw } { name = dir +/+ name ++ ".scsyndef"; if(overwrite or: { pathMatch(name).isEmpty }) { file = File(name, "w"); protect { AbstractMDPlugin.clearMetadata(name); this.asArray.writeDefOld(file); }{ file.close; } } } } } }SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Math/0000775000000000000000000000000012245452763023734 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Math/Polar.sc0000664000000000000000000000237412014636263025337 0ustar rootrootPolar : Number { var <>rho, <>theta; *new { arg rho, theta; ^super.newCopyArgs(rho, theta) } magnitude { ^rho } angle { ^theta } phase { ^theta } real { ^rho * cos(theta) } imag { ^rho * sin(theta) } asPolar { ^this } asComplex { ^Complex.new(this.real, this.imag) } asPoint { ^Point.new(this.real, this.imag) } scale { arg scale; ^Polar.new(rho * scale, theta) } rotate { arg angle; // in radians ^Polar.new(rho, theta + angle) } // do math as Complex + { arg aNumber; ^this.asComplex + aNumber } - { arg aNumber; ^this.asComplex - aNumber } * { arg aNumber; ^this.asComplex * aNumber } / { arg aNumber; ^this.asComplex / aNumber } == { arg aPolar; ^aPolar respondsTo: #[\rho, \theta] and: { rho == aPolar.rho and: { theta == aPolar.theta } } } hash { ^rho.hash bitXor: theta.hash } neg { ^Polar.new(rho, theta + pi) } performBinaryOpOnSomething { |aSelector, thing, adverb| ^thing.asComplex.perform(aSelector, this, adverb) } performBinaryOpOnUGen { arg aSelector, aUGen; ^Complex.new( BinaryOpUGen.new(aSelector, aUGen, this.real), BinaryOpUGen.new(aSelector, aUGen, this.imag) ); } printOn { arg stream; stream << "Polar( " << rho << ", " << theta << " )"; } storeArgs { ^[rho,theta] } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Math/Signal.sc0000664000000000000000000002515012014636263025474 0ustar rootrootSignal[float] : FloatArray { *sineFill { arg size, amplitudes, phases; ^Signal.newClear(size).sineFill(amplitudes, phases).normalize } *chebyFill { arg size, amplitudes, normalize=true; ^Signal.newClear(size).chebyFill(amplitudes, normalize); //.normalizeTransfer //shouldn't normalize by default! } *hammingWindow { arg size, pad=0; if (pad == 0, { ^this.newClear(size).fill(0.5).addSine(1, 0.39, -0.5pi); },{ ^this.newClear(size-pad).fill(0.5).addSine(1, 0.39, -0.5pi) ++ this.newClear(pad); }); } *hanningWindow { arg size, pad=0; if (pad == 0, { ^this.newClear(size).fill(0.5).addSine(1, 0.5, -0.5pi); },{ ^this.newClear(size-pad).fill(0.5).addSine(1, 0.5, -0.5pi) ++ this.newClear(pad); }); } *welchWindow { arg size, pad=0; if (pad == 0, { ^this.newClear(size).addSine(0.5, 1, 0); },{ ^this.newClear(size-pad).addSine(0.5, 1, 0) ++ this.newClear(pad); }); } *rectWindow { arg size, pad=0; if (pad == 0, { ^this.newClear(size).fill(1.0); },{ ^this.newClear(size-pad).fill(1.0) ++ this.newClear(pad); }); } *readNew { arg file; ^file.readAllSignal; } // operations fill { arg val; _SignalFill ^this.primitiveFailed } scale { arg scale; _SignalScale ^this.primitiveFailed } offset { arg offset; _SignalOffset ^this.primitiveFailed } asWavetable { // Interpolating oscillators require wavetables in a special format. // This method returns a wavetable in that format. _SignalAsWavetable; ^this.primitiveFailed } asWavetableNoWrap { // Shaper requires wavetables without wrap. // This method returns a wavetable in that format. //To generate size N wavetable need N/2+1 signal values rather than N/2 //because Buffer's add_wchebyshev calculates N/2+1 values whilst //Signal's _SignalAddChebyshev calculates N/2! var newsig = Signal.newClear((this.size-1)*2); var next, cur; cur= this[0]; (this.size-1).do{|i| var index= 2*i; next= this[i+1]; newsig[index]= 2*cur -next; newsig[index+1]= next-cur; cur=next; }; ^newsig } peak { _SignalPeak; ^this.primitiveFailed } normalize { arg beginSamp=0, endSamp; _SignalNormalize; ^this.primitiveFailed } normalizeTransfer { _SignalNormalizeTransferFn; ^this.primitiveFailed } invert { arg beginSamp=0, endSamp; _SignalInvert; ^this.primitiveFailed } reverse { arg beginSamp=0, endSamp; _SignalReverse; ^this.primitiveFailed } fade { arg beginSamp=0, endSamp, beginLevel=0.0, endLevel=1.0; _SignalFade; ^this.primitiveFailed } rotate { arg n=1; _SignalRotate ^this.primitiveFailed } zeroPad { arg minSize; var size = max(minSize ? 0, this.size).nextPowerOfTwo; ^this ++ Signal.newClear(size - this.size); } integral { _SignalIntegral; ^this.primitiveFailed } overDub { arg aSignal, index=0; _SignalOverDub // add a signal to myself starting at the index // if the other signal is too long only the first part is overdubbed ^this.primitiveFailed } overWrite { arg aSignal, index=0; _SignalOverWrite // write a signal to myself starting at the index // if the other signal is too long only the first part is overwritten ^this.primitiveFailed } play { arg loop=false, mul=0.2, numChannels=1, server; var buf; buf = Buffer.sendCollection(server ? Server.default, this, numChannels, -1, { buf.play(loop, mul); }); ^buf } waveFill { arg function, start = 0.0, end = 1.0; var i = 0, step, size, val, x; // evaluate a function for every sample over the interval from // start to end. size = this.size; if (size <= 0, { ^this }); x = start; step = (end - start) / size; while ({ i < size }, { val = function.value(x, this.at(i), i); this.put(i, val); x = x + step; i = i + 1; }); ^this } addSine { arg harmonicNumber = 1, amplitude = 1.0, phase = 0.0; _SignalAddHarmonic ^this.primitiveFailed } sineFill { arg amplitudes, phases; this.fill(0.0); if (phases.isNil, { phases = #[0]; }); amplitudes.do({ arg amp, i; this.addSine(i+1, amp, phases @@ i) }); } sineFill2 { arg list; this.fill(0.0); list.do({ arg item, i; var harm, amp, phase; # harm, amp, phase = item; this.addSine(harm, amp ? 1.0, phase ? 0.0); }); } addChebyshev { arg harmonicNumber = 1, amplitude = 1.0; _SignalAddChebyshev ^this.primitiveFailed } chebyFill { arg amplitudes, normalize=true; this.fill(0.0); amplitudes.do({ arg amp, i; this.addChebyshev(i+1, amp); if(i%4==1,{this.offset(1)}); if(i%4==3,{this.offset(-1)}); }); //corrections for JMC DC offsets, as per Buffer:cheby if(normalize,{this.normalizeTransfer}); //no automatic cheby } //old version chebyFill_old { arg amplitudes; this.fill(0.0); amplitudes.do({ arg amp, i; this.addChebyshev(i+1, amp) }); this.normalizeTransfer } *fftCosTable { arg fftsize; ^this.newClear((fftsize/4) + 1).fftCosTable } fftCosTable { var harm; harm = this.size / ((this.size - 1) * 4); this.addSine(harm, 1, 0.5pi); } fft { arg imag, cosTable; // argCosTable must contain 1/4 cycle of a cosine (use fftCosTable) // fftsize is the next greater power of two than the receiver's length _Signal_FFT ^this.primitiveFailed } ifft { arg imag, cosTable; // argCosTable must contain 1/4 cycle of a cosine (use fftCosTable) // fftsize is the next greater power of two than the receiver's length _Signal_IFFT ^this.primitiveFailed } neg { _Neg; ^this.primitiveFailed } abs { _Abs; ^this.primitiveFailed } sign { _Sign; ^this.primitiveFailed } squared { _Squared; ^this.primitiveFailed } cubed { _Cubed; ^this.primitiveFailed } sqrt { _Sqrt; ^this.primitiveFailed } exp { _Exp; ^this.primitiveFailed } //reciprocal { _Recip; ^this.primitiveFailed } //midicps { _MIDICPS; ^this.primitiveFailed } //cpsmidi { _CPSMIDI; ^this.primitiveFailed } //midiratio { _MIDIRatio; ^this.primitiveFailed } //ratiomidi { _RatioMIDI; ^this.primitiveFailed } //ampdb { _AmpDb; ^this.primitiveFailed } //dbamp { _DbAmp; ^this.primitiveFailed } //octcps { _OctCPS; ^this.primitiveFailed } //cpsoct { _CPSOct; ^this.primitiveFailed } log { _Log; ^this.primitiveFailed } log2 { _Log2; ^this.primitiveFailed } log10 { _Log10; ^this.primitiveFailed } sin { _Sin; ^this.primitiveFailed } cos { _Cos; ^this.primitiveFailed } tan { _Tan; ^this.primitiveFailed } asin { _ArcSin; ^this.primitiveFailed } acos { _ArcCos; ^this.primitiveFailed } atan { _ArcTan; ^this.primitiveFailed } sinh { _SinH; ^this.primitiveFailed } cosh { _CosH; ^this.primitiveFailed } tanh { _TanH; ^this.primitiveFailed } distort { _Distort; ^this.primitiveFailed } softclip { _SoftClip; ^this.primitiveFailed } rectWindow { _RectWindow; ^this.primitiveFailed } hanWindow { _HanWindow; ^this.primitiveFailed } welWindow { _WelchWindow; ^this.primitiveFailed } triWindow { _TriWindow; ^this.primitiveFailed } scurve { _SCurve; ^this.primitiveFailed } ramp { _Ramp; ^this.primitiveFailed } + { arg aNumber; _Add; ^aNumber.performBinaryOpOnSignal('+', this) } - { arg aNumber; _Sub; ^aNumber.performBinaryOpOnSignal('-', this) } * { arg aNumber; _Mul; ^aNumber.performBinaryOpOnSignal('*', this) } / { arg aNumber; _FDiv; ^aNumber.performBinaryOpOnSignal('/', this) } mod { arg aNumber; _Mod; ^aNumber.performBinaryOpOnSignal('mod', this) } div { arg aNumber; _IDiv; ^aNumber.performBinaryOpOnSignal('div', this) } pow { arg aNumber; _Pow; ^aNumber.performBinaryOpOnSignal('pow', this) } min { arg aNumber; _Min; ^aNumber.performBinaryOpOnSignal('min', this) } max { arg aNumber; _Max; ^aNumber.performBinaryOpOnSignal('max', this) } ring1 { arg aNumber; _Ring1; ^aNumber.performBinaryOpOnSignal('ring1', this) } ring2 { arg aNumber; _Ring2; ^aNumber.performBinaryOpOnSignal('ring2', this) } ring3 { arg aNumber; _Ring3; ^aNumber.performBinaryOpOnSignal('ring3', this) } ring4 { arg aNumber; _Ring4; ^aNumber.performBinaryOpOnSignal('ring4', this) } difsqr { arg aNumber; _DifSqr; ^aNumber.performBinaryOpOnSignal('difsqr', this) } sumsqr { arg aNumber; _SumSqr; ^aNumber.performBinaryOpOnSignal('sumsqr', this) } sqrsum { arg aNumber; _SqrSum; ^aNumber.performBinaryOpOnSignal('sqrsum', this) } sqrdif { arg aNumber; _SqrDif; ^aNumber.performBinaryOpOnSignal('sqrdif', this) } absdif { arg aNumber; _AbsDif; ^aNumber.performBinaryOpOnSignal('absdif', this) } thresh { arg aNumber; _Thresh; ^aNumber.performBinaryOpOnSignal('thresh', this) } amclip { arg aNumber; _AMClip; ^aNumber.performBinaryOpOnSignal('amclip', this) } scaleneg { arg aNumber; _ScaleNeg; ^aNumber.performBinaryOpOnSignal('scaleneg', this) } clip2 { arg aNumber=1; _Clip2; ^aNumber.performBinaryOpOnSignal('clip2', this) } fold2 { arg aNumber; _Fold2; ^aNumber.performBinaryOpOnSignal('fold2', this) } wrap2 { arg aNumber; _Wrap2; ^aNumber.performBinaryOpOnSignal('wrap2', this) } excess { arg aNumber; _Excess; ^aNumber.performBinaryOpOnSignal('excess', this) } firstArg { arg aNumber; _FirstArg; ^aNumber.performBinaryOpOnSignal('firstArg', this) } == { arg aNumber; _EQ; ^aNumber.performBinaryOpOnSignal('==', this) } != { arg aNumber; _NE; ^aNumber.performBinaryOpOnSignal('!=', this) } clip { arg lo, hi; _ClipSignal; ^this.primitiveFailed } wrap { arg lo, hi; _WrapSignal; ^this.primitiveFailed } fold { arg lo, hi; _FoldSignal; ^this.primitiveFailed } asInteger { _AsInt; ^this.primitiveFailed } asFloat { _AsFloat; ^this.primitiveFailed } asComplex { ^Complex.new(this, 0.0) } asSignal { ^this } // complex support real { ^this } imag { ^0.0 } //PRIVATE: performBinaryOpOnSignal { arg aSelector, aNumber, adverb; BinaryOpFailureError(this, aSelector, [aNumber, adverb]).throw; } } Wavetable[float] : FloatArray { // the only way to make a Wavetable is by Signal::asWavetable *new { ^this.shouldNotImplement(thisMethod) } *newClear { ^this.shouldNotImplement(thisMethod) } *sineFill { arg size, amplitudes, phases; ^Signal.sineFill(size, amplitudes, phases).asWavetable } //size must be N/2+1 for N power of two; N is eventual size of wavetable *chebyFill { arg size, amplitudes, normalize=true; ^Signal.chebyFill(size, amplitudes, normalize).asWavetableNoWrap; //asWavetable causes wrap here, problem } *chebyFill_old { arg size, amplitudes; //this.deprecated(thisMethod, Buffer.findRespondingMethodFor(\cheby)); ^Signal.chebyFill(size, amplitudes).asWavetable; //asWavetable causes wrap here, problem } asSignal { _WavetableAsSignal ^this.primitiveFailed } blend { arg anotherWavetable, blendFrac=0.5; ^this.asSignal.blend(anotherWavetable.asSignal, blendFrac).asWavetable; } *readNew { arg file; ^file.readAllSignal.asWavetable; } write { arg path; var file; file = File.new(path, "wb"); if (file.notNil, { file.write(this.asSignal); file.close; }); } //libMenuAction { arg names; // this.plot(names.last); //} } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Math/Integer.sc0000664000000000000000000001324012245365552025657 0ustar rootrootInteger : SimpleNumber { isInteger { ^true } hash { ^this.asFloat.hash } + { arg aNumber, adverb; _AddInt; ^aNumber.performBinaryOpOnSimpleNumber('+', this, adverb) } - { arg aNumber, adverb; _SubInt; ^aNumber.performBinaryOpOnSimpleNumber('-', this, adverb) } * { arg aNumber, adverb; _MulInt; ^aNumber.performBinaryOpOnSimpleNumber('*', this, adverb) } clip { arg lo, hi; _ClipInt; ^this.primitiveFailed } wrap { arg lo, hi; _WrapInt; ^this.primitiveFailed } fold { arg lo, hi; _FoldInt; ^this.primitiveFailed } even { ^(this & 1) == 0 } odd { ^(this & 1) == 1 } xrand { arg exclude=0; ^(exclude + (this - 1).rand + 1) % this; } xrand2 { arg exclude=0; var res; res = (2 * this).rand - this; if (res == exclude, { ^this },{ ^res }); } degreeToKey { arg scale, stepsPerOctave = 12; ^scale.performDegreeToKey(this, stepsPerOctave) } // iteration do { arg function; // iterates function from 0 to this-1 // special byte codes inserted by compiler for this method var i = 0; while ({ i < this }, { function.value(i, i); i = i + 1; }); } // override 'do' generate { arg function; function.value(this) } collectAs { arg function, class; var res = (class ? Array).new(this); this.do {|i| res.add(function.value(i)) } ^res; } collect { arg function; ^this.collectAs(function, Array) } reverseDo { arg function; // iterates function from 0 to this-1 // special byte codes inserted by compiler for this method var i=0, j=0; i = this - 1; while ({ i >= 0 }, { function.value(i, j); i = i - 1; j = j + 1; }); } for { arg endval, function; // iterates function from this to endval (inclusive) // special byte codes inserted by compiler for this method var i, j=0, stepval=1; i = this; while ({ i <= endval }, { function.value(i, j); i = i + 1; j = j + 1; }); } forBy { arg endval, stepval, function; // iterates function from this to endval (inclusive) by step // special byte codes inserted by compiler for this method var i, j=0; i = this; while ({ i <= endval }, { function.value(i, j); i = i + stepval; j = j + 1; }); } to { arg hi, step=1; ^Interval.new(this, hi, step) } // conversions to Char asAscii { // must be 0 <= this <= 255 _AsAscii ^this.primitiveFailed } asUnicode { ^this } asDigit { // must be 0 <= this <= 35 _AsDigit ^this.primitiveFailed } asBinaryDigits { arg numDigits = 8; var array; array = Array.new(numDigits); numDigits.do({ arg i; array.addFirst(this >> i & 1) }); ^array } asDigits { arg base=10, numDigits; var array, num = this; numDigits = numDigits ?? { (this.log / base.log + 1e-10).asInteger + 1 }; array = Array.new(numDigits); numDigits.do { array = array.addFirst(num % base); num = num div: base } ^array } nextPowerOfTwo { _NextPowerOfTwo } isPowerOfTwo { _IsPowerOfTwo } leadingZeroes { _CLZ } trailingZeroes { _CTZ } numBits { _NumBits } log2Ceil { _Log2Ceil } grayCode { _BinaryGrayCode } setBit { arg bitNumber, bool = true; _SetBit ^this.primitiveFailed } nthPrime { _NthPrime } prevPrime { _PrevPrime } nextPrime { _NextPrime } indexOfPrime { _IndexOfPrime } isPrime { _IsPrime /* var sqrtThis; if ( this <= 2, { if (this == 2, { ^true }, { ^false }); }); sqrtThis = this.sqrt.asInteger; 256.do({ arg i; var p; p = i.nthPrime; if (this % p == 0, { ^false }); if (p >= sqrtThis, { ^true }); }); ^nil */ } // exit the program and return the result code to unix shell exit { _Exit } asStringToBase { | base=10, width=8 | var rest = this, string, mask; if (base.inclusivelyBetween(2, 36).not) { base = clip(base, 2, 36); warn(thisMethod + ": base not between 2 and 36"); }; string = String.newClear(width); if (base.isPowerOfTwo) { mask = base - 1; base = base.trailingZeroes; width.do { | i | string.put(width-i-1, (rest & mask).asDigit); rest = rest >> base; }; } { width.do { | i | string.put(width-i-1, (rest mod: base).asDigit); rest = rest div: base; }; }; ^string } asBinaryString { | width=8 | ^this.asStringToBase(2, width) } asHexString { | width=8 | ^this.asStringToBase(16, width) } asIPString { ^((this >> 24) & 255).asString ++ "." ++ ((this >> 16) & 255).asString ++ "." ++ ((this >> 8) & 255).asString ++ "." ++ (this & 255).asString } archiveAsCompileString { ^true } geom { arg start, grow; ^Array.geom(this, start, grow); } fib { arg a=0.0, b=1.0; ^Array.fib(this, a, b); } factors { var num, array, prime; if(this <= 1) { ^[] }; // no prime factors exist below the first prime num = this.abs; // there are 6542 16 bit primes from 2 to 65521 6542.do {|i| prime = i.nthPrime; while { (num mod: prime) == 0 }{ array = array.add(prime); num = num div: prime; if (num == 1) {^array} }; if (prime.squared > num) { array = array.add(num); ^array }; }; // because Integer is 32 bit, and we have tested all 16 bit primes, // any remaining number must be a prime. array = array.add(num); ^array } pidRunning { _PidRunning; ^this.primitiveFailed } factorial { ^#[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600] @ this.max(0) ?? { Error("integer resolution too low for this factorial:" + this).throw }; /*var product = 1; if(this <= 1) { ^1 } { this.do { |x| product = product * (x+1) }; ^product }*/ } // support for modifiers keys isCaps { ^this & 65536 == 65536} isShift { ^this & 131072 == 131072 } isCtrl { ^this & 262144 == 262144 } isAlt { ^this & 524288 == 524288 } isCmd { ^this & 1048576 == 1048576 } isNumPad { ^this & 2097152 == 2097152 } isHelp { ^this & 4194304 == 4194304 } isFun { ^this & 8388608 == 8388608 } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Math/Float.sc0000664000000000000000000000427012014636263025324 0ustar rootrootFloat : SimpleNumber { isFloat { ^true } asFloat { ^this } + { arg aNumber, adverb; _AddFloat; ^aNumber.performBinaryOpOnSimpleNumber('+', this, adverb) } - { arg aNumber, adverb; _SubFloat; ^aNumber.performBinaryOpOnSimpleNumber('-', this, adverb) } * { arg aNumber, adverb; _MulFloat; ^aNumber.performBinaryOpOnSimpleNumber('*', this, adverb) } clip { arg lo, hi; _ClipFloat; ^this.primitiveFailed } wrap { arg lo, hi; _WrapFloat; ^this.primitiveFailed } fold { arg lo, hi; _FoldFloat; ^this.primitiveFailed } coin { ^1.0.rand < this } xrand2 { ^this.rand2 } // returns an Integer which is the bit pattern of this as a // 32bit single precision float as32Bits { _As32Bits } // returns an Integer which is the bit pattern of high // 32 bits of the 64 bit double precision floating point value high32Bits { _High32Bits } low32Bits { _Low32Bits } *from32Bits { arg word; _From32Bits ^this.primitiveFailed } *from64Bits { arg hiWord, loWord; _From64Bits ^this.primitiveFailed } // iteration do { arg function; // iterates function from 0 to this-1 // special byte codes inserted by compiler for this method var i = 0.0; while ({ (i + 0.5) < this }, { function.value(i, i); i = i + 1.0; }); } reverseDo { arg function; // iterates function from this-1 to 0 // special byte codes inserted by compiler for this method var i, j=0.0; i = this - 1.0; while ({ (i + 0.5) >= 0.0 }, { function.value(i, j); i = i - 1.0; j = j + 1.0; }); } asStringPrec { arg precision; _Float_AsStringPrec ^this.primitiveFailed } archiveAsCompileString { ^true } // the correct place to implement compileString for Float is in DumpParseNode.cpp // int asCompileString(PyrSlot *slot, char *str) // for now, solve it here. storeOn { |stream| var str; if(this == inf) { stream << "inf"; ^this }; if(this == -inf) { stream << "-inf"; ^this }; str = super.asString; stream << str; // if it doesn't already have a . or is 1e-05 then add a .0 to force it to Float if(str.find(".").isNil and: { str.find("e").isNil }) { stream << ".0"; } } switch { | ... cases| "Float:switch is unsafe, rounding via Float:asInteger:switch".warn; ^this.asInteger.switch(*cases) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Math/Magnitude.sc0000664000000000000000000000163312014636263026174 0ustar rootrootMagnitude : Object { // Magnitudes are objects which represent a linear measure == { arg aMagnitude; ^this.subclassResponsibility(thisMethod) } != { arg aMagnitude; ^(this == aMagnitude).not } hash { ^this.subclassResponsibility(thisMethod) } // all of the other compare operations are built upon < < { arg aMagnitude; ^this.subclassResponsibility(thisMethod) } > { arg aMagnitude; ^aMagnitude < this } <= { arg aMagnitude; ^(aMagnitude < this).not } >= { arg aMagnitude; ^(this < aMagnitude).not } exclusivelyBetween { arg lo, hi; ^(lo < this) and: { this < hi } } inclusivelyBetween { arg lo, hi; ^(lo <= this) and: { this <= hi } } min { arg aMagnitude; if (this < aMagnitude, {^this}, {^aMagnitude}) } max { arg aMagnitude; if (this < aMagnitude, {^aMagnitude}, {^this}) } clip { arg lo, hi; // clip the receiver to the range lo, hi ^if (this < lo, {^lo}, { if (hi < this, {^hi}, {^this}) }) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Math/SimpleNumber.sc0000664000000000000000000004123312245365552026667 0ustar rootrootSimpleNumber : Number { *new { ^this.shouldNotImplement(thisMethod) } isValidUGenInput { ^this.isNaN.not } numChannels { ^1 } magnitude { ^this.abs } angle { if (this >= 0, {^0.0}, {^pi} ) } neg { _Neg; ^this.primitiveFailed } bitNot { _BitNot; ^this.primitiveFailed } abs { _Abs; ^this.primitiveFailed } ceil { _Ceil; ^this.primitiveFailed } floor { _Floor; ^this.primitiveFailed } frac { _Frac; ^this.primitiveFailed } sign { _Sign; ^this.primitiveFailed } squared { _Squared; ^this.primitiveFailed } cubed { _Cubed; ^this.primitiveFailed } sqrt { _Sqrt; ^this.primitiveFailed } exp { _Exp; ^this.primitiveFailed } reciprocal { _Recip; ^this.primitiveFailed } midicps { _MIDICPS; ^this.primitiveFailed } cpsmidi { _CPSMIDI; ^this.primitiveFailed } midiratio { _MIDIRatio; ^this.primitiveFailed } ratiomidi { _RatioMIDI; ^this.primitiveFailed } ampdb { _AmpDb; ^this.primitiveFailed } dbamp { _DbAmp; ^this.primitiveFailed } octcps { _OctCPS; ^this.primitiveFailed } cpsoct { _CPSOct; ^this.primitiveFailed } log { _Log; ^this.primitiveFailed } log2 { _Log2; ^this.primitiveFailed } log10 { _Log10; ^this.primitiveFailed } sin { _Sin; ^this.primitiveFailed } cos { _Cos; ^this.primitiveFailed } tan { _Tan; ^this.primitiveFailed } asin { _ArcSin; ^this.primitiveFailed } acos { _ArcCos; ^this.primitiveFailed } atan { _ArcTan; ^this.primitiveFailed } sinh { _SinH; ^this.primitiveFailed } cosh { _CosH; ^this.primitiveFailed } tanh { _TanH; ^this.primitiveFailed } rand { _Rand; ^this.primitiveFailed } rand2 { _Rand2; ^this.primitiveFailed } linrand { _LinRand; ^this.primitiveFailed } bilinrand { _BiLinRand; ^this.primitiveFailed } sum3rand { _Sum3Rand; ^this.primitiveFailed } distort { _Distort; ^this.primitiveFailed } softclip { _SoftClip; ^this.primitiveFailed } coin { _Coin; ^this.primitiveFailed } isPositive { ^this >= 0 } isNegative { ^this < 0 } isStrictlyPositive { ^this > 0 } isNaN { ^(this >= 0 or: { this <= 0 }).not } asBoolean { ^this > 0 } booleanValue { ^this > 0 } // TODO in the long-run, deprecate for asBoolean binaryValue { ^this.sign.max(0) } // TODO in the long-run, deprecate for asInteger rectWindow { _RectWindow; ^this.primitiveFailed } hanWindow { _HanWindow; ^this.primitiveFailed } welWindow { _WelchWindow; ^this.primitiveFailed } triWindow { _TriWindow; ^this.primitiveFailed } scurve { _SCurve; ^this.primitiveFailed } ramp { _Ramp; ^this.primitiveFailed } + { arg aNumber, adverb; _Add; ^aNumber.performBinaryOpOnSimpleNumber('+', this, adverb) } - { arg aNumber, adverb; _Sub; ^aNumber.performBinaryOpOnSimpleNumber('-', this, adverb) } * { arg aNumber, adverb; _Mul; ^aNumber.performBinaryOpOnSimpleNumber('*', this, adverb) } / { arg aNumber, adverb; _FDiv; ^aNumber.performBinaryOpOnSimpleNumber('/', this, adverb) } mod { arg aNumber, adverb; _Mod; ^aNumber.performBinaryOpOnSimpleNumber('mod', this, adverb) } div { arg aNumber, adverb; _IDiv; ^aNumber.performBinaryOpOnSimpleNumber('div', this, adverb) } pow { arg aNumber, adverb; _Pow; ^aNumber.performBinaryOpOnSimpleNumber('pow', this, adverb) } min { arg aNumber, adverb; _Min; ^aNumber.performBinaryOpOnSimpleNumber('min', this, adverb) } max { arg aNumber=0.0, adverb; _Max; ^aNumber.performBinaryOpOnSimpleNumber('max', this, adverb) } bitAnd { arg aNumber, adverb; _BitAnd; ^aNumber.performBinaryOpOnSimpleNumber('bitAnd', this, adverb) } bitOr { arg aNumber, adverb; _BitOr; ^aNumber.performBinaryOpOnSimpleNumber('bitOr', this, adverb) } bitXor { arg aNumber, adverb; _BitXor; ^aNumber.performBinaryOpOnSimpleNumber('bitXor', this, adverb) } bitHammingDistance { arg aNumber, adverb; _HammingDistance ^aNumber.performBinaryOpOnSimpleNumber('hammingDistance', this, adverb) } bitTest { arg bit; ^( (this & 1.leftShift(bit)) != 0) } lcm { arg aNumber, adverb; _LCM; ^aNumber.performBinaryOpOnSimpleNumber('lcm', this, adverb) } gcd { arg aNumber, adverb; _GCD; ^aNumber.performBinaryOpOnSimpleNumber('gcd', this, adverb) } round { arg aNumber=1.0, adverb; _Round; ^aNumber.performBinaryOpOnSimpleNumber('round', this, adverb) } roundUp { arg aNumber=1.0, adverb; _RoundUp; ^aNumber.performBinaryOpOnSimpleNumber('roundUp', this, adverb) } trunc { arg aNumber=1.0, adverb; _Trunc; ^aNumber.performBinaryOpOnSimpleNumber('trunc', this, adverb) } atan2 { arg aNumber, adverb; _Atan2; ^aNumber.performBinaryOpOnSimpleNumber('atan2', this, adverb) } hypot { arg aNumber, adverb; _Hypot; ^aNumber.performBinaryOpOnSimpleNumber('hypot', this, adverb) } hypotApx { arg aNumber, adverb; _HypotApx; ^aNumber.performBinaryOpOnSimpleNumber('hypotApx', this, adverb) } leftShift { arg aNumber=1, adverb; _ShiftLeft; ^aNumber.performBinaryOpOnSimpleNumber('leftShift', this, adverb) } rightShift { arg aNumber=1, adverb; _ShiftRight; ^aNumber.performBinaryOpOnSimpleNumber('rightShift', this, adverb) } unsignedRightShift { arg aNumber, adverb; _UnsignedShift; ^aNumber.performBinaryOpOnSimpleNumber('unsignedRightShift', this, adverb) } ring1 { arg aNumber, adverb; _Ring1; ^aNumber.performBinaryOpOnSimpleNumber('ring1', this, adverb) } ring2 { arg aNumber, adverb; _Ring2; ^aNumber.performBinaryOpOnSimpleNumber('ring2', this, adverb) } ring3 { arg aNumber, adverb; _Ring3; ^aNumber.performBinaryOpOnSimpleNumber('ring3', this, adverb) } ring4 { arg aNumber, adverb; _Ring4; ^aNumber.performBinaryOpOnSimpleNumber('ring4', this, adverb) } difsqr { arg aNumber, adverb; _DifSqr; ^aNumber.performBinaryOpOnSimpleNumber('difsqr', this, adverb) } sumsqr { arg aNumber, adverb; _SumSqr; ^aNumber.performBinaryOpOnSimpleNumber('sumsqr', this, adverb) } sqrsum { arg aNumber, adverb; _SqrSum; ^aNumber.performBinaryOpOnSimpleNumber('sqrsum', this, adverb) } sqrdif { arg aNumber, adverb; _SqrDif; ^aNumber.performBinaryOpOnSimpleNumber('sqrdif', this, adverb) } absdif { arg aNumber, adverb; _AbsDif; ^aNumber.performBinaryOpOnSimpleNumber('absdif', this, adverb) } thresh { arg aNumber, adverb; _Thresh; ^aNumber.performBinaryOpOnSimpleNumber('thresh', this, adverb) } amclip { arg aNumber, adverb; _AMClip; ^aNumber.performBinaryOpOnSimpleNumber('amclip', this, adverb) } scaleneg { arg aNumber, adverb; _ScaleNeg; ^aNumber.performBinaryOpOnSimpleNumber('scaleneg', this, adverb) } clip2 { arg aNumber, adverb; _Clip2; ^aNumber.performBinaryOpOnSimpleNumber('clip2', this, adverb) } fold2 { arg aNumber, adverb; _Fold2; ^aNumber.performBinaryOpOnSimpleNumber('fold2', this, adverb) } wrap2 { arg aNumber, adverb; _Wrap2; ^aNumber.performBinaryOpOnSimpleNumber('wrap2', this, adverb) } excess { arg aNumber, adverb; _Excess; ^aNumber.performBinaryOpOnSimpleNumber('excess', this, adverb) } firstArg { arg aNumber, adverb; _FirstArg; ^aNumber.performBinaryOpOnSimpleNumber('firstArg', this, adverb) } rrand { arg aNumber, adverb; _RandRange; ^aNumber.performBinaryOpOnSimpleNumber('rrand', this, adverb) } exprand { arg aNumber, adverb; _ExpRandRange; ^aNumber.performBinaryOpOnSimpleNumber('exprand', this, adverb) } == { arg aNumber, adverb; _EQ; ^aNumber.perform('==', this, adverb) } != { arg aNumber, adverb; _NE; ^aNumber.perform('!=', this, adverb) } < { arg aNumber, adverb; _LT; ^aNumber.performBinaryOpOnSimpleNumber('<', this, adverb) } > { arg aNumber, adverb; _GT; ^aNumber.performBinaryOpOnSimpleNumber('>', this, adverb) } <= { arg aNumber, adverb; _LE; ^aNumber.performBinaryOpOnSimpleNumber('<=', this, adverb) } >= { arg aNumber, adverb; _GE; ^aNumber.performBinaryOpOnSimpleNumber('>=', this, adverb) } equalWithPrecision { arg that, precision=0.0001; ^absdif(this, that) < precision } hash { _ObjectHash; ^this.primitiveFailed } asInteger { _AsInt; ^this.primitiveFailed } asFloat { _AsFloat; ^this.primitiveFailed } asComplex { ^Complex.new(this, 0.0) } asRect { ^Rect(this, this, this, this) } degrad { ^this*pi/180 } raddeg { ^this*180/pi } performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb; BinaryOpFailureError(this, aSelector, [aNumber, adverb]).throw; } performBinaryOpOnComplex { arg aSelector, aComplex, adverb; ^aComplex.perform(aSelector, this.asComplex, adverb) } performBinaryOpOnSignal { arg aSelector, aSignal, adverb; BinaryOpFailureError(this, aSelector, [aSignal, adverb]).throw; } nextPowerOfTwo { ^this.nextPowerOf(2) } nextPowerOf { arg base; ^pow(base, ceil(log(this) / log(base))) } nextPowerOfThree { ^pow(3, ceil(log(this) / log(3))) } previousPowerOf { arg base; ^pow(base, ceil(log(this) / log(base)) - 1) } quantize { arg quantum = 1.0, tolerance = 0.05, strength = 1.0; var round = round(this, quantum); var diff = round - this; if (abs(diff) < tolerance) { ^this + (strength * diff) }{ ^this } } linlin { arg inMin, inMax, outMin, outMax, clip=\minmax; // linear to linear mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^(this-inMin)/(inMax-inMin) * (outMax-outMin) + outMin; } linexp { arg inMin, inMax, outMin, outMax, clip=\minmax; // linear to exponential mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^pow(outMax/outMin, (this-inMin)/(inMax-inMin)) * outMin } explin { arg inMin, inMax, outMin, outMax, clip=\minmax; // exponential to linear mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^(log(this/inMin)) / (log(inMax/inMin)) * (outMax-outMin) + outMin; } expexp { arg inMin, inMax, outMin, outMax, clip=\minmax; // exponential to exponential mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^pow(outMax/outMin, log(this/inMin) / log(inMax/inMin)) * outMin; } lincurve { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; var grow, a, b, scaled; switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); if (abs(curve) < 0.001) { ^this.linlin(inMin, inMax, outMin, outMax) }; grow = exp(curve); a = outMax - outMin / (1.0 - grow); b = outMin + a; scaled = (this - inMin) / (inMax - inMin); ^b - (a * pow(grow, scaled)); } curvelin { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; var grow, a, b, scaled; switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); if (abs(curve) < 0.001) { ^this.linlin(inMin, inMax, outMin, outMax) }; grow = exp(curve); a = inMax - inMin / (1.0 - grow); b = inMin + a; ^log((b - this) / a) * (outMax - outMin) / curve + outMin } bilin { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax; // triangular linear mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^if (this >= inCenter) { this.linlin(inCenter, inMax, outCenter, outMax, \none); } { this.linlin(inMin, inCenter, outMin, outCenter, \none); } } biexp { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax; // triangular exponential mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); if (this >= inCenter) { this.explin(inCenter, inMax, outCenter, outMax, \none); } { this.explin(inMin, inCenter, outMin, outCenter, \none); } } lcurve { arg a = 1.0, m = 0.0, n = 1.0, tau = 1.0; var rTau, x = this.neg; ^if(tau == 1.0) { a * (m * exp(x) + 1) / (n * exp(x) + 1) } { rTau = tau.reciprocal; a * (m * exp(x) * rTau + 1) / (n * exp(x) * rTau + 1) } } gauss { arg standardDeviation; ^((((-2*log(1.0.rand)).sqrt * sin(2pi.rand)) * standardDeviation) + this) } gaussCurve { arg a = 1.0, b = 0.0, c = 1.0; ^a * (exp(squared(this - b) / (-2.0 * squared(c)))) } asPoint { ^Point.new(this, this) } asWarp { arg spec; ^CurveWarp.new(spec, this) } // scheduled Routine support wait { ^this.yield } waitUntil { ^(this - thisThread.beats).max(0).yield } sleep { var thread = thisThread; thread.clock.sched(this, { thread.next; nil }); nil.yield; } printOn { arg stream; stream.putAll(this.asString); } storeOn { arg stream; stream.putAll(this.asString); } rate { ^'scalar' } // scalarRate constant asAudioRateInput { ^if(this == 0) { Silent.ar } { DC.ar(this) } } madd { arg mul, add; ^(this * mul) + add; } lag { ^this } lag2 { ^this } lag3 { ^this } lagud { ^this } lag2ud { ^this } lag3ud { ^this } varlag { ^this } slew { ^this } // support for writing synth defs writeInputSpec { arg file, synth; var constIndex = synth.constants.at(this.asFloat); if (constIndex.isNil) { Error("SimpleNumber-writeInputSpec constant not found: " ++ this.asFloat).throw; }; file.putInt32(-1); file.putInt32(constIndex); } series { arg second, last; _SimpleNumberSeries ^this.primitiveFailed /* var step, size; second = second ?? { if (this < last) { this + 1 } { this - 1 } }; step = second - this; size = floor((last - this) / step + 0.001).asInteger + 1; ^Array.series(size, this, step) */ } seriesIter { arg second, last; var step, size; if (second.isNil) { last = last ? inf; step = if (this < last, 1, -1); }{ last ?? { last = if (second < this, -inf, inf) }; step = second - this; }; ^if (step < 0) { r { var val = this; while { val >= last; }{ val.yield; val = val + step; }; } }{ r { var val = this; while { val <= last; }{ val.yield; val = val + step; }; } } } degreeToKey { arg scale, stepsPerOctave = 12; var scaleDegree = this.round.asInteger; var accidental = (this - scaleDegree) * 10.0; ^scale.performDegreeToKey(scaleDegree, stepsPerOctave, accidental) } keyToDegree { arg scale, stepsPerOctave=12; ^scale.performKeyToDegree(this, stepsPerOctave) } nearestInList { arg list; // collection is sorted ^list.performNearestInList(this); } nearestInScale { arg scale, stepsPerOctave=12; // collection is sorted ^scale.performNearestInScale(this, stepsPerOctave); } partition { arg parts=2, min=1; // randomly partition a number into parts of at least min size : var n = this - (min - 1 * parts); ^(1..n-1).scramble.keep(parts-1).sort.add(n).differentiate + (min - 1) } nextTimeOnGrid { arg clock; ^clock.nextTimeOnGrid(this, 0); } playAndDelta {} asQuant { ^Quant(this) } // a clock format inspired by ISO 8601 time interval display (truncated representation) // receiver is a time in seconds, returns string "ddd:hh:mm:ss:ttt" where t is milliseconds // see String:asSecs for complement asTimeString { arg precision = 0.001, maxDays = 365, dropDaysIfPossible = true; var decimal, days, hours, minutes, seconds, mseconds; decimal = this.asInteger; days = decimal.div(86400).min(maxDays); days = if(dropDaysIfPossible and: { days == 0 }) { days = "" } { days.asString.padLeft(3, "0").add($:); }; hours = (decimal.div(3600) % 24).asString.padLeft(2, "0").add($:); minutes = (decimal.div(60) % 60).asString.padLeft(2, "0").add($:); seconds = (decimal % 60).asString.padLeft(2, "0").add($:); mseconds = (this.frac / precision).round(precision).asInteger.asString.padLeft(3, "0"); ^days ++ hours ++ minutes ++ seconds ++ mseconds } asFraction {|denominator=100, fasterBetter=true| _AsFraction // asFraction will return a fraction that is the best approximation up to the given // denominator. // if fasterBetter is true it may find a much closer approximation and do it faster. ^this.primitiveFailed } prSimpleNumberSeries { arg second, last; _SimpleNumberSeries ^this.primitiveFailed } asBufWithValues { ^this } schedBundleArrayOnClock { |clock, bundleArray, lag = 0, server, latency| clock.sched(this, { if (lag != 0) { SystemClock.sched(lag, { server.sendBundle(latency ? server.latency, *bundleArray) }) } { server.sendBundle(latency ? server.latency, *bundleArray) } }) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Math/Complex.sc0000664000000000000000000000707212161364457025677 0ustar rootrootComplex : Number { var <>real, <>imag; *new { arg real, imag; ^super.newCopyArgs(real, imag); } + { arg aNumber, adverb; if ( aNumber.isNumber, { ^Complex.new(real + aNumber.real, imag + aNumber.imag) },{ ^aNumber.performBinaryOpOnComplex('+', this, adverb) }); } - { arg aNumber, adverb; if ( aNumber.isNumber, { ^Complex.new(real - aNumber.real, imag - aNumber.imag) },{ ^aNumber.performBinaryOpOnComplex('-', this, adverb) }); } * { arg aNumber, adverb; if ( aNumber.isNumber, { ^Complex.new( // these are implemented as additional message sends so that UGens can // optimize the 6 operations down to 2 UGen instances. (real * aNumber.real) - (imag * aNumber.imag), (real * aNumber.imag) + (imag * aNumber.real) ) },{ ^aNumber.performBinaryOpOnComplex('*', this, adverb) }); } / { arg aNumber, adverb; var denom, yr, yi; if ( aNumber.isNumber, { yr = aNumber.real; yi = aNumber.imag; denom = 1.0 / (yr * yr + (yi * yi)); ^Complex.new( ((real * yr) + (imag * yi)) * denom, ((imag * yr) - (real * yi)) * denom) },{ ^aNumber.performBinaryOpOnComplex('/', this, adverb) }); } < { arg aNumber, adverb; if ( aNumber.isNumber, { ^real < aNumber.real },{ ^aNumber.performBinaryOpOnComplex('<', this, adverb) }); } == { arg aNumber, adverb; if ( aNumber.isNumber, { ^real == aNumber.real and: { imag == aNumber.imag } },{ ^aNumber.performBinaryOpOnComplex('==', this, adverb) }); } hash { ^real.hash << 1 bitXor: imag.hash } // double dispatch performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb; ^aNumber.asComplex.perform(aSelector, this, adverb) } performBinaryOpOnSignal { arg aSelector, aSignal, adverb; ^aSignal.asComplex.perform(aSelector, this) } performBinaryOpOnComplex { arg aSelector, aNumber, adverb; BinaryOpFailureError(this, aSelector, [aNumber, adverb]).throw; } performBinaryOpOnUGen { arg aSelector, aUGen, adverb; ^aUGen.asComplex.perform(aSelector, this, adverb) } neg { ^Complex.new(real.neg, imag.neg) } conjugate { ^Complex.new(real, imag.neg) } squared { ^this * this } cubed { ^this * this * this } exp { ^exp(real) * Complex.new(cos(imag), sin(imag)) } pow { arg aNumber; // return(this ** aNumber) // Notation below: // t=this, p=power, i=sqrt(-1) // Derivation: // t ** p = exp(p*log(t)) = ... = r*exp(i*a) var p_real, p_imag, t_mag, t_phase, t_maglog; var mag, phase; aNumber = aNumber.asComplex; p_real = aNumber.real; p_imag = aNumber.imag; if(p_real == 0.0 and: { p_imag == 0 }) { ^Complex(1.0, 0.0) }; if(p_imag == 0.0 and: { imag == 0.0 } and: { real > 0.0 }) { ^Complex(real ** p_real, 0.0) }; t_mag = this.magnitude; if(t_mag == 0.0) { ^Complex(0.0, 0.0) }; t_maglog = 0.5 * log(t_mag); t_phase = this.phase; mag = exp((p_real * t_maglog) - (p_imag * t_phase)); phase = (p_imag * t_maglog) + (p_real * t_phase); ^Complex(mag * cos(phase), mag * sin(phase)) } magnitude { ^hypot(real, imag) } abs { ^hypot(real, imag) } rho { ^hypot(real, imag) } magnitudeApx { ^hypotApx(real, imag) } angle { ^atan2(imag, real) } phase { ^atan2(imag, real) } theta { ^atan2(imag, real) } coerce { arg aNumber; ^aNumber.asComplex } round { arg aNumber = 1.0; ^Complex(real.round(aNumber), imag.round(aNumber)) } asInteger { ^real.asInteger } asFloat { ^real.asFloat } asComplex { ^this } asPolar { ^Polar.new(this.rho, this.theta) } asPoint { ^Point.new(this.real, this.imag) } printOn { arg stream; stream << "Complex( " << real << ", " << imag << " )"; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Math/Date.sc0000664000000000000000000000342112245365552025137 0ustar rootrootDate { var <>year=2000, <>month=1, <>day=1, <>hour=0, <>minute=0, <>second=0, <>dayOfWeek=6, <>rawSeconds=0, <>bootSeconds=0; *getDate { ^this.localtime } *localtime { ^this.new.localtime } *gmtime { ^this.new.gmtime } *new { arg year, month, day, hour, minute, second, dayOfWeek, rawSeconds, bootSeconds; ^super.newCopyArgs(year, month, day, hour, minute, second, dayOfWeek, rawSeconds, bootSeconds); } storeArgs { ^[year, month, day, hour, minute, second, dayOfWeek, rawSeconds, bootSeconds] } localtime { _LocalTime ^this.primitiveFailed } gmtime { _GMTime ^this.primitiveFailed } *seed { // return a value suitable for seeding a random number generator. _TimeSeed } // strings for time stamping things like filenames. dayStamp { var s; s = (((year % 100) * 100 + month) * 100 + day + 1000000).asString; s.removeAt(0); // get rid of the leading '1' char that was put there to force leading zeroes. ^s } secStamp { var s; s = ((hour * 100 + minute) * 100 + second + 1000000).asString; s.removeAt(0); // get rid of the leading '1' char that was put there to force leading zeroes. ^s } stamp { ^this.dayStamp ++ "_" ++ this.secStamp } hourStamp { ^hour.asString ++ ":" ++ minute ++ ":" ++ (rawSeconds % 60).round(0.0001) } asSortableString { // standard database format, alphabetically sortable ^String.streamContents({ arg s; s << year; if(month < 10,{ s << 0 }); s << month; if(day < 10,{ s << 0 }); s << day; if(hour < 10,{ s << 0 }); s << hour; if(minute < 10, { s << 0 }); s << minute; if(second < 10, { s << 0 }); s << second; }) } asctime { _AscTime ^this.primitiveFailed } asString { ^this.asctime } format { arg format; _prStrFTime; ^this.primitiveFailed } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Math/Number.sc0000664000000000000000000000343112014636263025505 0ustar rootrootNumber : Magnitude { isNumber { ^true } + { arg aNumber; ^this.subclassResponsibility(thisMethod) } - { arg aNumber; ^this.subclassResponsibility(thisMethod) } * { arg aNumber; ^this.subclassResponsibility(thisMethod) } / { arg aNumber; ^this.subclassResponsibility(thisMethod) } mod { arg aNumber; ^this.subclassResponsibility(thisMethod) } div { arg aNumber; ^this.subclassResponsibility(thisMethod) } pow { arg aNumber; ^this.subclassResponsibility(thisMethod) } performBinaryOpOnSeqColl { arg aSelector, aSeqColl, adverb; ^aSeqColl.collect({ arg item; item.perform(aSelector, this, adverb) }) } performBinaryOpOnPoint { arg op, aPoint, adverb; ^Point.new(this.perform(op, aPoint.x, adverb), this.perform(op, aPoint.y, adverb)); } // polar support rho { ^this } theta { ^0.0 } // complex support real { ^this } imag { ^0.0 } // conversion @ { arg aNumber; ^Point.new(this, aNumber) } complex { arg imaginaryPart; ^Complex.new(this, imaginaryPart) } polar { arg angle; ^Polar.new(this, angle) } // iteration for { arg endValue, function; var i, j = 0; i = this; while ({ i <= endValue }, { function.value(i, j); i = i + 1; j = j + 1 }); } forBy { arg endValue, stepValue, function; var i, j=0; i = this; (stepValue > 0).if({ while ({ i <= endValue }, { function.value(i,j); i = i + stepValue; j=j+1; }); }, { while ({ i >= endValue }, { function.value(i,j); i = i + stepValue; j=j+1; }); }); } forSeries { arg second, last, function; // called by generator expression // compiler replaces this with special byte codes. var step, j=0; if (second.isNil) { last = last ? inf; step = if (this < last, 1, -1); }{ last ?? { last = if (second < this, -inf, inf) }; step = second - this; }; ^this.forBy(last, step, function) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/0000775000000000000000000000000012245452763023467 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/Model.sc0000664000000000000000000000414612014636263025054 0ustar rootrootSimpleController { var model, actions; // responds to updates of a model *new { arg model; ^super.newCopyArgs(model).init } init { model.addDependant(this); } put { arg what, action; if (actions.isNil, { actions = IdentityDictionary.new(4); }); actions.put(what, action); } update { arg theChanger, what ... moreArgs; var action; if(actions.notNil) { action = actions.at(what); if (action.notNil, { action.valueArray(theChanger, what, moreArgs); }); }; } remove { model.removeDependant(this); } } TestDependant { update { arg thing; (thing.asString ++ " was changed.\n").post; } } NotificationCenter { classvar registrations; // who \didSomething *notify { arg object, message, args; registrations.at(object,message).copy.do({ arg function; function.valueArray(args) }) } // who \didSomething *register { arg object,message,listener,action; var nr; nr = NotificationRegistration(object,message,listener); registrations.put(object,message,listener,action); ^nr; } *unregister { arg object,message,listener; var lastKey,lastDict; lastDict = registrations.at(object,message); if(lastDict.notNil,{ lastDict.removeAt(listener); (lastDict.size == 0).if({ registrations.removeAt(object,message); (registrations.at(object).size == 0).if({ registrations.removeAt(object); }); }); }); } *registerOneShot { arg object,message,listener,action; var nr; nr = NotificationRegistration(object,message,listener); registrations.put(object,message,listener, { |args| action.value(args); this.unregister(object,message,listener) }); ^nr } *clear { registrations = MultiLevelIdentityDictionary.new; } *registrationExists { |object,message,listener| ^registrations.at(object,message,listener).notNil } *initClass { this.clear } *removeForListener { |listener| registrations.removeAt(listener) } } NotificationRegistration { var <>object,<>message,<>listener; *new { arg o,m,l; ^super.new.object_(o).message_(m).listener_(l) } remove { NotificationCenter.unregister(object,message,listener) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/0000775000000000000000000000000012245452763024757 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Math/0000775000000000000000000000000012245452763025650 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Math/PlotView.sc0000664000000000000000000005311512243234136027743 0ustar rootrootPlot { var <>plotter, drawGrid; var plotColor, <>backgroundColor; var labelX, <>labelY; var valueCache,pen; *initClass { StartUp.add { GUI.skin.put(\plot, ( gridColorX: Color.grey(0.7), gridColorY: Color.grey(0.7), fontColor: Color.grey(0.3), plotColor: [Color.black, Color.blue, Color.red, Color.green(0.7)], background: Color.new255(235, 235, 235), gridLinePattern: nil, gridLineSmoothing: false, labelX: "", labelY: "", expertMode: false, gridFont: Font( Font.defaultSansFace, 9 ) )); } } *new { |plotter| ^super.newCopyArgs(plotter).init } init { var fontName; var gui = plotter.gui; var skin = GUI.skin.at(\plot); pen = gui.pen; drawGrid = DrawGrid(bounds ? Rect(0,0,1,1),nil,nil); drawGrid.x.labelOffset = Point(0,4); drawGrid.y.labelOffset = Point(-10,0); skin.use { font = ~gridFont ?? { gui.font.default }; if(font.class != gui.font) { fontName = font.name; if( gui.font.availableFonts.detect(_ == fontName).isNil, { fontName = gui.font.defaultSansFace }); font = gui.font.new(fontName, font.size) }; this.gridColorX = ~gridColorX; this.gridColorY = ~gridColorY; plotColor = ~plotColor; this.fontColor = ~fontColor; backgroundColor = ~background; this.gridLineSmoothing = ~gridLineSmoothing; this.gridLinePattern = ~gridLinePattern !? {~gridLinePattern.as(FloatArray)}; labelX = ~labelX; labelY = ~labelY; }; } bounds_ { |rect| var size = (try { "foo".bounds(font).height } ?? { font.size } * 1.5); plotBounds = if(rect.height > 40) { rect.insetBy(size, size) } { rect }; bounds = rect; valueCache = nil; drawGrid.bounds = plotBounds; } value_ { |array| value = array; valueCache = nil; } spec_ { |sp| spec = sp; if(gridOnY and: spec.notNil,{ drawGrid.vertGrid = spec.grid; },{ drawGrid.vertGrid = nil }) } domainSpec_ { |sp| domainSpec = sp; if(gridOnX and: domainSpec.notNil,{ drawGrid.horzGrid = domainSpec.grid; },{ drawGrid.horzGrid = nil }) } gridColorX_ { |c| drawGrid.x.gridColor = c; gridColorX = c; } gridColorY_ { |c| drawGrid.y.gridColor = c; gridColorY = c; } font_ { |f| font = f; drawGrid.font = f; } fontColor_ { |c| fontColor = c; drawGrid.fontColor = c; } gridLineSmoothing_ { |bool| drawGrid.smoothing = bool; } gridLinePattern_ { |pattern| drawGrid.linePattern = pattern; } gridOnX_ { |bool| gridOnX = bool; drawGrid.horzGrid = if(gridOnX,{domainSpec.grid},{nil}); } gridOnY_ { |bool| gridOnY= bool; drawGrid.vertGrid = if(gridOnY,{spec.grid},{nil}); } draw { this.drawBackground; drawGrid.draw; this.drawLabels; this.drawData; plotter.drawFunc.value(this); // additional elements } drawBackground { pen.addRect(bounds); pen.fillColor = backgroundColor; pen.fill; } drawLabels { var sbounds; if(gridOnX and: { labelX.notNil }) { sbounds = try { labelX.bounds(font) } ? 0; pen.font = font; pen.strokeColor = fontColor; pen.stringAtPoint(labelX, plotBounds.right - sbounds.width @ plotBounds.bottom ) }; if(gridOnY and: { labelY.notNil }) { sbounds = try { labelY.bounds(font) } ? 0; pen.font = font; pen.strokeColor = fontColor; pen.stringAtPoint(labelY, plotBounds.left - sbounds.width - 3 @ plotBounds.top ) }; } domainCoordinates { |size| var val = this.resampledDomainSpec.unmap(plotter.domain ?? { (0..size-1) }); ^plotBounds.left + (val * plotBounds.width); } dataCoordinates { var val = spec.unmap(this.prResampValues); ^plotBounds.bottom - (val * plotBounds.height); // measures from top left (may be arrays) } resampledSize { ^min(value.size, plotBounds.width / plotter.resolution) } resampledDomainSpec { var offset = if(this.hasSteplikeDisplay) { 0 } { 1 }; ^domainSpec.copy.maxval_(this.resampledSize - offset) } drawData { var mode = plotter.plotMode; var ycoord = this.dataCoordinates; var xcoord = this.domainCoordinates(ycoord.size); pen.width = 1.0; pen.joinStyle = 1; plotColor = plotColor.as(Array); if(ycoord.at(0).isSequenceableCollection) { // multi channel expansion ycoord.flop.do { |y, i| pen.beginPath; this.perform(mode, xcoord, y); pen.strokeColor = plotColor.wrapAt(i); pen.stroke; } } { pen.beginPath; pen.strokeColor = plotColor.at(0); this.perform(mode, xcoord, ycoord); pen.stroke; }; pen.joinStyle = 0; } // modes linear { |x, y| pen.moveTo(x.first @ y.first); y.size.do { |i| pen.lineTo(x[i] @ y[i]); } } points { |x, y| var size = min(bounds.width / value.size * 0.25, 4); y.size.do { |i| pen.addArc(x[i] @ y[i], 0.5, 0, 2pi); if(size > 2) { pen.addArc(x[i] @ y[i], size, 0, 2pi); }; } } plines { |x, y| var size = min(bounds.width / value.size * 0.25, 3); pen.moveTo(x.first @ y.first); y.size.do { |i| var p = x[i] @ y[i]; pen.lineTo(p); pen.addArc(p, size, 0, 2pi); pen.moveTo(p); } } levels { |x, y| pen.smoothing_(false); y.size.do { |i| pen.moveTo(x[i] @ y[i]); pen.lineTo(x[i + 1] ?? { plotBounds.right } @ y[i]); } } steps { |x, y| pen.smoothing_(false); pen.moveTo(x.first @ y.first); y.size.do { |i| pen.lineTo(x[i] @ y[i]); pen.lineTo(x[i + 1] ?? { plotBounds.right } @ y[i]); } } // editing editDataIndex { |index, x, y, plotIndex| // WARNING: assuming index is in range! var val = this.getRelativePositionY(y); plotter.editFunc.value(plotter, plotIndex, index, val, x, y); value.put(index, val); valueCache = nil; } editData { |x, y, plotIndex| var index = this.getIndex(x); this.editDataIndex( index, x, y, plotIndex ); } editDataLine { |pt1, pt2, plotIndex| var ptLeft, ptRight, ptLo, ptHi; var xSpec, ySpec; var i1, i2, iLo, iHi; var val; // get indexes related to ends of the line i1 = this.getIndex(pt1.x); i2 = this.getIndex(pt2.x); // if both ends at same index, simplify if( i1 == i2 ) { ^this.editDataIndex( i2, pt2.x, pt2.y, plotIndex ); }; // order points and indexes if( i1 < i2 ) { iLo = i1; iHi = i2; ptLeft = pt1; ptRight = pt2; }{ iLo = i2; iHi = i1; ptLeft = pt2; ptRight = pt1; }; // if same value all over, simplify if( ptLeft.y == ptRight.y ) { val = this.getRelativePositionY(ptLeft.y); while( {iLo <= iHi} ) { value.put( iLo, val ); iLo = iLo + 1; }; // trigger once for second end of the line plotter.editFunc.value(plotter, plotIndex, i2, val, pt2.x, pt2.y); valueCache = nil; ^this; }; // get actual points corresponding to indexes xSpec = ControlSpec( ptLeft.x, ptRight.x ); ySpec = ControlSpec( ptLeft.y, ptRight.y ); ptLo = Point(); ptHi = Point(); ptLo.x = domainSpec.unmap(iLo) * plotBounds.width + plotBounds.left; ptHi.x = domainSpec.unmap(iHi) * plotBounds.width + plotBounds.left; ptLo.y = ySpec.map( xSpec.unmap(ptLo.x) ); ptHi.y = ySpec.map( xSpec.unmap(ptHi.x) ); // interpolate and store ySpec = ControlSpec( this.getRelativePositionY(ptLo.y), this.getRelativePositionY(ptHi.y) ); xSpec = ControlSpec( iLo, iHi ); while( {iLo <= iHi} ) { val = ySpec.map( xSpec.unmap(iLo) ); value.put( iLo, val ); iLo = iLo+1; }; // trigger once for second end of the line plotter.editFunc.value(plotter, plotIndex, i2, val, pt2.x, pt2.y); valueCache = nil; } getRelativePositionX { |x| ^domainSpec.map((x - plotBounds.left) / plotBounds.width) } getRelativePositionY { |y| ^spec.map((plotBounds.bottom - y) / plotBounds.height) } hasSteplikeDisplay { ^#[\levels, \steps].includes(plotter.plotMode) } getIndex { |x| var offset = if(this.hasSteplikeDisplay) { 0.5 } { 0.0 }; // needs to be fixed. ^(this.getRelativePositionX(x) - offset).round.asInteger } getDataPoint { |x| var index = this.getIndex(x).clip(0, value.size - 1); ^[index, value.at(index)] } // settings zoomFont { |val| font = font.copy; font.size = max(1, font.size + val); this.font = font; drawGrid.clearCache; } copy { ^super.copy.drawGrid_(drawGrid.copy) } prResampValues { ^if(value.size <= (plotBounds.width / plotter.resolution)) { value } { valueCache ?? { valueCache = value.resamp1(plotBounds.width / plotter.resolution) } } } } Plotter { var <>name, <>bounds, <>parent; var domain; var plotMode = \linear, <>editMode = false, <>normalized = false; var <>resolution = 1, <>findSpecs = true, drawFunc, <>editFunc; var 1 ) { 4.0 } { 0.0 }; var distY = bounds.height / data.size; var height = distY - deltaY; plots.do { |plot, i| plot.bounds_( Rect(bounds.left, distY * i + bounds.top, bounds.width, height) ) } } makePlots { var template = if(plots.isNil) { Plot(this) } { plots.last }; plots !? { plots = plots.keep(data.size.neg) }; plots = plots ++ template.dup(data.size - plots.size); plots.do { |plot, i| plot.value = data.at(i) }; this.updatePlotSpecs; this.updatePlotBounds; } updatePlots { if(plots.size != data.size) { this.makePlots; } { plots.do { |plot, i| plot.value = data.at(i) } } } updatePlotSpecs { specs !? { plots.do { |plot, i| plot.spec = specs.clipAt(i) } }; domainSpecs !? { plots.do { |plot, i| plot.domainSpec = domainSpecs.clipAt(i) } } } setProperties { |... pairs| pairs.pairsDo { |selector, value| selector = selector.asSetter; plots.do { |x| x.perform(selector, value) } } } // specs specs_ { |argSpecs| specs = argSpecs.asArray.clipExtend(data.size).collect(_.asSpec); this.updatePlotSpecs; } domainSpecs_ { |argSpecs| domainSpecs = argSpecs.asArray.clipExtend(data.size).collect(_.asSpec); this.updatePlotSpecs; } minval_ { |val| val = val.asArray; specs.do { |x, i| x.minval = val.wrapAt(i) }; this.updatePlotSpecs; } maxval_ { |val| val = val.asArray; specs.do { |x, i| x.maxval = val.wrapAt(i) }; this.updatePlotSpecs; } calcSpecs { |separately = true| specs = (specs ? [\unipolar.asSpec]).clipExtend(data.size); if(separately) { this.specs = specs.collect { |spec, i| var list = data.at(i); list !? { spec = spec.looseRange(list.flat) }; } } { this.specs = specs.first.looseRange(data.flat); } } calcDomainSpecs { // for now, a simple version domainSpecs = data.collect { |val| [0, val.size - 1, \lin, 1].asSpec } } // interaction pointIsInWhichPlot { |point| var res = plots.detectIndex { |plot| point.y.exclusivelyBetween(plot.bounds.top, plot.bounds.bottom) }; ^res ?? { if(point.y < bounds.center.y) { 0 } { plots.size - 1 } } } getDataPoint { |x, y| var plotIndex = this.pointIsInWhichPlot(x @ y); ^plotIndex !? { plots.at(plotIndex).getDataPoint(x) } } postCurrentValue { |x, y| this.getDataPoint(x, y).postln } editData { |x, y| var plotIndex = this.pointIsInWhichPlot(x @ y); plotIndex !? { plots.at(plotIndex).editData(x, y, plotIndex); }; } refresh { parent !? { parent.refresh } } prReshape { |item| var size, array = item.asArray; if(item.first.isSequenceableCollection.not) { ^array.bubble; }; if(superpose) { if(array.first.first.isSequenceableCollection) { ^array }; size = array.maxItem { |x| x.size }.size; // for now, just extend data: ^array.collect { |x| x.asArray.clipExtend(size) }.flop.bubble }; ^array } } + ArrayedCollection { plot { |name, bounds, discrete=false, numChannels, minval, maxval| var array, plotter; array = this.as(Array); if(array.maxDepth > 3) { "Cannot currently plot an array with more than 3 dimensions".warn; ^nil }; plotter = Plotter(name, bounds); if(discrete) { plotter.plotMode = \points }; numChannels !? { array = array.unlace(numChannels) }; array = array.collect {|elem| if (elem.isKindOf(Env)) { elem.asMultichannelSignal.flop } { elem } }; plotter.setValue( array, findSpecs: true, refresh: false ); if(minval.isNumber && maxval.isNumber) { plotter.specs = [minval, maxval].asSpec } { minval !? { plotter.minval = minval }; maxval !? { plotter.maxval = maxval }; }; plotter.refresh; ^plotter } } + Collection { plotHisto { arg steps = 100, min, max; var histo = this.histo(steps, min, max); var plotter = histo.plot; plotter.domainSpecs = [[min ?? { this.minItem }, max ?? { this.maxItem }].asSpec]; plotter.specs = [[0, histo.maxItem, \linear, 1].asSpec]; plotter.plotMode = \steps; ^plotter } } + Function { loadToFloatArray { arg duration = 0.01, server, action; var buffer, def, synth, name, numChannels, val, rate; server = server ? Server.default; if(server.serverRunning.not) { "Server not running!".warn; ^nil }; name = this.hash.asString; def = SynthDef(name, { |bufnum| var val = this.value; if(val.isValidUGenInput.not) { val.dump; Error("loadToFloatArray failed: % is no valid UGen input".format(val)).throw }; val = UGen.replaceZeroesWithSilence(val.asArray); rate = val.rate; if(rate == \audio) { // convert mixed rate outputs: val = val.collect { |x| if(x.rate != \audio) { K2A.ar(x) } { x } } }; if(val.size == 0) { numChannels = 1 } { numChannels = val.size }; RecordBuf.perform(RecordBuf.methodSelectorForRate(rate), val, bufnum, loop:0); Line.perform(Line.methodSelectorForRate(rate), dur: duration, doneAction: 2); }); Routine.run({ var c, numFrames; c = Condition.new; numFrames = duration * server.sampleRate; if(rate == \control) { numFrames = numFrames / server.options.blockSize }; buffer = Buffer.new(server, numFrames, numChannels); server.sendMsgSync(c, *buffer.allocMsg); server.sendMsgSync(c, "/d_recv", def.asBytes); synth = Synth(name, [\bufnum, buffer], server); OSCFunc({ buffer.loadToFloatArray(action: { |array, buf| action.value(array, buf); buffer.free; server.sendMsg("/d_free", name); }); }, '/n_end', server.addr, nil, [synth.nodeID]).oneShot; }); } plot { |duration = 0.01, server, bounds, minval, maxval| var name = this.asCompileString, plotter; if(name.size > 50 or: { name.includes(Char.nl) }) { name = "function plot" }; plotter = Plotter(name, bounds); server = server ? Server.default; server.waitForBoot { this.loadToFloatArray(duration, server, { |array, buf| var numChan = buf.numChannels; { plotter.setValue( array.unlace(numChan).collect(_.drop(-1)), findSpecs: true, refresh: false ); if(minval.isNumber && maxval.isNumber) { plotter.specs = [minval, maxval].asSpec } { minval !? { plotter.minval = minval }; maxval !? { plotter.maxval = maxval }; }; plotter.domainSpecs = ControlSpec(0, duration, units: "s"); plotter.refresh; }.defer }) }; ^plotter } } + Wavetable { plot { |name, bounds, minval, maxval| ^this.asSignal.plot(name, bounds, minval: minval, maxval: maxval) } } + Buffer { plot { |name, bounds, minval, maxval| var plotter; if(server.serverRunning.not) { "Server % not running".format(server).warn; ^nil }; if(numFrames.isNil) { "Buffer not allocated, can't plot data".warn; ^nil }; plotter = [0].plot( name ? "Buffer plot (bufnum: %)".format(this.bufnum), bounds, minval: minval, maxval: maxval ); this.loadToFloatArray(action: { |array, buf| { plotter.setValue( array.unlace(buf.numChannels), findSpecs: true, refresh: false ); if(minval.isNumber && maxval.isNumber) { plotter.specs = [minval, maxval].asSpec } { minval !? { plotter.minval = minval }; maxval !? { plotter.maxval = maxval }; }; plotter.domainSpecs = ControlSpec(0.0, buf.numFrames, units:"frames"); plotter.refresh; }.defer }); ^plotter } } + Env { plot { |size = 400, bounds, minval, maxval, name| var plotLabel = if (name.isNil) { "envelope plot" } { name }; var plotter = [this.asMultichannelSignal(size).flop] .plot(name, bounds, minval: minval, maxval: maxval); var duration = this.duration.asArray; var channelCount = duration.size; var totalDuration = if (channelCount == 1) { duration } { duration.maxItem ! channelCount }; plotter.domainSpecs = totalDuration.collect(ControlSpec(0, _, units: "s")); plotter.setProperties(\labelX, "time"); plotter.refresh; ^plotter } } + AbstractFunction { plotGraph { arg n=500, from = 0.0, to = 1.0, name, bounds, discrete = false, numChannels, minval, maxval, parent, labels = true; var array = Array.interpolation(n, from, to); var res = array.collect { |x| this.value(x) }; res.plot(name, bounds, discrete, numChannels, minval, maxval, parent, labels) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Control/0000775000000000000000000000000012245452763026377 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Control/GeneralHIDGUI.sc0000664000000000000000000000343712161364457031203 0ustar rootrootGeneralHIDDeviceGUI{ var specialSynthDef, 2/dbRange // linear SynthDef("freqScope0", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, numSamples, mul, add; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; numSamples = (BufSamples.ir(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048) signal = In.ar(in); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); chain = PV_MagSmear(chain, 1); // -1023 to 1023, 0 to 2046, 2 to 2048 (skip first 2 elements DC and Nyquist) phasor = LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, numSamples, numSamples + 2); phasor = phasor.round(2); // the evens are magnitude ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum); }, [\kr, \ir, \ir, \ir, \kr]).add; SynthDef("freqScope0_shm", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, numSamples, mul, add; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; numSamples = (BufSamples.ir(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048) signal = In.ar(in); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); chain = PV_MagSmear(chain, 1); // -1023 to 1023, 0 to 2046, 2 to 2048 (skip first 2 elements DC and Nyquist) phasor = LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, numSamples, numSamples + 2); phasor = phasor.round(2); // the evens are magnitude ScopeOut2.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum, fftBufSize/rate); }, [\kr, \ir, \ir, \ir, \kr]).add; // logarithmic SynthDef("freqScope1", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, halfSamples, mul, add; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; halfSamples = BufSamples.ir(fftbufnum) * 0.5; signal = In.ar(in); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); chain = PV_MagSmear(chain, 1); phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize phasor = phasor.round(2); // the evens are magnitude ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum); }, [\kr, \ir, \ir, \ir, \kr]).add; SynthDef("freqScope1_shm", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, halfSamples, mul, add; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; halfSamples = BufSamples.ir(fftbufnum) * 0.5; signal = In.ar(in); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); chain = PV_MagSmear(chain, 1); phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize phasor = phasor.round(2); // the evens are magnitude ScopeOut2.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum, fftBufSize/rate); }, [\kr, \ir, \ir, \ir, \kr]).add; // These next two are based on the original two, but adapted by Dan Stowell // to calculate the frequency response between two channels SynthDef("freqScope0_magresponse", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02, in2=1; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, numSamples, mul, add; var signal2, chain2, divisionbuf; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; numSamples = (BufSamples.ir(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048) signal = In.ar(in); signal2 = In.ar(in2); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); divisionbuf = LocalBuf(BufFrames.ir(fftbufnum)); chain2 = FFT(divisionbuf, signal2, hop: 0.75, wintype:1); // Here we perform complex division to estimate the freq response chain = PV_Div(chain2, chain); chain = PV_MagSmear(chain, 1); // -1023 to 1023, 0 to 2046, 2 to 2048 (skip first 2 elements DC and Nyquist) phasor = LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, numSamples, numSamples + 2); phasor = phasor.round(2); // the evens are magnitude ScopeOut.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum); }, [\kr, \ir, \ir, \ir, \kr, \ir]).add; SynthDef("freqScope0_magresponse_shm", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02, in2=1; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, numSamples, mul, add; var signal2, chain2, divisionbuf; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; numSamples = (BufSamples.ir(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048) signal = In.ar(in); signal2 = In.ar(in2); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); divisionbuf = LocalBuf(BufFrames.ir(fftbufnum)); chain2 = FFT(divisionbuf, signal2, hop: 0.75, wintype:1); // Here we perform complex division to estimate the freq response chain = PV_Div(chain2, chain); chain = PV_MagSmear(chain, 1); // -1023 to 1023, 0 to 2046, 2 to 2048 (skip first 2 elements DC and Nyquist) phasor = LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, numSamples, numSamples + 2); phasor = phasor.round(2); // the evens are magnitude ScopeOut2.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum, fftBufSize/rate); }, [\kr, \ir, \ir, \ir, \kr, \ir]).add; SynthDef("freqScope1_magresponse", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02, in2=1; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, halfSamples, mul, add; var signal2, chain2, divisionbuf; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; halfSamples = BufSamples.ir(fftbufnum) * 0.5; signal = In.ar(in); signal2 = In.ar(in2); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); divisionbuf = LocalBuf(BufFrames.ir(fftbufnum)); chain2 = FFT(divisionbuf, signal2, hop: 0.75, wintype:1); // Here we perform complex division to estimate the freq response chain = PV_Div(chain2, chain); chain = PV_MagSmear(chain, 1); phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize phasor = phasor.round(2); // the evens are magnitude ScopeOut.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum); }, [\kr, \ir, \ir, \ir, \kr, \ir]).add; SynthDef("freqScope1_magresponse_shm", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02, in2=1; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, halfSamples, mul, add; var signal2, chain2, divisionbuf; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; halfSamples = BufSamples.ir(fftbufnum) * 0.5; signal = In.ar(in); signal2 = In.ar(in2); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); divisionbuf = LocalBuf(BufFrames.ir(fftbufnum)); chain2 = FFT(divisionbuf, signal2, hop: 0.75, wintype:1); // Here we perform complex division to estimate the freq response chain = PV_Div(chain2, chain); chain = PV_MagSmear(chain, 1); phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize phasor = phasor.round(2); // the evens are magnitude ScopeOut2.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum, fftBufSize/rate); }, [\kr, \ir, \ir, \ir, \kr, \ir]).add; } initFreqScope { arg parent, bounds; if (this.shmScopeAvailable) { scope = \QScope2.asClass.new(parent, bounds); scope.server = server; } { scope = ScopeView(parent, bounds); }; active = false; inBus = 0; dbRange = 96; dbFactor = 2/dbRange; rate = 4; freqMode = 0; bufSize = 2048; ServerQuit.add(this, server); ^this; } allocBuffersAndStart { if (this.shmScopeAvailable) { scopebuf = ScopeBuffer.alloc(server); scope.bufnum = scopebuf.bufnum; this.start; } { Buffer.alloc(server, bufSize/4, 1, { |sbuf| scope.bufnum = sbuf.bufnum; scopebuf = sbuf; this.start; }); } } freeBuffers { if (scopebuf.notNil) { scopebuf.free; scopebuf = nil; }; } start { var defname = specialSynthDef ?? {"freqScope" ++ freqMode.asString ++ if (this.shmScopeAvailable) {"_shm"} {""}}; var args = [\in, inBus, \dbFactor, dbFactor, \rate, 4, \fftBufSize, bufSize, \scopebufnum, scopebuf.bufnum] ++ specialSynthArgs; synth = Synth.tail(RootNode(server), defname, args); if (scope.class.name === \QScope2) { scope.start }; } kill { this.active_(false); this.freeBuffers; ServerQuit.remove(this, server); } active_ { arg activate; if (activate) { ServerTree.add(this, server); if (server.serverRunning) { active=activate; this.doOnServerTree; ^this } } { ServerTree.remove(this, server); if (server.serverRunning and: active) { if (scope.class.name === \QScope2) { scope.stop }; synth.free; }; }; active=activate; ^this } doOnServerTree { if (active) { if (scopebuf.isNil) { this.allocBuffersAndStart; } { this.start; } } } doOnServerQuit { scope.stop; scopebuf = synth = nil; } inBus_ { arg num; inBus = num; if(active, { synth.set(\in, inBus); }); ^this } dbRange_ { arg db; dbRange = db; dbFactor = 2/db; if(active, { synth.set(\dbFactor, dbFactor); }); } freqMode_ { arg mode; freqMode = mode.asInteger.clip(0,1); if(active, { synth.free; this.start; }); } specialSynthArgs_ {|args| specialSynthArgs = args; if(args.notNil and:{active}){ synth.set(*specialSynthArgs); } } special { |defname, extraargs| this.specialSynthDef_(defname); this.specialSynthArgs_(extraargs); if(active, { synth.free; this.start; }); } *response{ |parent, bounds, bus1, bus2, freqMode=1| var scope = this.new(parent, bounds).inBus_(bus1.index); var synthDefName = "freqScope%_magresponse%".format(freqMode, if (scope.shmScopeAvailable) {"_shm"} {""}); ^scope.special(synthDefName, [\in2, bus2]) } doesNotUnderstand { arg selector ... args; ^scope.performList(selector, args); } shmScopeAvailable { if (GUI.id != \qt) { ^false }; ^(server.isLocal and: (server.inProcess.not)) } } PlusFreqScopeWindow { classvar 1.0, { freqLabel[i].string_( kfreq.asString.keep(4) ++ "k" ) },{ freqLabel[i].string_( (kfreq*1000).asInteger.asString) }); }); }; setDBLabelVals = { arg db; dbLabel.size.do({ arg i; dbLabel[i].string = (i * db/(dbLabel.size-1)).asInteger.neg.asString; }); }; window = Window("Freq Analyzer", rect.resizeBy(pad[0] + pad[1] + 4, pad[2] + pad[3] + 4), false); freqLabel.size.do({ arg i; freqLabel[i] = StaticText(window, Rect(pad[0] - (freqLabelDist*0.5) + (i*freqLabelDist), pad[2] - 10, freqLabelDist, 10)) .font_(font) .align_(\center) ; StaticText(window, Rect(pad[0] + (i*freqLabelDist), pad[2], 1, rect.height)) .string_("") .background_(scopeColor.alpha_(0.25)) ; }); dbLabel.size.do({ arg i; dbLabel[i] = StaticText(window, Rect(0, pad[2] + (i*dbLabelDist), pad[0], 10)) .font_(font) .align_(\left) ; StaticText(window, Rect(pad[0], dbLabel[i].bounds.top, rect.width, 1)) .string_("") .background_(scopeColor.alpha_(0.25)) ; }); scope = PlusFreqScope(window, rect.moveBy(pad[0], pad[2])); scope.xZoom_((scope.bufSize*0.25) / width); setFreqLabelVals.value(scope.freqMode, 2048); setDBLabelVals.value(scope.dbRange); Button(window, Rect(pad[0] + rect.width, pad[2], pad[1], 16)) .states_([["Power", Color.white, Color.green(0.5)], ["Power", Color.white, Color.red(0.5)]]) .action_({ arg view; if(view.value == 0, { scope.active_(true); },{ scope.active_(false); }); }) .font_(font) .canFocus_(false) ; StaticText(window, Rect(pad[0] + rect.width, pad[2]+20, pad[1], 10)) .string_("BusIn") .font_(font) ; NumberBox(window, Rect(pad[0] + rect.width, pad[2]+30, pad[1], 14)) .action_({ arg view; view.value_(view.value.asInteger.clip(0, Server.internal.options.numAudioBusChannels)); scope.inBus_(view.value); }) .value_(busNum) .font_(font) ; StaticText(window, Rect(pad[0] + rect.width, pad[2]+48, pad[1], 10)) .string_("FrqScl") .font_(font) ; PopUpMenu(window, Rect(pad[0] + rect.width, pad[2]+58, pad[1], 16)) .items_(["lin", "log"]) .action_({ arg view; scope.freqMode_(view.value); setFreqLabelVals.value(scope.freqMode, 2048); }) .canFocus_(false) .font_(font) .valueAction_(1) ; StaticText(window, Rect(pad[0] + rect.width, pad[2]+76, pad[1], 10)) .string_("dbCut") .font_(font) ; PopUpMenu(window, Rect(pad[0] + rect.width, pad[2]+86, pad[1], 16)) .items_(Array.series(12, 12, 12).collect({ arg item; item.asString })) .action_({ arg view; scope.dbRange_((view.value + 1) * 12); setDBLabelVals.value(scope.dbRange); }) .canFocus_(false) .font_(font) .value_(7) ; scope .inBus_(busNum) .active_(true) .background_(bgColor) .style_(1) .waveColors_([scopeColor.alpha_(1)]) .canFocus_(false) ; window.onClose_({ scope.kill; scopeOpen = false; }).front; ^super.newCopyArgs(scope, window) }); } *server { ^PlusFreqScope.server } *server_ {|aServer| ^PlusFreqScope.server_(aServer) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Control/UGen-scope.sc0000664000000000000000000000315012014636263030663 0ustar rootroot+ UGen { scope { arg name = "UGen Scope", bufsize = 4096, zoom = 1.0; var gui, server; gui = GUI.current; server = gui.stethoscope.defaultServer; ^SynthDef.wrap({ var bus, numChannels, rate, scope; numChannels = this.numChannels; rate = this.rate; bus = Bus.perform(rate, server, numChannels); switch(rate, \audio, {Out.ar(bus.index, this)}, \control, {Out.kr(bus.index, this)} ); { scope = gui.stethoscope.new( server, numChannels, bus.index, bufsize, zoom, rate ); scope.window.name_(name.asString).bounds_( gui.stethoscope.tileBounds); gui.stethoscope.ugenScopes.add(scope); scope.window.onClose = { scope.free; bus.free; gui.stethoscope.ugenScopes.remove(scope) }; CmdPeriod.doOnce({ {scope.window.close}.defer }); }.defer(0.001); this; }) } } + Array { scope { arg name = "UGen Scope", bufsize = 4096, zoom = 1.0; var gui, server; gui = GUI.current; server = gui.stethoscope.defaultServer; ^SynthDef.wrap({ var bus, numChannels, rate, scope; numChannels = this.numChannels; rate = this.rate; bus = Bus.perform(rate, server, numChannels); switch(rate, \audio, {Out.ar(bus.index, this)}, \control, {Out.kr(bus.index, this)} ); { scope = gui.stethoscope.new( server, numChannels, bus.index, bufsize, zoom, rate ); scope.window.name_(name.asString).bounds_( gui.stethoscope.tileBounds); gui.stethoscope.ugenScopes.add(scope); scope.window.onClose = { scope.free; bus.free; gui.stethoscope.ugenScopes.remove(scope) }; CmdPeriod.doOnce({ {scope.window.close}.defer }); }.defer(0.001); this; }) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Control/scopeResponse.sc0000664000000000000000000000465412245365552031566 0ustar rootroot/* Server.default = s = Server.internal.boot; {|in| MoogFF.ar(in, freq: LFCub.kr(0.2).exprange(10, 10000))}.scopeResponse {|in| MoogFF.ar(in)}.scopeResponse LPF.scopeResponse HPF.scopeResponse MoogFF.scopeResponse BLowPass.scopeResponse BBandPass.scopeResponse BLowShelf.scopeResponse // by default BLowShelf doesn't mangle much Resonz.scopeResponse BRF.scopeResponse Integrator.scopeResponse Formlet.scopeResponse Median.scopeResponse // nonlinear, and therefore interesting Slew.scopeResponse */ + Function { scopeResponse{ |server, freqMode=1, label="Empirical Frequency response", mute = false| var bus1, bus2, synth, win, fs; if (server.isNil) { server = GUI.freqScopeView.server; } { if (server != GUI.freqScopeView.server) { "Function-scopeReponse: resetting GUI.freqScopeView.server".warn; GUI.freqScopeView.server = server; }; }; // Create two private busses bus1 = Bus.audio(server, 1); bus2 = Bus.audio(server, 1); // Create the SCFreqScope.response using the same simple window as in the helpfile // Also, onClose must free the synth and the busses win = GUI.window.new(label, Rect(100, 100, 511, 300)); fs = GUI.freqScopeView.response(win, win.view.bounds, bus1, bus2, freqMode); win.onClose_ { fs.kill; synth.release; }; win.front; fs.active_(true); // Create a synth using this function and the busses synth = { |gate = 1| var noise = PinkNoise.ar; var filtered = this.value(noise); var env = EnvGen.kr(Env.asr(0.1, 1, 0.1, \sine), gate, 0.1, doneAction: 2); if (not(mute)) { Out.ar(0, (filtered * env) ! 2); // filter only }; Out.ar(bus1, noise); Out.ar(bus2, filtered); }.play(server.defaultGroup); synth.register; synth.onFree { { [bus1, bus2].do(_.free); fs.active_(false); win.close; }.defer; } ^fs } } + Filter { *scopeResponse { |server, freqMode=1, label, args| var argNames = this.class.findRespondingMethodFor(\ar).argNames; var hasFreqInput = argNames.includes(\freq); ^if(hasFreqInput){ {|in| this.ar(in: in, freq:MouseX.kr(10, SampleRate.ir / 4, 1)) * Line.ar(0,1,0.1) } .scopeResponse(server, freqMode, label ?? {"%: empirical frequency response (move mouse to change freq)".format(this.asString)} ) }{ // no freq input {|in| this.ar(in: in) * Line.ar(0,1,0.1) } .scopeResponse(server, freqMode, label ?? {"%: empirical frequency response".format(this.asString)} ) } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Control/server-scope.sc0000664000000000000000000000355212161364457031347 0ustar rootroot+ Server { scope { arg numChannels, index = 0, bufsize = 4096, zoom = (1), rate = \audio; numChannels = numChannels ?? { if (index == 0) { options.numOutputBusChannels } { 2 } }; if(scopeWindow.isNil) { scopeWindow = Stethoscope(this, numChannels, index, bufsize, zoom, rate, nil, this.options.numBuffers); // prevent buffer conflicts by using reserved bufnum scopeWindow.window.onClose = scopeWindow.window.onClose.addFunc({ scopeWindow = nil }); ServerTree.add(this, this); } { scopeWindow.setProperties(numChannels, index, bufsize, zoom, rate); scopeWindow.run; scopeWindow.window.front; }; ^scopeWindow } freqscope { GUI.current.freqScopeView.tryPerform('server_', this); // FIXME: Can not change server in SwingOSC GUI. ^GUI.freqScope.new; } } + Bus { scope { arg bufsize = 4096, zoom; ^server.scope(numChannels, index, bufsize, zoom, rate); } } + Function { scope { arg numChannels, outbus = 0, fadeTime = 0.05, bufsize = 4096, zoom; var synth, synthDef, bytes, synthMsg, outUGen, server; server = GUI.stethoscope.defaultServer; if(server.serverRunning.not) { (server.name.asString ++ " server not running!").postln; ^nil }; synthDef = this.asSynthDef(name: SystemSynthDefs.generateTempName, fadeTime:fadeTime); outUGen = synthDef.children.detect { |ugen| ugen.class === Out }; numChannels = numChannels ?? { if(outUGen.notNil) { (outUGen.inputs.size - 1) } { 1 } }; synth = Synth.basicNew(synthDef.name, server); bytes = synthDef.asBytes; synthMsg = synth.newMsg(server, [\i_out, outbus, \out, outbus], \addToHead); server.sendMsg("/d_recv", bytes, synthMsg); server.scope(numChannels, outbus, bufsize, zoom, outUGen.rate); ^synth } freqscope { var server = if (GUI.id === \swing) { GUI.freqScopeView.audioServer } { GUI.freqScopeView.server }; this.play(server); ^GUI.freqScope.new } } ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Control/SynthDescLibPlusGUI.scSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Control/SynthDescLibPlusGU0000664000000000000000000001221112014636263031743 0ustar rootroot+ SynthDescLib { browse { var w; var synthDescLib; var synthDescLibListView; var synthDescListView; var ugensListView; var controlsListView; var inputsListView; var outputsListView; var synthDescList; var hvBold12; var updateSynthDefs; var updateSynthDefData; var btn, testFn; var fntMono, gui; gui = GUI.current; hvBold12 = Font.sansSerif( 12 ).boldVariant; fntMono = Font.monospace( 10 ); w = gui.window.new("SynthDef browser", Rect(128, (gui.window.screenBounds.height - 638).clip(0, 320), 700, 608)); w.view.decorator = FlowLayout(w.view.bounds); w.view.decorator.shift(220); testFn = { var synth, item; item = this[synthDescListView.item.asSymbol]; if (item.notNil) { synth = Synth(item.name); synth.postln; synth.play; SystemClock.sched(3, { if (item.hasGate) { synth.release } { synth.free }; }); }; }; btn = gui.button.new(w, 48 @ 20); btn.states = [["test"]]; btn.action = testFn; btn = gui.button.new(w, 48 @ 20); btn.states = [["window"]]; btn.action = { var item; item = this[synthDescListView.item.asSymbol]; if (item.notNil) { GUI.use( gui, { item.makeWindow }); } }; w.view.decorator.nextLine; gui.staticText.new(w, Rect(0,0,220,24)).string_("SynthDescLibs").font_(hvBold12); gui.staticText.new(w, Rect(0,0,220,24)).string_("SynthDefs").font_(hvBold12); gui.staticText.new(w, Rect(0,0,220,24)).string_("UGens").font_(hvBold12); w.view.decorator.nextLine; synthDescLibListView = gui.listView.new(w, Rect(0,0, 220, 320)).focus; synthDescListView = gui.listView.new(w, Rect(0,0, 220, 320)); synthDescListView.beginDragAction_({arg v; v.items[v.value].asSymbol; }); ugensListView = gui.listView.new(w, Rect(0,0, 220, 320)); w.view.decorator.nextLine; gui.staticText.new(w, Rect(0,0,240,24)).string_("SynthDef Controls") .font_(hvBold12).align_(\center); gui.staticText.new(w, Rect(0,0,200,24)).string_("SynthDef Inputs") .font_(hvBold12).align_(\center); gui.staticText.new(w, Rect(0,0,200,24)).string_("SynthDef Outputs") .font_(hvBold12).align_(\center); w.view.decorator.nextLine; controlsListView = gui.listView.new(w, Rect(0,0, 240, 160)); inputsListView = gui.listView.new(w, Rect(0,0, 200, 160)); outputsListView = gui.listView.new(w, Rect(0,0, 200, 160)); controlsListView.resize = 4; inputsListView.resize = 4; outputsListView.resize = 4; if (GUI.id == \qt) { [controlsListView, inputsListView, outputsListView].do { |listview| listview.selectionMode = \none }; } { // this is a trick to not show hilighting. controlsListView.hiliteColor = Color.clear; inputsListView.hiliteColor = Color.clear; outputsListView.hiliteColor = Color.clear; controlsListView.selectedStringColor = Color.black; inputsListView.selectedStringColor = Color.black; outputsListView.selectedStringColor = Color.black; }; controlsListView.font = fntMono; inputsListView.font = fntMono; outputsListView.font = fntMono; w.view.decorator.nextLine; synthDescLibListView.items_(SynthDescLib.all.keys.asArray.sort) .value_(synthDescLibListView.items.indexOf(name) ? 0); synthDescLibListView.action = { synthDescListView.value = 0; updateSynthDefs.value; }; synthDescListView.items = []; synthDescListView.action = { updateSynthDefData.value; }; synthDescListView.enterKeyAction = testFn; updateSynthDefs = { var libName; libName = synthDescLibListView.item; synthDescLib = SynthDescLib.all[libName]; synthDescList = synthDescLib.synthDescs.values.sort {|a,b| a.name <= b.name }; synthDescListView.items = synthDescList.collect {|desc| desc.name.asString }; updateSynthDefData.value; }; updateSynthDefData = { var synthDesc; synthDesc = synthDescList[synthDescListView.value]; if (synthDesc.isNil) { ugensListView.items = []; inputsListView.items = []; outputsListView.items = []; controlsListView.items = []; }{ ugensListView.items = synthDesc.def.children.collect { |x, i| i.asString.copy.extend(7, $ ) ++ x.class.name.asString; }; inputsListView.items = synthDesc.inputs.collect { |x| var string; string = x.rate.asString.copy; string = string.extend(9, $ ) ++ " " ++ x.startingChannel; string = string.extend(19, $ ) ++ " " ++ x.numberOfChannels; }; outputsListView.items = synthDesc.outputs.collect { |x| var string; string = x.rate.asString.copy; string = string.extend(9, $ ) ++ " " ++ x.startingChannel; string = string.extend(19, $ ) ++ " " ++ x.numberOfChannels; }; controlsListView.items = synthDesc.controls.reject {|a| a.name == '?' }.collect { |x| var string; string = if (x.name.notNil) { x.name.asString.copy; }{ "" }; if (x.rate.notNil) { string = string.extend(12, $ ) ++ " " ++ x.rate; }; if (x.defaultValue.notNil) { if (x.defaultValue.isArray) { string = string.extend(22, $ ) ++ " " ++ x.defaultValue.collect(_.asStringPrec(6)); } { string = string.extend(22, $ ) ++ " " ++ x.defaultValue.asStringPrec(6); } }; }; }; }; updateSynthDefs.value; w.front; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Control/server-meter.sc0000664000000000000000000000026112014636263031336 0ustar rootroot+ Server { meter { var clzz; ^if( GUI.id == \swing and: { \JSCPeakMeter.asClass.notNil }, { \JSCPeakMeter.asClass.meterServer( this ); }, { ServerMeter(this) }); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Control/ServerPlusGUI.sc0000664000000000000000000003162312245365552031411 0ustar rootroot+ Server { // splitting makeWindow and makeGui, makes sure that makeWindow can be overridden // while maintaining the availability of the GUI server window makeWindow { arg w; if (Platform.makeServerWindowAction.notNil) { ^Platform.makeServerWindowAction.value(this, w) } { ^this.makeGui( w ); } } calculateViewBounds { var width = 288, height = 98, taskBarHeight = 27; // the latter should be in SCWindow var keys = set.asArray.collect(_.name).sort; ^Rect(5, keys.indexOf(name) * (height + taskBarHeight) + 5, width, height) } makeGui { arg w; var active, booter, killer, makeDefault, running, booting, stopped, bundling, showDefault; var startDump, stopDump, blockAliveThread, dumping = false; var recorder, scoper; var countsViews, ctlr; var label, gui, font, volumeNum; var buttonColor, faintGreen, faintRed; if (window.notNil) { ^window.front }; gui = GUI.current; font = Font.sansSerif(10); if (gui.id == \qt) { buttonColor = gui.palette.button; faintGreen = buttonColor.blend(Color.green, 0.2); faintRed = buttonColor.blend(Color.red, 0.25); } { faintGreen = Color.green.alpha_(0.2); faintRed = Color.red.alpha_(0.3) }; if(w.isNil) { label = name.asString + "server"; w = window = gui.window.new(label, this.calculateViewBounds, resizable: false); w.view.decorator = FlowLayout(w.view.bounds); } { label = w.name }; if(isLocal) { booter = gui.button.new(w, Rect(0,0, 44, 18)); booter.canFocus = false; booter.font = font; booter.states = [["Boot"], ["Quit", nil, faintGreen]]; booter.action = { arg view; if(view.value == 1, { booting.value; this.boot; }); if(view.value == 0,{ this.quit; }); }; booter.setProperty(\value,serverRunning.binaryValue); killer = gui.button.new(w, Rect(0,0, 20, 18)); killer.states = [["K"]]; killer.font = font; killer.canFocus = false; killer.action = { Server.killAll; stopped.value; }; }; active = gui.staticText.new(w, Rect(0,0, 78, 18)); active.string = this.name.asString; active.align = \center; active.font = Font.sansSerif( 12 ).boldVariant; if(serverRunning,running,stopped); makeDefault = gui.button.new(w, Rect(0,0, 54, 18)); makeDefault.font = font; makeDefault.canFocus = false; makeDefault.states = [["-> default"], ["-> default", nil, faintGreen]]; makeDefault.value_((this == Server.default).binaryValue); makeDefault.action = { Server.default_(this) }; //w.view.decorator.nextLine; if(isLocal){ recorder = gui.button.new(w, Rect(0,0, 66, 18)); recorder.font = font; recorder.states = [ ["record >"], ["stop []", nil, faintGreen] ]; recorder.action = { if (recorder.value == 1) { this.record } { this.stopRecording }; }; recorder.enabled = false; }; w.view.keyDownAction = { arg view, char, modifiers; // if any modifiers except shift key are pressed, skip action if(modifiers & 16515072 == 0) { case {char === $n } { this.queryAllNodes(false) } {char === $N } { this.queryAllNodes(true) } {char === $l } { this.tryPerform(\meter) } {char === $p} { if(serverRunning) { this.plotTree } } {char === $ } { if(serverRunning.not) { this.boot } } {char === $s } { if( (this.isLocal and: (GUI.id == \qt)) or: ( this.inProcess )) {this.scope(options.numOutputBusChannels)} {warn("Scope not supported")} } {char === $f } { if( (this.isLocal and: (GUI.id == \qt)) or: ( this.inProcess )) {this.freqscope} {warn("FreqScope not supported")} } {char == $d } { if(this.isLocal or: { this.inProcess }) { if(dumping, stopDump, startDump) } { "cannot dump a remote server's messages".inform } } {char === $m } { if(this.volume.isMuted) { this.unmute } { this.mute } } {char === $0 and: {volumeNum.hasFocus.not}} { this.volume = 0.0; }; }; }; if (isLocal) { running = { active.stringColor_(Color.new255(74, 120, 74)); active.string = "running"; booter.setProperty(\value,1); recorder.enabled = true; }; stopped = { active.stringColor_(Color.grey(0.3)); active.string = "inactive"; stopDump.value; booter.setProperty(\value,0); recorder.setProperty(\value,0); recorder.enabled = false; countsViews.do(_.string = ""); }; booting = { active.stringColor_(Color.new255(255, 140, 0)); active.string = "booting"; //booter.setProperty(\value,0); }; bundling = { active.stringColor_(Color.new255(237, 157, 196)); booter.setProperty(\value,1); recorder.enabled = false; }; blockAliveThread = { SystemClock.sched(0.2, { this.stopAliveThread }); }; startDump = { this.dumpOSC(1); this.stopAliveThread; dumping = true; w.name = "dumping osc: " ++ name.asString; CmdPeriod.add(blockAliveThread); }; stopDump = { this.dumpOSC(0); if(serverRunning) { this.startAliveThread }; dumping = false; w.name = label; CmdPeriod.remove(blockAliveThread); }; w.onClose = { window = nil; ctlr.remove; }; } { running = { active.stringColor_(Color.new255(74, 120, 74)); active.string = "running"; active.background = Color.clear; }; stopped = { active.stringColor_(Color.grey(0.5)); active.string = "inactive"; }; booting = { active.stringColor_(Color.new255(255, 140, 0)); active.string = "booting"; }; bundling = { active.stringColor = Color.new255(237, 157, 196); active.background = Color.red(0.5); booter.setProperty(\value,1); }; w.onClose = { // but do not remove other responders this.stopAliveThread; window = nil; ctlr.remove; }; }; showDefault = { makeDefault.value = (Server.default == this).binaryValue; }; if(serverRunning,running,stopped); w.view.decorator.nextLine; countsViews = #[ "Avg CPU:", "Peak CPU:", "UGens:", "Synths:", "Groups:", "SynthDefs:" ].collect { arg name, i; var label,numView, pctView; label = gui.staticText.new(w, Rect(0,0, 80, 12)); label.string = name; label.font = font; label.align = \right; if (i < 2, { numView = gui.staticText.new(w, Rect(0,0, 34, 12)); numView.font = font; numView.align = \left; pctView = gui.staticText.new(w, Rect(0,0, 12, 12)); pctView.string = "%"; pctView.font = font; pctView.align = \left; },{ numView = gui.staticText.new(w, Rect(0,0, 50, 12)); numView.font = font; numView.align = \left; }); numView }; if(isLocal or: { options.remoteControlVolume }) { { var volSpec, cpVol; var volumeSlider, muteButton, muteActions, volController; muteActions = [{this.unmute}, {this.mute}]; volSpec = [volume.min, volume.max, \db].asSpec; gui.staticText.new(w, Rect(0,0, 44, 18)) .font_(font) .string_("volume:"); muteButton = gui.button.new(w, Rect(0, 0, 20, 18)) .font_(font) .canFocus_(false) .states_([ ["M"], ["M", nil, faintRed] ]) .action_({arg me; this.serverRunning.if({ muteActions[me.value].value; }, { "The server must be booted to mute it".warn; me.value_(0); }) }); volumeNum = gui.numberBox.new(w, Rect(0, 0, 28, 18)) .font_(font) .value_(0.0) .align_(\center) .action_({arg me; var newdb; newdb = me.value.clip(-90, 6); this.volume_(newdb); volumeSlider.value_(volSpec.unmap(newdb)); }); volumeSlider = gui.slider.new(w, Rect(0, 0, 172, 18)) .value_(volSpec.unmap(0)) .onClose_{volController.remove} .action_({arg me; var newdb; newdb = volSpec.map(me.value).round(0.1); this.volume_(newdb); volumeNum.value_(newdb); }) .keyDownAction_({arg slider, char, modifiers, unicode, keycode; if (char == $], { slider.increment; }); if (char == $[, { slider.decrement; }); if (unicode == 16rF700, { slider.increment; }); if (unicode == 16rF703, { slider.increment; }); if (unicode == 16rF701, { slider.decrement; }); if (unicode == 16rF702, { slider.decrement; }); nil; }) ; volController = SimpleController(volume) .put(\amp, {|changer, what, vol| { volumeNum.value_(vol.round(0.01)); volumeSlider.value_(volSpec.unmap(vol)); }.defer }) .put(\mute, {|changer, what, flag| { muteButton.value_(flag.binaryValue); }.defer }) .put(\ampRange, {|changer, what, min, max| volSpec = [min, max, \db].asSpec; volumeSlider.value_(volSpec.unmap(volume.volume)); }) }.value; }; w.front; ctlr = SimpleController(this) .put(\serverRunning, { if(serverRunning,running,stopped) }) .put(\counts,{ countsViews.at(0).string = avgCPU.round(0.1); countsViews.at(1).string = peakCPU.round(0.1); countsViews.at(2).string = numUGens; countsViews.at(3).string = numSynths; countsViews.at(4).string = numGroups; countsViews.at(5).string = numSynthDefs; }) .put(\bundling, bundling) .put(\default, showDefault); if(isLocal){ ctlr.put(\cmdPeriod,{ recorder.setProperty(\value,0); }) }; this.startAliveThread; } plotTree {|interval=0.5| var resp, done = false; var collectChildren, levels, countSize; var window, view, bounds; var updater, updateFunc; var tabSize = 25; var pen, font; pen = GUI.current.pen; font = Font.sansSerif(10); window = Window.new(name.asString + "Node Tree", Rect(128, 64, 400, 400), scroll:true ).front; window.view.hasHorizontalScroller_(false).background_(Color.grey(0.9)); view = UserView.new(window, Rect(0,0,400,400)); view.drawFunc = { var xtabs = 0, ytabs = 0, drawFunc; drawFunc = {|group| var thisSize, rect, endYTabs; xtabs = xtabs + 1; ytabs = ytabs + 1; pen.font = font; group.do({|node| if(node.value.isArray, { thisSize = countSize.value(node); endYTabs = ytabs + thisSize + 0.2; rect = Rect(xtabs * tabSize + 0.5, ytabs * tabSize + 0.5, window.view.bounds.width - (xtabs * tabSize * 2), thisSize * tabSize; ); pen.fillColor = Color.grey(0.8); pen.fillRect(rect); pen.strokeRect(rect); pen.color = Color.black; pen.stringInRect( " Group" + node.key.asString + (node.key == 1).if("- default group", ""), rect ); drawFunc.value(node.value); ytabs = endYTabs; },{ rect = Rect(xtabs * tabSize + 0.5, ytabs * tabSize + 0.5, 7 * tabSize, 0.8 * tabSize ); pen.fillColor = Color.white; pen.fillRect(rect); pen.strokeRect(rect); pen.color = Color.black; pen.stringInRect( " " ++ node.key.asString + node.value.asString, rect ); ytabs = ytabs + 1; }); }); xtabs = xtabs - 1; }; drawFunc.value(levels); }; // msg[1] controls included // msg[2] nodeID of queried group // initial number of children resp = OSCFunc({ arg msg; var finalEvent; var i = 2, j, controls, printControls = false, dumpFunc; if(msg[1] != 0, {printControls = true}); dumpFunc = {|numChildren| var event, children; event = ().group; event.id = msg[i]; event.instrument = nil; // need to know it's a group i = i + 2; children = Array.fill(numChildren, { var id, child; // i = id // i + 1 = numChildren // i + 2 = def (if synth) id = msg[i]; if(msg[i+1] >=0, { child = dumpFunc.value(msg[i+1]); }, { j = 4; child = ().synth.instrument_(msg[i+2]); if(printControls, { controls = (); msg[i+3].do({ controls[msg[i + j]] = msg[i + j + 1]; j = j + 2; }); child.controls = controls; i = i + 4 + (2 * controls.size); }, {i = i + 3 }); }); child.id = id; }); event.children = children; event; }; finalEvent = dumpFunc.value(msg[3]); done = true; collectChildren = {|group| group.children.collect({|child| if(child.children.notNil,{ child.id -> collectChildren.value(child); }, { child.id -> child.instrument; }); }); }; levels = collectChildren.value(finalEvent); countSize = {|array| var size = 0; array.do({|elem| if(elem.value.isArray, { size = size + countSize.value(elem.value) + 2}, {size = size + 1;}); }); size }; defer { view.bounds = Rect(0, 0, 400, max(400, tabSize * (countSize.value(levels) + 2))); view.refresh; } }, '/g_queryTree.reply', addr).fix; updateFunc = { fork { loop { this.sendMsg("/g_queryTree", 0, 0); interval.wait; } } }; updater = updateFunc.value; CmdPeriod.add(updateFunc); window.onClose = { updater.stop; CmdPeriod.remove(updateFunc); resp.free; }; SystemClock.sched(3, { if(done.not, { defer {window.close}; "Server failed to respond to Group:queryTree!".warn; }); }); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Control/WiiMoteGUI.sc0000664000000000000000000001224112014636263030641 0ustar rootroot/* class to display wiimote data as a gui */ WiiMoteGUI { classvar <>xposScreen=0, <>yposScreen=20; classvar w, <>wiimote, 700, { yposScreen = 20; xposScreen = xposScreen + xsize + 10; if ( xposScreen > 900, { xposScreen = 0; }); }); GUI.staticText.new(w, Rect(0, 0, xsize - 2, 20)).string_("WiiMote" + wiimote.id + wiimote.address ) .align_(0); //.background_(labelColor); rmview = GUI.compositeView.new( w, Rect( 5, 30, 205, 130 )); rm = WiiRemoteGUI.new( rmview, wiimote, 0 ); //30 ); ncview = GUI.compositeView.new( w, Rect( 5, 160, 205, 105 )); nc = WiiNunchukGUI.new( ncview, wiimote, 0 ); // 160 ); watcher = SkipJack.new( { this.updateVals }, 0.1, { w.isClosed }, (\wiimote_gui_ ++ counter)); watcher.start; } updateVals { { rm.updateVals; if ( wiimote.ext_type == 1, { nc.updateVals; }); // cl.updateVals; }.defer; } hide{ if ( GUI.scheme.id == \swing, { w.visible_( false ); },{ w.close; }); watcher.stop; } show{ if ( GUI.scheme.id == \swing, { w.visible_( true ); }); watcher.start; } } WiiRemoteGUI{ var <>wiimote; var <>w; var " ).background_(onColor).align_( 0 ); xpos = xpos + 25; sliders = wiimote.remote_motion.collect{ |it,i| xpos = xpos + 25; GUI.slider.new( w, Rect( xpos-25, ypos, 20, 70 ) ); }; sliders = sliders.add( GUI.slider.new( w, Rect( xpos, ypos, 20, 70 ) ) ); ypos = ypos + 75; xpos = 5; led = wiimote.remote_led.collect{ |it,i| xpos = xpos + 25; GUI.button.new( w, Rect( xpos-25, ypos, 20, 20 ) ) .states_( [ [ "X", Color.black, Color.yellow ],["O", Color.yellow, Color.black ] ] ) .action_( { |but| wiimote.setLEDState( i, but.value ) } ); }; rumble = GUI.button.new( w, Rect( xpos, ypos, 70, 20 ) ) .states_( [ [ "rumble", Color.black, Color.yellow ],["RUMBLING", Color.yellow, Color.black ] ] ) .action_( { |but| wiimote.rumble( but.value ) } ); } updateVals{ led.do{ |it,i| it.value = wiimote.remote_led[i] }; //rumble.value = wiimote.rumble; wiimote.remote_motion.do{ |it,i| sliders[i].value = it }; //sliders[3].value = wiimote.remote_motion[3]/3; sliders[4].value = wiimote.battery; wiimote.remote_buttons.do{ |it,i| if ( it == 1 , { buttons[i].background = onColor; },{ buttons[i].background = offColor; }); }; } } WiiNunchukGUI{ var <>wiimote; var <>w; var docTitle = "History repeats", <>docHeight=120; var stickMode=0; var 0); if (filtering) { this.filterLines }; history.hasMovedOn = true; }); keyPop = PopUpMenu(w, Rect(0, 0, 40, 20)) .items_([\all] ++ history.keys).value_(0) .action_({ |pop| this.setKeyFilter(pop.items[pop.value]) }); filTextV = TextView(w, Rect(0,0, 88, 20)).string_("") .enterInterpretsSelection_(false) .resize_(2) .keyDownAction_({ |txvw, char, mod, uni, keycode| this.setStrFilter(txvw.string); if (this.filtering) { this.filterLines; } }); topBut = Button(w, Rect(0, 0, 32, 20)) .states_([["top"], ["keep"]]).value_(0) .resize_(3) .canFocus_(false) .action_({ |but| this.stickMode_(but.value) }); Button(w, Rect(0, 0, 32, 20)) //// .states_([["rip"]]) .resize_(3) .canFocus_(false) .action_({ |btn| this.rip(textV.string) }); Button(w, Rect(0,0, 16, 20)) .states_([["v"], ["^"]]) .resize_(3) .action_ { |btn| var views = w.view.children; var resizes = [ [2, 1, 1, 1, 2, 3, 3, 3, 5], [5, 7, 7, 7, 8, 9, 9, 9, 8] ][btn.value.asInteger]; views.do { |v, i| v.resize_(resizes[i]) }; }; listV = ListView(w, bounds.copy.insetBy(2).height_(230)) .font_(font) .items_([]) .resize_(5) .background_(Color.grey(0.62)) .action_({ |lview| var index = lview.value; if (lview.items.isEmpty) { "no entries yet.".postln; } { lastLineSelected = listV.items[index]; if (filtering.not) { this.postInlined(index) } { this.postInlined(filteredIndices[index]) } } }) .enterKeyAction_({ |lview| var index = lview.value; if (filtering) { index = filteredIndices[index] }; try { history.lines[index][2].postln.interpret.postln; // "did execute.".postln; } { "execute line from history failed.".postln; }; }); history.hasMovedOn = true; SkipJack({ var newIndex, selectedLine, linesToShow, keys; var newStr = filTextV.string; if (filTextV.hasFocus and: (newStr != filters[1])) { this.setStrFilter(newStr); }; // clumsy, but filTextV has no usable action... if (history.hasMovedOn) { startBut.enabled_(history.isCurrent); startBut.value_(History.started.binaryValue).refresh; filtBut.value_(filtering.binaryValue).refresh; if (filTextV.hasFocus.not) { filTextV.string_(filters[1]) }; keys = [\all] ++ history.keys.asArray.sort; keyPop.items_(keys); keyPop.value_(keys.indexOf(filters[0]) ? 0); if (stickMode == 1) { // remember old selection selectedLine = (lastLinesShown ? [])[listV.value]; } { }; linesToShow = if (filtering.not) { history.lineShorts.array.copy } { this.filterLines; filteredShorts; } ? []; if (linesToShow != lastLinesShown) { // "or updating listview here?".postln; listV.items_(linesToShow); lastLinesShown = linesToShow; }; newIndex = if (selectedLine.isNil) { 0 } { linesToShow.indexOf(selectedLine) }; listV.value_(newIndex ? 0); if(stickMode == 0) { listV.action.value(listV) }; history.hasMovedOn = false; }; }, 1, { w.isClosed }, "histwin"); } setKeyFilter { |key| filters.put(0, key); this.filterLines; } setStrFilter { |str| filters.put(1, str); this.filterLines; } filtering_ { |flag=true| filtering = flag; history.hasMovedOn_(true); } filterOn { this.filtering_(true) } filterOff { this.filtering_(false) } filterLines { filteredIndices = history.indicesFor(*filters); filteredShorts = history.lineShorts[filteredIndices]; defer { keyPop.value_(keyPop.items.indexOf(filters[0] ? 0)); filTextV.string_(filters[1]); }; if (filtering) { history.hasMovedOn = true; }; } postInlined { |index| var line; if (history.lines.isNil) { "no history lines yet.".postln; ^this }; line = history.lines[index]; if (line.isNil) { "history: no line found!".inform; ^this }; textV.string_(line[2]); } postDoc { |index| var line; if (history.lines.isNil) { "no history lines yet.".postln; ^this }; line = history.lines[index]; if (line.isNil) { "history: no line found!".inform; ^this }; this.findDoc; doc.string_(line[2]).front; try { this.alignDoc }; w.front; } alignDoc { var docbounds, winbounds; docbounds = doc.bounds; winbounds = w.bounds; doc.bounds_( Rect( winbounds.left, winbounds.top + winbounds.height + 24, winbounds.width, docHeight ) ) } rip { this.findDoc; doc.view.children.first.string_(textV.string); doc.front; } findDoc { if (docFlag == \newDoc) { oldDocs = oldDocs.add(doc) }; if (docFlag == \newDoc or: doc.isNil or: { Window.allWindows.includes(doc).not }) { doc = Window(docTitle, Rect(300, 500, 300, 100)); doc.addFlowLayout; TextView(doc, doc.bounds.resizeBy(-8, -8)).resize_(5); }; oldDocs = oldDocs.select {|d| d.notNil and: { d.dataptr.notNil } }; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Core/ClassBrowser.sc0000664000000000000000000005316212161364457030615 0ustar rootroot// A thorough refactoring of JMc's original class browser // Previously a state was a Class or an array representing a search result // Now it's an Environment holding more info // James Harkins ClassBrowser { classvar updateProtos, searchMenuKeys, viewList, buttonSet, gray; var 0) { historyPos = historyPos - 1; this.restoreHistory; } }; ~fwdButton = gui.button.new(~window, Rect(0,0, 24, 24)); ~fwdButton.states = [[">"]]; ~fwdButton.action = { if (historyPos < (history.size - 1)) { historyPos = historyPos + 1; this.restoreHistory; } }; ~superButton = gui.button.new(~window, Rect(0,0, 50, 24)); ~superButton.states = [["super"]]; ~superButton.action = { if(currentState.currentClass.notNil) { this.makeState( currentState.currentClass.superclass ); } }; ~metaButton = gui.button.new(~window, Rect(0,0, 50, 24)); ~metaButton.states = [["meta"]]; ~metaButton.action = { if(currentState.currentClass.notNil) { this.makeState( currentState.currentClass.class ); }; }; ~helpButton = gui.button.new(~window, Rect(0,0, 50, 24)); ~helpButton.states = [["help"]]; ~helpButton.action = { if(currentState.currentClass.notNil) { currentState.currentClass.help; } }; ~classSourceButton = gui.button.new(~window, Rect(0,0, 90, 24)); ~classSourceButton.states = [["class source"]]; ~classSourceButton.action = { if(currentState.currentClass.notNil) { currentState.currentClass.openCodeFile; } }; ~methodSourceButton = gui.button.new(~window, Rect(0,0, 90, 24)); ~methodSourceButton.states = [["method source"]]; ~methodSourceButton.action = { if(currentState.currentMethod.notNil) { currentState.currentMethod.openCodeFile; }; }; ~implementationButton = gui.button.new(~window, Rect(0,0, 100, 24)); ~implementationButton.states = [["implementations"]]; ~implementationButton.action = { if(currentState.currentMethod.notNil) { thisProcess.interpreter.cmdLine = currentState.currentMethod.name.asString; thisProcess.methodTemplates; }; }; ~refsButton = gui.button.new(~window, Rect(0,0, 70, 24)); ~refsButton.states = [["references"]]; ~refsButton.action = { if(currentState.currentMethod.notNil) { thisProcess.interpreter.cmdLine = currentState.currentMethod.name.asString; thisProcess.methodReferences; }; }; ~window.view.decorator.nextLine; GUI.staticText.new(~window, Rect(0, 0, 65, 20)).string_("Search for"); ~searchField = GUI.textField.new(~window, Rect(0, 0, 235, 20)) .action_({ this.searchClasses(views.searchField.string, views.searchMenu.value, views.matchCaseButton.value); }); GUI.staticText.new(~window, Rect(0, 0, 15, 20)).string_("in").align_(\center); ~searchMenu = GUI.popUpMenu.new(~window, Rect(0, 0, 200, 20)); ~matchCaseButton = GUI.button.new(~window, Rect(0, 0, 100, 20)) .states_([["Case insensitive"], ["Match case"]]); ~searchButton = GUI.button.new(~window, Rect(0, 0, 40, 20)) .states_([["GO"]]) .action_({ this.searchClasses(views.searchField.string, views.searchMenu.value, views.matchCaseButton.value); }); ~window.view.decorator.nextLine; ~filenameView = gui.staticText.new(~window, Rect(0,0, 600, 18)); ~filenameView.font = Font.sansSerif( 10 ); ~window.view.decorator.nextLine; gui.staticText.new(~window, Rect(0,0, 180, 24)) .font_(hvBold12).align_(\center).string_("class vars"); gui.staticText.new(~window, Rect(0,0, 180, 24)) .font_(hvBold12).align_(\center).string_("instance vars"); ~window.view.decorator.nextLine; ~classVarView = gui.listView.new(~window, Rect(0,0, 180, 130)); ~instVarView = gui.listView.new(~window, Rect(0,0, 180, 130)); ~classVarView.value = 0; ~instVarView.value = 0; ~window.view.decorator.nextLine; ~subclassTitle = gui.staticText.new(~window, Rect(0,0, 220, 24)) .font_(hvBold12).align_(\center).string_("subclasses (press return)"); ~methodTitle = gui.staticText.new(~window, Rect(0,0, 240, 24)) .font_(hvBold12).align_(\center).string_("methods"); gui.staticText.new(~window, Rect(0,0, 200, 24)) .font_(hvBold12).align_(\center).string_("arguments"); ~window.view.decorator.nextLine; ~subclassView = gui.listView.new(~window, Rect(0,0, 220, 260)); ~methodView = gui.listView.new(~window, Rect(0,0, 240, 260)); ~argView = gui.listView.new(~window, Rect(0,0, 200, 260)); ~subclassView.resize = 4; ~methodView.resize = 4; ~argView.resize = 4; ~window.view.decorator.nextLine; [~classVarView, ~instVarView, ~subclassView, ~methodView, ~argView].do ( _.beginDragAction_({nil}) ); }; this.addInstanceActions .makeState(class, \class); views.window.front; } makeState { |result, state = \class, addHistory = true, extraValuesDict| currentState = Environment(proto: views, parent: updateProtos, know: true).make { ~result = result; if(~result.isNil or: { result.isArray and: { result.isEmpty } }) { ~state = ("empty" ++ state).asSymbol } { ~state = state; }; if(extraValuesDict.respondsTo(\keysValuesDo)) { currentEnvironment.putAll(extraValuesDict); }; ~state.envirGet[\init].value; ~subclassViewIndex = ~subclassViewIndex.value ? 0; ~methodViewIndex = ~methodViewIndex.value ? 0; ~argView.value = 0; }; if (addHistory) { if (history.size > 1000) { history = history.drop(1) }; historyPos = historyPos + 1; history = history.extend(historyPos).add(currentState); }; this.updateViews; } restoreHistory { // note, don't use makeState because we already have the complete state saved currentState = history[historyPos]; this.updateViews; } updateViews { var updaters, bstate, view; currentState.use { updaters = ~state.envirGet; viewList.do { |viewname| updaters[viewname].value(viewname.envirGet); }; buttonSet.do { |viewname| viewname.envirGet.tryPerform(\enabled_, updaters[\buttonsDisabled].includes(viewname).not); }; ~window.refresh; } } close { if(views.window.isClosed.not) { views.window.close }; currentState = history = views = nil; // dump garbage } // workaround for the fact that you can't get a non-metaclass from a metaclass *getClass { |method| var class; if(method.isNil) { ^nil }; ^if((class = method.ownerClass).isMetaClass) { class.name.asString[5..].asSymbol.asClass; } { class } } getClass { |method| ^this.class.getClass(method) } searchClasses { |string, rootNumber, matchCase, addHistory = true| var pool, rootdir, result, searchType = searchMenuKeys[rootNumber] ? \classSearch, isClassSearch; string = string ?? { "" }; matchCase = matchCase > 0; switch(rootNumber) { 0 } { isClassSearch = true; pool = Class.allClasses } { 1 } { isClassSearch = false; pool = Class.allClasses; } { 2 } { isClassSearch = true; pool = this.currentClass.allSubclasses } { 3 } { isClassSearch = false; pool = this.currentClass.allSubclasses ++ this.currentClass; if(this.currentClass.isMetaClass.not) { pool = pool ++ pool.collect(_.class); }; } { 4 } { isClassSearch = true; rootdir = PathName(currentState.currentClass.filenameSymbol.asString).pathOnly; pool = Class.allClasses.select({ |class| PathName(class.filenameSymbol.asString).pathOnly == rootdir }); if(string.isEmpty) { this.makeState( pool.reject(_.isMetaClass).sort({ |a, b| a.name < b.name }), searchType ); ^this // just to force early exit }; }; if (isClassSearch) { result = case ( {string.isEmpty}, pool, {matchCase}, { pool.select({ |class| class.isMetaClass.not and: { class.name.asString.contains(string) } }) }, //else { pool.select({ |class| class.isMetaClass.not and: { class.name.asString.containsi(string) } }) } ).sort({ |a, b| a.name < b.name }); } { // else - method search result = Array.new; case ( {string.isEmpty}, { pool.do { |class| result = result.addAll(class.methods); } }, {matchCase}, { pool.do({ |class| result = result.addAll(class.methods.select({ |method| method.name.asString.contains(string) })); }); }, { pool.do({ |class| result = result.addAll(class.methods.select({ |method| method.name.asString.containsi(string) })); }); } ); result = result.sort({ |a, b| if(a.name == b.name) { a.ownerClass.name < b.ownerClass.name } { a.name < b.name }; }); }; this.makeState(result, searchType, addHistory, extraValuesDict: ( searchString: string, searchMenuValue: rootNumber, caseButtonValue: matchCase.binaryValue )); } *initGUI { updateProtos ?? { gray = Color.grey(0.5); searchMenuKeys = #[classSearch, methodSearch, classSearch, methodSearch, classSearch]; viewList = #[currentClassNameView, superClassNameView, filenameView, classVarView, instVarView, subclassTitle, methodTitle, subclassView, methodView, argView, searchMenu]; buttonSet = IdentitySet[\superButton, \metaButton, \helpButton, \classSourceButton, \methodSourceButton, \implementationButton, \refsButton]; // updateProtos holds instructions to update the GUI // for each kind of browser result to display updateProtos = ( class: ( init: { ~setSubclassArray.value; ~setMethodArray.value; ~setCurrentClass.value(~result); ~setCurrentMethod.value(~methodArray[0]); }, // ~result must be a Class currentClassNameView: { |v| v.string = ~currentClass.name.asString }, superClassNameView: { |v| v.string = "superclass: " ++ ~currentClass.superclass.tryPerform(\name).asString }, filenameView: { |v| v.string = ~currentClass.filenameSymbol.asString }, classVarView: { |v| v.items = ~currentClass.classVarNames.asArray.collectAs ({|name| name.asString }, Array).sort }, instVarView: { |v| v.items = ~currentClass.instVarNames.asArray.collectAs ({|name| name.asString }, Array).sort }, subclassTitle: { |v| v.string_("subclasses (press return)") }, subclassView: { |v| ~subclassView.items_(~subclassArray.collect({|class| class.name.asString })) .value_(~subclassViewIndex ? 0) .action_(~subclassViewNormalAction) .enterKeyAction_(~navigateToSubclassAction) .mouseDownAction_(~listViewDoubleClickAction); }, methodTitle: { |v| v.string_("methods") }, methodView: { |v| var colorFunc = { |class, name| if(class.findOverriddenMethod(name.asSymbol).isNil) { nil } { Color.grey(0.5, 0.8) } }; var classMethodColors = ~classMethodNames.collect { |name| colorFunc.value(~currentClass.class, name) }; var methodColors = ~methodNames.collect { |name| colorFunc.value(~currentClass, name) }; var methodNames = ~classMethodNames ++ ~methodNames; var colors = classMethodColors ++ methodColors; ~methodView.items_(methodNames) .value_(~methodViewIndex ? 0) .action_(~displayCurrentMethodArgsAction) .mouseDownAction_(~listViewDoubleClickAction) .tryPerform(\colors_, colors) }, argView: { |v| if (~currentMethod.isNil or: { ~currentMethod.argNames.isNil }) { ~argView.items = ["this"]; } { ~argView.items = ~currentMethod.argNames.collectAs( {|name, i| var defval; defval = ~currentMethod.prototypeFrame[i]; if (defval.isNil) { name.asString }{ name.asString ++ " = " ++ defval.asString } }, Array); }; }, searchMenu: { |v| v.items = ["All classes", "All methods", "Subclasses of " ++ ~currentClass.name, "% + subclass methods".format(~currentClass.name), "Classes in folder " ++ PathName(~currentClass.filenameSymbol.asString) .allFolders.last ]; }, buttonsDisabled: IdentitySet.new // all buttons OK ), // this could happen if the user types a wrong class name into the class name box emptyclass: ( currentClassNameView: { |v| v.string = "Class does not exist" }, superClassNameView: { |v| v.string = "" }, filenameView: { |v| v.string = "" }, classVarView: { |v| v.items_(#[]) }, instVarView: { |v| v.items_(#[]) }, subclassTitle: { |v| v.string = "no subclasses" }, methodTitle: { |v| v.string = "no methods" }, subclassView: { |v| v.items_(#[]) }, methodView: { |v| v.items_(#[]) }, argView: { |v| v.items_(#[]) }, buttonsDisabled: buttonSet // all buttons disabled ), classSearch: ( // init: set current class and current method init: { ~currentClass = ~result[0]; ~subclassArray = ~result; ~setMethodArray.value(~currentClass); ~currentMethod = ~methodArray[0]; }, // result must be an array of classes currentClassNameView: { |v| v.string = "Class Search: " ++ ~searchString }, superClassNameView: { |v| v.string = "" }, filenameView: { |v| ~class[\filenameView].value(v) }, classVarView: { |v| ~class[\classVarView].value(v) }, instVarView: { |v| ~class[\instVarView].value(v) }, subclassTitle: { |v| v.string = "matching classes (press return)" }, methodTitle: { |v| v.string = "methods" }, subclassView: { |v| v.items_(~result.collect(_.name)) .value_(~subclassViewIndex ? 0) .action_(~classSearchSubclassViewAction) .enterKeyAction_(~navigateToCurrentClassAction); }, methodView: { |v| ~class[\methodView].value(v) }, argView: { |v| ~class[\argView].value(v) }, buttonsDisabled: #[] // all buttons OK ), emptyclassSearch: ( currentClassNameView: { |v| v.string = "Class Search: " ++ ~searchString }, superClassNameView: { |v| v.string = "No results found!" }, filenameView: { |v| v.string = "" }, classVarView: { |v| v.items_(#[]) }, instVarView: { |v| v.items_(#[]) }, subclassTitle: { |v| v.string = "no classes" }, methodTitle: { |v| v.string = "no methods" }, subclassView: { |v| v.items_(#[]) }, methodView: { |v| v.items_(#[]) }, argView: { |v| v.items_(#[]) }, buttonsDisabled: buttonSet // all buttons disabled ), methodSearch: ( init: { ~methodArray = ~result; ~currentMethod = ~methodArray[0]; ~methodViewIndex = 0; ~setClassArrayFromMethodSearch.value(~result); ~currentClass = this.getClass(~currentMethod); ~subclassViewIndex = ~subclassArray.indexOf(~currentClass); }, // result must be an array of methods currentClassNameView: { |v| v.string = "Method Search: " ++ ~searchString }, superClassNameView: { |v| v.string = "" }, filenameView: { |v| v.string = ~currentMethod.filenameSymbol }, classVarView: { |v| ~class[\classVarView].value(v) }, instVarView: { |v| ~class[\instVarView].value(v) }, subclassTitle: { |v| v.string = "classes (press return)" }, methodTitle: { |v| v.string = "matching methods (press return)" }, subclassView: { |v| v.items_(~subclassArray.collect({ |class| class.name })) .value_(~subclassViewIndex ? 0) .action_(nil) .enterKeyAction_(~navigateToSubclassAction); }, methodView: { |v| v.items_(~methodArray.collect({ |method| method.name ++ " (" ++ method.ownerClass ++ ")" })).action_(~methodSearchMethodViewAction) .value_(~methodViewIndex ? 0) .enterKeyAction_(~navigateToCurrentClassAction) }, argView: { |v| ~class[\argView].value(v) }, buttonsDisabled: #[] // all buttons OK ), emptymethodSearch: ( currentClassNameView: { |v| v.string = "Method Search: " ++ ~searchString }, superClassNameView: { |v| v.string = "No results found!" }, filenameView: { |v| v.string = "" }, classVarView: { |v| v.items_(#[]) }, instVarView: { |v| v.items_(#[]) }, subclassTitle: { |v| v.string = "no classes" }, methodTitle: { |v| v.string = "no methods" }, subclassView: { |v| v.items_(#[]) }, methodView: { |v| v.items_(#[]) }, argView: { |v| v.items_(#[]) }, buttonsDisabled: buttonSet // all buttons disabled ), // support funcs shared in common setCurrentClass: { |class| ~currentClass = class ?? { ~subclassArray[~subclassView.value ? 0] }; }, setCurrentMethod: { |method| ~currentMethod = method ?? { ~methodArray[~methodView.value ? 0] }; }, setSubclassArray: { |class| class = class ? ~result; if (class.subclasses.isNil) { ~subclassArray = []; } { ~subclassArray = class.subclasses.copy.sort {|a,b| a.name <= b.name }; }; }, setMethodArray: { |class| class = class ? ~result; if (class.class.methods.isNil) { ~classMethodArray = []; ~classMethodNames = []; } { ~classMethodArray = class.class.methods.asArray.copy.sort {|a,b| a.name <= b.name }; ~classMethodNames = ~classMethodArray.collect {|method| "*" ++ method.name.asString }; }; if (class.methods.isNil) { ~methodArray = []; ~methodNames = []; } { ~methodArray = class.methods.asArray.copy.sort {|a,b| a.name <= b.name }; ~methodNames = ~methodArray.collect {|method| method.name.asString }; }; ~methodArray = ~classMethodArray ++ ~methodArray; }, setClassArrayFromMethodSearch: { |result| var classSet = IdentitySet.new, class; ~result.do({ |method| classSet.add(this.getClass(method)); }); ~subclassArray = classSet.asArray.sort({ |a, b| a.name < b.name }); } ); } } // because these use instance variables, they cannot be defined in the above class method // each ClassBrowser instance gets a separate dictionary with the proper object scope addInstanceActions { views.putAll(( // these are called from GUI, cannot assume currentState is already in force navigateToSubclassAction: { var prevState = currentState, prevMethod = prevState.currentMethod; this.makeState(currentState.subclassArray[currentState.subclassView.value], \class, // methodViewIndex func runs in context // of the new state environment // might be nil unless subclass also implements extraValuesDict: (methodViewIndex: { if(prevMethod.isNil) { 0 } { ~methodArray.detectIndex({ |item| item.name == prevMethod.name }) }; })); }, navigateToCurrentClassAction: { var prevState = currentState; this.makeState(currentState.currentClass, \class, extraValuesDict: (methodViewIndex: { ~methodArray.indexOf(prevState.currentMethod) })); }, subclassViewNormalAction: { |view| currentState.subclassViewIndex = view.value; }, displayCurrentMethodArgsAction: { |view| currentState.use { ~methodViewIndex = view.value; ~setCurrentMethod.value; ~class[\argView].value(~argView) } }, methodEnterKeyAction: { currentState.currentMethod !? { currentState.currentMethod.openCodeFile }; }, classSearchSubclassViewAction: { |view| currentState.use { ~subclassViewIndex = view.value; ~setCurrentClass.value; ~setMethodArray.value(~currentClass); ~methodViewIndex = 0; ~class[\filenameView].value(~filenameView); ~class[\methodView].value(~methodView); ~class[\argView].value(~argView); ~class[\classVarView].value(~classVarView); ~class[\instVarView].value(~instVarView); } }, methodSearchMethodViewAction: { |view| currentState.use { var index; ~methodViewIndex = view.value; ~currentMethod = ~methodArray[~methodView.value ? 0]; ~currentClass = this.getClass(~currentMethod); ~methodSearch[\filenameView].value(~filenameView); ~class[\argView].value(~argView); ~class[\classVarView].value(~classVarView); ~class[\instVarView].value(~instVarView); if((index = ~subclassArray.indexOf(~currentClass)).notNil) { ~subclassView.value = index; ~subclassViewIndex = index; }; }; }, listViewDoubleClickAction: { |view, x, y, mods, buttonNumber, clickCount| if(clickCount == 2) { view.enterKeyAction.value } } )); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Core/KernelPlusGUI.sc0000664000000000000000000000025212014636263030617 0ustar rootroot+ Process{ //this called when the menu item file-new or file-open is called addDocument { Document.prGetLast; } } + Class { browse { ^ClassBrowser.new(this) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Core/ObjectPlusGUI.sc0000664000000000000000000000010212014636263030577 0ustar rootroot+ Object { mouseDown { ^nil } mouseOver { ^nil } keyDown { } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Core/NilPlusGUI.sc0000664000000000000000000000014712014636263030124 0ustar rootroot+ Nil { // nil parent view asView {} // graphical support asRect { ^Rect.new } asArray { ^[] } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Collections/0000775000000000000000000000000012245452763027235 5ustar rootroot././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Collections/StringPlusGUI.scSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/PlusGUI/Collections/StringPlusGUI.0000664000000000000000000000626112245365552031721 0ustar rootroot+ String { newTextWindow { arg title="Untitled", makeListener=false; Document.new(title, this, makeListener); } openHTMLFile{ arg selectionStart=0, selectionLength=0; var webView; if (Platform.openHTMLFileAction.notNil) { Platform.openHTMLFileAction.value(this, selectionStart, selectionLength); ^this }; webView = \QWebView.asClass; if (webView.notNil) { webView = webView.new; webView.url_(this); webView.front; ^this; }; this.openDocument(selectionStart, selectionLength) } openDocument { arg selectionStart=0, selectionLength=0; var ideClass; if(Document.implementationClass.notNil) { Document.open(this, selectionStart, selectionLength); ^this }; ideClass = \ScIDE.asClass; if ( ideClass.notNil ) { if ( this.endsWith(".sc") || this.endsWith(".scd") ) { ideClass.open(this, selectionStart, selectionLength); ^this } }; this.openOS } draw { this.drawAtPoint(Point(0,0), Font.default, Color.black); } drawAtPoint { arg point, font, color; if(GUI.id === \cocoa) { this.prDrawAtPoint( point, font, color ) } { Pen.stringAtPoint( this, point, font, color ) } } drawInRect { arg rect, font, color; if(GUI.id === \cocoa) { this.prDrawInRect( rect, font, color ) } { Pen.stringInRect( this, rect, font, color ) } } prDrawAtPoint { arg point, font, color; _String_DrawAtPoint ^this.primitiveFailed } prDrawInRect { arg rect, font, color; _String_DrawInRect ^this.primitiveFailed } drawCenteredIn { arg rect, font, color; if(GUI.id === \cocoa) { this.drawAtPoint(this.bounds( font ).centerIn(rect), font, color) } { Pen.stringCenteredIn( this, rect, font, color ) } } drawLeftJustIn { arg rect, font, color; var pos, bounds; if(GUI.id === \cocoa) { bounds = this.bounds( font ); pos = bounds.centerIn(rect); pos.x = rect.left + 2; this.drawAtPoint(pos, font, color); } { Pen.stringLeftJustIn( this, rect, font, color ) } } drawRightJustIn { arg rect, font, color; var pos, bounds; if(GUI.id === \cocoa) { bounds = this.bounds( font ); pos = bounds.centerIn(rect); pos.x = rect.right - 2 - bounds.width; this.drawAtPoint(pos, font, color); } { Pen.stringRightJustIn( this, rect, font, color ) } } bounds { arg font; if(GUI.id === \swing,{ // since Swing is not in svn and can't be easily updated // let's put this temporary hack/if-statement here // rather than pollute everybody else's code with hacks/if-statements font = font ?? { Font.default }; ^Rect(0, 0, this.size * font.size * 0.52146, font.size * 1.25) // width in Helvetica approx = string size * font size * 0.52146 // 0.52146 is average of all 32-127 ascii characters widths },{ ^GUI.stringBounds(this, font) }); } prBounds { arg rect, font; _String_GetBounds ^this.primitiveFailed } findHelpFile { ^SCDoc.findHelpFile(this); } findHelpFileOrElse { this.findHelpFile; } help { if (Platform.openHelpFileAction.notNil) { Platform.openHelpFileAction.value(this) } { HelpBrowser.openHelpFor(this); } } } + Symbol { openDocument { arg selectionStart=0, selectionLength=0; ^this.asString.openDocument(selectionStart, selectionLength) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/ControlModel.sc0000664000000000000000000002140412014636263026411 0ustar rootroot// ControlSpec - defines the range and curve of a control. Spec { classvar <>specs; *initClass { specs = IdentityDictionary.new; } *add { arg name, args; var spec = args.asSpec; specs.put(name, spec); ^spec } asSpec { ^this } defaultControl { ^this.subclassResponsibility(thisMethod) } == { arg that; ^this.compareObject(that) } hash { ^this.instVarHash } findKey { ^Spec.specs.findKeyForValue(this) } printOn { arg stream; var args; this.printClassNameOn(stream); args = this.storeArgs; if(args.notEmpty) { stream << "(" <<<* args << ")"; } } } ControlSpec : Spec { var default, <>units, >grid; var ControlSpec(0, 1), \bipolar -> ControlSpec(-1, 1, default: 0), \freq -> ControlSpec(20, 20000, \exp, 0, 440, units: " Hz"), \lofreq -> ControlSpec(0.1, 100, \exp, 0, 6, units: " Hz"), \midfreq -> ControlSpec(25, 4200, \exp, 0, 440, units: " Hz"), \widefreq -> ControlSpec(0.1, 20000, \exp, 0, 440, units: " Hz"), \phase -> ControlSpec(0, 2pi), \rq -> ControlSpec(0.001, 2, \exp, 0, 0.707), \audiobus -> ControlSpec(0, Server.default.options.numAudioBusChannels-1, step: 1), \controlbus -> ControlSpec(0, Server.default.options.numControlBusChannels-1, step: 1), \midi -> ControlSpec(0, 127, default: 64), \midinote -> ControlSpec(0, 127, default: 60), \midivelocity -> ControlSpec(1, 127, default: 64), \db -> ControlSpec(0.ampdb, 1.ampdb, \db, units: " dB"), \amp -> ControlSpec(0, 1, \amp, 0, 0), \boostcut -> ControlSpec(-20, 20, units: " dB",default: 0), \pan -> ControlSpec(-1, 1, default: 0), \detune -> ControlSpec(-20, 20, default: 0, units: " Hz"), \rate -> ControlSpec(0.125, 8, \exp, 0, 1), \beats -> ControlSpec(0, 20, units: " Hz"), \delay -> ControlSpec(0.0001, 1, \exp, 0, 0.3, units: " secs") ]); } copy { ^this.class.newFrom(this) } } // Warps specify the mapping from 0..1 and the control range Warp { classvar <>warps; var <>spec; *new { arg spec; ^super.newCopyArgs(spec.asSpec); } map { arg value; ^value } unmap { arg value; ^value } *asWarp { arg spec; ^this.new(spec) } asWarp { ^this } *initClass { // support Symbol-asWarp warps = IdentityDictionary[ \lin -> LinearWarp, \exp -> ExponentialWarp, \sin -> SineWarp, \cos -> CosineWarp, \amp -> FaderWarp, \db -> DbFaderWarp, \linear -> LinearWarp, \exponential -> ExponentialWarp ]; // CurveWarp is specified by a number, not a Symbol } asSpecifier { ^warps.findKeyForValue(this.class) } == { arg that; if(this === that,{ ^true; }); if(that.class !== this.class,{ ^false }); //^spec == that.spec ^true } hash { ^this.class.hash } } LinearWarp : Warp { map { arg value; // maps a value from [0..1] to spec range ^value * spec.range + spec.minval } unmap { arg value; // maps a value from spec range to [0..1] ^(value - spec.minval) / spec.range } } ExponentialWarp : Warp { // minval and maxval must both be non zero and have the same sign. map { arg value; // maps a value from [0..1] to spec range ^(spec.ratio ** value) * spec.minval } unmap { arg value; // maps a value from spec range to [0..1] ^log(value/spec.minval) / log(spec.ratio) } } CurveWarp : Warp { var a, b, grow, x,<>y; var <>opacity=0.7,<>smoothing=false,<>linePattern; var pen; *new { |bounds,horzGrid,vertGrid| ^super.new.init(bounds, horzGrid, vertGrid) } *test { arg horzGrid,vertGrid,bounds; var w,grid; bounds = bounds ?? {Rect(0,0,500,400)}; grid = DrawGrid(bounds,horzGrid,vertGrid); w = Window("Grid",bounds).front; UserView(w,bounds ?? {w.bounds.moveTo(0,0)}) .resize_(5) .drawFunc_({ arg v; grid.bounds = v.bounds; grid.draw }) .background_(Color.white) ^grid } init { arg bounds,h,v; var w; pen = GUI.pen; x = DrawGridX(h); y = DrawGridY(v); this.bounds = bounds; this.font = Font( Font.defaultSansFace, 9 ); this.fontColor = Color.grey(0.3); this.gridColors = [Color.grey(0.7),Color.grey(0.7)]; } bounds_ { arg b; bounds = b; x.bounds = b; y.bounds = b; } draw { pen.push; pen.alpha = opacity; pen.smoothing = smoothing; if(linePattern.notNil) {Pen.lineDash_(linePattern)}; x.commands.do({ arg cmd; pen.perform(cmd) }); y.commands.do({ arg cmd; pen.perform(cmd) }); pen.pop; } font_ { arg f; x.font = f; y.font = f; } fontColor_ { arg c; x.fontColor = c; y.fontColor = c; } gridColors_ { arg colors; x.gridColor = colors[0]; y.gridColor = colors[1]; } horzGrid_ { arg g; x.grid = g; } vertGrid_ { arg g; y.grid = g; } copy { ^DrawGrid(bounds,x.grid,y.grid).x_(x.copy).y_(y.copy).opacity_(opacity).smoothing_(smoothing).linePattern_(linePattern) } clearCache { x.clearCache; y.clearCache; } } DrawGridX { var range,<>bounds; var <>font,<>fontColor,<>gridColor,<>labelOffset; var commands,cacheKey; *new { arg grid; ^super.newCopyArgs(grid.asGrid).init } init { range = [grid.spec.minval, grid.spec.maxval]; labelOffset = 4 @ -10; } grid_ { arg g; grid = g.asGrid; range = [grid.spec.minval, grid.spec.maxval]; this.clearCache; } setZoom { arg min,max; range = [min,max]; } commands { var p; if(cacheKey != [range,bounds],{ commands = nil }); ^commands ?? { cacheKey = [range,bounds]; commands = []; p = grid.getParams(range[0],range[1],bounds.left,bounds.right); p['lines'].do { arg val; // value, [color] var x; val = val.asArray; x = val[0].linlin(range[0],range[1],bounds.left,bounds.right); commands = commands.add( ['strokeColor_',val[1] ? gridColor] ); commands = commands.add( ['line', Point( x, bounds.top), Point(x,bounds.bottom) ] ); commands = commands.add( ['stroke' ] ); }; if(bounds.width >= 12 ,{ commands = commands.add(['font_',font ] ); commands = commands.add(['color_',fontColor ] ); p['labels'].do { arg val; var x; // value, label, [color, font] if(val[2].notNil,{ commands = commands.add( ['color_',val[2] ] ); }); if(val[3].notNil,{ commands = commands.add( ['font_',val[3] ] ); }); x = val[0].linlin(range[0],range[1],bounds.left,bounds.right); commands = commands.add( ['stringAtPoint', val[1].asString, Point(x, bounds.bottom) + labelOffset ] ); } }); commands } } clearCache { cacheKey = nil; } copy { ^super.copy.clearCache } } DrawGridY : DrawGridX { init { range = [grid.spec.minval, grid.spec.maxval]; labelOffset = 4 @ 4; } commands { var p; if(cacheKey != [range,bounds],{ commands = nil }); ^commands ?? { commands = []; p = grid.getParams(range[0],range[1],bounds.top,bounds.bottom); p['lines'].do { arg val; // value, [color] var y; val = val.asArray; y = val[0].linlin(range[0],range[1],bounds.bottom,bounds.top); commands = commands.add( ['strokeColor_',val[1] ? gridColor] ); commands = commands.add( ['line', Point( bounds.left,y), Point(bounds.right,y) ] ); commands = commands.add( ['stroke' ] ); }; if(bounds.height >= 20 ,{ commands = commands.add(['font_',font ] ); commands = commands.add(['color_',fontColor ] ); p['labels'].do { arg val,i; var y; y = val[0].linlin(range[0],range[1],bounds.bottom,bounds.top); if(val[2].notNil,{ commands = commands.add( ['color_',val[2] ] ); }); if(val[3].notNil,{ commands = commands.add( ['font_',val[3] ] ); }); commands = commands.add( ['stringAtPoint', val[1].asString, Point(bounds.left, y) + labelOffset ] ); } }); commands } } } // DrawGridRadial : DrawGridX {} GridLines { var <>spec; *new { arg spec; ^super.newCopyArgs(spec.asSpec) } asGrid { ^this } niceNum { arg val,round; // http://books.google.de/books?id=fvA7zLEFWZgC&pg=PA61&lpg=PA61 var exp,f,nf,rf; exp = floor(log10(val)); f = val / 10.pow(exp); rf = 10.pow(exp); if(round,{ if(f < 1.5,{ ^rf * 1.0 }); if(f < 3.0,{ ^rf * 2.0 }); if( f < 7.0,{ ^rf * 5.0 }); ^rf * 10.0 },{ if(f <= 1.0,{ ^rf * 1.0; }); if(f <= 2,{ ^rf * 2.0 }); if(f <= 5,{ ^rf * 5.0; }); ^rf * 10.0 }); } ideals { arg min,max,ntick=5; var nfrac,d,graphmin,graphmax,range,x; range = this.niceNum(max - min,false); d = this.niceNum(range / (ntick - 1),true); graphmin = floor(min / d) * d; graphmax = ceil(max / d) * d; nfrac = max( floor(log10(d)).neg, 0 ); ^[graphmin,graphmax,nfrac,d]; } looseRange { arg min,max,ntick=5; ^this.ideals(min,max).at( [ 0,1] ) } getParams { |valueMin,valueMax,pixelMin,pixelMax,numTicks| var lines,p,pixRange; var nfrac,d,graphmin,graphmax,range; pixRange = pixelMax - pixelMin; if(numTicks.isNil,{ numTicks = (pixRange / 64); numTicks = numTicks.max(3).round(1); }); # graphmin,graphmax,nfrac,d = this.ideals(valueMin,valueMax,numTicks); lines = []; if(d != inf,{ forBy(graphmin,graphmax + (0.5*d),d,{ arg tick; if(tick.inclusivelyBetween(valueMin,valueMax),{ lines = lines.add( tick ); }) }); }); p = (); p['lines'] = lines; if(pixRange / numTicks > 9) { p['labels'] = lines.collect({ arg val; [val, this.formatLabel(val,nfrac) ] }); }; ^p } formatLabel { arg val, numDecimalPlaces; ^val.round( (10**numDecimalPlaces).reciprocal).asString + (spec.units?"") } } BlankGridLines : GridLines { getParams { ^() } } + Nil { asGrid { ^BlankGridLines.new } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/guicrucial/0000775000000000000000000000000012245452763025616 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/guicrucial/PageLayout.sc0000664000000000000000000000776612245365552030236 0ustar rootroot PageLayout { // a Window with a FlowView on it // it also manages onClose handlers for use by ObjectGui's MVC model, var isClosed=false,boundsWereExplicit=false,<>onClose; var autoRemoves; *new { arg title,bounds,margin,background,scroll=true,front=true; ^super.new.init(title,bounds,margin,background,scroll,front) } init { arg title,bounds,argMargin,background,argScroll=true,front=true; var w,v; if(bounds.notNil,{ boundsWereExplicit = true; bounds = bounds.asRect },{ bounds = GUI.window.screenBounds.insetAll(10,20,0,25) }); window = GUI.window.new("< " ++ title.asString ++ " >",bounds, border: true, scroll: argScroll ); window.onClose_({ this.close }); if(background.isKindOf(Boolean),{ // bwcompat : metal=true/false background = background.if(nil,{Color(0.88, 0.94, 0.87, 1)}) }); if(background.notNil,{ window.view.background_(background); }); isClosed = false; view = FlowView.new( window, window.view.bounds.insetAll(4,4,0,0) ); view.decorator.margin_(argMargin ?? {GUI.skin.margin}); autoRemoves = []; if(front,{ window.front }); } *on { arg window,bounds,margin,background; ^super.new.initOn(window,bounds,margin,background) } initOn { arg argWindow,bounds,argMargin,background; window = argWindow; view = FlowView.new(window,bounds); if(argMargin.notNil,{ view.decorator.margin_(argMargin); }); autoRemoves = []; } asView { ^this.view.asView } asFlowView { arg bounds; ^if(bounds.notNil,{ FlowView(this,bounds) },{ this.view }) } bounds { ^this.view.bounds } add { arg view; this.view.add(view); } asPageLayout { arg name,bounds; if(isClosed,{ ^this.class.new(name,bounds) },{ ^this }) } startRow { this.view.startRow; } indentedRemaining { ^this.view.indentedRemaining } *guify { arg parent,title,width,height,background; ^parent ?? { this.new(title,width@height,background: background ) } } // act like a GUI window checkNotClosed { ^isClosed.not } front { window.front } hide { window.alpha = 0.0; } show { window.alpha = 1.0; } close { // called when the GUI.window closes if(isClosed.not,{ isClosed = true; autoRemoves.do({ arg updater; updater.remove(false) }); autoRemoves = nil; window.close; onClose.value; NotificationCenter.notify(window,\didClose); window=view=nil; }); } refresh { window.refresh } hr { arg color,height=8,borderStyle=1; this.view.hr; } focus { arg index=0; var first; first = this.window.views.at(index); if(first.notNil,{first.focus }); } background_ { arg c; this.view.background_(c) } removeOnClose { arg dependant; autoRemoves = autoRemoves.add(dependant); } resizeToFit { arg reflow=false,center=false; var fs, b,wb,wbw,wbh; b = this.view.resizeToFit(reflow); if(GUI.scheme.id == \cocoa,{ wbw = b.width + 4; wbh = b.height + 17; },{ wbw = b.width + 11; wbh = b.height + 15; }); window.setInnerExtent(wbw,wbh); if(center and: {window.respondsTo(\setTopLeftBounds)}) { // this should be a window method fs = GUI.window.screenBounds; wb = window.bounds; // bounds are inaccurate until the end of the code cycle/refresh wb.width = wbw; wb.height = wbh; // if height is less than 60% of full screen if(wbh <= (fs.height * 0.6),{ // then move its top to be level at golden ratio wb.top = fs.height - (fs.height / 1.6180339887); },{ wb.top = 0; }); // center it horizontally wb.left = (fs.width - wbw) / 2; window.setTopLeftBounds(wb); } } reflowAll { view.reflowAll; } fullScreen { window.bounds = GUI.window.screenBounds.insetAll(10,20,0,25); } endFullScreen { window.endFullScreen } flow { arg func,bounds; ^this.view.flow(func,bounds) } vert { arg func,bounds,spacing; ^this.view.vert(func,bounds,spacing) } horz { arg func,bounds,spacing; ^this.view.horz(func,bounds,spacing) } comp { arg func,bounds; ^this.view.comp(func,bounds) } scroll { arg ... args; ^this.view.performList(\scroll,args) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/guicrucial/ObjectGui.sc0000664000000000000000000000533412014636263030016 0ustar rootroot ObjectGui : SCViewHolder { /* this is a controller class: it creates the views and implements the relationship between them and the model model: the object for which this is a graphical user interface view: this.view is the flow view (aka the arg layout) that is passed to guiBody individual views/widgets are placed in it and their actions talk to either this object or the model */ var 40,{ string = string.copyRange(0,40) ++ "..."; }); dragSource = GUI.dragSource.new(layout,Rect(0,0,(string.bounds(font).width + 10).max(70),GUI.skin.buttonHeight)) .stringColor_(Color.new255(70, 130, 200)) .font_(font) .background_(Color.white) .align_(\left) .beginDragAction_({ model }) .object_(string); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/guicrucial/StringGui.sc0000664000000000000000000000157612014636263030062 0ustar rootroot// just a label with the name of the object StringGui : ObjectGui { writeName {} gui { arg parent, bounds ... args; var layout,string,font; var width,height; layout=this.guify(parent,bounds); font = GUI.font.new(*GUI.skin.fontSpecs); if(model.isString,{ string = " "++model; },{ // floats, integers, symbols will show more clearly what they are string = " "++model.asCompileString; }); if(string.size > 1024,{ string = string.copyRange(0,1024) ++ "..."; }); if(bounds.notNil,{ bounds = bounds.asRect; },{ bounds = Rect(0,0, string.bounds.width(font).max(30), GUI.skin.buttonHeight); }); this.view = GUI.staticText.new(layout,bounds) .stringColor_(GUI.skin.fontColor) .font_(font) .background_(GUI.skin.background) .align_(\left) .object_(string); if(parent.isNil,{ layout.resizeToFit; layout.front }); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/guicrucial/gui.sc0000664000000000000000000000110712014636263026721 0ustar rootroot + Object { gui { arg parent,bounds ... args; ^this.guiClass.new(this).performList(\gui,[parent,bounds] ++ args); } guiClass { ^ObjectGui } } // just a label with the name + String { guiClass { ^StringGui } } + Symbol { guiClass { ^StringGui } } + SimpleNumber { guiClass { ^StringGui } } + Boolean { guiClass { ^StringGui } } + Nil { guiClass { ^StringGui } // create a window/FlowView if you don't supply a parent to: thing.gui asPageLayout { arg name,bounds; ^PageLayout(name.asString,bounds ).front } asFlowView { arg bounds; ^FlowView(nil,bounds) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/SCViewHolder.sc0000664000000000000000000001532412014636263026312 0ustar rootroot// SCViewHolder makes it possible to add more capabilities by holding an SCView, not subclassing it SCViewHolder { classvar <>consumeKeyDowns = false;// should the view by default consume keydowns var bounds.bottom } rows { ^rows.copy } prInitFlowViewLayout { fOnViewClose = { |view| this.remove(view); }; } prAddRow { rows = rows.add(List.new); } } FlowView : SCViewHolder { // a CompositeView with a FlowLayout as its decorator // has the advantage that it preserves startRow when the view is resized var current; classvar <>globalKeyDownAction, <> globalKeyUpAction, <>initAction; classvar <>autoRun = true; classvar <>implementationClass; //don't change the order of these vars: var keyDownAction, <>keyUpAction, <>mouseUpAction; var <>toFrontAction, <>endFrontAction, <>onClose, <>mouseDownAction; var = 0 } } { start = start - 1 }; while { str[end] !== Char.nl and: { end < max } } { end = end + 1 }; ^str.copyRange(start + 1, end); } //actions: didBecomeKey { this.class.current = this; this.saveCurrentEnvironment; toFrontAction.value(this); } didResignKey { endFrontAction.value(this); this.restoreCurrentEnvironment; } mouseUp{ | x, y, modifiers, buttonNumber, clickCount, clickPos | mouseUpAction.value(this, x, y, modifiers, buttonNumber, clickCount) } keyDown { | character, modifiers, unicode, keycode | this.class.globalKeyDownAction.value(this,character, modifiers, unicode, keycode); keyDownAction.value(this,character, modifiers, unicode, keycode); } keyUp { | character, modifiers, unicode, keycode | this.class.globalKeyUpAction.value(this,character, modifiers, unicode, keycode); keyUpAction.value(this,character, modifiers, unicode, keycode); } == { | doc | ^if(this.path.isNil or: { doc.path.isNil }) { doc === this } { this.path == doc.path } } hash { ^(this.path ? this).hash } *defaultUsesAutoInOutdent_ {|bool| Document.implementationClass.prDefaultUsesAutoInOutdent_(bool) } usesAutoInOutdent_ {|bool| this.prUsesAutoInOutdent_(bool) } *prDefaultUsesAutoInOutdent_{|bool| this.subclassResponsibility(thisMethod); } *prPostColor_{ |color| this.subclassResponsibility(thisMethod); } prUsesAutoInOutdent_{|bool| ^this.subclassResponsibility(thisMethod); } // private implementation prIsEditable_{ | editable=true | ^this.subclassResponsibility(thisMethod) } prSetTitle { | argName | ^this.subclassResponsibility(thisMethod) } prGetTitle { ^this.subclassResponsibility(thisMethod) } prGetFileName { ^this.subclassResponsibility(thisMethod) } prSetFileName { | apath | ^this.subclassResponsibility(thisMethod) } prGetBounds { | argBounds | ^this.subclassResponsibility(thisMethod) } prSetBounds { | argBounds | ^this.subclassResponsibility(thisMethod) } text { ^this.subclassResponsibility(thisMethod) } selectedText { ^this.subclassResponsibility(thisMethod) } selectUnderlinedText { | clickPos | ^this.subclassResponsibility(thisMethod) } linkAtClickPos { | clickPos | ^this.subclassResponsibility(thisMethod) } rangeText { | rangestart=0, rangesize=1 | ^this.subclassResponsibility(thisMethod) } prclose { ^this.subclassResponsibility(thisMethod) } closed { onClose.value(this); // call user function this.restoreCurrentEnvironment; allDocuments.remove(this); dataptr = nil; } prinsertText { | dataPtr, txt | ^this.subclassResponsibility(thisMethod) } insertTextRange { | string, rangestart, rangesize | ^this.subclassResponsibility(thisMethod) } prAdd { allDocuments = allDocuments.add(this); this.editable = true; if (autoRun) { if (this.rangeText(0,7) == "/*RUN*/") { this.text.interpret; } }; current = this; initAction.value(this); } //this is called after recompiling the lib *prnumberOfOpen { ^this.subclassResponsibility(thisMethod) } *numberOfOpen { thisProcess.platform.when(\_NumberOfOpenTextWindows) { ^this.prnumberOfOpen } { ^allDocuments.size }; ^0 } *newFromIndex { | idx | ^super.new.initByIndex(idx) } initByIndex { | idx | //allDocuments = allDocuments.add(this); var doc; doc = this.prinitByIndex(idx); if(doc.isNil,{^nil}); this.prAdd; } prinitByIndex { | idx | ^this.subclassResponsibility(thisMethod) } //this is called from the menu: open, new *prGetLast { ^Document.implementationClass.prBasicNew.initLast } initLast { ^this.subclassResponsibility(thisMethod) } prGetLastIndex { ^this.subclassResponsibility(thisMethod) } // private open initFromPath { | path, selectionStart, selectionLength | var stpath; // path = apath; stpath = this.class.standardizePath(path); this.propen(stpath, selectionStart, selectionLength); if(dataptr.isNil,{ this.class.allDocuments.do{ |d| if(d.path == stpath.absolutePath){ ^d } }; ^nil }); this.background_(Color.white); ^this.prAdd; } propen { | path, selectionStart=0, selectionLength=0 | ^this.subclassResponsibility(thisMethod) } // private newTextWindow initByString{ | argTitle, str, makeListener | this.prinitByString(argTitle, str, makeListener); this.background_(Color.white); if(dataptr.isNil,{^nil}); this.prAdd; this.title = argTitle; } prinitByString { | title, str, makeListener | ^this.subclassResponsibility(thisMethod) } // other private // if -1 whole doc prSetBackgroundColor { | color | ^this.subclassResponsibility(thisMethod) } prGetBackgroundColor { | color | ^this.subclassResponsibility(thisMethod) } prSetSelectedBackgroundColor { | color | ^this.subclassResponsibility(thisMethod); } prGetSelectedBackgroundColor { | color | ^this.subclassResponsibility(thisMethod); } selectedRangeLocation { ^this.subclassResponsibility(thisMethod) } selectedRangeSize { ^this.subclassResponsibility(thisMethod) } prSelectLine { | line | ^this.subclassResponsibility(thisMethod) } *prGetIndexOfListener { if (this.implementationClass.isNil) { ^nil }; if (this.implementationClass.respondsTo(\prGetIndexOfListener)) { ^this.implementationClass.prGetIndexOfListener } { ^nil } } //---not yet implemented // ~/Documents // /Volumes // Music/Patches //*reviewUnsavedDocumentsWithAlertTitle //*saveAllDocuments //*recentDocumentPaths //save //saveAs //print // //hasPath was loaded // Environment handling Document with its own envir must set and restore currentEnvironment on entry and exit. // Requires alteration of *open, *new, closed, didBecomeKey, and didResignKey envir_ { | ev | envir = ev; if (this.class.current == this) { if (savedEnvir.isNil) { this.saveCurrentEnvironment } } } restoreCurrentEnvironment { if (envir.notNil) { currentEnvironment = savedEnvir }; } saveCurrentEnvironment { if (envir.notNil) { savedEnvir = currentEnvironment; currentEnvironment = envir; } } *prBasicNew { ^super.new } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/GUI.sc0000664000000000000000000001266012245365552024446 0ustar rootroot/** * Factory abstraction for all GUI related core classes. * Each GUI kit is described by a scheme that maps class names * to actual classes. * * See the help file for details. The default * scheme is cocoa. * * Changelog: * - jrh added makeGUI * - sciss added add, set, get, use, useID * * @version 0.16, 10-Apr-07 */ GUI { classvar margin, <>gap; var <>left, <>top, <>maxHeight,<>maxRight; var <>owner; *new { arg bounds, margin, gap; ^super.newCopyArgs(bounds, margin, gap).init } init { gap = gap ? Point(4,4); margin = margin ? Point(4,4); this.reset; } clear { this.reset; } reset { maxRight = left = bounds.left + margin.x; top = bounds.top + margin.y; maxHeight = 0; } place { arg view; var height, width,vbounds; vbounds = view.bounds; width = vbounds.width; height = vbounds.height; if ((left + width) > (bounds.right - margin.x), { this.nextLine; }); view.bounds = Rect(left, top, width, height); maxRight = max(maxRight,left + width); left = left + width + gap.x; maxHeight = max(maxHeight, height); } remove { } nextLine { left = bounds.left + margin.x; top = top + maxHeight + gap.y; maxHeight = 0; } shift { arg x=0, y=0; left = left + x; top = top + y; } innerBounds { ^bounds.insetBy(margin.x * 2,margin.y * 2) } bounds_ { arg b; var d; left = left + ( d = (b.left - bounds.left)); maxRight = maxRight + (d); top = top + (d = (b.top - bounds.top)); maxHeight = maxHeight + (d); bounds = b; // and then you need to re-place all views // but nextLine will be broken, see FlowView } currentBounds { var currentBounds; currentBounds = bounds; currentBounds.height = top + maxHeight; ^currentBounds } // rounded out to the nearest rect + margin used { ^Rect(bounds.left,bounds.top, maxRight + margin.x - bounds.left, (top + maxHeight + margin.y ) - bounds.top) } // largest allocatable rect starting in the current row // going down as far as possible indentedRemaining { var inb; inb = this.innerBounds; ^Rect(left,top, inb.width - (left - inb.left - margin.x), inb.height - (top - inb.top - margin.y)) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/HelpBrowser.sc0000664000000000000000000002047612245365552026262 0ustar rootrootHelpBrowser { classvar singleton; classvar <>defaultHomeUrl; classvar <>openNewWindows = false; var <>homeUrl; var "], [\Reload, "Reload"]].do { |item| var str = item[1]; var w = str.bounds.width + hPad; toolbar[item[0]] = Button( window, Rect(x,y,w,h) ).states_([[str]]); x = x + w + 2; }; x = x + 10; str = "Quick lookup:"; w = str.bounds.width + 5; StaticText(window, Rect(x,y,w,h)).string_(str); x = x + w; w = 200; srchBox = TextField.new( window, Rect(x,y,w,h) ).resize_(1); if(GUI.current.id == \qt) { srchBox.toolTip = "Smart quick help lookup. Prefix with # to just search."; }; srchBox.action = {|x| if(x.string.notEmpty) { this.goTo(if(x.string.first==$#) {SCDoc.helpTargetUrl ++ "/Search.html" ++ x.string} {SCDoc.findHelpFile(x.string)} ); } }; openNewWin = aNewWin; x = x + w + 10; if(GUI.current.respondsTo(\checkBox)) { str = "Open links in new window"; w = str.bounds.width + 50; CheckBox.new (window, Rect(x, y, w, h) ) .resize_(1) .string_(str) .value_(openNewWin) .action_({ |b| openNewWin = b.value }); } { str = "Open links in same window"; w = str.bounds.width + 5; Button.new( window, Rect(x, y, w, h) ) .resize_(1) .states_([[str],["Open links in new window"]]) .value_(openNewWin.asInteger) .action_({ |b| openNewWin = b.value.asBoolean }); }; x = 0; y = marg + h + 5; w = winRect.width; findView = CompositeView(window, Rect(x,y,w,h+10)).visible_(false).resize_(2); y = marg; w = 200; x = winRect.width - marg - w; txtFind = TextField.new( findView, Rect(x,y,w,h) ).resize_(3); str = "Find text in document:"; w = str.bounds.width + 5; x = x - w - 5; lblFind = StaticText.new( findView, Rect(x, y, w, h) ) .string_(str) .resize_(3); x = 5; y = marg + h + 5; w = winRect.width - 10; h = winRect.height - y - marg; webView = WebView.new( window, Rect(x,y,w,h) ).resize_(5); webView.html = "Please wait while initializing Help... (This might take several seconds the first time)"; if(webView.respondsTo(\setFontFamily)) { webView.setFontFamily(\fixed, Platform.case( \osx, { "Monaco" }, \linux, { "Andale Mono" }, { "Monospace" } )) }; webView.onLoadFinished = { this.stopAnim; window.name = "SuperCollider Help: %".format(webView.title); }; webView.onLoadFailed = { this.stopAnim }; webView.onLinkActivated = {|wv, url| var redirected, newPath, oldPath; redirected = this.redirectTextFile(url); if (not(redirected)) { if(openNewWin) { #newPath, oldPath = [url,webView.url].collect {|x| if(x.notEmpty) {x.findRegexp("(^\\w+://)?([^#]+)(#.*)?")[1..].flop[1][1]} }; }; if(newPath!=oldPath) { HelpBrowser.new(newWin:true).goTo(url); } { this.goTo(url); }; } }; if(webView.respondsTo(\onReload_)) { webView.onReload = {|wv, url| if(WebView.implClass.respondsTo(\clearCache)) { WebView.clearCache; }; this.goTo(url); }; }; if(webView.respondsTo(\onJavaScriptMsg_)) { webView.onJavaScriptMsg = {|wv, err, type| "JavaScript %: %".format(if(type==0,"Error","Message"),err).postln; }; }; toggleFind = { if(findView.visible.not) { saveSize = webView.bounds; h = findView.bounds.height + marg; webView.bounds = Rect(saveSize.left,saveSize.top+h,saveSize.width,saveSize.height-h); findView.visible = true; txtFind.focus; } { webView.bounds = saveSize; findView.visible = false; }; }; webView.enterInterpretsSelection = true; webView.keyDownAction = { arg view, char, mods; if( (char.ascii == 13) && (mods.isCtrl || mods.isCmd || mods.isShift) ) { view.tryPerform(\evaluateJavaScript,"selectLine()"); }; }; window.view.keyDownAction = { arg view, char, mods, uni, kcode, key; if( ((key == 70) && mods.isCtrl) || (char == $f && mods.isCmd) ) { toggleFind.value; }; if(char.ascii==27) { if(findView.visible) {toggleFind.value}; } }; toolbar[\Back].action = { this.goBack }; toolbar[\Forward].action = { this.goForward }; toolbar[\Reload].action = { this.goTo( webView.url ) }; if(GUI.id === \cocoa) { txtFind.action = { |x| webView.focus; AppClock.sched(0, {webView.findText( x.string );}) }; } { txtFind.action = { |x| webView.findText( x.string ) }; }; } redirectTextFile {|url| var plainTextExts = #[".sc",".scd",".txt",".schelp",".rtf"]; plainTextExts.do {|x| var path; if(url.endsWith(x)) { path = url.replace("%20"," ") .findRegexp("(^\\w+://)?([^#]+)(#.*)?")[1..].flop[1][1]; if(File.exists(path)) { path.openDocument; } { webView.url = SCDoc.helpTargetUrl++"/BrokenLink.html#"++path; window.front; }; ^true } }; ^false } startAnim { var progress = [">---","->--","-->-","--->"]; if(loading.not) { loading = true; Routine { block {|break| loop { progress.do {|p| window.name = ("Loading"+p); 0.3.wait; if(loading.not) {break.value}; }; }; }; // lblStatus.string_(""); }.play(AppClock); }; } stopAnim { loading = false; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/Inspector.sc0000664000000000000000000001527112014636263025763 0ustar rootrootInspector { classvar index, redirectQueries = false; *implScheme{ ^GUI.scheme } *implClass { var scheme, key, target; scheme = GUI.scheme; if (scheme.isNil) { Error("No GUI scheme active.", this).throw }; key = this.key; target = key !? {GUI.scheme.tryPerform(key)}; if (target.isNil) { Error("No redirection for" + this.name + "available in the active GUI scheme:" + scheme.id ++ ".", this).throw; } ^target; } *classRedirect { ^redirectQueries.if({this.implClass ? this}, this)} *key { ^nil } *new { arg ...args; ^this.implClass.new(*args); } *doesNotUnderstand{|selector ... args| var impl; ^this.implClass.perform(selector, *args); } *browse { ^ClassBrowser( this.key !? {this.implClass} ? this ) } } ViewRedirect : GuiRedirect { // Abstract class *new { arg parent, bounds; ^super.new(parent, bounds); } } Window : GuiRedirect { *key { ^\window } *new { arg name = "panel", bounds, resizable = true, border = true, server, scroll = false; ^super.new(name, bounds, resizable, border, server, scroll) } } CompositeView : ViewRedirect { *key { ^\compositeView }} ScrollView : ViewRedirect { *key { ^\scrollView }} HLayoutView : ViewRedirect { *key { ^\hLayoutView }} VLayoutView : ViewRedirect { *key { ^\vLayoutView }} Slider : ViewRedirect { *key { ^\slider }} Pen : GuiRedirect { *key { ^\pen }} Stethoscope : GuiRedirect { *new { arg server, numChannels = 2, index = 0, bufsize = 4096, zoom = 1, rate = \audio, view, bufnum; index = index.asControlInput; if (GUI.id == \qt and: { server.serverRunning and: server.hasShmInterface.not }) { ^GUI.current.stethoscope1.new (server, numChannels, index, bufsize, zoom, rate, view, bufnum) }{ ^super.new(server, numChannels, index, bufsize, zoom, rate, view, bufnum) }; } *key { ^\stethoscope } } ScopeView : ViewRedirect { *key { ^\scopeView }} FreqScopeView : ViewRedirect { *key { ^\freqScopeView }} // redirects to FreqScope FreqScope : GuiRedirect { // redirects to FreqScopeWindow *new { arg width=512, height=300, busNum=0, scopeColor, bgColor; busNum = busNum.asControlInput; ^super.new(width, height, busNum, scopeColor) } *key { ^\freqScope } } Dialog : GuiRedirect { *key { ^\dialog } *openPanel { arg okFunc, cancelFunc, multipleSelection=false; ^super.openPanel(okFunc, cancelFunc, multipleSelection) } *savePanel { arg okFunc, cancelFunc; ^super.savePanel(okFunc, cancelFunc) } } View : ViewRedirect { *key { ^\view }} RangeSlider : ViewRedirect { *key { ^\rangeSlider }} Slider2D : ViewRedirect { *key { ^\slider2D }} TabletSlider2D : ViewRedirect { *key { ^\tabletSlider2D }} Button : ViewRedirect { *key { ^\button }} PopUpMenu : ViewRedirect { *key { ^\popUpMenu }} StaticText : ViewRedirect { *key { ^\staticText }} NumberBox : ViewRedirect { *key { ^\numberBox }} ListView : ViewRedirect { *key { ^\listView }} DragSource : ViewRedirect { *key { ^\dragSource }} DragSink : ViewRedirect { *key { ^\dragSink }} DragBoth : ViewRedirect { *key { ^\dragBoth }} UserView : ViewRedirect { *key { ^\userView }} MultiSliderView : ViewRedirect { *key { ^\multiSliderView }} EnvelopeView : ViewRedirect { *key { ^\envelopeView }} TextField : ViewRedirect { *key { ^\textField }} TabletView : ViewRedirect { *key { ^\tabletView }} SoundFileView : ViewRedirect { *key { ^\soundFileView }} MovieView : ViewRedirect { *key { ^\movieView }} TextView : ViewRedirect { *key { ^\textView }} Font : GuiRedirect { *key { ^\font } *findFirstAvailable { |fontNames, action| Routine { fontNames.do { |name| if(this.availableFonts.any(_.contains(name))) { action.value(name); nil.alwaysYield; } } }.play(AppClock) } *new { arg name, size, bold = false, italic = false, isPointSize = false; ^super.new(name, size, bold, italic, isPointSize) } } Knob : ViewRedirect { *key { ^\knob }} LevelIndicator : ViewRedirect { *key { ^\levelIndicator }} Image : ViewRedirect { *key { ^\image }} WebView : ViewRedirect { *key { ^\webView }} CheckBox : ViewRedirect { *key { ^\checkBox }} TreeView : ViewRedirect { *key { ^\treeView }} HLayout : GuiRedirect { *key { ^\hLayout }} VLayout : GuiRedirect { *key { ^\vLayout }} GridLayout : GuiRedirect { *key { ^\gridLayout }} StackLayout : GuiRedirect { *key { ^\stackLayout } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/ServerMeter.sc0000664000000000000000000001607012245365552026264 0ustar rootrootServerMeterView{ classvar serverMeterViews, updateFreq = 10, dBLow = -80, meterWidth = 15, gapWidth = 4, 0).if({ // ins StaticText(view, Rect(10, 5, 100, 15)) .font_(Font.sansSerif(10).boldVariant) .string_("Inputs"); inmeters = Array.fill( numIns, { arg i; var comp; comp = CompositeView(innerView, Rect(0,0,meterWidth,195)).resize_(5); StaticText(comp, Rect(0, 180, meterWidth, 15)) .font_(Font.sansSerif(9).boldVariant) .string_(i.asString); levelIndic = LevelIndicator( comp, Rect(0,0,meterWidth,180) ).warning_(0.9).critical_(1.0) .drawsPeak_(true) .numTicks_(9) .numMajorTicks_(3); }); }); if((numIns > 0) && (numOuts > 0)){ // divider UserView(innerView, Rect(0,0,meterWidth,180)).drawFunc_({ try { Pen.color = \QPalette.asClass.new.windowText; } { Pen.color = Color.white; }; Pen.line(((meterWidth + gapWidth) * 0.5)@0, ((meterWidth + gapWidth) * 0.5)@180); Pen.stroke; }); }; // outs (numOuts > 0).if({ StaticText(view, Rect(10 + if(numIns > 0 , ((numIns + 2) * (meterWidth + gapWidth)), 0), 5, 100, 15)) .font_(Font.sansSerif(10).boldVariant) .string_("Outputs"); outmeters = Array.fill( numOuts, { arg i; var comp; comp = CompositeView(innerView, Rect(0,0,meterWidth,195)); StaticText(comp, Rect(0, 180, meterWidth, 15)) .font_(Font.sansSerif(9).boldVariant) .string_(i.asString); levelIndic = LevelIndicator( comp, Rect(0,0,meterWidth,180) ).warning_(0.9).critical_(1.0) .drawsPeak_(true) .numTicks_(9) .numMajorTicks_(3); }); }); this.setSynthFunc(inmeters, outmeters); startResponderFunc = {this.startResponders}; this.start; } setSynthFunc{ var numRMSSamps, numRMSSampsRecip; synthFunc = { //responders and synths are started only once per server var numIns = server.options.numInputBusChannels; var numOuts = server.options.numOutputBusChannels; numRMSSamps = server.sampleRate / updateFreq; numRMSSampsRecip = 1 / numRMSSamps; server.bind({ var insynth, outsynth; (numIns > 0).if({ insynth = SynthDef(server.name ++ "InputLevels", { var in = In.ar(NumOutputBuses.ir, numIns); SendPeakRMS.kr(in, updateFreq, 3, "/" ++ server.name ++ "InLevels") }).play(RootNode(server), nil, \addToHead); }); (numOuts > 0).if({ outsynth = SynthDef(server.name ++ "OutputLevels", { var in = In.ar(0, numOuts); SendPeakRMS.kr(in, updateFreq, 3, "/" ++ server.name ++ "OutLevels") }).play(RootNode(server), nil, \addToTail); }); if (serverCleanupFuncs.isNil) { serverCleanupFuncs = IdentityDictionary.new; }; serverCleanupFuncs.put(server, { insynth.free; outsynth.free; ServerTree.remove(synthFunc, server); }); }); }; } startResponders{ var numRMSSamps, numRMSSampsRecip; //responders and synths are started only once per server numRMSSamps = server.sampleRate / updateFreq; numRMSSampsRecip = 1 / numRMSSamps; (numIns > 0).if({ inresp = OSCFunc({|msg| { try { var channelCount = msg.size - 3 / 2; channelCount.do {|channel| var baseIndex = 3 + (2*channel); var peakLevel = msg.at(baseIndex); var rmsValue = msg.at(baseIndex + 1); var meter = inmeters.at(channel); if (meter.isClosed.not) { meter.peakLevel = peakLevel.ampdb.linlin(dBLow, 0, 0, 1, \min); meter.value = rmsValue.ampdb.linlin(dBLow, 0, 0, 1); } } } { |error| if(error.isKindOf(PrimitiveFailedError).not) { error.throw } }; }.defer; }, ("/" ++ server.name ++ "InLevels").asSymbol, server.addr).fix; }); (numOuts > 0).if({ outresp = OSCFunc({|msg| { try { var channelCount = msg.size - 3 / 2; channelCount.do {|channel| var baseIndex = 3 + (2*channel); var peakLevel = msg.at(baseIndex); var rmsValue = msg.at(baseIndex + 1); var meter = outmeters.at(channel); if (meter.isClosed.not) { meter.peakLevel = peakLevel.ampdb.linlin(dBLow, 0, 0, 1, \min); meter.value = rmsValue.ampdb.linlin(dBLow, 0, 0, 1); } } } { |error| if(error.isKindOf(PrimitiveFailedError).not) { error.throw } }; }.defer; }, ("/" ++ server.name ++ "OutLevels").asSymbol, server.addr).fix; }); } start { if(serverMeterViews.isNil){ serverMeterViews = IdentityDictionary.new; }; if(serverMeterViews[server].isNil){ serverMeterViews.put(server, List()); }; if(serverMeterViews[server].size == 0){ ServerTree.add(synthFunc, server); if(server.serverRunning, synthFunc); // otherwise starts when booted }; serverMeterViews[server].add(this); if (server.serverRunning) { this.startResponders } { ServerBoot.add (startResponderFunc, server) } } stop{ serverMeterViews[server].remove(this); if(serverMeterViews[server].size == 0 and: (serverCleanupFuncs.notNil)) { serverCleanupFuncs[server].value; serverCleanupFuncs.removeAt(server); }; (numIns > 0).if({ inresp.free; }); (numOuts > 0).if({ outresp.free; }); ServerBoot.remove(startResponderFunc, server) } remove{ view.remove } } ServerMeter{ var 0).if{ //only add a unitLabel if desired // unitView = GUI.staticText.new(view, unitBounds); // }; minView = GUI.numberBox.new(view, minBounds); maxView = GUI.numberBox.new(view, maxBounds); warpView = GUI.textField.new(view, warpBounds); stepView = GUI.numberBox.new(view, stepBounds); // set view parameters and actions controlSpec = argControlSpec.asSpec; minView.value = controlSpec.minval; maxView.value = controlSpec.maxval; warpView.value = controlSpec.warp.asSpecifier.asCompileString; stepView.value = controlSpec.step; minView.action = { controlSpec.minval = minView.value }; maxView.action = { controlSpec.maxval = maxView.value }; warpView.action = { try { controlSpec.warp = warpView.value.interpret.asWarp(controlSpec) } }; stepView.action = { controlSpec.step = stepView.value }; //this.prSetViewParams; } prSubViewBounds{arg rect; // calculate subview bounds var labelBounds, minBounds, maxBounds, warpBounds, stepBounds; var gap1, gap2, gap3, tmp, labelH, componentSize; gap1 = gap.copy; gap2 = gap.copy; gap3 = gap.copy; labelH=labelSize.y;// needed for \vert switch (layout, \line2, { componentSize = ((rect.width - (3 * gap.x) - labelSize.x) / 4)@labelH; stepBounds = componentSize.asRect.left_(rect.width - componentSize.x); warpBounds = componentSize.asRect.left_(stepBounds.left-componentSize.x-gap.x); maxBounds = componentSize.asRect.left_(warpBounds.left-componentSize.x-gap.x); minBounds = componentSize.asRect.left_(maxBounds.left-componentSize.x-gap.x); labelBounds = (labelSize.x@labelSize.y).asRect.width_(minBounds.left-gap.x); //adjust width }, \vert, { componentSize = labelSize.x@((rect.height - (3 * gap.y) - labelH) / 4); labelBounds = (rect.width@labelH).asRect; // to top minBounds = (rect.width@componentSize.y) .asRect.top_(labelBounds.bottom + gap.y); maxBounds = (rect.width@componentSize.y) .asRect.top_(minBounds.bottom + gap.y); warpBounds = (rect.width@componentSize.y) .asRect.top_(maxBounds.bottom + gap.y); stepBounds = (rect.width@componentSize.y) .asRect.top_(warpBounds.bottom + gap.y); }, \horz, { componentSize = ((rect.width - (3 * gap.x) - labelSize.x) / 4)@labelH; stepBounds = componentSize.asRect.left_(rect.width - componentSize.x); warpBounds = componentSize.asRect.left_(stepBounds.left-componentSize.x-gap.x); maxBounds = componentSize.asRect.left_(warpBounds.left-componentSize.x-gap.x); minBounds = componentSize.asRect.left_(maxBounds.left-componentSize.x-gap.x); labelBounds = (labelSize.x@labelSize.y).asRect.width_(minBounds.left-gap.x); //adjust width } ); ^[labelBounds, minBounds, maxBounds, warpBounds, stepBounds].collect{arg v; v.moveBy(margin.x,margin.y)} } }SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/Base/EZKnob.sc0000664000000000000000000002146412014636263026020 0ustar rootrootEZKnob : EZGui { classvar <>compactRatio=0.87; var controlSpec, popUp=false, knobSize,unitWidth, gap; var <>round = 0.001; *new { arg parent, bounds, label, controlSpec, action, initVal, initAction=false, labelWidth=60, knobSize, unitWidth=0, labelHeight=20, layout=\vert, gap, margin; ^super.new.init(parent, bounds, label, controlSpec, action, initVal, initAction, labelWidth, knobSize, unitWidth, labelHeight, layout, gap, margin) } init { arg parentView, bounds, label, argControlSpec, argAction, initVal, initAction, labelWidth, argKnobSize,argUnitWidth, labelHeight, argLayout, argGap, argMargin; var labelBounds, numBounds, unitBounds,knobBounds; var numberStep; // Set Margin and Gap this.prMakeMarginGap(parentView, argMargin, argGap); unitWidth = argUnitWidth; layout=argLayout; bounds.isNil.if{bounds = 50@90}; knobSize = argKnobSize ; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); labelSize=labelWidth@labelHeight; // calculate bounds of all subviews # labelBounds,numBounds,knobBounds, unitBounds = this.prSubViewBounds(innerBounds, label.notNil, unitWidth>0); // instert the views label.notNil.if{ //only add a label if desired labelView = GUI.staticText.new(view, labelBounds); labelView.string = label; }; (unitWidth>0).if{ //only add a unitLabel if desired unitView = GUI.staticText.new(view, unitBounds); }; knobView = GUI.knob.new(view, knobBounds); numberView = GUI.numberBox.new(view, numBounds); // set view parameters and actions controlSpec = argControlSpec.asSpec; (unitWidth>0).if{unitView.string = " "++controlSpec.units.asString}; initVal = initVal ? controlSpec.default; action = argAction; numberStep = controlSpec.step; if (numberStep == 0) { numberStep = controlSpec.guessNumberStep }{ // controlSpec wants a step, so zooming in with alt is disabled. numberView.alt_scale = 1.0; knobView.alt_scale = 1.0; }; numberView.step = numberStep; numberView.scroll_step = numberStep; if((controlSpec.minval + controlSpec.maxval)==0){knobView.centered=true}; knobView.action = { this.valueAction_(controlSpec.map(knobView.value)); }; if (controlSpec.step != 0) { knobView.step = (controlSpec.step / (controlSpec.maxval - controlSpec.minval)); }; knobView.receiveDragHandler = { arg slider; slider.valueAction = controlSpec.unmap(GUI.view.currentDrag); }; knobView.beginDragAction = { arg slider; controlSpec.map(slider.value) }; numberView.action = { this.valueAction_(numberView.value) }; if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; this.prSetViewParams; } // just set, no action value_ { arg val; value = controlSpec.constrain(val); numberView.value = value.round(round); knobView.value = controlSpec.unmap(value); } // set and do action valueAction_ { arg val; this.value_(val); this.doAction; } doAction { action.value(this) } set { arg label, spec, argAction, initVal, initAction = false; labelView.notNil.if { labelView.string = label.asString }; spec.notNil.if { controlSpec = spec.asSpec }; argAction.notNil.if { action = argAction }; initVal = initVal ? value ? controlSpec.default; if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; } centered_ { arg bool; knobView.centered_(bool) } centered{ ^knobView.centered } setColors{arg stringBackground,stringColor,numBackground, numStringColor,numNormalColor,numTypingColor,knobColors,background; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)}; unitView.notNil.if{unitView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)}; unitView.notNil.if{unitView.stringColor_(stringColor)};}; numBackground.notNil.if{ numberView.background_(numBackground);}; numNormalColor.notNil.if{ numberView.normalColor_(numNormalColor);}; numTypingColor.notNil.if{ numberView.typingColor_(numTypingColor);}; numStringColor.notNil.if{ numberView.stringColor_(numStringColor);}; knobColors.notNil.if{ knobView.color_(knobColors);}; background.notNil.if{ view.background=background;}; numberView.refresh; knobView.refresh; } font_{ arg font; labelView.notNil.if{labelView.font=font}; unitView.notNil.if{unitView.font=font}; numberView.font=font; } ///////Private methods /////// prSetViewParams{ // sets resize and alignment for different layouts switch (layout, \line2, { labelView.notNil.if{ labelView.resize_(5); unitView.notNil.if{unitView.resize_(9)}; numberView.resize_(8); }{ unitView.notNil.if{ unitView.resize_(6); numberView.resize_(5); }{ numberView.resize_(5); }; }; knobView.resize_(9); popUp.if{view.resize_(2)}; }, \vert, { labelView.notNil.if{labelView.resize_(2)}; unitView.notNil.if{unitView.resize_(6)}; numberView.resize_(5); popUp.if{view.resize_(2)}; }, \vert2, { labelView.notNil.if{labelView.resize_(2).align_(\center)}; unitView.notNil.if{unitView.resize_(6)}; numberView.resize_(5); popUp.if{view.resize_(2)}; }, \horz, { labelView.notNil.if{labelView.resize_(4).align_(\right)}; unitView.notNil.if{unitView.resize_(6)}; numberView.resize_(5); knobView.resize_(9); popUp.if{view.resize_(2)}; }); } prSubViewBounds{arg rect, hasLabel, hasUnit; // calculate subview bounds var numBounds,labelBounds,knobBounds, unitBounds,knobHeight, numHeight; var gap1, gap2, gap3, tmp, labelH, unitH; gap1 = gap.copy; gap2 = gap.copy; gap3 = gap.copy; (rect.height<= (labelSize.y*2)).if{labelSize.y=rect.height/2}; numHeight=labelSize.y; switch (layout, \line2, { knobSize.isNil.if{knobSize=( ((rect.height/compactRatio)-margin.x)@(rect.height))}; knobSize=(knobSize.x-margin.x)@(knobSize.y.min(rect.height)); hasUnit.not.if{ gap2 = 0@0; unitWidth = 0}; labelBounds = Rect(0,0,rect.width-knobSize.x-gap3.x,labelSize.y); //to left hasLabel.if{ unitBounds = Rect(labelBounds.width-unitWidth,labelSize.y+gap1.y, unitWidth, rect.height-labelSize.y-gap1.y); numBounds = Rect(0,labelSize.y+gap1.y, labelBounds.width-gap2.x-unitBounds.width,rect.height-labelSize.y-gap1.y); }{ unitBounds = Rect(labelBounds.width-unitWidth,0, unitWidth, rect.height); numBounds = Rect(0,0, labelBounds.width-gap2.x-unitBounds.width,rect.height); }; knobBounds=knobSize.asRect.moveTo(rect.width-knobSize.x,0); }, \horz, { knobSize.isNil.if{knobSize=( ((rect.height/compactRatio)-margin.x)@(rect.height))}; knobSize=(knobSize.x-margin.x)@(knobSize.y.min(rect.height)); knobBounds=knobSize.asRect.moveTo(rect.width-knobSize.x,0); hasUnit.not.if{ gap2 = 0@0; unitWidth = 0}; hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0}; labelBounds = (labelSize.x@rect.height).asRect; unitBounds = (unitWidth@rect.height).asRect .moveTo(rect.width-knobBounds.width-gap2.x-unitWidth,0); numBounds = Rect.newSides(labelSize.x+gap1.x,0,unitBounds.left-gap2.x,rect.height); }, \vert , { hasUnit.not.if{ gap3 = 0@0; unitWidth = 0}; hasLabel.not.if{ gap1 = 0@0; labelSize.y = 0}; knobSize.isNil.if{ knobSize=( ((rect.height-labelSize.y-numHeight-gap1.y-gap2.y)/compactRatio) @(rect.height-labelSize.y-numHeight-gap1.y-gap2.y)) }; knobSize=((knobSize.x).min(rect.width)) @(knobSize.y.min(rect.height-labelSize.y-numHeight-gap1.y-gap2.y)); labelBounds = (rect.width@labelSize.y).asRect; knobBounds=knobSize.asRect.moveTo(0,labelSize.y+gap1.y); numBounds = Rect(0,rect.height-numHeight,rect.width-unitWidth-gap3.x, numHeight); unitBounds = Rect(rect.width-unitWidth,rect.height-numHeight,unitWidth,numHeight); }, \vert2 , { hasUnit.not.if{ gap3 = 0@0; unitWidth = 0}; hasLabel.not.if{ gap1 = 0@0; labelSize.y = 0}; knobSize.isNil.if{ knobSize=( ((rect.height-labelSize.y-numHeight-gap1.y-gap2.y)/compactRatio) @(rect.height-labelSize.y-numHeight-gap1.y-gap2.y)) }; knobSize=((knobSize.x).min(rect.width)) @(knobSize.y.min(rect.height-labelSize.y-numHeight-gap1.y-gap2.y)); labelBounds = (rect.width@labelSize.y).asRect; knobBounds=knobSize.asRect.moveTo(0,labelSize.y+gap1.y); knobBounds=knobBounds.moveBy((rect.width-knobBounds.width)/2,0); numBounds = Rect(0,rect.height-numHeight,rect.width-unitWidth-gap3.x, numHeight); unitBounds = Rect(rect.width-unitWidth,rect.height-numHeight,unitWidth,numHeight); } ); ((knobBounds.height<0)||(knobBounds.width<0)).if{knobBounds=knobBounds.height_(0).width_(0)}; ^[labelBounds, numBounds, knobBounds, unitBounds].collect{arg v; v.moveBy(margin.x,margin.y)} } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/Base/EZScroller.sc0000664000000000000000000000346712245365552026725 0ustar rootrootEZScroller { var action, controlSpec, popUp=false, numSize,numberWidth,unitWidth, gap; var <>round = 0.001; *new { arg parent, bounds, label, controlSpec, action, initVal, initAction=false, labelWidth=60, numberWidth=45, unitWidth=0, labelHeight=20, layout=\horz, gap, margin; ^super.new.init(parent, bounds, label, controlSpec, action, initVal, initAction, labelWidth, numberWidth, unitWidth, labelHeight, layout, gap, margin) } init { arg parentView, bounds, label, argControlSpec, argAction, initVal, initAction, labelWidth, argNumberWidth,argUnitWidth, labelHeight, argLayout, argGap, argMargin; var labelBounds, numBounds, unitBounds,sliderBounds; var numberStep; // Set Margin and Gap this.prMakeMarginGap(parentView, argMargin, argGap); unitWidth = argUnitWidth; numberWidth = argNumberWidth; layout=argLayout; bounds.isNil.if{bounds = 350@20}; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); labelSize=labelWidth@labelHeight; numSize = numberWidth@labelHeight; // calculate bounds of all subviews # labelBounds,numBounds,sliderBounds, unitBounds = this.prSubViewBounds(innerBounds, label.notNil, unitWidth>0); // instert the views label.notNil.if{ //only add a label if desired labelView = GUI.staticText.new(view, labelBounds); labelView.string = label; }; (unitWidth>0).if{ //only add a unitLabel if desired unitView = GUI.staticText.new(view, unitBounds); }; sliderView = GUI.slider.new(view, sliderBounds); numberView = GUI.numberBox.new(view, numBounds); // set view parameters and actions controlSpec = argControlSpec.asSpec; controlSpec.addDependant(this); this.onClose = { controlSpec.removeDependant(this) }; (unitWidth>0).if{unitView.string = " "++controlSpec.units.asString}; initVal = initVal ? controlSpec.default; action = argAction; sliderView.action = { this.valueAction_(controlSpec.map(sliderView.value)); }; sliderView.receiveDragHandler = { arg slider; slider.valueAction = controlSpec.unmap(GUI.view.currentDrag); }; sliderView.beginDragAction = { arg slider; controlSpec.map(slider.value) }; numberView.action = { this.valueAction_(numberView.value) }; numberStep = controlSpec.step; if (numberStep == 0) { numberStep = controlSpec.guessNumberStep }{ // controlSpec wants a step, so zooming in with alt is disabled. numberView.alt_scale = 1.0; sliderView.alt_scale = 1.0; }; numberView.step = numberStep; numberView.scroll_step = numberStep; //numberView.scroll=true; if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; if (labelView.notNil) { labelView.mouseDownAction = {|view, x, y, modifiers, buttonNumber, clickCount| if(clickCount == 2, {this.editSpec}); } }; this.prSetViewParams; } value_ { arg val; value = controlSpec.constrain(val); numberView.value = value.round(round); sliderView.value = controlSpec.unmap(value); } valueAction_ { arg val; this.value_(val); this.doAction; } doAction { action.value(this) } set { arg label, spec, argAction, initVal, initAction = false; labelView.notNil.if { labelView.string = label.asString }; spec.notNil.if { controlSpec = spec.asSpec }; argAction.notNil.if { action = argAction }; initVal = initVal ? value ? controlSpec.default; if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; } setColors{arg stringBackground,stringColor,sliderBackground,numBackground, numStringColor,numNormalColor,numTypingColor,knobColor,background; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)}; unitView.notNil.if{unitView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)}; unitView.notNil.if{unitView.stringColor_(stringColor)};}; numBackground.notNil.if{ numberView.background_(numBackground);}; numNormalColor.notNil.if{ numberView.normalColor_(numNormalColor);}; numTypingColor.notNil.if{ numberView.typingColor_(numTypingColor);}; numStringColor.notNil.if{ numberView.stringColor_(numStringColor);}; sliderBackground.notNil.if{ sliderView.background_(sliderBackground);}; knobColor.notNil.if{ sliderView.knobColor_(knobColor);}; background.notNil.if{ view.background=background;}; numberView.refresh; } font_{ arg font; labelView.notNil.if{labelView.font=font}; unitView.notNil.if{unitView.font=font}; numberView.font=font; } ///////Private methods /////// prSetViewParams{ // sets resize and alignment for different layouts switch (layout, \line2, { labelView.notNil.if{ labelView.resize_(2); unitView.notNil.if{unitView.resize_(3)}; numberView.resize_(3); }{ unitView.notNil.if{ unitView.resize_(2); numberView.resize_(1); }{ numberView.resize_(2); }; }; sliderView.resize_(5); popUp.if{view.resize_(2)}; }, \vert, { labelView.notNil.if{labelView.resize_(2)}; unitView.notNil.if{unitView.resize_(8)}; numberView.resize_(8); sliderView.resize_(5); popUp.if{view.resize_(4)}; }, \horz, { labelView.notNil.if{labelView.resize_(4).align_(\right)}; unitView.notNil.if{unitView.resize_(6)}; numberView.resize_(6); sliderView.resize_(5); popUp.if{view.resize_(2)}; }); } prSubViewBounds{arg rect, hasLabel, hasUnit; // calculate subview bounds var numBounds,labelBounds,sliderBounds, unitBounds; var gap1, gap2, gap3, tmp, labelH, unitH; gap1 = gap.copy; gap2 = gap.copy; gap3 = gap.copy; labelH=labelSize.y;// needed for \vert unitH=labelSize.y; // needed for \vert hasUnit.not.if{ gap3 = 0@0; unitWidth = 0}; switch (layout, \line2, { hasLabel.if{ // with label unitBounds = (unitWidth@labelSize.y) .asRect.left_(rect.width-unitWidth);// view to right numBounds = (numSize.x@labelSize.y) .asRect.left_(rect.width-unitBounds.width-numberWidth-gap3.x); // view to right labelBounds = (labelSize.x@labelSize.y) .asRect.width_(numBounds.left-gap2.x); //adjust width }{ // no label labelBounds = (0@labelSize.y).asRect; //just a dummy numBounds = (numberWidth@labelSize.y).asRect; //view to left (unitWidth>0).if{ unitBounds = Rect (numBounds.width+gap3.x, 0, rect.width-numBounds.width-gap3.x,labelSize.y); //adjust to fit }{ unitBounds = Rect (0, 0,0,0); //no unitView numBounds = (rect.width@labelSize.y).asRect; //view to left }; }; sliderBounds = Rect( //adjust to fit 0, labelSize.y+gap1.y, rect.width, rect.height-numSize.y-gap1.y; ); }, \vert, { hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0 ;}; hasLabel.not.if{labelH=0}; labelBounds = (rect.width@labelH).asRect; // to top hasUnit.not.if{unitH=0}; unitBounds = (rect.width@unitH) .asRect.top_(rect.height-labelSize.y); // to bottom numBounds = (rect.width@labelSize.y) .asRect.top_(rect.height-unitBounds.height-numSize.y-gap3.y); // to bottom sliderBounds = Rect( //adjust to fit 0, labelBounds.height+gap1.y, rect.width, rect.height - labelBounds.height - unitBounds.height - numBounds.height - gap1.y - gap2.y - gap3.y ); }, \horz, { hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0 ;}; labelSize.y = rect.height; labelBounds = (labelSize.x@labelSize.y).asRect; //to left unitBounds = (unitWidth@labelSize.y).asRect.left_(rect.width-unitWidth); // to right numBounds = (numSize.x@labelSize.y).asRect .left_(rect.width-unitBounds.width-numSize.x-gap3.x);// to right sliderBounds = Rect( // adjust to fit labelBounds.width+gap1.x, 0, rect.width - labelBounds.width - unitBounds.width - numBounds.width - gap1.x - gap2.x - gap3.x, labelBounds.height ); }); ^[labelBounds, numBounds, sliderBounds, unitBounds].collect{arg v; v.moveBy(margin.x,margin.y)} } update {arg changer, what ...moreArgs; var oldValue; if(changer === controlSpec, { oldValue = this.value; this.value = oldValue; if(this.value != oldValue, { this.doAction }); }); } editSpec { var ezspec; [labelView, sliderView, numberView, unitView].do({|view| view.notNil.if({ view.enabled_(false).visible_(false)}); }); ezspec = EZControlSpecEditor(view, view.bounds.moveTo(0,0), controlSpec: controlSpec, layout: layout); ezspec.labelView.mouseDownAction = {|view, x, y, modifiers, buttonNumber, clickCount| if(clickCount == 2, { ezspec.remove; [labelView, sliderView, numberView, unitView].do({|view| view.notNil.if({ view.enabled_(true).visible_(true)}); }); }); }; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/Base/EZRangerSC.sc0000664000000000000000000002077712014636263026601 0ustar rootrootEZRanger : EZGui { var controlSpec, <>action,round = 0.001; *new { arg parent, bounds, label, controlSpec, action, initVal, initAction=false, labelWidth=60, numberWidth=45, unitWidth=0, labelHeight=20, layout=\horz, gap,margin; ^super.new.init(parent, bounds, label, controlSpec, action, initVal, initAction, labelWidth, numberWidth, unitWidth, labelHeight, layout, gap, margin) } init { arg parentView, bounds, label, argControlSpec, argAction, initVal, initAction, labelWidth, argNumberWidth,argUnitWidth, labelHeight, argLayout, argGap,argMargin; var labelBounds, hiBounds,loBounds, unitBounds,rangerBounds; var numberStep; // Set Margin and Gap this.prMakeMarginGap(parentView, argMargin, argGap); unitWidth = argUnitWidth; numberWidth = argNumberWidth; layout=argLayout; bounds.isNil.if{bounds = 350@20}; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); labelSize=labelWidth@labelHeight; numSize = numberWidth@labelHeight; // calcualate bounds # labelBounds,hiBounds,loBounds,rangerBounds, unitBounds = this.prSubViewBounds(innerBounds, label.notNil, unitWidth>0); label.notNil.if{ //only add a label if desired labelView = GUI.staticText.new(view, labelBounds); labelView.string = label; }; (unitWidth>0).if{ //only add a unitLabel if desired unitView = GUI.staticText.new(view, unitBounds); }; loBox = GUI.numberBox.new(view, loBounds); rangeSlider = GUI.rangeSlider.new(view, rangerBounds); hiBox = GUI.numberBox.new(view, hiBounds); controlSpec = argControlSpec.asSpec; (unitWidth>0).if{unitView.string = " "++controlSpec.units.asString}; action = argAction; loBox.action_({ |box| this.lo_(box.value).doAction; }); rangeSlider.action_({ |sl| this.lo_(controlSpec.map(sl.lo)); this.hi_(controlSpec.map(sl.hi)); this.doAction; }); hiBox.action_({ |box| this.hi_(box.value).doAction; }); if (initVal.notNil) { this.value_(initVal) }; if (initAction) { this.doAction }; // if (controlSpec.step != 0) { // rangeSlider.step = (controlSpec.step / (controlSpec.maxval - controlSpec.minval)); // }; numberStep = controlSpec.step; if (numberStep == 0) { numberStep = controlSpec.guessNumberStep; }{ // controlSpec wants a step, so zooming in with alt is disabled. hiBox.alt_scale = 1.0; loBox.alt_scale = 1.0; rangeSlider.alt_scale = 1.0; }; hiBox.step=numberStep; loBox.step=numberStep; hiBox.scroll_step=numberStep; loBox.scroll_step=numberStep; rangeSlider.receiveDragHandler = { arg slider; slider.valueAction = controlSpec.unmap(GUI.view.currentDrag); }; rangeSlider.beginDragAction = { arg slider; controlSpec.map(slider.value) }; this.prSetViewParams; } doAction { action.value(this); } set { arg label, spec, argAction, initVal, initAction = false; labelView.notNil.if { labelView.string = label.asString }; spec.notNil.if { controlSpec = spec.asSpec }; argAction.notNil.if { action = argAction }; initVal = initVal ? this.value ? controlSpec.default.dup(2); if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; } value { ^[lo, hi] } value_ { |vals| this.lo_(vals[0]).hi_(vals[1]) } valueAction_ { |vals| this.value_(vals).doAction } lo_ { |val| lo = controlSpec.constrain(val); loBox.value_(lo.round(round)); rangeSlider.lo_(controlSpec.unmap(lo)); } hi_ { |val| hi = controlSpec.constrain(val); hiBox.value_(hi.round(round)); rangeSlider.hi_(controlSpec.unmap(hi)); } setColors{arg stringBackground, stringColor, sliderColor, numBackground,numStringColor, numNormalColor, numTypingColor, knobColor,background ; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)}; unitView.notNil.if{unitView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)}; unitView.notNil.if{unitView.stringColor_(stringColor)};}; sliderColor.notNil.if{ rangeSlider.background_(sliderColor);}; numBackground.notNil.if{ hiBox.background_(numBackground); loBox.background_(numBackground);}; numNormalColor.notNil.if{ hiBox.normalColor_(numNormalColor); loBox.normalColor_(numNormalColor);}; numTypingColor.notNil.if{ hiBox.typingColor_(numTypingColor); loBox.typingColor_(numTypingColor);}; numStringColor.notNil.if{ hiBox.stringColor_(numStringColor); loBox.stringColor_(numStringColor);}; knobColor.notNil.if{ rangeSlider.knobColor_(knobColor);}; background.notNil.if{ view.background=background;}; hiBox.refresh; } font_{ arg font; labelView.notNil.if{labelView.font=font}; unitView.notNil.if{unitView.font=font}; hiBox.font=font; loBox.font=font; } prSetViewParams{ switch (layout, \line2, { labelView.notNil.if{ labelView.resize_(2); unitView.notNil.if{unitView.resize_(3)}; hiBox.resize_(3); loBox.resize_(3); }{ unitView.notNil.if{ unitView.resize_(2).align_(\left)}; hiBox.resize_(1); loBox.resize_(1); }; rangeSlider.resize_(5); popUp.if{view.resize_(2)}; }, \vert, { labelView.notNil.if{labelView.resize_(2)}; unitView.notNil.if{unitView.resize_(8)}; loBox.resize_(8); hiBox.resize_(2); rangeSlider.resize_(5); popUp.if{view.resize_(4)}; }, \horz, { labelView.notNil.if{labelView.resize_(4).align_(\right)}; unitView.notNil.if{unitView.resize_(6)}; loBox.resize_(4); hiBox.resize_(6); rangeSlider.resize_(5); popUp.if{view.resize_(2)}; }); } prSubViewBounds{arg rect, hasLabel, hasUnit; var hiBounds,loBounds,labelBounds,rangerBounds; var unitBounds, gap1, gap2, gap3,gap4, tmp, labelH, unitH; gap1 = gap.copy; // use copy to make sure these are unique gap2 = gap.copy; // since you later set the .x or .y gap3 = gap.copy; gap4 = gap.copy; labelH=labelSize.y;// needed for \vert unitH=labelSize.y; // needed for \vert switch (layout, \line2, { hasLabel.not.if{ gap2 = 0@0; labelSize.x = 0 ;}; hasUnit.not.if{ gap4 = 0@0; unitWidth = 0}; hasLabel.if{ // with label unitBounds = (unitWidth@labelSize.y) .asRect.left_(rect.width-unitWidth);// view to right hiBounds = (numSize.x@labelSize.y) .asRect.left_(rect.width-unitBounds.width-numberWidth-gap4.x); // view to right loBounds = (numSize.x@labelSize.y) .asRect.left_(rect.width-unitBounds.width-numberWidth -gap3.x-hiBounds.width-gap4.x); // view to right labelBounds = (labelSize.x@labelSize.y) .asRect.width_(loBounds.left-gap2.x); //adjust width }{ // no label labelBounds = (0@labelSize.y).asRect; //just a dummy loBounds = (numberWidth@labelSize.y).asRect; //view to left hiBounds = (numberWidth@labelSize.y).asRect.moveTo(loBounds.width+gap3.x,0); //view to left (unitWidth>0).if{ unitBounds = Rect.newSides (hiBounds.right+gap4.x, 0,rect.width, labelSize.y); //adjust width }{ unitBounds = Rect (0, 0,0,0); //no unitView }; }; rangerBounds = Rect( 0, labelSize.y+gap1.y, rect.width, rect.height-numSize.y-gap1.y; ); }, \vert, { hasLabel.not.if{labelH=0; gap1.y=0}; labelBounds = (rect.width@labelH).asRect; // to top hasUnit.not.if{unitH=0; gap4 = 0@0;}; unitBounds = (rect.width@unitH) .asRect.top_(rect.height-unitH); // to bottom hiBounds = (rect.width@labelSize.y) .asRect.top_(labelBounds.height+gap1.y); // to bottom loBounds = (rect.width@labelSize.y) .asRect.top_(rect.height-unitBounds.height-numSize.y-gap4.y); // to bottom rangerBounds = Rect.newSides( 0, hiBounds.bottom+gap2.y, rect.width, loBounds.top-gap3.y ); }, \horz, { hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0 ;}; hasUnit.not.if{ gap4 = 0@0; unitWidth = 0}; labelSize.y=rect.height; labelBounds = (labelSize.x@labelSize.y).asRect; unitBounds = (unitWidth@labelSize.y).asRect.left_(rect.width-unitWidth); loBounds = (numSize.x@labelSize.y).asRect .left_(labelBounds.width+gap1.x); hiBounds = (numSize.x@labelSize.y).asRect .left_(rect.width-unitBounds.width-numSize.x-gap4.x); rangerBounds = Rect.newSides( loBounds.right+gap2.x , 0, rect.width-hiBounds.width-unitBounds.width -gap3.x-gap4.x, labelSize.y); }); ^[labelBounds, hiBounds, loBounds, rangerBounds, unitBounds] .collect{arg v; v.moveBy(margin.x,margin.y)} } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/Base/EZNumber.sc0000664000000000000000000001324112014636263026351 0ustar rootrootEZNumber : EZGui{ var controlSpec, numSize,numberWidth,unitWidth, gap, gap2; var <>round = 0.001; var scaler=1; //for swing compatibility *new { arg parent, bounds, label, controlSpec, action, initVal, initAction=false, labelWidth=60, numberWidth, unitWidth=0, labelHeight=20, layout=\horz, gap, margin; ^super.new.init(parent, bounds, label, controlSpec, action, initVal, initAction, labelWidth, numberWidth, unitWidth, labelHeight, layout, gap, margin) } init { arg parentView, bounds, label, argControlSpec, argAction, initVal, initAction, labelWidth, argNumberWidth,argUnitWidth, labelHeight, argLayout, argGap, argMargin; var labelBounds, numBounds, unitBounds; var numberStep; // Set Margin and Gap this.prMakeMarginGap(parentView, argMargin, argGap); unitWidth = argUnitWidth; numberWidth = argNumberWidth; layout=argLayout; bounds.isNil.if {bounds= 160@20}; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); numberWidth.isNil.if{numberWidth=45}{ labelWidth=bounds.width-unitWidth-numberWidth; //override the labelWidth if (layout==\line2){unitWidth=bounds.width-numberWidth}; //override the unitWidth }; labelSize=labelWidth@labelHeight; numSize = numberWidth@labelHeight; // calcualate bounds # labelBounds,numBounds, unitBounds = this.prSubViewBounds(innerBounds, label.notNil, unitWidth>0); // insert the views label.notNil.if{ //only add a label if desired labelView = GUI.staticText.new(view, labelBounds); if (layout==\line2) {labelView.align = \left;} {labelView.align = \right;}; labelView.string = label; }; (unitWidth>0).if{ //only add a unitLabel if desired unitView = GUI.staticText.new(view, unitBounds); }; // set view parameters and actions controlSpec = argControlSpec.asSpec; // let default to nil.asSpec! (unitWidth>0).if{ unitView.string = " "++controlSpec.units.asString}; initVal = initVal ? controlSpec.default; action = argAction; numberView = GUI.numberBox.new(view, numBounds).resize_(2); numberStep = controlSpec.step; if (numberStep == 0) { numberStep = controlSpec.guessNumberStep; }{ // controlSpec wants a step, so zooming in with alt is disabled. numberView.alt_scale = 1.0 }; numberView.step = numberStep; numberView.scroll_step = numberStep; numberView.scroll=true; numberView.action = { this.valueAction_(numberView.value); }; if (initAction) { this.valueAction = initVal; }{ this.value = initVal; }; this.prSetViewParams; } value_{ arg val; value = controlSpec.constrain(val); numberView.value = value.round(round); } valueAction_ { arg val; this.value_(val); this.doAction; } doAction { action.value(this) } set { arg label, spec, argAction, initVal, initAction=false; labelView.notNil.if { labelView.string = label.asString }; spec.notNil.if { controlSpec = spec.asSpec }; argAction.notNil.if { action = argAction }; initVal = initVal ? value ? controlSpec.default; if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; } setColors{ arg stringBackground, stringColor,numBackground,numStringColor, numNormalColor, numTypingColor, background ; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)}; unitView.notNil.if{unitView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)}; unitView.notNil.if{unitView.stringColor_(stringColor)};}; numBackground.notNil.if{ numberView.background_(numBackground); }; numNormalColor.notNil.if{ numberView.normalColor_(numNormalColor);}; numTypingColor.notNil.if{ numberView.typingColor_(numTypingColor);}; numStringColor.notNil.if{ numberView.stringColor_(numStringColor);}; background.notNil.if{ view.background=background;}; } font_{ arg font; labelView.notNil.if{labelView.font=font}; unitView.notNil.if{unitView.font=font}; numberView.font=font; } /////// Private methods ///////// prSetViewParams{ // sets resize and alignment for different layouts switch (layout, \line2, { labelView.notNil.if{labelView.resize_(2)}; unitView.notNil.if{unitView.resize_(6)}; numberView.resize_(5); }, \horz, { labelView.notNil.if{ labelView.resize_(4).align_(\right); numberView.resize_(5); unitView.notNil.if{unitView.resize_(6)}; }{ unitView.notNil.if{ unitView.resize_(6)}; numberView.resize_(5); }; }); popUp.if{view.resize_(2)}; } prSubViewBounds{arg rect, hasLabel, hasUnit; var numBounds,labelBounds,sliderBounds; var unitBounds, gap1, gap2, numY; gap1 = gap.copy; gap2 = gap.copy; hasLabel.not.if{ gap1 = 0@0; labelSize=0@0}; hasUnit.not.if{gap2 = 0@0}; switch (layout, \line2, { labelBounds = Rect( // fill the line 0, 0, rect.width, labelSize.y; ); numSize.y=numSize.y-gap1.y; numY=labelBounds.height+gap1.y; unitBounds = Rect( rect.width - unitWidth, // //adjust to fit numY, unitWidth, rect.height-labelSize.y-gap1.y); numBounds = Rect(0, numY, rect.width-unitWidth-gap2.x, rect.height-labelSize.y-gap1.y); // to right }, \horz, { labelSize.y=rect.height; labelBounds = (labelSize.x@labelSize.y).asRect; // to left unitBounds = (unitWidth@labelSize.y).asRect.left_(rect.width-unitWidth); // to right numBounds = Rect( //adjust to fit labelBounds.width+gap1.x, 0, rect.width - labelBounds.width - unitBounds.width - gap1.x - gap2.x , labelBounds.height ); }); ^[labelBounds, numBounds, unitBounds].collect{arg v; v.moveBy(margin.x,margin.y)} } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/Base/EZgui.sc0000664000000000000000000001241112014636263025703 0ustar rootrootEZGui{ // an abstract class var <>labelView, action, globalAction; *new { arg parentView, bounds, label,items, globalAction, initVal=0, initAction=false, labelWidth,labelHeight=20, layout, gap, margin; ^super.new.init(parentView, bounds, label, items, globalAction, initVal, initAction, labelWidth,labelHeight,layout, gap, margin); } init { arg parentView, bounds, label, argItems, argGlobalAction, initVal, initAction, labelWidth, labelHeight, layout, argGap, argMargin; // try to use the parent decorator gap this.prMakeMarginGap(parentView, argMargin, argGap); // init the views (handled by subclasses) this.initViews( parentView, bounds, label, labelWidth,labelHeight,layout ); this.items=argItems ? []; globalAction=argGlobalAction; widget.action={arg obj; items.at(obj.value).value.value(this); globalAction.value(this); }; this.value_(initVal); items.notNil.if{ if(initAction){ items.at(initVal).value.value(this); // You must do this like this globalAction.value(this); // since listView's array is not accessible yet }; this.value_(initVal); }; } initViews{} // override this for your subclass views value{ ^widget.value} value_{|val| widget.value=val} valueAction_{|val| widget.value_(val); this.doAction} doAction {widget.doAction;} items_{ arg assocArray; assocArray = assocArray.collect({ |it| if (it.isKindOf(Association), { it }, { it -> nil }) }); items=assocArray; widget.items=assocArray.collect({|item| item.key}); } item {^items.at(this.value).key} itemFunc {^items.at(this.value).value} addItem{arg name, action; this.insertItem(nil, name, action); } insertItem{ arg index, name, action; var temp; index = index ? items.size; this.items=items.insert(index, name.asSymbol -> action); } removeItemAt{ arg index; var temp; items.removeAt(index); this.items_(items) } replaceItemAt{ arg index, name, action; var temp; name = name ? items.at(index).key; action = action ? items.at(index).value; this.removeItemAt(index); this.insertItem(index, name, action); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/Base/EZListView.sc0000664000000000000000000000306512014636263026672 0ustar rootrootEZListView : EZLists{ initViews{ arg parentView, bounds, label, labelWidth,labelHeight,arglayout; var labelBounds, listBounds; labelWidth = labelWidth ? 80; layout=arglayout ? \vert; labelSize=labelWidth@labelHeight; bounds.isNil.if{bounds= 160@200}; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); // calcualate bounds # labelBounds,listBounds = this.prSubViewBounds(innerBounds, label.notNil); // insert the views label.notNil.if{ //only add a label if desired if (layout==\vert){ labelView = GUI.staticText.new(view, labelBounds).resize_(2); labelView.align = \left; }{ labelView = GUI.staticText.new(view, labelBounds).resize_(4); labelView.align = \right; }; labelView.string = label; }; widget = GUI.listView.new(view, listBounds).resize_(5); } listView{^widget} setColors{arg stringBackground, stringColor, listBackground, listStringColor, selectedStringColor,hiliteColor, background ; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)};}; listBackground.notNil.if{ this.listview.background_(listBackground);}; listStringColor.notNil.if{ this.listview.stringColor_(listStringColor);}; selectedStringColor.notNil.if{ this.listview.selectedStringColor_(selectedStringColor);}; hiliteColor.notNil.if{ this.listview.hiliteColor_(hiliteColor);}; background.notNil.if{ view.background=background;}; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/GUI/viewExtensions.sc0000664000000000000000000000365512014636263027052 0ustar rootroot + FlowView { // place a FlowView on this FlowView flow { arg func,bounds; var f,consumed,b; if(bounds.notNil,{ f = FlowView(this,bounds); func.value(f); ^f }); f = FlowView(this,this.allocateRemaining); func.value(f); consumed = f.resizeToFit; // did we exceed ? if(this.decorator.bounds.containsRect(consumed).not,{ // yes // pretend I just consumed nothing this.didUseAllocated(consumed.resizeTo(0,0)); // goto the next line this.decorator.nextLine; // don't put a StartRow in there, the decorator should auto-flow on resize // take everything b = this.allocateRemaining; // and if its too big for that then it will just have to jutt or scroll over // that's what you asked for. // move the last object there f.bounds = b; // reflow the sub view f.reflowAll.resizeToFit; this.didUseAllocated(f.bounds); },{ this.didUseAllocated(consumed); }); ^f } horz { arg func,bounds,spacing; var comp; comp = GUI.hLayoutView.new(this,bounds ?? { this.indentedRemaining }); try { // not on Qt comp.spacing = spacing ? GUI.skin.gap.x; }; func.value(comp); ^comp } vert { arg func,bounds,spacing; var comp; comp = GUI.vLayoutView.new(this,bounds ?? { this.indentedRemaining }); try { // not on Qt comp.spacing = spacing ? GUI.skin.gap.y; }; func.value(comp); ^comp } comp { arg func,bounds; var comp; comp = GUI.compositeView.new(this,bounds ?? { this.indentedRemaining }); func.value(comp); ^comp } scroll { arg func,bounds, autohidesScrollers=true,autoScrolls=true, hasHorizontalScroller=true,hasVerticalScroller=true; var comp; comp = GUI.scrollView.new(this,bounds ?? { this.bounds }); comp.autohidesScrollers = autohidesScrollers; try { // not on Qt comp.autoScrolls = autoScrolls; }; comp.hasHorizontalScroller = hasHorizontalScroller; comp.hasVerticalScroller = hasVerticalScroller; func.value(comp); ^comp } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/0000775000000000000000000000000012245452763024463 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/SerialPort.sc0000664000000000000000000000467312161364457027107 0ustar rootrootSerialPort { classvar <>devicePattern, allPorts; var dataptr, semaphore; var <>doneAction; *initClass { allPorts = Array[]; ShutDown.add { this.cleanupAll; }; } // device listing *devices { ^(devicePattern ?? { thisProcess.platform.name.switch( \linux, "/dev/tty[A,S,U]*", \osx, "/dev/tty.*", \windows, "COM" ) }).pathMatch } *listDevices { this.devices.do(_.postln); } *new { | port, baudrate(9600), databits(8), stopbit(true), parity(nil), crtscts(false), xonxoff(false) exclusive(false) | if (port.isNumber) { port = this.devices[port] ?? { Error("invalid port index").throw; }; } ^super.new.initSerialPort( port, exclusive, baudrate, databits, stopbit, ( even: 1, odd: 2 ).at(parity) ? 0, crtscts, xonxoff ) } initSerialPort { | ... args | semaphore = Semaphore(0); if ( dataptr.isNil ){ this.prOpen(*args); allPorts = allPorts.add(this); doneAction = { ("SerialPort"+args[0]+"was closed").postln; }; } } isOpen { ^dataptr.notNil } close { if (this.isOpen) { this.prClose; allPorts.remove(this); } } *closeAll { var ports = allPorts; allPorts = Array[]; ports.do(_.close); } *cleanupAll { var ports = allPorts; allPorts = Array[]; ports.do(_.primCleanup); } // non-blocking read next { _SerialPort_Next ^this.primitiveFailed } // blocking read read { var byte; while { (byte = this.next).isNil } { semaphore.wait; }; ^byte } // rx errors since last query rxErrors { _SerialPort_RXErrors } // always blocks put { | byte, timeout=0.005 | if ( dataptr.notNil ){ while { this.prPut(byte).not } { timeout.wait; timeout = timeout * 2; } }{ "SerialPort not open".warn; } } putAll { | bytes, timeout=0.005 | bytes.do { |byte| this.put(byte, timeout); } } // PRIMITIVE prOpen { | ... args | // was: | port, baudRate | but that misses out on all the other args? _SerialPort_Open ^this.primitiveFailed } prClose { _SerialPort_Close ^this.primitiveFailed } primCleanup { _SerialPort_Cleanup ^this.primitiveFailed } prCleanup{ if (this.isOpen) { this.primCleanup; allPorts.remove(this); } } prPut { | byte | _SerialPort_Put ^this.primitiveFailed } prDataAvailable { // callback semaphore.signal; } prDoneAction { // callback this.doneAction.value; // cleanup the port this.prCleanup } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/Score.sc0000664000000000000000000001007412161364457026066 0ustar rootrootScore { var <>score, routine, isPlaying = false; classvar <>program, <>options; *initClass { options = ServerOptions.new; } *new { arg list; ^super.new.init(list); } *newFromFile { arg path; var list; list = thisProcess.interpreter.executeFile(path); ^super.new.init(list); } init { arg list; score = [[0.0, ["/g_new", 1, 0, 0]]] ++ list; this.sort; } add { arg bundle; score = score.add(bundle) } *playFromFile { arg path, server; var list; list = thisProcess.interpreter.executeFile(path); ^this.new(list).play(server); } *play { arg list, server; ^this.new(list).play(server); } sort { score = score.sort({ arg a, b; b[0] >= a[0] }); } play { arg server, clock, quant=0.0; var size, osccmd, timekeep, inserver, rout; isPlaying.not.if({ inserver = server ? Server.default; size = score.size; timekeep = 0; routine = Routine({ size.do { |i| var deltatime, msg; osccmd = score[i]; deltatime = osccmd[0]; msg = osccmd.copyToEnd(1); (deltatime-timekeep).wait; inserver.listSendBundle(inserver.latency, msg); timekeep = deltatime; }; isPlaying = false; }); isPlaying = true; routine.play(clock, quant); }, {"Score already playing".warn;} ); } endTime { ^score.last[0] } startTime { ^score.first[0] } section { arg start = 0, end, configevents; var sectionlist; if(end.isNil) { end = this.endTime }; sectionlist = Array.new; score.do { arg item; if(item[0].inclusivelyBetween(start, end)) { item = item.copy; item[0] = item[0] - start; sectionlist = sectionlist.add(item); } }; sectionlist = sectionlist.add([end - start, [0]]); // add dummy command (cmd_none) if(configevents.notNil, {if(configevents.isArray, {if(configevents[0] == 0.0, {sectionlist = sectionlist.addFirst(configevents)}, {"Configuration events should have a timestamp of 0.0".warn; ^nil})}, {"Configuration events need to be a bundle array: [time, [events]]".warn; ^nil})}); ^this.class.new(sectionlist); } writeOSCFile { arg path, from, to, clock; if(to.notNil or: {from.notNil}) { from = from ? 0.0; to = to ? this.endTime; this.section(from, to).write(path, clock) } { this.write(path, clock) }; } recordNRT { arg oscFilePath, outputFilePath, inputFilePath, sampleRate = 44100, headerFormat = "AIFF", sampleFormat = "int16", options, completionString="", duration = nil, action = nil; this.writeOSCFile(oscFilePath, 0, duration); unixCmd(program + " -N" + oscFilePath.quote + if(inputFilePath.notNil, { inputFilePath.quote }, { "_" }) + outputFilePath.quote + sampleRate + headerFormat + sampleFormat + (options ? Score.options).asOptionsString + completionString, action); } *recordNRT { arg list, oscFilePath, outputFilePath, inputFilePath, sampleRate = 44100, headerFormat = "AIFF", sampleFormat = "int16", options, completionString="", duration = nil, action = nil; this.new(list).recordNRT(oscFilePath, outputFilePath, inputFilePath, sampleRate, headerFormat, sampleFormat, options, completionString, duration, action); } stop { isPlaying.if({routine.stop; isPlaying = false; routine = nil;}, {"Score not playing".warn;} ); } *writeFromFile { arg path, oscFilePath, clock; var list; list = thisProcess.interpreter.executeFile(path); this.write(list, oscFilePath, clock); } *write { arg list, oscFilePath, clock; var osccmd, f, tempoFactor; f = File(oscFilePath, "w"); tempoFactor = (clock ? TempoClock.default).tempo.reciprocal; protect { list.size.do { |i| var msg = list[i].copy; msg[0] = msg[0]* tempoFactor; osccmd = msg.asRawOSC; f.write(osccmd.size).write(osccmd); }; }{ f.close; }; //"done".postln; } write { arg oscFilePath, clock; this.class.write(score, oscFilePath, clock); } saveToFile { arg path; var f; f = File.new(path, "w"); f.putString("[ // SuperCollider Score output " ++ Date.getDate ++ "\n"); score.do{ arg me; f.putString((me).asCompileString ++ ",\n"); }; f.putString("]"); f.close; } storeArgs { ^score } asScore {} } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/asNodeArg.sc0000664000000000000000000000010712014636263026644 0ustar rootroot+ Object { asNodeArg {^this.asUGenInput} // replaced by asUGenInput } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/NetAddr.sc0000664000000000000000000001253412161364457026337 0ustar rootrootNetAddr { var port=0, 65535) {// udp max size. args.clumpBundles.do { |item| if(time.notNil) { time = time + 1e-9 }; // make it a nanosecond later this.sendBundle(time, *item) }; } { this.sendBundle(time, *args) } } sync { arg condition, bundles, latency; // array of bundles that cause async action var resp, id; if (condition.isNil) { condition = Condition.new }; if(bundles.isNil) { id = this.makeSyncResponder(condition); this.sendBundle(latency, ["/sync", id]); condition.wait; } { // not sure what the exact size is, but its about 20000 // this relates to what _NetAddr_SendBundle can send if(bundles.bundleSize > 20000/*65515*/) { // 65515 = 65535 - 16 - 4 (sync msg size) bundles.clumpBundles.do { |item| id = this.makeSyncResponder(condition); this.sendBundle(latency, *(item ++ [["/sync", id]])); if(latency.notNil) { latency = latency + 1e-9 }; condition.wait; } } { id = this.makeSyncResponder(condition); this.sendBundle(latency, *(bundles ++ [["/sync", id]])); condition.wait; } }; // maybe needed: a timeout } makeSyncResponder { arg condition; var id = UniqueID.next; var resp; resp = OSCFunc({|msg| if (msg[1] == id) { resp.free; condition.test = true; condition.signal; }; }, '/synced', this); condition.test = false; ^id } isConnected { ^socket.notNil } connect { | disconnectHandler | if (this.isConnected.not) { this.prConnect; connections.put(this, disconnectHandler); }; } disconnect { if (this.isConnected) { this.prDisconnect; this.prConnectionClosed; }; } == { arg that; ^this.compareObject(that, #[\port, \addr]) } hash { ^this.instVarHash(#[\port, \addr]) } // Asymmetric: "that" may be nil or have nil port (wildcards) matches { arg that; ^this==that or:{ that.isNil or: { this.addr == that.addr and: { that.port.isNil } } } } ip { ^addr.asIPString } hasBundle { ^false } printOn { | stream | super.printOn(stream); stream << $( << this.ip << ", " << port << $) } storeOn { | stream | super.storeOn(stream); stream << $( << "\"" << this.ip << "\", " << port << $) } // PRIVATE prConnect { _NetAddr_Connect ^this.primitiveFailed; } prDisconnect { _NetAddr_Disconnect ^this.primitiveFailed; } prConnectionClosed { // called when connection is closed either by sclang or by peer socket = nil; connections.removeAt(this).value(this); } recover { ^this } } BundleNetAddr : NetAddr { var bundle; var objects; classvar clearClocks = true; classvar <>freeServers = true; classvar <>freeRemote = false; *doOnce { arg object; var f = { this.remove(f); object.doOnCmdPeriod }; this.add(f); } *run { if(clearClocks, { SystemClock.clear; AppClock.clear; // TempoClock.default.clear; }); objects.copy.do({ arg item; item.doOnCmdPeriod; }); if(freeServers, { Server.freeAll(freeRemote); // stop all sounds on local, or remote servers Server.resumeThreads; }); era = era + 1; } *hardRun { SystemClock.clear; AppClock.clear; TempoClock.default.clear; objects.copy.do({ arg item; item.doOnCmdPeriod; }); Server.hardFreeAll; // stop all sounds on local servers Server.resumeThreads; era = era + 1; } } // things to do after startup file executed StartUp : AbstractSystemAction { classvar <>objects, objects; *run { objects.copy.do({ arg item; item.doOnShutDown; }); // "ShutDown done.".postln; } } // things to do on a system reset OnError : AbstractSystemAction { classvar <>objects; *run { objects.copy.do({ arg item; item.doOnError; }); } } AbstractServerAction : AbstractSystemAction { *init { this.objects = IdentityDictionary.new; } *performFunction { arg server, function; if (this.objects.notNil) { this.objects.at(server).copy.do(function); if(server === Server.default) { this.objects.at(\default).copy.do(function) }; this.objects.at(\all).copy.do(function); } } *run { arg server; var selector = this.functionSelector; // selector.postln; this.performFunction(server, { arg obj; obj.perform(selector, server) }); } *functionSelector { ^this.subclassResponsibility(thisMethod) } *add { arg object, server; var list; if (server.isNil) { server = \all }; if (this.objects.isNil) { this.init }; list = this.objects.at(server); if (list.isNil) { list = List.new; this.objects.put(server, list) }; if (list.includes(object).not) { list.add(object) }; } *addToAll { arg object; Server.all.do({ arg s; this.add(object, s) }); } *remove { arg object, server; if(server.isNil) { server = \default }; this.objects !? { this.objects.at(server).remove(object) }; } *removeServer { arg server; this.objects.removeAt(server) } } // things to do after server has booted ServerBoot : AbstractServerAction { classvar <>objects; *functionSelector { ^\doOnServerBoot } } // things to do after server has quit ServerQuit : AbstractServerAction { classvar <>objects; *functionSelector { ^\doOnServerQuit } } // things to do after server has booted and initialised ServerTree : AbstractServerAction { classvar <>objects; *functionSelector { ^\doOnServerTree } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/Buffer.sc0000664000000000000000000005123712245365552026232 0ustar rootrootBuffer { classvar serverCaches; // don't use the setter methods for the vars below // they're private and have no effect on the server var numFrames, <>numChannels, <>sampleRate; var <>path, >doOnInfo; *initClass { serverCaches = IdentityDictionary.new } // doesn't send *new { arg server, numFrames, numChannels, bufnum; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; ^super.newCopyArgs(server, bufnum, numFrames, numChannels).sampleRate_(server.sampleRate).cache; } *alloc { arg server, numFrames, numChannels = 1, completionMessage, bufnum; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; ^super.newCopyArgs(server, bufnum, numFrames, numChannels) .alloc(completionMessage).sampleRate_(server.sampleRate).cache; } *allocConsecutive { |numBufs = 1, server, numFrames, numChannels = 1, completionMessage, bufnum| var bufBase, newBuf; bufBase = bufnum ?? { server.bufferAllocator.alloc(numBufs) }; if(bufBase.isNil) { Error("No block of % consecutive buffer numbers is available.".format(numBufs)).throw }; ^Array.fill(numBufs, { |i| newBuf = Buffer.new(server, numFrames, numChannels, i + bufBase); server.sendMsg(\b_alloc, i + bufBase, numFrames, numChannels, completionMessage.value(newBuf, i)); newBuf.cache }); } alloc { arg completionMessage; server.listSendMsg( this.allocMsg(completionMessage) ) } allocRead { arg argpath,startFrame = 0,numFrames = -1, completionMessage; path = argpath; server.listSendMsg(this.allocReadMsg( argpath,startFrame,numFrames, completionMessage)); } allocReadChannel { arg argpath,startFrame,numFrames = 0, channels = -1, completionMessage; path = argpath; server.listSendMsg(this.allocReadChannelMsg( argpath,startFrame,numFrames, channels, completionMessage)); } allocMsg { arg completionMessage; this.cache; ^["/b_alloc", bufnum, numFrames.asInt, numChannels, completionMessage.value(this)] } allocReadMsg { arg argpath,startFrame = 0,numFrames = -1, completionMessage; this.cache; path = argpath; ^["/b_allocRead",bufnum, path,startFrame,(numFrames ? -1).asInt, completionMessage.value(this)] } allocReadChannelMsg { arg argpath,startFrame = 0,numFrames = -1, channels, completionMessage; this.cache; path = argpath; ^["/b_allocReadChannel",bufnum, path,startFrame, (numFrames ? -1).asInt] ++ channels ++ [completionMessage.value(this)] } // read whole file into memory for PlayBuf etc. // adds a query as a completion message *read { arg server,path,startFrame = 0,numFrames = -1, action, bufnum; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; ^super.newCopyArgs(server, bufnum) .doOnInfo_(action).cache .allocRead(path,startFrame,numFrames,{|buf|["/b_query",buf.bufnum]}); } read { arg argpath, fileStartFrame = 0, numFrames = -1, bufStartFrame = 0, leaveOpen = false, action; this.cache; doOnInfo = action; server.listSendMsg( this.readMsg(argpath,fileStartFrame,numFrames,bufStartFrame, leaveOpen,{|buf|["/b_query",buf.bufnum]} ) ); } *readChannel { arg server,path,startFrame = 0,numFrames = -1, channels, action, bufnum; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; ^super.newCopyArgs(server, bufnum) .doOnInfo_(action).cache .allocReadChannel(path,startFrame,numFrames,channels, {|buf|["/b_query",buf.bufnum]}); } readChannel { arg argpath, fileStartFrame = 0, numFrames = -1, bufStartFrame = 0, leaveOpen = false, channels, action; this.cache; doOnInfo = action; server.listSendMsg( this.readChannelMsg(argpath,fileStartFrame,numFrames,bufStartFrame, leaveOpen,channels,{|buf|["/b_query",buf.bufnum]} ) ); } *readNoUpdate { arg server,path,startFrame = 0,numFrames = -1, bufnum, completionMessage; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; ^super.newCopyArgs(server, bufnum) .allocRead(path,startFrame,numFrames, completionMessage); } readNoUpdate { arg argpath, fileStartFrame = 0, numFrames = -1, bufStartFrame = 0, leaveOpen = false, completionMessage; server.listSendMsg( this.readMsg(argpath,fileStartFrame,numFrames,bufStartFrame, leaveOpen, completionMessage) ); } readMsg { arg argpath, fileStartFrame = 0, numFrames = -1, bufStartFrame = 0, leaveOpen = false, completionMessage; path = argpath; ^["/b_read", bufnum, path, fileStartFrame, (numFrames ? -1).asInt, bufStartFrame, leaveOpen.binaryValue, completionMessage.value(this)] // doesn't set my numChannels etc. } readChannelMsg { arg argpath, fileStartFrame = 0, numFrames = -1, bufStartFrame = 0, leaveOpen = false, channels, completionMessage; path = argpath; ^["/b_readChannel", bufnum, path, fileStartFrame, (numFrames ? -1).asInt, bufStartFrame, leaveOpen.binaryValue] ++ channels ++ [completionMessage.value(this)] // doesn't set my numChannels etc. } // preload a buffer for use with DiskIn *cueSoundFile { arg server,path,startFrame = 0,numChannels= 2, bufferSize=32768,completionMessage; ^this.alloc(server,bufferSize,numChannels,{ arg buffer; buffer.readMsg(path,startFrame,bufferSize,0,true,completionMessage) }).cache; } cueSoundFile { arg path,startFrame,completionMessage; this.path_(path); server.listSendMsg( this.cueSoundFileMsg(path,startFrame,completionMessage) ) } cueSoundFileMsg { arg path,startFrame = 0,completionMessage; ^["/b_read", bufnum,path,startFrame,numFrames.asInt,0,1,completionMessage.value(this) ] } // transfer a collection of numbers to a buffer through a file *loadCollection { arg server, collection, numChannels = 1, action; var data, sndfile, path, bufnum, buffer; server = server ? Server.default; bufnum = server.bufferAllocator.alloc(1); if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; server.isLocal.if({ if(collection.isKindOf(RawArray).not) { collection = collection.as(FloatArray) }; sndfile = SoundFile.new; sndfile.sampleRate = server.sampleRate; sndfile.numChannels = numChannels; path = PathName.tmp ++ sndfile.hash.asString; if(sndfile.openWrite(path), { sndfile.writeData(collection); sndfile.close; ^super.newCopyArgs(server, bufnum) .cache.doOnInfo_({ |buf| if(File.delete(path), { buf.path = nil}, {("Could not delete data file:" + path).warn;}); action.value(buf); }).allocRead(path, 0, -1,{|buf|["/b_query",buf.bufnum]}); }, {"Failed to write data".warn; ^nil} ); }, {"cannot use loadCollection with a non-local Server".warn; ^nil}); } loadCollection { arg collection, startFrame = 0, action; var data, sndfile, path; server.isLocal.if({ if(collection.isKindOf(RawArray).not, {data = collection.collectAs({|item| item}, FloatArray)}, {data = collection;} ); if ( collection.size > ((numFrames - startFrame) * numChannels), { "Collection larger than available number of Frames".warn }); sndfile = SoundFile.new; sndfile.sampleRate = server.sampleRate; sndfile.numChannels = numChannels; path = PathName.tmp ++ sndfile.hash.asString; if(sndfile.openWrite(path), { sndfile.writeData(data); sndfile.close; this.read(path, bufStartFrame: startFrame, action: { |buf| if(File.delete(path), { buf.path = nil }, {("Could not delete data file:" + path).warn;}); action.value(buf); }); }, {"Failed to write data".warn;} ); }, {"cannot do fromCollection with a non-local Server".warn;}); } // send a Collection to a buffer one UDP sized packet at a time *sendCollection { arg server, collection, numChannels = 1, wait = -1, action; var buffer = this.new(server, ceil(collection.size / numChannels), numChannels); forkIfNeeded { buffer.alloc; server.sync; buffer.sendCollection(collection, 0, wait, action); } ^buffer; } sendCollection { arg collection, startFrame = 0, wait = -1, action; var collstream, collsize, bundsize; if(collection.isSequenceableCollection and: { startFrame.isNumber and: { wait.isNumber } }) { collstream = CollStream.new; collstream.collection = collection; collsize = collection.size; if ( collsize > ((numFrames - startFrame) * numChannels), { "Collection larger than available number of Frames".warn }); this.streamCollection(collstream, collsize, startFrame * numChannels, wait, action); } { MethodError("Invalid arguments to Buffer:sendCollection", this).throw; }; } // called internally streamCollection { arg collstream, collsize, startFrame = 0, wait = -1, action; var bundsize, pos; { // wait = -1 allows an OSC roundtrip between packets // wait = 0 might not be safe in a high traffic situation // maybe okay with tcp pos = collstream.pos; while { pos < collsize } { // 1626 max size for setn under udp bundsize = min(1626, collsize - pos); server.listSendMsg(['/b_setn', bufnum, pos + startFrame, bundsize] ++ Array.fill(bundsize, { collstream.next })); pos = collstream.pos; if(wait >= 0) { wait.wait } { server.sync }; }; action.value(this); }.forkIfNeeded; } // these next two get the data and put it in a float array which is passed to action loadToFloatArray { arg index = 0, count = -1, action; var msg, cond, path, file, array; { path = PathName.tmp ++ this.hash.asString; msg = this.write(path, "aiff", "float", count, index); server.sync; file = SoundFile.new; protect { file.openRead(path); array = FloatArray.newClear(file.numFrames * file.numChannels); file.readData(array); } { file.close; if(File.delete(path).not) { ("Could not delete data file:" + path).warn }; }; action.value(array, this); }.forkIfNeeded; } // risky without wait getToFloatArray { arg index = 0, count, wait = 0.01, timeout = 3, action; var refcount, array, pos, getsize, resp, done = false; pos = index = index.asInteger; count = (count ? (numFrames * numChannels)).asInteger; array = FloatArray.newClear(count); refcount = (count / 1633).roundUp; count = count + pos; //("refcount" + refcount).postln; resp = OSCFunc({ arg msg; if(msg[1] == bufnum, { //("received" + msg).postln; array = array.overWrite(FloatArray.newFrom(msg.copyToEnd(4)), msg[2] - index); refcount = refcount - 1; //("countDown" + refcount).postln; if(refcount <= 0, {done = true; resp.clear; action.value(array, this); }); }); }, '/b_setn', server.addr); { while({pos < count}, { // 1633 max size for getn under udp getsize = min(1633, count - pos); //("sending from" + pos).postln; server.listSendMsg(this.getnMsg(pos, getsize)); pos = pos + getsize; if(wait >= 0) { wait.wait } { server.sync }; }); }.forkIfNeeded; // lose the responder if the network choked SystemClock.sched(timeout, { done.not.if({ resp.free; "Buffer-streamToFloatArray failed!".warn; "Try increasing wait time".postln;}); }); } write { arg path, headerFormat = "aiff", sampleFormat = "int24", numFrames = -1, startFrame = 0,leaveOpen = false, completionMessage; path = path ?? { thisProcess.platform.recordingsDir +/+ "SC_" ++ Date.localtime.stamp ++ "." ++ headerFormat }; server.listSendMsg( this.writeMsg(path, headerFormat, sampleFormat, numFrames, startFrame, leaveOpen, completionMessage) ); } writeMsg { arg path,headerFormat="aiff",sampleFormat="int24",numFrames = -1, startFrame = 0,leaveOpen = false, completionMessage; // doesn't change my path ^["/b_write", bufnum, path, headerFormat,sampleFormat, numFrames, startFrame, leaveOpen.binaryValue, completionMessage.value(this)]; // writeEnabled = true; } free { arg completionMessage; server.listSendMsg( this.freeMsg(completionMessage) ); } freeMsg { arg completionMessage; var msg; this.uncache; server.bufferAllocator.free(bufnum); msg = ["/b_free", bufnum, completionMessage.value(this)]; bufnum = numFrames = numChannels = sampleRate = path = nil; ^msg } *freeAll { arg server; var b; server = server ? Server.default; server.bufferAllocator.blocks.do({ arg block; (block.address .. block.address + block.size - 1).do({ |i| b = b.add( ["/b_free", i] ); }); server.bufferAllocator.free(block.address); }); server.sendBundle(nil, *b); this.clearServerCaches(server); } zero { arg completionMessage; server.listSendMsg(this.zeroMsg(completionMessage)); } zeroMsg { arg completionMessage; ^["/b_zero", bufnum , completionMessage.value(this) ] } set { arg index,float ... morePairs; server.listSendMsg(["/b_set",bufnum,index,float] ++ morePairs); } setMsg { arg index,float ... morePairs; ^["/b_set",bufnum,index,float] ++ morePairs; } setn { arg ... args; server.sendMsg(*this.setnMsg(*args)); } setnMsgArgs{arg ... args; var nargs; nargs = List.new; args.pairsDo{ arg control, moreVals; if(moreVals.isArray,{ nargs.addAll([control, moreVals.size]++ moreVals) },{ nargs.addAll([control, 1, moreVals]); }); }; ^nargs; } setnMsg { arg ... args; ^["/b_setn",bufnum] ++ this.setnMsgArgs(*args); } get { arg index, action; OSCpathResponder(server.addr,['/b_set',bufnum,index],{ arg time, r, msg; action.value(msg.at(3)); r.remove }).add; server.listSendMsg(["/b_get",bufnum,index]); } getMsg { arg index; ^["/b_get",bufnum,index]; } getn { arg index, count, action; OSCpathResponder(server.addr,['/b_setn',bufnum,index],{arg time, r, msg; action.value(msg.copyToEnd(4)); r.remove } ).add; server.listSendMsg(["/b_getn",bufnum,index, count]); } getnMsg { arg index, count; ^["/b_getn",bufnum,index, count]; } fill { arg startAt,numFrames,value ... more; server.listSendMsg(["/b_fill",bufnum,startAt,numFrames.asInt,value] ++ more); } fillMsg { arg startAt,numFrames,value ... more; ^["/b_fill",bufnum,startAt,numFrames.asInt,value] ++ more; } normalize { arg newmax=1, asWavetable=false; server.listSendMsg(["/b_gen",bufnum,if(asWavetable, "wnormalize", "normalize"),newmax]); } normalizeMsg { arg newmax=1, asWavetable=false; ^["/b_gen",bufnum,if(asWavetable, "wnormalize", "normalize"),newmax]; } gen { arg genCommand, genArgs, normalize=true,asWavetable=true,clearFirst=true; server.listSendMsg(["/b_gen",bufnum,genCommand, normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ genArgs) } genMsg { arg genCommand, genArgs, normalize=true,asWavetable=true,clearFirst=true; ^["/b_gen",bufnum,genCommand, normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ genArgs; } sine1 { arg amps,normalize=true,asWavetable=true,clearFirst=true; server.listSendMsg(["/b_gen",bufnum,"sine1", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ amps) } sine2 { arg freqs, amps,normalize=true,asWavetable=true,clearFirst=true; server.listSendMsg(["/b_gen",bufnum,"sine2", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ [freqs, amps].lace(freqs.size * 2)) } sine3 { arg freqs, amps, phases,normalize=true,asWavetable=true,clearFirst=true; server.listSendMsg(["/b_gen",bufnum,"sine3", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ [freqs, amps, phases].lace(freqs.size * 3)) } cheby { arg amplitudes,normalize=true,asWavetable=true,clearFirst=true; server.listSendMsg(["/b_gen",bufnum,"cheby", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ amplitudes) } sine1Msg { arg amps,normalize=true,asWavetable=true,clearFirst=true; ^["/b_gen",bufnum,"sine1", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ amps } sine2Msg { arg freqs, amps,normalize=true,asWavetable=true,clearFirst=true; ^["/b_gen",bufnum,"sine2", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ [freqs, amps].lace(freqs.size * 2) } sine3Msg { arg freqs, amps, phases,normalize=true,asWavetable=true,clearFirst=true; ^["/b_gen",bufnum,"sine3", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ [freqs, amps, phases].lace(freqs.size * 3) } chebyMsg { arg amplitudes,normalize=true,asWavetable=true,clearFirst=true; ^["/b_gen",bufnum,"cheby", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ amplitudes } copyData { arg buf, dstStartAt = 0, srcStartAt = 0, numSamples = -1; server.listSendMsg( this.copyMsg(buf, dstStartAt, srcStartAt, numSamples) ) } copyMsg { arg buf, dstStartAt = 0, srcStartAt = 0, numSamples = -1; ^["/b_gen", buf.bufnum, "copy", dstStartAt, bufnum, srcStartAt, numSamples] } // close a file, write header, after DiskOut usage close { arg completionMessage; server.listSendMsg( this.closeMsg(completionMessage) ); } closeMsg { arg completionMessage; ^["/b_close", bufnum, completionMessage.value(this) ]; } query { OSCFunc({ arg msg; Post << "bufnum : " << msg[1] << Char.nl << "numFrames : " << msg[2] << Char.nl << "numChannels : " << msg[3] << Char.nl << "sampleRate : " << msg[4] << Char.nl << Char.nl; }, '/b_info', server.addr).oneShot; server.sendMsg("/b_query",bufnum) } updateInfo { |action| // add to the array here. That way, update will be accurate even if this buf // has been freed this.cache; doOnInfo = action; server.sendMsg("/b_query", bufnum); } // cache Buffers for easy info updating cache { Buffer.initServerCache(server); serverCaches[server][bufnum] = this; } uncache { if(serverCaches[server].notNil,{ serverCaches[server].removeAt(bufnum); }); if(serverCaches[server].size == 1) { // the 1 item would be the responder // if there is more than 1 item then the rest are cached buffers // else we can remove. // cx: tho i don't see why its important. it will just have to be added // back when the next buffer is added and the responder is removed when // the server reboots Buffer.clearServerCaches(server); } } *initServerCache { |server| serverCaches[server] ?? { serverCaches[server] = IdentityDictionary.new; serverCaches[server][\responder] = OSCFunc({ |m| var buffer = serverCaches[server][m[1]]; if(buffer.notNil) { buffer.numFrames = m[2]; buffer.numChannels = m[3]; buffer.sampleRate = m[4]; buffer.queryDone; }; }, '/b_info', server.addr).fix; NotificationCenter.register(server,\newAllocators,this,{ this.clearServerCaches(server); }); } } *clearServerCaches { |server| if(serverCaches[server].notNil) { serverCaches[server][\responder].free; serverCaches.removeAt(server); } } *cachedBuffersDo { |server, func| var i = 0; serverCaches[server] !? { serverCaches[server].keysValuesDo({ |key, value| if(key.isNumber) { func.value(value, i); i = i + 1 }; }); } } *cachedBufferAt { |server, bufnum| ^serverCaches[server].tryPerform(\at, bufnum) } // called from Server when b_info is received queryDone { doOnInfo.value(this); doOnInfo = nil; } printOn { arg stream; stream << this.class.name << "(" <<* [bufnum,numFrames,numChannels,sampleRate,path] <<")"; } *loadDialog { arg server,startFrame = 0,numFrames, action, bufnum; var buffer; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; buffer = super.newCopyArgs(server, bufnum).cache; File.openDialog("Select a file...",{ arg path; buffer.doOnInfo_(action) .allocRead(path,startFrame,numFrames, {["/b_query",buffer.bufnum]}) }); ^buffer; } play { arg loop = false, mul = 1; ^{ var player; player = PlayBuf.ar(numChannels,bufnum,BufRateScale.kr(bufnum), loop: loop.binaryValue); loop.not.if(FreeSelfWhenDone.kr(player)); player * mul; }.play(server); } duration { ^numFrames / sampleRate } asUGenInput { ^this.bufnum } asControlInput { ^this.bufnum } asBufWithValues { ^this } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/asDefName.sc0000664000000000000000000000313312245365552026634 0ustar rootroot+ SynthDef { asSynthDef { ^this } asDefName { ^name } } + Object { asSynthDef { error("Cannot convert this object to a SynthDef:" + this); this.dump; ^nil } asDefName { ^this.asSynthDef.name } } + String { asDefName { ^this } } + Symbol { asDefName { ^this.asString } } + Function { /* this is mainly for {}.play and Synth({ }) Synth({ SinOsc.ar }) or: Synth({ Out.ar(0,SinOsc.ar) }) it inserts an Out only if it needs it */ asDefName { // won't work immediately for Synth.new var def; def = this.asSynthDef; def.send(Server.default); ^def.name } asSynthDef { arg rates, prependArgs, outClass=\Out, fadeTime, name; ^GraphBuilder.wrapOut(name ?? { this.identityHash.abs.asString }, this, rates, prependArgs, outClass, fadeTime ); } play { arg target, outbus = 0, fadeTime = 0.02, addAction=\addToHead, args; var def, synth, server, bytes, synthMsg; target = target.asTarget; server = target.server; if(server.serverRunning.not) { ("server '" ++ server.name ++ "' not running.").warn; ^nil }; def = this.asSynthDef( fadeTime:fadeTime, name: SystemSynthDefs.generateTempName ); synth = Synth.basicNew(def.name, server); // if notifications are enabled on the server, // use the n_end signal to remove the temp synthdef if(server.notified) { OSCpathResponder(server.addr, ['/n_end', synth.nodeID], { |time, resp, msg| server.sendMsg(\d_free, def.name); resp.remove; }).add; }; synthMsg = synth.newMsg(target, [\i_out, outbus, \out, outbus] ++ args, addAction); def.doSend(server, synthMsg); ^synth } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/GeneralHIDSpec.sc0000664000000000000000000000623012245365552027527 0ustar rootrootGeneralHIDSpec{ classvar <>all,cmdPathIndices; var <>pathResponders; var <>maxPathSize = 0; *new { arg addr, cmdName, action, pathSize; ^super.new(addr, cmdName, action).initPathSize(pathSize); } initPathSize { arg pathSize; maxPathSize = pathSize; pathResponders = Set.new; } value { arg time, msg; var cmdPath, match, responder; super.value(time, msg); if (maxPathSize.notNil, { cmdPath = [cmdName] ++ msg[1..maxPathSize]; responder = OSCpathResponder(addr, cmdPath); match = pathResponders.findMatch(responder); if (match.notNil, { match.value(time, msg); }); (maxPathSize - 1).do({ arg i; responder.path.removeAt(responder.path.size - 1); match = pathResponders.findMatch(responder); if (match.notNil, { match.value(time, msg); }); }); }); } addChild { arg responder; var old; old = pathResponders.findMatch(responder); if(old.notNil,{ pathResponders.remove(old) }); pathResponders.add(responder); if(responder.path.size > maxPathSize) { maxPathSize = responder.path.size }; } removeChild { arg responder; pathResponders.remove(responder); if(responder.path.size == maxPathSize) { maxPathSize = pathResponders.maxValue({ |resp| resp.path.size }) ? 0; }; if(this.isEmpty) { this.remove }; } isEmpty { ^(nodes.size + pathResponders.size) == 0 } } OSCpathResponder : OSCresponder { var <>path; var <>dispatcher; *new { arg addr, cmdPath, action; var cmdName, path; #cmdName ...path = cmdPath; ^super.new(addr, cmdName, action).path_(path); } findDispatcher { var responder, match, pathIndices; responder = OSCpathDispatcher(addr, cmdName, nil, path.size); match = OSCresponder.all.findMatch(responder); if(match.isNil, { ^responder.add }); if (match.class === OSCresponder, { match.remove; responder.nodes_([match]); ^responder.add }); if (match.class === OSCMultiResponder, { match.remove; responder.nodes_(match.nodes); ^responder.add; }); ^match; } add { dispatcher = this.findDispatcher; dispatcher.addChild(this); } remove { dispatcher.removeChild(this); } == { arg that; ^that respondsTo: \path and: { path == that.path } } hash { ^path.hash } } /* ( var s, commandpath, response, aSynth, nodeID, triggerID; s = Server.local; s.boot; triggerID = 1; aSynth = {arg freq = 1, triggerID = 1; SendTrig.kr(SinOsc.kr(freq), triggerID, 666); }.play; nodeID = aSynth.nodeID; commandpath = ['/tr', nodeID, triggerID]; response = { arg time, responder, message; message.postln }; o = OSCpathResponder(s.addr, commandpath, response); o.add; ) o.remove ( var s, commandpath, response, aSynth, nodeID, triggerID; s = Server.local; commandpath = ['/tr', nil, triggerID]; response = { arg time, responder, message; message.postln }; o = OSCpathResponder(s.addr, commandpath, response); o.add; ) */ SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/OSC.sc0000664000000000000000000001310012014636263025422 0ustar rootroot// this is probably not working anymore. see NetAddr.sc instead for the newer way. /* // Open Sound Control support OSCNode { classvar <>sc; // this contains the "/sc" default behaviour for all input ports. // a not-very-secure password for access to the compiler // setting password to a Symbol opens SC to potential hacking classvar <>password; var children, <>function, <>value, oscNode; *closeAll { if (openPorts.notNil, { openPorts.copy.do({ arg port; port.close; }); }); } close { openPorts.remove(this); this.prClose; } // PRIVATE prClose { _OSCPort_Close ^this.primitiveFailed; } addOpenPort { if (openPorts.isNil, { openPorts = Array.new(4); }); openPorts = openPorts.add(this); } } OSCInPort : OSCPort { // UDP port for incoming OSC messages *new { arg portID, oscNode; ^super.new.init(portID, oscNode) } reply { arg oscAddress ... args; _OSCInPort_Reply ^this.primitiveFailed; } // PRIVATE init { arg argPortID, argOSCNode; portID = argPortID; oscNode = argOSCNode; this.addOpenPort; this.prInit } prInit { _OSCInPort_Init ^this.primitiveFailed; } } OSCOutPort : OSCPort { // UDP port for outgoing OSC messages var func; value { this.subclassResponsibility(thisMethod) } valueArray {arg args; ^this.value(*args) } // needed to work in FunctionLists } ///////////////////// OSC OSCMessageDispatcher : AbstractWrappingDispatcher { wrapFunc {|funcProxy| var func, srcID, recvPort, argTemplate; func = funcProxy.func; srcID = funcProxy.srcID; recvPort = funcProxy.recvPort; argTemplate = funcProxy.argTemplate; if(argTemplate.notNil, { func = OSCArgsMatcher(argTemplate, func)}); ^case( { srcID.notNil && recvPort.notNil }, { OSCFuncBothMessageMatcher(srcID, recvPort, func) }, { srcID.notNil }, { OSCFuncAddrMessageMatcher(srcID, func) }, { recvPort.notNil }, { OSCFuncRecvPortMessageMatcher(recvPort, func) }, { func } ); } getKeysForFuncProxy {|funcProxy| ^[funcProxy.path];} value {|msg, time, addr, recvPort| active[msg[0]].value(msg, time, addr, recvPort);} register { thisProcess.addOSCRecvFunc(this); registered = true; } unregister { thisProcess.removeOSCRecvFunc(this); registered = false; } typeKey { ^('OSC unmatched').asSymbol } } OSCMessagePatternDispatcher : OSCMessageDispatcher { value {|msg, time, addr, recvPort| var pattern; pattern = msg[0]; active.keysValuesDo({|key, func| if(key.matchOSCAddressPattern(pattern), {func.value(msg, time, addr, recvPort);}); }) } typeKey { ^('OSC matched').asSymbol } } OSCFunc : AbstractResponderFunc { classvar <>defaultDispatcher, <>defaultMatchingDispatcher, traceFunc, traceRunning = false; var messageType; *new {|messageType| ^super.new.messageType_(messageType) } getKeysForFuncProxy {|funcProxy| ^(funcProxy.msgNum ? (0..127)).asArray;} // noteNum, etc. value {|src, chan, num, val| active[num].value(val, num, chan, src);} register { MIDIIn.perform(messageType.asSetter, MIDIIn.perform(messageType.asGetter).addFunc(this)); registered = true; } unregister { MIDIIn.perform(messageType.asSetter, MIDIIn.perform(messageType.asGetter).removeFunc(this)); registered = false; } // wrapper objects based on arg type and testing requirements wrapFunc {|funcProxy| var func, chan, srcID, argTemplate; func = funcProxy.func; chan = funcProxy.chan; srcID = funcProxy.srcID; argTemplate = funcProxy.argTemplate; if(argTemplate.notNil, { func = MIDIValueMatcher(argTemplate, func)}); ^case( { srcID.notNil && chan.isArray }, {MIDIFuncBothCAMessageMatcher(chan, srcID, func)}, { srcID.notNil && chan.notNil }, {MIDIFuncBothMessageMatcher(chan, srcID, func)}, { srcID.notNil }, {MIDIFuncSrcMessageMatcher(srcID, func)}, { chan.isArray }, {MIDIFuncChanArrayMessageMatcher(chan, func)}, { chan.notNil }, {MIDIFuncChanMessageMatcher(chan, func)}, { func } ); } typeKey { ^('MIDI ' ++ messageType).asSymbol } } // for \touch, \program, \bend MIDIMessageDispatcherNV : MIDIMessageDispatcher { getKeysForFuncProxy {|funcProxy| ^(funcProxy.chan ? (0..15)).asArray;} // chan value {|src, chan, val| active[chan].value(val, chan, src);} // wrapper objects based on arg type and testing requirements wrapFunc {|funcProxy| var func, chan, srcID, argTemplate; func = funcProxy.func; chan = funcProxy.chan; srcID = funcProxy.srcID; argTemplate = funcProxy.argTemplate; if(argTemplate.notNil, { func = MIDIValueMatcher(argTemplate, func)}); ^case( { srcID.notNil }, {MIDIFuncSrcMessageMatcherNV(srcID, func)}, { func } ); } } // for \sysex MIDISysexDispatcher : MIDIMessageDispatcher { getKeysForFuncProxy {|funcProxy| ^(funcProxy.srcID ? \all)} // chan value {|srcID, data| active[srcID].value(data, srcID); active[\all].value(data, srcID); } wrapFunc {|funcProxy| var func, srcID, argTemplate; func = funcProxy.func; srcID = funcProxy.srcID; argTemplate = funcProxy.argTemplate; if(argTemplate.notNil, { func = MIDIValueMatcher(argTemplate, func)}); ^func; } } MIDIFunc : AbstractResponderFunc { classvar <>defaultDispatchers, traceFuncs, traceRunning = false; var all; // same as other def classes, do we need a setter really? var verbose = false, dt, <>stopTest, presets.size, { presets = presets.add(values); }); presets.put(presetIndex, values); } recall { if (presetIndex < presets.size, { values = presets.at(presetIndex).copy; // set gui elems and synth controls }); } save { presets.writeArchive("server/presets/" ++ name ++ ".scpreset"); } load { var filename; filename = "server/presets/" ++ name ++ ".scpreset"; if (File.exists(filename), { presets = Object.readArchive(filename); }); } start { var msg; isOn = true; msg = ["/s_new", name, id, 0]; values.keysValuesDo({ arg key, value; msg = msg.addAll([key, value]); }); server.addr.sendBundle(nil, msg); } stop { isOn = false; server.sendMsg("/n_set", id, \gate, 0); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/Engine.sc0000664000000000000000000001744212161364457026226 0ustar rootrootNodeIDAllocator { var 31) { "NodeIDAllocator user id > 31".error; ^nil }; ^super.newCopyArgs(user, initTemp).reset } reset { mask = user << 26; temp = initTemp; perm = 2; permFreed = IdentitySet.new; } alloc { var x; x = temp; temp = (x + 1).wrap(initTemp, 0x03FFFFFF); ^x | mask } allocPerm { var x; if(permFreed.size > 0) { x = permFreed.minItem; permFreed.remove(x); } { x = perm; perm = (x + 1).min(initTemp - 1); } ^x | mask } freePerm { |id| // should not add a temp node id to the freed-permanent collection id = id bitAnd: 0x03FFFFFF; if(id < initTemp) { permFreed.add(id) } } } PowerOfTwoBlock { var next; *new { arg address, size; ^super.newCopyArgs(address, size) } } PowerOfTwoAllocator { // THIS IS THE RECOMMENDED ALLOCATOR FOR BUSES AND BUFFERS var size, array, freeLists, pos=0; *new { arg size, pos=0; ^super.newCopyArgs(size, Array.newClear(size), Array.newClear(32), pos) } alloc { arg n; var sizeClass, node, address; n = n.nextPowerOfTwo; sizeClass = n.log2Ceil; node = freeLists.at(sizeClass); if (node.notNil, { freeLists.put(sizeClass, node.next); ^node.address }); if (pos + n <= size, { array.put(pos, PowerOfTwoBlock(pos, n)); address = pos; pos = pos + n; ^address }); ^nil } free { arg address; var node, sizeClass,next; if((node = array.at(address)).notNil,{ sizeClass = node.size.log2Ceil; node.next = freeLists.at(sizeClass); freeLists.put(sizeClass, node); array.put(address, nil); }); } blocks { ^array.select({ arg b; b.notNil }) } } LRUNumberAllocator { // implements a least recently used ID allocator. var lo, hi; var array, size, head=0, tail=0; *new { arg lo, hi; ^super.newCopyArgs(lo, hi).init } init { size = hi-lo+1; array = Array.newClear(size); for(lo, hi-1, { arg i, j; array.put(j, i) }); head = size-1; tail=0; } free { arg id; var nextIndex; nextIndex = (head+1) % size; if ( nextIndex == tail, { ^nil }); // full array.put(head, id); head = nextIndex; } alloc { var id; if (head == tail, { ^nil }); // empty id = array.at(tail); tail = (tail+1) % size; ^id } } StackNumberAllocator { var lo, hi, freeList, next; *new { arg lo, hi; ^super.newCopyArgs(lo, hi).init } init { next = lo - 1; } alloc { if (freeList.size > 0, { ^freeList.pop }); if (next < hi, { ^next = next + 1; }); ^nil } free { arg inIndex; freeList = freeList.add(inIndex); } } RingNumberAllocator { var lo, hi, next; *new { arg lo, hi; ^super.newCopyArgs(lo, hi).init } init { next = hi; } alloc { ^next = (next + 1).wrap(lo,hi) } } // by hjh: for better handling of dynamic allocation ContiguousBlock { var used = false; // assume free; owner must say otherwise *new { |start, size| ^super.newCopyArgs(start, size) } address { ^start } adjoins { |block| ^(start < block.start and: { start + size >= block.start }) or: { start > block.start and: { block.start + block.size >= start } } } join { |block| var newstart; this.adjoins(block).if({ ^this.class.new(newstart = min(start, block.start), max(start + size, block.start + block.size) - newstart) }, { ^nil }); } split { |span| (span < size).if({ ^[this.class.new(start, span), this.class.new(start + span, size - span)] }, { (span == size).if({ ^[this, nil] }, { ^nil }); }); } storeArgs { ^[start, size, used] } printOn { |stream| this.storeOn(stream) } } ContiguousBlockAllocator { var size, array, freed, pos, top; *new { |size, pos = 0| ^super.newCopyArgs(size, Array.newClear(size).put(pos, ContiguousBlock(pos, size-pos)), IdentityDictionary.new, pos, pos); } alloc { |n = 1| var block; (block = this.findAvailable(n)).notNil.if({ ^this.prReserve(block.start, n, block).start }, { ^nil }); } reserve { |address, size = 1, warn = true| var block, new; ((block = array[address] ?? { this.findNext(address) }).notNil and: { block.used and: { address + size > block.start } }).if({ warn.if({ "The block at (%, %) is already in use and cannot be reserved." .format(address, size).warn; }); }, { (block.start == address).if({ new = this.prReserve(address, size, block); ^new; }, { ((block = this.findPrevious(address)).notNil and: { block.used and: { block.start + block.size > address } }).if({ warn.if({ "The block at (%, %) is already in use and cannot be reserved." .format(address, size).warn; }); }, { new = this.prReserve(address, size, nil, block); ^new; }); }); }); ^nil } free { |address| var block, prev, next, temp; // this 'if' prevents an error if a Buffer object is freed twice if(address.isNil) { ^this }; ((block = array[address]).notNil and: { block.used }).if({ block.used = false; this.addToFreed(block); ((prev = this.findPrevious(address)).notNil and: { prev.used.not }).if({ (temp = prev.join(block)).notNil.if({ // if block is the last one, reduce the top (block.start == top).if({ top = temp.start }); array[temp.start] = temp; array[block.start] = nil; this.removeFromFreed(prev).removeFromFreed(block); (top > temp.start).if({ this.addToFreed(temp); }); block = temp; }); }); ((next = this.findNext(block.start)).notNil and: { next.used.not }).if({ (temp = next.join(block)).notNil.if({ // if next is the last one, reduce the top (next.start == top).if({ top = temp.start }); array[temp.start] = temp; array[next.start] = nil; this.removeFromFreed(next).removeFromFreed(block); (top > temp.start).if({ this.addToFreed(temp); }); }); }); }); } blocks { ^array.select({ arg b; b.notNil and: { b.used } }) } findAvailable { |n| (freed[n].size > 0).if({ ^freed[n].choose }); freed.keysValuesDo({ |size, set| (size >= n and: { set.size > 0 }).if({ ^set.choose }); }); (top + n > size or: { array[top].used }).if({ ^nil }); ^array[top] } addToFreed { |block| freed[block.size].isNil.if({ freed[block.size] = IdentitySet.new }); freed[block.size].add(block); } removeFromFreed { |block| freed[block.size].tryPerform(\remove, block); // I tested without gc; performance is about half as efficient without it (freed[block.size].size == 0).if({ freed.removeAt(block.size) }); } findPrevious { |address| forBy(address-1, pos, -1, { |i| array[i].notNil.if({ ^array[i] }); }); ^nil } findNext { |address| var temp; (temp = array[address]).notNil.if({ ^array[temp.start + temp.size] }, { for(address+1, top, { |i| array[i].notNil.if({ ^array[i] }); }); }); ^nil } prReserve { |address, size, availBlock, prevBlock| var new, leftover; (availBlock.isNil and: { prevBlock.isNil }).if({ prevBlock = this.findPrevious(address); }); availBlock = availBlock ? prevBlock; (availBlock.start < address).if({ #leftover, availBlock = this.prSplit(availBlock, address - availBlock.start, false); }); ^this.prSplit(availBlock, size, true)[0]; } prSplit { |availBlock, n, used = true| var new, leftover; #new, leftover = availBlock.split(n); new.used = used; this.removeFromFreed(availBlock); used.not.if({ this.addToFreed(new) }); array[new.start] = new; leftover.notNil.if({ array[leftover.start] = leftover; top = max(top, leftover.start); (top > leftover.start).if({ this.addToFreed(leftover); }); }); ^[new, leftover] } debug { |text| Post << text << ":\n\nArray:\n"; array.do({ |item, i| item.notNil.if({ Post << i << ": " << item << "\n"; }); }); Post << "\nFree sets:\n"; freed.keysValuesDo({ |size, set| Post << size << ": " <<< set << "\n"; }); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/extSystemActions.sc0000664000000000000000000000114712014636263030334 0ustar rootroot+ Server { onBootAdd { arg object; ServerBoot.add(object, this); } onBootRemove { arg object; ServerBoot.remove(object, this); } onQuitAdd { arg object; ServerQuit.add(object, this); } onQuitRemove { arg object; ServerQuit.remove(object, this); } } + Function { doOnStartUp { this.value } doOnCmdPeriod { this.value } doOnShutDown { this.value } doOnError { this.value } doOnServerBoot { arg server; this.value(server) } doOnServerQuit { arg server; this.value(server) } doOnServerTree { arg server; this.value(server) } } + Object { doOnCmdPeriod { ^this.cmdPeriod } // compatibility } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/NodeWatcher.sc0000664000000000000000000001023512245365552027215 0ustar rootroot//watches a server address for node-related messages AbstractNodeWatcher { var all; *initClass { all = IdentityDictionary.new; CmdPeriod.add(this); } *cmdPeriod { all.do { arg item; item.clear } } *newFrom { arg server; var res; res = all.at(server.name); if(res.isNil, { res = this.new(server); res.start; all.put(server.name, res) }); ^res } *register { arg node, assumePlaying=false; var watcher; watcher = this.newFrom(node.server); watcher.register(node, assumePlaying); } *unregister { arg node; var watcher; watcher = this.newFrom(node.server); watcher.unregister(node); } cmds { ^#["/n_go", "/n_end", "/n_off", "/n_on"] } respond { arg method, msg; var node, group; node = nodes.at(msg.at(1)); if(node.notNil, { group = nodes.at(msg.at(2)); this.performList(method, node, group) }) } clear { // we must copy 'nodes' // b/c a /n_end dependant might add or remove nodes // from the collection // NEVER iterate over a collection that might change nodes.copy.do({ arg node; node.isPlaying = false; node.isRunning = false; node.changed(\n_end); }); nodes = IdentityDictionary.new } register { arg node, assumePlaying=false; if(server.serverRunning.not) { nodes.removeAll; ^this }; if(isWatching) { if(assumePlaying and: { nodes.at(node.nodeID).isNil }) { node.isPlaying = true }; nodes.put(node.nodeID, node); }; } unregister { arg node; nodes.removeAt(node.nodeID); } //////////////private implementation////////////// n_go { arg node; node.isPlaying = true; node.isRunning = true; node.changed(\n_go); // notify all the node's dependents of the change } n_end { arg node; this.unregister(node); node.isPlaying = false; node.isRunning = false; node.changed(\n_end); } n_off { arg node; node.isRunning = false; node.changed(\n_off); } n_on { arg node; node.isRunning = true; node.changed(\n_on); } } DebugNodeWatcher : BasicNodeWatcher { cmds { ^#["/n_go", "/n_end", "/n_off", "/n_on"] } //////////////private implementation////////////// doPost { arg action, nodeID, groupID, prevID, nextID; Post << ("[ server: " + server.name + "]" + action + nodeID + "in group" + groupID + "between nodes" + prevID + "and" + nextID ) << Char.nl } n_go { arg nodeID, groupID, prevID, nextID; this.doPost("started", nodeID, groupID, prevID, nextID); nodes.add(nodeID); } n_end { arg nodeID, groupID, prevID, nextID; nodes.remove(nodeID); this.doPost("ended", nodeID, groupID, prevID, nextID); } n_off { arg nodeID, groupID, prevID, nextID; this.doPost("turned off", nodeID, groupID, prevID, nextID); } n_on { arg nodeID, groupID, prevID, nextID; this.doPost("turned on", nodeID, prevID, nextID); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/Node.sc0000664000000000000000000003661112245365552025705 0ustar rootrootNode { var <>nodeID, <>server, <>group; var <>isPlaying = false, <>isRunning = false; classvar 0, { result = result.add(["/n_mapn", nodeID] ++ krVals) }); if(arVals.size > 0, { result = result.add(["/n_mapan",nodeID] ++ arVals) }); if(result.size < 2, { result = result.flatten; }); ^result; } mapn { arg ... args; server.sendMsg(48, nodeID, *(args.asControlInput)); //"/n_mapn" } mapnMsg { arg ... args; ^[48, nodeID] ++ args.asControlInput; //"/n_mapn" } set { arg ... args; server.sendMsg(15, nodeID, *(args.asOSCArgArray)); //"/n_set" } setMsg { arg ... args; // ^[15, nodeID] ++ args.unbubble.asControlInput; ^[15, nodeID] ++ args.asOSCArgArray; //"/n_set" } setn { arg ... args; server.sendMsg(*this.setnMsg(*args)); } *setnMsgArgs{ arg ... args; var nargs=List.new; args = args.asControlInput; args.pairsDo { arg control, moreVals; if(moreVals.isArray,{ nargs.addAll([control, moreVals.size]++ moreVals); },{ nargs.addAll([control, 1, moreVals]); }); }; ^nargs; } setnMsg { arg ... args; ^[16, nodeID] ++ Node.setnMsgArgs(*args); // "n_setn" } fill { arg controlName, numControls, value ... args; server.sendMsg(17, nodeID, controlName, numControls, value, *(args.asControlInput));//"n_fill" } fillMsg { arg controlName, numControls, value ... args; ^[17, nodeID, controlName, numControls, value] ++ args.asControlInput; //"n_fill" } release { arg releaseTime; server.sendMsg(*this.releaseMsg(releaseTime)) } releaseMsg { arg releaseTime; //assumes a control called 'gate' in the synth if(releaseTime.isNil, { releaseTime = 0.0; },{ releaseTime = -1.0 - releaseTime; }); ^[15, nodeID, \gate, releaseTime] } trace { server.sendMsg(10, nodeID);//"/n_trace" } query { OSCFunc({ arg msg; var cmd,argnodeID,parent,prev,next,isGroup,head,tail; # cmd,argnodeID,parent,prev,next,isGroup,head,tail = msg; // assuming its me ... if(nodeID == argnodeID) Post << if(isGroup == 1, "Group:" , "Synth:") << nodeID << Char.nl << "parent : " << parent << Char.nl << "prev : " << prev << Char.nl << "next :" << next << Char.nl; if(isGroup==1,{ Post << "head :" << head << Char.nl << "tail :" << tail << Char.nl << Char.nl; }); }, '/n_info', server.addr).oneShot; server.sendMsg(46, nodeID) //"/n_query" } register { arg assumePlaying=false; NodeWatcher.register(this, assumePlaying) } onFree {|func| var f = {|n,m| if(m==\n_end) { func.value(this,m); this.removeDependant(f); } }; this.register; this.addDependant(f); } waitForFree { var c = Condition.new; this.onFree({c.unhang}); c.hang; } moveBefore { arg aNode; group = aNode.group; server.sendMsg(18, nodeID, aNode.nodeID); //"/n_before" } moveAfter { arg aNode; group = aNode.group; server.sendMsg(19, nodeID, aNode.nodeID); //"/n_after" } moveToHead { arg aGroup; (aGroup ? server.defaultGroup).moveNodeToHead(this); } moveToTail { arg aGroup; (aGroup ? server.defaultGroup).moveNodeToTail(this); } // message creating methods moveBeforeMsg { arg aNode; group = aNode.group; ^[18, nodeID, aNode.nodeID];//"/n_before" } moveAfterMsg { arg aNode; group = aNode.group; ^[19, nodeID, aNode.nodeID]; //"/n_after" } moveToHeadMsg { arg aGroup; ^(aGroup ? server.defaultGroup).moveNodeToHeadMsg(this); } moveToTailMsg { arg aGroup; ^(aGroup ? server.defaultGroup).moveNodeToTailMsg(this); } *orderNodesMsg { arg nodes; var msg = [18]; // "/n_after" nodes.doAdjacentPairs { |first, toMoveAfter| msg = msg.add(toMoveAfter.nodeID); msg = msg.add(first.nodeID); }; ^msg } == { arg that; ^this.compareObject(that, #[\nodeID, \server]) } hash { ^this.instVarHash(#[\nodeID, \server]) } printOn { arg stream; stream << this.class.name << "(" << nodeID <<")" } asUGenInput { Error("should not use a % inside a SynthDef".format(this.class.name)).throw } asControlInput { ^this.nodeID } } // common base for Group and ParGroup classes AbstractGroup : Node { /** immediately sends **/ *new { arg target, addAction=\addToHead; var group, server, addNum, inTarget; inTarget = target.asTarget; server = inTarget.server; group = this.basicNew(server); addNum = addActions[addAction]; if((addNum < 2), { group.group = inTarget; }, { group.group = inTarget.group; }); server.sendMsg(this.creationCmd, group.nodeID, addNum, inTarget.nodeID); ^group } newMsg { arg target, addAction = \addToHead; var addNum, inTarget; // if target is nil set to default group of server specified when basicNew was called inTarget = (target ? server.defaultGroup).asTarget; addNum = addActions[addAction]; (addNum < 2).if({ group = inTarget; }, { group = inTarget.group; }); ^[this.class.creationCmd, nodeID, addNum, inTarget.nodeID] } // for bundling addToHeadMsg { arg aGroup; // if aGroup is nil set to default group of server specified when basicNew was called group = (aGroup ? server.defaultGroup); ^[this.class.creationCmd, nodeID, 0, group.nodeID] } addToTailMsg { arg aGroup; // if aGroup is nil set to default group of server specified when basicNew was called group = (aGroup ? server.defaultGroup); ^[this.class.creationCmd, nodeID, 1, group.nodeID] } addAfterMsg { arg aNode; group = aNode.group; ^[this.class.creationCmd, nodeID, 3, aNode.nodeID] } addBeforeMsg { arg aNode; group = aNode.group; ^[this.class.creationCmd, nodeID, 2, aNode.nodeID] } addReplaceMsg { arg nodeToReplace; group = nodeToReplace.group; ^[this.class.creationCmd, nodeID, 4, nodeToReplace.nodeID] } *after { arg aNode; ^this.new(aNode, \addAfter) } *before { arg aNode; ^this.new(aNode, \addBefore) } *head { arg aGroup; ^this.new(aGroup, \addToHead) } *tail { arg aGroup; ^this.new(aGroup, \addToTail) } *replace { arg nodeToReplace; ^this.new(nodeToReplace, \addReplace) } // move Nodes to this group moveNodeToHead { arg aNode; aNode.group = this; server.sendMsg(22, nodeID, aNode.nodeID); //"/g_head" } moveNodeToTail { arg aNode; aNode.group = this; server.sendMsg(23, nodeID, aNode.nodeID); //"/g_tail" } moveNodeToHeadMsg { arg aNode; aNode.group = this; ^[22, nodeID, aNode.nodeID]; //"/g_head" } moveNodeToTailMsg { arg aNode; aNode.group = this; ^[23, nodeID, aNode.nodeID]; //g_tail } freeAll { // free my children, but this node is still playing server.sendMsg(24, nodeID); //"/g_freeAll" } freeAllMsg { // free my children, but this node is still playing ^[24, nodeID]; //"/g_freeAll" } deepFree { server.sendMsg(50, nodeID) //"/g_deepFree" } deepFreeMsg { ^[50, nodeID] //"/g_deepFree" } // Introspection dumpTree { arg postControls = false; server.sendMsg("/g_dumpTree", nodeID, postControls.binaryValue) } queryTree { //|action| var resp, done = false; resp = OSCFunc({ arg msg; var i = 2, tabs = 0, printControls = false, dumpFunc; if(msg[1] != 0, {printControls = true}); ("NODE TREE Group" + msg[2]).postln; if(msg[3] > 0, { dumpFunc = {|numChildren| var j; tabs = tabs + 1; numChildren.do({ if(msg[i + 1] >=0, {i = i + 2}, { i = i + 3 + if(printControls, {msg[i + 3] * 2 + 1}, {0}); }); tabs.do({ " ".post }); msg[i].post; // nodeID if(msg[i + 1] >=0, { " group".postln; if(msg[i + 1] > 0, { dumpFunc.value(msg[i + 1]) }); }, { (" " ++ msg[i + 2]).postln; // defname if(printControls, { if(msg[i + 3] > 0, { " ".post; tabs.do({ " ".post }); }); j = 0; msg[i + 3].do({ " ".post; if(msg[i + 4 + j].isMemberOf(Symbol), { (msg[i + 4 + j] ++ ": ").post; }); msg[i + 5 + j].post; j = j + 2; }); "\n".post; }); }); }); tabs = tabs - 1; }; dumpFunc.value(msg[3]); }); // action.value(msg); done = true; }, '/g_queryTree.reply', server.addr).oneShot; server.sendMsg("/g_queryTree", nodeID); SystemClock.sched(3, { done.not.if({ resp.free; "Server failed to respond to Group:queryTree!".warn; }); }); } *creationCmd { ^this.subclassMustImplementThisMethod } // queryTree { |action| // var resp, done = false; // resp = OSCresponderNode(server.addr, '/g_queryTree.reply', { arg time, responder, msg; // action.value(msg); // done = true; // }).add.removeWhenDone; // server.sendMsg("/g_queryTree", nodeID); // SystemClock.sched(3, { // done.not.if({ // resp.remove; // "Server failed to respond to Group:queryTree!".warn; // }); // }); // } } Group : AbstractGroup { *creationCmd { ^21 } //"/g_new" } Synth : Node { var <>defName; /** immediately sends **/ *new { arg defName, args, target, addAction=\addToHead; var synth, server, addNum, inTarget; inTarget = target.asTarget; server = inTarget.server; addNum = addActions[addAction]; synth = this.basicNew(defName, server); if((addNum < 2), { synth.group = inTarget; }, { synth.group = inTarget.group; }); // server.sendMsg(59, //"s_newargs" // defName, synth.nodeID, addNum, inTarget.nodeID, // *Node.setnMsgArgs(*args)); server.sendMsg(9, //"s_new" defName, synth.nodeID, addNum, inTarget.nodeID, *(args.asOSCArgArray) ); ^synth } *newPaused { arg defName, args, target, addAction=\addToHead; var synth, server, addNum, inTarget; inTarget = target.asTarget; server = inTarget.server; addNum = addActions[addAction]; synth = this.basicNew(defName, server); if((addNum < 2), { synth.group = inTarget; }, { synth.group = inTarget.group; }); server.sendBundle(nil, [9, defName, synth.nodeID, addNum, inTarget.nodeID] ++ args.asOSCArgArray, [12, synth.nodeID, 0]); // "s_new" + "/n_run" ^synth } /** does not send (used for bundling) **/ *basicNew { arg defName, server, nodeID; ^super.basicNew(server, nodeID).defName_(defName.asDefName) } newMsg { arg target, args, addAction = \addToHead; var addNum, inTarget; addNum = addActions[addAction]; // if target is nil set to default group of server specified when basicNew was called inTarget = (target ? server.defaultGroup).asTarget; (addNum < 2).if({ group = inTarget; }, { group = inTarget.group; }); ^[9, defName, nodeID, addNum, inTarget.nodeID] ++ args.asOSCArgArray; //"/s_new" } *after { arg aNode, defName, args; ^this.new(defName, args, aNode, \addAfter); } *before { arg aNode, defName, args; ^this.new(defName, args, aNode, \addBefore); } *head { arg aGroup, defName, args; ^this.new(defName, args, aGroup, \addToHead); } *tail { arg aGroup, defName, args; ^this.new(defName, args, aGroup, \addToTail); } *replace { arg nodeToReplace, defName, args; ^this.new(defName, args, nodeToReplace, \addReplace) } // for bundling addToHeadMsg { arg aGroup, args; // if aGroup is nil set to default group of server specified when basicNew was called group = (aGroup ? server.defaultGroup); ^[9, defName, nodeID, 0, group.nodeID] ++ args.asOSCArgArray // "/s_new" } addToTailMsg { arg aGroup, args; // if aGroup is nil set to default group of server specified when basicNew was called group = (aGroup ? server.defaultGroup); ^[9, defName, nodeID, 1, group.nodeID] ++ args.asOSCArgArray // "/s_new" } addAfterMsg { arg aNode, args; group = aNode.group; ^[9, defName, nodeID, 3, aNode.nodeID] ++ args.asOSCArgArray // "/s_new" } addBeforeMsg { arg aNode, args; group = aNode.group; ^[9, defName, nodeID, 2, aNode.nodeID] ++ args.asOSCArgArray // "/s_new" } addReplaceMsg { arg nodeToReplace, args; group = nodeToReplace.group; ^[9, defName, nodeID, 4, nodeToReplace.nodeID] ++ args.asOSCArgArray // "/s_new" } // nodeID -1 *grain { arg defName, args, target, addAction=\addToHead; var server; target = target.asTarget; server = target.server; server.sendMsg(9, defName.asDefName, -1, addActions[addAction], target.nodeID, *(args.asOSCArgArray)); //"/s_new" ^nil; } get { arg index, action; OSCpathResponder(server.addr,['/n_set',nodeID,index],{ arg time, r, msg; action.value(msg.at(3)); r.remove }).add; server.sendMsg(44, nodeID, index); //"/s_get" } getMsg { arg index; ^[44, nodeID, index]; //"/s_get" } getn { arg index, count, action; OSCpathResponder(server.addr,['/n_setn',nodeID,index],{arg time, r, msg; action.value(msg.copyToEnd(4)); r.remove } ).add; server.sendMsg(45, nodeID, index, count); //"/s_getn" } getnMsg { arg index, count; ^[45, nodeID, index, count]; //"/s_getn" } seti { arg ... args; // args are [key, index, value, key, index, value ...] var msg = Array.new(args.size div: 3 * 2); var synthDesc = SynthDescLib.at(defName.asSymbol); if(synthDesc.isNil) { "message seti failed, because SynthDef % was not added.".format(defName).warn; ^this }; forBy(0, args.size-1, 3, { |i| var key = args[i], offset = args[i+1], value = args[i+2]; var controlName = synthDesc.controlDict[key]; if(controlName.notNil and: { offset < controlName.numChannels }) { msg.add(controlName.index+offset); if(value.isArray) { msg.add(value.keep(controlName.numChannels - offset)) } { msg.add(value) } } }); server.sendMsg("/n_set", nodeID, *msg.asOSCArgArray); } printOn { arg stream; stream << this.class.name << "(" <<< defName << " : " << nodeID <<")" } } RootNode : Group { classvar numControlBusChannels=4096; var maxNodes=1024; var <>maxSynthDefs=1024; var <>protocol = \udp; var <>blockSize = 64; var <>hardwareBufferSize = nil; var <>memSize = 8192; var <>numRGens = 64; var <>numWireBufs = 64; var <>sampleRate = nil; var <>loadDefs = true; var <>inputStreamsEnabled; var <>outputStreamsEnabled; var <>inDevice = nil; var <>outDevice = nil; var <>verbosity = 0; var <>zeroConf = false; // Whether server publishes port to Bonjour, etc. var <>restrictedPath = nil; var <>initialNodeID = 1000; var <>remoteControlVolume = false; var <>memoryLocking = false; var <>threads = nil; // for supernova var local, <>internal, named, <>set, <>program, <>sync_s = true; var addr, sendQuit, <>remoteControlled; var options, <>latency = 0.2, aliveThreadPeriod = 0.7, statusWatcher; var <>tree; var scopeWindow; var recHeaderFormat="aiff", <>recSampleFormat="float"; var <>recChannels=2; var 0}) and: { pid.tryPerform(\pidRunning) == true } },{ 0.2.wait; }); if(serverRunning.not,{ if(onFailure.notNil) { postError = (onFailure.value == false); }; if(postError) { "server failed to start".error; "For advice: [http://supercollider.sf.net/wiki/index.php/ERROR:_server_failed_to_start]".postln; }; serverBooting = false; this.changed(\serverRunning); }, onComplete); }).play(AppClock); } bootSync { arg condition; condition ?? { condition = Condition.new }; condition.test = false; this.waitForBoot({ // Setting func to true indicates that our condition has become true and we can go when signaled. condition.test = true; condition.signal }); condition.wait; } ping { arg n=1, wait=0.1, func; var result=0, pingFunc; if(serverRunning.not) { "server not running".postln; ^this }; pingFunc = { Routine.run { var t, dt; t = Main.elapsedTime; this.sync; dt = Main.elapsedTime - t; ("measured latency:" + dt + "s").postln; result = max(result, dt); n = n - 1; if(n > 0) { SystemClock.sched(wait, {pingFunc.value; nil }) } { ("maximum determined latency of" + name + ":" + result + "s").postln; func.value(result) } }; }; pingFunc.value; } addStatusWatcher { if(statusWatcher.isNil) { statusWatcher = OSCFunc({ arg msg; var cmd, one; if(notify){ if(notified.not){ this.sendNotifyRequest; "Receiving notification messages from server %\n".postf(this.name); } }; alive = true; #cmd, one, numUGens, numSynths, numGroups, numSynthDefs, avgCPU, peakCPU, sampleRate, actualSampleRate = msg; { this.serverRunning_(true); this.changed(\counts); nil // no resched }.defer; }, '/status.reply', addr).fix; } { statusWatcher.enable; }; } cachedBuffersDo { |func| Buffer.cachedBuffersDo(this, func) } cachedBufferAt { |bufnum| ^Buffer.cachedBufferAt(this, bufnum) } inputBus { ^Bus(\audio, this.options.numOutputBusChannels, this.options.numInputBusChannels, this); } outputBus { ^Bus(\audio, 0, this.options.numOutputBusChannels, this); } startAliveThread { arg delay=0.0; this.addStatusWatcher; ^aliveThread ?? { aliveThread = Routine({ // this thread polls the server to see if it is alive delay.wait; loop({ this.status; aliveThreadPeriod.wait; this.serverRunning = alive; alive = false; }); }); AppClock.play(aliveThread); aliveThread } } stopAliveThread { if( aliveThread.notNil, { aliveThread.stop; aliveThread = nil; }); if( statusWatcher.notNil, { statusWatcher.free; statusWatcher = nil; }); } aliveThreadIsRunning { ^aliveThread.notNil and: {aliveThread.isPlaying} } *resumeThreads { set.do({ arg server; server.stopAliveThread; server.startAliveThread(server.aliveThreadPeriod); }); } boot { arg startAliveThread=true, recover=false, onFailure; var resp; if (serverRunning, { "server already running".inform; ^this }); if (serverBooting, { "server already booting".inform; ^this }); serverBooting = true; if(startAliveThread, { this.startAliveThread }); if(recover) { this.newNodeAllocators } { this.newAllocators }; bootNotifyFirst = true; this.doWhenBooted({ serverBooting = false; if (sendQuit.isNil) { sendQuit = this.inProcess or: {this.isLocal}; }; if (this.inProcess) { serverInterface = ServerShmInterface(thisProcess.pid); } { if (isLocal) { serverInterface = ServerShmInterface(addr.port); } }; this.initTree; }, onFailure: onFailure ? false); if (remoteControlled.not, { "You will have to manually boot remote server.".inform; },{ this.bootServerApp; }); } bootServerApp { if (inProcess, { "booting internal".inform; this.bootInProcess; //alive = true; //this.serverRunning = true; pid = thisProcess.pid; },{ if (serverInterface.notNil) { serverInterface.disconnect; serverInterface = nil; }; pid = (program ++ options.asOptionsString(addr.port)).unixCmd; //unixCmd(program ++ options.asOptionsString(addr.port)).postln; ("booting " ++ addr.port.asString).inform; }); } reboot { arg func; // func is evaluated when server is off if (isLocal.not) { "can't reboot a remote server".inform; ^this }; if(serverRunning) { Routine.run { this.quit; this.wait(\done); 0.1.wait; func.value; this.boot; } } { func.value; this.boot } } status { addr.sendStatusMsg } notify_ { |flag = true| notify = flag; if(flag){ if(serverRunning){ this.sendNotifyRequest(true); notified = true; "Receiving notification messages from server %\n".postf(this.name); } }{ this.sendNotifyRequest(false); notified = false; "Switched off notification messages from server %\n".postf(this.name); } } sendNotifyRequest { arg flag=true; notified = flag; addr.sendMsg("/notify", flag.binaryValue); } dumpOSC { arg code=1; /* 0 - turn dumping OFF. 1 - print the parsed contents of the message. 2 - print the contents in hexadecimal. 3 - print both the parsed and hexadecimal representations of the contents. */ dumpMode = code; this.sendMsg(\dumpOSC,code); } quit { var serverReallyQuitWatcher, serverReallyQuit = false; statusWatcher !? { statusWatcher.disable; if(notified) { serverReallyQuitWatcher = OSCFunc({ |msg| if(msg[1] == '/quit') { statusWatcher.enable; serverReallyQuit = true; serverReallyQuitWatcher.free; }; }, '/done', addr); // don't accumulate quit-watchers if /done doesn't come back AppClock.sched(3.0, { if(serverReallyQuit.not) { "Server % failed to quit after 3.0 seconds.".format(this.name).warn; serverReallyQuitWatcher.free; }; }); }; }; addr.sendMsg("/quit"); if (inProcess, { this.quitInProcess; "quit done\n".inform; },{ "/quit sent\n".inform; }); alive = false; notified = false; dumpMode = 0; pid = nil; serverBooting = false; sendQuit = nil; this.serverRunning = false; if(scopeWindow.notNil) { scopeWindow.quit }; if(volume.isPlaying) { volume.free }; RootNode(this).freeAll; this.newAllocators; } *quitAll { set.do({ arg server; if (server.sendQuit === true) { server.quit }; }) } *killAll { // if you see Exception in World_OpenUDP: unable to bind udp socket // its because you have multiple servers running, left // over from crashes, unexpected quits etc. // you can't cause them to quit via OSC (the boot button) // this brutally kills them all off thisProcess.platform.killAll(this.program.basename); this.quitAll; } freeAll { this.sendMsg("/g_freeAll", 0); this.sendMsg("/clearSched"); this.initTree; } *freeAll { arg evenRemote = false; if (evenRemote) { set.do { arg server; if ( server.serverRunning ) { server.freeAll } } } { set.do { arg server; if (server.isLocal and:{ server.serverRunning }) { server.freeAll } } } } *hardFreeAll { arg evenRemote = false; if (evenRemote) { set.do { arg server; server.freeAll } } { set.do { arg server; if (server.isLocal) { server.freeAll } } } } *allRunningServers { ^this.all.select(_.serverRunning) } // bundling support openBundle { arg bundle; // pass in a bundle that you want to // continue adding to, or nil for a new bundle. if(addr.hasBundle) { bundle = addr.bundle.addAll(bundle); addr.bundle = []; // debatable }; addr = BundleNetAddr.copyFrom(addr, bundle); } closeBundle { arg time; // set time to false if you don't want to send. var bundle; if(addr.hasBundle) { bundle = addr.closeBundle(time); addr = addr.saveAddr; } { "there is no open bundle.".warn }; ^bundle; } makeBundle { arg time, func, bundle; this.openBundle(bundle); try { func.value(this); bundle = this.closeBundle(time); }{|error| addr = addr.saveAddr; // on error restore the normal NetAddr error.throw } ^bundle } bind { arg func; ^this.makeBundle(this.latency, func) } // internal server commands bootInProcess { ^options.bootInProcess; } quitInProcess { _QuitInProcessServer ^this.primitiveFailed } allocSharedControls { arg numControls=1024; _AllocSharedControls ^this.primitiveFailed } setSharedControl { arg num, value; _SetSharedControl ^this.primitiveFailed } getSharedControl { arg num; _GetSharedControl ^this.primitiveFailed } // recording output record { |path| if(recordBuf.isNil){ this.prepareForRecord(path); Routine({ this.sync; this.record; }).play; }{ if(recordNode.isNil){ recordNode = Synth.tail(RootNode(this), "server-record", [\bufnum, recordBuf.bufnum]); CmdPeriod.doOnce { recordNode = nil; if (recordBuf.notNil) { recordBuf.close {|buf| buf.freeMsg }; recordBuf = nil; }; } } { recordNode.run(true) }; "Recording: %\n".postf(recordBuf.path); }; } pauseRecording { recordNode.notNil.if({ recordNode.run(false); "Paused".postln }, { "Not Recording".warn }); } stopRecording { if(recordNode.notNil) { recordNode.free; recordNode = nil; recordBuf.close({ |buf| buf.freeMsg }); "Recording Stopped: %\n".postf(recordBuf.path); recordBuf = nil; } { "Not Recording".warn }; } prepareForRecord { arg path; if (path.isNil) { if(File.exists(thisProcess.platform.recordingsDir).not) { thisProcess.platform.recordingsDir.mkdir }; // temporary kludge to fix Date's brokenness on windows if(thisProcess.platform.name == \windows) { path = thisProcess.platform.recordingsDir +/+ "SC_" ++ Main.elapsedTime.round(0.01) ++ "." ++ recHeaderFormat; } { path = thisProcess.platform.recordingsDir +/+ "SC_" ++ Date.localtime.stamp ++ "." ++ recHeaderFormat; }; }; recordBuf = Buffer.alloc(this, 65536, recChannels, {arg buf; buf.writeMsg(path, recHeaderFormat, recSampleFormat, 0, 0, true);}, this.options.numBuffers + 1); // prevent buffer conflicts by using reserved bufnum recordBuf.path = path; SynthDef("server-record", { arg bufnum; DiskOut.ar(bufnum, In.ar(0, recChannels)) }).send(this); } // CmdPeriod support for Server-scope and Server-record and Server-volume cmdPeriod { addr = addr.recover; this.changed(\cmdPeriod); } doOnServerTree { if(scopeWindow.notNil) { scopeWindow.run } } defaultGroup { ^Group.basicNew(this, 1) } queryAllNodes { arg queryControls = false; var resp, done = false; if(isLocal, {this.sendMsg("/g_dumpTree", 0, queryControls.binaryValue);}, { resp = OSCFunc({ arg msg; var i = 2, tabs = 0, printControls = false, dumpFunc; if(msg[1] != 0, {printControls = true}); ("NODE TREE Group" + msg[2]).postln; if(msg[3] > 0, { dumpFunc = {|numChildren| var j; tabs = tabs + 1; numChildren.do({ if(msg[i + 1] >=0, {i = i + 2}, { i = i + 3 + if(printControls, {msg[i + 3] * 2 + 1}, {0}); }); tabs.do({ " ".post }); msg[i].post; // nodeID if(msg[i + 1] >=0, { " group".postln; if(msg[i + 1] > 0, { dumpFunc.value(msg[i + 1]) }); }, { (" " ++ msg[i + 2]).postln; // defname if(printControls, { if(msg[i + 3] > 0, { " ".post; tabs.do({ " ".post }); }); j = 0; msg[i + 3].do({ " ".post; if(msg[i + 4 + j].isMemberOf(Symbol), { (msg[i + 4 + j] ++ ": ").post; }); msg[i + 5 + j].post; j = j + 2; }); "\n".post; }); }); }); tabs = tabs - 1; }; dumpFunc.value(msg[3]); }); done = true; }, '/g_queryTree.reply', addr).oneShot; this.sendMsg("/g_queryTree", 0, queryControls.binaryValue); SystemClock.sched(3, { done.not.if({ resp.free; "Remote server failed to respond to queryAllNodes!".warn; }); }); }) } printOn { |stream| stream << name; } storeOn { arg stream; var codeStr = this.switch ( Server.default, { if (sync_s) { "s" } { "Server.default" } }, Server.local, { "Server.local" }, Server.internal, { "Server.internal" }, { "Server.fromName(" + name.asCompileString + ")" } ); stream << codeStr; } archiveAsCompileString { ^true } archiveAsObject { ^true } volume_ {arg newVolume; volume.volume_(newVolume); } mute { volume.mute; } unmute { volume.unmute; } hasShmInterface { ^serverInterface.notNil } reorder { arg nodeList, target, addAction=\addToHead; target = target.asTarget; this.sendMsg(62, Node.actionNumberFor(addAction), target.nodeID, *(nodeList.collect(_.nodeID))); //"/n_order" } getControlBusValue {|busIndex| if (serverInterface.isNil) { Error("Server-getControlBusValue only supports local servers").throw; } { ^serverInterface.getControlBusValue(busIndex) } } getControlBusValues {|busIndex, busChannels| if (serverInterface.isNil) { Error("Server-getControlBusValues only supports local servers").throw; } { ^serverInterface.getControlBusValues(busIndex, busChannels) } } setControlBusValue {|busIndex, value| if (serverInterface.isNil) { Error("Server-getControlBusValue only supports local servers").throw; } { ^serverInterface.setControlBusValue(busIndex, value) } } setControlBusValues {|busIndex, valueArray| if (serverInterface.isNil) { Error("Server-getControlBusValues only supports local servers").throw; } { ^serverInterface.setControlBusValues(busIndex, valueArray) } } *scsynth { this.program = this.program.replace("supernova", "scsynth") } *supernova { this.program = this.program.replace("scsynth", "supernova") } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/OSCresponder.sc0000664000000000000000000000530412014636263027353 0ustar rootrootOSCresponder { classvar <>all; var <>addr, action; var nodes; value { arg time, msg, addr; var iterlist; iterlist = nodes.copy; iterlist.do({ arg node; node.value(time, msg, addr) }); } isEmpty { ^nodes.size == 0 } } OSCresponderNode : OSCresponder { var window, model; var window, spec, slider, box, simpleController; *new{|model, win, bounds| ^super.new.model_(model).init(win, bounds) } init{|win, bounds| spec = [model.min, model.max, \db].asSpec; bounds = bounds ?? {Rect(100, 100, 80, 330)}; window = win ?? {GUI.window.new("Volume", bounds).front}; box = GUI.numberBox.new(window, Rect(10, 10, 60, 30)) .value_(model.volume) ; slider = GUI.slider.new(window, Rect(10, 40, 60, 280)) .value_(spec.unmap(model.volume)) ; slider.action_({ arg item ; model.volume_(spec.map(item.value)); }) ; box.action_({ arg item ; model.volume_(item.value) ; }) ; window.onClose_({ simpleController.remove; }); simpleController = SimpleController(model) .put(\amp, {|changer, what, volume| this.debug(volume); box.value_(volume.round(0.01)) ; slider.value_(spec.unmap(volume)) ; }) .put(\ampRange, {|changer, what, min, max| spec = [min, max, \db].asSpec.debug; slider.value_(spec.unmap(model.volume)) ; }) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/ignore/0000775000000000000000000000000012245452763025746 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/ignore/GeneralHID.sc0000664000000000000000000000217012014636263030170 0ustar rootrootGeneralHID{ classvar <>all, <>maps, <>verbose=false; classvar all, <>verbose=false; classvar key; *initClass{ // typeMap is modeled after Linux input system. // to get the Mac work in a similar way, some tricks will be needed typeMap = IdentityDictionary.new.addAll([ 0x0000 -> "Syn", 0x0001 -> "Button", 0x0002 -> "Relative", 0x0003 -> "Absolute", 0x0004 -> "Miscellaneous", 0x0011 -> "LED", 0x0012 -> "Sound", 0x0014 -> "Rep", 0x0015 -> "Force Feedback", 0x0016 -> "Power", 0x0017 -> "Force Feedback Status", 0x0FFF -> "Linear" ]); } *new{ |type,id,device,devSlot| ^super.newCopyArgs( type, id, device, devSlot ).init; } init{ busAction = {}; debugAction = {}; action = {}; devSlot.action = { |v| this.debugAction.value(v); this.busAction.value(v); this.action.value(v) }; } value { ^devSlot.value; } rawValue { ^devSlot.rawValue; } value_ { |v| devSlot.value_( v ); } debug_{ |onoff| if ( onoff, { // this.action_({ |slot| [ slot.type, slot.code, slot.value, key ].postln; }); this.debugAction_({ |slot| [ slot.type, slot.code, slot.value, key ].postln; }); },{ // this.action_({}); this.debugAction_({}); }); } debugAction_{ |actionFunc| debugAction = actionFunc; } action_{ |actionFunc| action = actionFunc; // devSlot.action = { |v| this.action.value(v); this.busAction.value(v); this.debugAction.value(v) }; } createBus{ |s| s = s ? Server.default; if ( bus.isNil, { bus = Bus.control( s, 1 ); },{ if ( bus.index.isNil, { bus = Bus.control( s, 1 ); }); }); /* if ( s.serverRunning.not and: s.isLocal, { "Server seems not running, so bus will be invalid".warn; });*/ busAction = { |v| bus.set( v.value ); }; // devSlot.action = { |v| action.value(v); busAction.value(v); }; } freeBus{ busAction = {}; bus.free; } printOn { | stream | stream << this.class.name << $( << this.class.typeMap[type] << ", " << "type: " << type << ", " << "id: " << id << ", " << "value: " << this.value << $) } // JITLib support kr{ this.createBus; ^In.kr( bus ); } }SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/OSCService.sc0000664000000000000000000000202612014636263026750 0ustar rootrootOSCService { var name; *new { arg node,index; ^super.newCopyArgs(node,index) } value_ { arg aval; node.set(index,aval) } readFromBus { arg bus; node.map(index,bus) } stopReadFromBus { node.map(index,-1) } setMsg { arg value; ^[15, node.nodeID,index, value] } server { ^node.server } group { ^node.group } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/asScore/0000775000000000000000000000000012245452763026062 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/asScore/RenderNotePlayer.sc0000664000000000000000000000146612014636263031633 0ustar rootroot//RenderNotePlayer : NotePlayer { // var <>maxTime, <>score, beats, <>tempo; var <>bundleList, <>maxTime; *new { ^super.new("record").initScoreStreamPlayer } initScoreStreamPlayer { this.latency_(0); Server.set.remove(this); // we do not want to be part of the server list ^this } beats2secs { | beats | ^beats } secs2beats { | beats | ^beats } add { | beats, args| bundleList = bundleList.add([beats min: maxTime] ++ args) } prepareEvent { | event | event = event.copy; event.use({ ~schedBundle = { | lag, offset, server ...bundle | this.add(offset * tempo + lag + beats, bundle) }; ~schedBundleArray = { | lag, offset, server, bundle | this.add(offset * tempo + lag + beats, bundle) }; }); ^event; } makeScore { | stream, duration = 1, event, timeOffset = 0| var ev, startTime, proto; proto = ( server: this, schedBundle: { | lag, offset, server ...bundle | this.add(offset * tempo + lag + beats, bundle) }, schedBundleArray: { | lag, offset, server, bundle | this.add(offset * tempo + lag + beats, bundle) } ); event = event ? Event.default; event = event.copy.putAll(proto); beats = timeOffset; tempo = 1; bundleList = []; maxTime = timeOffset + duration; Routine { thisThread.clock = this; while ({ thisThread.beats = beats; ev = stream.next(event.copy); (maxTime >= beats) && ev.notNil },{ ev.putAll(proto); ev.play; beats = ev.delta * tempo + beats }) }.next; bundleList = bundleList.sort({ | a, b | b[0] >= a[0] }); if ((startTime = bundleList[0][0]) < 0 ) { timeOffset = timeOffset - startTime; }; // bundleList.do { | b | b[0] = b[0] + timeOffset } ^Score(bundleList.add([duration+timeOffset, [\c_set, 0, 0]]) ); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/asScore/asScore.sc0000664000000000000000000000130112014636263027774 0ustar rootroot+ Pattern { asScore{|duration=1.0, timeOffset=0.0, protoEvent| var player; ^ScoreStreamPlayer.new.makeScore(this.asStream, duration, protoEvent, timeOffset); } } + Object { render { arg path, maxTime=60, sampleRate = 44100, headerFormat = "AIFF", sampleFormat = "int16", options, inputFilePath, action; var file, oscFilePath, score; oscFilePath = "temp_oscscore" ++ UniqueID.next; score = this.asScore(maxTime); score.recordNRT( oscFilePath, path, inputFilePath, sampleRate, headerFormat, sampleFormat, options, "; rm" + oscFilePath, action: action; ); } } + Event { asOSC { var score; score = Pseq([this]).asScore.score; ^score.copyRange(1, score.size - 2); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/MIDIResponder.sc0000664000000000000000000001410212014636263027405 0ustar rootroot// see MIDIResponder help for all classes on this page MIDIResponder { var <>function,<>swallowEvent=false, <>matchEvent; // for matching ports, channels, and parameters init { arg install; if(this.class.initialized.not,{ this.class.init }); matchEvent.port = matchEvent.port.asMIDIInPortUID; if(install,{this.class.add(this);}); } respond { arg src,chan,num,value; if(this.match(src,chan,num,value),{ this.value(src,chan,num,value) ^swallowEvent }); ^false; } match { arg src,chan,num,value; ^matchEvent.match(src,chan,num,value); } value { arg src,chan,a,b; function.value(src, chan, a, b) } remove { this.class.remove(this) } *removeAll { if(this == MIDIResponder,{ this.allSubclasses.do({ |responderClass| responderClass.removeAll }) },{ this.init }) } } NoteOnResponder : MIDIResponder { classvar device, <>name, <>uid; *new{ arg device, name, uid; ^super.newCopyArgs(device, name, uid) } printOn { arg stream; stream << this.class.name << "(" <<<* [device, name] <<")" } } MIDIClient { classvar status, <>port, <>chan, <>b, <>c, <>thread; *new { arg status, port, chan, b, c, thread; ^super.newCopyArgs(status, port, chan, b, c, thread) } set { arg inStatus, inPort, inChan, inB, inC, inThread; status = inStatus; port = inPort; chan = inChan; b = inB; c = inC; inThread !? { thread = inThread }; } match { arg inPort, inChan, inB, inC; ^port.matchItem(inPort) and: { chan.matchItem(inChan) and: { b.matchItem(inB) and: { c.matchItem(inC) }}} } // convenience accessors note { ^b } veloc { ^c } ctlnum { ^b } ctlval { ^c } } MIDIIn { var port; classvar <>action, <> noteOn, <> noteOff, <> polytouch, <> control, <> program, <> touch, <> bend, <> sysex, sysexPacket, <> sysrt, <> smpte, <> invalid; classvar <> noteOnList, <> noteOffList, <> polyList, <> controlList, <> programList, <> touchList, <> bendList; // safer than global setters *addFuncTo { |what, func| this.perform(what.asSetter, this.perform(what).addFunc(func)) } *removeFuncFrom { |what, func| this.perform(what.asSetter, this.perform(what).removeFunc(func)) } *replaceFuncTo { |what, func, newFunc| this.perform(what.asSetter, this.perform(what).replaceFunc(func, newFunc)) } *waitNoteOn { arg port, chan, note, veloc; var event; event = MIDIEvent(\noteOn, port, chan, note, veloc, thisThread); noteOnList = noteOnList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitNoteOff { arg port, chan, note, veloc; var event; event = MIDIEvent(\noteOff, port, chan, note, veloc, thisThread); noteOffList = noteOffList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitPoly { arg port, chan, note, veloc; var event; event = MIDIEvent(\poly, port, chan, note, veloc, thisThread); polyList = polyList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitTouch { arg port, chan, val; var event; event = MIDIEvent(\touch, port, chan, val, nil, thisThread); touchList = touchList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitControl { arg port, chan, num, val; var event; event = MIDIEvent(\control, port, chan, num, val, thisThread); controlList = controlList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitBend { arg port, chan, val; var event; event = MIDIEvent(\bend, port, chan, val, nil, thisThread); bendList = bendList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitProgram { arg port, chan, num; var event; event = MIDIEvent(\program, port, chan, num, nil, thisThread); programList = programList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *doAction { arg src, status, a, b, c; action.value(src, status, a, b, c); } *doNoteOnAction { arg src, chan, num, veloc; noteOn.value(src, chan, num, veloc); this.prDispatchEvent(noteOnList, \noteOn, src, chan, num, veloc); } *doNoteOffAction { arg src, chan, num, veloc; noteOff.value(src, chan, num, veloc); this.prDispatchEvent(noteOffList, \noteOff, src, chan, num, veloc); } *doPolyTouchAction { arg src, chan, num, val; polytouch.value(src, chan, num, val); this.prDispatchEvent(polyList, \poly, src, chan, num, val); } *doControlAction { arg src, chan, num, val; control.value(src, chan, num, val); this.prDispatchEvent(controlList, \control, src, chan, num, val); } *doProgramAction { arg src, chan, val; program.value(src, chan, val); this.prDispatchEvent(programList, \program, src, chan, val); } *doTouchAction { arg src, chan, val; touch.value(src, chan, val); this.prDispatchEvent(touchList, \touch, src, chan, val); } *doBendAction { arg src, chan, val; bend.value(src, chan, val); this.prDispatchEvent(bendList, \bend, src, chan, val); } *doSysexAction { arg src, packet; sysexPacket = sysexPacket ++ packet; if (packet.last == -9, { sysex.value(src, sysexPacket); sysexPacket = nil }); } *doInvalidSysexAction { arg src, packet; invalid.value(src, packet); } *doSysrtAction { arg src, index, val; sysrt.value(src, index, val); } *doSMPTEaction { arg src, frameRate, timecode; smpte.value(src, frameRate, timecode); } *findPort { arg deviceName,portName; ^MIDIClient.sources.detect({ |endPoint| endPoint.device == deviceName and: {endPoint.name == portName}}); } *connectAll { if(MIDIClient.initialized.not,{ MIDIClient.init }); MIDIClient.sources.do({ |src,i| MIDIIn.connect(i,src); }); } *connect { arg inport=0, device=0; var uid,source; if(MIDIClient.initialized.not,{ MIDIClient.init }); if(device.isNumber, { if(device >= 0, { if ( device > MIDIClient.sources.size,{ // on linux the uid's are very large numbers source = MIDIClient.sources.detect{ |it| it.uid == device }; if(source.isNil,{ ("MIDI device with uid"+device+ "not found").warn; },{ uid = source.uid; }) },{ source = MIDIClient.sources.at(device); if(source.isNil,{ "MIDIClient failed to init".warn; },{ uid = MIDIClient.sources.at(device).uid; }); }); },{ // elsewhere they tend to be negative uid = device; }); },{ if(device.isKindOf(MIDIEndPoint), {uid = device.uid}); // else error }); this.connectByUID(inport,uid); } *disconnect { arg inport=0, device=0; var uid, source; if(device.isKindOf(MIDIEndPoint), {uid = device.uid}); if(device.isNumber, { if(device.isPositive, { if ( device > MIDIClient.sources.size, { source = MIDIClient.sources.select{ |it| it.uid == device }.first; if(source.isNil,{ ("MIDI device with uid"+device+ "not found").warn; },{ uid = source.uid; }) }, { source = MIDIClient.sources.at(device); if(source.isNil,{ "MIDIClient failed to init".warn; },{ uid = MIDIClient.sources.at(device).uid; }); }); },{ uid = device; }); }); this.disconnectByUID(inport,uid); } *connectByUID {arg inport, uid; _ConnectMIDIIn } *disconnectByUID {arg inport, uid; _DisconnectMIDIIn } *prDispatchEvent { arg eventList, status, port, chan, b, c; var selectedEvents; eventList ?? {^this}; eventList.takeThese {| event | if (event.match(port, chan, b, c)) { selectedEvents = selectedEvents.add(event); true } { false }; }; selectedEvents.do{ |event| event.set(status, port, chan, b, c); event.thread.next; } } } MIDIOut { var <>port, <>uid, <>latency=0.2; *new { arg port, uid; if(thisProcess.platform.name != \linux) { ^super.newCopyArgs(port, uid ?? { MIDIClient.destinations[port].uid }); } { ^super.newCopyArgs(port, uid ?? 0 ); } } *newByName { arg deviceName,portName,dieIfNotFound=true; var endPoint,index; endPoint = MIDIClient.destinations.detect({ |ep,epi| index = epi; ep.device == deviceName and: {ep.name == portName} }); if(endPoint.isNil,{ if(dieIfNotFound,{ Error("Failed to find MIDIOut port " + deviceName + portName).throw; },{ ("Failed to find MIDIOut port " + deviceName + portName).warn; }); }); ^this.new(index,endPoint.uid) } *findPort { arg deviceName,portName; ^MIDIClient.destinations.detect({ |endPoint| endPoint.device == deviceName and: {endPoint.name == portName}}); } write { arg len, hiStatus, loStatus, a=0, b=0; this.send(port, uid, len, hiStatus, loStatus, a, b, latency); } noteOn { arg chan, note=60, veloc=64; this.write(3, 16r90, chan.asInteger, note.asInteger, veloc.asInteger); } noteOff { arg chan, note=60, veloc=64; this.write(3, 16r80, chan.asInteger, note.asInteger, veloc.asInteger); } polyTouch { arg chan, note=60, val=64; this.write(3, 16rA0, chan.asInteger, note.asInteger, val.asInteger); } control { arg chan, ctlNum=7, val=64; this.write(3, 16rB0, chan.asInteger, ctlNum.asInteger, val.asInteger); } program { arg chan, num=1; this.write(2, 16rC0, chan.asInteger, num.asInteger); } touch { arg chan, val=64; this.write(2, 16rD0, chan.asInteger, val.asInteger); } bend { arg chan, val=8192; val = val.asInteger; this.write(3, 16rE0, chan, val bitAnd: 127, val >> 7); } allNotesOff { arg chan; this.control(chan, 123, 0); } smpte { arg frames=0, seconds=0, minutes=0, hours=0, frameRate = 3; var packet; packet = [frames, seconds, minutes, hours] .asInteger .collect({ arg v, i; [(i * 2 << 4) | (v & 16rF), (i * 2 + 1 << 4) | (v >> 4) ] }); packet = packet.flat; packet.put(7, packet.at(7) | ( frameRate << 1 ) ); packet.do({ arg v; this.write(2, 16rF0, 16r01, v); }); } songPtr { arg songPtr; songPtr = songPtr.asInteger; this.write(4, 16rF0, 16r02, songPtr & 16r7f, songPtr >> 7 & 16r7f); } songSelect { arg song; this.write(3, 16rF0, 16r03, song.asInteger); } midiClock { this.write(1, 16rF0, 16r08); } start { this.write(1, 16rF0, 16r0A); } continue { this.write(1, 16rF0, 16r0B); } stop { this.write(1, 16rF0, 16r0C); } reset { this.write(1, 16rF0, 16r0F); } sysex { arg packet; ^this.prSysex( uid, packet ); } send { arg outport, uid, len, hiStatus, loStatus, a=0, b=0, late; _SendMIDIOut } prSysex { arg uid, packet; _SendSysex ^this.primitiveFailed; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/asTarget.sc0000664000000000000000000000042412014636263026555 0ustar rootroot+Server { asTarget { ^Group.basicNew(this, 1) } asNodeID { ^0 } } +Node { asTarget { ^this } asNodeID { ^nodeID } } +Nil { asTarget { ^Server.default.asTarget } asNodeID { ^this } } +Integer { asTarget { ^Group.basicNew(Server.default, this) } asNodeID { ^this } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/schedBundle.sc0000664000000000000000000000335612014636263027232 0ustar rootroot// these support different ways of specifying the timing of a scheduled event // see the atTime help file + Nil { // now schedBundle { arg bundle,server,timeOfRequest; bundle.send(server,nil,nil); //0.0 } } + Float { // relative seconds schedBundle { arg bundle,server,timeOfRequest; // this also need doPrepare bundle.send(server,this,timeOfRequest); } } /** * 1 : bar * 2 : half-note * 4 : quarter note * 8 : 8th note * 16 : 16th note */ + Integer { // at the next N beat schedBundle { arg bundle,server,timeOfRequest; bundle.doPrepare(server,{ var now,nowRound,latencyBeats,deltaTillSend; latencyBeats = Tempo.secs2beats(server.latency ? 0.05); now = TempoClock.default.elapsedBeats; nowRound = now.roundUp(4 / this); deltaTillSend = (nowRound - now - latencyBeats); if(deltaTillSend < 0.05,{ nowRound = nowRound + (4/this); deltaTillSend = (nowRound - now - latencyBeats); }); TempoClock.default.sched( deltaTillSend, { var lateness,delta; // this executes at Server.latency before the event is due. // calculate actual latency to the requested time delta = Tempo.beats2secs(nowRound - TempoClock.default.elapsedBeats); /*SystemClock.sched(delta,{ var b; b = TempoClock.default.elapsedBeats; [b,nowRound - b].debug("actual sched"); nil; });*/ bundle.prSend(server, delta,Main.elapsedTime); nil }); }); } } + Date { // Date raw seconds has to be set correctly ! // *new won't do this for you schedBundle { arg bundle,server,timeOfRequest; var delta; delta = rawSeconds - this.class.localtime.rawSeconds; if(delta >= 0.0,{ // should we prepare this a few seconds ahead of time ? bundle.send(server,delta,timeOfRequest); }); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/asGroup.sc0000664000000000000000000000035312014636263026424 0ustar rootroot+ AbstractGroup { asGroup {} } + Nil { asGroup { ^Group.basicNew(this, 1) } } + Server { asGroup { ^Group.basicNew(this, 1) } } + Synth { asGroup { ^this.group } } + Integer { asGroup { ^Group.basicNew(nil, this) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/GraphBuilder.sc0000664000000000000000000001132012245365552027356 0ustar rootrootGraphBuilder { //used to create an out ugen automatically and a fade envelope *wrapOut { arg name, func, rates, prependArgs, outClass=\Out, fadeTime; ^SynthDef.new(name, { arg i_out=0; var result, rate, env; result = SynthDef.wrap(func, rates, prependArgs).asUGenInput; rate = result.rate; if(rate === \scalar,{ // Out, SendTrig etc. probably a 0.0 result },{ if(fadeTime.notNil, { result = this.makeFadeEnv(fadeTime) * result; }); outClass = outClass.asClass; outClass.replaceZeroesWithSilence(result.asArray); outClass.multiNewList([rate, i_out]++result) }) }) } *makeFadeEnv { arg fadeTime = (0.02); var dt = NamedControl.kr(\fadeTime, fadeTime); var gate = NamedControl.kr(\gate, 1.0); var startVal = (dt <= 0); ^EnvGen.kr(Env.new([startVal, 1, 0], #[1, 1], \lin, 1), gate, 1.0, 0.0, dt, 2) } } EnvGate { *new { arg i_level=1, gate, fadeTime, doneAction=2, curve='sin'; var synthGate = gate ?? { NamedControl.kr(\gate, 1.0) }; var synthFadeTime = fadeTime ?? { NamedControl.kr(\fadeTime, 0.02) }; var startVal = (synthFadeTime <= 0); ^EnvGen.kr( Env.new([ startVal, 1.0, 0.0], #[1.0, 1.0], curve, 1), synthGate, i_level, 0.0, synthFadeTime, doneAction ) } } /*EnvGate { classvar currentControl, buildSynthDef; *new { arg i_level=1, gate, fadeTime, doneAction=2, curve='sin'; var synthGate, synthFadeTime, startVal; if(gate.isNil and: { fadeTime.isNil }) { #synthGate, synthFadeTime = this.currentControl } { synthGate = gate ?? { Control.names('gate').kr(1.0) }; synthFadeTime = fadeTime ?? { Control.names('fadeTime').kr(0.02) }; }; startVal = (synthFadeTime <= 0); ^EnvGen.kr( Env.new([ startVal,1,0], #[1,1],curve,1), synthGate, i_level, 0.0, synthFadeTime, doneAction ) } // this allows several instances within a single synthdef *currentControl { if(this.hasCurrentControl.not) { currentControl = Control.names(['gate', 'fadeTime']).kr([1, 0.02]); buildSynthDef = UGen.buildSynthDef; } ^currentControl } *hasCurrentControl { ^UGen.buildSynthDef === buildSynthDef and: { currentControl.notNil } } } */ NamedControl { classvar currentControls, buildSynthDef; var closeAction; *new{arg manufacturer, product, usage, vendorID, productID, locID, version, serial; ^super.newCopyArgs(manufacturer, product, usage, vendorID, productID, locID, version, serial).init; } init{ info = HIDInfo.new( product, 0, vendorID, productID, version ); closeAction = {}; elements = Array.new; } value{arg elementNum=0; ^HIDDeviceService.value(locID,elements.at(elementNum).cookie) } valueByCookie{arg cookie; ^HIDDeviceService.value(locID,cookie) } setValue{|elementNum, val| HIDDeviceService.setValue(locID,elements.at(elementNum).cookie, val) } setValueByCookie{|cookie, val| HIDDeviceService.setValue(locID,cookie, val) } queueDevice{ isQueued = true; HIDDeviceService.queueDevice(locID); } dequeueDevice{ isQueued = false; HIDDeviceService.dequeueDevice(locID); } queueElement{arg elementNum=0; HIDDeviceService.queueElement(locID, elements.at(elementNum).cookie); } dequeueElement{arg elementNum=0; HIDDeviceService.dequeueElement(locID, elements.at(elementNum).cookie); } wasClosed{ ("WARNING: Device was removed: " + info).postln; closeAction.value; } //private: prAddElement{arg type, usage, cookie, min, max, ioType, usagePage, usageType; elements = elements.add(HIDDeviceElement(type, usage, cookie, min, max, ioType, usagePage, usageType)); } } HIDDeviceElement { var < type, action; classvar < initialized = false; classvar < deviceSpecs; classvar < eventLoopIsRunning = false; classvar <> closeAction; *initClass { deviceSpecs = IdentityDictionary.new; closeAction = {}; ShutDown.add( { this.releaseDeviceList } ); } *keyToIndex { arg key, locID=0; var device, deviceSpec; device = devices.at(locID); ^if(device.isNil, { ^nil }, { deviceSpec = deviceSpecs.at(device.product.asSymbol); if(deviceSpec.notNil, { deviceSpec.at(key) }, { nil }); }) } *value{arg locID, cookie; _HIDGetValue } *setValue{arg locID, cookie, value; _HIDSetValue } *buildDeviceList{arg usagePage=1, usage=4; var devlist, elelist; var alreadyOpen; alreadyOpen = devices.select( _.isQueued ).asArray; alreadyOpen.do{ |it| it.dequeueDevice }; alreadyOpen = alreadyOpen.collect( _.locID ).asArray; //alreadyOpen.postln; // the following line would solve the bug when rebuilding the device list, but then there is no way to keep track of already opened devices: this.releaseDeviceList; devices = Array.new; devlist = this.prbuildDeviceList(usagePage, usage); devlist ?? {"HIDDeviceService: no devices found".warn; ^nil}; devlist.do({arg dev; var newdev; // this is an ugly, ugly workaround: if ( dev.isKindOf( Array ), { if ( dev[0].isKindOf( String ) and: dev[1].isKindOf( String ) and: dev[2].isKindOf( String ) and: dev[7].isKindOf( String ) and: dev[3].isKindOf( Integer ) and: dev[4].isKindOf( Integer ) and: dev[5].isKindOf( Integer ) and: dev[6].isKindOf( Integer ), { newdev = HIDDevice(dev.at(0), dev.at(1), dev.at(2), dev.at(3), dev.at(4), dev.at(5), dev.at(6), dev.at(7)); elelist = this.prbuildElementList(newdev.locID, Array.newClear(HIDDeviceService.prGetElementListSize(newdev.locID))); elelist.do({arg ele; if(ele.notNil){ newdev.prAddElement(ele.at(0), ele.at(1), ele.at(2), ele.at(3), ele.at(4), ele.at(5), ele.at(6), ele.at(7)); }; }); devices = devices.add(newdev); // reopen the device if it already was open if ( alreadyOpen.includes( newdev.locID ) ){ newdev.queueDevice; } }); }); }); initialized = true; } *prbuildDeviceList{arg usagePage=1, usage; _HIDBuildDeviceList ^this.primitiveFailed } *prbuildElementList{arg locID; _HIDBuildElementList ^this.primitiveFailed } *prGetElementListSize{arg locID; _HIDGetElementListSize ^this.primitiveFailed } *releaseDeviceList{ //must be called before closing the program.. if(initialized,{ this.prreleaseDeviceList; devices = nil; }); } *prreleaseDeviceList{ //must be called before closing the program.. _HIDReleaseDeviceList } *runEventLoop {arg rate=0.002; eventLoopIsRunning.if({ "META_HIDDeviceService-runEventLoop: \n\t stopping and restarting running eventLoop".warn; }); this.stopEventLoop; this.pr_runEventLoop(rate); eventLoopIsRunning = true; } *pr_runEventLoop{arg rate; _HIDRunEventLoop } *stopEventLoop{ this.pr_stopEventLoop; eventLoopIsRunning = false; } *pr_stopEventLoop{ _HIDStopEventLoop } *prHidAction{arg vendorID, productID, locID, cookie, val; action.value(vendorID, productID, locID, cookie, val); } *prReadError{ arg locID; var dev; HIDDeviceService.dequeueDevice( locID ); dev = devices.detect( { |dv| dv.locID == locID } ); dev.wasClosed; closeAction.value( locID ); } *queueDevice{arg locID; _HIDQueueDevice ^this.primitiveFailed } *dequeueDevice{arg locID; _HIDDequeueDevice ^this.primitiveFailed } *queueElement{arg locID, cookie; _HIDQueueElement ^this.primitiveFailed } *dequeueElement{arg locID, cookie; _HIDDequeueElement ^this.primitiveFailed } } //HIDDeviceService by jan trutzschler v. falkenstein [10/2003] /* these are values to pass in buildDeviceList(usagePage, usage); this is an incomplete list. for more look at IOHIDUsageTables.h most common usagePages for hid: enum { kHIDPage_Undefined = 0x00, kHIDPage_GenericDesktop = 0x01, kHIDPage_Simulation = 0x02, kHIDPage_VR = 0x03, kHIDPage_Sport = 0x04, kHIDPage_Game = 0x05, } most common usage for hid: /* GenericDesktop Page (0x01) */ enum { kHIDUsage_GD_Pointer = 0x01, /* Physical Collection */ kHIDUsage_GD_Mouse = 0x02, /* Application Collection */ /* 0x03 Reserved */ kHIDUsage_GD_Joystick = 0x04, /* Application Collection */ kHIDUsage_GD_GamePad = 0x05, /* Application Collection */ kHIDUsage_GD_Keyboard = 0x06, /* Application Collection */ kHIDUsage_GD_Keypad = 0x07, /* Application Collection */ kHIDUsage_GD_MultiAxisController = 0x08, /* Application Collection */ } /* Simulation Page (0x02) */ /* This section provides detailed descriptions of the usages employed by simulation devices. */ enum { kHIDUsage_Sim_FlightSimulationDevice = 0x01, /* Application Collection */ kHIDUsage_Sim_AutomobileSimulationDevice = 0x02, /* Application Collection */ kHIDUsage_Sim_TankSimulationDevice = 0x03, /* Application Collection */ kHIDUsage_Sim_SpaceshipSimulationDevice = 0x04, /* Application Collection */ kHIDUsage_Sim_SubmarineSimulationDevice = 0x05, /* Application Collection */ kHIDUsage_Sim_SailingSimulationDevice = 0x06, /* Application Collection */ kHIDUsage_Sim_MotorcycleSimulationDevice = 0x07, /* Application Collection */ kHIDUsage_Sim_SportsSimulationDevice = 0x08, /* Application Collection */ kHIDUsage_Sim_AirplaneSimulationDevice = 0x09, /* Application Collection */ kHIDUsage_Sim_HelicopterSimulationDevice = 0x0A, /* Application Collection */ kHIDUsage_Sim_MagicCarpetSimulationDevice = 0x0B, /* Application Collection */ kHIDUsage_Sim_BicycleSimulationDevice = 0x0C, /* Application Collection */ /* 0x0D - 0x1F Reserved */ kHIDUsage_Sim_FlightControlStick = 0x20, /* Application Collection */ kHIDUsage_Sim_FlightStick = 0x21, /* Application Collection */ kHIDUsage_Sim_CyclicControl = 0x22, /* Physical Collection */ kHIDUsage_Sim_CyclicTrim = 0x23, /* Physical Collection */ kHIDUsage_Sim_FlightYoke = 0x24, /* Application Collection */ kHIDUsage_Sim_TrackControl = 0x25, /* Physical Collection */ } /* Game Page (0x05) */ enum { kHIDUsage_Game_3DGameController = 0x01, /* Application Collection */ kHIDUsage_Game_PinballDevice = 0x02, /* Application Collection */ kHIDUsage_Game_GunDevice = 0x03, /* Application Collection */ } */ SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Control/WII.sc0000664000000000000000000003057512014636263025445 0ustar rootroot/// NOTE: this code is still in an experimental state and only works on Linux, if compiled with Wii support. /// Therefor, it also has no helpfile yet /// This code may change without notice; do not use this code, unless you really want to and don't mind /// having to change your code in the future. /// Expect this code to be fully functional by version 3.2 /// - october 2007 - nescivi WiiCalibrationInfo { var id, <>valid, <>posx, <>posy, <>size; var <>action; } WiiMote { var dataPtr, id; var closeAction, <>connectAction, <>disconnectAction; var remote_buttons, <>remote_motion, <>remote_ir; var <>nunchuk_buttons, <>nunchuk_motion, <>nunchuk_stick; var <>classic_buttons, <>classic_stick1, <>classic_stick2, <>classic_analog; var <>dumpEvents = false; classvar all; classvar < eventLoopIsRunning = false; // classvar < updateDataTask, numChannels if(this.isSettable, { server.sendBundle(nil, ["/c_setn",index,values.size] ++ values); }, {error("Cannot set an audio rate bus")}); } setnMsg { arg values; if(this.isSettable, { ^["/c_setn",index,values.size] ++ values; }, {error("Cannot set an audio rate bus"); ^nil}); } setAt { |offset ... values| // shouldn't be larger than this.numChannels - offset if(this.isSettable, { server.sendBundle(nil,(["/c_set"] ++ values.collect({ arg v,i; [index + offset + i ,v] }).flat)); }, {error("Cannot set an audio rate bus")}); } setnAt { |offset, values| // could throw an error if values.size > numChannels if(this.isSettable, { server.sendBundle(nil, ["/c_setn",index + offset, values.size] ++ values); }, {error("Cannot set an audio rate bus")}); } setPairs { | ... pairs| if(this.isSettable, { server.sendBundle(nil,(["/c_set"] ++ pairs.clump(2).collect({ arg pair; [pair[0] + index, pair[1]] }).flat)); }, {error("Cannot set an audio rate bus")}); } get { arg action; if(numChannels == 1) { action = action ? { |vals| "Bus % index: % value: %.\n".postf(rate, index, vals); }; OSCpathResponder(server.addr,['/c_set',index], { arg time, r, msg; action.value(msg.at(2)); r.remove }).add; server.listSendMsg(["/c_get",index]); } { this.getn(numChannels, action) }; } getn { arg count, action; action = action ? { |vals| "Bus % index: % values: %.\n".postf(rate, index, vals); }; OSCpathResponder(server.addr,['/c_setn',index],{arg time, r, msg; action.value(msg.copyToEnd(3)); r.remove } ).add; server.listSendMsg(this.getnMsg(count)); } getMsg { ^["/c_get",index]; } getnMsg { arg count; ^["/c_getn",index, count ? numChannels]; } getSynchronous { if (not(this.isSettable)) { Error("Bus-getSynchronous only works for control-rate busses").throw; } { ^server.getControlBusValue(index); } } getnSynchronous {|count| if (not(this.isSettable)) { Error("Bus-getnSynchronous only works for control-rate busses").throw; } { ^server.getControlBusValues(index, count ? numChannels); } } setSynchronous { |... values| if (not(this.isSettable)) { Error("Bus-setSynchronous only works for control-rate busses").throw; } { if (values.size == 1) { server.setControlBusValue(index, values[0]) } { server.setControlBusValues(index, values) } } } setnSynchronous {|values| if (not(this.isSettable)) { Error("Bus-setnSynchronous only works for control-rate busses").throw; } { server.setControlBusValues(index, values) } } fill { arg value,numChans; // could throw an error if numChans > numChannels server.sendBundle(nil, ["/c_fill",index,numChans,value]); } fillMsg { arg value; ^["/c_fill",index,numChannels,value]; } free { if(index.isNil,{ (this.asString + " has already been freed").warn; ^this }); if(rate == \audio,{ server.audioBusAllocator.free(index); },{ server.controlBusAllocator.free(index); }); index = nil; numChannels = nil; mapSymbol = nil; } // allow reallocation alloc { if(rate === 'audio', { index = server.audioBusAllocator.alloc(numChannels); }, { index = server.controlBusAllocator.alloc(numChannels); }); mapSymbol = nil; } realloc { var r, n; if(index.notNil, { r = rate; n = numChannels; this.free; rate = r; numChannels = n; this.alloc; }) } // alternate syntaxes setAll { arg value; this.fill(value,numChannels); } value_ { arg value; this.fill(value,numChannels); } printOn { arg stream; stream << this.class.name << "(" <<* [rate, index, numChannels, server] <<")" } storeOn { arg stream; stream << this.class.name << "(" <<* [rate.asCompileString, index, numChannels, server.asCompileString] <<")" } == { arg aBus; ^this.compareObject(aBus, #[\index, \numChannels, \rate, \server]) } hash { ^this.instVarHash(#[\index, \numChannels, \rate, \server]) } isAudioOut { // audio interface ^(rate === \audio and: {index < server.options.firstPrivateBus}) } ar { |numChannels=(this.numChannels), offset=0| if(rate == \audio,{ ^In.ar(index + offset, numChannels) },{ //"Bus converting control to audio rate".inform; ^K2A.ar( In.kr(index + offset, numChannels) ) }) } kr { |numChannels=(this.numChannels), offset=0| if(rate == \audio,{ ^A2K.kr( In.ar(index + offset, numChannels) ) },{ ^In.kr(index + offset, numChannels) }) } play { arg target=0, outbus, fadeTime, addAction=\addToTail; if(this.isAudioOut.not,{ // returns a Synth ^{ this.ar }.play(target, outbus, fadeTime, addAction); }); } asUGenInput { ^this.index } asControlInput { ^this.index } asMap { ^mapSymbol ?? { if(index.isNil) { MethodError("bus not allocated.", this).throw }; mapSymbol = if(rate == \control) { "c" } { "a" }; mapSymbol = (mapSymbol ++ index).asSymbol; } } // added by nescivi; gets a subbus from another bus *newFrom { |bus, offset, numChannels=1| if ( offset > bus.numChannels or: {numChannels + offset > bus.numChannels} ) { Error( "Bus:newFrom tried to reach outside the channel range of %".format( bus )).throw }; ^Bus.new( bus.rate, bus.index + offset, numChannels); } subBus{|offset, numChannels=1| ^Bus.newFrom( this, offset, numChannels ); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Geometry/0000775000000000000000000000000012245452763024636 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Geometry/Point.sc0000664000000000000000000000447512245365552026267 0ustar rootrootPoint { var <>x = 0, <>y = 0; *new { arg x=0, y=0; ^super.newCopyArgs(x, y); } @ { arg aPoint; ^Rect.fromPoints(this, aPoint) } set { arg argX=0, argY=0; x = argX; y = argY; } asPoint { ^this } asComplex { ^Complex.new(x,y) } asPolar { ^Polar.new(this.rho, this.theta) } asSize { ^Size(x,y) } asRect { ^Rect.new(0,0,x,y) } asArray { ^[this.x, this.y] } == { arg aPoint; ^this.compareObject(aPoint, #[\x, \y]) } hash { ^this.instVarHash(#[\x, \y]) } performBinaryOpOnSomething { |aSelector, thing, adverb| ^thing.asPoint.perform(aSelector, this, adverb) } + { arg delta; var deltaPoint; deltaPoint = delta.asPoint; ^(this.x + deltaPoint.x) @ (this.y + deltaPoint.y) } - { arg delta; var deltaPoint; deltaPoint = delta.asPoint; ^(this.x - deltaPoint.x) @ (this.y - deltaPoint.y) } * { arg scale; var scalePoint; scalePoint = scale.asPoint; ^(this.x * scalePoint.x) @ (this.y * scalePoint.y) } / { arg scale; var scalePoint; scalePoint = scale.asPoint; ^(this.x / scalePoint.x) @ (this.y / scalePoint.y) } div { arg scale; var scalePoint; scalePoint = scale.asPoint; ^(this.x div: scalePoint.x) @ (this.y div: scalePoint.y) } translate { arg delta; ^(this.x + delta.x) @ (this.y + delta.y) } scale { arg scale; ^(this.x * scale.x) @ (this.y * scale.y) } rotate { arg angle; // in radians var sinr, cosr; sinr = angle.sin; cosr = angle.cos; ^((x * cosr) - (y * sinr)) @ ((y * cosr) + (x * sinr)) } abs { ^x.abs @ y.abs } rho { ^hypot(x, y) } theta { ^atan2(y, x) } dist { arg aPoint; aPoint = aPoint.asPoint; ^hypot(x - aPoint.x, y - aPoint.y) } transpose { ^y @ x } round { arg quant; quant = quant.asPoint; ^x.round(quant.x) @ y.round(quant.y) } trunc { arg quant; quant = quant.asPoint; ^x.trunc(quant.x) @ y.trunc(quant.y) } mod {|that| var thatPoint; thatPoint = that.asPoint; ^(this.x mod: thatPoint.x) @ (this.y mod: thatPoint.y) } printOn { arg stream; stream << this.class.name << "( " << x << ", " << y << " )"; } storeArgs { ^[x,y] } } PointArray : Point { *new { arg n; ^super.new(Signal.new(n), Signal.new(n)) } add { arg point; x = x.add(point.x); y = y.add(point.y); } } //Lines : PointArray //{ // *new { arg n; // ^super.new(2*n) // } //} // //Polygon : PointArray //{ //} // //ZigZag : PointArray //{ //} SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Geometry/Rect.sc0000664000000000000000000001137112161364457026064 0ustar rootrootRect { var <>left=0, <>top=0, <>width=0, <>height=0; *new { arg left=0, top=0, width=0, height=0; ^super.newCopyArgs(left, top, width, height) } *newSides { arg left=0, top=0, right=0, bottom=0; ^super.newCopyArgs(left, top, right-left, bottom-top) } *fromPoints { arg pt1, pt2; ^super.newCopyArgs( pt1.x min: pt2.x, pt1.y min: pt2.y, absdif(pt1.x, pt2.x), absdif(pt1.y, pt2.y) ) } *fromRect { arg rect; ^this.new(rect.left, rect.top, rect.width, rect.height) } *fromArray {|array| ^this.new(*array) } *aboutPoint { arg point, dx, dy; ^this.new(point.x-dx, point.y-dy, 2*dx, 2*dy) } set { arg argLeft=0, argTop=0, argWidth=0, argHeight=0; left = argLeft; top = argTop; width = argWidth; height = argHeight; } setExtent { arg argWidth=0, argHeight=0; width = argWidth; height = argHeight; } origin { ^Point.new(left, top) } origin_ { | pt | left = pt.x; top = pt.y } extent { ^Point.new(width, height) } extent_ { | pt | width = pt.x; height = pt.y } center { ^Point.new(left + (width * 0.5), top + (height * 0.5)) } center_ { arg center; ^this.class.aboutPoint(center, width * 0.5, height * 0.5) } bottom { ^top + height } bottom_ { |b| top = top - (this.bottom - b) } right { ^left + width } right_ { |r| left = left - (this.right - r) } leftTop { ^Point.new(this.left, this.top) } rightTop { ^Point.new(this.right, this.top) } leftBottom { ^Point.new(this.left, this.bottom) } rightBottom { ^Point.new(this.right, this.bottom) } size { ^Size(width,height) } size_ { |sz| width = sz.width; height = sz.height } moveBy { arg h, v; ^this.class.new(left + h, top + v, width, height) } moveTo { arg h, v; ^this.class.new(h, v, width, height) } moveToPoint { arg aPoint; ^this.class.new(aPoint.x, aPoint.y, width, height) } resizeBy { arg h, v; ^this.class.new(left, top, width + h, height + (v ? h)) } resizeTo { arg h, v; ^this.class.new(left, top, h, v) } insetBy { arg h, v; if(v.isNil){ v = h }; ^this.class.new(left + h, top + v, width - h - h, height - v - v) } insetAll { arg a, b, c, d; ^this.class.new(left + a, top + b, width - a - c, height - b - d) } insetByRect { arg r; ^this.copy.insetAll(r.left, r.top, r.right, r.bottom) } centerSquare { var pos, center; if (width > height, { pos = (width - height) * 0.5 + left; ^Rect(pos, top, height, height) },{ pos = (height - width) * 0.5 + top; ^Rect(left, pos, width, width) }); } centerIn { arg inRect; var pos, spacing; spacing = (inRect.extent - this.extent) * 0.5; ^inRect.origin - this.origin + spacing; } contains{ arg anObject; if ( anObject.isKindOf( Point ), { ^this.containsPoint( anObject ) }); if ( anObject.isKindOf( Rect ), { ^this.containsRect( anObject ) }); ^false; } containsPoint { arg aPoint; ^(aPoint.x.inclusivelyBetween(left, left + width) and: { aPoint.y.inclusivelyBetween(top, top + height) }) } containsRect { arg aRect; ^(this.containsPoint(aRect.leftTop) and: {this.containsPoint(aRect.rightBottom) }) } intersects { arg aRect; if (aRect.right <= this.left, { ^false }); if (aRect.bottom <= this.top, { ^false }); if (aRect.left >= this.right, { ^false }); if (aRect.top >= this.bottom, { ^false }); ^true } & { arg aRect; ^this sect: aRect } | { arg aRect; ^this union: aRect } union { arg aRect; ^this.class.newSides( left min: aRect.left, top min: aRect.top, this.right max: aRect.right, this.bottom max: aRect.bottom) } sect { arg aRect; ^this.class.newSides( left max: aRect.left, top max: aRect.top, this.right min: aRect.right, this.bottom min: aRect.bottom) } storeArgs { ^[left,top,width,height] } printOn { arg stream; stream << this.class.name << "(" <<* [left, top, width, height] << ")"; } // the drawing routine here use Quickdraw. // If you want CoreGraphics drawing, use methods in Pen. draw { arg color, operation=2; _Rect_Draw ^this.primitiveFailed } asRect { ^this } bounds { ^Rect.new(left, top, width, height) } == { arg that; ^this.compareObject(that, #[\left, \top, \width, \height]) } hash { ^this.instVarHash(#[\left, \top, \width, \height]) } // deprec layout { arg argBounds; this.set(argBounds.left, argBounds.top, argBounds.width, argBounds.height); } asArray { ^[this.left, this.top, this.width, this.height] } performBinaryOpOnSomething { |aSelector, thing, adverb| ^thing.asRect.perform(aSelector, this, adverb) } + {|that| var thatRect; thatRect = that.asRect; ^Rect( this.left + thatRect.left, this.top + thatRect.top, this.width + thatRect.width, this.height + thatRect.height ) } - {|that| var thatRect; thatRect = that.asRect; ^Rect( this.left - thatRect.left, this.top - thatRect.top, this.width - thatRect.width, this.height - thatRect.height ) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Geometry/Size.sc0000664000000000000000000000067712014636263026102 0ustar rootrootSize { var <>width = 0, <>height = 0; *new { arg width=0, height=0; ^super.newCopyArgs(width, height); } asSize { ^this } asRect { ^Rect(0,0,width,height); } asPoint { ^Point(width,height); } asString { ^("Size(" ++ width ++ ", " ++ height ++ ")"); } == { arg other; ^ other respondsTo: #[\width, \height] and: { (other.width == width) && (other.height == height) } } } + SimpleNumber { asSize { ^Size(this, this) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/0000775000000000000000000000000012245452763024461 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/TimePatterns.sc0000664000000000000000000000422212014636263027420 0ustar rootrootPstep : Pattern { var <>list, <>durs, <>repeats; *new { arg levels, durs = 1, repeats = 1; ^super.newCopyArgs(levels, durs, repeats).init } init { if (list.isKindOf(Collection)) { list = Pseq(list); } } embedInStream { arg inval; var stream, val,dur; thisThread.endBeat = thisThread.endBeat ? thisThread.beats; // endBeat > beats only if Pfindur ended something early thisThread.endBeat = thisThread.endBeat min: thisThread.beats; repeats.value(inval).do { | i | stream = Ptuple([list, durs]).asStream; while ( { #val, dur = stream.next(inval) ? [nil, nil]; val.notNil; }, { thisThread.endBeat = thisThread.endBeat + dur; while( { thisThread.endBeat > thisThread.beats }, { inval = val.embedInStream(inval) } ) }); }; ^inval; } storeArgs { ^[list, durs, repeats] } } Pseg : Pstep { var <>curves; *new { arg levels, durs = 1, curves = \lin, repeats = 1 ; ^super.new(levels, durs, repeats).curves_(curves) } embedInStream { arg inval; var valStream, durStream, curveStream, startVal, val, dur, curve; var env; var startTime, curTime; repeats.value(inval).do { valStream = list.asStream; durStream = durs.asStream; curveStream = curves.asStream; val = valStream.next(inval) ?? {^inval}; thisThread.endBeat = thisThread.endBeat ? thisThread.beats min: thisThread.beats; while { startVal = val; val = valStream.next(inval); dur = durStream.next(inval); curve = curveStream.next(inval); val.notNil and: { dur.notNil and: { curve.notNil } } } { startTime = thisThread.endBeat; thisThread.endBeat = thisThread.endBeat + dur; if (startVal.isArray) { env = [startVal,val, dur, curve].flop.collect { | args | Env([args[0], args[1]], [args[2]], args[3]) }; while { thisThread.endBeat > curTime = thisThread.beats } { inval = yield(env.collect{ | e | e.at(curTime - startTime)}) } } { env = Env([startVal, val], [dur], curve); while { thisThread.endBeat > curTime = thisThread.beats } { inval = yield(env.at(curTime - startTime)) } } } } } storeArgs { ^[list, durs, curves, repeats] } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Stream.sc0000664000000000000000000002516612161364457026254 0ustar rootrootStream : AbstractFunction { // 'reset' is defined in class Object to do nothing. // reading parent { ^nil } next { ^this.subclassResponsibility(thisMethod) } iter { ^this } value { arg inval; ^this.next(inval) } valueArray { ^this.next } nextN { arg n, inval; ^Array.fill(n, { this.next(inval) }); } all { arg inval; // don't do this on infinite streams. var array; this.do({|item| array = array.add(item) }, inval); ^array } // writing put { arg item; ^this.subclassResponsibility(thisMethod) } putN { arg n, item; n.do({ this.put(item); }); } putAll { arg aCollection; aCollection.do {|item| this.put(item); }; } do { arg function, inval; var item, i=0; while { item = this.next(inval); item.notNil }{ function.value(item, i); i = i + 1; }; } subSample {| offset= 0, skipSize = 0| ^Routine { offset.do{ this.next }; loop { this.next.yield; skipSize.do { this.next } } } } generate { arg function, item; var i=0; while { item = this.next(item); item.notNil }{ function.value(item, i); i = i + 1; }; } // combination collect { arg argCollectFunc; // modify a stream var nextFunc = { arg inval; var nextval = this.next(inval); if ( nextval.notNil, { argCollectFunc.value(nextval, inval) }) }; var resetFunc = { this.reset }; ^FuncStream.new(nextFunc, resetFunc); } reject { arg function; // reject elements from a stream var nextFunc = { arg inval; var nextval = this.next(inval); while { nextval.notNil and: { function.value(nextval, inval) } }{ nextval = this.next(inval); }; nextval }; var resetFunc = { this.reset }; ^FuncStream.new(nextFunc, resetFunc); } select { arg function; // select elements from a stream var nextFunc = { arg inval; var nextval = this.next(inval); while { nextval.notNil and: { function.value(nextval, inval).not } }{ nextval = this.next(inval); }; nextval }; var resetFunc = { this.reset }; ^FuncStream.new(nextFunc, resetFunc); } dot { arg function, stream; // combine item by item with another stream ^FuncStream.new( { arg inval; var x = this.next(inval); var y = stream.next(inval); if ( x.notNil and: { y.notNil }, { function.value(x, y, inval) }); }, { this.reset; stream.reset; } ); } interlace { arg function, stream; // interlace with another stream var nextx = this.next; var nexty = stream.next; ^FuncStream.new({ |inval| var val; if ( nextx.isNil ) { if ( nexty.isNil) {nil}{ val = nexty; nexty = stream.next(inval); val }; }{ if ( nexty.isNil or: { function.value(nextx, nexty, inval) }, { val = nextx; nextx = this.next(inval); val }, { val = nexty; nexty = stream.next(inval); val } ); }; }, { this.reset; stream.reset; nextx = this.next; nexty = stream.next; }); } ++ { arg stream; ^this.appendStream(stream) } appendStream { arg stream; var reset = false; ^Routine({ arg inval; if (reset) { this.reset; stream.reset; }; reset = true; inval = this.embedInStream(inval); stream.embedInStream(inval); }); } collate { arg stream; // ascending order merge of two streams ^this.interlace({|x y| x < y }, stream); } <> { arg obj; ^Pchain(this, obj).asStream } // function composition composeUnaryOp { arg argSelector; ^UnaryOpStream.new(argSelector, this) } composeBinaryOp { arg argSelector, argStream, adverb; if(adverb.isNil) { ^BinaryOpStream.new(argSelector, this, argStream.asStream) } { if (adverb == 'x') { ^BinaryOpXStream.new(argSelector, this, argStream.asStream); }; }; ^nil } reverseComposeBinaryOp { arg argSelector, argStream, adverb; if(adverb.isNil) { ^BinaryOpStream.new(argSelector, argStream.asStream, this) } { if (adverb == 'x') { ^BinaryOpXStream.new(argSelector, argStream.asStream, this); }; }; ^nil } composeNAryOp { arg argSelector, anArgList; ^NAryOpStream.new(argSelector, this, anArgList.collect(_.asStream)); } embedInStream { arg inval; var outval; while { outval = this.value(inval); outval.notNil }{ inval = outval.yield; }; ^inval } asEventStreamPlayer { arg protoEvent; ^EventStreamPlayer(this, protoEvent); } play { arg clock, quant; clock = clock ? TempoClock.default; clock.play(this, quant.asQuant); } trace { arg key, printStream, prefix=""; ^Ptrace(this, key, printStream, prefix).asStream } // constrain { arg sum, tolerance=0.001; // ^Pconst(sum, tolerance).asStream // } repeat { arg repeats = inf; ^r { arg inval; repeats.value(inval).do { inval = this.reset.embedInStream(inval) } } } } OneShotStream : Stream { var value, once = true; *new { arg value; ^super.newCopyArgs(value) } next { ^if (once) {once = false; value} } reset { once = true } storeArgs { ^[value] } } EmbedOnce : Stream { var nextFunc; // Func is evaluated for each next state var <>resetFunc; // Func is evaluated on reset var <>envir; *new { |nextFunc, resetFunc| ^super.new.nextFunc_(nextFunc).resetFunc_(resetFunc).envir_(currentEnvironment) } next { arg inval; ^envir.use({ nextFunc.value(inval).processRest(inval) }) } reset { ^envir.use({ resetFunc.value }) } storeArgs { ^[nextFunc, resetFunc] } } StreamClutch : Stream { var <>stream, <>connected, value, >reset=true; *new { arg pattern, connected = true; ^super.newCopyArgs(pattern.asStream, connected) } next { arg inval; if(reset) { reset = false; value = stream.next(inval) }; if(connected.value(inval)) { value = stream.next(inval); }; ^value } lastValue { ^value } reset { stream.reset; reset = true } step { arg inval; value = stream.next(inval ? Event.default) } } CleanupStream : Stream { var cleanup; *new { arg stream, cleanup; ^super.newCopyArgs(stream, cleanup) } next { arg inval; var outval = stream.next(inval); if (outval.isNil) { cleanup.value(this, inval); cleanup = nil; } ^outval } reset { stream.reset } } // PauseStream is a stream wrapper that can be started and stopped. PauseStream : Stream { var streamHasEnded=false; var isWaiting = false, era=0; *new { arg argStream, clock; ^super.newCopyArgs(nil, argStream, clock ? TempoClock.default) } isPlaying { ^stream.notNil } play { arg argClock, doReset = (false), quant; if (stream.notNil, { "already playing".postln; ^this }); if (doReset, { this.reset }); clock = argClock ? clock ? TempoClock.default; streamHasEnded = false; this.refresh; //stream = originalStream; isWaiting = true; // make sure that accidental play/stop/play sequences // don't cause memory leaks era = CmdPeriod.era; clock.play({ if(isWaiting and: { nextBeat.isNil }) { clock.sched(0, this); isWaiting = false; this.changed(\playing) }; nil }, quant.asQuant); this.changed(\userPlayed); ^this } reset { originalStream.reset } stop { this.prStop; this.changed(\userStopped); } prStop { stream = nil; isWaiting = false; } removedFromScheduler { nextBeat = nil; this.prStop; this.changed(\stopped); } streamError { this.removedFromScheduler; streamHasEnded = true; } wasStopped { ^streamHasEnded.not and: { stream.isNil } // stopped by clock or stop-message or: { CmdPeriod.era != era } // stopped by cmd-period, after stream has ended } canPause { ^this.streamHasEnded.not } pause { this.stop; } resume { arg argClock, quant; ^this.play(clock ? argClock, false, quant) } refresh { stream = originalStream.threadPlayer_(this) } start { arg argClock, quant; ^this.play(argClock, true, quant) } stream_ { arg argStream; originalStream.threadPlayer_(nil); // not owned any more originalStream = argStream.threadPlayer_(this); if (stream.notNil, { stream = argStream; streamHasEnded = argStream.isNil; }); } next { arg inval; var nextTime = stream.next(inval); if (nextTime.isNil) { streamHasEnded = stream.notNil; this.removedFromScheduler; } { nextBeat = inval + nextTime }; // inval is current logical beat ^nextTime } awake { arg beats, seconds, inClock; stream.beats = beats; ^this.next(beats) } threadPlayer { ^this } } // Task is a PauseStream for wrapping a Routine Task : PauseStream { *new { arg func, clock; ^super.new(Routine(func), clock) } storeArgs { ^originalStream.storeArgs ++ if(clock != TempoClock.default) { clock } } } //////////////////////////////////////////////////////////////////////// EventStreamPlayer : PauseStream { var <>event, <>muteCount = 0, <>cleanup, <>routine; *new { arg stream, event; ^super.new(stream).event_(event ? Event.default).init; } init { cleanup = EventStreamCleanup.new; routine = Routine{ | inTime | loop { inTime = this.prNext(inTime).yield } }; } // freeNodes is passed as false from //TempoClock:cmdPeriod removedFromScheduler { | freeNodes = true | nextBeat = nil; cleanup.terminate(freeNodes); this.prStop; this.changed(\stopped); } prStop { stream = nextBeat = nil; isWaiting = false; } stop { cleanup.terminate; this.prStop; this.changed(\userStopped); } reset { routine.reset; super.reset } mute { muteCount = muteCount + 1; } unmute { muteCount = muteCount - 1; } canPause { ^this.streamHasEnded.not and: { cleanup.functions.isEmpty } } next { | inTime | ^routine.next(inTime) } prNext { arg inTime; var nextTime; var outEvent = stream.next(event.copy); if (outEvent.isNil) { streamHasEnded = stream.notNil; cleanup.clear; this.removedFromScheduler; ^nil }{ nextTime = outEvent.playAndDelta(cleanup, muteCount > 0); if (nextTime.isNil) { this.removedFromScheduler; ^nil }; nextBeat = inTime + nextTime; // inval is current logical beat ^nextTime }; } asEventStreamPlayer { ^this } play { arg argClock, doReset = (false), quant; if (stream.notNil, { "already playing".postln; ^this }); if (doReset, { this.reset }); clock = argClock ? clock ? TempoClock.default; streamHasEnded = false; stream = originalStream; isWaiting = true; // make sure that accidental play/stop/play sequences // don't cause memory leaks era = CmdPeriod.era; quant = quant.asQuant; event = event.synchWithQuant(quant); clock.play({ if(isWaiting and: { nextBeat.isNil }) { clock.sched(0, this ); isWaiting = false; this.changed(\playing) }; nil }, quant); this.changed(\userPlayed); ^this } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/ListPatterns.sc0000664000000000000000000002323112161364457027444 0ustar rootrootPindex : Pattern { var listPat, indexPat, repeats; *new { arg listPat, indexPat, repeats=1; ^super.newCopyArgs(listPat, indexPat, repeats) } storeArgs { ^[listPat,indexPat,repeats] } embedInStream { arg inval; var indexStream, index, item, itemCount; var listStream = listPat.asStream; repeats.value(inval).do { var list = listStream.next(inval); if (list.isNil) { ^inval }; indexStream = indexPat.asStream; itemCount = 0; while { index = indexStream.next(inval); index.notNil }{ itemCount = itemCount + 1; item = list.wrapAt(index); inval = item.embedInStream(inval); }; if(itemCount == 0) { ^inval } }; ^inval; } } ListPattern : Pattern { var <>list, <>repeats=1; *new { arg list, repeats=1; if (list.size > 0) { ^super.new.list_(list).repeats_(repeats) }{ Error("ListPattern (" ++ this.name ++ ") requires a non-empty collection; received " ++ list ++ ".").throw; } } copy { ^super.copy.list_(list.copy) } storeArgs { ^[ list, repeats ] } } Pseq : ListPattern { var <>offset; *new { arg list, repeats=1, offset=0; ^super.new(list, repeats).offset_(offset) } embedInStream { arg inval; var item, offsetValue; offsetValue = offset.value(inval); if (inval.eventAt('reverse') == true, { repeats.value(inval).do({ arg j; list.size.reverseDo({ arg i; item = list.wrapAt(i + offsetValue); inval = item.embedInStream(inval); }); }); },{ repeats.value(inval).do({ arg j; list.size.do({ arg i; item = list.wrapAt(i + offsetValue); inval = item.embedInStream(inval); }); }); }); ^inval; } storeArgs { ^[ list, repeats, offset ] } } Pser : Pseq { embedInStream { arg inval; var item; var offsetValue = offset.value(inval); if (inval.eventAt('reverse') == true, { repeats.value(inval).reverseDo({ arg i; item = list.wrapAt(i + offsetValue); inval = item.embedInStream(inval); }); },{ repeats.value(inval).do({ arg i; item = list.wrapAt(i + offsetValue); inval = item.embedInStream(inval); }); }); ^inval; } } Pshuf : ListPattern { embedInStream { arg inval; var item, stream; var localList = list.copy.scramble; repeats.value(inval).do({ arg j; localList.size.do({ arg i; item = localList.wrapAt(i); inval = item.embedInStream(inval); }); }); ^inval; } } Prand : ListPattern { embedInStream { arg inval; var item; repeats.value(inval).do({ arg i; item = list.at(list.size.rand); inval = item.embedInStream(inval); }); ^inval; } } Pxrand : ListPattern { embedInStream { arg inval; var item, size; var index = list.size.rand; repeats.value(inval).do({ arg i; size = list.size; index = (index + (size - 1).rand + 1) % size; item = list.at(index); inval = item.embedInStream(inval); }); ^inval; } } Pwrand : ListPattern { var <>weights; *new { arg list, weights, repeats=1; ^super.new(list, repeats).weights_(weights) } embedInStream { arg inval; var item, wVal; var wStr = weights.asStream; repeats.value(inval).do({ arg i; wVal = wStr.next(inval); if(wVal.isNil) { ^inval }; item = list.at(wVal.windex); inval = item.embedInStream(inval); }); ^inval } storeArgs { ^[ list, weights, repeats ] } } Pfsm : ListPattern { embedInStream { arg inval; var item, index=0; var maxState = ((list.size - 1) div: 2) - 1; repeats.value(inval).do({ index = 0; while({ index = list.at(index).choose.clip(0, maxState) * 2 + 2; item = list.at(index - 1); item.notNil },{ inval = item.embedInStream(inval); }); }); ^inval; } } Pdfsm : ListPattern { var <>startState; *new { arg list, startState=0, repeats=1; ^super.new( list, repeats ).startState_(startState) } embedInStream { arg inval; var currState, sigStream; var sig, state, stream; var numStates = list.size - 1; repeats.value(inval).do({ currState = startState; sigStream = list[0].asStream; while({ sig = sigStream.next(inval); state = list[currState + 1]; if( sig.isNil, { false }, { if( state.includesKey(sig), { #currState, stream = state[sig]; }, { #currState, stream = state[\default]; }); currState.notNil and: {currState < numStates}; }) }, { inval = stream.embedInStream(inval); }) }); ^inval; } } Pswitch : Pattern { var <>list, <>which=0; *new { arg list, which=0; ^super.new.list_(list).which_(which) } embedInStream { arg inval; var item, index; var indexStream = which.asStream; while ({ (index = indexStream.next(inval)).notNil; },{ inval = list.wrapAt(index.asInteger).embedInStream(inval); }); ^inval; } storeArgs { ^[ list, which ] } } Pswitch1 : Pswitch { embedInStream { arg inval; var cleanup = EventStreamCleanup.new; var index, outval; var streamList = list.collect({ arg pattern; pattern.asStream; }); var indexStream = which.asStream; loop { if ((index = indexStream.next(inval)).isNil) { ^cleanup.exit(inval) }; outval = streamList.wrapAt(index.asInteger).next(inval); if (outval.isNil) { ^cleanup.exit(inval) }; cleanup.update(outval); inval = outval.yield; }; } } Ptuple : ListPattern { embedInStream { arg inval; var item, streams, tuple, outval; repeats.value(inval).do({ arg j; var sawNil = false; streams = list.collect({ arg item; item.asStream }); while ({ tuple = Array.new(streams.size); streams.do({ arg stream; outval = stream.next(inval); if (outval.isNil, { sawNil = true; }); tuple.add(outval); }); sawNil.not },{ inval = yield(tuple); }); }); ^inval; } } Place : Pseq { embedInStream { arg inval; var item; var offsetValue = offset.value(inval); if (inval.eventAt('reverse') == true, { repeats.value(inval).do({ arg j; list.size.reverseDo({ arg i; item = list.wrapAt(i + offsetValue); if (item.isSequenceableCollection, { item = item.wrapAt(j); }); inval = item.embedInStream(inval); }); }); },{ repeats.value(inval).do({ arg j; list.size.do({ arg i; item = list.wrapAt(i + offsetValue); if (item.isSequenceableCollection, { item = item.wrapAt(j); }); inval = item.embedInStream(inval); }); }); }); ^inval; } } // similar to Place, but the list is an array of Patterns or Streams Ppatlace : Pseq { embedInStream { |inval| var consecutiveNils = 0, index, repeat, item; var streamList = list.collect({ |item| item.asStream }); var offsetValue = offset.value(inval); var localRepeats = repeats.value(inval); index = repeat = 0; while { (repeat < localRepeats) and: { consecutiveNils < list.size } } { if(inval.eventAt(\reverse) == true) { item = streamList.wrapAt(offsetValue - index - 1); } { item = streamList.wrapAt(offsetValue + index); }; if((item = item.next(inval)).notNil) { consecutiveNils = 0; inval = item.embedInStream(inval); } { consecutiveNils = consecutiveNils + 1; }; if((index = index + 1) == list.size) { index = 0; repeat = repeat + 1; }; }; ^inval; } } Pslide : ListPattern { // 'repeats' is the number of segments. // 'len' is the length of each segment. // 'step' is how far to step the start of each segment from previous. // 'start' is what index to start at. // indexing wraps around if goes past beginning or end. // step can be negative. var <>len, <>step, <>start, <>wrapAtEnd; *new { arg list, repeats = 1, len = 3, step = 1, start = 0, wrapAtEnd = true; ^super.new(list, repeats).len_(len).step_(step).start_(start) .wrapAtEnd_(wrapAtEnd); } embedInStream { arg inval; var item; var pos = start; var stepStr = step.asStream, stepVal; var lengthStr = len.asStream, lengthVal; repeats.value(inval).do { lengthVal = lengthStr.next(inval); if(lengthVal.isNil) { ^inval }; if(wrapAtEnd) { lengthVal.do { |j| item = list.wrapAt(pos + j); inval = item.embedInStream(inval); } } { lengthVal.do { |j| item = list.at(pos + j); if(item.notNil) { inval = item.embedInStream(inval); } { ^inval }; } }; stepVal = stepStr.next(inval); if(stepVal.isNil) { ^inval }; pos = pos + stepVal; }; ^inval; } } Pwalk : ListPattern { // random walk pattern - hjh - jamshark70@gmail.com var <>startPos, // starting index <>stepPattern, // pattern for steps <>directionPattern; // pattern should return a stream of: // 1 to move in direction of stepPattern // -1 to reverse the direction of stepPattern // a new direction will be chosen when the walker // reaches a boundary *new { arg list, stepPattern, directionPattern = 1, startPos = 0; ^super.new(list).startPos_(startPos) .stepPattern_(stepPattern ?? { Prand([-1, 1], inf) }) .directionPattern_(directionPattern ? 1); } storeArgs { ^[list, stepPattern, directionPattern, startPos] } embedInStream { arg inval; var step; var index = startPos; var stepStream = stepPattern.asStream; var directionStream = directionPattern.asStream; // 1 = use steps as is; -1 = reverse direction var direction = directionStream.next(inval) ? 1; // start with first value while({ // get step, stop when nil (step = stepStream.next(inval)).notNil },{ inval = list[index].embedInStream(inval); // get value/stream out step = step * direction; // apply direction // if next thing will be out of bounds if(((index + step) < 0) or: { (index + step) >= list.size }, { direction = directionStream.next(inval) ? 1; // next direction, or 1 step = step.abs * direction.sign; // apply to this step }); index = (index + step) % list.size; }); ^inval; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Plambda.sc0000664000000000000000000000363512014636263026350 0ustar rootrootPlambda : FilterPattern { var <>scope; *new { arg pattern, scope; ^super.new(pattern).scope_(scope) } embedInStream { arg inval; var embedScope, stream, outval, parentScope; stream = pattern.asStream; inval !? { parentScope = inval[\eventScope] }; embedScope = (scope.copy ? ()).parent_(parentScope); while { inval = inval.copy ? (); inval[\eventScope] = embedScope; outval = stream.next(inval); outval.notNil } { // return outer scope outval = outval.copy; outval[\eventScope] = outval[\eventScope].eventAt(\parent); inval = outval.yield }; ^inval } storeArgs { ^if(scope.notNil) { [pattern, scope] } { [pattern] } } } Plet : Pattern { var <>pattern, <>key, <>return; *new { arg key, pattern, return; ^super.newCopyArgs(pattern, key, return) } embedInStream { arg inval; var str = pattern.asStream, val, sval, outval, scope; var returnStr = return.asStream, returnVal; while { outval = str.next(inval); returnVal = returnStr.next(inval); outval.notNil } { scope = inval[\eventScope]; if(scope.isNil) { Error("no scope defined in event").throw }; // don't transmit scope val = outval.copy; if(val.eventAt(\eventScope).notNil) { val[\eventScope] = nil }; scope[key] = val; inval = (returnVal ? outval).yield; } } silent { return = Event.silent } storeArgs { ^[key, pattern] ++ return } } Pget : Pattern { var <>key, <>default, <>repeats; *new { arg key, default, repeats = 1; ^super.newCopyArgs(key, default, repeats) } embedInStream { arg inval; var scope = inval[\eventScope], outval; if(scope.isNil) { Error("no scope defined in event").throw }; repeats.value(inval).do { outval = scope[key] ? default; if(outval.isNil) { ^inval }; outval.yield }; ^inval } storeArgs { var list = [key]; if(repeats != 1) { ^[key, default, repeats] }; if(default.notNil) { ^[key, default] } ^[key] } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/PatternConductor.sc0000664000000000000000000000250512014636263030301 0ustar rootroot/* PatternConductor provides interactive control of patterns. When a Conductor is stopped it flushes its queue, immediately ending any notes left hanging by the pattern. */ PatternConductor { var <>patterns, <>event, <>quant, <>eventStreamPlayers; var <>clock, defaultPauseTempo, <>defaultStopTempo; *new { |patterns, event, quant| ^super.new .patterns_(patterns.asArray) .event_(event ? Event.default) .quant_(quant ? 0).tempo_(1).defaultPauseTempo_(1e-8).defaultStopTempo_(1e+8); } play { Routine.run({ this.prPlay }, 64, TempoClock.default, quant) } prPlay { if (clock.notNil) { this.stop }; CmdPeriod.add(this); clock = TempoClock(tempo); eventStreamPlayers = patterns.collect { | p | p.asEventStreamPlayer(event) }; eventStreamPlayers.do { | p | p.play(clock, false, 0) }; } pause { | pauseTempo| clock.tempo = pauseTempo ? defaultPauseTempo } resume { clock.tempo = tempo } stop { |stopTempo| var oldClock; oldClock = clock; eventStreamPlayers.do { | p | p.stop }; clock.tempo = stopTempo ? defaultStopTempo; Task({ while {oldClock.queue.size >= 2 } { yield(1) }; oldClock.stop }).play(clock); clock = nil; eventStreamPlayers = nil; CmdPeriod.remove(this); } tempo_ { | temp | tempo = temp; if (clock.notNil) { clock.tempo_(tempo) }; } cmdPeriod { clock = nil } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Pproto.sc0000664000000000000000000000506212014636263026267 0ustar rootrootPfpar : ListPattern { initStreams { arg priorityQ; list.do({ arg pattern, i; priorityQ.put(0.0, pattern.asStream); }); } asStream { | cleanup| ^Routine({ arg inval; this.embedInStream(inval, cleanup) }) } embedInStream { arg inval, cleanup; var assn; var priorityQ = PriorityQueue.new; cleanup ?? { cleanup = EventStreamCleanup.new }; repeats.value(inval).do({ arg j; var outval, stream, nexttime, now = 0.0; this.initStreams(priorityQ); // if first event not at time zero if (priorityQ.notEmpty and: { (nexttime = priorityQ.topPriority) > 0.0 }, { inval = Event.silent(nexttime, inval).yield; now = nexttime; }); while({ priorityQ.notEmpty },{ stream = priorityQ.pop; outval = stream.next(inval).asEvent; if (outval.isNil, { priorityQ.clear; ^cleanup.exit(inval); },{ cleanup.update(outval); // requeue stream priorityQ.put(now + outval.delta, stream); nexttime = priorityQ.topPriority; outval.put(\delta, nexttime - now); inval = outval.yield; // inval ?? { this.purgeQueue(priorityQ); ^nil.yield }; now = nexttime; }); }); }); ^inval; } } Pproto : Pattern { var <>makeFunction, <>pattern, <>cleanupFunc; *new { | makeFunction, pattern, cleanupFunc| ^super.newCopyArgs( makeFunction, pattern, cleanupFunc) } storeArgs { ^[makeFunction,pattern,cleanupFunc] } embedInStream { | event | var stream, ev, evType; var cleanup, cleanupList, eventCleanupFunc; var proto; // temporary proto event used in allocation var makeRoutine; // routine wrapper for function that makes protoEvent var protoEvent; // protoEvent created by function // Step 1: generate resources from function proto = ( delta: 0, // events occur simultaneously finish: { ev = currentEnvironment} // get copy of event object actually played ); protoEvent = (); makeRoutine = Routine({ protoEvent.make (makeFunction) }); while { (ev = makeRoutine.next(ev)).notNil; } { event = ev.proto_(proto).yield; ev.proto = nil; cleanupList = cleanupList.add(ev) }; cleanup = EventStreamCleanup.new; eventCleanupFunc = { | flag | cleanupList.do { | ev | EventTypesWithCleanup.cleanup(ev, flag) } }; cleanupFunc = eventCleanupFunc ?? { { | flag | eventCleanupFunc.value(proto, flag) } }; cleanup.addFunction(event, cleanupFunc); stream = Pfpar(pattern.asArray).asStream(cleanup); loop { ev = event.copy.putAll(protoEvent); ev = stream.next(ev) ?? { ^cleanup.exit(event) }; event = ev.yield; }; ^event } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/IOStream.sc0000664000000000000000000001510712245365552026476 0ustar rootrootIOStream : Stream { reset { this.pos = 0; } skip { arg n; this.pos = this.pos + n; } comma { this.put(Char.comma);} space { this.put(Char.space); } nl { this.put(Char.nl); } ff { this.put(Char.ff); } tab { this.put(Char.tab); } << { arg item; item.printOn(this); } <<< { arg item; item.storeOn(this); } <<* { arg collection; collection.printItemsOn(this); } <<<* { arg collection; collection.storeItemsOn(this); } readUpTo { arg delimiter = $\f; var string, char; string = String.new; char = this.next; if(char.isNil) { ^nil }; while ({ char.notNil and: { char != delimiter } },{ string = string.add(char); char = this.next; }); ^string } flush {} pos_ { ^this.subclassResponsibility(thisMethod) } } CollStream : IOStream { var <>collection, = collection.size, { ^nil },{ pos = pos + 1; ^collection.at(pos - 1); }) } nextN { arg n; ^collection.species.fill(n, { this.next; }); } contents { ^collection.copyRange(0, collection.size-1); } put { arg item; //_RWStream_Put if (pos >= collection.size, { pos = collection.size + 1; collection = collection.add(item); },{ collection.put(pos, item); pos = pos + 1; }) } putAll { arg aCollection; collection = collection.overWrite(aCollection, pos); pos = pos + aCollection.size; } // write { arg item; // /* writes any of the following items as binary: // a double float, // a long, // an rgb color, // a char, // the name of a Symbol as chars, // the indexable part of any non-Slot format object, // (i.e. Strings, Int8Arrays, Int16Arrays, // Signals, etc.) // */ // _CollStream_Write // ^this.primitiveFailed; // } getChar { ^this.next; } getInt8 { ^this.next & 255; } getInt16 { ^this.getInt8 << 8 | this.getInt8; } getInt32 { ^this.getInt16 << 16 | this.getInt16; } getFloat { ^Float.from32Bits(this.getInt32); } getDouble { ^Float.from64Bits(this.getInt32, this.getInt32); } getPascalString { var size = this.getInt8; ^String.fill(size, { this.getChar.asAscii }) } // array should be some subclass of RawArray read { |array| array.readFromStream(this); } // // collection should be an Int8Array putChar { arg aChar; this.put(aChar.ascii); } putInt8 { arg anInteger; this.put(anInteger & 255); } putInt16 { arg anInteger; this.putInt8(anInteger>>8); this.putInt8(anInteger); } putInt16LE { arg anInteger; this.putInt8(anInteger); this.putInt8(anInteger>>8); } putInt32 { arg anInteger; this.putInt8(anInteger>>24); this.putInt8(anInteger>>16); this.putInt8(anInteger>>8); this.putInt8(anInteger); } putInt32LE { arg anInteger; this.putInt8(anInteger); this.putInt8(anInteger>>8); this.putInt8(anInteger>>16); this.putInt8(anInteger>>24); } putFloat { arg aFloat; aFloat = aFloat.asFloat; this.putInt32(aFloat.as32Bits); } putDouble { arg aFloat; aFloat = aFloat.asFloat; this.putInt32(aFloat.high32Bits); this.putInt32(aFloat.low32Bits); } putFloatLE { arg aFloat; aFloat = aFloat.asFloat; this.putInt32LE(aFloat.as32Bits); } putDoubleLE { arg aFloat; aFloat = aFloat.asFloat; this.putInt32LE(aFloat.low32Bits); this.putInt32LE(aFloat.high32Bits); } putString { arg aString; aString.do({ arg char; this.putChar(char); }); } putPascalString { arg aString; this.putInt8(aString.size); this.putString(aString); } } LimitedWriteStream : CollStream { var <>limit, <>limitFunc; atLimit { ^pos >= limit } put { arg item; var newpos; newpos = pos + 1; if (newpos > limit, { limitFunc.value; limitFunc = nil; },{ super.put(item); }); } putAll { arg aCollection; var newpos; newpos = pos + aCollection.size; if (newpos > limit, { aCollection = aCollection.copyFromStart(limit - pos - 1); collection = collection.overWrite(aCollection, pos); pos = limit; limitFunc.value; limitFunc = nil; },{ collection = collection.overWrite(aCollection, pos); pos = newpos; }); } } Post { classvar <>formats; *initClass { formats = IdentityDictionary[ $c -> { |x| x.asCompileString }, ]; } //*flush { this.flushPostBuf } * << { arg item; item.printOn(this); } * <<< { arg item; item.storeOn(this); } * <<* { arg collection; collection.printItemsOn(this); } * <<<* { arg collection; collection.storeItemsOn(this); } * put { arg item; item.post; } * putAll { arg aCollection; aCollection.post; } * comma { this.put(Char.comma);} * space { this.put(Char.space); } * nl { this.put(Char.nl); } * ff { this.put(Char.ff); } * tab { this.put(Char.tab); } * close { this.flush; } } Pretty : IOStream { var <>out, <>level = 0, <>state; *new { arg out; var stream; stream = super.new.out_(out); stream.state_(PrettyEcho(stream)); ^stream } put { arg char; state.put(char); } close { out.close; } } PrettyState { var <>pretty; *new { arg pretty; ^super.new.pretty_(pretty); } } PrettyEcho : PrettyState { put { arg char; // echo chars until new line if ((char == $\n) || (char == $\r), { pretty.out.put($\n); pretty.state_(PrettyEat(pretty)); },{ if (char == ${ , /* } */ { pretty.out.put($\n); pretty.level.do({ pretty.out.put($\t) }); pretty.out.put(char); pretty.out.put($\n); pretty.level = pretty.level + 1; pretty.state_(PrettyEat(pretty)); },{ if ( /*{*/ char == $}, { pretty.level = pretty.level - 1; pretty.out.put($\n); pretty.level.do({ pretty.out.put($\t) }); pretty.out.put(char); pretty.out.put($\n); pretty.state_(PrettyEat(pretty)); },{ pretty.out.put(char); }) }) }); } } PrettyEat : PrettyState { put { arg char; if (char == ${, /*}*/ { pretty.level.do({ pretty.out.put($\t) }); pretty.out.put(char); pretty.out.put($\n); pretty.level = pretty.level + 1; },{ if (((char == $\n) || (char == $\r)) && (pretty.level == 0), { pretty.out.put($\n); },{ if (char.isSpace.not, { if ( /*{*/ char == $}, { pretty.level = pretty.level - 1; pretty.level.do({ pretty.out.put($\t) }); pretty.out.put(char); pretty.out.put($\n); },{ pretty.level.do({ pretty.out.put($\t) }); pretty.out.put(char); pretty.state_(PrettyEcho(pretty)); }); }); }); }); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Quant.sc0000664000000000000000000000177012014636263026076 0ustar rootroot// This class is used to encapsulate quantization issues associated with EventStreamPlayer and TempoClock // quant and phase determine the starting time of something scheduled by a TempoClock // timingOffset is an additional timing factor that allows an EventStream to compute "ahead of time" enough to allow // negative lags for strumming a chord, etc Quant { classvar default; var <>quant, <>phase, <>timingOffset; *default { ^default ?? { Quant.new } } *default_ { |quant| default = quant.asQuant } *new { |quant = 0, phase, timingOffset| ^super.newCopyArgs(quant, phase, timingOffset) } nextTimeOnGrid { | clock | ^clock.nextTimeOnGrid(quant, (phase ? 0) - (timingOffset ? 0)); } asQuant { ^this.copy } printOn { |stream| stream << "Quant(" << quant; if(phase.notNil) { stream << ", " << phase }; if(timingOffset.notNil) { stream << ", "; if(phase.isNil) { stream << "nil, "; }; stream << timingOffset }; stream << ")" } storeArgs { ^[quant, phase, timingOffset] } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/TabFileReader.sc0000664000000000000000000000361012014636263027432 0ustar rootrootFileReader : Stream { // a class to read text files automatically classvar 0 }) { record = record.add(string); string = String.new; } } { if (c == $\n or: { c == $\r }) { record = record.add(string); string = String.new; if (skipEmptyLines.not or: { (record != [ "" ]) }) { ^record }; record = nil; }{ string = string.add(c); } } }; if (string.notEmpty) { ^record.add(string) }; ^record; } read { ^this.all } *read { | path, skipEmptyLines=false, skipBlanks=false, func, delimiter, startRow = 0, skipSize = 0 | var fr, table; fr = this.new(path, skipEmptyLines, skipBlanks, delimiter) ?? { ^nil }; if (func.notNil) { table = fr.subSample(startRow, skipSize).collect(_.collect(func)).all; } { table = fr.subSample(startRow, skipSize).all; }; fr.close; ^table } *readInterpret { | path, skipEmptyLines=false, skipBlanks=false, delimiter, startRow = 0, skipSize = 0 | ^this.read(path, skipEmptyLines, skipBlanks, _.interpret, delimiter, startRow, skipSize ) } } TabFileReader : FileReader { classvar randSeed; *new { arg randSeed, pattern; ^super.new(pattern).randSeed_(randSeed) } storeArgs { ^[randSeed,pattern] } embedInStream { arg inval; var seedStream; var seed, thread; seedStream = randSeed.asStream; while { seed = seedStream.next(inval); seed.notNil }{ thread = Routine { |inval| pattern.embedInStream(inval) }; thread.randSeed = seed; inval = thread.embedInStream(inval); }; ^inval } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/FilterPatterns.sc0000664000000000000000000004363112245365552027764 0ustar rootrootFilterPattern : Pattern { var <>pattern; *new { arg pattern; ^super.new.pattern_(pattern) } } Pn : FilterPattern { var <>repeats, <>key; *new { arg pattern, repeats=inf, key; ^super.newCopyArgs(pattern, repeats, key ) } storeArgs { ^[pattern,repeats, key] } embedInStream { | event | if(key.isNil) { repeats.value(event).do { event = pattern.embedInStream(event) }; } { repeats.value(event).do { event = pattern.embedInStream(event); event[key] = true; }; event[key] = false; }; ^event; } } Pgate : Pn { *new { arg pattern, repeats=inf, key ; ^super.new(pattern).repeats_(repeats).key_(key) } storeArgs { ^[pattern,repeats, key] } embedInStream { | event | var stream, output; repeats.do { stream = pattern.asStream; output = stream.next(event); while { if (event[key] == true) { output = stream.next(event) }; output.notNil; } { event = output.copy.embedInStream(event) } }; ^event; } } FuncFilterPattern : FilterPattern { var <>func; *new { arg func, pattern; ^super.new(pattern).func_(func) } storeArgs { ^[func,pattern] } } Pcollect : FuncFilterPattern { embedInStream { arg inval; var stream, outval; stream = pattern.asStream; loop { outval = stream.next(inval); if (outval.isNil) { ^inval }; inval = yield(func.value(outval, inval)); } } asStream { ^pattern.asStream.collect(func); } } Pselect : FuncFilterPattern { embedInStream { arg inval; var stream, outval; stream = pattern.asStream; loop { while ({ outval = stream.next(inval); if (outval.isNil) { ^inval }; func.value(outval, inval).not }); inval = yield(outval); } } asStream { ^pattern.asStream.select(func); } } Preject : FuncFilterPattern { embedInStream { arg inval; var stream, outval; stream = pattern.asStream; loop { while ({ outval = stream.next(inval); if (outval.isNil) { ^inval }; func.value(outval, inval); }); inval = yield(outval); } } asStream { ^pattern.asStream.reject(func); } } Pfset : FuncFilterPattern { var <>cleanupFunc; *new { |func, pattern, cleanupFunc| ^super.new(func, pattern).cleanupFunc_(cleanupFunc) } embedInStream { arg inevent; var event, cleanup = EventStreamCleanup.new; // cleanup should actually not be passed in // but retaining (temporarily) for backward compatibility var envir = Event.make({ func.value(cleanup) }); var stream = pattern.asStream; var once = true; loop { inevent.putAll(envir); event = stream.next(inevent); if(once) { cleanup.addFunction(event, { |flag| envir.use({ cleanupFunc.value(flag) }); }); once = false; }; if (event.isNil) { ^cleanup.exit(inevent) } { cleanup.update(event); }; inevent = yield(event); if(inevent.isNil) { ^cleanup.exit(event) } }; } } Psetpre : FilterPattern { var <>name, <>value; *new { arg name, value, pattern; ^super.new(pattern).name_(name).value_(value) } storeArgs { ^[name,value,pattern] } filterEvent { arg event, val; ^event[name] = val; } embedInStream { arg event; var cleanup = EventStreamCleanup.new; var val, inevent, filteredEvent; var valStream = value.asStream; var evtStream = pattern.asStream; loop { val = valStream.next(event); if (val.isNil or: event.isNil) { ^cleanup.exit(event) }{ event = event.copy; filteredEvent = this.filterEvent(event, val); }; inevent = evtStream.next(filteredEvent); if (inevent.isNil) { ^cleanup.exit(event) }; cleanup.update(inevent); event = yield(inevent); // if(event.isNil) { nil.yield; ^inevent } } } } Paddpre : Psetpre { filterEvent { arg event, val; ^event[name] = event[name] + val; } } Pmulpre : Psetpre { filterEvent { arg event, val; ^event[name] = event[name] * val; } } Pset : FilterPattern { var <>name, <>value; *new { arg name, value, pattern; ^super.new(pattern).name_(name).value_(value) } storeArgs { ^[name,value,pattern] } filterEvent { arg event, val; ^event[name] = val; } embedInStream { arg event; var cleanup = EventStreamCleanup.new; var val, inEvent; var valStream = value.asStream; var evtStream = pattern.asStream; loop { inEvent = evtStream.next(event); // if (event.isNil) { ^nil.yield }; if (inEvent.isNil) { ^cleanup.exit(event) }; val = valStream.next(inEvent); if (val.isNil) { ^cleanup.exit(event) }; this.filterEvent(inEvent, val); cleanup.update(inEvent); event = inEvent.yield; } } } Padd : Pset { filterEvent { arg event, val; ^event[name] = event[name] + val; } } Pmul : Pset { filterEvent { arg event, val; ^event[name] = event[name] * val; } } Psetp : Pset { embedInStream { arg event; var evtStream, val, inevent; var valStream = value.iter; while { val = valStream.next(event); val.notNil }{ evtStream = pattern.asStream; while { inevent = evtStream.next(event); if(event.isNil) { ^nil.yield }; inevent.notNil; } { this.filterEvent(inevent, val); event = inevent.yield; }; }; ^event; } } Paddp : Psetp { filterEvent { arg event, val; ^event[name] = event[name] + val; } } Pmulp : Psetp { filterEvent { arg event, val; ^event[name] = event[name] * val; } } Pstretch : FilterPattern { var <>value; *new { arg value, pattern; ^super.new(pattern).value_(value) } storeArgs { ^[value,pattern] } embedInStream { arg event; var cleanup = EventStreamCleanup.new; var inevent; var val, delta; var valStream = value.asStream; var evtStream = pattern.asStream; loop { inevent = evtStream.next(event).asEvent; if (inevent.isNil) { ^cleanup.exit(event) }; val = valStream.next(inevent); if (val.isNil) { ^cleanup.exit(event) }; delta = event[\delta]; if (delta.notNil) { inevent[\delta] = delta * val; }; inevent[\dur] = inevent[\dur] * val; cleanup.update(inevent); event = yield(inevent); } } } Pstretchp : Pstretch { embedInStream { arg event; var evtStream, val, inevent, delta; var valStream = value.asStream; while { val = valStream.next(event).asEvent; val.notNil } { evtStream = pattern.asStream; while { inevent = evtStream.next(event); // if(event.isNil) { ^nil.yield }; inevent.notNil } { delta = inevent[\delta]; if (delta.notNil) { inevent[\delta] = delta * val; }; inevent[\dur] = inevent[\dur] * val; event = inevent.yield; }; }; ^event; } } // needs testing - hjh Pplayer : FilterPattern { var <>subPattern; *new { arg playerPattern, subPattern; ^super.newCopyArgs(playerPattern, subPattern) } storeArgs { ^[ pattern, subPattern ] } embedInStream { arg event; var player, inevent; var playerStream = pattern.asStream; var stream = subPattern.asStream; loop{ inevent = stream.next(event); if (inevent.isNil) { ^event }; player = playerStream.next(event); if (player.isNil) { ^event }; inevent.parent = player.event; event = yield(inevent); } } // backward compatibility: unnecessary var playerPattern was removed playerPattern { ^pattern } playerPattern_ { |playerPattern| pattern = playerPattern } } Pdrop : FilterPattern { var <>count; *new { arg count, pattern; ^super.new(pattern).count_(count) } storeArgs { ^[count,pattern] } embedInStream { arg event; var inevent; var stream = pattern.asStream; count.value(event).do { inevent = stream.next(event); if (inevent.isNil, { ^event }); }; loop { inevent = stream.next(event); if (inevent.isNil, { ^event }); event = inevent.yield; }; } } Pfin : FilterPattern { var <>count; *new { arg count, pattern; ^super.new(pattern).count_(count) } storeArgs { ^[count,pattern] } asStream { | cleanup| ^Routine({ arg inval; this.embedInStream(inval, cleanup) }) } embedInStream { arg event, cleanup; var inevent; var stream = pattern.asStream; cleanup ?? { cleanup = EventStreamCleanup.new }; count.value(event).do({ inevent = stream.next(event) ?? { ^event }; cleanup.update(inevent); event = inevent.yield; }); ^cleanup.exit(event) } } // it is not correct to call stream.next(nil) on a value stream // but there is no good way to distinguish in Pfin so we need a subclass // might be ok to deprecate this now Pfinval : Pfin { embedInStream { arg event; var inevent; var stream = pattern.asStream; count.value(event).do({ inevent = stream.next(event); if (inevent.isNil, { ^event }); event = inevent.yield; }); ^event } } Pfindur : FilterPattern { var <>dur, <>tolerance; *new { arg dur, pattern, tolerance = 0.001; ^super.new(pattern).dur_(dur).tolerance_(tolerance) } storeArgs { ^[dur,pattern,tolerance] } asStream { | cleanup| ^Routine({ arg inval; this.embedInStream(inval, cleanup) }) } embedInStream { arg event, cleanup; var item, delta, elapsed = 0.0, nextElapsed, inevent, localdur = dur.value(event); var stream = pattern.asStream; cleanup ?? { cleanup = EventStreamCleanup.new }; loop { inevent = stream.next(event).asEvent ?? { ^event }; cleanup.update(inevent); delta = inevent.delta; nextElapsed = elapsed + delta; if (nextElapsed.roundUp(tolerance) >= localdur) { // must always copy an event before altering it. // fix delta time and yield to play the event. inevent = inevent.copy.put(\delta, localdur - elapsed).yield; ^cleanup.exit(inevent); }; elapsed = nextElapsed; event = inevent.yield; } } } Psync : FilterPattern { var <>quant, <>maxdur, <>tolerance; *new { arg pattern, quant, maxdur, tolerance = 0.001; ^super.new(pattern).quant_(quant).maxdur_(maxdur).tolerance_(tolerance) } storeArgs { ^[pattern,quant,maxdur,tolerance] } embedInStream { arg event; var item, stream, delta, elapsed = 0.0, nextElapsed, clock, inevent; var localquant = quant.value(event), localmaxdur = maxdur.value(event); var cleanup = EventStreamCleanup.new; stream = pattern.asStream; loop { inevent = stream.next(event).asEvent; if(inevent.isNil) { if(localquant.notNil) { delta = elapsed.roundUp(localquant) - elapsed; if(delta > 0) { Event.silent(delta, event).yield }; ^cleanup.exit(event); }; }; cleanup.update(inevent); delta = inevent.delta; nextElapsed = elapsed + delta; if (localmaxdur.notNil and: { nextElapsed.round(tolerance) >= localmaxdur }) { inevent = inevent.copy; inevent.put(\delta, localmaxdur - elapsed); event = inevent.yield; ^cleanup.exit(event); } { elapsed = nextElapsed; event = inevent.yield; }; }; } } Pconst : FilterPattern { var <>sum, <>tolerance; *new { arg sum, pattern, tolerance=0.001; ^super.new(pattern).sum_(sum).tolerance_(tolerance) } storeArgs { ^[sum,pattern,tolerance] } embedInStream { arg inval; var delta, elapsed = 0.0, nextElapsed, str=pattern.asStream, localSum = sum.value(inval); loop ({ delta = str.next(inval); if(delta.isNil) { inval = (localSum - elapsed).yield; ^inval }; nextElapsed = elapsed + delta; if (nextElapsed.round(tolerance) >= localSum) { inval = (localSum - elapsed).yield; ^inval }{ elapsed = nextElapsed; inval = delta.yield; }; }); } } Plag : FilterPattern { var <>lag; *new { arg lag, pattern; ^super.new(pattern).lag_(lag) } storeArgs { ^[lag,pattern] } embedInStream { arg event; var item; var stream = pattern.asStream; var inevent = event.copy; event = Event.silent(lag.value(event), event).yield; loop { inevent = stream.next(event); if (inevent.isNil) { ^event}; event = inevent.yield; }; } } Pbindf : FilterPattern { var <>patternpairs; *new { arg pattern ... pairs; if (pairs.size.odd, { Error("Pbindf should have odd number of args.\n").throw }); ^super.new(pattern ? Event.default).patternpairs_(pairs) } storeArgs { ^[pattern] ++ patternpairs } embedInStream { arg event; var cleanup = EventStreamCleanup.new; var eventStream; var outevent; var streampairs = patternpairs.copy; var endval = streampairs.size - 1; forBy (1, endval, 2) { arg i; streampairs.put(i, streampairs[i].asStream); }; eventStream = pattern.asStream; loop{ outevent = eventStream.next(event); if (outevent.isNil) { ^cleanup.exit(event) }; forBy (0, endval, 2) { arg i; var name = streampairs[i]; var stream = streampairs[i+1]; var streamout = stream.next(outevent); if (streamout.isNil) { ^cleanup.exit(event) }; if (name.isSequenceableCollection) { if (name.size > streamout.size) { ("the pattern is not providing enough values to assign to the key set:" + name).warn; ^outevent }; name.do { arg key, i; outevent.put(key, streamout[i]); }; }{ outevent.put(name, streamout); }; }; cleanup.update(outevent); event = yield(outevent); }; } } Pstutter : FilterPattern { var <>n; *new { arg n, pattern; ^super.new(pattern).n_(n) } storeArgs { ^[n,pattern] } embedInStream { arg event; var inevent, nn; var stream = pattern.asStream; var nstream = n.asStream; while { (inevent = stream.next(event)).notNil } { if((nn = nstream.next(event)).notNil) { nn.abs.do { event = inevent.copy.yield; }; } { ^event }; }; ^event; } } PdurStutter : Pstutter { // float streams embedInStream { arg event; var dur, stut; var durs = pattern.asStream; var stutts = n.asStream; while({ (dur = durs.next(event)).notNil and: {(stut = stutts.next(event)).notNil} },{ if(stut > 0,{ // 0 skips it if(stut > 1,{ dur = dur / stut; stut.do({ event = dur.yield; }) },{ event = dur.yield }) }) }) ^event; } } Pclutch : FilterPattern { var <>connected; *new { arg pattern, connected = true; ^super.new(pattern).connected_(connected) } storeArgs { ^[ pattern, connected ] } embedInStream { arg inval; var clutchStream = connected.asStream; var stream = pattern.asStream; var outval, clutch; while { clutch = clutchStream.next(inval); clutch.notNil } { if(clutch === true or: { clutch == 1 }) { outval = stream.next(inval); if(outval.isNil) { ^inval }; inval = outval.yield; } { outval ?? { outval = stream.next(inval) }; inval = outval.copy.yield; }; } } } Pwhile : FuncFilterPattern { embedInStream {arg event; while({ func.value(event) },{ event = pattern.embedInStream(event); }); ^event; } } Pwrap : FilterPattern { var <>lo, <>hi; *new { arg pattern,lo,hi; ^super.new(pattern).lo_(lo).hi_(hi) } storeArgs { ^[pattern,lo,hi] } embedInStream { arg event; var next; var stream = pattern.asStream; var loStr = lo.asStream; var hiStr = hi.asStream; var loVal, hiVal; while({ loVal = loStr.next(event); hiVal = hiStr.next(event); next = stream.next(event); next.notNil and: { loVal.notNil } and: { hiVal.notNil } },{ event = next.wrap(loVal, hiVal).yield }); ^event; } } Ptrace : FilterPattern { var <>key, printStream, prefix; *new { arg pattern, key, printStream, prefix = ""; ^super.newCopyArgs(pattern, key, printStream, prefix) } storeArgs { ^[ pattern, key, printStream, prefix ] } embedInStream { arg inval; var func, collected; printStream = printStream ? Post; if(key.isNil) { collected = pattern.collect {|item| printStream << prefix << item << Char.nl; item } } { func = { |val, item, prefix| if(val.isKindOf(Function) and: { item.isKindOf(Environment) }) { val = item.use { val.value }; printStream << prefix << val << "\t(printed function value)\n"; } { printStream << prefix << val << Char.nl; }; }.flop; collected = pattern.collect {|item| var val = item.atAll(key.asArray).unbubble; func.value(val, item, prefix); item } }; ^collected.embedInStream(inval) } } Pclump : FilterPattern { var <>n; *new { arg n, pattern; ^super.new(pattern).n_(n) } embedInStream { arg event; var next, list, nval; var stream = pattern.asStream; var nstream = n.asStream; loop { list = []; nval = nstream.next(event); if (nval.isNil) { ^event }; nval.do { next = stream.next(event); if (next.isNil) { if (list.size > 0) { event = list.yield }; ^event }; list = list.add(next); }; event = list.yield; } } storeArgs { ^[ n, pattern ] } } Pflatten : Pclump { embedInStream { arg event; var next, nval; var stream = pattern.asStream; var nstream = n.asStream; while { next = stream.next(event); nval = nstream.next(event); next.notNil and: { nval.notNil }; }{ if (next.isKindOf(SequenceableCollection)) { next = next.flatten(nval); next.do {|item| event = item.yield }; }{ event = next.yield; } } ^event } } Pdiff : FilterPattern { embedInStream { arg event; var stream = pattern.asStream; var next, prev = stream.next(event); while { next = stream.next(event); next.notNil; }{ event = (next - prev).yield; prev = next; } ^event } } Prorate : FilterPattern { var <>proportion; *new { arg proportion, pattern=1; ^super.new(pattern).proportion_(proportion) } embedInStream { arg inval; var val, c; var str = pattern.asStream; var prop = proportion.asStream; loop { val = str.next(inval); c = prop.next(inval); if(val.isNil or: { c.isNil }) { ^inval }; if(c.isSequenceableCollection) { c.do { |el| inval = yield(el * val) } } { inval = yield(c * val); inval = yield(1 - c * val); } } } storeArgs { ^[proportion,pattern] } } Pavaroh : FilterPattern { var <>aroh, <>avaroh, <>stepsPerOctave; *new { arg pattern, aroh, avaroh, stepsPerOctave=12; ^super.newCopyArgs(pattern, aroh, avaroh, stepsPerOctave) } storeArgs { ^[pattern, aroh, avaroh, stepsPerOctave ] } embedInStream { arg inval; var me, melast = 0, scale; var mestream = pattern.asStream; var stepsStr = stepsPerOctave.asStream, stepVal; while { stepVal = stepsStr.next(inval); me = mestream.next(inval); me.notNil and: { stepVal.notNil } } { scale = if(me >= melast) { aroh } { avaroh }; melast = me; inval = me.degreeToKey(scale, stepVal).yield }; ^inval } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Penv.sc0000664000000000000000000000044112014636263025710 0ustar rootrootPenv : Env { embedInStream { arg inval; var startTime; startTime = thisThread.endBeat ? thisThread.beats; thisThread.endBeat = this.times.sum + startTime; while { thisThread.beats < thisThread.endBeat } { inval = yield(this.at(thisThread.beats - startTime))}; ^inval } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Pspawner.sc0000664000000000000000000000712612161364457026614 0ustar rootrootSpawner : Pattern { var <>genStream; var <>priorityQ; var <>now; var <>event; *new { | func, stackSize=64 | ^super.new.init( func, stackSize) } suspend { | stream | priorityQ.removeValue(stream); } suspendAll { priorityQ.clear } init { | func, stackSize | priorityQ = PriorityQueue.new; genStream = Routine({func.value(this) }, stackSize); now = 0; priorityQ.put(now, genStream); } par { | pattern, delta = 0 | var stream = pattern.asStream; priorityQ.put(now + delta, stream); ^stream; } seq { | pat | pat.embedInStream(event) } wait { | dur | Event.silent(dur, event).yield } embedInStream { | inevent, cleanup| var outevent, stream, nexttime; event = inevent; // gives genStream access to the event cleanup ?? { cleanup = EventStreamCleanup.new }; while({ priorityQ.notEmpty },{ stream = priorityQ.pop; outevent = stream.next(event).asEvent; if (outevent.isNil, { nexttime = priorityQ.topPriority; if (nexttime.notNil, { // that child stream ended, so rest until next one outevent = Event.silent(nexttime - now, event); cleanup.update(outevent); event = outevent.yield; now = nexttime; },{ priorityQ.clear; ^cleanup.exit(event); }); },{ cleanup.update(outevent); // requeue stream priorityQ.put(now + outevent.delta, stream); nexttime = priorityQ.topPriority; outevent.put(\delta, nexttime - now); event = outevent.yield; now = nexttime; }); }); ^event; } } Pspawner : Prout { asStream { ^Routine({ | ev | this.embedInStream(ev) }) } embedInStream { | inevent, cleanup | ^Spawner(routineFunc).embedInStream(inevent, cleanup ?? { EventStreamCleanup.new }); } } Pspawn : FilterPattern { var <>spawnProtoEvent; *new { |pattern, spawnProtoEvent| ^super.new(pattern) .spawnProtoEvent_(spawnProtoEvent ?? { Event.default }); } embedInStream { |inevent, cleanup| ^Spawner({ |sp| var event, stream = pattern.asStream, child; while { (event = stream.next(spawnProtoEvent.copy.put(\spawner, sp))).notNil } { case { event.method == \wait } { event.spawner.wait(event.delta) } { #[seq, par].includes(event.method) } { child = event[\pattern]; if(child.isKindOf(Symbol)) { child = (event[\dict] ? Pdef).at(child); }; event.spawner.perform(event.method, child.value(event)); if(event.delta > 0) { event.spawner.wait(event.delta) } } // suspend requires access to the specific stream // don't know how to get it... maybe implement later { event.method == \suspendAll } { event.spawner.suspendAll } { "Unrecognized method % in spawner event." .format(event.method.asCompileString).warn; } }; }).embedInStream(inevent, cleanup ?? { EventStreamCleanup.new }) } } /* ( Pseq([ Pspawner({ | sp | sp.postln; sp.par(Pbind(*[degree: Pwhite(0,12), dur: 0.1, db: -30]) ); sp.seq(Pbind(*[degree: Pseq((0..4).mirror.mirror, 1) + [-3, 0,2], ctranspose: -12, dur: 0.2 ]) ); "hi".postln; sp.wait(1); "bye".postln; sp.suspendAll; }), Pspawner({ | sp | sp.postln; sp.par(Pbind(*[degree: Pwhite(0,12), dur: 0.2, ctranspose: -12]) ); "hi".postln; sp.wait(4); "bye".postln; sp.suspendAll }), ]).play a = Spawner({ |sp | 100.do{ sp.wait(1) } }); a.play; b = a.par(Pbind(*[degree: Pwhite(0, 10), dur: 0.2])); a.suspend(b) a.par(b) Pspawner({ | sp | 5.do { sp.par(Pbind(*[ octave: (5.rand + 3).postln, degree: Pwhite(0,12), dur: 0.1, db: -30 ]) ); sp.wait(1); sp.clear; } }).play ) */ SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Prewrite.sc0000664000000000000000000000314012161364457026606 0ustar rootrootPrewrite : FilterPattern { var <>dict, <>levels; *new { arg pattern, dict, levels=1; ^super.new(pattern).dict_(dict).levels_(levels) } storeArgs { ^[ pattern, dict, levels ] } rewriteList { arg list, inval, level; var newlist; if (level == 0, { // if at bottom level, then embed all items in the stream if (list.isSequenceableCollection, { // isKindOf is necessary because Integer.do would do the wrong thing.. list.do({ arg item; inval = item.embedInStream(inval); }); },{ inval = list.embedInStream(inval); }); },{ if (list.isSequenceableCollection, { // isKindOf is necessary because Integer.do would do the wrong thing.. list.do({ arg item; // lookup item in rewrite dictionary newlist = dict.at(item); // found an entry ? if (newlist.notNil, { // do another level of rewriting inval = this.rewriteList( newlist, inval, level - 1 ); },{ // has no dictionary entry, so embed in stream inval = item.embedInStream(inval); }); }); },{ // lookup item in rewrite dictionary newlist = dict.at(list); // found an entry ? if (newlist.notNil, { // do another level of rewriting inval = this.rewriteList( newlist, inval, level - 1 ); },{ // has no dictionary entry, so embed in stream inval = list.embedInStream(inval); }); }); }); ^inval; } embedInStream { arg inval; var outval; var stream; stream = pattern.asStream; while({ outval = stream.next(inval); outval.notNil; },{ inval = this.rewriteList(outval, inval, levels); }); ^inval } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Ppatmod.sc0000664000000000000000000000423312014636263026407 0ustar rootrootPlazy : Pattern { var <>func; *new { arg func; ^super.new.func_(func) } //asStream { arg ... args; // ^func.valueArray(args).asStream // } embedInStream { arg inval; ^func.value(inval).embedInStream(inval) } storeArgs { ^[func] } } PlazyEnvir : Plazy { var <>passEvent=false; embedInStream { arg inval; ^if(inval.isNil) { func.value.embedInStream(inval) } { inval.use { if(passEvent) { func.valueEnvir(inval) } { func.valueEnvir }.embedInStream(inval) } } } } PlazyEnvirN : PlazyEnvir { var genFunc; *new { arg func; ^super.new(func).makeGenFunc } embedInStream { arg inval; var patterns; ^if(inval.isNil) { func.value.embedInStream(inval) } { inval.use { patterns = if(passEvent) { genFunc.valueEnvir(inval) } { genFunc.valueEnvir }; }; if(patterns.size > 1) { Ppar(patterns).embedInStream(inval) } { patterns.unbubble.embedInStream(inval) } } } // expand arguments makeGenFunc { genFunc = if(func.def.argNames.notNil) { func.envirFlop } { func } } } Penvir : Pattern { var <>envir, <>pattern, <>independent; *new { arg envir, pattern, independent=true; ^super.newCopyArgs(envir, pattern, independent) } storeArgs { ^[envir,pattern,independent] } embedInStream { arg inval; if(independent) { Event.new(8, nil, envir) } { envir } .use { pattern.embedInStream(inval) }; ^inval } } Ppatmod : Pattern { var <>pattern, <>func, <>repeats=1; *new { arg pattern, func, repeats; ^super.newCopyArgs(pattern, func, repeats) } embedInStream { arg inval; var localPat; localPat = pattern.value(inval).copy; repeats.do({ arg i; inval = localPat.embedInStream(inval); localPat = func.value(localPat, i); }); ^inval; } storeArgs { ^[pattern, func, repeats] } } Peventmod : Pattern { var <>func, <>event, <>repeats; *new { arg func, event, repeats=inf; ^super.newCopyArgs(func, event, repeats) } embedInStream { arg inval; var localEvent = event.copy ?? { Event.default }; repeats.value(inval).do { arg i; if(inval.isNil) { ^nil.yield }; localEvent.use { func.valueEnvir(inval, i) }; inval = localEvent.yield; }; ^inval } storeArgs { ^[func, event, repeats] } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/BasicOpsStream.sc0000664000000000000000000000427212014636263027665 0ustar rootroot// These Streams are instantiated by math operations on other Streams UnaryOpStream : Stream { var >operator, >a; *new { arg operator, a; ^super.newCopyArgs(operator, a) } next { arg inval; var vala; vala = a.next(inval); if (vala.isNil, { ^nil },{ ^vala.perform(operator); }); } reset { a.reset } storeOn { arg stream; stream <<< a << "." << operator } } BinaryOpStream : Stream { var >operator, >a, >b; *new { arg operator, a, b; ^super.newCopyArgs(operator, a, b) } next { arg inval; var vala, valb; vala = a.next(inval); if (vala.isNil, { ^nil }); valb = b.next(inval); if (valb.isNil, { ^nil }); ^vala.perform(operator, valb); } reset { a.reset; b.reset } storeOn { arg stream; stream << "(" <<< a << " " << operator.asBinOpString << " " <<< b << ")" } } BinaryOpXStream : Stream { var operator, a, b, vala; *new { arg operator, a, b; ^super.newCopyArgs(operator, a, b) } next { arg inval; var valb; if (vala.isNil) { vala = a.next(inval); if (vala.isNil) { ^nil }; valb = b.next(inval); if (valb.isNil, { ^nil }); }{ valb = b.next(inval); if (valb.isNil) { vala = a.next(inval); if (vala.isNil) { ^nil }; b.reset; valb = b.next(inval); if (valb.isNil) { ^nil }; }; }; ^vala.perform(operator, valb); } reset { vala = nil; a.reset; b.reset } storeOn { arg stream; stream << "(" <<< a << " " << operator.asBinOpString; stream << ".x"; stream << " " <<< b << ")" } } NAryOpStream : Stream { var >operator, >a, arglist; var isNumeric; *new { arg operator, a, arglist; ^super.newCopyArgs(operator, a).arglist_(arglist) } arglist_ { arg list; // optimization isNumeric = list.every({ arg item; item.isNumber or: {item.class === Symbol} }); arglist = list; } next { arg inval; var vala, values; vala = a.next(inval); if (vala.isNil, { ^nil }); values = if (isNumeric) { arglist } { arglist.collect({ arg item; var res; res = item.next(inval); if(res.isNil) { ^nil }; res }) }; ^vala.performList(operator, values); } reset { a.reset; arglist.do({ arg item; item.reset }) } storeOn { arg stream; stream <<< a << "." << operator << "(" <<<* arglist << ")" } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Pfx.sc0000664000000000000000000001275112014636263025544 0ustar rootrootPfx : FilterPattern { var <>fxname, <>pairs; *new { arg pattern, fxname ... pairs; if (pairs.size.odd, { Error("Pfx should have even number of args.\n").throw }); ^super.new(pattern).fxname_(fxname).pairs_(pairs) } storeArgs { ^[pattern, fxname] ++ pairs } embedInStream { arg inevent; var stream, cleanup = EventStreamCleanup.new; var server = inevent[\server] ?? { Server.default }; var id = server.nextNodeID; var event = inevent.copy; var cleanupEvent; pairs.pairsDo {|name, value| event[name] = value; }; event[\addAction] = 0; // \addToHead event[\instrument] = fxname; event[\type] = \on; event[\id] = id; event[\delta] = 0; cleanupEvent = (type: \off, parent: event); cleanup.addFunction(event, { |flag| if (flag) { cleanupEvent.play } }); inevent = event.yield; stream = pattern.asStream; loop { event = stream.next(inevent) ?? { ^cleanup.exit(inevent) }; cleanup.update(event); inevent = event.yield; }; } isolate { ^Prout { arg inevent; var outputData, synthDesc; synthDesc = (inevent[\synthLib] ?? { SynthDescLib.global }).at(fxname); if(synthDesc.isNil) { Error("Pfx: SynthDesc not found: %".format(fxname)).throw }; outputData = synthDesc.outputData; if(outputData.size > 1) { Error("Pfx does not support more than one output UGen.").throw }; if(outputData.isEmpty) { this.embedInStream(inevent) } { outputData = outputData.unbubble; if(outputData[\numChannels] > SystemSynthDefs.numChannels) { Error("Pfx: SynthDef % has too many channels." "Set SystemSynthDefs.numChannels >= %" .format(fxname, outputData[\numChannels])).throw }; Pbus(this, inevent[\endTime] ? 2.0, inevent[\fadeTime] ? 0.02, outputData[\numChannels], outputData[\rate] ).embedInStream(inevent) } } } } Pfxb : Pfx { *new { arg pattern, fxname ... pairs; if (pairs.size.odd, { Error("Pfx should have even number of args.\n").throw }); ^super.new(pattern, fxname, *pairs).isolate } } PAbstractGroup : FilterPattern { embedInStream { arg inevent; var server, groupID, event, cleanup; var stream, lag = 0, clock = thisThread.clock, groupReleaseTime = inevent[\groupReleaseTime] ? 0.1, cleanupEvent; var eventType = this.class.eventType; cleanup = EventStreamCleanup.new; server = inevent[\server] ?? { Server.default }; groupID = server.nextNodeID; event = inevent.copy; event[\addAction] = 0; // \addToHead event[\type] = eventType; event[\delta] = 0; event[\id] = groupID; cleanupEvent = (type: \kill, parent: event); cleanup.addFunction(event, { | flag | if (flag) { cleanupEvent.lag_(lag - clock.beats + groupReleaseTime).play } }); inevent = event.yield; inevent !? { inevent = inevent.copy; inevent[\group] = groupID; }; stream = pattern.asStream; loop { event = stream.next(inevent) ?? { ^cleanup.exit(inevent) }; lag = max(lag, clock.beats + event.use { ~sustain.value }); inevent = event.yield; inevent.put(\group, groupID); } } *embedLoop { arg inevent, stream, groupID, ingroup, cleanup; var event, lag; loop { event = stream.next(inevent) ?? { ^cleanup.exit(inevent) }; lag = event[\dur]; inevent = event.yield; inevent.put(\group, groupID); } } } Pgroup : PAbstractGroup { *eventType { ^\group } } PparGroup : PAbstractGroup { *eventType { ^\parGroup } } Pbus : FilterPattern { var <>numChannels, <>rate, <>dur=2.0, <>fadeTime; *new { arg pattern, dur=2.0, fadeTime=0.02, numChannels=2, rate=\audio; ^super.new(pattern).dur_(dur).numChannels_(numChannels).rate_(rate).fadeTime_(fadeTime) } storeArgs { ^[ pattern, dur, fadeTime, numChannels, rate ] } embedInStream { arg inevent; var server, groupID, linkID, bus, ingroup, cleanup; var patterns, event, freeBus, stream, cleanupEvent; cleanup = EventStreamCleanup.new; server = inevent[\server] ?? { Server.default }; groupID = server.nextNodeID; linkID = server.nextNodeID; ingroup = inevent[\group]; // could use a special event type for this: if(rate == \audio) { bus = server.audioBusAllocator.alloc(numChannels); freeBus = { server.audioBusAllocator.free(bus) }; } { bus = server.controlBusAllocator.alloc(numChannels); freeBus = { server.controlBusAllocator.free(bus) }; }; CmdPeriod.doOnce(freeBus); event = inevent.copy; event[\addAction] = 0; // \addToHead event[\type] = \group; event[\delta] = 0; event[\id] = groupID; event[\group] = ingroup; event.yield; inevent = event = inevent.copy; event[\type] = \on; event[\group] = groupID; event[\addAction] = 3; // \addBefore event[\delta] = 0; event[\id] = linkID; event[\fadeTime] = fadeTime; event[\instrument] = format("system_link_%_%", rate, numChannels); event[\in] = bus; event[\msgFunc] = #{ |out, in, fadeTime, gate=1| [\out, out, \in, in, \fadeTime, fadeTime, \gate, gate, \doneAction, 3] }; cleanupEvent = (type: \off, parent: event, fadeTime: fadeTime.abs, hasGate: true, gate: 0); cleanup.addFunction(event, { | flag | if(flag) { defer ( {cleanupEvent.play}, dur) }; }); cleanup.addFunction(event, { defer({ freeBus.value;}, fadeTime.abs + dur) }); // doneAction = 3; // remove and deallocate both this synth and the preceeding node // (which is the group). inevent = event.yield; // now embed the pattern stream = Pchain(pattern, (group: groupID, out: bus)).asStream; loop { event = stream.next(inevent) ?? { ^cleanup.exit(inevent) }; cleanup.update(event); inevent = event.yield; } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Patterns.sc0000664000000000000000000004211312245365552026610 0ustar rootrootPattern : AbstractFunction { // concatenate Patterns ++ { arg aPattern; ^Pseq.new([this, aPattern]) } // compose Patterns <> { arg aPattern; ^Pchain(this, aPattern) } play { arg clock, protoEvent, quant; ^this.asEventStreamPlayer(protoEvent).play(clock, false, quant) } // phase causes pattern to start somewhere in the current measure rather than on a downbeat // offset allows pattern to compute ahead a bit to allow negative lags for strummed chords // and to ensure one pattern computes ahead of another asStream { ^Routine({ arg inval; this.embedInStream(inval) }) } iter { ^this.asStream } asEventStreamPlayer { arg protoEvent; ^EventStreamPlayer(this.asStream, protoEvent); } embedInStream { arg inval; ^this.asStream.embedInStream(inval); } do { arg function; this.asStream.do(function) } // filtering operations collect { arg function; ^Pcollect.new(function, this) } select { arg function; ^Pselect.new(function, this) } reject { arg function; ^Preject.new(function, this) } // function composition composeUnaryOp { arg operator; ^Punop.new(operator, this) } composeBinaryOp { arg operator, pattern, adverb; ^Pbinop.new(operator, this, pattern, adverb) } reverseComposeBinaryOp { arg operator, pattern, adverb; ^Pbinop.new(operator, pattern, this, adverb) } composeNAryOp { arg selector, argList; ^Pnaryop.new(selector, this, argList); } ////////////////////// mtranspose { arg n; ^Paddp(\mtranspose, n, this) } ctranspose { arg n; ^Paddp(\ctranspose, n, this) } gtranspose { arg n; ^Paddp(\gtranspose, n, this) } detune { arg n; ^Paddp(\detune, n, this) } scaleDur { arg x; ^Pmulp(\dur, x, this) } addDur { arg x; ^Paddp(\dur, x, this) } stretch { arg x; ^Pmulp(\stretch, x, this) } lag { arg t; ^Plag(t, this) } legato { arg x; ^Pmulp(\legato, x, this) } db { arg db; ^Paddp(\db, db, this) } clump { arg n; ^Pclump(n, this) } flatten { arg n = 1; ^Pflatten(n, this) } repeat { arg n=inf; ^Pn(this, n) } keep { arg n; ^Pfin(n, this) } drop { arg n; ^Pdrop(n, this) } stutter { arg n; ^Pstutter(n, this) } finDur { arg dur, tolerance = 0.001; ^Pfindur(dur, this, tolerance) } fin { arg n; ^Pfin(n, this) } trace { arg key, printStream, prefix=""; ^Ptrace(this, key, printStream, prefix) } differentiate { ^Pdiff(this) } integrate { ^Plazy { var sum = 0; this.collect { |x| sum = sum + x } } } ////////////////////// // realtime recording // for NRT see Pattern:asScore // path: if nil, auto-generate path // dur: if nil, record until pattern stops (infinite pattern = problem) // fadeTime: allow extra time after last Event for nodes to become silent record { |path, headerFormat = "AIFF", sampleFormat = "float", numChannels = 2, dur = nil, fadeTime = 0.2, clock(TempoClock.default), protoEvent(Event.default), server(Server.default), out = 0| var buf, bus, recsynth, pattern, defname, cond, startTime; if(dur.notNil) { pattern = Pfindur(dur, this) } { pattern = this }; path ?? { if(thisProcess.platform.name == \windows) { path = thisProcess.platform.recordingsDir +/+ "SC_" ++ Main.elapsedTime.round(0.01) ++ "." ++ headerFormat; } { path = thisProcess.platform.recordingsDir +/+ "SC_" ++ Date.localtime.stamp ++ "." ++ headerFormat; }; }; fork { cond = Condition.new; buf = Buffer.alloc(server, 65536, numChannels); SynthDef(defname = ("patrec"++numChannels).asSymbol, { |bufnum, bus, out| var sig = In.ar(bus, numChannels); DiskOut.ar(bufnum, sig); Out.ar(out, sig); }).add; bus = Bus.audio(server, numChannels); server.sync(cond); buf.write(path, headerFormat, sampleFormat, numFrames: 0, startFrame: 0, leaveOpen: true); server.sync(cond); "Recording pattern into % at %\n".postf(path, thisThread.beats); recsynth = server.nextNodeID; Pprotect( // Pfset has a cleanupFunc, which executes even if pattern is stopped by cmd-. Pfset(nil, Pseq([ Pfuncn { startTime = thisThread.beats; 0 }, (type: \on, instrument: defname, bufnum: buf, bus: bus, out: out, id: recsynth, delta: 0), pattern <> (out: bus), Plazy { Pn((type: \rest, delta: (fadeTime ? 0) .roundUp(buf.numFrames / server.sampleRate)), 1) } ], 1), { (type: \kill, id: recsynth).play } ), // on error, killing the recsynth triggers rest of cleanup below { (type: \kill, id: recsynth).play } ).play(clock, protoEvent, quant: 0); // clean up after recording synth stops OSCpathResponder(server.addr, ['/n_end', recsynth], { |time, resp, msg| resp.remove; cond.unhang; }).add; cond.hang; buf.close.free; bus.free; server.sendMsg(\d_free, defname); "Finished recording % at %\n".postf(path, thisThread.beats); } } } Pfunc : Pattern { var <>nextFunc; // Func is evaluated for each next state var <>resetFunc; // Func is evaluated for each next state *new { arg nextFunc, resetFunc; ^super.newCopyArgs(nextFunc, resetFunc) } storeArgs { ^[nextFunc] ++ resetFunc } asStream { ^FuncStream.new(nextFunc, resetFunc) } } Prout : Pattern { var <>routineFunc; *new { arg routineFunc; ^super.newCopyArgs(routineFunc) } storeArgs { ^[routineFunc] } asStream { ^Routine.new(routineFunc) } embedInStream { arg inval; ^routineFunc.value(inval) } } Proutine : Prout { *new { |routineFunc| "Proutine is deprecated. Use Prout instead.".postln; ^Prout(routineFunc) } } Pfuncn : Pattern { var <>func, <>repeats; *new { arg func, repeats = 1; ^super.newCopyArgs(func, repeats) } storeArgs { ^[func,repeats] } embedInStream { arg inval; repeats.value(inval).do({ inval = func.value(inval).yield; }); ^inval } } // Punop and Pbinop are used to create patterns in response to math operations Punop : Pattern { var <>operator, <>a; *new { arg operator, a; ^super.newCopyArgs(operator, a) } storeOn { arg stream; stream <<< a << "." << operator } embedInStream { arg inval; var stream, outval; stream = a.asStream; loop { outval = stream.next(inval); if (outval.isNil) { ^inval }; inval = yield(outval.perform(operator)); } } asStream { ^UnaryOpStream.new(operator, a.asStream); } } Pbinop : Pattern { var <>operator, <>a, <>b, <>adverb; *new { arg operator, a, b, adverb; ^super.newCopyArgs(operator, a, b, adverb) } storeOn { arg stream; stream << "(" <<< a << " " << operator.asBinOpString; if(adverb.notNil) { stream << "." << adverb }; stream << " " <<< b << ")" } asStream { if (adverb.isNil) { ^BinaryOpStream.new(operator, a.asStream, b.asStream); }; if (adverb == 'x') { ^BinaryOpXStream.new(operator, a.asStream, b.asStream); }; ^nil } } Pnaryop : Pattern { var <>operator, <>a, <>arglist; *new { arg operator, a, arglist; ^super.newCopyArgs(operator, a, arglist) } storeOn { arg stream; stream <<< a << "." << operator << "(" <<<* arglist << ")" } embedInStream { arg inval; var streamA, streamlist, vala, values, isNumeric; streamA = a.asStream; // optimization isNumeric = arglist.every { arg item; item.isNumber or: {item.class === Symbol} }; if (isNumeric) { loop { vala = streamA.next(inval); if (vala.isNil) { ^inval }; inval = yield(vala.performList(operator, arglist)); } }{ streamlist = arglist.collect({ arg item; item.asStream }); loop { vala = streamA.next(inval); if (vala.isNil) { ^inval }; values = streamlist.collect({ arg item; var result = item.next(inval); if (result.isNil) { ^inval }; result }); inval = yield(vala.performList(operator, values)); } }; } asStream { ^NAryOpStream.new(operator, a.asStream, arglist.collect({ arg item; item.asStream })); } } PdegreeToKey : Pnaryop { *new { arg pattern, scale, stepsPerOctave=12; ^super.new('degreeToKey', pattern, [scale, stepsPerOctave]) } // this is not reversible // but it would save as something that played the same //storeArgs { ^[ pattern, scale, stepsPerOctave ] } } Pchain : Pattern { var <>patterns; *new { arg ... patterns; ^super.newCopyArgs(patterns); } <> { arg aPattern; var list; list = patterns.copy.add(aPattern); ^this.class.new(*list) } embedInStream { arg inval; var streams, inevent, cleanup = EventStreamCleanup.new; streams = patterns.collect(_.asStream); loop { inevent = inval.copy; streams.reverseDo { |str| inevent = str.next(inevent); if(inevent.isNil) { ^cleanup.exit(inval) }; }; cleanup.update(inevent); inval = yield(inevent); }; } storeOn { arg stream; stream << "("; patterns.do { |item,i| if(i != 0) { stream << " <> " }; stream <<< item; }; stream << ")" } } Pevent : Pattern { var <>pattern, <>event; *new { arg pattern, event; ^super.newCopyArgs(pattern, event ?? { Event.default }); } storeArgs { ^[pattern, event] } embedInStream { arg inval; var outval; var stream = pattern.asStream; loop { outval = stream.next(event); if (outval.isNil) { ^inval }; inval = outval.yield } } } Pbind : Pattern { var <>patternpairs; *new { arg ... pairs; if (pairs.size.odd, { Error("Pbind should have even number of args.\n").throw; }); ^super.newCopyArgs(pairs) } storeArgs { ^patternpairs } embedInStream { arg inevent; var event; var sawNil = false; var streampairs = patternpairs.copy; var endval = streampairs.size - 1; forBy (1, endval, 2) { arg i; streampairs.put(i, streampairs[i].asStream); }; loop { if (inevent.isNil) { ^nil.yield }; event = inevent.copy; forBy (0, endval, 2) { arg i; var name = streampairs[i]; var stream = streampairs[i+1]; var streamout = stream.next(event); if (streamout.isNil) { ^inevent }; if (name.isSequenceableCollection) { if (name.size > streamout.size) { ("the pattern is not providing enough values to assign to the key set:" + name).warn; ^inevent }; name.do { arg key, i; event.put(key, streamout[i]); }; }{ event.put(name, streamout); }; }; inevent = event.yield; } } } Pmono : Pattern { var <>synthName, <>patternpairs; *new { arg name ... pairs; if (pairs.size.odd, { Error("Pmono should have odd number of args.\n").throw; }); ^super.newCopyArgs(name.asSymbol, pairs) } embedInStream { | inevent | ^PmonoStream(this).embedInStream(inevent) } } PmonoArtic : Pmono { embedInStream { |inevent| ^PmonoArticStream(this).embedInStream(inevent) } } Pseries : Pattern { // arithmetic series var <>start=0, <>step=1, <>length=inf; *new { arg start = 0, step = 1, length=inf; ^super.newCopyArgs(start, step, length) } storeArgs { ^[start,step,length] } embedInStream { arg inval; var outval, counter = 0; var cur = start.value(inval); var len = length.value(inval); var stepStr = step.asStream, stepVal; while { counter < len } { stepVal = stepStr.next(inval); if(stepVal.isNil) { ^inval }; outval = cur; cur = cur + stepVal; counter = counter + 1; inval = outval.yield; }; ^inval; } } Pgeom : Pattern { // geometric series var <>start=1.0, <>grow=1.0, <>length=inf; *new { arg start = 0, grow = 1, length=inf; ^super.newCopyArgs(start, grow, length) } storeArgs { ^[start,grow,length] } embedInStream { arg inval; var outval, counter = 0; var cur = start.value(inval); var len = length.value(inval); var growStr = grow.asStream, growVal; while { counter < len } { growVal = growStr.next(inval); if(growVal.isNil) { ^inval }; outval = cur; cur = cur * growVal; counter = counter + 1; inval = outval.yield; }; ^inval; } } Pbrown : Pattern { var <>lo, <>hi, <>step, <>length; *new { arg lo=0.0, hi=1.0, step=0.125, length=inf; ^super.newCopyArgs(lo, hi, step, length) } storeArgs { ^[lo,hi,step,length] } embedInStream { arg inval; var cur; var loStr = lo.asStream, loVal; var hiStr = hi.asStream, hiVal; var stepStr = step.asStream, stepVal; loVal = loStr.next(inval); hiVal = hiStr.next(inval); stepVal = stepStr.next(inval); cur = rrand(loVal, hiVal); if(loVal.isNil or: { hiVal.isNil } or: { stepVal.isNil }) { ^inval }; length.value(inval).do { loVal = loStr.next(inval); hiVal = hiStr.next(inval); stepVal = stepStr.next(inval); if(loVal.isNil or: { hiVal.isNil } or: { stepVal.isNil }) { ^inval }; cur = this.calcNext(cur, stepVal).fold(loVal, hiVal); inval = cur.yield; }; ^inval; } calcNext { arg cur, step; ^cur + step.xrand2 } } Pgbrown : Pbrown { calcNext { arg cur, step; ^cur * (1 + step.xrand2) } } Pwhite : Pattern { var <>lo, <>hi, <>length; *new { arg lo=0.0, hi=1.0, length=inf; ^super.newCopyArgs(lo, hi, length) } storeArgs { ^[lo,hi,length] } embedInStream { arg inval; var loStr = lo.asStream; var hiStr = hi.asStream; var hiVal, loVal; length.value(inval).do({ hiVal = hiStr.next(inval); loVal = loStr.next(inval); if(hiVal.isNil or: { loVal.isNil }) { ^inval }; inval = rrand(loVal, hiVal).yield; }); ^inval; } } Pprob : Pattern { var <>hi, <>lo, <>length, pattern1, <>pattern2; *new { arg pattern1, pattern2; ^super.newCopyArgs(pattern1, pattern2) } storeArgs { ^[pattern1,pattern2] } embedInStream { arg inval; var stream1, stream2, val1, val2; stream1 = pattern1.asStream; while { (val1 = stream1.next(inval)).notNil; }{ stream2 = pattern2.asStream; while { (val2 = stream2.next(inval)).notNil; }{ inval = yield( val1 + val2 ); }; }; ^inval } } Pstep3add : Pattern { var <>pattern1, <>pattern2, <>pattern3; *new { arg pattern1, pattern2, pattern3; ^super.newCopyArgs(pattern1, pattern2, pattern3) } storeArgs { ^[pattern1,pattern2,pattern3] } embedInStream { arg inval; var stream1, stream2, stream3, val1, val2, val3; stream1 = pattern1.asStream; while { (val1 = stream1.next(inval)).notNil; }{ stream2 = pattern2.asStream; while { (val2 = stream2.next(inval)).notNil; }{ stream3 = pattern3.asStream; while { (val3 = stream3.next(inval)).notNil; }{ inval = yield( val1 + val2 + val3 ); }; }; }; ^inval; } } PstepNfunc : Pattern { var patterns; *new { arg function, patterns; ^super.newCopyArgs(function ? { |x| x }, patterns) } storeArgs { ^[function,patterns] } embedInStream { arg inval; var val; var size = patterns.size; var max = size - 1; var streams = Array.newClear(size); var vals = Array.newClear(size); // this variable is needed because of recursion var f = { arg inval, level=0; var val; streams[level] = patterns[level].asStream; while{ vals[level] = val = streams[level].next(inval); val.notNil; }{ if(level < max) { inval = f.value(inval, level + 1) }{ inval = yield(function.value(vals)); } }; inval; }; ^f.value(inval); } } PstepNadd : PstepNfunc { *new { arg ... patterns; ^super.new({ arg vals; vals.sum }, patterns) } storeArgs { ^patterns } } // returns relative time (in beats) from moment of embedding Ptime : Pattern { var <>repeats; *new { arg repeats=inf; ^super.newCopyArgs(repeats) } storeArgs { ^[repeats] } embedInStream { arg inval; var start = thisThread.beats; repeats.value(inval).do { inval = (thisThread.beats - start).yield }; ^inval } } // if an error is thrown in the stream, func is evaluated Pprotect : FilterPattern { var <>func; *new { arg pattern, func; ^super.new(pattern).func_(func) } storeArgs { ^[ pattern, func ] } asStream { var rout = Routine(pattern.embedInStream(_)); rout.exceptionHandler = { |error| func.value(error, rout); nil.handleError(error) }; ^rout } } // access a key from the input event Pkey : Pattern { var <>key, <>repeats; *new { |key| ^super.newCopyArgs(key) } storeArgs { ^[key] } // avoid creating a routine asStream { var keystream = key.asStream; ^FuncStream({ |inevent| inevent !? { inevent[keystream.next(inevent)] } }); } } Pif : Pattern { var <>condition, <>iftrue, <>iffalse, <>default; *new { |condition, iftrue, iffalse, default| ^super.newCopyArgs(condition, iftrue, iffalse, default) } storeArgs { ^[condition, iftrue, iffalse,default] } asStream { var condStream = condition.asStream, trueStream = iftrue.asStream, falseStream = iffalse.asStream; ^FuncStream({ |inval| var test; if((test = condStream.next(inval)).isNil) { nil } { if(test) { trueStream.next(inval) ? default } { falseStream.next(inval) ? default }; }; }, { // reset func condStream.reset; trueStream.reset; falseStream.reset; }) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/RandomDistPatterns.sc0000664000000000000000000000676112014636263030600 0ustar rootrootPlprand : Pwhite { embedInStream { |inval| var localLength = length.value(inval), pat = Pwhite(lo, hi, localLength); ^min(pat, pat).embedInStream(inval) } } Phprand : Pwhite { embedInStream { |inval| var localLength = length.value(inval), pat = Pwhite(lo, hi, localLength); ^max(pat, pat).embedInStream(inval) } } Pmeanrand : Pwhite { embedInStream { |inval| var localLength = length.value(inval), pat = Pwhite(lo, hi, localLength); ^((pat + pat) * 0.5).embedInStream(inval) } } Pbeta : Pattern { var <>lo, <>hi, <>prob1, <>prob2, <>length; *new{ arg lo = 0.0, hi = 1.0, prob1 = 1, prob2 = 1, length = inf; ^super.newCopyArgs(lo, hi, prob1, prob2, length); } storeArgs { ^[lo, hi, prob1, prob2, length] } embedInStream { arg inval; var loStr = lo.asStream; var hiStr = hi.asStream; var prob1Str = prob1.asStream; var prob2Str = prob2.asStream; var loVal, hiVal; length.value(inval).do({ var sum = 2, temp, rprob1, rprob2; rprob1 = prob1Str.next(inval); rprob2 = prob2Str.next(inval); if(rprob1.isNil or: { rprob2.isNil }) { ^inval }; rprob1 = rprob1.reciprocal; rprob2 = rprob2.reciprocal; loVal = loStr.next(inval); hiVal = hiStr.next(inval); if(loVal.isNil or: { hiVal.isNil }) { ^inval }; while ({ temp = 1.0.rand ** rprob1; sum = temp + (1.0.rand ** rprob2); sum > 1; }); inval = (((temp/sum) * (hiVal - loVal)) + loVal).yield; }); ^inval; } } Pcauchy : Pattern { var <>mean, <>spread, <>length; *new{arg mean = 0.0, spread = 1.0, length = inf; ^super.newCopyArgs(mean, spread, length); } storeArgs{ ^[mean, spread, length] } embedInStream { arg inval; var meanStr = mean.asStream; var spreadStr = spread.asStream; var meanVal, spreadVal; length.value(inval).do({ var ran = 0.5; meanVal = meanStr.next(inval); spreadVal = spreadStr.next(inval); if(meanVal.isNil or: { spreadVal.isNil }) { ^inval }; while({ ran = 1.0.rand; ran == 0.5 }); inval = ((spreadVal * (ran * pi).tan) + meanVal).yield; }); ^inval; } } Pgauss : Pattern { var <>mean, <>dev, <>length; *new{ arg mean = 0.0, dev = 1, length = inf; ^super.newCopyArgs(mean, dev, length); } storeArgs{ ^[mean, dev, length] } embedInStream{arg inval; var meanStr = mean.asStream; var devStr = dev.asStream; var devVal, meanVal; length.value(inval).do({ devVal = devStr.next(inval); meanVal = meanStr.next(inval); if(meanVal.isNil or: { devVal.isNil }) { ^inval }; inval = ((((-2*log(1.0.rand)).sqrt * sin(2pi.rand)) * devVal) + meanVal).yield; }); ^inval; } } Ppoisson : Pattern { var <>mean, <>length; *new{arg mean = 1, length = inf; ^super.newCopyArgs(mean, length); } storeArgs{ ^[mean, length] } embedInStream{ arg inval; var meanStr = mean.asStream; length.value(inval).do({ var inc, test, temp, meanVal = meanStr.next(inval); if(meanVal.isNil) { ^inval }; inc = 0; test = 1.0.rand; temp = exp(meanVal.neg); while({ test > temp; }, { inc = inc + 1; test = test * 1.0.rand; }); inval = inc.yield; }); ^inval; } } Pexprand : Pwhite { *new { arg lo=0.0001, hi=1.0, length=inf; ^super.newCopyArgs(lo, hi, length) } storeArgs { ^[ lo, hi, length ] } embedInStream { arg inval; var loStr = lo.asStream; var hiStr = hi.asStream; var hiVal, loVal; length.value(inval).do({ hiVal = hiStr.next(inval); loVal = loStr.next(inval); if(hiVal.isNil or: { loVal.isNil }) { ^inval }; inval = exprand(loVal, hiVal).yield; }); ^inval; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Ppar.sc0000664000000000000000000000545112014636263025710 0ustar rootrootPpar : ListPattern { initStreams { arg priorityQ; list.do({ arg pattern, i; priorityQ.put(0.0, pattern.asStream); }); } embedInStream { arg inval; var assn; var priorityQ = PriorityQueue.new; repeats.value(inval).do({ arg j; var outval, stream, nexttime, now = 0.0; this.initStreams(priorityQ); // if first event not at time zero if (priorityQ.notEmpty and: { (nexttime = priorityQ.topPriority) > 0.0 }) { outval = Event.silent(nexttime, inval); inval = outval.yield; now = nexttime; }; while { priorityQ.notEmpty } { stream = priorityQ.pop; outval = stream.next(inval).asEvent; if (outval.isNil) { nexttime = priorityQ.topPriority; if (nexttime.notNil, { // that child stream ended, so rest until next one outval = Event.silent(nexttime - now, inval); inval = outval.yield; now = nexttime; },{ priorityQ.clear; }); } { // requeue stream priorityQ.put(now + outval.delta, stream); nexttime = priorityQ.topPriority; outval.put(\delta, nexttime - now); inval = outval.yield; // inval ?? { this.purgeQueue(priorityQ); ^nil.yield }; now = nexttime; }; }; }); ^inval; } } Ptpar : Ppar { initStreams { arg priorityQ; forBy(0, list.size-1, 2, { arg i; priorityQ.put(list.at(i).value, list.at(i+1).asStream); }); } } Pgpar : Ppar { embedInStream { arg inevent; var server, ids, patterns, event, ingroup, cleanup, stream; var lag = 0, clock = thisThread.clock, groupReleaseTime = inevent[\groupReleaseTime] ? 0.1; server = inevent[\server] ?? { Server.default }; ingroup = inevent[\group]; ids = { server.nextNodeID } ! this.numberOfGroups; event = inevent.copy; event[\addAction] = 1; event[\type] = \group; event[\delta] = 0; event[\id] = ids; event[\group] = ingroup; inevent = event.yield.copy; cleanup = EventStreamCleanup.new; cleanup.addFunction(inevent, { | flag | if (flag) { ( lag: lag - clock.beats + groupReleaseTime, type: \kill, id: ids, server: server ).play }; }); patterns = this.wrapPatterns(ids); stream = this.class.implClass.new(patterns, repeats).asStream; inevent !? { inevent = inevent.copy; inevent[\group] = ingroup }; loop { event = stream.next(inevent) ?? { ^cleanup.exit(inevent) }; cleanup.update(event); lag = max(lag, clock.beats + event.use { ~sustain.value }); inevent = event.yield; } } numberOfGroups { ^list.size } wrapPatterns { arg ids; ^ids.collect { |id, i| Psetpre(\group, id, list[i]) }; } *implClass { ^Ppar } } Pgtpar : Pgpar { numberOfGroups { ^list.size div: 2 } wrapPatterns { arg ids; var patterns = list.copy; ids.do { |id, i| patterns[((i << 1) + 1)] = Psetpre(\group, id, patterns[(i << 1) + 1]) }; ^patterns } *implClass { ^Ptpar } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/PgeneralHid.sc0000664000000000000000000000416212014636263027166 0ustar rootroot//human device interface pattern. pulls values from devices like gamepads etc. // based on GeneralHID PhidSlot : Pattern { var <>slot,<>type,<>device; var <>repeats; var <>pSlot; // the Device list must have been built. *new { arg slot, type, device, repeats=inf; ^super.new.init(slot, type, device, repeats) } init{|sl,tp,dev,rep| device = dev; slot = sl; type = tp; repeats = rep; if ( device.isKindOf( GeneralHIDDevice ).not, { try { device = GeneralHID.open( device ); }{ "device argument is not a GeneralHIDDevice".error; ^nil } }); } storeArgs { ^[slot, type, device, repeats] } embedInStream { arg inval; // slot and type streams var slotStr = slot.asStream; var typeStr = type.asStream; var slotVal, typeVal, slottypes; repeats.value.do({ slotVal = slotStr.next(inval); typeVal = typeStr.next(inval); slottypes = [slotVal, typeVal].flop; inval = slottypes.collect{ |it| var ret; if ( device.slots[ it[1] ].isNil, { "slot type not found".warn; ret = inval; },{ if ( device.slots[ it[1] ][ it[0] ].isNil, { "slot not found".warn; ret = inval; },{ ret = device.slots[ it[1] ][ it[0] ].value; }); }); ret; }.unbubble.yield; }); ^inval; } } PhidKey : Pattern { var <>key,<>device; var <>repeats; var <>pSlot; // the Device list must have been built. *new { arg key, device, repeats=inf; ^super.new.init(key, device, repeats) } init{|ky,dev,rep| key = ky; device = dev; repeats = rep; if ( device.isKindOf( GeneralHIDDevice ).not, { try { device = GeneralHID.open( device ); }{ "device argument is not a GeneralHIDDevice".error; ^nil } }); } storeArgs { ^[key, device, repeats] } embedInStream { arg inval; // key stream var keyStr = key.asStream; var keyVal; repeats.value.do({ keyVal = keyStr.next(inval); keyVal = keyVal.asArray; inval = keyVal.collect{ |it| var ret; if ( device.at(it).isNil, { "slot not found".warn; ret = inval; },{ ret = device.at( it ).value; }); ret; }.unbubble.yield; }); ^inval; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/EventStreamCleanup.sc0000664000000000000000000000243412014636263030551 0ustar rootroot// Cleanup functions are passed a flag. // The flag is set false if nodes have already been freed by CmdPeriod // This caused a minor change to TempoClock:clear and TempoClock:cmdPeriod EventStreamCleanup { var <>functions; // cleanup functions from child streams and parent stream *new { ^super.new.clear } clear { functions = IdentitySet.new; } addFunction { |event, function | if(event.isKindOf(Dictionary)) { functions = functions.add(function); event[\addToCleanup] = event[\addToCleanup].add(function); }; } addNodeCleanup { |event, function | if(event.isKindOf(Dictionary)) { functions = functions.add(function); event[\addToNodeCleanup] = event[\addToNodeCleanup].add(function); }; } update { | event | if(event.isKindOf(Dictionary)) { functions = functions.addAll(event[\addToNodeCleanup]); functions = functions.addAll(event[\addToCleanup]); functions = functions.removeAll(event[\removeFromCleanup]); }; ^event } exit { | event, freeNodes = true | if(event.isKindOf(Dictionary)) { this.update(event); functions.do(_.value(freeNodes) ); event[\removeFromCleanup] = event[\removeFromCleanup].addAll(functions); this.clear; }; ^event } terminate { | freeNodes = true | functions.do(_.value(freeNodes)); this.clear } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/History.sc0000664000000000000000000003416212014636263026450 0ustar rootrootHistory { // adc 2006, Birmingham; rewrite 2007. classvar <>forwardFunc, verbose = false, <>recordLocally = true, saveFolder = "~/Desktop/", keepsLog = true; classvar <>current, <>maxShortLength=65; var 0) { // reverse indexing lineIndices = (e.endLine.min(linesSize) .. e.startLine.min(linesSize)); lineIndices.do { |index| var time, id, code, waittime; #time, id, code = lines[index]; waittime = time - (lastTimePlayed ? time); lastTimePlayed = time; waittime.wait; if (e.verbose) { code.postln }; code.compile.value; // so it does not change cmdLine. }; }; 0.5.wait; "history is over.".postln; }).set(\startLine, 0, \endLine, 0); } makeCurrent { History.current = this; hasMovedOn = true } isCurrent { ^this === History.current } play { |start=0, end, verbose=true| // line numbers; // starting from past 0 may not work. start = start.clip(0, lines.lastIndex); end = (end ? lines.lastIndex).clip(0, lines.lastIndex); player.set(\startLine, start, \endLine, end, \verbose, verbose); player.play; } stop { player.stop; } addLine { |now, authID, lineStr| var line = [ now, authID, lineStr ]; if (lines.isEmpty) { lines.add(line); lineShorts.add(this.class.shorten(line)); } { lines.addFirst(line); lineShorts.addFirst(this.class.shorten(line)); }; keys.add(authID); } // simple editing removeAt { |index| if (index.isKindOf(Collection)) { index.sort.reverseDo (this.removeAt(_)); ^this }; if (index < lines.size) { // ignore out of range indices, keep lists synced. [lines, lineShorts].do(_.removeAt(index)); }; hasMovedOn = true; } removeLast { this.removeAt(lines.size - 1) } keep { |num| lines = lines.keep(num); lineShorts = lineShorts.keep(num); hasMovedOn = true; } drop { |num| lines = lines.drop(num); lineShorts = lineShorts.drop(num); hasMovedOn = true; } // loading from and saving to files *saveCS { |path, forward=false| current.saveCS(path, forward) } saveCS { |path, forward=false| var file, lines2write; lines2write = if (forward) { lines.reverse } { lines }; path = path ?? { saveFolder ++ "history_" ++ this.class.timeStamp ++ ".scd" }; file = File(path.standardizePath, "w"); file.write(lines2write.asCompileString); inform("History written to:" + path); file.close; } *loadCS { |path, forward=false| current.loadCS(path, forward) } loadCS { |path, forward=false| var file, ll; protect { file = File(path.standardizePath, "r"); ll = file.readAllString; } { file.close; }; ll !? { ll = ll.compile.value; if (forward) { ll = ll.reverse }; this.lines_(ll) }; } // network setups support *network { } *localOn { recordLocally = true } *localOff { recordLocally = false } // string formatting utils storyString { var alone = lines.collectAs({ |line| line[1] }, IdentitySet).size == 1; var str; str = "///////////////////////////////////////////////////\n"; str = str ++ format("// History, as it was on %.\n", this.class.dateString); str = str ++ "///////////////////////////////////////////////////\n\n"; lines.reverseDo { |x| var now, id, cmdLine; #now, id, cmdLine = x; str = str ++ format("// - % - % \n", this.class.formatTime(now), if(alone) { "" } { "(" ++ id ++ ")" } ); if(cmdLine.find("\n").notNil and: { cmdLine[0] != $( }) { cmdLine = format("(\n%\n);", cmdLine) }; str = str ++ cmdLine ++ "\n\n"; }; ^str; } *saveStory { |path| current.saveStory(path) } saveStory { |path| var file; path = path ?? { saveFolder ++ "History_" ++ this.class.timeStamp ++ ".scd" }; file = File(path.standardizePath, "w"); file.write(this.storyString); file.close; } *formatTime { arg val; var h, m, s; h = val div: (60 * 60); val = val - (h * 60 * 60); m = val div: 60; val = val - (m * 60); s = val; ^"%:%:%".format(h, m, s.round(0.01)) } *unformatTime { arg str; var h, m, s; #h, m, s = str.split($:).collect(_.interpret); ^h * 60 + m * 60 + s } *prettyString { |str| // remove returns at beginning or end of the string var startIndex = str.detectIndex({ |ch| ch != $\n }); var endChar = str.last; var lastCharIndex = str.lastIndex; while { endChar == $\n } { lastCharIndex = lastCharIndex - 1; endChar = str[lastCharIndex]; }; // [startIndex, lastCharIndex].postln; ^str.copyRange(startIndex, lastCharIndex); } // convert to shortline for gui *shorten { |line, maxLength| var time, id, lineStr, head, length; #time, id, lineStr = line; head = (this.formatTime(time) + "-" + id + "- "); maxLength = maxLength ? maxShortLength; ^head ++ lineStr.keep(maxLength - head.size); } // not used yet *getTimeFromString { arg str; var ts, i; if(str.beginsWith("// - ").not) { ^nil }; i = str.find(" - ", offset: 4); if(i.isNil) { i = 10 }; // assume it's ok. ts = str[5..i+2].postln.split($:).collect(_.asFloat); ^ts[0] * (60 * 60) + (ts[1] * 60) + ts[2] } // not used yet *asLines { arg str; var indices; indices = str.findAll("// -"); ^str.clumps(indices.differentiate) } /* // problem: interpreter cancels backslashes etc. *stream { arg str, func; var lastTime=0, time; func = func ?? { {|str| var dt = ~prev / str.size; fork { 0.2.wait; // wait until result from last evaluation is printed str.do {|char| char.post; dt.wait; }; str.compile.value; }; } }; ^Routine { this.asLines(str).do { |line| time = this.getTimeFromString(line) ? lastTime; (prev:lastTime, delta: time - lastTime, play: { func.(line); }).yield; lastTime = time; } } } *play { arg str, clock; str = str ? Document.current.string; ^this.stream(str).asEventStreamPlayer.play(clock); } *playDocument { } */ *cmdPeriod { this.enter("// thisProcess.cmdPeriod"); } // log file support - global only *makeLogFolder { var supportDir = thisProcess.platform.userAppSupportDir; var specialFolder = supportDir ++ "/HistoryLogs"; if (pathMatch(supportDir).isEmpty) { logFolder = ""; ^this }; if (pathMatch(specialFolder).isEmpty) { specialFolder.mkdir; if (pathMatch(specialFolder).isEmpty) { logFolder = supportDir; // if not there, put it in flat } } { logFolder = specialFolder; }; // ("// History.logFolder:" + logFolder).postln; } *showLogFolder { openOS(logFolder) } *checkLogStarted { var isOpen; if (logFile.isNil) { this.startLog }; isOpen = logFile.isOpen; ^if (isOpen.not) { this.startLog; ^logFile.isOpen } { true }; } *startLog { var timeStamp = this.timeStamp; var timeString = this.dateString; // open file with current date logPath = logFolder ++ "/log_History_" ++ timeStamp ++ ".scd"; logFile = File(logPath, "w"); if (logFile.isOpen) { logFile.write(format("// History, as it was on %.\n\n", timeString) ++ "[\n" /*]*/ ); "// History.logFile opened.".inform; } { "// History: could not open logFile!".warn; }; } *addToLog { |line| // add a single line if (this.checkLogStarted) { try { logFile.write(line.asCompileString ++ ",\n") } { "// History: could not write to logFile!".warn; } } { warn("// History: logFile is not open!"); }; } *endLog { // close file try { logFile.write( /*[*/ "];") }; try { logFile.close; "// History.logFile closed.".inform; }; } *showLogFile { Document.open(this.logPath) } matchKeys { |key| var indices = []; if (key == \all) { ^(0..lines.size - 1) }; if (key.isNil) { ^nil }; // list of keys: if (key.isArray) { lines.do { |line, i| if (key.includes(line[1])) { indices = indices.add(i) } } } { lines.do { |line, i| if (line[1] == key) { indices = indices.add(i) } } }; ^indices } matchString { |str, ignoreCase=true| var indices = []; if (str.notNil and: (str != "")) { lines.do { |line, i| if (line[2].find(str, ignoreCase).notNil) { indices = indices.add(i) } }; ^indices } { ^nil } } indicesFor { |keys, string=""| var indicesK, indicesS, indicesFound; indicesK = this.matchKeys(keys); indicesS = this.matchString(string); // [\indicesK, indicesK, \indicesS, indicesS].postln; indicesFound = if (indicesK.notNil) { if (indicesS.notNil) { indicesK.sect(indicesS) } { indicesK } } { if (indicesS.notNil) { indicesS } { (0.. lines.size - 1) } }; ^indicesFound } *makeWin { |where, textHeight=12| ^current.makeWin(where, textHeight) } makeWin { |where, textHeight=12| ^HistoryGui(this, where, textHeight) } *document { current.document } document { arg title=""; // platform dependent ... var docTitle; Platform.case( \windows, { this.storyString.newTextWindow("History_documented"); }, { docTitle = title ++ Date.getDate.format("%Y-%m-%e-%Hh%M-History"); Document.new(docTitle, this.storyString) .path_(docTitle); // don't lose title. } ) } *readFromDoc { |path| var file, line, count = 0, lineStrings = [], comLineIndices = [], splitPoints; file = File(path.standardizePath, "r"); if (file.isOpen.not) { ("History: file" + path + "not found!").warn; ^false }; // read all lines, keep indices of commentlines while { line = file.getLine; line.notNil } { lineStrings = lineStrings.add(line); if (line.beginsWith("// - ")) { splitPoints = line.findAll(" - "); comLineIndices = comLineIndices.add([count] ++ splitPoints); }; count = count + 1; }; ^comLineIndices.collect { |list, i| var lineIndex, sep1, sep2, nextComIndex; var comLine, timeStr, time, key, codeStr; #lineIndex, sep1, sep2 = list; comLine = lineStrings[lineIndex]; timeStr = comLine.copyRange(sep1 + 3, sep2 - 1); time = History.unformatTime(timeStr); key = comLine.copyToEnd(sep2 + 3).select(_.isAlphaNum).asSymbol; nextComIndex = (comLineIndices[i + 1] ? [lineStrings.size]).first; codeStr = lineStrings.copyRange(lineIndex + 1, nextComIndex - 2).join; [time, key, codeStr]; }; } *checkPath { |path| var ext = path.splitext[1]; if ([\sc, \scd, \txt, \nil, \rtf].includes(ext.asSymbol)) { ^true } { warn("History: file format" + ext + "for story files likely not supported! Please use .txt, .scd, or other text format."); ^false }; } // load file saved with saveStory *loadStory { |path| current.loadStory(path) } loadStory { |path| var lines; if (this.class.checkPath(path)) { lines = this.class.readFromDoc(path); if (lines == false) { warn("History: no lines, so could not be loaded.") } { this.lines_(lines.reverse) } }; } *rewrite { |path, open = true| var lines, time, repath, file2; lines = path.load; if (lines.isNil) { "no history, no future.".warn; ^this }; time = path.basename.splitext.first.keep(-13).split($_).collect { |str, i| str.clump(2).join("-:"[i]); }.join($ ); repath = path.splitext.collect { |str, i| str ++ ["_rewritten.", ""][i] }.join; file2 = File.open(repath, "w"); file2.write("// History rewritten from" + time); lines.do { |line| var time, tag, code; #time, tag, code = line; file2.write("\n\n\n// when: % - who: % \n\n(\n%\n)\n".format(time, tag, code)); }; file2.close; if (open) { repath.openTextFile }; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/Rest.sc0000664000000000000000000000233612245365552025730 0ustar rootrootRest { var <>dur = 1; *new { |dur(1)| ^super.newCopyArgs(dur) } // for use by Pfunc and Pfuncn *processRest { |inval| inval.put(\isRest, true); ^1 } processRest { |inval| inval.put(\isRest, true); ^dur } // for use e.g. in ListPatterns *embedInStream { |inval| ^this.processRest(inval).yield; // the actual return value is the next inval } embedInStream { |inval| ^this.processRest(inval).yield; } *asStream { ^Routine({ |inval| loop { inval = this.embedInStream(inval); } }) } asStream { ^Routine({ |inval| loop { inval = this.embedInStream(inval); } }) } storeOn { |stream| stream << "Rest(" << dur << ")" } } + Object { processRest { ^this } } + Collection { processRest { |inval| this.do(_.processRest(inval)) } } + SimpleNumber { // Some patterns call .delta on the eventstream's yield value // since a SimpleNumber is a valid rest, it must answer 'delta' with itself delta {} // but Ppar and several other patterns do "put(\delta, ...)" // so they need to convert the simplenumber into a real rest event asEvent { ^Event.silent(this) } } + Event { asEvent {} } + Nil { // Ppar etc. need stream.next(event).asEvent to be nil when the stream ends asEvent {} } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/PmonoStreams.sc0000775000000000000000000000676112235141106027435 0ustar rootroot// these are internal classes, used by Pmono and PmonoArtic // they're not likely to work well if you try to use them outside that context PmonoStream : Stream { var pattern, id, server, cleanup, currentCleanupFunc, event, streamout, name, streampairs, endval, msgFunc, hasGate, synthLib, desc, schedBundleArray, schedBundle; *new { |pattern| ^super.newCopyArgs(pattern) } embedInStream { |inevent| inevent ?? { ^nil.yield }; this.prInit(inevent); loop { if(this.prDoStreams) { // always on the first iteration; should not happen thereafter if(id.isNil) { this.prInitNode }; cleanup.update(event); inevent = event.yield; this.prSetNextEvent(inevent); } { ^cleanup.exit(inevent) } } } // private methods abstracted out for the benefit of subclasses // you should not use these directly prInit { |inevent| cleanup = EventStreamCleanup.new; streampairs = pattern.patternpairs.copy; endval = pattern.patternpairs.size - 1; forBy (1, endval, 2) { | i | streampairs[i] = streampairs[i].asStream }; event = inevent.copy; event.use { synthLib = ~synthLib ?? { SynthDescLib.global }; ~synthDesc = desc = synthLib.match(pattern.synthName); if (desc.notNil) { ~hasGate = hasGate = desc.hasGate; ~msgFunc = desc.msgFunc; }{ ~msgFunc = ~defaultMsgFunc; ~hasGate = hasGate = false; }; msgFunc = ~msgFunc; } } prInitNode { event.use { if (~id.notNil) { ~type = \monoSet; id = ~id; } { // If the event is a rest, no node would be created // so there is no need to add a cleanup function // (for a node that will never exist). If a later // event is not a rest, ~id will be nil and the // cleanup will be set at that time. if(event.isRest.not) { ~type = \monoNote; ~instrument = pattern.synthName; cleanup.addFunction(event, currentCleanupFunc = { | flag | if (flag) { (id: id, server: server, type: \off, hasGate: hasGate, schedBundleArray: schedBundleArray, schedBundle: schedBundle).play }; currentCleanupFunc = nil; }); }; }; // this should happen whether or not ~id is nil ~updatePmono = { | argID, argServer | id = argID; server = argServer; schedBundleArray = ~schedBundleArray; schedBundle = ~schedBundle; }; }; } prDoStreams { forBy (0, endval, 2) { | i | name = streampairs[i]; streamout = streampairs[i+1].next(event); streamout ?? { ^false }; if (name.isSequenceableCollection) { name.do { | n, i | event[n] = streamout[i] }; }{ event[name] = streamout; }; }; ^true } prSetNextEvent { |inevent| event = inevent.copy; event.use{ ~server = server; ~id = id; ~type = \monoSet; ~msgFunc= msgFunc; }; } } PmonoArticStream : PmonoStream { embedInStream { |inevent| var sustain, rearticulating = true; inevent ?? { ^nil.yield }; this.prInit(inevent); loop { if(this.prDoStreams) { if(rearticulating and: { event.isRest.not }) { event[\id] = nil; this.prInitNode; rearticulating = false; }; sustain = event.use { ~sustain.value }; if(sustain.notNil and: { sustain < event.delta }) { event[\removeFromCleanup] = event[\removeFromCleanup].add(currentCleanupFunc); thisThread.clock.sched(sustain, { currentCleanupFunc.value(true); rearticulating = true; }); }; cleanup.update(event); inevent = event.yield; this.prSetNextEvent(inevent); } { ^cleanup.exit(inevent) } } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/ControlPatterns.sc0000664000000000000000000000215612014636263030146 0ustar rootroot//human device interface pattern. pulls values from devices like gamepads etc. Phid : Pattern { var <>element, <>locID, <>repeats; //element can be key or index *new { arg element, locID=0, repeats=inf; ^super.newCopyArgs(element, locID, repeats) } storeArgs { ^[element,locID,repeats] } embedInStream { arg event; var all, device, spec, elements, deviceName, min, max; all = HIDDeviceService.devices; if(all.isNil, { HIDDeviceService.buildDeviceList; all = HIDDeviceService.devices; }); device = all.at(locID); if(device.isNil, { "device not found".error; ^nil }); if(element.isNumber.not, { element = HIDDeviceService.keyToIndex(element, locID); if(element.isNil, { "key not found".error; ^nil }); }); elements = device.elements; min = elements.at(element).min; max = elements.at(element).max; spec = ControlSpec.new(min, max, 'lin', 1); if((min === 0) and: {max === 1}, { repeats.value(event).do({ event = device.value(element).yield }); ^event }, { repeats.value(event).do({ event = spec.unmap(device.value(element)).yield }); ^event; }) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Streams/FuncStreamAsRoutine.sc0000664000000000000000000000042612014636263030704 0ustar rootrootFuncStreamAsRoutine : Routine { var <>nextFunc; var <>resetFunc; *new { arg nextFunc, resetFunc; ^super.new({ arg inval; loop { inval = yield(thisThread.nextFunc.value(inval)) } }) .nextFunc_(nextFunc).resetFunc_(resetFunc) } reset { ^resetFunc.value } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Files/0000775000000000000000000000000012245452763024105 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Files/SoundFile.sc0000664000000000000000000003274312245365552026334 0ustar rootroot/* Sound File Format strings: header formats: read/write formats: "AIFF", - Apple's AIFF "WAV","RIFF" - Microsoft .WAV "SD2", - Sound Designer 2 "Sun", - NeXT/Sun "IRCAM", - old IRCAM format "none" - no header = raw data A huge number of other formats are supported read only. sample formats: "int8", "int16", "int24", "int32" "mulaw", "alaw", "float" not all header formats support all sample formats. */ SoundFile { classvar fileptr; var <>headerFormat = "AIFF"; var <>sampleFormat = "float"; var numChannels = 1; // number of channels var <>sampleRate = 44100.0; var <> path; *closeAll { if (openFiles.notNil, { openFiles.copy.do({ arg file; file.close; }); }); } isOpen { ^fileptr.notNil } *new { arg pathName; ^super.new.path_(pathName); } *openRead{ arg pathName; var file; file = SoundFile(pathName); if(file.openRead(pathName)){^file}{^nil} } *openWrite{ arg pathName; var file; file = SoundFile(pathName); if(file.openWrite(pathName)){ ^file}{^nil} } *use { arg path, function; var file = this.new, res; protect { file.openRead(path); res = function.value(file); } { file.close; } ^res } openRead{ arg pathName; path = pathName ? path; ^this.prOpenRead(path); } prOpenRead { arg pathName; // returns true if success, false if file not found or error reading. _SFOpenRead ^this.primitiveFailed; } readData { arg rawArray; // must have called openRead first! // returns true if success, false if file not found or error reading. _SFRead ^this.primitiveFailed; } readHeaderAsString { // must have called openRead first! //returns the whole header as String _SFHeaderInfoString ^this.primitiveFailed; } openWrite{ arg pathName; pathName = pathName ? path; ^this.prOpenWrite(pathName) } prOpenWrite { arg pathName; // write the header // format written is that indicated in headerFormat and sampleFormat. // return true if successful, false if not found or error writing. _SFOpenWrite ^this.primitiveFailed; } writeData { arg rawArray; // must have called openWrite first! // format written is that indicated in sampleFormat. // return true if successful, false if not found or error writing. _SFWrite ^this.primitiveFailed; } close { _SFClose ^this.primitiveFailed; } seek { arg offset = 0, origin = 0; // offset is in frames // origin is an integer, one of: // 0 - from beginning of file // 1 - from current position // 2 - from end of file _SFSeek ^this.primitiveFailed; } duration { ^numFrames/sampleRate } // normalizer utility *normalize { |path, outPath, newHeaderFormat, newSampleFormat, startFrame = 0, numFrames, maxAmp = 1.0, linkChannels = true, chunkSize = 4194304, threaded = false| var file, outFile, action = { protect { outFile = file.normalize(outPath, newHeaderFormat, newSampleFormat, startFrame, numFrames, maxAmp, linkChannels, chunkSize, threaded); } { file.close }; file.close; }; (file = SoundFile.openRead(path.standardizePath)).notNil.if({ // need to clean up in case of error if(threaded, { Routine(action).play(AppClock) }, action); ^outFile }, { MethodError("Unable to read soundfile at: " ++ path, this).throw; }); } normalize { |outPath, newHeaderFormat, newSampleFormat, startFrame = 0, numFrames, maxAmp = 1.0, linkChannels = true, chunkSize = 4194304, threaded = false| var peak, outFile; outFile = SoundFile.new.headerFormat_(newHeaderFormat ?? { this.headerFormat }) .sampleFormat_(newSampleFormat ?? { this.sampleFormat }) .numChannels_(this.numChannels) .sampleRate_(this.sampleRate); // can we open soundfile for writing? outFile.openWrite(outPath.standardizePath).if({ protect { "Calculating maximum levels...".postln; peak = this.channelPeaks(startFrame, numFrames, chunkSize, threaded); Post << "Peak values per channel are: " << peak << "\n"; peak.includes(0.0).if({ MethodError("At least one of the soundfile channels is zero. Aborting.", this).throw; }); // if all channels should be scaled by the same amount, // choose the highest peak among all channels // otherwise, retain the array of peaks linkChannels.if({ peak = peak.maxItem }); "Writing normalized file...".postln; this.scaleAndWrite(outFile, maxAmp / peak, startFrame, numFrames, chunkSize, threaded); "Done.".postln; } { outFile.close }; outFile.close; ^outFile }, { MethodError("Unable to write soundfile at: " ++ outPath, this).throw; }); } *groupNormalize { |paths, outDir, newHeaderFormat, newSampleFormat, maxAmp = 1.0, chunkSize = 4194304, threaded = true| var action; action = { var groupPeak = 0.0, files, outFiles; "Calculating maximum levels...".postln; paths.do({|path| var file, peak; (file = SoundFile.openRead(path.standardizePath)).notNil.if({ "Checking levels for file %\n".postf(path.standardizePath); files = files.add(file); peak = file.channelPeaks(0, nil, chunkSize, threaded); Post << "Peak values per channel are: " << peak << "\n"; peak.includes(0.0).if({ MethodError("At least one of the soundfile channels is zero. Aborting.", this).throw; }); groupPeak = max(groupPeak, peak.maxItem); }, { MethodError("Unable to read soundfile at: " ++ path, this).throw; }); }); "Overall peak level: %\n".postf(groupPeak); outDir = outDir.standardizePath.withTrailingSlash; files.do({|file| var outPath, outFile; outPath = outDir ++ file.path.basename; outFile = SoundFile.new.headerFormat_(newHeaderFormat ?? { file.headerFormat }) .sampleFormat_(newSampleFormat ?? { file.sampleFormat }) .numChannels_(file.numChannels) .sampleRate_(file.sampleRate); outFile.openWrite(outPath).if({ protect { "Writing normalized file %\n".postf(outPath); file.scaleAndWrite(outFile, maxAmp / groupPeak, 0, nil, chunkSize, threaded); } { outFile.close }; outFile.close; }, { MethodError("Unable to write soundfile at: " ++ outPath, this).throw; }); }); "////// Group Normalize complete //////".postln; }; if(threaded, { Routine(action).play(AppClock) }, action); } channelPeaks { |startFrame = 0, numFrames, chunkSize = 1048576, threaded = false| var rawData, peak, numChunks, chunksDone, test; peak = 0 ! numChannels; numFrames.isNil.if({ numFrames = this.numFrames }); numFrames = numFrames * numChannels; // chunkSize must be a multiple of numChannels chunkSize = (chunkSize/numChannels).floor * numChannels; if(threaded) { numChunks = (numFrames / chunkSize).roundUp(1); chunksDone = 0; }; this.seek(startFrame, 0); { (numFrames > 0) and: { rawData = FloatArray.newClear(min(numFrames, chunkSize)); this.readData(rawData); rawData.size > 0 } }.while({ rawData.do({ |samp, i| (samp.abs > peak[i % numChannels]).if({ peak[i % numChannels] = samp.abs }); }); numFrames = numFrames - chunkSize; if(threaded) { chunksDone = chunksDone + 1; test = chunksDone / numChunks; (((chunksDone-1) / numChunks) < test.round(0.02) and: { test >= test.round(0.02) }).if({ $..post; }); 0.0001.wait; }; }); if(threaded) { $\n.postln }; ^peak } scaleAndWrite { |outFile, scale, startFrame, numFrames, chunkSize, threaded = false| var rawData, numChunks, chunksDone, test; numFrames.isNil.if({ numFrames = this.numFrames }); numFrames = numFrames * numChannels; scale = scale.asArray; // (scale.size == 0).if({ scale = [scale] }); // chunkSize must be a multiple of numChannels chunkSize = (chunkSize/numChannels).floor * numChannels; if(threaded) { numChunks = (numFrames / chunkSize).roundUp(1); chunksDone = 0; }; this.seek(startFrame, 0); { (numFrames > 0) and: { rawData = FloatArray.newClear(min(numFrames, chunkSize)); this.readData(rawData); rawData.size > 0 } }.while({ rawData.do({ |samp, i| rawData[i] = rawData[i] * scale.wrapAt(i) }); // write, and check whether successful // throwing the error invokes error handling that closes the files (outFile.writeData(rawData) == false).if({ MethodError("SoundFile writeData failed.", this).throw }); numFrames = numFrames - chunkSize; if(threaded) { chunksDone = chunksDone + 1; test = chunksDone / numChunks; (((chunksDone-1) / numChunks) < test.round(0.02) and: { test >= test.round(0.02) }).if({ $..post; }); 0.0001.wait; }; }); if(threaded) { $\n.postln }; ^outFile } // diskIn synthdefs are now created on demand in SoundFile:cue // *initClass { // StartUp.add { // (1..16).do { | i | // SynthDef("diskIn" ++ i, { | out, amp = 1, bufnum, sustain, ar = 0, dr = 0.01 gate = 1 | // Out.ar(out, DiskIn.ar(i, bufnum) // * Linen.kr(gate, ar, 1, dr, 2) // * EnvGen.kr(Env.linen(ar, sustain - ar - dr max: 0 ,dr),1, doneAction: 2) * amp) // }).store // } // }; // } info { | path | var flag = this.openRead; if (flag) { this.close; } { ^nil } } *collect { | path = "sounds/*" | var paths, files; paths = path.pathMatch; files = paths.collect { | p | SoundFile(p).info }; files = files.select(_.notNil); ^files; } *collectIntoBuffers { | path = "sounds/*", server | server = server ?? { Server.default }; if (server.serverRunning) { ^SoundFile.collect(path) .collect { | sf | Buffer(server, sf.numFrames, sf.numChannels) .allocRead(sf.path) .sampleRate_(sf.sampleRate); } } { "the server must be running to collect soundfiles into buffers".error } } asBuffer { |server| var buffer, rawData; server = server ? Server.default; if(server.serverRunning.not) { Error("SoundFile:asBuffer - Server not running.").throw }; if(this.isOpen.not) { Error("SoundFile:asBuffer - SoundFile not open.").throw }; if(server.isLocal) { buffer = Buffer.read(server, path) } { forkIfNeeded { buffer = Buffer.alloc(server, numFrames, numChannels); rawData = FloatArray.newClear(numFrames * numChannels); this.readData(rawData); server.sync; buffer.sendCollection(rawData, wait: -1); } }; ^buffer } cue { | ev, playNow = false, closeWhenDone = false | var server, packet, defname = "diskIn" ++ numChannels, condition, onClose; ev = ev ? (); if (this.numFrames == 0) { this.info }; fork { ev.use { server = ~server ?? { Server.default}; if(~instrument.isNil) { SynthDef(defname, { | out, amp = 1, bufnum, sustain, ar = 0, dr = 0.01 gate = 1 | Out.ar(out, VDiskIn.ar(numChannels, bufnum, BufRateScale.kr(bufnum) ) * Linen.kr(gate, ar, 1, dr, 2) * EnvGen.kr(Env.linen(ar, sustain - ar - dr max: 0 ,dr),1, doneAction: 2) * amp) }).add; ~instrument = defname; condition = Condition.new; server.sync(condition); }; ev.synth; // set up as a synth event (see Event) ~bufnum = server.bufferAllocator.alloc(1); ~bufferSize = 0x10000; ~firstFrame = ~firstFrame ? 0; ~lastFrame = ~lastFrame ? numFrames; ~sustain = (~lastFrame - ~firstFrame)/(sampleRate ?? {server.options.sampleRate ? 44100}); ~close = { | ev | server.bufferAllocator.free(ev[\bufnum]); server.sendBundle(server.latency, ["/b_close", ev[\bufnum]], ["/b_free", ev[\bufnum] ] ) }; ~setwatchers = { |ev| OSCFunc({ server.sendBundle(server.latency, ["/b_close", ev[\bufnum]], ["/b_read", ev[\bufnum], path, ev[\firstFrame], ev[\bufferSize], 0, 1]); }, "/n_end", server.addr, nil, ev[\id][0]).oneShot; }; if (playNow) { packet = server.makeBundle(false, {ev.play})[0]; // makeBundle creates an array of messages // need one message, take the first } { packet = []; }; server.sendBundle(server.latency,["/b_alloc", ~bufnum, ~bufferSize, numChannels, ["/b_read", ~bufnum, path, ~firstFrame, ~bufferSize, 0, 1, packet] ]); }; }; if (closeWhenDone) { onClose = SimpleController(ev).put(\n_end, { ev.close; onClose.remove; }); ev.addDependant(onClose) }; ^ev; } play { | ev, playNow = true | ^this.cue(ev, playNow) } asEvent { | type = \allocRead | if (type == \cue) { ^( type: type, path: path, numFrames: numFrames, sampleRate: sampleRate, numChannels: numChannels, bufferSize: 0x10000, firstFileFrame: 0, firstBufferFrame: 0, leaveOpen: 1 ) } { ^( type: type, path: path, numFrames: numFrames, sampleRate: sampleRate, numChannels: numChannels, firstFileFrame: 0 ) } } toCSV { |outpath, headers, delim=",", append=false, func, action| var outfile, dataChunk; // Prepare input if(this.openRead(this.path).not){ ^"SoundFile:toCSV could not open the sound file".error }; dataChunk = FloatArray.newClear(this.numChannels * min(this.numFrames, 1024)); // Prepare output if(outpath.isNil){ outpath = path.splitext.at(0) ++ ".csv" }; outfile = File(outpath, if(append, "a", "w")); if(headers.notNil){ if(headers.isString){ outfile.write(headers ++ Char.nl); }{ outfile.write(headers.join(delim) ++ Char.nl); } }; // Now do it while{this.readData(dataChunk); dataChunk.size > 0}{ dataChunk.clump(this.numChannels).do{|row| outfile.write(if(func.isNil, {row}, {func.value(row)}).join(delim) ++ Char.nl) }; }; outfile.close; this.close; action.value(outpath); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Files/File.sc0000664000000000000000000000722512161364457025320 0ustar rootrootFile : UnixFILE { classvar scroot; classvar <>secondVolume; //needed only for OS9 path conversions classvar <>tmp; *new { arg path = ""; ^super.new.init(path.standardizePath); } *fromOS9 { arg path=""; if(secondVolume.notNil and: { path.copyRange(0,secondVolume.size - 1) == secondVolume },{ path = "/Volumes/" ++ path; }); ^super.new.init( String.streamContents({ arg s; path.do({ arg char,i; if(char == $:,{ if(i != 0,{ // leading : is not wanted in unix s << $/ }) },{ s << char }); }) }) ) } *initClass { scroot = File.getcwd; tmp = Platform.defaultTempDir; tmp.isNil.if( {"No valid temp directory found. Please set this manually using PathName.tmp_".warn}); } init { arg inPath; fullPath = inPath; } colonIndices { ^colonIndices ?? { colonIndices = List.new; fullPath.do({ arg eachChar, i; if (eachChar.isPathSeparator, { colonIndices.add(i) }); }); colonIndices } } fileName { ^fullPath.copyRange((this.lastColonIndex) + 1, (fullPath.size -1).max(0)); } fileNameWithoutExtension { var fileName; fileName = this.fileName; fileName.reverseDo({ arg char,i; if(char == $.,{ ^fileName.copyRange(0,fileName.size - (i + 2)) }) }); ^fileName } fileNameWithoutDoubleExtension { var fileName, pathName; fileName = this.fileNameWithoutExtension; pathName = PathName( fileName ); ^pathName.fileNameWithoutExtension; } extension { var fileName; fileName = this.fileName; fileName.reverseDo({ arg char,i; if(char == $.,{ ^fileName.copyRange(fileName.size - i,fileName.size - 1) }) }); ^"" } pathOnly { ^fullPath.copyRange(0, this.lastColonIndex); } diskName { ^fullPath.copyRange(0, this.colonIndices.first - 1) } isRelativePath { ^this.isAbsolutePath.not } isAbsolutePath { ^fullPath.at(0).isPathSeparator } absolutePath{ ^fullPath.absolutePath; } asRelativePath { |relativeTo| var r, a, b, i, mePath; mePath = this.fullPath.absolutePath; relativeTo = (relativeTo ? scroot ).absolutePath; r = thisProcess.platform.pathSeparator; a = mePath.split(r); b = relativeTo.split(r); i=0; while{a[i]==b[i] and:{i 1), { fullPath.copyRange(0, ci[ci.size - 2]); }, { fullPath.copyRange(0, this.lastColonIndex) }); } foldersWithoutCVS { arg path; ^this.folders(path).reject({ arg item; item.isCVS }) } isCVS { ^this.fileName == "CVS"; } foldersWithoutSVN { arg path; ^this.folders(path).reject({ arg item; item.isSVN }) } isSVN { ^this.fileName == ".svn"; } filesDo { arg func; this.files.do(func); this.foldersWithoutSVN.do { arg pathname; pathname.filesDo(func) } } filesDoNoCVS { arg func; this.files.do(func); this.foldersWithoutCVS.do { arg pathname; pathname.filesDo(func) } } filesDoNoSVN { arg func; this.files.do(func); this.foldersWithoutSVN.do { arg pathname; pathname.filesDo(func) } } // Iterates over all files within this path which match criteria for being help files. // Doesn't iterate over the help files listed in the Help tree - see Help:do for that. helpFilesDo { arg func; var extensions = #['html', 'htm', 'scd', 'rtf', 'rtfd']; // included var ignoreFolders = #['ignore', '.svn', '_darcs', 'CVS', '.git']; // excluded this.files.select{|afile| extensions.includes(afile.extension.asSymbol) } .do(func); this.folders.reject{|afolder| ignoreFolders.includes(afolder.folderName.asSymbol) } .do{ arg pathname; pathname.helpFilesDo(func) } } streamTree { arg str, tabs=0; str << this.fullPath << Char.nl; this.files.do({ arg item; tabs.do({ str << Char.tab }); str << item.fileNameWithoutExtension << Char.nl }); this.foldersWithoutSVN.do({ arg item; item.streamTree(str, tabs + 1); }); } streamTreeNoCVS { arg str, tabs=0; str << this.fullPath << Char.nl; this.files.do({ arg item; tabs.do({ str << Char.tab }); str << item.fileNameWithoutExtension << Char.nl }); this.foldersWithoutCVS.do({ arg item; item.streamTree(str, tabs + 1); }); } dumpTree { this.streamTree(Post) } printOn { arg stream; stream << "PathName(" << fullPath <<")" } dumpToDoc { arg title="Untitled"; var str, doc; doc = Document.new(title); str = CollStream.new; this.streamTree(str); doc.string = str.collection; ^doc } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Files/Directory.sc0000664000000000000000000000207112014636263026371 0ustar rootroot/* Not working, but see String-pathMatch */ /* DirectoryEntry { var pathName; *new { arg pathName; ^super.new.pathName_(pathName); } numFiles { var numFiles = 0; this.scanFiles({ numFiles = numFiles + 1; }); ^numFiles } at { arg index; ^this.prAt(DirectoryEntry.new, index); } scan { arg func; // scan all entries in this Directory var entry, index = 0; while ({ entry = this.at(index); entry.notNil },{ func.value(entry, index); index = index + 1; }); } scanFiles { arg func; var index = 0; // scan only files in this Directory this.scan({ arg entry; if (entry.isDir.not and: { entry.isVisible }, { func.value(entry, index); index = index + 1; }) }); } deepScan { arg func; // recursively scan all files in and below this Directory this.scan({ arg entry; if (entry.isDir, { Directory.new(entry.pathName).scanFiles(func); },{ func.value(entry); }) }); } // PRIVATE prAt { arg entry, index; _Directory_At } } */ SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/0000775000000000000000000000000012245452763023733 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/Char.sc0000664000000000000000000000343512161364457025143 0ustar rootrootChar : Magnitude { const classesInited; // Every class has a metaclass which has 'Meta_' prepended to the name. // Though there is a class Meta_Class which is the class of Class, the // class of Meta_Class is Class. It is a loop, but a different one // than the structure in Smalltalk. superclass { // superclass is stored as a symbol to allow forward reference during compilation ^superclass.asClass } asClass { ^this } isMetaClass { ^this.class === Class } initClass { } // call Class.initClassTree(SomeClass) to force a class to init if you depend on its resources *initClassTree { arg aClass; var implementsInitClass; // sometimes you need a class to be inited before another class // start the process: Class.initClassTree(Object) if(classesInited.isNil, { classesInited = IdentitySet.new }); if(classesInited.includes(aClass).not, { if(aClass.isMetaClass.not and: { aClass.class.findMethod(\initClass).notNil }, { aClass.initClass; }); classesInited.add(aClass); if(aClass.subclasses.notNil,{ aClass.subclasses.do({ arg class; this.initClassTree(class); }); }); }); } *allClasses { _AllClasses } findMethod { arg methodName; if ( methods.notNil, { ^methods.detect({ arg method; method.name == methodName }); },{ ^nil }); } findRespondingMethodFor { arg methodName; this.superclassesDo { arg class; var method = class.findMethod(methodName); method !? { ^method }; }; ^nil } findOverriddenMethod { arg methodName; if(this.findMethod(methodName).isNil) { ^nil }; this.superclass.superclassesDo { arg class; var method = class.findMethod(methodName); if(method.notNil) { ^method } }; ^nil } superclassesDo { arg function; var class = this; while { class.notNil } { function.value(class); class = class.superclass; } } dumpByteCodes { arg methodName; var meth; meth = this.findMethod(methodName); if (meth.notNil, { meth.dumpByteCodes },{ Post << methodName << " not found.\n"; }); } dumpClassSubtree { _DumpClassSubtree } dumpInterface { // show all methods and their arguments defined for this class // does not include methods defined in superclasses this.methods.do({ arg meth; var numargs; numargs = meth.argNames.size - 1; " ".post; meth.name.post; " ( ".post; meth.argNames.do({ arg name, i; if (i > 0, { // skip 'this' name.post; if (i < numargs, { ", ".post; }); }); }); " )\n".post; }); } asString { ^name.asString } printOn { arg stream; stream << "class " << name; } storeOn { arg stream; stream << name; } archiveAsCompileString { ^true } hasHelpFile { //should cache this in Library or classvar //can't add instance variables to Class ^this.name.asString.findHelpFile.notNil } helpFilePath { ^this.name.asString.findHelpFile } help { this.openHelpFile } openHelpFile { // NOTE: because wslib provided the shortcut "Object:*help --> Object:*openHelpFile", we do the same // rather than moving the implementation to the future-compatible :help method. // This prevents infinite recursions for people with wslib installed. // In future (3.7) this method content should be moved to :help, but no sooner. this.name.asString.help } shallowCopy { ^this } //listInstances { _ListInstancesOf } //traceAnyPathToAllInstancesOf { _TraceAnyPathToAllInstancesOf } openCodeFile { this.filenameSymbol.asString.openTextFile(this.charPos, -1); } classVars { var start, end; start = this.classVarIndex; end = start + this.classVarNames.size; ^thisProcess.instVarAt(0).copyRange(start, end) } inspectorClass { ^ClassInspector } findReferences { arg aSymbol, references; methods.do({ arg meth; references = meth.findReferences(aSymbol, references) }); ^references } *findAllReferences { arg aSymbol; // this will not find method calls that are compiled with special byte codes such as 'value'. var references; Class.allClasses.do({ arg class; references = class.findReferences(aSymbol, references); }); ^references; } allSubclasses { var list; list = subclasses.copy; subclasses.do({ arg class; list = list ++ class.allSubclasses; }); ^list } superclasses { var list; this.superclass.superclassesDo { arg class; list = list.add(class) } ^list } } Process { // A Process is a runtime environment. var classVars, nowExecutingPath; startup { var time; Class.initClassTree(AppClock); // AppClock first in case of error time = this.class.elapsedTime; Class.initClassTree(Object); ("Class tree inited in" + (this.class.elapsedTime - time).round(0.01) + "seconds").inform; Class.classesInited = nil; topEnvironment = Environment.new; currentEnvironment = topEnvironment; Archive.read; // This method is called automatically right after compiling. // Override in class 'Main' to do initialization stuff, // but make sure to call this superclass method. // the AppClock is not started until after this method is complete } run { // This method is called when 'Run Main' is chosen from the menu. // Override in class 'Main' to do whatever you want. } stop { // This method is called when 'Stop Main' is chosen from the menu. // Override in class 'Main' to do whatever you want. } shutdown { // This method is called before recompiling or quitting. // Override in class 'Main' to do whatever you want. ShutDown.run; NetAddr.disconnectAll; File.closeAll; Archive.write; } tick { // called repeatedly by SCVirtualMachine::doPeriodicTask ^AppClock.tick; } *tailCallOptimize { _GetTailCallOptimize } *tailCallOptimize_ { arg bool; _SetTailCallOptimize ^this.primitiveFailed } getCurrentSelection { var qt = \QtGUI.asClass; ^if(qt.notNil and: {qt.focusView.notNil}) { qt.selectedText; } { interpreter.cmdLine; } } openCodeFile { var string, class, method, words; string = this.getCurrentSelection; if (string.includes($:), { string.removeAllSuchThat(_.isSpace); words = string.delimit({ arg c; c == $: }); class = words.at(0).asSymbol.asClass; if (class.notNil, { method = class.findMethod(words.at(1).asSymbol); if (method.notNil, { method.filenameSymbol.asString.openTextFile(method.charPos, -1); }); }); },{ class = string.asSymbol.asClass; if (class.notNil, { class = class.classRedirect; class.filenameSymbol.asString.openTextFile(class.charPos, -1); }); }); } openWinCodeFile { var string, class, method, words; string = this.getCurrentSelection; if (string.includes($:), { string.removeAllSuchThat(_.isSpace); words = string.delimit({ arg c; c == $: }); class = words.at(0).asSymbol.asClass; if (class.notNil, { method = class.findMethod(words.at(1).asSymbol); if (method.notNil, { method.filenameSymbol.asString.openWinTextFile(method.charPos, -1); }); }); },{ class = string.asSymbol.asClass; if (class.notNil, { class = class.classRedirect; class.filenameSymbol.asString.openWinTextFile(class.charPos, -1); }); }); } methodReferences { // this will not find method calls that are compiled with special byte codes such as 'value'. var name, out, references, nameString; out = CollStream.new; name = this.getCurrentSelection.asSymbol; references = Class.findAllReferences(name); if (references.notNil, { out << "References to '" << name << "' :\n"; references.do({ arg ref; nameString = ref.ownerClass.name ++ ":" ++ ref.name; out << " [" << nameString << "]\n"; }); out.collection.newTextWindow(name.asString); },{ Post << "\nNo references to '" << name << "'.\n"; }); } methodTemplates { // this constructs the method templates when cmd-Y is pressed in the Lang menu. var name, out, found = 0, namestring, text; out = CollStream.new; text = this.getCurrentSelection; if (text.isEmpty){ Post << "\nNo implementations of ''.\n"; ^this }; if (text[0].toLower != text[0]) { // user pressed the wrong key. DWIM. ^this.openCodeFile; }; name = text.asSymbol; out << "Implementations of '" << name << "' :\n"; Class.allClasses.do({ arg class; class.methods.do({ arg method; if (method.name == name, { found = found + 1; namestring = class.name ++ ":" ++ name; out << " [" << namestring << "] : "; if (method.argNames.isNil or: { method.argNames.size == 1 }, { out << "this." << name; if (name.isSetter, { out << "(val)"; }); },{ out << method.argNames.at(0); if (name.asString.at(0).isAlpha, { out << "." << name << "("; method.argNames.do({ arg argName, i; if (i > 0, { if (i != 1, { out << ", " }); out << argName; }); }); out << ")"; },{ out << " " << name << " "; out << method.argNames.at(1); }); }); out.nl; }); }); }); case { found == 0 } { Post << "\nNo implementations of '" << name << "'.\n"; } { found == 1 } { interpreter.cmdLine = namestring; this.openCodeFile; } { out.collection.newTextWindow(name.asString); }; } interpretCmdLine { // interpret some text from the command line interpreter.interpretCmdLine; } interpretPrintCmdLine { // interpret some text from the command line and print result interpreter.interpretPrintCmdLine; } interpretPrintSelectedText { interpreter.cmdLine = this.getCurrentSelection; interpreter.interpretPrintCmdLine; } showHelp { this.getCurrentSelection.help } argv { ^[] } shallowCopy { ^this } *elapsedTime { _ElapsedTime } storeOn { arg stream; stream << "thisProcess"; } archiveAsCompileString { ^true } prSchedulerQueue { ^schedulerQueue } } FunctionDef { var raw1, raw2, cmdLine; // place holder for text executed from a worksheet var context; // faked interpreter context frame. Don't mess with it. // a-z are predefined variables for use by the interactive context. // They are read+write so that programmatic methods can // get and alter the values that the interpreter has access to. var <>a, <>b, <>c, <>d, <>e, <>f, <>g, <>h, <>i, <>j; var <>k, <>l, <>m, <>n, <>o, <>p, <>q, <>r, <>s, <>t; var <>u, <>v, <>w, <>x, <>y, <>z; var <>codeDump, <>preProcessor; *new { ^this.shouldNotImplement(thisMethod) } interpretCmdLine { ^this.compile(cmdLine).value; } interpretPrintCmdLine { var res, func, code = cmdLine, doc = Document.current, ideClass = \ScIDE.asClass; preProcessor !? { cmdLine = preProcessor.value(cmdLine, this) }; func = this.compile(cmdLine); if (ideClass.notNil) { thisProcess.nowExecutingPath = ideClass.currentPath } { if(doc.tryPerform(\dataptr).notNil) { thisProcess.nowExecutingPath = doc.tryPerform(\path); } }; res = func.value; thisProcess.nowExecutingPath = nil; codeDump.value(code, res, func, this); res.postln; } interpret { arg string ... args; // compile, evaluate cmdLine = string; ^this.compile(string).valueArray(args); } interpretPrint { arg string ... args; // compile, evaluate, print cmdLine = string; ^this.compile(string).valueArray(args).postln; } compile { arg string; _CompileExpression // compiles string and returns a Function. // the string must be a valid expression. // You cannot compile a class definition this way. // This method is not implemented in SCPlay. ^nil } clearAll { a = b = c = d = e = f = g = h = i = j = k = l = m = n = o = p = q = r = s = t = u = v = w = x = y = z = nil; } executeFile { arg pathName ... args; var result, saveExecutingPath = thisProcess.nowExecutingPath; if (File.exists(pathName).not) { "file \"%\" does not exist.\n".postf(pathName); ^nil }; thisProcess.nowExecutingPath = pathName; protect { result = this.compileFile(pathName).valueArray(args) } { |exception| exception !? { exception.path = pathName }; thisProcess.nowExecutingPath = saveExecutingPath }; ^result } compileFile { arg pathName; var file, text; file = File.new(pathName, "r"); if (file.isNil, { error("file open failed\n"); ^nil }); text = file.readAllString; file.close; if (text.beginsWith("#!"), { // comment out shebang to preserve line count text.overWrite("//"); }); ^this.compile(text) } // PRIVATE functionCompileContext { // compiler uses this method as a fake context in which to compile // the user's function. // Do not edit this method! {} // this forces the compiler to generate a heap allocated frame rather than // a frame on the stack } shallowCopy { ^this } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/Condition.sc0000664000000000000000000000234712161364457026215 0ustar rootrootCondition { var <>test, waitingThreads; *new { arg test=false; ^super.newCopyArgs(test, Array(8)) } wait { if (test.value.not, { waitingThreads = waitingThreads.add(thisThread.threadPlayer); \hang.yield; }); } hang { arg value = \hang; // ignore the test, just wait waitingThreads = waitingThreads.add(thisThread.threadPlayer); value.yield; } signal { var tempWaitingThreads, time; if (test.value, { time = thisThread.seconds; tempWaitingThreads = waitingThreads; waitingThreads = nil; tempWaitingThreads.do({ arg thread; thread.clock.sched(0, thread); }); }); } unhang { var tempWaitingThreads, time; // ignore the test, just resume all waiting threads time = thisThread.seconds; tempWaitingThreads = waitingThreads; waitingThreads = nil; tempWaitingThreads.do({ arg thread; thread.clock.sched(0, thread); }); } } FlowVar { var value = \unbound; var condition; *new { arg inVal = \unbound; ^super.init(inVal) } init { arg inVal; value = inVal; condition = Condition { value != \unbound }; } value_ { arg inVal; if (value == \unbound) { Error("cannot rebind a FlowVar").throw }; value = inVal; condition.signal; } value { condition.wait ^value } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/Object.sc0000664000000000000000000005264612245365552025504 0ustar rootrootObject { classvar { arg obj; ^Association.new(this, obj) } // stream next { ^this } reset { ^this } first { arg inval; this.reset; ^this.next(inval) } iter { ^OneShotStream(this) } stop { ^this } free { ^this } clear { ^this } removedFromScheduler { ^this } isPlaying { ^false } embedInStream { ^this.yield; } cyc { arg n = inf; ^r {|inval| n.do { inval = this.embedInStream(inval); this.reset; } } } fin { arg n = 1; ^r {|inval| var item; n.do { item = this.next(inval); if (item.isNil) { nil.alwaysYield }; inval = item.yield } } } repeat { arg repeats = inf; ^Pn(this, repeats).asStream } loop { ^this.repeat(inf) } asStream { ^this } eventAt { ^nil } composeEvents { arg event; ^event.copy } finishEvent {} atLimit { ^false } isRest { ^false } threadPlayer {} threadPlayer_ {} // testing ? { arg obj; ^this } ?? { arg obj; ^this } !? { arg obj; ^obj.value(this) } isNil { ^false } notNil { ^true } isNumber { ^false } isInteger { ^false } isFloat { ^false } isSequenceableCollection { ^false } isCollection { ^false } isArray { ^false } isString { ^false } containsSeqColl { ^false } isValidUGenInput { ^false } isException { ^false } isFunction { ^false } matchItem {|item| ^this === item } trueAt { ^false } falseAt { arg key; ^this.trueAt(key).not } pointsTo { arg obj; _ObjectPointsTo; ^this.primitiveFailed } mutable { _ObjectIsMutable; ^this.primitiveFailed } frozen { _ObjectIsPermanent; ^this.primitiveFailed } // errors halt { thisProcess.nowExecutingPath = nil; OnError.run; this.prHalt } prHalt { _Halt } primitiveFailed { PrimitiveFailedError(this).throw; } reportError { error(this.asString); this.dumpBackTrace; } subclassResponsibility { arg method; SubclassResponsibilityError(this, method, this.class).throw; } doesNotUnderstand { arg selector ... args; DoesNotUnderstandError(this, selector, args).throw; } shouldNotImplement { arg method; ShouldNotImplementError(this, method, this.class).throw; } outOfContextReturn { arg method, result; OutOfContextReturnError(this, method, result).throw; } immutableError { arg value; ImmutableError(this, value).throw; } deprecated { arg method, alternateMethod; DeprecatedError(this, method, alternateMethod, this.class).throw; } mustBeBoolean { MustBeBooleanError(nil, this).throw; } notYetImplemented { NotYetImplementedError(nil, this).throw; } dumpBackTrace { _DumpBackTrace } getBackTrace { _GetBackTrace } throw { if (Error.handling) { error("throw during error handling!\n"); this.dump; ^this }; thisThread.handleError(this); } // conversion species { ^this.class } asCollection { ^[this] } asSymbol { ^this.asString.asSymbol } asString { arg limit = 512; var string; _ObjectString string = String.streamContentsLimit({ arg stream; this.printOn(stream); }, limit); if (string.size >= limit, { ^(string ++ "...etc..."); }); ^string } asCompileString { _ObjectCompileString ^String.streamContents({ arg stream; this.storeOn(stream); }); } cs { ^this.asCompileString } printClassNameOn { arg stream; var title; title = this.class.name.asString; stream << if((title @ 0).isVowel, { "an " }, { "a " }) << title; } printOn { arg stream; this.printClassNameOn(stream); } storeOn { arg stream; stream << this.class.name; this.storeParamsOn(stream); this.storeModifiersOn(stream); } storeParamsOn { arg stream; var args = this.storeArgs; if(args.notEmpty) { stream << "(" <<<* this.simplifyStoreArgs(args) << ")"; } { stream << ".new" } } simplifyStoreArgs { arg args; var res = Array.new, newMethod, methodArgs; newMethod = this.class.class.findRespondingMethodFor(\new); methodArgs = newMethod.prototypeFrame.drop(1); args.size.reverseDo { |i| if(methodArgs[i] != args[i]) { ^args.keep(i + 1) } } ^[] } storeArgs { ^#[] } storeModifiersOn { arg stream;} as { arg aSimilarClass; ^aSimilarClass.newFrom(this) } dereference { ^this } // see Ref::dereference reference { ^Ref.new(this) } asRef { ^Ref.new(this) } // asArray { ^Array.with(this) } asArray { ^this.asCollection.asArray } asSequenceableCollection { ^this.asArray } // arrays rank { ^0 } deepCollect { arg depth, function, index = 0, rank = 0; ^function.value(this, index, rank) } deepDo { arg depth, function, index = 0, rank = 0; function.value(this, index, rank) } slice { ^this } shape { ^nil } unbubble { ^this } bubble { arg depth=0, levels=1; if (levels <= 1) { ^[this] }; ^[this.bubble(depth,levels-1)] } // compatibility with sequenceable collection obtain { arg index, default; ^if(index == 0) { this } { default } } instill { arg index, item, default; ^if(index == 0) { item } { this.asArray.instill(index, item, default) } } // FunctionList support addFunc { arg ... functions; ^FunctionList([this] ++ functions) } removeFunc { arg function; if(this === function) { ^nil } } replaceFunc { arg find, replace; if(this === find) { ^replace } } addFuncTo { arg variableName ... functions; this.perform(variableName.asSetter, this.perform(variableName).addFunc(*functions)) } removeFuncFrom { arg variableName, function; this.perform(variableName).removeFunc(function) } // looping while { arg body; // compiler magic: the compiler inlines the following loop // thus an uninlinable while can be implemented using while itself while({ this.value }, { body.value }); } switch { arg ... cases; cases.pairsDo { | test, trueFunc | if (this == test.value) { ^trueFunc.value }; }; if (cases.size.odd) { ^cases.last.value }; ^nil } // coroutine support yield { _RoutineYield ^this.primitiveFailed } alwaysYield { _RoutineAlwaysYield ^this.primitiveFailed } yieldAndReset { arg reset = true; _RoutineYieldAndReset ^this.primitiveFailed } idle { arg val; var time = thisThread.beats; while { thisThread.beats - time < val } { this.value.yield } } // dependancy support *initClass { dependantsDictionary = IdentityDictionary.new(4); } dependants { ^dependantsDictionary.at(this) ?? { IdentitySet.new }; } changed { arg what ... moreArgs; dependantsDictionary.at(this).copy.do({ arg item; item.update(this, what, *moreArgs); }); } addDependant { arg dependant; var theDependants; theDependants = dependantsDictionary.at(this); if(theDependants.isNil,{ theDependants = IdentitySet.new.add(dependant); dependantsDictionary.put(this, theDependants); },{ theDependants.add(dependant); }); } removeDependant { arg dependant; var theDependants; theDependants = dependantsDictionary.at(this); if (theDependants.notNil, { theDependants.remove(dependant); if (theDependants.size == 0, { dependantsDictionary.removeAt(this); }); }); } release { this.releaseDependants; } releaseDependants { dependantsDictionary.removeAt(this); } update { arg theChanged, theChanger; // respond to a change in a model } // instance specific method support addUniqueMethod { arg selector, function; var methodDict; if(function.isKindOf(Function).not) { Error("A method must be defined using a function").throw }; if(uniqueMethods.isNil, { uniqueMethods = IdentityDictionary.new }); methodDict = uniqueMethods.at(this); if (methodDict.isNil, { methodDict = IdentityDictionary.new; uniqueMethods.put(this, methodDict); }); methodDict.put(selector, function); } removeUniqueMethods { if (uniqueMethods.notNil, { uniqueMethods.removeAt(this); }); } removeUniqueMethod { arg selector; var methodDict; if (uniqueMethods.notNil, { methodDict = uniqueMethods.at(this); if (methodDict.notNil, { methodDict.removeAt(selector); if (methodDict.size < 1, { uniqueMethods.removeAt(this); }); }); }); } inspect { ^this.inspectorClass.new(this) } inspectorClass { ^ObjectInspector } inspector { // finds the inspector for this object, if any. ^Inspector.inspectorFor(this) } // virtual machine debugging... crash { _HostDebugger } // for serious problems.. stackDepth { _StackDepth } dumpStack { _DumpStack } dumpDetailedBackTrace { _DumpDetailedBackTrace } freeze { _ObjectDeepFreeze ^this.primitiveFailed } // Math protocol support // translate these operators to names the code generator can safely generate in C++ & { arg that; ^bitAnd(this, that) } | { arg that; ^bitOr(this, that) } % { arg that; ^mod(this, that) } ** { arg that; ^pow(this, that) } << { arg that; ^leftShift(this, that) } >> { arg that; ^rightShift(this, that) } +>> { arg that; ^unsignedRightShift(this, that) } 0) { stream << "(" << size << ")" }; }; }; stream << "\n];\np = ["; // put in slots firsttime = true; list.do {|obj, i| var slots; if (obj.archiveAsCompileString.not) { slots = obj.getSlots; if (slots.size > 0) { if (firsttime.not) { stream << ", "; }; firsttime = false; stream << "\n\t// " << obj.class.name; stream << "\n\t"; stream << i << ", [ "; if (obj.isKindOf(ArrayedCollection)) { slots.do {|slot, j| var index; if (j != 0) { stream << ", "; }; if ((j != 0) && ((j & 3) == 0)) { stream << "\n\t\t" }; index = objects[slot]; if (index.isNil) { stream << slot.asCompileString; }{ stream << "o[" << index << "]"; }; }; }{ slots.pairsDo {|key, slot, j| var index; if (j != 0) { stream << ", "; }; if ((j != 0) && ((j & 3) == 0)) { stream << "\n\t\t" }; stream << key << ": "; index = objects[slot]; if (index.isNil) { stream << slot.asCompileString; }{ stream << "o[" << index << "]"; }; }; }; stream << " ]"; }; }; }; stream << "\n];\n"; stream << "prUnarchive(o,p);\n"; ^stream.contents } getContainedObjects { arg objects; if (objects[this].notNil) {^this}; objects[this] = objects.size; if (this.archiveAsCompileString.not) { this.slotsDo {|key, slot| if (slot.archiveAsObject) { slot.getContainedObjects(objects); }; }; }; } // old binary archiving // this will break if the instance vars change ! // not recommended writeBinaryArchive { arg pathname; _WriteArchive ^this.primitiveFailed; } *readBinaryArchive { arg pathname; _ReadArchive ^this.primitiveFailed; } asBinaryArchive { _AsArchive ^this.primitiveFailed; } // support for Gen genNext { ^nil } genCurrent { ^this } // support for ViewRedirect *classRedirect { ^this } help { this.class.asString.help } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/Semaphore.sc0000664000000000000000000000065012161364457026205 0ustar rootrootSemaphore { var value; *new { arg thing; ^super.new.value_(thing) } set { arg thing; value = thing } get { ^value } dereference { ^value } asRef { ^this } valueArray { ^value } valueEnvir { ^value } valueArrayEnvir { ^value } // behave like a stream next { ^value } // embedInStream { arg inval; // ^this.value.embedInStream(inval) // } // prevent multichannel expansion in ugens asUGenInput { ^this } printOn { arg stream; stream << "`(" << value << ")"; } storeOn { arg stream; stream << "`(" <<< value << ")"; } at { | key | ^value.at(key) } put { | key, val | value.put(key, val) } seq { | pat | value = pat.embedInStream(this) } asControlInput { ^value.asControlInput } // Some UGens take Buffer data which // the user might want to specify simply as `[0.9, 0.1, 0.3] asBufWithValues { ^LocalBuf.newFrom(value); } // Allow to multichannel expand ugen specs, like those of Klank, // in the case of which two is the rank, but could be otherwise. multichannelExpandRef { |rank| var array, refarray; array = this.value.asArray; if(array.maxSizeAtDepth(rank) <= 1) { ^this }; // no need to expand refarray = array.flopDeep(rank).collect { |item| this.class.new(item) }; ^refarray.unbubble } } RefCopy : Ref { next { ^value.copy } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/Boolean.sc0000664000000000000000000000340012014636263025627 0ustar rootrootBoolean { *new { ^this.shouldNotImplement(thisMethod) } xor { arg bool; ^(this === bool).not } if { ^this.subclassResponsibility(thisMethod) } not { ^this.subclassResponsibility(thisMethod) } && { ^this.subclassResponsibility(thisMethod) } || { ^this.subclassResponsibility(thisMethod) } and { ^this.subclassResponsibility(thisMethod) } or { ^this.subclassResponsibility(thisMethod) } nand { ^this.subclassResponsibility(thisMethod) } asInteger { ^this.subclassResponsibility(thisMethod) } binaryValue { ^this.subclassResponsibility(thisMethod) } // TODO: deprecate for asInteger asBoolean { ^this } booleanValue { ^this } // TODO in the long-run, deprecate for asBoolean keywordWarnings { // turn on/off warnings if a keyword argument is not found _KeywordError } trace { _Trace } // this is only available in a special debugging version of the app printOn { arg stream; stream.putAll(this.asString); } storeOn { arg stream; stream.putAll(this.asCompileString); } archiveAsCompileString { ^true } while { ^"While was called with a fixed (unchanging) Boolean as the condition. Please supply a Function instead.".error } } True : Boolean { if { arg trueFunc, falseFunc; ^trueFunc.value } not { ^false } && { arg that; ^that.value } || { arg that; ^this } and { arg that; ^that.value } or { arg that; ^this } nand { arg that; ^that.value.not } asInteger { ^1 } binaryValue { ^1 } // TODO in the long-run, deprecate for asInteger } False : Boolean { if { arg trueFunc, falseFunc; ^falseFunc.value } not { ^true } && { arg that; ^this } || { arg that; ^that.value } and { arg that; ^this } or { arg that; ^that.value } nand { arg that; ^true } asInteger { ^0 } binaryValue { ^0 } // TODO in the long-run, deprecate for asInteger } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/Message.sc0000664000000000000000000000071412014636263025641 0ustar rootrootMessage { var <>receiver, <>selector, <>args; *new { arg receiver, selector, args; ^super.newCopyArgs(receiver, selector, args); } value { arg ... moreArgs; ^receiver.performList(selector, args ++ moreArgs); } storeArgs { ^[receiver, selector, args] } } MethodQuote { var <>selector; *new { arg selector; ^super.newCopyArgs(selector); } value { arg receiver ... args; ^receiver.performList(selector, args); } storeArgs { ^[selector] } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/AbstractFunction.sc0000664000000000000000000003253012245365552027535 0ustar rootrootAbstractFunction { // function compositions // override these in subclasses to perform different kinds of function compositions composeUnaryOp { arg aSelector; ^UnaryOpFunction.new(aSelector, this) } composeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunction.new(aSelector, this, something, adverb); } reverseComposeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunction.new(aSelector, something, this, adverb); } composeNAryOp { arg aSelector, anArgList; ^NAryOpFunction.new(aSelector, this, anArgList) } // double dispatch for mixed operations performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb; ^this.reverseComposeBinaryOp(aSelector, aNumber, adverb) } performBinaryOpOnSignal { arg aSelector, aSignal, adverb; ^this.reverseComposeBinaryOp(aSelector, aSignal, adverb) } performBinaryOpOnComplex { arg aSelector, aComplex, adverb; ^this.reverseComposeBinaryOp(aSelector, aComplex, adverb) } performBinaryOpOnSeqColl { arg aSelector, aSeqColl, adverb; ^this.reverseComposeBinaryOp(aSelector, aSeqColl, adverb) } // respond to math operators neg { ^this.composeUnaryOp('neg') } reciprocal { ^this.composeUnaryOp('reciprocal') } bitNot { ^this.composeUnaryOp('bitNot') } abs { ^this.composeUnaryOp('abs') } asFloat { ^this.composeUnaryOp('asFloat') } asInteger { ^this.composeUnaryOp('asInteger') } ceil { ^this.composeUnaryOp('ceil') } floor { ^this.composeUnaryOp('floor') } frac { ^this.composeUnaryOp('frac') } sign { ^this.composeUnaryOp('sign') } squared { ^this.composeUnaryOp('squared') } cubed { ^this.composeUnaryOp('cubed') } sqrt { ^this.composeUnaryOp('sqrt') } exp { ^this.composeUnaryOp('exp') } midicps { ^this.composeUnaryOp('midicps') } cpsmidi { ^this.composeUnaryOp('cpsmidi') } midiratio { ^this.composeUnaryOp('midiratio') } ratiomidi { ^this.composeUnaryOp('ratiomidi') } ampdb { ^this.composeUnaryOp('ampdb') } dbamp { ^this.composeUnaryOp('dbamp') } octcps { ^this.composeUnaryOp('octcps') } cpsoct { ^this.composeUnaryOp('cpsoct') } log { ^this.composeUnaryOp('log') } log2 { ^this.composeUnaryOp('log2') } log10 { ^this.composeUnaryOp('log10') } sin { ^this.composeUnaryOp('sin') } cos { ^this.composeUnaryOp('cos') } tan { ^this.composeUnaryOp('tan') } asin { ^this.composeUnaryOp('asin') } acos { ^this.composeUnaryOp('acos') } atan { ^this.composeUnaryOp('atan') } sinh { ^this.composeUnaryOp('sinh') } cosh { ^this.composeUnaryOp('cosh') } tanh { ^this.composeUnaryOp('tanh') } rand { ^this.composeUnaryOp('rand') } rand2 { ^this.composeUnaryOp('rand2') } linrand { ^this.composeUnaryOp('linrand') } bilinrand { ^this.composeUnaryOp('bilinrand') } sum3rand { ^this.composeUnaryOp('sum3rand') } distort { ^this.composeUnaryOp('distort') } softclip { ^this.composeUnaryOp('softclip') } coin { ^this.composeUnaryOp('coin') } even { ^this.composeUnaryOp('even') } odd { ^this.composeUnaryOp('odd') } rectWindow { ^this.composeUnaryOp('rectWindow') } hanWindow { ^this.composeUnaryOp('hanWindow') } welWindow { ^this.composeUnaryOp('welWindow') } triWindow { ^this.composeUnaryOp('triWindow') } scurve { ^this.composeUnaryOp('scurve') } ramp { ^this.composeUnaryOp('ramp') } isPositive { ^this.composeUnaryOp('isPositive') } isNegative { ^this.composeUnaryOp('isNegative') } isStrictlyPositive { ^this.composeUnaryOp('isStrictlyPositive') } rho { ^this.composeUnaryOp('rho') } theta { ^this.composeUnaryOp('theta') } rotate { arg function; ^this.composeBinaryOp('rotate', function) } dist { arg function; ^this.composeBinaryOp('dist', function) } + { arg function, adverb; ^this.composeBinaryOp('+', function, adverb) } - { arg function, adverb; ^this.composeBinaryOp('-', function, adverb) } * { arg function, adverb; ^this.composeBinaryOp('*', function, adverb) } / { arg function, adverb; ^this.composeBinaryOp('/', function, adverb) } div { arg function, adverb; ^this.composeBinaryOp('div', function, adverb) } mod { arg function, adverb; ^this.composeBinaryOp('mod', function, adverb) } pow { arg function, adverb; ^this.composeBinaryOp('pow', function, adverb) } min { arg function, adverb; ^this.composeBinaryOp('min', function, adverb) } max { arg function=0, adverb; ^this.composeBinaryOp('max', function, adverb) } < { arg function, adverb; ^this.composeBinaryOp('<', function, adverb) } <= { arg function, adverb; ^this.composeBinaryOp('<=', function, adverb) } > { arg function, adverb; ^this.composeBinaryOp('>', function, adverb) } >= { arg function, adverb; ^this.composeBinaryOp('>=', function, adverb) } bitAnd { arg function, adverb; ^this.composeBinaryOp('bitAnd', function, adverb) } bitOr { arg function, adverb; ^this.composeBinaryOp('bitOr', function, adverb) } bitXor { arg function, adverb; ^this.composeBinaryOp('bitXor', function, adverb) } bitHammingDistance { arg function, adverb; ^this.composeBinaryOp('hammingDistance', function, adverb) } lcm { arg function, adverb; ^this.composeBinaryOp('lcm', function, adverb) } gcd { arg function, adverb; ^this.composeBinaryOp('gcd', function, adverb) } round { arg function=1, adverb; ^this.composeBinaryOp('round', function, adverb) } roundUp { arg function=1, adverb; ^this.composeBinaryOp('roundUp', function, adverb) } trunc { arg function=1, adverb; ^this.composeBinaryOp('trunc', function, adverb) } atan2 { arg function, adverb; ^this.composeBinaryOp('atan2', function, adverb) } hypot { arg function, adverb; ^this.composeBinaryOp('hypot', function, adverb) } hypotApx { arg function, adverb; ^this.composeBinaryOp('hypotApx', function, adverb) } leftShift { arg function, adverb; ^this.composeBinaryOp('leftShift', function, adverb) } rightShift { arg function, adverb; ^this.composeBinaryOp('rightShift', function, adverb) } unsignedRightShift { arg function, adverb; ^this.composeBinaryOp('unsignedRightShift', function, adverb) } ring1 { arg function, adverb; ^this.composeBinaryOp('ring1', function, adverb) } ring2 { arg function, adverb; ^this.composeBinaryOp('ring2', function, adverb) } ring3 { arg function, adverb; ^this.composeBinaryOp('ring3', function, adverb) } ring4 { arg function, adverb; ^this.composeBinaryOp('ring4', function, adverb) } difsqr { arg function, adverb; ^this.composeBinaryOp('difsqr', function, adverb) } sumsqr { arg function, adverb; ^this.composeBinaryOp('sumsqr', function, adverb) } sqrsum { arg function, adverb; ^this.composeBinaryOp('sqrsum', function, adverb) } sqrdif { arg function, adverb; ^this.composeBinaryOp('sqrdif', function, adverb) } absdif { arg function, adverb; ^this.composeBinaryOp('absdif', function, adverb) } thresh { arg function, adverb; ^this.composeBinaryOp('thresh', function, adverb) } amclip { arg function, adverb; ^this.composeBinaryOp('amclip', function, adverb) } scaleneg { arg function, adverb; ^this.composeBinaryOp('scaleneg', function, adverb) } clip2 { arg function=1, adverb; ^this.composeBinaryOp('clip2', function, adverb) } fold2 { arg function=1, adverb; ^this.composeBinaryOp('fold2', function, adverb) } wrap2 { arg function=1, adverb; ^this.composeBinaryOp('wrap2', function, adverb) } excess { arg function=1, adverb; ^this.composeBinaryOp('excess', function, adverb) } firstArg { arg function, adverb; ^this.composeBinaryOp('firstArg', function, adverb) } rrand { arg function, adverb; ^this.composeBinaryOp('rrand', function, adverb) } exprand { arg function, adverb; ^this.composeBinaryOp('exprand', function, adverb) } @ { arg function, adverb; ^this.composeBinaryOp('@', function, adverb) } // complex support real { ^this } imag { ^0.0 } || { arg function, adverb; ^this.composeBinaryOp('||', function, adverb) } && { arg function, adverb; ^this.composeBinaryOp('&&', function, adverb) } xor { arg function, adverb; ^this.composeBinaryOp('xor', function, adverb) } nand { arg function, adverb; ^this.composeBinaryOp('nand', function, adverb) } not { ^this.composeUnaryOp('not') } ref { ^this.composeUnaryOp('asRef') } // nary operators clip { arg lo, hi; ^this.composeNAryOp('clip', [lo,hi]) } wrap { arg lo, hi; ^this.composeNAryOp('wrap', [lo,hi]) } fold { arg lo, hi; ^this.composeNAryOp('fold', [lo,hi]) } blend { arg that, blendFrac = 0.5; ^this.composeNAryOp('blend', [that, blendFrac]) } linlin { arg inMin, inMax, outMin, outMax, clip=\minmax; ^this.composeNAryOp('linlin', [inMin, inMax, outMin, outMax, clip]) } linexp { arg inMin, inMax, outMin, outMax, clip=\minmax; ^this.composeNAryOp('linexp', [inMin, inMax, outMin, outMax, clip]) } explin { arg inMin, inMax, outMin, outMax, clip=\minmax; ^this.composeNAryOp('explin', [inMin, inMax, outMin, outMax, clip]) } expexp { arg inMin, inMax, outMin, outMax, clip=\minmax; ^this.composeNAryOp('expexp', [inMin, inMax, outMin, outMax, clip]) } lincurve { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; ^this.composeNAryOp('lincurve', [inMin, inMax, outMin, outMax, curve, clip]) } curvelin { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; ^this.composeNAryOp('curvelin', [inMin, inMax, outMin, outMax, curve, clip]) } bilin { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax; ^this.composeNAryOp('bilin', [inCenter, inMin, inMax, outCenter, outMin, outMax, clip]) } biexp { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax; ^this.composeNAryOp('biexp', [inCenter, inMin, inMax, outCenter, outMin, outMax, clip]) } degreeToKey { arg scale, stepsPerOctave=12; ^this.composeNAryOp('degreeToKey', [scale, stepsPerOctave]) } degrad { ^this.composeUnaryOp('degrad') } raddeg { ^this.composeUnaryOp('raddeg') } applyTo { arg ... args; ^this.valueArray(args) } <> { arg that; // function composition ^{|...args| this.value(that.value(*args)) } } sampled{ |n=80,from=0.0,to=1.0| var valueArray; valueArray = (from,(to-from)/(n-1) .. to).collect{|x| this.value(x) }; ^{ |x| valueArray.blendAt( ((x.clip(from,to)-from)/(to-from))*(n-1) ) } } // embed in ugen graph asUGenInput { arg for; ^this.value(for) } asAudioRateInput { |for| var result = this.value(for); ^if(result.rate != \audio) { K2A.ar(result) } { result } } // convert to control input asControlInput { ^this.value } isValidUGenInput { ^true } } UnaryOpFunction : AbstractFunction { var selector, a; *new { arg selector, a; ^super.newCopyArgs(selector, a) } value { arg ... args; ^a.valueArray(args).perform(selector) } valueArray { arg args; ^a.valueArray(args).perform(selector) } valueEnvir { arg ... args; ^a.valueArrayEnvir(args).perform(selector) } valueArrayEnvir { arg ... args; ^a.valueArrayEnvir(args).perform(selector) } functionPerformList { arg selector, arglist; ^this.performList(selector, arglist) } storeOn { arg stream; stream <<< a << "." << selector; } } BinaryOpFunction : AbstractFunction { var selector, a, b, adverb; *new { arg selector, a, b, adverb; ^super.newCopyArgs(selector, a, b, adverb) } value { arg ... args; ^a.valueArray(args).perform(selector, b.valueArray(args), adverb) } valueArray { arg args; ^a.valueArray(args).perform(selector, b.valueArray(args), adverb) } valueEnvir { arg ... args; ^a.valueArrayEnvir(args).perform(selector, b.valueArrayEnvir(args), adverb) } valueArrayEnvir { arg ... args; ^a.valueArrayEnvir(args).perform(selector, b.valueArrayEnvir(args), adverb) } functionPerformList { arg selector, arglist; ^this.performList(selector, arglist) } storeOn { arg stream; stream << "(" <<< a << " " << selector.asBinOpString; if(adverb.notNil) { stream << "." << adverb }; stream << " " <<< b << ")" } } NAryOpFunction : AbstractFunction { var selector, a, arglist; *new { arg selector, a, arglist; ^super.newCopyArgs(selector, a, arglist) } value { arg ... args; ^a.valueArray(args).performList(selector, arglist.collect(_.valueArray(args))) } valueArray { arg args; ^a.valueArray(args).performList(selector, arglist.collect(_.valueArray(args))) } valueEnvir { arg ... args; ^a.valueArrayEnvir(args).performList(selector, arglist.collect(_.valueArrayEnvir(args))) } valueArrayEnvir { arg ... args; ^a.valueArrayEnvir(args).performList(selector, arglist.collect(_.valueArrayEnvir(args))) } functionPerformList { arg selector, arglist; ^this.performList(selector, arglist) } storeOn { arg stream; stream <<< a << "." << selector << "(" <<<* arglist << ")" } } FunctionList : AbstractFunction { var <>array, handling = false; classvar <>debug = false; classvar <>inProtectedFunction = false; var <>what, <>protectedBacktrace, <>path; *new { arg what; var protectedBacktrace, instance; if (debug || inProtectedFunction, { protectedBacktrace = this.getBackTrace.caller; inProtectedFunction = false; }); ^super.newCopyArgs(what ? this.name, protectedBacktrace, thisProcess.nowExecutingPath); } errorString { ^"EXCEPTION: " ++ what } reportError { this.errorString.postln; if(protectedBacktrace.notNil, { this.postProtectedBacktrace }); this.dumpBackTrace; // this.adviceLink.postln; "^^ The preceding error dump is for %\n".postf(this.errorString); } adviceLink { ^("For advice: [http://supercollider.sf.net/wiki/index.php/%]" .format(this.adviceLinkPage)); } adviceLinkPage { ^this.errorString.tr($ , $_).tr($\n, $_); } postProtectedBacktrace { var out, currentFrame, def, ownerClass, methodName, pos, tempStr; out = CollStream.new; "\nPROTECTED CALL STACK:".postln; currentFrame = protectedBacktrace; while({currentFrame.notNil}, { def = currentFrame.functionDef; if(def.isKindOf(Method), { ownerClass = def.ownerClass; methodName = def.name; if(ownerClass == Function && { #['protect', 'try'].includes(methodName) }, { pos = out.pos; }); out << "\t%:%\t%\n".format(ownerClass, methodName, currentFrame.address); }, { out << "\ta FunctionDef\t%\n".format(currentFrame.address); // sourceCode may be ridiculously huge, // so steal the technique from Object:asString to reduce the printed size tempStr = String.streamContentsLimit({ |stream| stream << "\t\tsourceCode = " <<< (def.sourceCode ? ""); }, 512); out << tempStr; if(tempStr.size >= 512) { out << "...etc..." << $" }; out << Char.nl; }); def.argNames.do({|name, i| out << "\t\targ % = %\n".format(name, currentFrame.args[i]); }); def.varNames.do({|name, i| out << "\t\tvar % = %\n".format(name, currentFrame.vars[i]); }); currentFrame = currentFrame.caller; }); // lose everything after the last Function:protect // it just duplicates the normal stack with less info // but, an Error in a routine in a Scheduler // may not have a try/protect in the protectedBacktrace // then, pos is nil and we should print everything postln( if(pos.notNil) { out.collection.copyFromStart(pos) } { out.collection } ); } isException { ^true } } Error : Exception { errorString { ^"ERROR: " ++ what } errorPathString { ^if(path.isNil) { "" } { "PATH:" + path ++ "\n" } } } MethodError : Error { var <>receiver; *new { arg what, receiver; ^super.new(what).receiver_(receiver) } reportError { this.errorString.postln; "RECEIVER:\n".post; receiver.dump; this.errorPathString.post; if(protectedBacktrace.notNil, { this.postProtectedBacktrace }); this.dumpBackTrace; // this.adviceLink.postln; "^^ The preceding error dump is for %\nRECEIVER: %\n".postf(this.errorString, receiver); } adviceLinkPage { ^this.class.name } } PrimitiveFailedError : MethodError { var <>failedPrimitiveName; *new { arg receiver; ^super.new(Thread.primitiveErrorString, receiver) .failedPrimitiveName_(thisThread.failedPrimitiveName) } errorString { ^"ERROR: Primitive '%' failed.\n%".format(failedPrimitiveName, what ? "") } } SubclassResponsibilityError : MethodError { var <>method, <>class; *new { arg receiver, method, class; ^super.new(nil, receiver).method_(method).class_(class) } errorString { ^"ERROR: '" ++ method.name ++ "' should have been implemented by " ++ class.name ++ "." } } ShouldNotImplementError : MethodError { var <>method, <>class; *new { arg receiver, method, class; ^super.new(nil, receiver).method_(method).class_(class) } errorString { ^"ERROR: '" ++ method.ownerClass.name ++ "-" ++ method.name ++ "' Message not valid for this subclass: " ++ class.name ++ "." } } DoesNotUnderstandError : MethodError { var <>selector, <>args; *new { arg receiver, selector, args; ^super.new(nil, receiver).selector_(selector).args_(args) } errorString { ^"ERROR: Message '" ++ selector ++ "' not understood." } reportError { this.errorString.postln; "RECEIVER:\n".post; receiver.dump; "ARGS:\n".post; args.dumpAll; this.errorPathString.post; if(protectedBacktrace.notNil, { this.postProtectedBacktrace }); this.dumpBackTrace; // this.adviceLink.postln; "^^ The preceding error dump is for %\nRECEIVER: %\n".postf(this.errorString, receiver); } adviceLinkPage { ^"%#%".format(this.class.name, selector) } } MustBeBooleanError : MethodError { errorString { ^"ERROR: Non Boolean in test." } } NotYetImplementedError : MethodError { } OutOfContextReturnError : MethodError { var <>method, <>result; *new { arg receiver, method, result; ^super.new(nil, receiver).method_(method).result_(result) } errorString { ^"ERROR: '" ++ method.ownerClass.name ++ "-" ++ method.name ++ "' Out of context return of value: " ++ result } } ImmutableError : MethodError { var <>value; *new { arg receiver, value; ^super.new(nil, receiver).value_(value) } errorString { ^"ERROR: Object is immutable: " ++ receiver } } BinaryOpFailureError : DoesNotUnderstandError { errorString { ^"ERROR: binary operator '" ++ selector ++ "' failed." } } DeprecatedError : MethodError { var <>method, <>class, <>alternateMethod; *new { arg receiver, method, alternateMethod, class; ^super.new(nil).receiver_(receiver).method_(method).class_(class).alternateMethod_(alternateMethod) } errorString { var methodSignature = { arg m; m.ownerClass.name.asString ++ ":" ++ m.name; }; var searchForCaller = { arg backtrace, m; while { backtrace.notNil and: { backtrace.functionDef !== m } } { backtrace = backtrace.caller; }; // backtrace.caller may now be a FunctionDef, // useless for troubleshooting // so roll back to the last real method while { backtrace.notNil and: { backtrace = backtrace.caller; backtrace.functionDef.isKindOf(Method).not } }; if(backtrace.notNil) { backtrace.tryPerform(\functionDef) }; }; var caller, string; if(protectedBacktrace.notNil) { caller = searchForCaller.value(protectedBacktrace, method); }; if(caller.isNil) { caller = searchForCaller.value(this.getBackTrace, method); }; if(caller.isNil) { caller = "{unknown}" } { if(caller.isKindOf(Method)) { caller = methodSignature.value(caller); } { caller = caller.asString; }; }; string = "WARNING: Called from %, method % is deprecated and will be removed.".format( caller, methodSignature.value(method) ); if(alternateMethod.notNil, { string = string + "Use" + methodSignature.value(alternateMethod) + "instead."; }); ^string; } reportError { this.errorString.postln; this.errorPathString.post; // this.adviceLink.postln; } throw { Error.handling = true; this.reportError; if (Error.debug) { if(protectedBacktrace.notNil, { this.postProtectedBacktrace }); this.dumpBackTrace; Error.handling = false; this.halt; } { Error.handling = false; }; } adviceLinkPage { ^"DeprecatedError" } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/Color.sc0000664000000000000000000011126412245365552025344 0ustar rootrootColor { var <>red, <>green, <>blue, <>alpha; *new { arg red=0.0, green=0.0, blue=0.0, alpha=1.0; ^super.newCopyArgs(red, green, blue, alpha); } *new255 { arg red=0, green=0, blue=0, alpha=255; ^super.newCopyArgs(red/255, green/255, blue/255, alpha/255); } *fromArray { arg array; ^this.new(*array) } *black { ^Color.new(0.0, 0.0, 0.0) } *white { ^Color.new(1.0, 1.0, 1.0) } *red { arg val = 1.0, alpha = 1.0; ^Color.new(min(1,val), max(val-1,0), max(val-1,0), alpha) } *green { arg val = 1.0, alpha = 1.0; ^Color.new(max(val-1,0), min(1,val), max(val-1,0), alpha) } *blue { arg val = 1.0, alpha = 1.0; ^Color.new(max(val-1,0), max(val-1,0), min(1,val), alpha) } *cyan { arg val = 1.0, alpha = 1.0; ^Color.new(max(val-1,0), min(1,val), min(1,val), alpha) } *magenta { arg val = 1.0, alpha = 1.0; ^Color.new(min(1,val), max(val-1,0), min(1,val), alpha) } *yellow { arg val = 1.0, alpha = 1.0; ^Color.new(min(1,val), min(1,val), max(val-1,0), alpha) } *clear { ^Color.new(0.0, 0.0, 0.0, 0.0) } *grey { arg grey = 0.5, alpha = 1.0; ^Color.new(grey, grey, grey, alpha); } *gray { arg gray = 0.5, alpha = 1.0; // synonym ^Color.grey(gray, alpha); } *rand { arg lo=0.3,hi=0.9; ^Color.new(rrand(lo,hi),rrand(lo,hi),rrand(lo,hi)) } == { arg that; ^this.compareObject(that, #[\red, \green, \blue, \alpha]) } hash { ^this.instVarHash(#[\red, \green, \blue, \alpha]) } scaleByAlpha { ^Color.new(red * alpha, green * alpha, blue * alpha, 1.0) } blend { arg that, blend = 0.5; ^Color.fromArray(blend(this.asArray, that.asArray, blend)); } vary { arg val=0.1, lo=0.3, hi=0.9, alphaVal=0; ^Color.new( (red + val.rand2).clip(lo,hi), (green + val.rand2).clip(lo,hi), (blue + val.rand2).clip(lo,hi), (alpha + alphaVal.rand2).clip(0,1) ) } round { arg val=0.01; ^Color.fromArray([red, green, blue].round(val) ++ alpha) } complementary { ^Color.new(1.0 - red, 1.0 - green, 1.0 - blue, alpha) } multiply { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, vals * this.asArray, opacity) ++ alpha) } divide { arg aColor, opacity=1.0; var vals = aColor.asArray, d=0.0001 ! 3; ^Color.fromArray(blend(vals, ((this.asArray + d) / vals).min(1.0), opacity) ++ alpha) } subtract { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, (this.asArray - vals).max(0.0), opacity) ++ alpha) } add { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, (vals + this.asArray).min(1.0), opacity) ++ alpha) } symmetricDifference { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, abs(vals - this.asArray), opacity) ++ alpha) } screen { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, (1-vals) * (1-this.asArray), opacity) ++ alpha) } lighten { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, max(vals, this.asArray), opacity) ++ alpha) } darken { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, min(vals, this.asArray), opacity) ++ alpha) } hueBlend { arg aColor, blend=0.0; var f, b; f = this.asHSV; b = aColor.asHSV; ^Color.hsv(blend(f[0], b[0], blend), b[1], b[2], alpha) } saturationBlend { arg aColor, blend=0.0; var f, b; f = this.asHSV; b = aColor.asHSV; ^Color.hsv(b[0], blend(f[1], b[1], blend), b[2], alpha) } valueBlend { arg aColor, blend=0.0; var f, b; f = this.asHSV; b = aColor.asHSV; ^Color.hsv(b[0], b[1], blend(f[2], b[2], blend), alpha) } *hsv { arg hue, sat, val, alpha=1; var r, g, b, segment, fraction, t1, t2, t3; hue = hue.linlin(0, 1, 0, 360); if( sat == 0 ) { r = g = b = val } { segment = floor( hue/60 )%6; fraction = ( hue/60 - segment ); t1 = val * (1 - sat); t2 = val * (1 - (sat * fraction)); t3 = val * (1 - (sat * (1 - fraction))); if( segment == 0, { r=val; g=t3; b=t1 }); if( segment == 1, { r=t2; g = val; b=t1 }); if( segment == 2, { r=t1; g=val; b=t3 }); if( segment == 3, { r=t1; g=t2; b=val }); if( segment == 4, { r=t3; g=t1; b=val }); if( segment == 5, { r=val; g=t1; b=t2 }); }; //[r, g, b].postln; ^this.new(r, g, b, alpha); } asHSV { var max, min, delta, hue, sat, val; max = [red,green,blue].maxItem; min = [red,green,blue].minItem; delta = max - min; if (red == max, {hue = (green - blue) / delta}); if (green == max, {hue = (blue - red) / delta + 2}); if (blue == max, {hue = (red - green) / delta + 4}); hue = hue/6; if (hue < 0, {hue = hue + 1}); sat = delta / max; val = max; ^[hue, sat, val, alpha] } asArray { ^[red, green, blue, alpha] } printOn { arg stream; var title; stream << this.class.name; this.storeParamsOn(stream); } storeArgs { ^[red,green,blue,alpha] } // FIXME The following GUI redirections are rather ugly. // Shall we make GUI.color instead, and then CocoaColor, SwingColor, QColor etc. ? setStroke { if( GUI.id === \cocoa ) { ^this.cocoaPrSetStroke } { Pen.strokeColor = this; } } setFill { if( GUI.id === \cocoa ) { ^this.cocoaPrSetFill } { Pen.fillColor = this; } } set { this.setStroke.setFill; } hexString { // ignores alpha var hexRed, hexGreen, hexBlue; #hexRed, hexGreen, hexBlue = [red, green, blue] * 255; ^$# ++ hexRed.round.asInteger.asStringToBase(16, 2) ++ hexGreen.round.asInteger.asStringToBase(16, 2) ++ hexBlue.round.asInteger.asStringToBase(16, 2) } *fromHexString {|string| var red, green, blue; if(string[0] == $#, {string = string.copyToEnd(1)}); if(string.size == 3, {string = string[0] ++ string[0] ++ string[1] ++ string[1] ++ string[2] ++ string[2]}); red = ("0x" ++ string.copyRange(0, 1)).interpret; green = ("0x" ++ string.copyRange(2, 3)).interpret; blue = ("0x" ++ string.copyRange(4, 5)).interpret; ^this.new255(red, green, blue, 255); } } /* X-windows colors : ( alice blue: Color.new255(240, 248, 255), AliceBlue: Color.new255(240, 248, 255), antique white: Color.new255(250, 235, 215), AntiqueWhite: Color.new255(250, 235, 215), AntiqueWhite1: Color.new255(255, 239, 219), AntiqueWhite2: Color.new255(238, 223, 204), AntiqueWhite3: Color.new255(205, 192, 176), AntiqueWhite4: Color.new255(139, 131, 120), aquamarine: Color.new255(127, 255, 212), aquamarine1: Color.new255(127, 255, 212), aquamarine2: Color.new255(118, 238, 198), aquamarine3: Color.new255(102, 205, 170), aquamarine4: Color.new255(69, 139, 116), azure: Color.new255(240, 255, 255), azure1: Color.new255(240, 255, 255), azure2: Color.new255(224, 238, 238), azure3: Color.new255(193, 205, 205), azure4: Color.new255(131, 139, 139), beige: Color.new255(245, 245, 220), bisque: Color.new255(255, 228, 196), bisque1: Color.new255(255, 228, 196), bisque2: Color.new255(238, 213, 183), bisque3: Color.new255(205, 183, 158), bisque4: Color.new255(139, 125, 107), black: Color.new255(0, 0, 0), blanched almond: Color.new255(255, 235, 205), BlanchedAlmond: Color.new255(255, 235, 205), blue: Color.new255(0, 0, 255), blue violet: Color.new255(138, 43, 226), blue1: Color.new255(0, 0, 255), blue2: Color.new255(0, 0, 238), blue3: Color.new255(0, 0, 205), blue4: Color.new255(0, 0, 139), BlueViolet: Color.new255(138, 43, 226), brown: Color.new255(165, 42, 42), brown1: Color.new255(255, 64, 64), brown2: Color.new255(238, 59, 59), brown3: Color.new255(205, 51, 51), brown4: Color.new255(139, 35, 35), burlywood: Color.new255(222, 184, 135), burlywood1: Color.new255(255, 211, 155), burlywood2: Color.new255(238, 197, 145), burlywood3: Color.new255(205, 170, 125), burlywood4: Color.new255(139, 115, 85), cadet blue: Color.new255(95, 158, 160), CadetBlue: Color.new255(95, 158, 160), CadetBlue1: Color.new255(152, 245, 255), CadetBlue2: Color.new255(142, 229, 238), CadetBlue3: Color.new255(122, 197, 205), CadetBlue4: Color.new255(83, 134, 139), chartreuse: Color.new255(127, 255, 0), chartreuse1: Color.new255(127, 255, 0), chartreuse2: Color.new255(118, 238, 0), chartreuse3: Color.new255(102, 205, 0), chartreuse4: Color.new255(69, 139, 0), chocolate: Color.new255(210, 105, 30), chocolate1: Color.new255(255, 127, 36), chocolate2: Color.new255(238, 118, 33), chocolate3: Color.new255(205, 102, 29), chocolate4: Color.new255(139, 69, 19), coral: Color.new255(255, 127, 80), coral1: Color.new255(255, 114, 86), coral2: Color.new255(238, 106, 80), coral3: Color.new255(205, 91, 69), coral4: Color.new255(139, 62, 47), cornflower blue: Color.new255(100, 149, 237), CornflowerBlue: Color.new255(100, 149, 237), cornsilk: Color.new255(255, 248, 220), cornsilk1: Color.new255(255, 248, 220), cornsilk2: Color.new255(238, 232, 205), cornsilk3: Color.new255(205, 200, 177), cornsilk4: Color.new255(139, 136, 120), cyan: Color.new255(0, 255, 255), cyan1: Color.new255(0, 255, 255), cyan2: Color.new255(0, 238, 238), cyan3: Color.new255(0, 205, 205), cyan4: Color.new255(0, 139, 139), dark goldenrod: Color.new255(184, 134, 11), dark green: Color.new255(0, 100, 0), dark khaki: Color.new255(189, 183, 107), dark olive green: Color.new255(85, 107, 47), dark orange: Color.new255(255, 140, 0), dark orchid: Color.new255(153, 50, 204), dark salmon: Color.new255(233, 150, 122), dark sea green: Color.new255(143, 188, 143), dark slate blue: Color.new255(72, 61, 139), dark slate gray: Color.new255(47, 79, 79), dark slate grey: Color.new255(47, 79, 79), dark turquoise: Color.new255(0, 206, 209), dark violet: Color.new255(148, 0, 211), DarkGoldenrod: Color.new255(184, 134, 11), DarkGoldenrod1: Color.new255(255, 185, 15), DarkGoldenrod2: Color.new255(238, 173, 14), DarkGoldenrod3: Color.new255(205, 149, 12), DarkGoldenrod4: Color.new255(139, 101, 8), DarkGreen: Color.new255(0, 100, 0), DarkKhaki: Color.new255(189, 183, 107), DarkOliveGreen: Color.new255(85, 107, 47), DarkOliveGreen1: Color.new255(202, 255, 112), DarkOliveGreen2: Color.new255(188, 238, 104), DarkOliveGreen3: Color.new255(162, 205, 90), DarkOliveGreen4: Color.new255(110, 139, 61), DarkOrange: Color.new255(255, 140, 0), DarkOrange1: Color.new255(255, 127, 0), DarkOrange2: Color.new255(238, 118, 0), DarkOrange3: Color.new255(205, 102, 0), DarkOrange4: Color.new255(139, 69, 0), DarkOrchid: Color.new255(153, 50, 204), DarkOrchid1: Color.new255(191, 62, 255), DarkOrchid2: Color.new255(178, 58, 238), DarkOrchid3: Color.new255(154, 50, 205), DarkOrchid4: Color.new255(104, 34, 139), DarkSalmon: Color.new255(233, 150, 122), DarkSeaGreen: Color.new255(143, 188, 143), DarkSeaGreen1: Color.new255(193, 255, 193), DarkSeaGreen2: Color.new255(180, 238, 180), DarkSeaGreen3: Color.new255(155, 205, 155), DarkSeaGreen4: Color.new255(105, 139, 105), DarkSlateBlue: Color.new255(72, 61, 139), DarkSlateGray: Color.new255(47, 79, 79), DarkSlateGray1: Color.new255(151, 255, 255), DarkSlateGray2: Color.new255(141, 238, 238), DarkSlateGray3: Color.new255(121, 205, 205), DarkSlateGray4: Color.new255(82, 139, 139), DarkSlateGrey: Color.new255(47, 79, 79), DarkTurquoise: Color.new255(0, 206, 209), DarkViolet: Color.new255(148, 0, 211), deep pink: Color.new255(255, 20, 147), deep sky blue: Color.new255(0, 191, 255), DeepPink: Color.new255(255, 20, 147), DeepPink1: Color.new255(255, 20, 147), DeepPink2: Color.new255(238, 18, 137), DeepPink3: Color.new255(205, 16, 118), DeepPink4: Color.new255(139, 10, 80), DeepSkyBlue: Color.new255(0, 191, 255), DeepSkyBlue1: Color.new255(0, 191, 255), DeepSkyBlue2: Color.new255(0, 178, 238), DeepSkyBlue3: Color.new255(0, 154, 205), DeepSkyBlue4: Color.new255(0, 104, 139), dim gray: Color.new255(105, 105, 105), dim grey: Color.new255(105, 105, 105), DimGray: Color.new255(105, 105, 105), DimGrey: Color.new255(105, 105, 105), dodger blue: Color.new255(30, 144, 255), DodgerBlue: Color.new255(30, 144, 255), DodgerBlue1: Color.new255(30, 144, 255), DodgerBlue2: Color.new255(28, 134, 238), DodgerBlue3: Color.new255(24, 116, 205), DodgerBlue4: Color.new255(16, 78, 139), firebrick: Color.new255(178, 34, 34), firebrick1: Color.new255(255, 48, 48), firebrick2: Color.new255(238, 44, 44), firebrick3: Color.new255(205, 38, 38), firebrick4: Color.new255(139, 26, 26), floral white: Color.new255(255, 250, 240), FloralWhite: Color.new255(255, 250, 240), forest green: Color.new255(34, 139, 34), ForestGreen: Color.new255(34, 139, 34), gainsboro: Color.new255(220, 220, 220), ghost white: Color.new255(248, 248, 255), GhostWhite: Color.new255(248, 248, 255), gold: Color.new255(255, 215, 0), gold1: Color.new255(255, 215, 0), gold2: Color.new255(238, 201, 0), gold3: Color.new255(205, 173, 0), gold4: Color.new255(139, 117, 0), goldenrod: Color.new255(218, 165, 32), goldenrod1: Color.new255(255, 193, 37), goldenrod2: Color.new255(238, 180, 34), goldenrod3: Color.new255(205, 155, 29), goldenrod4: Color.new255(139, 105, 20), gray: Color.new255(190, 190, 190), gray0: Color.new255(0, 0, 0), gray1: Color.new255(3, 3, 3), gray10: Color.new255(26, 26, 26), gray100: Color.new255(255, 255, 255), gray11: Color.new255(28, 28, 28), gray12: Color.new255(31, 31, 31), gray13: Color.new255(33, 33, 33), gray14: Color.new255(36, 36, 36), gray15: Color.new255(38, 38, 38), gray16: Color.new255(41, 41, 41), gray17: Color.new255(43, 43, 43), gray18: Color.new255(46, 46, 46), gray19: Color.new255(48, 48, 48), gray2: Color.new255(5, 5, 5), gray20: Color.new255(51, 51, 51), gray21: Color.new255(54, 54, 54), gray22: Color.new255(56, 56, 56), gray23: Color.new255(59, 59, 59), gray24: Color.new255(61, 61, 61), gray25: Color.new255(64, 64, 64), gray26: Color.new255(66, 66, 66), gray27: Color.new255(69, 69, 69), gray28: Color.new255(71, 71, 71), gray29: Color.new255(74, 74, 74), gray3: Color.new255(8, 8, 8), gray30: Color.new255(77, 77, 77), gray31: Color.new255(79, 79, 79), gray32: Color.new255(82, 82, 82), gray33: Color.new255(84, 84, 84), gray34: Color.new255(87, 87, 87), gray35: Color.new255(89, 89, 89), gray36: Color.new255(92, 92, 92), gray37: Color.new255(94, 94, 94), gray38: Color.new255(97, 97, 97), gray39: Color.new255(99, 99, 99), gray4: Color.new255(10, 10, 10), gray40: Color.new255(102, 102, 102), gray41: Color.new255(105, 105, 105), gray42: Color.new255(107, 107, 107), gray43: Color.new255(110, 110, 110), gray44: Color.new255(112, 112, 112), gray45: Color.new255(115, 115, 115), gray46: Color.new255(117, 117, 117), gray47: Color.new255(120, 120, 120), gray48: Color.new255(122, 122, 122), gray49: Color.new255(125, 125, 125), gray5: Color.new255(13, 13, 13), gray50: Color.new255(127, 127, 127), gray51: Color.new255(130, 130, 130), gray52: Color.new255(133, 133, 133), gray53: Color.new255(135, 135, 135), gray54: Color.new255(138, 138, 138), gray55: Color.new255(140, 140, 140), gray56: Color.new255(143, 143, 143), gray57: Color.new255(145, 145, 145), gray58: Color.new255(148, 148, 148), gray59: Color.new255(150, 150, 150), gray6: Color.new255(15, 15, 15), gray60: Color.new255(153, 153, 153), gray61: Color.new255(156, 156, 156), gray62: Color.new255(158, 158, 158), gray63: Color.new255(161, 161, 161), gray64: Color.new255(163, 163, 163), gray65: Color.new255(166, 166, 166), gray66: Color.new255(168, 168, 168), gray67: Color.new255(171, 171, 171), gray68: Color.new255(173, 173, 173), gray69: Color.new255(176, 176, 176), gray7: Color.new255(18, 18, 18), gray70: Color.new255(179, 179, 179), gray71: Color.new255(181, 181, 181), gray72: Color.new255(184, 184, 184), gray73: Color.new255(186, 186, 186), gray74: Color.new255(189, 189, 189), gray75: Color.new255(191, 191, 191), gray76: Color.new255(194, 194, 194), gray77: Color.new255(196, 196, 196), gray78: Color.new255(199, 199, 199), gray79: Color.new255(201, 201, 201), gray8: Color.new255(20, 20, 20), gray80: Color.new255(204, 204, 204), gray81: Color.new255(207, 207, 207), gray82: Color.new255(209, 209, 209), gray83: Color.new255(212, 212, 212), gray84: Color.new255(214, 214, 214), gray85: Color.new255(217, 217, 217), gray86: Color.new255(219, 219, 219), gray87: Color.new255(222, 222, 222), gray88: Color.new255(224, 224, 224), gray89: Color.new255(227, 227, 227), gray9: Color.new255(23, 23, 23), gray90: Color.new255(229, 229, 229), gray91: Color.new255(232, 232, 232), gray92: Color.new255(235, 235, 235), gray93: Color.new255(237, 237, 237), gray94: Color.new255(240, 240, 240), gray95: Color.new255(242, 242, 242), gray96: Color.new255(245, 245, 245), gray97: Color.new255(247, 247, 247), gray98: Color.new255(250, 250, 250), gray99: Color.new255(252, 252, 252), green: Color.new255(0, 255, 0), green yellow: Color.new255(173, 255, 47), green1: Color.new255(0, 255, 0), green2: Color.new255(0, 238, 0), green3: Color.new255(0, 205, 0), green4: Color.new255(0, 139, 0), GreenYellow: Color.new255(173, 255, 47), grey: Color.new255(190, 190, 190), grey0: Color.new255(0, 0, 0), grey1: Color.new255(3, 3, 3), grey10: Color.new255(26, 26, 26), grey100: Color.new255(255, 255, 255), grey11: Color.new255(28, 28, 28), grey12: Color.new255(31, 31, 31), grey13: Color.new255(33, 33, 33), grey14: Color.new255(36, 36, 36), grey15: Color.new255(38, 38, 38), grey16: Color.new255(41, 41, 41), grey17: Color.new255(43, 43, 43), grey18: Color.new255(46, 46, 46), grey19: Color.new255(48, 48, 48), grey2: Color.new255(5, 5, 5), grey20: Color.new255(51, 51, 51), grey21: Color.new255(54, 54, 54), grey22: Color.new255(56, 56, 56), grey23: Color.new255(59, 59, 59), grey24: Color.new255(61, 61, 61), grey25: Color.new255(64, 64, 64), grey26: Color.new255(66, 66, 66), grey27: Color.new255(69, 69, 69), grey28: Color.new255(71, 71, 71), grey29: Color.new255(74, 74, 74), grey3: Color.new255(8, 8, 8), grey30: Color.new255(77, 77, 77), grey31: Color.new255(79, 79, 79), grey32: Color.new255(82, 82, 82), grey33: Color.new255(84, 84, 84), grey34: Color.new255(87, 87, 87), grey35: Color.new255(89, 89, 89), grey36: Color.new255(92, 92, 92), grey37: Color.new255(94, 94, 94), grey38: Color.new255(97, 97, 97), grey39: Color.new255(99, 99, 99), grey4: Color.new255(10, 10, 10), grey40: Color.new255(102, 102, 102), grey41: Color.new255(105, 105, 105), grey42: Color.new255(107, 107, 107), grey43: Color.new255(110, 110, 110), grey44: Color.new255(112, 112, 112), grey45: Color.new255(115, 115, 115), grey46: Color.new255(117, 117, 117), grey47: Color.new255(120, 120, 120), grey48: Color.new255(122, 122, 122), grey49: Color.new255(125, 125, 125), grey5: Color.new255(13, 13, 13), grey50: Color.new255(127, 127, 127), grey51: Color.new255(130, 130, 130), grey52: Color.new255(133, 133, 133), grey53: Color.new255(135, 135, 135), grey54: Color.new255(138, 138, 138), grey55: Color.new255(140, 140, 140), grey56: Color.new255(143, 143, 143), grey57: Color.new255(145, 145, 145), grey58: Color.new255(148, 148, 148), grey59: Color.new255(150, 150, 150), grey6: Color.new255(15, 15, 15), grey60: Color.new255(153, 153, 153), grey61: Color.new255(156, 156, 156), grey62: Color.new255(158, 158, 158), grey63: Color.new255(161, 161, 161), grey64: Color.new255(163, 163, 163), grey65: Color.new255(166, 166, 166), grey66: Color.new255(168, 168, 168), grey67: Color.new255(171, 171, 171), grey68: Color.new255(173, 173, 173), grey69: Color.new255(176, 176, 176), grey7: Color.new255(18, 18, 18), grey70: Color.new255(179, 179, 179), grey71: Color.new255(181, 181, 181), grey72: Color.new255(184, 184, 184), grey73: Color.new255(186, 186, 186), grey74: Color.new255(189, 189, 189), grey75: Color.new255(191, 191, 191), grey76: Color.new255(194, 194, 194), grey77: Color.new255(196, 196, 196), grey78: Color.new255(199, 199, 199), grey79: Color.new255(201, 201, 201), grey8: Color.new255(20, 20, 20), grey80: Color.new255(204, 204, 204), grey81: Color.new255(207, 207, 207), grey82: Color.new255(209, 209, 209), grey83: Color.new255(212, 212, 212), grey84: Color.new255(214, 214, 214), grey85: Color.new255(217, 217, 217), grey86: Color.new255(219, 219, 219), grey87: Color.new255(222, 222, 222), grey88: Color.new255(224, 224, 224), grey89: Color.new255(227, 227, 227), grey9: Color.new255(23, 23, 23), grey90: Color.new255(229, 229, 229), grey91: Color.new255(232, 232, 232), grey92: Color.new255(235, 235, 235), grey93: Color.new255(237, 237, 237), grey94: Color.new255(240, 240, 240), grey95: Color.new255(242, 242, 242), grey96: Color.new255(245, 245, 245), grey97: Color.new255(247, 247, 247), grey98: Color.new255(250, 250, 250), grey99: Color.new255(252, 252, 252), honeydew: Color.new255(240, 255, 240), honeydew1: Color.new255(240, 255, 240), honeydew2: Color.new255(224, 238, 224), honeydew3: Color.new255(193, 205, 193), honeydew4: Color.new255(131, 139, 131), hot pink: Color.new255(255, 105, 180), HotPink: Color.new255(255, 105, 180), HotPink1: Color.new255(255, 110, 180), HotPink2: Color.new255(238, 106, 167), HotPink3: Color.new255(205, 96, 144), HotPink4: Color.new255(139, 58, 98), indian red: Color.new255(205, 92, 92), IndianRed: Color.new255(205, 92, 92), IndianRed1: Color.new255(255, 106, 106), IndianRed2: Color.new255(238, 99, 99), IndianRed3: Color.new255(205, 85, 85), IndianRed4: Color.new255(139, 58, 58), ivory: Color.new255(255, 255, 240), ivory1: Color.new255(255, 255, 240), ivory2: Color.new255(238, 238, 224), ivory3: Color.new255(205, 205, 193), ivory4: Color.new255(139, 139, 131), khaki: Color.new255(240, 230, 140), khaki1: Color.new255(255, 246, 143), khaki2: Color.new255(238, 230, 133), khaki3: Color.new255(205, 198, 115), khaki4: Color.new255(139, 134, 78), lavender: Color.new255(230, 230, 250), lavender blush: Color.new255(255, 240, 245), LavenderBlush: Color.new255(255, 240, 245), LavenderBlush1: Color.new255(255, 240, 245), LavenderBlush2: Color.new255(238, 224, 229), LavenderBlush3: Color.new255(205, 193, 197), LavenderBlush4: Color.new255(139, 131, 134), lawn green: Color.new255(124, 252, 0), LawnGreen: Color.new255(124, 252, 0), lemon chiffon: Color.new255(255, 250, 205), LemonChiffon: Color.new255(255, 250, 205), LemonChiffon1: Color.new255(255, 250, 205), LemonChiffon2: Color.new255(238, 233, 191), LemonChiffon3: Color.new255(205, 201, 165), LemonChiffon4: Color.new255(139, 137, 112), light blue: Color.new255(173, 216, 230), light coral: Color.new255(240, 128, 128), light cyan: Color.new255(224, 255, 255), light goldenrod: Color.new255(238, 221, 130), light goldenrod yellow: Color.new255(250, 250, 210), light gray: Color.new255(211, 211, 211), light grey: Color.new255(211, 211, 211), light pink: Color.new255(255, 182, 193), light salmon: Color.new255(255, 160, 122), light sea green: Color.new255(32, 178, 170), light sky blue: Color.new255(135, 206, 250), light slate blue: Color.new255(132, 112, 255), light slate gray: Color.new255(119, 136, 153), light slate grey: Color.new255(119, 136, 153), light steel blue: Color.new255(176, 196, 222), light yellow: Color.new255(255, 255, 224), LightBlue: Color.new255(173, 216, 230), LightBlue1: Color.new255(191, 239, 255), LightBlue2: Color.new255(178, 223, 238), LightBlue3: Color.new255(154, 192, 205), LightBlue4: Color.new255(104, 131, 139), LightCoral: Color.new255(240, 128, 128), LightCyan: Color.new255(224, 255, 255), LightCyan1: Color.new255(224, 255, 255), LightCyan2: Color.new255(209, 238, 238), LightCyan3: Color.new255(180, 205, 205), LightCyan4: Color.new255(122, 139, 139), LightGoldenrod: Color.new255(238, 221, 130), LightGoldenrod1: Color.new255(255, 236, 139), LightGoldenrod2: Color.new255(238, 220, 130), LightGoldenrod3: Color.new255(205, 190, 112), LightGoldenrod4: Color.new255(139, 129, 76), LightGoldenrodYellow: Color.new255(250, 250, 210), LightGray: Color.new255(211, 211, 211), LightGrey: Color.new255(211, 211, 211), LightPink: Color.new255(255, 182, 193), LightPink1: Color.new255(255, 174, 185), LightPink2: Color.new255(238, 162, 173), LightPink3: Color.new255(205, 140, 149), LightPink4: Color.new255(139, 95, 101), LightSalmon: Color.new255(255, 160, 122), LightSalmon1: Color.new255(255, 160, 122), LightSalmon2: Color.new255(238, 149, 114), LightSalmon3: Color.new255(205, 129, 98), LightSalmon4: Color.new255(139, 87, 66), LightSeaGreen: Color.new255(32, 178, 170), LightSkyBlue: Color.new255(135, 206, 250), LightSkyBlue1: Color.new255(176, 226, 255), LightSkyBlue2: Color.new255(164, 211, 238), LightSkyBlue3: Color.new255(141, 182, 205), LightSkyBlue4: Color.new255(96, 123, 139), LightSlateBlue: Color.new255(132, 112, 255), LightSlateGray: Color.new255(119, 136, 153), LightSlateGrey: Color.new255(119, 136, 153), LightSteelBlue: Color.new255(176, 196, 222), LightSteelBlue1: Color.new255(202, 225, 255), LightSteelBlue2: Color.new255(188, 210, 238), LightSteelBlue3: Color.new255(162, 181, 205), LightSteelBlue4: Color.new255(110, 123, 139), LightYellow: Color.new255(255, 255, 224), LightYellow1: Color.new255(255, 255, 224), LightYellow2: Color.new255(238, 238, 209), LightYellow3: Color.new255(205, 205, 180), LightYellow4: Color.new255(139, 139, 122), lime green: Color.new255(50, 205, 50), LimeGreen: Color.new255(50, 205, 50), linen: Color.new255(250, 240, 230), magenta: Color.new255(255, 0, 255), magenta1: Color.new255(255, 0, 255), magenta2: Color.new255(238, 0, 238), magenta3: Color.new255(205, 0, 205), magenta4: Color.new255(139, 0, 139), maroon: Color.new255(176, 48, 96), maroon1: Color.new255(255, 52, 179), maroon2: Color.new255(238, 48, 167), maroon3: Color.new255(205, 41, 144), maroon4: Color.new255(139, 28, 98), medium aquamarine: Color.new255(102, 205, 170), medium blue: Color.new255(0, 0, 205), medium orchid: Color.new255(186, 85, 211), medium purple: Color.new255(147, 112, 219), medium sea green: Color.new255(60, 179, 113), medium slate blue: Color.new255(123, 104, 238), medium spring green: Color.new255(0, 250, 154), medium turquoise: Color.new255(72, 209, 204), medium violet red: Color.new255(199, 21, 133), MediumAquamarine: Color.new255(102, 205, 170), MediumBlue: Color.new255(0, 0, 205), MediumOrchid: Color.new255(186, 85, 211), MediumOrchid1: Color.new255(224, 102, 255), MediumOrchid2: Color.new255(209, 95, 238), MediumOrchid3: Color.new255(180, 82, 205), MediumOrchid4: Color.new255(122, 55, 139), MediumPurple: Color.new255(147, 112, 219), MediumPurple1: Color.new255(171, 130, 255), MediumPurple2: Color.new255(159, 121, 238), MediumPurple3: Color.new255(137, 104, 205), MediumPurple4: Color.new255(93, 71, 139), MediumSeaGreen: Color.new255(60, 179, 113), MediumSlateBlue: Color.new255(123, 104, 238), MediumSpringGreen: Color.new255(0, 250, 154), MediumTurquoise: Color.new255(72, 209, 204), MediumVioletRed: Color.new255(199, 21, 133), midnight blue: Color.new255(25, 25, 112), MidnightBlue: Color.new255(25, 25, 112), mint cream: Color.new255(245, 255, 250), MintCream: Color.new255(245, 255, 250), misty rose: Color.new255(255, 228, 225), MistyRose: Color.new255(255, 228, 225), MistyRose1: Color.new255(255, 228, 225), MistyRose2: Color.new255(238, 213, 210), MistyRose3: Color.new255(205, 183, 181), MistyRose4: Color.new255(139, 125, 123), moccasin: Color.new255(255, 228, 181), navajo white: Color.new255(255, 222, 173), NavajoWhite: Color.new255(255, 222, 173), NavajoWhite1: Color.new255(255, 222, 173), NavajoWhite2: Color.new255(238, 207, 161), NavajoWhite3: Color.new255(205, 179, 139), NavajoWhite4: Color.new255(139, 121, 94), navy: Color.new255(0, 0, 128), navy blue: Color.new255(0, 0, 128), NavyBlue: Color.new255(0, 0, 128), old lace: Color.new255(253, 245, 230), OldLace: Color.new255(253, 245, 230), olive drab: Color.new255(107, 142, 35), OliveDrab: Color.new255(107, 142, 35), OliveDrab1: Color.new255(192, 255, 62), OliveDrab2: Color.new255(179, 238, 58), OliveDrab3: Color.new255(154, 205, 50), OliveDrab4: Color.new255(105, 139, 34), orange: Color.new255(255, 165, 0), orange red: Color.new255(255, 69, 0), orange1: Color.new255(255, 165, 0), orange2: Color.new255(238, 154, 0), orange3: Color.new255(205, 133, 0), orange4: Color.new255(139, 90, 0), OrangeRed: Color.new255(255, 69, 0), OrangeRed1: Color.new255(255, 69, 0), OrangeRed2: Color.new255(238, 64, 0), OrangeRed3: Color.new255(205, 55, 0), OrangeRed4: Color.new255(139, 37, 0), orchid: Color.new255(218, 112, 214), orchid1: Color.new255(255, 131, 250), orchid2: Color.new255(238, 122, 233), orchid3: Color.new255(205, 105, 201), orchid4: Color.new255(139, 71, 137), pale goldenrod: Color.new255(238, 232, 170), pale green: Color.new255(152, 251, 152), pale turquoise: Color.new255(175, 238, 238), pale violet red: Color.new255(219, 112, 147), PaleGoldenrod: Color.new255(238, 232, 170), PaleGreen: Color.new255(152, 251, 152), PaleGreen1: Color.new255(154, 255, 154), PaleGreen2: Color.new255(144, 238, 144), PaleGreen3: Color.new255(124, 205, 124), PaleGreen4: Color.new255(84, 139, 84), PaleTurquoise: Color.new255(175, 238, 238), PaleTurquoise1: Color.new255(187, 255, 255), PaleTurquoise2: Color.new255(174, 238, 238), PaleTurquoise3: Color.new255(150, 205, 205), PaleTurquoise4: Color.new255(102, 139, 139), PaleVioletRed: Color.new255(219, 112, 147), PaleVioletRed1: Color.new255(255, 130, 171), PaleVioletRed2: Color.new255(238, 121, 159), PaleVioletRed3: Color.new255(205, 104, 137), PaleVioletRed4: Color.new255(139, 71, 93), papaya whip: Color.new255(255, 239, 213), PapayaWhip: Color.new255(255, 239, 213), peach puff: Color.new255(255, 218, 185), PeachPuff: Color.new255(255, 218, 185), PeachPuff1: Color.new255(255, 218, 185), PeachPuff2: Color.new255(238, 203, 173), PeachPuff3: Color.new255(205, 175, 149), PeachPuff4: Color.new255(139, 119, 101), peru: Color.new255(205, 133, 63), pink: Color.new255(255, 192, 203), pink1: Color.new255(255, 181, 197), pink2: Color.new255(238, 169, 184), pink3: Color.new255(205, 145, 158), pink4: Color.new255(139, 99, 108), plum: Color.new255(221, 160, 221), plum1: Color.new255(255, 187, 255), plum2: Color.new255(238, 174, 238), plum3: Color.new255(205, 150, 205), plum4: Color.new255(139, 102, 139), powder blue: Color.new255(176, 224, 230), PowderBlue: Color.new255(176, 224, 230), purple: Color.new255(160, 32, 240), purple1: Color.new255(155, 48, 255), purple2: Color.new255(145, 44, 238), purple3: Color.new255(125, 38, 205), purple4: Color.new255(85, 26, 139), red: Color.new255(255, 0, 0), red1: Color.new255(255, 0, 0), red2: Color.new255(238, 0, 0), red3: Color.new255(205, 0, 0), red4: Color.new255(139, 0, 0), rosy brown: Color.new255(188, 143, 143), RosyBrown: Color.new255(188, 143, 143), RosyBrown1: Color.new255(255, 193, 193), RosyBrown2: Color.new255(238, 180, 180), RosyBrown3: Color.new255(205, 155, 155), RosyBrown4: Color.new255(139, 105, 105), royal blue: Color.new255(65, 105, 225), RoyalBlue: Color.new255(65, 105, 225), RoyalBlue1: Color.new255(72, 118, 255), RoyalBlue2: Color.new255(67, 110, 238), RoyalBlue3: Color.new255(58, 95, 205), RoyalBlue4: Color.new255(39, 64, 139), saddle brown: Color.new255(139, 69, 19), SaddleBrown: Color.new255(139, 69, 19), salmon: Color.new255(250, 128, 114), salmon1: Color.new255(255, 140, 105), salmon2: Color.new255(238, 130, 98), salmon3: Color.new255(205, 112, 84), salmon4: Color.new255(139, 76, 57), sandy brown: Color.new255(244, 164, 96), SandyBrown: Color.new255(244, 164, 96), sea green: Color.new255(46, 139, 87), SeaGreen: Color.new255(46, 139, 87), SeaGreen1: Color.new255(84, 255, 159), SeaGreen2: Color.new255(78, 238, 148), SeaGreen3: Color.new255(67, 205, 128), SeaGreen4: Color.new255(46, 139, 87), seashell: Color.new255(255, 245, 238), seashell1: Color.new255(255, 245, 238), seashell2: Color.new255(238, 229, 222), seashell3: Color.new255(205, 197, 191), seashell4: Color.new255(139, 134, 130), sienna: Color.new255(160, 82, 45), sienna1: Color.new255(255, 130, 71), sienna2: Color.new255(238, 121, 66), sienna3: Color.new255(205, 104, 57), sienna4: Color.new255(139, 71, 38), sky blue: Color.new255(135, 206, 235), SkyBlue: Color.new255(135, 206, 235), SkyBlue1: Color.new255(135, 206, 255), SkyBlue2: Color.new255(126, 192, 238), SkyBlue3: Color.new255(108, 166, 205), SkyBlue4: Color.new255(74, 112, 139), slate blue: Color.new255(106, 90, 205), slate gray: Color.new255(112, 128, 144), slate grey: Color.new255(112, 128, 144), SlateBlue: Color.new255(106, 90, 205), SlateBlue1: Color.new255(131, 111, 255), SlateBlue2: Color.new255(122, 103, 238), SlateBlue3: Color.new255(105, 89, 205), SlateBlue4: Color.new255(71, 60, 139), SlateGray: Color.new255(112, 128, 144), SlateGray1: Color.new255(198, 226, 255), SlateGray2: Color.new255(185, 211, 238), SlateGray3: Color.new255(159, 182, 205), SlateGray4: Color.new255(108, 123, 139), SlateGrey: Color.new255(112, 128, 144), snow: Color.new255(255, 250, 250), snow1: Color.new255(255, 250, 250), snow2: Color.new255(238, 233, 233), snow3: Color.new255(205, 201, 201), snow4: Color.new255(139, 137, 137), spring green: Color.new255(0, 255, 127), SpringGreen: Color.new255(0, 255, 127), SpringGreen1: Color.new255(0, 255, 127), SpringGreen2: Color.new255(0, 238, 118), SpringGreen3: Color.new255(0, 205, 102), SpringGreen4: Color.new255(0, 139, 69), steel blue: Color.new255(70, 130, 180), SteelBlue: Color.new255(70, 130, 180), SteelBlue1: Color.new255(99, 184, 255), SteelBlue2: Color.new255(92, 172, 238), SteelBlue3: Color.new255(79, 148, 205), SteelBlue4: Color.new255(54, 100, 139), tan: Color.new255(210, 180, 140), tan1: Color.new255(255, 165, 79), tan2: Color.new255(238, 154, 73), tan3: Color.new255(205, 133, 63), tan4: Color.new255(139, 90, 43), thistle: Color.new255(216, 191, 216), thistle1: Color.new255(255, 225, 255), thistle2: Color.new255(238, 210, 238), thistle3: Color.new255(205, 181, 205), thistle4: Color.new255(139, 123, 139), tomato: Color.new255(255, 99, 71), tomato1: Color.new255(255, 99, 71), tomato2: Color.new255(238, 92, 66), tomato3: Color.new255(205, 79, 57), tomato4: Color.new255(139, 54, 38), turquoise: Color.new255(64, 224, 208), turquoise1: Color.new255(0, 245, 255), turquoise2: Color.new255(0, 229, 238), turquoise3: Color.new255(0, 197, 205), turquoise4: Color.new255(0, 134, 139), violet: Color.new255(238, 130, 238), violet red: Color.new255(208, 32, 144), VioletRed: Color.new255(208, 32, 144), VioletRed1: Color.new255(255, 62, 150), VioletRed2: Color.new255(238, 58, 140), VioletRed3: Color.new255(205, 50, 120), VioletRed4: Color.new255(139, 34, 82), wheat: Color.new255(245, 222, 179), wheat1: Color.new255(255, 231, 186), wheat2: Color.new255(238, 216, 174), wheat3: Color.new255(205, 186, 150), wheat4: Color.new255(139, 126, 102), white: Color.new255(255, 255, 255), white smoke: Color.new255(245, 245, 245), WhiteSmoke: Color.new255(245, 245, 245), yellow: Color.new255(255, 255, 0), yellow green: Color.new255(154, 205, 50), yellow1: Color.new255(255, 255, 0), yellow2: Color.new255(238, 238, 0), yellow3: Color.new255(205, 205, 0), yellow4: Color.new255(139, 139, 0), YellowGreen: Color.new255(154, 205, 50) ); */ SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/Finalize.sc0000664000000000000000000000166112014636263026020 0ustar rootroot/* Finalization is a way for the C primitives to release resources back to the system. Rather than having a very complex system where any object can be finalized, I have decided to centralize finalization in one class. This makes handling it in the garbage collector very efficient. Any class that needs finalizable data should create and point to an instance of this class and put the data into it. This should be done from a primitive. When the garbage collector collects this object it will call the C function you stored in cFunction with this object as the parameter. You can also call the finalize method to finalize on demand. You should put your C function pointer into cFunction, and the finalizable object into 'object'. */ Finalizer { var cFunction, object; // no getters or setters! // no *new method! Create in a primitive. //finalize { _Finalize } notFinalized { ^cFunction.notNil } isFinalized { ^cFunction.isNil } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/Thread.sc0000664000000000000000000000720112161364457025470 0ustar rootroot// you must not make any change at all to the order or number of // instance variables in these classes! // You should also not muck with the contents of the instance // variables unless you are sure you know what you are doing. // You may add methods. // Thread inherits from Stream for the benefit of its subclass Routine which can // behave like a Stream. Thread itself is not used like a Stream. Thread : Stream { var endBeat, <>endValue; var environment; var <>exceptionHandler, >threadPlayer; var 1) { forBy(1, queue.size-1, 3) {|i| queue[i+1].removedFromScheduler }; }; this.prClear; } *sched { arg delta, item; _SystemClock_Sched ^this.primitiveFailed } *schedAbs { arg time, item; _SystemClock_SchedAbs ^this.primitiveFailed } *prClear { _SystemClock_Clear ^this.primitiveFailed } } AppClock : Clock { classvar scheduler; *initClass { scheduler = Scheduler.new(this, drift:true, recursive:false); } *clear { scheduler.clear; } *sched { arg delta, item; scheduler.sched(delta, item); this.prSchedNotify; } *tick { var saveClock = thisThread.clock; thisThread.clock = this; scheduler.seconds = Main.elapsedTime; thisThread.clock = saveClock; ^scheduler.queue.topPriority; } *prSchedNotify { // notify clients that something has been scheduled _AppClock_SchedNotify } } Scheduler { var clock, drift, <>recursive, beats = 0.0, default; var permanent=false; /* You should only change the tempo 'now'. You can't set the tempo at some beat in the future or past, even though you might think so from the methods. There are several ideas of now: elapsed time, i.e. "real time" logical time in the current time base. logical time in another time base. logical time is time that is incremented by exact amounts from the time you started. It is not affected by the actual time your task gets scheduled, which may shift around somewhat due to system load. By calculating using logical time instead of actual time, your process will not drift out of sync over long periods. every thread stores a clock and its current logical time in seconds and beats relative to that clock. elapsed time is whatever the system clock says it is right now. elapsed time is always advancing. logical time only advances when your task yields or returns. */ *new { arg tempo, beats, seconds, queueSize=256; ^super.new.init(tempo, beats, seconds, queueSize) } *initClass { default = this.new(queueSize: 2048).permanent_(true); CmdPeriod.add(this); } *cmdPeriod { all.do({ arg item; item.clear(false) }); // copy is important: You must never iterate over the same // collection from which you're removing items all.copy.do({ arg item; if (item.permanent.not, { item.stop }) }) } init { arg tempo, beats, seconds, queueSize; queue = Array.new(queueSize); this.prStart(tempo, beats, seconds); all = all.add(this); } stop { this.changed(\stop); this.releaseDependants; all.take(this); this.prStop; } play { arg task, quant = 1; this.schedAbs(quant.nextTimeOnGrid(this), task) } playNextBar { arg task; this.schedAbs(this.nextBar, task) } tempo { _TempoClock_Tempo ^this.primitiveFailed } beatDur { _TempoClock_BeatDur ^this.primitiveFailed } elapsedBeats { _TempoClock_ElapsedBeats ^this.primitiveFailed /* primitive does this: ^this.secs2beats(Main.elapsedTime). */ } beats { // returns the appropriate beats for this clock from any thread _TempoClock_Beats ^this.primitiveFailed /* primitive does this: if (thisThread.clock == this) { ^thisThread.beats } ^this.secs2beats(thisThread.seconds) */ } seconds { ^thisThread.seconds } sched { arg delta, item; _TempoClock_Sched ^this.primitiveFailed } schedAbs { arg beat, item; _TempoClock_SchedAbs ^this.primitiveFailed } clear { | releaseNodes = true | // flag tells EventStreamPlayers that CmdPeriod is removing them, so // nodes are already freed // NOTE: queue is an Array, not a PriorityQueue, but it's used as such internally. That's why each item uses 3 slots. if (queue.size > 1) { forBy(1, queue.size-1, 3) {|i| queue[i+1].removedFromScheduler(releaseNodes) }; }; ^this.prClear; } // for setting the tempo at the current logical time // (even another TempoClock's logical time). tempo_ { arg newTempo; this.setTempoAtBeat(newTempo, this.beats); this.changed(\tempo); // this line is added } beatsPerBar_ { arg newBeatsPerBar; if (thisThread.clock != this) { "should only change beatsPerBar within the scheduling thread.".error; ^this }; this.setMeterAtBeat(newBeatsPerBar, thisThread.beats); } // for setting the tempo at the current elapsed time . etempo_ { arg newTempo; this.setTempoAtSec(newTempo, Main.elapsedTime); } beats2secs { arg beats; _TempoClock_BeatsToSecs ^this.primitiveFailed } secs2beats { arg secs; _TempoClock_SecsToBeats ^this.primitiveFailed } prDump { _TempoClock_Dump ^this.primitiveFailed } nextTimeOnGrid { arg quant = 1, phase = 0; if (quant == 0) { ^this.beats + phase }; if (quant < 0) { quant = beatsPerBar * quant.neg }; if (phase < 0) { phase = phase % quant }; ^roundUp(this.beats - baseBarBeat - (phase % quant), quant) + baseBarBeat + phase } timeToNextBeat { arg quant=1.0; // logical time to next beat ^quant.nextTimeOnGrid(this) - this.beats } beats2bars { arg beats; ^(beats - baseBarBeat) * barsPerBeat + baseBar; } bars2beats { arg bars; ^(bars - baseBar) * beatsPerBar + baseBarBeat; } bar { // return the current bar. ^this.beats2bars(this.beats).floor; } nextBar { arg beat; // given a number of beats, determine number beats at the next bar line. if (beat.isNil) { beat = this.beats }; ^this.bars2beats(this.beats2bars(beat).ceil); } beatInBar { // return the beat of the bar, range is 0 to < t.beatsPerBar ^this.beats - this.bars2beats(this.bar) } // PRIVATE prStart { arg tempo; _TempoClock_New ^this.primitiveFailed } prStop { _TempoClock_Free ^this.primitiveFailed } prClear { _TempoClock_Clear ^this.primitiveFailed } setTempoAtBeat { arg newTempo, beats; _TempoClock_SetTempoAtBeat ^this.primitiveFailed } setTempoAtSec { arg newTempo, secs; _TempoClock_SetTempoAtTime ^this.primitiveFailed } // meter should only be changed in the TempoClock's thread. setMeterAtBeat { arg newBeatsPerBar, beats; // bar must be integer valued when meter changes or confusion results later. baseBar = round((beats - baseBarBeat) * barsPerBeat + baseBar, 1); baseBarBeat = beats; beatsPerBar = newBeatsPerBar; barsPerBeat = beatsPerBar.reciprocal; this.changed(\meter); } // these methods allow TempoClock to act as TempoClock.default *stop { TempoClock.default.stop } *play { | task, quant | TempoClock.default.play(task, quant) } *sched { | delta, item | TempoClock.default.sched(delta, item) } *schedAbs { | beat, item | TempoClock.default.schedAbs(beat, item) } *clear { | releaseNodes | TempoClock.default.clear(releaseNodes) } *tempo_ { | newTempo | TempoClock.default.tempo_(newTempo) } *etempo_ { | newTempo | TempoClock.default.etempo_(newTempo) } *tempo { ^TempoClock.default.tempo } *beats { ^TempoClock.default.beats } *beats2secs { | beats | ^TempoClock.default.beats2secs(beats) } *secs2beats { | secs | ^TempoClock.default.secs2beats(secs) } *nextTimeOnGrid { | quant = 1, phase = 0 | ^TempoClock.default.nextTimeOnGrid(quant, phase) } *timeToNextBeat { | quant = 1 | ^TempoClock.default.timeToNextBeat(quant) } *setTempoAtBeat { | newTempo, beats | TempoClock.default.setTempoAtBeat(newTempo, beats) } *setTempoAtSec { | newTempo, secs | TempoClock.default.setTempoAtSec(newTempo, secs) } *setMeterAtBeat { | newBeatsPerBar, beats | TempoClock.default.setMeterAtBeat(newBeatsPerBar, beats) } *beatsPerBar { ^TempoClock.default.beatsPerBar } *baseBarBeat { ^TempoClock.default.baseBarBeat } *baseBar { ^TempoClock.default.baseBar } *playNextBar { | task | ^TempoClock.default.playNextBar(task) } *beatDur { ^TempoClock.default.beatDur } *elapsedBeats { ^TempoClock.default.elapsedBeats } *beatsPerBar_ { | newBeatsPerBar | TempoClock.default.beatsPerBar_(newBeatsPerBar) } *beats2bars { | beats | ^TempoClock.default.beats2bars(beats) } *bars2beats { | bars | ^TempoClock.default.bars2beats(bars) } *bar { ^TempoClock.default.bar } *nextBar { | beat | ^TempoClock.default.nextBar(beat) } *beatInBar { ^TempoClock.default.beatInBar } archiveAsCompileString { ^true } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Core/Symbol.sc0000664000000000000000000001124212245365552025526 0ustar rootrootSymbol { *new { ^this.shouldNotImplement(thisMethod) } // conversion asSymbol { ^this } asInteger { _Symbol_AsInteger ^this.primitiveFailed } asFloat { _Symbol_AsFloat ^this.primitiveFailed } ascii { ^this.asString.ascii } // the primitive fails to escape ' asCompileString { ^("'" ++ super.asString.escapeChar($') ++ "'") } asClass { _SymbolClass // if Symbol represents a class name then return the class, else return nil. } asSetter { _SymbolAsSetter ^this.primitiveFailed } asGetter { _SymbolAsGetter ^this.primitiveFailed } asSpec { ^Spec.specs.at(this) } asWarp { arg spec; ^Warp.warps.at(this).new(spec) } asTuning { ^TuningInfo.at(this) } asScale { ^ScaleInfo.at(this) } // testing isSetter { // returns true if last character of symbol is an underscore _SymbolIsSetter ^this.primitiveFailed } isClassName { _SymbolIsClassName // returns true if first character of symbol is a capital letter } isMetaClassName { _SymbolIsMetaClassName // returns true if there is a meta class by this name } isPrefix { | other | _SymbolIsPrefix } isPrimitiveName { // returns true if symbol is a valid primitive name ^this.isPrefix(\_) } isPrimitive { // returns true if symbol names a bound primitive ^this.isPrimitiveName and: { this.primitiveIndex > 0 } } isMap { _Symbol_IsMap // returns true if symbol starts with 'a' or 'c' followed by a number } isRest { ^this.isMap.not } // Environment support // The compiler translates use of an Environment variable like ~myvar // to a call to one of these methods, for example: // ~myvar = 5; translates to: 'myvar'.envirPut(5); // the implementations have been replaced by primitives envirGet { _Symbol_envirGet ^currentEnvironment.at(this) } envirPut { arg aValue; _Symbol_envirPut currentEnvironment.put(this, aValue); ^aValue } blend { // Envelopes may call this on the curves inst var. ^this } ++ { arg aString; ^this.asString ++ aString } asBinOpString { var res; res = this.asString; ^if(res[0].isAlphaNum) { res ++ ":" } { res } } applyTo { arg firstArg ... args; ^firstArg.performList(this, args) } // support for math on symbols performBinaryOpOnSomething { ^this } // unary ops neg { ^this } bitNot { ^this } abs { ^this } ceil { ^this } floor { ^this } frac { ^this } sign { ^this } sqrt { ^this } exp { ^this } midicps { ^this } cpsmidi { ^this } midiratio { ^this } ratiomidi { ^this } ampdb { ^this } dbamp { ^this } octcps { ^this } cpsoct { ^this } log { ^this } log2 { ^this } log10 { ^this } sin { ^this } cos { ^this } tan { ^this } asin { ^this } acos { ^this } atan { ^this } sinh { ^this } cosh { ^this } tanh { ^this } rand { ^this } rand2 { ^this } linrand { ^this } bilinrand { ^this } sum3rand { ^this } distort { ^this } softclip { ^this } coin { ^this } even { ^this } odd { ^this } rectWindow { ^this } hanWindow { ^this } welWindow { ^this } triWindow { ^this } scurve { ^this } ramp { ^this } // binary ops + { ^this } - { ^this } * { ^this } / { ^this } mod { ^this } min { ^this } max { ^this } bitAnd { ^this } bitOr { ^this } bitXor { ^this } bitHammingDistance { ^this } hammingDistance { |that| ^this.asString.hammingDistance(that.asString) } lcm { ^this } gcd { ^this } round { ^this } roundUp { ^this } trunc { ^this } atan2 { ^this } hypot { ^this } hypotApx { ^this } pow { ^this } leftShift { ^this } rightShift { ^this } unsignedRightShift { ^this } rrand { ^this } exprand { ^this } < { arg aNumber; _LT; ^this } > { arg aNumber; _GT; ^this } <= { arg aNumber; _LE; ^this } >= { arg aNumber; _GE; ^this } degreeToKey { ^this } degrad { ^this } raddeg { ^this } doNumberOp { ^this } doComplexOp { ^this } doSignalOp { ^this } doListOp { arg aSelector, aList; aList.collect({ arg item; item.perform(aSelector, this) }) } primitiveIndex { _Symbol_PrimitiveIndex ^this.primitiveFailed } specialIndex { // used by BasicOpUGens to get an ID number for the operator _Symbol_SpecialIndex ^this.primitiveFailed } printOn { arg stream; stream.putAll(this.asString); } storeOn { arg stream; stream.putAll(this.asCompileString); } // code gen codegen_UGenCtorArg { arg stream; this.asString.codegen_UGenCtorArg(stream); } archiveAsCompileString { ^true } kr { | val, lag, fixedLag = false | ^NamedControl.kr(this, val, lag, fixedLag) } ir { | val | ^NamedControl.ir(this, val) } tr { | val | ^NamedControl.tr(this, val) } ar { | val, lag | ^NamedControl.ar(this, val, lag) } matchOSCAddressPattern { arg addressPattern; _Symbol_matchOSCPattern ^this.primitiveFailed } help { this.asString.help } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/0000775000000000000000000000000012245452763025321 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/String.sc0000664000000000000000000002632312245365552027123 0ustar rootrootString[char] : RawArray { classvar <>unixCmdActions; *initClass { unixCmdActions = IdentityDictionary.new; } *doUnixCmdAction { arg res, pid; unixCmdActions[pid].value(res, pid); unixCmdActions.removeAt(pid); } prUnixCmd { arg postOutput = true; _String_POpen ^this.primitiveFailed } // runs a unix command and sends stdout to the post window unixCmd { arg action, postOutput = true; var pid; pid = this.prUnixCmd(postOutput); if(action.notNil) { unixCmdActions.put(pid, action); }; ^pid; } // Like unixCmd but gets the result into a string unixCmdGetStdOut { var pipe, lines, line; pipe = Pipe.new(this, "r"); lines = ""; line = pipe.getLine; while({line.notNil}, {lines = lines ++ line ++ "\n"; line = pipe.getLine; }); pipe.close; ^lines; } asSymbol { _StringAsSymbol ^this.primitiveFailed } asInteger { _String_AsInteger ^this.primitiveFailed } asFloat { _String_AsFloat ^this.primitiveFailed } ascii { ^Array.fill(this.size, { |i| this[i].ascii }) } stripRTF { _StripRtf ^this.primitiveFailed } stripHTML { _StripHtml ^this.primitiveFailed } *scDir { ^Platform.resourceDir } compare { arg aString, ignoreCase=false; _StringCompare } < { arg aString; ^this.compare(aString, false) < 0 } > { arg aString; ^this.compare(aString, false) > 0 } <= { arg aString; ^this.compare(aString, false) <= 0 } >= { arg aString; ^this.compare(aString, false) >= 0 } == { arg aString; ^this.compare(aString, false) == 0 } != { arg aString; ^this.compare(aString, false) != 0 } hash { _StringHash } // no sense doing collect as per superclass collection performBinaryOpOnSimpleNumber { arg aSelector, aNumber; ^aNumber.asString.perform(aSelector, this); } performBinaryOpOnComplex { arg aSelector, aComplex; ^aComplex.asString.perform(aSelector, this); } isString { ^true } asString { ^this } asCompileString { _String_AsCompileString; } species { ^String } postln { _PostLine } post { _PostString } postcln { "// ".post; this.postln; } postc { "// ".post; this.post; } postf { arg ... items; ^this.prFormat( items.collect(_.asString) ).post } format { arg ... items; ^this.prFormat( items.collect(_.asString) ) } prFormat { arg items; _String_Format ^this.primitiveFailed } matchRegexp { arg string, start = 0, end; _String_Regexp ^this.primitiveFailed } fformat { arg ... args; var str, resArgs, val, func; var suffixes, sig = false; this.do { |char| if(sig) { val = args.removeAt(0); func = Post.formats[char]; if(func.isNil) { resArgs = resArgs.add(val); str = str ++ char } { resArgs = resArgs.add(func.value(val)) }; sig = false; } { str = str ++ char }; if(char == $%) { sig = true }; }; ^str.format(*resArgs) } die { arg ... culprits; if(culprits.notEmpty,{ ("\n\nFATAL ERROR: ").postln; culprits.do({ arg c; if(c.isString,{c.postln},{c.dump}) }); }); Error(this).throw; } error { "ERROR: ".post; this.postln; } warn { "WARNING: ".post; this.postln } inform { ^this.postln } ++ { arg anObject; ^this prCat: anObject.asString; } + { arg anObject; ^this prCat: " " prCat: anObject.asString; } catArgs { arg ... items; ^this.catList(items) } scatArgs { arg ... items; ^this.scatList(items) } ccatArgs { arg ... items; ^this.ccatList(items) } catList { arg list; // concatenate this with a list as a string var string = this.copy; list.do({ arg item, i; string = string ++ item; }); ^string } scatList { arg list; var string = this.copy; list.do({ arg item, i; string = string prCat: " " ++ item; }); ^string } ccatList { arg list; var string = this.copy; list.do({ arg item, i; string = string prCat: ", " ++ item; }); ^string } split { arg separator=$/; var word=""; var array=[]; separator=separator.ascii; this.do({arg let,i; if(let.ascii != separator ,{ word=word++let; },{ array=array.add(word); word=""; }); }); ^array.add(word); } containsStringAt { arg index, string; ^compare( this[index..index + string.size-1], string, false) == 0 } icontainsStringAt { arg index, string; ^compare( this[index..index + string.size-1], string, true) == 0 } contains { arg string, offset = 0; ^this.find(string, false, offset).notNil } containsi { arg string, offset = 0; ^this.find(string, true, offset).notNil } findRegexp { arg regexp, offset = 0; _String_FindRegexp ^this.primitiveFailed } findAllRegexp { arg string, offset = 0; var indices = [], i=[]; while { i = this.findRegexp(string, offset); i.notNil and: {i.size != 0} }{ indices = indices.add(i); offset = i[0][0] + 1; } ^indices } find { arg string, ignoreCase = false, offset = 0; _String_Find ^this.primitiveFailed } findBackwards { arg string, ignoreCase = false, offset = 0x7FFFFFFE; _String_FindBackwards ^this.primitiveFailed } endsWith { arg string; ^this.contains(string, this.size - string.size) } beginsWith { arg string; ^this.containsStringAt(0, string) } findAll { arg string, ignoreCase = false, offset=0; var indices, i=0; while { i = this.find(string, ignoreCase, offset); i.notNil }{ indices = indices.add(i); offset = i + 1; } ^indices } replace { arg find, replace; ^super.replace(find, replace).join } escapeChar { arg charToEscape; // $" _String_EscapeChar } shellQuote { ^"'"++this.replace("'","'\\''")++"'" } quote { ^"\"" ++ this ++ "\"" } tr { arg from,to; ^this.collect({ arg char; if(char == from,{to},{char}) }) } insert { arg index, string; ^this.keep(index) ++ string ++ this.drop(index) } wrapExtend { arg size; ^this.dup(size div: this.size).join ++ this.keep(size % this.size) } zeroPad { ^" " ++ this ++ " " } padLeft { arg size, string = " "; ^string.wrapExtend(max(0, size - this.size)) ++ this } padRight { arg size, string = " "; ^this ++ string.wrapExtend(max(0, size - this.size)) } underlined { arg char = $-; ^this ++ "\n" ++ String.fill(this.size, char) } scramble { ^this.as(Array).scramble.as(String) } rotate { arg n = 1; ^this.as(Array).rotate(n).as(String) } compile { ^thisProcess.interpreter.compile(this); } interpret { ^thisProcess.interpreter.interpret(this); } interpretPrint { ^thisProcess.interpreter.interpretPrint(this); } *readNew { arg file; ^file.readAllString; } prCat { arg aString; _ArrayCat } printOn { arg stream; stream.putAll(this); } storeOn { arg stream; stream.putAll(this.asCompileString); } inspectorClass { ^StringInspector } /// unix standardizePath { _String_StandardizePath ^this.primitiveFailed } realPath { _String_RealPath ^this.primitiveFailed } withTrailingSlash { var sep = thisProcess.platform.pathSeparator; if(this.last != sep, { ^this ++ sep },{ ^this }) } withoutTrailingSlash { var sep = thisProcess.platform.pathSeparator; if(this.last == sep,{ ^this.copyRange(0, this.size-2) },{ ^this }) } absolutePath { var first, sep; sep = thisProcess.platform.pathSeparator; first = this[0]; if(first == sep){^this}; if(first == $~){^this.standardizePath}; ^File.getcwd ++ sep ++ this; } pathMatch { _StringPathMatch ^this.primitiveFailed } // glob load { ^thisProcess.interpreter.executeFile(this); } loadPaths { |warn=true| var paths = this.pathMatch; if(warn and:{paths.isEmpty}) { ("no files found for this path:" + this.quote).warn }; ^paths.collect({ arg path; thisProcess.interpreter.executeFile(path); }); } loadRelative { var path = thisProcess.nowExecutingPath; if(path.isNil) { Error("can't load relative to an unsaved file").throw}; if(path.basename == this) { Error("should not load a file from itself").throw }; ^(path.dirname ++ thisProcess.platform.pathSeparator ++ this).loadPaths } resolveRelative { var path, caller; caller = thisMethod.getBackTrace.caller.functionDef; if(caller.isKindOf(Method) && (caller != Interpreter.findMethod(\interpretPrintCmdLine)), { path = caller.filenameSymbol.asString; }, { path = thisProcess.nowExecutingPath; }); if(this[0] == thisProcess.platform.pathSeparator, {^this}); if(path.isNil) { Error("can't resolve relative to an unsaved file").throw}; ^(path.dirname ++ thisProcess.platform.pathSeparator ++ this) } include { if(Quarks.isInstalled(this).not) { Quarks.install(this); "... the class library may have to be recompiled.".postln; // maybe check later whether there are .sc files included. } } exclude { if(Quarks.isInstalled(this)) { Quarks.uninstall(this); "... the class library may have to be recompiled.".postln; } } basename { _String_Basename; ^this.primitiveFailed } dirname { _String_Dirname; ^this.primitiveFailed } splitext { this.reverseDo({ arg char, i; if (char == $\., { ^[this.copyFromStart(this.size - 2 - i), this.copyToEnd(this.size - i)] }); }); ^[this, nil] } // path concatenate +/+ { arg path; var pathSeparator = thisProcess.platform.pathSeparator; if (path.respondsTo(\fullPath)) { ^PathName(this +/+ path.fullPath) }; if (this.last == pathSeparator or: { path.first == pathSeparator }) { ^this ++ path }; ^this ++ pathSeparator ++ path } asRelativePath { |relativeTo| ^PathName(this).asRelativePath(relativeTo) } asAbsolutePath { // changed because there is no need to create a separate object // when String already knows how to make an absolute path ^this.absolutePath; // was ^PathName(this).asAbsolutePath } // runs a unix command and returns the result code. systemCmd { _String_System ^this.primitiveFailed } gethostbyname { _GetHostByName ^this.primitiveFailed } // gets value of environment variable getenv { _String_Getenv ^this.primitiveFailed } // sets value of environment variable // value may be nil to unset the variable setenv { arg value; _String_Setenv ^this.primitiveFailed } unsetenv { ^this.setenv(nil) } /// code gen codegen_UGenCtorArg { arg stream; stream << this.asCompileString; } ugenCodeString { arg ugenIndex, isDecl, inputNames=#[], inputStrings=#[]; _UGenCodeString ^this.primitiveFailed } asSecs { |maxDays = 365| // assume a timeString of ddd:hh:mm:ss.sss. see asTimeString. var time = 0, sign = 1, str = this; var limits = [inf, 60, 60, 24, maxDays]; var scaling = [0.001, 1.0, 60.0, 3600.0, 86400.0]; var padding = [3, 2, 2, 2, 3]; if (this.first == $-) { str = this.drop(1); sign = -1 }; str.split($:).reverseDo { |num, i| num = num.padRight(padding[i], "0").asInteger; if (num > limits[i]) { ("asSecs: number greater than allowed:" + this).warn; num = limits[i]; }; if (num < 0) { ("asSecs: negative numbers within slots not supported:" + this).warn; num = 0; }; time = time + (num * scaling[i]); }; ^time * sign; } speak { arg channel = 0, force = false; // FIXME: this should better be handled by Platform than GUI var speech = GUI.current.speech; if( speech.initialized.not, { speech.init }); speech.channels[ channel ].speak( this, force ); } toLower { ^this.collect(_.toLower) } toUpper { ^this.collect(_.toUpper) } mkdir { File.mkdir(this); } parseYAML { _String_ParseYAML ^this.primitiveFailed } parseYAMLFile { _String_ParseYAMLFile ^this.primitiveFailed } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Array2D.sc0000664000000000000000000000235112014636263027106 0ustar rootrootArray2D : Collection { var dictionary; *new { ^super.new.init } init { dictionary = this.newInternalNode; } newInternalNode { ^this.nodeType.new } nodeType { ^IdentityDictionary; } at { arg ... path; ^this.atPath(path) } atPathFail { arg path, function; var item; item = dictionary; path.do({ arg name; item = item.at(name); if (item.isNil, { ^function.value }); }); ^item } atPath { arg path; ^this.atPathFail(path) } put { arg ... path; var item; item = path.pop; ^this.putAtPath(path, item); } putAtPath { arg path, val; var item, lastName; path = path.copy; lastName = path.pop; item = dictionary; path.do({ arg name; item = item.atFail(name, { var newitem; newitem = this.newInternalNode; item.put(name, newitem); newitem }); }); item.put(lastName, val); } create { arg ... args; var item; item = dictionary; args.do({ arg name; item = item.atFail(name, { var newitem; newitem = this.newInternalNode; item.put(name, newitem); newitem }); }); } choose { arg ... start; var item; if(start.isEmpty,{ item = dictionary; },{ item = this.at(*start); if(item.isNil,{ Error("Library-choose start address not found: " ++ start).throw; }); }); ^this.prChooseFrom(item); } putTree { arg ... items; this.prPutTree([],items) } postTree { arg obj,tabs=0; if(obj.isNil,{ obj = dictionary }); if(obj.isKindOf(this.nodeType),{ "".postln; obj.keysValuesDo({ arg k,v; tabs.do({ Char.tab.post }); k.post; ": ".post; this.postTree(v,tabs + 1) }); },{ Char.tab.post; obj.asString.postln; }) } do { arg function; dictionary.do(function); } // remove only the leaf node indicated by path // parent nodes remain in the MLID even if they are empty removeAt { arg ... path; ^this.removeAtPath(path) } removeAtPath { arg path; var item, lastName; path = path.copy; lastName = path.pop; item = dictionary; path.do({ arg name; item = item.at(name); if (item.isNil, { ^nil }); }); ^item.removeAt(lastName); } // remove the leaf node // as well as parent nodes that become empty after removing the child // slower but leaves less cruft in the tree prRemoveAtPathRecursive { |path, i = 0, item| var name = path[i], result; if(item[name].isNil) { ^nil }; if(i < (path.size-1)) { result = this.prRemoveAtPathRecursive(path, i+1, item[name]); (item[name].isEmpty).if({ item.removeAt(name) }); ^result } { ^item.removeAt(name) }; } removeEmptyAtPath { arg path; ^this.prRemoveAtPathRecursive(path, 0, dictionary) } removeEmptyAt { arg ...path; ^this.prRemoveAtPathRecursive(path, 0, dictionary); } //private add { arg assn; this.put(assn.key, assn.value); } remove { ^this.shouldNotImplement(thisMethod) } removeFail { ^this.shouldNotImplement(thisMethod) } prChooseFrom { arg dict; var item; item = dict.choose; if(item.isKindOf(this.nodeType),{ ^this.prChooseFrom(item); },{ ^item }) } prPutTree { arg keys,items; forBy(0,items.size - 1,2,{ arg i; var key,item; key = items.at(i); item = items.at(i + 1); if(item.isArray.not,{ this.put(* keys ++ [key,item]); },{ //array this.prPutTree(keys ++ [key],item); }) }); } leaves { arg startAt; if(startAt.isNil,{ startAt = dictionary; },{ startAt = this.at(*startAt); }); ^this.prNestedValuesFromDict(startAt); } prNestedValuesFromDict { arg dict; ^dict.values.collect({ arg thing; if(thing.isKindOf(this.nodeType),{ this.prNestedValuesFromDict(thing) },{ thing }) }) } // Tree-like do methods leafDo { arg func; this.doLeafDo([], this.dictionary, func); } leafDoFrom { arg folderpath, func; var folder; folderpath = folderpath.asArray; folder = this.atPath(folderpath); if (folder.notNil && folder.isKindOf(this.nodeType), { this.doLeafDo(folderpath, folder, func); }); } doLeafDo { arg path, object, func; if (object.isKindOf(this.nodeType), { object.keysValuesDo({ arg name, subobject; this.doLeafDo(path ++ [name], subobject, func) }); }, { func.value(path, object); }) } treeDo { arg branchFunc, leafFunc, argument0, postBranchFunc; var result; result = this.doTreeDo([], this.dictionary, branchFunc, leafFunc, argument0, postBranchFunc); ^result; } treeDoFrom { arg folderpath, branchFunc, leafFunc, argument0, postBranchFunc; var folder, result; folderpath = folderpath.asArray; folder = this.atPath(folderpath); if (folder.isKindOf(this.nodeType), { result = this.doTreeDo(folderpath, folder, branchFunc, leafFunc, argument0, postBranchFunc); }, { result = nil; }); ^result; } doTreeDo { arg path, object, branchFunc, leafFunc, argument, postBranchFunc; var result; if (object.isKindOf(this.nodeType), { if (branchFunc.notNil, { result = branchFunc.value(path, object, argument); }, { result = argument; }); object.keysValuesDo({ arg name, subobject; this.doTreeDo(path ++ [name], subobject, branchFunc, leafFunc, result, postBranchFunc) }); if (postBranchFunc.notNil, { result = postBranchFunc.value(path, object, result); }); ^result }, { leafFunc.value(path, object, argument); }) } treeCollect { arg branchFunc, leafFunc, postBranchFunc; var result; result = this.doTreeCollect([], this.dictionary, branchFunc, leafFunc, postBranchFunc); ^result; } doTreeCollect { arg path, object, branchFunc, leafFunc, postBranchFunc; var confirm, collection, result; if (object.isKindOf(this.nodeType), { if (branchFunc.notNil, { #confirm, result = branchFunc.value(path, object); }, { #confirm, result = [true, nil] }); if (confirm, { collection = []; object.keysValuesDo({ arg name, subobject; collection = collection.add(this.doTreeCollect(path ++ [name], subobject, branchFunc, leafFunc, postBranchFunc)); }); collection.removeAllSuchThat({arg item; item.isNil}); if (postBranchFunc.notNil, { result = postBranchFunc.value(path, object, collection); }, { result = nil; }); ^result }, { ^nil }); }, { ^leafFunc.value(path, object) }); } sortedTreeDo { arg branchFunc, leafFunc, argument0, postBranchFunc, sortFunc; var result; result = this.doSortedTreeDo([], this.dictionary, branchFunc, leafFunc, argument0, postBranchFunc, sortFunc); ^result; } doSortedTreeDo { arg path, object, branchFunc, leafFunc, argument, postBranchFunc, sortFunc; var result; sortFunc = sortFunc ? {arg a, b; a < b}; if (object.isKindOf(this.nodeType), { if (branchFunc.notNil, { result = branchFunc.value(path, object, argument); }, { result = argument; }); object.sortedKeysValuesDo({ arg name, subobject; this.doSortedTreeDo(path ++ [name], subobject, branchFunc, leafFunc, result, postBranchFunc, sortFunc) }); if (postBranchFunc.notNil, { postBranchFunc.value(path, object, result); }); ^result }, { leafFunc.value(path, object, argument); }) } leafDoInBranch { arg folderpath, function; var path, folder; folderpath = folderpath.asArray; folder = this.atPath(folderpath); if (folder.notNil && folder.isKindOf(this.nodeType), { folder.keysValuesDo({ arg name, object; if (object.isKindOf(this.nodeType).not, { function.value(folderpath ++ [name], object); }); }); }); } storeOn { arg stream; stream << this.class.name << "[" <<<* dictionary << "]" } printOn { arg stream; stream << this.class.name << "[" <<* dictionary << "]" } } LibraryBase : MultiLevelIdentityDictionary { *global { ^this.subclassResponsibility(thisMethod); } *global_ { arg obj; ^this.subclassResponsibility(thisMethod); } *clear { this.global = this.new; } *at { arg ... args; ^this.global.at(*args); } *atList { arg args; ^this.global.at(*args) } *putList { arg args; ^this.global.put(*args) } *put { arg ... args; ^this.global.put(*args) } *create { arg ... args; ^this.global.create(*args) } *postTree { this.global.postTree } } Library : LibraryBase { classvar global; *global { ^global } *global_ { arg obj; global = obj; } *initClass { global = this.new; } } Archive : LibraryBase { classvar global; classvar <>archiveDir; *global { ^global } *global_ { arg obj; global = obj; } *initClass { global = this.new; archiveDir = Platform.userAppSupportDir; } *read { arg filename; var expandedFileName; expandedFileName = filename ?? (archiveDir ++ "/archive.sctxar"); if (File.exists(expandedFileName)) { if (expandedFileName.endsWith(".scar")) { global = this.readBinaryArchive(expandedFileName); }{ global = this.readArchive(expandedFileName); }; if (global.isNil) { global = this.new; }; } } *write { arg filename; var expandedFileName; expandedFileName = filename ?? (archiveDir ++ "/archive.sctxar"); global.writeArchive(expandedFileName); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/List.sc0000664000000000000000000000624612014636263026564 0ustar rootrootList : SequenceableCollection { var <>array; *new { arg size = 8; ^super.new.setCollection(Array.new(size)); } *newClear { arg size = 0; if ( size == 0, { ^super.new.setCollection(Array.new(8)); },{ ^super.new.setCollection(Array.newClear(size)); }); } *copyInstance { arg aList; ^super.new.array_( aList.array.copy ) } *newUsing { arg anArray; // an array is supplied to use directly ^super.new.setCollection( anArray ) } asArray { ^array.copy } copy { ^this.class.copyInstance(this) } copyRange { arg start, end; ^this.class.newUsing(array.copyRange(start, end)) } copySeries { arg first, second, last; ^this.class.newUsing(array.copySeries(first, second, last)) } putSeries { arg first, second, last, value; array.putSeries(first, second, last, value); } grow { arg sizeIncrease; array = array.grow(sizeIncrease); } size { ^array.size } dump { "List's array:\n".post; array.dump } clear { this.setCollection(Array.new(8)); } // accessing at { arg i; ^array.at(i) } clipAt { arg i; i = i.asInteger.clip(0, this.size - 1); ^array.at(i) } wrapAt { arg i; i = i.asInteger.wrap(0, this.size - 1); ^array.at(i) } foldAt { arg i; i = i.asInteger.fold(0, this.size - 1); ^array.at(i) } put { arg i, item; array.put(i, item) } clipPut { arg i, item; i = i.asInteger.clip(0, this.size - 1); ^array.put(i, item) } wrapPut { arg i, item; i = i.asInteger.wrap(0, this.size - 1); ^array.put(i, item) } foldPut { arg i, item; i = i.asInteger.fold(0, this.size - 1); ^array.put(i, item) } add { arg item; array = array.add(item); } addFirst { arg item; array = array.addFirst(item); } insert { arg index, item; array = array.insert(index, item); } removeAt { arg index; ^array.removeAt(index); } pop { ^array.pop } first { if (this.size > 0, { ^array.at(0) }, { ^nil }) } last { if (this.size > 0, { ^array.at(this.size - 1) }, { ^nil }) } fill { arg item; array.fill(item) } // enumerating do { arg function; array.do(function); } reverseDo { arg function; array.reverseDo(function); } pairsDo { arg function; array.pairsDo(function); } doAdjacentPairs { arg function; array.doAdjacentPairs(function); } // ordering swap { arg i,j; array.swap(i, j) } reverse { ^this.class.newUsing(array.reverse); } rotate { arg n=1; ^this.class.newUsing(array.rotate(n)); } stutter { arg n=2; ^this.class.newUsing(array.stutter(n)); } mirror { ^this.class.newUsing(array.mirror); } mirror2 { ^this.class.newUsing(array.mirror2); } mirror1 { ^this.class.newUsing(array.mirror1); } scramble { ^this.class.newUsing(array.scramble); } permute { arg nthPermutation; ^this.class.newUsing(array.permute(nthPermutation)); } wrapExtend { arg length; ^this.class.newUsing(array.wrapExtend(length)); } foldExtend { arg length; ^this.class.newUsing(array.foldExtend(length)); } pyramid { arg patternType=1; // an integer from 1-10 ^this.class.newUsing(array.pyramid(patternType)); } lace { arg length; ^this.class.newUsing(array.lace(length)) } slide { arg windowLength=3, stepSize=1; ^this.class.newUsing(array.slide(windowLength, stepSize)); } // PRIVATE: setCollection { arg aColl; array = aColl.asArray; } asList { ^this } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/EventTypesWithCleanup.sc0000664000000000000000000001425712014636263032124 0ustar rootrootEventTypesWithCleanup { classvar <>cleanupTypes, <>ugenInputTypes, <>notNodeType; *initClass { Class.initClassTree(Event); Event.default[\eventTypes].putAll( ( // ~bufnum has a default of 0, so we use ~bufNum instead.... table: #{ | server | var bufNum; if ( (bufNum = ~bufNum).notNil) { ~schedBundle.value(~lag, ~timingOffset, server, [\b_setn, bufNum.asUGenInput, 0, ~amps.size] ++ ~amps) } { ~type = \buffer; bufNum = ~bufNum = server.bufferAllocator.alloc; ~numFrames = ~amps.size; ~numChannels = 1; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels, [\b_setn, bufNum.asUGenInput, 0, ~amps.size] ++ ~amps ]); } }, cheby: #{ | server | var bufNum; if ( (bufNum = ~bufNum).notNil) { ~schedBundle.value(~lag, ~timingOffset, server, [\b_gen, bufNum.asUGenInput, \cheby, ~genflags ? 7] ++ ~amps) } { ~type = \buffer; bufNum = ~bufNum = server.bufferAllocator.alloc; ~numFrames = ~numFrames ? 1024; ~numChannels = ~numChannels ? 1; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels, [\b_gen, bufNum, \cheby, ~genflags ? 7] ++ ~amps ]); } }, sine1: #{ | server | var bufNum; if ( (bufNum = ~bufNum).notNil) { ~schedBundle.value(~lag, ~timingOffset, server, [\b_gen, bufNum.asUGenInput, \sine1, ~genflags ? 7] ++ ~amps) } { ~type = \buffer; bufNum = ~bufNum = server.bufferAllocator.alloc; ~numFrames = ~numFrames ? 1024; ~numChannels = ~numChannels ? 1; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels, [\b_gen, bufNum, \sine1, ~genflags ? 7] ++ ~amps ]); } }, sine2: #{ | server | var bufNum, array = [~freqs, ~amps].lace(~freqs.size * 2); if ( (bufNum = ~bufNum).notNil) { ~schedBundle.value(~lag, ~timingOffset, server, [\b_gen, bufNum.asUGenInput, \sine2, ~genflags ? 7] ++ array) } { ~type = \buffer; bufNum = ~bufNum = server.bufferAllocator.alloc; ~numFrames = ~numFrames ? 1024; ~numChannels = ~numChannels ? 1; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels, [\b_gen, bufNum, \sine1, ~genflags ? 7] ++ array ]); } }, sine3: #{ | server | var bufNum, array = [~freqs, ~amps, ~phases].lace(~freqs.size * 3); if ( (bufNum = ~bufNum).notNil) { ~schedBundle.value(~lag, ~timingOffset, server, [\b_gen, bufNum.asUGenInput, \sine3, ~genflags ? 7] ++ array) } { ~type = \buffer; bufNum = ~bufNum = server.bufferAllocator.alloc; ~numFrames = ~numFrames ? 1024; ~numChannels = ~numChannels ? 1; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels, [\b_gen, bufNum, \sine1, ~genflags ? 7] ++ array ]); } }, buffer: #{ | server | ~bufNum = server.bufferAllocator.alloc(~numBufs ?? { ~numBufs = 1}); ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, ~bufNum, ~numFrames, ~numChannels]); }, freeBuffer: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_free, ~bufNum]); server.bufferAllocator.free(~bufNum); }, allocRead: #{|server| var bufNum; if ( (bufNum = ~bufNum).isNil ) { bufNum = ~bufNum = server.bufferAllocator.alloc; ~type = \allocReadID }; ~schedBundle.value(~lag, ~timingOffset, server, [\b_allocRead, bufNum, ~path, ~firstFileFrame, ~numFrames]); }, cue: #{ | server | var bufNum, bndl, completion; if ( (bufNum = ~bufNum).isNil ) { bufNum = ~bufNum = server.bufferAllocator.alloc; ~type = \cueID }; completion = ["/b_read", bufNum, ~path, ~firstFileFrame, ~bufferSize, ~firstBufferFrame, ~leaveOpen]; bndl = ["/b_alloc", bufNum, ~bufferSize, ~numChannels, completion]; ~schedBundle.value(~lag, ~timingOffset, server, bndl); }, freeAllocRead: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_free, ~bufNum]); }, freeCue: #{ | server | var bufNum = ~bufNum; server.schedBundleArray.value(~lag, ~timingOffset, server, [["/b_close", bufNum], ["/b_free", bufNum ] ] ); }, freeCueID: #{ | server | var bufNum = ~bufNum; server.schedBundleArray.value(~lag, ~timingOffset, server, [["/b_close", bufNum], ["/b_free", bufNum ] ] ); server.bufferAllocator.free(bufNum); }, audioBus: #{ | server | ~out = server.audioBusAllocator.alloc(~channels ? 1) }, controlBus: #{ | server | ~out = server.controlBusAllocator.alloc(~channels ? 1) }, freeAudioBus: #{ | server | server.audioBusAllocator.free(~out) }, freeControlBus: #{ | server | server.controlBusAllocator.free(~out) } //, // // group: #{|server| // var bundle; // if (~id.isNil) { ~id = server.nextNodeID }; // bundle = [\g_new, ~id.asArray, Node.actionNumberFor(~addAction), ~group.asUGenInput].flop; // ~schedBundleArray.value(~lag, ~timingOffset, server, bundle); // } ) ); notNodeType = ( note: false, on: false, group: false, tree: false ); cleanupTypes = ( table: \freeBuffer, // free buffer and deallocate bufNum buffer: \freeBuffer, // free buffer and deallocate bufNum allocRead: \freeAllocRead, // free buffer cue: \freeCue, // free buffer, close file allocReadID: \freeBuffer, // free buffer and deallocate bufNum cueID: \freeCueID, // free buffer, close file, and deallocate bufNum audioBus: \freeAudioBus, // deallocate bus controlBus: \freeControlBus, // deallocate bus // load: \free, // bufNum was allocated elsewhere, let the source clean it up // gen: \free, // read: \free, alloc: \free, on: \off, group: \kill, tree: \kill ); ugenInputTypes = ( buffer: \bufNum, allocRead: \bufNum, allocReadID: \bufNum, audioBus: \out, controlBus: \out, on: \id, group: \id, tree: \id ); } *cleanup { | ev, flag = true | var type, notNode; type = ev[\type]; notNode = notNodeType[type] ? true; if (flag || notNode) { ( parent: ev, type: cleanupTypes[type] ).play; } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/ArrayedCollection.sc0000664000000000000000000002553212245365552031261 0ustar rootrootArrayedCollection : SequenceableCollection { *newClear { arg indexedSize = 0; _BasicNewClear ^this.primitiveFailed // creates a new instance with indexedSize indexable slots. // the slots are filled with nil, zero or something else // appropriate to the type of indexable slots in the // object. } // ArrayedCollections are vectors which have a // fixed maximum capacity. indexedSize { _BasicSize } size { _BasicSize } maxSize { _BasicMaxSize } swap { arg i, j; var temp; _BasicSwap; ^this.primitiveFailed; } at { arg index; _BasicAt; ^this.primitiveFailed; } clipAt { arg index; _BasicClipAt; ^this.primitiveFailed; } wrapAt { arg index; _BasicWrapAt; ^this.primitiveFailed; } foldAt { arg index; _BasicFoldAt; ^this.primitiveFailed; } put { arg index, item; _BasicPut; ^this.primitiveFailed; } clipPut { arg index, item; _BasicClipPut; ^this.primitiveFailed; } wrapPut { arg index, item; _BasicWrapPut; ^this.primitiveFailed; } foldPut { arg index, item; _BasicFoldPut; ^this.primitiveFailed; } removeAt { arg index; _BasicRemoveAt; ^this.primitiveFailed; } takeAt { arg index; _BasicTakeAt; ^this.primitiveFailed; } indexOf { arg item; _ArrayIndexOf ^this.primitiveFailed; } indexOfGreaterThan { arg val; _ArrayIndexOfGreaterThan ^super.indexOfGreaterThan(val) } takeThese { arg func; var i = 0; while { i < this.size } { if (func.value(this[i], i)) { this.takeAt(i) }{ i = i + 1 } } } replace { arg find, replace; var index, out = [], array = this; find = find.asArray; replace = replace.asArray; while { (index = array.find(find)).notNil }{ out = out ++ array.keep(index) ++ replace; array = array.drop(index + find.size); }; ^out ++ array } // see counterparts to these in Object slotSize { ^this.size; } slotAt { arg index; ^this.at(index); } slotPut { arg index, value; ^this.put(index, value); } slotKey { arg index; ^index } slotIndex { arg key; ^nil } getSlots { ^this.copy } setSlots { arg array; this.overWrite(array) } atModify { arg index, function; this.put(index, function.value(this.at(index), index)) } atInc { arg index, inc=1; this.put(index, this.at(index)+inc); } atDec { arg index, dec=1; this.put(index, this.at(index)-dec); } isArray { ^true } asArray { ^this } copyRange { arg start, end; // copies the fixed part of an object and the indexed slots // from start to end. _ObjectCopyRange; ^this.primitiveFailed } copySeries { arg first, second, last; // copies elements from first to last, stepping by (second-first) // copySeries(3,5,11) copies elements 3,5,7,9,11 // if second is nil then the step is 1. // copySeries(3,nil,11) copies elements 3,4,5,6,7,8,9,10,11 _ObjectCopySeries; ^this.primitiveFailed } putSeries { arg first, second, last, value; // puts value into array at indices defined by the series. see copySeries. _ArrayPutSeries; ^this.primitiveFailed } add { arg item; // add item to end of array. // if the capacity is exceeded, this returns a new // ArrayedCollection. _ArrayAdd ^this.primitiveFailed; } addAll { arg aCollection; var array; _ArrayAddAll array = this; aCollection.asCollection.do({ arg item; array = array.add(item) }) ; ^array } putEach { arg keys, values; _ArrayPutEach ^super.putEach(keys, values) } extend { arg size, item; _ArrayExtend ^this.primitiveFailed } insert { arg index, item; // add item at specified index. // if the capacity is exceeded, this returns a new // ArrayedCollection. _ArrayInsert ^this.primitiveFailed; } addFirst { arg item; ^this.insert(0, item) } addIfNotNil { arg item; if(item.notNil,{ ^this.add(item) }) } pop { // remove and return last item in array _ArrayPop ^nil; } ++ { arg anArray; // concatenate two arrays of the same type // this primitive will handle all array element types _ArrayCat; // primitive fails if arrays are different types ^super ++ anArray } overWrite { arg aCollection, pos=0; var array, grow; _ArrayOverwrite ^this.primitiveFailed //array = this.growClear(pos + aCollection.size - this.size); //grow = pos + aCollection.size - this.size; //if (grow > 0, { array = this ++ this.class.newClear(grow); },{ array = this }); //aCollection.do({ arg item, i; array.put(pos + i, item); }); //^array } grow { arg sizeIncrease; // returns an array of sufficient capacity. // may return same object if it still has enough space or if sizeIncrease <= 0. _ArrayGrow ^this.primitiveFailed } growClear { arg sizeIncrease; // returns an array of sufficient capacity. // may return same object if it still has enough space or if sizeIncrease <= 0. // clears new space _ArrayGrowClear ^this.primitiveFailed } seriesFill { arg start, step; this.size.do({ arg i; this.put(i, start); start = start + step; }); } fill { arg value; _ArrayFill ^this.primitiveFailed /* replaced by primitive var i = 0, size; size = this.size; while ({ i < size }, { this.put(i, val); i = i + 1; }); */ } do { arg function; // special byte codes inserted by compiler for this method var i=0; while ({ i < this.size }, { function.value(this.at(i), i); i = i + 1; }) } reverseDo { arg function; // special byte codes inserted by compiler for this method var i=0, j=0; i = this.size - 1; while ({ i >= 0 },{ function.value(this.at(i), j); i = i - 1; j = j + 1; }) } reverse { var i = 0; var res = this.copy; var size1 = res.size - 1; var halfsize = res.size div: 2; halfsize.do({ arg i; res.swap(i, size1 - i); }); ^res } windex { _ArrayWIndex ^this.primitiveFailed // var r, sum = 0.0, index; // r = 1.0.rand; // this.detect({ arg weight, i; // sum = sum + weight; // if (sum >= r, { // index = i; // true; // },{ false }); // }); // ^index; } normalizeSum { _ArrayNormalizeSum ^(this * this.sum.reciprocal) } normalize { arg min=0.0, max=1.0; var minItem = this.minItem; var maxItem = this.maxItem; ^this.collect { |el| el.linlin(minItem, maxItem, min, max) }; } asciiPlot { // draw the waveform down the page as asterisks var lo = this.minItem; var hi = this.maxItem; var scale = 80 / (hi - lo); this.size.do { |i| var pt = ((this[i] - lo) * scale).asInteger; pt.do({ " ".post; }); "*\n".post; }; } perfectShuffle { if(this.size < 2) { ^this.copy }; ^this[(0 .. this.size div: 2 - 1).stutter + [0, this.size + 1 div: 2]] } performInPlace { arg selector, from, to, argList; ^this.overWrite(this.copyRange(from, to).performList(selector, argList), from) } clipExtend { arg length; ^this.extend(length, this.last) } // concepts borrowed from J programming language rank { // rank is the number of dimensions in a multidimensional array. // see also Object-rank // this assumes every element has the same rank ^1 + this.first.rank } shape { // this assumes every element has the same shape ^[this.size] ++ this[0].shape } reshape { arg ... shape; var size = shape.product; var result = this.flat.wrapExtend(size); shape[1..].reverseDo {|n| result = result.clump(n) }; ^result } reshapeLike { arg another, indexing=\wrapAt; var index = 0; var flat = this.flat; ^another.deepCollect(0x7FFFFFFF) { var item = flat.perform(indexing, index); index = index + 1; item; }; } deepCollect { arg depth = 1, function, index = 0, rank = 0; if(depth.isNil) { rank = rank + 1; ^this.collect { |item, i| item.deepCollect(depth, function, i, rank) } }; if (depth <= 0) { ^function.value(this, index, rank) }; depth = depth - 1; rank = rank + 1; ^this.collect { |item, i| item.deepCollect(depth, function, i, rank) } } deepDo { arg depth = 1, function, index = 0, rank = 0; if(depth.isNil) { rank = rank + 1; ^this.do { |item, i| item.deepDo(depth, function, i, rank) } }; if (depth <= 0) { function.value(this, index, rank); ^this }; depth = depth - 1; rank = rank + 1; ^this.do { |item, i| item.deepDo(depth, function, i, rank) } } unbubble { arg depth=0, levels=1; if (depth <= 0) { // converts a size 1 array to the item. if (this.size > 1) { ^this }; if (levels <= 1) { ^this[0] } ^this[0].unbubble(depth, levels-1) }; ^this.collect {|item| item.unbubble(depth-1) } } bubble { arg depth=0, levels=1; if (depth <= 0) { if (levels <= 1) { ^[this] } ^[this.bubble(depth,levels-1)] }; ^this.collect {|item| item.bubble(depth-1, levels) } } slice { arg ... cuts; var firstCut, index, list; if (cuts.size == 0) { ^this.copy }; firstCut = cuts[0]; if (firstCut.isNil) { list = this.copy } { list = this[firstCut.asArray] }; if (cuts.size == 1) { ^list.unbubble }{ cuts = cuts[1..]; ^list.collect {|item| item.slice(*cuts) }.unbubble } } *iota { arg ... sizes; ^(0..sizes.product-1).reshape(*sizes) } // random distribution table asRandomTable { arg size; var a=this, b; if(size.isNil) { size = this.size } { a = a.resamp1(size) }; a = a.integrate; // incrementally integrate a = a.normalize(0, size-1); // normalize and scale by max index b = Array.fill(size, { arg i; a.indexInBetween(i) }); // flip array b = b / size // rescale to 0..1 ^b } tableRand { ^this.blendAt((this.size - 1).asFloat.rand) } // osc bundle support msgSize { _NetAddr_MsgSize; ^this.primitiveFailed } bundleSize { // array of messages ^([nil] ++ this).prBundleSize; } clumpBundles { var size=0, res, clumps, count=0, bundleSizes; bundleSizes = this.collect {|item| [item].bundleSize }; bundleSizes.do { |a, i| size = size + a; if(size >= 8192) { clumps = clumps.add(count); count = 0; size = a }; count = count + 1; }; ^this.clumps(clumps); } prBundleSize { _NetAddr_BundleSize; ^this.primitiveFailed } includes { |item| ^this.indexOf(item).notNil } } RawArray : ArrayedCollection { // species { ^this.class } archiveAsCompileString { ^true } archiveAsObject { ^true } rate { ^\scalar } readFromStream { |stream, method| if(method.notNil) { this.size.do({ |i| this.put(i, stream.perform(method)); }) } { this.shouldNotImplement(thisMethod); } } powerset { ^this.as(Array).powerset } } Int8Array[int8] : RawArray { unarchive { _Unarchive ^this.primitiveFailed } readFromStream { |stream| super.readFromStream(stream, \getInt8); } } Int16Array[int16] : RawArray { readFromStream { |stream| super.readFromStream(stream, \getInt16); } } Int32Array[int32] : RawArray { readFromStream { |stream| super.readFromStream(stream, \getInt32); } } FloatArray[float] : RawArray { readFromStream { |stream| super.readFromStream(stream, \getFloat); } } DoubleArray[double] : RawArray { readFromStream { |stream| super.readFromStream(stream, \getDouble); } } // readFromStream not implemented yet SymbolArray[symbol] : RawArray { } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Bag.sc0000664000000000000000000000365612014636263026344 0ustar rootrootBag : Collection { var > 1).rand << 1; // generate an even index. array.at(index).isNil; // key is at even index. }); // return the first non-nil key ^array.at(index); } wchoose { var items = Array(contents.size), counts = Array(contents.size); contents.keysValuesDo({ |item, count| items.add(item); counts.add(count); }); ^items[counts.normalizeSum.windex] } take { var result = this.choose; this.remove(result); ^result } // enumerating do { arg function; var j = 0; contents.associationsDo({ arg assn; assn.value.do({ function.value(assn.key, j); j = j + 1; }) }); } countsDo { arg function; var j = 0; contents.associationsDo({ arg assn; function.value(assn.key,assn.value,j); j = j + 1; }); } itemCount { arg item; ^(contents.at(item) ? 0) } // PRIVATE IMPLEMENTATION setDictionary { arg n; contents = Dictionary.new(n) } asBag { ^this } } IdentityBag : Bag { // PRIVATE IMPLEMENTATION setDictionary { arg n; contents = IdentityDictionary.new(n) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Pair.sc0000664000000000000000000000470412014636263026541 0ustar rootroot// LISP-like two element cells Pair : Collection { var <>linkDown, <>linkAcross; *new { arg linkDown, linkAcross; ^super.newCopyArgs(linkDown, linkAcross) } // create from nested array *newFrom { arg collection; var linkDown = collection.at(0); var linkAcross = collection.at(1); if(linkDown.isKindOf(Collection)) { linkDown = this.newFrom(linkDown) }; if(linkAcross.isKindOf(Collection)) { linkAcross = this.newFrom(linkAcross) }; ^this.new(linkDown, linkAcross) } size { var i = 0, link; link = linkAcross; while ({ link.respondsTo('linkAcross') },{ i = i + 1; link = link.linkAcross; }); ^i } depth { var i = 0, link; link = linkDown; while ({ link.respondsTo('linkDown') },{ i = i + 1; link = link.linkDown; }); ^i } do { arg function; var i = 0, link, res; link = linkAcross; while ({ link.respondsTo('linkAcross') },{ i = i + 1; res = function.value(link, i); link = link.linkAcross; }); ^res } traverse { arg function; // the default traversal order ^this.depthFirstPreOrderTraversal(function) } depthFirstPreOrderTraversal { arg function; var link; function.value(this); if ( linkDown.respondsTo('depthFirstPreOrderTraversal'), { linkDown.depthFirstPreOrderTraversal(function); }); // iterate linkAcross to conserve stack depth link = linkAcross; while ({ link.notNil },{ function.value(link); if (link.respondsTo(\linkDown) and: { link.linkDown.respondsTo('depthFirstPreOrderTraversal') }, { link.linkDown.depthFirstPreOrderTraversal(function); }); if(link.respondsTo('linkAcross')) { link = link.linkAcross; } { link = nil }; }); } depthFirstPostOrderTraversal { arg function; var link; if ( linkDown.respondsTo('depthFirstPostOrderTraversal'), { linkDown.depthFirstPostOrderTraversal(function); }); function.value(this); // iterate linkAcross to conserve stack depth link = linkAcross; while ({ link.notNil },{ if (link.respondsTo(\linkDown) and: { link.linkDown.respondsTo('depthFirstPostOrderTraversal') }, { link.linkDown.depthFirstPostOrderTraversal(function); }); function.value(link); if(link.respondsTo('linkAcross')) { link = link.linkAcross; } { link = nil }; }); } storeArgs { arg stream; ^[linkDown, linkAcross] } printOn { arg stream; stream << this.class.name << "(" <<* this.storeArgs << ")" } storeOn { arg stream; stream << this.class.name << "(" <<<* this.storeArgs << ")" } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Event.sc0000664000000000000000000006606512245365552026745 0ustar rootrootEvent : Environment { classvar defaultParentEvent; classvar event does not specify note release defaultMsgFunc: #{|freq = 440, amp = 0.1, pan = 0, out = 0| [\freq, freq, \amp, amp, \pan, pan, \out, out] }, // for \type \set args: #[\freq, \amp, \pan, \trig], timingOffset: 0, // it is more efficient to directly use schedBundleArrayOnClock // we keep these for compatibility. schedBundle: #{ |lag, offset, server ... bundle | schedBundleArrayOnClock(offset, thisThread.clock, bundle, lag, server); }, schedBundleArray: #{ | lag, offset, server, bundleArray, latency | schedBundleArrayOnClock(offset, thisThread.clock, bundleArray, lag, server, latency); }, schedStrummedNote: {| lag, strumTime, sustain, server, msg, sendGate | var dur, schedBundle = ~schedBundle; schedBundle.value(lag, strumTime + ~timingOffset, server, msg); if(sendGate) { if (~strumEndsTogether) { dur = sustain ; } { dur = sustain + strumTime }; schedBundle.value(lag, dur + ~timingOffset, server, [15 /* \n_set */, msg[2], \gate, 0]) } } ), bufferEvent: ( bufnum: 0, filename: "", frame: 0, numframes: 0, numchannels: 1, gencmd: \sine1, genflags: 7, genarray: [1], bufpos: 0, leaveOpen: 0 ), midiEvent: ( midiEventFunctions: ( noteOn: #{ arg chan=0, midinote=60, amp=0.1; [chan, midinote, asInteger((amp * 127).clip(0, 127)) ] }, noteOff: #{ arg chan=0, midinote=60, amp=0.1; [ chan, midinote, asInteger((amp * 127).clip(0, 127)) ] }, polyTouch: #{ arg chan=0, midinote=60, polyTouch=125; [ chan, midinote, polyTouch ] }, control: #{ arg chan=0, ctlNum, control=125; [chan, ctlNum, control ] }, program: #{ arg chan=0, progNum=1; [ chan, progNum ] }, touch: #{ arg chan=0, val=125; [ chan, val ] }, bend: #{ arg chan=0, val=125; [ chan, val ] }, allNotesOff: #{ arg chan=0; [chan] }, smpte: #{ arg frames=0, seconds=0, minutes=0, hours=0, frameRate=25; [frames, seconds, minutes, hours, frameRate] }, songPtr: #{ arg songPtr; [songPtr] }, sysex: #{ arg uid, array; [array] } // Int8Array ), midicmd: \noteOn ), nodeEvent: ( delta: 0, addAction: 0, group: 1, latency: 0.2, instrument: \default, hasGate: true, stopServerNode: #{ if (~hasGate == true) {currentEnvironment.set(\gate, 0) } {currentEnvironment.sendOSC([11, ~id]) }; ~isPlaying = false; }, freeServerNode: #{ currentEnvironment.sendOSC([11, ~id]); ~isPlaying = false; }, releaseServerNode: #{ currentEnvironment.set(\gate, 0); ~isPlaying = false; }, pauseServerNode: #{ currentEnvironment.sendOSC([12, ~id, false]); }, resumeServerNode: #{ currentEnvironment.sendOSC([12, ~id, true]); }, // perhaps these should be changed into mapServerNode etc. map: #{ | ev, key, busIndex | ev.sendOSC([14, ev[\id], key, busIndex]) }, before: #{ | ev,target | ev.sendOSC([18, ev[\id], target]); ev[\group] = target; ev[\addAction] = 2; }, after: #{ | ev, target | ev.sendOSC([19, ev[\id], target]); ev[\group] = target; ev[\addAction] = 3; }, headOf: #{ | ev, group | ev.sendOSC([22, group, ev[\id]]); ev[\group] = group; ev[\addAction] = 0; }, tailOf: #{ |ev, group | ev.sendOSC([23, group, ev[\id]]); ev[\group] = group; ev[\addAction] = 1; }, isPlaying: #{ |ev| ^(ev[\isPlaying] == true) }, isPlaying_: #{ | ev, flag | ev[\isPlaying] = flag; }, nodeID: #{ |ev| ^ev[\id].asArray.last }, asEventStreamPlayer: #{|ev| ev } ), playerEvent: ( type: \note, play: #{ var tempo, server; ~finish.value; server = ~server ?? { Server.default }; tempo = ~tempo; if (tempo.notNil) { thisThread.clock.tempo = tempo; }; // ~isRest may be nil - force Boolean behavior if(~isRest != true) { ~eventTypes[~type].value(server) }; }, // synth / node interface // this may be better moved into the cleanup events, but for now // it avoids confusion. // this is a preliminary implementation and does not recalculate dependent // values like degree, octave etc. freeServerNode: #{ if(~id.notNil) { ~server.sendMsg("/n_free", *~id); ~isPlaying = false; }; }, // for some yet unknown reason, this function is uncommented, // it breaks the play method for gatelesss synths releaseServerNode: #{ |releaseTime| var sendGate, msg; if(~id.notNil) { releaseTime = if(releaseTime.isNil) { 0.0 } { -1.0 - releaseTime }; sendGate = ~sendGate ? ~hasGate; if(sendGate) { ~server.sendBundle(~server.latency, *["/n_set", ~id, "gate", releaseTime].flop); } { ~server.sendBundle(~server.latency, ["/n_free"] ++ ~id); }; ~isPlaying = false; }; }, // the event types eventTypes: ( rest: #{}, note: #{|server| var freqs, lag, strum, sustain; var bndl, addAction, sendGate, ids; var msgFunc, instrumentName, offset, strumOffset; // var schedBundleArray; freqs = ~detunedFreq.value; if (freqs.isRest.not) { // msgFunc gets the synth's control values from the Event msgFunc = ~getMsgFunc.valueEnvir; instrumentName = ~synthDefName.valueEnvir; // determine how to send those commands // sendGate == false turns off releases sendGate = ~sendGate ? ~hasGate; // update values in the Event that may be determined by functions ~freq = freqs; ~amp = ~amp.value; ~sustain = sustain = ~sustain.value; lag = ~lag; offset = ~timingOffset; strum = ~strum; ~server = server; ~isPlaying = true; addAction = Node.actionNumberFor(~addAction); // compute the control values and generate OSC commands bndl = msgFunc.valueEnvir; bndl = [9 /* \s_new */, instrumentName, ids, addAction, ~group] ++ bndl; if(strum == 0 and: { (sendGate and: { sustain.isArray }) or: { offset.isArray } or: { lag.isArray } }) { bndl = flopTogether( bndl, [sustain, lag, offset] ); #sustain, lag, offset = bndl[1].flop; bndl = bndl[0]; } { bndl = bndl.flop }; // produce a node id for each synth ~id = ids = Array.fill(bndl.size, { server.nextNodeID }); bndl = bndl.collect { | msg, i | msg[2] = ids[i]; msg.asOSCArgArray }; // schedule when the bundles are sent if (strum == 0) { ~schedBundleArray.(lag, offset, server, bndl, ~latency); if (sendGate) { ~schedBundleArray.( lag, sustain + offset, server, [15 /* \n_set */, ids, \gate, 0].flop, ~latency ); } } { if (strum < 0) { bndl = bndl.reverse }; strumOffset = offset + Array.series(bndl.size, 0, strum.abs); ~schedBundleArray.( lag, strumOffset, server, bndl, ~latency ); if (sendGate) { if (~strumEndsTogether) { strumOffset = sustain + offset } { strumOffset = sustain + strumOffset }; ~schedBundleArray.( lag, strumOffset, server, [15 /* \n_set */, ids, \gate, 0].flop, ~latency ); } } } }, // optimized version of type \note, about double as efficient. // Synth must have no gate and free itself after sustain. // Event supports no strum, no conversion of argument objects to controls grain: #{|server| var freqs, lag, instr; var bndl, addAction, sendGate, ids; var msgFunc, instrumentName, offset; freqs = ~detunedFreq.value; if (freqs.isRest.not) { // msgFunc gets the synth's control values from the Event instr = ( ~synthLib ?? { SynthDescLib.global } ).at(~instrument); if(instr.isNil) { "Event: instrument % not found in SynthDescLib" .format(~instrument).warn; ^this }; msgFunc = instr.msgFunc; instrumentName = ~synthDefName.valueEnvir; // update values in the Event that may be determined by functions ~freq = freqs; ~amp = ~amp.value; ~sustain = ~sustain.value; addAction = Node.actionNumberFor(~addAction); // compute the control values and generate OSC commands bndl = msgFunc.valueEnvir; bndl = [9 /* \s_new */, instrumentName, -1, addAction, ~group] ++ bndl; ~schedBundleArray.( ~lag, ~timingOffset, server, bndl.flop, ~latency ); } }, on: #{|server| var freqs; var bndl, sendGate, ids; var msgFunc, desc, synthLib, bundle, instrumentName; freqs = ~detunedFreq.value; if (freqs.isRest.not) { ~freq = freqs; ~amp = ~amp.value; ~isPlaying = true; msgFunc = ~getMsgFunc.valueEnvir; instrumentName = ~synthDefName.valueEnvir; bndl = msgFunc.valueEnvir; bndl = [9 /* \s_new */, instrumentName, ~id, Node.actionNumberFor(~addAction), ~group] ++ bndl; bndl = bndl.flop; if ( (ids = ~id).isNil ) { ids = Array.fill(bndl.size, {server.nextNodeID }); bndl = bndl.collect { | msg, i | msg[2] = ids[i]; msg.asOSCArgArray }; } { bndl = bndl.asOSCArgBundle; }; ~schedBundleArray.value(~lag, ~timingOffset, server, bndl); }; ~server = server; ~id = ids; ~callback.value(currentEnvironment) }, set: #{|server| var freqs, lag, dur, strum, bndl, msgFunc; freqs = ~freq = ~detunedFreq.value; if (freqs.isRest.not) { ~server = server; freqs = ~freq; ~amp = ~amp.value; if(~args.size == 0) { msgFunc = ~getMsgFunc.valueEnvir; bndl = msgFunc.valueEnvir; } { bndl = ~args.envirPairs; }; bndl = ([15 /* \n_set */, ~id] ++ bndl).flop.asOSCArgBundle; ~schedBundleArray.value(~lag, ~timingOffset, server, bndl); }; }, off: #{|server| var gate; if (~hasGate) { gate = min(0.0, ~gate ? 0.0); // accept release times ~schedBundleArray.value(~lag, ~timingOffset, server, [15 /* \n_set */, ~id.asControlInput, \gate, gate].flop) } { ~schedBundleArray.value(~lag, ~timingOffset, server, [\n_free, ~id.asControlInput].flop) }; ~isPlaying = false; }, kill: #{|server| ~schedBundleArray.value(~lag, ~timingOffset, server, [\n_free, ~id.asControlInput].flop) }, group: #{|server| var bundle, cmd; if (~id.isNil) { ~id = server.nextNodeID }; bundle = [21 /* \g_new */, ~id.asArray, Node.actionNumberFor(~addAction), ~group.asControlInput].flop; ~schedBundleArray.value(~lag, ~timingOffset, server, bundle); }, parGroup: #{|server| var bundle, cmd; if (~id.isNil) { ~id = server.nextNodeID }; bundle = [63 /* \p_new */, ~id.asArray, Node.actionNumberFor(~addAction), ~group.asControlInput].flop; ~schedBundleArray.value(~lag, ~timingOffset, server, bundle); }, bus: #{|server| var array; array = ~array.asArray; ~schedBundle.value(~lag, ~timingOffset, server, [\c_setn, ~out.asControlInput, array.size] ++ array); }, gen: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_gen, ~bufnum.asControlInput, ~gencmd, ~genflags] ++ ~genarray); }, load: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_allocRead, ~bufnum.asControlInput, ~filename, ~frame, ~numframes]); }, read: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_read, ~bufnum.asControlInput, ~filename, ~frame, ~numframes, ~bufpos, ~leaveOpen]); }, alloc: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, ~bufnum.asControlInput, ~numframes, ~numchannels]); }, free: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_free, ~bufnum.asControlInput]); }, midi: #{|server| var freqs, lag, dur, sustain, strum; var bndl, midiout, hasGate, midicmd; freqs = ~freq = ~detunedFreq.value; if (freqs.isRest.not) { ~amp = ~amp.value; ~midinote = (freqs.cpsmidi).round(1).asInteger; strum = ~strum; lag = ~lag; sustain = ~sustain = ~sustain.value; midiout = ~midiout.value; ~uid ?? { ~uid = midiout.uid }; // mainly for sysex cmd hasGate = ~hasGate ? true; midicmd = ~midicmd; bndl = ~midiEventFunctions[midicmd].valueEnvir; if(midicmd != \sysex, { bndl = bndl.asCollection.asControlInput.flop; }); bndl.do {|msgArgs, i| var latency; latency = i * strum + lag; if(latency == 0.0) { midiout.performList(midicmd, msgArgs) } { thisThread.clock.sched(latency, { midiout.performList(midicmd, msgArgs); }) }; if(hasGate and: { midicmd === \noteOn }) { thisThread.clock.sched(sustain + latency, { midiout.noteOff(*msgArgs) }); }; }; } }, setProperties: { var receiver = ~receiver, go = { ~args.do { |each| var selector, value = each.envirGet; if(value.notNil) { selector = each.asSetter; if(~doTrace == true) { postf("%.%_(%)\n",receiver,selector,value) }; receiver.perform(selector.asSetter, value) }; } }; if(~defer ? true) { // inEnvir is needed // because we'll no longer be in this Event // when defer wakes up go.inEnvir.defer } { go.value }; }, monoOff: #{|server| if(~hasGate == false) { ~schedBundle.value(~lag, ~timingOffset, server, [\n_free] ++ ~id.asControlInput); } { ~schedBundle.value(~lag, ~timingOffset, server, *([15 /* \n_set */, ~id.asControlInput, \gate, 0].flop) ); }; }, monoSet: #{|server| var freqs, lag, bndl; freqs = ~freq = ~detunedFreq.value; if (freqs.isRest.not) { ~amp = ~amp.value; ~sustain = ~sustain.value; bndl = ([15 /* \n_set */, ~id.asControlInput] ++ ~msgFunc.valueEnvir).flop; bndl = bndl.collect(_.asOSCArgArray); ~schedBundle.value(~lag, ~timingOffset, server, *bndl); }; }, monoNote: #{ |server| var bndl, id, ids, addAction, f; addAction = ~addAction; ~freq = ~detunedFreq.value; f = ~freq; ~amp = ~amp.value; bndl = ( [9 /* \s_new */, ~instrument, ids, addAction, ~group.asControlInput] ++ ~msgFunc.valueEnvir).flop; bndl.do { | b | id = server.nextNodeID; ids = ids.add(id); b[2] = id; }; if ((addAction == 0) || (addAction == 3)) { bndl = bndl.reverse; }; bndl = bndl.collect(_.asOSCArgArray); ~schedBundle.value(~lag, ~timingOffset, server, *bndl); ~updatePmono.value(ids, server); }, Synth: #{ |server| var instrumentName, desc, msgFunc, sustain; var bndl, synthLib, addAction, group, latency, ids, id, groupControls; ~server = server; addAction = Node.actionNumberFor(~addAction); group = ~group.asControlInput; ~freq = ~detunedFreq.value; ~amp = ~amp.value; ~sustain = sustain = ~sustain.value; ids = ~id; msgFunc = ~getMsgFunc.valueEnvir; instrumentName = ~synthDefName.valueEnvir; bndl = [9 /* \s_new */, instrumentName, ids, addAction, group] ++ msgFunc.valueEnvir; if ((addAction == 0) || (addAction == 3)) { bndl = bndl.reverse; }; bndl = bndl.collect(_.asOSCArgArray); server.sendBundle(server.latency, *bndl); ~id = ids; ~isPlaying = true; NodeWatcher.register(currentEnvironment); }, Group: #{|server| var ids, group, addAction, bundle; ids = ~id = (~id ?? { server.nextNodeID }).asArray; addAction = Node.actionNumberFor(~addAction); group = ~group.asControlInput; ~server = server; if ((addAction == 0) || (addAction == 3) ) { ids = ids.reverse; }; bundle = ids.collect {|id, i| [21 /* \g_new */, id, addAction, group]; }; server.sendBundle(server.latency, *bundle); ~isPlaying = true; NodeWatcher.register(currentEnvironment); }, tree: #{ |server| var doTree = { |tree, currentNode, addAction=1| if(tree.isKindOf(Association)) { ~bundle = ~bundle.add([21 /* \g_new */, tree.key.asControlInput, Node.actionNumberFor(addAction), currentNode.asControlInput]); currentNode = tree.key; tree = tree.value; }; if(tree.isSequenceableCollection) { tree.do { |x, i| x ?? { tree[i] = x = server.nextNodeID }; doTree.(x, currentNode) }; } { ~bundle = ~bundle.add([21 /* \g_new */, tree.asControlInput, Node.actionNumberFor(addAction), currentNode.asControlInput]); }; }; ~bundle = nil; ~treeGroups = ~treeGroups ?? { ~tree.deepCopy }; ~treeGroups !? { doTree.(~treeGroups, ~group, ~addAction); CmdPeriod.doOnce { ~treeGroups = nil }; }; ~bundle !? { server.sendBundle(server.latency, *~bundle); }; ~bundle = nil; } ) ) ); parentEvents = ( default: ().putAll( partialEvents.pitchEvent, partialEvents.ampEvent, partialEvents.durEvent, partialEvents.bufferEvent, partialEvents.serverEvent, partialEvents.playerEvent, partialEvents.midiEvent ), groupEvent: ( lag: 0, play: #{ var server, group, addAction, ids, bundle; ~finish.value; group = ~group.asControlInput; addAction = Node.actionNumberFor(~addAction); ~server = server= ~server ?? {Server.default}; ids = Event.checkIDs(~id, server); if (ids.isNil) { ids = ~id = server.nextNodeID }; if ((addAction == 0) || (addAction == 3) ) { ids = ids.asArray.reverse; }; bundle = ids.collect {|id, i| [21 /* \g_new */, id, addAction, group]; }; server.sendBundle(server.latency, *bundle); ~isPlaying = true; ~isRunning = true; NodeWatcher.register(currentEnvironment); }).putAll(partialEvents.nodeEvent), synthEvent: ( lag: 0, play: #{ var server, latency, group, addAction; var instrumentName, synthLib, desc, msgFunc; var msgs, cvs; var bndl, ids; ~finish.value; ~server = server = ~server ?? { Server.default }; ~sustain = ~sustain.value; group = ~group.asControlInput; addAction = Node.actionNumberFor(~addAction); synthLib = ~synthLib ?? { SynthDescLib.global }; instrumentName = ~instrument.asSymbol; desc = synthLib.synthDescs[instrumentName]; if (desc.notNil) { msgFunc = desc.msgFunc; ~hasGate = desc.hasGate; }{ msgFunc = ~defaultMsgFunc; }; msgs = msgFunc.valueEnvir.flop; ids = Event.checkIDs(~id, server); if (ids.isNil) { ids = msgs.collect { server.nextNodeID } }; bndl = ids.collect { |id, i| [9 /* \s_new */, instrumentName, id, addAction, group] ++ msgs[i] }; if ((addAction == 0) || (addAction == 3)) { bndl = bndl.reverse; }; bndl = bndl.asOSCArgBundle; if (~lag !=0) { server.sendBundle(server.latency ? 0 + ~lag, *bndl); } { server.sendBundle(server.latency, *bndl); }; ~id = ids; ~isPlaying = true; ~isRunning = true; NodeWatcher.register(currentEnvironment); }, defaultMsgFunc: #{|freq = 440, amp = 0.1, pan = 0, out = 0| [\freq, freq, \amp, amp, \pan, pan, \out, out] } ).putAll(partialEvents.nodeEvent) ); defaultParentEvent = parentEvents.default; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/EnvironmentRedirect.sc0000664000000000000000000000751212245365552031642 0ustar rootroot// abstract class that dispatches assignment / reference in environments. EnvironmentRedirect { var proxyClass=\Maybe; makeProxy { ^proxyClass.asClass.new } at { arg key; var proxy; proxy = super.at(key); if(proxy.isNil) { proxy = this.makeProxy(key); envir.put(key, proxy); }; ^proxy } put { arg key, obj; this.at(key).source_(obj); dispatch.value(key, obj); // forward to dispatch for networking } removeAt { arg key; var proxy; proxy = envir.removeAt(key); if(proxy.notNil) { proxy.clear }; } localPut { arg key, obj; this.at(key).source_(obj); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Environment.sc0000664000000000000000000000336512245365552030162 0ustar rootrootEnvironment : IdentityDictionary { classvar <>stack; *make { arg function; ^this.new.make(function) } *use { arg function; ^this.new.use(function) } make { arg function; // pushes the Envir, executes function, returns the Envir // usually used to create an environment by adding new variables to it. var result, saveEnvir; saveEnvir = currentEnvironment; currentEnvironment = this; protect { function.value(this); }{ currentEnvironment = saveEnvir; }; } use { arg function; // temporarily replaces the currentEnvironment with this, // executes function, returns the result of the function var result, saveEnvir; saveEnvir = currentEnvironment; currentEnvironment = this; protect { result = function.value(this); }{ currentEnvironment = saveEnvir; }; ^result } eventAt { arg key; ^this.at(key) } composeEvents { arg event; ^this.copy.putAll(event) } *pop { if(stack.notNil and: { stack.notEmpty }) { currentEnvironment = stack.pop }; } *push { arg envir; stack = stack.add(currentEnvironment); currentEnvironment = envir; } pop { ^this.class.pop } push { this.class.push(this) } linkDoc { arg doc, pushNow = true; if(Platform.ideName == "scqt") { Error("Current platform doesn't support linking environments to documents.").throw }; doc = doc ? Document.current; doc.envir_(this); if(pushNow and: { currentEnvironment !== this }) { this.push }; } unlinkDoc { arg doc, popNow = false; if(Platform.ideName == "scqt") { Error("Current platform doesn't support linking environments to documents.").throw }; doc = doc ? Document.current; if(doc.envir === this) { doc.envir_(nil) }; if(popNow and: { currentEnvironment === this }) { this.pop }; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Collection.sc0000664000000000000000000003546012245365552027752 0ustar rootrootCollection { *newFrom { | aCollection | var newCollection = this.new(aCollection.size); aCollection.do {| item | newCollection.add(item) }; ^newCollection } *with { | ... args | var newColl; // answer a collection of my class of the given arguments // the class Array has a simpler implementation newColl = this.new(args.size); newColl.addAll(args); ^newColl } *fill { | size, function | var obj; if(size.isSequenceableCollection) { ^this.fillND(size, function) }; obj = this.new(size); size.do { | i | obj.add(function.value(i)); }; ^obj } *fill2D { | rows, cols, function | var obj = this.new(rows); rows.do { |row| var obj2 = this.new(cols); cols.do { |col| obj2 = obj2.add(function.value(row, col)) }; obj = obj.add(obj2); }; ^obj } *fill3D { | planes, rows, cols, function | var obj = this.new(planes); planes.do { |plane| var obj2 = this.new(rows); rows.do { |row| var obj3 = this.new(cols); cols.do { |col| obj3 = obj3.add(function.value(plane, row, col)) }; obj2 = obj2.add(obj3); }; obj = obj.add(obj2); }; ^obj } *fillND { | dimensions, function, args = #[] | // args are private var n = dimensions.first; var obj = this.new(n); var argIndex = args.size; args = args ++ 0; if(dimensions.size <= 1) { n.do { |i| obj.add(function.valueArray(args.put(argIndex, i))) } } { dimensions = dimensions.drop(1); n.do { |i| obj = obj.add(this.fillND(dimensions, function, args.put(argIndex, i))) } }; ^obj } @ { | index | ^this[index] } == { | aCollection | if (aCollection.class != this.class) { ^false }; if (this.size != aCollection.size) { ^false }; this.do { | item, i | // this is enough since both collections are finite if ((aCollection.includes(item)).not) { ^false }; }; ^true } hash { var hash = this.class.hash; this.do { | item | hash = hash bitXor: item.hash; }; ^hash } species { ^Array } do { ^this.subclassResponsibility(thisMethod) } iter { ^r { this.do {|item| item.yield } } } size { // this is the slow way. Most collections have a faster way. var tally = 0; this.do { tally = tally + 1 }; ^tally } flatSize { ^this.sum(_.flatSize) } isEmpty { ^this.size == 0 } notEmpty { ^this.size > 0 } asCollection { ^this } isCollection { ^true } add { ^this.subclassResponsibility(thisMethod) } addAll { | aCollection | aCollection.asCollection.do { | item | this.add(item) } } remove { ^this.subclassResponsibility(thisMethod) } removeAll { | list | list.do { | item | this.remove(item) } } removeEvery { | list | this.removeAllSuchThat(list.includes(_)) } removeAllSuchThat { | function | var removedItems = this.class.new; var copy = this.copy; copy.do { | item, i | if ( function.value(item, i) ) { this.remove(item); removedItems = removedItems.add(item); } }; ^removedItems } atAll { arg keys; ^keys.collect {|index| this[index] } } putEach { arg keys, values; // works for ArrayedCollections and Dictionaries keys = keys.asArray; values = values.asArray; keys.do { |key, i| this[key] = values.wrapAt(i) } ; } includes { | item1 | this.do {|item2| if (item1 === item2) {^true} }; ^false } includesEqual { | item1 | this.do {|item2| if (item1 == item2) {^true} }; ^false } includesAny { | aCollection | aCollection.do { | item | if (this.includes(item)) {^true} }; ^false } includesAll { | aCollection | aCollection.do { | item | if (this.includes(item).not) {^false} }; ^true } matchItem { | item | ^this.includes(item) } collect { | function | ^this.collectAs(function, this.species); } select { | function | ^this.selectAs(function, this.species); } reject { | function | ^this.rejectAs(function, this.species); } collectAs { | function, class | var res = class.new(this.size); this.do {|elem, i| res.add(function.value(elem, i)) } ^res; } selectAs { | function, class | var res = class.new(this.size); this.do {|elem, i| if (function.value(elem, i)) { res = res.add(elem) } } ^res; } rejectAs { | function, class | var res = class.new(this.size); this.do {|elem, i| if (function.value(elem, i).not) {res.add(elem)} } ^res; } detect { | function | this.do {|elem, i| if (function.value(elem, i)) { ^elem } } ^nil; } detectIndex { | function | this.do {|elem, i| if (function.value(elem, i)) { ^i } } ^nil; } doMsg { | selector ... args | this.do {| item | item.performList(selector, args) } } collectMsg { | selector ... args | ^this.collect {| item | item.performList(selector, args) } } selectMsg { | selector ... args | ^this.select {| item | item.performList(selector, args) } } rejectMsg { | selector ... args | ^this.reject {| item | item.performList(selector, args) } } detectMsg { | selector ... args | ^this.detect {| item | item.performList(selector, args) } } detectIndexMsg { | selector ... args | ^this.detectIndex {| item | item.performList(selector, args) } } lastForWhich { | function | var prev; this.do {|elem, i| if (function.value(elem, i)) { prev = elem; }{ ^prev } }; ^prev } lastIndexForWhich { | function | var prev; this.do {|elem, i| if (function.value(elem, i)) { prev = i; }{ ^prev } }; ^prev } inject { | thisValue, function | var nextValue = thisValue; this.do { | item, i | nextValue = function.value(nextValue, item, i); }; ^nextValue } count { | function | var sum = 0; this.do {|elem, i| if (function.value(elem, i)) { sum=sum+1 } } ^sum; } occurrencesOf { | obj | var sum = 0; this.do { | elem | if (elem == obj) { sum=sum+1 } } ^sum; } any { | function | this.do {|elem, i| if (function.value(elem, i)) { ^true } } ^false; } every { | function | this.do {|elem, i| if (function.value(elem, i).not) { ^false } } ^true; } sum { | function | var sum = 0; if (function.isNil) { // optimized version if no function this.do { | elem | sum = sum + elem; } }{ this.do {|elem, i| sum = sum + function.value(elem, i); } } ^sum; } mean { | function | ^this.sum(function) / this.size; } product { | function | var product = 1; if (function.isNil) { // optimized version if no function this.do { | elem | product = product * elem; } }{ this.do {|elem, i| product = product * function.value(elem, i); } } ^product; } sumabs { // sum of the absolute values - used to convert Mikael Laursen's rhythm lists. var sum = 0; this.do { | elem | if (elem.isSequenceableCollection) { elem = elem[0] }; sum = sum + elem.abs; } ^sum; } maxItem { | function | var maxValue, maxElement; if (function.isNil) { // optimized version if no function this.do { | elem | if (maxElement.isNil) { maxElement = elem; }{ if (elem > maxElement) { maxElement = elem; } } } ^maxElement; }{ this.do {|elem, i| var val; if (maxValue.isNil) { maxValue = function.value(elem, i); maxElement = elem; }{ val = function.value(elem, i); if (val > maxValue) { maxValue = val; maxElement = elem; } } } ^maxElement; } } minItem { | function | var minValue, minElement; if (function.isNil) { // optimized version if no function this.do {|elem, i| if (minElement.isNil) { minElement = elem; }{ if (elem < minElement) { minElement = elem; } } }; ^minElement; }{ this.do {|elem, i| var val; if (minValue.isNil) { minValue = function.value(elem, i); minElement = elem; }{ val = function.value(elem, i); if (val < minValue) { minValue = val; minElement = elem; } } } ^minElement; } } maxIndex { | function | var maxValue, maxIndex; if (function.isNil) { // optimized version if no function this.do { | elem, index | if (maxValue.isNil) { maxValue = elem; maxIndex = index; }{ if (elem > maxValue) { maxValue = elem; maxIndex = index; } } } ^maxIndex; }{ this.do {|elem, i| var val; if (maxValue.isNil) { maxValue = function.value(elem, i); maxIndex = i; }{ val = function.value(elem, i); if (val > maxValue) { maxValue = val; maxIndex = i; } } } ^maxIndex; } } minIndex { | function | var minValue, minIndex; if (function.isNil) { // optimized version if no function this.do {|elem, i| if (minValue.isNil) { minValue = elem; minIndex = i; }{ if (elem < minValue) { minValue = elem; minIndex = i; } } }; ^minIndex; }{ this.do {|elem, i| var val; if (minValue.isNil) { minValue = function.value(elem, i); minIndex = i; }{ val = function.value(elem, i); if (val < minValue) { minValue = val; minIndex = i; } } } ^minIndex; } } maxValue { | function | // must supply a function var maxValue, maxElement; this.do {|elem, i| var val; if (maxValue.isNil) { maxValue = function.value(elem, i); maxElement = elem; }{ val = function.value(elem, i); if (val > maxValue) { maxValue = val; maxElement = elem; } } }; ^maxValue; } minValue { | function | var minValue, minElement; this.do {|elem, i| var val; if (minValue.isNil) { minValue = function.value(elem, i); minElement = elem; }{ val = function.value(elem, i); if (val < minValue) { minValue = val; minElement = elem; } } }; ^minValue; } maxSizeAtDepth { arg rank; var maxsize = 0; if(rank == 0) { ^this.size }; this.do { |sublist| var sz = if(sublist.isCollection) { sublist.maxSizeAtDepth(rank - 1) } { 1 }; if (sz > maxsize) { maxsize = sz }; }; ^maxsize } maxDepth { arg max = 1; var res = max; this.do { |elem| if(elem.isCollection) { res = max(res, elem.maxDepth(max + 1)) } }; ^res } deepCollect { | depth = 1, function, index = 0, rank = 0 | if(depth.isNil) { rank = rank + 1; ^this.collect { |item, i| item.deepCollect(depth, function, i, rank) } }; if (depth <= 0) { ^function.value(this, index, rank) }; depth = depth - 1; rank = rank + 1; ^this.collect { |item, i| item.deepCollect(depth, function, i, rank) } } deepDo { | depth = 1, function, index = 0, rank = 0 | if(depth.isNil) { rank = rank + 1; ^this.do { |item, i| item.deepDo(depth, function, i, rank) } }; if (depth <= 0) { function.value(this, index, rank); ^this }; depth = depth - 1; rank = rank + 1; ^this.do { |item, i| item.deepDo(depth, function, i, rank) } } invert { | axis | var index; // can be used to invert a pitch list about a given axis // [3, 2, 9, 7].invert(11) becomes [ 19, 20, 13, 15 ] // if axis is nil, invert uses the registral center // [3, 2, 9, 7].invert becomes [ 8, 9, 2, 4 ] if(this.isEmpty) { ^this.species.new }; if(axis.notNil) { index = axis * 2 } { index = this.minItem + this.maxItem }; ^index - this; } sect { | that | var result = this.species.new; this.do { | item | if (that.includes(item)) { result = result.add(item); } }; ^result } union { | that | var result = this.copy; that.do { | item | if (result.includes(item).not) { result = result.add(item); } }; ^result } difference { | that | ^this.copy.removeAll(that); } symmetricDifference { | that | var result = this.species.new; this.do { | item | if (that.includes(item).not) { result = result.add(item); } }; that.do { | item | if (this.includes(item).not) { result = result.add(item); } }; ^result; } isSubsetOf { | that | ^that.includesAll(this) } asArray { ^Array.new(this.size).addAll(this); } asBag { ^Bag.new(this.size).addAll(this); } asList { ^List.new(this.size).addAll(this); } asSet { ^Set.new(this.size).addAll(this); } asSortedList { | function | ^SortedList.new(this.size, function).addAll(this); } powerset { var species = this.species; var result = this.asArray.powerset; ^if(species == Array) { result } { result.collectAs({ | item | item.as(species) }, species) } } flopDict { | unbubble=true | var res, first = true; this.do { | dict | if(first) { res = dict.class.new; first = false }; dict.keysValuesDo { | key, val | res[key] = res[key].add(val) } }; if(unbubble) { res = res.collect(_.unbubble) }; ^res } histo { arg steps = 100, min, max; var freqs, freqIndex, lastIndex, stepSize, outliers = 0; if(this.isEmpty) { ^this.species.new }; min = min ?? { this.minItem }; max = max ?? { this.maxItem }; freqs = Array.fill(steps, 0); lastIndex = steps - 1; stepSize = steps / (max - min); this.do { arg el; freqIndex = ((el - min) * stepSize).asInteger; if (freqIndex.inclusivelyBetween(0, lastIndex)) { freqs[freqIndex] = freqs[freqIndex] + 1; } { // if max is derived from maxItem, count it in: if (el == max) { freqs[steps-1] = freqs[steps-1] + 1; } { // else it is an outlier. outliers = outliers + 1; }; }; }; if (outliers > 0) { ("histogram :" + outliers + "out of (histogram) range values in collection.").inform; }; ^freqs; } // printAll { this.do { | item | item.postln; }; } // convenience method printAll { |before, after| if (before.isNil and: after.isNil) { this.do { | item | item.postln; }; } { before = before ? ""; after = after ? ""; this.do { | item | before.post; item.post; after.postln; }; }; } printcsAll { this.do { | item | item.postcs; }; } // convenience method dumpAll { this.do { | item | item.dump; }; } // convenience method printOn { | stream | if (stream.atLimit) { ^this }; stream << this.class.name << "[ " ; this.printItemsOn(stream); stream << " ]" ; } storeOn { | stream | if (stream.atLimit) { ^this }; stream << this.class.name << "[ " ; this.storeItemsOn(stream); stream << " ]" ; } storeItemsOn { | stream | var addComma = false; this.do { | item | if (stream.atLimit) { ^this }; if (addComma) { stream.comma.space; } { addComma = true }; item.storeOn(stream); }; } printItemsOn { | stream | var addComma = false; this.do { | item | if (stream.atLimit) { ^this }; if (addComma) { stream.comma.space; } { addComma = true }; item.printOn(stream); }; } // Synth support writeDef { | file | file.putString("SCgf"); file.putInt32(2); // file version file.putInt16(this.size); // number of defs in file. this.do { | item | item.writeDef(file); } } writeInputSpec { | file, synthDef | this.do { | item | item.writeInputSpec(file, synthDef) }; } // Flow control case { | default | var out = this.detect {|it| it.key.value;}; if (out.notNil) { ^out.value.value }{ ^default.value; } } // Event support makeEnvirValPairs { var res = Array.new(this.size * 2); this.do { |item| res.add(item); res.add(currentEnvironment[item]); }; ^res } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Interval.sc0000664000000000000000000000301312014636263027422 0ustar rootrootInterval : Collection { var <>start, <>end, <>step; *new { arg start, end, step=1; ^super.newCopyArgs(start, end, step) } size { ^end - start div: step + 1 } at { arg index; if (index < 0 or: { index >= this.size }, { ^nil }); ^step * index + start; } wrapAt { arg index; ^step * (index % this.size) + start } clipAt { arg index; if (index < 0) { ^start }; if (index >= this.size) { ^end }; ^step * index + start; } do { arg function; forBy(start, end, step, function); } add { ^this.shouldNotImplement(thisMethod) } put { ^this.shouldNotImplement(thisMethod) } storeArgs { ^[start, end, step] } storeOn { arg stream; stream << this.class.name; this.storeParamsOn(stream); } printOn { arg stream; this.storeOn(stream) } } Range : Collection { var <>start, <>size; *new { arg start, size; ^super.newCopyArgs(start, size); } end { ^start + size } do { arg function; for(start, start+size-1, function); } at { arg index; var val; if (index < 0 or: { index >= size }, { ^nil }); ^start + index; } includes { arg val; ^(val >= start) and: { (val < this.end) and: { val.frac == 0 }} } add { ^this.shouldNotImplement(thisMethod) } put { ^this.shouldNotImplement(thisMethod) } split { arg num; // assert: size > num var newRange = this.class.new(start, num); start = start + num; size = size - num; ^newRange } storeArgs { ^[start, size] } storeOn { arg stream; stream << this.class.name; this.storeParamsOn(stream); } printOn { arg stream; this.storeOn(stream) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/RingBuffer.sc0000664000000000000000000000254412014636263027677 0ustar rootroot// Fixed size ringbuffer RingBuffer : SequenceableCollection { var 0) { array.put(writePos, value); writePos = (writePos + 1) % array.size; } } // return next readable item and increase readPos. // return nil if no items can be read. pop { var result; if (this.readable > 0) { result = array.at(readPos); readPos = (readPos + 1) % array.size; }; ^result } // add value and increase writePos by overwriting oldest readable // item. overwrite { | value | var result; if (this.writable == 0) { result = this.pop; }; this.add(value); ^result } // iterate over the currently readable items. do { | function | var n = this.readable, i = 0; while { i < n } { function.value(array.wrapAt(readPos + i), i); i = i + 1; } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Association.sc0000664000000000000000000000107312014636263030116 0ustar rootrootAssociation : Magnitude { var <>key, <>value; *new { arg key, value; ^super.newCopyArgs(key, value) } == { arg anAssociation; ^anAssociation respondsTo: \key and: { key == anAssociation.key } } hash { ^key.hash } < { arg anAssociation; ^key < anAssociation.key } printOn { arg stream; stream << "(" << key << " -> " << value << ")"; } storeOn { arg stream; stream << "(" <<< key << " -> " <<< value << ")"; } // Pattern support embedInStream { arg inval; ^inval.add(this).yield; } transformEvent { arg event; ^event.add(this); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Set.sc0000664000000000000000000001061612014636263026400 0ustar rootrootSet : Collection { var <>array, 0, { array.do({ arg item; if (item.notNil, { function.value(item, i); i = i + 1; }) }) }) } clear { array.fill; size=0 } makeEmpty { this.clear; } includes { arg item; ^array.at(this.scanFor(item)).notNil; } findMatch { arg item; // return an item that matches a given item ^array.at(this.scanFor(item)); } add { arg item; var index; if (item.isNil, { Error("A Set cannot contain nil.\n").throw; }); index = this.scanFor(item); if ( array.at(index).isNil, { this.putCheck(index, item) }); } remove { arg item; var index = this.scanFor(item); if ( array.at(index).notNil, { array.put(index, nil); size = size - 1; this.fixCollisionsFrom(index); }); } choose { var index, val; if (size <= 0, { ^nil }); while({ index = array.size.rand; (val = array.at(index)).isNil; }); ^val } pop { var index = 0, val; while({ (index < array.size) and: { (val = array.at(index)).isNil } },{ index = index + 1 }); if (index < array.size, { this.remove(val); ^val }, { ^nil }); } // powerset { // ^this.asArray.sort.powerset // } unify { var result = this.species.new; this.do {|x| result.addAll(x) } ^result } sect { arg that; var result = this.species.new; this.do({ arg item; if (that.includes(item), { result.add(item); }); }); ^result } union { arg that; var result = this.species.new; result.addAll(this); result.addAll(that); ^result } difference { arg that; ^this.copy.removeAll(that); } symmetricDifference { arg that; var result = this.species.new; this.do({ arg item; if (that.includes(item).not, { result.add(item); }); }); that.do({ arg item; if (this.includes(item).not, { result.add(item); }); }); ^result; } isSubsetOf { | that | ^that.includesAll(this) } & { arg that; ^this.sect(that) } | { arg that; ^this.union(that) } - { arg that; ^this.difference(that) } -- { arg that; ^this.symmetricDifference(that) } // PRIVATE IMPLEMENTATION initSet { arg n; array = Array.newClear(n); size = 0; } putCheck { arg index, item; array.put(index, item); size = size + 1; this.fullCheck; } fullCheck { if (array.size < (size * 2), { this.grow }); } grow { var oldElements = array; array = Array.newClear(array.size * 2); size = 0; oldElements.do({ arg item; if ( item.notNil, { this.noCheckAdd(item) }) }); } noCheckAdd { arg item; array.put(this.scanFor(item), item); size = size + 1; } scanFor { arg obj; var elem; var start = obj.hash % array.size; var end = array.size; var i = start; while ({ i < end }, { elem = array.at(i); if ( elem.isNil or: { elem == obj }, { ^i }); i = i + 1; }); end = start - 1; i = 0; while ({ i <= end }, { elem = array.at(i); if ( elem.isNil or: { elem == obj }, { ^i }); i = i + 1; }); error("There is no free space in this set!\n"); array.postln; ^-1 } fixCollisionsFrom { arg index; var newIndex, element; var oldIndex = index; var lastKeyIndex = array.size - 1; while ({ if (oldIndex == lastKeyIndex, { oldIndex = 0 }, { oldIndex = oldIndex + 1 }); (element = this.keyAt(oldIndex)).notNil },{ newIndex = this.scanFor(element); if ( oldIndex != newIndex, { array.swap(oldIndex, newIndex) }) }) } keyAt { arg index; ^array.at(index) } asSet { ^this } } IdentitySet : Set { scanFor { arg argKey; ^array.atIdentityHash(argKey) /* var i, start, end, elem; start = obj.identityHash % array.size; end = array.size; i = start; while ({ i < end }, { elem = array.at(i); if ( elem.isNil or: { elem === obj }, { ^i }); i = i + 1; }); end = start - 1; i = 0; while ({ i < end }, { elem = array.at(i); if ( elem.isNil or: { elem === obj }, { ^i }); i = i + 1; }); ^-1 */ } } OrderedIdentitySet : IdentitySet { var >items; copy { ^this.shallowCopy .array_( array.copy ) .items_( items.copy ) } do { arg function; items.do(function) } clear { super.clear; items = nil; } remove { arg item; super.remove(item); items.remove(item); } sort { arg func; items.sort(func) } // private putCheck { arg index, item; super.putCheck(index, item); items = items.add(item); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Array.sc0000664000000000000000000001542512161364457026734 0ustar rootrootArray[slot] : ArrayedCollection { *with { arg ... args; // return an array of the arguments given // cool! the interpreter does it for me.. ^args } reverse { _ArrayReverse ^this.primitiveFailed } scramble { _ArrayScramble ^this.primitiveFailed } mirror { _ArrayMirror ^this.primitiveFailed } mirror1 { _ArrayMirror1 ^this.primitiveFailed } mirror2 { _ArrayMirror2 ^this.primitiveFailed } stutter { arg n=2; _ArrayStutter ^this.primitiveFailed } rotate { arg n=1; _ArrayRotate ^this.primitiveFailed } pyramid { arg patternType=1; // an integer from 1-10 _ArrayPyramid ^this.primitiveFailed } pyramidg { arg patternType=1; var list = []; var lastIndex = this.lastIndex; if (patternType == 1) { for (0,lastIndex) {|i| list = list.add(this[0..i]) }; ^list }; if (patternType == 2) { for (0,lastIndex) {|i| list = list.add(this[lastIndex-i..lastIndex]) }; ^list }; if (patternType == 3) { for (lastIndex,0) {|i| list = list.add(this[0..i]) }; ^list }; if (patternType == 4) { for (0,lastIndex) {|i| list = list.add(this[i..lastIndex]) }; ^list }; if (patternType == 5) { for (0,lastIndex) {|i| list = list.add(this[0..i]) }; for (lastIndex-1,0) {|i| list = list.add(this[0..i]) }; ^list }; if (patternType == 6) { for (0,lastIndex) {|i| list = list.add(this[lastIndex-i..lastIndex]) }; for (lastIndex-1,0) {|i| list = list.add(this[lastIndex-i..lastIndex]) }; ^list }; if (patternType == 7) { for (lastIndex,0) {|i| list = list.add(this[0..i]) }; for (1,lastIndex) {|i| list = list.add(this[0..i]) }; ^list }; if (patternType == 8) { for (0,lastIndex) {|i| list = list.add(this[i..lastIndex]) }; for (lastIndex-1,0) {|i| list = list.add(this[i..lastIndex]) }; ^list }; if (patternType == 9) { for (0,lastIndex) {|i| list = list.add(this[0..i]) }; for (1,lastIndex) {|i| list = list.add(this[i..lastIndex]) }; ^list }; if (patternType == 10) { for (0,lastIndex) {|i| list = list.add(this[lastIndex-i..lastIndex]) }; for (lastIndex-1,0) {|i| list = list.add(this[0..i]) }; ^list }; } sputter { arg probability=0.25, maxlen = 100; var i=0; var list = Array.new; var size = this.size; probability = 1.0 - probability; while { (i < size) and: { list.size < maxlen }}{ list = list.add(this[i]); if (probability.coin) { i = i + 1; } }; ^list } lace { arg length; _ArrayLace ^this.primitiveFailed } permute { arg nthPermutation; _ArrayPermute ^this.primitiveFailed } allTuples { arg maxTuples = 16384; _ArrayAllTuples ^this.primitiveFailed } wrapExtend { arg length; _ArrayExtendWrap ^this.primitiveFailed } foldExtend { arg length; _ArrayExtendFold ^this.primitiveFailed } clipExtend { arg length; _ArrayExtendLast ^this.primitiveFailed } slide { arg windowLength=3, stepSize=1; _ArraySlide ^this.primitiveFailed } containsSeqColl { _ArrayContainsSeqColl ^this.primitiveFailed } //************** inconsistent argnames, see SequenceableColllection unlace! unlace { arg clumpSize=2, numChan=1, clip=false; ^if(clip) { super.unlace(clumpSize, numChan, true) } { this.prUnlace(clumpSize, numChan) // clip not yet implemented in primitive } } prUnlace { arg clumpSize=2, numChan=1; _ArrayUnlace ^this.primitiveFailed; } interlace { arg clumpSize=1; //_ArrayInterlace //^this.primitiveFailed; Error("interlace was replaced by lace\n").throw } deinterlace { arg clumpSize=2, numChan=1; //_ArrayUnlace //^this.primitiveFailed; Error("deinterlace was replaced by unlace\n").throw } // multiChannelExpand and flop do the same thing. flop { _ArrayMultiChannelExpand ^super.flop } multiChannelExpand { _ArrayMultiChannelExpand ^super.flop } envirPairs { // given an array of symbols, this returns an array of pairs of symbol, value // from the current environment var result; this.do {|name| var value = name.envirGet; value !? { result = result.add(name).add(value); }; }; ^result } shift { arg n, filler = 0.0; var fill = Array.fill(n.abs, filler); var remain = this.drop(n.neg); ^if (n<0) { remain ++ fill } { fill ++ remain } } powerset { var arrSize = this.size; var powersize = (2 ** arrSize).asInteger; var powersOf2 = ({ |i| 2 ** i }).dup(arrSize); ^Array.fill(powersize, { |i| var elemArr = Array.new; powersOf2.do { |mod, j| if (i div: mod % 2 != 0) { elemArr = elemArr.add(this[j]) }; }; elemArr; }); } // UGen support: source { // returns the source UGen from an Array of OutputProxy(s) var elem = this.at(0); if (elem.isKindOf(OutputProxy), { ^elem.source },{ Error("source: Not an Array of OutputProxy(s)\n").throw; }); } asUGenInput { arg for; ^this.collect(_.asUGenInput(for)) } asControlInput { ^this.collect(_.asControlInput) } isValidUGenInput { ^true } numChannels { ^this.size } // multichannel UGen-poll poll { arg trig = 10, label, trigid = -1; if(label.isNil){ label = this.size.collect{|index| "UGen Array [%]".format(index) } }; ^Poll(trig, this, label, trigid) } dpoll { arg label, run = 1, trigid = -1; if(label.isNil){ label = this.size.collect{|index| "UGen Array [%]".format(index) } }; ^Dpoll(this, label, run, trigid) } envAt { arg time; _ArrayEnvAt ^this.primitiveFailed } // // 2D array support // *newClear2D { arg rows=1, cols=1; // ^super.fill(rows, { Array.newClear(cols) }); // } // *new2D { arg rows=1, cols=1; // ^this.newClear2D(rows, cols); // } // at2D { arg row, col; ^this.at(row).at(col) } // put2D { arg row, col, val; ^this.at(row).put(col, val) } // fill2D { arg val; // this.do({ arg row; // row.size.do({ arg i; // row.put(i, val) // }) // }) // } // IdentitySet support atIdentityHash { arg argKey; _Array_AtIdentityHash ^this.primitiveFailed } // IdentityDictionary support atIdentityHashInPairs { arg argKey; _Array_AtIdentityHashInPairs ^this.primitiveFailed } asSpec { ^ControlSpec( *this ) } // threads fork { arg join (this.size), clock, quant=0.0, stackSize=64; var count = 0; var cond = Condition({ count >= join }); this.do({ arg func; Routine({ arg time; func.value(time); count = count + 1; cond.signal; }).play(clock, quant); }); cond.wait; } // UGen support madd { arg mul = 1.0, add = 0.0; ^MulAdd(this, mul, add); } // OSC asRawOSC { _Array_OSCBytes ^this.primitiveFailed; } printOn { arg stream; if (stream.atLimit, { ^this }); stream << "[ " ; this.printItemsOn(stream); stream << " ]" ; } storeOn { arg stream; if (stream.atLimit, { ^this }); stream << "[ " ; this.storeItemsOn(stream); stream << " ]" ; } prUnarchive { arg slotArray; slotArray.pairsDo {|index, slots| this[index].setSlots(slots) }; this.do {|obj| obj.initFromArchive }; ^this.first } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/SortedList.sc0000664000000000000000000000545712014636263027750 0ustar rootrootSortedList : List { var <>function; *new { arg size = 8, function; function = function ? { arg a, b; a < b } ^super.new(size).function_(function) } add { arg item; var nextIndex; if ( this.isEmpty, { ^super.add(item); }); nextIndex = this.indexForInserting(item); this.insert(nextIndex, item); } addAll { arg aCollection; aCollection = aCollection.asCollection; if ( aCollection.size > (this.size div: 3), { // Faster to add the new elements and resort aCollection.do({ arg each; super.add(each) }); this.sort },{ // Faster to add the elements individually in their proper places aCollection.do({ arg each; this.add(each) }); }); } copyRange { arg start, end; ^this.class.newUsing(array.copyRange(start, end)).function_(function) } copySeries { arg first, second, last; ^this.class.newUsing(array.copySeries(first, second, last)).function_(function) } // PRIVATE indexForInserting { arg newObject; var index; var low = 0; var high = this.size-1; while ({ index = high + low div: 2; low <= high; },{ if (function.value(array.at(index), newObject), { low = index + 1; },{ high = index - 1; }); }); ^low } sort { this.sortRange(0, array.size - 1) } sortRange { arg i, j; //Sort elements i through j of this to be nondescending according to // function. var di, dij, dj, tt, ij, k, l, n; // The prefix d means the data at that index. if ((n = j + 1 - i) <= 1, { ^this }); // Nothing to sort. //Sort di,dj. di = array.at(i); dj = array.at(j); if (function.value(di, dj).not, { // i.e., should di precede dj? array.swap(i,j); tt = di; di = dj; dj = tt; }); if ( n > 2, { // More than two elements. ij = (i + j) div: 2; // ij is the midpoint of i and j. dij = array.at(ij); // Sort di,dij,dj. Make dij be their median. if (function.value(di, dij), { // i.e. should di precede dij? if (function.value(dij, dj).not, { // i.e., should dij precede dj? array.swap(j, ij); dij = dj; }) },{ // i.e. di should come after dij" array.swap(i, ij); dij = di; }); if ( n > 3, { // More than three elements. // Find k>i and lprev, <>next, <>obj; // this class supports the LinkedList class *new { arg item; ^super.new.obj_(item) } remove { if (prev.notNil, { prev.next_(next); }); if (next.notNil, { next.prev_(prev); }); next = prev = nil; } } LinkedList : SequenceableCollection { var head, tail, = 0 and: { index < size }, { if (index < (size - index), { node = head; while ({ i != index },{ node = node.next; i = i + 1; }); ^node },{ i = size - 1; node = tail; while ({ i != index },{ node = node.prev; i = i - 1; }); ^node }); },{ this.indexOutOfRange; ^nil }) } findNodeOfObj { arg obj; var node = head; while ({ node.notNil },{ if (node.obj == obj, { ^node }); node = node.next; }); ^nil } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Dictionary.sc0000664000000000000000000002526012245365552027761 0ustar rootrootDictionary : Set { *new { arg n=8; ^super.new(n*2) } *newFrom { arg aCollection; var newCollection = this.new(aCollection.size); aCollection.keysValuesDo({ arg k,v, i; newCollection.put(k,v) }); ^newCollection } // accessing at { arg key; ^array.at(this.scanFor(key) + 1) } atFail { arg key, function; var val; val = this.at(key); if ( val.isNil, { ^function.value }, { ^val }); } matchAt { |key| this.keysValuesDo({ |k, v| if(k.matchItem(key)) { ^v } }); ^nil } trueAt { arg key; ^this.at(key) ? false } add { arg anAssociation; this.put(anAssociation.key, anAssociation.value); } put { arg key, value; var atKey; var index; value ?? { this.removeAt(key); ^this }; index = this.scanFor(key); array.put(index+1, value); if ( array.at(index).isNil, { array.put(index, key); size = size + 1; if (array.size < (size * 4), { this.grow }); }); } putAll { arg ... dictionaries; dictionaries.do {|dict| dict.keysValuesDo { arg key, value; this.put(key, value) } } } putPairs { arg args; args.pairsDo { |key, val| this.put(key, val) } } getPairs { arg args; var result; args = args ?? { this.keys }; args.do { |key| var val = this.at(key); val !? { result = result.add(key).add(val) } }; ^result } associationAt { arg key; var index = this.scanFor(key); if (index >= 0, { ^Association.new(array.at(index), array.at(index+1)); },{ ^nil }); } associationAtFail { arg argKey, function; var index = this.scanFor(argKey); var key = array.at(index); if ( key.isNil, { ^function.value }, { ^Association.new(key, array.at(index+1)) }); } keys { arg species(Set); var set = species.new(size); this.keysDo({ arg key; set.add(key) }); ^set } values { var list = List.new(size); this.do({ arg value; list.add(value) }); ^list } // testing includes { arg item1; this.do({ arg item2; if (item1 == item2, {^true}) }); ^false } includesKey { arg key; ^this.at( key ).notNil; } // removing removeAt { arg key; var val; var index = this.scanFor(key); var atKeyIndex = array.at(index); if ( atKeyIndex.isNil, { ^nil }); val = array.at(index+1); array.put(index, nil); array.put(index+1, nil); size = size - 1; this.fixCollisionsFrom(index); ^val } removeAtFail { arg key, function; var val; var index = this.scanFor(key); var atKeyIndex = array.at(index); if ( atKeyIndex.isNil, { ^function.value }); val = array.at(index+1); array.put(index, nil); array.put(index+1, nil); size = size - 1; this.fixCollisionsFrom(index); ^val } remove { ^this.shouldNotImplement(thisMethod) } removeFail { ^this.shouldNotImplement(thisMethod) } // enumerating keysValuesDo { arg function; this.keysValuesArrayDo(array, function); } keysValuesChange { arg function; this.keysValuesDo({ arg key, value, i; this.put(key, function.value(key, value, i)); }) } do { arg function; this.keysValuesDo({ arg key, value, i; function.value(value, i); }) } keysDo { arg function; this.keysValuesDo({ arg key, val, i; function.value(key, i); }) } associationsDo { arg function; this.keysValuesDo({ arg key, val, i; function.value( Association.new(key, val), i); }) } pairsDo { arg function; this.keysValuesArrayDo(array, function); } collect { arg function; var res = this.class.new(this.size); this.keysValuesDo { arg key, elem; res.put(key, function.value(elem, key)) } ^res; } select { arg function; var res = this.class.new(this.size); this.keysValuesDo { arg key, elem; if(function.value(elem, key)) { res.put(key, elem) } } ^res; } reject { arg function; var res = this.class.new(this.size); this.keysValuesDo { arg key, elem; if(function.value(elem, key).not) { res.put(key, elem) } } ^res; } invert { var dict = this.class.new(this.size); this.keysValuesDo {|key, val| dict.put(val, key) }; ^dict } merge {|that, func, fill = true| var commonKeys, myKeys = this.keys, otherKeys = that.keys; var res = (); if (myKeys == otherKeys) { commonKeys = myKeys } { commonKeys = myKeys.sect(otherKeys); }; commonKeys.do { |key| res[key] = func.value(this[key], that[key], key) }; if (fill) { myKeys.difference(otherKeys).do { |key| res[key] = this[key] }; otherKeys.difference(myKeys).do { |key| res[key] = that[key] }; }; ^res } blend { |that, blend = 0.5, fill = true, specs| ^this.merge(that, { |a, b, key| var spec = if (specs.notNil) { specs[key].asSpec }; if (spec.notNil) { spec.map(blend(spec.unmap(a), spec.unmap(b), blend)) } { blend(a, b, blend) } }, fill) } findKeyForValue { arg argValue; this.keysValuesArrayDo(array, { arg key, val, i; if (argValue == val, { ^key }) }); ^nil } sortedKeysValuesDo { arg function, sortFunc; var keys = this.keys(Array); keys.sort(sortFunc); keys.do { arg key, i; function.value(key, this[key], i); }; } choose { var index, key, val; if( this.isEmpty, { ^nil }); // empty dictionary while({ index = (array.size >> 1).rand << 1; // generate an even index. array.at(index).isNil; // key is at even index. }); // return the value for the first non Nil key we find. // the value is at the odd index. ^array.at(index + 1); } order { arg func; var assoc; if( this.isEmpty, { ^nil }); this.keysValuesDo { arg key, val; assoc = assoc.add(key -> val); }; ^assoc.sort(func).collect(_.key) } powerset { var keys = this.keys.asArray.powerset; ^keys.collect { | list | var dict = this.class.new; list.do { |key| dict.put(key, this[key]) }; dict } } // Pattern support transformEvent { arg event; ^event.putAll(this); } embedInStream { arg event; ^yield(event !? { event.copy.putAll(this) }) } asSortedArray { var array; if ( this.notEmpty ){ this.keysValuesDo({ arg key, value; array = array.add([key,value]); }); array = array.sort({ arg a, b; a.at(0) < b.at(0) }); }{ array = []; }; ^array; } asKeyValuePairs { var array = Array.new(this.size * 2); this.keysValuesDo { |key, val| array.add(key); array.add(val) }; ^array } // PRIVATE IMPLEMENTATION keysValuesArrayDo { arg argArray, function; // special byte codes inserted by compiler for this method var i=0, j=0, key, val; var arraySize = argArray.size; while ({ i < arraySize },{ key = argArray.at(i); if (key.notNil, { val = argArray.at(i+1); function.value(key, val, j); j = j + 1; }); i = i + 2; }); } grow { var index; var oldElements = array; array = Array.newClear(array.size * 2); this.keysValuesArrayDo(oldElements, { arg key, val; index = this.scanFor(key); array.put(index, key); array.put(index+1, val); }); } fixCollisionsFrom { arg index; var newIndex, key; var oldIndex = index; var lastKeyIndex = array.size - 2; while ({ if (oldIndex == lastKeyIndex, { oldIndex = 0 }, { oldIndex = oldIndex + 2 }); (key = array.at(oldIndex)).notNil },{ newIndex = this.scanFor(key); if ( oldIndex != newIndex, { array.swap(oldIndex, newIndex); array.swap(oldIndex+1, newIndex+1) }) }) } scanFor { arg argKey; var maxHash = array.size div: 2; var start = (argKey.hash % maxHash) * 2; var end = array.size-1; var i = start; forBy( start, end, 2, { arg i; var key = array.at(i); if ( key.isNil or: { key == argKey }, { ^i }); }); end = start - 1; forBy( 0, start-2, 2, { arg i; var key = array.at(i); if ( key.isNil or: { key == argKey }, { ^i }); }); ^-2 } storeItemsOn { arg stream, itemsPerLine = 5; var itemsPerLinem1 = itemsPerLine - 1; var last = this.size - 1; this.associationsDo({ arg item, i; item.storeOn(stream); if (i < last, { stream.comma.space; if (i % itemsPerLine == itemsPerLinem1, { stream.nl.space.space }); }); }); } printItemsOn { arg stream, itemsPerLine = 5; var itemsPerLinem1 = itemsPerLine - 1; var last = this.size - 1; this.associationsDo({ arg item, i; item.printOn(stream); if (i < last, { stream.comma.space; if (i % itemsPerLine == itemsPerLinem1, { stream.nl.space.space }); }); }); } } IdentityDictionary : Dictionary { var <>proto; // inheritance of properties var <>parent; // inheritance of properties var <>know = false; // if know is set to true then not understood messages will look in the dictionary // for that selector and send the value message to them. *new { arg n=8, proto, parent, know=false; ^super.new(n).proto_(proto).parent_(parent).know_(know) } at { arg key; _IdentDict_At ^this.primitiveFailed /*^array.at(this.scanFor(key) + 1)*/ } put { arg key, value; _IdentDict_Put value ?? { this.removeAt(key); ^this }; ^this.primitiveFailed /* var index, atKey; index = this.scanFor(key); array.put(index+1, value); if ( array.at(index).isNil, { array.put(index, key); size = size + 1; if (array.size < (size * 4), { this.grow }); }); */ } putGet { arg key, value; _IdentDict_PutGet ^this.primitiveFailed /* var index, atKey, prev; index = this.scanFor(key); prev = array.at(index + 1); array.put(index+1, value); if ( array.at(index).isNil, { array.put(index, key); size = size + 1; if (array.size < (size * 4), { this.grow }); }); ^prev */ } includesKey { arg key; ^this.at( key ).notNil; } findKeyForValue { arg argValue; this.keysValuesArrayDo(array, { arg key, val, i; if (argValue === val, { ^key }) }); ^nil } scanFor { arg argKey; ^array.atIdentityHashInPairs(argKey) } doesNotUnderstand { arg selector ... args; var func; if (know) { func = this[selector]; if (func.notNil) { ^func.functionPerformList(\value, this, args); }; if (selector.isSetter) { selector = selector.asGetter; if(this.respondsTo(selector)) { warn(selector.asCompileString + "exists a method name, so you can't use it as pseudo-method.") }; ^this[selector] = args[0]; }; func = this[\forward]; if (func.notNil) { ^func.functionPerformList(\value, this, selector, args); }; ^nil }; ^this.superPerformList(\doesNotUnderstand, selector, args); } // Quant support. // The Quant class assumes the quant/phase/offset scheduling model. // If you want a different model, you can write a dictionary like so: // (nextTimeOnGrid: { |self, clock| ... calculate absolute beat number here ... }, // parameter: value, parameter: value, etc.) // If you leave out the nextTimeOnGrid function, fallback to quant/phase/offset. nextTimeOnGrid { |clock| if(this[\nextTimeOnGrid].notNil) { ^this[\nextTimeOnGrid].value(this, clock) } { ^clock.nextTimeOnGrid(this[\quant] ? 1, (this[\phase] ? 0) - (this[\offset] ? 0)) } } asQuant { ^this.copy } timingOffset { ^this[\timingOffset] } // for synchWithQuant() } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/SparseArray.sc0000664000000000000000000002227512245365552030113 0ustar rootrootOrder : SequenceableCollection { var <>array, <>indices; *new { arg size = 8; ^super.new.clear(size) } *newFromIndices { arg array, indices; ^super.newCopyArgs(array, indices) } clear { arg size; array = Array.new(size); indices = Array.new(size); } makeEmpty { this.clear } copy { ^this.class.newCopyArgs(array.copy, indices.copy) } asArray { ^array.copy } do { arg function; indices.do { |index, i| function.value(array.at(i), index, i) }; } doRange { arg function, from = 0, to; if(from <= indices.last) { if(to.isNil) { to = indices.size - 1 } { to = min(to, this.lastIndex) }; for(this.slotFor(from), to) { |i| function.value(array.at(i), indices.at(i), i) } } } keysValuesDo { arg function; indices.do { |index, i| function.value(index, array.at(i), i) } } size { ^indices.size } lastIndex { ^indices.last } // current write position pos { var index = this.lastIndex; ^if(index.isNil) { 0 } { index + 1 } } add { arg obj; array = array.add(obj); indices = indices.add(this.pos); } put { arg index, obj; this.prPutSlot(this.nextSlotFor(index), index, obj) } at { arg index; var slot = this.slotFor(index); ^if(slot.notNil) { if(indices.at(slot) == index) { array.at(slot) } } } removeAt { arg index, obj; var nextSlot = this.nextSlotFor(index), slot; ^if(nextSlot.notNil) { slot = max(0, nextSlot - 1); if(indices.at(slot) == index) { this.removeAtSlot(slot) } } } removeAtSlot { arg slot; indices.removeAt(slot); ^array.removeAt(slot) } pop { indices.pop; ^array.pop } collect { arg function; ^this.copy.array_(array.collect(function)); } select { arg function; var res = this.class.new; this.indicesDo { |item, i| if(function.value(item, i)) { res.put(i, item) } } ^res } reject { arg function; var res = this.class.new; this.indicesDo { |item, i| if(function.value(item, i).not) { res.put(i, item) } } ^res } removeAllSuchThat { arg function; var removedItems = this.class.new; var copy = this.copy; copy.indicesDo { | item, i | if ( function.value(item, i) ) { this.remove(item); removedItems = removedItems.put(i, item); } }; ^removedItems } selectInPlace { arg function; indices.copy.do { |index, i| if(function.value(array.at(i), index).not) { this.removeAtSlot(i) } } } rejectInPlace { arg function; indices.copy.do { |index, i| if(function.value(array.at(i), index)) { this.removeAtSlot(i) } } } indicesDo { arg function; indices.do { |slot, i| function.value(array.at(i), slot, i) } } // private implementation resetIndices { arg step = 1, offset = 0; indices = (offset, step .. indices.size - 1); } nextSlotFor { arg index; ^indices.indexOfGreaterThan(index) ?? { indices.size } } slotFor { arg index; ^max(0, this.nextSlotFor(index) - 1) } prPutSlot { arg nextSlot, index, obj; var slot = max(0, nextSlot - 1); if(indices.at(slot) == index) { array.put(slot, obj) } { array = array.insert(nextSlot, obj); indices = indices.insert(nextSlot, index); } } choose { ^array.choose } storeOn { arg stream; stream << this.class.name; stream << ".newFromIndices( " <<<* [ array, indices ] << " )"; } } SparseArray : Order { var <>default, <>defaultSize; *newClear { arg size, default; ^super.new(size).defaultSize_(size).default_(default) } *reduceArray { arg array, default; var res = this.new.default_(default); array.do { |item, i| res.putIfNotDefault(i, item) }; res.defaultSize = if(default.isNil) { res.size } { array.size }; ^res } clear { arg size; size = size.min(67108864 / 2); // For very large data we must assume sparse indices or we can't initialise the indices here array = Array.new(size); indices = Array.new(size); } putIfNotDefault { arg i, item; if(item != default) { this.put(i, item) } } copy { ^this.class.newCopyArgs(array.copy, indices.copy, default, defaultSize) } asArray { ^this[_] ! this.size } at { arg index; ^super.at(index) ? default } do { arg function; if(this.isEmpty) { ^this }; this.size.do { |i| function.value(this.at(i), i) } } size { var last = super.lastIndex ? (-1); ^if(defaultSize.isNil) { last + 1 } { max(last + 1, defaultSize) } } lastIndex { var last = super.lastIndex ? 0; ^if(defaultSize.isNil) { last } { max(last, defaultSize) } } // current write position pos { var index = super.lastIndex; ^if(index.isNil) { 0 } { index + 1 } } collect { arg function; ^this.class.reduceArray( this.asArray.collect(function), default !? { function.value(default, 0) } ) } select { arg function; ^this.class.reduceArray( this.asArray.select(function), if(default.notNil and: { function.value(default, 0) }) { default } ) } reject { arg function; ^this.class.reduceArray( this.asArray.reject(function), if(default.notNil and: { function.value(default, 0).not }) { default } ) } sum { | function | var sum = 0; ^if (function.isNil or: {function.numArgs < 2}) { // optimized version if no function, or if index is irrelevant this.sparseSum }{ this.do {|elem, i| sum = sum + function.value(elem, i); }; sum } } // if index is irrelevant, assume that the result for all implicit elements is the same sparseSum { | function | var sum = 0; "sparseSum : inner array size is %".format(array.size).postln; if (function.isNil) { // optimized version if no function array.do { | elem | sum = sum + elem; }; sum = sum + (default * (this.size-array.size)); }{ array.do {|elem| sum = sum + function.value(elem); }; sum = sum + (function.value(default) * (this.size-array.size)); } ^sum; } // does not pass the index to each default item: faster than collect sparseCollect { arg function; var res = super.collect(function); default !? { res.default = function.value(default) }; ^res } sparseSelect { arg function; var res = super.select(function); if(default.notNil and: { function.value(default, 0) }) { res.default = default } ^res } sparseReject { arg function; var res = super.reject(function); if(default.notNil and: { function.value(default, 0).not }) { res.default = default } ^res } sparseRemoveAt { arg index; ^super.removeAt(index) } sparseRemove { arg item; var index = super.indexOf(item); ^if(index.notNil) { super.removeAt(index) } { nil } } removeAt { arg index; //^this.notYetImplemented(thisMethod) var res, slot = this.slotFor(index), size = indices.size; if(index >= this.size) { ^nil }; if(indices[slot] == index) { res = this.removeAtSlot(slot); slot = slot - 1; } { if(size > 0) { res = default }; if(indices.first > index) { slot = -1 }; }; indices = indices[..slot] ++ (indices[slot+1..] - 1); if(defaultSize.notNil and: { defaultSize > 0 } and: { index < defaultSize }) { defaultSize = defaultSize - 1; }; ^res } firstGap { arg from = 0, to; if(indices.first == 0) { ^nil }; to = to ?? { indices.size }; (from..to).do { |i| if(indices[i] != i) { ^i }; }; ^nil } indexOf { arg item; var slot = array.indexOf(item), res; if(item == default) { res = this.firstGap(0, slot); if(res.notNil) { ^res }; }; ^if(slot.isNil) { nil } { indices[slot] } } compress { var ind, list, size = defaultSize ?? { this.size }; array.do { |item, i| if(item != default) { list = list.add(item); ind = ind.add(indices.at(i)) }; }; ^this.class.newFromIndices(list, ind).default_(default).defaultSize_(size) } pop { ^if(defaultSize.notNil and: { defaultSize > indices.last }) { defaultSize = defaultSize - 1; default } { super.pop } } ++ { arg coll; var res = this.copy.sparseAddAll(coll); if(defaultSize.notNil) { res.defaultSize_(this.size + coll.size) }; ^res } sparseAddAll { arg coll; var slot = this.size; coll.do { |item, i| if(item != default) { this.put(slot + i, item) } }; } putSeries { arg first, second, last, value; (first, second..last).do { |index| this.put(index, value) } } atSeries { arg first, second, last; ^(first, second..last).collect { |index| this.at(index) } } minItem { |function| ^if(function.isNil or: {function.numArgs < 2}){ if(array.size == this.size){ // full up! default not used (weird) array.minItem(function) }{ array.minItem(function).min(if(function.isNil, default, function.value(default))) } }{ super.minItem(function); } } maxItem { |function| ^if(function.isNil or: {function.numArgs < 2}){ if(array.size == this.size){ // full up! default not used (weird) array.maxItem(function) }{ array.maxItem(function).max(if(function.isNil, default, function.value(default))) } }{ super.maxItem(function); } } storeOn { | stream | if (stream.atLimit) { ^this }; stream << this.class.name << "[ " ; this.storeItemsOn(stream); stream << " ]" ; } // private implementation prPutSlot { arg nextSlot, index, obj; var slot = max(0, nextSlot - 1); index = index.asInteger; // SparseArray supports only integer indices if(indices.at(slot) == index) { array.put(slot, obj) } { array = array.insert(nextSlot, obj); indices = indices.insert(nextSlot, index); } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/ObjectTable.sc0000664000000000000000000000245212014636263030022 0ustar rootrootTwoWayIdentityDictionary : Collection { var idToObj, objToID; *new { ^super.new.init; } add { arg anAssociation; this.put(anAssociation.key, anAssociation.value); } put { arg key, obj; idToObj.put(key, obj); objToID.put(obj, key); } remove { arg obj; var key; key = this.getID(obj); idToObj.removeAt(key); objToID.removeAt(obj); } removeAt { arg key; var obj = this.at(key); idToObj.removeAt(key); objToID.removeAt(obj); } do { arg function; ^idToObj.do(function); } at { arg id; ^idToObj.at(id); } getID { arg obj; ^objToID.at(obj); } // PRIVATE init { idToObj = IdentityDictionary.new; objToID = IdentityDictionary.new; } } UniqueID { classvar =0) { ^this.copyRange(0, n-1) }{ size = this.size; ^this.copyRange(size+n, size-1) } } drop { arg n; var size = this.size; if (n>=0) { ^this.copyRange(n, size-1) }{ ^this.copyRange(0, size+n-1) } } copyToEnd { arg start; ^this.copyRange(start, this.size - 1) } copyFromStart { arg end; ^this.copyRange(0, end) } indexOf { arg item; this.do({ arg elem, i; if ( item === elem, { ^i }) }); ^nil } indexOfEqual { arg item, offset=0; (this.size - offset).do ({ arg i; i = i + offset; if ( item == this[i], { ^i }) }); ^nil } indicesOfEqual { |item| var indices; this.do { arg val, i; if (item == val) { indices = indices.add(i) } }; ^indices } find { |sublist, offset=0| var subSize_1 = sublist.size - 1, first = sublist.first, index; (this.size - offset).do { |i| index = i + offset; if (this[index] == first) { if (this.copyRange(index, index + subSize_1) == sublist) { ^index } }; }; ^nil } findAll { arg arr, offset=0; var indices, i=0; while { i = this.find(arr, offset); i.notNil }{ indices = indices.add(i); offset = i + 1; } ^indices } indexOfGreaterThan { arg val; ^this.detectIndex { |item| item > val }; } indexIn { arg val; // collection is sorted, returns closest index var i, a, b; var j = this.indexOfGreaterThan(val); if(j.isNil) { ^this.size - 1 }; if(j == 0) { ^j }; i = j - 1; ^if((val - this[i]) < (this[j] - val)) { i } { j } } indexInBetween { arg val; // collection is sorted, returns linearly interpolated index var a, b, div, i; if(this.isEmpty) { ^nil }; i = this.indexOfGreaterThan(val); if(i.isNil) { ^this.size - 1 }; if(i == 0) { ^i }; a = this[i-1]; b = this[i]; div = b - a; if(div == 0) { ^i }; ^((val - a) / div) + i - 1 } resamp0 { arg newSize; var factor = this.size - 1 / (newSize - 1); ^this.species.fill(newSize, { |i| this.at((i * factor).round(1.0).asInteger) }) } resamp1 { arg newSize; var factor = this.size - 1 / (newSize - 1); ^this.species.fill(newSize, { |i| this.blendAt(i * factor) }) } remove { arg item; var index = this.indexOf(item); ^if ( index.notNil, { this.removeAt(index); },{ nil }); } removing { arg item; var coll = this.copy; coll.remove(item); ^coll } take { arg item; var index = this.indexOf(item); ^if ( index.notNil, { this.takeAt(index); },{ nil }); } // accessing lastIndex { ^if(this.size > 0) { this.size - 1 } { nil } } middleIndex { ^if(this.size > 0) { (this.size - 1) div: 2 } { nil } } first { if (this.size > 0, { ^this.at(0) }, { ^nil }) } last { if (this.size > 0, { ^this.at(this.size - 1) }, { ^nil }) } middle { if (this.size > 0, { ^this.at((this.size - 1) div: 2) }, { ^nil }) } top { ^this.last } putFirst { arg obj; if (this.size > 0, { ^this.put(0, obj) }) } putLast { arg obj; if (this.size > 0, { ^this.put(this.size - 1, obj) }) } // compatibility with isolated objects obtain { arg index, default; ^this[index] ? default } instill { arg index, item, default; var res = if (index >= this.size) { this.extend(index + 1, default) }{ this.copy }; ^res.put(index, item) } // ordering pairsDo { arg function; forBy(0, this.size-2, 2) {|i| function.value(this[i], this[i+1], i); } } keysValuesDo { arg function; ^this.pairsDo(function) } doAdjacentPairs { arg function; (this.size - 1).do({ arg i; function.value(this.at(i), this.at(i+1), i); }) } separate { arg function = true; var list = Array.new; var sublist = this.species.new; this.doAdjacentPairs({ arg a, b, i; sublist = sublist.add(a); if ( function.value(a, b, i), { list = list.add(sublist); sublist = this.species.new; }); }); if(this.notEmpty) { sublist = sublist.add(this.last) }; list = list.add(sublist); ^list } delimit { arg function; var list, sublist; list = Array.new; sublist = this.species.new; this.do({ arg item, i; if ( function.value(item, i), { list = list.add(sublist); sublist = this.species.new; },{ sublist = sublist.add(item); }); }); list = list.add(sublist); ^list } clump { arg groupSize; var list = Array.new((this.size / groupSize).roundUp.asInteger); var sublist = this.species.new(groupSize); this.do({ arg item; sublist.add(item); if (sublist.size >= groupSize, { list.add(sublist); sublist = this.species.new(groupSize); }); }); if (sublist.size > 0, { list = list.add(sublist); }); ^list } clumps { arg groupSizeList; var i = 0; var list = Array.new(groupSizeList.size); // still better estimate than default var subSize = groupSizeList.at(0); var sublist = this.species.new(subSize); this.do({ arg item; sublist = sublist.add(item); if (sublist.size >= subSize, { i = i + 1; list = list.add(sublist); subSize = groupSizeList.wrapAt(i); sublist = this.species.new(subSize); }); }); if (sublist.size > 0, { list = list.add(sublist); }); ^list } curdle { arg probability; ^this.separate({ probability.coin }); } flatten { arg numLevels=1; var list; if (numLevels <= 0, { ^this }); numLevels = numLevels - 1; list = this.species.new; this.do({ arg item; if (item.respondsTo('flatten'), { list = list.addAll(item.flatten(numLevels)); },{ list = list.add(item); }); }); ^list } flat { ^this.prFlat(this.species.new(this.flatSize)) } prFlat { |list| this.do({ arg item, i; if (item.respondsTo('prFlat'), { list = item.prFlat(list); },{ list = list.add(item); }); }); ^list } flatIf { |func| var list = this.species.new(this.size); // as we don't know the size, just guess this.do({ arg item, i; if (item.respondsTo('flatIf') and: { func.value(item, i) }, { list = list.addAll(item.flatIf(func)); },{ list = list.add(item); }); }); ^list } flop { var list, size, maxsize; size = this.size; maxsize = 0; this.do({ arg sublist; var sz; sz = if(sublist.isSequenceableCollection, { sublist.size }, { 1 }); if (sz > maxsize, { maxsize = sz }); }); list = this.species.fill(maxsize, { this.species.new(size) }); this.do({ arg isublist, i; if(isublist.isSequenceableCollection, { list.do({ arg jsublist, j; jsublist.add( isublist.wrapAt(j) ); }); },{ list.do({ arg jsublist, j; jsublist.add( isublist ); }); }); }); ^list } flopWith { |func| var maxsize = this.maxValue { |sublist| if(sublist.isSequenceableCollection) { sublist.size } { 1 } }; ^this.species.fill(maxsize, { |i| func.value( *this.collect { |sublist| if(sublist.isSequenceableCollection) { sublist.wrapAt(i) } { sublist } }) }) } flopTogether { arg ... moreArrays; var standIn, maxSize = 0, array; array = [this] ++ moreArrays; array.do { |sublist| sublist.do { |each| maxSize = max(maxSize, each.size) } }; standIn = 0.dup(maxSize); array = array.collect { |sublist| sublist.add(standIn) }; ^array.collect { |sublist| sublist.flop.collect { |each| each.drop(-1) } // remove stand-in }; } flopDeep { arg rank; var size, maxsize; if(rank.isNil) { rank = this.maxDepth - 1 }; if(rank <= 1) { ^this.flop }; size = this.size; maxsize = this.maxSizeAtDepth(rank); ^this.species.fill(maxsize, { |i| this.wrapAtDepth(rank, i) }) } wrapAtDepth { arg rank, index; if(rank == 0) { ^this.wrapAt(index) }; ^this.collect { |item, i| if(item.isSequenceableCollection) { item.wrapAtDepth(rank - 1, index) } { item } } } unlace { arg numlists, clumpSize=1, clip=false; var size, list, sublist, self; size = (this.size + numlists - 1) div: numlists; list = this.species.fill(numlists, { this.species.new(size) }); self = if(clip) { this.keep(this.size.trunc(clumpSize * numlists).postln)} { this }; self.do({ arg item, i; sublist = list.at(i div: clumpSize % numlists); sublist.add(item); }); ^list } integrate { var list, sum = 0; list = this.class.new(this.size); this.do {|item| sum = sum + item; list.add( sum ); }; ^list } differentiate { var list, prev = 0; list = this.class.new(this.size); this.do {|item| list.add( item - prev ); prev = item; }; ^list } // complement to Integer:asDigits convertDigits { arg base=10; var lastIndex = this.lastIndex; ^this.sum { |x, i| if(x >= base) { Error("digit too large for base").throw }; base ** (lastIndex - i) * x }.asInteger } hammingDistance { |that| // if this is shorter than that, size difference should be included // (if this is longer, the do loop will take care of it) var count = (that.size - this.size).max(0); this.do({ |elem, i| if(elem != that[i]) { count = count + 1 }; }); ^count } // pitch operations degreeToKey { arg scale, stepsPerOctave=12; ^this.collect({ arg scaleDegree; scaleDegree.degreeToKey(scale, stepsPerOctave); }); } keyToDegree { arg scale, stepsPerOctave=12; ^this.collect { arg val; val.keyToDegree(scale, stepsPerOctave) } } nearestInScale { arg scale, stepsPerOctave=12; // collection is sorted var key, root; root = this.trunc(stepsPerOctave); key = this % stepsPerOctave; ^key.nearestInList(scale) + root } nearestInList { arg list; // collection is sorted ^this.collect({ arg item; list.at(list.indexIn(item)) }) } transposeKey { arg amount, octave=12; ^((this + amount) % octave).sort } mode { arg degree, octave=12; ^(rotate(this, degree.neg) - this.wrapAt(degree)) % octave } performDegreeToKey { arg scaleDegree, stepsPerOctave = 12, accidental = 0; var baseKey = (stepsPerOctave * (scaleDegree div: this.size)) + this.wrapAt(scaleDegree); ^if(accidental == 0) { baseKey } { baseKey + (accidental * (stepsPerOctave / 12.0)) } } performKeyToDegree { | degree, stepsPerOctave = 12 | var n = degree div: stepsPerOctave * this.size; var key = degree % stepsPerOctave; ^this.indexInBetween(key) + n } performNearestInList { | degree | ^this.at(this.indexIn(degree)) } performNearestInScale { arg degree, stepsPerOctave=12; // collection is sorted var root = degree.trunc(stepsPerOctave); var key = degree % stepsPerOctave; ^key.nearestInList(this) + root } // supports a variation of Mikael Laurson's rhythm list RTM-notation. convertRhythm { var list, tie; list = List.new; tie = this.convertOneRhythm(list); if (tie > 0.0, { list.add(tie) }); // check for tie at end of rhythm ^list } sumRhythmDivisions { var sum = 0; this.do {|beats| sum = sum + abs(if (beats.isSequenceableCollection) { beats[0]; }{ beats }); }; ^sum } convertOneRhythm { arg list, tie = 0.0, stretch = 1.0; var beats, divisions, repeats; #beats, divisions, repeats = this; repeats = repeats ? 1; stretch = stretch * beats / divisions.sumRhythmDivisions; repeats.do({ divisions.do { |val| if (val.isSequenceableCollection) { tie = val.convertOneRhythm(list, tie, stretch) }{ val = val * stretch; if (val > 0.0) { list.add(val + tie); tie = 0.0; }{ tie = tie - val }; }; }; }); ^tie } isSequenceableCollection { ^true } containsSeqColl { ^this.any(_.isSequenceableCollection) } // unary math ops neg { ^this.performUnaryOp('neg') } bitNot { ^this.performUnaryOp('bitNot') } abs { ^this.performUnaryOp('abs') } ceil { ^this.performUnaryOp('ceil') } floor { ^this.performUnaryOp('floor') } frac { ^this.performUnaryOp('frac') } sign { ^this.performUnaryOp('sign') } squared { ^this.performUnaryOp('squared') } cubed { ^this.performUnaryOp('cubed') } sqrt { ^this.performUnaryOp('sqrt') } exp { ^this.performUnaryOp('exp') } reciprocal { ^this.performUnaryOp('reciprocal') } midicps { ^this.performUnaryOp('midicps') } cpsmidi { ^this.performUnaryOp('cpsmidi') } midiratio { ^this.performUnaryOp('midiratio') } ratiomidi { ^this.performUnaryOp('ratiomidi') } ampdb { ^this.performUnaryOp('ampdb') } dbamp { ^this.performUnaryOp('dbamp') } octcps { ^this.performUnaryOp('octcps') } cpsoct { ^this.performUnaryOp('cpsoct') } log { ^this.performUnaryOp('log') } log2 { ^this.performUnaryOp('log2') } log10 { ^this.performUnaryOp('log10') } sin { ^this.performUnaryOp('sin') } cos { ^this.performUnaryOp('cos') } tan { ^this.performUnaryOp('tan') } asin { ^this.performUnaryOp('asin') } acos { ^this.performUnaryOp('acos') } atan { ^this.performUnaryOp('atan') } sinh { ^this.performUnaryOp('sinh') } cosh { ^this.performUnaryOp('cosh') } tanh { ^this.performUnaryOp('tanh') } rand { ^this.performUnaryOp('rand') } rand2 { ^this.performUnaryOp('rand2') } linrand { ^this.performUnaryOp('linrand') } bilinrand { ^this.performUnaryOp('bilinrand') } sum3rand { ^this.performUnaryOp('sum3rand') } distort { ^this.performUnaryOp('distort') } softclip { ^this.performUnaryOp('softclip') } coin { ^this.performUnaryOp('coin') } even { ^this.performUnaryOp('even') } odd { ^this.performUnaryOp('odd') } isPositive { ^this.performUnaryOp('isPositive') } isNegative { ^this.performUnaryOp('isNegative') } isStrictlyPositive { ^this.performUnaryOp('isStrictlyPositive') } rectWindow { ^this.performUnaryOp('rectWindow') } hanWindow { ^this.performUnaryOp('hanWindow') } welWindow { ^this.performUnaryOp('welWindow') } triWindow { ^this.performUnaryOp('triWindow') } scurve { ^this.performUnaryOp('scurve') } ramp { ^this.performUnaryOp('ramp') } asFloat { ^this.performUnaryOp('asFloat') } asInteger { ^this.performUnaryOp('asInteger') } nthPrime { ^this.performUnaryOp('nthPrime') } prevPrime { ^this.performUnaryOp('prevPrime') } nextPrime { ^this.performUnaryOp('nextPrime') } indexOfPrime { ^this.performUnaryOp('indexOfPrime') } real { ^this.performUnaryOp('real') } imag { ^this.performUnaryOp('imag') } magnitude { ^this.performUnaryOp('magnitude') } magnitudeApx { ^this.performUnaryOp('magnitudeApx') } phase { ^this.performUnaryOp('phase') } angle { ^this.performUnaryOp('angle') } rho { ^this.performUnaryOp('rho') } theta { ^this.performUnaryOp('theta') } degrad { ^this.performUnaryOp('degrad') } raddeg { ^this.performUnaryOp('raddeg') } // binary math ops + { arg aNumber, adverb; ^this.performBinaryOp('+', aNumber, adverb) } - { arg aNumber, adverb; ^this.performBinaryOp('-', aNumber, adverb) } * { arg aNumber, adverb; ^this.performBinaryOp('*', aNumber, adverb) } / { arg aNumber, adverb; ^this.performBinaryOp('/', aNumber, adverb) } div { arg aNumber, adverb; ^this.performBinaryOp('div', aNumber, adverb) } mod { arg aNumber, adverb; ^this.performBinaryOp('mod', aNumber, adverb) } pow { arg aNumber, adverb; ^this.performBinaryOp('pow', aNumber, adverb) } min { arg aNumber, adverb; ^this.performBinaryOp('min', aNumber, adverb) } max { arg aNumber=0, adverb; ^this.performBinaryOp('max', aNumber, adverb) } < { arg aNumber, adverb; ^this.performBinaryOp('<', aNumber, adverb) } <= { arg aNumber, adverb; ^this.performBinaryOp('<=', aNumber, adverb) } > { arg aNumber, adverb; ^this.performBinaryOp('>', aNumber, adverb) } >= { arg aNumber, adverb; ^this.performBinaryOp('>=', aNumber, adverb) } bitAnd { arg aNumber, adverb; ^this.performBinaryOp('bitAnd', aNumber, adverb) } bitOr { arg aNumber, adverb; ^this.performBinaryOp('bitOr', aNumber, adverb) } bitXor { arg aNumber, adverb; ^this.performBinaryOp('bitXor', aNumber, adverb) } bitHammingDistance { arg aNumber, adverb; ^this.performBinaryOp('hammingDistance', aNumber, adverb) } lcm { arg aNumber, adverb; ^this.performBinaryOp('lcm', aNumber, adverb) } gcd { arg aNumber, adverb; ^this.performBinaryOp('gcd', aNumber, adverb) } round { arg aNumber=1, adverb; ^this.performBinaryOp('round', aNumber, adverb) } roundUp { arg aNumber=1, adverb; ^this.performBinaryOp('roundUp', aNumber, adverb) } trunc { arg aNumber=1, adverb; ^this.performBinaryOp('trunc', aNumber, adverb) } atan2 { arg aNumber, adverb; ^this.performBinaryOp('atan2', aNumber, adverb) } hypot { arg aNumber, adverb; ^this.performBinaryOp('hypot', aNumber, adverb) } hypotApx { arg aNumber, adverb; ^this.performBinaryOp('hypotApx', aNumber, adverb) } leftShift { arg aNumber, adverb; ^this.performBinaryOp('leftShift', aNumber, adverb) } rightShift { arg aNumber, adverb; ^this.performBinaryOp('rightShift', aNumber, adverb) } unsignedRightShift { arg aNumber, adverb; ^this.performBinaryOp('unsignedRightShift', aNumber, adverb) } ring1 { arg aNumber, adverb; ^this.performBinaryOp('ring1', aNumber, adverb) } ring2 { arg aNumber, adverb; ^this.performBinaryOp('ring2', aNumber, adverb) } ring3 { arg aNumber, adverb; ^this.performBinaryOp('ring3', aNumber, adverb) } ring4 { arg aNumber, adverb; ^this.performBinaryOp('ring4', aNumber, adverb) } difsqr { arg aNumber, adverb; ^this.performBinaryOp('difsqr', aNumber, adverb) } sumsqr { arg aNumber, adverb; ^this.performBinaryOp('sumsqr', aNumber, adverb) } sqrsum { arg aNumber, adverb; ^this.performBinaryOp('sqrsum', aNumber, adverb) } sqrdif { arg aNumber, adverb; ^this.performBinaryOp('sqrdif', aNumber, adverb) } absdif { arg aNumber, adverb; ^this.performBinaryOp('absdif', aNumber, adverb) } thresh { arg aNumber, adverb; ^this.performBinaryOp('thresh', aNumber, adverb) } amclip { arg aNumber, adverb; ^this.performBinaryOp('amclip', aNumber, adverb) } scaleneg { arg aNumber, adverb; ^this.performBinaryOp('scaleneg', aNumber, adverb) } clip2 { arg aNumber=1, adverb; ^this.performBinaryOp('clip2', aNumber, adverb) } fold2 { arg aNumber, adverb; ^this.performBinaryOp('fold2', aNumber, adverb) } wrap2 { arg aNumber, adverb; ^this.performBinaryOp('wrap2', aNumber, adverb) } excess { arg aNumber, adverb; ^this.performBinaryOp('excess', aNumber, adverb) } firstArg { arg aNumber, adverb; ^this.performBinaryOp('firstArg', aNumber, adverb) } rrand { arg aNumber, adverb; ^this.performBinaryOp('rrand', aNumber, adverb) } exprand { arg aNumber, adverb; ^this.performBinaryOp('exprand', aNumber, adverb) } // math op dispatch support performUnaryOp { arg aSelector; ^this.collect({ arg item; item.perform(aSelector) }); } performBinaryOp { arg aSelector, theOperand, adverb; ^theOperand.performBinaryOpOnSeqColl(aSelector, this, adverb); } performBinaryOpOnSeqColl { arg aSelector, theOperand, adverb; var size, newList; if (adverb == nil) { size = this.size max: theOperand.size; newList = this.species.new(size); size.do({ arg i; newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i))); }); ^newList }; if (adverb.isInteger) { if (adverb == 0) { size = this.size max: theOperand.size; newList = this.species.new(size); size.do({ arg i; newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i))); }); ^newList }{ if (adverb > 0) { ^theOperand.collect {|item, i| item.perform(aSelector, this, adverb-1) } }{ ^this.collect {|item, i| theOperand.perform(aSelector, item, adverb+1) } } } }; if (adverb == 't') { // size = this.size; // newList = this.species.new(size); // size.do({ arg i; // newList.add(theOperand.perform(aSelector, this.at(i))); // }); // ^newList size = theOperand.size; newList = this.species.new(size); size.do({ arg i; newList.add(theOperand.at(i).perform(aSelector, this)); }); ^newList }; if (adverb == 'x') { // size = this.size; // newList = this.species.new(size); // size.do({ arg i; // newList.add(theOperand.perform(aSelector, this.at(i))); // }); // ^newList size = theOperand.size * this.size; newList = this.species.new(size); theOperand.do({ arg a; this.do({ arg b; newList.add(a.perform(aSelector, b)); }); }); ^newList }; if (adverb == 's') { size = this.size min: theOperand.size; newList = this.species.new(size); size.do({ arg i; newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i))); }); ^newList }; if (adverb == 'f') { size = this.size max: theOperand.size; newList = this.species.new(size); size.do({ arg i; newList.add(theOperand.foldAt(i).perform(aSelector, this.foldAt(i))); }); ^newList }; Error("unrecognized adverb: '" ++ adverb ++ "' for operator '" ++ aSelector ++ "'\n").throw; ^nil } performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb; ^this.collect({ arg item; aNumber.perform(aSelector, item, adverb) }) } performBinaryOpOnComplex { arg aSelector, aComplex, adverb; ^this.collect({ arg item; aComplex.perform(aSelector, item, adverb) }) } asFraction { arg denominator=100, fasterBetter=true; ^this.collect { |item| item.asFraction(denominator, fasterBetter) } } asPoint { ^Point(this[0] ? 0, this[1] ? 0) } asRect { ^Rect(this[0] ? 0, this[1] ? 0, this[2] ? 0, this[3] ? 0) } ascii { ^this.collect { arg item; item.ascii } } // support UGen rate access rate { var rate, rates; if(this.size == 1, { ^this.first.rate }); ^this.collect({ arg item; item.rate }).minItem; // 'scalar' > 'control' > 'audio' } // if we don't catch the special case of an empty array, // Object:multiChannelPerform goes into infinite recursion multiChannelPerform { arg selector ... args; if(this.size > 0) { ^super.multiChannelPerform(selector, *args); } { ^this.class.new } } // this method is for UGen inputs that require Refs to block direct multichannel expansion. // here, we assume this is already an array of Refs, which we simply return. multichannelExpandRef { arg rank; ^this } // support some UGen convenience methods. // NOTE: don't forget to add a wrapper here when adding a method to UGen or AbstractFunction clip { arg ... args; ^this.multiChannelPerform('clip', *args) } wrap { arg ... args; ^this.multiChannelPerform('wrap', *args) } fold { arg ... args; ^this.multiChannelPerform('fold', *args) } linlin { arg ... args; ^this.multiChannelPerform('linlin', *args) } linexp { arg ... args; ^this.multiChannelPerform('linexp', *args) } explin { arg ... args; ^this.multiChannelPerform('explin', *args) } expexp { arg ... args; ^this.multiChannelPerform('expexp', *args) } lincurve { arg ... args; ^this.multiChannelPerform('lincurve', *args) } curvelin { arg ... args; ^this.multiChannelPerform('curvelin', *args) } bilin { arg ... args; ^this.multiChannelPerform('bilin', *args) } biexp { arg ... args; ^this.multiChannelPerform('biexp', *args) } range { arg ... args; ^this.multiChannelPerform('range', *args) } exprange { arg ... args; ^this.multiChannelPerform('exprange', *args) } unipolar { arg ... args; ^this.multiChannelPerform('unipolar', *args) } bipolar { arg ... args; ^this.multiChannelPerform('bipolar', *args) } lag { arg ... args; ^this.multiChannelPerform('lag', *args) } lag2 { arg ... args; ^this.multiChannelPerform('lag2', *args) } lag3 { arg ... args; ^this.multiChannelPerform('lag3', *args) } lagud { arg ... args; ^this.multiChannelPerform('lagud', *args) } lag2ud { arg ... args; ^this.multiChannelPerform('lag2ud', *args) } lag3ud { arg ... args; ^this.multiChannelPerform('lag3ud', *args) } varlag { arg ... args; ^this.multiChannelPerform('varlag', *args) } slew { arg ... args; ^this.multiChannelPerform('slew', *args) } blend { arg ... args; ^this.multiChannelPerform('blend', *args) } checkBadValues { arg ... args; ^this.multiChannelPerform('checkBadValues', *args) } prune { arg ... args; ^this.multiChannelPerform('prune', *args) } minNyquist { ^min(this, SampleRate.ir * 0.5) } // sorting sort { arg function; if (function.isNil) { function = { arg a, b; a <= b }; }; ^this.mergeSort(function) } sortBy { arg key; ^this.sort({| a, b | a[key] <= b[key] }) } sortMap { arg function; ^this.sort({| a, b | function.value(a) <= function.value(b) }) } sortedMedian { var index; if (this.size.odd) { ^this.middle }{ index = this.middleIndex; ^(this[index] + this[index+1]) / 2; } } median { arg function; //^this.sort(function).sortedMedian // Note the copy, to prevent changing the input. ^this.copy.hoareMedian(function) } quickSort { arg function; this.quickSortRange(0, this.size - 1, function) } order { arg function; var array, orderFunc; // returns an array of indices that would sort the collection into order. if(this.isEmpty) { ^[] }; if (function.isNil) { function = { arg a, b; a <= b }; }; array = [this, (0..this.lastIndex)].flop; orderFunc = {|a,b| function.value(a[0], b[0]) }; ^array.mergeSort(orderFunc).flop[1] } swap { arg i, j; var temp; temp = this[i]; this[i] = this[j]; this[j] = temp; } quickSortRange { arg i, j, function; //Sort elements i through j of this to be nondescending according to // function. var di, dij, dj, tt, ij, k, l, n; // The prefix d means the data at that index. if ((n = j + 1 - i) <= 1, { ^this }); // Nothing to sort. //Sort di,dj. di = this.at(i); dj = this.at(j); if (function.value(di, dj).not, { // i.e., should di precede dj? this.swap(i,j); tt = di; di = dj; dj = tt; }); if ( n > 2, { // More than two elements. ij = (i + j) div: 2; // ij is the midpoint of i and j. dij = this.at(ij); // Sort di,dij,dj. Make dij be their median. if (function.value(di, dij), { // i.e. should di precede dij? if (function.value(dij, dj).not, { // i.e., should dij precede dj? this.swap(j, ij); dij = dj; }) },{ // i.e. di should come after dij" this.swap(i, ij); dij = di; }); if ( n > 3, { // More than three elements. // Find k>i and l> 1; this.mergeSortTemp(function, tempArray, left, mid); this.mergeSortTemp(function, tempArray, mid+1, right); this.mergeTemp(function, tempArray, left, mid+1, right); } mergeTemp { arg function, tempArray, left, mid, right; var i, leftEnd, size, tempPos; leftEnd = mid - 1; tempPos = left; size = right - left + 1; while { (left <= leftEnd) && (mid <= right) } { if (function.value( this[left], this[mid] )) { tempArray[tempPos] = this[left]; tempPos = tempPos + 1; left = left + 1; } { tempArray[tempPos] = this[mid]; tempPos = tempPos + 1; mid = mid + 1; } }; while { left <= leftEnd } { tempArray[tempPos] = this[left]; tempPos = tempPos + 1; left = left + 1; }; while { mid <= right } { tempArray[tempPos] = this[mid]; tempPos = tempPos + 1; mid = mid + 1; }; size.do { this[right] = tempArray[right]; right = right - 1; }; } insertionSort { arg function; ^this.insertionSortRange(function, 0, this.size - 1) } insertionSortRange { arg function, left, right; var i, j, test; i = left + 1; while { i <= right } { test = this[i]; j = i; while { (j > left) && { function.value(this[j-1], test).not } } { this[j] = this[j-1]; j = j - 1; }; this[j] = test; i = i + 1; } } // Finds the median efficiently, by rearranging the array IN-PLACE. hoareMedian { |function| if(this.isEmpty) { ^nil }; ^if(this.size.even, { [this.hoareFind(this.size/ 2 - 1, function), this.hoareFind(this.size/ 2, function)].mean; }, { this.hoareFind(this.size - 1 / 2, function); }); } // Finds the kth element in the array, according to a given sorting function. // This is typically fast (order is O(n) rather than O(n log n)) because it // doesn't attempt to completely sort the array. Method is due to C. A. F. Hoare. // Note: this rearranges array elements IN PLACE. hoareFind { |k, function, left, right| var i,j,p,r,l; if (function.isNil) { function = { | a, b | a < b } }; i = left ? 0; j = right ?? {this.size-1}; while{ i < j }{ p = this[k]; # l, r = this.hoarePartition(i,j,p, function); if(r < k, { // kth smallest is in right split i = l; }); if(k < l, { // kth smallest is in left split j = r; }); }; // The desired element is in desired position ^this[k]; } // In-place partitioning method used by hoareFind. // Note: for efficiency this doesn't check that function is defined, so you // must supply a function! See hoareFind for example hoarePartition { |l0, r0, p, function| var l, r, tmp; l = l0; r = r0; while({ l <= r }, { // left_scan while { (l < this.size) and: { function.value(this[l], p) } }{ l = l + 1; }; // right_scan while { (r >= 0) and: { function.value(p, this[r]) } }{ r = r - 1; }; // check and exchange if(l <= r){ tmp = this[l]; this[l] = this[r]; this[r] = tmp; // then l = l + 1; r = r - 1; }; }); ^[l,r]; } // streaming *streamContents { arg function; var stream; stream = CollStream.on(this.new(100)); function.value(stream); ^stream.contents } *streamContentsLimit { arg function, limit=2000; var stream; stream = LimitedWriteStream.on(this.new(100 min: limit)); stream.limit_(limit).limitFunc_({ ^stream.contents }); function.value(stream); ^stream.contents } wrapAt { arg index; index = index % this.size; ^this.at(index) } wrapPut { arg index, value; index = index % this.size; ^this.put(index, value) } reduce { arg operator; var once = true, result; if(this.size==1){ ^this[0] }; this.doAdjacentPairs {|a, b| if (once) { once = false; result = operator.applyTo(a, b); }{ result = operator.applyTo(result, b); }; }; ^result } join { arg joiner; ^String.streamContents { arg stream; var stop; if(joiner.isNil) { this.do { arg item; stream << item }; } { stop = this.size - 1; this.do { arg item,i; stream << item; if(i < stop) { stream << joiner }; }; } } } // TempoClock play quantization nextTimeOnGrid { arg clock; ^clock.nextTimeOnGrid(*this); } // we break up the array so that missing elements are set to nil in the Quant asQuant { ^Quant(*this) } // asUGenInput { ^this.asArray.asUGenInput } schedBundleArrayOnClock { |clock, bundleArray, lag = 0, server, latency| latency = latency ? server.latency; if (lag != 0) { lag = lag.asArray; this.do { |time, i| clock.sched(time, { SystemClock.sched(lag.wrapAt(i), { server.sendBundle(latency, bundleArray.wrapAt(i)) }) }) } } { this.do { |time, i| clock.sched(time, { server.sendBundle(latency, bundleArray.wrapAt(i)) }) } } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Scale.sc0000664000000000000000000005052112245365552026701 0ustar rootrootScale { var name; *new { | degrees, pitchesPerOctave, tuning, name = "Unknown Scale" | ^super.new.init(degrees ? \ionian, pitchesPerOctave, tuning, name); } init { | inDegrees, inPitchesPerOctave, inTuning, inName | degrees = Int32Array.newFrom(inDegrees.asArray.asInteger); pitchesPerOctave = inPitchesPerOctave ? this.guessPPO(degrees); name = inName; ^this.tuning_(inTuning ? Tuning.default(pitchesPerOctave)); } *newFromKey { |key, tuning| var scale = ScaleInfo.at(key); scale ?? { ("Unknown scale " ++ key.asString).warn; ^nil }; tuning !? { scale.tuning_(tuning.asTuning) }; ^scale } checkTuningForMismatch { |aTuning| ^pitchesPerOctave == aTuning.size; } tuning_ { | inTuning | inTuning = inTuning.asTuning; if(this.checkTuningForMismatch(inTuning)) { tuning = inTuning } { "Scale steps per octave % does not match tuning size ".format(pitchesPerOctave).warn; } } guessPPO { // most common flavors of ET // pick the smallest one that contains all scale degrees var etTypes = #[12, 19, 24, 53, 128]; ^etTypes[etTypes.indexInBetween(degrees.maxItem).ceil]; } as { |class| ^this.semitones.as(class) } size { ^degrees.size } semitones { ^degrees.collect(tuning.wrapAt(_)); } cents { ^this.semitones * 100 } ratios { ^this.semitones.midiratio } at { |index| ^tuning.at(degrees.wrapAt(index)) } wrapAt { |index| ^tuning.wrapAt(degrees.wrapAt(index)) } performDegreeToKey { | scaleDegree, stepsPerOctave, accidental = 0 | var baseKey; stepsPerOctave = stepsPerOctave ? tuning.stepsPerOctave; baseKey = (stepsPerOctave * (scaleDegree div: this.size)) + this.wrapAt(scaleDegree); ^if(accidental == 0) { baseKey } { baseKey + (accidental * (stepsPerOctave / 12.0)) } } performKeyToDegree { | degree, stepsPerOctave = 12 | ^degrees.performKeyToDegree(degree, stepsPerOctave) } performNearestInList { | degree | ^degrees.performNearestInList(degree) } performNearestInScale { | degree, stepsPerOctave=12 | // collection is sorted ^degrees.performNearestInScale(degree, stepsPerOctave) } degreeToRatio { |degree, octave = 0| octave = octave + (degree div: degrees.size); ^this.ratios.wrapAt(degree) * (this.octaveRatio ** octave); } degreeToFreq { |degree, rootFreq, octave| ^this.degreeToRatio(degree, octave) * rootFreq; } *choose { |size = 7, pitchesPerOctave = 12| var scale = ScaleInfo.choose({ |x| (x.size == size) && (x.pitchesPerOctave == pitchesPerOctave) }); scale.isNil.if({ ("No known scales with size " ++ size.asString ++ " and pitchesPerOctave " ++ pitchesPerOctave.asString).warn; ^nil }); ^scale } *doesNotUnderstand { |selector, args| var scale = this.newFromKey(selector, args); ^scale ?? { super.doesNotUnderstand(selector, args) }; } *directory { ^ScaleInfo.directory } octaveRatio { ^tuning.octaveRatio } stepsPerOctave { ^tuning.stepsPerOctave } == { arg that; ^this.compareObject(that, #[\degrees, \tuning]) } hash { ^this.instVarHash(#[\degrees, \tuning]) } storeOn { |stream| var storedKey = this.storedKey; stream << this.class.name; if(storedKey.notNil) { stream << "." << storedKey } { this.storeParamsOn(stream) } } storedKey { // can be optimised later var stored = ScaleInfo.scales.detect(_ == this); ^stored !? { ScaleInfo.scales.findKeyForValue(stored) } } storeArgs { ^[degrees, pitchesPerOctave, tuning, name] } printOn { |stream| this.storeOn(stream) } } Tuning { var name; *new { | tuning, octaveRatio = 2.0, name = "Unknown Tuning" | ^super.newCopyArgs(DoubleArray.newFrom(tuning), octaveRatio, name); } *newFromKey { | key | ^TuningInfo.at(key) } *default { | pitchesPerOctave | ^this.et(pitchesPerOctave); } *et { |pitchesPerOctave = 12 | ^this.new(this.calcET(pitchesPerOctave), 2.0, this.etName(pitchesPerOctave)); } *calcET { | pitchesPerOctave | ^(0..(pitchesPerOctave - 1)) * (12/pitchesPerOctave) } *etName { |pitchesPerOctave| ^"ET" ++ pitchesPerOctave.asString } *choose { |size = 12| ^TuningInfo.choose({ |x| x.size == size }) } ratios { ^tuning.midiratio } semitones { ^tuning } cents { ^this.semitones * 100 } as { |class| ^this.semitones.as(class) } size { ^tuning.size } at { |index| ^tuning.at(index) } wrapAt { |index| ^tuning.wrapAt(index) } == { |argTuning| ^this.compareObject(argTuning, #[\tuning, \octaveRatio]) } hash { ^this.instVarHash([\tuning, \octaveRatio]) } *doesNotUnderstand { |selector, args| var tuning = this.newFromKey(selector, args); ^tuning ?? { super.doesNotUnderstand(selector, args) } } *directory { ^TuningInfo.directory } stepsPerOctave { ^octaveRatio.log2 * 12.0 } asTuning { ^this } printOn { |stream| this.storeOn(stream) } storeOn { |stream| var storedKey = this.storedKey; stream << this.class.name; if(storedKey.notNil) { stream << "." << storedKey } { this.storeParamsOn(stream) } } storedKey { // can be optimised later var stored = TuningInfo.tunings.detect(_ == this); ^stored !? { TuningInfo.tunings.findKeyForValue(stored) } } storeArgs { ^[tuning, octaveRatio, name] } } ScaleAD : Scale { var <>descScale; *new { | degrees, pitchesPerOctave, descDegrees, tuning, name = "Unknown Scale" | ^super.new.init(degrees ? \ionian, pitchesPerOctave, tuning, name) .descScale_(Scale(descDegrees ? \ionian, pitchesPerOctave, tuning, name ++ "desc")) ; } asStream { ^ScaleStream(this, 0) } embedInStream { ScaleStream(this).yield } } ScaleStream { var <>scale, <>curDegree; *new { | scale, startDegree = 0 | ^super.newCopyArgs(scale, startDegree) } chooseScale { |scaleDegree | if (scaleDegree >= curDegree) { curDegree = scaleDegree; ^scale } { curDegree = scaleDegree; ^scale.descScale } } performDegreeToKey { | degree, stepsPerOctave, accidental = 0 | ^this.chooseScale(degree).performDegreeToKey(degree, stepsPerOctave, accidental); } performKeyToDegree { | degree, stepsPerOctave = 12 | ^this.chooseScale(degree).performKeyToDegree(degree, stepsPerOctave) } performNearestInList { | degree | ^this.chooseScale(degree).performNearestInList(degree) } performNearestInScale { | degree, stepsPerOctave=12 | // collection is sorted ^this.chooseScale(degree).performNearestInScale(degree, stepsPerOctave) } } ScaleInfo { classvar Scale.new(#[0,3,5,7,10], 12, name: "Minor Pentatonic"), \majorPentatonic -> Scale.new(#[0,2,4,7,9], 12, name: "Major Pentatonic"), // another mode of major pentatonic \ritusen -> Scale.new(#[0,2,5,7,9], 12, name: "Ritusen"), // another mode of major pentatonic \egyptian -> Scale.new(#[0,2,5,7,10], 12, name: "Egyptian"), \kumoi -> Scale.new(#[0,2,3,7,9], 12, name: "Kumai"), \hirajoshi -> Scale.new(#[0,2,3,7,8], 12, name: "Hirajoshi"), \iwato -> Scale.new(#[0,1,5,6,10], 12, name: "Iwato"), // mode of hirajoshi \chinese -> Scale.new(#[0,4,6,7,11], 12, name: "Chinese"), // mode of hirajoshi \indian -> Scale.new(#[0,4,5,7,10], 12, name: "Indian"), \pelog -> Scale.new(#[0,1,3,7,8], 12, name: "Pelog"), \prometheus -> Scale.new(#[0,2,4,6,11], 12, name: "Prometheus"), \scriabin -> Scale.new(#[0,1,4,7,9], 12, name: "Scriabin"), // han chinese pentatonic scales \gong -> Scale.new(#[0,2,4,7,9], 12, name: "Gong"), \shang -> Scale.new(#[0,2,5,7,10], 12, name: "Shang"), \jiao -> Scale.new(#[0,3,5,8,10], 12, name: "Jiao"), \zhi -> Scale.new(#[0,2,5,7,9], 12, name: "Zhi"), \yu -> Scale.new(#[0,3,5,7,10], 12, name: "Yu"), // 6 note scales \whole -> Scale.new((0,2..10), 12, name: "Whole Tone"), \augmented -> Scale.new(#[0,3,4,7,8,11], 12, name: "Augmented"), \augmented2 -> Scale.new(#[0,1,4,5,8,9], 12, name: "Augmented 2"), // Partch's Otonalities and Utonalities \partch_o1 -> Scale.new(#[0,8,14,20,25,34], 43, Tuning.partch, "Partch Otonality 1"), \partch_o2 -> Scale.new(#[0,7,13,18,27,35], 43, Tuning.partch, "Partch Otonality 2"), \partch_o3 -> Scale.new(#[0,6,12,21,29,36], 43, Tuning.partch, "Partch Otonality 3"), \partch_o4 -> Scale.new(#[0,5,15,23,30,37], 43, Tuning.partch, "Partch Otonality 4"), \partch_o5 -> Scale.new(#[0,10,18,25,31,38], 43, Tuning.partch, "Partch Otonality 5"), \partch_o6 -> Scale.new(#[0,9,16,22,28,33], 43, Tuning.partch, "Partch Otonality 6"), \partch_u1 -> Scale.new(#[0,9,18,23,29,35], 43, Tuning.partch, "Partch Utonality 1"), \partch_u2 -> Scale.new(#[0,8,16,25,30,36], 43, Tuning.partch, "Partch Utonality 2"), \partch_u3 -> Scale.new(#[0,7,14,22,31,37], 43, Tuning.partch, "Partch Utonality 3"), \partch_u4 -> Scale.new(#[0,6,13,20,28,38], 43, Tuning.partch, "Partch Utonality 4"), \partch_u5 -> Scale.new(#[0,5,12,18,25,33], 43, Tuning.partch, "Partch Utonality 5"), \partch_u6 -> Scale.new(#[0,10,15,21,27,34], 43, Tuning.partch, "Partch Utonality 6"), // hexatonic modes with no tritone \hexMajor7 -> Scale.new(#[0,2,4,7,9,11], 12, name: "Hex Major 7"), \hexDorian -> Scale.new(#[0,2,3,5,7,10], 12, name: "Hex Dorian"), \hexPhrygian -> Scale.new(#[0,1,3,5,8,10], 12, name: "Hex Phrygian"), \hexSus -> Scale.new(#[0,2,5,7,9,10], 12, name: "Hex Sus"), \hexMajor6 -> Scale.new(#[0,2,4,5,7,9], 12, name: "Hex Major 6"), \hexAeolian -> Scale.new(#[0,3,5,7,8,10], 12, name: "Hex Aeolian"), // 7 note scales \major -> Scale.new(#[0,2,4,5,7,9,11], 12, name: "Major"), \ionian -> Scale.new(#[0,2,4,5,7,9,11], 12, name: "Ionian"), \dorian -> Scale.new(#[0,2,3,5,7,9,10], 12, name: "Dorian"), \phrygian -> Scale.new(#[0,1,3,5,7,8,10], 12, name: "Phrygian"), \lydian -> Scale.new(#[0,2,4,6,7,9,11], 12, name: "Lydian"), \mixolydian -> Scale.new(#[0,2,4,5,7,9,10], 12, name: "Mixolydian"), \aeolian -> Scale.new(#[0,2,3,5,7,8,10], 12, name: "Aeolian"), \minor -> Scale.new(#[0,2,3,5,7,8,10], 12, name: "Natural Minor"), \locrian -> Scale.new(#[0,1,3,5,6,8,10], 12, name: "Locrian"), \harmonicMinor -> Scale.new(#[0,2,3,5,7,8,11], 12, name: "Harmonic Minor"), \harmonicMajor -> Scale.new(#[0,2,4,5,7,8,11], 12, name: "Harmonic Major"), \melodicMinor -> Scale.new(#[0,2,3,5,7,9,11], 12, name: "Melodic Minor"), \melodicMinorDesc -> Scale.new(#[0,2,3,5,7,8,10], 12, name: "Melodic Minor Descending"), \melodicMajor -> Scale.new(#[0,2,4,5,7,8,10], 12, name: "Melodic Major"), \bartok -> Scale.new(#[0,2,4,5,7,8,10], 12, name: "Bartok"), \hindu -> Scale.new(#[0,2,4,5,7,8,10], 12, name: "Hindu"), // raga modes \todi -> Scale.new(#[0,1,3,6,7,8,11], 12, name: "Todi"), \purvi -> Scale.new(#[0,1,4,6,7,8,11], 12, name: "Purvi"), \marva -> Scale.new(#[0,1,4,6,7,9,11], 12, name: "Marva"), \bhairav -> Scale.new(#[0,1,4,5,7,8,11], 12, name: "Bhairav"), \ahirbhairav -> Scale.new(#[0,1,4,5,7,9,10], 12, name: "Ahirbhairav"), \superLocrian -> Scale.new(#[0,1,3,4,6,8,10], 12, name: "Super Locrian"), \romanianMinor -> Scale.new(#[0,2,3,6,7,9,10], 12, name: "Romanian Minor"), \hungarianMinor -> Scale.new(#[0,2,3,6,7,8,11], 12, name: "Hungarian Minor"), \neapolitanMinor -> Scale.new(#[0,1,3,5,7,8,11], 12, name: "Neapolitan Minor"), \enigmatic -> Scale.new(#[0,1,4,6,8,10,11], 12, name: "Enigmatic"), \spanish -> Scale.new(#[0,1,4,5,7,8,10], 12, name: "Spanish"), // modes of whole tones with added note -> \leadingWhole -> Scale.new(#[0,2,4,6,8,10,11], 12, name: "Leading Whole Tone"), \lydianMinor -> Scale.new(#[0,2,4,6,7,8,10], 12, name: "Lydian Minor"), \neapolitanMajor -> Scale.new(#[0,1,3,5,7,9,11], 12, name: "Neapolitan Major"), \locrianMajor -> Scale.new(#[0,2,4,5,6,8,10], 12, name: "Locrian Major"), // 8 note scales \diminished -> Scale.new(#[0,1,3,4,6,7,9,10], 12, name: "Diminished"), \diminished2 -> Scale.new(#[0,2,3,5,6,8,9,11], 12, name: "Diminished 2"), // 12 note scales \chromatic -> Scale.new((0..11), 12, name: "Chromatic"), // TWENTY-FOUR TONES PER OCTAVE \chromatic24 -> Scale.new((0..23), 24, name: "Chromatic 24"), // maqam ajam \ajam -> Scale.new(#[0,4,8,10,14,18,22], 24, name: "Ajam"), \jiharkah -> Scale.new(#[0,4,8,10,14,18,21], 24, name: "Jiharkah"), \shawqAfza -> Scale.new(#[0,4,8,10,14,16,22], 24, name: "Shawq Afza"), // maqam sikah \sikah -> Scale.new(#[0,3,7,11,14,17,21], 24, name: "Sikah"), \sikahDesc -> Scale.new(#[0,3,7,11,13,17,21], 24, name: "Sikah Descending"), \huzam -> Scale.new(#[0,3,7,9,15,17,21], 24, name: "Huzam"), \iraq -> Scale.new(#[0,3,7,10,13,17,21], 24, name: "Iraq"), \bastanikar -> Scale.new(#[0,3,7,10,13,15,21], 24, name: "Bastanikar"), \mustar -> Scale.new(#[0,5,7,11,13,17,21], 24, name: "Mustar"), // maqam bayati \bayati -> Scale.new(#[0,3,6,10,14,16,20], 24, name: "Bayati"), \karjighar -> Scale.new(#[0,3,6,10,12,18,20], 24, name: "Karjighar"), \husseini -> Scale.new(#[0,3,6,10,14,17,21], 24, name: "Husseini"), // maqam nahawand \nahawand -> Scale.new(#[0,4,6,10,14,16,22], 24, name: "Nahawand"), \nahawandDesc -> Scale.new(#[0,4,6,10,14,16,20], 24, name: "Nahawand Descending"), \farahfaza -> Scale.new(#[0,4,6,10,14,16,20], 24, name: "Farahfaza"), \murassah -> Scale.new(#[0,4,6,10,12,18,20], 24, name: "Murassah"), \ushaqMashri -> Scale.new(#[0,4,6,10,14,17,21], 24, name: "Ushaq Mashri"), // maqam rast \rast -> Scale.new(#[0,4,7,10,14,18,21], 24, name: "Rast"), \rastDesc -> Scale.new(#[0,4,7,10,14,18,20], 24, name: "Rast Descending"), \suznak -> Scale.new(#[0,4,7,10,14,16,22], 24, name: "Suznak"), \nairuz -> Scale.new(#[0,4,7,10,14,17,20], 24, name: "Nairuz"), \yakah -> Scale.new(#[0,4,7,10,14,18,21], 24, name: "Yakah"), \yakahDesc -> Scale.new(#[0,4,7,10,14,18,20], 24, name: "Yakah Descending"), \mahur -> Scale.new(#[0,4,7,10,14,18,22], 24, name: "Mahur"), // maqam hijaz \hijaz -> Scale.new(#[0,2,8,10,14,17,20], 24, name: "Hijaz"), \hijazDesc -> Scale.new(#[0,2,8,10,14,16,20], 24, name: "Hijaz Descending"), \zanjaran -> Scale.new(#[0,2,8,10,14,18,20], 24, name: "Zanjaran"), // maqam hijazKar \zanjaran -> Scale.new(#[0,2,8,10,14,16,22], 24, name: "Zanjaran"), // maqam saba \saba -> Scale.new(#[0,3,6,8,12,16,20], 24, name: "Saba"), \zamzam -> Scale.new(#[0,2,6,8,14,16,20], 24, name: "Zamzam"), // maqam kurd \kurd -> Scale.new(#[0,2,6,10,14,16,20], 24, name: "Kurd"), \kijazKarKurd -> Scale.new(#[0,2,8,10,14,16,22], 24, name: "Kijaz Kar Kurd"), // maqam nawa Athar \nawaAthar -> Scale.new(#[0,4,6,12,14,16,22], 24, name: "Nawa Athar"), \nikriz -> Scale.new(#[0,4,6,12,14,18,20], 24, name: "Nikriz"), \atharKurd -> Scale.new(#[0,2,6,12,14,16,22], 24, name: "Athar Kurd"), // Ascending/descending scales \melodicMinor -> ScaleAD(#[0,2,3,5,7,9,11], 12, #[0,2,3,5,7,8,10], name: "Melodic Minor"), \sikah -> ScaleAD(#[0,3,7,11,14,17,21], 24, #[0,3,7,11,13,17,21], name: "Sikah"), \nahawand -> ScaleAD(#[0,4,6,10,14,16,22], 24, #[0,4,6,10,14,16,20], name: "Nahawand"), ]; } *at { |key| var res = scales[key]; ^res !? { res.deepCopy }; } *choose { |selectFunc| ^scales.values.select(selectFunc ? { true }).choose.deepCopy; } *names { ^scales.keys.asArray.sort } *directory { var dirString = scales.keys.asArray.sort.collect({ |k| "\\" ++ k ++ ": " ++ scales.at(k).name }).join("\n"); if(Document.implementationClass.notNil) { dirDoc = dirDoc ?? { Document.new("Tuning Directory", dirString) .onClose_({ dirDoc.free; dirDoc = nil }); }; dirDoc.front; dirDoc.string = dirString; } { dirString.postln; } } } TuningInfo { classvar Tuning.new((0..11), 2, "ET12"), \pythagorean -> Tuning.new([1, 256/243, 9/8, 32/27, 81/64, 4/3, 729/512, 3/2, 128/81, 27/16, 16/9, 243/128].ratiomidi, 2, "Pythagorean"), \just -> Tuning.new([1, 16/15, 9/8, 6/5, 5/4, 4/3, 45/32, 3/2, 8/5, 5/3, 9/5, 15/8].ratiomidi, 2, "5-Limit Just Intonation"), \sept1 -> Tuning.new([1, 16/15, 9/8, 6/5, 5/4, 4/3, 7/5, 3/2, 8/5, 5/3, 9/5, 15/8].ratiomidi, 2, "Septimal Tritone Just Intonation"), \sept2 -> Tuning.new([1, 16/15, 9/8, 6/5, 5/4, 4/3, 7/5, 3/2, 8/5, 5/3, 7/4, 15/8].ratiomidi, 2, "7-Limit Just Intonation"), \mean4 -> Tuning.new(#[0, 0.755, 1.93, 3.105, 3.86, 5.035, 5.79, 6.965, 7.72, 8.895, 10.07, 10.82], 2, "Meantone, 1/4 Syntonic Comma"), \mean5 -> Tuning.new(#[0, 0.804, 1.944, 3.084, 3.888, 5.028, 5.832, 6.972, 7.776, 8.916, 10.056, 10.86], 2, "Meantone, 1/5 Pythagorean Comma"), \mean6 -> Tuning.new(#[0, 0.86, 1.96, 3.06, 3.92, 5.02, 5.88, 6.98, 7.84, 8.94, 10.04, 10.9], 2, "Meantone, 1/6 Pythagorean Comma"), \kirnberger -> Tuning.new([1, 256/243, (5.sqrt)/2, 32/27, 5/4, 4/3, 45/32, 5 ** 0.25, 128/81, (5 ** 0.75)/2, 16/9, 15/8].ratiomidi, 2, "Kirnberger III"), \werckmeister -> Tuning.new(#[0, 0.92, 1.93, 2.94, 3.915, 4.98, 5.9, 6.965, 7.93, 8.895, 9.96, 10.935], 2, "Werckmeister III"), \vallotti -> Tuning.new(#[0, 0.94135, 1.9609, 2.98045, 3.92180, 5.01955, 5.9218, 6.98045, 7.9609, 8.94135, 10, 10.90225], 2, "Vallotti"), \young -> Tuning.new(#[0, 0.9, 1.96, 2.94, 3.92, 4.98, 5.88, 6.98, 7.92, 8.94, 9.96, 10.9], 2, "Young"), \reinhard -> Tuning.new([1, 14/13, 13/12, 16/13, 13/10, 18/13, 13/9, 20/13, 13/8, 22/13, 13/7, 208/105].ratiomidi, 2, "Mayumi Reinhard"), \wcHarm -> Tuning.new([1, 17/16, 9/8, 19/16, 5/4, 21/16, 11/8, 3/2, 13/8, 27/16, 7/4, 15/8].ratiomidi, 2, "Wendy Carlos Harmonic"), \wcSJ -> Tuning.new([1, 17/16, 9/8, 6/5, 5/4, 4/3, 11/8, 3/2, 13/8, 5/3, 7/4, 15/8].ratiomidi, 2, "Wendy Carlos Super Just"), //MORE THAN TWELVE-TONE ET \et19 -> Tuning.new((0 .. 18) * 12/19, 2, "ET19"), \et22 -> Tuning.new((0 .. 21) * 6/11, 2, "ET22"), \et24 -> Tuning.new((0 .. 23) * 0.5, 2, "ET24"), \et31 -> Tuning.new((0 .. 30) * 12/31, 2, "ET31"), \et41 -> Tuning.new((0 .. 40) * 12/41, 2, "ET41"), \et53 -> Tuning.new((0 .. 52) * 12/53, 2, "ET53"), //NON-TWELVE-TONE JI \johnston -> Tuning.new([1, 25/24, 135/128, 16/15, 10/9, 9/8, 75/64, 6/5, 5/4, 81/64, 32/25, 4/3, 27/20, 45/32, 36/25, 3/2, 25/16, 8/5, 5/3, 27/16, 225/128, 16/9, 9/5, 15/8, 48/25].ratiomidi, 2, "Ben Johnston"), \partch -> Tuning.new([1, 81/80, 33/32, 21/20, 16/15, 12/11, 11/10, 10/9, 9/8, 8/7, 7/6, 32/27, 6/5, 11/9, 5/4, 14/11, 9/7, 21/16, 4/3, 27/20, 11/8, 7/5, 10/7, 16/11, 40/27, 3/2, 32/21, 14/9, 11/7, 8/5, 18/11, 5/3, 27/16, 12/7, 7/4, 16/9, 9/5, 20/11, 11/6, 15/8, 40/21, 64/33, 160/81].ratiomidi, 2, "Harry Partch"), \catler -> Tuning.new([1, 33/32, 16/15, 9/8, 8/7, 7/6, 6/5, 128/105, 16/13, 5/4, 21/16, 4/3, 11/8, 45/32, 16/11, 3/2, 8/5, 13/8, 5/3, 27/16, 7/4, 16/9, 24/13, 15/8].ratiomidi, 2, "Jon Catler"), \chalmers -> Tuning.new([1, 21/20, 16/15, 9/8, 7/6, 6/5, 5/4, 21/16, 4/3, 7/5, 35/24, 3/2, 63/40, 8/5, 5/3, 7/4, 9/5, 28/15, 63/32].ratiomidi, 2, "John Chalmers"), \harrison -> Tuning.new([1, 16/15, 10/9, 8/7, 7/6, 6/5, 5/4, 4/3, 17/12, 3/2, 8/5, 5/3, 12/7, 7/4, 9/5, 15/8].ratiomidi, 2, "Lou Harrison"), \sruti -> Tuning.new([1, 256/243, 16/15, 10/9, 9/8, 32/27, 6/5, 5/4, 81/64, 4/3, 27/20, 45/32, 729/512, 3/2, 128/81, 8/5, 5/3, 27/16, 16/9, 9/5, 15/8, 243/128].ratiomidi, 2, "Sruti"), //HARMONIC SERIES -- length arbitary \harmonic -> Tuning.new((1 .. 24).ratiomidi, 2, "Harmonic Series 24"), //STRETCHED/SHRUNK OCTAVE //Bohlen-Pierce \bp -> Tuning.new((0 .. 12) * (3.ratiomidi/13), 3.0, "Bohlen-Pierce"), \wcAlpha -> Tuning.new((0 .. 14) * 0.78, (15 * 0.78).midiratio, "Wendy Carlos Alpha"), \wcBeta -> Tuning.new((0 .. 18) * 0.638, (19 * 0.638).midiratio, "Wendy Carlos Beta"), \wcGamma -> Tuning.new((0 .. 33) * 0.351, (34 * 0.351).midiratio, "Wendy Carlos Gamma") ]; } *choose { |selectFunc| ^tunings.values.select(selectFunc ? { true }).choose; } *names { ^tunings.keys.asArray.sort } *at { |key| var res = tunings[key]; ^res !? { res.deepCopy }; } *directory { var dirString = tunings.keys.asArray.sort.collect({ |k| "\\" ++ k ++ ": " ++ tunings.at(k).name }).join("\n"); if(Document.implementationClass.notNil) { dirDoc = dirDoc ?? { Document.new("Tuning Directory", dirString) .onClose_({ dirDoc.free; dirDoc = nil }); }; dirDoc.front; dirDoc.string = dirString; } { dirString.postln; } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/PriorityQueue.sc0000664000000000000000000000162212014636263030470 0ustar rootrootPriorityQueue { var array; put { arg time, item; _PriorityQueueAdd ^this.primitiveFailed; } pop { _PriorityQueuePop ^this.primitiveFailed; } topPriority { _PriorityQueueTop ^this.primitiveFailed; } clear { _PriorityQueueClear ^this.primitiveFailed; } postpone { arg time; _PriorityQueuePostpone ^this.primitiveFailed; } isEmpty { _PriorityQueueEmpty ^this.primitiveFailed; } notEmpty { ^this.isEmpty.not } removeValue {|value| var newObject = PriorityQueue(), currentPriority, topObject; while {this.notEmpty} { currentPriority = this.topPriority; topObject = this.pop; if (topObject != value) { newObject.put(currentPriority, topObject) } }; array = newObject.prInternalArray; } do {|func| if (array.size > 1) { forBy(1, array.size-1, 3) {|i| func.value(array[i+1],array[i+0]) } } } // private prInternalArray { ^array } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/Harmonics.sc0000664000000000000000000000352512014636263027571 0ustar rootrootHarmonics { var <>size; // Harmonics objects are convenient factories for creating Arrays that // are used to fill buffers using the b_gen sine fill commands on the server. *new { arg size = 32; ^super.newCopyArgs(size) } // decays with frequency decay { arg k = 1; ^Array.fill(size) {|i| 1.0 / ((i+1) ** k) } } geom { arg k = 1.2; ^Array.fill(size) {|i| 1.0 / (k ** i) } } // random values rand { arg lo=0.0, hi=1.0; ^Array.rand(size, lo, hi) } exprand { arg lo=0.01, hi=1.0; ^Array.exprand(size, lo, hi) } linrand { arg lo=0.0, hi=1.0; ^Array.linrand(size, lo, hi) } rand2 { arg val=1.0; ^Array.rand2(size, val) } coin { arg prob = 0.5; ^Array.fill(size) { if (prob.coin, 1.0, -1.0) } } // other useful shapes formant { arg center=12, width = 3; var start, end; start = center - (width/2); end = center + (width/2); ^Array.fill(size) {|i| if (i <= start) { 0.0 } { if (i >= end) { 0.0 } { hanWindow((i - start) / width); } } } } teeth { arg spacing = 2, start = 0; ^Array.fill(size) {|i| if (i < start) { 0.0 } { i = i - start; if ((i % spacing) == 0, 1.0, 0.0) } } } cutoff { arg n; ^Array.fill(size) {|i| if (i <= n, 1.0, 0.0) } } shelf { arg start, end, startLevel = 1.0, endLevel = 0.0; ^Array.fill(size) {|i| if (i <= start) { startLevel } { if (i >= end) { endLevel } { ((i - start) / (end - start)) * (endLevel - startLevel) + startLevel; } } } } sine { arg wavelength=4, iphase=0.5pi, mul=1.0, add=0.0; ^Array.fill(size) {|i| sin(2pi/wavelength * i + iphase) * mul + add } } pulse { arg wavelength=4, iphase=0, duty = 0.5, mul=1.0, add=0.0; ^Array.fill(size) {|i| if (((i - iphase) % wavelength) < duty, 1.0, 0.0) * mul + add } } ramp { arg start=1.0, step; step = step ? size.reciprocal; ^Array.series(size, start, step) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/linux/0000775000000000000000000000000012245452763026460 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Common/Collections/linux/extString_linux.sc0000664000000000000000000000031412014636263032204 0ustar rootroot+ String { runInTerminal {|shell="sh"| ("xterm -hold -T 'SuperCollider runInTerminal' -e" + shell + "-c" + this.shellQuote).unixCmd; } openOS { ("xdg-open " ++ this.escapeChar($ )).systemCmd } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/DefaultLibrary/0000775000000000000000000000000012245452763024524 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/DefaultLibrary/dumpFullInterface.sc0000664000000000000000000000765012161364457030473 0ustar rootroot+ Class { dumpFullInterface { ("\nFull Interface for " ++ this.name).postln; // post the superclasses ("\nSuperclasses: " ++ this.superclasses).postln; // Instance methods this.dumpAllMethods; // Class methods this.class.dumpAllMethods; } dumpAllMethods { var methodlist, superclasses, prependString, superPrependString, name; methodlist = IdentitySet[]; if(this.isMetaClass, { prependString = "\nClass Methods for "; superPrependString = "\nClass Methods inherited from "; name = this.asString.copyToEnd(5); superclasses = name.asSymbol.asClass.superclasses; }, { prependString = "\nInstance Methods for "; superPrependString = "\nInstance Methods inherited from "; name = this.name; superclasses = this.superclasses; } ); (prependString ++ name ++ "\n").postln; this.methods.do({ arg meth; var numargs, methname; methname = meth.name; methodlist.add(methname); numargs = meth.argNames.size - 1; " ".post; methname.post; " ( ".post; meth.argNames.do({ arg name, i; if (i > 0, { // skip 'this' name.post; if (i < numargs, { ", ".post; }); }); }); " )\n".post; }); // Methods for superclasses superclasses.do({ arg superclass, superobject, supername; if(this.isMetaClass, { superobject = superclass.class; }, { superobject = superclass; } ); supername = superobject.asString; if(supername.containsStringAt(0, "Meta_"), { supername = supername.copyToEnd(5) }); (superPrependString ++ supername ++ "\n").postln; superobject.methods.do({ arg meth; var numargs, methname; methname = meth.name; if(methodlist.includes(methname).not, { methodlist.add(methname); numargs = meth.argNames.size - 1; " ".post; methname.post; " ( ".post; meth.argNames.do({ arg name, i; if (i > 0, { // skip 'this' name.post; if (i < numargs, { ", ".post; }); }); }); " )\n".post; }); }); }); // include methods for Class if(this.isMetaClass, {"\nMethods inherited from Class\n".postln; Class.dumpInterface; }); } dumpMethodList { var mList, sc; mList = IdentityDictionary.new; // repository for methods this.collectMethods(mList); // get them sc = this; // to print superclass chain { sc != Object }.while({ (sc.name ++ " : ").post; sc = sc.superclass; }); "Object".postln; mList.asSortedArray.do({ |pair| (pair[0] ++ " <" ++ pair[1].ownerClass.name ++ "-" ++ pair[0] ++ ">").post; (pair[1].argNames.size > 1).if({ " (".post; pair[1].argNames.do({ |argname, i| (i > 1).if({ ", ".post }); (i > 0).if({ argname.post; }); }); ")".post; }); "".postln; }); } collectMethods { arg list; // only collect if not Object or Class ((this.name != \Object) && (this.name != \Class)).if({ this.methods.do({ |meth| // if keys already includes methodname, // then a subclass has overridden this superclass method, so don't add list.keys.includes(meth.name).not.if({ list.put((meth.name.asString).asSymbol, meth); }); }); superclass.asClass.collectMethods(list); // go up a level }); } helpFileForMethod { arg methodSymbol; this.findRespondingMethodFor(methodSymbol).ownerClass.help; } // show all subclasses of this class sorted in alpha order (not tree order) dumpSubclassList { var list, listCollector; // recursive function to collect class objects listCollector = { arg node, l; l.add(node); node.subclasses.do({ arg n; listCollector.value(n, l) }); }; list = List.new; listCollector.value(this, list); // do the recursion list.sort({ arg a, b; a.name < b.name }) // sort it .do({ arg n; // and iterate to post the class names (w/ supers) n.name.post; n.superclasses.do({ arg s; (" : " ++ s.name).post; }); "\n".post; }); ("\n" ++ list.size.asString ++ " classes listed.").postln; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/DefaultLibrary/extNumber.sc0000664000000000000000000000075212014636263027021 0ustar rootroot// method extensions // add or replace methods // This allows you to add or redefine methods without changing the original file. // A file may contain either class definitions, or method extensions, but never both. // Do not name an extension file with the same name as a class definition file. + Number { half { ^this * 0.5 } twice { ^this * 2 } } + Point { *big { arg x, y; ^this.new(2*x, 10*y) } swap { ^this.class.new(y, x) } conjugate { ^this.class.new(x, y.neg) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/DefaultLibrary/MyLFSaw.sc0000664000000000000000000000000012014636263026314 0ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/DefaultLibrary/Main.sc0000664000000000000000000001563212245365552025745 0ustar rootrootMain : Process { var = min }{ this.scVersionMajor >= maj }; } *versionAtMost { |maj, min| ^if((maj==this.scVersionMajor) and:{min.notNil}){ this.scVersionMinor <= min }{ this.scVersionMajor <= maj }; } pid { _GetPid ^this.primitiveFailed } // PRIVATE prArgv { _Argv ^[] } recompile { platform.recompile } escapeWindow { platform.escapeWindow } exitFullScreen { platform.exitFullScreen } setDeferredTaskInterval { |interval| platform.setDeferredTaskInterval(interval) } *overwriteMsg { _MainOverwriteMsg ^this.primitiveFailed } } MethodOverride { var currentPath; classvar 0) { this.prSend(id, res); }; } *completeClassMethod { |id, text| var class, methods, res; class = text.asSymbol.asClass; if (class.notNil) { methods = IdentityDictionary(); class = class.class; while { class.notNil } { class.methods.do { |method| // methods include operators like "+", but those are // actually not valid in the method call syntax if (method.name.asString[0].isAlpha && methods[method.name].isNil) { methods.put(method.name, method); }; }; class = class.superclass; }; res = methods.values.collect { |m| this.serializeMethod(m) }; if (res.size > 0) { this.prSend(id, res) }; } } *completeMethod { |id, text| var res = []; Class.allClasses.do { |class| class.methods.do { |method| var signature; var definition; if (method.name.asString.beginsWith(text)) { res = res.add( this.serializeMethod(method) ); }; }; }; if (res.size > 0) { this.prSend(id, res) }; } *findMethod { |id, text| var cname, mname, tokens, res; var class, method; tokens = text.split($.); if (tokens.size > 1) { cname = tokens[0]; mname = tokens[1]; }{ mname = tokens[0]; }; if (mname.size < 1) { ^this }; if (cname.size > 0) { class = cname.asSymbol.asClass; if (class.isNil) { warn("No class named" + cname.asString); ^this; }; method = class.class.findRespondingMethodFor(mname.asSymbol); if (method.isNil) { warn("No such method:" + cname.asString ++ "." ++ mname.asString); ^this; }; this.prSend(id, [this.serializeMethod(method)]); }{ res = []; this.allMethodsDo { |method| if (method.name.asString == mname) { res = res.add( this.serializeMethod(method) ); }; }; if (res.size > 0) { this.prSend(id, res) }{ warn("No such method:" + mname.asString); ^this; }; } } *serializeMethod { arg method; var data = [method.ownerClass.name, method.name]; if (method.argNames.size > 1) { data = data ++ [ method.argNames.as(Array), method.prototypeFrame.collect { |val| val !? val.cs } ].lace [2..]; }; ^data; } *serializeMethodDetailed { arg method; var args, data; args = []; if (method.argNames.size > 1) { args = args ++ [ method.argNames.as(Array), method.prototypeFrame.collect { |val| val !? { if (val.class === Float) { val.asString } { val.cs } } }; ].lace [2..]; }; data = [ method.ownerClass.name, method.name, method.filenameSymbol, method.charPos, args ]; ^data; } *allMethodsDo { arg func; Class.allClasses.do { |class| class.methods.do { |method| func.value(method); }; }; } *findReferencesToSymbol {|requestId, symbol| var methods; var result = SortedList(8, subListSorter); var references = Class.findAllReferences(symbol.asSymbol); if (references.notNil) { methods = IdentitySet.new; references.do { | funcDef | var homeContext; homeContext = if(funcDef.context.isNil) {funcDef} {funcDef.context.homeContext}; if (homeContext.isKindOf(Method)) { methods.add(homeContext); }; }; methods.do { | method | result.add([ method.ownerClass.name, method.name, method.filenameSymbol.asString, method.charPos + 1 ]) } }; ScIDE.prSend(requestId, [symbol, result.asArray]) } *openHelpUrl { |url| ScIDE.processUrl(url, { |processedUrl| this.prSend("openHelpUrl", processedUrl.asString) }); } *cmdPeriod { docRoutine.play(AppClock) } *processUrl { |urlString, doneAction| // NOTE: Copied and modified from HelpBrower:-goTo var url, brokenFunc; brokenFunc = { |fragment| var brokenUrl = URI.fromLocalPath( SCDoc.helpTargetDir++"/BrokenLink.html" ); brokenUrl.fragment = fragment; brokenUrl; }; url = URI(urlString); if (docRoutine.notNil) { docRoutine.stop }; docRoutine = Routine { try { url = SCDoc.prepareHelpForURL(url) ?? { brokenFunc.(urlString) }; doneAction.value(url); } {|err| err.throw; }; CmdPeriod.remove(this); docRoutine = nil; }.play(AppClock); CmdPeriod.add(this); } // PRIVATE /////////////////////////////////////////////////////////// *prSend {|id, data| _ScIDE_Send this.primitiveFailed } *prConnect {|ideName| _ScIDE_Connect this.primitiveFailed } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/SCDoc/0000775000000000000000000000000012245452763022546 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/SCDoc/SCDoc.sc0000664000000000000000000010154512245365552024035 0ustar rootrootSCDocEntry { var <>path, // document "path" without basedir and extension, like "Classes/SinOsc" <>title, <>summary, <>redirect, <>categories, // a list of categories <>related, // a list of related docs <>docimethods, // a set of documented methods <>doccmethods, // a set of documented methods <>docmethods, // a set of documented methods <>privcmethods, // a set of private methods <>privimethods, // a set of private methods <>undoccmethods, <>undocimethods, <>keywords, // a list of keywords <>additions, <>isExtension, <>mtime, <>fullPath, <>oldHelp; var <>isClassDoc; var <>klass, <>implKlass, <>implements; var <>isUndocumentedClass; printOn {|stream| stream << "SCDocEntry(" << path.cs << ", " << title.cs << ", " << summary.cs << ")"; } prJSONString {|stream, key, x| if(x.isNil) { x = "" }; stream << "'" << key << "': \"" << x.escapeChar(34.asAscii) << "\",\n"; } prJSONList {|stream, key, v| if(v.isNil) { v = "" }; stream << "'" << key << "': [ " << v.collect{|x|"\""++x.escapeChar(34.asAscii)++"\""}.join(",") << " ],\n"; } toJSON {|stream| stream << "\"" << path.escapeChar(34.asAscii) << "\": {\n"; this.prJSONString(stream, "title", title); this.prJSONString(stream, "path", path); this.prJSONString(stream, "summary", summary); this.prJSONString(stream, "installed", if(isExtension,"extension","standard")); //FIXME: also 'missing'.. better to have separate extension and missing booleans.. this.prJSONString(stream, "categories", if(categories.notNil) {categories.join(", ")} {""}); // FIXME: export list instead this.prJSONList(stream, "keywords", keywords); this.prJSONList(stream, "related", related); this.prJSONList(stream, "methods", this.makeMethodList); if(oldHelp.notNil) { this.prJSONString(stream, "oldhelp", oldHelp); }; if(klass.notNil) { klass.superclasses !? { this.prJSONList(stream, "superclasses", klass.superclasses.collect {|c| c.name.asString }) }; klass.subclasses !? { this.prJSONList(stream, "subclasses", klass.subclasses.collect {|c| c.name.asString }) }; implKlass !? { this.prJSONString(stream, "implementor", implKlass.name.asString); } }; stream << "},\n"; } *new {|node,path| ^super.new.init(node,path); } *newUndocClass {|name| var doc = super.new.init(nil,"Classes/"++name.asString); var f, cats, implements, c; doc.klass = name.asSymbol.asClass; doc.isClassDoc = true; doc.isUndocumentedClass = true; doc.title = name.asString; f = doc.klass.filenameSymbol.asString; doc.mtime = 0; doc.isExtension = f.beginsWith(Platform.classLibraryDir).not; doc.undoccmethods = doc.klass.class.methods.collectAs({|m|m.name.asGetter},IdentitySet); doc.undocimethods = doc.klass.methods.collectAs({|m|m.name.asGetter},IdentitySet); if((implements=doc.klass.tryPerform(\implementsClass)).class===Symbol) { (c = implements.asClass) !? { doc.implements = c; doc.summary = "Implements "++implements; doc.categories = ["Redirect Class Implementors"]; ^doc; }; }; doc.summary = "(Undocumented class)"; cats = ["Undocumented classes"]; if(SCDoc.classHasArKrIr(doc.klass)) { cats = cats.add("UGens>Undocumented"); }; doc.klass.categories !? { cats = cats ++ doc.klass.categories; }; doc.categories = cats; ^doc; } init {|node,aPath| var hdr, bdy; // 'path' variable is used as a key for SCDoc.documents dictionary. // Make sure it always uses forward slashes. // FIXME: implement & use a generic path conversion method? path = aPath.replace("\\","/"); if(node.isNil) {^this}; #hdr, bdy = node.children; isExtension = false; isUndocumentedClass = false; doccmethods = IdentitySet(); docimethods = IdentitySet(); docmethods = IdentitySet(); privcmethods = IdentitySet(); privimethods = IdentitySet(); undoccmethods = IdentitySet(); undocimethods = IdentitySet(); hdr.children.do {|n| switch(n.id, \TITLE, { title = n.text }, \CLASS, { title = n.text }, // not used anymore? \SUMMARY, { summary = n.text }, \REDIRECT, { redirect = n.text }, \CATEGORIES, { categories = n.children.collect {|child| child.text} }, \RELATED, { related = n.children.collect {|child| child.text} }, ); }; this.prScanMethodsKeywords(bdy); if(title.isNil) { warn("SCDoc:"+path+"has no title!"); title = "(Untitled)"; }; if(isClassDoc = (path.dirname=="Classes")) { klass = title.asSymbol.asClass; // if(klass.isNil) { // warn("SCDoc:"+path++": No such class!"); // }; if(title != path.basename ) { warn("SCDoc:"+path++": Title and filename mismatch. Must be same for class docs!"); }; }; if(categories.isNil) { warn("SCDoc:"+path+"has no categories!"); categories = ["Uncategorized"]; }; if(summary.isNil) { warn("SCDoc:"+path+"has no summary!"); summary = "(Missing summary)"; }; } destPath { ^SCDoc.helpTargetDir +/+ path ++ ".html"; } makeMethodList { var list; //FIXME: no need for the extra _ char.. docimethods.do {|name| list = list.add("_-"++name.asString); }; doccmethods.do {|name| list = list.add("_*"++name.asString); }; undocimethods.do {|name| list = list.add("?-"++name.asString); }; undoccmethods.do {|name| list = list.add("?*"++name.asString); }; docmethods.do {|name| list = list.add("_."++name.asString); }; ^list; } setAdditions {|a| var x; additions = a; a.do {|f| (x = SCDoc.parseFilePartial(f)) !? { this.prScanMethodsKeywords(x); } } } indexUndocumentedMethods { var ignoreMethods = IdentitySet[\categories, \init, \checkInputs, \new1, \argNamesInputsOffset, \initClass, \storeArgs, \storeOn, \printOn]; var syms, name, mets, l = Array.new; var docmets = IdentitySet.new; if(klass.isNil) { ^this }; if(redirect.notNil) { try { implKlass = klass.perform(redirect.asSymbol) }; } { implKlass = nil; }; docmets = docimethods | privimethods | ignoreMethods; (mets = klass.methods) !? { mets.collectAs({|m|m.name.asGetter},IdentitySet).do {|name| if(docmets.includes(name).not) { undocimethods = undocimethods.add(name); }; }; }; docmets = doccmethods | privcmethods | ignoreMethods; (mets = klass.class.methods) !? { mets.collectAs({|m|m.name.asGetter},IdentitySet).do {|name| if(docmets.includes(name).not) { undoccmethods = undoccmethods.add(name); }; }; }; } prAddMethodNames {|node, list| node.children.do {|n| list = list.add(n.text.asSymbol); } ^list; } prAddCopyMethod {|node, list| ^list.add(node.text.split($ )[1].drop(1)) } prScanMethodsKeywords {|node| if(node.isNil) { // warn("FIXME: for some reason prScanMethodsKeywords was called on a nil node") ^this; }; switch(node.id, \METHOD, { docmethods = this.prAddMethodNames(node.children[0], docmethods) }, \CMETHOD, { doccmethods = this.prAddMethodNames(node.children[0], doccmethods) }, \IMETHOD, { docimethods = this.prAddMethodNames(node.children[0], docimethods) }, \COPYMETHOD, { docmethods = this.prAddCopyMethod(node,docmethods) }, \CCOPYMETHOD, { doccmethods = this.prAddCopyMethod(node,doccmethods) }, \ICOPYMETHOD, { docimethods = this.prAddCopyMethod(node,docimethods) }, \CPRIVATE, { privcmethods = this.prAddMethodNames(node, privcmethods) }, \IPRIVATE, { privimethods = this.prAddMethodNames(node, privimethods) }, \KEYWORD, { node.children.do {|n| keywords = keywords.add(n.text); } }, { node.children.do {|n| this.prScanMethodsKeywords(n); } } ); } } SCDocNode { var <>id, <>text, <>children, <>makeDiv, notPrivOnly, <>sort; printOn {|stream| stream << "SCDocNode(" << id << ", " << text.cs << ", " << children << ")"; } findChild {|id| ^children.detect {|node| node.id===id} } notPrivOnly { if(notPrivOnly.isNil) { notPrivOnly = (children.detect {|x| x.id != \CPRIVATE and: {x.id != \IPRIVATE}}.notNil) }; ^notPrivOnly } addDivAfter {|id, div, title, childs| var node = this.findChild(id); var mets = SCDocNode() .id_(\SUBSECTION) .text_(title) .children_(childs) .makeDiv_(div); if(node.isNil) { //no subtree, create one children = children.add( node = SCDocNode().id_(id) ); }; node.children = node.children.add(mets); } sortClassDoc { var x = 0; // FIXME: does this work correctly for prose before first section, etc? children.do {|n| switch(n.id, \DESCRIPTION, { n.sort = 10 }, \CLASSMETHODS, { n.sort = 11 }, \INSTANCEMETHODS, { n.sort = 12 }, \EXAMPLES, { n.sort = 13 }, \SECTION, { n.sort = 14 + x = x + 1 }, { n.sort = x = x + 1 } ); }; children = children.sort {|a,b| a.sortverbosity = 1; classvar <>renderer; classvar documents; classvar helpSourceDirs; *parseFileFull {|path| ^this.prParseFile(path, 0) } *parseFilePartial {|path| ^this.prParseFile(path, 1) } *parseFileMetaData {|dir,path| var fullPath = dir +/+ path; var subpath = path.drop(-7); var entry, x = this.prParseFile(fullPath, 2); if(x.isNil) {^nil}; entry = SCDocEntry(x, subpath); entry.isExtension = (dir != this.helpSourceDir); entry.fullPath = fullPath; entry.mtime = File.mtime(fullPath); if(dir.beginsWith(Platform.userExtensionDir +/+ "quarks")) { entry.categories = entry.categories ++ ["Quarks>"++dir.dirname.basename]; }; ^entry; } *prParseFile {|path, mode| _SCDoc_ParseFile ^this.primitiveFailed } *indexOldHelp { var f = {|x,cat="Old Helpfiles",indent=0| var a,b,doc; x.pairsDo {|k,v| if(v.isKindOf(Dictionary)) { k = k.asString; a = 0; b = k.size-1; while({ $[ == k[a]},{a=a+1}); while({ $] == k[b]},{b=b-1}); k = k.copyRange(a,b); f.(v,cat++">"++k.asString,indent+1); } { if(v.size>0) { doc = SCDocEntry(nil,"Old Help"+/+v); doc.oldHelp = URI.fromLocalPath(v).asString; doc.title = v.basename; doc.summary = "(not yet converted to new help format)"; doc.categories = [cat]; doc.isExtension = true; SCDoc.documents[doc.path] = doc; } } } }; Help.rebuildTree; f.(Help.tree); } *indexAllDocuments { |clearCache=false| var now = Main.elapsedTime; var key, doc; var nonHelpFiles; var undocClasses = Class.allClasses.reject(_.isMetaClass).collectAs({|c|c.name},IdentitySet); var additions = Dictionary(); this.checkVersion(clearCache); this.postMsg("Indexing help-files...",0); documents = Dictionary(); // or use IdDict and symbols as keys? helpSourceDirs = nil; // force re-scan of HelpSource folders this.helpSourceDirs.do {|dir| PathName(dir).filesDo {|f| case {f.fullPath.endsWith(".ext.schelp")} { f = f.fullPath; key = f[dir.size+1 ..].drop(-11).replace("\\","/"); additions[key] = additions[key].add(f); } {f.extension=="schelp"} { doc = this.parseFileMetaData(dir, f.fullPath.drop(dir.size+1)); doc !? { documents[doc.path] = doc; if(doc.isClassDoc) { undocClasses.remove(doc.title.asSymbol); } } } { f = f.fullPath; nonHelpFiles = nonHelpFiles.add([f,f.drop(dir.size+1)]); }; } }; this.postMsg("Handling"+additions.size+"document additions...",1); additions.pairsDo {|key, val| doc = documents[key]; if(doc.notNil) { doc.setAdditions(val); } { warn("SCDoc: Additions % for non-existent help file".format(val)); } }; this.postMsg("Indexing undocumented methods...",1); documents.do {|d| if(d.isClassDoc) { d.indexUndocumentedMethods }; }; this.postMsg("Adding entries for"+undocClasses.size+"undocumented classes...",1); undocClasses.do {|x| doc = SCDocEntry.newUndocClass(x); documents[doc.path] = doc; }; this.postMsg("Copying"+nonHelpFiles.size+"non-help files...",1); nonHelpFiles.do {|x| var dest = SCDoc.helpTargetDir+/+x[1]; var folder = dest.dirname; File.mkdir(folder); if(File.exists(dest).not or: {File.mtime(x[0]) > File.mtime(dest)}) { File.delete(dest); File.copy(x[0],dest); }; }; this.postMsg("Indexing old helpfiles..."); this.indexOldHelp; this.postMsg("Exporting docmap.js...",1); this.exportDocMapJS(this.helpTargetDir +/+ "docmap.js"); this.postMsg("Indexed % documents in % seconds".format(documents.size,round(Main.elapsedTime-now,0.01)),0); NotificationCenter.notify(SCDoc, \didIndexAllDocs); } *didIndexDocuments { ^documents.notNil } *documents { if(documents.isNil) { this.indexAllDocuments; }; ^documents; } *helpSourceDirs { var find; if(helpSourceDirs.isNil) { this.postMsg("locating HelpSource folders...",2); helpSourceDirs = [helpSourceDir]; // Note: an array will keep the order. find = {|dir| dir.folders.do {|f| if(f.folderName=="HelpSource") { helpSourceDirs = helpSourceDirs.add(f.fullPath.withoutTrailingSlash); } { find.(f); }; } }; [thisProcess.platform.userExtensionDir, thisProcess.platform.systemExtensionDir].do {|dir| find.(PathName(dir)); }; }; ^helpSourceDirs } *exportDocMapJS {|path| var f = File.open(path,"w"); f << "docmap = {\n"; this.documents.do {|doc| doc.toJSON(f); }; f << "}\n"; f.close; } *helpSourceDir_ {|path| helpSourceDir = path.standardizePath; } *helpTargetDir_ {|path| // if(path!=helpTargetDir) {didRun = false}; helpTargetDir = path.standardizePath; helpTargetUrl = URI.fromLocalPath(helpTargetDir).asString; } *postMsg {|txt, lvl=0| if(verbosity>lvl) { postln("SCDoc: "++txt); }; if(thisThread.isKindOf(Routine)) { 0.yield; } } *parseDoc {|doc| var add, root; (root = this.parseFileFull(doc.fullPath)) !? { doc.additions.do {|f| (add = this.parseFilePartial(f)) !? { root.children[1].merge(add); } }; this.handleCopyMethods(root,doc); }; ^root; } *parseAndRender {|doc| var dest = doc.destPath; var root = this.parseDoc(doc); root !? { this.postMsg("% -> %".format(doc.fullPath, dest),2); this.renderer.renderToFile(dest, doc, root); } } *prepareHelpForURL {|url| var path, targetBasePath, pathIsCaseInsensitive; var subtarget, src, c, cmd, doc, destExist, destMtime; var verpath = this.helpTargetDir +/+ "version"; path = url.asLocalPath; // detect old helpfiles and wrap them in OldHelpWrapper if(url.scheme == "sc") { ^URI(SCDoc.findHelpFile(path)); }; // just pass through remote url's if(url.scheme != "file") {^url}; targetBasePath = SCDoc.helpTargetDir; if (thisProcess.platform.name === \windows) { targetBasePath = targetBasePath.replace("/","\\") }; pathIsCaseInsensitive = thisProcess.platform.name === \windows; // detect old helpfiles and wrap them in OldHelpWrapper if( /* // this didn't work for quarks due to difference between registered old help path and the quarks symlink in Extensions. // we could use File.realpath(path) below but that would double the execution time, // so let's just assume any local file outside helpTargetDir is an old helpfile. block{|break| Help.do {|key, path| if(url.endsWith(path)) { break.value(true) } }; false }*/ compare( path [..(targetBasePath.size-1)], targetBasePath, pathIsCaseInsensitive ) != 0 ) { ^SCDoc.getOldWrapUrl(url) }; if(destExist = File.exists(path)) { destMtime = File.mtime(path); }; if(path.endsWith(".html")) { subtarget = path.drop(this.helpTargetDir.size+1).drop(-5).replace("\\","/"); doc = this.documents[subtarget]; doc !? { if(doc.isUndocumentedClass) { if(doc.mtime == 0) { this.renderUndocClass(doc); doc.mtime = 1; }; ^url; }; if(File.mtime(doc.fullPath)>doc.mtime) { // src changed after indexing this.postMsg("% changed, re-indexing documents".format(doc.path),2); this.indexAllDocuments; ^this.prepareHelpForURL(url); }; if(destExist.not or: {doc.mtime>destMtime} or: {doc.additions.detect {|f| File.mtime(f)>destMtime}.notNil} or: {File.mtime(this.helpTargetDir +/+ "scdoc_version")>destMtime} or: {doc.klass.notNil and: {File.mtime(doc.klass.filenameSymbol.asString)>destMtime}} ) { this.parseAndRender(doc); }; ^url; }; }; if(destExist) { ^url; }; warn("SCDoc: Broken link:" + url.asString); ^nil; } *initClass { this.helpSourceDir_(thisProcess.platform.classLibraryDir.dirname +/+ "HelpSource"); this.helpTargetDir_(thisProcess.platform.userAppSupportDir +/+ "Help"); renderer = SCDocHTMLRenderer; } *classHasArKrIr {|c| ^#[\ar,\kr,\ir].collect {|m| c.class.findRespondingMethodFor(m).notNil }.reduce {|a,b| a or: b}; } *checkVersion {|clearCache=false| var f, path = this.helpTargetDir +/+ "scdoc_version"; if(clearCache or: {path.load != version}) { this.postMsg("refreshing scdoc version timestamp",1); // this will update the mtime of the version file, triggering re-rendering of files older than now File.mkdir(this.helpTargetDir); f = File.open(path,"w"); f.write(version.asCompileString); f.close; ^true; }; ^false; } *renderAll {|includeExtensions=true| this.postMsg("Rendering all documents"); this.documents.do {|doc| if(doc.oldHelp.isNil and: {includeExtensions or: {doc.isExtension.not}}) { if(doc.isUndocumentedClass) { this.renderUndocClass(doc); } { this.parseAndRender(doc); } } }; this.postMsg("Done!"); } *makeClassTemplate {|doc| var name = doc.title; var cats = doc.categories; var class = doc.klass; var n, m, f, c; f = {|cm| var txt,c,m,l,last,sym; if(cm) { txt = "\nCLASSMETHODS::\n\n"; n = doc.undoccmethods; c = class.class; } { txt = "\nINSTANCEMETHODS::\n\n"; n = doc.undocimethods; c = class; }; n.do {|x| txt = txt ++ "METHOD::" + x ++ "\n(describe method here)\n\n"; sym = x.asSymbol; m = c.findRespondingMethodFor(sym.asSetter); m = m ?? {c.findRespondingMethodFor(sym)}; m !? { l = m.argNames; last = l.size-1; l.do {|a,i| if (i>0) { //skip 'this' (first arg) txt = txt ++ "ARGUMENT:: "; if(i==last and: {m.varArgs}) { txt = txt ++ " ... "; }; txt = txt ++ a ++ "\n(describe argument here)\n\n"; } } }; txt = txt ++ "returns:: (describe returnvalue here)\n\n"; }; txt; }; ^ "TITLE::"+name ++"\nsummary:: (put short description here)\n" ++"categories::"+cats.join(", ") ++"\nrelated:: Classes/SomeRelatedClass, Reference/SomeRelatedStuff, etc.\n\n" ++"DESCRIPTION::\n(put long description here)\n\n" ++ f.(true) ++ f.(false) ++"\nEXAMPLES::\n\ncode::\n(some example code)\n::\n"; } *renderUndocClass {|doc| var node, desc, body; node = SCDocNode().id_(\DOCUMENT).children_([ SCDocNode().id_(\HEADER).children_([ // the header content is already in the SCDocEntry.. ]), body = SCDocNode().id_(\BODY).children_([ SCDocNode().id_(\DESCRIPTION).children_([ desc = SCDocNode().id_(\PROSE) ]) ]) ]); if(doc.implements.notNil) { this.postMsg("Generating class redirect implementor doc: % for %".format(doc.title,doc.implements.name),2); desc.children = [ SCDocNode().id_(\TEXT).text_("Implements "), SCDocNode().id_(\LINK).text_("Classes/"++doc.implements.name) ]; } { this.postMsg("Undocumented class: "++doc.title++", generating stub and template",2); desc.children = [ SCDocNode().id_(\TEXT).text_("This class is missing documentation.") ]; body.children = body.children.add( SCDocNode().id_(\SECTION).text_("Help template").children_([ SCDocNode().id_(\PROSE).children_([ SCDocNode().id_(\TEXT).text_("Copy and paste the text below and save to HelpSource/Classes/"++doc.title++".schelp") ]), SCDocNode().id_(\CODEBLOCK).text_(this.makeClassTemplate(doc)) ]) ); }; this.renderer.renderToFile(doc.destPath, doc, node); } *getMethodDoc {|classname,methodname| var doc, id, node, mname; var findmet = {|n| if((n.id == id) and: {n.children[0].children.detect{|x|x.text==mname}.notNil}) { n; } { block {|break| n.children.do {|n2| n2 = findmet.(n2,id); if(n2.notNil) { break.value(n2); } }; nil; } } }; var err = {|txt| warn("SCDoc.getMethodDoc(%, %): %".format(classname,methodname,txt)); }; doc = this.documents["Classes/"++classname]; if(doc.isNil or: {doc.fullPath.isNil}) { err.("class document not found"); ^nil; }; id = switch(methodname[0], $*, \CMETHOD, $-, \IMETHOD, $., \METHOD, { err.("methodname must be prefixed with '*', '-' or '.'"); ^nil; } ); mname = methodname.drop(1); node = this.parseDoc(doc); if(node.isNil) { err.("could not parse class document"); ^nil; }; node = findmet.(node); if(node.isNil) { err.("method not found"); ^nil; }; ^node; } *handleCopyMethods {|node,doc| var found = {|n| var name, met, x; #name, met = n.text.findRegexp("[^ ,]+").flop[1]; x = this.getMethodDoc(name, met); if(x.isNil) { warn(" from: %".format(doc.fullPath)); }; x; }; node.children.do{|n,i| switch(n.id, \CCOPYMETHOD, { n = found.(n); n !? {n.id_(\CMETHOD); node.children[i] = n} }, \ICOPYMETHOD, { n = found.(n); n !? {n.id_(\IMETHOD); node.children[i] = n} }, \COPYMETHOD, { n = found.(n); n !? {n.id_(\METHOD); node.children[i] = n} }, { this.handleCopyMethods(n,doc); } ); }; } *findHelpFile {|str| var old, sym, pfx = SCDoc.helpTargetUrl; if(str.isNil or: {str.isEmpty}) { ^pfx ++ "/Help.html" }; if(this.documents[str].notNil) { ^pfx ++ "/" ++ str ++ ".html" }; sym = str.asSymbol; if(sym.asClass.notNil) { ^pfx ++ (if(this.documents["Classes/"++str].isUndocumentedClass) { (old = Help.findHelpFile(str)) !? { "/OldHelpWrapper.html#"++old++"?"++SCDoc.helpTargetUrl ++ "/Classes/" ++ str ++ ".html" } } ?? { "/Classes/" ++ str ++ ".html" }); }; if(str.last == $_) { str = str.drop(-1) }; ^pfx ++ if("^[a-z][a-zA-Z0-9_]*$|^[-<>@|&%*+/!?=]+$".matchRegexp(str)) { "/Overviews/Methods.html#" } { "/Search.html#" } ++ str; } *getOldWrapUrl {|url| var urlString, className, newUrl; urlString = url.asString; newUrl = URI.fromLocalPath( SCDoc.helpTargetDir +/+ "OldHelpWrapper.html" ); newUrl.fragment = urlString; newUrl.query = SCDoc.helpTargetUrl ++ if((className=urlString.basename.split($.).first).asSymbol.asClass.notNil) {"/Classes/" ++ className ++ ".html"} {"/Guides/WritingHelp.html"} ^newUrl; } } URI { /* NOTE: This class attempts compliance with specification Uniform Resource Identifier (URI): Generic Syntax (RFC 3986) http://datatracker.ietf.org/doc/rfc3986/ If you intend to modify it, please consult the specification! */ classvar parseRegexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"; var <>scheme, <>authority, <>path, <>query, <>fragment; *new { |validUriString| ^super.new.init(validUriString) } *fromLocalPath { |string| var uri = super.new; uri.scheme = "file"; uri.authority = ""; uri.path = string; if (thisProcess.platform.name === \windows) { uri.path = uri.path.replace("\\","/"); if (uri.path.size >= 2 and: {uri.path[1] == $:}) { uri.path = "/" ++ uri.path; } } ^ uri; } *tolerant { |string| var uri; if (thisProcess.platform.name === \windows and: { string.size >= 2 and: { string[1] == $:} } ) { ^ this.fromLocalPath(string); }; uri = this.new(string); if (uri.scheme.isNil) { uri.scheme = "file"; if (uri.authority.isNil) { uri.authority = "" } }; ^ uri; } init { |string| var result; if (string.notNil) { string = string.replace("%20"," "); result = string.findRegexp( parseRegexp ).flop[1]; if (result[1].size > 0) { scheme = result[2] }; if (result[3].size>0) { authority = result[4] }; path = result[5]; if (result[6].size > 0) { query = result[7] }; if (result[8].size > 0) { fragment = result[9] }; }; } asLocalPath { var localPath; if (scheme != "file") { ^nil }; if (thisProcess.platform.name === \windows) { localPath = path; if (localPath.beginsWith("/")) { localPath = localPath.drop(1) }; localPath = localPath.replace("/","\\"); ^localPath; } ^ path.copy; } asString { var str = ""; if (scheme.notNil) { str = str ++ scheme ++ ":" }; if (authority.notNil) { str = str ++ "//" ++ authority }; str = str ++ path; if (query.notNil) { str = str ++ "?" ++ query }; if (fragment.notNil) { str = str ++ "#" ++ fragment }; ^str; } } + String { stripWhiteSpace { var ws = [$\n, $\r, $\t, $\ ]; var a=0, b=this.size-1; while({ ws.includes(this[a])},{a=a+1}); while({ ws.includes(this[b])},{b=b-1}); ^this.copyRange(a,b); } unixCmdGetStdOutLines { var pipe, lines, line; pipe = Pipe.new(this, "r"); lines = Array.new; line = pipe.getLine; while({line.notNil}, {lines = lines.add(line); line = pipe.getLine; }); pipe.close; ^lines; } } + Method { isExtensionOf {|class| ^( (this.filenameSymbol != class.filenameSymbol) and: if((class!=Object) and: (class!=Meta_Object), {class.superclasses.includes(this.ownerClass).not}, {true}) ); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/SCDoc/TODO0000664000000000000000000001506112161364457023240 0ustar rootrootTODO ---- - should we allow *.ext.schelp to add to related:: and categories:: ? - clean up old-help compatibility, do we really need it in both HelpBrowser-goTo and SCDoc.findHelpFile? - HelpBrowser: clean up openNewWindows setting. only have a single class variable? - how to merge methods docs for overwritten methods? replace the whole method doc, or add to it? - copymethod:: should we warn if the method signature is not the same as the target method, if any? what to do with method argstring when copying from non-class/instance to class/instance and vice versa? should we cache last used parse tree in the common case of copying many methods from the same source? - Additional triggers for dest-doc should update: - implementing class changed if(doc.redirect.notNil and: {doc.implKlass != doc.klass.tryPerform(doc.redirect.asSymbol)}) but this only works if doc.implKlass was the *old* implementing class.. so in this case we actually need to store stuff on disk. - another docs metadata changed (for link:: titles) not sure what to do about that.. actually it must be solved by a dependency system. docs that links to other docs has those as dependencies. - class hier changed (for classtree:: tag) this means we need to know if a doc uses classtree::, could be marked in the SCDocMapEntry. also we need to store last class hier on disk, or just always re-render docs that use classtree:: (once per session) - SCDoc.cpp: replace node->children with a linked list (node->next and node->tail) instead of realloc'ing? same for text strings instead of using strmerge? or realloc in blocks? - also write the arg string and the first line of each method description to a methods.js, to show in Search. - private:: now counts as a subsection (like method:: and copymethod::) this means it is a section that can't have any text in it, meaning it needs to come after any section text. an alternative would be to use the syntax: class/instancemethods optprivate subsections but that would mean it *must* come right after the class/instancemethods section header. This would be a lot better actually, since we can then collect all private methodnames easier instead of having to scan the whole section! - deprecate keyword:: and introduce a keywords:: in header only? one could then optionally use anchor::kw_word:: to set kw locations in the doc. the idea is that it would speed up metadata parsing, but I'm not sure it would. - error lines are not always correct, probably because many tags eat trailing newlines. but if we eat newlines before a tag, it will break EOL termination detection.. - move inherit-mets from JS to renderer. get rid of docmap.js loading in docs. Export those lists locally for each class doc instead. OTOH, that means that we write the whole Object method list into *each* class doc! Not so nice.. so keep it like this for the moment! (then, do we really need the subclasses/superclasses in docmap.js? yes, maybe for method search results ("class A inherited by B, etc..") but then, at least only write it to docmap.js, no need to store it in SCDocMapEntry.) * Adjust or deprecate all old classes and methods related to help: Classes: AutoClassHelper HelpSearchResult UGenHelper AutoClassHelperTest TopicHelper Help ClassHelper Helper Methods todo: *Platform, Platform : helpDir - deprecate in favor of SCDoc.helpTargetDir ? PathName : helpFilesDo Help, *Help : findHelpFile - Used by SCDoc to get old help, fix this when all old help is converted Help : findHelpFileOrElse Class, Method : hasHelpFile - in SCDoc all classes has a helpfile - even if it's an autogenerated stub Methods to deprecate? AutoClassHelper, ClassHelper, *Help, TopicHelper, UGenHelper : makeHelp Helper : initHelper TopicHelper : initTopicHelper UGenHelper : initUGenHelper *Quarks, Quarks : help *Help : makeAutoHelp Integer : isHelp AutoClassHelper, ClassHelper : initClassHelper Methods done but could be improved: // Class : helpFileForMethod - FIXME: should jump to method anchor // Method : help - FIXME: should jump to method anchor Also deprecate class.categories since this is now in the helpfiles instead? (categories can still be reached run-time from SCDoc.documents[path]) IDEAS AND IMPROVEMENTS ---------------------- * description for categories? HelpSource/category_descriptions, example: Server>Abstractions: Client-side classes representing server-side stuff show in header and category browser/overview.. extensions should be able to add such descriptions too, but not overwrite existing descriptions? * comments (* like this? *) * shortcuts for links to method in class? mlink::Node-set:: -> link::Classes/Node#-set:: or clink::Node#-set:: -> link::Classes/Node#-set:: ? * render binary op methods differently? like ArrayedCollections ++ we don't want it to display as "++ (aCollection)" do we? rather "++ aCollection" or "this ++ that" or something.. binary ops only uses chars from this list: !@%&*-+=|<>?/ Crazy ideas: - make a new renderer also in C?? integrated with sclang that can access the introspection data (classtree and methods). it could use the docnode tree directly from the parser instead of going through sclang objects - or, let both parser and renderer be standalone. * introspection data could be provided by a machine-readable file written by sclang - class tree, their methods, the filenameSymbol for each class and method. C classname F filenameSymbol CM methodname F filenameSymbol A name defaultvalue A etc... XM IM methodname etc... XM C subclassname etc... XC XC but then we need also an output mode that generates sclang code for docmap construction. - even make the whole scdoc thing in C? * find all helpsource files and render if newer than html target * copy any other files as is * write docmap.json and/or docmap.scd for sclang interface, needed by find-help-for-string, etc. * docmap is also needed internally by scdoc renderer: - document title for links - class summary for classtree:: We could have a mode to only parse the header, and run this first to create the initial docmap. then when we parse all docs fully, the other metadata would be filled in (documented methods, keywords, etc) * it should be fast enough to render all updated files at startup * the process can run in background with .unixCmd, with an action to set helpAvailable=true ... SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/SCDoc/Help.sc0000664000000000000000000000263612161364457023773 0ustar rootrootHelp { // These classvars and vars are part of the deprecated Help.tree stuff. When that stuff is removed from the classlib, this can be removed too. classvar cachePath; var tree, fileslist, , { x = x ++ str.copyRange(beg, i-1) ++ ">"; beg = i+1; }, { end = i } ); }; if(beg<=end) { x = x ++ str[beg..end]; }; ^x; } *htmlForLink {|link| var n, m, f, c, doc; // FIXME: how slow is this? can we optimize #n, m, f = link.split($#); // link, anchor, label ^if ("^[a-zA-Z]+://.+".matchRegexp(link) or: (link.first==$/)) { if(f.size<1) {f=link}; c = if(m.size>0) {n++"#"++m} {n}; ""++this.escapeSpecialChars(f)++""; } { if(n.size>0) { c = baseDir+/+n; doc = SCDoc.documents[n]; // link to other doc (might not be rendered yet) if(doc.notNil) { c = c ++ ".html"; } { // link to ready-made html (Search, Browse, etc) if(File.exists(SCDoc.helpTargetDir+/+n++".html")) { c = c ++ ".html"; } { // link to other file? if(File.exists(SCDoc.helpTargetDir+/+n).not) { "SCDoc: In %\n" " Broken link: '%'" .format(currDoc.fullPath, link).warn; }; }; }; } { c = ""; // link inside same document }; if(m.size>0) { c = c ++ "#" ++ m }; // add #anchor if(f.size<1) { // no label if(n.size>0) { f = if(doc.notNil) {doc.title} {n.basename}; if(m.size>0) { f = f++": "++m; } } { f = if(m.size>0) {m} {"(empty link)"}; }; }; ""++this.escapeSpecialChars(f)++""; }; } *makeArgString {|m, par=true| var res = ""; var value; var l = m.argNames; var last = l.size-1; l.do {|a,i| if (i>0) { //skip 'this' (first arg) if(i==last and: {m.varArgs}) { res = res ++ " " ++ "... " ++ a; } { if (i>1) { res = res ++ ", " }; res = res ++ "" ++ a; (value = m.prototypeFrame[i]) !? { value = if(value.class===Float) { value.asString } { value.cs }; res = res ++ ": " ++ value; }; }; res = res ++ ""; }; }; if (res.notEmpty and: par) { ^("("++res++")"); }; ^res; } *renderHeader {|stream, doc| var x, cats, m, z; var folder = doc.path.dirname; var undocumented = false; if(folder==".",{folder=""}); // FIXME: use SCDoc.helpTargetDir relative to baseDir baseDir = "."; doc.path.occurrencesOf($/).do { baseDir = baseDir ++ "/.."; }; stream << "" << doc.title << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" // FIXME: remove? << "\n" << "\n" << "\n" << "\n" << "\n"; stream << "\n" << "\n" << "
\n" << "
\n" << "
SuperCollider " << folder.asString.toUpper; if(doc.isExtension) { stream << " (extension)"; }; stream << "
\n"; doc.categories !? { stream << "
" << (doc.categories.collect {|r| ""++r++"" }.join(", ")) << "
\n"; }; stream << "

" << doc.title; if((folder=="") and: {doc.title=="Help"}) { stream << ""; }; stream << "

\n" << "
" << this.escapeSpecialChars(doc.summary) << "
\n" << "
\n" << "
\n"; if(doc.isClassDoc) { if(currentClass.notNil) { m = currentClass.filenameSymbol.asString; stream << "
Source: " << m.dirname << "/" << m.basename << "
"; if(currentClass != Object) { stream << "
" << "Inherits from: " << (currentClass.superclasses.collect {|c| ""++c.name++"" }.join(" : ")) << "
\n"; }; if(currentClass.subclasses.notNil) { z = false; stream << "
" << "Subclasses: " << (currentClass.subclasses.collect(_.name).sort.collect {|c,i| if(i==12,{z=true;"… see all"; }; stream << "
\n"; }; if(currentImplClass.notNil) { stream << "
Implementing class: " << "" << currentImplClass.name << "
\n"; }; } { stream << "
Location: NOT INSTALLED!
\n"; }; }; doc.related !? { stream << "\n"; }; // FIXME: Remove this when conversion to new help system is done! if(doc.isUndocumentedClass) { x = Help.findHelpFile(name); x !? { stream << ("[ old help ]") }; }; stream << "
\n"; } *renderChildren {|stream, node| node.children.do {|child| this.renderSubTree(stream, child) }; } *renderMethod {|stream, node, cls, icls, css, pfx| var args = node.text ?? ""; // only outside class/instance methods var names = node.children[0].children.collect(_.text); var mstat, sym, m, m2, mname2; var lastargs, args2; var x, maxargs = -1; var methArgsMismatch = false; minArgs = inf; currentMethod = nil; names.do {|mname| mname2 = this.escapeSpecialChars(mname); if(cls.notNil) { mstat = 0; sym = mname.asSymbol; //check for normal method or getter m = icls !? {icls.findRespondingMethodFor(sym.asGetter)}; m = m ?? {cls.findRespondingMethodFor(sym.asGetter)}; m !? { mstat = mstat | 1; args = this.makeArgString(m); args2 = m.argNames !? {m.argNames[1..]}; }; //check for setter m2 = icls !? {icls.findRespondingMethodFor(sym.asSetter)}; m2 = m2 ?? {cls.findRespondingMethodFor(sym.asSetter)}; m2 !? { mstat = mstat | 2; args = m2.argNames !? {this.makeArgString(m2,false)} ?? {"value"}; args2 = m2.argNames !? {m2.argNames[1..]}; }; maxargs.do {|i| var a = args2[i]; var b = lastargs[i]; if(a!=b and: {a!=nil} and: {b!=nil}) { methArgsMismatch = true; } }; lastargs = args2; case {args2.size>maxargs} { maxargs = args2.size; currentMethod = m2 ?? m; } {args2.size" << "" << (pfx??" ") << "" << "" << mname2 << "" }; x.value; switch (mstat, // getter only 1, { stream << " " << args << "\n"; }, // getter and setter 3, { stream << "\n"; }, // method not found 0, { "SCDoc: In %\n" " Method %% not found.".format(currDoc.fullPath,pfx,mname2).warn; stream << ": METHOD NOT FOUND!\n"; } ); // has setter if(mstat & 2 > 0) { x.value; if(args2.size<2) { stream << " = " << args << "\n"; } { stream << "_ (" << args << ")\n"; } }; m = m ?? m2; m !? { if(m.isExtensionOf(cls) and: {icls.isNil or: {m.isExtensionOf(icls)}}) { stream << "
From extension in " << m.filenameSymbol << "
\n"; } { if(m.ownerClass == icls) { stream << "
From implementing class
\n"; } { if(m.ownerClass != cls) { m = m.ownerClass.name; m = if(m.isMetaClassName) {m.asString.drop(5)} {m}; stream << "
From superclass: " << m << "
\n"; } } }; }; }; if(methArgsMismatch) { "SCDoc: In %\n" " Grouped methods % does not have the same argument signature." .format(currDoc.fullPath, names).warn; }; // ignore trailing mul add arguments if(currentMethod.notNil) { currentNArgs = currentMethod.argNames.size; if(currentNArgs > 2 and: {currentMethod.argNames[currentNArgs-1] == \add} and: {currentMethod.argNames[currentNArgs-2] == \mul}) { currentNArgs = currentNArgs - 2; } } { currentNArgs = 0; }; if(node.children.size > 1) { stream << "
"; this.renderChildren(stream, node.children[1]); stream << "
"; }; currentMethod = nil; } *renderSubTree {|stream, node| var f, z; switch(node.id, \PROSE, { if(noParBreak) { noParBreak = false; } { stream << "\n

"; }; this.renderChildren(stream, node); }, \NL, { }, // these shouldn't be here.. // Plain text and modal tags \TEXT, { stream << this.escapeSpecialChars(node.text); }, \LINK, { stream << this.htmlForLink(node.text); }, \CODEBLOCK, { stream << "

"
                << this.escapeSpecialChars(node.text)
                << "
\n"; }, \CODE, { stream << "" << this.escapeSpecialChars(node.text) << ""; }, \EMPHASIS, { stream << "" << this.escapeSpecialChars(node.text) << ""; }, \TELETYPEBLOCK, { stream << "
" << this.escapeSpecialChars(node.text) << "
"; }, \TELETYPE, { stream << "" << this.escapeSpecialChars(node.text) << ""; }, \STRONG, { stream << "" << this.escapeSpecialChars(node.text) << ""; }, \SOFT, { stream << "" << this.escapeSpecialChars(node.text) << ""; }, \ANCHOR, { stream << " "; }, \KEYWORD, { node.children.do {|child| stream << " "; } }, \MATHBLOCK, { // uses MathJax to typeset TeX math stream << "\\[\n" << this.escapeSpecialChars(node.text) << "\n\\]\n"; }, \MATH, { stream << "\\(" << this.escapeSpecialChars(node.text) << "\\)"; }, \IMAGE, { f = node.text.split($#); stream << "
"; f[1] !? { stream << "
" << f[1] << "" }; // ugly.. stream << "
\n"; }, // Other stuff \NOTE, { stream << "
NOTE: "; noParBreak = true; this.renderChildren(stream, node); stream << "
"; }, \WARNING, { stream << "
WARNING: "; noParBreak = true; this.renderChildren(stream, node); stream << "
"; }, \FOOTNOTE, { footNotes = footNotes.add(node); stream << "" << footNotes.size << " "; }, \CLASSTREE, { stream << "
    "; this.renderClassTree(stream, node.text.asSymbol.asClass); stream << "
"; }, // Lists and tree \LIST, { stream << "
    \n"; this.renderChildren(stream, node); stream << "
\n"; }, \TREE, { stream << "
    \n"; this.renderChildren(stream, node); stream << "
\n"; }, \NUMBEREDLIST, { stream << "
    \n"; this.renderChildren(stream, node); stream << "
\n"; }, \ITEM, { // for LIST, TREE and NUMBEREDLIST stream << "
  • "; noParBreak = true; this.renderChildren(stream, node); }, // Definitionlist \DEFINITIONLIST, { stream << "
    \n"; this.renderChildren(stream, node); stream << "
    \n"; }, \DEFLISTITEM, { this.renderChildren(stream, node); }, \TERM, { stream << "
    "; noParBreak = true; this.renderChildren(stream, node); }, \DEFINITION, { stream << "
    "; noParBreak = true; this.renderChildren(stream, node); }, // Tables \TABLE, { stream << "\n"; this.renderChildren(stream, node); stream << "
    \n"; }, \TABROW, { stream << ""; this.renderChildren(stream, node); }, \TABCOL, { stream << ""; noParBreak = true; this.renderChildren(stream, node); }, // Methods \CMETHOD, { this.renderMethod ( stream, node, currentClass !? {currentClass.class}, currentImplClass !? {currentImplClass.class}, "cmethodname", "*" ); }, \IMETHOD, { this.renderMethod ( stream, node, currentClass, currentImplClass, "imethodname", "-" ); }, \METHOD, { this.renderMethod ( stream, node, nil, nil, "imethodname", nil ); }, \CPRIVATE, {}, \IPRIVATE, {}, \COPYMETHOD, {}, \CCOPYMETHOD, {}, \ICOPYMETHOD, {}, \ARGUMENTS, { stream << "

    Arguments:

    \n\n"; currArg = 0; if(currentMethod.notNil and: {node.children.size < (currentNArgs-1)}) { "SCDoc: In %\n" " Method %% has % args, but doc has % argument:: tags.".format( currDoc.fullPath, if(currentMethod.ownerClass.isMetaClass) {"*"} {"-"}, currentMethod.name, currentNArgs-1, node.children.size, ).warn; }; this.renderChildren(stream, node); stream << "
    "; }, \ARGUMENT, { currArg = currArg + 1; stream << ""; if(node.text.isNil) { currentMethod !? { if(currentMethod.varArgs and: {currArg==(currentMethod.argNames.size-1)}) { stream << "... "; }; stream << if(currArg < currentMethod.argNames.size) { if(currArg > minArgs) { "("++currentMethod.argNames[currArg]++")"; } { currentMethod.argNames[currArg]; } } { "(arg"++currArg++")" // excessive arg }; }; } { stream << if(currentMethod.isNil or: {currArg < currentMethod.argNames.size}) { currentMethod !? { f = currentMethod.argNames[currArg].asString; if( (z = if(currentMethod.varArgs and: {currArg==(currentMethod.argNames.size-1)}) {"... "++f} {f} ) != node.text; ) { "SCDoc: In %\n" " Method %% has arg named '%', but doc has 'argument:: %'.".format( currDoc.fullPath, if(currentMethod.ownerClass.isMetaClass) {"*"} {"-"}, currentMethod.name, z, node.text, ).warn; }; }; if(currArg > minArgs) { "("++node.text++")"; } { node.text; }; } { "("++node.text++")" // excessive arg }; }; stream << ""; this.renderChildren(stream, node); }, \RETURNS, { stream << "

    Returns:

    \n
    "; this.renderChildren(stream, node); stream << "
    "; }, \DISCUSSION, { stream << "

    Discussion:

    \n"; this.renderChildren(stream, node); }, // Sections \CLASSMETHODS, { if(node.notPrivOnly) { stream << "

    Class Methods

    \n"; }; this.renderChildren(stream, node); }, \INSTANCEMETHODS, { if(node.notPrivOnly) { stream << "

    Instance Methods

    \n"; }; this.renderChildren(stream, node); }, \DESCRIPTION, { stream << "

    Description

    \n"; this.renderChildren(stream, node); }, \EXAMPLES, { stream << "

    Examples

    \n"; this.renderChildren(stream, node); }, \SECTION, { stream << "

    " << this.escapeSpecialChars(node.text) << "

    \n"; if(node.makeDiv.isNil) { this.renderChildren(stream, node); } { stream << "
    "; this.renderChildren(stream, node); stream << "
    "; }; }, \SUBSECTION, { stream << "

    " << this.escapeSpecialChars(node.text) << "

    \n"; if(node.makeDiv.isNil) { this.renderChildren(stream, node); } { stream << "
    "; this.renderChildren(stream, node); stream << "
    "; }; }, { "SCDoc: In %\n" " Unknown SCDocNode id: %".format(currDoc.fullPath, node.id).warn; this.renderChildren(stream, node); } ); } *renderTOC {|stream, node| node.children !? { stream << ""; }; } *addUndocumentedMethods {|list, body, id2, id, title| var l; if(list.size>0) { l = list.collectAs(_.asString,Array).sort.collect {|name| SCDocNode() .id_(id2) .children_([ SCDocNode() .id_(\METHODNAMES) .children_([ SCDocNode() .id_(\STRING) .text_(name.asString) ]) ]); }; body.addDivAfter(id, nil, title, l); } } *renderClassTree {|stream, cls| var name, doc, desc = ""; name = cls.name.asString; doc = SCDoc.documents["Classes/"++name]; doc !? { desc = " - "++doc.summary }; if(cls.name.isMetaClassName, {^this}); stream << "
  • " << name << "" << desc << "\n"; cls.subclasses !? { stream << "
      \n"; cls.subclasses.copy.sort {|a,b| a.name < b.name}.do {|x| this.renderClassTree(stream, x); }; stream << "
    \n"; }; } *renderFootNotes {|stream| if(footNotes.notNil) { stream << "
    \n"; footNotes.do {|n,i| stream << "
    " << "[" << (i+1) << "] - "; noParBreak = true; this.renderChildren(stream, n); stream << "
    "; }; stream << "
    "; }; } *renderFooter {|stream, doc| stream << "" << "
  • "; } *renderOnStream {|stream, doc, root| var body = root.children[1]; var redirect; currDoc = doc; footNotes = nil; noParBreak = false; if(doc.isClassDoc) { currentClass = doc.klass; currentImplClass = doc.implKlass; if(currentClass != Object) { body.addDivAfter(\CLASSMETHODS,"inheritedclassmets","Inherited class methods"); body.addDivAfter(\INSTANCEMETHODS,"inheritedinstmets","Inherited instance methods"); }; this.addUndocumentedMethods(doc.undoccmethods, body, \CMETHOD, \CLASSMETHODS, "Undocumented class methods"); this.addUndocumentedMethods(doc.undocimethods, body, \IMETHOD, \INSTANCEMETHODS, "Undocumented instance methods"); body.sortClassDoc; } { currentClass = nil; currentImplClass = nil; }; this.renderHeader(stream, doc); stream << "
    \n"; this.renderTOC(stream, body); stream << "
    "; this.renderChildren(stream, body); this.renderFootNotes(stream); this.renderFooter(stream, doc); currDoc = nil; } *renderToFile {|filename, doc, root| var stream; File.mkdir(filename.dirname); stream = File(filename, "w"); if(stream.isOpen) { this.renderOnStream(stream, doc, root); stream.close; } { warn("SCDoc: Could not open file % for writing".format(filename)); } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/backwards_compatibility/0000775000000000000000000000000012245452763026505 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/backwards_compatibility/PMOsc.sc0000664000000000000000000000236512014636263030014 0ustar rootroot// these pseudo ugens replicate some SC2 ugens // still useful as shorthands PMOsc { *ar { arg carfreq,modfreq,pmindex=0.0,modphase=0.0,mul=1.0,add=0.0; ^SinOsc.ar(carfreq, SinOsc.ar(modfreq, modphase, pmindex),mul,add) } *kr { arg carfreq,modfreq,pmindex=0.0,modphase=0.0,mul=1.0,add=0.0; ^SinOsc.kr(carfreq, SinOsc.kr(modfreq, modphase, pmindex),mul,add) } } MultiTap { *ar { arg timesArray, levelsArray, in = 0.0, mul = 1.0, add = 0.0,bufnum; var sampleRate; timesArray = timesArray.dereference; levelsArray = levelsArray.dereference; RecordBuf.ar(in,bufnum,0.0, run: -1.0); sampleRate = BufSampleRate.kr(bufnum); ^Mix.fill(timesArray.size,{ arg i; PlayBuf.ar(in.numChannels, bufnum, -1.0,1.0, timesArray.at(i) * sampleRate, loop: 1) .madd(levelsArray.at(i) ? 1.0) }).madd(mul,add); } } /* GrainTap { // overlap determines density *ar { arg bufnum, grainDur = 0.2, pchRatio = 1.0, pchDispersion = 0.0, timeDispersion = 0.0, overlap = 2.0, mul = 1.0, add = 0.0; var sampleRate; sampleRate = BufSampleRate.kr(bufnum); pchRatio = pchRatio * BufRateScale.kr(bufnum); ^Mix.fill( howMany ? ,{ arg i; PlayBuf.ar(buf.numChannels, bufnum,1.0,1.0, loop: 1) }).madd(mul,add); } } */ SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/backwards_compatibility/extMethods.sc0000664000000000000000000000331012014636263031146 0ustar rootroot// The following interface in an optimized version of asControlInput that // flattens arrayed values and marks the outermost array of a value with $[ and $] // These Chars are turning into typetags ([ and ]) in the OSC message to mark that array // Inner arrays are flattened (they are not meaningful in the server context) // This makes it possible to write Synth("test", [0, [[100,200,300], [0.1,0.2,0.3], [10,20,30]] ]) // and have all the arguments be assigned to consecutive controls in the synth. +Array { asOSCArgBundle { var array = Array(100); // allocate a bunch of space this.do { | msg | array = array.add(msg.asOSCArgArray) }; ^array } asOSCArgArray { var array = Array(100); // allocate a bunch of space this.do { | e | array = e.asOSCArgEmbeddedArray(array) }; ^array } asOSCArgEmbeddedArray { | array| array = array.add($[); this.do{ | e | array = e.asOSCArgEmbeddedArray(array) }; array.add($]); ^array; } } +Env { asControlInput { ^this.asArray } asOSCArgEmbeddedArray { | array| ^this.asArray.asOSCArgEmbeddedArray(array) } } +Object { asOSCArgEmbeddedArray { | array| ^array.add(this.asControlInput) } asOSCArgArray { ^this.asControlInput } asOSCArgBundle { ^this.asControlInput } asStringff { | size = 8 | var str = this.asString; str = str[0..size-1]; str = str ++ String.fill(size - str.size, Char.space); ^str; } postff { | size = 8 | this.asStringff(size).post } } +Nil { asOSCArgArray {} } +Ref { asOSCArgEmbeddedArray { | array| ^value.asOSCArgEmbeddedArray(array) } } +AbstractFunction { eq { arg function, adverb; ^this.composeBinaryOp('==', function, adverb) } // ne { arg function, adverb; ^this.composeBinaryOp('!=', function, adverb) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/0000775000000000000000000000000012245452763022670 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/Patterns/0000775000000000000000000000000012245452763024470 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/Patterns/Fdef.sc0000664000000000000000000001034112245365552025661 0ustar rootroot// maybe we want to call "value" "reduce" and only use one class. Maybe : Ref { classvar callFunc; classvar <>defaultValue; classvar <>protected = false, <>verbose = false; classvar <>defaultValue=1; source { ^value } source_ { arg obj; this.value = obj; this.changed(\source, obj) } clear { value = nil } value { arg ... args; ^this.reduceFuncProxy(args) } valueArray { arg args; ^this.reduceFuncProxy(args) } valueEnvir { arg ... args; ^this.notYetImplemented(thisMethod) //^value.valueEnvir(*args) ? defaultValue } valueArrayEnvir { arg ... args; ^this.notYetImplemented(thisMethod) //^value.valueArrayEnvir(args) ? defaultValue } functionPerformList { arg selector, arglist; ^this.performList(selector, arglist) } // this allows recursion apply { arg ... args; ^this.reduceFuncProxy(args, false) } // function composition o { arg ... args; ^NAryValueProxy(this, args) } <> { arg that; ^o (this, that) } // use in list comprehension all { ^this.source.all } do { arg function; this.source.do(function) // problem: on the fly change is not picked up in this case. } doesNotUnderstand { arg selector ... args; ^this.composeNAryOp(selector, args) } // streams and patterns embedInStream { arg inval; ^Prout { arg inval; var curVal, str; var outval; while { if(curVal !== value) { str = value.asStream; curVal = value }; outval = str.next(inval); outval.notNil } { inval = outval.yield; } }.embedInStream(inval) } // math composeUnaryOp { arg aSelector; ^UnaryOpFunctionProxy.new(aSelector, this) } composeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, this, something, adverb); } reverseComposeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, something, this, adverb); } composeNAryOp { arg aSelector, anArgList; ^NAryOpFunctionProxy.new(aSelector, this, anArgList) } // used by AbstractFunction:reduceFuncProxy // to prevent reduction of enclosed functions valueFuncProxy { arg args; ^this.catchRecursion { value.valueFuncProxy(args) } ?? { this.valueEmpty(args) }; } valueEmpty { arg args; if(verbose) { ("* ? incomplete definition: %\n").postf(this.infoString(args)) }; ^defaultValue } reduceFuncProxy { arg args, protect=true; ^if(protect.not) { value.reduceFuncProxy(args) } { this.catchRecursion { value.reduceFuncProxy(args) } } ?? { this.valueEmpty(args) }; } catchRecursion { arg func; var val, previous; try { protect { previous = current; current = this; if(this.includedInCallers) { if(verbose) { ("* ! Couldn't solve a recursive definition in %\n") .postf(this.infoString) }; callFunc.value(this, callers, \recursion); this.throw; }; // add this to the list of current callers callers = callers.add(this); // evaluate function val = func.value; callFunc.value(this, callers, val); } { |exception| if(verbose and: { exception.isKindOf(Exception)} ) { ("Error or incomplete specification" + exception.errorString).postln; }; /* if(exception.isKindOf(this.class).not) { Exception.throw; }*/ // remove again callers.pop; current = previous; }; } ^val } includedInCallers { ^callers.notNil and: { callers.includes(this) } } postString { var res = this.findKey; ^if(res.notNil) { "~" ++ res } { this.asString } } infoString { arg args; var who, str="", src; who = this.findKey; if(who.isNil) { ^this.asString }; who = "~" ++ who; src = this.source.postString; if(args.notNil and: {args.notEmpty}) { args = args.collect(_.postString); str = "\nArguments passed: %".format(args) }; ^"% <- %".format(who, src.asString) ++ str } findKey { ^currentEnvironment.findKeyForValue(this) } storeOn { arg stream; // maybe should try to catch a recursion here: stream << this.class.name << "(" <<< value << ")" } } Fdef : Maybe { classvar <>all; *initClass { all = IdentityDictionary.new } *new { arg key, val; var res; res = all[key]; if(res.isNil) { res = super.new.source_(val); all[key] = res } { if(val.notNil) { res.source = val }; } ^res } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/Patterns/Psym.sc0000664000000000000000000000476612245365552025763 0ustar rootrootPsym : FilterPattern { var <>dict; *new { arg pattern, dict; ^super.new(pattern).dict_(dict) } storeArgs { ^[pattern,dict] } lookupClass { ^Pdef } lookUp { arg key; ^(dict ?? { this.lookupClass.all }).at(key) ?? { this.lookupClass.default } } embedInStream { arg inval; var str, outval, pat; str = pattern.asStream; while { outval = str.next(inval); outval.notNil } { pat = this.getPattern(outval); inval = pat.embedInStream(inval); }; ^inval } getPattern { arg key; ^if(key.isSequenceableCollection) { this.lookupClass.parallelise( key.collect {|each| this.lookUp(each.asSymbol) } ); } { this.lookUp(key.asSymbol) }; } } Pnsym : Psym { lookupClass { ^Pdefn } } Ptsym : Psym { var <>quant, <>dur, <>tolerance; *new { arg pattern, dict, quant, dur, tolerance = 0.001; ^super.newCopyArgs(pattern, dict, quant, dur, tolerance) } storeArgs { ^[ pattern, dict, quant, dur, tolerance ] } embedInStream { arg inval; var str, outval, pat, quantVal, quantStr, durVal, durStr; str = pattern.asStream; quantStr = quant.asStream; durStr = dur.asStream; while { outval = str.next(inval); quantVal = quantStr.next(inval) ? quantVal; durVal = durStr.next(inval) ? durVal; outval.notNil } { pat = Psync(this.getPattern(outval), quantVal, durVal, tolerance); inval = pat.embedInStream(inval); }; ^inval } } Pnsym1 : Pnsym { embedInStream { arg inval; var str, which, streams, outval, pat, currentStream; str = pattern.asStream; streams = IdentityDictionary.new; while { which = str.next(inval); which.notNil } { pat = this.getPattern(which); currentStream = streams.at(pat); if(currentStream.isNil) { currentStream = pat.asStream; streams.put(pat, currentStream); }; outval = currentStream.next(inval); outval ?? { ^inval }; inval = outval.yield }; ^inval } } Psym1 : Psym { embedInStream { arg inval, cleanup; var str, which, streams, outval, pat, currentStream; str = pattern.asStream; streams = IdentityDictionary.new; cleanup ?? { cleanup = EventStreamCleanup.new }; while { which = str.next(inval); which.notNil } { pat = this.getPattern(which); currentStream = streams.at(pat); if(currentStream.isNil) { currentStream = pat.asStream; streams.put(pat, currentStream); }; outval = currentStream.next(inval); if(outval.isNil) { ^cleanup.exit(inval) }; cleanup.update(outval); inval = outval.yield }; ^cleanup.exit(inval); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/Patterns/Pdef.sc0000664000000000000000000004475512245365552025713 0ustar rootroot// contains numerical / value patterns PatternProxy : Pattern { var envir; var >clock, quant, <>condition=true, reset; // quant new pattern insertion. can be [quant, phase, timingOffset] // in EventPatternProxy it can be [quant, phase, timingOffset, onset] classvar <>defaultQuant, defaultEnvir; *new { arg source; ^super.new.source_(source) } *default { ^1 } // safe for duration patterns *defaultValue { ^1 } clock { ^clock ? TempoClock.default } quant { ^quant ?? { this.class.defaultQuant } } quant_ { arg val; quant = val } constrainStream { arg stream; if(quant.isNil or: { stream.isNil }) { ^pattern.asStream }; ^Pseq([PfinQuant(EmbedOnce(stream), quant, clock), pattern]).asStream } source_ { arg obj; var pat = if(obj.isKindOf(Function)) { this.convertFunction(obj) }{ obj }; if (obj.isNil) { pat = this.class.default }; pattern = pat; source = obj; // keep original here. this.changed(\source, obj); } setSourceLikeInPbind { arg obj; var pat = if(obj.isKindOf(Function)) { this.convertFunction(obj) }{ obj }; if (obj.isNil) { pat = this.class.default }; pattern = pat.fin(inf); source = obj; // keep original here. this.changed(\source, obj); } defaultEvent { if(envir.isNil) { envir = this.class.event }; ^if(envir[\independent] === true) { (parent:envir) } { envir } } convertFunction { arg func; ^Prout { var inval = func.def.prototypeFrame !? { inval = this.defaultEvent }; func.value( inval ).embedInStream(inval) } } *parallelise { arg list; ^Ptuple(list) } pattern_ { arg pat; this.source_(pat) } timingOffset_ { arg val; quant = quant.instill(2, val) } timingOffset { arg val; ^quant.obtain(2) } phase_ { arg val; quant = quant.instill(1, val) } phase { arg val; ^quant.obtain(1) } quantBeat_ { arg val; quant = quant.instill(0, val) } quantBeat { arg val; ^quant.obtain(0) } set { arg ... args; if(envir.isNil) { this.envir = this.class.event }; args.pairsDo { arg key, val; envir.put(key, val) }; this.changed(\set, args); } unset { arg ... args; if(envir.notNil) { args.do { arg key; envir.removeAt(key) }; this.changed(\unset, args); } } get { arg key; ^if(envir.notNil) { envir[key] } { nil }; } place { arg ... args; if(envir.isNil) { this.envir = this.class.event }; args.pairsDo { arg key, val; envir.place(key, val) }; // place is defined in the event. } isEventPattern { ^false } receiveEvent { ^nil } embed { |val| ^if(val.notNil) { Pchain(this, val) } { this }.embedInStream } embedInStream { arg inval; var outval, count = 0; var pat = pattern; var test = condition; var resetTest = reset; var stream = pattern.asStream; while { this.receiveEvent(inval); // used in subclass if( (reset !== resetTest) or: { pat !== pattern and: { test.value(outval, count) } } ) { pat = pattern; test = condition; resetTest = reset; count = 0; stream = this.constrainStream(stream); }; outval = stream.next(inval); count = count + 1; outval.notNil }{ inval = outval.yield; }; ^inval } endless { ^Prout { arg inval; var outval, count = 0; var pat = pattern; var test = condition; var resetTest = reset; var stream = pattern.asStream; var default = this.class.defaultValue; loop { this.receiveEvent(inval); // used in subclass if( (reset !== resetTest) or: { pat !== pattern and: { test.value(outval, count) } } ) { pat = pattern; test = condition; resetTest = reset; count = 0; stream = this.constrainStream(stream); }; outval = stream.next(inval) ? default; count = count + 1; inval = outval.yield; } } } count { arg n=1; condition = { |val,i| i % n == 0 } } reset { reset = reset ? 0 + 1 } sched { arg func; if(quant.isNil) { func.value } { this.clock.schedAbs(quant.nextTimeOnGrid(this.clock), { func.value; nil }) } } storeArgs { ^[pattern] } // these following methods are factored out for the benefit of subclasses // they only work for Pdef/Tdef/Pdefn. *removeAll { this.clear; this.all.makeEmpty; } *clear { this.all.do { arg pat; pat.clear } } clear { this.stop; this.source = nil; ^nil } remove { if(this.class.hasGlobalDictionary) { this.class.all.removeAt(this.key) }; this.clear; } // backward compatibility *basicNew { arg source; ^super.new.init(source) } // global storage *at { arg key; ^if(this.hasGlobalDictionary) { this.all.at(key) } { nil } } repositoryArgs { ^[this.key, this.source] } *postRepository { arg keys, stream; if(this.hasGlobalDictionary.not) { Error("This class has no global repository.").throw }; keys = keys ?? { this.all.keys }; stream = stream ? Post; keys.do { arg key; var item; item = this.all[key]; if(item.notNil and: { item.source !== this.default }) { stream << item.class.name << "(" <<<* item.repositoryArgs << ")"; if(item.envir.notNil and: { item.envir.notEmpty }) { stream << ".set(" <<<* item.envir.asKeyValuePairs << ")" }; stream << ";\n" }; }; } *event { arg proxyClass = PatternProxy; var event, res; if(defaultEnvir.isNil) { defaultEnvir = Event.default; defaultEnvir.parent = defaultEnvir.parent.copy.putAll( ( forward: #{ 1 }, proxyClass: proxyClass, get: {|e, key| var x = e.at(key); if(x.isKindOf(e.proxyClass).not) { x = e.proxyClass.new; e.put(key, x); }; x }, place: { |e, key, val| var x = e.at(key); if(x.isKindOf(e.proxyClass).not) { x = e.proxyClass.new; e.put(key, x) }; x.source_(val) } ) ); }; event = defaultEnvir.copy; // event[\self] = event; // this risks a crash on storeOn. ^event } *hasGlobalDictionary { ^false } } Pdefn : PatternProxy { var all; *initClass { all = IdentityDictionary.new; } *new { arg key, item; var res = this.at(key); if(res.isNil) { res = super.new(item).prAdd(key); } { if(item.notNil) { res.source = item } } ^res } map { arg ... args; if(envir.isNil) { this.envir = () }; args.pairsDo { |key, name| envir.put(key, Pdefn(name)) }; this.changed(\map, args); } storeArgs { ^[key] } // assume it was created globally prAdd { arg argKey; key = argKey; all.put(argKey, this); } *hasGlobalDictionary { ^true } } // contains time patterns (tasks) TaskProxy : PatternProxy { var playQuant; classvar <>defaultQuant=1.0; storeArgs { ^[source] } source_ { arg obj; pattern = if(obj.isKindOf(Function)) { this.convertFunction(obj) }{ obj }; if (obj.isNil) { pattern = this.class.default; source = obj; }; this.wakeUp; source = obj; this.changed(\source, obj); } convertFunction { arg func; ^Prout { |inevent| var inval = func.def.prototypeFrame !? { this.defaultEvent }; if(inevent.isNumber or: {inevent.isNil} or: { inval.isNil }) { inevent = inval } { inevent.copy.parent_(inval); }; func.value(inevent) } } isEventPattern { ^true } *default { ^Pn(this.defaultValue, 1) } constrainStream { arg str; ^if(this.quant.notNil and: { str.notNil }) { Pseq([ EmbedOnce(Pconst(thisThread.clock.timeToNextBeat(this.quant), str, 0.001)), pattern ]) } { pattern }.asStream } align { arg argQuant; quant = argQuant; this.source = this.source.copy; } ////////// playing interface ////////// playOnce { arg argClock, doReset = (false), quant; var clock = argClock ? this.clock; ^PauseStream.new(this.asProtected.asStream).play(clock, doReset, quant ? this.quant) } play { arg argClock, doReset=false, quant; playQuant = quant ? this.quant; if(player.isNil) { player = this.playOnce(argClock, doReset, playQuant); } { // resets when stream has ended or after pause/cmd-period: if (player.streamHasEnded or: { player.wasStopped }) { doReset = true }; if(player.isPlaying.not) { player.play(argClock, doReset, playQuant); } { if (doReset) { player.reset }; } } } wakeUp { if(this.isPlaying) { this.play(quant:playQuant) } } asProtected { ^Pprotect(this, { if(this.player.notNil) { this.player.streamError } }) } // check playing states: isPlaying { ^player.notNil and: { player.wasStopped.not } } isActive { ^this.isPlaying and: { player.streamHasEnded.not } } hasSource { ^source.notNil } hasEnvir { ^envir.notNil } hasPlayer { ^player.notNil } hasEnded { ^player.isNil or: { player.streamHasEnded } } isPaused { ^player.isNil or: { player.wasStopped } } canPause { ^player.notNil and: { player.canPause } } fork { arg clock, quant, event; ^Routine { this.embedInStream(event) }.play(clock ? thisThread.clock, quant) } stop { player.stop; player = nil; } pause { if(player.notNil) { this.sched { player.pause } } } resume { arg clock, quant; player !? { player.resume(clock ? this.clock, quant ? this.quant) } } } Tdef : TaskProxy { var all; *initClass { all = IdentityDictionary.new; } *new { arg key, item; var res = this.at(key); if(res.isNil) { res = super.new(item).prAdd(key); } { if(item.notNil) { res.source = item } } ^res } storeArgs { ^[key] } prAdd { arg argKey; key = argKey; all.put(argKey, this); } *hasGlobalDictionary { ^true } } // contains event patterns EventPatternProxy : TaskProxy { var <>fadeTime; classvar <>defaultQuant=1.0; storeArgs { ^[source] } source_ { arg obj; if(obj.isKindOf(Function)) // allow functions to be passed in { pattern = PlazyEnvirN(obj) } { if (obj.isNil) { pattern = this.class.default } { pattern = obj } }; envir !? { pattern = pattern <> envir }; this.wakeUp; source = obj; this.changed(\source, obj); } envir_ { arg dict; envir = dict; this.source = source; } *defaultValue { ^Event.silent } embedInStream { arg inval, cleanup; var outval, count=0; var pat = pattern; var test = condition; var resetTest = reset; var stream = pattern.asStream; cleanup ?? { cleanup = EventStreamCleanup.new }; while { this.receiveEvent(inval); if( (reset !== resetTest) or: { pat !== pattern and: { test.value(outval, count) } } ) { pat = pattern; test = condition; resetTest = reset; count = 0; // inval is the next event that will be yielded // constrainStream may add some values to it so IT MUST BE YIELDED stream = this.constrainStream(stream, inval, cleanup); cleanup = EventStreamCleanup.new; }; outval = stream.next(inval); count = count + 1; outval.notNil }{ outval = cleanup.update(outval); inval = outval.yield; if(inval.isNil) { ^nil.alwaysYield } }; ^inval } endless { ^Prout { arg inval; var outval; var cleanup = EventStreamCleanup.new; var count = 0; var pat = pattern; var test = condition; var resetTest = reset; var stream = pattern.asStream; var default = this.class.defaultValue; loop { this.receiveEvent(inval); if( (reset !== resetTest) or: { pat !== pattern and: { test.value(outval, count) } } ) { pat = pattern; test = condition; resetTest = reset; count = 0; // inval is the next event that will be yielded // constrainStream may add some values to it so IT MUST BE YIELDED stream = this.constrainStream(stream, inval, cleanup); cleanup = EventStreamCleanup.new; }; outval = stream.next(inval) ? default; count = count + 1; outval = cleanup.update(outval); inval = outval.yield; } } } constrainStream { arg str, inval, cleanup; var delta, tolerance, new; var quantBeat, catchUp, deltaTillCatchUp, forwardTime, quant = this.quant; ^if(quant.notNil) { quantBeat = this.quantBeat ? 0; catchUp = this.outset; delta = thisThread.clock.timeToNextBeat(quant); tolerance = quantBeat % delta % 0.125; if(catchUp.notNil) { deltaTillCatchUp = thisThread.clock.timeToNextBeat(catchUp); new = pattern.asStream; forwardTime = quantBeat - delta + deltaTillCatchUp; delta = new.fastForward(forwardTime, tolerance) + deltaTillCatchUp; } { new = pattern }; if(fadeTime.isNil) { if(delta == 0) { cleanup.exit(inval); new } { Pseq([EmbedOnce(Pfindur(delta, str, tolerance).asStream(cleanup)), new]) } }{ Ppar([ EmbedOnce(PfadeOut(str, fadeTime, delta, tolerance).asStream(cleanup)), PfadeIn(new, fadeTime, delta, tolerance) ]) } } { cleanup.exit(inval); pattern }.asStream } *parallelise { arg list; ^Ppar(list) } outset_ { arg val; quant = quant.instill(3, val) } outset { arg val; ^this.quant.obtain(3) } // branching from another thread fork { arg argClock, quant, protoEvent; // usual fork arg order: clock, quant, ... argClock = argClock ? thisThread.clock; ^EventStreamPlayer(this.asStream, protoEvent).play(argClock, true, quant) } // playing one instance // playOnce { arg argClock, protoEvent, quant; ^this.fork(argClock ? this.clock, quant ? this.quant, protoEvent) } ////////// playing interface ////////// // start playing // play { arg argClock, protoEvent, quant, doReset=false; playQuant = quant ? this.quant; if(player.isNil) { player = EventStreamPlayer(this.asProtected.asStream, protoEvent); player.play(argClock, doReset, playQuant); } { // resets when stream has ended or after pause/cmd-period: if(player.streamHasEnded or: { player.wasStopped }) { doReset = true }; protoEvent !? { player.event = protoEvent }; if(player.isPlaying.not) { player.play(argClock, doReset, playQuant); } { if(doReset) { player.reset }; } } } } Pdef : EventPatternProxy { var all; storeArgs { ^[key] } *new { arg key, item; var res = this.at(key); if(res.isNil) { res = super.new(item).prAdd(key); } { if(item.notNil) { res.source = item } } ^res } map { arg ... args; if(envir.isNil) { this.envir = () }; args.pairsDo { |key, name| envir.put(key, Pdefn(name)) } } prAdd { arg argKey; key = argKey; all.put(argKey, this); } *hasGlobalDictionary { ^true } *initClass { var phraseEventFunc; all = IdentityDictionary.new; Class.initClassTree(Event); phraseEventFunc = { var pat, event, outerEvent, recursionLevel, instrument, embeddingLevel, freq, rest; embeddingLevel = ~embeddingLevel ? 0; // infinite recursion catch freq = ~freq.value; rest = freq.isKindOf(Symbol); // check for outer rests if(rest) { ~freq = freq }; pat = (~repository ? all).at(~instrument); if(pat.notNil and: { embeddingLevel < 8 }) { pat = pat.pattern; // optimization. outer pattern takes care for replacement // preserve information from outer pattern, but not delta. recursionLevel = ~recursionLevel; if(~transparency.isNil or: { ~transparency > (recursionLevel ? 0) } ) { outerEvent = currentEnvironment.copy } { outerEvent = Event.default; outerEvent.use { ~type = \phrase; ~recursionLevel = recursionLevel; } }; if(recursionLevel.notNil) { if(recursionLevel > 0) { // in recursion, some inner values have to be overridden instrument = ~instrument; pat = pat.collect { |inval| inval.use { ~instrument = instrument; ~parent = outerEvent; ~recursionLevel = recursionLevel - 1; }; inval }; } { // play pattern in the ordinary way ~type = \note; }; } { // avoid recursion, if instrument not set. outerEvent.put(\embeddingLevel, embeddingLevel + 1); outerEvent.parent_(Event.parentEvents.default); }; // maybe add a Pprotect here. // pat.asProtected pat = Pfindur(~sustain.value, pat); outerEvent.put(\delta, nil); // block delta modification by Ppar outerEvent.put(\instrument, ~synthDef ? \default); pat.play(thisThread.clock, outerEvent, 0.0); } { ~type = \note; ~play.value; } }; Event.addEventType(\phrase, phraseEventFunc); } } PbindProxy : Pattern { var <>pairs, dict, <>which, <>repeats, <>default; *new { arg dict, which, repeats=inf, default; ^super.newCopyArgs(dict, which, repeats, default); } storeArgs { ^[dict,which,repeats,default ] } embedInStream { arg inval; var keyStream, key; keyStream = which.asStream; repeats.value(inval).do({ key = keyStream.next(inval); if(key.isNil) { ^inval }; inval = (dict.at(key) ? default).embedInStream(inval); }); ^inval } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/Patterns/Pxfade.sc0000664000000000000000000000367212245365552026235 0ustar rootrootPfadeIn : FilterPattern { var <>fadeTime, <>holdTime=0, <>tolerance; *new { arg pattern, fadeTime=1.0, holdTime=0.0, tolerance=0.0001; ^super.new(pattern).fadeTime_(fadeTime).holdTime_(holdTime).tolerance_(tolerance) } embedInStream { arg inval; var outval, elapsed=0, stream, c; stream = pattern.asStream; if(holdTime > 0.0) { Event.silent(holdTime, inval).yield }; loop { outval = stream.next(inval); if(outval.isNil) { ^nil.yield }; elapsed = elapsed + outval.delta; c = elapsed / fadeTime; if(c >= 1.0) { inval = outval.yield; ^stream.embedInStream(inval); } { outval = outval.copy; outval[\amp] = c.max(0) * outval[\amp]; // outval[\amp] = (c.max(0) * pi * 0.25).sin * outval[\amp]; inval = outval.yield; } } } storeArgs { ^[ pattern, fadeTime, holdTime, tolerance ] } } PfadeOut : PfadeIn { asStream { | cleanup| ^Routine({ arg inval; this.embedInStream(inval, cleanup) }) } embedInStream { arg inval, cleanup; var outval, elapsed=0, stream, c; stream = pattern.asStream; cleanup ?? { cleanup = EventStreamCleanup.new }; loop { inval = stream.next(inval) ?? { ^cleanup.exit(inval) }; cleanup.update(inval); elapsed = elapsed + inval.delta; if(elapsed.round(tolerance) <= holdTime) { inval = inval.yield; } { c = elapsed - holdTime / fadeTime; if(c >= 1.0) { ^cleanup.exit(inval); } { inval[\amp] = (1.0 - c.max(0)) * inval[\amp]; inval = inval.yield; } } } } } PfinQuant : FilterPattern { var <>quant, <>clock; *new { arg pattern, quant, clock; ^super.new(pattern).quant_(quant).clock_(clock) } embedInStream { arg inval; var value, stream = pattern.asStream; var referenceClock = clock ? thisThread.clock; var endAt = quant.nextTimeOnGrid(referenceClock); while { value = stream.next(inval); value.notNil and: { referenceClock.beats < endAt } } { inval = value.yield; }; ^inval } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/Patterns/extFunction.sc0000664000000000000000000000067312245365552027332 0ustar rootroot+Object { valueFuncProxy { ^this } reduceFuncProxy { ^this } postString { ^this.asString } } +AbstractFunction { reduceFuncProxy { arg args; ^this.valueArray(args).valueFuncProxy(args) } } +Function { postString { ^this.asCompileString } } +UnaryOpFunctionProxy { postString { ^a.postString ++ "." ++ selector } } +BinaryOpFunctionProxy { postString { ^a.postString + selector.asBinOpString + b.postString } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/Patterns/extRoutine.sc0000664000000000000000000000212412245365552027163 0ustar rootroot+Pattern { lock { arg n=1; ^Pfin(n.asStream, this.asStream) } } +Stream { fastForward { arg by, tolerance=0, inevent; var t = 0, delta = 0, event; if(by <= 0) { ^0.0 }; inevent = inevent ?? { Event.default }; while { t.roundUp(tolerance) < by } { event = this.next(inevent.copy); if(event.isNil) { ("end of stream. Time left:" + (by - t)).inform; ^t - by }; event = event.copy.put(\freq, \rest); event.play; delta = event.delta; if(delta.isNil) { ("end of stream. Time left:" + (by - t)).inform; ^t - by }; t = t + delta; }; ^t - by // time left to next event } } + EventStreamPlayer { xplay { arg fadeTime, argClock, doReset = false, quant=1.0; if (doReset, { this.reset }); clock = argClock ? clock ? TempoClock.default; stream = PfadeIn(originalStream, fadeTime).asStream; clock.play(this, quant); } xstop { arg fadeTime; stream = PfadeOut(stream, fadeTime).asStream; } } +PauseStream { xplay { arg fadeTime, argClock, doReset = false, quant=1.0; this.play(argClock, doReset, quant); } xstop { // stop after fade? this.stop; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/Patterns/extPostAsCode.sc0000664000000000000000000000132312245365552027542 0ustar rootroot+ PatternProxy { // like asCompileString, but with full source etc. asCode { var mykey = this.key.asCompileString; var str; str = "" ++ this.class.name ++ "("; if(source.isNil or: { source == this.class.default }) { str = str ++ mykey; } { str = str ++ this.repositoryArgs.asCompileString.drop(1).drop(-1); }; str = str ++ ")"; if(this.envir.notNil and: { this.envir.notEmpty }) { str = str ++ ".set(" ++ this.envir.asKeyValuePairs.asCompileString.drop(1).drop(-1) ++ ")" }; str = str ++ ";" ^str } } + Tdef { printOn { |stream| ^this.storeOn(stream); } } + Pdef { printOn { |stream| ^this.storeOn(stream); } } + Pdefn { printOn { |stream| ^this.storeOn(stream); } }SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/Patterns/OpFunctionProxy.sc0000664000000000000000000000554012245365552030150 0ustar rootrootUnaryOpFunctionProxy : UnaryOpFunction { valueFuncProxy { arg args; ^this.reduceFuncProxy(args) } reduceFuncProxy { arg args; ^a.reduceFuncProxy(args).perform(selector) } value { arg ... args; ^this.reduceFuncProxy(args) } valueArray { arg args; ^this.reduceFuncProxy(args) } composeUnaryOp { arg aSelector; ^UnaryOpFunctionProxy.new(aSelector, this) } composeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, this, something, adverb); } reverseComposeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, something, this, adverb); } composeNAryOp { arg aSelector, anArgList; ^NAryOpFunctionProxy.new(aSelector, this, anArgList) } // behave like a pattern embedInStream { arg inval; ^this.value.embedInStream(inval) } } BinaryOpFunctionProxy : BinaryOpFunction { valueFuncProxy { arg args; ^this.reduceFuncProxy(args) } reduceFuncProxy { arg args; ^a.reduceFuncProxy(args) .perform(selector, b.reduceFuncProxy(args), adverb) } value { arg ... args; ^this.reduceFuncProxy(args) } valueArray { arg args; ^this.reduceFuncProxy(args) } composeUnaryOp { arg aSelector; ^UnaryOpFunctionProxy.new(aSelector, this) } composeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, this, something, adverb); } reverseComposeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, something, this, adverb); } composeNAryOp { arg aSelector, anArgList; ^NAryOpFunctionProxy.new(aSelector, this, anArgList) } // behave like a pattern embedInStream { arg inval; ^this.value.embedInStream(inval) } } NAryOpFunctionProxy : NAryOpFunction { reduceFuncProxy { arg args; ^a.reduceFuncProxy(args).performList(selector, arglist.collect(_.reduceFuncProxy(args))) } valueFuncProxy { arg args; ^this.reduceFuncProxy(args) } value { arg ... args; ^this.reduceFuncProxy(args) } valueArray { arg args; ^this.reduceFuncProxy(args) } composeUnaryOp { arg aSelector; ^UnaryOpFunctionProxy.new(aSelector, this) } composeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, this, something, adverb); } reverseComposeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, something, this, adverb); } composeNAryOp { arg aSelector, anArgList; ^NAryOpFunctionProxy.new(aSelector, this, anArgList) } // behave like a pattern embedInStream { arg inval; ^this.value.embedInStream(inval) } } // maybe make it an abstract function object. NAryValueProxy : NAryOpFunctionProxy { *new { arg receiver, args; ^super.new(nil, receiver, args ? []) } reduceFuncProxy { arg args; ^a.reduceFuncProxy(arglist.collect(_.reduceFuncProxy(args))) } storeOn { arg stream; stream << "o(" <<< a << "," <<<* arglist << ")" // is it always so? } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/GUI/0000775000000000000000000000000012245452763023314 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/GUI/TaskProxyGui.sc0000664000000000000000000002303512014636263026250 0ustar rootrootTaskProxyGui : JITGui { var 0) or: { parent.isKindOf(Window.implClass) }) { skin.margin } { 0@0 }; zone.decorator = FlowLayout(zone.bounds, zoneMargin, skin.gap); nameBut = Button(zone, Rect(0,0, nameWidth, height)) .font_(font) .resize_(2) .states_([ [" ", skin.fontColor, skin.onColor] ]) .keyDownAction_({ |btn, char| char.postcs; if (char.ascii == 127) { object.clear; object.class.all.removeAt(btn.states.first.first.asSymbol); object = nil; }; }); playBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ [" >", skin.fontColor, skin.offColor], [" _", skin.fontColor, skin.onColor ], [" |", skin.fontColor, skin.offColor ] ]) .action_({ |but| var string; if (object.notNil) { if (History.started) { // historical action, sets cmdLine and gets recorded. string = object.asCompileString ++ [".play;", ".play;", ".stop;" ][but.value]; thisProcess.interpreter.cmdLine_(string) .interpretPrintCmdLine; } { // a-historical, but faster [ { object.play }, { object.play }, { object.stop } ][but.value].value }; this.checkUpdate; }; }); pauseBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ ["paus", skin.fontColor, skin.onColor], ["rsum", skin.fontColor, skin.offColor] ]) .action_({ |but| var string; if (object.notNil) { if (History.started) { // "// historical".postln; string = object.asCompileString ++ [".resume;", ".pause;" ][but.value]; thisProcess.interpreter.cmdLine_(string) .interpretPrintCmdLine; } { // "// faster".postln; [ { object.resume },{ object.pause } ][but.value].value }; this.checkUpdate; }; }); srcBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ ["src", skin.fontColor, skin.offColor], ["src", skin.fontColor, skin.onColor] ]) .action_({ |but| this.openDoc(this.srcString); but.value_(object.hasSource.binaryValue) }); envBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ ["env", skin.fontColor, skin.offColor], ["env", skin.fontColor, skin.onColor] ]) .action_({ |but, mod| if (mod.isAlt) { this.class.new(object, max(object.envir.size, 8), nil, 400@20); } { if (object.envir.isNil) { this.openDoc(this.editString) } { this.openDoc(this.editStrings) } }; but.value_(object.hasEnvir.binaryValue) }); if (numItems > 0) { this.makeEnvirGui(lineWidth, height) }; this.checkUpdate; } makeEnvirGui { |lineWidth, height| zone.decorator.nextLine.shift(0, 2); envirGui = EnvirGui( try { this.object.envir }, numItems, zone, Rect(0, 20, lineWidth, numItems * height), false ); } accepts { |obj| ^obj.isNil or: { obj.isKindOf(this.class.observedClass) } } getState { if (object.isNil) { ^(playState: 0, hasSource: 0, hasEnvir: 0, canPause: 0, isPaused: 0) }; ^( isPlaying: object.isPlaying, // == proxy is playing now or will play isActive: object.isActive, // == really does something right now hasSource: object.source.notNil, // has a source hasEnvir: object.envir.notNil, // has an envir canPause: object.canPause, isPaused: object.isPaused ).collect(_.binaryValue) .put(\name, object.key) .put(\object, object); } checkUpdate { var newState = this.getState; var playState; // compare newState and prevState, update gui items as needed if (newState == prevState) { ^this }; if (newState[\object].isNil) { prevState = newState; zone.visible_(false); ^this; }; if (newState[\name] != prevState[\name]) { // name zone.visible_(true); nameBut.states_(nameBut.states.collect(_.put(0, object.key.asString))).refresh; }; playState = newState[\isPlaying] * 2 - newState[\isActive]; newState.put(\playState, playState); if (playState != prevState[\playState]) { // stopped/playing/ended // 0 is stopped, 1 is active, 2 is playing but waiting: playBut.value_(playState).refresh; }; if (newState[\hasSource] != prevState[\hasSource]) { srcBut.value_(newState[\hasSource]).refresh; }; if (newState[\hasEnvir] != prevState[\hasEnvir]) { // has envir envBut.value_(newState[\hasEnvir]).refresh; }; if (newState[\canPause] != prevState[\canPause]) { pauseBut.visible_(newState[\canPause] > 0).refresh; }; if (newState[\isPaused] != prevState[\isPaused]) { pauseBut.value_(newState[\isPaused]).refresh; }; // object_ does checkUpdate! if (envirGui.notNil) { envirGui.object_(if (object.isNil) { nil } { object.envir }); }; prevState = newState } clear { object = nil; this.checkUpdate } srcString { ^this.class.observedClass.asString ++ "(" + object.key.asCompileString + "," + object.source.asCompileString + ");\n" } editString { |edKey| var keyText = if (edKey.isNil) { "\\anyKey, nil" } { edKey.asCompileString + "," + object.envir[edKey].asCompileString }; ^(this.class.observedClass.asString ++ "(" + object.key.asCompileString + ").set(" + keyText + ");\n" ) } editStrings { |edKeys| edKeys = edKeys ? this.getUsedKeys; ^edKeys.collect (this.editString(_)) } getUsedKeys { if (object.envir.isNil) { ^[] }; ^usedKeys = object.envir.keys.rejectAs(_ == \self, Array).sort; } openDoc { |strings, bounds| var doc = strings.join.newTextWindow("edit me"); try { doc.bounds_(bounds ? Rect(0, 400, 400, 200)) }; } } TdefGui : TaskProxyGui { *observedClass { ^Tdef } } PdefGui : TaskProxyGui { *observedClass { ^Pdef } } TaskProxyAllGui :JITGui { var prefix = "", <>filtering = false; var 0); }); filTextV = TextView(zone, Rect(60,0, 80, skin.headHeight)) .string_("") .enterInterpretsSelection_(false) .resize_(2) .keyDownAction_({ |txvw, char, mod, uni, keycode| var str = txvw.string; if (str == "") { str = nil }; this.prefix_(txvw.string); }); edits = Array.fill(numItems, { this.class.tpGuiClass.new( numItems: 0, parent: zone, bounds: Rect(0,0, zone.bounds.width - 16, skin.buttonHeight), makeSkip: false ) }); parent.view.decorator.left_(zone.bounds.right - 12) .top_(zone.bounds.top + skin.headHeight); scroller = EZScroller(parent, Rect(0, 0, 12, numItems * skin.buttonHeight), numItems, numItems, { |sc| keysRotation = sc.value.asInteger.max(0) } ).visible_(false); scroller.slider.resize_(3); // if (options.includes(\edit)) { // editZone = CompositeView.new(parent,) // zone.resize_(1); // }; } checkUpdate { var overflow, tooMany; names = object.keys.as(Array); try { names.sort }; if (filtering) { if (prefix == "") { names = names.reject { |name| name.asString.includes($_) }; } { names = names.select { |name| name.asString.contains(prefix) }; }; }; overflow = (names.size - numItems).max(0); if (overflow > 0) { scroller.visible_(true); scroller.numItems_(names.size); scroller.value_(keysRotation ? overflow); names = names.drop(keysRotation).keep(numItems); } { scroller.visible_(false); }; edits.do { |edit, i| edit.object_(object[names[i]]) }; if (tpGui.notNil) { tpGui.checkUpdate }; } } PdefnGui : JITGui { *observedClass { ^Pdefn } accepts { |obj| ^obj.isNil or: { obj.isKindOf(this.class.observedClass) } } getState { // get all the state I need to know of the object I am watching ^(object: object, source: try { object.source }) } checkUpdate { var newState = this.getState; zone.visible_(newState[\object].notNil); if (newState[\object] != prevState[\object]) { // zone.visible_(newState[\object].notNil); this.name_(this.getName); }; if (newState[\source] != prevState[\source]) { if (csView.textField.hasFocus.not) { csView.value_(object); // ugly try { csView.textField.string_(object.asCode) }; }; }; } } TdefAllGui : TaskProxyAllGui { *observedClass { ^Tdef } *tpGuiClass { ^TdefGui } setDefaults { defPos = 10@660; minSize = 260 @ (numItems + 1 * 20); } } PdefAllGui : TaskProxyAllGui { *observedClass { ^Pdef } *tpGuiClass { ^PdefGui } setDefaults { defPos = 270@660; minSize = 260 @ (numItems + 1 * 20); } } PdefnAllGui : TaskProxyAllGui { *observedClass { ^Pdefn } *tpGuiClass { ^PdefnGui } setDefaults { defPos = 540@660; minSize = 260 @ (numItems + 1 * 20); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/GUI/ProxyMixerOld.sc0000664000000000000000000002602412245365552026433 0ustar rootroot// idea by adc, mods by /f0, jrh, mc, ... ProxyMixerOld { // proxymixer need not be built into a supplied window, // so just call the parent window. var nProxies; var = parOffset and: (i < (parOffset + num).max(0)), onCol, offCol); moni.nameView.background_(col.green_([0.5, 0.7].wrapAt(i - parOffset div: 2))); } }.defer; } updateKrSlots { var krProxyNames; krProxyNames = proxyspace.krProxyNames; if (krProxyNames.size > nProxies) { scrollyKr.visible_(true) .numItems_(krProxyNames.size) .value_(keysRotationKr ? (krProxyNames.size - nProxies)); krProxyNames = krProxyNames.drop(keysRotationKr).keep(nProxies); } { scrollyKr.visible_(false); }; if (krProxyNames != prevKrNames) { nProxies.do { arg i; var butLine, nameSink, key, px, showLine; key = krProxyNames[i]; px = proxyspace.envir[ key ]; butLine = buttonLinesKr[i]; nameSink = butLine[0]; nameSink.object_(px).string_(key ? ""); showLine = key.notNil and: px.notNil; butLine.do(_.visible_(showLine)); } }; prevKrNames = krProxyNames; } existingProxies { ^proxyspace.arProxyNames } activeProxies { ^proxyspace.arProxyNames({ |px, key| px.isPlaying }) } playingProxies { ^proxyspace.arProxyNames({ |px, key| px.monitor.isPlaying }) } selectedKeys { ^this.perform(selectMethod) } updateArSlots { var arPxNames, pxKey, px, pxMon; arPxNames = this.selectedKeys; if (arPxNames.size > nProxies) { scrollyAr.visible_(true) .numItems_(arPxNames.size) .value_(keysRotationAr ? (arPxNames.size - nProxies)); arPxNames = arPxNames.drop(keysRotationAr).keep(nProxies); } { scrollyAr.visible_(false); }; if (arPxNames != prevArNames) { nProxies.do { arg i; pxMon = pxMons[i]; pxKey = arPxNames[i]; px = proxyspace.envir.at(pxKey); if(px.notNil) { pxMon.zone.visible_(true); editBtnsAr[i].visible_(true); pxMon.proxy_(px); }{ pxMon.zone.visible_(false); editBtnsAr[i].visible_(false); } } }; arPxNames.do { |name, i| pxMons[i].updateAll }; prevArNames = arPxNames; } adjustWindowSize { arg n; n = n ? nProxies; window.bounds = if(editZoneOpen) { origBounds.resizeBy(0, 330) } { origBounds.copy.height_(n * 18 + 80) }; } } NdefMixerOld : ProxyMixerOld { *new { |server, nProxies = 16, title, bounds| var space; if (server.isKindOf(Symbol)) { server = Server.named.at(server); if (server.isNil) { Error("NdefMixer: no server named %.".format(server)).throw }; } { server = server ? Ndef.defaultServer ? Server.default; }; space = Ndef.dictFor(server); title = title ? ("Ndef:" + server.name); ^super.new(space, nProxies, title, bounds); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/GUI/JITGui.sc0000664000000000000000000001124212161364457024735 0ustar rootroot/*** Abstract superclass for TdefGui,PdefGui, TdefAllGui, PdefAllGui EnvirGui, MonitorGui, NPGui, NdefGui, ProxyMixer (ProxySpaceGui), ParamGui, and possibly others to follow. common traits: an observed object (a proxy, monitor, space, envir, ...) a skipjack for watching it; a getState method for getting all the observed state a prevState instvar for keeping the old state around; a checkUpdate method for comparing old and new state, and updating the gui elements that have changed; parent, minimum bounds for its numItems, actual bounds; if the object has settings, make an EnvirGui or ParamGui ParamGui can do sliders or knobs ... Simpler ones: EnvirGui, TaskProxyGui; ***/ JITGui { var lastOutBus = 99; var 0) { [value/20, value*20, \exp].asSpec } { [-2, 2, \lin].asSpec }; } *suggestString { |key, value| ^"Spec.add(" + this.guess.storeArgs + ");" } } + Dictionary { softPut { |param, val, within = 0.025, mapped = true, lastVal, spec| var curVal, curValNorm, newValNorm, lastValNorm, maxDiff; curVal = this.at(param); spec = (spec ? param).asSpec; if (curVal.isNil or: spec.isNil) { this.put(param, val); ^true }; curValNorm = spec.unmap( curVal ); maxDiff = max(within, spec.step); if (mapped) { newValNorm = spec.unmap(val); if (lastVal.notNil) { lastValNorm = spec.unmap(lastVal) }; } { newValNorm = val; lastValNorm = lastVal; val = spec.map(val); }; if ( (newValNorm.absdif(curValNorm) <= maxDiff) // new val is close enough // or controller remembers last value it sent. or: { lastValNorm.notNil and: { curValNorm.absdif(lastValNorm) <= maxDiff } }) { this.put(param, val); ^true } { ^false } } softSet { |param, val, within = 0.025, mapped = true, lastVal, spec| this.softPut(param, val, within, mapped, lastVal, spec); } } + PatternProxy { softSet { |param, val, within = 0.025, mapped = true, lastVal, spec| if(envir.isNil) { if (mapped.not) { spec = (spec ? param).asSpec; val = spec.map(val); ^this.set(param, val) } } { ^this.envir.softPut(param, val, within, lastVal, mapped, spec) } } } + NodeProxy { get { |param| ^this.nodeMap.get(param).value ?? { this.getDefaultVal(param) }; } getDefaultVal { |key| this.objects.do { |obj| obj.controlNames.do { |ctlname| if (ctlname.name == key) { ^ctlname.defaultValue } } }; ^nil } // must have a spec nudgeSet { |param, incr = 0.02, spec| var curValNorm, newValNorm; spec = (spec ? param).asSpec; curValNorm = spec.unmap( this.get(param) ); newValNorm = (curValNorm + incr).clip(0, 1); this.set(param, spec.map(newValNorm)); } nudgeVol { |incr = 0.02, spec| var curVolNorm, newVolNorm; spec = (spec ? \amp).asSpec; curVolNorm = spec.unmap(this.vol); newVolNorm = (curVolNorm + incr).clip(0, 1); this.vol_(spec.map(newVolNorm)) } softSet { |param, val, within = 0.025, mapped = true, lastVal, spec| var curVal, curValNorm, newValNorm, maxDiff, hasLast, lastValNorm; spec = (spec ? param).asSpec; curVal = this.get(param); if (curVal.isNil or: spec.isNil) { this.set(param, val); ^true }; curValNorm = spec.unmap( curVal ); maxDiff = max(within, spec.step); hasLast = lastVal.notNil; if (mapped) { newValNorm = spec.unmap(val); if (hasLast) { lastValNorm = spec.unmap(lastVal) }; } { newValNorm = val; val = spec.map(val); lastValNorm = lastVal; if (hasLast) { lastVal = spec.map(lastValNorm) }; }; // [\hasLast, hasLast, \curVal, curVal, \val, val].postln; if ( (newValNorm.absdif(curValNorm) <= maxDiff) // is Close Enough // or was the last value controller remembers. or: { hasLast and: { curValNorm.absdif(lastValNorm) <= maxDiff } }) { this.set(param, val); ^true } { ^false } } // val and lastVal are assumed to be mapped. // allows pausing when vol is 0. softVol_ { |val, within=0.025, pause=true, lastVal, spec| var curVolNorm, newVolNorm, hasLast, lastVolNorm; spec = (spec ? \amp).asSpec; hasLast = lastVal.notNil; curVolNorm = spec.unmap(this.vol); newVolNorm = spec.unmap(val); lastVolNorm = if (hasLast) { spec.unmap(lastVal) }; if ( (curVolNorm.absdif(newVolNorm) <= within) or: { hasLast and: { curVolNorm.absdif(lastVolNorm) <= within } } ) { this.vol_(val); if (pause) { if (val == 0) { // wait for vol to go down before pausing fork { 0.05.wait; this.pause } } { this.resume } }; ^true } { ^false } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/GUI/NdefParamGui.sc0000664000000000000000000001114412245365552026145 0ustar rootroot// list of named params - if single number, show EZSlider, // else show EZText NdefParamGui : EnvirGui { var 0) { scroller.visible_(true); scroller.numItems_(newState[\settings].size); scroller.value_(newState[\keysRotation]); } { scroller.visible_(false); }; if (newState[\editKeys] == prevState[\editKeys]) { this.setByKeys(newState[\editKeys], newState[\settings]); } { this.setByKeys(newState[\editKeys], newState[\settings]); if (newState[\overflow] == 0) { this.clearFields(newState[\editKeys].size) }; }; prevState = newState; } // clearFields { (object.size .. valFields.size).do(this.clearField(_)) } setByKeys { |newKeys, newSettings| var prevSettings = prevState[\settings] ? []; var newVal, oldVal, oldKey; newKeys.do { |newKey, i| newVal = newSettings.detect { |pair| pair[0] == newKey }; if (newVal.notNil) { newVal = newVal[1] }; oldKey = prevState[\editKeys][i]; if (oldKey.notNil) { oldVal = prevSettings.detect(_[0] == oldKey); if (oldVal.notNil) { oldVal = oldVal[1] }; }; if (oldKey != newKey or: { oldVal != newVal }) { // "val for % has changed: %\n".postf(key, newval); this.setField(i, newKey, newVal, newKey == oldKey); }; }; } setFunc { |key| ^{ |sl| object.set(key, sl.value) } } clearField { |index| var area = valFields[index]; try { drags[index].visible_(false); area.children.copy.do { |view| view.remove }; area.background_(skin.background); area.refresh; widgets[index] = nil; }; } setField { |index, key, value, sameKey = false| var area = valFields[index]; var widget = widgets[index]; // [replaceKeys, key].postcs; if (replaceKeys[key].notNil) { area.background_(skin.hiliteColor); } { area.background_(skin.background); }; try { // QT temp fix. if (value.isKindOf(NodeProxy)) { drags[index].object_(value).string_("->" ++ value.key); } { drags[index].object_(nil).string_("-"); }; // dodgy - defer should go away eventually. // needed for defer in setToSlider... { drags[index].visible_(true) }.defer(0.05); }; if (value.isKindOf(SimpleNumber) ) { this.setToSlider(index, key, value, sameKey); ^this }; this.setToText(index, key, value, sameKey); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/GUI/EnvirGui.sc0000664000000000000000000002311612014636263025367 0ustar rootroot // needs a defer for making new EZs after a clearField... // get rid of this later if possible. EnvirGui : JITGui { var useRanger = true; editKeys { ^prevState[\editKeys] } addReplaceKey { |replaced, replacer, spec| replaceKeys.put(replaced, replacer); if (spec.notNil) { specs.put(replaced, spec) }; } removeReplaceKey { |replaced| replaceKeys.removeAt(replaced) } *new { |object, numItems = 8, parent, bounds, makeSkip = true, options = #[]| ^super.new(object, numItems, parent, bounds, makeSkip = true, options); } setDefaults { if (parent.notNil) { skin = skin.copy.put(\margin, 0@0) }; defPos = 530@660; minSize = 250 @ (numItems * skin.buttonHeight + (skin.margin.y * 2)); } makeViews { |options| var height = skin.buttonHeight; specs = (); replaceKeys = (); prevState = ( overflow: 0, keysRotation: 0, editKeys: []); labelWidth = zone.bounds.width * 0.17; this.makeOptionalViews(options); valFields = { CompositeView(zone, Rect(0, 0, bounds.width - 20, height)) .resize_(2) .background_(skin.background); }.dup(numItems); widgets = nil.dup(numItems); // keep EZGui types here zone.decorator.reset.shift(zone.bounds.width - 16, 0); scroller = EZScroller(zone, Rect(0, 0, 12, numItems * height), numItems, numItems, { |sc| keysRotation = sc.value.asInteger.max(0); } ).visible_(false); scroller.slider.resize_(3); } name_ { |name| if (hasWindow) { parent.name_(this.winName(name)) }; if (nameView.notNil) { nameView.string_(name) }; } makeOptionalViews { |options, height = 20| var extraFuncs = ( name: { this.makeNameView(70, height) }, CLR: { this.makeClrBut(30, height) }, doc: { this.makeDocBut(30, height) }, proto: { this.makeProtoBut(40, height) }, parent: { this.makeParentBut(40, height) }, know: { this.makeKnowBut(70, height) } ); options.do { |key| extraFuncs[key].value; }; } makeNameView { |nameWid, height| nameView = StaticText(zone, Rect(0,0, nameWid, height)) .font_(font).align_(0); } makeClrBut { |width, height| Button(zone, width@height).font_(font) .states_([[\CLR, skin.fontColor, Color.clear]]) .action_({ arg btn, mod; if (mod.isAlt) { object.clear } { "Safety - use alt-click to clear object.".postln; } }) } makeProtoBut { |width, height| protoBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ ["proto", skin.fontColor, skin.offColor] ]) .enabled_(false) .action_({ EnvirGui(object.proto) }); } makeParentBut { |width, height| parentBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ ["parent", skin.fontColor, skin.offColor] ]) .enabled_(false) .action_({ EnvirGui(object.parent) }); } makeKnowBut { |width, height| knowBut = Button(zone, Rect(0,0, width, height)) .font_(font).resize_(3) .states_([ ["know: false", skin.fontColor, skin.offColor], ["know: true", skin.fontColor, skin.onColor] ]) .enabled_(false) .action_({ |but| object.know = (but.value > 0) }); } makeDocBut { |width, height| docBut = Button(zone, width@height).font_(font) .states_([[\doc, skin.fontColor, Color.clear]]) .enabled_(false) .action_({ |but, mod| if (object.notNil) { object.asCompileString.newTextWindow }; }) } accepts { |obj| ^(obj.isNil or: { obj.isKindOf(Dictionary) }) } // backwards compatibility envir_ { |envir| this.object_(envir) } envir { ^object } getState { var newKeys, overflow; if (object.isNil) { ^(editKeys: [], overflow: 0, keysRotation: 0) }; newKeys = object.keys.asArray.sort; overflow = (newKeys.size - numItems).max(0); keysRotation = keysRotation.clip(0, overflow); newKeys = newKeys.drop(keysRotation).keep(numItems); ^(object: object, editKeys: newKeys, overflow: overflow, keysRotation: keysRotation) } checkUpdate { |doFull = false| var newState = this.getState; var newKeys = newState[\editKeys]; this.updateButtons; if (doFull.not and: { newState == prevState }) { ^this }; if (object.isNil) { prevState = newState; ^this.clearFields(0); }; if (newState[\overflow] > 0) { scroller.visible_(true); scroller.numItems_(object.size); scroller.value_(newState[\keysRotation]); } { scroller.visible_(false); }; if (newKeys == prevState[\editKeys]) { this.setByKeys(newKeys); } { this.setByKeys(newKeys); if (newState[\overflow] == 0) { this.clearFields(newKeys.size) }; }; // "newState: %\n".postf(newState); // "prevState: %\n".postf(prevState); prevState = newState.put(\object, object.copy); } updateButtons { var flag = object.notNil; if (protoBut.notNil) { protoBut.enabled_(flag and: { object.proto.notNil }) }; if (parentBut.notNil) { parentBut.enabled_(flag and: { object.parent.notNil }) }; if (knowBut.notNil) { knowBut.enabled_(flag).value_((flag and: { object.know }).binaryValue) }; if (docBut.notNil) { docBut.enabled_(flag) }; } clearFields { |from = 0| (numItems - 1 .. from).do(this.clearField(_)) } setByKeys { |newKeys| var prevEnvir = prevState[\object] ?? {()}; var newVal, oldVal, oldKey; newKeys.do { |newKey, i| var isSameKey; oldKey = prevState[\editKeys][i]; isSameKey = oldKey == newKey; newVal = object[newKey]; oldVal = prevEnvir[newKey]; if (isSameKey.not or: { oldVal != newVal }) { // "val for % has changed: %\n".postf(key, newval); this.setField(i, newKey, newVal, isSameKey); }; }; } clearField { |index| var area = valFields[index]; try { area.children.copy.do { |view| view.remove }; area.background_(skin.background); area.refresh; widgets[index] = nil; }; } setFunc { |key| ^{ |elem| object.put(key, elem.value) } } setToSlider { |index, key, value, sameKey| var widget = widgets[index]; var area = valFields[index]; var keyToShow = this.showKeyFor(key); // "setToSlider...".postln; if (widget.isKindOf(EZSlider)) { // "was slider already".postln; if (sameKey.not) { // "new key - reset widget ...".postln; widget.set( keyToShow, this.getSpec(key, value), this.setFunc(key), value ); this.colorizeArea(area, keyToShow != key); } { // "old key, just set ...".postln; widget.value = value; }; ^this } { // "make new slider!".postln; this.clearField(index); // don't know why, but defer seems needed: { widget = EZSlider(area, area.bounds.extent, this.showKeyFor(key), this.getSpec(key, value), this.setFunc(key), value, labelWidth: labelWidth, numberWidth: labelWidth ) .font_(font); widget.view.resize_(2); widgets[index] = widget; this.colorizeArea(area, keyToShow != key); }.defer(0.03); ^this }; } setToRanger { |index, key, value, sameKey| var widget = widgets[index]; var area = valFields[index]; var keyToShow = this.showKeyFor(key); if (widget.isKindOf(EZRanger)) { if (sameKey.not) { widget.set( keyToShow, this.getSpec(key), this.setFunc(key), value ); this.colorizeArea(area, keyToShow != key); } { widget.value = value; }; } { this.clearField(index); { widget = EZRanger(valFields[index], valFields[index].bounds.extent, this.showKeyFor(key), this.getSpec(key, value.maxItem), this.setFunc(key), value, labelWidth: labelWidth, numberWidth: labelWidth ).font_(font); widget.view.resize_(2); widgets[index] = widget; this.colorizeArea(area, keyToShow != key); }.defer(0.03); ^this }; } showKeyFor { |key| ^(replaceKeys[key] ? key) } colorizeArea { |area, hilite = true| if (hilite) { area.background_(skin.hiliteColor); } { area.background_(skin.background); }; } setToText { |index, key, value, sameKey = false| var widget = widgets[index]; var area = valFields[index]; var keyToShow = this.showKeyFor(key); // default: EZText if (widget.isKindOf(EZText)) { if (sameKey.not) { widget.labelView.string = keyToShow.asString }; widget.action = this.setFunc(key); widget.value = value; this.colorizeArea(area, keyToShow != key); ^this } { this.clearField(index); { widget = EZText(area, area.bounds.extent, this.showKeyFor(key), this.setFunc(key), value, false, labelWidth, labelHeight: 18); widget.font_(font); widget.view.resize_(2); widgets[index] = widget; widget.value_(value); this.colorizeArea(area, keyToShow != key); }.defer(0.03); }; } setField { |index, key, value, sameKey = false| var widget = widgets[index]; var area = valFields[index]; if (value.isKindOf(SimpleNumber) ) { this.setToSlider(index, key, value, sameKey); ^this }; // Ranger - only if spec exists and value is 2 numbers if (useRanger and: { value.size == 2 and: { key.asSpec.notNil and: { value.every(_.isKindOf(SimpleNumber)) } } }) { this.setToRanger(index, key, value, sameKey); ^this }; // default this.setToText(index, key, value, sameKey); } findWidget { |key| ^widgets.reject(_.isNil).detect { |ez| ez.labelView.string.asSymbol == key }; } putSpec { |key, obj| var widge, spec; spec = obj.asSpec; specs.put(key, spec); // could check all widgets and update specs if same name ... widge = this.findWidget(key); if (widge.notNil) { widge.controlSpec_(spec).value_(widge.value) } } getSpec { |key, value| var spec = specs[key] ? Spec.specs[key]; spec = spec ?? { Spec.guess(key, value) }; specs.put(key, spec); ^spec } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/GUI/ProxyMixer.sc0000664000000000000000000002111412161364457025767 0ustar rootrootProxyMixer : JITGui { var = parOffset and: (i < (parOffset + num).max(0)), onCol, offCol); argui.nameView.background_(col.green_([0.5, 0.7].wrapAt(i - parOffset div: 2))); } }.defer; } title { ^this.parent.name } accepts { |obj| ^obj.isNil or: { obj.isKindOf(ProxySpace) } } *new { |obj, numItems = 16, parent, bounds, makeSkip = true, options| ^super.new(obj, numItems, parent, bounds, makeSkip, options); } setDefaults { var width = 600; var height = numItems * skin.buttonHeight + skin.headHeight + 20; skin = GUI.skins.jit; font = Font(*skin.fontSpecs); defPos = 10@260; sizes = ( small: (446 @ height), mid: (676 @ height), big: (1090 @ height) ); minSize = sizes[\big]; } makeViews { parent.bounds_(parent.bounds.extent_(sizes[\mid] + (8@8))); zone.decorator.gap_(6@6); zone.resize_(1).background_(Color.grey(0.7)); arZone = CompositeView(zone, Rect(0, 0, 444, sizes[\mid].y )) .background_(skin.foreground); arZone.addFlowLayout(skin.margin, skin.gap); krZone = CompositeView(zone, Rect(0, 0, 225, sizes[\mid].y )) .background_(skin.foreground); krZone.addFlowLayout(skin.margin, skin.gap); editZone = CompositeView(zone, Rect(0, 0, 400, sizes[\mid].y )) .background_(skin.foreground); editZone.addFlowLayout(skin.margin, skin.gap); this.makeTopLine; arZone.decorator.nextLine.shift(0, 10); this.makeArZone; this.makeKrZone; this.setEdButs; this.makeEditZone; this.switchSize(1); // show kr proxies, but not editor } makeTopLine { PopUpMenu(arZone, Rect(10, 10, 110, skin.headHeight)) .items_([\existingProxies, \activeProxies, \playingProxies]) .action_({ arg view; selectMethod = view.items[view.value] }) .font_(font); Button(arZone, Rect(10, 10, 50, skin.headHeight)) .states_( [["reduce", skin.fontcolor, Color.clear]] ) .action_({ object !? { object.reduce } }).font_(font); Button(arZone, Rect(10, 10, 30, skin.headHeight)) .states_( [["doc", skin.fontcolor, Color.clear]] ) .action_({ object !? { object.document } }).font_(font); Button(arZone, Rect(10, 10, 45, skin.headHeight)) .states_( [["docSel", skin.fontcolor, Color.clear]] ) .action_({ object !? { object.document(this.selectedKeys) } }).font_(font); Button(arZone, Rect(10, 10, 60, skin.headHeight)) .font_(font) .states_([ ["openKr", skin.fontcolor, Color.clear], ["openEdit", skin.fontcolor, Color.clear], ["closeEdit", skin.fontcolor, Color.clear] ]) .value_(1) .action_({ |b| this.switchSize(b.value) }); Button(arZone, Rect(10, 10, 50, skin.headHeight)) .font_(font) .states_( [ ["Record", Color.red, Color.clear] ]) .action_({ RecordProxyMixer(this, parent.bounds.resizeTo(472, 100)) }); } switchSize { |index| parent.bounds_(parent.bounds.extent_(sizes[[\small, \mid, \big][index]] + (8@12))); } setEdButs { (arGuis ++ krGuis).do { |pxgui| pxgui.edBut.states_([ ["ed", Color.black, Color.grey(0.75)], ["ed", Color.black, Color.white]]) .action_({ arg btn, mod; if (mod.notNil and: { mod.isAlt }) { NdefGui(pxgui.object); } { this.switchSize(2); editGui.object_(pxgui.object); arGuis.do { |gui| gui.edBut.value_(0) }; krGuis.do { |gui| gui.edBut.value_(0) }; btn.value_(1); }; }); }; } makeArZone { var arLayout = arZone.decorator; var dim = ((arZone.bounds.width - 20)@skin.buttonHeight); arLayout.nextLine; arLayout.shift(0,4); arGuis = numItems.collect { NdefGui(nil, 0, arZone, dim, makeSkip: false, options: NdefGui.audio) }; arLayout.top_(40).left_(arZone.bounds.width - 15); arScroller = EZScroller.new(arZone, Rect(0, 0, 12, numItems * skin.buttonHeight), numItems, numItems, { |sc| arKeysRotation = sc.value.asInteger.max(0); this.checkUpdate } ).value_(0).visible_(true); } makeKrZone { var krLayout = krZone.decorator; StaticText.new(krZone, Rect(0, 0, 180, 24)) .font_(font).align_(\center) .string_("Control Proxies"); krLayout.nextLine; krLayout.shift(0,4); krZone.decorator.nextLine.shift(0, 10); krGuis = numItems.collect { NdefGui(nil, 0, krZone, 180@18, makeSkip: false, options: NdefGui.control) }; krLayout.top_(40).left_(krZone.bounds.width - 15); krScroller = EZScroller.new(krZone, Rect(0, 0, 12, numItems * skin.buttonHeight), numItems, numItems, { |sc| krKeysRotation = sc.value.asInteger.max(0); this.checkUpdate } ).value_(0).visible_(true); } makeEditZone { editGui = NdefGui(nil, numItems, editZone, makeSkip: false, options: NdefGui.big); } existingProxies { ^object !? { object.arProxyNames } ? [] } activeProxies { ^object !? { object.arProxyNames({ |px, key| px.isPlaying }) } ? [] } playingProxies { ^object !? { object.arProxyNames({ |px, key| px.monitor.isPlaying }) } ? [] } selectedKeys { ^this.perform(selectMethod) } getState { var arNames, krNames; var newState = ( object: object, name: '-', arNames: [], krNames: [], editedName: nil, arOverflow: 0, krOverflow: 0 ); if (object.notNil) { arNames = this.selectedKeys.asArray; krNames = object.krProxyNames.asArray; newState.putPairs([ \name, object.asCode, \arNames, arNames, \krNames, krNames, \editedName, editGui.object !? { editGui.object.key }, \arOverflow, (arNames.size - numItems).max(0), \krOverflow, (krNames.size - numItems).max(0) ]); }; ^newState; } checkUpdate { var newState = this.getState; var arNames, prevArNames, fullSize; var krNames, prevKrNames; var editName, prevEditName; if (object.isNil) { arGuis.do { |g| g.object_(nil); g.zone.visible_(false) }; krGuis.do { |g| g.object_(nil); g.zone.visible_(false) }; [arScroller, krScroller].do(_.visible_(false)); this.name_(newState[\name]); prevState = newState; // editGui.object_(nil); ^this }; if (newState[\name] != prevState[\name]) { this.name_(newState[\name]) }; arNames = newState[\arNames]; prevArNames = prevState[\arNames]; fullSize = arNames.size; if (newState[\arOverflow] > 0) { arNames = arNames.drop(arKeysRotation).keep(numItems); newState[\arNames] = arNames; } { arKeysRotation = 0; }; arKeysRotation = min(arKeysRotation, newState[\arOverflow]); arScroller.numItems_(fullSize).value_(arKeysRotation).visible_(newState[\arOverflow] > 0); if (arNames != prevArNames) { arGuis.do { |argui, i| var newName = arNames[i]; var newPx = object.envir[newName]; argui.object_(newPx); argui.zone.visible_(newPx.notNil); }; }; arGuis.do { |gui| var pxIsEdited = gui.object.notNil and: { gui.object == editGui.object }; gui.checkUpdate; if(gui.hasName.not) { gui.name = this.proxyspace.findKeyForValue(gui.object) }; gui.edBut.value_(pxIsEdited.binaryValue); }; krNames = newState[\krNames]; prevKrNames = prevState[\krNames]; fullSize = krNames.size; if (newState[\krOverflow] > 0) { krNames = krNames.drop(krKeysRotation).keep(numItems); newState[\krNames] = krNames; } { krKeysRotation = 0; }; krKeysRotation = min(krKeysRotation, newState[\krOverflow]); krScroller.numItems_(fullSize) .value_(krKeysRotation).visible_(newState[\krOverflow] > 0); if (krNames != prevKrNames) { krGuis.do { |krgui, i| var newName = krNames[i]; var newPx = object.envir[newName]; krgui.object_(newPx); krgui.zone.visible_(newPx.notNil); }; }; krGuis.do { |gui| var pxIsEdited = gui.object.notNil and: { gui.object == editGui.object }; gui.checkUpdate; if(gui.hasName.not) { gui.name = this.proxyspace.findKeyForValue(gui.object) }; gui.edBut.value_(pxIsEdited.binaryValue); }; editGui.checkUpdate; prevState = newState; } } NdefMixer : ProxyMixer { object_ { |obj| obj = Server.named.at(obj) ? obj; if (obj.isKindOf(Server)) { super.object_(Ndef.dictFor(obj)); } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/GUI/ProxyMonitorGui.sc0000664000000000000000000001420512014636263026774 0ustar rootrootProxyMonitorGui { classvar <>lastOutBus = 99; var = parOffset and: (i < (parOffset + num).max(0)), onCol, offCol); widget.labelView.background_(col.green_([0.5, 0.7].wrapAt(i - parOffset div: 2))); } } }.defer; } *new { |object, numItems = (4), parent, bounds, makeSkip=true, options| options = options ?? { this.big }; ^super.newCopyArgs(object, numItems, parent, bounds).init(makeSkip, options) } *big { // two lines - for big editor ^[\name, \type, \CLR, \reset, \scope, \doc, \end, \fade, \poll, \monitorL, \playN, \pausR, \sendR ] } *full { // two lines - for big editor ^[\name, \type, \CLR, \reset, \scope, \doc, \end, \fade, \poll, \rip, \monitorL, \playN, \pausR, \sendR, ] } *audio { // one line, for ProxyMixer, ar ^[\monitorM, \playN, \name, \pausR, \sendR, \ed] } *control { // one short line - for ProxyMixer, kr ^[\name, \pausR, \sendR, \poll, \ed] } setDefaults { |options| var width = options.sum( buttonSizes[_] ); var xpositions; var numLines = 1; if (width > 500) { // two lines, break them up near the middle numLines = 2; xpositions = options.collect( NdefGui.buttonSizes[_] ).integrate; width = width * 0.5 + (xpositions.absdif(width * 0.5).minItem); }; if (numItems > 0) { width = width.max(320) }; // min width of NdefParamGui defPos = 300@20; minSize = width @ (numItems * skin.buttonHeight + (skin.buttonHeight * numLines)); // "NdefGui - width: % minSize: %\n".postf(width, minSize); if (parent.notNil) { skin = skin.copy.margin = 0@0; }; this.makeButFuncs(options, skin.buttonHeight); } makeButFuncs { |options, height| buttonFuncs = ( name: { this.makeNameView(buttonSizes[\name], height) }, type: { this.makeTypeView(buttonSizes[\type], height) }, CLR: { this.makeClrBut(buttonSizes[\CLR], height) }, reset: { this.makeResetBut(buttonSizes[\reset], height) }, scope: { this.makeScopeBut(buttonSizes[\scope], height) }, doc: { this.makeDocBut(buttonSizes[\doc], height) }, end: { this.makeEndBut(buttonSizes[\end], height) }, fade: { this.makeFadeBox(buttonSizes[\fade], height) }, monitor: { this.makeMonitor(buttonSizes[\monitor], height, options) }, monitorM:{ this.makeMonitor(buttonSizes[\monitorM], height, options) }, monitorL:{ this.makeMonitor(buttonSizes[\monitorL], height, options) }, pausR: { this.makePauseBut(buttonSizes[\pausR], height) }, sendR: { this.makeSendBut(buttonSizes[\sendR], height) }, rip: { this.makeRipBut(buttonSizes[\rip], height) }, ed: { this.makeEdBut(buttonSizes[\ed], height) }, poll: { this.makePollBut(buttonSizes[\poll], height) }, wake: { this.makeWakeBut(buttonSizes[\wake], height) } ) } accepts { |obj| ^(obj.isNil or: { obj.isKindOf(NodeProxy) }) } makeViews { |options| var lineBreakIndex, hasName, hasMonitor, resizer, butLines; // "NdefGui - zone.bounds: % zone.decorator.margin: %\n".postf(zone.bounds, zone.decorator.margin); options.do { |option| buttonFuncs[option].value; }; // a clumsy way to figure out how to set resizes for all children. lineBreakIndex = zone.children.detectIndex { |a, i| var b = zone.children[i + 1]; b.notNil and: { b.bounds.left < a.bounds.left } }; butLines = if (lineBreakIndex.isNil) { [zone.children] } { [zone.children.keep(lineBreakIndex + 1), zone.children.drop(lineBreakIndex + 1)] }; butLines.do { |butLine| var resizer = 1; var resizeIndex; var monIndex = if (monitorGui.notNil) { butLine.detectIndex(_ == monitorGui.zone) }; var nameIndex = if (nameView.notNil) { butLine.detectIndex(_ == nameView) }; if (monIndex.notNil) { resizeIndex = monIndex; } { if (nameIndex.notNil) { resizeIndex = nameIndex; } }; // [\monIndex, monIndex, \nameIndex, nameIndex, \resizeIndex, resizeIndex].postcs; if (resizeIndex.notNil) { butLine.do { |element, i| if (i == resizeIndex) { resizer = 2 }; if (i > resizeIndex) { resizer = 3 }; // [i, element, resizer].postln; element.resize_(resizer); }; }; }; if (numItems > 0) { zone.decorator.nextLine.shift(0, 2); zone.bounds; paramGui = NdefParamGui(object, numItems, zone, Rect(0,0, zone.bounds.width - (skin.margin.x * 2), 0)); } } makeNameView { |nameWid, height| try { // QT temp fix nameView = DragBoth(zone, Rect(0,0, nameWid, height)) .font_(font).align_(0) .receiveDragHandler_({ var drag = View.currentDrag; if (drag.isKindOf(String)) { drag = drag.interpret }; this.object_(drag); }); } { nameView = TextView(zone, Rect(0,0, nameWid, height)) .font_(font) } } makeTypeView { |width, height| typeView = StaticText(zone, width@height).string_("-").align_(0) .font_(font).align_(0); } makeClrBut { |width, height| Button(zone, width@height).font_(font) .states_([[\CLR, skin.fontColor, Color.clear]]) .action_({ arg btn, mod; if (mod.isAlt) { object.clear } { "Safety - use alt-click to clear object.".postln; } }) } makeWakeBut { |width, height| wakeBut = Button(zone, width@height).font_(font) .states_([[\WAKE, skin.fontColor, Color.clear], [\WAKE, skin.fontColor, skin.onColor]]) .action_({ object.resume.wakeUp; wakeBut.value_(1); }) } makeResetBut { |width, height| Button(zone, width@height).font_(font) .states_([[\reset, skin.fontColor, Color.clear]]) .action_({ |view, mod| object !? { if (mod.notNil and: { mod.isAlt }) { this.object.resetNodeMap; } { this.object.cleanNodeMap; }; this.checkUpdate; } }) } makeScopeBut { |width, height| Button(zone, width@height).font_(font) .states_([[\scope, skin.fontColor, Color.clear]]) .action_({ object !? { object.scope } }) } makeDocBut { |width, height| Button(zone, width@height).font_(font) .states_([[\doc, skin.fontColor, Color.clear]]) .action_({ |but, mod| if (object.notNil) { if (mod.isAlt) { try { ProxySpace.findSpace(object).document(object.key) }; } { object.document; } } }) } makeEndBut { |width, height| Button(zone, width@height).font_(font) .states_([[\end, skin.fontColor, Color.clear]]) .action_({ object !? { object.end } }) } makeFadeBox { |width = 60, height = 18| fadeBox = EZNumber(zone, width@height, \fade, \fadePx, { |num| try { object.fadeTime_(num.value) } }, try { object.fadeTime } ? 0.02, labelWidth: 28, numberWidth: width - 28 ); fadeBox.labelView.font_(font).background_(Color.clear); fadeBox.numberView.font_(font).background_(Color.clear); } makeMonitor { |width, height, npOptions| var monOptions = npOptions.sect([\level, \playN]); monitorGui = MonitorGui(object, zone, width@height, false, monOptions); } makePauseBut { |width, height| pauseBut = Button(zone, width@height).font_(font) .states_([ ["paus", skin.fontColor, skin.onColor], ["rsum", skin.fontColor, skin.offColor] ]) .action_({ arg btn; object !? { [ { object.resume; }, { object.pause; } ].at(btn.value).value; } }); } makeSendBut { |width, height| sendBut = Button(zone, width@height).font_(font) .states_([ ["send", skin.fontColor, skin.offColor], ["send", skin.fontColor, skin.onColor] ]) .action_({ arg btn, mod; var alt = mod.notNil and: { mod.isAlt }; if(object.notNil and: (btn.value == 0)) { if (alt) { object.rebuild } { object.send } }; btn.value_(1 - btn.value) }) } makeEdBut { |width, height| edBut = Button(zone, width@height).font_(font) .states_([['ed', skin.fontColor, Color.clear], ['ed', skin.fontColor, skin.onColor]]) } makeRipBut { |width, height| Button(zone, width@height).font_(font) .states_([['^', skin.fontColor, Color.clear]]) .action_({ this.class.new(object, numItems) }) } makePollBut { |width, height| Button(zone, width@height).font_(font) .states_([[\poll, skin.fontColor, Color.clear]]) .action_({ object !? { object.bus.getn(action: { |arr| (object.asCompileString + "poll:" + arr).postln }) } }) } getState { var newState = ( object: object, name: \_none_, type: "-", isPlaying: object.isPlaying, isPaused: false, canSend: false, fadeTime: 0.02 ); if (object.isNil) { ^newState }; newState.putPairs([ \name, object.key, \type, object.typeStr, \isPaused, object.paused, \canSend, object.sources.notNil, \fadeTime, object.fadeTime, \isPlaying, object.isPlaying ]); ^newState } checkUpdate { var newState = this.getState; if (monitorGui.notNil) { monitorGui.checkUpdate }; if (paramGui.notNil) { paramGui.checkUpdate }; // update common stuff first if (newState[\object] != prevState[\object]) { if (monitorGui.notNil) { monitorGui.object_(object) }; if (paramGui.notNil) { paramGui.object_(object) }; }; if (newState[\name] != prevState[\name]) { this.name_(newState[\name]) }; if (typeView.notNil) { if (newState[\type] != prevState[\type]) { typeView.string_(newState[\type]) } }; if (fadeBox.notNil) { if (newState[\fadeTime] != prevState[\fadeTime]) { fadeBox.value_(newState[\fadeTime]) } }; if (pauseBut.notNil) { if (newState[\isPaused] != prevState[\isPaused]) { pauseBut.value_(newState[\isPaused].binaryValue) } }; if (sendBut.notNil) { if (newState[\canSend] != prevState[\canSend]) { sendBut.value_(newState[\canSend].binaryValue) } }; if (wakeBut.notNil) { if (newState[\isPlaying] != prevState[\isPlaying]) { wakeBut.value_(newState[\isPlaying].binaryValue) } }; prevState = newState; } // support overwriting the param names shown, e.g. for ProxyChain addReplaceKey { |replaced, replacer, spec| if (paramGui.notNil) { paramGui.addReplaceKey(replaced, replacer, spec) } } removeReplaceKey { |replaced| if (paramGui.notNil) { paramGui.removeReplaceKey(replaced) } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/GUI/NodeProxyEditor.sc0000664000000000000000000004325112014636263026737 0ustar rootroot// document for non-current proxyspaces is not correct yet. NodeProxyEditor { classvar <>menuHeight=18; var ignoreKeys=#[]; var <>replaceKeys; // a dict for slider names to be replaced var = parOffset and: (i < (parOffset + num).max(0)), onCol, offCol); edi.labelView.background_(col.green_([0.5, 0.7].wrapAt(i - parOffset div: 2))); } }.defer; } makeButtonFuncs { buttonFuncs = ( CLR: { Button(zone, 30@20).font_(font) .states_([[\CLR, skin.fontColor, Color.clear]]) .action_({ arg btn, mod; if (mod.isAlt) { proxy.clear } { "use alt-click to clear proxy.".postln; } }) }, reset: { Button(zone, 30@20).font_(font) .states_([[\reset, skin.fontColor, Color.clear]]) .action_({ proxy !? { proxy.nodeMap = ProxyNodeMap.new; this.fullUpdate; } }) }, pausR: { pauseBut = Button(zone, 30@20).font_(font) .states_([ ["paus", skin.fontColor, skin.onColor], ["rsum", skin.fontColor, skin.offColor] ]) .action_({ arg btn; proxy !? { [ { proxy.resume; }, { proxy.pause; } ].at(btn.value).value; } }); }, sendR: { sendBut = Button(zone, 30@20).font_(font) .states_([ ["send", skin.fontColor, skin.offColor], ["send", skin.fontColor, skin.onColor] ]) .action_({ arg btn, mod; if(proxy.notNil and: (btn.value == 0)) { // alt-click osx, swingosc if (mod.isAlt) { proxy.rebuild } { proxy.send } }; btn.value_(1 - btn.value) }) }, scope: { Button(zone, 36@20).font_(font) .states_([[\scope, skin.fontColor, Color.clear]]) .action_({ proxy !? { proxy.scope } }) }, doc: { Button(zone, 30@20).font_(font) .states_([[\doc, skin.fontColor, Color.clear]]) .action_({ |but, mod| if (mod.isAlt) { try { ProxySpace.findSpace(proxy).document(proxy.key) }; } { proxy.document; } }) }, end: { Button(zone, 24@20).font_(font) .states_([[\end, skin.fontColor, Color.clear]]) .action_({ proxy !? { proxy.end } }) }, fade: { var nb = EZNumber(zone, 60@20, \fade, \fadePx, { |num| proxy.fadeTime_(num.value) }, try { proxy.fadeTime } ? 0.02, labelWidth: 24, numberWidth: 32); nb.labelView.font_(font).background_(Color.clear); nb.numberView.font_(font).background_(Color.clear); }, // extras: rip: { Button(zone, 15@20).font_(font) .states_([['^', skin.fontColor, Color.clear]]) .action_({ this.class.new(proxy, nSliders) }) }, wake: { Button(zone, 30@20).font_(font) .states_([[\wake, skin.fontColor, Color.clear]]) .action_({ proxy !? { proxy.wakeUp } }) }, send: { Button(zone, 30@20).font_(font) .states_([[\send, skin.fontColor, Color.clear]]) .action_({ proxy !? { proxy.send } }) }, rebuild: { Button(zone, 30@20).font_(font) .states_([[\rbld, skin.fontColor, Color.clear]]) .action_({ proxy !? { proxy.rebuild } }) } // poll: { Button(zone, 30@20).font_(font) // .states_([[\poll, skin.fontColor, Color.clear]]) // .action_({ proxy !? { proxy.poll } }) }, // // // show a little amp view? // amp: { Button(zone, 30@20).font_(font) // .states_([[\amp, skin.fontColor, Color.clear]]) // .action_({ "// show a little amp view?".postln }) } ); } makeSkipJack { skipjack = SkipJack( { this.checkUpdate }, 0.2, { zone.isClosed }, this.class.name ); // w.onClose_({ skipjack.stop; }); this.runUpdate; } getCurrentKeysValues { if (proxy.isNil, {^[] }); currentSettings = proxy.getKeysValues(except: ignoreKeys); editKeys = currentSettings.collect({ |list| list.first.asSymbol }); } checkTooMany { var oversize = (editKeys.size - nSliders).max(0); tooManyKeys = oversize > 0; keysRotation = keysRotation.clip(0, oversize); if (tooManyKeys) { // "tooManyKeys...".postln; scrolly.visible_(true); scrolly.numItems_(editKeys.size); editKeys = editKeys.drop(keysRotation).keep(nSliders); currentSettings = currentSettings.drop(keysRotation).keep(nSliders); } { // "plenty of space.".postln; scrolly.numItems_(editKeys.size); scrolly.visible_(false); }; scrolly.value_( keysRotation); } checkUpdate { var oldKeys, newType; oldKeys = editKeys; this.getCurrentKeysValues; this.checkTooMany; // [\oldKeys, oldKeys, \editKeys, editKeys].printAll; newType = if (proxy.notNil) { proxy.typeStr }; if (newType != oldType) { oldType = newType; typeChanView.string_(newType); }; if (monitor.notNil) { monitor.updateAll }; if (pauseBut.notNil) { pauseBut.value_((proxy.notNil and: { proxy.paused }).binaryValue) }; if (sendBut.notNil) { sendBut.value_((proxy.notNil and: { proxy.objects.notEmpty }).binaryValue) }; if ( (editKeys != oldKeys), { this.updateAllEdits }, { this.updateVals }); } fullUpdate { this.getCurrentKeysValues; this.checkTooMany; this.updateAllEdits; } updateVals { var sl, val, mapKey; // "updateVals : ".postln; if (currentSettings == prevSettings) { // "no change.".postln; ^this; }; // "values have changed - updating edits.".postln; editKeys.do { arg key, i; sl = edits[i]; // editKeys and currentSettings are in sync. val = currentSettings[i][1].unbubble; if (val != try { prevSettings[i][1] }) { // disable for arrayed controls sl.enabled_(val.size <= 1); // when in doubt, use this: // val = (currentSettings.detect { |set| set[0] == key } ? [])[1]; if(sl.numberView.hasFocus.not) { if (val.isKindOf(SimpleNumber), { sl.value_(val.value); sl.labelView.string_(this.replaceName(key)); sinks[i].string_("-"); }, { if (val.isKindOf(BusPlug), { mapKey = val.key; sinks[i].object_(val).string_(mapKey); sl.labelView.string = "->" + key; }); }); }; }; }; prevSettings = currentSettings; } replaceName { |key| var replaced; if (replaceKeys.isNil) { ^key }; replaced = replaceKeys[key.asSymbol]; if (replaced.isNil) { ^key }; // "NPXE: replacing % with %.".format(key.asCompileString, replaced.asCompileString).postln; ^replaced; } updateAllEdits { // var keyPressed = false; if (proxy.isNil) { [sinks, edits].do(_.do(_.visible_(false))); ^this; }; edits.do { arg sl, i; var key, val, mappx, spec, slider, number, sink, mapKey; var keyString, labelKey, isWet, isMix; key = editKeys[i]; sink = sinks[i]; if(key.notNil) { // editKeys and currentSettings are in sync. val = currentSettings[i][1]; labelKey = key; keyString = key.asString; spec = key.asSpec; isWet = keyString.beginsWith("wet"); // a filtered slot isMix = keyString.beginsWith("mix"); // an additive source if (isWet or: isMix) { if (isWet) { spec = \amp.asSpec }; if (isMix) { spec = \amp4.asSpec }; sl.sliderView.background_(Color.green(1.0, 0.5)).refresh; sl.labelView.background_(Color.green(1.0, 0.5)).refresh; } { sl.sliderView.background_(skin.foreground).refresh; sl.labelView.background_(skin.foreground).refresh; }; sl.visible_(true); sl.labelView.string = this.replaceName(key); sl.sliderView.enabled = spec.notNil; sl.sliderView.visible = spec.notNil; sl.numberView.enabled = true; sl.numberView.visible = true; sl.labelView.visible = true; sink.visible = true; // sl.sliderView.keyDownAction = { keyPressed = true }; // doesn't work yet. // sl.sliderView.keyUpAction = { proxy.xset(key, sl.value); keyPressed = false }; sl.action_({ arg nu; proxy.set(key, nu.value) }); if(spec.notNil) { sl.controlSpec = spec } { sl.controlSpec = ControlSpec(-1e8, 1e8); }; mappx = val.value ? 0; if(mappx.isNumber) { sl.value_(mappx ? 0); sink.object_(nil).string_("-"); } { // assume mappx is a proxy: if (val.isKindOf(BusPlug), { mapKey = currentEnvironment.findKeyForValue(mappx) ? "???"; sink.object_(mapKey).string_(mapKey); sl.labelView.string = "->" + key; }); } } { // "// hide unused edits".postln; sink.object_(nil).string_("-").visible_(false); sl.labelView.background_(skin.foreground).string_(""); sl.sliderView.background_(skin.foreground); sl.visible_(false); }; }; // this.adjustWindowSize; } runUpdate { skipjack.start } stopUpdate { skipjack.stop } } RecordProxyMixer { var <>proxymixer, bounds; var recHeaderFormat, <>recSampleFormat, ", Color.red, Color.gray(0.1)], ["stop []", this.skin.fontcolor, Color.red] ]).action_({|b| var list; switch(b.value, 1, { numChannels = this.prepareForRecord; if(numChannels.isNil) { b.value = 0; pbut.value = 0 } }, 2, { this.record(pbut.value == 1) }, 0, { this.removeRecorder } ); if(b.value == 1 and: { numChannels.notNil }) { list = this.selectedKeysValues; this.displayString = format("recording % channels: %", numChannels, list.join(" ")); }; }).font_(font); pbut = Button(rw, Rect(0, 0, 80, 20)).states_([ ["pause", this.skin.fontcolor, Color.clear], [">", Color.red, Color.gray(0.1)] ]).action_({|b| if(b.value == 1) { this.pauseRecorder } { this.unpauseRecorder } }).font_(font); recTypeChoice = PopUpMenu(rw, Rect(0, 0, 110, 20)) .items_([ \mix, \multichannel ]) .action_({ arg view; recType = view.items[view.value]; if(recbut.value != 0) { recbut.valueAction = 0 } }) .font_(font); recTypeChoice.value = 1; Button(rw, Rect(0, 0, 60, 20)) .states_([["cancel", this.skin.fontcolor, Color.clear]]) .action_({ if(recbut.value != 0) { recbut.valueAction = 0 } }) .font_(font); rw.view.decorator.nextLine; display = StaticText(rw, Rect(30, 40, 300, 20)).font_(font); rw.front; this.makeSkipJack; this.runUpdate; ^rw } displayString_ { arg str; display.string = str; } updateZones { if(preparedForRecording.not) { this.displayString = format("proxies: %", this.selectedKeysValues.join(" ")); } } title { ^"recorder for" + proxymixer.title } runUpdate { skipjack.start; } stopUpdate { skipjack.stop } makeSkipJack { // stoptest should check window. skipjack = SkipJack({ this.updateZones }, 0.5, name: this.title); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/GUI/extJITgui.sc0000664000000000000000000000275612014636263025522 0ustar rootroot+ NodeProxy { gui { | numItems, bounds, preset| // which options to support? ^NdefGui(this, numItems, nil, bounds, options: preset); } } + ProxySpace { gui { | numItems, bounds, preset| ^ProxyMixer(this, numItems, nil, bounds, options: preset); } } + Ndef { *gui { |numItems, bounds, preset| ^NdefMixer(numItems, nil, bounds, options: preset); } } + Tdef { *gui { | numItems, bounds, preset| ^TdefAllGui(numItems, nil, bounds, options: preset); } gui { | numItems, bounds, preset| ^TdefGui(this, numItems, nil, bounds, options: preset); } } + Pdef { *gui { | numItems, bounds, preset| ^PdefAllGui(numItems, nil, bounds, options: preset); } gui { | numItems, bounds, preset| ^PdefGui(this, numItems, nil, bounds, options: preset); } } + Dictionary { /* This method was introducing a conflict with the use of .gui(view,bounds) which is what the Object.gui system expects everything to be able to respond to. For the 3.5 release we decided (felix, julian, adc) to detect what args are passed in and just switch between systems. a Number indiciates jitlib usage: how many items to show in an editor. Nil would result in the super implementation which is a simple string representation of the key values list. A cleaner solution will be decided upon later. */ gui { |...args| var numItems, bounds, preset; if(args[0].isNumber,{ # numItems, bounds, preset = args; ^EnvirGui(this, numItems, nil, bounds, options: preset); },{ ^super.gui(*args) }) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/0000775000000000000000000000000012245452763024765 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/BusPlug.sc0000664000000000000000000001520712245365552026701 0ustar rootrootBusPlug : AbstractFunction { var monitor, <>parentGroup; // if nil, uses default group var busArg; // cache for "/s_new" bus arg var busLoaded = false; classvar <>defaultNumAudio=2, <>defaultNumControl=1; *new { | server | ^super.newCopyArgs(server ? Server.default); } *for { | bus | bus = bus.asBus; ^this.new(bus.server).bus_(bus) } *audio { | server, numChannels | ^this.new(server).defineBus(\audio, numChannels) } *control { | server, numChannels | ^this.new(server).defineBus(\control, numChannels) } clear { this.free; this.stop; this.freeBus; monitor = nil; this.changed(\clear); } // playing and access rate { ^if(bus.isNil) { \scalar } { bus.rate } } numChannels { ^if(bus.isNil) { nil } { bus.numChannels } } index { ^if(bus.isNil) { nil } { bus.index } } isNeutral { ^bus.isNil or: { bus.index.isNil and: { bus.numChannels.isNil } } } isMonitoring { ^monitor.isPlaying } isPlaying { ^this.index.notNil and: { server.serverRunning } } prepareOutput { } // see subclass clock { ^nil } ar { | numChannels, offset = 0 | if(this.isNeutral) { this.defineBus(\audio, numChannels) }; this.prepareOutput; ^InBus.ar(bus, numChannels ? bus.numChannels, offset) } kr { | numChannels, offset = 0 | if(this.isNeutral) { this.defineBus(\control, numChannels) }; this.prepareOutput; ^InBus.kr(bus, numChannels ? bus.numChannels, offset) } embedInStream { | inval | // for now, force multichannel expansion in streams early. ^this.asControlInput.embedInStream(inval); } asControlInput { if(this.isPlaying.not) { if(this.isNeutral) { this.defineBus(\control, 1) }; this.wakeUp }; ^this.busArg; } asUGenInput { ^this.value; } // math support value { | something | var n; if(UGen.buildSynthDef.isNil) { ^this }; // only return when in ugen graph. something !? { n = something.numChannels }; ^if(something.respondsTo(\rate) and: { something.rate == 'audio'}) { this.ar(n) } { this.kr(n) } } composeUnaryOp { | aSelector | ^UnaryOpPlug.new(aSelector, this) } composeBinaryOp { | aSelector, something | ^BinaryOpPlug.new(aSelector, this, something) } reverseComposeBinaryOp { | aSelector, something | ^BinaryOpPlug.new(aSelector, something, this) } composeNAryOp { |aSelector, anArgList| ^thisMethod.notYetImplemented //^NAryOpPlug.new(aSelector, [this]++anArgList) // nary op ugens are not yet implemented } // bus initialization bus_ { | inBus | this.freeBus; bus = inBus; this.makeBusArg; busLoaded = bus.server.serverRunning; } // returns false if failed initBus { | rate, numChannels | if(rate.isNil or: { rate === 'scalar' }) { ^true }; // this is no problem if(this.isNeutral) { this.defineBus(rate, numChannels); ^true } { numChannels = numChannels ? this.numChannels; ^(bus.rate === rate) and: { numChannels <= bus.numChannels } } } defineBus { | rate = \audio, numChannels | if(numChannels.isNil) { numChannels = if(rate === \audio) { this.class.defaultNumAudio } { this.class.defaultNumControl } }; this.bus = Bus.alloc(rate, server, numChannels); } freeBus { if(bus.notNil) { if(bus.rate === \control) { bus.setAll(0) }; // clean up bus.free; monitor.stop; }; busArg = bus = nil; busLoaded = false; } busArg { ^busArg ?? { this.makeBusArg } } makeBusArg { var index, numChannels, prefix; if(bus.isNil) { ^busArg = "" }; // still neutral prefix = if(this.rate == \audio) { "\a" } { "\c" }; index = this.index; numChannels = this.numChannels; ^busArg = if(numChannels == 1) { prefix ++ index } { { |i| prefix ++ (index + i) }.dup(numChannels) } } asMap { ^this.busArg } wakeUpToBundle {} wakeUp {} asBus { ^if(this.isNeutral) { nil } { bus } } asNodeArg { ^if(this.isNeutral) { nil } { this.busArg } } // monitoring play { | out, numChannels, group, multi=false, vol, fadeTime, addAction | var bundle = MixedBundle.new; if(this.homeServer.serverRunning.not) { ("server not running:" + this.homeServer).warn; ^this }; this.playToBundle(bundle, out.asControlInput, numChannels, group, multi, vol, fadeTime, addAction); // homeServer: multi client support: monitor only locally bundle.schedSend(this.homeServer, this.clock ? TempoClock.default, this.quant); this.changed(\play, [out, numChannels, group, multi, vol, fadeTime, addAction]); } playN { | outs, amps, ins, vol, fadeTime, group, addAction | var bundle = MixedBundle.new; if(this.homeServer.serverRunning.not) { ("server not running:" + this.homeServer).warn; ^this }; this.playNToBundle(bundle, outs.asControlInput, amps, ins, vol, fadeTime, group, addAction); bundle.schedSend(this.homeServer, this.clock ? TempoClock.default, this.quant); this.changed(\playN, [outs, amps, ins, vol, fadeTime, group, addAction]); } fadeTime { ^0.02 } quant { ^nil } vol { ^if(monitor.isNil) { 1.0 } { monitor.vol } } vol_ { arg val; this.initMonitor(val) } monitorIndex { ^if(monitor.isNil) { nil } { monitor.out } } monitorGroup { ^if(monitor.isNil) { nil } { monitor.group } } initMonitor { | vol | if(this.rate !== 'audio') { Error("can only monitor audio proxy").throw }; if(monitor.isNil) { monitor = Monitor.new }; if (vol.notNil) { monitor.vol_(vol) }; ^monitor } stop { | fadeTime = 0.1, reset = false | monitor.stop(fadeTime); if(reset) { monitor = nil }; this.changed(\stop, [fadeTime, reset]); } scope { | bufsize = 4096, zoom | if(this.isNeutral.not) { ^bus.scope(bufsize, zoom) } } // bundling messages playToBundle { | bundle, out, numChannels, group, multi=false, vol, fadeTime, addAction | this.newMonitorToBundle(bundle, numChannels); group = group ?? { if(parentGroup.isPlaying) { parentGroup } { this.homeServer.asGroup } }; monitor.usedPlayN = false; monitor.playToBundle(bundle, bus.index, bus.numChannels, out, numChannels, group, multi, vol, fadeTime, addAction); } playNToBundle { | bundle, outs, amps, ins, vol, fadeTime, group, addAction | this.newMonitorToBundle(bundle); // todo: numChannels monitor.usedPlayN = true; group = group ?? { if(parentGroup.isPlaying) { parentGroup } { this.homeServer.asGroup } }; monitor.playNBusToBundle(bundle, outs, amps, ins, bus, vol, fadeTime, group, addAction); } newMonitorToBundle { | bundle, numChannels | this.initBus(\audio, numChannels); this.initMonitor; if(this.isPlaying.not) { this.wakeUpToBundle(bundle) }; } // netwrk node proxy support shared { ^false } homeServer { ^server } printOn { | stream | stream << this.class.name << "." << bus.rate << "(" << server << ", " << bus.numChannels <<")"; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/extStoreOn.sc0000664000000000000000000002477012245365552027437 0ustar rootroot+ AbstractPlayControl { storeOn { | stream | source.storeOn(stream) } } +Symbol { isBasicOperator { ^#['+', '-', '*', '/', '%', '==', '!=', '<', '<=', '>', '>=', '&&', '||', '@' ] .includes(this); } } +Object { // might need correction for literals. envirKey { | envir | ^(envir ? currentEnvironment).findKeyForValue(this) } envirCompileString { var key = this.envirKey; ^if(key.notNil) { "~" ++ key } { this.asCompileString }; } } +NodeProxy { key { | envir | ^super.envirKey(envir); } servStr { ^if (server != Server.default) { "(" ++ server.asCompileString ++")" } { "" } } // not ideal, but usable for now. storeOn { | stream | var key = this.key; if (currentEnvironment.includes(this)) { stream << ("~" ++ key) } { if (key.isNil) { stream << "a = NodeProxy.new" ++ this.servStr } }; } playEditString { |usePlayN, dropDefaults = false, nameStr| var editString, outs, amps; nameStr = nameStr ?? { this.asCompileString }; if (nameStr.beginsWith("a = ")) { // anon proxy nameStr = nameStr.keep(1); }; usePlayN = usePlayN ?? { if (monitor.notNil) { monitor.usedPlayN } ? false }; // if they are defaults, don't post them if (usePlayN) { editString = nameStr ++ this.playNString(dropDefaults) } { editString = nameStr ++ this.playString(dropDefaults) }; ^editString; } playString { |dropDefaults = false| var defOut = 0, defVol = 1, defNumCh = this.numChannels ? 2; var out, numCh, vol, setStr = ""; out = try { this.monitor.out } ? defOut; numCh = this.numChannels ? defNumCh; // should be able to be different, or not? vol = try { this.monitor.vol } ? defVol; if (dropDefaults.not or: { out != defOut }) { setStr = setStr ++ "\tout:" + out }; if (dropDefaults.not or: { numCh != defNumCh }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tnumChannels:" + numCh; }; if (dropDefaults.not or: { vol != defVol }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tvol:" + vol ++ "\n"; }; if (setStr.size > 0) { setStr = "(\n" ++ setStr ++ "\n)"; }; ^(".play" ++ setStr ++ ";\n"); } playNString { |dropDefaults = false| var numCh = this.numChannels ? 2; var defOuts = { |i| i } ! numCh; var defAmps = 1 ! numCh; var defIns = { |i| i + this.index } ! numCh; var defVol = 1; var outs = try { this.monitor.outs } ? defOuts; var amps = try { this.monitor.amps } ? defAmps; var ins = try { this.monitor.ins } ? defIns; var vol = try { this.monitor.vol } ? defVol; var setStr = ""; // [\o, defOuts, outs, \a, defAmps, amps, \i, defIns, ins].postcs; if (dropDefaults.not or: { outs != defOuts }) { setStr = setStr ++ "\touts:" + outs }; if (dropDefaults.not or: { amps != defAmps }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tamps:" + amps; }; if (dropDefaults.not or: { ins != defIns }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tins:" + ins; }; if (dropDefaults.not or: { vol != defVol }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tvol:" + vol ++ "\n"; }; if (setStr.size > 0) { setStr = "(\n" ++ setStr ++ "\n)"; }; ^(".playN" ++ setStr ++ ";\n"); } playNDialog { | bounds, usePlayN | var doc = this.playEditString(usePlayN).newTextWindow("edit outs:"); try { doc.bounds_(bounds) }; // swingosc safe } findInOpenDocuments { |index = 0| var src, str, startSel, doc; src = this.at(index); src ?? { "NodeProxy: no source at index %.\n".postf(index); ^this }; str = src.asCompileString; doc = Document.allDocuments.detect { |doc| startSel = doc.string.find(str); startSel.notNil; }; doc !? { doc.front.selectRange(startSel, 0); } } asCode { | includeSettings = true, includeMonitor = true, envir | var nameStr, srcStr, str, docStr, indexStr, key; var space, spaceCS; var isAnon, isSingle, isInCurrent, isOnDefault, isMultiline; envir = envir ? currentEnvironment; nameStr = envir.use { this.asCompileString }; indexStr = nameStr; isAnon = nameStr.beginsWith("a = "); isSingle = this.objects.isEmpty or: { this.objects.size == 1 and: { this.objects.indices.first == 0 } }; isInCurrent = envir.includes(this); isOnDefault = server === Server.default; // [\isAnon, isAnon, \isSingle, isSingle, \isInCurrent, isInCurrent, \isOnDefault, isOnDefault].postln; space = ProxySpace.findSpace(this); spaceCS = try { space.asCode } { inform("// ".format(this.asCompileString)); "" }; docStr = String.streamContents { arg stream; if(isSingle) { str = nameStr; srcStr = if (this.source.notNil) { this.source.envirCompileString } { "" }; if ( isAnon ) { // "a = NodeProxy.new" if (isOnDefault.not) { str = str ++ "(" ++ this.server.asCompileString ++ ")" }; if (srcStr.notEmpty) { str = str ++ ".source_(" ++ srcStr ++ ")" }; } { if (isInCurrent) { // ~out if (srcStr.notEmpty) { str = str + "=" + srcStr }; } { // Ndef('a') - put sourceString before closing paren. if (srcStr.notEmpty) { str = str.copy.drop(-1) ++ ", " ++ srcStr ++ nameStr.last }; } }; } { // multiple sources if (isAnon) { str = nameStr ++ ";\n"; indexStr = "a"; }; this.objects.keysValuesDo { arg index, item; srcStr = item.source.envirCompileString ? ""; isMultiline = srcStr.includes(Char.nl); if (isMultiline) { srcStr = "(" ++ srcStr ++ ")" }; srcStr = indexStr ++ "[" ++ index ++ "] = " ++ srcStr ++ ";\n"; str = str ++ srcStr; }; }; stream << str << if (str.keep(-2).includes($;)) { "\n" } { ";\n" }; // add settings to compile string if(includeSettings) { this.nodeMap.storeOn(stream, indexStr, true); }; // include play settings if playing ... // hmmm - also keep them if not playing, // but inited to something non-default? if (this.rate == \audio and: includeMonitor) { if (this.monitor.notNil) { if (this.isMonitoring) { stream << this.playEditString(this.monitor.usedPlayN, true) } }; }; }; isMultiline = docStr.drop(-1).includes(Char.nl); if (isMultiline) { docStr = "(\n" ++ docStr ++ ");\n" }; ^docStr } document { | includeSettings = true, includeMonitor = true | ^this.asCode(includeSettings, includeMonitor).newTextWindow("document :" + this.asCompileString) } } +BinaryOpPlug { envirCompileString { var astr, bstr, opstr, str = ""; var basic = operator.isBasicOperator; astr = a.envirCompileString; bstr = b.envirCompileString; if(b.isKindOf(AbstractOpPlug)) { bstr = "(%)".format(bstr) }; opstr = if(basic.not) { ".%(" } { " % " }.format(operator); str = str ++ astr ++ opstr ++ bstr; if(basic.not) { str = str ++ ")" }; ^str } } +UnaryOpPlug { envirCompileString { ^(a.envirCompileString ? "") ++ " " ++ operator } } + ProxySpace { // where am I globally accessible? asCode { var key; if (this == thisProcess.interpreter.p) { ^"p" }; if (this == currentEnvironment) { ^"currentEnvironment" }; if (Ndef.all.includes(this)) { key = Ndef.all.findKeyForValue(this); ^"Ndef.all[%]".format(key.asCompileString); }; if (ProxySpace.all.includes(this)) { key = ProxySpace.all.findKeyForValue(this); ^"ProxySpace.all[%]".format(key.asCompileString); }; ^"/***( cannot locate this proxyspace )***/" } storeOn { | stream, keys, includeSettings = true, includeMonitors = true | var proxies, hasGlobalClock; hasGlobalClock = clock.isKindOf(TempoBusClock); stream << "\n(\n"; // ) if(hasGlobalClock) { stream <<< this.asCode << ".makeTempoClock(" << clock.tempo << ");\n\n"; }; // find keys for all parents if(keys.notNil) { proxies = IdentitySet.new; keys.do { arg key; var p = envir[key]; p !? { p.getFamily(proxies) } }; keys = proxies.collect { arg item; item.key(envir) }; } { keys = envir.keys }; if(hasGlobalClock) { keys.remove(\tempo) }; // add all objects to compilestring keys.do { arg key; var proxy = envir.at(key); stream << proxy.asCode(includeSettings, includeMonitors, this.envir) << "\n"; }; stream << /*(*/ ");\n"; } documentOutput { ^this.document(nil, true) } document { | keys, onlyAudibleOutput = false, includeSettings = true | var str; if(onlyAudibleOutput) { keys = this.monitors.collect { arg item; item.key(envir) }; }; str = String.streamContents { arg stream; stream << "// ( p = ProxySpace.new(s).push; ) \n\n"; this.storeOn(stream, keys, includeSettings); // this.do { arg px; if(px.monitorGroup.isPlaying) { // stream << px.playEditString << ".play; \n" // } // }; }; ^str.newTextWindow((name ? "proxyspace").asString) } } + ProxyNodeMap { storeOn { | stream, namestring = "", dropOut = false | var strippedSetArgs, storedSetNArgs, rates, proxyMapKeys, proxyMapNKeys; this.updateBundle; if(dropOut) { forBy(0, setArgs.size - 1, 2, { arg i; var item; item = setArgs[i]; if(item !== 'out' and: { item !== 'i_out' }) { strippedSetArgs = strippedSetArgs.add(item); strippedSetArgs = strippedSetArgs.add(setArgs[i+1]); } }) } { strippedSetArgs = setArgs }; if(strippedSetArgs.notNil) { stream << namestring << ".set(" <<<* strippedSetArgs << ");" << Char.nl; }; if(mapArgs.notNil or: { mapnArgs.notNil }) { settings.keysValuesDo { arg key, setting; var proxy; if(setting.isMapped) { proxy = setting.value; if(proxy.notNil) { if(setting.isMultiChannel) { proxyMapNKeys = proxyMapNKeys.add(key); proxyMapNKeys = proxyMapNKeys.add(proxy); }{ proxyMapKeys = proxyMapKeys.add(key); proxyMapKeys = proxyMapKeys.add(proxy); } }; }; }; if(proxyMapKeys.notNil) { stream << namestring << ".map(" <<<* proxyMapKeys << ");" << Char.nl; }; if(proxyMapNKeys.notNil) { stream << namestring << ".mapn(" <<<* proxyMapNKeys << ");" << Char.nl; }; }; if(setnArgs.notNil) { storedSetNArgs = Array.new; settings.keysValuesDo { arg key, setting; if(setting.isMapped.not and: setting.isMultiChannel) { storedSetNArgs = storedSetNArgs.add(key); storedSetNArgs = storedSetNArgs.add(setting.value); } }; stream << namestring << ".setn(" <<<* storedSetNArgs << ");" << Char.nl; }; settings.keysValuesDo { arg key, setting; if(setting.rate.notNil) { rates = rates.add(key); rates = rates.add(setting.rate) }; }; if(rates.notNil) { stream << namestring << ".setRates(" <<<* rates << ");" << Char.nl; } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/ProxySynthDef.sc0000664000000000000000000000671712245365552030114 0ustar rootrootProxySynthDef : SynthDef { var <>rate, <>numChannels; var <>canReleaseSynth, <>canFreeSynth; classvar <>sampleAccurate=false; *new { arg name, func, rates, prependArgs, makeFadeEnv=true, channelOffset=0, chanConstraint, rateConstraint; var def, rate, numChannels, output, isScalar, envgen, canFree, hasOwnGate; var hasGateArg=false, hasOutArg=false; def = super.new(name, { var out, outCtl; // build the controls from args output = SynthDef.wrap(func, rates, prependArgs); output = output.asUGenInput; // determine rate and numChannels of ugen func rate = output.rate; isScalar = rate === 'scalar'; numChannels = output.numChannels; // check for out key. this is used by internal control. func.def.argNames.do { arg name; if(name === \out) { hasOutArg = true }; if(name === \gate) { hasGateArg = true }; }; if(isScalar.not and: hasOutArg) { "out argument is provided internally!".error; // avoid overriding generated out ^nil }; //detect inner gates canFree = UGen.buildSynthDef.children.canFreeSynth; hasOwnGate = UGen.buildSynthDef.hasGateControl; makeFadeEnv = if(hasOwnGate && canFree.not) { "warning: gate does not free synth!".inform; false } { makeFadeEnv and: { (isScalar || canFree).not }; }; hasOwnGate = canFree && hasOwnGate; //only counts when it can actually free synth. if(hasOwnGate.not && hasGateArg) { "supplied gate overrides inner gate.".error; ^nil }; //"gate detection:".postln; //[\makeFadeEnv, makeFadeEnv, \canFree, canFree, \hasOwnGate, hasOwnGate].debug; // constrain the output to the right number of channels if supplied // if control rate, no channel wrapping is applied // and wrap it in a fade envelope envgen = if(makeFadeEnv) { EnvGate(1, nil, nil, 2, if(rate === 'audio') { 'sin' } { 'lin' }) } { 1.0 }; if(chanConstraint.notNil and: { chanConstraint < numChannels } and: { isScalar.not }, { if(rate === 'audio') { postln( "wrapped channels from" + numChannels + "to" + chanConstraint + "channels"); output = NumChannels.ar(output, chanConstraint, true); numChannels = chanConstraint; } { postln("kept first" + chanConstraint + "channels from" + numChannels + "channel input"); output = output.keep(chanConstraint); numChannels = chanConstraint; } }); output = output * envgen; //"passed in rate: % output rate: %\n".postf(rateConstraint, rate); if(isScalar, { output }, { // rate adaption. \scalar proxy means neutral if(rateConstraint != \scalar and: { rateConstraint !== rate }) { if(rate === 'audio') { output = A2K.kr(output); rate = 'control'; "adopted proxy input to control rate".postln; } { if(rateConstraint === 'audio') { output = K2A.ar(output); rate = 'audio'; "adopted proxy input to audio rate".postln; } } }; outCtl = Control.names(\out).ir(0) + channelOffset; if(rate === \audio and: { sampleAccurate }) { OffsetOut } { Out } .multiNewList([rate, outCtl]++output) }) }); // set the synthDefs instvars, so they can be used later def.rate = rate; def.numChannels = numChannels; def.canReleaseSynth = makeFadeEnv || hasOwnGate; def.canFreeSynth = def.canReleaseSynth || canFree; //[\defcanReleaseSynth, def.canReleaseSynth, \defcanFreeSynth, def.canFreeSynth].debug; ^def } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/ProxySpace.sc0000664000000000000000000001454112245365552027415 0ustar rootrootProxySpace : LazyEnvir { classvar <>all; var px } }); } } } activeProxies { ^this.arProxyNames({ |px, key| px.isPlaying }) } playingProxies { ^this.arProxyNames({ |px, key| px.monitor.isPlaying }) } existingProxies { ^this.arProxyNames } arProxyNames { |func=true| ^this.proxyNames(\audio, func) } krProxyNames { |func=true| ^this.proxyNames(\control, func) } proxyNames { |rate, func=true| var pxs; pxs = SortedList(8, { |a,b| a < b }); this.keysValuesDo({ arg key, px; if (px.rate === rate) { if (func.value(px, key), { pxs.add(key) }) } }); ^pxs; } doFunctionPerform { arg selector; ^this[selector] } // global access add { if(name.notNil) { if(this.class.all[name].isNil) { this.class.all.put(name, this) } { "there is already an environment with this name".warn }; } { "a ProxySpace with no name cannot be added to the repository".warn } } remove { this.class.all.removeAt(name) } *clearAll { this.all.do({ arg item; item.clear }); } printOn { arg stream; stream << this.class.name; if(envir.isEmpty) { stream << " ()\n"; ^this }; stream << " ( " << (name ? "") << Char.nl; this.keysValuesDo { arg key, item, i; stream << "~" << key << " - "; stream << if(item.rate === 'audio') { "ar" } { if(item.rate === 'control', { "kr" }, { "ir" }) } << "(" << item.numChannels << ") " << if(i.even) { "\t\t" } { "\n" }; }; stream << "\n)\n" } postln { Post << this } includes { |proxy| ^envir.includes(proxy) } *findSpace { |proxy, getCode = false| var space = [ currentEnvironment, thisProcess.interpreter.p ] .detect { |cand| cand.isKindOf(this) and: { cand.includes(proxy) } }; if (space.notNil) { ^space }; space = ProxySpace.all.detect(_.includes(proxy)); if (space.notNil) { ^space }; space = Ndef.all.detect(_.includes(proxy)); if (space.notNil) { ^space }; // none found ^nil } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/wrapForNodeProxy.sc0000664000000000000000000002075112245365552030610 0ustar rootroot//these extensions provide means to wrap Objects so that they //make sense within the server bus system according to a node proxy. ////////////////////// graphs, functions, numericals and arrays ////////////////// +Object { //objects can define their own wrapper classes dependant on //how they play, stop, build, etc. see SynthDefControl for example //the original (wrapped) object can be reached by the .source message //for objects that only create ugen graphs, define prepareForProxySynthDef(proxy) proxyControlClass { ^SynthDefControl } makeProxyControl { arg channelOffset=0; ^this.proxyControlClass.new(this, channelOffset); } //any preparations that have to be done to prepare the object //implement 'prepareForProxySynthDef' to return a ugen func //this method is called from within the Control buildForProxy { arg proxy, channelOffset=0, index; var argNames; argNames = this.argNames; ^ProxySynthDef( SystemSynthDefs.tempNamePrefix ++ proxy.generateUniqueName ++ index, this.prepareForProxySynthDef(proxy), proxy.nodeMap.ratesFor(argNames), nil, true, channelOffset, proxy.numChannels, proxy.rate ); } prepareForProxySynthDef { ^this.subclassResponsibility(thisMethod) } defaultArgs { ^nil } argNames { ^nil } //support for unop / binop proxy isNeutral { ^true } initBus { ^true } wakeUp {} } +Function { prepareForProxySynthDef { ^this } argNames { ^def.argNames } defaultArgs { ^def.prototypeFrame } } +AbstractFunction { prepareForProxySynthDef { ^{ this.value } } } +SimpleNumber { prepareForProxySynthDef { arg proxy; proxy.initBus(\control, 1); ^{DC.multiNewList([proxy.rate] ++ this) }; } } +Synth { // better information about common error prepareForProxySynthDef { arg proxy; Error( "A synth is no valid source for a proxy.\n" "For instance, ~out = { ... }.play would cause this and should be:\n" "~out = { ... }; ~out.play; or (~out = { ... }).play;" ).throw; } } +RawArray { prepareForProxySynthDef { arg proxy; proxy.initBus(\control, this.size); ^{DC.multiNewList([proxy.rate] ++ this) }; } } +SequenceableCollection { prepareForProxySynthDef { arg proxy; proxy.initBus(\control, this.size); ^{ this.collect({ |el| el.prepareForProxySynthDef(proxy).value }) } // could use SynthDef.wrap, but needs type check for function. } } +BusPlug { prepareForProxySynthDef { arg proxy; proxy.initBus(this.rate, this.numChannels); ^{ this.value(proxy) } } } +AbstractOpPlug { prepareForProxySynthDef { arg proxy; proxy.initBus(this.rate, this.numChannels); ^{ this.value(proxy) } } } //needs a visit: lazy init + channelOffset +Bus { prepareForProxySynthDef { arg proxy; ^BusPlug.for(this).prepareForProxySynthDef(proxy); } } ///////////////////////////// SynthDefs and alike //////////////////////////////////// +SynthDef { buildForProxy {} numChannels { ^nil } //don't know rate { ^nil } } +Symbol { buildForProxy {} proxyControlClass { ^SynthControl } } ///////////////////////////// Pattern - Streams /////////////////////////////////// +Stream { proxyControlClass { ^StreamControl } buildForProxy { ^PauseStream.new(this) } } +PauseStream { buildForProxy { ^this } proxyControlClass { ^StreamControl } } +PatternProxy { buildForProxy { "a numerical pattern does not make sense here.".error; ^nil } } +TaskProxy { proxyControlClass { ^StreamControl } buildForProxy { arg proxy, channelOffset=0; ^PauseStream(this.endless.asStream <> ( nodeProxy: proxy, channelOffset: channelOffset, server: { proxy.server }, out: { proxy.index }, group: { proxy.group } ) ) } } +EventPatternProxy { proxyControlClass { ^PatternControl } buildForProxy { arg proxy, channelOffset=0; ^this.endless.buildForProxy(proxy, channelOffset) } } +Pattern { proxyControlClass { ^PatternControl } buildForProxy { arg proxy, channelOffset=0; var player = this.asEventStreamPlayer; var event = player.event.buildForProxy(proxy, channelOffset); ^event !? { player }; } } + Event { proxyControlClass { ^StreamControl } buildForProxy { arg proxy, channelOffset=0; var ok, index, server, numChannels, rate, finish; ok = if(proxy.isNeutral) { rate = this.at(\rate) ? 'audio'; numChannels = this.at(\numChannels) ? NodeProxy.defaultNumAudio; proxy.initBus(rate, numChannels); } { rate = proxy.rate; // if proxy is initialized, it is user's responsibility numChannels = proxy.numChannels; true }; ^if(ok) { index = proxy.index; server = proxy.server; this.use({ ~channelOffset = channelOffset; // default value ~out = { ~channelOffset % numChannels + index }; ~server = server; // not safe for server changes yet finish = ~finish; ~group = { proxy.group.asNodeID }; ~finish = { finish.value; proxy.nodeMap.addToEvent(currentEnvironment); ~group = ~group.value; ~out = ~out.value; } }); this } { nil } } } /////////// pluggable associations ////////////// +Association { buildForProxy { arg proxy, channelOffset=0, index; ^AbstractPlayControl.buildMethods[key].value(value, proxy, channelOffset, index) } proxyControlClass { ^AbstractPlayControl.proxyControlClasses[key] ? SynthDefControl } } +AbstractPlayControl { makeProxyControl { ^this.deepCopy } //already wrapped, but needs to be copied /* these adverbial extendible interfaces are for supporting different role schemes. it is called by Association, so ~out = \filter -> ... will call this. The first arg passed is the value of the association */ *initClass { proxyControlClasses = ( filter: SynthDefControl, xset: StreamControl, set: StreamControl, stream: PatternControl, setbus: StreamControl, setsrc: StreamControl ); buildMethods = ( filter: #{ arg func, proxy, channelOffset=0, index; var ok, ugen; if(proxy.isNeutral) { ugen = func.value(Silent.ar); ok = proxy.initBus(ugen.rate, ugen.numChannels); if(ok.not) { Error("NodeProxy input: wrong rate/numChannels").throw } }; { arg out; var e; e = EnvGate.new * Control.names(["wet"++(index ? 0)]).kr(1.0); if(proxy.rate === 'audio') { XOut.ar(out, e, SynthDef.wrap(func, nil, [In.ar(out, proxy.numChannels)])) } { XOut.kr(out, e, SynthDef.wrap(func, nil, [In.kr(out, proxy.numChannels)])) }; }.buildForProxy( proxy, channelOffset, index ) }, set: #{ arg pattern, proxy, channelOffset=0, index; var args; args = proxy.controlNames.collect(_.name); Pbindf( pattern, \type, \set, \id, Pfunc { proxy.group.nodeID }, \args, args ).buildForProxy( proxy, channelOffset, index ) }, xset: #{ arg pattern, proxy, channelOffset=0, index; Pbindf( pattern, \play, { proxy.xset(*proxy.controlNames.collect(_.name).envirPairs) } ).buildForProxy( proxy, channelOffset, index ) }, setbus: #{ arg pattern, proxy, channelOffset=0, index; var ok = proxy.initBus(\control); if(ok.not) { Error("NodeProxy input: wrong rate").throw }; Pbindf( pattern, \type, \bus, \id, Pfunc { proxy.group.nodeID }, \array, Pkey(\value).collect { |x| x.keep(proxy.numChannels) }, \out, Pfunc { proxy.index } ).buildForProxy( proxy, channelOffset, index ) }, setsrc: #{ arg pattern, proxy, channelOffset=0, index=0; pattern.collect { |event| event[\type] = \rest; proxy.put(index + 1, event[\source]); event }.buildForProxy( proxy, channelOffset, index ); }, control: #{ arg values, proxy, channelOffset=0, index; { Control.kr(values) }.buildForProxy( proxy, channelOffset, index ); }, filterIn: #{ arg func, proxy, channelOffset=0, index; var ok, ugen; if(proxy.isNeutral) { ugen = func.value(Silent.ar); ok = proxy.initBus(ugen.rate, ugen.numChannels); if(ok.not) { Error("NodeProxy input: wrong rate/numChannels").throw } }; { arg out; var in; var egate = EnvGate.new; var wetamp = Control.names(["wet"++(index ? 0)]).kr(1.0); var dryamp = 1 - wetamp; if(proxy.rate === 'audio') { in = In.ar(out, proxy.numChannels); XOut.ar(out, egate, SynthDef.wrap(func, nil, [in * wetamp]) + (dryamp * in)) } { in = In.kr(out, proxy.numChannels); XOut.kr(out, egate, SynthDef.wrap(func, nil, [in * wetamp]) + (dryamp * in)) }; }.buildForProxy( proxy, channelOffset, index ) }, mix: #{ arg func, proxy, channelOffset=0, index; { var e = EnvGate.new * Control.names(["mix"++(index ? 0)]).kr(1.0); e * SynthDef.wrap(func); }.buildForProxy( proxy, channelOffset, index ) }; ) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/ProxyInterfaces.sc0000664000000000000000000001710712245365552030446 0ustar rootroot// lightweight objects that insulate different ways of playing/stopping. // the bundle that is passed in is a MixedBundle AbstractPlayControl { var channelOffset; var buildMethods, <>proxyControlClasses; // see wrapForNodeProxy for methods *new { | source, channelOffset = 0 | ^super.newCopyArgs(source, channelOffset); } build { ^true } pause { this.stop } resume { this.start } nodeID { ^nil } readyForPlay { ^true } distributable { ^false } // shared proxy support loadToBundle {} spawnToBundle {} // only active in synthcontrols playToBundle { | bundle, args | bundle.addOnSendMessage(this, \play); //no latency (latency is in stream already) ^nil //return a nil object instead of a synth } stopToBundle { | bundle | bundle.addOnSendMessage(this, \stop); } freeToBundle {} set {} controlNames { ^nil } play { this.subclassResponsibility(thisMethod) } stop { this.subclassResponsibility(thisMethod) } wakeUpParentsToBundle {} addParent { "wrong object in NodeProxy.buildControl".error } // for now. parents { ^nil } store {} } // The stream is a pause stream. This is meant for running in the proxy to control inner properties so it is stopped when removed. StreamControl : AbstractPlayControl { var stream, clock; playToBundle { | bundle | // no latency (latency is in stream already) if(paused.not) { bundle.addOnSendMessage(this, \play) } ^nil // return a nil object instead of a synth } build { | proxy, orderIndex = 0 | clock = proxy.clock; paused = proxy.paused; stream = source.buildForProxy(proxy, channelOffset, orderIndex); ^true; } pause { stream.pause; paused=true } resume { | clock, quant = 1.0 | stream.resume(clock, quant); paused = false; } readyForPlay { ^stream.notNil } play { if(stream.isPlaying.not) { stream.play(clock, false, 0.0) } } stop { stream.stop } } PatternControl : StreamControl { var fadeTime, nodeID; var settings; // cache args: var <>upToDate, <>setArgs, <>setnArgs, <>mapArgs, <>mapnArgs, <>mapaArgs, <>mapanArgs; var controlNames; *new { ^super.new.clear } settingClass { ^NodeMapSetting } clear { settings = IdentityDictionary.new; upToDate = false; this.changed(\clear); } map { arg ... args; forBy(0, args.size-1, 2, { arg i; this.get(args.at(i)).map(args.at(i+1)); }); upToDate = false; this.changed(\map, args); } mapa { arg ... args; forBy(0, args.size-1, 2, { arg i; this.get(args.at(i)).mapa(args.at(i+1)); }); upToDate = false; this.changed(\map, args); } unmap { arg ... keys; keys.do { arg key; var setting; setting = settings.at(key); if(setting.notNil and: { setting.isMapped }) { setting.map(nil, nil); if(setting.isEmpty) { settings.removeAt(key) } }; }; upToDate = false; this.changed(\unmap, keys); } set { arg ... args; forBy(0, args.size-1, 2, { arg i; this.get(args.at(i)).set(args.at(i+1)); }); upToDate = false; this.changed(\set, args); } setn { arg ... args; this.set(*args) } unset { arg ... keys; keys.do { arg key; var setting; setting = settings.at(key); if(setting.notNil and: { setting.isMapped.not }) { setting.map(nil, nil); if(setting.isEmpty) { settings.removeAt(key) } }; }; upToDate = false; this.changed(\unset, keys); } mapn { arg ... args; forBy(0, args.size-1, 3, { arg i; this.get(args.at(i)).mapn(args.at(i+1), args.at(i+2)); }); upToDate = false; this.changed(\mapn, args); } mapan { arg ... args; forBy(0, args.size-1, 3, { arg i; this.get(args.at(i)).mapan(args.at(i+1), args.at(i+2)); }); upToDate = false; this.changed(\mapan, args); } send { arg server, nodeID, latency; var bundle; bundle = List.new; this.addToBundle(bundle, nodeID); server.listSendBundle(latency, bundle); } sendToNode { arg node, latency; node = node.asTarget; this.send(node.server, node.nodeID, latency) } controlNames { this.updateBundle; ^controlNames } get { arg key; var setting; setting = settings.at(key); if(setting.isNil, { setting = this.settingClass.new(key); settings.put(key, setting) }); ^setting } at { arg key; ^settings.at(key) } settingKeys { var res; settings.do { arg item; if(item.isMapped.not) { res = res.add(item.key) } }; ^res } mappingKeys { var res; settings.do { arg item; if(item.isMapped) { res = res.add(item.key) } }; ^res } updateBundle { if(upToDate.not) { upToDate = true; setArgs = setnArgs = mapArgs = mapnArgs = mapaArgs = mapanArgs = nil; settings.do { arg item; item.updateNodeMap(this) }; controlNames = settings.values.collect(_.asControlName); } } addToEvent { arg event; settings.do { |x| x.addToEvent(event) } } addToBundle { arg bundle, target; var msgs; target = target.asNodeID; this.updateBundle; if(setArgs.notNil) { bundle.add([15, target] ++ setArgs) }; if(setnArgs.notNil) { bundle.add([16, target] ++ setnArgs) }; if(mapArgs.notNil) { bundle.add([14, target] ++ mapArgs) }; if(mapnArgs.notNil) { bundle.add([48, target] ++ mapnArgs) }; if(mapaArgs.notNil) { bundle.add([60, target] ++ mapaArgs) }; if(mapanArgs.notNil) { bundle.add([61, target] ++ mapanArgs) }; } unsetArgsToBundle { arg bundle, target, keys; var args; if(settings.isEmpty) { ^this }; (keys ?? { settings.keys }).do { arg key; var item; item = settings[key]; if(item.notNil) { args = args ++ [key, -1] } }; if(args.notNil) { bundle.add([15, target.asNodeID] ++ args) }; } unmapArgsToBundle { arg bundle, target, keys; var args; if(settings.isEmpty) { ^this }; (keys ?? { settings.keys }).do { arg key; var item; item = settings[key]; if(item.notNil and: { item.isMapped }) { args = args ++ [key, -1, item.busNumChannels]; }; }; if(args.notNil) { bundle.add([48, target.asNodeID] ++ args) }; } blend { arg another, frac; var res = this.copy; another.updateBundle; another.setArgs.pairsDo { |key, x| var s = settings[key], y; s !? { y = s.getValue }; y !? { res.set(key, blend(y, x, frac)) } }; ^res } copy { var res, nset; res = this.class.new; nset = res.settings; settings.keysValuesDo({ arg key, val; nset.put(key, val.copy) }); ^res } printOn { arg stream; stream << this.class.name << "("; settings.printItemsOn(stream); stream << ")" } } ProxyNodeMap : NodeMap { var <>parents, <>proxy; var hasRates=false; clear { super.clear; parents = IdentityDictionary.new; } settingClass { ^ProxyNodeMapSetting } wakeUpParentsToBundle { arg bundle, checkedAlready; parents.do({ arg item; item.wakeUpToBundle(bundle, checkedAlready) }); } setRates { arg args; forBy(0, args.size-1, 2, { arg i; var key, rate, setting; key = args[i]; setting = this.get(key); rate = args[i+1]; if(rate.isNil and: { setting.notNil } and: { setting.isEmpty }) { settings.removeAt(key) } { setting.rate_(rate) }; }); hasRates = settings.any { arg item; item.rate.notNil }; } ratesFor { arg keys; ^if(hasRates) { keys.collect({ arg key; var res; res = settings.at(key); if(res.notNil, { res.rate }, { nil }) }) } { nil } } mapn { arg ... args; this.map(args) // for now, avoid errors. } map { arg ... args; var playing; playing = proxy.isPlaying; args.pairsDo { arg key, mapProxy; var setting, numChannels; if(mapProxy.isKindOf(BusPlug).not) { Error("map: not a node proxy").throw }; if(playing) { mapProxy.wakeUp }; setting = this.get(key); setting.map(mapProxy); parents = parents.put(key, mapProxy); }; upToDate = false; this.changed(\map, args); } mapEnvir { arg ... keys; var args; keys = keys ? settings.keys; args = Array.new(keys.size*2); keys.do({ arg key; args.add(key); args.add(currentEnvironment.at(key)) }); this.map(*args); } unmap { arg ... keys; var setting; if(keys.at(0).isNil, { keys = this.mappingKeys }); keys.do({ arg key; setting = settings.at(key); if(setting.notNil, { setting.map(nil, nil); parents.removeAt(key); if(setting.isEmpty, { settings.removeAt(key) }) }); }); upToDate = false; this.changed(\unmap, keys); } changed { arg ... args; proxy.changed(*args) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/NodeProxy.sc0000664000000000000000000005574212245365552027257 0ustar rootrootNodeProxy : BusPlug { var awake=true, clock, <>quant; classvar <>buildProxyControl; *new { | server, rate, numChannels, inputs | var res = super.new(server).init; res.initBus(rate, numChannels); inputs.do { |o| res.add(o) }; ^res } init { nodeMap = ProxyNodeMap.new; objects = Order.new; loaded = false; } clear { | fadeTime = 0 | this.free(fadeTime, true); // free group and objects this.removeAll; // take out all objects this.stop(fadeTime, true); // stop any monitor monitor = nil; this.freeBus; // free the bus from the server allocator this.init; // reset the environment this.changed(\clear, [fadeTime]); } end { | fadeTime, reset = false | var dt = fadeTime ? this.fadeTime; fork { this.free(dt, true); (dt + (server.latency ? 0)).wait; this.stop(0, reset); }; this.changed(\end, [fadeTime, reset]); } isPlaying { ^group.isPlaying } free { | fadeTime, freeGroup = true | var bundle; var oldGroup = group; if(this.isPlaying) { bundle = MixedBundle.new; if(fadeTime.notNil) { bundle.add([15, group.nodeID, "fadeTime", fadeTime]) }; this.stopAllToBundle(bundle, fadeTime); if(freeGroup) { oldGroup = group; group = nil; bundle.sched((fadeTime ? this.fadeTime) + (server.latency ? 0), { oldGroup.free }); }; bundle.send(server); this.changed(\free, [fadeTime, freeGroup]); } } release { | fadeTime | this.free(fadeTime, false) } pause { if(this.isPlaying) { objects.do { |item| item.pause(clock, quant) } }; paused = true; this.changed(\pause); } resume { paused = false; if(this.isPlaying) { objects.do { |item| item.resume(clock, quant) } }; this.changed(\resume); } fadeTime_ { | dur | if(dur.isNil) { this.unset(\fadeTime) } { this.set(\fadeTime, dur) }; } fadeTime { ^nodeMap.at(\fadeTime).value ? 0.02; } prFadeTime { ^nodeMap.at(\fadeTime).value } asGroup { ^group.asGroup } asTarget { ^group.asGroup } asNodeID { ^group.asNodeID } parentGroup_ { | node | if(node.isPlaying.not) { "node not playing and registered: % \n".postf(node); ^this }; parentGroup = node; if(group.isPlaying) { group.moveToHead(parentGroup) }; } // setting the source source_ { | obj | this.put(nil, obj, 0) } prime { | obj | this.put(nil, obj, 0, nil, false); } sources_ { | list | this[0..] = list; } source { ^objects.at(0).source } sources { ^objects.array.collect(_.source) } add { | obj, channelOffset = 0, extraArgs, now = true | this.put(objects.pos, obj, channelOffset, extraArgs, now) } at { | index | ^objects.at(index).source } put { | index, obj, channelOffset = 0, extraArgs, now = true | var container, bundle, orderIndex; if(obj.isNil) { this.removeAt(index); ^this }; if(index.isSequenceableCollection) { ^this.putAll(obj.asArray, index, channelOffset) }; orderIndex = index ? 0; container = obj.makeProxyControl(channelOffset, this); container.build(this, orderIndex); // bus allocation happens here if(this.shouldAddObject(container, index)) { bundle = MixedBundle.new; if(index.isNil) { this.removeAllToBundle(bundle) } { this.removeToBundle(bundle, index) }; objects = objects.put(orderIndex, container); this.changed(\source, [obj, index, channelOffset, extraArgs, now]); } { format("failed to add % to node proxy: %", obj, this).inform; ^this }; if(server.serverRunning) { now = awake && now; if(now) { this.prepareToBundle(nil, bundle); }; container.loadToBundle(bundle, server); loaded = true; if(now) { container.wakeUpParentsToBundle(bundle); this.sendObjectToBundle(bundle, container, extraArgs, index); }; nodeMap.wakeUpParentsToBundle(bundle); bundle.schedSend(server, clock ? TempoClock.default, quant); } { loaded = false; } } putAll { | list, index = (0), channelOffset = 0 | channelOffset = channelOffset.asArray; if(index.isSequenceableCollection) { max(list.size, index.size).do { |i| this.put(index.wrapAt(i), list.wrapAt(i), channelOffset.wrapAt(i)) } }{ list.do { |item, i| this.put(i + index, item, channelOffset.wrapAt(i)) } } } putSeries { | first, second, last, value | last = last ?? { max(1, max(objects.size, value.size)) - 1 }; this.putAll(value.asArray, (first, second..last)) } filter { | i, func | this.put(i, \filter -> func) } removeFirst { | fadeTime | this.removeAt(objects.indices.first, fadeTime) } removeLast { | fadeTime | this.removeAt(objects.indices.last, fadeTime) } removeAll { | fadeTime | this.removeAt(nil, fadeTime) } removeAt { | index, fadeTime | var bundle = MixedBundle.new; if(index.isNil) { this.removeAllToBundle(bundle, fadeTime) } { this.removeToBundle(bundle, index, fadeTime) }; this.changed(\source, [nil, index, fadeTime]); bundle.schedSend(server); } rebuild { var bundle; if(this.isPlaying) { bundle = MixedBundle.new; this.stopAllToBundle(bundle); bundle.schedSend(server, clock ? TempoClock.default, quant); bundle = MixedBundle.new; loaded = false; this.loadToBundle(bundle); this.sendAllToBundle(bundle); bundle.schedSend(server, clock ? TempoClock.default, quant); } { loaded = false; }; } lag { | ... args | nodeMap.setRates(args); this.rebuild; } setRates { | ... args | nodeMap.setRates(args); this.rebuild; } server_ { | inServer | if(this.isNeutral.not) { this.end; loaded = false; }; server = inServer; } bus_ { | inBus | var oldBus = bus; if(server != inBus.server) { Error("can't change the server").throw }; super.bus_(inBus); this.linkNodeMap; if(oldBus.notNil) { this.rebuild }; } group_ { | inGroup | var bundle; if(inGroup.server !== server, { Error("cannot move to another server").throw }); NodeWatcher.register(inGroup.isPlaying_(true)); // assume it is playing if(this.isPlaying) { bundle = MixedBundle.new; this.stopAllToBundle(bundle); group = inGroup; this.sendAllToBundle(bundle); bundle.schedSend(server, clock ? TempoClock.default, 0.0); } { group = inGroup }; } read { | proxies | proxies = proxies.asCollection; proxies.do { arg item; item.wakeUp }; this.readFromBus(proxies) } readFromBus { | busses | var n, x; busses = busses.asCollection; n = this.numChannels; busses.do { arg item, i; x = min(item.numChannels ? n, n); this.put(i, SynthControl.new("system_link_" ++ this.rate ++ "_" ++ x), 0, ["in", item.index, "out", this.index] ) }; } // modifying context, setting controls set { | ... args | // pairs of keys or indices and value nodeMap.set(*args); if(this.isPlaying) { server.sendBundle(server.latency, [15, group.nodeID] ++ args); } } setn { | ... args | nodeMap.set(*args); if(this.isPlaying) { server.sendBundle(server.latency, group.setnMsg(*args)); } } setGroup { | args, useLatency = false | if(this.isPlaying) { server.sendBundle(if(useLatency) { server.latency }, [15, group.nodeID] ++ args); }; } map { | ... args | // key(s), proxy, key(s), proxy ... var bundle; if(this.isPlaying) { bundle = List.new; nodeMap.unmapArgsToBundle(bundle, group.nodeID, args[0,2..args.size-2]); nodeMap.map(*args).updateBundle; nodeMap.addToBundle(bundle, group.nodeID); server.listSendBundle(server.latency, bundle); } { nodeMap.map(*args) }; } mapn { | ... args | "NodeProxy: mapn is deprecated, please use map instead".postln; ^this.map(*args) } xset { | ... args | this.xFadePerform(\set, args) } xmap { | ... args | this.xFadePerform(\map, args) } xsetn { | ... args | this.xFadePerform(\setn, args) } xmapn { | ... args | "NodeProxy: xmapn is decrepated, please use xmap instead".postln; this.xFadePerform(\map, args) } xunset { | ... args | this.xFadePerform(\unset, args) } xFadePerform { | selector, args | var bundle; if(this.isPlaying) { nodeMap.performList(selector, args); this.sendEach(nil, true) } { this.performList(selector, args) } } mapEnvir { | ... keys | // map to current environment nodeMap.mapEnvir(*keys); if(this.isPlaying) { nodeMap.sendToNode(group); }; } unset { | ... keys | var bundle = List.new; this.unsetToBundle(bundle, keys); if(bundle.notEmpty) { server.listSendBundle(server.latency, bundle) }; } unmap { | ... keys | var bundle; if(keys.isEmpty) { keys = nodeMap.mappingKeys; if(keys.isEmpty) { ^this } }; if(this.isPlaying) { bundle = List.new; nodeMap.unmapArgsToBundle(bundle, group.nodeID, keys); if(bundle.notEmpty) { server.listSendBundle(server.latency, bundle) }; }; nodeMap.unmap(*keys); } nodeMap_ { | map | this.setNodeMap(map, false) } setNodeMap { | map, xfade = true | var bundle, old, fadeTime; map.set(\fadeTime, this.fadeTime); // keep old fadeTime bundle = MixedBundle.new; old = nodeMap; nodeMap = map; old.clear; this.linkNodeMap; this.nodeMapChanged; if(this.isPlaying) { if(xfade) { this.sendEach(nil,true) } { this.unsetToBundle(bundle); // unmap old nodeMap.addToBundle(bundle, group); // map new bundle.schedSend(server, clock ? TempoClock.default, quant); } }; } nodeMapChanged { var set, map; nodeMap.settings.do { |setting| if(setting.isMapped) { map = map.add(setting.key).add(setting.value) } { set = set.add(setting.key).add(setting.value) } }; if(set.notNil) { this.changed(\set, set) }; if(map.notNil) { this.changed(\map, map) }; } // play proxy as source of receiver <-- { | proxy | var bundle = MixedBundle.new; this.source = proxy; if(proxy.monitorGroup.isPlaying) { proxy.stop(fadeTime: 0.5); if(this.monitorGroup.isPlaying.not) { this.playToBundle(bundle, fadeTime:0.1) } }; bundle.add(proxy.moveBeforeMsg(this)); bundle.send(server, server.latency); } // map receiver to proxy input // second argument is an adverb <>> { | proxy, key = \in | proxy.perform('<<>', this, key); ^proxy } // map proxy to receiver input // second argument is an adverb <<> { | proxy, key = \in | var ctl, rate, numChannels, canBeMapped; if(proxy.isNil) { ^this.unmap(key) }; ctl = this.controlNames.detect { |x| x.name == key }; rate = ctl.rate ?? { if(proxy.isNeutral) { if(this.isNeutral) { \audio } { this.rate } } { proxy.rate } }; numChannels = ctl !? { ctl.defaultValue.asArray.size }; canBeMapped = proxy.initBus(rate, numChannels); if(canBeMapped) { if(this.isNeutral) { this.defineBus(rate, numChannels) }; this.xmap(key, proxy); } { "Could not link node proxies, no matching input found.".warn }; ^proxy // returns first argument for further chaining } // starting processes spawn { | extraArgs, index = 0 | var bundle, obj, i; obj = objects.at(index); if(obj.notNil) { i = this.index; bundle = this.getBundle; obj.spawnToBundle(bundle, extraArgs, this); nodeMap.addToBundle(bundle, -1); bundle.schedSend(server); } } send { | extraArgs, index, freeLast = true | var bundle, obj; if(objects.isEmpty) { ^this }; if(index.isNil) { bundle = this.getBundle; if(freeLast) { this.stopAllToBundle(bundle) }; this.sendAllToBundle(bundle, extraArgs); bundle.schedSend(server); } { obj = objects.at(index); if(obj.notNil) { bundle = this.getBundle; if(freeLast) { obj.stopToBundle(bundle) }; this.sendObjectToBundle(bundle, obj, extraArgs, index); bundle.schedSend(server); } } } sendAll { | extraArgs, freeLast = true | this.send(extraArgs, nil, freeLast); } sendEach { | extraArgs, freeLast = true | var bundle; bundle = this.getBundle; if(freeLast, { this.stopAllToBundle(bundle) }); this.sendEachToBundle(bundle, extraArgs); bundle.schedSend(server); } quantize { | ... proxies | var quant = this.quant ? 1.0; ([this]++proxies).do { |x| x.quant = quant; x.send; } } wakeUp { // do not touch internal state if already playing if(this.isPlaying.not) { this.deepWakeUp } } deepWakeUp { var bundle = MixedBundle.new; this.wakeUpToBundle(bundle); bundle.schedSend(server, clock ? TempoClock.default, quant) } // gui support typeStr { if(this.rate === 'audio') { ^"ar" + this.numChannels }; if(this.rate === 'control') { ^"kr" + this.numChannels }; ^"ir"; } edit { | nSliders, parent, bounds | ^NdefGui(this, nSliders ? this.getKeysValues.size.max(5), parent, bounds); } // interproxy structure and reading other busses orderNodes { | ... proxies | var msg = this.moveBeforeMsg(*proxies); msg !? { server.sendBundle(nil, msg) } } getFamily { | set, alreadyAsked | var parents; parents = IdentitySet.new; alreadyAsked = alreadyAsked ?? { IdentitySet.new }; if(alreadyAsked.includes(this).not) { alreadyAsked.add(this); objects.do { arg obj; parents.addAll(obj.parents) }; parents.addAll(nodeMap.parents); parents.do { arg proxy; proxy.getFamily(parents, alreadyAsked) }; set.add(this); set.addAll(parents); }; ^set } getStructure { | alreadyAsked | var parents, substructure; parents = List.new; alreadyAsked = alreadyAsked ?? { IdentitySet.new }; if(alreadyAsked.includes(this).not) { alreadyAsked.add(this); objects.do { arg obj; parents.addAll(obj.parents) }; parents.addAll(nodeMap.parents); substructure = parents.collect { arg proxy; proxy.getStructure(alreadyAsked) }; ^[this, substructure.flatten(1)]; }; ^nil } moveBeforeMsg { | ... proxies | var list; ([this] ++ proxies).do { |el| if(el.isPlaying) { list = list.add(el.group); if(el.monitor.isPlaying) { list = list.add(el.monitor.group) // debatable. maybe check whether special } } }; ^list !? { Node.orderNodesMsg(list) } } // node map settings internalKeys { ^#[\out, \i_out, \gate, \fadeTime]; } // return names in the order they have in .objects controlNames { | except, addNodeMap = true | var all = Array.new; // Set doesn't work, because equality undefined for ControlName except = except ? this.internalKeys; objects.do { |el| el.controlNames.do { |item| if(except.includes(item.name).not and: { all.every { |cn| cn.name !== item.name } }) { all = all.add(item); } }; }; ^if (addNodeMap.not or: nodeMap.isNil) { all } { this.addNodeMapControlNames(all, except) }; } // if a name is set in nodemap, overwrite the values in objCtlNames; // if a key is set in the nodemap, but is not used in the objects yet, add at the end. addNodeMapControlNames { |objCtlNames, except = #[]| nodeMap.controlNames .reject { |ctlname| except.includes(ctlname.name) } .do { |mapCtl| var index = objCtlNames.detectIndex { |objCtl| objCtl.name == mapCtl.name }; if (index.notNil) { objCtlNames.put(index, mapCtl) } { objCtlNames = objCtlNames.add(mapCtl) } }; ^objCtlNames } resetNodeMap { this.nodeMap = ProxyNodeMap.new; } cleanNodeMap { var nodeMapSettingKeys, nodeMapMappingKeys, keysToUnset, keysToUnmap, currentKeys; if (nodeMap.isNil) { ^this }; nodeMapSettingKeys = difference(nodeMap.settingKeys ? [], this.internalKeys); nodeMapMappingKeys = difference(nodeMap.mappingKeys ? [], this.internalKeys); currentKeys = this.controlNames(addNodeMap: false).collect(_.name); keysToUnset = difference(nodeMapSettingKeys, currentKeys); keysToUnmap = difference(nodeMapMappingKeys, currentKeys); keysToUnset.do(this.unset(_)); keysToUnmap.do(this.unmap(_)); } controlKeys { | except, noInternalKeys = true | var list = Array.new; if (noInternalKeys) { except = except ++ this.internalKeys; }; this.controlNames.do { |el, i| if(except.includes(el.name).not) { list = list.add(el.name) } } ^list } getKeysValues { | keys, except, withDefaults = true, noInternalKeys = true | var pairs, result = [], myKeys, defaults, mapSettings; if (noInternalKeys) { except = except ++ this.internalKeys; }; pairs = this.controlKeysValues(keys, except).clump(2); #myKeys, defaults = pairs.flop; mapSettings = nodeMap.settings; myKeys.collect { |key, i| var val, doAdd; val = mapSettings[key]; doAdd = withDefaults or: val.notNil; if (doAdd) { result = result.add([ key, (val ? defaults[i]).value ]); }; } ^result } // controlPairs, gets default values controlKeysValues { | keys, except | var list, fullList; except = except ? this.internalKeys; fullList = this.controlNames(except); if(keys.isNil or: { keys.isEmpty }) { list = Array(fullList.size * 2); fullList.do { |cn| list.add(cn.name).add(cn.defaultValue) } } { list = Array(keys.size * 2); keys.do { |key| var val = fullList.detect { |cn| cn.name == key }; val = if(val.isNil) { 0 } { val.defaultValue }; list.add(key).add(val) } } ^list; } // derive names and default args from synthDefs supplementNodeMap { | keys, replaceOldKeys=false | this.controlNames.do { |el| var key = el.name; if ( ( replaceOldKeys or: { nodeMap.at(key).isNil } ) and: { keys.isNil or: { keys.includes(key) } } ) { nodeMap.set(key, el.defaultValue) } } } // bundling messages getBundle { var bundle; bundle = MixedBundle.new; this.prepareToBundle(nil, bundle); ^bundle } prepareToBundle { | argGroup, bundle, addAction = \addToTail | if(this.isPlaying.not) { group = Group.basicNew(server, this.defaultGroupID); NodeWatcher.register(group); group.isPlaying = server.serverRunning; if(argGroup.isNil and: { parentGroup.isPlaying }) { argGroup = parentGroup }; bundle.addPrepare(group.newMsg(argGroup ?? { server.asGroup }, addAction)); } } // bundle: apply the node map settings to the entire group sendAllToBundle { | bundle, extraArgs | objects.do { arg item; item.playToBundle(bundle, extraArgs.value, this); }; if(objects.notEmpty) { nodeMap.addToBundle(bundle, group) }; } // bundle: apply the node map settings to each synth separately sendEachToBundle { | bundle, extraArgs | objects.do { arg item; this.sendObjectToBundle(bundle, item, extraArgs.value) } } // bundle: send single object sendObjectToBundle { | bundle, object, extraArgs, index | var synthID, target, nodes; synthID = object.playToBundle(bundle, extraArgs.value, this); if(synthID.notNil) { if(index.notNil and: { objects.size > 1 }) { // if nil, all are sent anyway // make list of nodeIDs following the index nodes = Array(4); objects.doRange({ arg obj; var id = obj.nodeID; if(id.notNil and: { id != synthID }) { nodes = nodes ++ id ++ synthID }; }, index + 1); if(nodes.size > 0) { bundle.add(["/n_before"] ++ nodes.reverse) }; }; nodeMap.addToBundle(bundle, synthID) } } // bundle: remove single object removeToBundle { | bundle, index, fadeTime | var obj, dt, playing; playing = this.isPlaying; obj = objects.removeAt(index); if(obj.notNil) { dt = fadeTime ? this.fadeTime; if(playing) { obj.stopToBundle(bundle, dt) }; obj.freeToBundle(bundle, dt); } } // bundle: remove all objects removeAllToBundle { | bundle, fadeTime | var dt, playing; dt = fadeTime ? this.fadeTime; playing = this.isPlaying; objects.do { arg obj; if(playing) { obj.stopToBundle(bundle, dt) }; obj.freeToBundle(bundle, dt); }; objects.makeEmpty; } // bundle: stop single process stopAllToBundle { | bundle, fadeTime | var obj, dt; dt = fadeTime ? this.fadeTime; if(this.isPlaying) { objects.do { |obj| obj.stopToBundle(bundle, dt) } } } loadToBundle { | bundle | this.reallocBusIfNeeded; objects.do { arg item, i; item.build(this, i); item.loadToBundle(bundle, server); }; loaded = true; } unsetToBundle { | bundle, keys | var pairs = this.controlKeysValues(keys); if(this.isPlaying) { if(pairs.notEmpty) { bundle.add([15, group.nodeID] ++ pairs); }; }; nodeMap.unset(*pairs[0,2..]); } wakeUpToBundle { | bundle, checkedAlready | if(checkedAlready.isNil) { checkedAlready = IdentitySet.new }; if(checkedAlready.includes(this).not) { checkedAlready.add(this); this.wakeUpParentsToBundle(bundle, checkedAlready); if(loaded.not) { this.loadToBundle(bundle) }; if(awake and: { this.isPlaying.not }) { this.prepareToBundle(nil, bundle, \addToHead); this.sendAllToBundle(bundle); }; }; } wakeUpParentsToBundle { | bundle, checkedAlready | nodeMap.wakeUpParentsToBundle(bundle, checkedAlready); objects.do { arg item; item.wakeUpParentsToBundle(bundle, checkedAlready) }; } // allocation defineBus { | rate = \audio, numChannels | super.defineBus(rate, numChannels); this.linkNodeMap; } reallocBusIfNeeded { // bus is reallocated only if the server was not booted on creation. if(busLoaded.not and: { bus.notNil }) { bus.realloc; this.linkNodeMap } } // network support shouldAddObject { | obj | ^obj.readyForPlay } // shared node proxy overrides this defaultGroupID { ^server.nextNodeID } // private implementation linkNodeMap { var index; index = this.index; if(index.notNil) { nodeMap.set(\out, index, \i_out, index) }; nodeMap.proxy = this; } generateUniqueName { // if named, give us the name so we see it // in synthdef names of the server's nodes. var key = this.key ?? this.identityHash.abs; ^server.clientID.asString ++ key ++ "_"; } prepareOutput { var parentPlaying; parentPlaying = this.addToChild; if(parentPlaying) { this.deepWakeUp }; } addToChild { var child; child = buildProxyControl; if(child.notNil) { child.addParent(this) }; ^child.isPlaying; } // renames synthdef so one can use it in patterns nameDef { |name, index = 0| var func = objects[index].synthDef.func; name = name ?? { "New SynthDef name: ".post; (this.key ++ "_" ++ index).asSymbol.postcs; }; ^SynthDef(name, func); } } Ndef : NodeProxy { classvar <>defaultServer, <>all; var <>key; *initClass { all = () } *new { | key, object | // key may be simply a symbol, or an association of a symbol and a server name var res, server, dict; if(key.isKindOf(Association)) { server = Server.named.at(key.value); if(server.isNil) { Error("Ndef(%): no server found with this name.".format(key)).throw }; key = key.key; } { server = Server.default; }; dict = this.dictFor(server); res = dict.envir.at(key); if(res.isNil) { res = super.new(server).key_(key); dict.envir.put(key, res) }; object !? { res.source = object }; ^res; } *ar { | key, numChannels, offset = 0 | ^this.new(key).ar(numChannels, offset) } *kr { | key, numChannels, offset = 0 | ^this.new(key).kr(numChannels, offset) } *clear { | fadeTime | all.do(_.clear(fadeTime)); all.clear; } *dictFor { | server | var dict = all.at(server.name); if(dict.isNil) { dict = ProxySpace.new(server); // use a proxyspace for ease of access. all.put(server.name, dict); dict.registerServer; }; ^dict } proxyspace { ^this.class.dictFor(this.server) } storeOn { | stream | this.printOn(stream); } printOn { | stream | var serverString = if (server == Server.default) { "" } { " ->" + server.name.asCompileString; }; stream << this.class.name << "(" <<< this.key << serverString << ")" } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/InBus.sc0000664000000000000000000002034612245365552026340 0ustar rootrootInBus { *ar { | bus, numChannels = 2, offset = 0 | ^this.getOutput(bus.asBus, 'audio', numChannels, offset); } *kr { | bus, numChannels=1, offset = 0 | ^this.getOutput(bus.asBus, 'control', numChannels, offset); } *getOutput { | bus, argRate, numChannels, offset = 0 | var out, index; var rate = bus.rate; var startIndex = bus.index + offset; var n = bus.numChannels; if(n >= numChannels) { index = startIndex.min(n + bus.index); } { index = Array.fill(numChannels, { arg i; startIndex + (i % n) }); numChannels = 1; }; out = if(offset.isInteger) { if(rate === 'audio') { InFeedback.ar(index, numChannels) } { In.kr(index, numChannels) } } { if(rate === 'audio') { XInFeedback.ar(index, numChannels) } { XIn.kr(index, numChannels) } }; ^if(argRate === rate) { out } { // if not the same rate, convert rates if(argRate === 'audio') { K2A.ar(out) } { A2K.kr(out) } }; } } XIn { *ar { | which, n | ^XFade2.ar( // use equal power crossfading for audio rate In.ar(which.round(2), n), In.ar(which.trunc(2) + 1, n), (which * 2 - 1).fold2(1) ) } *kr { | which, n | ^LinXFade2.kr( // use linear crossfading for control rate In.kr(which.round(2), n), In.kr(which.trunc(2) + 1, n), (which * 2 - 1).fold2(1) ) } } XInFeedback { *ar { | which, n | ^XFade2.ar( InFeedback.ar(which.round(2), n), InFeedback.ar(which.trunc(2) + 1, n), (which * 2 - 1).fold2(1) ); } } // listens on a fixed index (or several) // plays out to various other indices. Monitor { classvar <>warnPlayN = true; var fadeTime = 0.02; var key, <>value, <>busNumChannels, <>isMultiChannel=false, <>isMapped=false, <>mappedRate; *new { arg key, value, busNumChannels; ^super.newCopyArgs(key, value, busNumChannels) } map { arg index; value = index; isMultiChannel = false; isMapped = true; busNumChannels = 1; } mapn { arg index, numChannels; value = index; busNumChannels = numChannels; isMultiChannel = true; isMapped = true; } mapa { arg index; this.map(index); mappedRate = \audio; } mapan { arg index, numChannels; this.map(index, numChannels); mappedRate = \audio; } set { arg val; value = val; isMapped = false; isMultiChannel = val.isSequenceableCollection; } getValue { // unmapped, single channel only ^if(this.isMapped.not and: { this.isMultiChannel.not }) { value } { nil } } addToEvent { arg event; var mapPrefix; if(isMapped) { mapPrefix = if(mappedRate === \audio) { "a" } { "c" }; event.put(key, [{ |i| mapPrefix ++ (i + this.index) }.dup(busNumChannels)]) } { if(isMultiChannel) { event.put(key, [value]) } { event.put(key, value) } } } updateNodeMap { arg nodeMap; if(isMapped) { if(this.isNeutral) { nodeMap.upToDate = false; ^this }; // ignore setting this.updateBusNumChannels; if(isMultiChannel) { if(mappedRate === \audio) { nodeMap.mapanArgs = nodeMap.mapanArgs.addAll([key,this.index,busNumChannels]) } { nodeMap.mapnArgs = nodeMap.mapnArgs.addAll([key, this.index, busNumChannels]) } }{ if(mappedRate === \audio) { nodeMap.mapaArgs = nodeMap.mapaArgs.addAll([key, this.index]); } { nodeMap.mapArgs = nodeMap.mapArgs.addAll([key, this.index]); } } } { if(value.notNil) { if(isMultiChannel) { nodeMap.setnArgs = nodeMap.setnArgs.addAll([key, value.size]++value) } { nodeMap.setArgs = nodeMap.setArgs.addAll([key, value]) } }; } } copy { ^this.class.prNew(key, value, busNumChannels, isMultiChannel, isMapped, mappedRate) } asControlName { ^ControlName(key, nil, mappedRate, value) } isEmpty { ^value.isNil } index { ^value } isNeutral { ^false } updateBusNumChannels {} storeArgs { ^[key, value, busNumChannels] } printOn { arg stream; stream << this.storeArgs } *prNew { arg key, value, busNumChannels, isMultiChannel=false, isMapped=false, mappedRate; ^super.newCopyArgs(key, value, busNumChannels, isMultiChannel, isMapped, mappedRate) } } ProxyNodeMapSetting : NodeMapSetting { var <>rate; // rate is the synthDef "rate" arg, value is a proxy ! index { ^value.index } isEmpty { ^value.isNil and: { rate.isNil } } map { arg proxy; value = proxy; isMapped = true; // stays neutral if both mappedRate, busNumChannels are nil if(proxy.isNeutral) { proxy.initBus(mappedRate, busNumChannels) }; // could add a test busNumChannels = proxy.numChannels; busNumChannels !? { isMultiChannel = busNumChannels > 1 }; mappedRate = proxy.rate; // here we determine the rate simply from the input proxy } isNeutral { ^value.isNeutral } storeArgs { ^[value, busNumChannels, rate] } updateBusNumChannels { if(isMultiChannel and: { busNumChannels.isNil }) { busNumChannels = value.numChannels; }; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/operators.sc0000664000000000000000000000522212014636263027324 0ustar rootrootAbstractOpPlug : AbstractFunction { composeUnaryOp { arg aSelector; ^UnaryOpPlug.new(aSelector, this) } composeBinaryOp { arg aSelector, something; ^BinaryOpPlug.new(aSelector, this, something) } reverseComposeBinaryOp { arg aSelector, something; ^BinaryOpPlug.new(aSelector, something, this) } composeNAryOp { arg aSelector, anArgList; ^{ this.value(anArgList).performList(aSelector, anArgList) } } writeInputSpec { Error("use .ar or .kr to use within a synth.").throw; } } UnaryOpPlug : AbstractOpPlug { var >operator, >a; *new { arg operator, a; ^super.newCopyArgs(operator, a) } isNeutral { ^a.isNeutral } rate { ^a.rate } numChannels { arg max; var n, res; max = max ? 0; n = a.numChannels(max); ^if(n.isNil, { nil }, { max(n, max) }); } value { arg proxy; var rate, numChannels; rate = this.rate; if(rate === 'stream') { rate = nil }; // cx defines rate of func as \stream numChannels = this.numChannels; if(rate.notNil and: { numChannels.notNil } and: { proxy.notNil }, { proxy.initBus(rate, numChannels) }); a.initBus(rate, numChannels); ^a.value(proxy).perform(operator) } initBus { arg rate, numChannels; ^a.initBus(rate, numChannels) } wakeUp { a.wakeUp; } prepareForProxySynthDef { arg proxy; ^{ this.value(proxy) } } asControlInput { "UnaryOpPlug: Cannot calculate this value. Use direct mapping only.".warn; ^this } } BinaryOpPlug : AbstractOpPlug { var >operator, <>a, <>b; *new { arg operator, a, b; ^super.newCopyArgs(operator, a, b) } value { arg proxy; var vala, valb, rate, numChannels; rate = this.rate; if(rate === 'stream') { rate = nil }; // cx defines rate of func as \stream numChannels = this.numChannels; if(rate.notNil and: { numChannels.notNil } and: { proxy.notNil }, { proxy.initBus(rate, numChannels) }); this.initBus(rate, numChannels); vala = a.value(proxy); valb = b.value(proxy); ^vala.perform(operator, valb) } initBus { arg rate, numChannels; ^a.initBus(rate, numChannels) and: { b.initBus(rate, numChannels) }; } isNeutral { ^a.isNeutral && b.isNeutral } rate { if(a.isNeutral) { ^b.rate }; if(b.isNeutral) { ^a.rate }; ^if(a.rate !== \control) { a.rate } { b.rate } // as function.rate is defined as \stream } numChannels { arg max; var n1, n2, res; max = max ? 0; n1 = a.numChannels(max); if(n1.notNil, { max = n1 }); n2 = b.numChannels(max); res = if(n1.isNil, { n2 }, { if(n2.isNil, { n1 }, { max(n1, n2) }) }); ^if(res.notNil, { max(max,res) }, { nil }) } wakeUp { a.wakeUp; b.wakeUp; } asControlInput { "BinaryOpPlug: Cannot calculate this value. Use direct mapping only.".warn; ^this } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/JITLib/ProxySpace/TempoBusClock.sc0000664000000000000000000000066012014636263030021 0ustar rootrootTempoBusClock : TempoClock { var <>control; classvar <>default; *new { arg control, tempo, beats, seconds; ^super.new(tempo, beats, seconds).control_(control) } setTempoAtBeat { arg newTempo, beats; control.set(\fadeTime, 0.0, \tempo, newTempo); ^super.setTempoAtBeat(newTempo, beats) } setTempoAtSec { arg newTempo, secs; control.set(\fadeTime, 0.0, \tempo, newTempo) ^super.setTempoAtSec(newTempo, secs) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Platform/0000775000000000000000000000000012245452763023377 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Platform/Platform.sc0000664000000000000000000001174212245365552025516 0ustar rootrootPlatform { classvar defaultStartupFile; // IDE actions classvar <>makeServerWindowAction, <>makeSynthDescWindowAction, <>openHelpFileAction, <>openHTMLFileAction; var recordingsDir, features; var <>devpath; *initClass { defaultStartupFile = this.userConfigDir +/+ "startup.scd" } initPlatform { classLibraryDir = thisMethod.filenameSymbol.asString.dirname.dirname; helpDir = thisMethod.filenameSymbol.asString.dirname.dirname.dirname ++ "/Help"; features = IdentityDictionary.new; recordingsDir = this.userAppSupportDir +/+ "Recordings"; } name { ^this.subclassResponsibility } recompile { _Recompile } *case { | ... cases | ^thisProcess.platform.name.switch(*cases) } // directories *classLibraryDir { ^thisProcess.platform.classLibraryDir } *helpDir { ^thisProcess.platform.helpDir } userHomeDir { _Platform_userHomeDir } *userHomeDir { ^thisProcess.platform.userHomeDir } systemAppSupportDir { _Platform_systemAppSupportDir } *systemAppSupportDir { ^thisProcess.platform.systemAppSupportDir } userAppSupportDir { _Platform_userAppSupportDir } *userAppSupportDir { ^thisProcess.platform.userAppSupportDir } systemExtensionDir { _Platform_systemExtensionDir } *systemExtensionDir { ^thisProcess.platform.systemExtensionDir } userExtensionDir { _Platform_userExtensionDir } *userExtensionDir { ^thisProcess.platform.userExtensionDir } userConfigDir { _Platform_userConfigDir } *userConfigDir { ^thisProcess.platform.userConfigDir } resourceDir { _Platform_resourceDir } *resourceDir { ^thisProcess.platform.resourceDir } defaultTempDir { ^this.subclassResponsibility() } *defaultTempDir { ^thisProcess.platform.defaultTempDir } // The "ideName" is for ide-dependent compilation. // From SC.app, the value is "scapp" meaning "scide_scapp" folders will be compiled and other "scide_*" ignored. ideName { _Platform_ideName } *ideName { ^thisProcess.platform.ideName } platformDir { ^this.name.asString } *platformDir { ^thisProcess.platform.platformDir } pathSeparator { ^this.subclassResponsibility } *pathSeparator { ^thisProcess.platform.pathSeparator } isPathSeparator { |char| ^this.subclassResponsibility } *isPathSeparator { |char| ^thisProcess.platform.isPathSeparator(char) } clearMetadata { |path| ^this.subclassResponsibility } *clearMetadata { |path| ^thisProcess.platform.clearMetadata(path) } getMouseCoords { ^Platform.getMouseCoords } *getMouseCoords { ^GUI.cursorPosition } // startup/shutdown hooks startup { } shutdown { } startupFiles { ^[defaultStartupFile]; } *deprecatedStartupFiles {|paths| var postWarning = false; paths.do {|path| if (File.exists(path.standardizePath)) { warn("Deprecated startup file found: %\n".format(path)); postWarning = true; } }; if (postWarning) { postln("Please use % as startup file.\nDeprecated startup files will be ignored in future versions.\n".format(defaultStartupFile)); } } loadStartupFiles { this.startupFiles.do{|afile| afile = afile.standardizePath; if(File.exists(afile), {afile.load}) } } // features declareFeature { | aFeature | var str = aFeature.asString; if (str.first.isUpper) { Error("cannot declare class name features").throw; }; if (str.first == $_) { Error("cannot declare primitive name features").throw; }; features.put(aFeature, true); } hasFeature { | symbol | if (features.includesKey(symbol).not) { features.put( symbol, symbol.asSymbol.asClass.notNil or: { symbol.isPrimitive } ) }; ^features.at(symbol) } when { | features, ifFunction, elseFunction | ^features.asArray.inject(true, { |v,x| v and: { this.hasFeature(x) } }).if(ifFunction, elseFunction) } *when { | features, ifFunction, elseFunction | ^thisProcess.platform.when(features, ifFunction, elseFunction) } // Prefer qt but fall back to swing if qt not installed. defaultGUIScheme { if (GUI.get(\qt).notNil) {^\qt} {^\swing} } defaultHIDScheme { ^\none } isSleeping { ^false } // unless defined otherwise // used on systems to deduce a svn directory path, if system wide location is used for installed version. (tested on Linux). devLoc{ |inpath| var outpath; if ( devpath.isNil ){ ^inpath }; outpath = inpath.copyToEnd( inpath.find( "SuperCollider") ); outpath = outpath.replace( "SuperCollider", devpath ); ^outpath; } // hook for clients to write frontend.css writeClientCSS {} killAll { |cmdLineArgs| ^this.subclassResponsibility(\killAll) } } UnixPlatform : Platform { pathSeparator { ^$/ } isPathSeparator { |char| ^(char === this.pathSeparator) } clearMetadata { |path| "rm -f %\.*meta".format(path.splitext[0].escapeChar($ )).systemCmd; } arch { var pipe, arch; pipe = Pipe("arch", "r"); arch = pipe.getLine; pipe.close; ^arch.asSymbol; } killAll { |cmdLineArgs| ("killall -9 " ++ cmdLineArgs).unixCmd; } defaultTempDir { // +/+ "" looks funny but ensures trailing slash ^["/tmp/", this.userAppSupportDir +/+ ""].detect({ |path| File.exists(path); }); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Platform/linux/0000775000000000000000000000000012245452763024536 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Platform/linux/extMain.sc0000664000000000000000000000005512014636263026463 0ustar rootroot+ Main { platformClass { ^LinuxPlatform } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Platform/linux/extMIDIOut.sc0000664000000000000000000000444612014636263027021 0ustar rootroot+ MIDIOut{ // uid is not set by connect, in order to enable several connections to one output. set the uid directly, if you only want to send data to one MIDI destination. connect{ arg device = 0; MIDIOut.connect( port, device ); /* var cuid, dest; if(device.isNumber, { if(device >= 0, { if(MIDIClient.initialized.not,{ MIDIClient.init }); if ( device > MIDIClient.destinations.size, { cuid = device; },{ dest = MIDIClient.destinations.at(device); if(dest.isNil,{ "MIDIClient failed to init".warn; },{ cuid = MIDIClient.destinations.at(device).uid; }) }) },{ cuid = device; }); },{ if(device.isKindOf(MIDIEndPoint), {cuid = device.uid}); // else error }); MIDIOut.connectByUID( port,cuid );*/ } disconnect{ |cuid| var res; MIDIOut.disconnect( port, cuid ); // MIDIOut.disconnectByUID(port,cuid); // reset the uid to 0 // uid = 0; } *connect { arg outport=0, device=0; var uid,dest; if(MIDIClient.initialized.not,{ MIDIClient.init }); if(device.isNumber, { if(device >= 0, { if ( device > MIDIClient.destinations.size, { dest = MIDIClient.destinations.select{ |it| it.uid == device }.first; if(dest.isNil,{ ("MIDI device with uid"+device+ "not found").warn; },{ uid = dest.uid; }) },{ dest = MIDIClient.destinations.at(device); if(dest.isNil,{ "MIDIClient failed to init".warn; },{ uid = MIDIClient.destinations.at(device).uid; }) }) },{ uid = device; }); },{ if(device.isKindOf(MIDIEndPoint), {uid = device.uid}); // else error }); this.connectByUID(outport,uid); } *disconnect { arg outport=0, device=0; var uid,dest; if(device.isKindOf(MIDIEndPoint), {uid = device.uid}); if(device.isNumber, { if(device.isPositive, { if ( device > MIDIClient.destinations.size, { dest = MIDIClient.destinations.select{ |it| it.uid == device }.first; if(dest.isNil,{ ("MIDI device with uid"+device+ "not found").warn; },{ uid = dest.uid; }) },{ uid = MIDIClient.destinations.at(device).uid }); },{ uid = device; }); }); this.disconnectByUID(outport,uid); } *connectByUID {arg outport, uid; _ConnectMIDIOut } *disconnectByUID {arg outport, uid; _DisconnectMIDIOut } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Platform/linux/GLID.sc0000664000000000000000000000666512014636263025612 0ustar rootroot/* Wrapper for LID for General HID support */ GLID{ classvar extraClasses; classvar hidDeviceAction; *initClass{ if ( \LID.asClass.notNil, { Class.initClassTree( Event ); extraClasses = Event.new; Class.initClassTree( GeneralHID ); GeneralHID.add( this ); }); } *id { ^\linux_hid } *put { arg key, object; extraClasses.put( key, object ); } *doesNotUnderstand { arg selector ... args; ^extraClasses.perform( selector, *args ); } // ------------ functions ------------ *buildDeviceList{ deviceList = LID.buildDeviceList.collect{ |dev,i| [ dev[0], this.getInfo( dev ) ] }; ^deviceList; } *postDevices { "HID devices at your disposal:".postln; deviceList.do{ |dev,i| "\t%:\t[%], vendor: %, product: %, locID: [\"%\"], path: [\"%\"]\n".postf( i, dev[1].name, dev[1].vendor, dev[1].product, dev[1].physical, dev[0] ); }; } *postDevicesAndProperties { LID.deviceList.do({arg dev; "".postln; if ( dev[1].isKindOf( LIDInfo ), { [ dev[1].vendor, dev[1].asString, dev[0]].postcs; //[dev[0], dev[1].name, dev[1].product, dev[1].vendor, dev[1].version].postcs; dev[2].keysValuesDo{ |key,slotgroup,i| ("\t"++key+LIDSlot.slotTypeStrings[key]).postln; slotgroup.do{ |slot| "\t\t".post; if ( slot.isKindOf( LIDAbsSlot ),{ [ slot.type, LIDSlot.slotTypeStrings[slot.type], slot.code, slot.info.asString ].postcs; },{ [ slot.type, LIDSlot.slotTypeStrings[slot.type], slot.code ].postcs; }); }; }; },{ dev.postcs; }); }); } *startEventLoop{ |rate| // event loop starts at startup with LID } *stopEventLoop{ // event loop is stopped at shutdown with LID } *eventLoopIsRunning{ ^LID.eventLoopIsRunning; } *debug_{ |onoff| debug = onoff; } *open { arg dev; ^super.new.init( dev ); } *getInfo{ |dev| var info; if ( dev[1].isKindOf( LIDInfo ), { info = GeneralHIDInfo.new( dev[1].name, dev[1].bustype, dev[1].vendor, dev[1].product, dev[1].version, dev[1].physical, dev[1].unique ); },{ info = GeneralHIDInfo.new( "could not open device" ); } ); ^info; } init{ |dev| // var mydev; // mydev = dev[0]; //mydev.postln; if ( dev[1].isKindOf( LIDInfo ) or: dev[1].isKindOf( GeneralHIDInfo ), { device = LID.new( dev[0] ); ^GeneralHIDDevice.new( this ); },{ "not a valid device or could not open device".warn; ^nil; }); } getInfo{ var info; info = GeneralHIDInfo.new( device.info.name, device.info.bustype, device.info.vendor, device.info.product, device.info.version, device.info.physical, device.info.unique ); ^info; } getSlots{ var mySlots = IdentityDictionary.new; var devSlots = device.slots; devSlots.keysValuesDo{ |key,value,i| // (""++i+"key"+key+"value"+value).postcs; mySlots[key] = IdentityDictionary.new; value.keysValuesDo{ |key2,value2,i2| mySlots[key][key2] = GeneralHIDSlot.new( key, key2, device, value2 ); }; }; ^mySlots; } close{ if ( device.notNil, { device.close; }); } isOpen{ if ( device.notNil, { ^device.isOpen; },{ ^false; } ); } info{ if ( device.notNil, { ^device.info; },{ ^nil; } ); } action_{ |act| device.action = act; } grab{ device.grab; } ungrab{ device.ungrab; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/Platform/linux/LID.sc0000664000000000000000000003043312014636263025471 0ustar rootrootLIDInfo { var action; var <>closeAction; classvar all, eventTypes, <>specs, <>deviceRoot = "/dev/input", deviceList; classvar < eventLoopIsRunning = true; *initClass { all = []; specs = IdentityDictionary.new; eventTypes = [ // maps event type (index) to max code value 0x0001, // EV_SYN 0x02ff, // EV_KEY 0x000f, // EV_REL 0x003f, // EV_ABS 0x0007, // EV_MSC 0x000f, // EV_SW (switch) added by nescivi nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 0x000f, // EV_LED 0x0007, // EV_SND nil, 0x0001, // EV_REP 0x007f, // EV_FF 0x0000, // EV_PWR 0x0001, // EV_FF_STATUS nil, nil, nil, nil, nil, nil, nil ]; ShutDown.add { this.closeAll; this.prStopEventLoop; }; this.prStartEventLoop; } *buildDeviceTable{ |name| "WARNING: buildDeviceTable is obsolete, please use buildDeviceList".postln; ^LID.buildDeviceList( name ); } *deviceTable{ "WARNING: deviceTable is obsolete, please use deviceList".postln; ^deviceList; } *deviceList{ ^deviceList; } *buildDeviceList{ |name| var table, devices, d, open; name = name ? "event"; devices = (deviceRoot++"/"++name++"*").pathMatch; deviceList = Array.fill( devices.size, 0 ); devices.do{ |it,i| open = false; if ( all.detect({ | dev | dev.path == it }).notNil, {open = true}); d = try { LID( it ) }; if ( d != nil, { deviceList[i] = [ it, d.info, d.slots ]; if ( open.not, {d.close}); }, { deviceList[i] = [ it, "could not open device" ]; }); }; ^deviceList; } *mouseDeviceSpec { ^( // key b1: #[0x0001, 0x0110], // left button b2: #[0x0001, 0x0111], // middle button b3: #[0x0001, 0x0112], // right button // rel x: #[0x0002, 0x0000], // x axis y: #[0x0002, 0x0001], // y axis s: #[0x0002, 0x0008] // scroll wheel ) } *keyboardDeviceSpec { ^( esc: [1, 1], one: [1, 2], two: [1, 3], three: [1, 4], four: [1, 5], five: [1, 6], six: [1, 7], seven: [1, 8], eight: [1, 9], nine: [1, 10], zero: [1, 11], minus: [1, 12], equal: [1, 13], backspace: [1, 14], tab: [1, 15], q: [1, 16], w: [1, 17], e: [1, 18], r: [1, 19], t: [1, 20], y: [1, 21], u: [1, 22], i: [1, 23], o: [1, 24], p: [1, 25], leftbrace: [1, 26], rightbrace: [1, 27], enter: [1, 28], leftctrl: [1, 29], a: [1, 30], s: [1, 31], d: [1, 32], f: [1, 33], g: [1, 34], h: [1, 35], j: [1, 36], k: [1, 37], l: [1, 38], semicolon: [1, 39], apostrophe: [1, 40], grave: [1, 41], leftshift: [1, 42], backslash: [1, 43], z: [1, 44], x: [1, 45], c: [1, 46], v: [1, 47], b: [1, 48], n: [1, 49], m: [1, 50], comma: [1, 51], dot: [1, 52], slash: [1, 53], rightshift: [1, 54], kpasterisk: [1, 55], leftalt: [1, 56], space: [1, 57], capslock: [1, 58], f1: [1, 59], f2: [1, 60], f3: [1, 61], f4: [1, 62], f5: [1, 63], f6: [1, 64], f7: [1, 65], f8: [1, 66], f9: [1, 67], f10: [1, 68], numlock: [1, 69], scrolllock: [1, 70], kp7: [1, 71], kp8: [1, 72], kp9: [1, 73], kpminus: [1, 74], kp4: [1, 75], kp5: [1, 76], kp6: [1, 77], kpplus: [1, 78], kp1: [1, 79], kp2: [1, 80], kp3: [1, 81], kp0: [1, 82], kpdot: [1, 83], zenkakuhankaku: [1, 85], the102nd: [1, 86], f11: [1, 87], f12: [1, 88], ro: [1, 89], katakana: [1, 90], hiragana: [1, 91], henkan: [1, 92], katakanahiragana: [1, 93], muhenkan: [1, 94], kpjpcomma: [1, 95], kpenter: [1, 96], rightctrl: [1, 97], kpslash: [1, 98], sysrq: [1, 99], rightalt: [1, 100], linefeed: [1, 101], home: [1, 102], up: [1, 103], pageup: [1, 104], left: [1, 105], right: [1, 106], end: [1, 107], down: [1, 108], pagedown: [1, 109], insert: [1, 110], delete: [1, 111], macro: [1, 112], mute: [1, 113], volumedown: [1, 114], volumeup: [1, 115], power: [1, 116], kpequal: [1, 117], kpplusminus: [1, 118], pause: [1, 119], kpcomma: [1, 121], hanguel: [1, 122], hanja: [1, 123], yen: [1, 124], leftmeta: [1, 125], rightmeta: [1, 126], compose: [1, 127], stop: [1, 128], again: [1, 129], props: [1, 130], undo: [1, 131], front: [1, 132], copy: [1, 133], open: [1, 134], paste: [1, 135], find: [1, 136], cut: [1, 137], help: [1, 138], menu: [1, 139], calc: [1, 140], setup: [1, 141], sleep: [1, 142], wakeup: [1, 143], file: [1, 144], sendfile: [1, 145], deletefile: [1, 146], xfer: [1, 147], prog1: [1, 148], prog2: [1, 149], www: [1, 150], msdos: [1, 151], coffee: [1, 152], direction: [1, 153], cyclewindows: [1, 154], mail: [1, 155], bookmarks: [1, 156], computer: [1, 157], back: [1, 158], forward: [1, 159], closecd: [1, 160], ejectcd: [1, 161], ejectclosecd: [1, 162], nextsong: [1, 163], playpause: [1, 164], previoussong: [1, 165], stopcd: [1, 166], record: [1, 167], rewind: [1, 168], phone: [1, 169], iso: [1, 170], config: [1, 171], homepage: [1, 172], refresh: [1, 173], exit: [1, 174], move: [1, 175], edit: [1, 176], scrollup: [1, 177], scrolldown: [1, 178], kpleftparen: [1, 179], kprightparen: [1, 180], new: [1, 181], redo: [1, 182], f13: [1, 183], f14: [1, 184], f15: [1, 185], f16: [1, 186], f17: [1, 187], f18: [1, 188], f19: [1, 189], f20: [1, 190], f21: [1, 191], f22: [1, 192], f23: [1, 193], f24: [1, 194], playcd: [1, 200], pausecd: [1, 201], prog3: [1, 202], prog4: [1, 203], suspend: [1, 205], close: [1, 206], play: [1, 207], fastforward: [1, 208], bassboost: [1, 209], print: [1, 210], hp: [1, 211], camera: [1, 212], sound: [1, 213], question: [1, 214], email: [1, 215], chat: [1, 216], search: [1, 217], connect: [1, 218], finance: [1, 219], sport: [1, 220], shop: [1, 221], alterase: [1, 222], cancel: [1, 223], brightnessdown: [1, 224], brightnessup: [1, 225], media: [1, 226], switchvideomode: [1, 227], kbdillumtoggle: [1, 228], kbdillumdown: [1, 229], kbdillumup: [1, 230], send: [1, 231], reply: [1, 232], forwardmail: [1, 233], save: [1, 234], documents: [1, 235] ) } *all { ^all.copy } *closeAll { all.copy.do({ | dev | dev.close }); } *register { | name, spec | specs[name] = spec; } *new { | path | path = PathName(path); if (path.isRelativePath) { path = (deviceRoot ++ "/" ++ path.fullPath).standardizePath }{ path = path.fullPath; }; ^all.detect({ | dev | dev.path == path }) ?? { super.new.prInit(path) } } isOpen { ^dataPtr.notNil } close { if (this.isOpen) { this.prClose; all.remove(this); }; } dumpCaps { caps.keys.do { | evtType | Post << "0x" << evtType.asHexString << ":\n"; caps[evtType].do { | evtCode | Post << $\t << "0x" << evtCode.asHexString << "\n"; } } } dumpEvents { action = { | evtType, evtCode, value | [evtType.asHexString, evtCode.asHexString, value].postln; } } slot { | evtType, evtCode | ^slots.atFail(evtType, { Error("event type not supported").throw }).atFail(evtCode, { Error("event code not supported").throw }) } at { | controlName | ^this.slot(*spec.atFail(controlName, { Error("invalid control name").throw })) } getAbsInfo { | evtCode | ^this.prGetAbsInfo(evtCode, LIDAbsInfo.new) } getKeyState { | evtCode | ^this.prGetKeyState(evtCode) } getLEDState { | evtCode | ^0 } setLEDState { |evtCode, evtValue | ^this.prSetLedState( evtCode, evtValue ) } setMSCState { |evtCode, evtValue | ^this.prSetMscState( evtCode, evtValue ) } grab { | flag = true | // useful when using mouse or keyboard. be sure to have an // 'exit point', or your desktop will be rendered useless ... if (isGrabbed != flag) { this.prGrab(flag); isGrabbed = flag; }; } ungrab { this.grab(false) } // PRIVATE *prStartEventLoop { _LID_Start ^this.primitiveFailed } *prStopEventLoop { _LID_Stop ^this.primitiveFailed } prInit { | argPath | this.prOpen(argPath); all = all.add(this); closeAction = {}; path = argPath; info = this.prGetInfo(LIDInfo.new); spec = specs.atFail(info.name, { IdentityDictionary.new }); caps = IdentityDictionary.new; slots = IdentityDictionary.new; eventTypes.do { | evtTypeMax, evtType | // nescivi: below was evtType.notNil, but since that is the index, that makes no sense... however evtTypeMax can be nil, and should be skipped if it is... so I'm changing it. if (evtTypeMax.notNil and: { this.prEventTypeSupported(evtType) }) { caps[evtType] = List.new; slots[evtType] = IdentityDictionary.new; for (0, evtTypeMax, { | evtCode | if (this.prEventCodeSupported(evtType, evtCode)) { caps[evtType].add(evtCode); slots[evtType][evtCode] = LIDSlot.new( this, evtType, evtCode ); }; }); caps[evtType].sort; } }; } prOpen { | path | _LID_Open ^this.primitiveFailed } prClose { _LID_Close ^this.primitiveFailed } prEventTypeSupported { | evtType | _LID_EventTypeSupported ^this.primitiveFailed } prEventCodeSupported { | evtType, evtCode | _LID_EventCodeSupported ^this.primitiveFailed } prGetInfo { | info | _LID_GetInfo ^this.primitiveFailed } prGetKeyState { | evtCode | _LID_GetKeyState ^this.primitiveFailed } prGetAbsInfo { | evtCode, absInfo | _LID_GetAbsInfo ^this.primitiveFailed } prGrab { | flag | _LID_Grab ^this.primitiveFailed } prHandleEvent { | evtType, evtCode, evtValue | // not either or for the device action. Do slot actions in any case: slots[evtType][evtCode].value_(evtValue); // event callback if (action.notNil) { action.value(evtType, evtCode, evtValue, slots[evtType][evtCode].value); }; } // this prevents a high cpu cycle when device was detached; added by marije prReadError{ this.close; ("WARNING: Device was removed: " + this.path + this.info).postln; closeAction.value; } prSetLedState { |evtCode, evtValue| // added by Marije Baalman // set LED value _LID_SetLedState ^this.primitiveFailed } prSetMscState { |evtCode, evtValue| // set MSC value _LID_SetMscState ^this.primitiveFailed } } LIDSlot { var action; classvar slotTypeMap, LIDKeySlot, 0x0002 -> LIDRelSlot, 0x0003 -> LIDAbsSlot, 0x0011 -> LIDLedSlot ]); slotTypeStrings = IdentityDictionary.new.addAll([ 0x0000 -> "Syn", 0x0001 -> "Button", 0x0002 -> "Relative", 0x0003 -> "Absolute", 0x0004 -> "MSC", 0x0011 -> "LED", 0x0012 -> "Sound", 0x0014 -> "Rep", 0x0015 -> "Force Feedback", 0x0016 -> "Power", 0x0017 -> "Force Feedback Status" ]); } *new { | device, evtType, evtCode | ^(slotTypeMap[evtType] ? this).newCopyArgs(device, evtType, evtCode).initSpec } initSpec { spec = ControlSpec(0, 1, \lin, 1, 0); } rawValue { ^value } value { ^spec.unmap(value) } value_ { | rawValue | value = rawValue; action.value(this); } next { ^this.value } } LIDKeySlot : LIDSlot { initSpec { super.initSpec; value = device.getKeyState(code); } } LIDRelSlot : LIDSlot { var delta, <>deltaAction; initSpec { } value { ^value } value_ { | dta | delta = dta; value = value + delta; action.value(this); deltaAction.value(this); } delta { ^delta } } LIDLedSlot : LIDSlot { initSpec { } value { ^value } value_ { | v | value = v; device.setLEDState( code, value ); action.value(this); } } LIDAbsSlot : LIDSlot { var docname, <>path, <>goodness, <>context, <>catpath; *new{|docname, path, goodness, context, catpath| ^this.newCopyArgs(docname, path, goodness, context, catpath); } asString { ^ "HelpSearchResult(%, %, %, %)".format(docname, path.basename, goodness, this.contextTrimmed) } // used for sorting: <= { |that| ^ this.goodness >= that.goodness } contextTrimmed { ^context.tr($\n, $ ).tr($\t, $ ) } drawRow { |parent, bounds, action| // SCButton Button.new(parent, bounds.copy.setExtent(bounds.width * 0.3, bounds.height).insetBy(5, 5)) .states_([[docname]]).action_(action ? { path.openHTMLFile }); StaticText.new(parent, bounds.copy.setExtent(bounds.width * 0.7, bounds.height) .moveBy(bounds.width * 0.3, 0) .insetBy(5, 5)) .string_(this.contextTrimmed); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/deprecated/deprecated-3.6-help/Help.sc0000664000000000000000000007133412245365552030473 0ustar rootroot/* Help.tree and Help.gui - a scheme to allow UGens, no wait I mean ALL classes, to be "self-classified" and provide a pleasant-ish browsing interface. No wait, let's put all help docs into the tree too! Yeah! By Dan Stowell, 2007 with lots of input from Scott Wilson and crossplatform tips from nescivi Try it: Help.gui Help.dumpTree see also: Class.browse */ + Help { *initClass { var dir; cachePath = Platform.userAppSupportDir +/+ "SC_helptree.cache.txt"; categoriesSkipThese = [ Filter, BufInfoUGenBase, InfoUGenBase, MulAdd, BinaryOpUGen, UnaryOpUGen, BasicOpUGen, MultiOutUGen, ChaosGen, OutputProxy, AbstractOut, AbstractIn, Object, Class, UGen]; if(\SCImageFilter.asClass.notNil) { categoriesSkipThese = categoriesSkipThese.add(\SCImageFilter.asClass) }; filterUserDirEntries = [ "Extensions", "SuperCollider", "SuperCollider3", "Help", "svn", "share", "classes", "trunk", "Downloads", "Application Support" ]; [Platform.systemExtensionDir, Platform.userExtensionDir].do({ |path| path.split(Platform.pathSeparator).do({ |dirname| if(filterUserDirEntries.detect(_ == dirname).isNil) { filterUserDirEntries = filterUserDirEntries.add(dirname); }; }); }); global = this.new; } *new { |root| if(root.isNil and: { global.notNil }) { ^global } { ^super.new.init(root) } } init { |rootdir| root = rootdir !? { rootdir.absolutePath }; if(root.isNil or: { root.size == 0 }) { this.tree; } { this.tree(false, false, false, root, false); } } tree { |sysext=true, userext=true, allowCached=true, root, writeCache=true| var classes, node, subc, helpRootLen; var helpExtensions = ['html', 'htm', 'scd', 'rtf', 'rtfd']; var helpDirs = Array.new; var thisHelpExt; if(allowCached and: {tree.isNil and: {File.exists(this.cachePath)}}){ "Help tree read from cache in % seconds".format({ this.readTextArchive; // Attempt to read cached version }.bench(false)).postln; }; if(tree.isNil, { "Help files scanned in % seconds".format({ // Building the tree // Help file paths - will be used for categorising, if categories is nil or if not a class's helpfile. // Otherwise they'll be stored for quick access to helpfile. fileslist = IdentityDictionary.new; if(root.isNil) { helpDirs = helpDirs.add( Platform.helpDir ); } { helpDirs = helpDirs.add(root); }; if ( sysext ,{ helpDirs = helpDirs.add( Platform.systemExtensionDir ); }); if ( userext ,{ helpDirs = helpDirs.add( Platform.userExtensionDir ); }); // Now check each class's ".categories" response classes = Object.allSubclasses.difference(categoriesSkipThese).reject({|c| c.asString.beginsWith("Meta_")}); if(root.notNil) { // consider only classes whose main definition is in the root folder classes = classes.select({ |c| c.filenameSymbol.asString.beginsWith(root) }); }; tree = Dictionary.new(8); classes.do({|class| this.addCatsToTree(class, fileslist)}); // Now add the remaining ones to the tree - they're everything except the classes which // have declared their own categorisation(s). helpDirs.do{ |helpDir| this.addDirTree( helpDir,tree ); }; if(writeCache) { { this.writeTextArchive; }.defer(4.312); { var sclang_completion_dict, dictfile; // Also piggyback on the tree struct to write out an auto-completion dictionary: sclang_completion_dict = SortedList.new; this.do{|key, value| if("0123456789".includes(key[0]).not and:{key.includes($ ).not}){ sclang_completion_dict.add(key); } }; dictfile = File(Platform.userAppSupportDir +/+ "sclang_completion_dict", "w"); if(dictfile.isOpen){ sclang_completion_dict.do{|entry| dictfile.write(entry ++ Char.nl)}; dictfile.close; }; }.defer(7.1101); }; }.bench(false)).postln}); ^tree; } findKeysForValue{|val| var func, node, keyPath; keyPath =[]; if( val.beginsWith( "SC://" ), { ^keyPath }); // only file scheme urls in tree if( val.beginsWith( "file:" ), { val = val.copyToEnd( if( val.copyRange( 5, 6 ) == "//", 7, 5 )); }); val = val.replace("%20", " "); func = {|dict, depth = 0| node = dict.findKeyForValue(val); node.isNil.if({ dict.keysValuesDo({|key, item| item.isKindOf(Dictionary).if({ keyPath = keyPath.copyFromStart(depth - 1).add(key); func.value(item, depth + 1) }) }); }, {^keyPath.add(node)}); }; func.value(this.tree); ^[]; } addUserFilter{ |subpath| filterUserDirEntries = filterUserDirEntries.add( subpath ); this.forgetTree; } addDirTree{ |helppath,tree| var helpExtensions = #['html', 'htm', 'scd', 'rtf', 'rtfd']; var subfileslist; var node, subc, helpRootLen, thisHelpExt; subfileslist = IdentityDictionary.new; PathName.new(helppath.standardizePath).helpFilesDo({|pathname| if( pathname.fullPath.contains("ignore")){ "Not ignoring: %".format(pathname.fullPath).postln; }; if( pathname.fullPath.contains("3vs2").not and: { pathname.fullPath.contains("help-scripts").not } , { subfileslist[pathname.fileNameWithoutDoubleExtension.asSymbol] = pathname.fullPath; fileslist[pathname.fileNameWithoutDoubleExtension.asSymbol] = pathname.fullPath; }) }); helpRootLen = (helppath.standardizePath).size + 1; subfileslist.keysValuesDo({ |classsym, path| subc = path[helpRootLen..].split(Platform.pathSeparator); if ( helppath == Platform.helpDir, { subc = subc[0..subc.size-2]; // Ignore "Help" and the filename at the end // subc = path[helpRootLen..].split(Platform.pathSeparator); },{ //helpRootLen = "~".standardizePath; if ( helppath == Platform.systemExtensionDir, { // subc = path[helpRootLen..].split(Platform.pathSeparator); subc = [ "SystemExtensions" ] ++ subc; //subc.postcs; }); if ( helppath == Platform.userExtensionDir, { helpRootLen = "~/".absolutePath.size; // + 1; subc = path[helpRootLen..].split(Platform.pathSeparator); subc = [ "UserExtensions" ] ++ subc; // check for common superfluous names that may confuse the categorisation; filterUserDirEntries.do{ |spath| subc = subc.reject{ |it| it == spath; }; }; // check for double entries (e.g. SwingOSC) subc[..subc.size-2].do{ |it,i| var subset; subset = subc[..i-1]; if ( subset.detect( { |jt| jt == it } ).size > 0, { subc = subc[..i-1] ++ subc[i+1..]; }); }; }); if ( helppath == root, { // exactly the same as the previous if, // but it isn't right to change helpRootLen // check for common superfluous names that may confuse the categorisation; filterUserDirEntries.do{ |spath| subc = subc.reject{ |it| it == spath; }; }; // check for double entries (e.g. SwingOSC) subc[..subc.size-2].do{ |it,i| var subset; subset = subc[..i-1]; if ( subset.detect( { |jt| jt == it } ).size > 0, { subc = subc[..i-1] ++ subc[i+1..]; }); }; }); subc = subc[..subc.size-2]; } ); if(subc.size > 0) { thisHelpExt = helpExtensions.select{ |ext| subc.last.endsWith("."++ext) }; }; if ( thisHelpExt.size > 0 , { subc = subc[..subc.size-2]; }); subc = subc.collect({|i| "[["++i++"]]"}); node = tree; // Crawl up the tree, creating hierarchy as needed subc.do({|catname| if(node[catname].isNil, { node[catname] = Dictionary.new(3); }); node = node[catname]; }); // "node" should now be the tiniest branch node[classsym.asClass ? classsym] = path; }); } rebuildTree { this.forgetTree; if(root.isNil) { this.tree(allowCached:false); } { this.tree(false, false, false, root, false); } } forgetTree { tree = nil; } dumpTree { |node, prefix=""| node = node ?? {this.tree}; node.keysValuesDo({ |key, val| if(val.isKindOf(Dictionary), { (prefix + key).postln; this.dumpTree(val, prefix ++ " "); }, { (prefix + key ++":" + val).postln; }); }); } addCatsToTree { |class, fileslist| var subc, node; if(class.categories.isNil.not, { class.categories.do({|cat| subc = cat.split($>).collect({|i| "[["++i++"]]"}); node = tree; // Crawl up the tree, creating hierarchy as needed subc.do({|catname| if(node[catname].isNil, { node[catname] = Dictionary.new(3); }); node = node[catname]; }); // "node" should now be the tiniest branch node[class] = fileslist[class.asSymbol] ? ""; }); // Class has been added to list so we're OK fileslist.removeAt(class.asSymbol); }); // end if } writeTextArchive{ |path| var fp; if(path.isNil){ path = this.cachePath }; fp = File(path, "w"); this.prRecurseTreeToFile(fp, this.tree); // Must use this.tree - will create if not exists fp.write(fileslist.asTextArchive); fp.close; } prRecurseTreeToFile{ | fp, treeBit, numtabs=0 | fp.write("%%\n".format($\t.dup(numtabs).join, treeBit.size)); treeBit.keysValuesDo{| key, val | fp.write("%%\n".format($\t.dup(numtabs).join, key.asString)); if(val.isKindOf(Dictionary)){ this.prRecurseTreeToFile(fp, val, numtabs + 1) }{ fp.write("%%\n".format($\t.dup(numtabs).join, val.asString)); } }; } readTextArchive{ |path| var fp, filesliststr; if(path.isNil){ path = this.cachePath }; fp = File(path, "r"); try{ tree = this.prRecurseTreeFromFile(fp); }{ "Failure to read tree in Help.treeFromFile(%)".format(path).warn; this.forgetTree; }; try{ filesliststr = fp.readAllString; if(filesliststr.size < 10){ // Old version of cache didn't store it... "Help.tree cache has no fileslisttree. Will regenerate it".warn; this.forgetTree; }{ fileslist = filesliststr.interpret; }; }{ "Failure to read fileslist in Help.treeFromFile(%)".format(path).warn; this.forgetTree; }; fp.close; } prRecurseTreeFromFile{ | fp, numtabs=0 | var line, numentries, dict, key; line = fp.getLine[numtabs..]; numentries = line.asInteger; dict = Dictionary.new(numentries); numentries.do{ line = fp.getLine[numtabs..]; key = line; if(key[0]==$[ and:{ key[1]==$[ }){ // starting with [[ is indicator of being a category dict[key] = this.prRecurseTreeFromFile(fp, numtabs+1); }{ line = fp.getLine[numtabs..]; key = key.asSymbol; key = key.asClass ? key; // Classes become classes, topics stay as symbols dict[key] = line; } }; ^dict } gui { |sysext=true,userext=true, allowCached=true| var classes, win, lists, listviews, numcols=7, selecteditem, node, newlist, curkey; var selectednodes, scrollView, compView, textView, keys; var classButt, browseButt, bwdButt, fwdButt; var isClass, history = [], historyIdx = 0, fBwdFwd, fHistoryDo, fHistoryMove; var screenBounds, bounds, textViewBounds, results, resultsview, statictextloc; var searchField, helpguikeyacts, fSelectTreePath, inPathSelect = false, fUpdateWinTitle, fLoadError; // Call to ensure the tree has been built this.tree( sysext, userext, allowCached ); // Now for a GUI screenBounds = Window.screenBounds; bounds = Rect(128, 264, 1040, 564); bounds = bounds.center_(screenBounds.center); bounds = bounds.sect(screenBounds.insetBy(15)); win = Window.new("Help browser", bounds); // SCWindow // scrollView and compView hold the category-browsing list widgets scrollView = ScrollView.new(win, Rect(5, 0, 425, 529)).hasBorder_(true).resize_(4); compView = CompositeView.new(scrollView, Rect(0, 0, numcols * 200, /*504*/ bounds.height-60)); // textView displays a help file "inline" textViewBounds = Rect(435, 0, /*620*/bounds.width-435, /*554*/ bounds.height-35); textView = TextView.new(win, textViewBounds) .hasVerticalScroller_(true) .hasHorizontalScroller_(false) .autohidesScrollers_(false) .resize_(5) .canFocus_(true); if(GUI.current.id == \swing, { textView.editable_( false ).canFocus_( true ) }); textView.bounds = textView.bounds; // hack to fix origin on first load // hidden at first, this will receive search results when the search field is activated resultsview = ScrollView(win, textViewBounds) .resize_(5) .visible_(false); // updates the history arrow buttons fBwdFwd = { bwdButt.enabled = historyIdx > 0; fwdButt.enabled = historyIdx < (history.size - 1); }; fLoadError = { |error| error.reportError; "\n\nA discrepancy was found in the help tree.".postln; if(allowCached) { "rm \"%\"".format(cachePath).unixCmd; "The help tree cache may be out of sync with the file system. Rebuilding cache. Please reopen the Help GUI when this is finished.".postln; this.rebuildTree; win.close; } { "Please report the above error dump on the sc-users mailing list.".postln; }; }; // cuts the redo history, adds and performs a new text open action fHistoryDo = { arg selector, argum; history = history.copyFromStart( historyIdx ).add([ selector, argum ]); historyIdx = history.size - 1; try({ textView.perform( selector, argum ) }, fLoadError); fBwdFwd.value; }; // moves relatively in the history, and performs text open action fHistoryMove = { arg incr; var entry; historyIdx = historyIdx + incr; entry = history[ historyIdx ]; try({ textView.perform( entry[ 0 ], entry[ 1 ]) }, fLoadError); fBwdFwd.value; }; // keep this check for compatibility with old versions of swingOSC if( textView.respondsTo( \linkAction ), { textView .linkAction_({ arg view, url, descr; var path; if( url.notEmpty, { //fHistoryDo.value( \open, url ); keys = this.findKeysForValue(url); if(keys.size == 0, { ("Invalid hyperlink:" + url + "Please repair this.\nSearching help directories for alternative.").warn; url = Help.findHelpFile(url.basename.splitext.first); url.notNil.if({keys = this.findKeysForValue(url)}); }); if(keys.size > 0, { fSelectTreePath.value(keys.drop(-1), keys.last.asString); }); }, { if( descr.beginsWith( "SC://" ), { fHistoryDo.value( \open, descr ); }); }); }); }); lists = Array.newClear(numcols); lists[0] = tree.keys(Array).collect(_.asString).sort; selectednodes = Array.newClear(numcols); // SCListView listviews = (0..numcols-1).collect({ arg index; var view; view = ListView( compView, Rect( 5 + (index * 200), 4, 190, /* 504 */ bounds.height - 60 )); //view.items = []; // trick me into drawing correctly in scrollview if( view.respondsTo( \allowsDeselection ), { view.allowsDeselection_( true ).value_( nil ); }); view .resize_(4) .action_({ arg lv; var lv2; if( lv.value.notNil, { // We've clicked on a category or on a class if((lv.items.size != 0), { lv2 = if( index < (listviews.size - 1), { listviews[ index + 1 ]}); selecteditem = lists[index][lv.value]; if( lv2.notNil, { // Clear the GUI for the subsequent panels listviews[index+1..].do({ arg lv; lv.items=#[]; if( lv.respondsTo( \allowsDeselection ), { lv.value = nil })}); }); // Get the current node, from the parent node node = try { if(index==0, tree, {selectednodes[index-1]})[selecteditem] }; curkey = selecteditem; selectednodes[index] = node; if(node.isNil, { // We have a "leaf" (class or helpdoc), since no keys found if( (index + 1 < lists.size), { lists[index+1] = #[] }); if(inPathSelect.not, { { // Note: the "isClosed" check is to prevent errors caused by event triggering while user closing window if(textView.isClosed.not){textView.visible = true}; if(resultsview.isClosed.not){resultsview.visible = false}; fHistoryDo.value( \open, fileslist.at( selecteditem.asSymbol ) ? fileslist.at( \Help )); }.defer( 0.001 ); }); isClass = selecteditem.asSymbol.asClass.notNil; // Note: "Help" class is not the class that matches "Help.html", so avoid potential confusion via special case if(classButt.notNil){ classButt.enabled_((selecteditem!="Help") and: {isClass}); }; browseButt.enabled_((selecteditem!="Help") and: {isClass}); // The "selectednodes" entry for the leaf, is the path to the helpfile (or "") selectednodes[index] = try { if(index==0, {tree}, {selectednodes[index-1]}) [curkey.asSymbol.asClass ? curkey.asSymbol]}; fUpdateWinTitle.value; }, { // We have a category on our hands if( lv2.notNil, { lists[ index + 1 ] = node.keys(Array).collect(_.asString).sort({|a,b| // the outcomes: // a and b both start with open-bracket: // test result should be a < b // or one starts with open-bracket and the other doesn't (xor) // test result should be whether it's a that has the bracket if(a[0] == $[ /*]*/ xor: (b[0] == $[ /*]*/)) { a[0] == $[ /*]*/ } { a < b } }); lv2.items = lists[index+1]; }); }); if( (index + 1) < listviews.size, { listviews[index+1].value = if( listviews[index+1].respondsTo( \allowsDeselection ).not, 1 ); listviews[index+1].valueAction_( 0 ); }); selectednodes[index+2 ..] = nil; // Clear out the now-unselected }); }); }); }); listviews[0].items = lists[0]; // Add keyboard navigation between columns listviews.do({ |lv, index| // SCView lv.keyDownAction_({|view,char,modifiers,unicode,keycode| var nowFocused, lv2; nowFocused = lv; switch(unicode, // cursor left 63234, { if(index > 0, { lv2 = listviews[ index - 1 ]; lv2.focus; nowFocused = lv2 }) }, // cursor right 63235, { if( index < (listviews.size - 1) and: { listviews[ index + 1 ].items.notNil }, { lv2 = listviews[ index + 1 ]; try { lv2.value_( if( lv2.respondsTo( \allowsDeselection ).not, - 1 )).valueAction_( 0 ).focus; nowFocused = lv2; } }) }, 13, { // Hit RETURN to open source or helpfile // The class name, or helpfile name we're after if(lv.value.notNil and: {if(index==0, tree, {selectednodes[index-1]})[lists[index][lv.value]].isNil}, { { selecteditem.help }.defer; }); }, //default: { // Returning nil is supposed to be sufficient to trigger the default action, // but on my SC this doesn't happen. view.defaultKeyDownAction(char,modifiers,unicode); }); if(scrollView.visibleOrigin.x > nowFocused.bounds.left or: {scrollView.visibleOrigin.x + scrollView.bounds.width > nowFocused.bounds.left}, { scrollView.visibleOrigin_(Point(nowFocused.bounds.left - 5, 0)); }); }) .mouseDownAction_({|view, x, y, modifiers, buttonNumber, clickCount| { if(lists[index][lv.value][0]==$[, { if(scrollView.visibleOrigin.x != (lv.bounds.left - 5), { { 10.do({|i| { scrollView.visibleOrigin_( Point(((lv.bounds.left - lv.bounds.width)+((10+i)*10)-5), 0)) }.defer; 0.02.wait; }); }.fork; }); }); }.defer(0.01); // defer because .action above needs to register the new index if(clickCount == 2, { if(lv.value.notNil and: { try { if(index==0, tree, {selectednodes[index-1]})[lists[index][lv.value]] }.isNil}, { { selecteditem.help }.defer; }); }); }); }); // Add ability to programmatically select an item in a tree fSelectTreePath = { | catpath, leaf | var foundIndex; Task{ 0.001.wait; inPathSelect = true; catpath.do{ |item, index| foundIndex = listviews[index].items.indexOfEqual(item); if(foundIndex.notNil){ listviews[index].value_(foundIndex).doAction; }{ "Could not select menu list item % in %".format(item, listviews[index].items).postln; }; 0.02.wait; }; inPathSelect = false; foundIndex = listviews[catpath.size].items.indexOfEqual(leaf); if(foundIndex.notNil){ listviews[catpath.size].value_(foundIndex).doAction; // history = history.drop(-1); // historyIdx = history.size - 1; }{ "Could not select menu list item %".format(leaf).postln; }; textView.visible = true; resultsview.visible = false; fUpdateWinTitle.value; win.front; }.play(AppClock); }; fUpdateWinTitle = { win.name_( (["Help browser"] ++ listviews.collect{|lv| lv.value !? {lv.items[lv.value]} }.reject(_.isNil)).join(" > ") ); }; Platform.case(\windows, { // TEMPORARY WORKAROUND: // At present, opening text windows from GUI code can cause crashes on Psycollider // (thread safety issue?). To work around this we just remove those buttons. }, { Button.new( win, Rect( 5, /* 534 */ bounds.height - 30, 110, 20 )) .states_([["Open Help File", Color.black, Color.clear]]) .resize_(7) .action_({{ selecteditem.help }.defer;}); classButt = Button.new( win, Rect( 119, /* 534 */ bounds.height - 30, 110, 20 )) .states_([["Open Class File", Color.black, Color.clear]]) .resize_(7) .action_({ if(selecteditem.asSymbol.asClass.notNil, { {selecteditem.asSymbol.asClass.openCodeFile }.defer; }); }); }); browseButt = Button.new( win, Rect( 233, /* 534 */ bounds.height - 30, 110, 20 )) .states_([["Browse Class", Color.black, Color.clear]]) .resize_(7) .action_({ if(selecteditem.asSymbol.asClass.notNil, { {selecteditem.asSymbol.asClass.browse }.defer; }); }); bwdButt = Button.new( win, Rect( 347, /* 534 */ bounds.height - 30, 30, 20 )) .states_([[ "<" ]]) .resize_(7) .action_({ if( historyIdx > 0, { fHistoryMove.value( -1 ); }); }); fwdButt = Button.new( win, Rect( 380, /* 534 */ bounds.height - 30, 30, 20 )) .states_([[ ">" ]]) .resize_(7) .action_({ if( historyIdx < (history.size - 1), { fHistoryMove.value( 1 ); }); }); fBwdFwd.value; // textfield for searching: statictextloc = Rect(10, 10, textViewBounds.width-20, 200); StaticText.new(win, Rect(435, bounds.height-35, 100 /* bounds.width-435 */, 35)) .align_(\right).resize_(7).string_("Search help files:"); searchField = TextField.new(win, Rect(535, bounds.height-35, bounds.width-535-35, 35).insetBy(8)) .resize_(8).action_({|widget| if(widget.value != ""){ // Let's search! // hide the textView, show the resultsview, do a query textView.visible = false; resultsview.visible = true; resultsview.removeAll; results = this.search(widget.value); // Now add the results! StaticText(resultsview, Rect(0, 0, textViewBounds.width / 2, 30)) .resize_(1) .align_(\right) .string_("% results found for query '%'.".format(results.size, widget.value)); Button(resultsview, Rect(textViewBounds.width / 2, 0, 100, 30).insetBy(5)) .resize_(1) .states_([["Clear"]]) .action_({ searchField.valueAction_("") }) .focus(); results.do{|res, index| res.drawRow(resultsview, Rect(0, index*30 + 30, textViewBounds.width, 30), // Add an action that uses the gui itself: { fSelectTreePath.(res.catpath, res.docname) } ); }; }{ // Empty query string, go back to textView textView.visible = true; resultsview.visible = false; }; }); // Handle some "global" (for the Help gui) key actions helpguikeyacts = {|view, char, modifiers, unicode, keycode| if((modifiers & (262144 | 1048576)) != 0){ // cmd or control key is pressed unicode.switch( 6, { // f for find searchField.focus; }, 8, // h for home { { listviews[0].valueAction_(listviews[0].items.find(["Help"])); scrollView.visibleOrigin_(0@0); }.defer(0.001) } ); }; }; win.view.addAction(helpguikeyacts, \keyUpAction); win.onClose_{ // This is done to prevent Cmd+W winclose from trying to do things in vanishing textviews! fHistoryDo = {}; }; win.front; listviews[0].focus; if(listviews[0].items.detect({ |item| item == "Help" }).notNil) { fSelectTreePath.([], "Help"); // Select the "Help" entry in the root selecteditem = "Help"; } { selecteditem = listviews[0].items.first; fSelectTreePath.([], selecteditem); } } // end gui all { // ^this.new("Help/").dumpToDoc("all-helpfiles"); var doc; var helpExtensions = ['html', 'htm', 'scd', 'rtf', 'rtfd']; var str = CollStream.new; doc = Document.new("all-helpfiles"); [ Platform.helpDir, Platform.systemExtensionDir, Platform.userExtensionDir ].do{ |it| PathName.new( it ).foldersWithoutSVN.do{ |folderPn| str << folderPn.fullPath << Char.nl; folderPn.helpFilesDo { |filePn| str << Char.tab << filePn.fileNameWithoutExtension << Char.nl; }; } }; doc.string = str.collection; } // Iterates the tree, finding the help-doc paths and calling action.value(docname, path) do { |action| this.pr_do(action, this.tree, []); } pr_do { |action, curdict, catpath| curdict.keysValuesDo{|key, val| if(val.class == Dictionary){ this.pr_do(action, val, catpath ++ [key]) // recurse }{ action.value(key.asString, val, catpath) } } } // Returns an array of hits as HelpSearchResult instances search { |query, ignoreCase=true| var results = List.new, file, ext, docstr, pos; this.do{ |docname, path, catpath| if(path != ""){ if(docname.find(query, ignoreCase).notNil){ results.add(HelpSearchResult(docname, path, 100 / (docname.size - query.size + 1), "", catpath.deepCopy)); }{ ext = path.splitext[1]; // OK, let's open the document, see if it contains the string... HEAVY! file = File(path, "r"); if(file.isOpen){ docstr = ext.switch( "html", {file.readAllStringHTML}, "htm", {file.readAllStringHTML}, "rtf", {file.readAllStringRTF}, {file.readAllString} ); file.close; pos = docstr.findAll(query, ignoreCase); if(pos.notNil){ results.add(HelpSearchResult(docname, path, pos.size, docstr[pos[0] .. pos[0]+50], catpath.deepCopy)); } }{ "Help.search will rebuild help cache, since an expected file was not found: %".format(path).postln; // EXPERIMENTAL: // File:isOpen failure means that the help tree cache is out of date. // So let's explicitly destroy and recreate it. // There may be a danger of infinite loops if some weird filesystem stuff is happening...? this.forgetTree; this.tree(allowCached: false); ^this.search(query, ignoreCase); } } }{ //"empty path: %".format(docname).postln; } }; results = results.sort; ^results } // This iterates the Help.tree to find the file. Can be used instead of platform-specific approaches findHelpFile { |str| str = str.asString; this.do { |key, path| if(key == str and: { path.size > 0 }) { ^path } }; ^nil } // does the same as findHelpFile, but replaces the string with "Help" if the string is empty. This makes it possible in sced to open the main help if nothing is selected. findHelpFileOrElse { |str| str = str.asString; if ( str.isEmpty ) { str = "Help" }; ^Help.findHelpFile( str ); } // class method interface *tree { |sysext = true, userext = true, allowCached = true| ^global.tree(sysext, userext, allowCached) } *addUserFilter { |subpath| ^global.addUserFilter(subpath) } *addDirTree { |helppath, tree| ^global.addDirTree(helppath, tree) } *rebuildTree { ^global.rebuildTree } *forgetTree { ^global.forgetTree } *dumpTree { |node, prefix = ""| ^global.dumpTree(node, prefix) } *addCatsToTree { |class, fileslist| ^global.addCatsToTree(class, fileslist) } *all { ^global.all } *do { |action| ^global.do(action) } *pr_do { |action, curdict| ^global.pr_do(action, curdict) } *searchGUI { ^global.searchGUI } *search { |query, ignoreCase| ^global.search(query, ignoreCase) } *findHelpFile { |str| ^global.findHelpFile(str) } *makeHelp { |undocumentedObject, path| ^global.makeHelp(undocumentedObject, path) } *makeAutoHelp { |andocumentedClass, path| ^global.makeAutoHelp(andocumentedClass, path) } // instance-based getters filterUserDirEntries { ^filterUserDirEntries } cachePath { ^cachePath } } // End class + Object { // Classes may override this to specify where they fit in a thematic classification, // if they want to classify differently than the help doc location would indicate. // // Multiple categorisations are allowed (hence the array). // // Extension libs (which won't automatically get allocated, since their help won't be in the main // help tree) SHOULD override this to specify where best to fit. // (Note: *Please* use the "Libraries" and/or "UGens" main classifications, those are the best // places for users to find extensions docs. Don't add new "root" help categories, that's // not good for GUI usability.) // // Each categorisation should be a string using ">" marks to separate categories from subcategories. // For examples see (e.g.) SinOsc, Gendy1, LPF, Integrator, EnvGen //*categories { ^ #["Unclassified"] } *categories { ^ nil } } + Pattern { *categories { ^ #["Streams-Patterns-Events>Patterns"] } } // This allows it to be called from sclang menu item + Process { helpGui { Help.gui } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/deprecated/deprecated-3.6-categories/0000775000000000000000000000000012245452763030442 5ustar rootroot././@LongLink0000000000000000000000000000016100000000000011563 Lustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/deprecated/deprecated-3.6-categories/PatternCategories.scSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/deprecated/deprecated-3.6-categories/PatternC0000664000000000000000000001777012245365552032120 0ustar rootroot+ FilterPattern { *categories{ ^ #["Streams-Patterns-Events>Patterns>Filter"] }} + ListPattern { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Pclutch { *categories{ ^ #["Streams-Patterns-Events>Patterns>Repetition"] }} + Pn { *categories{ ^ #["Streams-Patterns-Events>Patterns>Repetition"] }} + Pgate { *categories{ ^ #["Streams-Patterns-Events>Patterns>Repetition"] }} + Pstutter { *categories{ ^ #["Streams-Patterns-Events>Patterns>Repetition"] }} + PdurStutter { *categories{ ^ #["Streams-Patterns-Events>Patterns>Repetition"] }} + Pfin { *categories{ ^ #["Streams-Patterns-Events>Patterns>Repetition"] }} + Pconst { *categories{ ^ #["Streams-Patterns-Events>Patterns>Repetition"] }} + Pfindur { *categories{ ^ #["Streams-Patterns-Events>Patterns>Repetition"] }} + Psync { *categories{ ^ #["Streams-Patterns-Events>Patterns>Repetition"] }} + Ptime { *categories{ ^ #["Streams-Patterns-Events>Patterns>Time"] }} + Pstep { *categories{ ^ #["Streams-Patterns-Events>Patterns>Time"] }} + Pstep2add { *categories{ ^ #["Streams-Patterns-Events>Patterns>Time"] }} + Pstep3add { *categories{ ^ #["Streams-Patterns-Events>Patterns>Time"] }} + PstepNadd { *categories{ ^ #["Streams-Patterns-Events>Patterns>Time"] }} + PstepNfunc { *categories{ ^ #["Streams-Patterns-Events>Patterns>Time"] }} + Pseg { *categories{ ^ #["Streams-Patterns-Events>Patterns>Time"] }} + Pbindf { *categories{ ^ #["Streams-Patterns-Events>Patterns>Composition"] }} + Pchain { *categories{ ^ #["Streams-Patterns-Events>Patterns>Composition"] }} + Ppar { *categories{ ^ #["Streams-Patterns-Events>Patterns>Parallel"] }} + Ptpar { *categories{ ^ #["Streams-Patterns-Events>Patterns>Parallel"] }} + Pgpar { *categories{ ^ #["Streams-Patterns-Events>Patterns>Parallel"] }} + Pgtpar { *categories{ ^ #["Streams-Patterns-Events>Patterns>Parallel"] }} + Spawner { *categories{ ^ #["Streams-Patterns-Events>Patterns>Parallel"] }} + Pspawner { *categories{ ^ #["Streams-Patterns-Events>Patterns>Parallel"] }} + Pspawn { *categories{ ^ #["Streams-Patterns-Events>Patterns>Parallel"] }} + Pif { *categories{ ^ #["Streams-Patterns-Events>Patterns>Language Control"] }} + Pseed { *categories{ ^ #["Streams-Patterns-Events>Patterns>Language Control"] }} + Pprotect { *categories{ ^ #["Streams-Patterns-Events>Patterns>Language Control"] }} + Ptrace { *categories{ ^ #["Streams-Patterns-Events>Patterns>Language Control"] }} + Pwhile { *categories{ ^ #["Streams-Patterns-Events>Patterns>Language Control"] }} + Pbus { *categories{ ^ #["Streams-Patterns-Events>Patterns>Server Control"] }} + Pgroup { *categories{ ^ #["Streams-Patterns-Events>Patterns>Server Control"] }} + Pfx { *categories{ ^ #["Streams-Patterns-Events>Patterns>Server Control"] }} + Pfxb { *categories{ ^ #["Streams-Patterns-Events>Patterns>Server Control"] }} + Pproto { *categories{ ^ #["Streams-Patterns-Events>Patterns>Server Control"] }} + Pkey { *categories{ ^ #["Streams-Patterns-Events>Patterns>Data Sharing"] }} + Penvir { *categories{ ^ #["Streams-Patterns-Events>Patterns>Data Sharing"] }} + Pfset { *categories{ ^ #["Streams-Patterns-Events>Patterns>Data Sharing"] }} + Plambda { *categories{ ^ #["Streams-Patterns-Events>Patterns>Data Sharing"] }} + Pset { *categories{ ^ #["Streams-Patterns-Events>Patterns>Filter"] }} + Psetp { *categories{ ^ #["Streams-Patterns-Events>Patterns>Filter"] }} + Ppatmod { *categories{ ^ #["Streams-Patterns-Events>Patterns>Filter"] }} + Pcollect { *categories{ ^ #["Streams-Patterns-Events>Patterns>Filter"] }} + Padd { *categories{ ^ #["Streams-Patterns-Events>Patterns>Math"] }} + Paddp { *categories{ ^ #["Streams-Patterns-Events>Patterns>Math"] }} + Paddpre { *categories{ ^ #["Streams-Patterns-Events>Patterns>Math"] }} + Punop { *categories{ ^ #["Streams-Patterns-Events>Patterns>Math"] }} + Pbinop { *categories{ ^ #["Streams-Patterns-Events>Patterns>Math"] }} + Pnaryop { *categories{ ^ #["Streams-Patterns-Events>Patterns>Math"] }} + Pavaroh { *categories{ ^ #["Streams-Patterns-Events>Patterns>Math"] }} + PdegreeToKey { *categories{ ^ #["Streams-Patterns-Events>Patterns>Math"] }} + Pdiff { *categories{ ^ #["Streams-Patterns-Events>Patterns>Math"] }} + Prorate { *categories{ ^ #["Streams-Patterns-Events>Patterns>Math"] }} + Pseq { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Prand { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Pxrand { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Pshuf { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Pwrand { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Pseries { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Pgeom { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Pwhite { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Pexprand { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Pbrown { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Pfunc { *categories{ ^ #["Streams-Patterns-Events>Patterns>Function"] }} + Pfuncn { *categories{ ^ #["Streams-Patterns-Events>Patterns>Function"] }} + Proutine { *categories{ ^ #["Streams-Patterns-Events>Patterns>Function"] }} + Plazy { *categories{ ^ #["Streams-Patterns-Events>Patterns>Function"] }} + PlazyEnvir { *categories{ ^ #["Streams-Patterns-Events>Patterns>Function"] }} + PlazyEnvirN { *categories{ ^ #["Streams-Patterns-Events>Patterns>Function"] }} + Prout { *categories{ ^ #["Streams-Patterns-Events>Patterns>Function"] }} + Pser { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Pslide { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Pwalk { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Place { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Ppatlace { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Ptuple { *categories{ ^ #["Streams-Patterns-Events>Patterns>List"] }} + Pgbrown { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Pbeta { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Pcauchy { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Pgauss { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Phprand { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Plprand { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Pmeanrand { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Ppoisson { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} + Pprob { *categories{ ^ #["Streams-Patterns-Events>Patterns>Random"] }} //+ DebugPbind { *categories{ ^ #["Streams-Patterns-Events>Patterns>Event"] }} + Pevent { *categories{ ^ #["Streams-Patterns-Events>Patterns>Event"] }} + Pbind { *categories{ ^ #["Streams-Patterns-Events>Patterns>Event"] }} + Pmono { *categories{ ^ #["Streams-Patterns-Events>Patterns>Event"] }} + PmonoArtic { *categories{ ^ #["Streams-Patterns-Events>Patterns>Event"] }} + Pindex { *categories{ ^ #["Streams-Patterns-Events>Patterns>List>Indexing"] }} + Pswitch { *categories{ ^ #["Streams-Patterns-Events>Patterns>List>Indexing"] }} + Pfsm { *categories{ ^ #["Streams-Patterns-Events>Patterns>List>Indexing"] }} + Pdfsm { *categories{ ^ #["Streams-Patterns-Events>Patterns>List>Indexing"] }} + PatternProxy { *categories{ ^ #["Streams-Patterns-Events>Patterns>Lookup"] }} + Psym { *categories{ ^ #["Streams-Patterns-Events>Patterns>Lookup"] }} + Pdef { *categories{ ^ #["Streams-Patterns-Events>Patterns>Lookup"] }} + Pdefn { *categories{ ^ #["Streams-Patterns-Events>Patterns>Lookup"] }} + Pbindef { *categories{ ^ #["Streams-Patterns-Events>Patterns>Lookup"] }} + PbindProxy { *categories{ ^ #["Streams-Patterns-Events>Patterns>Lookup"] }} + Pdict { *categories{ ^ #["Streams-Patterns-Events>Patterns>Lookup"] }} + PhidKey { *categories{ ^ #["Streams-Patterns-Events>Patterns>User Input"] }} + PhidSlot { *categories{ ^ #["Streams-Patterns-Events>Patterns>User Input"] }} + Phid { *categories{ ^ #["Streams-Patterns-Events>Patterns>User Input"] }} ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/deprecated/deprecated-3.6-categories/UGenCategories.scSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/deprecated/deprecated-3.6-categories/UGenCate0000664000000000000000000003375512245365552032034 0ustar rootroot/* Categorisation of SC UGens, created by Dan Stowell, 2007. */ + A2K { *categories { ^ #["UGens>Conversion"] } } + AbstractIn { *categories { ^ #["UGens>InOut"] } } + AbstractOut { *categories { ^ #["UGens>InOut"] } } + AmpComp { *categories { ^ #["UGens>Analysis>Amplitude"] } } + AmpCompA { *categories { ^ #["UGens>Analysis>Amplitude"] } } + Amplitude { *categories { ^ #["UGens>Analysis>Amplitude"] } } + AudioIn { *categories { ^ #["UGens>InOut"] } } + Ball { *categories { ^ #["UGens>Filters>Nonlinear"] } } + BasicOpUGen { } + BeatTrack { *categories { ^ #["UGens>Analysis", "UGens>FFT"] } } + BeatTrack2 { *categories { ^ #["UGens>Analysis", "UGens>FFT"] } } + BiPanB2 { *categories { ^ #["UGens>Multichannel>Ambisonics"] } } + Blip { *categories { ^ #["UGens>Generators>Deterministic"] } } + BufCombN { *categories { ^ #["UGens>Delays"] } } + BufDelayN { *categories { ^ #["UGens>Delays"] } } + BufInfoUGenBase { *categories { ^ #["UGens>Buffer>Info"] } } + BufRd { *categories { ^ #["UGens>Buffer"] } } + BufWr { *categories { ^ #["UGens>Buffer"] } } + ChaosGen { *categories { ^ #["UGens>Generators>Chaotic"] } } + CheckBadValues { *categories { ^ #["UGens>Info"] } } + ClearBuf { *categories { ^ #["UGens>Buffer"] } } + CoinGate { *categories { ^ #["UGens>Generators>Stochastic"] } } + CombN { *categories { ^ #["UGens>Delays"] } } + Compander { *categories { ^ #["UGens>Analysis>Amplitude"] } } + CompanderD { *categories { ^ #["UGens>Analysis>Amplitude"] } } + Convolution { *categories { ^ #["UGens>FFT"] } } + Convolution2 { *categories { ^ #["UGens>FFT"] } } + Convolution2L { *categories { ^ #["UGens>FFT"] } } + StereoConvolution2L { *categories { ^ #["UGens>FFT"] } } + Convolution3 { *categories { ^ #["UGens>FFT"] } } + COsc { *categories { ^ #["UGens>Generators>Deterministic"] } } + Crackle { *categories { ^ #["UGens>Generators>Stochastic"] } } + DecodeB2 { *categories { ^ #["UGens>Multichannel>Ambisonics"] } } + DUGen { *categories { ^ #["UGens>Demand"] } } + DC { *categories { ^ #["UGens>Generators>Single-value"] } } + DegreeToKey { *categories { ^ #["UGens>Conversion"] } } + Delay1 { *categories { ^ #["UGens>Delays"] } } + DelayN { *categories { ^ #["UGens>Delays"] } } + Demand { *categories { ^ #["UGens>Demand"] } } + DemandEnvGen { *categories { ^ #["UGens>Demand", "UGens>Envelopes"] } } + DetectSilence { *categories { ^ #["UGens>Synth control", "UGens>Analysis>Amplitude"] } } + DiskIn { *categories { ^ #["UGens>InOut", "UGens>Buffer"] } } + DiskOut { *categories { ^ #["UGens>InOut", "UGens>Buffer"] } } + Done { *categories { ^ #["UGens>Synth control"] } } + Dust { *categories { ^ #["UGens>Generators>Stochastic"] } } + Dust2 { *categories { ^ #["UGens>Generators>Stochastic"] } } + Duty { *categories { ^ #["UGens>Demand"] } } + Dwhite { *categories { ^ #["UGens>Demand"] } } + DynKlang { *categories { ^ #["UGens>Generators>Deterministic"] } } + DynKlank { *categories { ^ #["UGens>Generators>Deterministic", "UGens>Filters>Linear"] } } + Env { } + EnvGen { *categories { ^ #["UGens>Envelopes"] } } + ExpRand { *categories { ^ #["UGens>Generators>Stochastic", "UGens>Generators>Single-value"]} } + FFT { *categories { ^ #["UGens>FFT"] } } + FFTTrigger { *categories { ^ #["UGens>FFT"] } } + Filter { *categories { ^ #["UGens>Filters>Linear"] } } + Formant { *categories { ^ #["UGens>Generators>Deterministic"] } } + Free { *categories { ^ #["UGens>Synth control"] } } + FreeSelf { *categories { ^ #["UGens>Synth control"] } } + FreeSelfWhenDone{ *categories { ^ #["UGens>Synth control"] } } + FreeVerb { *categories { ^ #["UGens>Reverbs"] } } + FreeVerb2 { *categories { ^ #["UGens>Reverbs"] } } + FreqShift { *categories { ^ #["UGens>Filters>Nonlinear", "UGens>Filters>Pitch"] } } + FSinOsc { *categories { ^ #["UGens>Generators>Deterministic"] } } + Gendy1 { *categories { ^ #["UGens>Generators>Stochastic"] } } + Gendy2 { *categories { ^ #["UGens>Generators>Stochastic"] } } + Gendy3 { *categories { ^ #["UGens>Generators>Stochastic"] } } + GrainBuf { *categories { ^ #["UGens>Buffer", "UGens>Generators>Granular"] } } + GrainFM { *categories { ^ #["UGens>Generators>Granular"] } } + GrainSin { *categories { ^ #["UGens>Generators>Granular"] } } + GrainIn { *categories { ^ #["UGens>Generators>Granular"] } } + GVerb { *categories { ^ #["UGens>Reverbs"] } } + Hasher { *categories { ^ #["UGens>Filters>Nonlinear"] } } + Hilbert { *categories { ^ #["UGens>Filters>Nonlinear"] } } + HilbertFIR { *categories { ^ #["UGens>Filters>Nonlinear"] } } + IEnvGen { *categories { ^ #["UGens>Envelopes"] } } + IFFT { *categories { ^ #["UGens>FFT"] } } + Impulse { *categories { ^ #["UGens>Generators>Deterministic"] } } + Index { *categories { ^ #["UGens>Buffer"] } } + IndexL { *categories { ^ #["UGens>Generators>Deterministic"] } } + InfoUGenBase { *categories { ^ #["UGens>Info"] } } + InRange { *categories { ^ #["UGens>Maths"] } } + InRect { *categories { ^ #["UGens>Maths"] } } + Integrator { *categories { ^ #["UGens>Filters>Linear", "UGens>Maths"] } } + IRand { *categories { ^ #["UGens>Generators>Stochastic", "UGens>Generators>Single-value"]} } + K2A { *categories { ^ #["UGens>Conversion"] } } + KeyTrack { *categories { ^ #["UGens>Analysis>Pitch"] } } + KeyState { *categories { ^ #["UGens>User interaction"] } } + Klang { *categories { ^ #["UGens>Generators>Deterministic", "UGens>Filters>Linear"] } } + Klank { *categories { ^ #["UGens>Generators>Deterministic", "UGens>Filters>Linear"] } } + LastValue { *categories { ^ #["UGens>Triggers"] } } + Latch { *categories { ^ #["UGens>Triggers"] } } + LFGauss { *categories { ^ #["UGens>Generators>Stochastic"] } } + LFNoise0 { *categories { ^ #["UGens>Generators>Stochastic"] } } + LFPulse { *categories { ^ #["UGens>Generators>Deterministic"] } } + LFSaw { *categories { ^ #["UGens>Generators>Deterministic"] } } + Line { *categories { ^ #["UGens>Envelopes"] } } + Linen { *categories { ^ #["UGens>Envelopes"] } } + LinExp { *categories { ^ #["UGens>Maths"] } } + LinLin { *categories { ^ #["UGens>Maths"] } } + LinRand { *categories { ^ #["UGens>Generators>Stochastic", "UGens>Generators>Single-value"]} } + LocalBuf { *categories { ^ #["UGens>Buffer"] } } + Logistic { *categories { ^ #["UGens>Generators>Chaotic"] } } + Loudness { *categories { ^ #["UGens>Analysis>Amplitude"] } } + MantissaMask { *categories { ^ #["UGens>Filters>Nonlinear"] } } + MaxLocalBufs { *categories { ^ #["UGens>Buffer>Info"] } } + Median { *categories { ^ #["UGens>Filters>Nonlinear"] } } + MFCC { *categories { ^ #["UGens>Analysis"] } } + Mix {} + MostChange { *categories { ^ #["UGens>Maths"] } } + MouseButton { *categories { ^ #["UGens>User interaction"] } } + MouseX { *categories { ^ #["UGens>User interaction"] } } + MulAdd {} + Normalizer { *categories { ^ #["UGens>Analysis>Amplitude"] } } + NRand { *categories { ^ #["UGens>Generators>Stochastic", "UGens>Generators>Single-value"]} } + Onsets { *categories { ^ #["UGens>Analysis"] } } + Osc { *categories { ^ #["UGens>Generators>Deterministic"] } } + OscN { *categories { ^ #["UGens>Generators>Deterministic"] } } + PackFFT { *categories { ^ #["UGens>FFT"] } } + PanB { *categories { ^ #["UGens>Multichannel>Ambisonics"] } } + PanB2 { *categories { ^ #["UGens>Multichannel>Ambisonics"] } } + PartConv { *categories { ^ #["UGens>FFT"] } } + Pause { *categories { ^ #["UGens>Synth control"] } } + PauseSelf { *categories { ^ #["UGens>Synth control"] } } + PauseSelfWhenDone { *categories { ^ #["UGens>Synth control"] } } + Peak { *categories { ^ #["UGens>Analysis>Amplitude"] } } + PeakFollower { *categories { ^ #["UGens>Analysis>Amplitude"] } } + Phasor { *categories { ^ #["UGens>Triggers", "UGens>Buffer"] } } + Pitch { *categories { ^ #["UGens>Analysis>Pitch", "UGens>MachineListening"] } } + PitchShift { *categories { ^ #["UGens>Filters>Pitch"] } } + PlayBuf { *categories { ^ #["UGens>Buffer"] } } + Pluck { *categories { ^ #["UGens>Generators>Deterministic"] } } + PMOsc { *categories { ^ #["UGens>Generators>Deterministic"] } } + Poll { *categories { ^ #["UGens>Info"] } } + PSinGrain { *categories { ^ #["UGens>Generators>Deterministic"] } } + Pulse { *categories { ^ #["UGens>Generators>Deterministic"] } } + PulseCount { *categories { ^ #["UGens>Triggers"] } } + PulseDivider { *categories { ^ #["UGens>Triggers"] } } + PV_BinScramble { *categories { ^ #["UGens>FFT"] } } + PV_BinShift { *categories { ^ #["UGens>FFT"] } } + PV_BinWipe { *categories { ^ #["UGens>FFT"] } } + PV_BrickWall { *categories { ^ #["UGens>FFT"] } } + PV_ChainUGen { *categories { ^ #["UGens>FFT"] } } + PV_ConformalMap { *categories { ^ #["UGens>FFT"] } } + PV_Diffuser { *categories { ^ #["UGens>FFT"] } } + PV_HainsworthFoote{ *categories { ^ #["UGens>FFT"] } } + PV_JensenAndersen { *categories { ^ #["UGens>FFT"] } } + PV_MagAbove { *categories { ^ #["UGens>FFT"] } } + PV_MagDiv { *categories { ^ #["UGens>FFT"] } } + PV_MagFreeze { *categories { ^ #["UGens>FFT"] } } + PV_MagMul { *categories { ^ #["UGens>FFT"] } } + PV_MagSmear { *categories { ^ #["UGens>FFT"] } } + PV_MagSquared { *categories { ^ #["UGens>FFT"] } } + PV_PhaseShift { *categories { ^ #["UGens>FFT"] } } + PV_RandComb { *categories { ^ #["UGens>FFT"] } } + PV_RandWipe { *categories { ^ #["UGens>FFT"] } } + PV_RectComb { *categories { ^ #["UGens>FFT"] } } + PV_RectComb2 { *categories { ^ #["UGens>FFT"] } } + Rand { *categories { ^ #["UGens>Generators>Stochastic", "UGens>Generators>Single-value"] } } + RandID { *categories { ^ #["UGens>Generators>Stochastic"] } } + RandSeed { *categories { ^ #["UGens>Generators>Stochastic"] } } + RecordBuf { *categories { ^ #["UGens>Buffer"] } } + Rotate2 { *categories { ^ #["UGens>Multichannel>Ambisonics","UGens>Multichannel>Panners"] } } + RunningSum { *categories { ^ #["UGens>Maths"] } } + RunningMin { *categories { ^ #["UGens>Maths"] } } + RunningMax { *categories { ^ #["UGens>Maths"] } } + Saw { *categories { ^ #["UGens>Generators>Deterministic"] } } + ScopeOut { *categories { ^ #["UGens>Buffer"] } } + Select { *categories { ^ #["UGens>Multichannel>Select"] } } + SelectX { *categories { ^ #["UGens>Multichannel>Select"] } } + SelectXFocus { *categories { ^ #["UGens>Multichannel>Select"] } } + SendTrig { *categories { ^ #["UGens>Triggers"] } } + SetBuf { *categories { ^ #["UGens>Buffer"] } } + Silent { *categories { ^ #["UGens>Generators>Single-value"] } } + SinOsc { *categories { ^ #["UGens>Generators>Deterministic"] } } + SinOscFB { *categories { ^ #["UGens>Generators>Deterministic"] } } + Slew { *categories { ^ #["UGens>Filters>Nonlinear"] } } + Slope { *categories { ^ #["UGens>Filters>Linear", "UGens>Maths"] } } + SpecCentroid { *categories { ^ #["UGens>Analysis", "UGens>FFT"] } } + SpecFlatness { *categories { ^ #["UGens>Analysis", "UGens>FFT"] } } + SpecPcile { *categories { ^ #["UGens>Analysis", "UGens>FFT"] } } + Spring { *categories { ^ #["UGens>Filters>Nonlinear"] } } + Stepper { *categories { ^ #["UGens>Triggers"] } } + Sweep { *categories { ^ #["UGens>Triggers"] } } + SyncSaw { *categories { ^ #["UGens>Generators>Deterministic"] } } + T2A { *categories { ^ #["UGens>Conversion"] } } + T2K { *categories { ^ #["UGens>Conversion"] } } + Tap { *categories { ^ #["UGens>Buffer"] } } + TBall { *categories { ^ #["UGens>Filters>Nonlinear"] } } + TDelay { *categories { ^ #["UGens>Triggers", "UGens>Delays"] } } + TExpRand { *categories { ^ #["UGens>Generators>Stochastic"] } } + TGrains { *categories { ^ #["UGens>Buffer", "UGens>Generators>Granular"] } } + Timer { *categories { ^ #["UGens>Triggers"] } } + TIRand { *categories { ^ #["UGens>Generators>Stochastic"] } } + ToggleFF { *categories { ^ #["UGens>Triggers"] } } + TRand { *categories { ^ #["UGens>Generators>Stochastic"] } } + Trig1 { *categories { ^ #["UGens>Triggers"] } } + TWindex { *categories { ^ #["UGens>Generators>Stochastic"] } } + TWChoose { *categories { ^ #["UGens>Multichannel>Select"] } } + UGen { *categories { ^ #["UGens>Unclassified"] } } + UnpackFFT { *categories { ^ #["UGens>FFT"] } } + Unpack1FFT { *categories { ^ #["UGens>FFT"] } } + VarSaw { *categories { ^ #["UGens>Generators>Deterministic"] } } + VDiskIn { *categories { ^ #["UGens>InOut", "UGens>Buffer"] } } + Vibrato { *categories { ^ #["UGens>Filters>Pitch"] } } + VOsc { *categories { ^ #["UGens>Generators>Deterministic"] } } + VOsc3 { *categories { ^ #["UGens>Generators>Deterministic"] } } + Warp1 { *categories { ^ #["UGens>Buffer", "UGens>Generators>Granular"] } } + WhiteNoise { *categories { ^ #["UGens>Generators>Stochastic"] } } + XLine { *categories { ^ #["UGens>Envelopes"] } } + ZeroCrossing { *categories { ^ #["UGens>Analysis>Pitch"] } } + Control { *categories { ^#["UGens>Synth control"]}} + AudioControl { *categories { ^#["UGens>Synth control"]}} + LagControl { *categories { ^#["UGens>Synth control"]}} + TrigControl { *categories { ^#["UGens>Synth control"]}} SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/deprecated/deprecated-3.7.sc0000664000000000000000000000367712245365552026663 0ustar rootroot// in 3.6, both "help" and "openHelpFile" will work fine. In 3.7, "openHelpFile" will be deprecated. In 3.8 it will be gone. + Object { openHelpFile { this.help } } + String { openHelpFile { this.help } } + Method { openHelpFile { this.help } } + Quark { openHelpFile { this.help } } // openTextFile is actually the same as openDocument + String { openTextFile { arg selectionStart=0, selectionLength=0; this.openDocument(selectionStart, selectionLength) } } + Symbol { openTextFile { arg selectionStart=0, selectionLength=0; ^this.openDocument(selectionStart, selectionLength) } } // Document: themes are cocoa-specific + Document { *theme_ { |...args| this.deprecated(thisMethod); this.implementationClass.tryPerform(\theme_, args) } *theme { this.deprecated(thisMethod); ^this.implementationClass.tryPerform(\theme) } *postColor { this.deprecated(thisMethod); ^this.implementationClass.tryPerform(\postColor) } *postColor_ {|...args| this.deprecated(thisMethod); ^this.implementationClass.tryPerform(\postColor_, args) } *background { this.deprecated(thisMethod); ^this.implementationClass.tryPerform(\background) } *background_ {|...args| this.deprecated(thisMethod); ^this.implementationClass.tryPerform(\background_, args) } *selectedBackground { this.deprecated(thisMethod); ^this.implementationClass.tryPerform(\selectedBackground) } *selectedBackground_ {|...args| this.deprecated(thisMethod); ^this.implementationClass.tryPerform(\selectedBackground_, args) } *stringColor_ {|...args| this.deprecated(thisMethod); ^this.implementationClass.tryPerform(\stringColor_, args) } setFont { | ...args | this.deprecated(thisMethod); ^this.subclassResponsibility(thisMethod) } setTextColor { | ...args | this.deprecated(thisMethod); ^this.subclassResponsibility(thisMethod) } syntaxColorize { this.deprecated(thisMethod); ^this.subclassResponsibility(thisMethod) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/0000775000000000000000000000000012245452763023655 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QtGUI.sc0000664000000000000000000000632712245365552025144 0ustar rootrootQtGUI { classvar userCanClose=true, <>deleteOnClose = true; // actions var keyTyped; // focus var dragLabel; var 0 ) } canFocus_ { arg bool; var policy; if( bool ) { policy = 16r1 | 16r2 | 16r8 } { policy = 0 }; this.setProperty(\focusPolicy, policy); } focus { arg flag=true; _QWidget_SetFocus ^this.primitiveFailed; } hasFocus { ^this.getProperty( \focus ); } acceptsMouse { _QWidget_AcceptsMouse ^this.primitiveFailed; } acceptsMouse_ { arg bool; _QWidget_SetAcceptsMouse ^this.primitiveFailed; } focusColor_ { arg color; this.setProperty(\focusColor, color); } focusColor { ^this.getProperty(\focusColor) ? Color(); } // ------------------ container stuff ---------------------------- children { arg class = QView; var ch = super.children( class ); ^ch.select { |v| (v.tryPerform(\isClosed) ? false).not }; } parent { arg class = QView; if (wasRemoved) { ^nil } { ^super.parent(class) }; } parents { var allParents; var p; if (wasRemoved.not) { p = this.parent; while { p.notNil } { allParents = allParents.add( p ); p = p.parent; }; }; ^allParents; } getParents { ^this.parents; } removeAll { var childWidgets = this.children( QView ); childWidgets.do { |child| child.remove }; } layout_ { arg newLayout; if( newLayout.notNil && (newLayout != layout) ) { this.prSetLayout( newLayout ); layout = newLayout; }; } addFlowLayout { arg margin, gap; this.decorator_( FlowLayout( this.bounds.moveTo(0, 0), margin, gap ) ); ^this.decorator; } decorator_ { arg decor; decor.bounds = decor.bounds.moveTo(0, 0); decor.reset; decorator = decor; } // ................. top window stuff ............................ name { ^this.getProperty( \windowTitle ); } name_ { arg string; this.setProperty( \windowTitle, string ); } front { _QWidget_BringFront ^this.primitiveFailed; } minimize { if( this.visible ) { this.invokeMethod( \showMinimized, synchronous:false ) }; } unminimize { if( this.getProperty( \minimized ) ) { this.invokeMethod( \showNormal, synchronous:false ) }; } fullScreen { this.invokeMethod( \showFullScreen, synchronous:false ); } endFullScreen { if( this.getProperty( \fullScreen ) ) { this.invokeMethod( \showNormal, synchronous:false ) }; } alpha_ { arg aFloat; alpha = aFloat; this.setProperty( \windowOpacity, aFloat ); } alwaysOnTop { _QWidget_GetAlwaysOnTop ^this.primitiveFailed; } alwaysOnTop_ { arg boolean; _QWidget_SetAlwaysOnTop ^this.primitiveFailed; } close { if( deleteOnClose ) { this.remove; } { this.visible_( false ); } } isClosed { if (wasRemoved) {^true} {^this.isValid.not}; } notClosed { ^this.isClosed.not } // TODO: deprecate acceptsMouseOver and expose 'mouseTracking' property directly acceptsMouseOver { ^this.getProperty(\_qc_win_mouse_tracking) == true } acceptsMouseOver_ { arg flag; this.setProperty(\_qc_win_mouse_tracking, flag == true) } // ----------------- actions ..................................... action_ { arg func; // NOTE: not all widgets have action() signal try { this.manageMethodConnection( action, func, 'action()', \doAction ); }; action = func; } addAction { arg func, selector=\action; this.perform(selector.asSetter, this.perform(selector).addFunc(func)); } removeAction { arg func, selector=\action; this.perform(selector.asSetter, this.perform(selector).removeFunc(func)); } *globalKeyDownAction_ { arg action; globalKeyDownAction = action; this.setGlobalEventEnabled( 16r01 /* KeyPress */, true ); } *globalKeyUpAction_ { arg action; globalKeyUpAction = action; this.setGlobalEventEnabled( 16r02 /* KeyRelease */, true ); } keyDownAction_ { arg aFunction; keyDownAction = aFunction; this.setEventHandlerEnabled( QObject.keyDownEvent, true ); } keyUpAction_ { arg aFunction; keyUpAction = aFunction; this.setEventHandlerEnabled( QObject.keyUpEvent, true ); } keyModifiersChangedAction_ { arg aFunction; keyModifiersChangedAction = aFunction; this.setEventHandlerEnabled( QObject.keyDownEvent, true ); this.setEventHandlerEnabled( QObject.keyUpEvent, true ); } mouseDownAction_ { arg aFunction; mouseDownAction = aFunction; this.setEventHandler( QObject.mouseDownEvent, \mouseDownEvent, true ); this.setEventHandler( QObject.mouseDblClickEvent, \mouseDownEvent, true ); } mouseUpAction_ { arg aFunction; mouseUpAction = aFunction; this.setEventHandler( QObject.mouseUpEvent, \mouseUpEvent, true ); } mouseMoveAction_ { arg aFunction; mouseMoveAction = aFunction; this.setEventHandler( QObject.mouseMoveEvent, \mouseMoveEvent, true ); } // mouseOverAction responds to same Qt event as mouseMoveAction, // but on different conditions. // See QView:-mouseMoveEvent method. mouseOverAction_ { arg aFunction; mouseOverAction = aFunction; this.setEventHandler( QObject.mouseMoveEvent, \mouseMoveEvent, true ); this.setProperty(\mouseTracking, true); } mouseEnterAction_ { arg aFunction; mouseEnterAction = aFunction; this.setEventHandler( QObject.mouseEnterEvent, \mouseEnterEvent, true ); } mouseLeaveAction_ { arg aFunction; mouseLeaveAction = aFunction; this.setEventHandler( QObject.mouseLeaveEvent, \mouseLeaveEvent, true ); } mouseWheelAction_ { arg aFunction; mouseWheelAction = aFunction; this.setEventHandler( QObject.mouseWheelEvent, \mouseWheelEvent, true ); } beginDragAction_ { arg handler; beginDragAction = handler; this.setEventHandler( QObject.mouseDownEvent, \mouseDownEvent, true ) } canReceiveDragHandler_ { arg handler; canReceiveDragHandler = handler; this.setDragEventsEnabled( true ); } receiveDragHandler_ { arg handler; receiveDragHandler = handler; this.setDragEventsEnabled( true ); } toFrontAction_ { arg aFunction; toFrontAction = aFunction; this.setEventHandler( QObject.windowActivateEvent, \onWindowActivateEvent ); } endFrontAction_ { arg aFunction; endFrontAction = aFunction; this.setEventHandler( QObject.windowDeactivateEvent, \onWindowDeactivateEvent ); } focusGainedAction_ { arg handler; focusGainedAction = handler; this.setEventHandler( 8 /* QEvent::FocusIn */, \focusInEvent ); } focusLostAction_ { arg handler; focusLostAction = handler; this.setEventHandler( 9 /* QEvent::FocusOut */, \focusOutEvent ); } onMove_ { arg aFunction; onMove = aFunction; this.setEventHandler( 13 /* QEvent::Move */, \moveEvent ); } onResize_ { arg aFunction; onResize = aFunction; this.setEventHandler( 14 /* QEvent::Resize */, \resizeEvent ); } onClose_ { arg func; this.manageFunctionConnection( onClose, func, 'destroyed()', false ); onClose = func; } doAction { action.value(this); } defaultKeyDownAction { arg char, modifiers, unicode, keycode, key; } defaultKeyUpAction { arg char, modifiers, unicode, keycode, key; } keyDown { arg char, modifiers, unicode, keycode, key; if( keyDownAction.notNil ) { ^keyDownAction.value( this, char, modifiers, unicode, keycode, key ); } { ^this.defaultKeyDownAction( char, modifiers, unicode, keycode, key ); }; } keyUp { arg char, modifiers, unicode, keycode, key; keyTyped = char; if( keyUpAction.notNil ) { ^keyUpAction.value( this, char, modifiers, unicode, keycode, key ); } { ^this.defaultKeyUpAction( char, modifiers, unicode, keycode, key ); }; } keyModifiersChanged { arg modifiers; keyModifiersChangedAction.value( this, modifiers); } mouseDown { arg x, y, modifiers, buttonNumber, clickCount; ^mouseDownAction.value( this, x, y, modifiers, buttonNumber, clickCount ); } mouseUp { arg x, y, modifiers, buttonNumber; ^mouseUpAction.value( this, x, y, modifiers, buttonNumber ); } mouseMove { arg x, y, modifiers; ^mouseMoveAction.value( this, x, y, modifiers ); } mouseOver { arg x, y; ^mouseOverAction.value( this, x, y ); } mouseEnter { ^mouseEnterAction.value(this); } mouseLeave { ^mouseLeaveAction.value(this); } mouseWheel { arg x, y, modifiers, xDelta, yDelta; ^mouseWheelAction.value( this, x, y, modifiers, xDelta, yDelta ); } /* ---------------- private ----------------------- */ *prSetCurrentDrag { arg obj; currentDrag = obj; currentDragString = obj.asCompileString; } *prClearCurrentDrag { currentDrag = nil; currentDragString = nil; } *setGlobalEventEnabled { arg event, enabled; _QWidget_SetGlobalEventEnabled } initQView { arg parent; var handleKeyDown, handleKeyUp, overridesMouseDown, handleDrag; if (parent.notNil) { if( parent.decorator.notNil ) { parent.decorator.place(this) } }; this.setEventHandler( QObject.closeEvent, \onCloseEvent, true ); // key events handleKeyDown = handleKeyUp = this.overrides( \keyModifiersChanged ); if( handleKeyDown.not ) { handleKeyDown = this.overrides( \defaultKeyDownAction ) }; if( handleKeyUp.not ) { handleKeyUp = this.overrides( \defaultKeyUpAction )}; this.setEventHandler( QObject.keyDownEvent, \keyDownEvent, true, enabled: handleKeyDown ); this.setEventHandler( QObject.keyUpEvent, \keyUpEvent, true, enabled: handleKeyUp ); // mouse events overridesMouseDown = this.overrides( \mouseDown ); if( this.respondsTo(\defaultGetDrag) || overridesMouseDown ) {this.setEventHandler( QObject.mouseDownEvent, \mouseDownEvent, true )}; if( overridesMouseDown ) {this.setEventHandler( QObject.mouseDblClickEvent, \mouseDownEvent, true )}; if( this.overrides( \mouseUp ) ) {this.setEventHandler( QObject.mouseUpEvent, \mouseUpEvent, true )}; if( this.overrides( \mouseMove ) || this.overrides( \mouseOver ) ) {this.setEventHandler( QObject.mouseMoveEvent, \mouseMoveEvent, true )}; if( this.overrides( \mouseEnter ) ) {this.setEventHandler( QObject.mouseEnterEvent, \mouseEnterEvent, true )}; if( this.overrides( \mouseLeave ) ) {this.setEventHandler( QObject.mouseLeaveEvent, \mouseLeaveEvent, true )}; if( this.overrides( \mouseWheel ) ) {this.setEventHandler( QObject.mouseWheelEvent, \mouseWheelEvent, true )}; // DnD events handleDrag = this.respondsTo(\defaultCanReceiveDrag) or: {this.respondsTo(\defaultReceiveDrag)}; this.setEventHandler( 60, \dragEnterEvent, true, enabled:handleDrag ); this.setEventHandler( 61, \dragMoveEvent, true, enabled:handleDrag ); this.setEventHandler( 63, \dropEvent, true, enabled:handleDrag ); } onCloseEvent { if( userCanClose != false ) { if( deleteOnClose != false ) { this.remove; ^true }; }{ ^false; }; } onWindowActivateEvent { toFrontAction.value(this); } onWindowDeactivateEvent { endFrontAction.value(this); } focusInEvent { focusGainedAction.value(this) } focusOutEvent { focusLostAction.value(this) } moveEvent { onMove.value(this) } resizeEvent { onResize.value(this) } keyDownEvent { arg char, modifiers, unicode, keycode, key, spontaneous; modifiers = QKeyModifiers.toCocoa(modifiers); if( spontaneous ) { // this event has never been propagated to parent yet QView.globalKeyDownAction.value( this, char, modifiers, unicode, keycode, key ); }; if( (key == 16r1000020) || (key == 16r1000021) || (key == 16r1000022) || (key == 16r1000023 ) ) { this.keyModifiersChanged( modifiers ) }; ^this.keyDown( char, modifiers, unicode, keycode, key ); } keyUpEvent { arg char, modifiers, unicode, keycode, key, spontaneous; modifiers = QKeyModifiers.toCocoa(modifiers); if( spontaneous ) { // this event has never been propagated to parent yet QView.globalKeyUpAction.value( this, char, modifiers, unicode, keycode, key ); }; if( (key == 16r1000020) || (key == 16r1000021) || (key == 16r1000022) || (key == 16r1000023 ) ) { this.keyModifiersChanged( modifiers ) }; ^this.keyUp( char, modifiers, unicode, keycode, key ); } mouseDownEvent { arg x, y, modifiers, buttonNumber, clickCount; // WARNING: QDragView and QListView override this method! if( (modifiers & QKeyModifiers.control) > 0 ) { // if Ctrl / Cmd mod // Try to get drag obj and start a drag. // If successful, block further processing of this event. if( this.beginDrag( x, y ) ) { ^true }; }; // else continue to handle mouse down event modifiers = QKeyModifiers.toCocoa(modifiers); ^this.mouseDown( x, y, modifiers, buttonNumber, clickCount ); } mouseUpEvent { arg x, y, modifiers, buttonNumber; modifiers = QKeyModifiers.toCocoa(modifiers); ^this.mouseUp( x, y, modifiers, buttonNumber ); } mouseMoveEvent { arg x, y, modifiers, buttons; // WARNING: Overridden in QListView! if( buttons != 0 ) { modifiers = QKeyModifiers.toCocoa(modifiers); ^this.mouseMove( x, y, modifiers ); }{ ^this.mouseOver( x, y ) } } mouseEnterEvent { var dummy = 0; // prevent this method from being optimized away ^this.mouseEnter; } mouseLeaveEvent { var dummy = 0; // prevent this method from being optimized away ^this.mouseLeave; } mouseWheelEvent { arg x, y, modifiers, xDelta, yDelta; modifiers = QKeyModifiers.toCocoa(modifiers); ^this.mouseWheel( x, y, modifiers, xDelta, yDelta ); } beginDrag { arg x, y; var obj, str; if( beginDragAction.notNil ) { obj = beginDragAction.value( this, x, y ) } { obj = this.tryPerform( \defaultGetDrag, x, y ) }; if( obj.notNil ) { QView.prSetCurrentDrag( obj ); str = obj.asString; this.prStartDrag( dragLabel ?? str, obj, str ); ^true; }; ^false; } canReceiveDrag { arg x, y; if( canReceiveDragHandler.notNil ) { ^this.canReceiveDragHandler.value( this, x, y ) } { ^( this.tryPerform( \defaultCanReceiveDrag, x, y ) ? false ) }; } receiveDrag { arg x, y; if( receiveDragHandler.notNil ) { this.receiveDragHandler.value( this, x, y ) } { this.tryPerform( \defaultReceiveDrag, x, y ) }; } prStartDrag { arg label, data, dataAsString; _QWidget_StartDrag ^this.primitiveFailed; } dragEnterEvent { arg internal, data; if(internal.not) { // dnd incoming from outside SC QView.prSetCurrentDrag(data); }; // always accept the event ^true; } dragMoveEvent { arg x, y; // make sure the event is always consumed ^this.canReceiveDrag( x, y ).switch ( true, true, false, false, false ) } dropEvent { arg x, y; this.receiveDrag( x, y ); // always accept the event ^true } setDragEventsEnabled { arg enabled; this.setEventHandlerEnabled( 60, enabled ); this.setEventHandlerEnabled( 61, enabled ); this.setEventHandlerEnabled( 63, enabled ); } prSetLayout { arg layout; _QWidget_SetLayout ^this.primitiveFailed; } manageMethodConnection { arg oldAction, newAction, signal, method, sync=false; if( newAction !== oldAction ) { case { oldAction.isNil && newAction.notNil } {this.connectMethod (signal, method, sync)} { oldAction.notNil && newAction.isNil } {this.disconnectMethod (signal, method)} ; }; } manageFunctionConnection { arg oldAction, newAction, signal, sync=false; if( newAction !== oldAction ) { if( oldAction.notNil ) {this.disconnectFunction (signal, oldAction)}; if( newAction.notNil ) {this.connectFunction (signal, newAction, sync)}; }; } overrides { arg method; ^this.prOverrides(QView, method) } prOverrides { arg superclass, method; _Qt_IsMethodOverridden ^this.primitiveFailed } nonimpl { arg methodName; this.class.nonimpl( methodName ); } *nonimpl { arg methodName; this.debug( msg: methodName.asString ++ " is not implemented yet" ) } *debug { arg level = 1, msg = ""; if( QtGUI.debugLevel >= level ) { ("Qt: " ++ this.asString ++ ": " ++ msg).postln } } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QObject.sc0000664000000000000000000000701412161364457025534 0ustar rootrootQMetaObject { var className; *new { arg className; ^super.newCopyArgs(className); } properties { _QMetaObject_Properties ^this.primitiveFailed } methods { arg plain = true, signals = false, slots = true; _QMetaObject_Methods ^this.primitiveFailed } } QObject { classvar heap, < closeEvent = 19, < showEvent = 17, < windowActivateEvent = 24, < windowDeactivateEvent = 25, < mouseDownEvent = 2, < mouseUpEvent = 3, < mouseDblClickEvent = 4, < mouseMoveEvent = 5, < mouseEnterEvent = 10, < mouseLeaveEvent = 11, < mouseWheelEvent = 31, < keyDownEvent = 6, < keyUpEvent = 7; var qObject, finalizer; var virtualSlots; *qtClass { ^nil } *meta { ^QMetaObject(this.qtClass) } *new { arg argumentArray; var className = this.qtClass; if( className.isNil ) { Error("Qt:" + this.name + "is an abstract class and can not be instantiated.").throw; }; ^super.new.initQObject( className, argumentArray ); } *heap { ^heap.copy } initQObject{ arg className, argumentArray; this.prConstruct( className, argumentArray ); heap = heap.add( this ); } destroy { _QObject_Destroy ^this.primitiveFailed } isValid { _QObject_IsValid ^this.primitiveFailed } parent { arg class; ^this.prGetParent( if( class.notNil ){class.name}{nil} ); } children { arg class; ^this.prGetChildren( if( class.notNil ){class.name}{nil} ); } setParent { arg parent; _QObject_SetParent ^this.primitiveFailed } properties { _QObject_GetProperties ^this.primitiveFailed } methods { arg plain = true, signals = false, slots = true; _QObject_GetMethods ^this.primitiveFailed } getProperty { arg property; _QObject_GetProperty ^this.primitiveFailed } setProperty { arg property, value, direct=true; _QObject_SetProperty ^this.primitiveFailed } setEventHandler{ arg event, method, direct=false, enabled=true; _QObject_SetEventHandler ^this.primitiveFailed } setEventHandlerEnabled { arg event, enabled=true; _QObject_SetEventHandlerEnabled ^this.primitiveFailed } connectMethod { arg signal, handler, direct=false; _QObject_ConnectMethod ^this.primitiveFailed } disconnectMethod { arg signal, method; _QObject_DisconnectMethod; ^this.primitiveFailed } connectFunction { arg signal, object, synchronous = false; virtualSlots = virtualSlots.add( object ); this.prConnectObject( signal, object, synchronous ); } disconnectFunction { arg signal, object; virtualSlots.remove( object ); this.prDisconnectObject( signal, object ); } connectSlot { arg signal, receiver, slot; _QObject_ConnectSlot; ^this.primitiveFailed } invokeMethod { arg method, arguments, synchronous = true; _QObject_InvokeMethod ^this.primitiveFailed } ////////////////////// private ////////////////////////////////// prConstruct { arg className, argumentArray; _QObject_New ^this.primitiveFailed; } prConnectObject { arg signal, object, synchronous = false; _QObject_ConnectObject; ^this.primitiveFailed } prDisconnectObject { arg signal, object; _QObject_DisconnectObject; ^this.primitiveFailed } prGetChildren { arg className; _QObject_GetChildren ^this.primitiveFailed } prGetParent { arg className; _QObject_GetParent ^this.primitiveFailed } prRelease { heap.remove(this); } doFunction { arg f ... args; f.performList(\value, this, args); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QPenPrinter.sc0000664000000000000000000000267212014636263026413 0ustar rootrootQPenPrinter : QObject { var printFunc, cancelFunc, okFunc; *qtClass { ^'QcPenPrinter' } *new { ^super.new.init; } *print { |printFunc, cancelFunc| this.new.showDialog( { |p| p.print(printFunc) }, cancelFunc); } init { heap.remove(this); this.connectFunction('printFunc()', synchronous:true) { printFunc.value(this); printFunc = nil; heap.remove(this); }; this.connectFunction('dialogDone(int)', synchronous:false) { |me, ok| if( ok == 1 ) { okFunc.value(this); } { cancelFunc.value(this); }; okFunc = nil; cancelFunc = nil; heap.remove(this); }; } showDialog { |aOkFunc, aCancelFunc| if(okFunc.notNil or: cancelFunc.notNil) { "QPenPrinter: dialog already open".warn; ^this; }; okFunc = aOkFunc; cancelFunc = aCancelFunc; heap = heap.add(this); this.invokeMethod(\show, synchronous:false); } print { |aPrintFunc| if(printFunc.notNil) { "QPenPrinter: printing already in progress".warn; ^this; }; printFunc = aPrintFunc; heap = heap.add(this); this.invokeMethod(\print, synchronous:false); } newPage { this.invokeMethod(\newPage, synchronous:true); } pageRect { ^this.getProperty(\pageRect) } paperRect { ^this.getProperty(\paperRect) } fromPage { ^this.getProperty(\fromPage) } toPage { ^this.getProperty(\toPage) } pageSize { ^this.pageRect.size } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QFont.sc0000664000000000000000000000444012161364457025234 0ustar rootrootQFont { classvar name, bold, <>italic, 0) { [curves.collect{|c| QCurve(c)}] } { QCurve(curves) } ); } setEnv { arg env; var times = [0] ++ env.times.integrate; if( times.last > 0 ) {times = times / times.last}; this.value = [times, env.levels]; this.curves = env.curves; } grid_ { arg aPoint; grid = aPoint; this.setProperty( \grid, aPoint ); } gridOn_ { arg aBool; gridOn = aBool; this.setProperty( \gridOn, aBool ); } connect { arg source, targets; this.invokeMethod( \connectElements, [source, targets] ); } gridColor { ^this.getProperty(\gridColor) } gridColor_ { arg color; this.setProperty( \gridColor, color ) } selectionColor { ^this.getProperty(\selectionColor) } selectionColor_ { arg color; this.setProperty(\selectionColor, color) } strokeColor { ^this.getProperty(\strokeColor) } strokeColor_ { arg color; this.setProperty( \strokeColor, color ) } fillColor_ { arg aColor; fillColor = aColor; this.setProperty( \fillColor, aColor ); } setFillColor { arg index, color; this.invokeMethod( \setFillColorAt, [index, color] ); } colors_ { arg strokeColor, fillColor; this.strokeColor_( strokeColor ); this.fillColor_( fillColor ); } drawLines_ { arg aBool; drawLines = aBool; this.setProperty( \drawLines, aBool ); } drawRects_ { arg aBool; drawRects = aBool; this.setProperty( \drawRects, aBool ); } style { ^this.getProperty(\style) } style_ { arg style; if (style.isNumber.not) { style = style.switch ( \dots, 0, \rects, 1, 0 ); }; style = style.clip(0,1).asInteger; this.setProperty(\style, style) } thumbWidth_ { arg width; this.setProperty( \thumbWidth, width.asInteger; ); } thumbHeight_ { arg height; this.setProperty( \thumbHeight, height.asInteger; ); } thumbSize_ { arg size; this.setProperty( \thumbSize, size.asInteger; ); } setThumbWidth { arg index, width; this.invokeMethod(\setThumbWidthAt, [index, width.asInteger]) } setThumbHeight { arg index, height; this.invokeMethod(\setThumbHeightAt, [index, height.asInteger]) } setThumbSize { arg index, size; this.invokeMethod(\setThumbSizeAt, [index, size.asInteger]) } metaAction_ { arg function; this.manageMethodConnection( metaAction, function, 'metaAction()', \doMetaAction ); metaAction = function; } doMetaAction { metaAction.value(this); } defaultGetDrag { ^this.value; } defaultCanReceiveDrag { ^true; } defaultReceiveDrag { this.value = QView.currentDrag; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QSoundFileView.sc0000664000000000000000000001504712161364457027056 0ustar rootrootQSoundFileView : QView { var <>soundfile; var elasticMode; // NOTE: no-op, only for compatibility var curDoneAction; *qtClass { ^'QcWaveform' } load { arg filename, startframe, frames, block, doneAction; if( filename.isString && filename != "" ) { if( curDoneAction.notNil ) { this.disconnectFunction( 'loadingDone()', curDoneAction ) }; if( doneAction.notNil ) { this.connectFunction( 'loadingDone()', doneAction ); }; curDoneAction = doneAction; if( startframe.notNil && frames.notNil ) { this.invokeMethod( \load, [filename, startframe.asInteger, frames.asInteger] ); }{ this.invokeMethod( \load, filename ); } } } alloc { arg frames, channels=1, samplerate=44100; this.invokeMethod( \allocate, [frames.asInteger, channels.asInteger, samplerate.asInteger] ); } data_ { arg data; this.setData(data); } setData { arg data, block, startframe=0, channels=1, samplerate=44100; if( data.isKindOf(DoubleArray).not and: {data.isKindOf(FloatArray).not} ) { data = data.as(DoubleArray) }; this.invokeMethod( \load, [data, startframe, channels, samplerate] ); } set { arg offset=0, data; if( data.isKindOf(DoubleArray).not and: {data.isKindOf(FloatArray).not} ) { data = data.as(DoubleArray) }; this.invokeMethod( \write, [data, offset.asInteger] ); } readFile { arg aSoundFile, startframe, frames, block, closeFile, doneAction; this.load( aSoundFile.path, startframe, frames, block, doneAction ); } read { arg startframe, frames, block, closeFile, doneAction; if( soundfile.notNil ) { this.readFile( soundfile, startframe, frames, block, nil, doneAction ); }; } readFileWithTask { arg aSoundFile, startframe, frames, block, doneAction, showProgress; this.readFile( aSoundFile, startframe, frames, block, nil, doneAction ); } readWithTask { arg startframe, frames, block, doneAction, showProgress; this.read( startframe, frames, block, nil, doneAction ); } drawsWaveForm { ^this.getProperty( \drawsWaveform ); } drawsWaveForm_ { arg boolean; this.setProperty( \drawsWaveform, boolean ); } waveColors { ^this.getProperty( \waveColors ) } waveColors_ { arg colors; this.setProperty( \waveColors, colors ) } //// Info startFrame { ^this.getProperty( \startFrame ); } numFrames { ^this.getProperty( \frames ); } scrollPos { ^this.getProperty( \scrollPos ); } // a fraction of the full scrolling range viewFrames { ^this.getProperty( \viewFrames ); } readProgress { ^this.getProperty( \readProgress ); } //// Navigation zoom { arg factor; this.invokeMethod( \zoomBy, factor.asFloat ); } zoomToFrac { arg fraction; this.invokeMethod( \zoomTo, fraction.asFloat ); } zoomAllOut { this.invokeMethod( \zoomAllOut ); } zoomSelection { arg selection; if( selection.isNil ) { selection = this.currentSelection }; this.invokeMethod( \zoomSelection, selection ); } scrollTo { arg fraction; // a fraction of the full scrolling range this.setProperty( \scrollPos, fraction ); } scroll { arg fraction; // a fraction of the visible range var frames = this.viewFrames * fraction + this.getProperty(\viewStartFrame); this.setProperty( \viewStartFrame, frames ); } scrollToStart { this.invokeMethod( \scrollToStart ); } scrollToEnd { this.invokeMethod( \scrollToEnd ); } xZoom { ^this.getProperty( \xZoom ); } xZoom_ { arg seconds; this.setProperty( \xZoom, seconds ); } yZoom { ^this.getProperty( \yZoom ); } yZoom_ { arg factor; this.setProperty( \yZoom, factor.asFloat ); } //// Selections selections { ^this.getProperty( \selections ); } currentSelection { ^this.getProperty( \currentSelection ); } currentSelection_ { arg index; this.setProperty( \currentSelection, index ); } selection { arg index; ^this.invokeMethod( \selection, index, true ); } setSelection { arg index, selection; this.invokeMethod( \setSelection, [index, selection] ); } selectionStart { arg index; var sel = this.selection( index ); ^sel.at(0); } setSelectionStart { arg index, frame; var sel = this.selection( index ); sel.put( 0, frame ); this.setSelection( index, sel ); } selectionSize { arg index; var sel = this.selection( index ); ^sel.at(1); } setSelectionSize { arg index, frames; var sel = this.selection( index ); sel.put( 1, frames ); this.setSelection( index, sel ); } selectAll { arg index; this.setSelection( index, [0, this.numFrames] ); } selectNone { arg index; this.setSelection( index, [0, 0] ); } setEditableSelectionStart { arg index, editable; ^this.nonimpl("setEditableSelectionStart"); } setEditableSelectionSize { arg index, editable; ^this.nonimpl("setEditableSelectionSize"); } setSelectionColor { arg index, color; this.invokeMethod( \setSelectionColor, [index,color] ); } selectionStartTime { arg index; ^this.nonimpl("selectionStartTime"); } selectionDuration { arg index; ^this.nonimpl("selectionDuration"); } readSelection { arg block, closeFile; ^this.nonimpl("readSelection"); } readSelectionWithTask { ^this.nonimpl("readSelectionWithTask"); } // cursor timeCursorOn { ^this.getProperty( \cursorVisible ); } timeCursorOn_ { arg flag; this.setProperty( \cursorVisible, flag ) } timeCursorEditable { ^this.getProperty( \cursorEditable ); } timeCursorEditable_ { arg flag; this.setProperty( \cursorEditable, flag ) } timeCursorPosition { ^this.getProperty( \cursorPosition ); } timeCursorPosition_ { arg frame; this.setProperty( \cursorPosition, frame ) } // grid gridOn { ^this.getProperty( \gridVisible ); } gridOn_ { arg flag; this.setProperty( \gridVisible, flag ) } gridResolution { ^this.getProperty( \gridResolution ) } gridResolution_ { arg seconds; this.setProperty( \gridResolution, seconds ) } gridOffset { ^this.getProperty( \gridOffset ) } gridOffset_ { arg seconds; this.setProperty( \gridOffset, seconds ) } // colors peakColor { ^this.getProperty(\peakColor) } peakColor_ { arg color; this.setProperty(\peakColor, color) } rmsColor { ^this.getProperty(\rmsColor) } rmsColor_ { arg color; this.setProperty(\rmsColor, color) } timeCursorColor { ^this.getProperty( \cursorColor ); } timeCursorColor_ { arg color; this.setProperty( \cursorColor, color ) } gridColor { ^this.getProperty( \gridColor ) } gridColor_ { arg color; this.setProperty( \gridColor, color ) } // actions metaAction_ { arg action; this.manageFunctionConnection( metaAction, action, 'metaAction()' ); metaAction = action } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QTreeView.sc0000664000000000000000000001065312161364457026063 0ustar rootrootQTreeView : QView { var = 0 ) { while { i < n } { id = i.wrap(0,nd); func.value( i, d[id] ); i = i + 1; }; }; } // dummy for convenience in case tree view is invalid prValidItem { ^nil; } } QTreeViewItem { var qtObject; var setBoth = true; *qtClass { ^'QcNumberBox' } *new { arg aParent, aBounds; var obj = super.new( aParent, aBounds ); obj.initQNumberBox; ^obj; } initQNumberBox { scroll = true; scroll_step = 1; normalColor = Color.black; typingColor = Color.red; } object_ { arg obj; if( setBoth ) { if( obj.isNumber ) { this.value = obj } { this.string = obj.asString } }; object = obj } value { var type = this.getProperty( \valueType ); var val; switch( type, 0 /* Number */, { val = this.getProperty( \value ) }, 1 /* Inf */, { val = inf }, 2 /* -Inf */, { val = -inf }, 3 /* NaN */, { val = 0 }, 4 /* Text */, { val = 0 } ); ^val; } value_ { arg value; case // isNaN has to be on the first plase, because a NaN is also equal to inf and -inf { value.isNaN } { this.invokeMethod( \setNaN ); } { value == inf } { this.invokeMethod( \setInfinite, true ); } { value == -inf } { this.invokeMethod( \setInfinite, false ); } { this.setProperty( \value, value.asFloat ); } ; } valueAction_ { arg val; this.value_(val); action.value(this); } string { ^this.getProperty( \text ); } string_ { arg string; this.setProperty( \text, string ); } clipLo { ^this.getProperty(\minimum) } clipLo_ { arg aFloat; this.setProperty( \minimum, aFloat ) } clipHi { ^this.getProperty(\maximum) } clipHi_ { arg aFloat; this.setProperty( \maximum, aFloat ) } scroll_ { arg aBool; scroll = aBool; this.setProperty( \scroll, aBool ); } scroll_step_ { arg aFloat; scroll_step = aFloat; this.setProperty( \scrollStep, aFloat ); } decimals { ^this.getProperty(\decimals); } minDecimals { ^this.getProperty(\minDecimals); } maxDecimals { ^this.getProperty(\maxDecimals); } decimals_ { arg decimals; this.setProperty( \decimals, decimals ); } minDecimals_ { arg decimals; this.setProperty( \minDecimals, decimals ); } maxDecimals_ { arg decimals; this.setProperty( \maxDecimals, decimals ); } align_ { arg alignment; align = alignment; this.setProperty( \alignment, QAlignment(alignment)); } stringColor { ^this.palette.baseText; } stringColor_ { arg color; this.palette = this.palette.baseText_(color); } normalColor_ { arg aColor; normalColor = aColor; this.setProperty( \normalColor, aColor ); } typingColor_ { arg aColor; typingColor = aColor; this.setProperty( \editingColor, aColor ); } background { ^this.palette.base; } background_ { arg color; this.palette = this.palette.base_(color); } buttonsVisible_ { arg aBool; buttonsVisible = aBool; this.setProperty( \buttonsVisible, aBool ); } defaultGetDrag { ^this.value; } defaultCanReceiveDrag { ^QView.currentDrag.isNumber; } defaultReceiveDrag { this.valueAction = QView.currentDrag; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QDialog.sc0000664000000000000000000000223112245365552025521 0ustar rootrootQFileDialog : QObject { *qtClass { ^'QcFileDialog' } *new { arg okFunc, cancelFunc, fileMode, acceptMode, stripResult = false; var me = super.new( [fileMode, acceptMode] ); if( okFunc.notNil ) { me.connectFunction( 'accepted(VariantList)', { |me, result| if( stripResult ) { okFunc.performList(\value, result) } { okFunc.value(result) } }); }; if( cancelFunc.notNil ) { me.connectFunction( 'rejected()', { cancelFunc.value() } ); }; me.invokeMethod('show', synchronous:false); ^me; } } QDialog { *implementsClass {^'Dialog'} *getPaths { arg okFunc, cancelFunc, allowsMultiple=true; var fileMode; if( allowsMultiple ) { fileMode = 3 } { fileMode = 1 }; ^QFileDialog.new( okFunc, cancelFunc, fileMode, 0 ); } *openPanel { arg okFunc, cancelFunc, multipleSelection=false; var fileMode; if( multipleSelection ) { fileMode = 3 } { fileMode = 1 }; ^QFileDialog.new( okFunc, cancelFunc, fileMode, 0, stripResult:multipleSelection.not ); } *savePanel { arg okFunc, cancelFunc; ^QFileDialog.new( okFunc, cancelFunc, 0, 1, stripResult:true ); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/deprecated-3.5.sc0000664000000000000000000000077412245365552026616 0ustar rootroot+ QWindow { drawHook { this.deprecated(thisMethod, this.class.findMethod(\drawFunc)); ^drawFunc } drawHook_ { |aFunction| this.deprecated(thisMethod, this.class.findMethod(\drawFunc_)); this.drawFunc_(aFunction) } } + QKnob { *isSquare { this.deprecated(thisMethod); ^false } *isSquare_ { this.deprecated(thisMethod) } *compactRatio { this.deprecated(thisMethod); ^0.87 } *compactRatio_ { this.deprecated(thisMethod) } skin { this.deprecated( thisMethod ); ^nil } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QUserView.sc0000664000000000000000000000255212245365552026101 0ustar rootrootQUserView : QView { var 0) {cmods = cmods | 131072}; if (mods & QKeyModifiers.alt > 0 ) {cmods = cmods | 524288}; Platform.case ( \osx, { if (mods & QKeyModifiers.control > 0) {cmods = cmods | 1048576}; // Cmd if (mods & QKeyModifiers.meta > 0) {cmods = cmods | 262144}; // Ctrl }, { if (mods & QKeyModifiers.control > 0) {cmods = cmods | 262144} } // Ctrl ); if (mods & QKeyModifiers.keypad > 0) {cmods = cmods | 2097152}; // TODO: caps-lock, func, help ^cmods; } } QWebFontFamily { classvar win; doDrawFunc { win.drawFunc.value(win); } } QScrollTopView : QScrollView { var >window; *qtClass {^'QcScrollWindow'} *new { arg win, name, bounds, resizable, border; ^super.newCustom([name, bounds, resizable, border]) .initQScrollTopView(win); } initQScrollTopView { arg win; var cnv; window = win; // NOTE: The canvas widget must not be a QView, so that asking its // children for parent will skip it and hit this view instead. cnv = QTopScrollWidget.new; cnv.win = win; this.canvas = cnv; } bounds { var r; r = this.getProperty( \geometry ); ^r.moveTo(0,0); } bounds_ { arg rect; var rNew = rect.asRect; var rOld = this.getProperty( \geometry ); this.setProperty( \geometry, rOld.resizeTo( rNew.width, rNew.height ) ); } drawingEnabled_ { arg bool; canvas.setProperty( \drawingEnabled, bool ); } findWindow { ^window; } } QTopView : QView { var >window; *qtClass {^'QcWindow'} *new { arg win, name, bounds, resizable, border; ^super.newCustom([name, bounds, resizable, border]) .initQTopView(win); } initQTopView { arg win; window = win; } bounds { var r; r = this.getProperty( \geometry ); ^r.moveTo(0,0); } bounds_ { arg rect; var rNew = rect.asRect; var rOld = this.getProperty( \geometry ); this.setProperty( \geometry, rOld.resizeTo( rNew.width, rNew.height ) ); } drawingEnabled_ { arg bool; this.setProperty( \drawingEnabled, bool ); } findWindow { ^window; } doDrawFunc { window.drawFunc.value(window) } } QWindow { classvar initAction; var resizable, acceptsClickThrough=false; var r.height ) { this.orientation_( \horizontal ); } { this.orientation_( \vertical ); } } } pixelStep { ^this.getProperty(\pixelStep) } orientation_ { arg aSymbol; orientation = aSymbol; this.setProperty( \orientation, QOrientation(aSymbol) ); } defaultKeyDownAction { arg char, modifiers, unicode, keycode, key; var scale = this.getScale( modifiers ); switch( char, $r, { this.valueAction = 1.0.rand }, $n, { this.valueAction = 0.0 }, $x, { this.valueAction = 1.0 }, $c, { this.valueAction = 0.5 }, { switch( key, 16r5d, { this.increment(scale) }, 16r1000013, { this.increment(scale) }, 16r1000014, { this.increment(scale) }, 16r5b, { this.decrement(scale) }, 16r1000015, { this.decrement(scale) }, 16r1000012, { this.decrement(scale) }, { ^this; } // if unhandled, let Qt process the event ); this.doAction; } ); ^true; // accept the event and stop its processing } defaultGetDrag { ^this.value; } defaultCanReceiveDrag { ^QView.currentDrag.isNumber; } defaultReceiveDrag { this.valueAction = QView.currentDrag; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QWebView.sc0000664000000000000000000001040512245365552025674 0ustar rootrootQWebView : QView { var 0) ) { if( this.beginDrag( x, y ) ) { ^true }; }; ^super.mouseMoveEvent(x, y, modifiers, buttons); } selectionMode_ { arg mode; var m; m = mode.switch( \none, {0}, \single, {1}, \multi, {2}, \extended, {3}, \contiguous, {4} ); if( m == 0 ) { this.invokeMethod( \clearSelection ); this.setProperty( \currentRow, -1 ); this.setProperty( \focusPolicy, 0 ); }; this.setProperty( \selectionMode, m ); } selectionMode { var modes = [\none, \single, \multi, \extended, \contiguous]; var m = this.getProperty( \selectionMode ); ^modes[m]; } value { var v = this.getProperty( \currentRow ); if( v < 0 ) { ^nil } { ^v }; } value_ { arg val; this.setProperty( \currentRow, val ? -1 ); } selection { ^ this.getProperty(\selection) } selection_ { arg indexes; if (indexes.isNumber) { indexes = [indexes] }; this.setProperty(\selection, indexes) } background { ^this.palette.base; } background_ { arg color; this.palette = this.palette.base_(color); } stringColor { ^this.palette.baseText; } stringColor_ { arg color; this.palette = this.palette.baseText_(color); } selectedStringColor { ^this.palette.highlightText; } selectedStringColor_ { arg color; this.palette = this.palette.highlightText_(color); } hiliteColor { ^this.palette.highlight; } hiliteColor_ { arg color; this.palette = this.palette.highlight_(color); } enterKeyAction_ { arg func; this.manageMethodConnection( enterKeyAction, func, 'returnPressed()', 'enterKey' ); enterKeyAction = func; } enterKey { enterKeyAction.value( this ); } selectionAction_ { arg func; this.manageFunctionConnection( selectionAction, func, 'itemSelectionChanged()' ); selectionAction = func; } colors_ { arg colorArray; colors = colorArray; this.setProperty( \colors, colorArray ); } defaultGetDrag { ^this.value; } defaultCanReceiveDrag { ^QView.currentDrag.isNumber; } defaultReceiveDrag { this.valueAction = QView.currentDrag; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QPen.sc0000664000000000000000000001323512245365552025052 0ustar rootrootQPen { classvar 150 ) { this.dragLabel = text.copyRange(0,149) ++ "..."; }{ this.dragLabel = text; } ^text; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QLayout.sc0000664000000000000000000001157312161364457025610 0ustar rootrootQLayout : QObject { spacing_ { arg spacing; this.setProperty( \spacing, spacing ); } margins_ { arg margins; this.setProperty( \margins, margins + [0,0,0,0] ); } } // LINE LAYOUTS /////////////////////////////////////////////////// QLineLayout : QLayout { *new { arg ...items; var serializedItems = items.collect( { |x| this.parse(x) } ); ^super.new( [serializedItems] ); } *parse { arg in; var out = [nil,0,0]; var key; var i; if( in.isKindOf(Array) ) { out[0] = in[0]; i = 1; while { i + 1 < in.size } { key = in[i]; case ( { (key === \stretch) || (key === \s) }, { out[1] = in[i+1] }, { (key === \align) || (key === \a) }, { out[2] = QAlignment(in[i+1]) } ); i = i + 2; }; }{ out[0] = in; }; ^out; } add { arg item, stretch = 0, align; this.invokeMethod( \addItem, [[item, stretch, QAlignment(align)]], true ); } insert { arg item, index=0, stretch = 0, align; this.invokeMethod( \insertItem, [[item, index, stretch, QAlignment(align)]], true ); } setStretch { arg item, stretch; this.invokeMethod( \setStretch, [item, stretch], true ); } setAlignment { arg item, align; this.invokeMethod( \setAlignment, [item, QAlignment(align)], true ); } } QHLayout : QLineLayout { *implementsClass {^'HLayout'} *qtClass { ^'QcHBoxLayout' } } QVLayout : QLineLayout { *implementsClass {^'VLayout'} *qtClass { ^'QcVBoxLayout' } } // GRID LAYOUT /////////////////////////////////////////////////// QGridLayout : QLayout { *implementsClass {^'GridLayout'} *new { // get rid of QObject's arguments ^super.new; } *qtClass { ^'QcGridLayout' } *parse { arg in, row, col; var out = [nil,row,col,1,1,nil]; var key; var i; if( in.isKindOf(Array) ) { out[0] = in[0]; i = 1; while { i + 1 < in.size } { key = in[i]; case ( { (key === \rows) || (key === \r) }, { out[3] = in[i+1] }, { (key === \columns) || (key === \c) }, { out[4] = in[i+1] }, { (key === \align) || (key === \a) }, { out[5] = QAlignment(in[i+1]) } ); i = i + 2; }; }{ out[0] = in; }; ^out; } *rows { arg ...rows ; var grid; var data; grid = this.new; rows.do { |row, r| if( row.size > 0 ) { row.do { |item, c| if( item.notNil ) { data = this.parse( item, r, c ); grid.invokeMethod( \addItem, [data], true ); }; }; }; } ^grid; } *columns { arg ...cols; var grid; var data; grid = this.new; cols.do { |col, c| if( col.size > 0 ) { col.do { |item, r| if( item.notNil ) { data = this.parse( item, r, c ); grid.invokeMethod( \addItem, [data], true ); }; }; }; } ^grid; } add { arg item, row, column, align; this.invokeMethod( \addItem, [[item, row, column, 1, 1, QAlignment(align)]], true ); } addSpanning { arg item, row, column, rowSpan=1, columnSpan=1, align; this.invokeMethod( \addItem, [[item, row, column, rowSpan, columnSpan, QAlignment(align) ]], true ); } hSpacing_ { arg spacing; this.setProperty( \horizontalSpacing, spacing ); } vSpacing_ { arg spacing; this.setProperty( \verticalSpacing, spacing ); } setRowStretch{ arg row, factor; this.invokeMethod( 'setRowStretch', [row, factor], true ); } setColumnStretch{ arg column, factor; this.invokeMethod( 'setColumnStretch', [column, factor], true ); } setAlignment { arg item, align; var args = if( item.class === Point ) { [item.y, item.x, QAlignment(align)] } { [item, QAlignment(align)] }; this.invokeMethod( \setAlignment, args, true ); } minRowHeight { arg row; ^this.invokeMethod( \minRowHeight, row ); } setMinRowHeight { arg row, height; this.invokeMethod( \setMinRowHeight, [row, height] ); } minColumnWidth { arg column; ^this.invokeMethod( \minColumnWidth, column ); } setMinColumnWidth { arg column, width; this.invokeMethod( \setMinColumnWidth, [column, width] ); } } QStackLayout : QLayout { *implementsClass {^'StackLayout'} *qtClass { ^'QcStackLayout' } *new { arg ...views; ^super.new([views]) } add { arg view; this.insert(view, -1) } insert { arg view, index = 0; this.invokeMethod( \insertWidget, [index, view] ) } index { ^this.getProperty(\currentIndex) } index_ { arg value; this.setProperty(\currentIndex, value) } count { ^this.getProperty(\count) } mode { ^this.getProperty(\stackingMode) } mode_ { arg value; value = value.switch( \stackOne, 0, \stackAll, 1, value ); value = value.clip(0, 1).asInteger; this.setProperty(\stackingMode, value) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QMultiSliderView.sc0000664000000000000000000001004212161364457027411 0ustar rootrootQMultiSliderView : QView { var 1 ) { i = this.index; ^val[i..(i+c-1)]; } ^this.value; } defaultCanReceiveDrag { ^true; } defaultReceiveDrag { arg data = QView.currentDrag; if( data.size > 0 ) { if( data[0].size > 0 ) { this.value = data[0]; this.reference = data[1]; }{ this.value = data; } }; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/flowViewSupportQt.sc0000664000000000000000000000026412014636263027703 0ustar rootroot + QWindow { asPageLayout { arg title,bounds; ^PageLayout.on(this,bounds) } } + QView { asPageLayout { arg title,bounds; ^FlowView(this,bounds ?? {this.bounds}) } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QScope.sc0000664000000000000000000000137712161364457025405 0ustar rootrootQScope : QView { var smallSize, <>largeSize; // runtime (mutable at runtime) var screenBounds.width) { x = floor(right % screenBounds.width / (w + 10)) * (w + 10) + 10 }; x = x + screenBounds.left; ^Rect(x, y, w, h) } *new { arg server, numChannels = 2, index = 0, bufsize = 4096, zoom = 1.0, rate = \audio, view, bufnum; var bus; if(server.isNil) {server = this.defaultServer}; if(server.isLocal.not) {Error("Can not scope on remote server.").throw}; bus = Bus(rate, index, numChannels, server); ^super.new.initQStethoscope( server, view, bus, bufsize, 1024 * zoom.asFloat.reciprocal ); } initQStethoscope { arg server_, parent, bus_, bufsize_, cycle_; var singleBus; server = server_; synth = BusScopeSynth(server); maxBufSize = max(bufsize_, 128); bus = bus_; singleBus = bus.class === Bus; aBusSpec = ControlSpec(0, server.options.numAudioBusChannels, step:1); cBusSpec = ControlSpec(0, server.options.numControlBusChannels, step:1); if( singleBus ) { busSpec = if(bus.rate===\audio){aBusSpec}{cBusSpec}; }; cycleSpec = ControlSpec( maxBufSize, 64, \exponential ); yZoomSpec = ControlSpec( 0.125, 16, \exponential ); cycle = cycleSpec.constrain(cycle_); yZoom = 1.0; smallSize = Size(250,250); largeSize = Size(500,500); makeGui = { arg parent; var gizmo; // WINDOW, WRAPPER VIEW if( window.notNil ) {window.close}; if( parent.isNil ) { view = window = QWindow( bounds: (smallSize).asRect.center_(QWindow.availableBounds.center) ).name_("Stethoscope"); }{ view = QView( parent, Rect(0,0,250,250) ); window = nil; }; // WIDGETS scopeView = QScope2(); scopeView.server = server; scopeView.canFocus = true; cycleSlider = QSlider().orientation_(\horizontal).value_(cycleSpec.unmap(cycle)); yZoomSlider = QSlider().orientation_(\vertical).value_(yZoomSpec.unmap(yZoom)); rateMenu = QPopUpMenu().items_(["Audio","Control"]).enabled_(singleBus); idxNumBox = QNumberBox().decimals_(0).step_(1).scroll_step_(1).enabled_(singleBus); chNumBox = QNumberBox().decimals_(0).step_(1).scroll_step_(1) .clipLo_(1).clipHi_(128).enabled_(singleBus); if( singleBus ) { rateMenu.value_(if(bus.rate===\audio){0}{1}); idxNumBox.clipLo_(busSpec.minval).clipHi_(busSpec.maxval).value_(bus.index); chNumBox.value_(bus.numChannels); }; styleMenu = QPopUpMenu().items_(["Tracks","Overlay","X/Y"]); // LAYOUT gizmo = "999".bounds( idxNumBox.font ).width + 20; idxNumBox.fixedWidth = gizmo; chNumBox.fixedWidth = gizmo; idxNumBox.align = \center; chNumBox.align = \center; view.layout = QGridLayout() .add( QHLayout( rateMenu, idxNumBox, chNumBox, nil, styleMenu ).margins_(0).spacing_(2), 0, 0 ) .add(scopeView,1,0) .add(yZoomSlider.maxWidth_(15), 1,1) .add(cycleSlider.maxHeight_(15), 2,0) .margins_(2).spacing_(2); // ACTIONS cycleSlider.action = { |me| setCycle.value(cycleSpec.map(me.value)) }; yZoomSlider.action = { |me| setYZoom.value(yZoomSpec.map(me.value)) }; idxNumBox.action = { |me| setIndex.value(me.value) }; chNumBox.action = { |me| setNumChannels.value(me.value) }; rateMenu.action = { |me| setRate.value(me.value) }; styleMenu.action = { |me| setStyle.value(me.value) }; view.asView.keyDownAction = { |v, char, mod| this.keyDown(char, mod) }; view.onClose = { view = nil; this.quit; }; // LAUNCH scopeView.focus; if( window.notNil ) { window.front }; }; setCycle = { arg val; cycle = val; synth.setCycle(val); }; setYZoom = { arg val; yZoom = val; scopeView.yZoom = val; }; // NOTE: assuming a single Bus setIndex = { arg i; bus = Bus(bus.rate, i, bus.numChannels, bus.server); synth.setBusIndex(i); }; // NOTE: assuming a single Bus setNumChannels = { arg n; // we have to restart the whole thing: bus = Bus(bus.rate, bus.index, n, bus.server); updateColors.value; this.run; }; // NOTE: assuming a single Bus setRate = { arg val; val.switch ( 0, { bus = Bus(\audio, bus.index, bus.numChannels, bus.server); busSpec = aBusSpec; }, 1, { bus = Bus(\control, bus.index, bus.numChannels, bus.server); busSpec = cBusSpec; } ); synth.setRate(val); idxNumBox.clipLo_(busSpec.minval).clipHi_(busSpec.maxval).value_(bus.index); this.index = bus.index; // ensure conformance with busSpec; updateColors.value; }; setStyle = { arg val; if(this.numChannels < 2 and: { val == 2 }) { "QStethoscope: x/y scoping with one channel only; y will be a constant 0".warn; }; scopeView.style = val; }; updateColors = { var colors; bus.do { |b| var c = if(b.rate === \audio){Color.new255(255, 218, 000)}{Color.new255(125, 255, 205)}; colors = colors ++ Array.fill(b.numChannels, c); }; scopeView.waveColors = colors; }; makeGui.value(parent); updateColors.value; ServerTree.add(this, server); ServerQuit.add(this, server); this.run; } doOnServerTree { this.run; } doOnServerQuit { this.stop; } run { synth.play(maxBufSize, bus, cycle); if( view.notNil && synth.bufferIndex.notNil) { scopeView.bufnum = synth.bufferIndex; scopeView.start; }; } stop { if( view.notNil ) { {scopeView.stop}.defer }; synth.stop; } quit { var win; this.stop; synth.free; if(window.notNil) { win = window; window = nil; { win.close }.defer; }; ServerTree.remove(this, server); ServerQuit.remove(this, server); } setProperties { arg numChannels, index, bufsize, zoom, rate; var new_bus; // process args if(index.notNil || numChannels.notNil || rate.notNil) { bus = if(bus.class === Bus) { Bus ( rate ? bus.rate, index ? bus.index, numChannels ? bus.numChannels, server ) }{ Bus ( rate ? \audio, index ? 0, numChannels ? 2, server ) }; }; if(bufsize.notNil) { maxBufSize = max(bufsize, 128) }; // set other vars related to args busSpec = if(bus.rate === \audio) {aBusSpec} {cBusSpec}; cycleSpec = ControlSpec( maxBufSize, 64, \exponential ); if(zoom.notNil) { cycle = cycleSpec.constrain( 1024 * zoom.asFloat.reciprocal ) }; // update GUI cycleSlider.value = cycleSpec.unmap(cycle); rateMenu.value_(if(bus.rate === \audio){0}{1}).enabled_(true); idxNumBox.clipLo_(busSpec.minval).clipHi_(busSpec.maxval).value_(bus.index).enabled_(true); chNumBox.value_(bus.numChannels).enabled_(true); updateColors.value; if (synth.isRunning) { synth.play(maxBufSize, bus, cycle) }; } bufsize { ^maxBufSize } bus_ { arg b; var isSingle = b.class === Bus; bus = b; if( isSingle ) { busSpec = if(bus.rate === \audio) {aBusSpec} {cBusSpec}; rateMenu.value = if(b.rate===\audio){0}{1}; idxNumBox.clipLo_(busSpec.minval).clipHi_(busSpec.maxval).value_(bus.index); chNumBox.value = b.numChannels; }{ busSpec = nil; rateMenu.value = nil; idxNumBox.string = "-"; chNumBox.string = "-"; }; rateMenu.enabled = isSingle; idxNumBox.enabled = isSingle; chNumBox.enabled = isSingle; updateColors.value; if (synth.isRunning) { synth.play(maxBufSize, bus, cycle); }; } numChannels { var num; if( bus.class === Bus ) { ^bus.numChannels; }{ num = 0; bus.do { |b| num = num + b.numChannels }; ^num; } } // will always be clipped between 0 and the amount of channels // at the beginning of the current run numChannels_ { arg n; if( (bus.class === Bus).not ) { ^this }; setNumChannels.value(n); chNumBox.value = n; } index { if( bus.class === Bus ) { ^bus.index } { nil } } index_ { arg i; if( (bus.class === Bus).not ) { ^this }; setIndex.value( busSpec.constrain(i) ); idxNumBox.value = i; } rate { if( bus.class === Bus ) { ^bus.rate } { nil } } rate_ { arg argRate=\audio; var val; if( (bus.class === Bus).not ) { ^this }; val = if(argRate===\audio){0}{1}; setRate.value(val); rateMenu.value = val; } switchRate { if( bus.class === Bus ) { this.rate = if(bus.rate === \control) {\audio} {\control}; } } // [0, 1] -> [64, 8192] frames cycle_ { arg val; setCycle.value( cycleSpec.constrain(val) ); cycleSlider.value = cycleSpec.unmap(val); } xZoom_ { arg val; this.cycle = 1024 * val.asFloat.reciprocal } xZoom { ^(1024 * cycle.reciprocal) } zoom { ^this.xZoom } zoom_ { arg val; this.xZoom_(val ? 1) } // [0, 1] -> [0.125, 16] y scaling factor yZoom_ { arg val; setYZoom.value( yZoomSpec.constrain(val) ); yZoomSlider.value = yZoomSpec.unmap(val); } style_ { arg val; setStyle.value(val); styleMenu.value = val; } size_ { arg value; var sz = value.asSize; if( window.notNil ) { window.setInnerExtent(sz.width,sz.height) }; } toggleSize { if(window.notNil) { sizeToggle = sizeToggle.not; if(sizeToggle) { this.size = largeSize } { this.size = smallSize }; } } toInputBus { var i = server.options.numOutputBusChannels; var c = server.options.numInputBusChannels; this.bus = Bus(\audio, i, c, server); } toOutputBus { var c = server.options.numOutputBusChannels; this.bus = Bus(\audio, 0, c, server); } keyDown { arg char, mod; if (mod != 0) { ^false }; case ( { char === $i }, { this.toInputBus }, { char === $o }, { this.toOutputBus }, { char === $ }, { this.run }, { char === $s }, { this.style = (scopeView.style + 1).wrap(0,2) }, { char === $S }, { this.style = 2 }, { char === $j }, { if(this.index.notNil) {this.index = this.index - 1} }, { char === $k }, { this.switchRate; }, { char === $l }, { if(this.index.notNil) {this.index = this.index + 1} }, { char === $- }, { cycleSlider.increment; cycleSlider.doAction }, { char === $+ }, { cycleSlider.decrement; cycleSlider.doAction }, { char === $* }, { yZoomSlider.increment; yZoomSlider.doAction }, { char === $_ }, { yZoomSlider.decrement; yZoomSlider.doAction }, { char === $m }, { this.toggleSize }, { char === $.}, { this.stop }, { ^false } ); ^true; } } BusScopeSynth { // Encapsulate management of server resources var server, buffer, synthDefName, synth; var playThread, playCond; *new { arg server; var instance; server = server ? Server.default; instance = super.newCopyArgs(server); ServerQuit.add(instance); ^instance; } play { arg bufSize, bus, cycle; var synthDef; var synthArgs; var bufIndex; var busChannels; if(server.serverRunning.not) { ^this }; this.stop; if (buffer.isNil) { buffer = ScopeBuffer.alloc(server); synthDefName = "stethoscope" ++ buffer.index.asString; }; bufIndex = buffer.index.asInteger; if( bus.class === Bus ) { busChannels = bus.numChannels.asInteger; synthDef = SynthDef(synthDefName, { arg busIndex, rate, cycle; var z; z = Select.ar(rate, [ In.ar(busIndex, busChannels), K2A.ar(In.kr(busIndex, busChannels))] ); ScopeOut2.ar(z, bufIndex, bufSize, cycle ); }); synthArgs = [\busIndex, bus.index.asInteger, \rate, if('audio' === bus.rate, 0, 1), \cycle, cycle]; }{ synthDef = SynthDef(synthDefName, { arg cycle; var z = Array(); bus.do { |b| z = z ++ b.ar }; ScopeOut2.ar(z, bufIndex, bufSize, cycle); }); synthArgs = [\cycle, cycle]; }; playThread = fork { var cond; //("BufScopeSynth: waiting on previous synth...").postln; if (playCond.notNil) { playCond.wait }; //postln("BufScopeSynth: got way."); synthDef.send(server); server.sync; //postln("BufScopeSynth: synthdef sent."); synth = Synth.tail(RootNode(server), synthDef.name, synthArgs); //postln("BufScopeSynth: made synth:" + synth.nodeID); playCond = cond = Condition(); synth.onFree { |thisSynth| //postln("BufScopeSynth: Synth freed:" + thisSynth.nodeID); cond.test = true; cond.signal; if (synth.notNil and: {synth.nodeID == thisSynth.nodeID}) { synth = nil; } } } } stop { if (playThread.notNil) { playThread.stop; playThread = nil }; if (synth.notNil) { synth.free; synth = nil }; } isRunning { ^playThread.notNil } bufferIndex { ^ buffer !? { buffer.index } } setBusIndex { arg index; if( synth.notNil ) { synth.set(\busIndex, index) }; } setRate { arg rate; // 0 = audio, 1 = control if( synth.notNil ) { synth.set(\rate, rate) }; } setCycle { arg frames; if( synth.notNil ) { synth.set(\cycle, frames) }; } free { this.stop; if (buffer.notNil) { buffer.free; buffer = nil; }; ServerQuit.remove(this, server); } doOnServerQuit { buffer = nil; synth = nil; playCond = nil; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QRangeSlider.sc0000664000000000000000000000345512161364457026532 0ustar rootrootQRangeSlider : QAbstractStepValue { *qtClass { ^'QcRangeSlider' } *new { arg parent, bounds; ^super.new( parent, bounds ).initQRangeSlider( bounds ); } initQRangeSlider { arg bounds; var r; if( bounds.notNil ) { r = bounds.asRect; if( r.width > r.height ) { this.orientation_( \horizontal ); } { this.orientation_( \vertical ); } } } pixelStep { // FIXME for now we are using step instead ^this.step; } orientation_ { arg aSymbol; this.setProperty( \orientation, QOrientation(aSymbol) ); } lo { ^this.getProperty( \loValue ); } lo_ { arg aFloat; this.setProperty( \loValue, aFloat ); } activeLo_ { arg aFloat; this.lo_(aFloat); this.doAction; } hi { ^this.getProperty( \hiValue ); } hi_ { arg aFloat; this.setProperty( \hiValue, aFloat ); } activeHi_ { arg aFloat; this.hi_(aFloat); this.doAction; } range { ^(this.hi - this.lo); } range_ { arg aFloat; this.hi_( this.lo + aFloat; ) } activeRange_ { arg aFloat; this.range_(aFloat); this.doAction; } setSpan { arg lo, hi; this.lo_(lo); this.hi_(hi); } setSpanActive { arg lo, hi; this.setSpan(lo,hi); this.doAction; } setDeviation { arg deviation, average; this.lo_( average - deviation ); this.hi_( average + deviation ); } knobColor { ^this.getProperty(\knobColor) } knobColor_ { arg color; this.setProperty(\knobColor, color) } background { ^this.getProperty(\grooveColor) } background_ { arg color; this.setProperty(\grooveColor, color) } defaultGetDrag { ^Point(this.lo,this.hi); } defaultCanReceiveDrag { ^(QView.currentDrag.class === Point); } defaultReceiveDrag { var pt = QView.currentDrag; this.setSpanActive( pt.x, pt.y ); } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QKnob.sc0000664000000000000000000000561312161364457025222 0ustar rootroot// blackrain at realizedsound dot net - 05/2006 // fix key modidiers bug by Stephan Wittwer 08/2006 - thanks! // Knob updates only on value changes - 10/2006 // GUI.cocoa changes - 04/2007 // // 03.10.2008 - new implementation: // - Knob now is a subclass of SCViewHolder // - Relative origin // // 01.20.2009 - SCKnob // - a subclass of SCUserView again. // - isSquare option // // 08.03.2010 - QKnob = SCKnob adjusted for GUI.qt scheme (by Jakob Leben) QKnob : QAbstractStepValue { classvar <>defaultMode = \round; var <>keystep = 0.01; *qtClass {^'QcKnob'} *new { arg parent, bounds; var me = super.new(parent,bounds); me.mode = defaultMode; ^me; } value { ^this.getProperty(\value) } value_ { arg val; this.setProperty(\value, val) } valueAction_ { arg val; this.value = val; this.doAction } mode { var m = this.getProperty(\mode); ^ #[\round, \horiz, \vert].at(m); } mode_ { arg inputMode; var iMode; switch ( inputMode, \round, { iMode = 0}, \horiz, { iMode = 1}, \vert, { iMode = 2 }, { ^this } ); this.setProperty( \mode, iMode ); } centered_ { arg bool; this.setProperty( \centered, bool ); } centered { ^this.getProperty( \centered ); } background { ^this.palette.button; } background_ { arg color; this.palette = this.palette.button_(color); } // FIXME: find better alternatives to set colors separately. color_ { arg colors; var p; p = this.palette; p.button = colors[0]; p.windowText = colors[1]; p.window = colors[2]; p.buttonText = colors[3]; this.palette = p; } color { var p; p = this.palette; ^[p.button, p.windowText, p.window, p.buttonText]; } getScale { |modifiers| ^case { modifiers.isShift } { this.shift_scale } { modifiers.isCtrl } { this.ctrl_scale } { modifiers.isAlt } { this.alt_scale } { 1 }; } defaultKeyDownAction { arg char, modifiers, unicode, keycode, key; var zoom = this.getScale(modifiers); // standard keydown switch( char, $r, { this.valueAction = 1.0.rand }, $n, { this.valueAction = 0.0 }, $x, { this.valueAction = 1.0 }, $c, { this.valueAction = 0.5 }, { switch( key, 16r5b, { this.decrement(zoom) }, 16r5d, { this.increment(zoom) }, 16r1000013, { this.increment(zoom) }, 16r1000014, { this.increment(zoom) }, 16r1000015, { this.decrement(zoom) }, 16r1000012, { this.decrement(zoom) }, {^this} // propagate on if the key is a no-op ) } ); ^true; } increment { |zoom=1| ^this.valueAction = (this.value + (keystep * zoom)) } decrement { |zoom=1| ^this.valueAction = (this.value - (keystep * zoom)) } defaultGetDrag { ^this.value } defaultCanReceiveDrag { ^QView.currentDrag.isNumber } defaultReceiveDrag { this.valueAction = QView.currentDrag } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/dnd_views.sc0000664000000000000000000000202412161364457026163 0ustar rootrootQDragView : QTextField { *new { arg parent, bounds; ^super.new(parent,bounds).initQDragView } initQDragView { var plt = this.palette; plt.base = plt.window; this.palette = plt; this.setProperty(\readOnly, true); } // override QView.mouseDownEvent to initiate drag without keyboard modifier mouseDownEvent { arg x, y, modifiers, buttonNumber, clickCount; // Try to get drag obj and start a drag. // If successful, block further processing of this event. if( this.beginDrag( x, y ) ) { ^true }; // else continue to handle mouse down event modifiers = QKeyModifiers.toCocoa(modifiers); ^this.mouseDown( x, y, modifiers, buttonNumber, clickCount ); } defaultGetDrag { ^nil } defaultCanReceiveDrag { ^false } defaultReceiveDrag { } } QDragSource : QDragView { defaultGetDrag { ^object } } QDragSink : QDragView { defaultCanReceiveDrag { ^true } defaultReceiveDrag { this.object = QView.currentDrag; action.value(this); } } QDragBoth : QDragSink { defaultGetDrag { ^object } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QScope2.sc0000664000000000000000000000213612161364457025461 0ustar rootrootQScope2 : QView { var screenBounds.right) { x = floor(right % screenBounds.width / 223) * (223 + 5) }; ^Rect(x, y, 223, 223) } makeBounds { arg size = 223; ^Rect(297, 5, size, size) } makeWindow { arg view; if(view.isNil) { window = QWindow("stethoscope", this.makeBounds); view = window.view; view.decorator = FlowLayout(window.view.bounds); window.front; window.onClose = { this.free }; } { if(view.decorator.isNil, { "QStethoscope: makeWindow added a decorator to view".warn; view.decorator = FlowLayout(view.bounds); }); }; scopeView = QScope(view, Rect(0,0, view.bounds.width - 10 - 20 - 4, view.bounds.height - 40) ); scopeView.background = Color.black; scopeView.resize = 5; view.keyDownAction = { arg view, char; this.keyDown(char) }; view.background = Color.grey(0.6); zx = scopeView.xZoom.log2; zy = scopeView.yZoom.log2; audiospec = ControlSpec(0, server.options.numAudioBusChannels, step:1); controlspec = ControlSpec(0, server.options.numControlBusChannels, step:1); zoomspec = ControlSpec(0.125, 16, \exp); xZoomSlider = QSlider(view, Rect(10, 10, view.bounds.width - 80, 20)); xZoomSlider.action = { arg x; /*var i; i = this.spec.map(x.value); this.index = i;*/ this.xZoom = zoomspec.map(x.value) }; xZoomSlider.resize = 8; xZoomSlider.value = zoomspec.unmap(this.xZoom); xZoomSlider.background = Color.grey(0.6); xZoomSlider.focusColor = Color.clear; indexView = QNumberBox(view, Rect(10, 10, 30, 20)) .value_(0).decimals_(0).step_(1).scroll_step_(1); indexView.action = { this.index = indexView.value; }; indexView.resize = 9; indexView.font = QFont("Monaco", 9); nChanView = QNumberBox(view, Rect(10, 10, 25, 20)) .value_(numChannels).decimals_(0).step_(1).scroll_step_(1); nChanView.action = { this.numChannels = nChanView.value.asInteger }; nChanView.resize = 9; nChanView.font = QFont("Monaco", 9); QStaticText(view, Rect(10, 10, 20, 20)).visible_(false); this.updateColors; view.decorator.reset; view.decorator.shift(scopeView.bounds.right, 0); yZoomSlider = QSlider(view, Rect(scopeView.bounds.right, 0, 20, scopeView.bounds.height)); yZoomSlider.action = { arg x; this.yZoom = zoomspec.map(x.value) }; yZoomSlider.resize = 6; yZoomSlider.value = zoomspec.unmap(this.yZoom); yZoomSlider.background = Color.grey(0.6); yZoomSlider.focusColor = Color.clear; } keyDown { arg char; if(char === $i) { this.toInputBus; ^this }; if(char === $o) { this.toOutputBus; ^this }; if(char === $ ) { this.run; ^this }; if(char === $s) { this.style = (style + 1) % 2; ^this }; if(char === $S) { this.style = 2; ^this }; if(char === $j or: { char.ascii === 0 }) { this.index = index - 1; ^this }; if(char === $k) { this.switchRate; ^this }; if(char === $l or: { char.ascii === 1 }) { this.index = index + 1 }; if(char === $-) { zx = zx + 0.25; this.xZoom = 2 ** zx; ^this }; if(char === $+) { zx = zx - 0.25; this.xZoom = 2 ** zx; ^this }; if(char === $*) { zy = zy + 0.25; this.yZoom = 2 ** zy; ^this }; if(char === $_) { zy = zy - 0.25; this.yZoom = 2 ** zy; ^this }; if(char === $A) { this.adjustBufferSize; ^this }; if(char === $m) { this.toggleSize; ^this }; if(char === $.) { if(synth.isPlaying) { synth.free } }; } spec { ^if(rate === \audio) { audiospec } { controlspec } } setProperties { arg numChannels, index, bufsize=4096, zoom, rate; if(rate.notNil) { this.rate = rate }; if(index.notNil) { this.index = index }; if(numChannels.notNil) { this.numChannels = numChannels }; if(this.bufsize != bufsize) { this.allocBuffer(bufsize) }; if(zoom.notNil) { this.zoom = zoom }; } allocBuffer { arg argbufsize, argbufnum; bufsize = argbufsize ? bufsize; if(buffer.notNil) { buffer.free }; buffer = Buffer.alloc(server, bufsize, numChannels, nil, argbufnum); scopeView.bufnum = buffer.bufnum; if(synth.isPlaying) { synth.set(\bufnum, buffer.bufnum) }; } run { if(synth.isPlaying.not) { synth = SynthDef("stethoscope", { arg in, switch, bufnum; var z; z = Select.ar(switch, [In.ar(in, numChannels), K2A.ar(In.kr(in, numChannels))]); ScopeOut.ar(z, bufnum); }).play(RootNode(server), [\bufnum, buffer.bufnum, \in, index, \switch] ++ if('audio' === rate) { 0 } { 1 }, \addToTail ); synth.isPlaying = true; NodeWatcher.register(synth); } } free { buffer.free; if(synth.isPlaying) { synth.free }; synth = nil; if(server.scopeWindow === this) { server.scopeWindow = nil } } quit { window.close; this.free; } numChannels_ { arg n; var isPlaying; if(n > 128) { "cannot display more than 128 channels at once".inform; n = 128 }; if(n != numChannels and: { n > 0 }) { isPlaying = synth.isPlaying; if(isPlaying) { synth.free; synth.isPlaying = false; synth = nil }; // immediate numChannels = n; nChanView.value = n; this.allocBuffer; if(isPlaying) { this.run }; this.updateColors; }; } index_ { arg val=0; var spec; spec = this.spec; index = spec.constrain(val); if(synth.isPlaying) { synth.set(\in, index) }; if(rate === \audio) { ai = index } { ki = index }; indexView.value = index; // xZoomSlider.value = spec.unmap(index) } rate_ { arg argRate=\audio; if(rate === argRate) { ^this }; if(argRate === \audio) { if(synth.isPlaying) { synth.set(\switch, 0) }; rate = \audio; this.updateColors; ki = index; this.index = ai; } { if(synth.isPlaying) { synth.set(\switch, 1) }; rate = \control; this.updateColors; ai = index; this.index = ki; } } size_ { arg val; if(window.notNil) { window.bounds = this.makeBounds(val) } } toggleSize { if(sizeToggle == 0) { sizeToggle = 1; this.size_(500) } { sizeToggle = 0; this.size_(212) } } xZoom_ { arg val; scopeView.xZoom = val; zx = val.log2; xZoomSlider.value = zoomspec.unmap(val); } yZoom_ { arg val; scopeView.yZoom = val; zy = val.log2; yZoomSlider.value = zoomspec.unmap(val); } xZoom { ^2.0 ** zx } yZoom { ^2.0 ** zy } zoom_ { arg val; this.xZoom_(val ? 1) } style_ { arg val; if(numChannels < 2 and: { val == 2 }) { "QStethoscope: can't do x/y scoping with one channel".warn; ^this; }; scopeView.style = style = val } updateColors { scopeView.waveColors = if(\audio === rate) { Array.fill(numChannels, { Color.new255(255, 218, 000) }); } { Array.fill(numChannels, { Color.new255(125, 255, 205) }); } } switchRate { if(rate === \control) { this.rate = \audio } { this.rate = \control } } toInputBus { this.index = server.options.numOutputBusChannels; this.numChannels = server.options.numInputBusChannels; } toOutputBus { this.index = 0; this.numChannels = server.options.numOutputBusChannels; } adjustBufferSize { this.allocBuffer(max(256,nextPowerOfTwo( asInteger(scopeView.bounds.width * scopeView.xZoom)))) } // ugenScopes *ugenScopes { if(ugenScopes.isNil, { ugenScopes = Set.new; }); ^ugenScopes } /** * @return (Server) the default server to scope on */ *defaultServer { ^Server.internal; } /** * @param aServer (Server) a server to test for scoping * @return (Boolean) indication whether the server can be scope'ed */ *isValidServer { arg aServer; ^aServer.inProcess; } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/QLevelIndicator.sc0000664000000000000000000001343412161364457027235 0ustar rootrootQLevelIndicator : QView { *qtClass {^'QcLevelIndicator'} value { ^this.getProperty(\value) } value_ { arg val; this.setProperty(\value, val); } valueAction_ { arg val; this.setProperty(\value, val); this.doAction; } warning_ {arg val; this.setProperty(\warning, val); } critical_ {arg val; this.setProperty(\critical, val); } // NOT IMPLEMENTED style_ {arg val; this.nonimpl("style"); } background { ^this.getProperty(\grooveColor) } background_ { arg color; this.setProperty(\grooveColor, color) } numSteps_ {arg val; this.nonimpl("numSteps"); } image_ {arg image; this.nonimpl("image"); } numTicks_ {arg number; this.setProperty(\ticks, number); } numMajorTicks_ {arg number; this.setProperty(\majorTicks, number); } drawsPeak_ {arg bool; this.setProperty(\drawPeak, bool); } peakLevel_ { arg val; this.setProperty(\peak, val); } *meterServer { arg server; var window, inmeters, outmeters, inresp, outresp, insynth, outsynth, func; var numIns, numOuts; var view, viewWidth, meterWidth = 15, gapWidth = 4; var updateFreq = 10, dBLow = -80; var numRMSSamps, numRMSSampsRecip; numIns = server.options.numInputBusChannels; numOuts = server.options.numOutputBusChannels; viewWidth = (numIns + numOuts + 2) * (meterWidth + gapWidth); window = Window.new(server.name ++ " levels (dBFS)", Rect(5, 305, viewWidth + 20, 230)); window.view.background = Color.grey(0.4); view = CompositeView(window, Rect(10,25, viewWidth, 180) ); view.addFlowLayout(0@0, gapWidth@gapWidth); // dB scale UserView(view, Rect(0,0,meterWidth,195)).drawFunc_({ Pen.color = Color.white; Pen.font = Font("Helvetica", 10, true); Pen.stringCenteredIn("0", Rect(0, 0, meterWidth, 12)); Pen.stringCenteredIn("-80", Rect(0, 170, meterWidth, 12)); }); (numIns > 0).if({ // ins StaticText(window, Rect(10, 5, 100, 15)) .font_(Font("Helvetica", 10, true)) .stringColor_(Color.white) .string_("Inputs"); inmeters = Array.fill( numIns, { arg i; var comp; comp = CompositeView(view, Rect(0,0,meterWidth,195)).resize_(5); StaticText(comp, Rect(0, 180, meterWidth, 15)) .font_(Font("Helvetica", 9, true)) .stringColor_(Color.white) .string_(i.asString); LevelIndicator( comp, Rect(0,0,meterWidth,180) ).warning_(0.9).critical_(1.0) .drawsPeak_(true) .numTicks_(9) .numMajorTicks_(3); }); // divider UserView(view, Rect(0,0,meterWidth,180)).drawFunc_({ Pen.color = Color.white; Pen.line(((meterWidth + gapWidth) * 0.5)@0, ((meterWidth + gapWidth) * 0.5)@180); Pen.stroke; }); }); // outs StaticText(window, Rect(10 + if(numIns > 0 , ((numIns + 2) * (meterWidth + gapWidth)), 0), 5, 100, 15)) .font_(Font("Helvetica", 10, true)) .stringColor_(Color.white) .string_("Outputs"); outmeters = Array.fill( numOuts, { arg i; var comp; comp = CompositeView(view, Rect(0,0,meterWidth,195)); StaticText(comp, Rect(0, 180, meterWidth, 15)) .font_(Font("Helvetica", 9, true)) .stringColor_(Color.white) .string_(i.asString); LevelIndicator( comp, Rect(0,0,meterWidth,180) ).warning_(0.9).critical_(1.0) .drawsPeak_(true) .numTicks_(9) .numMajorTicks_(3); }); window.front; func = { numRMSSamps = server.sampleRate / updateFreq; numRMSSampsRecip = 1 / numRMSSamps; (numIns > 0).if({ inresp = OSCProxy({ |msg, t| {try { msg.copyToEnd(3).pairsDo({|val, peak, i| var meter; i = i * 0.5; meter = inmeters[i]; meter.value = (val.max(0.0) * numRMSSampsRecip).sqrt.ampdb.linlin(dBLow, 0, 0, 1); meter.peakLevel = peak.ampdb.linlin(dBLow, 0, 0, 1); }) }}.defer; }, ("/" ++ server.name ++ "InLevels").asSymbol, server.addr).fix; }); outresp = OSCProxy({ |msg, t| {try { msg.copyToEnd(3).pairsDo({|val, peak, i| var meter; i = i * 0.5; meter = outmeters[i]; meter.value = (val.max(0.0) * numRMSSampsRecip).sqrt.ampdb.linlin(dBLow, 0, 0, 1); meter.peakLevel = peak.ampdb.linlin(dBLow, 0, 0, 1); }) }}.defer; }, ("/" ++ server.name ++ "OutLevels").asSymbol, server.addr).fix; server.bind({ (numIns > 0).if({ insynth = SynthDef(server.name ++ "InputLevels", { var in, imp; in = In.ar(NumOutputBuses.ir, numIns); imp = Impulse.ar(updateFreq); SendReply.ar(imp, "/" ++ server.name ++ "InLevels", // do the mean and sqrt clientside to save CPU [ RunningSum.ar(in.squared, numRMSSamps), Peak.ar(in, Delay1.ar(imp)).lag(0, 3)] .flop.flat ); }).play(RootNode(server), nil, \addToHead); }); outsynth = SynthDef(server.name ++ "OutputLevels", { var in, imp; in = In.ar(0, numOuts); imp = Impulse.ar(updateFreq); SendReply.ar(imp, "/" ++ server.name ++ "OutLevels", // do the mean and sqrt clientside to save CPU [ RunningSum.ar(in.squared, numRMSSamps), Peak.ar(in, Delay1.ar(imp)).lag(0, 3) ].flop.flat ); }).play(RootNode(server), nil, \addToTail); }); }; window.onClose_({ (server.options.numInputBusChannels > 0).if({ inresp.clear;}); outresp.clear; insynth.free; outsynth.free; ServerTree.remove(func); }); ServerTree.add(func); if(server.serverRunning, func); // otherwise starts when booted } } SuperCollider-3.6.6-Source-linux~repack/SCClassLibrary/QtCollider/BasicViews.sc0000664000000000000000000001762012161364457026250 0ustar rootroot/////////////////////// ABSTRACT CLASSES //////////////////////////// QTextViewBase : QView { var setBoth = true; var Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . SuperCollider-3.6.6-Source-linux~repack/HelpSource/0000775000000000000000000000000012413455462021040 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/HelpSource/Other/0000775000000000000000000000000012245452763022125 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/HelpSource/Other/.placeholder0000664000000000000000000000000012014636263024367 0ustar rootrootSuperCollider-3.6.6-Source-linux~repack/HelpSource/Other/ccbysa3_88x31.png0000664000000000000000000001173312014636263025033 0ustar rootrootPNG  IHDRXc pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_FIDATxZKl!2"v}JtuyJ,iSe-vԤ  rH([ڡ1&h0WjZmRpFP$J[awA;;wCq1 Ț !aq:X˲8,ˁcYyeY0 a0 0@':tHW]uD ! 0.qFbR:3Af0_XSdkNu]ځ~@8x]d2T*¬CQ;w>24˪ƀh,0XڦNs1{o, clQx uǖU^[TVFwSSSRvv삪i4j&Mjᕘ\1x^d2Pi‰ 6Ȳ ˅޾e)u 55/ӛ7WX-8 +#pid2IAd  ;b1xˊ b,s]L޾y^Z[kS 6Xw588$k>ӗ6eL5= %fz n0xy@%/ ȦK?sx0Uw2kWSo!SDA#>55kW &’JO$YHm{5?e?~%@PTl)LRpBm( ~?|>|>ut䭤%0M7). x]utR6>Znc0`Tp$( |>(PP~^8]%IB"@*2v6`%+T\,y,$5<'޾M5(k*dz䇗럜DwW0z{Π ::NZ`Rng r9Zgm>$Iu~џ%_L: 9x9bV?x8Ǐ70mK+Y˝};\.~?e<~?rp"tb_IqZ[in^~`\u-b||6D"6mrge2yuX\u Ķ5ݼ{}e,CEA( %J1뭟ۣwGaDdigi"Pq^xG/B<͡XCQ-XTYq ]4_S6+if> ߄0ꥭ },~g7s+(eW|,zv<6VhRnb\<Nthqv1j|of]+l QE<^GFtq@:"d^dɫ|Z($NJ.#(_"i2v/Ezz{hw(noȝ|!_ n2== Ӥ@ع!w2c#]0NigxDž G+>2醪M^_ i}Y~Vϰ߯DSg`4H|@nGv$s?Md{yo, ,VR\5- _JrW\]~^o =kr*FϮ~bn3*b֭۶3҅mp#~'Sx| ##k @\kӰг{lɮ]سwm߆\Z}U(qƚM1x)? C0@ B E|IENDB`SuperCollider-3.6.6-Source-linux~repack/HelpSource/Other/HelpDocsLicensing.html0000664000000000000000000000244112014636263026342 0ustar rootroot SuperCollider documentation licensing

    License for SuperCollider Help

     

    Creative Commons License SuperCollider help documentation is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.

    Executable SuperCollider code remains under the GPL as stated in SuperCollider's main license conditions.

    To supply attribution for a help document (which may have multiple contributors), unless otherwise indicated you may credit "SuperCollider 3 documentation contributors".

     

    (Note for editors: Please edit the source directly. This is because the HTML source has embedded metadata.)

    SuperCollider-3.6.6-Source-linux~repack/HelpSource/Other/Licensing.html0000664000000000000000000000444512014636263024726 0ustar rootroot

    SuperCollider Licensing 

    SuperCollider is copyright © James McCartney and many other contributors.

    SuperCollider is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.


    --

    Some further notes:

    SuperCollider was originally published under the terms of version 2 or later of the GPL, but the application now includes some GPL3-licensed code. If you have a need specifically for GPL2 compatibility then it is possible to recompile SuperCollider from source without the GPL3 elements.

    SuperCollider's help documentation is published under a Creative Commons license.

    SuperCollider-3.6.6-Source-linux~repack/HelpSource/lang-sc.js0000664000000000000000000000267312014636263022727 0ustar rootrootPR.registerLangHandler( PR.createSimpleLexer( [ /* whitespace */ [PR.PR_PLAIN, /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'], /* strings */ [PR.PR_STRING, /^"(?:[^\\"]|\\.)*(?:"|$)/, null, '"'], ], [ /* char literal */ [PR.PR_LITERAL, /^\$(\\)?./], /* symbols */ [PR.PR_ATTRIB_NAME, /^\\\w+/], [PR.PR_ATTRIB_NAME, /^'[^']+'/], [PR.PR_ATTRIB_VALUE, /^~\w+/], /* special variables */ [PR.PR_TAG, /^(?:super|thisFunctionDef|thisFunction|thisMethod|thisProcess|thisThread|this)\b/], /* special values */ [PR.PR_KEYWORD, /^(?:true|false|nil|inf)\b/], /* variable declarations */ [PR.PR_DECLARATION, /^(?:var|classvar|const|arg)\b/], // [PR.PR_DECLARATION, /^\|/], /* class names */ [PR.PR_TYPE, /^\b([A-Z][A-Za-z_0-9]+)\b/], [PR.PR_COMMENT, /^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/], //fixme: nested comments /* numbers */ [PR.PR_LITERAL, /^-?\d+r[\da-zA-Z]+(\.[\da-zA-Z]+)?/], // [PR.PR_LITERAL, /^-?(?:(?:\d+(?:\.\d*)?)(?:e[+\-]?\d+)?)(pi)?|pi/], [PR.PR_LITERAL, /^-?(?:(?:\d+(\.\d+)?)(?:e[+\-]?\d+)?(pi)?)|(?:pi\b)/], /* other stuff */ [PR.PR_PLAIN, /^[a-z_]\w*/i], // [PR.PR_PUNCTUATION, /^[-.,;!?#$%&\|/+*<>=@()\[\]{}]/] [PR.PR_PUNCTUATION, /^[-.,;#()\[\]{}]/] ]), ['sc']); SuperCollider-3.6.6-Source-linux~repack/HelpSource/Overviews/0000775000000000000000000000000012245452763023035 5ustar rootrootSuperCollider-3.6.6-Source-linux~repack/HelpSource/Overviews/.placeholder0000664000000000000000000000000012014636263025277 0ustar rootrootSuperCollider-3.6.6-Source-linux~repack/HelpSource/Overviews/Event_types.schelp0000664000000000000000000000475512014636263026546 0ustar rootroottitle:: Event types summary:: Different ways that an Event can "play" categories:: Streams-Patterns-Events>Events related:: Classes/Event Note:: this helpfile is incomplete. :: An link::Classes/Event:: responds to a code::play:: message by evaluating ~play in the event, and the default behaviour of ~play is determined by the value of ~type. Commonly-used event types include: definitionlist:: ## \note || used to instantiate a synth on the server, with specified arguments, and later to free it. The choice of link::Classes/SynthDef:: is specified using the \instrument key. This event type is commonly implicit in much Pattern usage. ## \set || used to set parameters of some already-running node(s). (See also: note in link::Classes/Pmono:: helpfile) :: A more complete list of event types is given further down this document. To see how event types are normally invoked, here is a slightly simplified version of the default definition of ~play as defined in the Event class: code:: { ~eventTypes[~type].value(server); }, :: The function uses the value of ~type to select a function from the Dictionary held in ~eventTypes. The collection of eventTypes can be readily extended using link::Classes/Event#*addEventType#*addEventType::(key, function). Here is an example the uses the event types \group and \note: code:: (type: \group, id: 2).play // create a group with nodeID 2 (type: \note, freq: 500, group: 2).play // play a synth in that group :: Here is a listing of currently existing event types: definitionlist:: ## group || creates group, ~id must be specified ## note || ~instrument specifies synthdef ## note_score || ## midi || ## monoNote || used by Pmono ## monoSet || used by Pmono ## monoOff || ## on || play synth, ~id must be specified ## off || release synth (or free if no gate) ## kill || free synth ## set || set parameter of synth ## rest || do nothing ## bus || write ~array to control buses starting at ~out ## alloc || allocate ~bufnum with ~numframes and ~numchannels ## free || free ~bufnum ## gen || send ~gencmd to ~bufnum ## load || load ~filename starting at ~frame into ~bufnum ## read || ## setProperties ~receiver, ~args || sends setter messages to ~receiver for each key in ~args that has a nonNil value in the Event. ## tree || creates a tree of groups. ~tree can be an array of nodeIDs, and may contain associations to further nested arrays. ## phrase || instead of playing a single synth from a SynthDef with ~instrument, it looks up a Pdef and plays a cluster of sounds. :: SuperCollider-3.6.6-Source-linux~repack/HelpSource/Overviews/ClassTree.schelp0000664000000000000000000000021012014636263026104 0ustar rootroottitle:: Class Tree related:: Overviews/Classes summary:: The whole class inheritance tree categories:: Language>OOP classtree::Object SuperCollider-3.6.6-Source-linux~repack/HelpSource/Overviews/Collections.schelp0000664000000000000000000000305012014636263026502 0ustar rootroottitle:: Collections summary:: A hierarchical overview of Collection subclasses categories:: Collections related:: Classes/Collection SuperCollider has a rich hierarchy of Collection subclasses, detailed below. Subclasses of a given class are indented (sub-lists) relative to the class. Classes labelled "abstract" are not for direct use, but classes lower down the tree may inherit methods from them. For this reason it is important to consult the helpfiles of classes farther up the tree in order to get a complete list of available methods. section:: Hierarchy classtree::Collection subsection:: Notes definitionlist:: ## link::Classes/List:: || is an expandable link::Classes/SequenceableCollection:: (compare to link::Classes/ArrayedCollection:: and link::Classes/Array::). ## link::Classes/Array:: || is more efficient than link::Classes/List::. ## link::Classes/SparseArray:: || is an array of elements optimized for huge gaps between them. ## link::Classes/TwoWayIdentityDictionary:: || is similar to link::Classes/IdentityDictionary:: and allows easy searching by both key and value. It is faster than link::Classes/IdentityDictionary:: on reverse lookup, but with more memory overhead. ## link::Classes/Environment:: || is an link::Classes/IdentityDictionary::, one of which is always current; useful for creating sets of persistent variables. ## link::Classes/Event:: || is a dictionary mapping names of musical parameters to their values. ## link::Classes/IdentitySet:: || is an unordered collection of unidentical objects (compare to link::Classes/Set::). :: SuperCollider-3.6.6-Source-linux~repack/HelpSource/Overviews/Documents.html0000664000000000000000000001076612161364457025675 0ustar rootroot Documents