uilleann

3d printable Uilleann bagpipes
git clone https://git.woozle.org/neale/uilleann.git

commit
8d8c1d3
parent
c38bb58
author
Neale Pickett
date
2025-11-28 20:10:22 -0700 MST
Add a bunch of work from previously
27 files changed,  +1141, -41
A coyne-colgan-b/chanter.scad
+44, -0
 1@@ -0,0 +1,44 @@
 2+// stops is an array of [diameter, distance]
 3+module rod(stops) {
 4+  end_d = stops[len(stops)-1][1];
 5+  p = concat([[0, 0]], stops, [[0, end_d]]);
 6+  rotate_extrude(convexity=4) {
 7+    polygon(p);
 8+  }
 9+}
10+
11+module cylinders_stacked(stops, y=0, i=0) {
12+  if (i < len(stops)) {
13+    cur = stops[i];
14+    translate([0, 0, y]) cylinder(h=cur[1], d=cur[0]);
15+    cylinders_stacked(stops, y+cur[1], i+1);
16+  }
17+}
18+
19+rod([
20+     [10.7, 0], // Bottom
21+     [10.4, 53.5],
22+     [10, 66],
23+     [9.5, 91],
24+     [9, 116],
25+     [8.5, 151.5],
26+     [8, 192],
27+     [7.5, 224],
28+     [7.2, 242.5],
29+     [7, 251],
30+     [6.7, 271],
31+     [6.5, 282],
32+     [6.3, 291],
33+     [6, 308],
34+     [5.8, 321],
35+     [5.5, 347],
36+     [5.2, 367],
37+     [5, 374],
38+     [4.7, 393],
39+     [4.5, 400],
40+     [4.2, 412],
41+     [4, 420],
42+     [3.8, 431],
43+     [7.1, 447.5],
44+     ]);
45+
A coyne-colgan-b/measurements.jpeg
+0, -0
A daye/chanter.quiet/Makefile
+8, -0
1@@ -0,0 +1,8 @@
2+rev=$(shell git log -1 --pretty='format:%cd' --date='format:%Y-%m-%d')
3+
4+all: top.3mf bottom.3mf
5+clean:
6+	rm -f *.3mf
7+
8+%.3mf: %.scad chanter.quiet.scad ../common.scad
9+	openscad -D rev=\"$(rev)\" -o $@ $<
A daye/chanter.quiet/bore.py
+16, -0
 1@@ -0,0 +1,16 @@
 2+#! /usr/bin/python3
 3+
 4+import math
 5+
 6+# lengths are in millimeters
 7+c = 343 * 1000 # speed of sound in air (mm/sec)
 8+
 9+def freq(l, r1, r2):
