Best way to send a sound as a parameter?

I want to pass sounds as parameters to functions, but, for example, sample, midi_not_on, :e2 all get played with different playback syntax. What’s the best way for dealing with that? A different play function for each sound type?

What’s more, when I pass a sample like this:

define :PlayMe do |sound|
  4.times do  

PlayMe (sample :drum_cymbal_pedal)

The sample plays the first time, but not in subsequent loops. Print out shows something about the sound going from “pending” to “destroyed,” which clued me in to the fact that I’m not clear on what’s happening.

This is because the returned result of the sample command is itself a playing ‘node’ in the sound server (scsynth)'s graph of sound objects. sample :drum_cymbal_pedal asks the server to play a sample, which adds a node to the sound graph/queues it up; the node becomes active at the time the sound is scheduled to play, and when the sound has finished playing, the node is ‘destroyed’.
Here, you pass the result of all this (the actual sound node) into the other function. What you no doubt intended to do was ask Sonic Pi to play a sample multiple times in the function; so you need to call sample four times.

define :PlayMe do |sound|
  4.times do  
    sample sound

PlayMe (:drum_cymbal_pedal)

So you’re saying that I’m passing to PlayMe the result of the call to sample, and not somehow telling PlayMe what I want it to play (right?). In that case, the sound is getting played (once) when PlayMe is called so that there’s nothing left for it to play during its four loops.

If I have that right, then how do I specify in a parameter what sound I want a function to use? In my non-toy version, I send the function a rhythm so that it will play a sound in that rhythm. The function contains its own call to sample. But now I want to be able to send the function both the rhythm and tell the function what sound it should use for that rhythm so that I can change sounds and rhythms that way while live coding. Do I need to pass the sound as a string, then have the function parse the string?

You have it correct :slight_smile:

A simple way is like I have demonstrated above: to pass in the name of or path to the sample as the parameter that is later passed to sample. You can pass the name/path in to PlayMe as an extra parameter in addition to the rhythm.

1 Like

Oh, duh! I misread your response as literally repeating my same call to PlayMe, but now I see the difference, and how yours doesn’t force evaluation of sample before ever entering the function. I guess I could also pass e2, etc. So for MIDI, I can pass :e2, velocity, and channel. Then the function decides on how to play :e2 (MIDI or not) based on, for example, whether velocity and channel are non-zero. Is that about the best way to have one function play different sound types?

No worries :slight_smile:
It’s entirely a matter of personal preference really. That is one way - to make the decision based on the presence of several midi specific parameters for example; another could be to just pass in a parameter that explicitly states what kind of sound we’re wanting to play, and another parameter that is just a generic map of options; like:
PlayMe(:midi, (map note: :e2, velocity: X, channel: Y)) or
PlayMe(:synth, (map note: e2, synth: :saw)), etc
and parse these parameters in the actual PlayMe function.

1 Like

…Although, it looks like it’s not currently possible to easily use a map as a way to pass options to the sample et al sound functions. It’s still idiomatic Sonic Pi syntax to just do something like:
PlayMe(:synth, note: e2, synth: :saw)
and then in PlayMe, it could even just be as simple (depending on your needs) as:

sample(opts) if sound_type == :sample
synth(opts) if sound_type == :synth
midi(opts) if sound_type == :midi
1 Like