/ proof-of-concept / soundbox
Sign in
proof-of-concept / soundbox
soundbox / src / studio / presets.ts
132 lines · 3.8 KBBlameHistoryRaw
1/**
2 * The preset scenes the Play layer offers — each one an ordinary SceneSpec,
3 * nothing a user could not build by hand in the Build tab. A preset is a
4 * starting point, not a mode: picking one loads its spec into the builder,
5 * and everything stays editable from there.
6 */
7import type { SceneSpec } from './types.ts';
9export interface Preset {
10 key: string;
11 label: string;
12 blurb: string;
13 /** What the excite button says for this scene. */
14 verb: string;
15 spec: SceneSpec;
16 /** Where the microphone starts, metres. */
17 mic: { x: number; y: number; z: number };
20export const PRESETS: Preset[] = [
21 {
22 key: 'dulcimer',
23 label: 'Dulcimer',
24 blurb: 'One plucked string over a rigid box with a sound hole — the scene the dulcimer project hardcodes, here just a preset.',
25 verb: 'Pluck',
26 spec: {
27 objects: [
28 {
29 id: 's1', type: 'string', size: { L1: 0.6 },
30 params: {}, place: {},
31 },
32 ],
33 body: { type: 'box', params: {} },
34 },
35 mic: { x: 0.12, y: 0.08, z: 0.1 },
36 },
37 {
38 key: 'drum',
39 label: 'Drum',
40 blurb: 'A struck membrane over a cylindrical shell. The head’s inharmonic modes plus the cavity under it are what make it a drum.',
41 verb: 'Strike',
42 spec: {
43 objects: [
44 {
45 id: 'm1', type: 'membrane', size: { L1: 0.32, L2: 0.32 },
46 params: {}, place: {},
47 },
48 ],
49 body: { type: 'shell', params: {} },
50 },
51 mic: { x: 0.15, y: 0.1, z: 0.12 },
52 },
53 {
54 key: 'chime',
55 label: 'Chime',
56 blurb: 'A stiff bar in open air, struck. No tension, so the stiffness sets the partials — at n²·f1, which is the bell-like sound.',
57 verb: 'Strike',
58 spec: {
59 objects: [
60 {
61 id: 'b1', type: 'bar', size: { L1: 0.3 },
62 params: {}, place: { oz: 0.05 },
63 },
64 ],
65 body: { type: 'none', params: {} },
66 },
67 mic: { x: 0.12, y: 0.08, z: 0.1 },
68 },
69 {
70 key: 'bare',
71 label: 'Bare string',
72 blurb: 'The control experiment: the same plucked string with no body at all. Compare it to the dulcimer to hear what the box adds.',
73 verb: 'Pluck',
74 spec: {
75 objects: [
76 {
77 id: 's1', type: 'string', size: { L1: 0.6 },
78 params: { gair: 1, gbridge: 0 }, place: {},
79 },
80 ],
81 body: { type: 'none', params: {} },
82 },
83 mic: { x: 0.12, y: 0.08, z: 0.1 },
84 },
85 {
86 key: 'duet',
87 label: 'Duet',
88 blurb: 'Two strings a fifth apart over one box, plucked together — the smallest ensemble, and the point of composing scenes.',
89 verb: 'Pluck',
90 spec: {
91 objects: [
92 {
93 id: 's1', type: 'string', size: { L1: 0.6 },
94 params: { f0: 294 }, place: { oy: -0.03 },
95 },
96 {
97 id: 's2', type: 'string', size: { L1: 0.6 },
98 params: { f0: 441, pluckpos: 0.3 }, place: { oy: 0.03 },
99 },
100 ],
101 body: { type: 'box', params: { boxw: 0.22 } },
102 },
103 mic: { x: 0.12, y: 0.08, z: 0.1 },
104 },
105 {
106 key: 'kit',
107 label: 'Drum and chime',
108 blurb: 'A membrane over its shell and a bar beside it, struck together — two kinds of physics in one air.',
109 verb: 'Strike',
110 spec: {
111 objects: [
112 {
113 id: 'm1', type: 'membrane', size: { L1: 0.3, L2: 0.3 },
114 params: { f0: 100 }, place: {},
115 },
116 {
117 id: 'b1', type: 'bar', size: { L1: 0.25 },
118 params: { f1: 880 }, place: { oy: -0.12, oz: 0.06 },
119 },
120 ],
121 body: { type: 'shell', params: { shellr: 0.16 } },
122 },
123 mic: { x: 0.18, y: 0.1, z: 0.12 },
124 },
125];
127export const presetByKey = (key: string): Preset | undefined =>
128 PRESETS.find((p) => p.key === key);
130/** Deep-copy a preset's spec so edits do not bleed back into the preset. */
131export const cloneSpec = (spec: SceneSpec): SceneSpec =>
132 JSON.parse(JSON.stringify(spec)) as SceneSpec;
↑↓ move↵openescclose