10+    return (c / (4*l)) * r2/r1
11+
12+for measurements in (
13+        [360, 5.51/2, 13.1/2],
14+        [360, 1.50, 3.56],
15+        [360, 1.50, 5.56],
16+):
17+    print (measurements, freq(*measurements))
A daye/chanter.quiet/bottom.scad
+6, -0
1@@ -0,0 +1,6 @@
2+include <../common.scad>
3+use <./chanter.quiet.scad>
4+
5+tenon(top=false) {
6+  chanter();
7+}
A daye/chanter.quiet/chanter.quiet.scad
+164, -0
  1@@ -0,0 +1,164 @@
  2+include <../common.scad>
  3+use <MCAD/regular_shapes.scad>
  4+
  5+height = 360.0;
  6+od = 16.0;
  7+od_derlin = od + 0.5;
  8+id_top = 5.51;
  9+id_bot = 5.51;
 10+cut_height = 155; // Where to cut it in half
 11+axianov = false; // Axianov tone holes?
 12+
 13+rev = "α";
 14+stamp = str("quiet ", rev);
 15+debug_stamp = str("id=", id_top, "–", id_bot);
 16+
 17+module tonehole_axianov(h=10, d=10, undercut=0) {
 18+  r = d/2;
 19+  area = PI*r*r;
 20+
 21+  rounding_r = 2;
 22+  rounding_area = (1 - PI/4) * (rounding_r^2); // area lost to rounding
 23+  goal_area = area + rounding_area;
 24+
 25+  w = 6.25; // Marat uses 6.25mm on every hole, so we will too
 26+  l = goal_area / w;
 27+  
 28+  rotate([0, 0, -90]) {
 29+    translate([od/2, 0, h]) {
 30+      rotate([0, -90+undercut, 0]) {
 31+        // Scoot it down a hair so it will penetrate the entire tube when rotated
 32+        translate([0, 0, -od/2]) {
 33+          render(convexity=2)
 34+          intersection() {
 35+            cube([l, w, 20]);
 36+            union() {
 37+              translate([r, r, 0]) cylinder(r=r, h=20, center=true);
 38+              translate([r, 0, 0]) cube(20, center=true);
 39+              translate([0, r, 0]) cube(20, center=true);
 40+            }
 41+          }
 42+        }
 43+      }
 44+    }
 45+  }
 46+}
 47+
 48+module tonehole(h=0, d=10, depth=od/2, undercut=0) {
 49+  translate([0, -od/2, h]) {
 50+    rotate([-90+undercut, 0, 0]) {
 51+      translate([0, 0, -d/2]) {
 52+        cylinder(d=d, h=depth+d/2);
 53+      }
 54+    }
 55+  }
 56+}
 57+
 58+// Something like David Daye's Penny Chanter,
 59+// based on my measurements and undercut hints on David's web site.
 60+// This is symmetrical, so both pieces can be printed at the same time,
 61+// with color changes
 62+module chanter() {
 63+  difference () {
 64+    union() {
 65+      // The core part of the instrument is this brass tube
 66+      difference() {
 67+        brass() cylinder(h=height, d=od);
 68+
 69+        // Seam guides
 70+        translate([0, od/2, 0]) cylinder(d=1, h=400);
 71+      }
 72+
 73+      // David adds this outer Derlin tube as an upgrade option
 74+      difference() {
 75+        derlin() translate([0, 0, 40.0]) cylinder(h=290, d=od_derlin);
 76+
 77+        // The slits up the sides serve three purposes:
 78+        // 1. directs the slicer to place seams in it (and not on the face)
 79+        // 2. provides alignment guides for attaching the two pieces
 80+        // 3. looks like an intentional stylistic thing
 81+        rotate([0, 0, 85]) translate([0, od_derlin/2, 0]) cylinder(d=1, h=cut_height+20); // overlap
 82+        rotate([0, 0, -85]) translate([0, od_derlin/2, cut_height-20]) cylinder(d=1, h=400);
 83+      }
 84+
 85+      // These little doodads are probably just to hide the Derlin seam
 86+      ivory() translate([0, 0, 30.0]) {
 87+        cylinder(h=3, d1=od, d2=22.0);
 88+        translate([0, 0, 3]) cylinder(h=6, d=22.0);
 89+        translate([0, 0, 9]) cylinder(h=3, d1=22.0, d2=od);
 90+      }
 91+      ivory() translate([0, 0, height - 30.0 - 12]) {
 92+        cylinder(h=3, d1=od, d2=22.0);
 93+        translate([0, 0, 3]) cylinder(h=6, d=22.0);
 94+        translate([0, 0, 9]) cylinder(h=3, d1=22.0, d2=od);
 95+      }
 96+    }
 97+
 98+    // Seam guides
 99+    translate([0, 11, 0]) cylinder(d=1, h=400);
100+
101+    // Inner bore, which runs up to the place where the reed drops in
102+    translate([0, 0,   -1]) cylinder(h=338.01, d1=id_bot, d2=id_top);
103+    translate([0, 0, 337]) cylinder(h=23.1, d1=id_top, d2=7.1);
104+
105+    // Fancy looking rings
106+    translate([0, 0, 3]) rings(d=16.0);
107+
108+    // Sigil
109+    translate([0, 0, 4]) intersection() {
110+      cylinder_tube(50, od/2+0.5, 1);
111+      union() {
112+        translate([0, 0, 8]) rotate([90, 0, -90]) {
113+          linear_extrude(height=30, convexity=4) {
114+            translate([-4, -5]) import("ruby.svg");
115+          }
116+        }
117+        translate([0, 0, 2]) rotate([90, 90, -160]) {
118+          linear_extrude(height=30, convexity=10) {
119+            text(stamp, size=3, halign="right", valign="center");
120+          }
121+        }
122+        translate([0, 0, 2]) rotate([90, 90, -200]) {
123+          linear_extrude(height=30, convexity=10) {
124+            text(debug_stamp, size=3, halign="right", valign="center");
125+          }
126+        }
127+      }
128+    }
129+
130+    // Tone Holes!
131+    // XXX: Undercut angle should be taken into account here
132+    tonehole(h=57.1, d=6.68); // E-
133+    tonehole(h=87.0, d=4.25); // E
134+    tonehole(h=118.0, d=8.33); // F#
135+    tonehole(h=149.0, d=5.51, undercut=-15); // G
136+    tonehole(h=184.5, d=7.75, undercut=15); // A
137+    tonehole(h=184.5, d=7.75, undercut=-15); // A (wide undercut)
138+    tonehole(h=219.0, d=6.72, undercut=15); // B
139+    tonehole(h=250.0, d=5.50, undercut=30); // C
140+    rotate([0, 0, 180]) tonehole(h=270.0, d=7.11, undercut=30); // D
141+  }
142+}
143+
144+module tenon(top=false, h=cut_height, od=od, depth=20, thickness=3) {
145+  module cut() {
146+        cylinder(h=cut_height+depth, d=od-thickness-clearance);
147+        cylinder(h=cut_height, d=50);
148+  }
149+
150+  if (top) {
151+    difference() {
152+      children();
153+      cut();
154+    }
155+  } else {
156+    intersection() {
157+      children();
158+      cut();
159+    }
160+  }
161+}
162+
163+chanter();
164+//translate([0, 50, 360]) rotate([180, 0, 0]) chanter();
165+
A daye/chanter.quiet/complete.scad
+164, -0
  1@@ -0,0 +1,164 @@
  2+include <../common.scad>
  3+use <MCAD/regular_shapes.scad>
  4+
  5+height = 360.0;
  6+od = 16.0;
  7+od_derlin = od + 0.5;
  8+id_bot = 13.2;
  9+id_top = 5.51;
 10+cut_height = 155; // Where to cut it in half
 11+axianov = false; // Axianov tone holes?
 12+
 13+rev = "preview";
 14+stamp = str(rev);
 15+
 16+module tonehole_axianov(h=10, d=10, undercut=0) {
 17+  r = d/2;
 18+  area = PI*r*r;
 19+
 20+  rounding_r = 2;
 21+  rounding_area = (1 - PI/4) * (rounding_r^2); // area lost to rounding
 22+  goal_area = area + rounding_area;
 23+
 24+  w = 6.25; // Marat uses 6.25mm on every hole, so we will too
 25+  l = goal_area / w;
 26+  
 27+  rotate([0, 0, -90]) {
 28+    translate([od/2, 0, h]) {
 29+      rotate([0, -90+undercut, 0]) {
 30+        // Scoot it down a hair so it will penetrate the entire tube when rotated
 31+        translate([0, 0, -od/2]) {
 32+          render(convexity=2)
 33+          intersection() {
 34+            cube([l, w, 20]);
 35+            union() {
 36+              translate([r, r, 0]) cylinder(r=r, h=20, center=true);
 37+              translate([r, 0, 0]) cube(20, center=true);
 38+              translate([0, r, 0]) cube(20, center=true);
 39+            }
 40+          }
 41+        }
 42+      }
 43+    }
 44+  }
 45+}
 46+
 47+module tonehole(h=10, d=10, undercut=0) {
 48+  if (axianov) {
 49+    tonehole_axianov(h, d, undercut);
 50+  } else {
 51+    rotate([0, 0, -90]) {
 52+      translate([od/2, 0, h]) {
 53+        rotate([0, -90+undercut, 0]) {
 54+	  translate([0, 0, -od/2]) {
 55+	    cylinder(d=d, h=20);
 56+	  }
 57+	}
 58+      }
 59+    }
 60+  }
 61+  // Cutaways. I don't like them, but if you do, uncomment this.
 62+  // translate([0, -od/2 - 8, h]) rotate([0, 90, 0]) cylinder(r=10, h=50, center=true);
 63+}
 64+
 65+
 66+// Something like David Daye's Penny Chanter,
 67+// based on my measurements and undercut hints on David's web site.
 68+// This is symmetrical, so both pieces can be printed at the same time,
 69+// with color changes
 70+module chanter() {
 71+  difference () {
 72+    union() {
 73+      // The core part of the instrument is this brass tube
 74+      difference() {
 75+        brass() cylinder(h=height, d=od);
 76+
 77+        // Seam guides
 78+        translate([0, od/2, 0]) cylinder(d=1, h=400);
 79+      }
 80+
 81+      // David adds this outer Derlin tube as an upgrade option
 82+      difference() {
 83+        derlin() translate([0, 0, 40.0]) cylinder(h=290, d=od_derlin);
 84+
 85+        // The slits up the sides serve three purposes:
 86+        // 1. directs the slicer to place seams in it (and not on the face)
 87+        // 2. provides alignment guides for attaching the two pieces
 88+        // 3. looks like an intentional stylistic thing
 89+        rotate([0, 0, 85]) translate([0, od_derlin/2, 0]) cylinder(d=1, h=cut_height+20); // overlap
 90+        rotate([0, 0, -85]) translate([0, od_derlin/2, cut_height-20]) cylinder(d=1, h=400);
 91+      }
 92+
 93+      // These little doodads are probably just to hide the Derlin seam
 94+      ivory() translate([0, 0, 30.0]) {
 95+        cylinder(h=3, d1=od, d2=22.0);
 96+        translate([0, 0, 3]) cylinder(h=9, d=22.0);
 97+      }
 98+      ivory() translate([0, 0, height - 30.0 - 12]) {
 99+        cylinder(h=12, d=22.0);
100+      }
101+    }
102+
103+    // Seam guides
104+    translate([0, 11, 0]) cylinder(d=1, h=400);
105+
106+    // Inner bore, which runs up to the place where the reed drops in
107+    translate([0, 0,   0]) cylinder(h=337.01, d1=id_bot, d2=id_top);
108+    translate([0, 0, 337]) cylinder(h=23.1, d1=id_top, d2=7.1);
109+
110+    // I totally dig David's minimalist aesthetic
111+    translate([0, 0, 3]) rings(d=16.0);
112+
113+    // Sigil
114+    translate([0, 0, 4]) intersection() {
115+      cylinder_tube(50, od/2+0.5, 1);
116+      union() {
117+        translate([0, 0, 8]) rotate([90, 0, -90]) {
118+          linear_extrude(height=d1, convexity=4) {
119+            translate([-4, -5]) import("ruby.svg");
120+          }
121+        }
122+        translate([0, 0, 4]) rotate([90, 90, -160]) {
123+          linear_extrude(height=od, convexity=10) {
124+            text(stamp, size=2, halign="right", valign="center");
125+          }
126+        }
127+      }
128+    }
129+
130+    // Tone Holes!
131+    // XXX: Undercut angle should be taken into account here
132+    tonehole(h=57.1, d=6.68); // E-
133+    tonehole(h=87.0, d=4.25); // E
134+    tonehole(h=118.0, d=8.33); // F#
135+    tonehole(h=149.0, d=5.51, undercut=-15); // G
136+    tonehole(h=184.5, d=7.75, undercut=15); // A
137+    tonehole(h=184.5, d=7.75, undercut=-15); // A (wide undercut)
138+    tonehole(h=219.0, d=6.72, undercut=15); // B
139+    tonehole(h=250.0, d=5.50, undercut=30); // C
140+    rotate([0, 0, 180]) tonehole(h=270.0, d=7.11, undercut=30); // D
141+  }
142+}
143+
144+module tenon(top=false, h=cut_height, od=od, depth=20, thickness=2) {
145+  module cut() {
146+        cylinder(h=cut_height+depth, d=od-thickness-clearance);
147+        cylinder(h=cut_height, d=50);
148+  }
149+
150+  if (top) {
151+    difference() {
152+      children();
153+      cut();
154+    }
155+  } else {
156+    intersection() {
157+      children();
158+      cut();
159+    }
160+  }
161+}
162+
163+chanter();
164+//translate([0, 50, 360]) rotate([180, 0, 0]) chanter();
165+
A daye/chanter.quiet/ruby.svg
+9, -0
 1@@ -0,0 +1,9 @@
 2+<?xml version="1.0" encoding="utf-8"?>
 3+<svg xmlns="http://www.w3.org/2000/svg" height="1cm" width="0.924cm" viewBox="0 0 500 500" xmlns:bx="https://boxy-svg.com">
 4+  <defs>
 5+    <bx:export>
 6+      <bx:file format="png" path="ruby.png"/>
 7+    </bx:export>
 8+  </defs>
 9+  <path style="stroke: rgb(0, 0, 0); fill: rgb(107, 84, 84); transform-box: fill-box; transform-origin: 50% 50%;" d="M 187.594 147.071 C 222.949 153.12 270.972 155.731 309.277 143.299 C 317.317 140.69 324.255 101.717 337.777 84.73 C 365.301 50.153 418.636 3.565 440.95 1.462 C 463.264 -0.641 461.076 -0.732 469.218 12.046 C 477.36 24.824 453.472 138.031 453.472 138.031 C 453.472 138.031 453.953 147.266 444.263 160.449 C 434.573 173.632 447.673 167.61 440.944 190.185 C 434.215 212.76 438.017 200.224 427.718 215.259 C 417.419 230.294 397.67 242.025 388.524 251.061 C 379.378 260.097 386.798 291.019 386.798 291.019 C 386.798 291.019 387.847 326.31 381.141 347.368 C 374.435 368.426 346.18 391.255 346.18 391.255 C 346.18 391.255 325.323 472.928 268.206 481.757 C 211.089 490.586 166.483 394.938 166.483 394.938 C 166.483 394.938 144.005 389.647 131.704 371.16 C 119.403 352.673 108.748 336.052 108.361 311.035 C 107.974 286.018 101.518 264.509 101.518 264.509 C 101.518 264.509 89.405 262.542 85.275 256.613 C 81.145 250.684 78.859 245.845 70.152 238.568 C 59.127 229.354 42.841 226.273 39.22 199.414 C 35.599 172.555 36.125 179.11 36.125 179.11 C 36.125 179.11 23.121 168.902 31.274 144.728 C 39.427 120.554 89.353 134.561 107.159 120.958 C 124.965 107.355 114.883 115.961 133.013 98.781 C 151.143 81.601 175.442 122.255 175.442 122.255 C 175.442 122.255 178.724 145.553 187.594 147.071 Z" id="object-1" transform="matrix(0.999073, 0.043046, -0.043046, 0.999073, 0.014376, 0.000286)"/>
10+</svg>
A daye/chanter.quiet/tonehole.scad
+6, -0
1@@ -0,0 +1,6 @@
2+module tonehole(d=10, depth=20, undercut=0) {
3+  rotate([-90+undercut, 0, 0]) translate([0, 0, -d/2]) cylinder(d=d, h=depth);
4+}
5+
6+tonehole(undercut=10);
7+
A daye/chanter.quiet/top.scad
+6, -0
1@@ -0,0 +1,6 @@
2+include <../common.scad>
3+use <./chanter.quiet.scad>
4+
5+tenon(top=true) {
6+  chanter();
7+}
A daye/chanter/complete.scad
+157, -0
  1@@ -0,0 +1,157 @@
  2+include <../common.scad>
  3+
  4+height = 360.0;
  5+od = 16.0;
  6+od_derlin = od + 0.5;
  7+id_bot = 13.2;
  8+id_top = 5.51;
  9+cut_height = 155; // Where to cut it in half
 10+axianov = false; // Axianov tone holes?
 11+
 12+module tonehole_axianov(h=10, d=10, undercut=0) {
 13+  r = d/2;
 14+  area = PI*r*r;
 15+
 16+  rounding_r = 2;
 17+  rounding_area = (1 - PI/4) * (rounding_r^2); // area lost to rounding
 18+  goal_area = area + rounding_area;
 19+
 20+  w = 6.25; // Marat uses 6.25mm on every hole, so we will too
 21+  l = goal_area / w;
 22+  
 23+  rotate([0, 0, -90]) {
 24+    translate([od/2, 0, h]) {
 25+      rotate([0, -90+undercut, 0]) {
 26+        // Scoot it down a hair so it will penetrate the entire tube when rotated
 27+        translate([0, 0, -od/2]) {
 28+          render(convexity=2)
 29+          intersection() {
 30+            cube([l, w, 20]);
 31+            union() {
 32+              translate([r, r, 0]) cylinder(r=r, h=20, center=true);
 33+              translate([r, 0, 0]) cube(20, center=true);
 34+              translate([0, r, 0]) cube(20, center=true);
 35+            }
 36+          }
 37+        }
 38+      }
 39+    }
 40+  }
 41+}
 42+
 43+module tonehole(h=10, d=10, undercut=0) {
 44+  if (axianov) {
 45+    tonehole_axianov(h, d, undercut);
 46+  } else {
 47+    rotate([0, 0, -90]) {
 48+      translate([od/2, 0, h]) {
 49+        rotate([0, -90+undercut, 0]) {
 50+	  translate([0, 0, -od/2]) {
 51+	    cylinder(d=d, h=20);
 52+	  }
 53+	}
 54+      }
 55+    }
 56+  }
 57+  translate([0, -od/2 - 8, h]) rotate([0, 90, 0]) cylinder(r=10, h=50, center=true);
 58+}
 59+
 60+
 61+// Something like David Daye's Penny Chanter,
 62+// based on my measurements and undercut hints on David's web site.
 63+// This is symmetrical, so both pieces can be printed at the same time,
 64+// with color changes
 65+module chanter() {
 66+  difference () {
 67+    union() {
 68+      // The core part of the instrument is this brass tube
 69+      difference() {
 70+        brass() cylinder(h=height, d=od);
 71+
 72+        // Seam guides
 73+        translate([0, od/2, 0]) cylinder(d=1, h=400);
 74+      }
 75+
 76+      // David adds this outer Derlin tube as an upgrade option
 77+      difference() {
 78+        derlin() translate([0, 0, 40.0]) cylinder(h=290, d=od_derlin);
 79+
 80+        // The slits up the sides serve three purposes:
 81+        // 1. directs the slicer to place seams in it (and not on the face)
 82+        // 2. provides alignment guides for attaching the two pieces
 83+        // 3. looks like an intentional stylistic thing
 84+        rotate([0, 0, 85]) translate([0, od_derlin/2, 0]) cylinder(d=1, h=cut_height+20); // overlap
 85+        rotate([0, 0, -85]) translate([0, od_derlin/2, cut_height-20]) cylinder(d=1, h=400);
 86+      }
 87+
 88+      // These little doodads are probably just to hide the Derlin seam
 89+      ivory() translate([0, 0, 30.0]) {
 90+        cylinder(h=3, d1=od, d2=22.0);
 91+        translate([0, 0, 3]) cylinder(h=9, d=22.0);
 92+      }
 93+      ivory() translate([0, 0, height - 30.0 - 12]) {
 94+        cylinder(h=12, d=22.0);
 95+        translate([0, 0, 12]) cylinder(h=3, d1=22.0, d2=od);
 96+      }
 97+    }
 98+
 99+    // Seam guides
100+    translate([0, 11, 0]) cylinder(d=1, h=400);
101+
102+    // Inner bore, which runs up to the place where the reed drops in
103+    translate([0, 0,   0]) cylinder(h=337.01, d1=id_bot, d2=id_top);
104+    translate([0, 0, 337]) cylinder(h=23.1, d1=id_top, d2=7.1);
105+
106+    // I totally dig David's minimalist aesthetic
107+    translate([0, 0, 3]) rings(d=16.0);
108+
109+    // Stamp my name on it
110+    difference() {
111+      translate([0, 0, 307]) {
112+        rotate([90, 0, 180]) {
113+          linear_extrude(50) {
114+            translate([0, 5]) text("neale", font="Fontdiner Swanky", valign="bottom", size=3, halign="center");
115+            translate([0, 0]) text("2024-2", font="Fontdiner Swanky", valign="bottom", size=3, halign="center");
116+          }
117+        }
118+      }
119+      cylinder(h=360, d=od-0.5);
120+    }
121+
122+
123+    // Tone Holes!
124+    // XXX: Undercut angle should be taken into account here
125+    tonehole(h=57.1, d=6.68); // E-
126+    tonehole(h=87.0, d=4.25); // E
127+    tonehole(h=118.0, d=8.33); // F#
128+    tonehole(h=149.0, d=5.51, undercut=-15); // G
129+    tonehole(h=184.5, d=7.75, undercut=15); // A
130+    tonehole(h=184.5, d=7.75, undercut=-15); // A (wide undercut)
131+    tonehole(h=219.0, d=6.72, undercut=15); // B
132+    tonehole(h=250.0, d=5.50, undercut=30); // C
133+    rotate([0, 0, 180]) tonehole(h=270.0, d=7.11, undercut=30); // D
134+  }
135+}
136+
137+module tenon(top=false, h=cut_height, od=od, depth=20, thickness=2) {
138+  module cut() {
139+        cylinder(h=cut_height+depth, d=od-thickness-clearance);
140+        cylinder(h=cut_height, d=50);
141+  }
142+
143+  if (top) {
144+    difference() {
145+      children();
146+      cut();
147+    }
148+  } else {
149+    intersection() {
150+      children();
151+      cut();
152+    }
153+  }
154+}
155+
156+chanter();
157+//translate([0, 50, 360]) rotate([180, 0, 0]) chanter();
158+
A daye/chanter/sander.scad
+8, -0
1@@ -0,0 +1,8 @@
2+include <../common.scad>
3+
4+difference() {
5+  cylinder(d=82, h=80);
6+  translate([-50, -80, -1]) cube(100);
7+  translate([0, 30, 78]) linear_extrude(2) text("d=82mm", size=4, halign="center");
8+  translate([0, 24, 78]) linear_extrude(2) text("reed sanding block", size=4, halign="center");
9+}
A daye/chanter/tonehole.scad
+20, -0
 1@@ -0,0 +1,20 @@
 2+module tonehole(h=10, d=10, undercut=0) {
 3+  r = d/2;
 4+  area = PI*r*r;
 5+
 6+  rounding_r = 2;
 7+  rounding_area = (1 - PI/4) * (rounding_r^2); // area lost to rounding
 8+  goal_area = area + rounding_area;
 9+
10+  w = 6.25; // Marat uses 6.25mm on every hole, so we will too
11+  l = goal_area / w;
12+
13+  union() {
14+    translate([rounding_r, rounding_r, 0]) cylinder(r=rounding_r, h=20);
15+    translate([rounding_r, 0, 0]) cube([w-rounding_r, l, 20]);
16+    translate([0, rounding_r, 0]) cube([w, l-rounding_r, 20]);
17+  }
18+}
19+
20+tonehole($fn=60);
21+
A daye/drones/baritone/tongue.scad
+36, -0
 1@@ -0,0 +1,36 @@
 2+include <../../common.scad>
 3+
 4+// 9mm od
 5+// 7.5mm from plane on reed holder to back
 6+// 9 - 7.5 = 2.5 thickness; 4.5-2.5=2 cutaway from center
 7+
 8+length = 45;
 9+thickness = 0.55;
10+d = 9;
11+base_thickness = 1.5;
12+
13+scrape_angle = atan((base_thickness-thickness)/length)*2.6;
14+
15+translate([0, 0, -d/2+base_thickness])
16+difference() {
17+  rotate([-88, 0, 0]) cylinder(d=d, h=length);
18+
19+  // Chop off excess cylinder at the base
20+  translate([-d/2, -d, 0]) cube(d);
21+
22+  // Shave off reed
23+  translate([-d/2, -length, -d/2-base_thickness]) cube([d, length*3, d]);
24+
25+  // Scrape reed
26+  translate([0, length, d/2-base_thickness+thickness]) rotate([-scrape_angle, 0, 0]) translate([-d/2, -length, 0]) cube([d, length, d]);
27+
28+  // Reed chopper
29+  translate([0, length, 0]) {
30+    translate([0, -d/2, 0]) {
31+      difference() {
32+        translate([-d/2, 0, 0]) cube([d, d/2, d]);
33+        cylinder(d=d, h=d);
34+      }
35+    }
36+  }
37+}
A daye/misc/adapter-bellows-tube.scad
+16, -0
 1@@ -0,0 +1,16 @@
 2+include <../common.scad>
 3+
 4+difference() {
 5+  union() {
 6+    translate([0, 0,  0.0]) cylinder(h=50, d=15); // Interface to bellows
 7+    for (h = [3 : 4 : 30]) {
 8+      translate([0, 0, h]) scale([1, 1, 0.75]) sphere(d=16);
 9+    }
10+    translate([0, 0, 33.0]) cylinder(h=16.9, d=21.9); // Bump-out stop
11+    translate([0, 0, 40.0]) cylinder(h=24, d=19.3); // Interface with tubing
12+    translate([0, 0, 40.0]) cylinder(h=34, d=18.2); // Carved out for binding
13+    translate([0, 0, 70.5]) cylinder(h=4, d=19.3); // Interface with tubing
14+  }
15+  cylinder(h=200, d=13); // Diameter here isn't very important
16+  translate([0, 0, -10]) cylinder(h=10, d=50); // Chop sphere off the bottom
17+}
A harrington-rowsome-c\342\231\257/Makefile
+8, -0
1@@ -0,0 +1,8 @@
2+rev=$(shell git log -1 --pretty='format:%cd' --date='format:%Y-%m-%d')
3+
4+all: top.3mf bottom.3mf
5+clean:
6+	rm -f *.3mf
7+
8+%.3mf: %.scad chanter.scad
9+	openscad -D rev=\"$(rev)\" -o $@ $<
A harrington-rowsome-c\342\231\257/bottom.scad
+5, -0
1@@ -0,0 +1,5 @@
2+use <./chanter.scad>
3+
4+tenon(top=false) {
5+  chanter();
6+}
A harrington-rowsome-c\342\231\257/chanter.b\342\231\256.scad
+126, -0
  1@@ -0,0 +1,126 @@
  2+use <BOSL/math.scad>
  3+
  4+$fn = $preview ? 0 : 180; // Make circles circular in final renders.
  5+
  6+// stops is an array of [d, h]
  7+module rod(stops) {
  8+  beg = stops[0][1];
  9+  end = stops[len(stops)-1][1];
 10+  p = concat([[0, beg]], stops, [[0, end]]);
 11+
 12+  halfp = [for (i = p) [i[0]/2, i[1]]];
 13+  rotate_extrude(convexity=4) {
 14+    polygon(halfp);
 15+  }
 16+}
 17+
 18+// Drill a tonehole.
 19+// The center of the tonehole will intersect [0, od, h] before rotation.
 20+//
 21+// Instrument makers think about
 22+// drilling from the outside of the pipe in.
 23+// So we need to know the outside diameter of the pipe.
 24+//
 25+// For now, we're pretending the pipe has a consistent outside diameter.
 26+// BOSL2 may have something that will let us calculate od given h and measurements.
 27+module tonehole(od, h, d, undercut=0, rot=0) {
 28+  render(convexity=2)
 29+  rotate([0, 0, rot]) {
 30+    translate([0, -od/2, h]) {
 31+      // Intersect with a cube to ensure an undercut tonehole doesn't drill past the center of the instrument
 32+      intersection() {
 33+        rotate([-90+undercut, 0, 0]) {
 34+          cylinder(d=d, h=od, center=true);
 35+        }
 36+        cube(od, center=true);
 37+      }
 38+    }
 39+  }
 40+}
 41+
 42+function inch(x) = x * 25.4;
 43+
 44+od = inch(0.762);
 45+
 46+// The original height was 381.
 47+// I couldn't get the reed to stay in with such a short reed area.
 48+//height = 381;
 49+height = 381+23;
 50+
 51+module chanter() {
 52+  difference() {
 53+    union() {
 54+      cylinder(d=16, h=height);
 55+      cylinder(d1=od, d2=16, h=280); // A nice taper
 56+    }
 57+
 58+    tonehole(od, 56.0, inch(0.162));
 59+    tonehole(od, 89.0, inch(0.182));
 60+    tonehole(od, 122.2, inch(0.201));
 61+    tonehole(od, 153.2, inch(0.180));
 62+    tonehole(od, 190.1, inch(0.183));
 63+    tonehole(od, 222.6, inch(0.187));
 64+    tonehole(od, 252.2, inch(0.162));
 65+    tonehole(od, 275.5, inch(0.173), rot=180);
 66+  
 67+    rod([
 68+         [7.1, height],
 69+         [inch(0.168), mean([361.3, 361.3])],
 70+         [inch(0.174), mean([351.9, 352.8])],
 71+         [inch(0.180), mean([345.1, 347.2])],
 72+         [inch(0.185), mean([342.0, 344.6])],
 73+         [inch(0.189), mean([337.5, 339.5])],
 74+         [inch(0.195), mean([330.7, 334.1])],
 75+         [inch(0.200), mean([325.5, 329.6])],
 76+         [inch(0.205), mean([318.2, 321.8])],
 77+         [inch(0.210), mean([315.2, 317.7])],
 78+         [inch(0.215), mean([309.7, 312.5])],
 79+         [inch(0.220), mean([302.0, 305.5])],
 80+         [inch(0.225), mean([294.7, 297.4])],
 81+         [inch(0.230), mean([288.5, 292.0])],
 82+         [inch(0.235), mean([282.5, 284.0])],
 83+         [inch(0.241), mean([274.0, 278.7])],
 84+         [inch(0.245), mean([269.0, 269.0])],
 85+         [inch(0.250), mean([265.0, 265.0])],
 86+         [inch(0.259), mean([266.0, 266.0])],
 87+         [inch(0.270), mean([237.9, 241.5])],
 88+         [inch(0.280), mean([224.5, 226.5])],
 89+         [inch(0.290), mean([209.0, 212.2])],
 90+         [inch(0.300), mean([195.4, 195.4])],
 91+         [inch(0.310), mean([183.0, 185.2])],
 92+         [inch(0.320), mean([179.0, 183.4])],
 93+         [inch(0.330), mean([160.2, 160.2])],
 94+         [inch(0.340), mean([135.0, 104.7])],
 95+         [inch(0.350), mean([119.6, 123.6])],
 96+         [inch(0.360), mean([104.0, 110.4])],
 97+         [inch(0.370), mean([ 79.0,  81.0, 89.2])],
 98+         [inch(0.380), mean([ 61.0,  63.0, 66.0])],
 99+         [inch(0.390), mean([ 59.5,  61.6])],
100+         [inch(0.400), mean([ 51.0,  54.5, 56.5])],
101+         [inch(0.410), mean([ 27.0,  29.5])],
102+         [inch(0.420), mean([ 21.5,  29.0])],
103+         [inch(0.427), mean([  0.0,   0.0])],
104+         ]);
105+  }
106+}
107+
108+module tenon(top=false, h=198, od=od-5, depth=20, thickness=2, clearance=0.12) {
109+  module cut() {
110+        cylinder(h=h+depth, d=od-thickness+clearance);
111+        cylinder(h=h, d=50);
112+  }
113+
114+  if (top) {
115+    difference() {
116+      children();
117+      cut();
118+    }
119+  } else {
120+    intersection() {
121+      children();
122+      cut();
123+    }
124+  }
125+}
126+
127+chanter();
A harrington-rowsome-c\342\231\257/chanter.scad
+119, -0
  1@@ -0,0 +1,119 @@
  2+use <BOSL/math.scad>
  3+
  4+$fn = $preview ? 0 : 180; // Make circles circular in final renders.
  5+
  6+// stops is an array of [d, h]
  7+module rod(stops) {
  8+  beg = stops[0][1];
  9+  end = stops[len(stops)-1][1];
 10+  p = concat([[0, beg]], stops, [[0, end]]);
 11+
 12+  halfp = [for (i = p) [i[0]/2, i[1]]];
 13+  rotate_extrude(convexity=4) {
 14+    polygon(halfp);
 15+  }
 16+}
 17+
 18+// Drill a tonehole.
 19+// The center of the tonehole will intersect [0, od, h] before rotation.
 20+//
 21+// Instrument makers think about
 22+// drilling from the outside of the pipe in.
 23+// So we need to know the outside diameter of the pipe.
 24+//
 25+// For now, we're pretending the pipe has a consistent outside diameter.
 26+// BOSL2 may have something that will let us calculate od given h and measurements.
 27+module tonehole(od, h, d, undercut=0, rot=0) {
 28+  render(convexity=2)
 29+  rotate([0, 0, rot]) {
 30+    translate([0, -od/2, h]) {
 31+      // Intersect with a cube to ensure an undercut tonehole doesn't drill past the center of the instrument
 32+      intersection() {
 33+        rotate([-90+undercut, 0, 0]) {
 34+          cylinder(d=d, h=od, center=true);
 35+        }
 36+        cube(od, center=true);
 37+      }
 38+    }
 39+  }
 40+}
 41+
 42+function inch(x) = x * 25.4;
 43+
 44+od = inch(0.762);
 45+
 46+height = 360;
 47+
 48+module chanter() {
 49+  difference() {
 50+    union() {
 51+      cylinder(d=16, h=height);
 52+      cylinder(d1=od, d2=16, h=280); // A nice taper
 53+    }
 54+
 55+    tonehole(od, 56.0, inch(0.162));
 56+    tonehole(od, 89.0, inch(0.182));
 57+    tonehole(od, 122.2, inch(0.201));
 58+    tonehole(od, 153.2, inch(0.180));
 59+    tonehole(od, 190.1, inch(0.183));
 60+    tonehole(od, 222.6, inch(0.187));
 61+    tonehole(od, 252.2, inch(0.162));
 62+    tonehole(od, 275.5, inch(0.173), rot=180);
 63+  
 64+    rod([
 65+         [7.1, height],
 66+         [inch(0.189), 337],
 67+         [inch(0.195), mean([330.7, 334.1])],
 68+         [inch(0.200), mean([325.5, 329.6])],
 69+         [inch(0.205), mean([318.2, 321.8])],
 70+         [inch(0.210), mean([315.2, 317.7])],
 71+         [inch(0.215), mean([309.7, 312.5])],
 72+         [inch(0.220), mean([302.0, 305.5])],
 73+         [inch(0.225), mean([294.7, 297.4])],
 74+         [inch(0.230), mean([288.5, 292.0])],
 75+         [inch(0.235), mean([282.5, 284.0])],
 76+         [inch(0.241), mean([274.0, 278.7])],
 77+         [inch(0.245), mean([269.0, 269.0])],
 78+         [inch(0.250), mean([265.0, 265.0])],
 79+         [inch(0.259), mean([266.0, 266.0])],
 80+         [inch(0.270), mean([237.9, 241.5])],
 81+         [inch(0.280), mean([224.5, 226.5])],
 82+         [inch(0.290), mean([209.0, 212.2])],
 83+         [inch(0.300), mean([195.4, 195.4])],
 84+         [inch(0.310), mean([183.0, 185.2])],
 85+         [inch(0.320), mean([179.0, 183.4])],
 86+         [inch(0.330), mean([160.2, 160.2])],
 87+         [inch(0.340), mean([135.0, 104.7])],
 88+         [inch(0.350), mean([119.6, 123.6])],
 89+         [inch(0.360), mean([104.0, 110.4])],
 90+         [inch(0.370), mean([ 79.0,  81.0, 89.2])],
 91+         [inch(0.380), mean([ 61.0,  63.0, 66.0])],
 92+         [inch(0.390), mean([ 59.5,  61.6])],
 93+         [inch(0.400), mean([ 51.0,  54.5, 56.5])],
 94+         [inch(0.410), mean([ 27.0,  29.5])],
 95+         [inch(0.420), mean([ 21.5,  29.0])],
 96+         [inch(0.427), mean([  0.0,   0.0])],
 97+         ]);
 98+  }
 99+}
