00001 #include "MusimatTutorial.h" 00002 MusimatTutorialSection(B0202) { 00003 Print("*** B.2.2 Rhythm ***"); 00004 /***************************************************************************** 00005 00006 B.2.2 Rhythm 00007 00008 Duration in common music notation is expressed as a fraction of a whole note. For example a whole 00009 note equals four quarter notes: 00010 00011 w = q + q + q + q 00012 00013 /***************************************************************************** 00014 We could write this mathematically as follows: 00015 00016 1 1 1 1 1 00017 - = -,-,-,- 00018 1 4 4 4 4 00019 00020 which suggests using rational fractions to represent rhythmic durations. A rational fraction is a 00021 ratio of integers. Musimat comes with a built-in data type called Rhythm, which emulates com- 00022 mon musical notation conventions regarding rhythm. For example, the quarter note is defined as 00023 *****************************************************************************/ 00024 00025 Rhythm Q = Rhythm( 1, 4 ); 00026 00027 /***************************************************************************** 00028 The first number is the numerator of the rational fraction, the second is the denominator. Note that 00029 we can’t write Rhythm(1/4) because the integer quotient of 1/4 is 0 with a remainder of 1; integer 00030 division is performed if both the numerator and denominator are integers, which won’t work here. 00031 Specifying the numerator and denominator separately avoids this problem and has some other 00032 numerical advantages as well. Executing Print(Q); prints (1, 4). Internally, Rhythm() 00033 keeps the integer numerator and denominator values separately. 00034 00035 Rhythmic duration can also be given as a real expression. 00036 *****************************************************************************/ 00037 00038 Print(Rhythm(0.5)); 00039 00040 /***************************************************************************** 00041 prints (1, 2). How does Rhythm() convert this real expression into a ratio of integers? It does so by 00042 calling the following function internally: 00043 *****************************************************************************/ 00044 para1(); // Step into this function to continue the tutorial 00045 para2(); // Step into this function to continue the tutorial 00046 } 00047 00048 Void realToRational(Real f, Integer Reference num, Integer Reference den) { 00049 Const Integer iterations = 3000000; 00050 Const Real limit = 0.000000000001; 00051 num = den = 1; // start off with ratio of 1/1 00052 For (Integer i = 0; i < iterations; i = i + 1) { 00053 If (Abs( Real(num) / Real(den) - f ) < limit) 00054 Return; // we have reached the limit 00055 Else { 00056 Real x = Abs(Real(num+1) / Real(den) - f); 00057 Real y = Abs(Real(num) / Real(den+1) - f); 00058 If (x < y) 00059 num = num + 1; 00060 Else 00061 den = den + 1; 00062 } 00063 } 00064 Return; // if we get here, we've not converged on the limit 00065 } // RealAbs() is just a version of Abs() that uses Real arithmetic 00066 00067 Static Void para1() { 00068 /***************************************************************************** 00069 Function realToRational() takes a Real value f and attempts to find a rational fraction 00070 num/den that is as close as possible to it. It starts by setting num = den = 1 and asking whether 00071 num/den is already close enough to f. If so, it returns. Otherwise, it asks whether (num+1) / den 00072 is closer than num / (den+1). If so, it increments num; otherwise it increments den and repeats the 00073 process. Because num and den are Reference arguments, any changes to these variables within 00074 realToRational() are reflected in the value of the actual arguments supplied to it. 00075 00076 This method can be used to find rational approximations to most any real value. For example, 00077 *****************************************************************************/ 00078 00079 Real Pi = 3.14159265; 00080 Print(Rhythm(Pi)); 00081 00082 /***************************************************************************** 00083 prints (1953857, 621932). Note that 1953857/621932 = 3.14159265, which is 00084 pretty close to the value of Pi. This method is limited by the precision of the computer hardware. 00085 The precision of a rational approximation depends upon the value of the built-in variables 00086 iterations and limit. For example, with the values shown in the preceding code, it took 00087 realToRational() 2,575,787 trials to come up with its best approximation of Pi, requiring 00088 about 1 second on my computer. The iteration and limit parameters can be set to whatever 00089 values produce the optimal performance/accuracy cost/benefit ratio. Barring obscure rhythms 00090 (nothing, say, beyond triplet eights), iterations = 240 and limit = 1.0/480 should be 00091 satisfactory. 00092 00093 Although the details go beyond the scope of this book, here is a sketch of how Rhythm() uses 00094 realToRational(): 00095 00096 Rhythm(Real x) { 00097 Integer num, den; // internal parameters for Rhythm 00098 realToRational( x, num, den ); // convert x to num / den rational fraction 00099 // . . . 00100 } 00101 00102 When called with a Real argument, Rhythm() calls realToRational() to set its internal integer 00103 rational fraction values. 00104 00105 Musimat provides built-in definitions for standard binary divisions of a whole note: 00106 *****************************************************************************/ 00107 00108 Rhythm Whole = Rhythm(1.0/1.0); 00109 Rhythm Half = Rhythm(1.0/2.0); 00110 Rhythm Quarter = Rhythm(1.0/4.0); 00111 Rhythm Eighth = Rhythm(1.0/8.0); 00112 Rhythm Sixteenth = Rhythm(1.0/16.0); 00113 00114 /***************************************************************************** 00115 It is easy to define ternary divisions as well. For example, a triplet eighth is Rhythm(1.0/12.0) 00116 because there are triplet eighths per whole note. By the same reasoning, a quintuplet 00117 eighth is 00118 *****************************************************************************/ 00119 00120 Rhythm Qe = Rhythm(1.0/20.0); 00121 00122 /***************************************************************************** 00123 We can express compound rhythms by addition. For example, a dotted half note is 00124 *****************************************************************************/ 00125 00126 Rhythm Hd = Rhythm(1.0/2.0 + 1.0/4.0); // dotted half 00127 00128 /***************************************************************************** 00129 Equivalently, 00130 *****************************************************************************/ 00131 00132 Rhythm H1 = Rhythm(3.0 / 4.0); // also a dotted half 00133 00134 /***************************************************************************** 00135 We can also do arithmetic directly with rhythms. For example, 00136 *****************************************************************************/ 00137 00138 Print(Eighth+Sixteenth); 00139 00140 /***************************************************************************** 00141 prints (3, 16). 00142 00143 Also, 00144 *****************************************************************************/ 00145 00146 Print(Whole - Sixteenth); 00147 00148 /***************************************************************************** 00149 prints (15,16), 00150 *****************************************************************************/ 00151 00152 Print(Quarter * Sixteenth); 00153 00154 /***************************************************************************** 00155 prints (1,64), and 00156 *****************************************************************************/ 00157 00158 Print(Quarter / Sixteenth); 00159 00160 /***************************************************************************** 00161 prints (4,1). The last value corresponds to a duration of four whole notes. 00162 00163 We can extract the numerator and denominator from Rhythm(): 00164 *****************************************************************************/ 00165 00166 Integer num, den; 00167 Rhythm z = Rhythm(Eighth + Sixteenth, num, den); // assigns rational fraction for E+S to num and den 00168 00169 /***************************************************************************** 00170 Used this way, Rhythm() calculates the rational fraction of its first argument and sets num and 00171 den by reference to the result. For the preceding example, num is set to 3 and den is set to 16. We 00172 can leverage this capability to obtain the duration of a rhythm as a real number: 00173 *****************************************************************************/ 00174 } 00175 00176 Real realRhythm(Rhythm x) { 00177 Integer num, den; 00178 Rhythm(x, num, den); // find rational fraction for x and set num and den 00179 Return(Real(num)/Real(den)); // convert num and den to reals and divide 00180 } 00181 00182 Void para2() { 00183 /***************************************************************************** 00184 Then, for example, executing Print(realRhythm(E + S)); prints 0.1875. 00185 As with pitches, we can make lists of rhythms. 00186 *****************************************************************************/ 00187 00188 RhythmList RL = RhythmList(Quarter, Eighth, Eighth, Eighth, Sixteenth, Sixteenth, Quarter); 00189 Print(RL); 00190 00191 /***************************************************************************** 00192 prints {(1,4), (1,8), (1,8), (1,8), (1,16), (1,16), (1,4)}. 00193 00194 *****************************************************************************/ 00195 }} 00196 00198 /* $Revision: 1.4 $ $Date: 2006/09/12 17:38:02 $ $Author: dgl $ $Name: $ $Id: _b0202_8cpp-source.html,v 1.4 2006/09/12 17:38:02 dgl Exp $ */ 00199 // The Musimat Tutorial © 2006 Gareth Loy 00200 // Derived from Chapter 9 and Appendix B of "Musimathics Vol. 1" © 2006 Gareth Loy 00201 // and published exclusively by The MIT Press. 00202 // This program is released WITHOUT ANY WARRANTY; without even the implied 00203 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00204 // For information on usage and redistribution, and for a DISCLAIMER OF ALL 00205 // WARRANTIES, see the file, "LICENSE.txt," in this distribution. 00206 // "Musimathics" is available here: http://mitpress.mit.edu/catalog/item/default.asp?ttype=2&tid=10916 00207 // Gareth Loy's Musimathics website: http://www.musimathics.com/ 00208 // The Musimat website: http://www.musimat.com/ 00209 // This program is released under the terms of the GNU General Public License 00210 // available here: http://www.gnu.org/licenses/gpl.txt 00211
1.4.7