Crates.io | tether-soundscape |
lib.rs | tether-soundscape |
version | 0.4.2 |
source | src |
created_at | 2024-11-19 16:33:27.443932 |
updated_at | 2024-12-05 10:33:20.673782 |
description | A remote-controllable audio sequencer |
homepage | |
repository | https://github.com/RandomStudio/tether-soundscape-rs |
max_upload_size | |
id | 1453505 |
size | 312,058 |
A multi-layered audio sequencer, remote-controllable via Tether, to create soundscapes. Runs in a full GUI mode or headless - even on a Raspberry Pi!
Install:
cargo install tether-soundscape
Run, pointing to your sample bank JSON:
tether-soundscape mysoundbank.json
If you have tether-egui installed (cargo install tether-egui
), you can test remote control:
tether-egui egui-demo.json
Currently, the Sample Bank JSON files are created "by hand". Later versions will allow creation, editing and saving of these via the GUI. See ./soundbank-demo.json
file for an example.
Clips in the Sample Bank may optionally be given a volume
and/or panning
setting.
If an incoming clipCommands
message specifies volume
or panning
values, then these will override any defaults specified in the JSON.
If neither a JSON-specified value nor a message-specified override is available for one or both of these, a default will be applied (full volume and centred panning).
See Conventions for more detail on how these values are intended to be used.
On the topic +/+/clipCommands
Has the following fields
command
(required): one of the following strings: "hit", "add", "remove"
clipName
(required): string name for the targetted clipfadeDuration
(optional): an integer value for milliseconds to fade in or out (command-dependent)panPosition
, panSpread
(both optional): if panPosition
is specified, this will override any per-clip panning specified in the Sample Bank JSON
panSpread
on its own will be ignoredpanPosition
on its own will apply a default spread value (0.0
)See the Conventions section for more detail on how these values are defined.
On the topic +/+/scenes
Has the following fields
mode
(optional, default is "loopAll"): one of the following strings: "loopAll", "onceAll", "onceRandom",clipNames
(required): zero or more clip names; if zero are provided, the system will transition to an empty scene (silence all clips)fade_duration
(optional): an integer value for milliseconds to transition from current scene to the new oneOn the topic +/+/globalControls
Has the following fields:
command
: one of the following:
volume
: only used when command is "masterVolume"A project file for Tether Egui is provided in ./egui-demo.json
for easy testing of the remote control functions.
Alternatively, use the tether send
commands below if using Tether Utils.
Single clip hit:
tether send --plug.topic dummy/dummy/clipCommands --message \{\"command\":\"hit\"\,\"clipName\":\"frog\"\}
Single clip hit, specify panning (ignored if in Stereo Mode):
tether send --plug.topic dummy/dummy/clipCommands --message \{\"command\":\"hit\"\,\"clipName\":\"frog\"\,\"panPosition\":0,\"panSpread\":1\}
Scene with two clips (default mode is "loopAll"):
tether send --plug.topic dummy/dummy/scenes --message \{\"clipNames\":\[\"frog\"\,\"squirrel\"]\}
Scene where system should "pick one random" from the list:
tether send --plug.topic dummy/dummy/scenes --message \{\"mode\":\"random\",\"clipNames\":\[\"frog\"\,\"squirrel\"]\}
Remove single clip
tether send --plug.topic dummy/dummy/clipCommands --message \{\"command\":\"remove\",\"clipName\":\"frog\"\}
Add single clip, custom fade duration
tether send --plug.topic dummy/dummy/clipCommands --message \{\"command\":\"add\",\"clipName\":\"squirrel2\",\"fadeDuration\":5000\}
Scene with zero clips (silence all), custom fade duration:
tether send --plug.topic dummy/dummy/scenes --message \{\"clipNames\":\[\],\"fadeDuration\":500\}
This agent publishes frequently on the topic soundscape/any/state
, which can be useful for driving animation, lighting effects, visualisation, etc. in sync with playback. The state messages include the following fields:
isPlaying
: whether or not the audio stream is playingclips
: an array of currently playing clips (only), with the following information for each:
id
(int)name
(string)progress
(float, normalised to range [0,1])currentVolume
(float, normalised to range [0,1])looping
(boolean)To minimise traffic, the agent will only publish an empty clip list (clips: []
) once and then resume as soon as at least one clip begins playing again.
Discrete events (clip begin/end) are published on the events
Plug, e.g. soundscape/any/events
. This can be useful for driving external applications that only need to subscribe to significant begin/end events.
volume
values are a multiplier, so 0.0
means silence and 1.0
means "full volume". A value > 1.0 will amplify the volume relative to the original source.
panning
is separated into two distance keys (in JSON file and/or messages) and a tuple (in Rust, internally) - position
followed by spread
. These values are meant to be used as follows:
position
(panPosition
in JSON) is a value in the range [0; output_channel_count - 1]
. So, in a 4 channel setup, position 3.0
would be "full right", i.e. loudest in channel 4.
spread
(panSpread
in JSON) is a multiple of the "width" of a channel. So, 0.0
means that the signal will be as focussed as possible, i.e. "1 channel width".
Minimal memory/CPU footprint for high performance
Cross-platform but without any need to install browser, use Electron, etc.
Full GUI or headless (text-only) modes are possible
Great way to learn about low-level audio sample/buffer control, multi-threading in Rust
+/someGroup/clipCommands
rather than the default +/+/clipCommands
, and also publish on soundscape/someGroup/state
Err(())
returns with something better, e.g. anyhow crate