prompt_objects 0.5.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 +142 -0
- data/README.md +211 -19
- 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 +1350 -18
- 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 +190 -432
- 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 +561 -52
- data/lib/prompt_objects/server/app.rb +134 -1
- 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 -207
- data/lib/prompt_objects/server.rb +170 -1
- data/lib/prompt_objects/service.rb +129 -0
- data/lib/prompt_objects/session/store.rb +774 -15
- 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 +78 -0
- 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 +58 -0
- 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 +57 -0
- 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/set_env_data.rb +101 -0
- data/lib/prompt_objects/version.rb +5 -0
- data/lib/prompt_objects.rb +36 -6
- 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 +6 -2
- data/templates/arc-agi-1/objects/solver.md +14 -4
- data/templates/arc-agi-1/objects/verifier.md +6 -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 +28 -1
- metadata +175 -65
- data/CLAUDE.md +0 -176
- data/Gemfile +0 -10
- data/Gemfile.lock +0 -233
- data/IMPLEMENTATION_PLAN.md +0 -1073
- data/Rakefile +0 -27
- data/design-doc-v2.md +0 -1232
- 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 -103
- 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/Inspector.tsx +0 -232
- 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 -517
- data/frontend/src/index.css +0 -103
- data/frontend/src/main.tsx +0 -10
- data/frontend/src/store/index.ts +0 -279
- data/frontend/src/types/index.ts +0 -165
- 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-D1myxE0l.js +0 -4345
- data/lib/prompt_objects/server/public/assets/index-DdCcwC-Z.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/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,46 @@
|
|
|
1
|
+
module OSC
|
|
2
|
+
class Bundle
|
|
3
|
+
attr_accessor :timetag
|
|
4
|
+
|
|
5
|
+
def initialize(timetag=nil, *args)
|
|
6
|
+
@timetag = timetag
|
|
7
|
+
@args = args
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def encode()
|
|
11
|
+
s = OSCString.new('#bundle').encode
|
|
12
|
+
s << encode_timetag(@timetag)
|
|
13
|
+
s << @args.collect do |x|
|
|
14
|
+
x2 = x.encode; [x2.size].pack('N') + x2
|
|
15
|
+
end.join
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_a
|
|
19
|
+
@args.collect{|x| x.to_a}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def encode_timetag(t)
|
|
25
|
+
case t
|
|
26
|
+
when nil # immediately
|
|
27
|
+
t1 = 0
|
|
28
|
+
t2 = 1
|
|
29
|
+
when Numeric
|
|
30
|
+
t1, t2 = construct_timetag(t)
|
|
31
|
+
when Time
|
|
32
|
+
t1, t2 = construct_timetag(t.to_ntp)
|
|
33
|
+
else
|
|
34
|
+
raise(ArgumentError, 'invalid time')
|
|
35
|
+
end
|
|
36
|
+
[t1, t2].pack('N2')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def construct_timetag(time)
|
|
40
|
+
t1, fr = time.divmod(1)
|
|
41
|
+
t2 = (fr * (2**32)).to_i
|
|
42
|
+
|
|
43
|
+
[t1, t2]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'eventmachine'
|
|
2
|
+
|
|
3
|
+
module OSC
|
|
4
|
+
Channel = EM::Channel.new
|
|
5
|
+
|
|
6
|
+
class Connection < EventMachine::Connection
|
|
7
|
+
def receive_data(data)
|
|
8
|
+
ip_info = get_peername[2,6].unpack("nC4")
|
|
9
|
+
Channel << OSC::OSCPacket.messages_from_network(data, ip_info)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class EMServer
|
|
14
|
+
|
|
15
|
+
def initialize(port = 3333)
|
|
16
|
+
@port = port
|
|
17
|
+
setup_dispatcher
|
|
18
|
+
@tuples = []
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def run
|
|
22
|
+
EM.error_handler{ |e|
|
|
23
|
+
Thread.main.raise e
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
EM.run do
|
|
27
|
+
EM::open_datagram_socket "0.0.0.0", @port, Connection
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def add_method(address_pattern, &proc)
|
|
32
|
+
matcher = AddressPattern.new(address_pattern)
|
|
33
|
+
|
|
34
|
+
@tuples << [matcher, proc]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
def setup_dispatcher
|
|
39
|
+
Channel.subscribe do |messages|
|
|
40
|
+
messages.each do |message|
|
|
41
|
+
diff = (message.time || 0) - Time.now.to_ntp
|
|
42
|
+
|
|
43
|
+
if diff <= 0
|
|
44
|
+
sendmesg(message)
|
|
45
|
+
else
|
|
46
|
+
EM.defer do
|
|
47
|
+
sleep(diff)
|
|
48
|
+
sendmesg(message)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def sendmesg(mesg)
|
|
56
|
+
@tuples.each do |matcher, obj|
|
|
57
|
+
if matcher.match?(mesg.address)
|
|
58
|
+
obj.call(mesg)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module OSC
|
|
2
|
+
class Message
|
|
3
|
+
attr_accessor :address
|
|
4
|
+
attr_accessor :time
|
|
5
|
+
attr_accessor :ip_address
|
|
6
|
+
attr_accessor :ip_port
|
|
7
|
+
|
|
8
|
+
def self.new_with_time(address, time, tags=nil, *args)
|
|
9
|
+
message = new(address, tags, *args)
|
|
10
|
+
message.time = time
|
|
11
|
+
message
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize(address, *args)
|
|
15
|
+
@address = address
|
|
16
|
+
@args = []
|
|
17
|
+
|
|
18
|
+
args.each do |arg|
|
|
19
|
+
case arg
|
|
20
|
+
when Integer; @args << OSCInt32.new(arg)
|
|
21
|
+
when Float; @args << OSCFloat32.new(arg)
|
|
22
|
+
when String; @args << OSCString.new(arg)
|
|
23
|
+
when OSCArgument; @args << arg
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def tags
|
|
29
|
+
@args.collect{|x| x.tag}.join
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def encode
|
|
33
|
+
s = OSCString.new(@address).encode
|
|
34
|
+
s << OSCString.new(',' + tags).encode
|
|
35
|
+
s << @args.collect{|x| x.encode}.join
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def to_a
|
|
39
|
+
@args.collect{|x| x.val}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def ==(other)
|
|
43
|
+
@address == other.address && to_a == other.to_a
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module OSC
|
|
2
|
+
class NetworkPacket
|
|
3
|
+
def initialize(str)
|
|
4
|
+
@str = str.force_encoding("BINARY")
|
|
5
|
+
@index = 0
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def to_s
|
|
9
|
+
@str
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def rem
|
|
13
|
+
@str.length - @index
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def eof?
|
|
17
|
+
rem <= 0
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def skip(n)
|
|
21
|
+
@index += n
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def skip_padding
|
|
25
|
+
skip((4 - (@index % 4)) % 4)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def getn(n)
|
|
29
|
+
raise(EOFError) if rem < n
|
|
30
|
+
s = @str[@index, n]
|
|
31
|
+
skip(n)
|
|
32
|
+
s
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def getc
|
|
36
|
+
raise(EOFError) if rem < 1
|
|
37
|
+
c = @str[@index]
|
|
38
|
+
skip(1)
|
|
39
|
+
c
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module OSC
|
|
2
|
+
class OSCArgument
|
|
3
|
+
def initialize(val)
|
|
4
|
+
@val = val
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
attr_accessor :val
|
|
8
|
+
|
|
9
|
+
def to_i()
|
|
10
|
+
@val.to_i
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_f()
|
|
14
|
+
@val.to_f
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_s()
|
|
18
|
+
@val.to_s
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
def padding(s)
|
|
23
|
+
s + ("\000" * ((4 - (s.size % 4)) % 4))
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
require File.join(File.dirname( __FILE__ ), 'network_packet')
|
|
2
|
+
require 'ostruct'
|
|
3
|
+
|
|
4
|
+
module OSC
|
|
5
|
+
class UnknownType < StandardError; end
|
|
6
|
+
|
|
7
|
+
class OSCPacket
|
|
8
|
+
def self.messages_from_network(string, ip_info=nil)
|
|
9
|
+
messages = []
|
|
10
|
+
osc = new(string)
|
|
11
|
+
|
|
12
|
+
if osc.bundle?
|
|
13
|
+
osc.get_string
|
|
14
|
+
time = osc.get_timestamp
|
|
15
|
+
|
|
16
|
+
osc.get_bundle_messages.each do |message|
|
|
17
|
+
msg = decode_simple_message(time, OSCPacket.new(message))
|
|
18
|
+
if ip_info
|
|
19
|
+
# Append info for the ip address
|
|
20
|
+
msg.ip_port = ip_info.shift
|
|
21
|
+
msg.ip_address = ip_info.join(".")
|
|
22
|
+
end
|
|
23
|
+
messages << msg
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
else
|
|
27
|
+
msg = decode_simple_message(time, osc)
|
|
28
|
+
if ip_info
|
|
29
|
+
# Append info for the ip address
|
|
30
|
+
msg.ip_port = ip_info.shift
|
|
31
|
+
msg.ip_address = ip_info.join(".")
|
|
32
|
+
end
|
|
33
|
+
messages << msg
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
return messages
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.decode_simple_message(time, osc_packet)
|
|
40
|
+
address = osc_packet.get_string
|
|
41
|
+
args = osc_packet.get_arguments
|
|
42
|
+
|
|
43
|
+
Message.new_with_time(address, time, nil, *args)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def initialize(string)
|
|
47
|
+
@packet = NetworkPacket.new(string)
|
|
48
|
+
|
|
49
|
+
@types = {
|
|
50
|
+
"i" => lambda{OSCInt32.new(get_int32)},
|
|
51
|
+
"f" => lambda{ OSCFloat32.new(get_float32)},
|
|
52
|
+
"d" => lambda{ OSCDouble64.new(get_double64)},
|
|
53
|
+
"s" => lambda{ OSCString.new(get_string)},
|
|
54
|
+
"b" => lambda{ OSCBlob.new(get_blob)}
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def get_bundle_messages
|
|
59
|
+
bundle_messages = []
|
|
60
|
+
|
|
61
|
+
until @packet.eof?
|
|
62
|
+
l = @packet.getn(4).unpack('N')[0]
|
|
63
|
+
bundle_messages << @packet.getn(l)
|
|
64
|
+
end
|
|
65
|
+
bundle_messages
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def get_string
|
|
69
|
+
result = ''
|
|
70
|
+
until ((c = @packet.getc) == string_delemeter)
|
|
71
|
+
result << c
|
|
72
|
+
end
|
|
73
|
+
@packet.skip_padding
|
|
74
|
+
result
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def get_timestamp
|
|
78
|
+
#TODO: refactor this so a mortal can figure it out
|
|
79
|
+
t1 = @packet.getn(4).unpack('N')[0]
|
|
80
|
+
t2 = @packet.getn(4).unpack('N')[0]
|
|
81
|
+
@packet.skip_padding
|
|
82
|
+
|
|
83
|
+
if t1 == 0 && t2 == 1
|
|
84
|
+
time = nil
|
|
85
|
+
else
|
|
86
|
+
time = t1 + t2.to_f / (2**32)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
time
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def get_arguments
|
|
93
|
+
if (@packet.getc == ?,)
|
|
94
|
+
tags = get_string
|
|
95
|
+
args = []
|
|
96
|
+
|
|
97
|
+
tags.scan(/./) do |tag|
|
|
98
|
+
type_handler = @types[tag]
|
|
99
|
+
raise(UnknownType, "Unknown OSC type: #{tag}") unless type_handler
|
|
100
|
+
args << type_handler.call
|
|
101
|
+
end
|
|
102
|
+
args
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def get_int32
|
|
107
|
+
i = @packet.getn(4).unpack('N')[0]
|
|
108
|
+
i -= 2**32 if i > (2**31-1)
|
|
109
|
+
@packet.skip_padding
|
|
110
|
+
i
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def get_float32
|
|
114
|
+
f = @packet.getn(4).unpack('g')[0]
|
|
115
|
+
@packet.skip_padding
|
|
116
|
+
f
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def get_double64
|
|
120
|
+
f = @packet.getn(8).unpack('G')[0]
|
|
121
|
+
@packet.skip_padding
|
|
122
|
+
f
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def get_blob
|
|
126
|
+
l = @packet.getn(4).unpack('N')[0]
|
|
127
|
+
b = @packet.getn(l)
|
|
128
|
+
@packet.skip_padding
|
|
129
|
+
b
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def bundle?
|
|
133
|
+
!(@packet.to_s =~ /\A\#bundle/).nil?
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def string_delemeter
|
|
137
|
+
"\x00"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), "osc_argument")
|
|
2
|
+
|
|
3
|
+
module OSC
|
|
4
|
+
class OSCInt32 < OSCArgument
|
|
5
|
+
def tag
|
|
6
|
+
'i'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def encode
|
|
10
|
+
[@val].pack('N').force_encoding("BINARY")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class OSCFloat32 < OSCArgument
|
|
15
|
+
def tag
|
|
16
|
+
'f'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def encode
|
|
20
|
+
[@val].pack('g').force_encoding("BINARY")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class OSCDouble64 < OSCArgument
|
|
25
|
+
def tag
|
|
26
|
+
'd'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def encode
|
|
30
|
+
[@val].pack('G').force_encoding("BINARY")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class OSCString < OSCArgument
|
|
35
|
+
def tag
|
|
36
|
+
's'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def encode
|
|
40
|
+
padding(@val.sub(/\000.*\z/, '') + "\000").force_encoding("BINARY")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class OSCBlob < OSCArgument
|
|
45
|
+
def tag
|
|
46
|
+
'b'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def encode
|
|
50
|
+
padding([@val.size].pack('N') + @val).force_encoding("BINARY")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module OSC
|
|
2
|
+
class Server
|
|
3
|
+
def initialize(port)
|
|
4
|
+
@socket = UDPSocket.new
|
|
5
|
+
@socket.bind('', port)
|
|
6
|
+
@matchers = []
|
|
7
|
+
@queue = Queue.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def run
|
|
11
|
+
start_dispatcher
|
|
12
|
+
|
|
13
|
+
start_detector
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def stop
|
|
17
|
+
@socket.close
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def add_method(address_pattern, &proc)
|
|
21
|
+
matcher = AddressPattern.new(address_pattern)
|
|
22
|
+
|
|
23
|
+
@matchers << [matcher, proc]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def start_detector
|
|
29
|
+
begin
|
|
30
|
+
detector
|
|
31
|
+
rescue
|
|
32
|
+
Thread.main.raise($!)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def start_dispatcher
|
|
37
|
+
Thread.fork do
|
|
38
|
+
begin
|
|
39
|
+
dispatcher
|
|
40
|
+
rescue
|
|
41
|
+
Thread.main.raise($!)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def dispatcher
|
|
47
|
+
loop do
|
|
48
|
+
mesg = @queue.pop
|
|
49
|
+
dispatch_message(mesg)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def dispatch_message(message)
|
|
54
|
+
diff = (message.time || 0) - Time.now.to_ntp
|
|
55
|
+
|
|
56
|
+
if diff <= 0
|
|
57
|
+
sendmesg(message)
|
|
58
|
+
else # spawn a thread to wait until it's time
|
|
59
|
+
Thread.fork do
|
|
60
|
+
sleep(diff)
|
|
61
|
+
sendmesg(message)
|
|
62
|
+
Thread.exit
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def sendmesg(mesg)
|
|
68
|
+
@matchers.each do |matcher, proc|
|
|
69
|
+
if matcher.match?(mesg.address)
|
|
70
|
+
proc.call(mesg)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def detector
|
|
76
|
+
loop do
|
|
77
|
+
osc_data, network = @socket.recvfrom(16384)
|
|
78
|
+
begin
|
|
79
|
+
ip_info = Array.new
|
|
80
|
+
ip_info << network[1]
|
|
81
|
+
ip_info.concat(network[2].split('.'))
|
|
82
|
+
OSCPacket.messages_from_network( osc_data, ip_info ).each do |message|
|
|
83
|
+
@queue.push(message)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
rescue(EOFError)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
require 'thread'
|
|
3
|
+
|
|
4
|
+
# core extensions
|
|
5
|
+
require 'osc-ruby/core_ext/time'
|
|
6
|
+
|
|
7
|
+
# jus the basics
|
|
8
|
+
require 'osc-ruby/osc_types'
|
|
9
|
+
require 'osc-ruby/osc_packet'
|
|
10
|
+
|
|
11
|
+
require 'osc-ruby/message'
|
|
12
|
+
require 'osc-ruby/bundle'
|
|
13
|
+
require 'osc-ruby/address_pattern'
|
|
14
|
+
|
|
15
|
+
# now we gettin fancy
|
|
16
|
+
require 'osc-ruby/server'
|
|
17
|
+
require 'osc-ruby/client'
|
|
18
|
+
require 'osc-ruby/broadcast_client'
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Auditioning Music Pro
|
|
2
|
+
|
|
3
|
+
## Start it
|
|
4
|
+
|
|
5
|
+
1. Create a new environment from the `music-pro` template and open it.
|
|
6
|
+
2. Open Sonic Pi. In Settings, allow incoming OSC if needed.
|
|
7
|
+
3. In a Sonic Pi buffer, run one line with the environment's absolute path:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
run_file "/Users/you/.prompt_objects/environments/my-music/extras/sonic_pi_boot.rb"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
4. Ask the `conductor` to check Sonic Pi, then ask it to begin a flowing,
|
|
14
|
+
talk-safe composition. Add one musician at a time while listening, but keep
|
|
15
|
+
one sustained, phrase-based, or rhythmic layer connecting the ensemble.
|
|
16
|
+
|
|
17
|
+
The autonomous timer stays dormant until the conductor receives a new human
|
|
18
|
+
message after the server starts. Its first evolution turn happens 24 seconds
|
|
19
|
+
later and uses the short evolution instruction in the conductor's frontmatter,
|
|
20
|
+
not the human's initialization prompt.
|
|
21
|
+
|
|
22
|
+
The Log should say `Prompt Objects Music Pro loaded`. The connection query reports engine `music-pro/1`.
|
|
23
|
+
|
|
24
|
+
`connected: true` confirms only that the engine is reachable. The conductor
|
|
25
|
+
must require each musician to call `set_live_pattern` and then verify an active
|
|
26
|
+
voice in live engine state. A connected engine with an empty `voices` object is
|
|
27
|
+
silent; prose proposals and defined-but-unused patches do not produce sound.
|
|
28
|
+
|
|
29
|
+
## Pattern notation
|
|
30
|
+
|
|
31
|
+
| Notation | Meaning |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| `C4/1` | C4 for one beat |
|
|
34
|
+
| `(C4,E4,G4)/2` | chord for two beats |
|
|
35
|
+
| `~/1` or `-/1` | one-beat rest |
|
|
36
|
+
| `@bd_haus/0.5` | built-in Sonic Pi sample |
|
|
37
|
+
| `[C4/1 E4/1 G4/1]/1` | subdivide/compress the sequence into one beat |
|
|
38
|
+
| `<C4 E4 G4>/1` | choose the next alternative on each cycle |
|
|
39
|
+
| `C4/0.5*4` | repeat an event four times |
|
|
40
|
+
| `C4/1{amp=0.4,pan=-0.2}` | per-event raw controls |
|
|
41
|
+
| `C4/1{gate=0.8}` | one-beat step with a shorter 0.8-beat synth envelope |
|
|
42
|
+
|
|
43
|
+
Patterns are whitespace-separated. Durations are Sonic Pi beats and determine
|
|
44
|
+
the distance to the next onset. Synth envelopes default to roughly 95% of that
|
|
45
|
+
duration so sustained parts connect; an explicit `gate` may shorten the sound or
|
|
46
|
+
overlap the next onset without changing the rhythm. Explicit patch `sustain`
|
|
47
|
+
still takes precedence. Updates take effect at the next bar. A pattern is padded
|
|
48
|
+
to the next bar boundary after completing, so every voice re-locks safely; this
|
|
49
|
+
prototype does not yet preserve free-running polymetric phase across rewrites.
|
|
50
|
+
|
|
51
|
+
Available cycle transforms are `transpose`, `stretch`, `rotate`, `reverse`, `probability`, deterministic `seed`, and `every`, for example:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"rotate": 1,
|
|
56
|
+
"seed": 42,
|
|
57
|
+
"every": { "cycles": 4, "transform": "reverse" }
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Raw patches
|
|
62
|
+
|
|
63
|
+
The bundled quiet patches are only starting points. A voice can define any installed Sonic Pi synth or built-in sample and up to three effects:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"name": "moving_blade",
|
|
68
|
+
"patch": {
|
|
69
|
+
"kind": "synth",
|
|
70
|
+
"synth": "blade",
|
|
71
|
+
"params": { "amp": 0.12, "attack": 0.4, "release": 2.5, "cutoff": 76 },
|
|
72
|
+
"effects": [
|
|
73
|
+
{ "name": "reverb", "params": { "mix": 0.25, "room": 0.8 } },
|
|
74
|
+
{ "name": "lpf", "params": { "cutoff": 90 } }
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Unknown synth, sample, effect, or parameter names are reported in Sonic Pi's Log without taking down other voice loops.
|
|
81
|
+
|
|
82
|
+
## Listening comparison
|
|
83
|
+
|
|
84
|
+
To judge the system rather than one lucky pattern, try three five-minute runs from fresh environments. Give each the same high-level request and note:
|
|
85
|
+
|
|
86
|
+
- whether a recognizable idea survives multiple autonomous changes;
|
|
87
|
+
- whether musicians leave room and respond to one another;
|
|
88
|
+
- harshness, muddiness, clipping, and distracting transients;
|
|
89
|
+
- how often a change feels motivated rather than random;
|
|
90
|
+
- whether human feedback produces an audible correction within one rewrite.
|
|
91
|
+
|
|
92
|
+
Agents can query structure but cannot hear audio. Specific human feedback is part of the perception loop.
|
|
93
|
+
|
|
94
|
+
For a stage rehearsal, begin with the venue output muted, start one voice at a time, set the computer/PA gain conservatively, and keep `stop_voice(voice: "all")` ready. The engine clamps generated event gain but cannot control the operating-system or venue mixer.
|
|
95
|
+
|
|
96
|
+
## Prototype compatibility and limits
|
|
97
|
+
|
|
98
|
+
This prototype targets Sonic Pi 4.6.0, the version used while checking the bundled synth/effect names and Ruby syntax. It uses Sonic Pi's Ruby `json` standard library and its `with_fx`/`play_chord` APIs. Verify it against the exact Sonic Pi build used for a performance.
|
|
99
|
+
|
|
100
|
+
The notation is inspired by live-pattern languages but is not Strudel syntax. It intentionally does not evaluate arbitrary Ruby. Runtime patches may select any installed synth, built-in sample, and up to three effects; arbitrary sample file paths are not accepted in this first protocol. Chords are simultaneous, while the events within one voice otherwise run sequentially. Free-running polymeter, hot control of already-ringing synth nodes, audio analysis, and agent listening are future work.
|