Pseq creation in a for loop

Hello everyone,

This is my first question on the forum. I have tried to figure out many solutions, also searched for similar topics on this forum but without success.

I have a function that creates an array of Pbind. The arguments of the Pbind are \freq and \dur, where each one is a Pseq taking as argument an array of values. The problem is that the index j is updated before the Pseq reads the array, so it gives the error ERROR: ListPattern (Pseq) requires a non-empty collection; received List[ ]. Here is the code snippet:

(
~soundCells = List.new(size: 0); // list of Pbind
)

(
var cells = List.new(size: 0); //freqs of the notes
var durs = List.new(size: 0); //duration of the notes

    //Function to create sound cells from osc messages
	~createSoundCells = {
		arg freqs, durs;
		var freqBuffer, durBuffer, j;
		j = 0; // index to cycle through cells
		freqBuffer = List.new(size: 0);
		durBuffer = List.new(size: 0);
		~soundCells.clear; // clear current sound cells
		for(0, freqs.size,{
			arg i;
			// Add new list for buffering frequency and duration of the cell notes
			freqBuffer.add(List.new(size:0));
			durBuffer.add(List.new(size:0));
			//verify if we have "end of cells" characters
			if ((freqs[i] == 0.0 && durs[i] == 1.0),
				{
					~soundCells.add(Pbind.new(
						\freq, Pseq(freqBuffer[j]),
						\dur, Pseq(durBuffer[j]);
					));
					j = j + 1; // increase cell counter
				},
				{
					//case we have to add freq and dur to buffer for the current sound cell
					freqBuffer[j].add(freqs[i]);
					durBuffer[j].add(durs[i]);
			});
		});
	};
)

I think this is a synchronous/asynchronous execution problem, but I still haven’t found any way to make it work.

Thanks in advance for every suggestion.

Hi!
I can see that the problem is that you are not feeding a list into Pseq, but a value (nil). \freq, Pseq(freqBuffer[j]), freqBuffer is a List, freqBuffer[j] is an element of that list.
Sorry, I now see that freqBuffer is a list of lists :slight_smile:

I admit I don’t fully understand what you are after: is it like you want to send an array of phrases and have all the phrases played in parallel?

In this case it would be much easier to first create your phrases and then the Pseqs. When you create a Pseq with an array, you can’t change the array later. (I mean, if you add or remove to it, the Pseq will not know).
Otherwise, if you need to dynamically change the sequences, you have to use something like Plazy and environment variables.

Here is an example of just getting parallel phrases played. I will keep your process to parse the phrases from arrays of freqs and durs, but I’m quite sure there are simpler techniques. Again, it depends on knowing more in detail the bigger picture of what you are after :slight_smile:

~createSoundCells = {
    arg freqs,durs;
    // parse phrases:
    // split phrases when freq==0 and dur==1
    // we get an array of "notes" for each phrase
    // where a "note" is an array containing [freq,dur]
    var phrases = [freqs,durs].flop.separate{|fd| fd == [0,1]};
    
    // filter out empty phrases
    phrases = phrases.select{|p| p.size>1};
    
    // create a Pbind for each phrase:
    ~soundCells = phrases.collect{|p|
        var freqs, durs;
        // drop last element (end character [freq:0,dur:1])
        // and get freqs and durs arrays
        # freqs, durs = p.drop(-1).flop;
        Pbind(
            \freq, Pseq(freqs),
            \dur, Pseq(durs);
        )
    }
}

Hi @elgiano, thanks for your reply! I tried your solution and seems to work great, thank you very much!

Yes, I want to create an array of phrases to be played by this method, where I use a Pspawner to start the phrases at random times to play them in a “random-like” manner without predefined time quantums:

// strategy to play the sound cells
~multiCellPlayer = Pspawner({ |sp|
	inf.do{
		~soundCells.size.do{
			arg i;
			sp.seq(~soundCells[i]);
			sp.wait(~forkTimes[i]);
			sp.suspendAll;
		}
	};
});

I have a processing application that sends me the freqs and durs values with two separate osc messages at regular time intervals, then a third osc message tells supercollider to call the createSoundCells function, where I have to parse the single phrases using the escape characters (0.0 for frequency and 1.0 for duration), as you already understood :smiley:

I’m not a supercollider expert but I will try to find a better way to achieve that :blush: