1 """Tonal space manipulations and analysis.
2
3 Note that this module is only intended for formalism-independent
4 tonal space manipulations. Functions should not rely on representations
5 that are formalism-specific, like
6 L{TonalDenotation<jazzparser.formalisms.music_keyspan.semantics.TonalDenotation>}.
7 They may use things like coordinates, which could be produced from
8 an formalism-specific semantics.
9
10 """
11 """
12 ============================== License ========================================
13 Copyright (C) 2008, 2010-12 University of Edinburgh, Mark Granroth-Wilding
14
15 This file is part of The Jazz Parser.
16
17 The Jazz Parser is free software: you can redistribute it and/or modify
18 it under the terms of the GNU General Public License as published by
19 the Free Software Foundation, either version 3 of the License, or
20 (at your option) any later version.
21
22 The Jazz Parser is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with The Jazz Parser. If not, see <http://www.gnu.org/licenses/>.
29
30 ============================ End license ======================================
31
32 """
33 __author__ = "Mark Granroth-Wilding <mark.granroth-wilding@ed.ac.uk>"
34
35
37 """
38 Returns the coordinate of the point with the given root number
39 that is closest to the given point base_coord. Coordinates are
40 represented as (x,y) tuples. The root number is the semitone
41 number of the root (0->I, 1->bII, etc). 0 is assumed to be the
42 ET equivalence set including the central point (0,0).
43
44 @rtype: (x,y) coordinate
45 @return: the location of the point with the given ET root number
46 that is closest to the base point.
47
48 """
49 base_x, base_y = base_coord
50
51 base_root = (7*base_x + 4*base_y) % 12
52
53
54 interval = (root_number - base_root) % 12
55
56
57
58
59
60 rel_coord = {
61 0 : (0,0),
62 1 : (-1,-1),
63 2 : (2,0),
64 3 : (1,-1),
65 4 : (0,1),
66 5 : (-1,0),
67 6 : (-2,-1),
68 7 : (1,0),
69 8 : (0,-1),
70 9 : (-1,1),
71 10 : (-2,0),
72 11 : (1,1)
73 }[interval]
74
75 return (base_x+rel_coord[0], base_y+rel_coord[1])
76
78 """
79 Given a list of tonal space coordinates, return a list of strings
80 giving the roman numeral names of the points. The name is the
81 unambiguous unique specifier of the point (e.g. bbIII++).
82
83 """
84 return [coordinate_to_roman_name(coord) for coord in coords]
85
88 """
89 Given a coordinate (x,y), returns the unique roman numeral name of
90 that point in the space, assuming that I is at (0,0).
91
92 """
93 region = coordinate_key_region(coord)
94
95 x,y = coordinate_within_region(coord)
96
97 if names is None:
98 roman_name = {
99 (0,0) : "IV",
100 (1,0) : "I",
101 (2,0) : "V",
102 (3,0) : "II",
103 (0,1) : "VI",
104 (1,1) : "III",
105 (2,1) : "VII"
106 }[(x,y)]
107 else:
108 roman_name = names[(x,y)]
109
110 acc_count = region[1]
111 if acc_count > 0:
112 accidentals = sharp * acc_count
113 elif acc_count < 0:
114 accidentals = flat * (-1*acc_count)
115 else:
116 accidentals = ""
117
118 plus_count = (coord[0] + 1) / 4
119 if plus_count > 0:
120 mods = plus * plus_count
121 elif plus_count < 0:
122 mods = minus * (-1*plus_count)
123 else:
124 mods = ""
125 if accidentals_after:
126 return u"%s%s%s" % (roman_name, accidentals, mods)
127 else:
128 return u"%s%s%s" % (accidentals, roman_name, mods)
129
131 """
132 Does the same as L{coordinate_to_roman_name}, but generates alphabetic
133 note names in the key of C (i.e. (0,0)=C).
134
135 """
136 names = {
137 (0,0) : "F",
138 (1,0) : "C",
139 (2,0) : "G",
140 (3,0) : "D",
141 (0,1) : "A",
142 (1,1) : "E",
143 (2,1) : "B"
144 }
145 kwargs['names'] = names
146 kwargs['accidentals_after'] = True
147 return coordinate_to_roman_name(*args, **kwargs)
148
150 """
151 Given a tonal space coordinate, returns the 2D identifier of the
152 key region that it lies in. A key region is the
153 not-quite-rectangular region of notes in a major scale. The central
154 one contains IV (at (-1,0)), rightwards to II ((2,0)), and VI
155 ((-1,1)), rightwards to VII ((1,0)). These regions are tessellated
156 across the infinite space.
157
158 The coordinate returned identifies the region. (0,0) is the central
159 region, with bottom left at point (-1,0). (1,0) is strictly to the
160 right and down one, so has its bottom left at (-1,3).
161
162 """
163 x,y = coord
164 return ((y + 2*x + 2) / 7, (4*y + x + 1) /7)
165
167 """
168 Given a tonal space coordinate, returns the coordinate of this point
169 relative to the bottom left corner of the local key region in which
170 it lies (see L{coordinate_key_region}).
171
172 This coordinate will be among (0,0),...,(3,0),(0,1),...,(2,1).
173
174 """
175 x,y = coord
176 spacex, spacey = coordinate_key_region(coord)
177 localx = x - 4*spacex + spacey + 1
178 localy = y - 2*spacey + spacex
179 return localx,localy
180
182 """
183 Translates the second list of coordinates so that it ends at the
184 same point as the first and returns the result.
185
186 """
187
188 shift = (coords0[-1][0] - coords1[-1][0]), (coords0[-1][1] - coords1[-1][1])
189
190 return [(x+shift[0], y+shift[1]) for (x,y) in coords1]
191
193 """
194 Takes a point in the tonal space and returns the number of
195 semitones above the origin's pitch that point would be in
196 equal temperament.
197
198 The coordinate is 3-dimensional.
199
200 """
201 x,y,z = coord
202
203
204 return (7*x + 4*y + 12*z)
205
207 """
208 2-dimensional version of L{coordinate_to_et}. Returns an interval
209 within one octave upwards ([0-12]).
210
211 """
212 x,y=coord
213 return coordinate_to_et((x,y,0))%12
214
216 """
217 Converts a number of cents (tuning theory unit of pitch ratio) into
218 a floating point pitch multiplier.
219
220 @type cents: float
221 @param cents: number of cents
222
223 """
224 return 2 ** (float(cents)/1200)
225
227 """
228 Inverse of L{cents_to_pitch_ratio}. Given a pitch multiplier,
229 returns the equivalent interval expressed in cents.
230
231 """
232 import math
233 return float(1200) * math.log(float(ratio), 2)
234
235
237 """
238 Given a 3D coordinate in the tonal space, returns the pitch ratio
239 of that point from the origin's pitch.
240 x: fifths
241 y: thirds
242 z: octaves
243
244 """
245 import math
246 x,y,z = coord
247 return math.pow(2, z) * math.pow(1.5, x) * math.pow(1.25, y)
248
250 """
251 Given a 2D coordinate in the tonal space, returns the pitch ratio
252 of that point from the origin's pitch assuming that the point is
253 within one octave above the origin.
254
255 """
256 x,y = coord
257 pitch = tonal_space_pitch((x,y,0))
258
259 if pitch < 1.0:
260 ratio = 2.0
261 else:
262 ratio = 0.5
263 while pitch < 1.0 or pitch >= 2.0:
264 pitch *= ratio
265 return pitch
266
277
279 """
280 Frequency ratio corresponding to a number of ET semitones and octaves.
281
282 """
283 import math
284 semitones = oct*12 + st
285 return math.exp(math.log(2.0)/12*semitones)
286 et_semitone = et_interval(1)
287
288
290 """
291 Given a list of (x,y) coordinates, adds a z-coordinate to each
292 such that the pitch of the notes is kept within a given number of
293 octaves around the given center.
294
295 @type coords: list of 2-tuples
296 @param coords: (x,y) coordinates
297 @type center: 3-tuple
298 @param center: point that defines the center of the range of
299 pitches within which the output coordinates will lie
300 @type pitch_range: int
301 @param pitch_range: width of the range of pitches, as an integer
302 number of octaves.
303
304 """
305 center_pitch = tonal_space_pitch(center)
306 half_range = float(pitch_range) / 2
307
308 bottom = center_pitch / (2**half_range)
309 top = center_pitch * (2**half_range)
310
311 coords3d = []
312 for (x,y) in coords:
313 z = 0
314 while tonal_space_pitch((x,y,z)) > top:
315 z -= 1
316 while tonal_space_pitch((x,y,z)) < bottom:
317 z += 1
318 coords3d.append((x,y,z))
319 return coords3d
320
322 """
323 Given a ET root as an integer in the range 0 <= r < 12, returns the
324 2D ET coordinate in the range (0,0) <= (x,y) < (4,3) that that
325 root has in the 4x3 ET space.
326
327 If the root is not within that range, it will be taken mod 12.
328
329 """
330
331
332
333
334 root_map = {
335 0 : (0,0),
336 1 : (3,1),
337 2 : (2,0),
338 3 : (1,2),
339 4 : (0,1),
340 5 : (3,2),
341 6 : (2,1),
342 7 : (1,0),
343 8 : (0,2),
344 9 : (3,0),
345 10 : (2,2),
346 11 : (1,1)
347 }
348 return root_map[root % 12]
349