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 00045 para1(); // Step into this function to continue the tutorial 00046 para2(); // Step into this function to continue the tutorial 00047 } 00048 00049 Void realToRational(Real f, Integer Reference num, Integer Reference den) { 00050 Const Integer iterations = 3000000; 00051 Const Real limit = 0.000000000001; 00052 num = den = 1; // start off with ratio of 1/1 00053 For (Integer i = 0; i < iterations; i = i + 1) { 00054 If (Abs( Real(num) / Real(den) - f ) < limit) 00055 Return; // we have reached the limit 00056 Else { 00057 Real x = Abs(Real(num+1) / Real(den) - f); 00058 Real y = Abs(Real(num) / Real(den+1) - f); 00059 If (x < y) 00060 num = num + 1; 00061 Else 00062 den = den + 1; 00063 } 00064 } 00065 Return; // if we get here, we've not converged on the limit 00066 } 00067 00068 Static Void para1() { 00069 00070 /***************************************************************************** 00071 Function realToRational() takes a Real value f and attempts to find a rational fraction 00072 num/den that is as close as possible to it. It starts by setting num = den = 1 and asking whether 00073 num/den is already close enough to f. If so, it returns. Otherwise, it asks whether (num+1) / den 00074 is closer than num / (den+1). If so, it increments num; otherwise it increments den and repeats the 00075 process. Because num and den are Reference arguments, any changes to these variables within 00076 realToRational() are reflected in the value of the actual arguments supplied to it. 00077 00078 This method can be used to find rational approximations to most any real value. For example, 00079 *****************************************************************************/ 00080 00081 Real Pi = 3.14159265; 00082 Print(Rhythm(Pi)); 00083 00084 /***************************************************************************** 00085 prints (1953857, 621932). Note that 1953857/621932 = 3.14159265, which is 00086 pretty close to the value of Pi. This method is limited by the precision of the computer hardware. 00087 The precision of a rational approximation depends upon the value of the built-in variables 00088 iterations and limit. For example, with the values shown in the preceding code, it took 00089 realToRational() 2,575,787 trials to come up with its best approximation of Pi, requiring 00090 about 1 second on my computer. The iteration and limit parameters can be set to whatever 00091 values produce the optimal performance/accuracy cost/benefit ratio. Barring obscure rhythms 00092 (nothing, say, beyond triplet eights), iterations = 240 and limit = 1.0/480 should be 00093 satisfactory. 00094 00095 Although the details go beyond the scope of this book, here is a sketch of how Rhythm() uses 00096 realToRational(): 00097 00098 Rhythm(Real x) { 00099 Integer num, den; // internal parameters for Rhythm 00100 realToRational( x, num, den ); // convert x to num / den rational fraction 00101 // . . . 00102 } 00103 00104 When called with a Real argument, Rhythm() calls realToRational() to set its internal integer 00105 rational fraction values. 00106 00107 Musimat provides built-in definitions for standard binary divisions of a whole note: 00108 *****************************************************************************/ 00109 00110 Rhythm Whole = Rhythm(1.0/1.0); 00111 Rhythm Half = Rhythm(1.0/2.0); 00112 Rhythm Quarter = Rhythm(1.0/4.0); 00113 Rhythm Eighth = Rhythm(1.0/8.0); 00114 Rhythm Sixteenth = Rhythm(1.0/16.0); 00115 00116 /***************************************************************************** 00117 It is easy to define ternary divisions as well. For example, a triplet eighth is Rhythm(1.0/12.0) 00118 because there are triplet eighths per whole note. By the same reasoning, a quintuplet 00119 eighth is 00120 *****************************************************************************/ 00121 00122 Rhythm Qe = Rhythm(1.0/20.0); 00123 00124 /***************************************************************************** 00125 We can express compound rhythms by addition. For example, a dotted half note is 00126 *****************************************************************************/ 00127 00128 Rhythm Hd = Rhythm(1.0/2.0 + 1.0/4.0); // dotted half 00129 00130 /***************************************************************************** 00131 Equivalently, 00132 *****************************************************************************/ 00133 00134 Rhythm H1 = Rhythm(3.0 / 4.0); // also a dotted half 00135 00136 /***************************************************************************** 00137 We can also do arithmetic directly with rhythms. For example, 00138 *****************************************************************************/ 00139 00140 Print(Eighth+Sixteenth); 00141 00142 /***************************************************************************** 00143 prints (3, 16). 00144 00145 Also, 00146 *****************************************************************************/ 00147 00148 Print(Whole - Sixteenth); 00149 00150 /***************************************************************************** 00151 prints (15,16), 00152 *****************************************************************************/ 00153 00154 Print(Quarter * Sixteenth); 00155 00156 /***************************************************************************** 00157 prints (1,64), and 00158 *****************************************************************************/ 00159 00160 Print(Quarter / Sixteenth); 00161 00162 /***************************************************************************** 00163 prints (4,1). The last value corresponds to a duration of four whole notes. 00164 00165 We can extract the numerator and denominator from Rhythm(): 00166 *****************************************************************************/ 00167 00168 Integer num, den; 00169 Rhythm z = Rhythm(Eighth + Sixteenth, num, den); // assigns rational fraction for E+S to num and den 00170 00171 /***************************************************************************** 00172 Used this way, Rhythm() calculates the rational fraction of its first argument and sets num and 00173 den by reference to the result. For the preceding example, num is set to 3 and den is set to 16. We 00174 can leverage this capability to obtain the duration of a rhythm as a real number: 00175 *****************************************************************************/ 00176 } 00177 00178 Real realRhythm(Rhythm x) { 00179 Integer num, den; 00180 Rhythm(x, num, den); // find rational fraction for x and set num and den 00181 Return(Real(num)/Real(den)); // convert num and den to reals and divide 00182 } 00183 00184 Void para2() { 00185 00186 /***************************************************************************** 00187 Then, for example, executing Print(realRhythm(E + S)); prints 0.1875. 00188 As with pitches, we can make lists of rhythms. 00189 *****************************************************************************/ 00190 00191 RhythmList RL = RhythmList(Quarter, Eighth, Eighth, Eighth, Sixteenth, Sixteenth, Quarter); 00192 Print(RL); 00193 00194 /***************************************************************************** 00195 prints {(1,4), (1,8), (1,8), (1,8), (1,16), (1,16), (1,4)}. 00196 *****************************************************************************/ 00197 } 00198 00200 /* $Revision: 1.3 $ $Date: 2006/09/05 08:03:08 $ $Author: dgl $ $Name: $ $Id: B0202.cpp,v 1.3 2006/09/05 08:03:08 dgl Exp $ */ 00201 // The Musimat Tutorial © 2006 Gareth Loy 00202 // Derived from Chapter 9 and Appendix B of "Musimathics Vol. 1" © 2006 Gareth Loy 00203 // and published exclusively by The MIT Press. 00204 // This program is released WITHOUT ANY WARRANTY; without even the implied 00205 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00206 // For information on usage and redistribution, and for a DISCLAIMER OF ALL 00207 // WARRANTIES, see the file, "LICENSE.txt," in this distribution. 00208 // "Musimathics" is available here: http://mitpress.mit.edu/catalog/item/default.asp?ttype=2&tid=10916 00209 // Gareth Loy's Musimathics website: http://www.musimathics.com/ 00210 // The Musimat website: http://www.musimat.com/ 00211 // This program is released under the terms of the GNU General Public License 00212 // available here: http://www.gnu.org/licenses/gpl.txt 00213