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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 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 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698
|
<!DOCTYPE html>
<html><head><title>Xmusic and Algorithmic Composition</title>
<link rel="stylesheet" type="text/css" href="nyquiststyle.css">
<link rel="icon" href="nyquist-icon.png" />
<link rel="shortcut icon" href="nyquist-icon.png" />
</head>
<body bgcolor="ffffff">
<a href = "part14.html">Previous Section</a> | <a href = "part16.html">Next Section</a> | <a href = "title.html#toc">Table of Contents</a> | <a href = "indx.html">Index</a> | <a href = "title.html">Title Page</a>
<hr>
<a name = "157"><h2>Xmusic and Algorithmic Composition</h2></a><a name="index1163"></a><a name="index1164"></a>
<p>Several Nyquist libraries offer support for algorithmic composition. Xmusic
is a library for generating sequences and patterns of data. Included in Xmusic
are:
<ul>
<li>
pattern objects, used to generate interesting sequences of parameter values,</li>
<li>random number generators, used to create random sequences from
different distributions (contained in the <code>distributions.lsp</code>
library) </li>
<li>a standard representation for "note lists" called <i>scores</i> and
functions to render them as sounds, </li>
<li>the <code>score-gen</code> macro which helps to generate scores from patterns, </li>
<li>score manipulation functions to select, transform, shift, and perform
other operations on scores.
</li></ul></p>
<a name = "158"><h3>Xmusic Basics</h3></a>
<p>Xmusic is inspired by and based on Common Music by Rick Taube.
Common Music supports MIDI and
various other synthesis languages and includes a graphical interface, some
visualization tools, and many other features. Common Music runs in Common
Lisp and Scheme, but not XLISP (the base language for Nyquist). </p>
<p>The Xmusic libraries in Nyquist offer an interesting subset of the
tools in Common Music. One important feature of Xmusic is that it is
integrated with all of the Nyquist synthesis functions, so you can use
Xmusic patterns and scores to control fine details of sound
synthesis. </p>
<a name = "159"><h3>Xmusic Patterns</h3></a><a name="index1165"></a>
<p>Xmusic patterns are objects that generate data streams. For example,
the <code>cycle-class</code> of objects generate cyclical patterns such as
"1 2 3 1 2 3 1 2 3 ...", or "1 2 3 4 3 2 1 2 3 4 ...". Patterns can
be used to specify pitch sequences, rhythm, loudness, and other parameters.</p>
<p>Xmusic functions are automatically loaded when you start Nyquist.
To use a pattern object, you first create the pattern, e.g.
</p>
<pre>
set pitch-source = make-cycle(list(c4, d4, e4, f4))
</pre>
<p>
<a name="index1166"></a><a name="index1167"></a>
In this example, <code>pitch-source</code> is an object of class
<code>cycle-class</code> which inherits from <code>pattern-class</code>. </p>
<small>
Because SAL is not an object-oriented language, these classes and
their methods are not directly accessible from SAL.
Instead, Xmusic defines a functional interface, e.g. <code>make-cycle</code>
creates an instance of <code>cycle-class</code>, and the <code>next</code>
function, introduced below, retrieves the next value from any instance
of <code>pattern-class</code>. Using LISP syntax, you can have full access
to the methods of all objects (see the source code in <code>xm.lsp</code>,
but the functional interface described here should be sufficient and
it is recommended that you limit your access to this interface.
</small>
<p>After creating the pattern, you can access it repeatedly
with <code>next</code><a name="index1168"></a> to generate data, e.g.
</p>
<pre>
play seqrep(i, 13, pluck(next(pitch-source), 0.2))
</pre>
<p>
This will create a sequence of notes with the following pitches: c, d,
e, f, c, d, e, f, c, d, e, f, c. If you evaluate this again, the
pitch sequence will continue, starting on "d".</p>
<p>It is very important not to confuse the creation of a sequence with
its access. Consider this example:
</p>
<pre>
play seqrep(i, 13,
pluck(next(make-cycle(list(c4, d4, e4, f4))), 0.2))
</pre>
<p>
This looks very much like the previous example, but it only repeats notes
on middle-C. The reason is that every time <code>pluck</code> is evaluated,
<code>make-cycle</code> is called and creates a new pattern object. After the
first item of the pattern is extracted with <code>next</code>, the cycle is not
used again, and no other items are generated.</p>
<p>To summarize this important point, there are two steps to using a pattern.
First, the pattern is created and stored in a
variable. Second, the pattern is accessed (multiple
times) using <code>next</code>.</p>
<dl>
<dt>
<code>next(<a name="index1169"></a><i>pattern-object</i> [, #t])</code> [SAL]<br>
<code>(next <i>pattern-object</i> [t])</code> [LISP]</dt>
<dd>Returns the next element from a pattern generator object. If the optional second argument is true (default value is false), then an entire period is returned as a list.
</dd></dl> <a name = "160"><h4>Nested Patterns</h4></a>
<p>Patterns can be nested, that is, you can write patterns of patterns.
In general, the <code>next</code> function does not return patterns. Instead,
if the next item in a pattern is a (nested) pattern, <code>next</code> recursively
gets the next item of the nested pattern.</p>
<p>While you might expect that each call to <code>next</code> would advance the
top-level pattern to the next item, and descend recursively if necessary
to the inner-most nesting level, this is not how <code>next</code> works. Instead,
<code>next</code> remembers the last top-level item, and if it was a pattern,
<code>next</code> continues to generate items from that same inner pattern
until the end of the inner pattern's <i>period</i> is reached. The next
paragraph explains the concept of the <i>period</i>.</p>
<a name = "161"><h4>Periods</h4></a>
<p>The data returned by a pattern object is structured into logical groups
called <i>periods</i>. You can get an entire period (as a list) by calling
<code>next(<i>pattern</i>, t)</code><a name="index1170"></a>. For example:
</p>
<pre>
set pitch-source = make-cycle(list(c4, d4, e4, f4))
print next(pitch-source, t)
</pre>
<p>
This prints the list <code>(60 62 64 65)</code>, which is one period
of the cycle.</p>
<p>You can also get explicit markers that
delineate periods by calling <code>send(<i>pattern</i>, :next)</code>. In this
case, the value returned is either the next item of the pattern, or the
symbol <code>+eop+</code> if the end of a period has been reached. What
determines a period? This is up to the specific pattern class, so see the
documentation for specifics. You can override the “natural” period
using the keyword <code>for:</code>, e.g.
</p>
<pre>
set pitch-source = make-cycle(list(c4, d4, e4, f4), for: 3)
print next(pitch-source, t)
print next(pitch-source, t)
</pre>
<p>
This prints the lists <code>(60 62 64) (60 62 64)</code>. Notice that
the cycle starts from the beginning after only 3 items and the
fourth is never reached in this case. The <code>for:</code> parameter
<i>could itself be a pattern</i>, in which case the a new cycle length would
be computed at the beginning of every cycle.</p>
<p>A variation on this restructures the stream of items
into groups of 3:
</p>
<pre>
set pitch-source = make-length(make-cycle(list(c4, d4, e4 f4)), 3)
print next(pitch-source, t)
print next(pitch-source, t)
</pre>
<p>
This prints the lists <code>(60 62 64) (65 60 62)</code>. Note that in
this case the cycle pattern is producing default cycles of length 4
because there is no <code>for:</code> specification, and these are regrouped
by the length pattern.</p>
<p>Nested patterns are probably easier to understand by example than by
specification. Here is a simple nested pattern of cycles:
</p>
<pre>
set cycle-1 = make-cycle({a b c})
set cycle-2 = make-cycle({x y z})
set cycle-3 = make-cycle(list(cycle-1, cycle-2))
loop repeat 9 exec format(t, "~A ", next(cycle-3)) end
</pre>
<p>
This will print "A B C X Y Z A B C". Notice that the inner-most
cycles <code>cycle-1</code> and <code>cycle-2</code> generate a period of items
before the top-level <code>cycle-3</code> advances to the next pattern.</p>
<a name = "162"><h4>General Parameters for Creating Pattern objects</h4></a>
<p>Before describing specific pattern classes, there are several optional
parameters that apply in the creating of any pattern object. These are:
<dl>
<dt>
<code>for:</code></dt>
<dd>The length of a period. This overrides the default
by providing a numerical length. The value of this optional
parameter may be a pattern that generates a sequence of integers
that determine the length of each successive period. A period
length may not be negative, but it may be zero.</p>
<dt><code>name:</code></dt>
<dd>A pattern object may be given a name. This is useful
if the <code>trace:</code> option is used.<br><br>
<dt><code>trace:</code></dt>
<dd>If non-null, this optional parameter causes information
about the pattern to be printed each time an item is generated
from the pattern.
</dd></dl>
The built-in pattern classes are described in the following section.<a name = "163"><h4>cycle</h4></a>
<p>The <code>cycle-class</code> iterates repeatedly through a list of items.
For example, two periods of <code>make-cycle({a b c})</code> would be
<code>(A B C) (A B C)</code>. </p>
<dl>
<dt>
<code>make-cycle(<a name="index1171"></a><a name="index1172"></a><a name="index1173"></a><i>items</i>, for: <i>for</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-cycle <i>items</i> :for <i>for</i> :name <i>name</i>
:trace <i>trace</i>)</code> [LISP]</dt>
<dd>Make a cycle
pattern that iterates over <i>items</i>. The default period length is the
length of <i>items</i>. (See above for a description of the
optional parameters.) The
list is replaced and restarted every period of the cycle, which
defaults to the whole list, but may be specified by the <code>for:</code> keyword.
If <i>items</i> is a pattern, a new period of <i>items</i>
becomes the list from which items are generated for each cycle pattern.
Note that the <i>items</i> list may be truncated by the use of <code>for:</code>.
Different groupings and repetitions can be obtained by nesting <code>make-cycle</code>
within <code>make-length</code> and/or <code>make-copier</code> patterns.
</dd></dl><a name = "164"><h4>line</h4></a>
<p>The <code>line-class</code> is similar to the cycle class, but when it reaches the
end of the list of items, it simply repeats the last item in the list.
For example, two periods of <code>make-line({a b c})</code> would be
<code>(A B C) (C C C)</code>. </p>
<dl>
<dt>
<code>make-line(<a name="index1174"></a><a name="index1175"></a><a name="index1176"></a><i>items</i>, for: <i>for</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-line <i>items</i> :for <i>for</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Make a line
pattern that iterates over <i>items</i>. The default period length is the
length of <i>items</i>. As with <code>make-cycle</code>, <i>items</i> may be a
pattern. (See above for a description of the optional parameters.)
</dd></dl><a name = "165"><h4>random</h4></a>
<p>The <code>random-class</code> generates items at random from a list. The default
selection is uniform random with replacement, but items may be further
specified with a weight, a minimum repetition count, and a maximum
repetition count. Weights give the relative probability of the selection
of the item (with a default weight of one). The minimum count specifies how
many times an item, once selected at random, will be repeated. The maximum
count specifies the maximum number of times an item can be selected in a row.
If an item has been generated <i>n</i> times in succession, and the maximum
is equal to <i>n</i>, then the item is disqualified in the next random selection.
Weights (but not currently minima and maxima) can be patterns. The patterns
(thus the weights) are recomputed every period. </p>
<dl>
<dt>
<code>make-random(<a name="index1177"></a><a name="index1178"></a><a name="index1179"></a><i>items</i>, for: <i>for</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-random <i>items</i> :for <i>for</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Make a random
pattern that selects from <i>items</i>. Any (or all) element(s) of <i>items</i>
may be lists of the following form: <code>(<i>value</i> :weight <i>weight</i>
:min <i>mincount</i> :max <i>maxcount</i>)</code>, where <i>value</i> is the item
(or pattern) to be generated, <i>weight</i> is the (optional)
relative probability of
selecting this item, <i>mincount</i> is the (optional) minimum number of repetitions
when this item is selected, and <i>maxcount</i> is the (optional) maximum number of
repetitions allowed before selecting some other item. The default period
length is the length of <i>items</i>. If <i>items</i> is a pattern, a period
from that pattern becomes the list from which random selections are
made, and a new list is generated every period.
</dd></dl><a name = "166"><h4>palindrome</h4></a>
<p>The <code>palindrome-class</code> repeatedly traverses a list forwards and then
backwards. For example, two periods of <code>make-palindrome({a b c})</code>
would be <code>(A B C C B A) (A B C C B A)</code>. The <code>elide:</code>
keyword parameter controls whether the first and/or last elements are
repeated:
</p>
<pre>
make-palindrome({a b c}, elide: nil)
;; generates A B C C B A A B C C B A ...
make-palindrome({a b c}, elide: t)
;; generates A B C B A B C B ...
make-palindrome({a b c}, elide: :first)
;; generates A B C C B A B C C B ...
make-palindrome({a b c}, elide: :last)
;; generates A B C B A A B C B A ...
</pre>
<p></p>
<dl>
<dt>
<code>make-palindrome(<a name="index1180"></a><a name="index1181"></a><a name="index1182"></a><i>items</i>, elide: <i>elide</i>, for: <i>for</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-palindrome <i>items</i> :elide <i>elide</i> :for <i>for</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Generate items
from list alternating in-order and reverse-order sequencing. The keyword
parameter <i>elide</i> can have the values <code>:first</code>, <code>:last</code>,
<code>t</code>, or <code>nil</code> to control repetition of the first and last elements.
The <i>elide</i> parameter can also be a pattern, in which case it is evaluated
every period. One period is one complete forward and backward traversal
of the list. If <i>items</i> is a pattern, a period
from that pattern becomes the list from which random selections are
made, and a new list is generated every period.
</dd></dl><a name = "167"><h4>heap</h4></a>
<p>The <code>heap-class</code> selects items in random order from a list
without replacement, which means that all items are generated once before
any item is repeated. For example, two periods of <code>make-heap({a b c})</code>
might be <code>(C A B) (B A C)</code>. Normally, repetitions can occur
even if all list elements are distinct. This happens when the last element
of a period is chosen first in the next period. To avoid repetitions, the
<code>max:</code> keyword argument can be set to 1. The <code>max:</code> keyword only
controls repetitions from the end of one period to the beginning of the next.
If the list contains more than one copy of the same value, it may be repeated
within a period regardless of the value of <code>max:</code>.</p>
<dl>
<dt>
<code>make-heap(<a name="index1183"></a><a name="index1184"></a><a name="index1185"></a><i>items</i>, for: <i>for</i>, max: <i>max</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-heap <i>items</i> :for <i>for</i> :max <i>max</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Generate items
randomly from list without replacement. If <i>max</i> is 1, the first element of
a new period will not be the same as the last element of the previous period,
avoiding repetition. The default value of <i>max</i> is 2, meaning repetition is
allowed. The period length is the length
of <i>items</i>. If <i>items</i> is a pattern, a period
from that pattern becomes the list from which random selections are
made, and a new list is generated every period.
</dd></dl><a name = "168"><h4>accumulation</h4></a>
<p>The <code>accumulation-class</code> takes a list of values and returns
the first, followed by the first two, followed by the first three,
etc. In other words, for each list item, return all items from the
first through the item. For example, if the list is (A B C), each
generated period is (A A B A B C).</p>
<dl>
<dt>
<code>make-accumulation(<a name="index1186"></a><a name="index1187"></a><a name="index1188"></a><i>items</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-accumulation <i>items</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Return
the prefixes of items, e.g. the first element followed by the
first and second elements, then the first three, until the
entire list is returned. The period length is (<i>n</i><sup T>2</sup> + <i>n</i>) / 2
where <i>n</i> is the length of <i>items</i>. If <i>items</i> is a pattern, a period
from that pattern becomes the list from which items are generated,
and a new list is generated every period. Note that this is similar in
name but different from <code>make-accumulate</code>.
</dd></dl><a name = "169"><h4>copier</h4></a>
<p>The <code>copier-class</code> makes copies of periods from a sub-pattern.
For example, three periods
of <code>make-copier(make-length(make-cycle({a b c}), 1), repeat: 2, merge: t)</code>
would be <code>(A A) (B B) (C C)</code>. Note that entire periods (not
individual items) are repeated, so in this example, <code>make-length</code>
is used to re-group the cycle into periods of length one so that
each item is repeated by the <code>repeat:</code> count.</p>
<dl>
<dt>
<code>make-copier(<a name="index1189"></a><a name="index1190"></a><a name="index1191"></a><i>sub-pattern</i>, repeat: <i>repeat</i>, merge: <i>merge</i>, for: <i>for</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-copier <i>sub-pattern</i> :repeat <i>repeat</i> :merge <i>merge</i> :for <i>for</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Generate a period
from <i>sub-pattern</i> and repeat it <i>repeat</i> times. If <i>merge</i> is false
(the default), each repetition of a period from <i>sub-pattern</i> results
in a period by default. If <i>merge</i> is true (non-null), then all
<i>repeat</i> repetitions of the period are merged into one result
period by default. If the <code>for:</code> keyword is used, the same items
are generated, but the items are grouped into periods determined by
the <code>for:</code> parameter. If the <code>for:</code> parameter is a pattern,
it is evaluated every result period. The <i>repeat</i> and <i>merge</i> values
may be patterns that return a repeat count and a boolean value, respectively.
If so, these patterns are evaluated initially and after each <i>repeat</i>
copies are made (independent of the <code>for:</code> keyword parameter, if any).
The <i>repeat</i> value returned by a pattern can also be negative. A negative
number indicates how many periods of <i>sub-pattern</i> to skip. After skipping
these patterns, new <i>repeat</i> and <i>merge</i> values are generated.
</dd></dl><a name = "170"><h4>accumulate</h4></a>
<p>The <code>accumulate-class</code> forms the sum of numbers returned by another
pattern. For example, each period
of <code>make-accumulate(make-cycle({1 2 -3}))</code> is <code>(1 3 0)</code>.
The default output period length is the length of the input period.</p>
<dl>
<dt>
<code>make-accumulate(<a name="index1192"></a><a name="index1193"></a><a name="index1194"></a><i>sub-pattern</i>, for: <i>for</i>, max: <i>maximum</i>, min: <i>minimum</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-accumulate <i>sub-pattern</i> :for <i>for</i> :max <i>maximum</i> :min <i>minimum</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Keep
a running sum of numbers generated by <i>sub-pattern</i>. The default
period lengths match the period lengths from <i>sub-pattern</i>.
If <i>maximum</i> (a pattern or a number) is specified, and the
running sum exceeds <i>maximum</i>, the running sum is reset
to <i>maximum</i>. If <i>minimum</i> (a pattern or a number) is
specified, and the running sum falls below <i>minimum</i>, the
running sum is reset to <i>minimum</i>. If <i>minimum</i> is greater
than <i>maximum</i>, the running sum will be set to one of the two
values. Minimum and maximum patterns are reevaluated every cycle.
Note that this is similar in name but not in function to <code>make-accumulation</code>.
</dd></dl><a name = "171"><h4>sum</h4></a>
<p>The <code>sum-class</code> forms the sum of numbers, one from each of two other
patterns. For example, each period
of <code>make-sum(make-cycle({1 2 3}), make-cycle({4 5 6}))</code>
is <code>(5 7 9)</code>.
The default output period length is the length of the input period of the
first argument. Therefore, the first argument must be a pattern, but the
second argument can be a pattern or a number.</p>
<dl>
<dt>
<code>make-sum(<a name="index1195"></a><a name="index1196"></a><a name="index1197"></a><i>x</i>, <i>y</i>, for: <i>for</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-sum <i>x</i> <i>y</i> :for <i>for</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Form
sums of items (which must be numbers) from pattern
<i>x</i> and pattern or number <i>y</i>. The default
period lengths match the period lengths from <i>x</i>.
</dd></dl><a name = "172"><h4>product</h4></a>
<p>The <code>product-class</code> forms the product of numbers, one
from each of two other
patterns. For example, each period
of <code>make-product(make-cycle({1 2 3}), make-cycle({4 5 6}))</code>
is <code>(4 10 18)</code>.
The default output period length is the length of the input period of the
first argument. Therefore, the first argument must be a pattern, but the
second argument can be a pattern or a number.</p>
<dl>
<dt>
<code>make-product(<a name="index1198"></a><a name="index1199"></a><a name="index1200"></a><i>x</i>, <i>y</i>, for: <i>for</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-product <i>x</i> <i>y</i> :for <i>for</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Form
products of items (which must be numbers) from pattern
<i>x</i> and pattern or number <i>y</i>. The default
period lengths match the period lengths from <i>x</i>.
</dd></dl><a name = "173"><h4>eval</h4></a>
<p>The <code>eval-class</code> evaluates an expression to produce each output item.
The default output period length is 1 if the expression is an expression;
otherwise, the expression must be a pattern that returns expressions to
be evaluated, and the output periods match the periods of the expression pattern.</p>
<dl>
<dt>
<code>make-eval(<a name="index1201"></a><a name="index1202"></a><a name="index1203"></a><a name="index1204"></a><a name="index1205"></a><i>expr</i>, for: <i>for</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-eval <i>expr</i> :for <i>for</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Evaluate
<i>expr</i> to generate each item. If <i>expr</i> is a pattern, each item is generated
by getting the next item from <i>expr</i> and evaluating it. Note that <i>expr</i> is
evaluated as a Lisp expression, which is a list consisting of the function name followed
by parameter expressions (which may also be lists). In the simplest case (recommended),
create a SAL function with no parameters that performs the computation. For example, to
create a pattern in SAL that calls the parameterless function <code>rrandom</code>, write
<code>make-eval({rrandom})</code>. In SAL, <code>{rrandom}</code> creates a list with the
(unevaluated) symbol <code>rrandom</code>, equivalent to <code>list(quote(rrandom))</code>.
</dd></dl><a name = "174"><h4>length</h4></a>
<p>The <code>length-class</code> generates periods of a specified length from
another pattern. This is similar to using the <code>for:</code> keyword, but
for many patterns, the <code>for:</code> parameter alters the points at which
other patterns are generated. For example, if the palindrome pattern
has an <code>elide:</code> pattern parameter, the value will be computed every
period. If there is also a <code>for:</code> parameter with a value of 2, then
<code>elide:</code> will be recomputed every 2 items. In contrast, if the
palindrome (without a <code>for:</code> parameter) is embedded in a <i>length</i>
pattern with a lenght of 2, then the periods will all be of length 2, but
the items will come from default periods of the palindrome, and therefore
the <code>elide:</code> values will be recomputed at the beginnings of
default palindrome periods.</p>
<dl>
<dt>
<code>make-length(<a name="index1206"></a><a name="index1207"></a><a name="index1208"></a><i>pattern</i>, <i>length-pattern</i>,
name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-length <i>pattern</i> <i>length-pattern</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Make a pattern of class
<code>length-class</code> that regroups items generated by a
<i>pattern</i> according to pattern lengths given by <i>length-pattern</i>.
Note that <i>length-pattern</i> is not optional: There is no default
pattern length and no <code>for:</code> keyword.
</dd></dl><a name = "175"><h4>window</h4></a>
<p>The <code>window-class</code> groups items from another pattern by using a sliding
window. If the <i>skip</i> value is 1, each output period is formed
by dropping the first item of the previous perioda and appending the next item
from the pattern. The <i>skip</i> value and the output period length can change
every period. For a simple example, if the period length is 3 and the
skip value is 1, and the input pattern generates the sequence A, B, C, ...,
then the output periods will be (A B C), (B C D), (C D E), (D E F), ....</p>
<dl>
<dt>
<code>make-window(<a name="index1209"></a><a name="index1210"></a><a name="index1211"></a><i>pattern</i>, <i>length-pattern</i>,
<i>skip-pattern</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-window <i>pattern</i> <i>length-pattern</i> <i>skip-pattern</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Make
a pattern of class
<code>window-class</code> that regroups items generated by a
<i>pattern</i> according to pattern lengths given by <i>length-pattern</i>
and where the period advances by the number of items given by
<i>skip-pattern</i>.
Note that <i>length-pattern</i> is not optional: There is no default
pattern length and no <code>for:</code> keyword.
</dd></dl><a name = "176"><h4>markov</h4></a>
<p>The <code>markov-class</code> generates items from a Markov model. A Markov model
generates a sequence of <i>states</i> according to rules which specify possible
future states
given the most recent states in the past. For example, states might be
pitches, and each pitch might lead to a choice of pitches for the next state.
In the <code>markov-class</code>, states can be either symbols or numbers, but
not arbitrary values or patterns. This makes it easier to specify rules.
However, symbols can be mapped to arbitrary values including pattern
objects, and these become the actual generated items.
By default, all future states are weighted equally, but weights
may be associated with future states. A Markov model must be
initialized with
a sequence of past states using the <code>past:</code> keyword.
The most common form of Markov model is a "first
order Markov model" in which the future item depends only upon one
past item. However, higher order models where the future items depend on
two or more past items are possible. A "zero-order" Markov model, which
depends on no past states, is essentially equivalent to the random pattern.
As an example of a first-order Markov pattern,
two periods of <code>make-markov({{a -> b c} {b -> c} {c -> a}}, past: {a})</code>
might be <code>(C A C) (A B C)</code>.</p>
<dl>
<dt>
<code>make-markov(<a name="index1212"></a><a name="index1213"></a><a name="index1214"></a><i>rules</i>, past: <i>past</i>, produces: <i>produces</i>, for: <i>for</i>, name: <i>name</i>, trace: <i>trace</i>)</code> [SAL]<br>
<code>(make-markov <i>rules</i> <i>past</i> :produces <i>produces</i> :for <i>for</i> :name <i>name</i> :trace <i>trace</i>)</code> [LISP]</dt>
<dd>Generate a sequence
of items from a Markov process. The <i>rules</i> parameter is a list of rules where each rule has the form:
<code>(<i>prev1</i> <i>prev2</i> ... <i>prevn</i> -> <i>next1</i> <i>next2</i> ... <i>nextn</i>)</code>
where <i>prev1</i> through <i>prevn</i> represent a sequence of most recent
(past) states. The symbol <code>*</code> is treated specially: it matches any
previous state. If <i>prev1</i> through <i>prevn</i> (which may be just one state
as in the example above) match the previously generated states, this
rule applies. Note that every rule must specify the same number of previous
states; this number is known as the order of the Markov model.
The first rule in <i>rules</i> that applies is used to select the
next state. If no rule applies, the next state is <code>NIL</code> (which is
a valid state that can be used in rules).
Assuming a rule applies, the list of possible next
states is specified by <i>next1</i>
through <i>nextn</i>. Notice that these are alternative choices for the
next state, not a sequence of future states, and each rule can have
any number of choices. Each choice may be the state
itself (a symbol or a number), or the choice may be a list consisting of
the state and a weight. The weight may be given by a pattern, in which
case the next item of the pattern is obtained every time the rule is
applied. For example, this rules says that if the previous states were
A and B, the next state can be A with a weight of 0.5 or C with an
implied weight of 1: <code>(A B -> (A 0.5) C)</code>. The
default length of the period is the length of <i>rules</i>. The
<i>past</i> parameter must be provided. It is a list of states whose length
matches the order of the Markov model. The keyword parameter <i>produces</i>
may be used to map from state symbols or numbers to other values or
patterns. The parameter is a list of alternating symbols and values. For
example, to map A to 69 and B to 71, use <code>list(quote(a), 69, quote(b), 71)</code>.
You can
also map symbols to patterns, for example
<code>list(quote(a), make-cycle({57 69}), quote(b), make-random({59 71}))</code>. The
next item of the pattern is is generated each time the Markov model generates
the corresponding state. Finally, the <i>produces</i> keyword can be
<code>:eval</code>, which means to evaluate the Markov model state. This could
be useful if states are Nyquist global variables such as
<code>C4, CS4, D4, ]..., which evaluate to numerical
values (60, 61, 62, ...</code>.<br><br>
<dt><code>markov-create-rules(<a name="index1215"></a><a name="index1216"></a><i>sequence</i>, <i>order</i> [, <i>generalize</i>])</code> [SAL]<br>
<code>(markov-create-rules <i>sequence</i> <i>order</i> [<i>generalize</i>])</code> [LISP]</dt>
<dd>Generate a set of rules suitable for the
<code>make-markov</code> function. The <i>sequence</i> is a “typical” sequence
of states, and <i>order</i> is the order of the Markov model. It is often the
case that a sample sequence will not have a transition from the last state
to any other state, so the generated Markov model can reach a “dead end”
where no rule applies. This might lead to an infinite stream of NIL's. To
avoid this, the optional parameter <i>generalize</i> can be set to <code>t</code>
(true), indicating that there should be a fallback rule that matches any
previous states and whose future states are weighted according to their
frequency in <i>sequence</i>. For example, if sequence contains 5 A's, 5 B's and
10 G's, the default rule will be <code>(* -> (A 5) (B 5) (G 10))</code>. This
rule will be appended to the end so it will only apply if no other rule does.
</dd></dl><a name = "177"><h3>Random Number Generators</h3></a><a name="index1217"></a><a name="index1218"></a><a name="index1219"></a><a name="index1220"></a>
<p>The <code>distributions.lsp</code> library implements random number generators that return random values with various probability distributions. Without this library, you can generate random numbers with <i>uniform</i> distributions. In a uniform distribution, all values are equally likely. To generate a random integer in some range, use <code>random</code>. To generate a real number (FLONUM) in some range, use <code>real-random</code> (or <code>rrandom</code> if the range is 0-1). But there are other interesting distributions. For example, the Gaussian distribution is often used to model
real-world errors and fluctuations where values are clustered around some central value and large deviations are more unlikely than small ones. See Dennis Lorrain, "A Panoply of Stochastic 'Canons'," <i>Computer Music Journal</i> vol. 4, no. 1, 1980, pp. 53-81.
Further discussion and examples can be found in
<code>nyquist/demos/probability_distributions.htm</code><a name="index1221"></a>. </p>
<p>In most of the random number generators described below, there are optional parameters to indicate a maximum and/or minimum value. These can be used to truncate the distribution. For example, if you basically want a Gaussian distribution, but you never want a value greater than 5, you can specify 5 as the maximum value.
The upper and lower bounds are implemented simply by drawing a random number from the full distribution repeatedly until a number falling into the desired range is obtained. Therefore, if you select an acceptable range that is unlikely, it may take Nyquist a long time to find each acceptable random number. The intended use of the upper and lower bounds is to weed out values that are already fairly unlikely.</p>
<dl>
<dt>
<code>linear-dist(<a name="index1222"></a><a name="index1223"></a><i>g</i>)</code> [SAL]<br>
<code>(linear-dist <i>g</i>)</code> [LISP]</dt>
<dd>Return a <code>FLONUM</code> value from a linear distribution, where the probability of a value decreases linearly from zero to <i>g</i> which must be greater than zero. (See Figure <a href = "#177">7</a>.) The linear distribution is useful for generating for generating time and pitch intervals.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="linear-fig.gif"><br><br>
<p><b>Figure 7: </b>The Linear Distribution, <i>g</i> = 1.
</p>
<hr><dl>
<dt>
<code>exponential-dist(<a name="index1224"></a><a name="index1225"></a><i>delta</i> [, <i>high</i>])</code> [SAL]<br>
<code>(exponential-dist <i>delta</i> [<i>high</i>])</code> [LISP]</dt>
<dd>Return a <code>FLONUM</code> value from an exponential distribution. The initial downward slope is steeper with larger values of <i>delta</i>, which must be greater than zero. (See Figure <a href = "#177">8</a>. The optional <i>high</i> parameter puts an artificial upper bound on the return value.
The exponential distribution generates values greater
than 0, and can be used to generate time intervals. Natural random intervals such as the time intervals between the release of atomic particles or the passing of yellow volkswagons in traffic have exponential distributions. The
exponential distribution is memory-less: knowing that a random number from this distribution is greater than some value (e.g. a note duration is at least 1 second) tells you nothing new about how soon the note will end. This
is a continuous distribution, but <code>geometric-dist</code> (described below) implements the discrete form.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="exponential-fig.gif"><br><br>
<p><b>Figure 8: </b>The Exponential Distribution, <i>delta</i> = 1.
</p>
<hr><dl>
<dt>
<code>gamma-dist(<a name="index1226"></a><i>nu</i> [, <i>high</i>])</code> [SAL]<br>
<code>(gamma-dist <i>nu</i> [<i>high</i>])</code> [LISP]</dt>
<dd>Return a <code>FLONUM</code> value from a Gamma distribution. The value is greater than zero, has a mean of <i>nu</i> (a <code>FIXNUM</code> greater than zero), and a mode (peak) of around <i>nu</i> - 1.
The optional <i>high</i> parameter puts an artificial upper bound on the return value.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="gamma-fig.gif"><br><br>
<p><b>Figure 9: </b>The Gamma Distribution, <i>nu</i> = 4.
</p>
<hr><dl>
<dt>
<code>bilateral-exponential-dist(<a name="index1227"></a><a name="index1228"></a><i>xmu</i>,
<i>tau</i> [, <i>low</i>, <i>high</i>])</code> [SAL]<br>
<code>(bilateral-exponential-dist <i>xmu</i> <i>tau</i> [<i>low</i> <i>high</i>])</code> [LISP]</dt>
<dd>Returns a <code>FLONUM</code> value from a bilateral exponential distribution, where <i>xmu</i> is the center of the double exponential and <i>tau</i> controls the spread of the distribution. A larger <i>tau</i> gives a wider distribution (greater variance), and <i>tau</i> must be greater than zero. The <i>low</i> and <i>high</i> parameters give optional artificial bounds on the minimum and maximum output values, respectively.
This distribution is similar to the exponential, except
it is centered at 0 and can output negative values as well. Like
the exponential, it can be used to generate time intervals; however, it might be necessary to add a lower bound so as not to compute a negative time interval.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="bilateral-fig.gif"><br><br>
<p><b>Figure 10: </b>The Bilateral Exponential Distribution.
</p>
<hr><dl>
<dt>
<code>cauchy-dist(<a name="index1229"></a><a name="index1230"></a><i>tau</i> [, <i>low</i>, <i>high</i>])</code> [SAL]<br>
<code>(cauchy-dist <i>tau</i> [<i>low</i> <i>high</i>])</code> [LISP]</dt>
<dd>Returns a <code>FLONUM</code> from the Cauchy distribution, a symmetric distribution with a high peak at zero and a width (variance) that increases with parameter <i>tau</i>, which must be greater than zero. The <i>low</i> and <i>high</i> parameters give optional artificial bounds on the minimum and maximum output values, respectively.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="cauchy-fig.gif"><br><br>
<p><b>Figure 11: </b>The Cauchy Distribution, <i>tau</i> = 1.
</p>
<hr><dl>
<dt>
<code>hyperbolic-cosine-dist(<a name="index1231"></a>[<i>low</i>, <i>high</i>])</code> [SAL]<br>
<code>(hyperbolic-cosine-dist [<i>low</i> <i>high</i>])</code> [LISP]</dt>
<dd>Returns a <code>FLONUM</code> value from the hyperbolic cosine distribution, a symmetric distribution with its peak at zero. The <i>low</i> and <i>high</i> parameters give optional artificial bounds on the minimum and maximum output values, respectively.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="hyperbolic-fig.gif"><br><br>
<p><b>Figure 12: </b>The Hyperbolic Cosine Distribution.
</p>
<hr><dl>
<dt>
<code>logistic-dist(<a name="index1232"></a><a name="index1233"></a><i>alpha</i>, <i>beta</i> [, <i>low</i>, <i>high</i>])</code> [SAL]<br>
<code>(logistic-dist <i>alpha</i> <i>beta</i> [<i>low</i> <i>high</i>])</code> [LISP]</dt>
<dd>Returns a <code>FLONUM</code> value from the logistic distribution, which is symmetric about the mean. The <i>alpha</i> parameter primarily affects dispersion (variance), with larger values resulting in values closer to the mean (less variance), and the <i>beta</i> parameter primarily influences the mean. The <i>low</i> and <i>high</i> parameters give optional artificial bounds on the minimum and maximum output values, respectively.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="logistic-fig.gif"><br><br>
<p><b>Figure 13: </b>The Logistic Distribution, alpha = 1, beta = 2.
</p>
<hr><dl>
<dt>
<code>arc-sine-dist(<a name="index1234"></a><a name="index1235"></a>)</code> [SAL]<br>
<code>(arc-sine-dist)</code> [LISP]</dt>
<dd>Returns a <code>FLONUM</code> value from the arc sine distribution, which outputs values between 0 and 1. It is symmetric about the mean of 1/2, but is more likely to generate values closer to 0 and 1.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="arcsine-fig.gif"><br><br>
<p><b>Figure 14: </b>The Arc Sine Distribution.
</p>
<hr><dl>
<dt>
<code>gaussian-dist(<a name="index1236"></a><a name="index1237"></a><i>xmu</i>, <i>sigma</i> [, <i>low</i>, <i>high</i>])</code> [SAL]<br>
<code>(gaussian-dist <i>xmu</i> <i>sigma</i> [<i>low</i> <i>high</i>])</code> [LISP]</dt>
<dd>Returns a <code>FLONUM</code> value from the Gaussian or Gauss-Laplace distribution, a linear function of the normal distribution. It is symmetric about the mean of <i>xmu</i>, with a standard deviation of <i>sigma</i>, which must be greater than zero. The <i>low</i> and <i>high</i> parameters give optional artificial bounds on the minimum and maximum output values, respectively.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="gaussian-fig.gif"><br><br>
<p><b>Figure 15: </b>The Gauss-Laplace (Gaussian) Distribution, <i>xmu</i> = 0, <i>sigma</i> = 1.
</p>
<hr><dl>
<dt>
<code>beta-dist(<a name="index1238"></a><a name="index1239"></a><i>a</i>, <i>b</i>)</code> [SAL]<br>
<code>(beta-dist <i>a</i> <i>b</i>)</code> [LISP]</dt>
<dd>Returns a <code>FLONUM</code> value from the Beta distribution. This distribution outputs values between 0 and 1, with outputs more likely to be close to 0 or 1. The parameter <i>a</i> controls the height (probability) of the right side of the distribution (at 1) and <i>b</i> controls the height of the left side (at 0). The distribution is symmetric about 1/2 when <i>a</i> = <i>b</i>.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="beta-fig.gif"><br><br>
<p><b>Figure 16: </b>The Beta Distribution, <i>alpha</i> = .5, <i>beta</i> = .25.
</p>
<hr><dl>
<dt>
<code>bernoulli-dist(<a name="index1240"></a><a name="index1241"></a><i>px1</i> [, <i>x1</i>, <i>x2</i>])</code> [SAL]<br>
<code>(bernoulli-dist <i>px1</i> [<i>x1</i> <i>x2</i>])</code> [LISP]</dt>
<dd>Returns either <i>x1</i> (default value is 1) with probability <i>px1</i> or <i>x2</i> (default value is 0) with probability 1 - <i>px1</i>. The value of <i>px1</i> should be between 0 and 1. By
convention, a result of <i>x1</i> is viewed as a success while <i>x2</i> is viewed as
a failure.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="bernoulli-fig.gif"><br><br>
<p><b>Figure 17: </b>The Bernoulli Distribution, <i>px1</i> = .75.
</p>
<hr><dl>
<dt>
<code>binomial-dist(<a name="index1242"></a><a name="index1243"></a><i>n</i>, <i>p</i>)</code> [SAL]<br>
<code>(binomial-dist <i>n</i> <i>p</i>)</code> [LISP]</dt>
<dd>Returns a <code>FIXNUM</code> value from the binomial distribution, where <i>n</i> is the number of Bernoulli trials run (a <code>FIXNUM</code>) and <i>p</i> is the probability of success in the Bernoulli trial (a <code>FLONUM</code> from 0 to 1). The mean is the product of <i>n</i> and <i>p</i>.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="binomial-fig.gif"><br><br>
<p><b>Figure 18: </b>The Binomial Distribution, <i>n</i> = 5, <i>p</i> = .5.
</p>
<hr><dl>
<dt>
<code>geometric-dist(<a name="index1244"></a><a name="index1245"></a><i>p</i>)</code> [SAL]<br>
<code>(geometric-dist <i>p</i>)</code> [LISP]</dt>
<dd>Returns a <code>FIXNUM</code> value from the geometric distribution, which is defined as the number of failures before a success is achieved in a Bernoulli trial with probability of success <i>p</i> (a <code>FLONUM</code> from 0 to 1).
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="geometric-fig.gif"><br><br>
<p><b>Figure 19: </b>The Geometric Distribution, <i>p</i> = .4.
</p>
<hr><dl>
<dt>
<code>poisson-dist(<a name="index1246"></a><a name="index1247"></a><i>delta</i>)</code> [SAL]<br>
<code>(poisson-dist <i>delta</i>)</code> [LISP]</dt>
<dd>Returns a <code>FIXNUM</code> value from the Poisson distribution with a mean of <i>delta</i> (a <code>FIXNUM</code>). The Poisson distribution is often used to generate a sequence of time intervals, resulting in random but often pleasing rhythms.
</dd></dl><hr>
<blockquote>
</blockquote>
<img src="poisson-fig.gif"><br><br>
<p><b>Figure 20: </b>The Poisson Distribution, <i>delta</i> = 3.
</p>
<hr><a name = "178"><h3>Score Generation and Manipulation</h3></a>
<p>A common application of pattern generators is to specify parameters
for notes. (It should be understood that “notes” in this context
means any Nyquist behavior, whether it represents a conventional note,
an abstract sound object, or even some micro-sound event that is just
a low-level component of a hierarchical sound organization. Similarly,
“score” should be taken to mean a specification for a
sequence of these “notes.”)
The <code>score-gen</code> macro (defined by
loading <code>xm.lsp</code>) establishes a convention for representing
scores and for generating them using patterns.</p>
<p>The <code>timed-seq</code> macro, described in Section <a href = "part8.html#99">Combination and Time Structure</a>,
already provides a way to represent a “score” as a list of expressions.
The Xmusic representation goes a bit further by specifying that
<i>all notes are specified by an alternation of keywords and values, where
some keywords have specific meanings and interpretations.</i></p>
<p>The basic idea of <code>score-gen</code><a name="index1248"></a> is you provide a template for notes in
a score as a set of keywords and values. For example,
</p>
<pre>
set pitch-pattern = make-cycle(list(c4, d4, e4, f4))
score-gen(dur: 0.4, name: quote(my-sound),
pitch: next(pitch-pattern), score-len: 9)
</pre>
<p>
generates a score of 9 notes as follows:
</p>
<pre>
((0 0 (SCORE-BEGIN-END 0 3.6))
(0 0.4 (MY-SOUND :PITCH 60))
(0.4 0.4 (MY-SOUND :PITCH 62))
(0.8 0.4 (MY-SOUND :PITCH 64))
(1.2 0.4 (MY-SOUND :PITCH 65))
(1.6 0.4 (MY-SOUND :PITCH 60))
(2 0.4 (MY-SOUND :PITCH 62))
(2.4 0.4 (MY-SOUND :PITCH 64))
(2.8 0.4 (MY-SOUND :PITCH 65))
(3.2 0.4 (MY-SOUND :PITCH 60)))
</pre>
<p>
The use of keywords like <code>:PITCH</code> helps to make scores
readable and easy to process without specific knowledge of
about the functions called in the score. For example, one
could write a transpose operation to transform all the
<code>:pitch</code> parameters in a score without having to know
that pitch is the first parameter of <code>pluck</code> and the
second parameter of <code>piano-note</code>. Keyword parameters are
also used to give flexibility to note specification with
<code>score-gen</code>. Since this approach requires the use of
keywords, the next section
is a brief explanation of how to define functions that use
keyword parameters.</p>
<a name = "179"><h4>Keyword Parameters</h4></a><a name="index1249"></a><a name="index1250"></a>
<p>Keyword parameters are parameters whose presence is
indicated by a special symbol, called a keyword, followed
by the actual parameter. Keyword parameters in SAL have
default values that are used if no actual parameter is
provided by the caller of the function. (See Appendix
<a href = "part19.html#224">Appendix 3: XLISP: An Object-oriented Lisp</a> to learn about keywords in XLISP.)</p>
<p>To specify that a parameter is a keyword parameter,
use a keyword symbol (one that ends in a colon) followed
by a default value.
For example, here is a function that
accepts keyword parameters and invokes the <code>pluck</code>
function:
</p>
<pre>
define function k-pluck(pitch: 60, dur: 1)
return pluck(pitch, dur)
</pre>
<p>
Now, we can call k-pluck with keyword parameters. The
keywords are simply the formal parameter names with
a prepended colon character (<code>:pitch</code> and <code>:dur</code>
in this example), so a function call would look like:
</p>
<pre>
k-pluck(pitch: c3, dur: 3)
</pre>
<p>
Usually, it is best to give keyword parameters useful
default values. That way, if a parameter such as <code>dur:</code>
is missing, a reasonable default value (1) can be used
automatically.
It is never an error to omit a keyword parameter, but the
called function can check to see if a keyword parameter
was supplied or not.
Because of default values, we can call
<code>k-pluck(pitch: c3)</code> with no duration,
<code>k-pluck(dur: 3)</code> with only a duration,
or even <code>k-pluck()</code> with no parameters.</p>
<p>In XLISP, there is additional syntax to specify an alternate symbol
to be used as the keyword and to allow the called function
to determine whether or not a keyword parameter was
supplied, but these features are little-used. See the XLISP
manual for details.</p>
<a name = "180"><h4>Using score-gen</h4></a><a name="index1251"></a>
<p>The <code>score-gen</code> macro computes a score based on keyword parameters.
Some keywords have a special meaning, while others are not interpreted
but merely placed in the score. The resulting score can be synthesized
using <code>timed-seq</code> (see Section <a href = "part8.html#99">Combination and Time Structure</a>).</p>
<p>The form of a call to <code>score-gen</code> is simply:
<dl>
<dt>
<code>score-gen(<a name="index1252"></a><i>k1:</i> <i>e1</i>, <i>k2:</i> <i>e2</i>, <span style="font-style:normal">...</span>)</code> [SAL]<br>
<code>(score-gen <i>:k1</i> <i>e1</i> <i>:k2</i> <i>e2</i> <span style="font-style:normal">...</span>)</code> [LISP]</dt>
<dd>where the <i>k</i>'s
are keywords and the <i>e</i>'s are
expressions. A score is generated by evaluating the expressions once for
each note and constructing a list of keyword-value pairs. A number
of keywords have special interpretations. The rules for interpreting
these parameters will be explained through a set of
questions and answers below.
</dd></dl></p>
<p> <i>How many notes will be generated?</i> The keyword
parameter <code>score-len:</code> specifies an upper bound on the number
of notes. (Note: in LISP syntax, keywords
are always <i>preceded</i> by colons, so you would write
<code>:score-len</code> instead.) The keyword <code>score-dur:</code> specifies an upper bound
on the starting time of the last note in the score. (To be more
precise, the <code>score-dur:</code> bound is reached when the
default starting time of the next note is greater than or equal
to the <code>score-dur:</code> value. This definition is necessary because
note times are not strictly increasing.) When either bound
is reached, score generation ends. At least one of these two
parameters must be specified or an error is raised. These keyword
parameters are evaluated just once and are not copied into the
parameter lists of generated notes.</p>
<p> <i>What is the duration of generated notes?</i> The
keyword <code>dur:</code> defaults to 1 and specifies the nominal duration
in seconds. Since the generated note list is compatible with
<code>timed-seq</code>, the starting time and duration (to be precise, the
<i>stretch factor</i>) are not passed as parameters to the notes. Instead,
they control the Nyquist environment in which the note will be evaluated.</p>
<p> <i>What is the start time of a note?</i> The default start time of the
first note is zero. Given a note, the default start time of the next note is
the start time plus the inter-onset time, which is given by the <code>ioi:</code>
parameter. If no <code>ioi:</code> parameter is specified, the inter-onset time
defaults to the duration, given by <code>dur:</code>. In all cases, the default
start time of a note can be overridden by the keyword parameter <code>time:</code>.</p>
<p> <i>When does the score begin and end?</i> The behavior <code>SCORE-BEGIN-END</code>
contains the beginning and ending of the
score (these are used for score manipulations, e.g. when scores are merged,
their begin times can be aligned.) When <code>timed-seq</code> is used to
synthesize a score, the <code>SCORE-BEGIN-END</code> marker is
not evaluated. The <code>score-gen</code> macro inserts a “note” of the form
<code>(0 0 (SCORE-BEGIN-END <i>begin-time</i> <i>end-time</i>))</code>
at the time given by the <code>begin:</code> keyword, with <i>begin-time</i> and
<i>end-time</i> determined by the <code>begin:</code> and <code>end:</code>
keyword parameters, respectively. If the <i>begin:</i> keyword is not
provided, the score begins at zero. If the <code>end:</code> keyword
is not provided, the score ends at the default start time
of what would be the next note after the last note in the score
(as described in the previous paragraph). Note: if <code>time:</code> is used to
compute note starting times, and these times are not increasing, it is
strongly advised to use <code>end:</code> to specify an end time for the score,
because the default end time may be anywhere in the middle of the
generated sequence.</p>
<p> <i>What function is called to synthesize the note?</i> The <code>name:</code>
parameter names the function. Like other parameters, the value can be any
expression, including something like <code>next(fn-name-pattern)</code>,
allowing function names to be recomputed for each note. The default value
is <code>note</code>.</p>
<p> <i>Can I make parameters depend upon the starting time or the duration
of the note?</i> Parameter expressions can use the variable <code>sg:start</code>
to access the start time of the note, <code>sg:ioi</code> to access the
inter-onset time, and <code>sg:dur</code> to access the
duration (stretch factor) of the note. Also, <code>sg:count</code> counts how
many notes have been computed so far, starting at 0. The order of
computation is: <code>sg:start</code> first, then <code>sg:ioi</code> and <code>sg:dur</code>,
so for example, an expression to compute <code>sg:dur</code> can
depend on <code>sg:ioi</code>.</p>
<p> <i>Can parameters depend on each other?</i> The keyword <code>pre:</code>
introduces an expression that is evaluated before each note, and
<code>post:</code> provides an expression to be evaluated after each note.
The <code>pre:</code> expression can assign one or more global variables
which are then used in one or more expressions for parameters.</p>
<p> <i>How do I debug <code>score-gen</code> expressions?</i> You can set the
<code>trace:</code> parameter to true (<code>t</code>) to enable a print statement
for each generated note.</p>
<p> <i>How can I save scores generated by <code>score-gen</code> that I like?</i> If the
keyword parameter <code>save:</code> is set to a symbol, the global variable
named by the symbol is set to the value of the generated sequence. Of
course, the value returned by <code>score-gen</code> is just an ordinary list that
can be saved like any other value.</p>
<p>In summary, the following keywords have special interpretations
in <code>score-gen</code>:
<code>begin:</code>, <code>end:</code>, <code>time:</code>, <code>dur:</code>, <code>name:</code>,
<code>ioi:</code>, <code>trace:</code>,
<code>save:</code>, <code>score-len:</code>, <code>score-dur:</code>, <code>pre:</code>, <code>post:</code>.
All other keyword
parameters are expressions that are evaluated once for each note
and become the parameters of the notes.</p>
<a name = "181"><h4>Score Manipulation</h4></a><a name="index1253"></a><a name="index1254"></a>
<p>Nyquist encourages the representation of music as
executable programs, or <i>behaviors</i>, and there are various
ways to modify behaviors, including time stretching,
transposition, etc. An alternative to composing executable
programs is to manipulate scores as editable data. Each
approach has its strengths and weaknesses. This section
describes functions intended to manipulate Xmusic scores
as generated by, or at least in the form generated by,
<code>score-gen</code>. Recall that this means scores are lists
of events (e.g. notes), where events are three-element lists of the form
(<i>time</i> <i>duration</i> <i>expression</i>, and where <i>expression</i>
is a standard lisp function call where all parameters are
keyword parameters. In addition, the first “note” may be
the special <code>SCORE-BEGIN-END</code> expression. If this is
missing, the score begins at zero and ends at the end of the
last note.</p>
<p>For convenience, a set of functions is offered to access properties
of events (or notes) in scores. Although lisp functions such as
<code>car</code>, <code>cadr</code>, and <code>caddr</code> can be used, code is more
readable when more mnemonic functions are used to access events.</p>
<dl>
<dt>
<code>event-time(<a name="index1255"></a><i>event</i>)</code> [SAL]<br>
<code>(event-time <i>event</i>)</code> [LISP]</dt>
<dd>Retrieve the time field from
an event.<br><br>
<dt><code>event-set-time(<a name="index1256"></a><i>event</i>, <i>time</i>)</code> [SAL]<br>
<code>(event-set-time <i>event</i> <i>time</i>)</code> [LISP]</dt>
<dd>Construct
a new event where the time of <i>event</i> is replaced by <i>time</i>.<br><br>
<dt><code>event-dur(<a name="index1257"></a><i>event</i>)</code> [SAL]<br>
<code>(event-dur <i>event</i>)</code> [LISP]</dt>
<dd>Retrieve the duration
(i.e. the stretch factor) field from an event.<br><br>
<dt><code>event-set-dur(<a name="index1258"></a><i>event</i>, <i>dur</i>)</code> [SAL]<br>
<code>(event-set-dur <i>event</i> <i>dur</i>)</code> [LISP]</dt>
<dd>Construct
a new event where the duration (or stretch factor) of <i>event</i> is
replaced by <i>dur</i>.<br><br>
<dt><code>event-expression(<a name="index1259"></a><i>event</i>)</code> [SAL]<br>
<code>(event-expression <i>event</i>)</code> [LISP]</dt>
<dd>Retrieve the expression
field from an event.<br><br>
<dt><code>event-set-expression(<a name="index1260"></a><i>event</i>,
<i>dur</i>)</code> [SAL]<br>
<code>(event-set-expression <i>event</i> <i>dur</i>)</code> [LISP]</dt>
<dd>Construct
a new event where the expression of <i>event</i> is replaced by <i>expression</i>.<br><br>
<dt><code>event-end(<a name="index1261"></a><i>event</i>)</code> [SAL]<br>
<code>(event-end <i>event</i>)</code> [LISP]</dt>
<dd>Retrieve the end time
of <i>event</i>, its time plus its duration.<br><br>
<dt><code>expr-has-attr(<a name="index1262"></a><i>expression</i>, <i>attribute</i>)</code> [SAL]<br>
<code>(expr-has-attr <i>expression</i> <i>attribute</i>)</code> [LISP]</dt>
<dd>Test
whether a score event <i>expression</i> has the given <i>attribute</i>.<br><br>
<dt><code>expr-get-attr(<a name="index1263"></a><i>expression</i>, <i>attribute</i> [, <i>default</i>])</code> [SAL]<br>
<code>(expr-get-attr <i>expression</i> <i>attribute</i> [<i>default</i>])</code> [LISP]</dt>
<dd>Get the value of the given <i>attribute</i> from a score event
<i>expression</i>. If <i>attribute</i> is not present, return <i>default</i> if
specified, and otherwise <code>nil</code>. (See the example
after <code>score-apply</code> below for an example using <code>expr-get-attr</code>.)<br><br>
<dt><code>expr-set-attr(<a name="index1264"></a><i>expr</i>, <i>attribute</i>, <i>value</i>)</code> [SAL]<br>
<code>(expr-set-attr <i>expr</i> <i>attribute</i> <i>value</i>)</code> [LISP]</dt>
<dd>Construct a new expression identical to <i>expr</i> except that the <i>attribute</i> has <i>value</i>. (See the example after <code>score-apply</code> below for an example
using <code>expr-set-attr</code>.)<br><br>
<dt><code>event-has-attr(<a name="index1265"></a><i>event</i>, <i>attribute</i>)</code> [SAL]<br>
<code>(event-has-attr <i>event</i> <i>attribute</i>)</code> [LISP]</dt>
<dd>Test
whether a given score <i>event</i>'s expression has the given <i>attribute</i>.<br><br>
<dt><code>event-get-attr(<a name="index1266"></a><i>event</i>, <i>attribute</i>,
[<i>default</i>])</code> [SAL]<br>
<code>(event-get-attr <i>event</i> <i>attribute</i> [<i>default</i>])</code> [LISP]</dt>
<dd>Get the value of the given <i>attribute</i> from a score
<i>event</i>'s expression. If <i>attribute</i> is not present, return <i>default</i> if
specified, and otherwise <code>nil</code>.<br><br>
<dt><code>event-set-attr(<a name="index1267"></a><i>event</i>, <i>attribute</i>, <i>value</i>)</code> [SAL]<br>
<code>(event-set-attr <i>event</i> <i>attribute</i> <i>value</i>)</code> [LISP]</dt>
<dd>Construct a new event identical to <i>event</i> except that the <i>attribute</i> has <i>value</i>.
</dd></dl>
<p>Functions are provided to shift the starting times of notes,
stretch times and durations, stretch only durations,
add an offset to a keyword parameter, scale a keyword parameter, and
other manipulations. Functions are also provided to extract
ranges of notes, notes that match criteria, and to combine scores.
Most of these functions (listed below in detail)
share a set of keyword parameters that optionally limit the range over which
the transformation operates. The <code>from-index:</code> and <code>to-index:</code>
parameters specify the index of the first note and the index of the
last note to be changed, where 1 (not zero) denotes the first note.
If indices are in range, the number of note selected is
<code>to-index</code> <code>-</code> <code>from-index</code> <code>+</code> <code>1</code>). Out-of-range
indices are ignored.
If these numbers are negative, they are offsets
from the end of the score, e.g. -1 denotes the last note of the score. The
<code>from-time:</code> and <code>to-time:</code> indicate a range of starting times
of notes that will be affected by the manipulation. Only notes whose time
is greater than or equal to the <i>from-time</i> and <i>strictly less than</i>
the <i>to-time</i> are modified. If both index and time ranges are specified,
only notes that satisfy <i>both</i> constraints are selected. (Note: in
LISP syntax, colons <i>precede</i> the keyword, so use
<code>:from-index</code>, <code>:to-index</code>,
<code>:from-time</code>, and <code>:to-time</code>.)</p>
<dl>
<dt>
<code>score-sorted(<a name="index1268"></a><i>score</i>)</code> [SAL]<br>
<code>(score-sorted <i>score</i>)</code> [LISP]</dt>
<dd>Test if <i>score</i> is sorted.<br><br>
<dt><code>score-sort(<a name="index1269"></a><i>score</i> [, <i>copy-flag</i>])</code> [SAL]<br>
<code>(score-sort <i>score</i> [<i>copy-flag</i>])</code> [LISP]</dt>
<dd>Sort
the notes in a
score into start-time order. If copy-flag is nil, this is a destructive
operation which should only be performed if the top-level score list
is a fresh copy that is not shared by any other variables. (The
<i>copy-flag</i> is intended for internal system use only.)
For the following operations, it is assumed
that scores are sorted, and all operations return a sorted score.<br><br>
<dt><code>score-shift(<a name="index1270"></a><i>score</i>, <i>offset</i>, from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>,
to-time: <i>y</i>)</code> [SAL]<br>
<code>(score-shift <i>score</i> <i>offset</i>
:from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i>
:to-time <i>y</i>)</code> [LISP]</dt>
<dd>Add a constant
<i>offset</i> to the starting time of a set of notes in <i>score</i>. By default,
all notes are modified, but the range of notes can be limited with the
keyword parameters. The begin time of the score is decreased if necessary to
the minimum time of any event that is moved to an earlier time (by a negative
<i>offset</i>), and the end time of the score is increased if necessary
to the maximum end time of any event that is moved to a later time. If
all shifted events remain within the score's begin-to-end range, the begin
and end times are not changed.
The original score is not modified, and a new score is returned.<br><br>
<dt><code>score-stretch(<a name="index1271"></a><i>score</i>, <i>factor</i>, dur: <i>dur-flag</i>, time: <i>time-flag</i>, from-index: <i>i</i>,
to-index: <i>j</i>, from-time: <i>x</i>, to-time: <i>y</i>)</code> [SAL]<br>
<code>(score-stretch <i>score</i> <i>factor</i>
:dur <i>dur-flag</i> :time <i>time-flag</i> :from-index <i>i</i>
:to-index <i>j</i> :from-time <i>x</i> :to-time <i>y</i>)</code> [LISP]</dt>
<dd>Stretch
note times and durations by <i>factor</i>. The default <i>dur-flag</i> is
non-null, but if <i>dur-flag</i> is null, the original durations are retained
and only times are stretched. Similarly, the default <i>time-flag</i> is
non-null, but if <i>time-flag</i> is null, the original times are retained
and only durations are stretched. If both <i>dur-flag</i> and <i>time-flag</i>
are null, the score is not changed. If a range
of notes is specified, times are scaled within that range, and
notes after the range are shifted so that the stretched region does not
create a "hole" or overlap with notes that follow. If the range begins
or ends with a time (via <code>from-time:</code> and <code>to-time:</code>), time
stretching
takes place over the indicated time interval independent of whether
any notes are present or where they start. In other words, the
“rests” are stretched along with the notes.
The original score is not modified, and a new score is returned.<br><br>
<dt><code>score-transpose(<a name="index1272"></a><i>score</i>,
<i>keyword</i>, <i>amount</i>, from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>, to-time: <i>y</i>)</code> [SAL]<br>
<code>(score-transpose <i>score</i>
<i>keyword</i> <i>amount</i> :from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i> :to-time <i>y</i>)</code> [LISP]</dt>
<dd>For
each note in the score and in any indicated range, if there is a keyword
parameter matching <i>keyword</i> and the
parameter value is a number, increment
the parameter value by <i>amount</i>. For example, to tranpose up by a whole
step, write <code>(score-transpose 2 :pitch <i>score</i>)</code>. The
original score is not modified, and a new score
is returned. If <i>keyword</i> is <code>:pitch</code> and a corresponding parameter value
is a list, each element of the list is incremented by <i>amount</i>. This special
case is in keeping with the convention of <code>timed-seq</code> in which score
events with lists for the <code>:pitch</code> attribute are expanded into "chords"
by instantiating an event for each element (pitch) in the list (chord).<br><br>
<dt><code>score-scale(<a name="index1273"></a><i>score</i>, <i>keyword</i>, <i>amount</i>, from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>,
to-time: <i>y</i>)</code> [SAL]<br>
<code>(score-scale <i>score</i> <i>keyword</i> <i>amount</i>
:from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i> :to-time <i>y</i>)</code> [LISP]</dt>
<dd>For each note
in the score and in any indicated range, if there is a keyword
parameter matching <i>keyword</i> and the
parameter value is a number, multiply
the parameter value by <i>amount</i>. The original score is not modified,
and a new score is returned.<br><br>
<dt><code>score-sustain(<a name="index1274"></a><i>score</i>, <i>factor</i>, from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>,
to-time: <i>y</i>)</code> [SAL]<br>
<code>(score-sustain <i>score</i> <i>factor</i>
:from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i>
:to-time <i>y</i>)</code> [LISP]</dt>
<dd>For each note
in the score and in any indicated range, multiply
the duration (stretch factor) by <i>amount</i>. This can be used to
make notes sound more legato or staccato, and does not change their
starting times. The original score is not modified, and
a new score is returned.<br><br>
<dt><code>score-voice(<a name="index1275"></a><i>score</i>,
<i>replacement-list</i>, from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>, to-time: <i>y</i>)</code> [SAL]<br>
<code>(score-voice <i>score</i>
<i>replacement-list</i> :from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i> :to-time <i>y</i>)</code> [LISP]</dt>
<dd>For each note
in the score and in any indicated range, replace the behavior (function)
name using <i>replacement-list</i>, which has the format:
<code>((<i>old1 new1</i>) (<i>old2 new2</i>) <span style="font-style:normal">...</span>)</code>, where <i>oldi</i> indicates
a current behavior name and <i>newi</i> is the replacement. If <i>oldi</i>
is <code>*</code>, it matches anything. For example, to
replace <code>my-note-1</code> by <code>trombone</code> and <code>my-note-2</code> by
<code>horn</code>, use <code>score-voice(<i>score</i>, {{my-note-1 trombone}
{my-note-2 horn}})</code>. To replace all instruments with
<code>piano</code>, use <code>score-voice(<i>score</i>, {{* piano}})</code>.
The original score is not modified, and a
new score is returned.<br><br>
<dt><code>score-merge(<a name="index1276"></a><i>score1</i>, <i>score2</i>, <span style="font-style:normal">...</span>)</code> [SAL]<br>
<code>(score-merge <i>score1</i> <i>score2</i> <span style="font-style:normal">...</span>)</code> [LISP]</dt>
<dd>Create
a new score containing all the notes of the parameters, which are all
scores. The resulting notes retain their original times and durations. The
merged score begin time is the minimum of the begin times of the parameters
and the merged score end time is the maximum of the end times of
the parameters. The original scores are not modified, and a new
score is returned.<br><br>
<dt><code>score-append(<a name="index1277"></a><i>score1</i>, <i>score2</i>, <span style="font-style:normal">...</span>)</code> [SAL]<br>
<code>(score-append <i>score1</i> <i>score2</i> <span style="font-style:normal">...</span>)</code> [LISP]</dt>
<dd>Create
a new score containing all the notes of the parameters, which are all
scores. The begin time of the first score is unaltered. The begin time of
each other score is aligned to the end time of the
previous score; thus, scores are “spliced” in sequence. The original
scores are not modified, and a new score is returned.<br><br>
<dt><code>score-select(<a name="index1278"></a><a name="index1279"></a><i>score</i>,
<i>predicate</i>, from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>,
to-time: <i>y</i>, reject: <i>flag</i>, extract: <i>ex</i></code> [SAL]<br>
<code>(score-select <i>score</i>
<i>predicate</i> :from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i>
:to-time <i>y</i> :reject <i>flag</i> :extract <i>ex</i>)</code> [LISP]</dt>
<dd>Select
(or reject) notes to form a new score. Notes are selected if they fall
into the given ranges of index and time <i>and</i> they satisfy
<i>predicate</i>, a function of three parameters that is applied to the
start time, duration, and the expression of the note. Alternatively,
<i>predicate</i> may be <code>t</code>, indicating that all notes in range are
to be selected. Note that <code>from-index:</code> <i>i</i> and <code>to-index:</code>
<i>j</i> are 1-based: A value of 1 refers to the first note, etc., because
the zeroth element of the score is a <code>SCORE-BEGIN-END</code> event.
For consistency, if a <code>SCORE-BEGIN-END</code> event is missing
from <i>score</i>, one is inserted before any further processing.
The selected notes are combined to form a new
score. By default, <i>ex</i>, the value of the <code>extract:</code> keyword,
is false, and the begin and end markers are retained from
<i>score</i>. Conceptually, the score and its timing are retained as an
object, but only some of its constituent sound events are retained.
Otherwise, if <i>ex</i> is
true (non-nil), the begin and end times are computed based on the
selected (extracted) events: The begin time is <code>from-time</code> <i>x</i>,
if present, and otherwise the time of the first event (if any), and
otherwise the begin time of <i>score</i>. Similarly, the end time is the
<code>to-time</code> <i>y</i>, if present, and otherwise the end time of the
last event (if any), and otherwise the new start time. Alternatively,
if the <code>reject:</code> parameter is non-null, the notes <i>not</i>
selected form the new score. In other words the selected notes are
rejected or removed to form the new score. The begin and end times of
<i>score</i> are
retained and the <code>extract</code> parameter (<i>ex</i>) is ignored. In all
cases, the original score is not modified, and a new score is
returned.<br><br>
<dt><code>score-set-begin(<a name="index1280"></a><i>score</i>, <i>time</i>)</code> [SAL]<br>
<code>(score-set-begin <i>score</i> <i>time</i>)</code> [LISP]</dt>
<dd>The begin
time
from the <i>score</i>'s <code>SCORE-BEGIN-END</code> marker is set to <i>time</i>. The
original score is not modified, and a new score is returned.<br><br>
<dt><code>score-get-begin(<a name="index1281"></a><i>score</i>)</code> [SAL]<br>
<code>(score-get-begin <i>score</i>)</code> [LISP]</dt>
<dd>Return the begin
time of the <i>score</i>.<br><br>
<dt><code>score-set-end(<a name="index1282"></a><i>score</i>, <i>time</i>)</code> [SAL]<br>
<code>(score-set-end <i>score</i> <i>time</i>)</code> [LISP]</dt>
<dd>The end time
from the <i>score</i>'s <code>SCORE-BEGIN-END</code> marker is set to <i>time</i>. The
original score is not modified, and a new score is returned.<br><br>
<dt><code>score-get-end(<a name="index1283"></a><i>score</i>)</code> [SAL]<br>
<code>(score-get-end <i>score</i>)</code> [LISP]</dt>
<dd>Return the end
time of the <i>score</i>.<br><br>
<dt><code>score-must-have-begin-end(<a name="index1284"></a><i>score</i>)</code> [SAL]<br>
<code>(score-must-have-begin-end <i>score</i>)</code> [LISP]</dt>
<dd>If
<i>score</i> does not have a begin and end time, construct a score with a
<code>SCORE-BEGIN-END</code> expression and return it. If score already has a begin
and end time, just return the score. The orignal score is not modified.<br><br>
<dt><code>score-filter-length(<a name="index1285"></a><i>score</i>,
<i>cutoff</i>)</code> [SAL]<br>
<code>(score-filter-length <i>score</i> <i>cutoff</i>)</code> [LISP]</dt>
<dd>Remove
notes that extend beyond the <i>cutoff</i> time. This
is similar to <code>score-select</code>, but the here, events are removed when
their nominal ending time (start time plus duration) exceeds the <i>cutoff</i>,
whereas the <code>to-time:</code> parameter is compared to the note's start time.
The original score is not modified, and a new score is returned.<br><br>
<dt><code>score-repeat(<a name="index1286"></a><i>score</i>, <i>n</i>)</code> [SAL]<br>
<code>(score-repeat <i>score</i> <i>n</i>)</code> [LISP]</dt>
<dd>Make a sequence
of <i>n</i> copies of <i>score</i>. Each copy is shifted to that it's begin
time aligns with the end time of the previous copy, as in <code>score-append</code>.
The original score is not modified, and a new score is returned.<br><br>
<dt><code>score-stretch-to-length(<a name="index1287"></a><i>score</i>,
<i>length</i>)</code> [SAL]<br>
<code>(score-stretch-to-length <i>score</i> <i>length</i>)</code> [LISP]</dt>
<dd>Stretch the score so that the end time of the score is
the score's begin time plus <i>length</i>.
The original score is not modified, and a new score is returned.<br><br>
<dt><code>score-filter-overlap(<a name="index1288"></a><i>score</i>)</code> [SAL]<br>
<code>(score-filter-overlap <i>score</i>)</code> [LISP]</dt>
<dd>Remove
overlapping notes (based on the note start time and duration), giving
priority to the
positional order within the note list (which is also time order).
The original score is not modified,
and a new score is returned.<br><br>
<dt><code>score-print(<a name="index1289"></a><i>score</i>, [<i>lines</i>])</code> [SAL]<br>
<code>(score-print <i>score</i> [<i>lines</i>])</code> [LISP]</dt>
<dd>Print a score with
one note per line. Returns <code>nil</code>. If <i>lines</i> (optional FIXNUM) is given, print a maximum of that many lines (but the minimum is at least 3). The format is first <i>lines</i>-2 score events, the line "<code>...</code>", and the last score event.<br><br>
<dt><code>score-play(<a name="index1290"></a><i>score</i>)</code> [SAL]<br>
<code>(score-play <i>score</i>)</code> [LISP]</dt>
<dd>Play <i>score</i>
using <code>timed-seq</code> to convert the score to a sound, and
<code>play</code> to play the sound.<br><br>
<dt><code>score-adjacent-events(<a name="index1291"></a><i>score</i>,
<i>function</i>,
from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>, to-time: <i>y</i>)</code> [SAL]<br>
<code>(score-adjacent-events <i>score</i> <i>function</i> :from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i> :to-time <i>y</i>)</code> [LISP]</dt>
<dd>Call
<code>(<i>function</i> <i>A</i> <i>B</i> <i>C</i>)</code>, where
<i>A</i>, <i>B</i>, and <i>C</i> are consecutive notes in the score. The result
replaces <i>B</i>. If the result is <code>nil</code>, <i>B</i> is deleted, and the
next call will be <code>(<i>function A C D</i>)</code>, etc. The first call is
to <code>(<i>function</i> nil <i>A B</i>)</code> and the last is to
<code>(<i>function</i> <i>Y Z</i> nil)</code>. If there is just one note in the
score, <code>(<i>function</i> nil <i>A</i> nil)</code> is called. Function calls
are not made if the note is outside of the indicated range.
This function
allows notes and their parameters to be adjusted according to their
immediate context. The original score is not modified,
and a new score is returned.<br><br>
<dt><code>score-apply(<a name="index1292"></a><i>score</i>, <i>function</i>,
from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>, to-time: <i>y</i>)</code>
[SAL]<br>
<code>(score-apply <i>score</i> <i>function</i> :from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i> :to-time <i>y</i>)</code> [LISP]</dt>
<dd>Replace
each note in the score with the result of
<code>(<i>function time dur expression</i>)</code> (in Lisp) or
<code><i>function</i>(<i>time</i>, <i>dur</i>, <i>expression</i>)</code> (in SAL),
where <i>time</i>, <i>dur</i>,
and <i>expression</i> are the time, duration, and expression of the note.
If a range is indicated, only notes in the range are replaced.
The original score is not modified, and a new score is returned.
</dd></dl>
For example, the following uses <code>score-apply</code> to insert an
<code>accent:</code> attribute with value 100 on every sound event
(note) where <code>pitch:</code> is greater than 70. Notice that
<code>add-accents</code> must be quoted to pass the <i>name</i> of the function
to <code>score-apply</code> (without the <code>quote</code>,
<code>add-accents</code> denotes the value of a variable, but as a variable,
<code>add-accents</code> is undefined). Also, note that <code>add-accents</code>
must construct and return a valid score event, hence the expression
<code>list(time, dur, sound))</code>.
<p></p>
<pre>
set my-score = {{0 1 {note pitch: 60}}
{1 1 {note pitch: 72}}}
function add-accents(time, dur, sound)
begin
if expr-get-attr(sound, :pitch, 70) > 70 then
set sound = expr-set-attr(sound, :accent, 100)
return list(time, dur, sound)
end
exec score-print(score-apply(my-score, quote(add-accents)))
</pre>
<p>
The output will be:
</p>
<pre>
((0 0 (SCORE-BEGIN-END 0 2))
(0 1 (NOTE :PITCH 60))
(1 1 (NOTE :PITCH 72 :ACCENT 100))
)
</pre>
<p></p>
<dl>
<dt>
<code>score-indexof(<a name="index1293"></a><i>score</i>, <i>function</i>,
from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>, to-time: <i>y</i>)</code> [SAL]<br>
<code>(score-indexof <i>score</i> <i>function</i> :from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i> :to-time <i>y</i>)</code> [LISP]</dt>
<dd>Return the index (position)
of the first score event (in range) for which applying <i>function</i>
using <code>(<i>function time dur expression</i>)</code> returns true.<br><br>
<dt><code>score-last-indexof(<a name="index1294"></a><i>score</i>,
<i>function</i>, from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>,
to-time: <i>y</i>)</code> [SAL]<br>
<code>(score-last-indexof <i>score</i> <i>function</i>
:from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i> :to-time <i>y</i>)</code> [LISP]</dt>
<dd>Return
the index (position)
of the last score event (in range) for which applying <i>function</i>
using <code>(<i>function time dur expression</i>)</code> returns true.<br><br>
<dt><code>score-randomize-start(<a name="index1295"></a><a name="index1296"></a><a name="index1297"></a><a name="index1298"></a><i>score</i>, <i>amt</i>, from-index: <i>i</i>, to-index: <i>j</i>, from-time: <i>x</i>, to-time: <i>y</i>)</code> [SAL]<br>
<code>(score-randomize-start <i>score</i> <i>amt</i>
:from-index <i>i</i> :to-index <i>j</i> :from-time <i>x</i> :to-time <i>y</i>)</code> [LISP]</dt>
<dd>Alter the
start times of notes by a
random amount up to plus or minus <i>amt</i>.
The original score is not modified, and a new score is returned.
</dd></dl><a name = "182"><h4>Xmusic and Standard MIDI Files</h4></a><a name="index1299"></a><a name="index1300"></a>
<p>Nyquist has a general facility to read and write MIDI files.
You can even translate to and from a text representation, as described
in Chapter <a href = "part12.html#123">MIDI, Adagio, and Sequences</a>. It is also useful sometimes to read notes
from Standard MIDI Files into Xmusic scores and vice versa. </p>
<p>Using <code>score-read-smf</code> and <code>score-read</code>, MIDI notes are
translated to Xmusic score events as follows:
<blockquote>
<code>(<i>time</i> <i>dur</i> (NOTE :chan <i>channel</i> :pitch <i>keynum</i> :vel <i>velocity</i>))</code>,<br>
</blockquote> where <i>channel</i>, <i>keynum</i>, and <i>velocity</i> come directly
from the MIDI message (channels are numbered starting from zero).
Note also that note-off messages are implied by the stretch factor
<i>dur</i> which is duration in seconds.</p>
<p>The <code>score-from-seq</code> function allows you to obtain control changes
and other MIDI messages.</p>
<dl>
<dt>
<code>score-read-smf(<a name="index1301"></a><a name="index1302"></a><i>filename</i>)</code> [SAL]<br>
<code>(score-read-smf <i>filename</i>)</code> [LISP]</dt>
<dd>Read a
standard MIDI file from <i>filename</i>. Return an Xmusic score, or <code>nil</code>
if the file could not be opened. The
start time is zero, and the end time is the maximum end time of all
notes. A very limited interface is offered to extract MIDI program numbers
from the file: The global variable <code>*rslt*</code> is set to a list of MIDI
program numbers for each channel. E.g. if <code>*rslt*</code> is <code>(0 20 77)</code>,
then program for channel 0 is 0, for channel 1 is 20, and for channel 2 is 77.
Program changes were not found on other channels. The default program number is
0, so in this example, it is not known whether the program 0 on channel 0
is the result of a real MIDI program change command or just a default value.
If more than one program change exists on a channel, the <i>last</i> program
number is recorded and returned, so this information will only be completely
correct when the MIDI file sends single program change per channel before
any notes are played. This, however, is a fairly common practice. Note that
the list returned as <code>*rslt*</code> can be passed
to <code>score-write-smf</code>, described below.<br><br>
<dt><code>score-read(<a name="index1303"></a><a name="index1304"></a><i>filename</i>)</code> [SAL]<br>
<code>(score-read <i>filename</i>)</code> [LISP]</dt>
<dd>Read an Adagio
file from <i>filename</i>. Return an Xmusic score, or <code>nil</code>
if the file could not be opened. See Chapter <a href = "part12.html#123">MIDI, Adagio, and Sequences</a> for details on
Adagio, a text-based score language. See <code>score-read-smf</code> for
details on handling program changes.<br><br>
<dt><code>score-from-seq(<a name="index1305"></a><a name="index1306"></a><i>seq</i>, prog: <i>pflag</i>, synths: <i>synths</i>, bend: <i>bend</i>, cpress: <i>cpress</i>, ctrl: <i>ctrls</i>)</code> [SAL]<br>
<code>(score-from-seq <i>seq</i> :prog <i>pflag</i> :synths <i>synths</i> :bend <i>bend</i> :cpress <i>cpress</i> :ctrl <i>ctrls</i>)</code> [LISP]</dt>
<dd>Produce
a score from a sequence (see Section <a href = "part12.html#124">The SEQ Type</a>) type
<i>seq</i>. The optional <i>pflag</i>, if non-null, will insert program
changes as event <code>:prog</code> attributes in score events. The
<i>bend</i> and <i>cpress</i> (channel pressure) values may be
<code>:onset</code> to introduce <code>:bend</code> or <code>:cpress</code> attributes
into score events, or <code>:contin</code> to encode these MIDI messages as
SOUNDs available through event <code>:contin</code> attributes. The
<i>ctrl</i> parameter is a list where the first element is either
<code>:onset</code> or <code>:contin</code> and the remaining elements are
controller numbers to be encoded. In all cases <code>:contin</code> values
appear in score events as an object. You can access the SOUNDs that
encode control changes using the functions
<code>ctrlfn-bend(<i>contin</i>)</code><a name="index1307"></a>,
<code>ctrlfn-cpress(<i>contin</i>)</code><a name="index1308"></a> or
<code>ctrlfn-ctrl(<i>contin</i>, <i>number</i>)</code><a name="index1309"></a>, which
will return <code>const(0)</code> if no corresponding MIDI messages were
found. (As a special case the default for controller 7 (volume pedal)
is <code>const(1)</code>).
See <code>lib/midi/midi_tutorial.htm</code> for more details and code
examples. To test for the presence of MIDI messages and avoid the
construction of <code>const(0)</code>, use
<code>ctrlfn-bend?(<i>contin</i>)</code><a name="index1310"></a>,
<code>ctrlfn-cpress?(<i>contin</i>)</code><a name="index1311"></a> or
<code>ctrlfn-ctrl?(<i>contin</i>, <i>number</i>)</code><a name="index1312"></a>.<br><br>
<dt><code>score-write-smf(<a name="index1313"></a><a name="index1314"></a><i>score</i>, <i>filename</i>,
[<i>programs</i> <i>as-adagio</i>])</code> [SAL]<br>
<code>(score-write-smf <i>score</i> <i>filename</i> [<i>programs</i> <i>as-adagio</i>])</code> [LISP]</dt>
<dd>Write a standard MIDI file to <i>filename</i>
with notes in <i>score</i>. In this function,
<i>every</i> event in the score with a <code>pitch:</code> attribute, regardless of the
“instrument” (or function name), generates a
MIDI note, using the <code>chan:</code> attribute for the channel (default 0) and
the <code>vel:</code> attribute for velocity (default 100). There is no facility
(in the current implementation) to issue control changes, but to allow
different instruments, MIDI programs may be set in two ways. The simplest is
to associate programs with channels using
the optional <i>programs</i> parameter, which is simply a list of up to 16 MIDI
program numbers. Corresponding program change commands are added to the
beginning of the MIDI file. If <i>programs</i> has less than 16 elements, program
change commands are only sent on the first <i>n</i> channels. The second way to
issue MIDI program changes is to add a <code>program:</code> keyword parameter to
a note in the score. Typically, the note will have a <code>pitch:</code> of
<code>nil</code> so that no actual MIDI note-on message is generated. If program
changes and notes have the same starting times, their relative playback
order is undefined, and the note may be cut off by an immediately
following program change. Therefore, program changes should occur slightly,
e.g. 1 ms, before any notes. <i>Program numbers and channels are numbered
starting at zero, matching the internal MIDI representation. This may be
one less than displayed on MIDI hardware, sequencers, etc.</i> The
<i>as-adagio</i> optional parameter should normally be omitted.
If non-nil, the file is written in Adagio format, but if you
want to do that, call <code>score-write</code> instead. Xmusic scores do not specify
tempo, so the MIDI file is written with a fixed tempo of 100bpm. If you create
scores or stretch scores so that each beat is exactly 0.6s (100bpm), sequencers
and score editors will quantize your scores correctly. Otherwise, the <i>timing</i>
will be correct, but for example a score with one note every second will be
notated as 1 note every 1 2/3 beats.<br><br>
<dt><code>score-write(<a name="index1315"></a><a name="index1316"></a><i>score</i>, <i>filename</i>,
[<i>programs</i>, <i>absolute</i>])</code> [SAL]<br>
<code>(score-write <i>score</i> <i>filename</i> [<i>programs</i> <i>absolute</i>)]</code> [LISP]</dt>
<dd>Write an Adagio format file to <i>filename</i> with notes in <i>score</i>, using absolute times if <i>absolute</i> is true, otherwise write relative times (the default). See Chapter <a href = "part12.html#123">MIDI, Adagio, and Sequences</a> for details on Adagio, a text-based score language. See <code>score-write-smf</code> for details on MIDI program changes.
</dd></dl><a name = "183"><h4>Workspaces</h4></a><a name="index1317"></a>
<p>When working with scores, you may find it necessary to save
them in files between work sessions. This is not an issue
with functions because they are
normally edited in files and loaded from them. In contrast,
scores are created as Lisp data, and unless you take care to
save them, they will be destroyed when you exit the Nyquist
program.</p>
<p>A simple mechanism called a workspace has been created
to manage scores (and any other Lisp data, for that matter).
A workspace is just a set of lisp global variables. These
variables are stored in the file <code>workspace.lsp</code>.
For simplicity, there is only one workspace, and no backups
or versions are maintained, but the user is free to make
backups and copies of <code>workspace.lsp</code>.
To help remember what each variable is for, you can also
associate and retrieve a text string with each variable.
The following functions manage workspaces.</p>
<p>In addition, when a workspace is loaded, you can request that
functions be called. For example, the workspace might store
descriptions of a graphical interface. When the workspace is
loaded, a function might run to convert saved data into a
graphical interface. (This is how sliders are saved by the IDE.)</p>
<dl>
<dt>
<code>add-to-workspace(<a name="index1318"></a><i>symbol</i>)</code> [SAL]<br>
<code>(add-to-workspace <i>symbol</i>)</code> [LISP]</dt>
<dd>Adds
a global variable to the workspace. The <i>symbol</i> should be a (quoted)
symbol.<br><br>
<dt><code>save-workspace(<a name="index1319"></a>)</code> [SAL]<br>
<code>(save-workspace)</code> [LISP]</dt>
<dd>All global variables
in the workspace are saved to <code>workspace.lsp</code> (in the current
directory), overwriting the previous file.<br><br>
<dt><code>describe(<a name="index1320"></a><i>symbol</i> [, <i>description</i>])</code>
[SAL]<br>
<code>(describe <i>symbol</i> [<i>description</i>])</code> [LISP]</dt>
<dd>If <i>description</i>, a text string, is present,
associate <i>description</i> with the variable named by the
<i>symbol</i>. If <i>symbol</i> is not already in the workspace,
it is added. If <i>description</i> is omitted, the function returns
the current description (from a previous call) for <i>symbol</i>.<br><br>
<dt><code>add-action-to-workspace(<a name="index1321"></a><i>symbol</i>)</code> [SAL]<br>
<code>(add-action-to-workspace <i>symbol</i>)</code> [LISP]</dt>
<dd>Requests that the function named by <i>symbol</i> be
called when the workspace is loaded (if the function is defined).
</dd></dl>
<p>To restore a workspace, use the command <code>load "workspace"</code>. This restores
the values of the workspace variables to the values they had when
<code>save-workspace</code> was last called. It also restores the documentation
strings, if set, by <code>describe</code>. If you load two or more
<code>workspace.lsp</code> files, the variables will be merged into a
single workspace. The current set of workspace variables are saved in
the list <code>*workspace*</code>. To clear the workspace, set <code>*workspace*</code>
to <code>nil</code>. This does not delete any variables, but means that
no variables will be saved by <code>save-workspace</code> until variables are
added again.</p>
<p>Functions to be called are saved in the list <code>*workspace-actions*</code>.
to clear the functions, set <code>*workspace-actions*</code> to <code>nil</code>.
Restore functions to the list with <code>add-action-to-workspace</code>.</p>
<a name = "184"><h4>Utility Functions</h4></a>
<p>This chapter concludes with details of various utility functions for score
manipulation.</p>
<dl>
<dt>
<code>patternp(<a name="index1322"></a><i>expression</i>)</code> [SAL]<br>
<code>(patternp <i>expression</i>)</code> [LISP]</dt>
<dd>Test if <i>expression</i> is
an Xmusic pattern.<br><br>
<dt><code>params-transpose(<a name="index1323"></a><i>params</i>, <i>keyword</i>,
<i>amount</i>)</code> [SAL]<br>
<code>(params-transpose <i>params</i> <i>keyword</i> <i>amount</i>)</code> [LISP]</dt>
<dd>Add a transposition amount to a score event parameter. The
<i>params</i>
parameter is a list of keyword/value pairs (not preceded by a function name).
The <i>keyword</i> is the keyword of the value to be altered, and <i>amount</i>
is a number to be added to the value. If no matching keyword is present
in <i>params</i>, then <i>params</i> is returned. Otherwise, a new parameter
list is constructed and returned. The original <i>params</i> is not changed.<br><br>
<dt><code>params-scale(<a name="index1324"></a><i>params</i>, <i>keyword</i>,
<i>amount</i>)</code> [SAL]<br>
<code>(params-scale <i>params</i> <i>keyword</i> <i>amount</i>)</code> [LISP]</dt>
<dd>Scale a score event parameter by some factor. This is like
<code>params-transpose</code>, only using multiplication. The <i>params</i>
list is a list of
keyword/value pairs, <i>keyword</i> is the parameter keyword,
and <i>amount</i> is the scale factor. <br><br>
<dt><code>interpolate(<a name="index1325"></a><a name="index1326"></a><i>x</i>, <i>x1</i>, <i>y1</i>, <i>x2</i>, <i>y2</i>)</code> [SAL]<br>
<code>(interpolate <i>x</i> <i>x1</i> <i>y1</i> <i>x2</i> <i>y2</i>)</code> [LISP]</dt>
<dd>Linearly interpolate (or extrapolate)
between points
(<i>x1</i>, <i>y1</i>) and (<i>x2</i>, <i>y2</i>) to compute the y value
corresponding to <i>x</i>.<br><br>
<dt><code>intersection(<a name="index1327"></a><a name="index1328"></a><i>a</i>,
<i>b</i>)</code> [SAL]<br>
<code>(intersection <i>a</i> <i>b</i>)</code> [LISP]</dt>
<dd>Compute the set intersection of lists <i>a</i> and <i>b</i>.<br><br>
<dt><code>union(<a name="index1329"></a><a name="index1330"></a><i>a</i>, <i>b</i>)</code> [SAL]<br>
<code>(union <i>a</i> <i>b</i>)</code> [LISP]</dt>
<dd>Compute
the set union of lists <i>a</i> and <i>b</i>.<br><br>
<dt><code>set-difference(<a name="index1331"></a><a name="index1332"></a><i>a</i>,
<i>b</i>)</code> [SAL]<br>
<code>(set-difference <i>a</i> <i>b</i>)</code> [LISP]</dt>
<dd>Compute the set of all elements that are in <i>a</i> but not in <i>b</i>.<br><br>
<dt><code>subsetp(<a name="index1333"></a><a name="index1334"></a><i>a</i>, <i>b</i>)</code> [SAL]<br>
<code>(subsetp <i>a</i> <i>b</i>)</code> [LISP]</dt>
<dd>Returns true iff
<i>a</i> is a subset of <i>b</i>, that is, each element of <i>a</i> is a member
of <i>b</i>.
</dd></dl><hr>
<a href = "part14.html">Previous Section</a> | <a href = "part16.html">Next Section</a> | <a href = "title.html#toc">Table of Contents</a> | <a href = "indx.html">Index</a> | <a href = "title.html">Title Page</a>
</body></html>
|