livepilot 1.9.24 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/AGENTS.md +3 -3
  3. package/CHANGELOG.md +73 -0
  4. package/CONTRIBUTING.md +1 -1
  5. package/README.md +56 -19
  6. package/bin/livepilot.js +87 -0
  7. package/installer/codex.js +147 -0
  8. package/livepilot/.Codex-plugin/plugin.json +2 -2
  9. package/livepilot/.claude-plugin/plugin.json +2 -2
  10. package/livepilot/skills/livepilot-core/SKILL.md +21 -4
  11. package/livepilot/skills/livepilot-core/references/device-knowledge/00-index.md +34 -0
  12. package/livepilot/skills/livepilot-core/references/device-knowledge/automation-as-music.md +204 -0
  13. package/livepilot/skills/livepilot-core/references/device-knowledge/chains-genre.md +173 -0
  14. package/livepilot/skills/livepilot-core/references/device-knowledge/creative-thinking.md +211 -0
  15. package/livepilot/skills/livepilot-core/references/device-knowledge/effects-distortion.md +188 -0
  16. package/livepilot/skills/livepilot-core/references/device-knowledge/effects-space.md +162 -0
  17. package/livepilot/skills/livepilot-core/references/device-knowledge/effects-spectral.md +229 -0
  18. package/livepilot/skills/livepilot-core/references/device-knowledge/instruments-synths.md +243 -0
  19. package/livepilot/skills/livepilot-core/references/overview.md +13 -9
  20. package/livepilot/skills/livepilot-core/references/sample-manipulation.md +724 -0
  21. package/livepilot/skills/livepilot-core/references/sound-design-deep.md +140 -0
  22. package/livepilot/skills/livepilot-devices/SKILL.md +16 -2
  23. package/livepilot/skills/livepilot-evaluation/references/capability-modes.md +1 -1
  24. package/livepilot/skills/livepilot-release/SKILL.md +5 -5
  25. package/livepilot/skills/livepilot-sample-engine/SKILL.md +104 -0
  26. package/livepilot/skills/livepilot-sample-engine/references/sample-critics.md +87 -0
  27. package/livepilot/skills/livepilot-sample-engine/references/sample-philosophy.md +51 -0
  28. package/livepilot/skills/livepilot-sample-engine/references/sample-techniques.md +131 -0
  29. package/livepilot/skills/livepilot-sound-design-engine/SKILL.md +45 -0
  30. package/livepilot/skills/livepilot-wonder/SKILL.md +15 -0
  31. package/livepilot.mcpb +0 -0
  32. package/m4l_device/livepilot_bridge.js +1 -1
  33. package/manifest.json +2 -2
  34. package/mcp_server/__init__.py +1 -1
  35. package/mcp_server/atlas/__init__.py +357 -0
  36. package/mcp_server/atlas/device_atlas.json +44067 -0
  37. package/mcp_server/atlas/enrichments/__init__.py +111 -0
  38. package/mcp_server/atlas/enrichments/audio_effects/auto_filter.yaml +162 -0
  39. package/mcp_server/atlas/enrichments/audio_effects/beat_repeat.yaml +183 -0
  40. package/mcp_server/atlas/enrichments/audio_effects/channel_eq.yaml +126 -0
  41. package/mcp_server/atlas/enrichments/audio_effects/chorus_ensemble.yaml +149 -0
  42. package/mcp_server/atlas/enrichments/audio_effects/color_limiter.yaml +109 -0
  43. package/mcp_server/atlas/enrichments/audio_effects/compressor.yaml +159 -0
  44. package/mcp_server/atlas/enrichments/audio_effects/convolution_reverb.yaml +143 -0
  45. package/mcp_server/atlas/enrichments/audio_effects/convolution_reverb_pro.yaml +178 -0
  46. package/mcp_server/atlas/enrichments/audio_effects/delay.yaml +151 -0
  47. package/mcp_server/atlas/enrichments/audio_effects/drum_buss.yaml +142 -0
  48. package/mcp_server/atlas/enrichments/audio_effects/dynamic_tube.yaml +147 -0
  49. package/mcp_server/atlas/enrichments/audio_effects/echo.yaml +167 -0
  50. package/mcp_server/atlas/enrichments/audio_effects/eq_eight.yaml +148 -0
  51. package/mcp_server/atlas/enrichments/audio_effects/eq_three.yaml +121 -0
  52. package/mcp_server/atlas/enrichments/audio_effects/erosion.yaml +103 -0
  53. package/mcp_server/atlas/enrichments/audio_effects/filter_delay.yaml +173 -0
  54. package/mcp_server/atlas/enrichments/audio_effects/gate.yaml +130 -0
  55. package/mcp_server/atlas/enrichments/audio_effects/gated_delay.yaml +133 -0
  56. package/mcp_server/atlas/enrichments/audio_effects/glue_compressor.yaml +142 -0
  57. package/mcp_server/atlas/enrichments/audio_effects/grain_delay.yaml +141 -0
  58. package/mcp_server/atlas/enrichments/audio_effects/hybrid_reverb.yaml +160 -0
  59. package/mcp_server/atlas/enrichments/audio_effects/limiter.yaml +97 -0
  60. package/mcp_server/atlas/enrichments/audio_effects/multiband_dynamics.yaml +174 -0
  61. package/mcp_server/atlas/enrichments/audio_effects/overdrive.yaml +119 -0
  62. package/mcp_server/atlas/enrichments/audio_effects/pedal.yaml +145 -0
  63. package/mcp_server/atlas/enrichments/audio_effects/phaser_flanger.yaml +161 -0
  64. package/mcp_server/atlas/enrichments/audio_effects/redux.yaml +114 -0
  65. package/mcp_server/atlas/enrichments/audio_effects/reverb.yaml +190 -0
  66. package/mcp_server/atlas/enrichments/audio_effects/roar.yaml +159 -0
  67. package/mcp_server/atlas/enrichments/audio_effects/saturator.yaml +146 -0
  68. package/mcp_server/atlas/enrichments/audio_effects/shifter.yaml +154 -0
  69. package/mcp_server/atlas/enrichments/audio_effects/spectral_resonator.yaml +141 -0
  70. package/mcp_server/atlas/enrichments/audio_effects/spectral_time.yaml +164 -0
  71. package/mcp_server/atlas/enrichments/audio_effects/vector_delay.yaml +140 -0
  72. package/mcp_server/atlas/enrichments/audio_effects/vinyl_distortion.yaml +141 -0
  73. package/mcp_server/atlas/enrichments/instruments/analog.yaml +222 -0
  74. package/mcp_server/atlas/enrichments/instruments/bass.yaml +202 -0
  75. package/mcp_server/atlas/enrichments/instruments/collision.yaml +150 -0
  76. package/mcp_server/atlas/enrichments/instruments/drift.yaml +167 -0
  77. package/mcp_server/atlas/enrichments/instruments/electric.yaml +137 -0
  78. package/mcp_server/atlas/enrichments/instruments/emit.yaml +163 -0
  79. package/mcp_server/atlas/enrichments/instruments/meld.yaml +164 -0
  80. package/mcp_server/atlas/enrichments/instruments/operator.yaml +197 -0
  81. package/mcp_server/atlas/enrichments/instruments/poli.yaml +192 -0
  82. package/mcp_server/atlas/enrichments/instruments/sampler.yaml +218 -0
  83. package/mcp_server/atlas/enrichments/instruments/simpler.yaml +217 -0
  84. package/mcp_server/atlas/enrichments/instruments/tension.yaml +156 -0
  85. package/mcp_server/atlas/enrichments/instruments/tree_tone.yaml +162 -0
  86. package/mcp_server/atlas/enrichments/instruments/vector_fm.yaml +165 -0
  87. package/mcp_server/atlas/enrichments/instruments/vector_grain.yaml +166 -0
  88. package/mcp_server/atlas/enrichments/instruments/wavetable.yaml +162 -0
  89. package/mcp_server/atlas/enrichments/midi_effects/arpeggiator.yaml +156 -0
  90. package/mcp_server/atlas/enrichments/midi_effects/bouncy_notes.yaml +93 -0
  91. package/mcp_server/atlas/enrichments/midi_effects/chord.yaml +147 -0
  92. package/mcp_server/atlas/enrichments/midi_effects/melodic_steps.yaml +97 -0
  93. package/mcp_server/atlas/enrichments/midi_effects/note_echo.yaml +108 -0
  94. package/mcp_server/atlas/enrichments/midi_effects/note_length.yaml +97 -0
  95. package/mcp_server/atlas/enrichments/midi_effects/pitch.yaml +76 -0
  96. package/mcp_server/atlas/enrichments/midi_effects/random.yaml +117 -0
  97. package/mcp_server/atlas/enrichments/midi_effects/rhythmic_steps.yaml +103 -0
  98. package/mcp_server/atlas/enrichments/midi_effects/scale.yaml +83 -0
  99. package/mcp_server/atlas/enrichments/midi_effects/step_arp.yaml +112 -0
  100. package/mcp_server/atlas/enrichments/midi_effects/velocity.yaml +119 -0
  101. package/mcp_server/atlas/enrichments/utility/amp.yaml +159 -0
  102. package/mcp_server/atlas/enrichments/utility/cabinet.yaml +109 -0
  103. package/mcp_server/atlas/enrichments/utility/corpus.yaml +150 -0
  104. package/mcp_server/atlas/enrichments/utility/resonators.yaml +131 -0
  105. package/mcp_server/atlas/enrichments/utility/spectrum.yaml +63 -0
  106. package/mcp_server/atlas/enrichments/utility/tuner.yaml +51 -0
  107. package/mcp_server/atlas/enrichments/utility/utility.yaml +136 -0
  108. package/mcp_server/atlas/enrichments/utility/vocoder.yaml +160 -0
  109. package/mcp_server/atlas/scanner.py +236 -0
  110. package/mcp_server/atlas/tools.py +224 -0
  111. package/mcp_server/composer/__init__.py +1 -0
  112. package/mcp_server/composer/engine.py +452 -0
  113. package/mcp_server/composer/layer_planner.py +427 -0
  114. package/mcp_server/composer/prompt_parser.py +329 -0
  115. package/mcp_server/composer/tools.py +201 -0
  116. package/mcp_server/connection.py +53 -8
  117. package/mcp_server/corpus/__init__.py +377 -0
  118. package/mcp_server/device_forge/__init__.py +1 -0
  119. package/mcp_server/device_forge/builder.py +377 -0
  120. package/mcp_server/device_forge/models.py +142 -0
  121. package/mcp_server/device_forge/templates.py +483 -0
  122. package/mcp_server/device_forge/tools.py +162 -0
  123. package/mcp_server/m4l_bridge.py +1 -0
  124. package/mcp_server/preview_studio/tools.py +4 -4
  125. package/mcp_server/runtime/capability_probe.py +21 -2
  126. package/mcp_server/runtime/execution_router.py +4 -0
  127. package/mcp_server/runtime/live_version.py +102 -0
  128. package/mcp_server/runtime/remote_commands.py +9 -4
  129. package/mcp_server/runtime/tools.py +18 -4
  130. package/mcp_server/sample_engine/__init__.py +1 -0
  131. package/mcp_server/sample_engine/analyzer.py +216 -0
  132. package/mcp_server/sample_engine/critics.py +390 -0
  133. package/mcp_server/sample_engine/models.py +193 -0
  134. package/mcp_server/sample_engine/moves.py +127 -0
  135. package/mcp_server/sample_engine/planner.py +186 -0
  136. package/mcp_server/sample_engine/sources.py +540 -0
  137. package/mcp_server/sample_engine/techniques.py +908 -0
  138. package/mcp_server/sample_engine/tools.py +442 -0
  139. package/mcp_server/semantic_moves/__init__.py +3 -0
  140. package/mcp_server/semantic_moves/device_creation_moves.py +237 -0
  141. package/mcp_server/semantic_moves/sample_compilers.py +372 -0
  142. package/mcp_server/server.py +51 -0
  143. package/mcp_server/sound_design/critics.py +89 -1
  144. package/mcp_server/splice_client/__init__.py +1 -0
  145. package/mcp_server/splice_client/client.py +347 -0
  146. package/mcp_server/splice_client/models.py +96 -0
  147. package/mcp_server/splice_client/protos/__init__.py +1 -0
  148. package/mcp_server/splice_client/protos/app_pb2.py +319 -0
  149. package/mcp_server/splice_client/protos/app_pb2.pyi +1153 -0
  150. package/mcp_server/splice_client/protos/app_pb2_grpc.py +1946 -0
  151. package/mcp_server/tools/arrangement.py +69 -0
  152. package/mcp_server/tools/automation.py +15 -2
  153. package/mcp_server/tools/devices.py +117 -6
  154. package/mcp_server/tools/notes.py +37 -4
  155. package/mcp_server/wonder_mode/diagnosis.py +5 -0
  156. package/mcp_server/wonder_mode/engine.py +85 -1
  157. package/package.json +12 -2
  158. package/remote_script/LivePilot/__init__.py +8 -1
  159. package/remote_script/LivePilot/arrangement.py +114 -0
  160. package/remote_script/LivePilot/browser.py +56 -1
  161. package/remote_script/LivePilot/devices.py +236 -6
  162. package/remote_script/LivePilot/mixing.py +8 -3
  163. package/remote_script/LivePilot/server.py +5 -1
  164. package/remote_script/LivePilot/transport.py +3 -0
  165. package/remote_script/LivePilot/version_detect.py +78 -0
