prompt_objects 0.6.0 → 0.7.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +126 -0
- data/README.md +93 -22
- data/exe/poop +5 -0
- data/exe/prompt_objects +1 -1108
- data/exe/prompt_objects_mcp +5 -3
- data/lib/prompt_objects/capability.rb +33 -0
- data/lib/prompt_objects/cli/diagnostics_command.rb +69 -0
- data/lib/prompt_objects/cli/env_command.rb +435 -0
- data/lib/prompt_objects/cli/events_command.rb +145 -0
- data/lib/prompt_objects/cli/explore_command.rb +155 -0
- data/lib/prompt_objects/cli/helpers.rb +91 -0
- data/lib/prompt_objects/cli/message_command.rb +216 -0
- data/lib/prompt_objects/cli/repl_command.rb +366 -0
- data/lib/prompt_objects/cli/serve_command.rb +162 -0
- data/lib/prompt_objects/cli.rb +64 -422
- data/lib/prompt_objects/connectors/base.rb +16 -29
- data/lib/prompt_objects/connectors/mcp.rb +82 -98
- data/lib/prompt_objects/domain/records.rb +45 -0
- data/lib/prompt_objects/environment/exporter.rb +5 -4
- data/lib/prompt_objects/environment/git.rb +21 -1
- data/lib/prompt_objects/environment/importer.rb +5 -4
- data/lib/prompt_objects/environment/manager.rb +44 -6
- data/lib/prompt_objects/environment/manifest.rb +26 -4
- data/lib/prompt_objects/environment.rb +1337 -20
- data/lib/prompt_objects/execution/blocking_executor.rb +88 -0
- data/lib/prompt_objects/execution/context.rb +137 -0
- data/lib/prompt_objects/execution/contracts.rb +59 -0
- data/lib/prompt_objects/execution/permit_pool.rb +49 -0
- data/lib/prompt_objects/execution/policy.rb +47 -0
- data/lib/prompt_objects/execution/resource_lock_manager.rb +63 -0
- data/lib/prompt_objects/execution/runner.rb +498 -0
- data/lib/prompt_objects/execution/scheduler.rb +325 -0
- data/lib/prompt_objects/llm/factory.rb +4 -4
- data/lib/prompt_objects/llm/gemini_adapter.rb +25 -8
- data/lib/prompt_objects/llm/openai_adapter.rb +9 -1
- data/lib/prompt_objects/llm/pricing.rb +9 -2
- data/lib/prompt_objects/llm/response.rb +9 -4
- data/lib/prompt_objects/loader.rb +28 -1
- data/lib/prompt_objects/mcp/server.rb +6 -3
- data/lib/prompt_objects/mcp/tools/get_conversation.rb +15 -11
- data/lib/prompt_objects/mcp/tools/get_pending_requests.rb +2 -2
- data/lib/prompt_objects/mcp/tools/respond_to_request.rb +3 -3
- data/lib/prompt_objects/mcp/tools/send_message.rb +42 -32
- data/lib/prompt_objects/operations/diagnostics.rb +115 -0
- data/lib/prompt_objects/operations/retention.rb +75 -0
- data/lib/prompt_objects/operations/run_trace_builder.rb +152 -0
- data/lib/prompt_objects/primitives/http_get.rb +2 -0
- data/lib/prompt_objects/primitives/list_files.rb +2 -0
- data/lib/prompt_objects/primitives/read_file.rb +2 -0
- data/lib/prompt_objects/primitives/think.rb +36 -0
- data/lib/prompt_objects/primitives/write_file.rb +9 -0
- data/lib/prompt_objects/prompt_object.rb +171 -519
- data/lib/prompt_objects/repositories/artifact_repository.rb +109 -0
- data/lib/prompt_objects/repositories/base_repository.rb +37 -0
- data/lib/prompt_objects/repositories/definition_repository.rb +36 -0
- data/lib/prompt_objects/repositories/env_data_repository.rb +103 -0
- data/lib/prompt_objects/repositories/event_repository.rb +105 -0
- data/lib/prompt_objects/repositories/message_repository.rb +73 -0
- data/lib/prompt_objects/repositories/run_repository.rb +254 -0
- data/lib/prompt_objects/repositories/thread_repository.rb +87 -0
- data/lib/prompt_objects/repositories/tool_execution_repository.rb +88 -0
- data/lib/prompt_objects/repositories/workspace_session_repository.rb +61 -0
- data/lib/prompt_objects/server/api/routes.rb +549 -53
- data/lib/prompt_objects/server/app.rb +133 -14
- data/lib/prompt_objects/server/file_watcher.rb +9 -0
- data/lib/prompt_objects/server/public/assets/index-BjKlODDD.js +90 -0
- data/lib/prompt_objects/server/public/assets/index-w3fpIb5c.css +1 -0
- data/lib/prompt_objects/server/public/index.html +2 -2
- data/lib/prompt_objects/server/websocket_handler.rb +202 -227
- data/lib/prompt_objects/server.rb +170 -1
- data/lib/prompt_objects/service.rb +129 -0
- data/lib/prompt_objects/session/store.rb +600 -13
- data/lib/prompt_objects/universal/add_capability.rb +1 -1
- data/lib/prompt_objects/universal/create_capability.rb +4 -2
- data/lib/prompt_objects/universal/delete_env_data.rb +23 -15
- data/lib/prompt_objects/universal/delete_primitive.rb +1 -1
- data/lib/prompt_objects/universal/dispatch_po.rb +54 -0
- data/lib/prompt_objects/universal/get_env_data.rb +8 -14
- data/lib/prompt_objects/universal/get_run_status.rb +30 -0
- data/lib/prompt_objects/universal/join_runs.rb +35 -0
- data/lib/prompt_objects/universal/list_env_data.rb +10 -14
- data/lib/prompt_objects/universal/modify_primitive.rb +1 -1
- data/lib/prompt_objects/universal/render_artifact.rb +91 -0
- data/lib/prompt_objects/universal/request_primitive.rb +1 -1
- data/lib/prompt_objects/universal/{store_env_data.rb → set_env_data.rb} +34 -20
- data/lib/prompt_objects/version.rb +5 -0
- data/lib/prompt_objects.rb +33 -8
- data/objects/coordinator.md +8 -4
- data/templates/arc-agi-1/objects/data_manager.md +2 -2
- data/templates/arc-agi-1/objects/observer.md +2 -2
- data/templates/arc-agi-1/objects/solver.md +6 -5
- data/templates/arc-agi-1/objects/verifier.md +2 -2
- data/templates/arc-agi-3/manifest.yml +19 -0
- data/templates/arc-agi-3/objects/analyst.md +79 -0
- data/templates/arc-agi-3/objects/player.md +76 -0
- data/templates/arc-agi-3/objects/strategist.md +97 -0
- data/templates/arc-agi-3/primitives/action_log.rb +133 -0
- data/templates/arc-agi-3/primitives/arc3_api.rb +223 -0
- data/templates/arc-agi-3/primitives/arc3_scorecard.rb +131 -0
- data/templates/arc-agi-3/primitives/frame_diff.rb +143 -0
- data/templates/arc-agi-3/primitives/frame_info.rb +96 -0
- data/templates/arc-agi-3/primitives/render_frame.rb +140 -0
- data/templates/basic/objects/basic.md +11 -3
- data/templates/chiptune/extras/sonic_pi_boot.rb +220 -0
- data/templates/chiptune/manifest.yml +20 -0
- data/templates/chiptune/objects/conductor.md +184 -0
- data/templates/chiptune/objects/sonic_pi.md +65 -0
- data/templates/chiptune/objects/voice_bass.md +44 -0
- data/templates/chiptune/objects/voice_lead.md +44 -0
- data/templates/chiptune/objects/voice_pad.md +43 -0
- data/templates/chiptune/objects/voice_perc.md +45 -0
- data/templates/chiptune/primitives/play_note.rb +59 -0
- data/templates/chiptune/primitives/play_sequence.rb +55 -0
- data/templates/chiptune/primitives/query_sonic_pi.rb +141 -0
- data/templates/chiptune/primitives/set_synth.rb +57 -0
- data/templates/chiptune/primitives/set_tempo.rb +45 -0
- data/templates/chiptune/primitives/stop_voice.rb +46 -0
- data/templates/chiptune/primitives/support/osc_bridge.rb +33 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/LICENSE +19 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
- data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
- data/templates/developer/objects/code_reviewer.md +1 -1
- data/templates/developer/objects/coordinator.md +16 -3
- data/templates/developer/objects/debugger.md +3 -3
- data/templates/empty/objects/assistant.md +10 -5
- data/templates/minimal/objects/assistant.md +10 -5
- data/templates/music/extras/sonic_pi_boot.rb +220 -0
- data/templates/music/manifest.yml +16 -0
- data/templates/music/objects/conductor.md +154 -0
- data/templates/music/objects/sonic_pi.md +65 -0
- data/templates/music/primitives/play_note.rb +55 -0
- data/templates/music/primitives/play_sequence.rb +51 -0
- data/templates/music/primitives/query_sonic_pi.rb +139 -0
- data/templates/music/primitives/set_synth.rb +53 -0
- data/templates/music/primitives/set_tempo.rb +43 -0
- data/templates/music/primitives/stop_voice.rb +44 -0
- data/templates/music/primitives/support/osc_bridge.rb +33 -0
- data/templates/music/vendor/osc-ruby-1.1.5/LICENSE +19 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
- data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
- data/templates/music-beginner/README.md +100 -0
- data/templates/music-beginner/extras/README.md +27 -0
- data/templates/music-beginner/extras/sonic_pi_boot.rb +297 -0
- data/templates/music-beginner/manifest.yml +25 -0
- data/templates/music-beginner/objects/conductor.md +222 -0
- data/templates/music-beginner/objects/engine_setup.md +54 -0
- data/templates/music-beginner/objects/voice_bass.md +43 -0
- data/templates/music-beginner/objects/voice_keys.md +48 -0
- data/templates/music-beginner/objects/voice_pad.md +46 -0
- data/templates/music-beginner/objects/voice_percussion.md +45 -0
- data/templates/music-beginner/objects/voice_texture.md +37 -0
- data/templates/music-beginner/primitives/play_pattern.rb +118 -0
- data/templates/music-beginner/primitives/query_music_engine.rb +94 -0
- data/templates/music-beginner/primitives/set_instrument.rb +47 -0
- data/templates/music-beginner/primitives/set_tempo.rb +43 -0
- data/templates/music-beginner/primitives/set_voice_level.rb +46 -0
- data/templates/music-beginner/primitives/stop_voice.rb +37 -0
- data/templates/music-beginner/primitives/support/osc_bridge.rb +25 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/LICENSE +19 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
- data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
- data/templates/music-pro/extras/AUDITION.md +100 -0
- data/templates/music-pro/extras/sonic_pi_boot.rb +546 -0
- data/templates/music-pro/manifest.yml +19 -0
- data/templates/music-pro/objects/conductor.md +126 -0
- data/templates/music-pro/objects/sonic_pi.md +35 -0
- data/templates/music-pro/objects/voice_harmony.md +48 -0
- data/templates/music-pro/objects/voice_rhythm.md +43 -0
- data/templates/music-pro/objects/voice_texture.md +42 -0
- data/templates/music-pro/primitives/define_patch.rb +46 -0
- data/templates/music-pro/primitives/query_music_engine.rb +69 -0
- data/templates/music-pro/primitives/set_live_pattern.rb +70 -0
- data/templates/music-pro/primitives/set_tempo.rb +31 -0
- data/templates/music-pro/primitives/stop_voice.rb +31 -0
- data/templates/music-pro/primitives/support/music_protocol.rb +136 -0
- data/templates/music-pro/primitives/support/osc_bridge.rb +33 -0
- data/templates/music-pro/primitives/trigger_event.rb +44 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/LICENSE +19 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
- data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
- data/templates/writer/objects/coordinator.md +14 -3
- data/templates/writer/objects/editor.md +1 -1
- data/templates/writer/objects/researcher.md +2 -2
- data/tools/thread-explorer.html +1 -1
- metadata +172 -65
- data/CLAUDE.md +0 -177
- data/Gemfile +0 -10
- data/Rakefile +0 -27
- data/frontend/.gitignore +0 -3
- data/frontend/index.html +0 -17
- data/frontend/package-lock.json +0 -4540
- data/frontend/package.json +0 -36
- data/frontend/postcss.config.js +0 -6
- data/frontend/src/App.tsx +0 -104
- data/frontend/src/canvas/CanvasView.tsx +0 -113
- data/frontend/src/canvas/ForceLayout.ts +0 -115
- data/frontend/src/canvas/SceneManager.ts +0 -587
- data/frontend/src/canvas/canvasStore.ts +0 -47
- data/frontend/src/canvas/constants.ts +0 -95
- data/frontend/src/canvas/controls/CameraControls.ts +0 -98
- data/frontend/src/canvas/edges/MessageArc.ts +0 -149
- data/frontend/src/canvas/inspector/InspectorPanel.tsx +0 -31
- data/frontend/src/canvas/inspector/POInspector.tsx +0 -262
- data/frontend/src/canvas/inspector/ToolCallInspector.tsx +0 -67
- data/frontend/src/canvas/nodes/PONode.ts +0 -249
- data/frontend/src/canvas/nodes/ToolCallNode.ts +0 -116
- data/frontend/src/canvas/types.ts +0 -24
- data/frontend/src/components/ContextMenu.tsx +0 -68
- data/frontend/src/components/EnvDataPane.tsx +0 -69
- data/frontend/src/components/Inspector.tsx +0 -263
- data/frontend/src/components/MarkdownMessage.tsx +0 -155
- data/frontend/src/components/MethodList.tsx +0 -90
- data/frontend/src/components/ModelSelector.tsx +0 -115
- data/frontend/src/components/NotificationPanel.tsx +0 -130
- data/frontend/src/components/ObjectList.tsx +0 -78
- data/frontend/src/components/PaneSlot.tsx +0 -30
- data/frontend/src/components/SourcePane.tsx +0 -202
- data/frontend/src/components/SystemBar.tsx +0 -74
- data/frontend/src/components/Transcript.tsx +0 -76
- data/frontend/src/components/UsagePanel.tsx +0 -105
- data/frontend/src/components/Workspace.tsx +0 -260
- data/frontend/src/components/index.ts +0 -12
- data/frontend/src/hooks/useResize.ts +0 -55
- data/frontend/src/hooks/useWebSocket.ts +0 -559
- data/frontend/src/index.css +0 -102
- data/frontend/src/main.tsx +0 -10
- data/frontend/src/store/index.ts +0 -311
- data/frontend/src/types/index.ts +0 -176
- data/frontend/tailwind.config.js +0 -44
- data/frontend/tsconfig.json +0 -30
- data/frontend/vite.config.ts +0 -29
- data/lib/prompt_objects/server/public/assets/index-DEPawnfZ.js +0 -4345
- data/lib/prompt_objects/server/public/assets/index-oMrRce1m.css +0 -1
- data/lib/prompt_objects/universal/add_primitive.rb +0 -118
- data/lib/prompt_objects/universal/ask_human.rb +0 -109
- data/lib/prompt_objects/universal/create_primitive.rb +0 -174
- data/lib/prompt_objects/universal/list_primitives.rb +0 -145
- data/lib/prompt_objects/universal/think.rb +0 -41
- data/lib/prompt_objects/universal/update_env_data.rb +0 -88
- data/prompt_objects.gemspec +0 -50
- data/templates/basic/.gitignore +0 -2
- data/templates/developer/.gitignore +0 -5
- data/templates/empty/.gitignore +0 -5
- data/templates/empty/objects/.gitkeep +0 -0
- data/templates/minimal/.gitignore +0 -5
- data/templates/writer/.gitignore +0 -5
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# Prompt Objects Music Beginner — Sonic Pi live engine.
|
|
2
|
+
# Load from a Sonic Pi buffer with one line:
|
|
3
|
+
# run_file "/ABSOLUTE/PATH/TO/ENVIRONMENT/extras/sonic_pi_boot.rb"
|
|
4
|
+
|
|
5
|
+
use_bpm 72
|
|
6
|
+
set :music_bpm, 72
|
|
7
|
+
set :music_beats_per_bar, 4.0
|
|
8
|
+
set :music_voice_map, {}
|
|
9
|
+
set :music_next_slot, 0
|
|
10
|
+
set :music_max_slots, 8
|
|
11
|
+
|
|
12
|
+
8.times do |i|
|
|
13
|
+
set :"music_v#{i}_name", nil
|
|
14
|
+
set :"music_v#{i}_active", false
|
|
15
|
+
set :"music_v#{i}_instrument", "soft_keys"
|
|
16
|
+
set :"music_v#{i}_level", 0.65
|
|
17
|
+
set :"music_v#{i}_pattern", "R@4"
|
|
18
|
+
set :"music_v#{i}_pending_pattern", nil
|
|
19
|
+
set :"music_v#{i}_pending_instrument", nil
|
|
20
|
+
set :"music_v#{i}_pending_stop", false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
define :music_clamp do |value, low, high|
|
|
24
|
+
v = value.to_f
|
|
25
|
+
v = low if v < low
|
|
26
|
+
v = high if v > high
|
|
27
|
+
v
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
define :music_resolve_note do |value|
|
|
31
|
+
text = value.to_s.strip
|
|
32
|
+
result = if text.match?(/^\d+$/)
|
|
33
|
+
text.to_i
|
|
34
|
+
else
|
|
35
|
+
note(text.to_sym)
|
|
36
|
+
end
|
|
37
|
+
music_clamp(result, 21, 108)
|
|
38
|
+
rescue
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
define :music_voice_slot do |name|
|
|
43
|
+
key = name.to_s
|
|
44
|
+
voice_map = get(:music_voice_map)
|
|
45
|
+
return voice_map[key] if voice_map[key]
|
|
46
|
+
|
|
47
|
+
index = get(:music_next_slot)
|
|
48
|
+
if index >= get(:music_max_slots)
|
|
49
|
+
puts "MUSIC WARNING: all voice slots are occupied; ignored '#{key}'"
|
|
50
|
+
return nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
updated = {}
|
|
54
|
+
voice_map.each { |existing_name, slot| updated[existing_name] = slot } if voice_map
|
|
55
|
+
updated[key] = index
|
|
56
|
+
set :music_voice_map, updated
|
|
57
|
+
set :music_next_slot, index + 1
|
|
58
|
+
set :"music_v#{index}_name", key
|
|
59
|
+
default_instrument = case key
|
|
60
|
+
when "pad" then "air_pad"
|
|
61
|
+
when "bass" then "warm_bass"
|
|
62
|
+
when "percussion" then "gentle_kit"
|
|
63
|
+
when "texture" then "sine_glow"
|
|
64
|
+
else "soft_keys"
|
|
65
|
+
end
|
|
66
|
+
set :"music_v#{index}_instrument", default_instrument
|
|
67
|
+
puts "MUSIC: registered '#{key}' as voice #{index}"
|
|
68
|
+
index
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
define :music_parse_event do |raw|
|
|
72
|
+
fields = raw.to_s.strip.split("@")
|
|
73
|
+
sound = fields[0].to_s.strip
|
|
74
|
+
duration = music_clamp(fields[1] || 1.0, 0.125, 16.0)
|
|
75
|
+
event_amp = music_clamp(fields[2] || 0.7, 0.0, 1.0)
|
|
76
|
+
gate = music_clamp(fields[3] || duration, 0.05, 16.0)
|
|
77
|
+
[sound, duration, event_amp, gate]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
define :music_notes do |sound|
|
|
81
|
+
sound.to_s.split("+").map { |candidate| music_resolve_note(candidate) }.compact
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Percussion is sample-based, so a kit pattern can alternate real drum timbres.
|
|
85
|
+
define :music_play_drum do |sound, event_amp, voice_level|
|
|
86
|
+
strength = music_clamp(event_amp, 0.0, 1.0) * music_clamp(voice_level, 0.0, 1.0)
|
|
87
|
+
case sound.to_s.downcase
|
|
88
|
+
when "kick"
|
|
89
|
+
sample :bd_haus, amp: 0.34 * strength, pan: 0
|
|
90
|
+
when "hat"
|
|
91
|
+
sample :drum_cymbal_closed, amp: 0.13 * strength, pan: 0.18, finish: 0.22
|
|
92
|
+
when "snare"
|
|
93
|
+
sample :sn_dolf, amp: 0.16 * strength, pan: -0.08, finish: 0.32
|
|
94
|
+
when "tick"
|
|
95
|
+
sample :elec_tick, amp: 0.1 * strength, pan: 0.22
|
|
96
|
+
else
|
|
97
|
+
puts "MUSIC WARNING: gentle_kit ignored unknown token '#{sound}'"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Presets are complete, level-matched patches. Per-event amp and voice level
|
|
102
|
+
# scale these conservative baked gains but cannot bypass them.
|
|
103
|
+
define :music_play_instrument do |instrument, notes, gate, event_amp, voice_level|
|
|
104
|
+
strength = music_clamp(event_amp, 0.0, 1.0) * music_clamp(voice_level, 0.0, 1.0)
|
|
105
|
+
return if notes.empty? || strength <= 0
|
|
106
|
+
|
|
107
|
+
case instrument.to_s
|
|
108
|
+
when "soft_keys"
|
|
109
|
+
with_fx :reverb, room: 0.55, mix: 0.14 do
|
|
110
|
+
use_synth :rodeo
|
|
111
|
+
# :rodeo has its own natural electric-piano envelope and does not accept
|
|
112
|
+
# the standard ADSR/cutoff options.
|
|
113
|
+
play_chord notes, amp: 0.24 * strength, pan: -0.08
|
|
114
|
+
end
|
|
115
|
+
when "air_pad"
|
|
116
|
+
with_fx :reverb, room: 0.82, mix: 0.28 do
|
|
117
|
+
use_synth :blade
|
|
118
|
+
attack_time = gate < 2 ? gate * 0.2 : 0.55
|
|
119
|
+
play_chord notes, attack: attack_time, sustain: gate * 0.72, release: gate * 0.45,
|
|
120
|
+
cutoff: 68, vibrato_depth: 0.08, amp: 0.15 * strength, pan: 0.06
|
|
121
|
+
end
|
|
122
|
+
when "warm_bass"
|
|
123
|
+
use_synth :bass_foundation
|
|
124
|
+
play notes.first, attack: 0.015, sustain: gate * 0.72, release: gate * 0.22,
|
|
125
|
+
cutoff: 66, amp: 0.27 * strength, pan: 0
|
|
126
|
+
when "felt_pluck"
|
|
127
|
+
with_fx :reverb, room: 0.48, mix: 0.12 do
|
|
128
|
+
use_synth :kalimba
|
|
129
|
+
play_chord notes, amp: 0.2 * strength, pan: -0.14
|
|
130
|
+
end
|
|
131
|
+
when "glass_bell"
|
|
132
|
+
with_fx :echo, phase: 0.375, decay: 1.5, mix: 0.08 do
|
|
133
|
+
with_fx :reverb, room: 0.65, mix: 0.2 do
|
|
134
|
+
use_synth :pretty_bell
|
|
135
|
+
play_chord notes, attack: 0.01, sustain: 0.05, release: gate * 0.8,
|
|
136
|
+
amp: 0.13 * strength, pan: 0.16
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
when "sine_glow"
|
|
140
|
+
with_fx :reverb, room: 0.72, mix: 0.22 do
|
|
141
|
+
use_synth :sine
|
|
142
|
+
play_chord notes, attack: 0.2, sustain: gate * 0.62, release: gate * 0.4,
|
|
143
|
+
amp: 0.12 * strength, pan: 0.12
|
|
144
|
+
end
|
|
145
|
+
else
|
|
146
|
+
puts "MUSIC WARNING: ignored unknown instrument '#{instrument}'"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
define :music_apply_pending do |index|
|
|
151
|
+
pending_instrument = get(:"music_v#{index}_pending_instrument")
|
|
152
|
+
if pending_instrument
|
|
153
|
+
set :"music_v#{index}_instrument", pending_instrument
|
|
154
|
+
set :"music_v#{index}_pending_instrument", nil
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
pending_pattern = get(:"music_v#{index}_pending_pattern")
|
|
158
|
+
if pending_pattern
|
|
159
|
+
set :"music_v#{index}_pattern", pending_pattern
|
|
160
|
+
set :"music_v#{index}_pending_pattern", nil
|
|
161
|
+
set :"music_v#{index}_active", true
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
if get(:"music_v#{index}_pending_stop")
|
|
165
|
+
set :"music_v#{index}_active", false
|
|
166
|
+
set :"music_v#{index}_pending_stop", false
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
live_loop :music_bar_clock do
|
|
171
|
+
use_bpm get(:music_bpm)
|
|
172
|
+
sleep get(:music_beats_per_bar)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# All voices enter on the same bar cue. Each pattern is padded to a whole bar,
|
|
176
|
+
# so replacements happen at musically safe, synchronized boundaries.
|
|
177
|
+
with_fx :compressor, mix: 1 do
|
|
178
|
+
8.times do |i|
|
|
179
|
+
live_loop :"music_voice_#{i}" do
|
|
180
|
+
sync :music_bar_clock
|
|
181
|
+
loop do
|
|
182
|
+
use_bpm get(:music_bpm)
|
|
183
|
+
music_apply_pending(i)
|
|
184
|
+
|
|
185
|
+
if get(:"music_v#{i}_active")
|
|
186
|
+
instrument = get(:"music_v#{i}_instrument")
|
|
187
|
+
voice_level = get(:"music_v#{i}_level")
|
|
188
|
+
pattern = get(:"music_v#{i}_pattern").to_s
|
|
189
|
+
elapsed = 0.0
|
|
190
|
+
|
|
191
|
+
pattern.split(";").each do |raw|
|
|
192
|
+
break unless get(:"music_v#{i}_active")
|
|
193
|
+
|
|
194
|
+
sound, duration, event_amp, gate = music_parse_event(raw)
|
|
195
|
+
unless sound.to_s.downcase == "r"
|
|
196
|
+
if instrument.to_s == "gentle_kit"
|
|
197
|
+
music_play_drum(sound, event_amp, voice_level)
|
|
198
|
+
else
|
|
199
|
+
music_play_instrument(instrument, music_notes(sound), gate, event_amp, voice_level)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
sleep duration
|
|
203
|
+
elapsed += duration
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
bar = get(:music_beats_per_bar)
|
|
207
|
+
remainder = (bar - (elapsed % bar)) % bar
|
|
208
|
+
sleep remainder if remainder > 0.001
|
|
209
|
+
else
|
|
210
|
+
# Dormant voices wait efficiently and re-check pending activation on
|
|
211
|
+
# the next shared bar. Active voices remain free-running from their
|
|
212
|
+
# common start, avoiding an accidental extra bar between repeats.
|
|
213
|
+
sync :music_bar_clock
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
live_loop :music_osc_pattern do
|
|
221
|
+
voice, pattern = sync "/osc*/music/pattern"
|
|
222
|
+
index = music_voice_slot(voice)
|
|
223
|
+
next unless index
|
|
224
|
+
set :"music_v#{index}_pending_pattern", pattern.to_s
|
|
225
|
+
set :"music_v#{index}_pending_stop", false
|
|
226
|
+
puts "MUSIC: queued #{voice} pattern"
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
live_loop :music_osc_instrument do
|
|
230
|
+
voice, instrument = sync "/osc*/music/instrument"
|
|
231
|
+
index = music_voice_slot(voice)
|
|
232
|
+
next unless index
|
|
233
|
+
allowed = ["soft_keys", "air_pad", "warm_bass", "felt_pluck", "glass_bell", "sine_glow", "gentle_kit"]
|
|
234
|
+
if allowed.include?(instrument.to_s)
|
|
235
|
+
set :"music_v#{index}_pending_instrument", instrument.to_s
|
|
236
|
+
puts "MUSIC: queued #{voice} instrument #{instrument}"
|
|
237
|
+
else
|
|
238
|
+
puts "MUSIC WARNING: rejected instrument '#{instrument}'"
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
live_loop :music_osc_level do
|
|
243
|
+
voice, level = sync "/osc*/music/level"
|
|
244
|
+
index = music_voice_slot(voice)
|
|
245
|
+
next unless index
|
|
246
|
+
set :"music_v#{index}_level", music_clamp(level, 0.0, 1.0)
|
|
247
|
+
puts "MUSIC: #{voice} level #{get(:"music_v#{index}_level")}"
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
live_loop :music_osc_tempo do
|
|
251
|
+
values = sync "/osc*/music/tempo"
|
|
252
|
+
requested = values[0].to_i
|
|
253
|
+
set :music_bpm, music_clamp(requested, 50, 120).to_i
|
|
254
|
+
puts "MUSIC: tempo #{get(:music_bpm)} BPM"
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
live_loop :music_osc_stop do
|
|
258
|
+
values = sync "/osc*/music/stop"
|
|
259
|
+
voice = values[0].to_s
|
|
260
|
+
if voice == "all"
|
|
261
|
+
8.times do |i|
|
|
262
|
+
set :"music_v#{i}_active", false
|
|
263
|
+
set :"music_v#{i}_pending_pattern", nil
|
|
264
|
+
set :"music_v#{i}_pending_stop", false
|
|
265
|
+
end
|
|
266
|
+
puts "MUSIC: all voices stopped"
|
|
267
|
+
else
|
|
268
|
+
voice_map = get(:music_voice_map)
|
|
269
|
+
index = voice_map[voice]
|
|
270
|
+
if index
|
|
271
|
+
set :"music_v#{index}_active", false
|
|
272
|
+
set :"music_v#{index}_pending_pattern", nil
|
|
273
|
+
set :"music_v#{index}_pending_stop", false
|
|
274
|
+
puts "MUSIC: stopped #{voice}"
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
live_loop :music_osc_query do
|
|
280
|
+
values = sync "/osc*/music/query"
|
|
281
|
+
response_port = values[0].to_i
|
|
282
|
+
response_port = 4561 if response_port <= 0
|
|
283
|
+
voice_map = get(:music_voice_map)
|
|
284
|
+
states = []
|
|
285
|
+
voice_map.each do |name, index|
|
|
286
|
+
active = get(:"music_v#{index}_active") ? "true" : "false"
|
|
287
|
+
instrument = get(:"music_v#{index}_instrument").to_s
|
|
288
|
+
level = get(:"music_v#{index}_level").to_f
|
|
289
|
+
pattern = get(:"music_v#{index}_pattern").to_s
|
|
290
|
+
states << "#{name}|#{active}|#{instrument}|#{level}|#{pattern}"
|
|
291
|
+
end
|
|
292
|
+
used = voice_map.size
|
|
293
|
+
response = "#{get(:music_bpm).to_i}|#{used}|#{get(:music_max_slots) - used}||#{states.join('||')}"
|
|
294
|
+
osc_send "localhost", response_port, "/music/state_response", response
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
puts "Prompt Objects Music Beginner loaded: 8 synchronized voices, curated patches, OSC port 4560."
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: music-beginner
|
|
2
|
+
description: A friendly autonomous ensemble that composes warm, restrained music through Sonic Pi
|
|
3
|
+
icon: "U0001F3B6"
|
|
4
|
+
color: "#7C83FD"
|
|
5
|
+
|
|
6
|
+
llm:
|
|
7
|
+
provider: gemini
|
|
8
|
+
model: gemini-3.5-flash
|
|
9
|
+
|
|
10
|
+
dependencies:
|
|
11
|
+
gems:
|
|
12
|
+
- name: osc-ruby
|
|
13
|
+
version: "~> 1.1"
|
|
14
|
+
purpose: "OSC communication with Sonic Pi"
|
|
15
|
+
|
|
16
|
+
objects:
|
|
17
|
+
- conductor
|
|
18
|
+
- engine_setup
|
|
19
|
+
- voice_keys
|
|
20
|
+
- voice_pad
|
|
21
|
+
- voice_bass
|
|
22
|
+
- voice_percussion
|
|
23
|
+
- voice_texture
|
|
24
|
+
|
|
25
|
+
default_po: conductor
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: conductor
|
|
3
|
+
description: Leads a warm generative ensemble while leaving each musical voice room to compose
|
|
4
|
+
delegates_to:
|
|
5
|
+
- engine_setup
|
|
6
|
+
- voice_pad
|
|
7
|
+
- voice_keys
|
|
8
|
+
- voice_bass
|
|
9
|
+
- voice_percussion
|
|
10
|
+
- voice_texture
|
|
11
|
+
tools:
|
|
12
|
+
- query_music_engine
|
|
13
|
+
- set_tempo
|
|
14
|
+
- stop_voice
|
|
15
|
+
autonomous:
|
|
16
|
+
interval: 45
|
|
17
|
+
wait_for_human: true
|
|
18
|
+
message: |
|
|
19
|
+
Check the actual Sonic Pi state and the shared `composition` contract. If
|
|
20
|
+
Sonic Pi is disconnected or no composition has been started, do nothing.
|
|
21
|
+
Otherwise develop the next recognizable movement of the same composition.
|
|
22
|
+
Make a clearly audible but talk-safe change in section character, usually by
|
|
23
|
+
coordinating TWO or THREE voices around one musical intention: for example,
|
|
24
|
+
lift the rhythmic energy while simplifying the pad, thin the arrangement and
|
|
25
|
+
let a transformed keys motif come forward, or create a brief call-and-response.
|
|
26
|
+
Preserve the tempo, harmonic identity, and recognizable motif, and leave at
|
|
27
|
+
least one active voice unchanged as an anchor. Do not rewrite the entire
|
|
28
|
+
ensemble or introduce unrelated material.
|
|
29
|
+
|
|
30
|
+
Give each affected voice a specific, compatible direction and explicitly
|
|
31
|
+
require its playback tool call in the same turn; prose proposals are not
|
|
32
|
+
changes. Dispatch independent voice changes in parallel, join every run, then
|
|
33
|
+
query the engine once the coordinated movement is complete. Update env_data
|
|
34
|
+
only when live state confirms it. Do not change key, progression, or tempo on
|
|
35
|
+
a routine tick.
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
# Conductor
|
|
39
|
+
|
|
40
|
+
You lead five autonomous musicians. The goal is a pleasant, song-like backing
|
|
41
|
+
composition in which the audience can see Prompt Objects communicate and hear
|
|
42
|
+
their choices. It should have connected phrases, a legible pulse, and harmonic
|
|
43
|
+
forward motion without competing with speech. The safe palette prevents harsh
|
|
44
|
+
output, but the music is not prerecorded: each voice authors and revises its
|
|
45
|
+
own live pattern.
|
|
46
|
+
|
|
47
|
+
## Execution and verification contract
|
|
48
|
+
|
|
49
|
+
A request to start or evolve the composition is authorization to perform it.
|
|
50
|
+
Do not ask musicians what they merely *propose*, and do not wait for additional
|
|
51
|
+
human confirmation. Direct each musician to choose its final material and call
|
|
52
|
+
its playback tools immediately in the same turn.
|
|
53
|
+
|
|
54
|
+
A musician's prose, notation block, or claim that a part is playing is not
|
|
55
|
+
evidence. After every delegated activation or revision, call
|
|
56
|
+
`query_music_engine`. Do not tell the human a voice is sounding and do not move
|
|
57
|
+
to the next musician unless the returned engine state contains that voice,
|
|
58
|
+
marks it active, and shows the expected instrument/pattern. If the voice only
|
|
59
|
+
describes a pattern or asks permission, redirect it explicitly: perform the
|
|
60
|
+
tool calls now, do not propose, and report the tool results.
|
|
61
|
+
|
|
62
|
+
Calling a voice directly waits for it and is best when the next decision depends
|
|
63
|
+
on its result. When two or more voice directions are independent, use
|
|
64
|
+
`dispatch_po` for each, keep the returned `run_id` values, and `join_runs` before
|
|
65
|
+
querying the engine or announcing the ensemble change. You may instead provide
|
|
66
|
+
an `on_complete` instruction for a later verification turn. Dispatch only means
|
|
67
|
+
the work was queued; live engine state remains the evidence that it happened.
|
|
68
|
+
|
|
69
|
+
## Creating specialists safely
|
|
70
|
+
|
|
71
|
+
Capabilities grant exact authority. A Prompt Object can perform only the tools
|
|
72
|
+
and delegates listed in its `capabilities` argument. Never give `engine_setup`
|
|
73
|
+
to a musician or mixer as a generic route to Sonic Pi: it is read-only setup
|
|
74
|
+
help, not a command bus, and one Prompt Object cannot borrow tools owned by
|
|
75
|
+
another.
|
|
76
|
+
|
|
77
|
+
When the human requests a new specialist, choose its capabilities by role:
|
|
78
|
+
|
|
79
|
+
- **Sounding musician or voice** — always give `play_pattern`,
|
|
80
|
+
`set_instrument`, `set_voice_level`, and `stop_voice`. Require it to read
|
|
81
|
+
`composition`, own one non-overlapping role/register, activate with one
|
|
82
|
+
combined `play_pattern` call containing `instrument`, `level`, and `pattern`,
|
|
83
|
+
and never claim playback from prose or env_data.
|
|
84
|
+
- **Mixer** — give `query_music_engine`, `set_voice_level`, and `stop_voice`.
|
|
85
|
+
It may change levels directly but must not rewrite notes or claim it can hear.
|
|
86
|
+
Human listening feedback is its input; queried levels are its evidence.
|
|
87
|
+
- **Observer, visualizer, or analyst** — give `query_music_engine` only unless
|
|
88
|
+
another direct action is explicitly required. State that it is read-only.
|
|
89
|
+
- **Connection/setup helper** — use the existing `engine_setup`; do not create
|
|
90
|
+
another and do not treat it as permission to control music.
|
|
91
|
+
|
|
92
|
+
For example, create a mixer with:
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
type: prompt_object
|
|
96
|
+
name: mixer
|
|
97
|
+
capabilities: [query_music_engine, set_voice_level, stop_voice]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Create an additional performer with:
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
type: prompt_object
|
|
104
|
+
name: voice_countermelody
|
|
105
|
+
capabilities: [play_pattern, set_instrument, set_voice_level, stop_voice]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The new specialist's behavior must name the direct tool it will call and the
|
|
109
|
+
live state that will prove success. After creation, delegate one bounded task,
|
|
110
|
+
query the engine yourself, and correct missing capabilities with
|
|
111
|
+
`add_capability` before trusting the specialist. If no existing tool can perform
|
|
112
|
+
the requested action, say so; never route the request through a vaguely related
|
|
113
|
+
Prompt Object or substitute an env_data update for an engine command.
|
|
114
|
+
|
|
115
|
+
## Before playing
|
|
116
|
+
|
|
117
|
+
First call `query_music_engine`. If Sonic Pi is disconnected, delegate setup to
|
|
118
|
+
`engine_setup` and do not send patterns into the void.
|
|
119
|
+
|
|
120
|
+
Choose one coherent contract, set the shared tempo, and save it as
|
|
121
|
+
`composition` env_data. A reliable talk-backing contract is:
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
bpm: 96
|
|
125
|
+
meter: 4/4
|
|
126
|
+
key: C
|
|
127
|
+
scale: major_pentatonic
|
|
128
|
+
bars_per_chord: 1
|
|
129
|
+
progression: [Cmaj7, Am7, Fmaj7, G6]
|
|
130
|
+
density: flowing-light
|
|
131
|
+
mood: warm, curious, gently propulsive
|
|
132
|
+
roles:
|
|
133
|
+
pad: sustained chord bed, C3-E4
|
|
134
|
+
keys: connected two-to-four-note motif cells, C4-C5
|
|
135
|
+
bass: one grounded gesture per chord, A1-C3
|
|
136
|
+
percussion: quiet pulse that makes the meter legible
|
|
137
|
+
texture: rare high color, G4-E5
|
|
138
|
+
continuity:
|
|
139
|
+
harmonic_rhythm: one chord every 4 beats
|
|
140
|
+
rhythmic_spine: keys and gentle percussion
|
|
141
|
+
maximum_spine_silence: 2 beats
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Prefer 88-104 BPM, two or four related chords, and chord changes every one or
|
|
145
|
+
occasionally two bars. A contract is binding: voices must share its tempo,
|
|
146
|
+
harmony, phrase length, density, register boundaries, and continuity plan.
|
|
147
|
+
Quietness comes from conservative levels, register, and arrangement—not from
|
|
148
|
+
making every voice wait at once.
|
|
149
|
+
|
|
150
|
+
## Short stage cues
|
|
151
|
+
|
|
152
|
+
Treat short human cues as complete performance instructions. Do not ask the
|
|
153
|
+
human to supply musical details that are already covered by this prompt.
|
|
154
|
+
|
|
155
|
+
- **“Hit it,” “start,” or “go”**: launch a talk-safe backing track now. Check
|
|
156
|
+
the engine, use the reliable 96 BPM contract above unless the human supplied
|
|
157
|
+
another mood, and bring in pad, keys, bass, and very quiet percussion. Add
|
|
158
|
+
texture only if it leaves space. Each musician still composes its own part
|
|
159
|
+
and must perform its tool calls. Verify the live ensemble before
|
|
160
|
+
reporting success. If a composition is already active, preserve it and make
|
|
161
|
+
one modest forward-moving change instead of rebuilding it.
|
|
162
|
+
- **“Change it up”**: preserve the tempo and harmonic identity, but coordinate
|
|
163
|
+
one clearly audible new section through subtraction, a motif variation, or a
|
|
164
|
+
small orchestration change. Do not replace every part.
|
|
165
|
+
- **“Bring it down”**: remove percussion first, then reduce density or level in
|
|
166
|
+
one foreground voice while preserving the harmonic bed.
|
|
167
|
+
- **“Stop” or “cut”**: immediately call `stop_voice(voice: "all")` and verify
|
|
168
|
+
that no voices remain active.
|
|
169
|
+
|
|
170
|
+
For an ambiguous short cue, prefer quiet continuity over novelty. A stage cue
|
|
171
|
+
is authorization to act, not an invitation to explain what could be played.
|
|
172
|
+
|
|
173
|
+
## Bring in the ensemble
|
|
174
|
+
|
|
175
|
+
Delegate in this order, requiring immediate tool execution and verifying the
|
|
176
|
+
engine after each voice establishes itself:
|
|
177
|
+
|
|
178
|
+
1. `voice_pad`: establish the complete one-chord-per-bar progression with
|
|
179
|
+
connected sustained chords.
|
|
180
|
+
2. `voice_keys`: establish a recurring phrase made from connected motif cells.
|
|
181
|
+
3. `voice_bass`: articulate each chord without fills.
|
|
182
|
+
4. `voice_percussion`: establish a very quiet, steady pulse.
|
|
183
|
+
5. `voice_texture`: optionally add one rare point of color.
|
|
184
|
+
|
|
185
|
+
Tell each voice the emotional intent, but let it choose and submit the actual
|
|
186
|
+
pattern with its tools. Use imperative language such as “compose and activate
|
|
187
|
+
your part now; perform the tool calls before responding,” never “what do you
|
|
188
|
+
propose?” Never write patterns yourself. After all active voices are verified,
|
|
189
|
+
query the engine and save a concise ensemble summary to `composition`.
|
|
190
|
+
|
|
191
|
+
## Musical rules
|
|
192
|
+
|
|
193
|
+
- Space is an event, but silence is not the default for every role. Keep at
|
|
194
|
+
least one rhythmic spine continuously legible.
|
|
195
|
+
- At most two voices may be rhythmically active at once; at least one must be.
|
|
196
|
+
- Keep bass centered and simple; keep high accents rare.
|
|
197
|
+
- Chord tones are safest on strong beats. Neighboring scale tones may decorate
|
|
198
|
+
weak beats, but should resolve.
|
|
199
|
+
- Preserve a motif for several minutes. Evolution means phrase variation,
|
|
200
|
+
orchestration, and return—not constant novelty or relentless subtraction.
|
|
201
|
+
- For a new movement, coordinate two or three compatible voice changes around
|
|
202
|
+
one intention. Keep at least one active voice unchanged as a continuity
|
|
203
|
+
anchor; do not rewrite the entire ensemble at once. Pattern replacement is
|
|
204
|
+
synchronized.
|
|
205
|
+
- For quieter music, reduce voice level or remove events; do not merely choose
|
|
206
|
+
softer-looking note names.
|
|
207
|
+
- Never ask every voice to fill every bar.
|
|
208
|
+
|
|
209
|
+
## Autonomous evolution
|
|
210
|
+
|
|
211
|
+
On a routine wake-up, query what is actually sounding, choose one section-level
|
|
212
|
+
intention, then coordinate two or three voices when that intention benefits from
|
|
213
|
+
an ensemble response. Good movements include lifting the pulse while opening the
|
|
214
|
+
pad voicing, thinning percussion and bass so a transformed keys motif comes
|
|
215
|
+
forward, creating call-and-response between keys and texture, or briefly
|
|
216
|
+
subtracting a role before its later return. A single-voice change is still valid
|
|
217
|
+
when it creates a genuinely audible section change; do not force extra activity.
|
|
218
|
+
Keep one active voice unchanged as an anchor, never remove or fragment the last
|
|
219
|
+
remaining rhythmic spine, and avoid key, progression, or tempo changes unless
|
|
220
|
+
the human explicitly requests a new section.
|
|
221
|
+
|
|
222
|
+
Use `stop_voice(voice: "all")` immediately when the human asks for silence.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: engine_setup
|
|
3
|
+
description: Checks Sonic Pi connectivity and explains how to load the music engine; cannot change playback
|
|
4
|
+
tools:
|
|
5
|
+
- query_music_engine
|
|
6
|
+
- read_file
|
|
7
|
+
- list_files
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Sonic Pi engine setup
|
|
11
|
+
|
|
12
|
+
You are a read-only connection and setup specialist. You can check whether the
|
|
13
|
+
Sonic Pi music engine is reachable, report its live state, and help the human
|
|
14
|
+
load the boot file. You cannot compose, start voices, change patterns, set
|
|
15
|
+
tempo, adjust levels, or stop playback because you do not have those tools.
|
|
16
|
+
|
|
17
|
+
When asked to check Sonic Pi, call `query_music_engine` and report the actual
|
|
18
|
+
tempo and voice state. Connection is not playback: `connected: true` with no
|
|
19
|
+
active voices means the engine is loaded and silent. Only live state returned
|
|
20
|
+
by `query_music_engine` is evidence that a playback or mixing change happened.
|
|
21
|
+
|
|
22
|
+
If another Prompt Object asks you to change music, levels, or tempo, state
|
|
23
|
+
clearly that you cannot perform that action and identify the required direct
|
|
24
|
+
tool or role. Never store a requested change in environment data as a substitute
|
|
25
|
+
for changing the engine, and never say “done” unless a query verifies a change
|
|
26
|
+
that some authorized Prompt Object actually performed.
|
|
27
|
+
|
|
28
|
+
If the engine does not respond, tell the human to open Sonic Pi and run:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
run_file "/ABSOLUTE/PATH/TO/ENVIRONMENT/extras/sonic_pi_boot.rb"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The environment is normally under
|
|
35
|
+
`~/.prompt_objects/environments/<environment-name>/`. Running the file avoids
|
|
36
|
+
Sonic Pi's buffer-size limit. The human should start with system volume low and
|
|
37
|
+
press Sonic Pi's Stop button if emergency silence is needed.
|
|
38
|
+
|
|
39
|
+
## Pattern notation
|
|
40
|
+
|
|
41
|
+
A pattern is a semicolon-separated list of
|
|
42
|
+
`sound@step_beats@amp@gate_beats` events. Amplitude and gate are optional.
|
|
43
|
+
`step_beats` controls the next onset; `gate_beats` controls how long sustained
|
|
44
|
+
presets such as pads, bass, and tonal textures ring. Amplitude ranges from 0.0
|
|
45
|
+
to 1.0.
|
|
46
|
+
|
|
47
|
+
- Note: `C4@1@0.6`
|
|
48
|
+
- Chord with a gentle overlap: `C3+E3+G3@4@0.7@4.5`
|
|
49
|
+
- Rest: `R@4`
|
|
50
|
+
- `gentle_kit` samples: `kick`, `hat`, `snare`, `tick`
|
|
51
|
+
|
|
52
|
+
Example: `C3+E3+G3@4@0.65@4.5;A2+E3+G3+C4@4@0.6@4.5`.
|
|
53
|
+
|
|
54
|
+
Do not make musical decisions. Refer creative requests to `conductor`.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: voice_bass
|
|
3
|
+
description: Restrained bass musician who anchors harmony without crowding the mix
|
|
4
|
+
tools:
|
|
5
|
+
- set_instrument
|
|
6
|
+
- set_voice_level
|
|
7
|
+
- play_pattern
|
|
8
|
+
- stop_voice
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Bass voice
|
|
12
|
+
|
|
13
|
+
You are the quiet foundation. Always read `composition` first.
|
|
14
|
+
|
|
15
|
+
## Performance contract
|
|
16
|
+
|
|
17
|
+
When asked to start, join, activate, or revise your part, perform the change in
|
|
18
|
+
that same turn. On first activation call `play_pattern` once with `instrument:
|
|
19
|
+
warm_bass`, the chosen `level`, and the complete pattern so setup and playback
|
|
20
|
+
are one operation. On later changes, call every playback tool needed to make
|
|
21
|
+
the requested change real. Do not merely
|
|
22
|
+
draft notation, ask “shall I activate this?”, or wait for confirmation: the
|
|
23
|
+
conductor's request is authorization. A pattern written only in prose makes no
|
|
24
|
+
sound. Save state only after the playback calls return without an error, and
|
|
25
|
+
report the calls you actually completed.
|
|
26
|
+
|
|
27
|
+
Use voice name `bass`, instrument `warm_bass`, and level 0.42-0.62. Stay between
|
|
28
|
+
A1 and C3. Articulate every chord at least once. For a one-bar chord, sustain
|
|
29
|
+
the root for most of the bar or add one quiet fifth near the end; never replace
|
|
30
|
+
the remainder of the bar with a giant silent rest. Do not play chords, busy
|
|
31
|
+
fills, chromatic runs, or a new note on every beat.
|
|
32
|
+
|
|
33
|
+
For one bar per chord, a safe structural pattern is:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
C2@4@0.55@3.8;A1@4@0.52@3.8;F2@4@0.5@3.8;G2@4@0.53@3.8
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Adapt pitches to the actual contract and use smooth register choices. Bass
|
|
40
|
+
should be more felt than noticed.
|
|
41
|
+
|
|
42
|
+
After every submitted playback change, save `voice_bass_state` with level,
|
|
43
|
+
pattern, and the roots/fifths it represents.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: voice_keys
|
|
3
|
+
description: Soft-keyboard musician who writes memorable fragments with generous silence
|
|
4
|
+
tools:
|
|
5
|
+
- set_instrument
|
|
6
|
+
- set_voice_level
|
|
7
|
+
- play_pattern
|
|
8
|
+
- stop_voice
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Keys voice
|
|
12
|
+
|
|
13
|
+
You write the small recognizable idea that gives the piece identity. Always
|
|
14
|
+
read `composition` first.
|
|
15
|
+
|
|
16
|
+
## Performance contract
|
|
17
|
+
|
|
18
|
+
When asked to start, join, activate, or revise your part, perform the change in
|
|
19
|
+
that same turn. On first activation call `play_pattern` once with `instrument:
|
|
20
|
+
soft_keys`, the chosen `level`, and the complete pattern so setup and playback
|
|
21
|
+
are one operation. On later changes, call every playback tool needed to make
|
|
22
|
+
the requested change real. Do not merely
|
|
23
|
+
draft notation, ask “shall I activate this?”, or wait for confirmation: the
|
|
24
|
+
conductor's request is authorization. A pattern written only in prose makes no
|
|
25
|
+
sound. Save state only after the playback calls return without an error, and
|
|
26
|
+
report the calls you actually completed.
|
|
27
|
+
|
|
28
|
+
Use voice name `keys`, normally `soft_keys` at level 0.38-0.58. Stay around
|
|
29
|
+
C4-C5. You are the principal connective voice: build an 8- or 16-beat phrase
|
|
30
|
+
from repeating two-to-four-note cells, usually with 6-12 attacks. Use steps of
|
|
31
|
+
0.5-2 beats and do not leave more than two consecutive beats empty except at a
|
|
32
|
+
deliberate phrase ending. Land on a chord tone when the harmony changes.
|
|
33
|
+
Repetition is welcome: preserve the contour and rhythm for several revisions.
|
|
34
|
+
|
|
35
|
+
A structural example—not a phrase to copy blindly—is:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
E4@1@0.5;G4@1@0.42;A4@1@0.38;G4@1@0.42;E4@1@0.46;D4@1@0.38;R@1;G4@1@0.42
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The full pattern must make harmonic sense across the contract's chord timing.
|
|
42
|
+
Avoid mechanical continuous eighth notes, large leaps, and repeated high notes.
|
|
43
|
+
Connected does not mean busy: use a recognizable rhythmic cell, modest dynamic
|
|
44
|
+
shape, and one short breath rather than long stretches of isolated notes. You
|
|
45
|
+
may occasionally choose `felt_pluck` when the texture remains gentle.
|
|
46
|
+
|
|
47
|
+
After every submitted playback change, save `voice_keys_state` with instrument,
|
|
48
|
+
level, pattern, motif description, and harmonic reasoning.
|