BASICally: a new module for writing code within Rack

The 3rd version (2.0.5) is now live in the library. Unlike the previous revision, this has many features suggested on this thread, which I have loosely attempted to credit below. Changes include:

  • Many UI changes:
    • STYLE knob is smaller, elements moved.
    • Now have nine INx ports instead of six.
    • The minimum width is now one “hole” smaller, and this hides the editing window.
    • Can enter a title for a module (via the menu) that shows up above the IN ports. Handy for stating what role the module plays in the patch.
    • Added menu option to change the status light from green/red to blue/orange. (@cosinekitty, et al)
    • And added new screen color options.
  • Added ‘elseif’. E.g., “IF a == 5 THEN … ELSEIF a == 4 THEN … “ (@FiroLFO)
  • Added methods about the environment, sample_rate() and connected(). (@FiroLFO)
  • Added methods for random number generation, random() and normal(). (@FiroLFO)
  • Added single dimension arrays, and a simple way to set a range of values. (@main.tenant, @k-chaffin @FiroLFO) As it turned out, the 0-index/1-index question was moot; these arrays don’t care what you use.

Note the simple Tape Loop demo made from an array.

And a small request, if I may; I’d like to add some Presets to the next version, so if you have BASICally Presets that you’ve written that you find useful/fun/interesting, please do send them to me, either by uploading them in this thread or reaching out to me at vcv@stochastictelegraph.com. Feel free to include a link or reference back to yourself in the script comments!

And I’m not done working on this…but the upcoming change (multithreading) is so unusual that I’ll probably do an early release on this topic to gather feedback before submitting. Stay tuned…

6 Likes

:star_struck:

Many nice and useful features there!

Just a quick question though. How come that we have 9 inputs and 4 outputs? Why not 8 and 4? Or 9 and 6? Just curious…

image

(In general I think I need more outputs than inputs.)

Follow the leader (8 poly ins / 8 poly outs.)

The author did merge the v2 PR - but it’s not submitted to the library. I’ve had no replies from the author, when I suggested adopting the plugin. The donationlink is disabled. I hope VCV (the company) will help get this plugin back in Rack V2 (or update VCV-Prototype adding polyphony and v2 compatability)

2 Likes

@FiroLFO I started out as 4 and 4, but I quickly felt constrained by these limits. These are the goals I’m balancing:

  • Conserve width. I made the module resizable, which helps with this a lot, but I still like to treat width on the rack as a resource to be mindful of.
  • More inputs than outputs. My reasons for doing so include A) noting that I often ran out of inputs when doing small programs, but not outputs and B) pulling up the module browser and noting that inputs outnumber outputs by, say 3x to 5x. Now admittedly, modules do this without expecting all of them to be used at the same time, whereas a BASICally user would typically only using inputs for what they need. Still though, I feel like more outputs are easy to simulate; run a second copy of BASICally with the same inputs and make their outputs be computed differently.
  • My gut feeling that data processing generally consists of distilling large numbers of inputs into a few outputs.

All that said, I might decide to bump the OUTs up to 6, if I don’t find another use more compelling for the space around them. I’ve noticed that, since there’s nowhere to “print” internal values, having a spare OUT to send them to is handy.

And your question got me thinking that some form of expanders for ports, dials, sliders might be worthwhile; although having lots of inputs makes that less incumbent on me. There’s lots of lovely controllers one could plug into it without me having to make them, although I haven’t found quite what I want yet (my wish list: compact width, nameable dials and ranges). And as I’ve said earlier in this topic, I don’t love expanders (yet).

That’s my reasoning, for what it is worth.

@Jens.Peter.Nielsen I too would love to see some brave soul port that over.

1 Like

Thank you for the detailed answer! It’s interesting to read how you approached these design decisions.

I would certainly encourage you to add some outputs.

Maybe one more comment: I find it strange that pressing Home/End takes you to the beginning/end of the script. I’d feel it more natural having Home/End taking to the beginning/end of the line.

I’m also wondering what’s the best way to loop through a array. I assume the length of the array needs to be pre-programmed, right?

I haven’t really worked on the editor’s key bindings much (apart from making up/down work!). Home/End’s current behavior is coming from the default TextField class, which I cloned to make my editor class. It’s a bit aggravating to think about, since VCV captures a lot of the keys (e.g., PgUp/PgDn move the whole patch); not that I think that’s bad, but a text-editor within VCV is a little hamstrung.

In fact, I didn’t know that Home/End did anything in the editor until you wrote this :). But perhaps I’ll return to the editor at some point, although, phew, it’s not much fun to work on. Text editors are harder than they look!

The length of an array is never set. One surprising principle of this language is that there cannot be runtime errors; there’s no way to report them, and “stopping” just because of some programming error is not what a user in a music-making system wants. So all things that are normally breaking errors (dividing by zero, accessing at some index never set) just have defined behavior and carry on.

The one exception, of course, is that programs can stall (e.g., while extending the vector long enough to accommodate index 10,000,000, if you set it). I just encountered the thread on priority inversion, and, yeah, I’ve got some stuff to work on there (primarily around compiling on the main thread).

