whistles

3d printable Irish whistles
git clone https://git.woozle.org/neale/whistles.git

Neale Pickett  ·  2025-05-03

common.scad

  1// Make circles circular in final renders.
  2$fn = $preview ? 0 : 180;
  3
  4// clearance in a permanent tenon/mortise joint
  5clearance = 0.2;
  6
  7module brass() {
  8  color("gold") children();
  9}
 10
 11module derlin() {
 12  color("dimgray") children();
 13}
 14
 15module ivory() {
 16  color("ivory") children();
 17}
 18
 19// tube creates a hollow cylinder
 20module tube(h=10, id=5, od=10) {
 21  difference() {
 22    cylinder(h=h, d=od);
 23    translate([0, 0, -1]) cylinder(h=h+2, d=id);
 24  }
 25}
 26
 27// donut creates a torus
 28module donut(h=1, d=10) {
 29  rotate_extrude(angle=360) {
 30    translate([d/2, 0]) {
 31      circle(d=h, $fn=120);
 32    }
 33  }
 34}
 35
 36// default height of rings
 37rings_height = 1.8;
 38
 39// rings of adornment.
 40// This engraves two rings, 1.4mm apart, at a depth of 0.4.
 41module rings(h=0.4, d=1, depth=0.4, spacing=1.4) {
 42  tube(h=h, id=d-depth, od=d+1);
 43  translate([0, 0, spacing]) tube(h=h, id=d-depth, od=d+1);
 44}
 45
 46// default brass tube thickness
 47brass_thickness = 0.75;
 48
 49// brass_tube creates a chamfered hollow cylinder with given inside diameter,
 50// and wall thickness of 0.75.
 51// Decorative rings are etched into the top and bottom.
 52module brass_tube(h=10, id=10, t=brass_thickness) {
 53  od = id + (t*2);
 54  cd = (id + od) / 2; // Chamfer diameter
 55
 56  brass() {
 57    difference() {
 58      tube(h=h, id=id, od=od);
 59
 60      // Chamfered ends
 61      translate([0, 0, 0]) cylinder(h=1, d1=cd, d2=id);
 62      translate([0, 0, h-1]) cylinder(h=1, d1=id, d2=cd);
 63
 64      translate([0, 0, 2]) rings(d=od);
 65      translate([0, 0, h-2-rings_height]) rings(d=od);
 66    }
 67  }
 68}
 69
 70// brass_bend provides a 180 degree bend in brass
 71module brass_bend(od=12.7, bend_r=16, t=brass_thickness) {
 72  color("gold") {
 73    rotate([90, 0, 0]) {
 74      rotate_extrude(angle=180) {
 75        translate([bend_r, 0, 0]) {
 76          difference() {
 77            circle(d=od);
 78            circle(d=od-t*2);
 79          }
 80        }
 81      }
 82    }
 83  }
 84}
 85
 86
 87// derlin_tube is a non-chamfered sky blue tube.
 88// I use blue so it's easier to see in preview.
 89module derlin_tube(h=10, id=5, od=10) {
 90  derlin() {
 91    tube(h=h, id=id, od=od);
 92  }
 93}
 94
 95// derlin_stop is a derlin tube, chamfered on one end.
 96module derlin_stop(h=10, id=5, od=10) {
 97  chamferh = h/5;
 98  derlin() {
 99    difference() {
100      union() {
101        cylinder(h=h-chamferh, d=od);
102        translate([0, 0, h-chamferh]) cylinder(h=chamferh, d1=od, d2=id);
103        }
104      cylinder(h=h, d=id);
105      }
106    }
107}
108
109// default bell height
110bell_height = 17;
111
112// derlin_bell makes a decorative flared bell.
113// od will default to 33% larger than id.
114module derlin_bell(h=bell_height, id=5, od=0) {
115  chamferh = 1;
116  chamferd = 1;
117  ringsmargin = 1;
118  toph = rings_height + ringsmargin*2 + chamferh;
119  flareh = h - toph;
120  od = (od == 0) ? (id * 1.33) : od;
121  derlin() {
122    difference() {
123      union() {
124        cylinder(h=flareh, d1=id, d2=od);
125        translate([0, 0, flareh]) cylinder(h=toph-chamferh, d=od);
126        translate([0, 0, flareh+toph-chamferh]) cylinder(h=chamferh, d1=od, d2=od-chamferd);
127      }
128      cylinder(h=h, d=id);
129      translate([0, 0, flareh + ringsmargin]) rings(d=od);
130    }
131  }
132}
133
134// A tenon joint.
135//
136// You have to do this twice, to make two pieces. Glue them together.
137module tenon(h, od, top, depth=20, thickness=2) {
138  cl = top ? 0 : clearance;
139  module cut() {
140    cutd = od - thickness - cl;
141    cylinder(h=h+depth, d=cutd);
142    cylinder(h=h, d=50);
143    translate([0, 0, h + depth]) cylinder(h=cutd, d1=cutd, d2=0);
144  }
145
146  if (top) {
147    difference() {
148      children();
149      cut();
150    }
151  } else {
152    intersection() {
153      children();
154      cut();
155    }
156  }
157}