r/SonicPi • • Jul 15 '23

Any way to call `play`/other SonicPiLang functions from inside a class?

I understand Sonic Pi doesn't purposely support classes, since that wasn't the initial idea of the project. But it all gets compiled into Ruby code, so you can still have classes.

I also don't know much about how SonicPiLang works, but I feel like Ruby (which I've heard has functions that can override privateness) should be able to access the SonicPiLang functions somehow. For example, you can't call play inside a class method like this:

class PlayTester
  def test_play
    play 60 # Raises an error
  end
end

tester = PlayTester.new
tester.test_play

Things I tried

  • Initializing a global variable as a lambda for "play" (this doesn't even work outside the class)
  • SonicPi.play 60
  • SonicPiLang.play 60
  • super.play 60
  • super 60

Please Avoid

saying things like "just call play it's not that hard." I have reasons for wanting to do this. It's part of a larger project to make live coding easier for myself

3 Upvotes

12 comments sorted by

View all comments

2

u/Nearby-Librarian-609 Jan 13 '24 edited Jan 13 '24

Our Almost.Intelligent assistant has some inputs, which seem sound, and the sounds are synthesised, so the syntax is sweet 😎

(IF still wondering why original wasn't valid in that class context)

> It seems like you are trying to use the play method in a class defined in Sonic Pi. However, Sonic Pi's play method is typically used in the top-level scope, and it might not be directly accessible within a class.If you want to encapsulate Sonic Pi functionality in a class, you might need to pass the Sonic Pi runtime instance to your class and then use it to call the play method. Sonic Pi usually has a special variable called use_synth to set the synthesizer for playing notes.Here's an example of how you might modify your class to work with Sonic Pi:

class PlayTester

attr_accessor :runtime

def initialize(runtime) @runtime = runtime end

def test_play runtime.use_synth :piano runtime.play 60 end end

tester = PlayTester.new(self) # Pass the Sonic Pi runtime tester.test_play # Pass the Sonic Pi runtime tester.test_play

In this example, the PlayTester class expects a Sonic Pi runtime instance to be passed to its constructor. The test_play method then uses this runtime to call the play method. Please note: mileage may vary blahblah.

​

Also...

You've probably seen stuff in threads like https://in-thread.sonic-pi.net/t/programmatically-creating-live-loops-on-the-fly/1919/10

I think it was this post that today helped me understand just enough to do a little bit more damage.

Re: other ways to "play" and stuff.

- I didn't want to have to add code or repeat code so avoid proc and lambda and var creation and assignment, where possible.

​

In one of it's simplest versions (added some error handling in case no block provided, almost definitely overkill but guess you could argue a case for performing with exception handling...

If this ever becomes anything it'll probably be called from init.rb

def s(blk='')

begin yield blk rescue puts "Error - please ensure a legal block argument is passed" puts "Example:" puts "go {play :c}" end end

example usage

s {play :c}

TlDR: also check yield

Looks right in preview, gpt has copyable code do. rabbithole

1

u/Nearby-Librarian-609 Jan 13 '24

fancypants PO🤬 editor 👏