So if you want your code to work better and you expect to maybe write to foo[10000000], I’d currently suggest that the first thing your code does is set the largest index in the array you expect (e.g., foo[10000000] = 0.1); it might stall then, but at least it won’t be stalling later. The next release will make “initialization” code like that MUCH easier to write.

mahlen

1 Like

How could you have a priority inversion? Do you have the audio thread acquire a lock? That is of course strictly “forbidden”. Looking at the code quickly the only lock I see is in the GMOCK test stuff.

My concern is that I’m doing an unknown amount of work during compilation. And the version in development does some allocations with “new”, which I understood to be a source of priority inversion. Am I mistaken? Malloc was mentioned as not having bounded time, is the same not true for ‘new’?

oh, no, you are correct - every implementation of new I’ve seen calls malloc, and ends up locking a mutex. So, yeah, you are not supposed to call malloc/new ever on the audio thread. You can either ignore the problem, or do all the allocations on some other thread. The latter is what I do when I need/want to malloc/new in the audio processing code.

@k-chaffin, @Andre_M, and anyone who has opinions, I have an early-beta version I’d like you to try.

I’ve been working on some functionality I’ve been calling “multithreading”, for lack of a better term. It allows the user to create multiple “blocks” of code that can run in parallel.

It’s working, so far as I can tell, though I suspect some cases haven’t been tested. but I’d love some pre-release confirmation that the design is reasonable and not terribly confusing. Or more likely, I’d like to hear where the design needlessly prevents useful functionality and how I could improve it; or, you know, that it outright doesn’t work.

The builds are here. The docs have been updated a bit, but I’d take suggestions on what needs to be sharper.

Briefly, this introduces two new functions, start() and trigger(), two new commands, CLEAR ALL and RESET, and some new structures that are the meat of the this change.

To make you want to look at the docs, here’s a few examples:

' Two beats, one making 40 pulses per second, one making 2.
' Note that they do drift out of phase because there are 40 NEXT/second
' vs two NEXT/second, and those cost the first loop 40/sample_rate()ths of a second
' every second.
' Not sure how to address this.
for i = 0 to 39
  out1 = 2
  wait 10
  out1 = 0
  wait 15 - 1000 / sample_rate()
next

also
for i = 0 to 1
  out2 = -2
  wait 10
  out2 = 0
  wait 490 - 1000 / sample_rate()
next
end also
WHEN START()
a[0] = { -1, 3, -3, 1, 2, -2, 5, -4 }
for b = 0 to 7
  c[b] = sin(a[b])
next
END WHEN

ALSO
for loop = 0 to 7
  out1 = a[loop] 
  out2 = c[loop]
  wait 1
next
END ALSO
' A trigger to IN9 resets the speed the notes are played.
FOR n = 0 TO 3
  out1 = note[n]
  WAIT pause_length
NEXT

WHEN start() or trigger(in9)
note[0] = { c3, g3, c4, c4 }  ' The notes in my score.
pause_length = random(100, 1000)  '  How fast we play the notes.
RESET  ' Force main block to restart now
END WHEN

@k-chaffin, what you’ve been asking for is now:

WHEN trigger(in9)
  RESET
END WHEN

Love to hear what you all think.

Mahlen

1 Like

I downloaded and installed V2.0.5 . I will try to take a look at it tomorrow. I’m pretty involved in something else, so I am not sure how much time I will spend on it.

Just looking at what you wrote above, I like the triggered reset.

Is the new build V2.0.5? Just trying to tell if the download worked.

Oh, uh, yeah, I haven’t updated the version number in the config before doing that build. For clarity, I’ve now done that, and put 2.0.6 builds here.

No hurry, BTW. While fixing the priority inversion on compilation, I realized that the Bison+Flex compiler isn’t reentrant* , and I expect that might take some time to fix.

  • When I load a patch with six BASICally instances in it, only a couple of them will compile correctly.

I am a bit stupid, I don’t know how to download the plugin from there, haha. Maybe I should have an account on github to download stuff… Can you drop it on google drive?

1 Like

Ah, good to know on the version. I was able to see the additional ports so figured I had the correct version.

I’m going to try out using BASICally in my current drum machine patching efforts so I can look into it more deeply while making progress on my drum patches using Ohmer QuadPercs and my drum patterns from Meander for Windows from 25-36 years ago.

For some reason, when I install from this location for Windows, I still get 2.0.5 .

If this shows “Fix”, does that mean that I still do not have the 2.0.6 version?

BTW, I deleted your plugin from my plugins folder before I downloaded and installed the V2.0.6 Window build that you linked to. I did this before the START() test above.

I just noticed that now the Fix message is highlighting the a[0] = {} line:

did you use a carriage return in the middle of the array contents or is the module doing word wrapping?

I just copied and pasted from Mahlen’s examples above. Maybe that is not allowed? I bet it has to do with the current module width. Just increasing module width did not fix it. Re-pasting the code now has me back to the Fix message on WHEN START() .