# Feasible way to modify text in buffer via external controller?

**URL:** <https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024>\
**Category:** Support, Help & Resources\
**Created:** [October 4, 2021, 7:36am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024 "2021-10-04T07:36:09Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![blipson](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/blipson/32/1772_2.png) [@blipson](https://in-thread.sonic-pi.net/u/blipson)\
**Post date:** [October 4, 2021, 7:36am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/1 "2021-10-04T07:36:09Z")

</div>

A friend and I are looking into building an external controller for Sonic Pi for live performance that’s tactile, but doesn’t involve typing text. My initial idea is to have buttons and encoders modify specific parts of a buffer template by filling in text that is associated with the button-push or encoder-increment at that control element’s designated line number and column number location in the text buffer. A different button push would effect the reload.

For example, say a template starts with a `live_loop` statement at line 10, and and `end` at line 20, and a `sleep 1` at line 19. Pressing a particular button could insert a `my_function_that_contains_a_sleep()` call at line 18 and comment out the sleep at line 19. You make other changes, then you hit the reload button when you’re ready.

This approach would make developing and debugging easy because, after an initial template setup, the state of the control elements (button on/off lights, encoder readouts, say -100 to 100) would represent exactly the buffer’s state. The goal would be to stuff a Raspberry Pi inside a box that has the control elements, hit start, which loads the template and runs its in the buffer, and voila! you’ve got a Sonic Pi MIDI controller.

My friend is the hardware person, not me, but does this sound feasible? I realize that operating SPI strictly from a limited number of control elements would limit how much of SPI’s operation you could use, but with clever library functions written for different buttons, I think you could do a lot to sequence external MIDI gear in a quick and reliable way that’s would be very musically useful.

---

<div class="post-metadata">

**Author:** ![ethancrawford](https://avatars.discourse-cdn.com/v4/letter/e/a88e4f/32.png) [@ethancrawford](https://in-thread.sonic-pi.net/u/ethancrawford)\
**Post date:** [October 4, 2021, 8:15am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/2 "2021-10-04T08:15:01Z")

</div>

I feel like I don’t have any particularly helpful advice on this off the top of my head 😅 at the moment, but I have daydreamed about a similar idea myself in the past - using external devices or software to affect the text in the buffer.

In theory, it sounds quite feasible - sending either text content or an event that Sonic Pi responds to sounds like the easy part. IMO the challenge would lie in the method of determining where and how to update the text content - certainly not impossible, just fiddly - tracking the boundaries of sections of text. Projects like [GitHub - Qirky/Troop: Real-time Live Coding collaboration app](https://github.com/Qirky/Troop) would already be doing something similar, to track the cursors and text limits of multiple users within multiple code editor panels - no doubt a Sonic Pi variation such as what you have described would do the same, just a little simpler.

---

<div class="post-metadata">

**Author:** ![blipson](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/blipson/32/1772_2.png) [@blipson](https://in-thread.sonic-pi.net/u/blipson)\
**Post date:** [October 4, 2021, 8:35am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/3 "2021-10-04T08:35:40Z")

</div>

I thought if you always work from a template, e.g., an 80 x 80 grid of text characters, then it would just be a matter of overwriting what’s at a location with new stuff, and you’d be able to track your buffer’s state exactly. The options would be limited, but with cleverly chosen options the thing would be dynamic and musical.

What I have no concept of is where and how and at what point does one specify the contents of a Sonic Pi buffer without typing at the keyboard? That Troop thing might be over my head to do, but before I get into it, how does SPI “know” what’s in its buffer? Or any text editor, for that matter. It must be reading some place in memory, right? Is there some way for me to write directly to that place in memory?

---

<div class="post-metadata">

**Author:** ![ethancrawford](https://avatars.discourse-cdn.com/v4/letter/e/a88e4f/32.png) [@ethancrawford](https://in-thread.sonic-pi.net/u/ethancrawford)\
**Post date:** [October 4, 2021, 9:58am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/4 "2021-10-04T09:58:43Z")

</div>

> [@blipson](#):
>
> thought if you always work from a template, e.g., an 80 x 80 grid of text characters, then it would just be a matter of overwriting what’s at a location with new stuff

Sure. If you guarantee that you will only be changing a known amount of lines, then yes.

> [@blipson](#):
>
> where and how and at what point does one specify the contents of a Sonic Pi buffer without typing at the keyboard?

To insert text into a buffer of the GUI could possibly be done with something like [GitHub - jordansissel/xdotool: fake keyboard/mouse input, window management, and more](https://github.com/jordansissel/xdotool), by simulating keyboard presses, and then doing the same to trigger a Run, thereby causing the current buffer contents to be stored as a Git commit (Given that Sonic Pi buffers are linked to files that are tracked with Git, where each Sonic Pi ‘Run’ is stored as a Git commit.)

---

<div class="post-metadata">

**Author:** ![blipson](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/blipson/32/1772_2.png) [@blipson](https://in-thread.sonic-pi.net/u/blipson)\
**Post date:** [October 4, 2021, 10:17am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/5 "2021-10-04T10:17:29Z")

</div>

A non-flexible template is an easy price to pay if it reduces the programming task to simply plastering sequences of text characters here and there. But that whole Git thing is new to me. I’ll have to study up, I guess, or else make my friend do that chore.

---

<div class="post-metadata">

**Author:** ![blipson](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/blipson/32/1772_2.png) [@blipson](https://in-thread.sonic-pi.net/u/blipson)\
**Post date:** [October 4, 2021, 11:58am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/7 "2021-10-04T11:58:11Z")

</div>

Reading through the xdotool documentation, it seems to be all about x, y screen locations in terms of pixels, not character row/column locations within a text buffer.

I see SPI’s buffers in `~/.sonic-pi/store/default` on my Mac, and they’re just text files. Is there some way to make SPI, for example, update its workspace #4 from `~/.sonic-pi/store/default/workspace_four.spi`, or monitor that file for updates, etc.?

---

<div class="post-metadata">

**Author:** ![ethancrawford](https://avatars.discourse-cdn.com/v4/letter/e/a88e4f/32.png) [@ethancrawford](https://in-thread.sonic-pi.net/u/ethancrawford)\
**Post date:** [October 4, 2021, 1:26pm UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/8 "2021-10-04T13:26:50Z")

</div>

Several ways, perhaps… but not necessarily trivial 🙂

There is a Sonic Pi function `load_buffer(file_path)` which replaces the contents of the buffer where it itself was called. (Which of course is of no direct use if we are trying to trigger the process outside of the GUI, but maybe there’s a way to work around that somehow and call other code that makes it act the same way).

Or perhaps it’s necessary to go lower level and try to hook into the same server code that is used at start up to load the buffers 🤷‍♂️

---

<div class="post-metadata">

**Author:** ![robin.newman](https://avatars.discourse-cdn.com/v4/letter/r/76d3ee/32.png) [@robin.newman](https://in-thread.sonic-pi.net/u/robin.newman)\
**Post date:** [October 4, 2021, 3:15pm UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/9 "2021-10-04T15:15:34Z")

</div>

Just a thought. You might find it useful the sonic-pi-cli gem to run an external text file in Sonic Pi. This will superimpose on whatever is already running. You can send a stop command first if you want a fresh start.  
You could then edit this file externally to sonic-pi in a different editor , which might be easier. You can at least get directly at the text source file. You have to work on the same machine as SP is running on.  
BTW the existing sonic-pi-cli gem will need updating to run with SP4.0beta and above as the log file structures have changed and the relevant port to communicate on has to be extracted differently. I have a trial version running here with that setup.

I did a project several years ago which produced a jukebox which could select files to be run on Sonic Pi pretty instantly. It was controllable using TouchOSC, and used the sonic-pi-cli to play selected files.

---

<div class="post-metadata">

**Author:** ![blipson](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/blipson/32/1772_2.png) [@blipson](https://in-thread.sonic-pi.net/u/blipson)\
**Post date:** [October 4, 2021, 3:50pm UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/11 "2021-10-04T15:50:16Z")

</div>

What on earth is “sonic-pi-cli gem”?

---

<div class="post-metadata">

**Author:** ![robin.newman](https://avatars.discourse-cdn.com/v4/letter/r/76d3ee/32.png) [@robin.newman](https://in-thread.sonic-pi.net/u/robin.newman)\
**Post date:** [October 4, 2021, 5:22pm UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/12 "2021-10-04T17:22:02Z")

</div>

> **[GitHub - Widdershin/sonic-pi-cli: A simple command line interface for Sonic...](https://github.com/Widdershin/sonic-pi-cli)**
>
> A simple command line interface for Sonic Pi, written in Ruby - GitHub - Widdershin/sonic-pi-cli: A simple command line interface for Sonic Pi, written in Ruby

OOPS types corrected  
A command line utility you can install to enable commands like ruN\_file to be sent to SP. you can use this in a script which codes a file and sends and runs it in Sonic Pi.

---

<div class="post-metadata">

**Author:** ![blipson](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/blipson/32/1772_2.png) [@blipson](https://in-thread.sonic-pi.net/u/blipson)\
**Post date:** [October 4, 2021, 11:31pm UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/13 "2021-10-04T23:31:31Z")

</div>

Thanks—I’d never heard of gems before. I still don’t know what “chords a file” means.

Interestingly, you can control SPI directly from an emacs shell buffer.

```ruby
Parsing documentation for sonic-pi-cli-0.2.0
Installing ri documentation for sonic-pi-cli-0.2.0
Done installing documentation for osc-ruby, sonic-pi-cli after 0 seconds
2 gems installed

```

How do you read the installed documentation?

---

<div class="post-metadata">

**Author:** ![ethancrawford](https://avatars.discourse-cdn.com/v4/letter/e/a88e4f/32.png) [@ethancrawford](https://in-thread.sonic-pi.net/u/ethancrawford)\
**Post date:** [October 5, 2021, 1:37am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/14 "2021-10-05T01:37:45Z")

</div>

> I still don’t know what “chords a file” means.

I believe that was a typo. Robin was just talking about a way that Sonic Pi has to send bulk amounts of code to the server by calling a single function - `run_file(file_path)` will tell the Sonic Pi server to execute the entire contents of the file at `file_path`.

> How do you read the installed documentation?

One way: notice where you shared the above command line output it talks about something called `ri`? That is a command line utility for reading Ruby documentation. Here’s a guide that describes it:

> **[Learn How to Blog and Build Websites for Profit!](https://heyblogging.com)**
>
> Ready to take your blogging skills to the next level? Learn how to build a website that generates income and sets you up for success.

---

<div class="post-metadata">

**Author:** ![blipson](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/blipson/32/1772_2.png) [@blipson](https://in-thread.sonic-pi.net/u/blipson)\
**Post date:** [October 5, 2021, 2:58am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/15 "2021-10-05T02:58:57Z")

</div>

> [@ethancrawford](#):
>
> One way: notice where you shared the above command line output it talks about something called `ri` ? That is a command line utility for reading Ruby documentation. Here’s a guide that describes it:

yeah, I’d guessed that (after also trying `man`), but I get:

```ruby
% ri sonic-pi-cli
Nothing known about .sonic-pi-cli

% ri sonic-pi-cli-0.2.0
Nothing known about sonic-pi-cli-0.2

```

What am I still missing?

---

<div class="post-metadata">

**Author:** ![ethancrawford](https://avatars.discourse-cdn.com/v4/letter/e/a88e4f/32.png) [@ethancrawford](https://in-thread.sonic-pi.net/u/ethancrawford)\
**Post date:** [October 5, 2021, 3:34am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/16 "2021-10-05T03:34:53Z")

</div>

Oh right - well, it seems no documentation is automatically generated that way.  
That message about ri must be a default message that occurs whether or not there is actually any available.  
The ri tool is able to display documentation generated with `RDoc` - so you _could_ use RDoc to generate basic documentation (RDoc inspects your source code and automatically parses things like class names, function definitions, etc) and then run `gem server` which runs a local web page that displays links to information about your local gems, including documentation.  
Honestly though, if you’re just after basic usage of the gem, you’ll probably get enough of an idea by looking at the official source repo ([GitHub - Widdershin/sonic-pi-cli: A simple command line interface for Sonic Pi, written in Ruby](https://github.com/Widdershin/sonic-pi-cli)).

---

<div class="post-metadata">

**Author:** ![blipson](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/blipson/32/1772_2.png) [@blipson](https://in-thread.sonic-pi.net/u/blipson)\
**Post date:** [October 5, 2021, 3:48am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/17 "2021-10-05T03:48:19Z")

</div>

> [@ethancrawford](#):
>
> if you’re just after basic usage of the gem, you’ll probably get enough of an idea by looking at the official source repo

yeah. it works great, actually.

---

<div class="post-metadata">

**Author:** ![Widdershin](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/widdershin/32/2123_2.png) [@Widdershin](https://in-thread.sonic-pi.net/u/Widdershin)\
**Post date:** [October 5, 2021, 4:18am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/18 "2021-10-05T04:18:30Z")

</div>

Glad to hear it 🙂

You might also like [GitHub - lpil/sonic-pi-tool: 🎻 Controlling Sonic Pi from the command line](https://github.com/lpil/sonic-pi-tool), which has a faster startup time due to being written in Rust, and has a few more features.

---

<div class="post-metadata">

**Author:** ![blipson](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/blipson/32/1772_2.png) [@blipson](https://in-thread.sonic-pi.net/u/blipson)\
**Post date:** [October 5, 2021, 4:22am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/19 "2021-10-05T04:22:25Z")

</div>

> [@robin.newman](#):
>
> This will superimpose on whatever is already running. You can send a stop command first if you want a fresh start.

I think stopping, then loading anew isn’t going to work for me. I need to be able to make small edits to a running buffer, then hit reload so that the changes take effect on the next beat. Is there a way to get standard reload behavior from the command line? Replace rather than superimpose, I guess you could say.

---

<div class="post-metadata">

**Author:** ![blipson](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/blipson/32/1772_2.png) [@blipson](https://in-thread.sonic-pi.net/u/blipson)\
**Post date:** [October 5, 2021, 6:31am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/20 "2021-10-05T06:31:53Z")

</div>

sonic-pi-tool reports `Sonic Pi server NOT listening on port 4557`.

I get:

```ruby
> sonic-pi-tool start-server
Sonic Pi server booting...

Using primary protocol: udp
Detecting port numbers...
Listen port: 4557
  - OK
Scsynth port: 4556
  - OK
Scsynth send port: 4556
  - OK
OSC cues port: 4560
Port 4560 unavailable. Perhaps Sonic Pi is already running?

```

then

```ruby
> sonic-pi-tool check
Sonic Pi server NOT listening on port 4557

```

---

<div class="post-metadata">

**Author:** ![ethancrawford](https://avatars.discourse-cdn.com/v4/letter/e/a88e4f/32.png) [@ethancrawford](https://in-thread.sonic-pi.net/u/ethancrawford)\
**Post date:** [October 5, 2021, 8:24am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/21 "2021-10-05T08:24:20Z")

</div>

Perhaps your versions of Sonic Pi and sonic-pi-tool are incompatible with each other 🤷‍♂️

---

<div class="post-metadata">

**Author:** ![samaaron](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/samaaron/32/7_2.png) [@samaaron](https://in-thread.sonic-pi.net/u/samaaron)\
**Post date:** [October 5, 2021, 8:49am UTC](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024/22 "2021-10-05T08:49:18Z")

</div>

This is very much likely to be the case. Sonic Pi’s internal language runtime server stopped listening on a fixed port such as 4557 quite a while ago and now randomises the port number to increase security.

Also, v4-BETA contains significantly reworked internals which would likely require an update from external tools such as this to work effectively (although things are still in flux at this stage).

It is the hope that getting a nice command line tool will both be possible and easier in the future and not be so brittle, but it hasn’t been a core development focus.

[Next page](https://in-thread.sonic-pi.net/t/feasible-way-to-modify-text-in-buffer-via-external-controller/6024.md?page=2)
