#!/usr/bin/python mm_to_in = 0.03937 scale_length = 648*mm_to_in string_sets = { 'regular light': ( # (desired note, tension, and type) ('E4' , 16, 'PL'), ('B3' , 16, 'PL'), ('G3' , 16, 'PL'), ('D3' , 16, 'NW'), ('A2' , 16, 'NW'), ('E2' , 16, 'NW'), ), 'light jazz': ( ('E4' , 24, 'PL'), ('B3' , 24, 'PL'), ('G3' , 24, 'NW'), ('D3' , 24, 'NW'), ('A2' , 24, 'NW'), ('E2' , 24, 'NW'), ), 'regular light (DADGAD)': ( ('D4' , 16, 'PL'), ('A3' , 16, 'PL'), ('G3' , 16, 'PL'), ('D3' , 16, 'NW'), ('A2' , 16, 'NW'), ('D2' , 16, 'NW'), ), 'open G (6-string)': ( ('D4' , 16, 'PL'), ('B3' , 16, 'PL'), ('G3' , 16, 'PL'), ('D3' , 16, 'NW'), ('B2' , 16, 'NW'), ('D2' , 16, 'NW'), ), 'open G (7-string)': ( ('D4' , 16, 'PL'), ('B3' , 16, 'PL'), ('G3' , 16, 'PL'), ('D3' , 16, 'NW'), ('B2' , 16, 'NW'), ('G2' , 16, 'NW'), ('D2' , 16, 'NW'), ), } # D'Addario stock via http://www.daddario.com/upload/tension_chart_13934.pdf stock = ( # (product name, unit weight) # plain steel ('PL007' , .00001085), ('PL008' , .00001418), ('PL0085', .00001601), ('PL009' , .00001794), ('PL0095', .00001999), ('PL010' , .00002215), ('PL0105', .00002442), ('PL011' , .00002680), ('PL0115', .00002930), ('PL012' , .00003190), ('PL013' , .00003744), ('PL0135', .00004037), ('PL014' , .00004342), ('PL015' , .00004984), ('PL016' , .00005671), ('PL017' , .00006402), ('PL018' , .00007177), ('PL019' , .00007997), ('PL020' , .00008861), ('PL022' , .00010722), ('PL024' , .00012760), ('PL027' , .00014975), # nickelplated steel round wound (XL) ('NW017' , .00005524), ('NW018' , .00006215), ('NW019' , .00006947), ('NW020' , .00007495), ('NW021' , .00008293), ('NW022' , .00009184), ('NW024' , .00010857), # they have a NW025 used in EXL110BT but it's not listed ('NW026' , .00012671), ('NW028' , .00014666), ('NW030' , .00017236), ('NW032' , .00019347), ('NW034' , .00021590), ('NW036' , .00023964), ('NW038' , .00026471), ('NW039' , .00027932), ('NW042' , .00032279), ('NW044' , .00035182), ('NW046' , .00038216), ('NW048' , .00041382), ('NW049' , .00043014), ('NW052' , .00048109), ('NW054' , .00053838), ('NW056' , .00057598), ('NW059' , .00064191), ('NW060' , .00066542), ('NW062' , .00070697), ('NW064' , .00074984), ('NW066' , .00079889), ('NW068' , .00084614), ('NW070' , .00089304), ('NW072' , .00094124), ('NW074' , .00098869), ('NW080' , .00115011), ) A = 440 notes = { 'C' : 0, 'D' : 2, 'E' : 4, 'F' : 5, 'G' : 7, 'A' : 9, 'B' : 11, } rel = (2**(1/12.)) def note2freq(name): sharp = name[1] == '#' flat = name[1] == 'b' if sharp or flat: note = name[0:1] octave = int(name[2]) else: note = name[0] octave = int(name[1]) num = notes[note] if sharp: num += 1 if flat: num -= 1 fullnum = num + 12*(octave - 5) return A*rel**(fullnum + 3) def test(name, expected): print('{:3} gave {: 9.2f} Hz\nexpected {: 9.2f} Hz'.format(name, note2freq(name), expected)) if False: test('C2' , 65.41) test('Ab4', 415.30) test('A4' , 440.00) test('B4' , 493.88) test('B#4', 523.25) test('Cb5', 493.88) test('C5' , 523.25) print() test('E4' , 329.63) test('B3' , 246.94) test('G3' , 196.00) test('D3' , 146.83) test('A2' , 110.00) test('E2' , 82.41) uw_const = 386.4 def uw2tension(uw, freq): return (uw*(2*scale_length*freq)**2)/uw_const def tension2uw(t, freq): return (t*uw_const)/(2*scale_length*freq)**2 outfmt = '{:<6} at {:> 5.2f} lbs ({:>+4.2f})' finalfmt = 'total: {:>7.2f} lbs ({:>+5.2f})' def print_ideal_stock(strings): total_tension = 0 total_desired_tension = 0 for note, tension, kind in strings: freq = note2freq(note) uw = tension2uw(tension, freq) closest = ('n/a', 0) for name, stock_uw in stock: if kind and name[:len(kind)] != kind: continue if abs(stock_uw - uw) < abs(closest[1] - uw): closest = (name, stock_uw) closest_tension = uw2tension(closest[1], freq) diff = closest_tension - tension print(outfmt.format(closest[0], closest_tension, diff)) total_tension += closest_tension total_desired_tension += tension error = total_tension - total_desired_tension print(finalfmt.format(total_tension, error)) print('for a scale length of {:>5.2f} inches'.format(scale_length)) for name, strings in string_sets.items(): print() print('"{}"'.format(name)) print_ideal_stock(strings)