100+
101+module tenon(top=false, h=198, od=od-5, depth=20, thickness=2, clearance=0.12) {
102+  module cut() {
103+        cylinder(h=h+depth, d=od-thickness+clearance);
104+        cylinder(h=h, d=50);
105+  }
106+
107+  if (top) {
108+    difference() {
109+      children();
110+      cut();
111+    }
112+  } else {
113+    intersection() {
114+      children();
115+      cut();
116+    }
117+  }
118+}
119+
120+chanter();
A harrington-rowsome-c\342\231\257/measurements.txt
+101, -0
  1@@ -0,0 +1,101 @@
  2+Possible Harrington C# Chanter 						
  3+Owned by Kevin Rowsome
  4+
  5+Copyright 1998 David C. Daye
  6+						
  7+Notes:	LOA: 381 mm					
  8+	Bell I.D.: .44" x .427"					
  9+	Construction: 		Medium brown wood			
 10+			Slight curved bore, slightly ovalled			
 11+	Special: Per Benedict Koehler, bottom end of chanter				
 12+		has been reamed and fit with new bottom &				
 13+		bell, feather-tapered into original top portion.				
 14+		"Gouges" and splinters I observed in bottom				
 15+		are feather edges chipping and peeling loose.				
 16+						
 17+	Measurement Notes:					
 18+		ID penetration numbers are identical for throat.
 19+
 20+		Elsewhere when 2 are same for an i.d., a tone hole
 21+   		is present and therefore only one penetration
 22+		distance could be taken. It is not necessarily
 23+		either the true min. or maximum penetration of
 24+		a pre-hole bore.
 25+
 26+		I.D.'s marked by *** are in gouged/chipped area.
 27+		Therefore 3 or 4 penetration numbers are given
 28+		because of measurement uncertainties.
 29+
 30+Chanter is said to be well behaved, has good tone.
 31+						
 32+Probe	   Distances From Bell (millimeters)					
 33+ID "	Min	Max	Min2	Max2		
 34+						
 35+0.255	381.0	381.0				
 36+0.250	379.5	380.0				
 37+0.245	379.0	379.0				
 38+0.230	377.0	377.5				
 39+0.220	376.0	377.0				
 40+0.215	375.0	376.0				
 41+0.200	372.2	374.0				
 42+0.195	371.0	371.0				
 43+0.189	370.1	370.9			
 44+0.185	371.0	371.0			
 45+0.169	367.0	368.1			
 46+0.168	366.3	366.3			
 47+0.168	361.3	361.3			
 48+0.174	351.9	352.8			
 49+0.180	345.1	347.2			
 50+0.185	342.0	344.6			
 51+0.189	337.5	339.5			
 52+0.195	330.7	334.1			
 53+0.200	325.5	329.6			
 54+0.205	318.2	321.8			
 55+0.210	315.2	317.7			
 56+0.215	309.7	312.5			
 57+0.220	302.0	305.5			
 58+0.225	294.7	297.4			
 59+0.230	288.5	292.0			
 60+0.235	282.5	284.0			
 61+0.241	274.0	278.7			
 62+0.245	269.0	269.0			
 63+0.250	265.0	265.0			
 64+0.259	266.0	266.0			
 65+0.270	237.9	241.5			
 66+0.280	224.5	226.5			
 67+0.290	209.0	212.2			
 68+0.300	195.4	195.4			
 69+0.310	183.0	185.2			
 70+0.320	179.0	183.4			
 71+0.330	160.2	160.2			
 72+0.340	135.0	104.7			
 73+0.350	119.6	123.6			
 74+0.360	104.0	110.4			
 75+0.370	 79.0	 81.0		89.2	***
 76+0.380	 61.0	 63.0		66.0	***
 77+0.390	 59.5	 61.6			
 78+0.400	 51.0	 54.5		56.5	***
 79+0.410	 27.0	 29.5	41.5	47.0	***
 80+0.420	 21.5	 29.0	33.0	36.0	***
 81+0.427	  0.0	  0.0			
 82+0.430	 11.0	 11.0			
 83+0.440	  0.0	  0.0			
 84+					
 85+Tone Hole Data	  (yes E-flat hole is smaller than E hole)
 86+
 87+Note	Dist from	I.D. 	I.D.#2	Chanter	Chanter
 88+Name	Bell (mm)	(in.)	(in.)	Width "	Depth "
 89+					
 90+E flat	 56.0		0.162		0.762	0.735
 91+E	 89.0		0.182		0.752	0.730
 92+F	104.5				
 93+F#	122.2		0.201		0.749	0.690
 94+G	153.2		0.180		0.709	0.735
 95+A	190.1		0.183			
 96+B flat	205.5				
 97+B	222.6		0.187			
 98+C'	236.8				
 99+C	252.2		0.162			0.661
