C:/Musimathics_local/Musimat/MusimatTutorial/B0202.cpp

Go to the documentation of this file.
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 

Generated on Tue Sep 12 10:14:24 2006 for Musimat Tutorial by  doxygen 1.4.7