@@ -0,0 +1,908 @@
1
+ """Sample Engine technique library — 30+ recipes indexed by material + intent.
2
+
3
+ Each technique is a named recipe with executable steps mapping to real MCP tools.
4
+ The steps use tool names that match LivePilot's existing MCP tools.
5
+
6
+ Zero I/O — pure data catalog.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from .models import SampleTechnique, TechniqueStep
12
+
13
+
14
+ # ── Catalog ─────────────────────────────────────────────────────────
15
+
16
+ _CATALOG: dict[str, SampleTechnique] = {}
17
+
18
+
19
+ def _register(t: SampleTechnique) -> SampleTechnique:
20
+ _CATALOG[t.technique_id] = t
21
+ return t
22
+
23
+
24
+ # ── Category 1: Rhythmic Sampling ──────────────────────────────────
25
+
26
+ _register(SampleTechnique(
27
+ technique_id="slice_and_sequence",
28
+ name="Slice & Sequence",
29
+ philosophy="surgeon",
30
+ material_types=["drum_loop", "full_mix"],
31
+ intents=["rhythm"],
32
+ difficulty="basic",
33
+ description="Classic MPC-style: load a loop, slice on transients, sequence the slices with MIDI",
34
+ inspiration="MPC workflow — chop and flip",
35
+ steps=[
36
+ TechniqueStep(tool="load_sample_to_simpler",
37
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
38
+ description="Load sample into new Simpler"),
39
+ TechniqueStep(tool="set_simpler_playback_mode",
40
+ params={"track_index": "{track_index}", "device_index": 0,
41
+ "playback_mode": 2, "slice_by": 0},
42
+ description="Set to Slice mode, slice by Transient"),
43
+ TechniqueStep(tool="get_simpler_slices",
44
+ params={"track_index": "{track_index}", "device_index": 0},
45
+ description="Read slice positions to understand the rhythm"),
46
+ TechniqueStep(tool="create_clip",
47
+ params={"track_index": "{track_index}", "clip_index": 0, "length": 4.0},
48
+ description="Create a 1-bar MIDI clip"),
49
+ TechniqueStep(tool="add_notes",
50
+ params={"track_index": "{track_index}", "clip_index": 0},
51
+ description="Program MIDI notes triggering slices (C1=slice1, C#1=slice2, etc.)"),
52
+ ],
53
+ success_signals=["rhythmic pattern audible", "slices trigger cleanly"],
54
+ failure_signals=["silence", "timing drift", "wrong slices triggered"],
55
+ ))
56
+
57
+ _register(SampleTechnique(
58
+ technique_id="vocal_chop_rhythm",
59
+ name="Vocal Chop → Rhythmic Instrument",
60
+ philosophy="alchemist",
61
+ material_types=["vocal"],
62
+ intents=["rhythm", "vocal"],
63
+ difficulty="intermediate",
64
+ description="Chop a vocal into syllable-length slices, trigger as staccato rhythmic pattern",
65
+ inspiration="Burial's staccato vocal stabs — ghostly, fragmented",
66
+ steps=[
67
+ TechniqueStep(tool="load_sample_to_simpler",
68
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
69
+ description="Load vocal into Simpler"),
70
+ TechniqueStep(tool="set_simpler_playback_mode",
71
+ params={"track_index": "{track_index}", "device_index": 0,
72
+ "playback_mode": 2, "slice_by": 2},
73
+ description="Set to Slice mode, slice by Region (preserves phrases)"),
74
+ TechniqueStep(tool="get_simpler_slices",
75
+ params={"track_index": "{track_index}", "device_index": 0},
76
+ description="Read slice positions"),
77
+ TechniqueStep(tool="create_clip",
78
+ params={"track_index": "{track_index}", "clip_index": 0, "length": 4.0},
79
+ description="Create MIDI clip"),
80
+ TechniqueStep(tool="add_notes",
81
+ params={"track_index": "{track_index}", "clip_index": 0},
82
+ description="Program short staccato notes on different slices"),
83
+ TechniqueStep(tool="find_and_load_device",
84
+ params={"track_index": "{track_index}", "device_name": "Auto Filter"},
85
+ description="Add Auto Filter for movement"),
86
+ TechniqueStep(tool="set_device_parameter",
87
+ params={"track_index": "{track_index}"},
88
+ description="Set filter cutoff ~2kHz, resonance ~30% for character"),
89
+ ],
90
+ success_signals=["staccato vocal pattern audible", "rhythmic energy added"],
91
+ failure_signals=["vocals sound unnatural", "timing feels wrong"],
92
+ ))
93
+
94
+ _register(SampleTechnique(
95
+ technique_id="micro_chop",
96
+ name="Micro-Chop",
97
+ philosophy="alchemist",
98
+ material_types=["drum_loop", "instrument_loop", "vocal", "full_mix"],
99
+ intents=["rhythm", "transform"],
100
+ difficulty="advanced",
101
+ description="Slice at 1/32 resolution, rearrange fragments with varied velocity — J Dilla micro-timing",
102
+ inspiration="J Dilla — 1/32 slices, disabled quantize, human swing",
103
+ steps=[
104
+ TechniqueStep(tool="load_sample_to_simpler",
105
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
106
+ description="Load sample into Simpler"),
107
+ TechniqueStep(tool="set_simpler_playback_mode",
108
+ params={"track_index": "{track_index}", "device_index": 0,
109
+ "playback_mode": 2, "slice_by": 3},
110
+ description="Set to Slice mode, Manual slicing"),
111
+ TechniqueStep(tool="create_clip",
112
+ params={"track_index": "{track_index}", "clip_index": 0, "length": 4.0},
113
+ description="Create MIDI clip"),
114
+ TechniqueStep(tool="add_notes",
115
+ params={"track_index": "{track_index}", "clip_index": 0},
116
+ description="Program dense 1/32 notes, varied velocity 40-127, slight timing offsets"),
117
+ ],
118
+ success_signals=["choppy rhythmic texture", "organic swing feel"],
119
+ failure_signals=["sounds like a glitch rather than groove"],
120
+ ))
121
+
122
+ _register(SampleTechnique(
123
+ technique_id="stab_isolation",
124
+ name="Stab Isolation",
125
+ philosophy="surgeon",
126
+ material_types=["full_mix", "instrument_loop"],
127
+ intents=["rhythm", "melody"],
128
+ difficulty="intermediate",
129
+ description="Isolate a single chord stab from a sample, trigger it rhythmically",
130
+ inspiration="DJ Premier — single chord stab extraction and rhythmic sequencing",
131
+ steps=[
132
+ TechniqueStep(tool="load_sample_to_simpler",
133
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
134
+ description="Load into Simpler"),
135
+ TechniqueStep(tool="set_simpler_playback_mode",
136
+ params={"track_index": "{track_index}", "device_index": 0,
137
+ "playback_mode": 0},
138
+ description="Set to Classic mode (manual region selection)"),
139
+ TechniqueStep(tool="crop_simpler",
140
+ params={"track_index": "{track_index}", "device_index": 0},
141
+ description="Crop to just the stab region"),
142
+ TechniqueStep(tool="create_clip",
143
+ params={"track_index": "{track_index}", "clip_index": 0, "length": 4.0},
144
+ description="Create MIDI clip"),
145
+ TechniqueStep(tool="add_notes",
146
+ params={"track_index": "{track_index}", "clip_index": 0},
147
+ description="Program rhythmic stab pattern"),
148
+ ],
149
+ success_signals=["clean stab playback", "rhythmic pattern feels musical"],
150
+ failure_signals=["stab includes unwanted material", "clicks at boundaries"],
151
+ ))
152
+
153
+ _register(SampleTechnique(
154
+ technique_id="euclidean_slice_trigger",
155
+ name="Euclidean Slice Trigger",
156
+ philosophy="alchemist",
157
+ material_types=["drum_loop", "vocal", "instrument_loop"],
158
+ intents=["rhythm", "transform"],
159
+ difficulty="intermediate",
160
+ description="Map Simpler slices to a Euclidean rhythm pattern for polyrhythmic texture",
161
+ inspiration="Euclidean rhythms meet sample chopping — mathematical groove",
162
+ steps=[
163
+ TechniqueStep(tool="load_sample_to_simpler",
164
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
165
+ description="Load sample into Simpler"),
166
+ TechniqueStep(tool="set_simpler_playback_mode",
167
+ params={"track_index": "{track_index}", "device_index": 0,
168
+ "playback_mode": 2, "slice_by": 0},
169
+ description="Slice by Transient"),
170
+ TechniqueStep(tool="get_simpler_slices",
171
+ params={"track_index": "{track_index}", "device_index": 0},
172
+ description="Read slice count"),
173
+ TechniqueStep(tool="generate_euclidean_rhythm",
174
+ params={"track_index": "{track_index}", "clip_index": 0,
175
+ "pulses": 5, "steps": 8, "length": 4.0},
176
+ description="Generate Euclidean pattern (5 pulses in 8 steps) across slice pitches"),
177
+ ],
178
+ success_signals=["polyrhythmic pattern from sample slices"],
179
+ failure_signals=["pattern too sparse or too dense for context"],
180
+ ))
181
+
182
+ # ── Category 2: Textural Transformation ────────────────────────────
183
+
184
+ _register(SampleTechnique(
185
+ technique_id="extreme_stretch",
186
+ name="Extreme Stretch",
187
+ philosophy="alchemist",
188
+ material_types=["vocal", "drum_loop", "instrument_loop", "one_shot", "texture", "foley", "fx", "full_mix"],
189
+ intents=["texture", "atmosphere"],
190
+ difficulty="basic",
191
+ description="Stretch a sample 10-50x using Texture warp mode — Paulstretch-style ambient wash",
192
+ inspiration="Paulstretch / Stars of the Lid — time as raw material",
193
+ steps=[
194
+ TechniqueStep(tool="load_sample_to_simpler",
195
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
196
+ description="Load sample into Simpler"),
197
+ TechniqueStep(tool="warp_simpler",
198
+ params={"track_index": "{track_index}", "device_index": 0, "beats": 64},
199
+ description="Warp to 16 bars (extreme stretch)"),
200
+ TechniqueStep(tool="find_and_load_device",
201
+ params={"track_index": "{track_index}", "device_name": "Reverb"},
202
+ description="Add Reverb for space"),
203
+ TechniqueStep(tool="set_device_parameter",
204
+ params={"track_index": "{track_index}"},
205
+ description="Set Reverb decay 8-15s, wet 60-80%"),
206
+ TechniqueStep(tool="set_track_volume",
207
+ params={"track_index": "{track_index}"},
208
+ description="Set volume -10 to -15dB for subtle layering"),
209
+ ],
210
+ success_signals=["ambient wash audible", "original material unrecognizable"],
211
+ failure_signals=["artifacts or glitches", "too prominent in mix"],
212
+ ))
213
+
214
+ _register(SampleTechnique(
215
+ technique_id="drum_to_pad",
216
+ name="Drum-to-Pad",
217
+ philosophy="alchemist",
218
+ material_types=["drum_loop", "one_shot"],
219
+ intents=["texture", "atmosphere"],
220
+ difficulty="intermediate",
221
+ description="Transform a drum hit into an ambient pad via reverse + stretch + reverb",
222
+ inspiration="Turning percussive energy into sustained atmosphere",
223
+ steps=[
224
+ TechniqueStep(tool="load_sample_to_simpler",
225
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
226
+ description="Load drum sample into Simpler"),
227
+ TechniqueStep(tool="reverse_simpler",
228
+ params={"track_index": "{track_index}", "device_index": 0},
229
+ description="Reverse the sample"),
230
+ TechniqueStep(tool="warp_simpler",
231
+ params={"track_index": "{track_index}", "device_index": 0, "beats": 32},
232
+ description="Stretch to 8 bars"),
233
+ TechniqueStep(tool="find_and_load_device",
234
+ params={"track_index": "{track_index}", "device_name": "Reverb"},
235
+ description="Add long reverb"),
236
+ TechniqueStep(tool="set_device_parameter",
237
+ params={"track_index": "{track_index}"},
238
+ description="Long decay 10s+, wet 70%+"),
239
+ ],
240
+ success_signals=["sustained pad texture from percussion source"],
241
+ failure_signals=["still sounds percussive", "harsh artifacts"],
242
+ ))
243
+
244
+ _register(SampleTechnique(
245
+ technique_id="reverse_layer",
246
+ name="Reverse Layer",
247
+ philosophy="alchemist",
248
+ material_types=["vocal", "instrument_loop", "one_shot", "fx"],
249
+ intents=["texture", "atmosphere"],
250
+ difficulty="basic",
251
+ description="Reverse a sample to create pre-echo swells and ghostly textures",
252
+ inspiration="Reversed elements as anticipation and mystery",
253
+ steps=[
254
+ TechniqueStep(tool="load_sample_to_simpler",
255
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
256
+ description="Load into Simpler"),
257
+ TechniqueStep(tool="reverse_simpler",
258
+ params={"track_index": "{track_index}", "device_index": 0},
259
+ description="Reverse the sample"),
260
+ TechniqueStep(tool="find_and_load_device",
261
+ params={"track_index": "{track_index}", "device_name": "Delay"},
262
+ description="Add delay for tail"),
263
+ TechniqueStep(tool="set_track_volume",
264
+ params={"track_index": "{track_index}"},
265
+ description="Set volume -8 to -12dB for subtle presence"),
266
+ ],
267
+ success_signals=["reverse swell before downbeat", "ghostly quality"],
268
+ failure_signals=["reverse element too prominent", "timing wrong"],
269
+ ))
270
+
271
+ _register(SampleTechnique(
272
+ technique_id="granular_scatter",
273
+ name="Granular Scatter",
274
+ philosophy="alchemist",
275
+ material_types=["vocal", "instrument_loop", "texture", "foley"],
276
+ intents=["texture", "transform"],
277
+ difficulty="intermediate",
278
+ description="Use Grain Delay as a granular engine — scatter grains for cloud textures",
279
+ inspiration="Granular synthesis from existing material — Amon Tobin territory",
280
+ steps=[
281
+ TechniqueStep(tool="load_sample_to_simpler",
282
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
283
+ description="Load source into Simpler"),
284
+ TechniqueStep(tool="find_and_load_device",
285
+ params={"track_index": "{track_index}", "device_name": "Grain Delay"},
286
+ description="Add Grain Delay after Simpler"),
287
+ TechniqueStep(tool="set_device_parameter",
288
+ params={"track_index": "{track_index}"},
289
+ description="Set spray 100-200ms, frequency random, pitch random ±12st"),
290
+ TechniqueStep(tool="find_and_load_device",
291
+ params={"track_index": "{track_index}", "device_name": "Reverb"},
292
+ description="Add reverb to smear grains"),
293
+ ],
294
+ success_signals=["granular cloud texture", "original material fragmented"],
295
+ failure_signals=["too chaotic", "no musical quality"],
296
+ ))
297
+
298
+ _register(SampleTechnique(
299
+ technique_id="spectral_freeze",
300
+ name="Spectral Freeze",
301
+ philosophy="alchemist",
302
+ material_types=["vocal", "instrument_loop", "full_mix", "texture"],
303
+ intents=["texture", "atmosphere"],
304
+ difficulty="advanced",
305
+ description="Capture one spectral moment and sustain it as a drone/pad",
306
+ inspiration="Spectral freezing — one moment becomes infinite",
307
+ steps=[
308
+ TechniqueStep(tool="load_sample_to_simpler",
309
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
310
+ description="Load into Simpler"),
311
+ TechniqueStep(tool="crop_simpler",
312
+ params={"track_index": "{track_index}", "device_index": 0},
313
+ description="Crop to a tiny region (50-200ms)"),
314
+ TechniqueStep(tool="warp_simpler",
315
+ params={"track_index": "{track_index}", "device_index": 0, "beats": 64},
316
+ description="Extreme stretch of tiny region — spectral freeze"),
317
+ TechniqueStep(tool="find_and_load_device",
318
+ params={"track_index": "{track_index}", "device_name": "Reverb"},
319
+ description="Reverb for sustain"),
320
+ ],
321
+ success_signals=["sustained spectral tone", "drone quality"],
322
+ failure_signals=["pulsing artifacts", "too short to freeze"],
323
+ ))
324
+
325
+ _register(SampleTechnique(
326
+ technique_id="tail_harvest",
327
+ name="Tail Harvest",
328
+ philosophy="alchemist",
329
+ material_types=["vocal", "instrument_loop", "one_shot", "drum_loop"],
330
+ intents=["texture", "atmosphere"],
331
+ difficulty="intermediate",
332
+ description="Resample only the reverb/delay tail of processed material as a new texture",
333
+ inspiration="Capturing the ghost of a sound — only the aftermath",
334
+ steps=[
335
+ TechniqueStep(tool="load_sample_to_simpler",
336
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
337
+ description="Load source material"),
338
+ TechniqueStep(tool="find_and_load_device",
339
+ params={"track_index": "{track_index}", "device_name": "Reverb"},
340
+ description="Add reverb with long tail"),
341
+ TechniqueStep(tool="set_device_parameter",
342
+ params={"track_index": "{track_index}"},
343
+ description="Set Reverb to 100% wet, decay 8-15s"),
344
+ TechniqueStep(tool="set_track_volume",
345
+ params={"track_index": "{track_index}"},
346
+ description="Level for subtle texture"),
347
+ ],
348
+ success_signals=["reverb tail as independent texture layer"],
349
+ failure_signals=["original transient still audible", "tail too thin"],
350
+ ))
351
+
352
+ # ── Category 3: Melodic/Harmonic ───────────────────────────────────
353
+
354
+ _register(SampleTechnique(
355
+ technique_id="key_matched_layer",
356
+ name="Key-Matched Layer",
357
+ philosophy="surgeon",
358
+ material_types=["instrument_loop"],
359
+ intents=["layer", "melody"],
360
+ difficulty="basic",
361
+ description="Transpose sample to match song key, layer behind existing elements",
362
+ inspiration="Seamless sample integration — should sound like it was always there",
363
+ steps=[
364
+ TechniqueStep(tool="load_sample_to_simpler",
365
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
366
+ description="Load into Simpler"),
367
+ TechniqueStep(tool="set_device_parameter",
368
+ params={"track_index": "{track_index}"},
369
+ description="Transpose to match song key (via Simpler transpose)"),
370
+ TechniqueStep(tool="find_and_load_device",
371
+ params={"track_index": "{track_index}", "device_name": "EQ Eight"},
372
+ description="Add EQ for frequency carving"),
373
+ TechniqueStep(tool="set_device_parameter",
374
+ params={"track_index": "{track_index}"},
375
+ description="Carve EQ to avoid masking existing elements"),
376
+ TechniqueStep(tool="set_track_volume",
377
+ params={"track_index": "{track_index}"},
378
+ description="Set volume -6 to -10dB behind existing layers"),
379
+ ],
380
+ success_signals=["sample blends with existing material", "no frequency masking"],
381
+ failure_signals=["key clash audible", "masking with other tracks"],
382
+ ))
383
+
384
+ _register(SampleTechnique(
385
+ technique_id="vocal_harmony_stack",
386
+ name="Vocal Harmony Stack",
387
+ philosophy="surgeon",
388
+ material_types=["vocal"],
389
+ intents=["vocal", "layer", "melody"],
390
+ difficulty="advanced",
391
+ description="Pitch-shift vocal to create harmony layers — Bon Iver 'Prismizer' approach",
392
+ inspiration="Bon Iver — vocoder + harmonizer stacked vocal textures",
393
+ steps=[
394
+ TechniqueStep(tool="load_sample_to_simpler",
395
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
396
+ description="Load vocal into Simpler"),
397
+ TechniqueStep(tool="duplicate_track",
398
+ params={"track_index": "{track_index}"},
399
+ description="Duplicate for harmony layer"),
400
+ TechniqueStep(tool="set_device_parameter",
401
+ params={"track_index": "{track_index}"},
402
+ description="Transpose duplicate +3, +5, or +7 semitones for harmony"),
403
+ TechniqueStep(tool="set_track_volume",
404
+ params={"track_index": "{track_index}"},
405
+ description="Blend harmony -4 to -6dB behind original"),
406
+ ],
407
+ success_signals=["harmonic vocal texture", "pitch layers blend"],
408
+ failure_signals=["robotic artifacts", "dissonant pitch choice"],
409
+ ))
410
+
411
+ _register(SampleTechnique(
412
+ technique_id="counterpoint_from_chops",
413
+ name="Counterpoint from Chops",
414
+ philosophy="alchemist",
415
+ material_types=["instrument_loop", "vocal", "full_mix"],
416
+ intents=["melody", "layer"],
417
+ difficulty="advanced",
418
+ description="Create a countermelody by rearranging melodic fragments from a chopped sample",
419
+ inspiration="Four Tet — found-sound countermelody, reorganized musical DNA",
420
+ steps=[
421
+ TechniqueStep(tool="load_sample_to_simpler",
422
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
423
+ description="Load melodic source"),
424
+ TechniqueStep(tool="set_simpler_playback_mode",
425
+ params={"track_index": "{track_index}", "device_index": 0,
426
+ "playback_mode": 2, "slice_by": 1},
427
+ description="Slice by Beat for melodic fragments"),
428
+ TechniqueStep(tool="get_simpler_slices",
429
+ params={"track_index": "{track_index}", "device_index": 0},
430
+ description="Read slice positions"),
431
+ TechniqueStep(tool="create_clip",
432
+ params={"track_index": "{track_index}", "clip_index": 0, "length": 8.0},
433
+ description="Create 2-bar clip for countermelody"),
434
+ TechniqueStep(tool="add_notes",
435
+ params={"track_index": "{track_index}", "clip_index": 0},
436
+ description="Program a melodic pattern from slice fragments"),
437
+ ],
438
+ success_signals=["new melody from existing fragments", "musical coherence"],
439
+ failure_signals=["random noise", "no melodic direction"],
440
+ ))
441
+
442
+ _register(SampleTechnique(
443
+ technique_id="chord_stab_extraction",
444
+ name="Chord Stab Extraction",
445
+ philosophy="surgeon",
446
+ material_types=["full_mix", "instrument_loop"],
447
+ intents=["melody", "rhythm"],
448
+ difficulty="intermediate",
449
+ description="Isolate chord hits from a full mix and retrigger them rhythmically",
450
+ inspiration="Classic house/disco sample flipping — one chord, infinite groove",
451
+ steps=[
452
+ TechniqueStep(tool="load_sample_to_simpler",
453
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
454
+ description="Load full mix into Simpler"),
455
+ TechniqueStep(tool="set_simpler_playback_mode",
456
+ params={"track_index": "{track_index}", "device_index": 0,
457
+ "playback_mode": 2, "slice_by": 0},
458
+ description="Slice by Transient"),
459
+ TechniqueStep(tool="crop_simpler",
460
+ params={"track_index": "{track_index}", "device_index": 0},
461
+ description="Crop to single chord region"),
462
+ TechniqueStep(tool="create_clip",
463
+ params={"track_index": "{track_index}", "clip_index": 0, "length": 4.0},
464
+ description="Create clip"),
465
+ TechniqueStep(tool="add_notes",
466
+ params={"track_index": "{track_index}", "clip_index": 0},
467
+ description="Rhythmic chord stab pattern"),
468
+ ],
469
+ success_signals=["clean chord stab playback", "groovy retrigger pattern"],
470
+ failure_signals=["stab includes drum bleed", "chord unclear"],
471
+ ))
472
+
473
+ # ── Category 4: Drum Enhancement ───────────────────────────────────
474
+
475
+ _register(SampleTechnique(
476
+ technique_id="break_layering",
477
+ name="Break Layering",
478
+ philosophy="surgeon",
479
+ material_types=["drum_loop"],
480
+ intents=["rhythm", "layer"],
481
+ difficulty="basic",
482
+ description="Layer a drum break underneath programmed drums for organic feel",
483
+ inspiration="Classic hip-hop/jungle layering — break under the beat",
484
+ steps=[
485
+ TechniqueStep(tool="load_sample_to_simpler",
486
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
487
+ description="Load break into Simpler"),
488
+ TechniqueStep(tool="warp_simpler",
489
+ params={"track_index": "{track_index}", "device_index": 0, "beats": 16},
490
+ description="Warp to 4 bars to match song tempo"),
491
+ TechniqueStep(tool="find_and_load_device",
492
+ params={"track_index": "{track_index}", "device_name": "EQ Eight"},
493
+ description="Add EQ for frequency carving"),
494
+ TechniqueStep(tool="set_device_parameter",
495
+ params={"track_index": "{track_index}"},
496
+ description="High-pass at 200-400Hz to avoid kick clash"),
497
+ TechniqueStep(tool="set_track_volume",
498
+ params={"track_index": "{track_index}"},
499
+ description="Set volume -10 to -15dB for subtle layer"),
500
+ ],
501
+ success_signals=["break adds organic texture under drums", "no low-end clash"],
502
+ failure_signals=["competing kick patterns", "break overpowers programmed drums"],
503
+ ))
504
+
505
+ _register(SampleTechnique(
506
+ technique_id="ghost_note_texture",
507
+ name="Ghost Note Texture",
508
+ philosophy="alchemist",
509
+ material_types=["drum_loop"],
510
+ intents=["rhythm", "texture"],
511
+ difficulty="intermediate",
512
+ description="Filter a drum loop heavily and layer at low volume for ghost-note texture",
513
+ inspiration="Ghost notes in jazz/funk — barely there, adds life",
514
+ steps=[
515
+ TechniqueStep(tool="load_sample_to_simpler",
516
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
517
+ description="Load loop into Simpler"),
518
+ TechniqueStep(tool="find_and_load_device",
519
+ params={"track_index": "{track_index}", "device_name": "Auto Filter"},
520
+ description="Add Auto Filter"),
521
+ TechniqueStep(tool="set_device_parameter",
522
+ params={"track_index": "{track_index}"},
523
+ description="Band-pass filter ~1-4kHz, narrow Q"),
524
+ TechniqueStep(tool="set_track_volume",
525
+ params={"track_index": "{track_index}"},
526
+ description="Set volume -18 to -24dB for ghost-level presence"),
527
+ ],
528
+ success_signals=["subtle rhythmic texture felt more than heard"],
529
+ failure_signals=["too loud", "filtering removes all useful content"],
530
+ ))
531
+
532
+ _register(SampleTechnique(
533
+ technique_id="transient_replacement",
534
+ name="Transient Replacement",
535
+ philosophy="surgeon",
536
+ material_types=["one_shot"],
537
+ intents=["rhythm", "layer"],
538
+ difficulty="basic",
539
+ description="Layer a one-shot transient over existing drums for punch/character",
540
+ inspiration="Drum layering for weight and impact",
541
+ steps=[
542
+ TechniqueStep(tool="load_sample_to_simpler",
543
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
544
+ description="Load one-shot into Simpler"),
545
+ TechniqueStep(tool="set_simpler_playback_mode",
546
+ params={"track_index": "{track_index}", "device_index": 0,
547
+ "playback_mode": 0},
548
+ description="Classic mode for one-shot playback"),
549
+ TechniqueStep(tool="create_clip",
550
+ params={"track_index": "{track_index}", "clip_index": 0, "length": 4.0},
551
+ description="Create clip"),
552
+ TechniqueStep(tool="add_notes",
553
+ params={"track_index": "{track_index}", "clip_index": 0},
554
+ description="Trigger on same hits as existing kick/snare"),
555
+ ],
556
+ success_signals=["added punch and character to drums"],
557
+ failure_signals=["phasing with original", "too much attack"],
558
+ ))
559
+
560
+ _register(SampleTechnique(
561
+ technique_id="shuffle_extract",
562
+ name="Shuffle Extract",
563
+ philosophy="alchemist",
564
+ material_types=["drum_loop"],
565
+ intents=["rhythm", "transform"],
566
+ difficulty="advanced",
567
+ description="Extract groove timing from a loop and apply it to programmed MIDI",
568
+ inspiration="Stealing the human feel from vinyl breaks",
569
+ steps=[
570
+ TechniqueStep(tool="load_sample_to_simpler",
571
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
572
+ description="Load break for groove analysis"),
573
+ TechniqueStep(tool="set_simpler_playback_mode",
574
+ params={"track_index": "{track_index}", "device_index": 0,
575
+ "playback_mode": 2, "slice_by": 0},
576
+ description="Slice by Transient to find hits"),
577
+ TechniqueStep(tool="get_simpler_slices",
578
+ params={"track_index": "{track_index}", "device_index": 0},
579
+ description="Read slice positions (these are the groove template)"),
580
+ ],
581
+ success_signals=["groove timing captured", "swing values extracted"],
582
+ failure_signals=["slice positions too irregular to use"],
583
+ ))
584
+
585
+ # ── Category 5: Vocal Processing ───────────────────────────────────
586
+
587
+ _register(SampleTechnique(
588
+ technique_id="syllable_instrument",
589
+ name="Syllable Instrument",
590
+ philosophy="alchemist",
591
+ material_types=["vocal"],
592
+ intents=["vocal", "rhythm", "melody"],
593
+ difficulty="advanced",
594
+ description="Chop vocal into individual syllables and play them as a melodic instrument",
595
+ inspiration="Vocal as instrument — each syllable is a playable note",
596
+ steps=[
597
+ TechniqueStep(tool="load_sample_to_simpler",
598
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
599
+ description="Load vocal into Simpler"),
600
+ TechniqueStep(tool="set_simpler_playback_mode",
601
+ params={"track_index": "{track_index}", "device_index": 0,
602
+ "playback_mode": 2, "slice_by": 2},
603
+ description="Slice by Region for syllable boundaries"),
604
+ TechniqueStep(tool="get_simpler_slices",
605
+ params={"track_index": "{track_index}", "device_index": 0},
606
+ description="Map slices to syllables"),
607
+ TechniqueStep(tool="create_clip",
608
+ params={"track_index": "{track_index}", "clip_index": 0, "length": 8.0},
609
+ description="Create 2-bar melodic clip"),
610
+ TechniqueStep(tool="add_notes",
611
+ params={"track_index": "{track_index}", "clip_index": 0},
612
+ description="Program melody using syllable slices as pitches"),
613
+ ],
614
+ success_signals=["vocal syllables form coherent melody"],
615
+ failure_signals=["syllables cut awkwardly", "no musical phrase"],
616
+ ))
617
+
618
+ _register(SampleTechnique(
619
+ technique_id="formant_shift_character",
620
+ name="Formant Shift Character",
621
+ philosophy="alchemist",
622
+ material_types=["vocal"],
623
+ intents=["vocal", "transform"],
624
+ difficulty="intermediate",
625
+ description="Shift vocal formants for alien/robotic/gender-shifted character",
626
+ inspiration="Vocal processing as character creation — not correction",
627
+ steps=[
628
+ TechniqueStep(tool="load_sample_to_simpler",
629
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
630
+ description="Load vocal into Simpler"),
631
+ TechniqueStep(tool="set_device_parameter",
632
+ params={"track_index": "{track_index}"},
633
+ description="Transpose +5 to +12 semitones (chipmunk) or -5 to -12 (deep)"),
634
+ TechniqueStep(tool="find_and_load_device",
635
+ params={"track_index": "{track_index}", "device_name": "Corpus"},
636
+ description="Add Corpus for resonant body character"),
637
+ ],
638
+ success_signals=["distinctive vocal character", "not obviously pitched"],
639
+ failure_signals=["robotic artifacts", "unintelligible"],
640
+ ))
641
+
642
+ _register(SampleTechnique(
643
+ technique_id="vocal_freeze_drone",
644
+ name="Vocal Freeze Drone",
645
+ philosophy="alchemist",
646
+ material_types=["vocal"],
647
+ intents=["texture", "atmosphere"],
648
+ difficulty="intermediate",
649
+ description="Sustain one vowel from a vocal as an ambient pad/drone",
650
+ inspiration="Freezing the human voice into pure tone",
651
+ steps=[
652
+ TechniqueStep(tool="load_sample_to_simpler",
653
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
654
+ description="Load vocal"),
655
+ TechniqueStep(tool="crop_simpler",
656
+ params={"track_index": "{track_index}", "device_index": 0},
657
+ description="Crop to a single vowel sound (100-300ms)"),
658
+ TechniqueStep(tool="warp_simpler",
659
+ params={"track_index": "{track_index}", "device_index": 0, "beats": 64},
660
+ description="Extreme stretch — vowel becomes drone"),
661
+ TechniqueStep(tool="find_and_load_device",
662
+ params={"track_index": "{track_index}", "device_name": "Chorus-Ensemble"},
663
+ description="Add chorus for width"),
664
+ TechniqueStep(tool="find_and_load_device",
665
+ params={"track_index": "{track_index}", "device_name": "Reverb"},
666
+ description="Add reverb for sustain"),
667
+ ],
668
+ success_signals=["sustained vocal drone", "ethereal pad quality"],
669
+ failure_signals=["pulsing from loop point", "harsh artifacts"],
670
+ ))
671
+
672
+ _register(SampleTechnique(
673
+ technique_id="phone_recording_texture",
674
+ name="Phone Recording Texture",
675
+ philosophy="alchemist",
676
+ material_types=["vocal", "foley"],
677
+ intents=["texture", "atmosphere"],
678
+ difficulty="basic",
679
+ description="Lo-fi vocal/field recording as ghostly background texture — Burial's signature",
680
+ inspiration="Burial — phone recordings, pitched down, barely audible ghosts",
681
+ steps=[
682
+ TechniqueStep(tool="load_sample_to_simpler",
683
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
684
+ description="Load recording into Simpler"),
685
+ TechniqueStep(tool="set_device_parameter",
686
+ params={"track_index": "{track_index}"},
687
+ description="Pitch down -5 to -12 semitones"),
688
+ TechniqueStep(tool="find_and_load_device",
689
+ params={"track_index": "{track_index}", "device_name": "Auto Filter"},
690
+ description="Add lo-pass filter"),
691
+ TechniqueStep(tool="set_device_parameter",
692
+ params={"track_index": "{track_index}"},
693
+ description="Filter cutoff ~800Hz for lo-fi character"),
694
+ TechniqueStep(tool="set_track_volume",
695
+ params={"track_index": "{track_index}"},
696
+ description="Set volume -20 to -30dB — ghost level"),
697
+ ],
698
+ success_signals=["barely audible presence", "adds emotional depth"],
699
+ failure_signals=["too prominent", "distracting from main elements"],
700
+ ))
701
+
702
+ # ── Category 6: Resampling Chains ──────────────────────────────────
703
+
704
+ _register(SampleTechnique(
705
+ technique_id="serial_resample",
706
+ name="Serial Resample",
707
+ philosophy="alchemist",
708
+ material_types=["vocal", "drum_loop", "instrument_loop", "one_shot", "texture", "full_mix"],
709
+ intents=["transform", "texture"],
710
+ difficulty="advanced",
711
+ description="Multi-pass destructive resampling — each pass adds character until unrecognizable",
712
+ inspiration="Amon Tobin — 80+ samples per track, serial destruction",
713
+ steps=[
714
+ TechniqueStep(tool="load_sample_to_simpler",
715
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
716
+ description="Load source material"),
717
+ TechniqueStep(tool="find_and_load_device",
718
+ params={"track_index": "{track_index}", "device_name": "Saturator"},
719
+ description="Add Saturator for harmonic destruction"),
720
+ TechniqueStep(tool="find_and_load_device",
721
+ params={"track_index": "{track_index}", "device_name": "Grain Delay"},
722
+ description="Add Grain Delay for fragmentation"),
723
+ TechniqueStep(tool="find_and_load_device",
724
+ params={"track_index": "{track_index}", "device_name": "Reverb"},
725
+ description="Add reverb for smearing"),
726
+ TechniqueStep(tool="freeze_track",
727
+ params={"track_index": "{track_index}"},
728
+ description="Freeze to capture processed result"),
729
+ TechniqueStep(tool="flatten_track",
730
+ params={"track_index": "{track_index}"},
731
+ description="Flatten — new audio is now the source for next pass"),
732
+ ],
733
+ success_signals=["material transformed beyond recognition", "new texture"],
734
+ failure_signals=["just sounds distorted", "lost all musical quality"],
735
+ ))
736
+
737
+ _register(SampleTechnique(
738
+ technique_id="parallel_resample",
739
+ name="Parallel Resample",
740
+ philosophy="alchemist",
741
+ material_types=["vocal", "instrument_loop", "drum_loop"],
742
+ intents=["transform", "layer"],
743
+ difficulty="intermediate",
744
+ description="Process through parallel effect chains and blend for controlled destruction",
745
+ inspiration="Wet/dry parallel processing for controlled chaos",
746
+ steps=[
747
+ TechniqueStep(tool="load_sample_to_simpler",
748
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
749
+ description="Load into Simpler"),
750
+ TechniqueStep(tool="duplicate_track",
751
+ params={"track_index": "{track_index}"},
752
+ description="Duplicate for parallel processing"),
753
+ TechniqueStep(tool="find_and_load_device",
754
+ params={"track_index": "{track_index}"},
755
+ description="Add destructive effects to duplicate (distortion, pitch shift)"),
756
+ TechniqueStep(tool="set_track_volume",
757
+ params={"track_index": "{track_index}"},
758
+ description="Blend wet/dry: original at 0dB, processed at -6 to -12dB"),
759
+ ],
760
+ success_signals=["controlled textural blend", "best of both worlds"],
761
+ failure_signals=["phase issues between copies", "processed too dominant"],
762
+ ))
763
+
764
+ _register(SampleTechnique(
765
+ technique_id="freeze_flatten_rechop",
766
+ name="Freeze-Flatten-Rechop",
767
+ philosophy="alchemist",
768
+ material_types=["vocal", "instrument_loop", "drum_loop", "texture"],
769
+ intents=["transform", "rhythm"],
770
+ difficulty="advanced",
771
+ description="Freeze processed material, flatten to audio, then re-slice the result",
772
+ inspiration="Recursive destruction — chop the chop",
773
+ steps=[
774
+ TechniqueStep(tool="freeze_track",
775
+ params={"track_index": "{track_index}"},
776
+ description="Freeze current state to audio"),
777
+ TechniqueStep(tool="flatten_track",
778
+ params={"track_index": "{track_index}"},
779
+ description="Flatten to new audio clip"),
780
+ TechniqueStep(tool="load_sample_to_simpler",
781
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
782
+ description="Load flattened audio back into Simpler"),
783
+ TechniqueStep(tool="set_simpler_playback_mode",
784
+ params={"track_index": "{track_index}", "device_index": 0,
785
+ "playback_mode": 2, "slice_by": 0},
786
+ description="Re-slice the processed material"),
787
+ TechniqueStep(tool="get_simpler_slices",
788
+ params={"track_index": "{track_index}", "device_index": 0},
789
+ description="Read new slice positions"),
790
+ ],
791
+ success_signals=["new rhythmic material from processed audio"],
792
+ failure_signals=["silence after flatten", "no useful slice points"],
793
+ ))
794
+
795
+ # ── Category 7: Creative Constraints ───────────────────────────────
796
+
797
+ _register(SampleTechnique(
798
+ technique_id="one_sample_challenge",
799
+ name="One-Sample Challenge",
800
+ philosophy="alchemist",
801
+ material_types=["vocal", "drum_loop", "instrument_loop", "full_mix", "texture", "foley"],
802
+ intents=["challenge", "transform"],
803
+ difficulty="advanced",
804
+ description="Build an entire beat from a single sample — kick, snare, hat, bass, pad all extracted",
805
+ inspiration="One-sample challenge — constraint breeds creativity",
806
+ steps=[
807
+ TechniqueStep(tool="load_sample_to_simpler",
808
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
809
+ description="Load the ONE sample"),
810
+ TechniqueStep(tool="set_simpler_playback_mode",
811
+ params={"track_index": "{track_index}", "device_index": 0,
812
+ "playback_mode": 2, "slice_by": 0},
813
+ description="Slice by Transient"),
814
+ TechniqueStep(tool="get_simpler_slices",
815
+ params={"track_index": "{track_index}", "device_index": 0},
816
+ description="Map all available slices"),
817
+ TechniqueStep(tool="create_clip",
818
+ params={"track_index": "{track_index}", "clip_index": 0, "length": 8.0},
819
+ description="Create 2-bar clip"),
820
+ TechniqueStep(tool="add_notes",
821
+ params={"track_index": "{track_index}", "clip_index": 0},
822
+ description="Program full beat using different slices as different drums"),
823
+ ],
824
+ success_signals=["full beat from single source", "each element distinct"],
825
+ failure_signals=["sounds monochromatic", "elements too similar"],
826
+ ))
827
+
828
+ _register(SampleTechnique(
829
+ technique_id="found_sound_only",
830
+ name="Found Sound Only",
831
+ philosophy="alchemist",
832
+ material_types=["foley"],
833
+ intents=["challenge", "texture", "rhythm"],
834
+ difficulty="advanced",
835
+ description="Use only non-musical field recordings to build a musical composition",
836
+ inspiration="Musique concrete — all music is organized sound",
837
+ steps=[
838
+ TechniqueStep(tool="load_sample_to_simpler",
839
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
840
+ description="Load found sound"),
841
+ TechniqueStep(tool="set_simpler_playback_mode",
842
+ params={"track_index": "{track_index}", "device_index": 0,
843
+ "playback_mode": 2, "slice_by": 0},
844
+ description="Slice for rhythmic extraction"),
845
+ TechniqueStep(tool="find_and_load_device",
846
+ params={"track_index": "{track_index}", "device_name": "EQ Eight"},
847
+ description="EQ to isolate musical frequencies"),
848
+ ],
849
+ success_signals=["non-musical source produces musical result"],
850
+ failure_signals=["just sounds like noise", "no rhythmic or tonal quality"],
851
+ ))
852
+
853
+ _register(SampleTechnique(
854
+ technique_id="reverse_engineering",
855
+ name="Reverse Engineering",
856
+ philosophy="both",
857
+ material_types=["full_mix"],
858
+ intents=["challenge", "layer"],
859
+ difficulty="advanced",
860
+ description="Recreate a reference track's texture by sampling and transforming similar elements",
861
+ inspiration="Reverse engineering a sound — forensic production",
862
+ steps=[
863
+ TechniqueStep(tool="load_sample_to_simpler",
864
+ params={"track_index": "{track_index}", "file_path": "{file_path}"},
865
+ description="Load reference material"),
866
+ TechniqueStep(tool="set_simpler_playback_mode",
867
+ params={"track_index": "{track_index}", "device_index": 0,
868
+ "playback_mode": 2, "slice_by": 1},
869
+ description="Slice by Beat to isolate sections"),
870
+ TechniqueStep(tool="get_simpler_slices",
871
+ params={"track_index": "{track_index}", "device_index": 0},
872
+ description="Analyze structure via slices"),
873
+ ],
874
+ success_signals=["captured essence of reference sound"],
875
+ failure_signals=["just copied rather than recreated"],
876
+ ))
877
+
878
+
879
+ # ── Public API ──────────────────────────────────────────────────────
880
+
881
+
882
+ def get_technique(technique_id: str) -> SampleTechnique | None:
883
+ """Get a technique by ID."""
884
+ return _CATALOG.get(technique_id)
885
+
886
+
887
+ def list_techniques() -> list[SampleTechnique]:
888
+ """Return all registered techniques."""
889
+ return list(_CATALOG.values())
890
+
891
+
892
+ def find_techniques(
893
+ material_type: str | None = None,
894
+ intent: str | None = None,
895
+ philosophy: str | None = None,
896
+ ) -> list[SampleTechnique]:
897
+ """Find techniques matching filters. All filters are AND'd."""
898
+ results = list(_CATALOG.values())
899
+
900
+ if material_type:
901
+ results = [t for t in results if material_type in t.material_types]
902
+ if intent:
903
+ results = [t for t in results if intent in t.intents]
904
+ if philosophy:
905
+ results = [t for t in results
906
+ if t.philosophy == philosophy or t.philosophy == "both"]
907
+
908
+ return results