1 #!/usr/bin/env python
2 '''
3 Copyright (C) 2004 Aaron Cyril Spike
5 This file is part of FretFind 2-D.
7 FretFind 2-D is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 FretFind 2-D is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with FretFind 2-D; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 '''
21 import sys
22 from ffgeom import *
23 threshold=0.0000000001
25 def FindFrets(strings, meta, scale, tuning, numfrets):
26 scale = scale['steps']
28 #if the string ends don't fall on the nut and bridge
29 #don't look for partial frets.
30 numStrings = len(strings)
31 doPartials = True
32 parallelFrets = True
34 nut = Segment(strings[0][0],strings[-1][0])
35 bridge = Segment(strings[0][1],strings[-1][1])
36 midline = Segment(
37 Point((nut[1]['x']+nut[0]['x'])/2.0,(nut[1]['y']+nut[0]['y'])/2.0),
38 Point((bridge[1]['x']+bridge[0]['x'])/2.0,(bridge[1]['y']+bridge[0]['y'])/2.0))
39 for s in strings:
40 if nut.perpDistanceToPoint(s[0])>=threshold or bridge.perpDistanceToPoint(s[1])>=threshold:
41 doPartials = False
42 break
44 denom = ((bridge[1]['y']-bridge[0]['y'])*(nut[1]['x']-nut[0]['x']))-((bridge[1]['x']-bridge[0]['x'])*(nut[1]['y']-nut[0]['y']))
45 if denom != 0:
46 parallelFrets = False
48 fretboard = []
49 tones = len(scale)-1
50 for i in range(len(strings)):
51 base = tuning[i]
52 frets = []
53 if doPartials:
54 frets.append(Segment(meta[i][0],meta[i+1][0]))
55 else:
56 frets.append(Segment(strings[i][0],strings[i][0]))
57 last = strings[i][0]
59 for j in range(numfrets):
60 step=((base+j-1)%(tones))+1
61 ratio=1.0-((scale[step][1]*scale[step-1][0])/(scale[step][0]*scale[step-1][1]))
62 x = last['x']+(ratio*(strings[i][1]['x']-last['x']))
63 y = last['y']+(ratio*(strings[i][1]['y']-last['y']))
64 current = Point(x,y)
65 temp = Segment(strings[i][0],current)
66 totalRatio = temp.length()/strings[i].length()
68 if doPartials:
69 #partials depending on outer strings (questionable)
70 if parallelFrets:
71 temp = nut.createParallel(current)
72 else:
73 temp = Segment(strings[0].pointAtLength(strings[0].length()*totalRatio),
74 strings[-1].pointAtLength(strings[-1].length()*totalRatio))
75 frets.append(Segment(intersectSegments(temp,meta[i]),intersectSegments(temp,meta[i+1])))
76 else:
77 frets.append(Segment(current,current))
78 last = current
79 fretboard.append(frets)
80 return fretboard
82 def FindStringsSingleScale(numStrings,scaleLength,nutWidth,bridgeWidth,oNF,oBF,oNL,oBL):
83 strings = []
84 meta = []
85 nutHalf = nutWidth/2
86 bridgeHalf = bridgeWidth/2
87 nutCandidateCenter = (nutHalf) + oNL
88 bridgeCandidateCenter = (bridgeHalf) + oBL
89 if bridgeCandidateCenter >= nutCandidateCenter:
90 center = bridgeCandidateCenter
91 else:
92 center = nutCandidateCenter
93 nutStringSpacing = nutWidth/(numStrings-1)
94 bridgeStringSpacing = bridgeWidth/(numStrings-1)
96 for i in range(numStrings):
97 strings.append(Segment(Point(center+nutHalf-(i*nutStringSpacing),0),
98 Point(center+bridgeHalf-(i*bridgeStringSpacing),scaleLength)))
100 meta.append(Segment(Point(center+nutHalf+oNF,0),Point(center+bridgeHalf+oBF,scaleLength)))
101 for i in range(1,numStrings):
102 meta.append(Segment(
103 Point((strings[i-1][0]['x']+strings[i][0]['x'])/2.0,
104 (strings[i-1][0]['y']+strings[i][0]['y'])/2.0),
105 Point((strings[i-1][1]['x']+strings[i][1]['x'])/2.0,
106 (strings[i-1][1]['y']+strings[i][1]['y'])/2.0)))
107 meta.append(Segment(Point(center-(nutHalf+oNL),0),Point(center-(bridgeHalf+oBL),scaleLength)))
109 return strings, meta
111 def FindStringsMultiScale(numStrings,scaleLengthF,scaleLengthL,nutWidth,bridgeWidth,perp,oNF,oBF,oNL,oBL):
112 strings = []
113 meta = []
114 nutHalf = nutWidth/2
115 bridgeHalf = bridgeWidth/2
116 nutCandidateCenter = (nutHalf)+oNL
117 bridgeCandidateCenter = (bridgeHalf)+oBL
118 if bridgeCandidateCenter >= nutCandidateCenter:
119 xcenter = bridgeCandidateCenter
120 else:
121 nutCandidateCenter
123 fbnxf = xcenter+nutHalf+oNF
124 fbbxf = xcenter+bridgeHalf+oBF
125 fbnxl = xcenter-(nutHalf+oNL)
126 fbbxl = xcenter-(bridgeHalf+oBL)
128 snxf = xcenter+nutHalf
129 sbxf = xcenter+bridgeHalf
130 snxl = xcenter-nutHalf
131 sbxl = xcenter-bridgeHalf
133 fdeltax = sbxf-snxf
134 ldeltax = sbxl-snxl
135 fdeltay = math.sqrt((scaleLengthF*scaleLengthF)-(fdeltax*fdeltax))
136 ldeltay = math.sqrt((scaleLengthL*scaleLengthL)-(ldeltax*ldeltax))
138 fperp = perp*fdeltay
139 lperp = perp*ldeltay
141 #temporarily place first and last strings
142 first = Segment(Point(snxf,0),Point(sbxf,fdeltay))
143 last = Segment(Point(snxl,0),Point(sbxl,ldeltay))
145 if fdeltay<=ldeltay:
146 first.translate(0,(lperp-fperp))
147 else:
148 last.translate(0,(fperp-lperp))
150 nut = Segment(first[0].copy(),last[0].copy())
151 bridge = Segment(first[1].copy(),last[1].copy())
152 #overhang measurements are now converted from delta x to along line lengths
153 oNF = (oNF*nut.length())/nutWidth
154 oNL = (oNL*nut.length())/nutWidth
155 oBF = (oBF*bridge.length())/bridgeWidth
156 oBL = (oBL*bridge.length())/bridgeWidth
157 #place fretboard edges
158 fbf = Segment(nut.pointAtLength(-oNF),bridge.pointAtLength(-oBF))
159 fbl = Segment(nut.pointAtLength(nut.length()+oNL),bridge.pointAtLength(bridge.length()+oBL))
160 #normalize values into the first quadrant via translate
161 if fbf[0]['y']<0 or fbl[0]['y']<0:
162 if fbf[0]['y']<=fbl[0]['y']:
163 move = -fbf[0]['y']
164 else:
165 move = -fbl[0]['y']
167 first.translate(0,move)
168 last.translate(0,move)
169 nut.translate(0,move)
170 bridge.translate(0,move)
171 fbf.translate(0,move)
172 fbl.translate(0,move)
174 #output values
175 nutStringSpacing = nut.length()/(numStrings-1)
176 bridgeStringSpacing = bridge.length()/(numStrings-1)
177 strings.append(first)
178 for i in range(1,numStrings-1):
179 n = nut.pointAtLength(i*nutStringSpacing)
180 b = bridge.pointAtLength(i*bridgeStringSpacing)
181 strings.append(Segment(Point(n['x'],n['y']),Point(b['x'],b['y'])))
182 strings.append(last)
184 meta.append(fbf)
185 for i in range(1,numStrings):
186 meta.append(Segment(
187 Point((strings[i-1][0]['x']+strings[i][0]['x'])/2.0,
188 (strings[i-1][0]['y']+strings[i][0]['y'])/2.0),
189 Point((strings[i-1][1]['x']+strings[i][1]['x'])/2.0,
190 (strings[i-1][1]['y']+strings[i][1]['y'])/2.0)))
192 meta.append(fbl)
194 return strings, meta