100+D"	264.1				
101+D'	271.5		0.173	0.159	0.669	0.636
102+					
A harrington-rowsome-c\342\231\257/top.scad
+5, -0
1@@ -0,0 +1,5 @@
2+use <./chanter.scad>
3+
4+tenon(top=true) {
5+  chanter();
6+}
A kenna-reck-b/README.md
+1, -0
1@@ -0,0 +1 @@
2+http://plans.source.pipers.ie.s3.amazonaws.com/plans/pdf_024758.pdf
A kenna-reck-b/chanter.pdf
+0, -0
A kenna-reck-b/chanter.scad
+85, -0
 1@@ -0,0 +1,85 @@
 2+use <BOSL/math.scad>
 3+
 4+// A cylinder-like object defined by probe measurements.
 5+// Each measurement is a 2-tuple: (d, h)
 6+module rod(measurements) {
 7+  end_d = measurements[len(measurements)-1][1];
 8+  p = concat([[0, 0]], measurements, [[0, end_d]]);
 9+  rotate_extrude(convexity=4) {
10+    polygon(p);
11+  }
12+}
13+
14+// Drill toneholes.
15+// Each hole is a 4-tuple: (h, d, rotation_angle, undercut_angle)
16+// The center of the tonehole will intersect [0, od, h] before rotation.
17+//
18+// Instrument makers think about
19+// drilling from the outside of the pipe in.
20+// So we need to know the outside diameter of the pipe.
21+//
22+// For now, we're pretending the pipe has a consistent outside diameter.
23+// BOSL2 may have something that will let us calculate od given h and measurements.
24+module toneholes(od, holes) {
25+  for (hole = holes) {
26+    h = holes[0];
27+    d = holes[1];
28+    rot = holes[2];
29+    undercut = holes[3];
30+
31+    rotate([0, 0, rot]) {
32+      translate([0, -od/2, h]) {
33+        // Intersect with a cube to ensure an undercut tonehole doesn't drill past the center of the instrument
34+        intersection() {
35+          rotate([-90+undercut, 0, 0]) {
36+            cylinder(d=d, h=od, center=true);
37+          }
38+          cube(od, center=true);
39+        }
40+      }
41+    }
42+  }
43+}
44+
45+rod([
46+     [6.2, 0], // Top
47+     [5.7, 5],
48+     [5.4, 7],
49+     [5, 10.5],
50+     [4.76, 11.5],
51+     [4.4, 14],
52+     [4.1, 15.5],
53+     [3.9, 16],
54+     [3.8, 16.5], // Height specified as "Through"
55+     [3.8, 20], // Continuation of "Through", I guess
56+     [3.9, 20.5],
57+     [4, 25.5],
58+     [4.2, 37.5],
59+     [4.5, 48],
60+     [4.7, 57.5],
61+     [5, 71.5],
62+     [5.2, 80],
63+     [5.5, 91.5],
64+     [5.8, 125.5],
65+     [6, 135.5],
66+     [6.3, 143],
67+     [6.5, 148.8],
68+     [6.7, 165.5],
69+     [7, 191.5],
70+     [7.2, 200.5],
71+     [7.5, 215.5],
72+     [7.8, 236.5],
73+     [8, 239],
74+     [8.2, 248.3],
75+     [8.5, 266],
76+     [8.8, 285.5],
77+     [9, 306],
78+     [9.2, 323],
79+     [9.5, 365.5],
80+     [9.8, 378],
81+     [10, 395.5],
82+     [10.6, 435.5], // End of timber
83+     [11.1, 440.5], // Ivory extension
84+     [11.5, 445.5], // Bell
85+     ]);
86+}
M pickett-d/Makefile
+3, -2
 1@@ -1,8 +1,9 @@
 2-rev=$(shell git log -1 --pretty='format:%cd' --date='format:%Y-%m-%d')
 3+commit_date=$(shell git log -1 --pretty='format:%cd' --date='format:%Y-%m-%d')
 4+commit_number=$(shell git rev-list --count HEAD)
 5 
 6 all: chanter.3mf split.3mf
 7 clean:
 8 	rm -f *.3mf
 9 
