/ simulated_instruments / cymbal
Sign in
simulated_instruments / cymbal
Pitch support by geometric scaling in the exported driver
MIDI pitch scales every structural length by 2^-((pitch - ref)/12), so the modal spectrum shifts by the semitone ratio exactly (bending modes go as thickness / length^2; the woodblock's cavity scales consistently). The exciter stays fixed. The default geometry sits at the reference note with a two-octave playable range around it.
Jeremy Magland <jmagland@flatironinstitute.org> committed commit 048e093d0a5d parent e136893 Browse files
3 changed files+33−8
export-src/cymbal/export.jsonmodified+15−3View file
@@ -1,10 +1,22 @@
11 {
22 "id": "cymbal",
33 "name": "Cymbal",
4- "description": "Struck cymbal; unpitched, velocity onto strike speed.",
4+ "description": "Struck cymbal; pitch scales the plate around MIDI 60 (48..72), velocity onto strike speed.",
55 "source": "simulated_instruments/cymbal",
66 "knobs": [
7- { "key": "strike_r", "label": "strike radius", "min": 0.05, "max": 0.99, "default": 0.94 },
8- { "key": "strike_angle_deg", "label": "strike angle (deg)", "min": 0, "max": 90, "default": 40 }
7+ {
8+ "key": "strike_r",
9+ "label": "strike radius",
10+ "min": 0.05,
11+ "max": 0.99,
12+ "default": 0.94
13+ },
14+ {
15+ "key": "strike_angle_deg",
16+ "label": "strike angle (deg)",
17+ "min": 0,
18+ "max": 90,
19+ "default": 40
20+ }
921 ]
1022 }
export-src/cymbal/render_note.mmodified+16−3View file
@@ -1,7 +1,12 @@
11 function y = render_note(note)
2-% Unpitched: MIDI pitch is ignored, velocity drives the strike speed.
3-% Fixed: a single strike, a fixed seed, normalize off so velocity
4-% survives in pascals.
2+% MIDI pitch scales the plate geometry: every length by
3+% s = 2^-((pitch - 60)/12), which shifts the bending-mode spectrum by the
4+% semitone ratio exactly (plate modes go as thickness / radius^2). The
5+% stick stays fixed, so this is one player striking a family of cymbal
6+% sizes; pitch 60 is the default 16-inch plate, playable 48..72. The
7+% sound is inharmonic, so the note number is a handle on register, not a
8+% tuned fundamental. Velocity drives the strike speed. Fixed: a single
9+% strike, a fixed seed, normalize off so velocity survives in pascals.
510 P = cymbal_defaults();
611 P.sample_rate = note.sample_rate;
712 P.strike_count = 1;
@@ -11,6 +16,14 @@ P.normalize = 0;
1116 if note.preview ~= 0
1217 P.oversample = 1;
1318 end
19+s = 2 ^ (-(max(48, min(72, note.pitch)) - 60) / 12);
20+P.radius_m = P.radius_m * s;
21+P.hole_radius_m = P.hole_radius_m * s;
22+P.bell_radius_m = P.bell_radius_m * s;
23+P.bell_height_m = P.bell_height_m * s;
24+P.bow_height_m = P.bow_height_m * s;
25+P.thickness_bell_m = P.thickness_bell_m * s;
26+P.thickness_rim_m = P.thickness_rim_m * s;
1427 P.strike_velocity = 0.1 + (8 - 0.1) * note.velocity;
1528 P.strike_r = note.params.strike_r;
1629 P.strike_angle_deg = note.params.strike_angle_deg;
exports/cymbal.jsonmodified+2−2View file
@@ -2,7 +2,7 @@
22 "format": "numbl-instrument-v1",
33 "id": "cymbal",
44 "name": "Cymbal",
5- "description": "Struck cymbal; unpitched, velocity onto strike speed.",
5+ "description": "Struck cymbal; pitch scales the plate around MIDI 60 (48..72), velocity onto strike speed.",
66 "source": "simulated_instruments/cymbal",
77 "knobs": [
88 {
@@ -23,7 +23,7 @@
2323 "files": [
2424 {
2525 "name": "render_note.m",
26- "content": "function y = render_note(note)\n% Unpitched: MIDI pitch is ignored, velocity drives the strike speed.\n% Fixed: a single strike, a fixed seed, normalize off so velocity\n% survives in pascals.\nP = cymbal_defaults();\nP.sample_rate = note.sample_rate;\nP.strike_count = 1;\nP.seed = 1;\nP.pre_delay_ms = 0;\nP.normalize = 0;\nif note.preview ~= 0\n P.oversample = 1;\nend\nP.strike_velocity = 0.1 + (8 - 0.1) * note.velocity;\nP.strike_r = note.params.strike_r;\nP.strike_angle_deg = note.params.strike_angle_deg;\ny = cymbal_render(P);\nend\n"
26+ "content": "function y = render_note(note)\n% MIDI pitch scales the plate geometry: every length by\n% s = 2^-((pitch - 60)/12), which shifts the bending-mode spectrum by the\n% semitone ratio exactly (plate modes go as thickness / radius^2). The\n% stick stays fixed, so this is one player striking a family of cymbal\n% sizes; pitch 60 is the default 16-inch plate, playable 48..72. The\n% sound is inharmonic, so the note number is a handle on register, not a\n% tuned fundamental. Velocity drives the strike speed. Fixed: a single\n% strike, a fixed seed, normalize off so velocity survives in pascals.\nP = cymbal_defaults();\nP.sample_rate = note.sample_rate;\nP.strike_count = 1;\nP.seed = 1;\nP.pre_delay_ms = 0;\nP.normalize = 0;\nif note.preview ~= 0\n P.oversample = 1;\nend\ns = 2 ^ (-(max(48, min(72, note.pitch)) - 60) / 12);\nP.radius_m = P.radius_m * s;\nP.hole_radius_m = P.hole_radius_m * s;\nP.bell_radius_m = P.bell_radius_m * s;\nP.bell_height_m = P.bell_height_m * s;\nP.bow_height_m = P.bow_height_m * s;\nP.thickness_bell_m = P.thickness_bell_m * s;\nP.thickness_rim_m = P.thickness_rim_m * s;\nP.strike_velocity = 0.1 + (8 - 0.1) * note.velocity;\nP.strike_r = note.params.strike_r;\nP.strike_angle_deg = note.params.strike_angle_deg;\ny = cymbal_render(P);\nend\n"
2727 },
2828 {
2929 "name": "cymbal_at.m",
↑↓ move↵openescclose