10 %.3mf: %.scad chanter.scad
11-	openscad -D rev=\"$(rev)\" -o $@ $<
12+	openscad -D rev=\"$(commit_number)/$(commit_date)\" -o $@ $<
M pickett-d/chanter.scad
+21, -38
 1@@ -3,6 +3,8 @@
 2 
 3 use <./sigil.scad>
 4 
 5+fancy = true;  // Fancy decorations?
 6+
 7 rev = "preview";
 8 stamp = str(rev);
 9 
10@@ -29,7 +31,7 @@ module wood() {
11 
12 // A compression fitting, basically.
13 module ringyding(h, d) {
14-  color("goldenrod") resize([d, d, h]) sphere(d=d);
15+  color("goldenrod") resize([d, d, h]) sphere();
16 }
17 
18 // A fillet is a sort of trumpet bell shape
19@@ -45,25 +47,6 @@ module fillet(h, d1, d2) {
20   }
21 }
22 
23-// Just a rotated cylinder
24-// h: height of the *top* of the protrusion
25-// d: height of the protrusion (diameter?)
26-// protrusion: amount of protrusion
27-module bumpout(h, d, protrusion) {
28-  intersection() {
29-    translate([0, -protrusion, h-d]) {
30-      cylinder(h=d, d=20.4);
31-    }
32-    translate([0, -protrusion, h-d/2]) {
33-      sphere(d=protrusion*4);
34-    }
35-    translate([0, 0, h-d]) {
36-      cylinder(h=d, d1=19, d2=50);
37-    }
38-  }
39-}
40-
41-
42 // A tonehole with :
43 // * height=h
44 // * transverse diameter = td
45@@ -90,25 +73,25 @@ module chanter() {
46             
47       // Wood body
48       translate([0, 0, 32.5]) wood() cylinder(h=258, d1=20.4, d2=18);
49+
50+      if (fancy) {
51+        // Bottom wood transition
52+        translate([0, 0, 33.7]) ringyding(h=8, d=23);
53+        translate([0, 0, 25.6]) ivory() fillet(h=7, d1=18, d2=22); // eliminate overhang
54+        translate([0, 0, 25.6]) ringyding(h=4.3, d=19);
55             
56-      // Bottom wood transition
57-      translate([0, 0, 33.7]) ringyding(h=8, d=23);
58-      translate([0, 0, 25.6]) ivory() fillet(h=7, d1=18, d2=22); // eliminate overhang
59-      translate([0, 0, 25.6]) ringyding(h=4.3, d=19);
60-            
61-      // Top wood transition
62-      translate([0, 0, 290.4]) ringyding(h=5.5, d=20);
63-      translate([0, 0, 305.6]) ringyding(h=4.3, d=19);
64-      translate([0, 0, 317.6]) ringyding(h=5.5, d=20.2);
65-      translate([0, 0, 318.6]) ivory() fillet(h=8.4, d1=17, d2=24); // eliminate overhang
66-      translate([0, 0, 328.3]) ringyding(h=8, d=25.4);
67-            
68+        // Top wood transition
69+        translate([0, 0, 290.4]) ringyding(h=5.5, d=20);
70+        translate([0, 0, 305.6]) ringyding(h=4.3, d=19);
71+        translate([0, 0, 317.6]) ringyding(h=5.5, d=20.2);
72+        translate([0, 0, 318.6]) ivory() fillet(h=8.4, d1=17, d2=24); // eliminate overhang
73+        translate([0, 0, 328.3]) ringyding(h=8, d=25.4);
74+      } else {
75+        translate([0, 0, 27.5]) wood() cylinder(h=5, d1=17, d2=20.4);
76+      }
77+
78       // This protects the reed and provides a place for tubing to connect
79-      translate([0, 0, 324.5]) metal() cylinder(h=32.7, d=14.8);
80-            
81-      // Bumpouts
82-      // These angles are my best guess based on photos
83-      rotate(220) wood() bumpout(161.2, 14.8, 6); // protrusion guessed
84+      translate([0, 0, 324.5]) metal() cylinder(h=32.7, d=16);
85     }
86 
87     // Inner bore
88@@ -121,7 +104,7 @@ module chanter() {
89 
90     // Tone Holes!
91     translate([0, 0, 5]) { // Magic offset from published measurements
92-      rotate(180) tonehole(263, 6.04, 7.95, 10.1, 1.2); // back D
93+      rotate(180) tonehole(268, 6.04, 7.95, 10.1, 1.2); // back D
94       rotate(0) tonehole(246.4, 6.42, 6.57, 11.3); // C♯
95       rotate(0) tonehole(216.2, 6.89, 6.96, 11.3); // B
96       rotate(0) tonehole(182, 8.85, 9.06, 11.4); // A
M pickett-d/sigil.scad
+7, -1
 1@@ -1,4 +1,10 @@
 2-use <MCAD/regular_shapes.scad>
 3+// A simple re-implementation from mcad
 4+module cylinder_tube(height, radius, wall) {
 5+  difference() {
 6+    cylinder(h=height, r=radius);
 7+    cylinder(h=height, r=radius-wall);
 8+  }
 9+}
10 
11 module sigil(d, stamp, rot=0) {
12   // Sigil