Hi,
I’m doing a project communicating SC and Arduino.
It’s an interactive narrative (composed by audio files) that is controled by the Arduino.
I made an array of audio buffers and I want to control the order that they will play according to a digital input.
(
s.latency= 0.05;
b.do{|x| x.free}; //free all previous buffers
b= [ //edit paths - any number of files - make sure mono
Buffer.read(s,"D:/Users/Daniela Tinoco/Music/domenico_mini.wav"),
Buffer.read(s,"D:/Users/Daniela Tinoco/Music/bixiga_mini.wav"),
Buffer.read(s,"D:/Users/Daniela Tinoco/Music/curumin_mini.wav"),
Buffer.read(s,"D:/Users/Daniela Tinoco/Music/tincoas_mini.wav"),
Buffer.read(s,"D:/Users/Daniela Tinoco/Music/russo_mini.wav")
];
SynthDef(\sample, {|out= 0, buf, rate= 1|
Out.ar(out, PlayBuf.ar(1, buf, rate, doneAction:2)!2);
}).add;
)
//test - looping through samples one after the other
(
Routine({
var index= 0;
var c= Condition.new;
inf.do{
var a= Synth(\sample, [\buf, b[index], \rate, 1]).register;
a.onFree{
("playing index:"+index).postln;
c.unhang;
};
c.hang;
index= index+1%b.size;
};
}).play;
)
How can I control the index value by the Osc msg value?
Hi Daniela, and welcome!
I’d like to help you but this is absolutely out of my reach
To make sure that we solve the right problem, I think we need to make the requirements a bit more specific first: will you
- send one OSC message that contains a complete sequence of indices to be played, or
- send successive OSC messages each containing a “next” index or list of indices to be played
In case of scenario 2, as soon as a new OSC message comes in, would you like to
- stop whatever is playing and start the newly received index immediately, or
- queue the received index and play it when it’s its turn to play (let the one that’s already playing finish first and the already scheduled ones play first), or
- let the currently playing buffer finish first, then start the most recently requested buffer playing, while forgetting about all the requests that came between starting the currently playing one and the most recently received one, or
- start to play the received buffer index immediately in parallel with other buffers already playing
(or something else still?)
Hi,
I’m sending successive OSC messages.
I would like to let the currently playing buffer finish first, then start the most recently requested buffer playing, while forgetting about all the requests that came between starting the currently playing one and the most recently received one.
I have a flowcharch of audios.
Ex.: The first audio will play, then, there will be two options. The second audio will be choosen according to the input value, and it will play immediately after the first one.
Is it more clear now?
Thanks for the help
Here’s one possibility, although perhaps more efficient ones can be thought of.
I probably should use a mutex to protect ~next_index
// this program block installs an OSC def that listens to OSC messages and triggers playing a buffer based on the arguments
(
s.waitForBoot({
// variable to remember the most recently requested index
~next_index = nil;
// flag to decide if new synth can start
~prevent_next = false;
//free all previous buffers
b.do{|x|
x.free
};
// load some buffers
b= [ //edit paths - any number of files - make sure mono
Buffer.read(s,"/home/development/supercollider/playindex/wavs/1.wav"),
Buffer.read(s,"/home/development/supercollider/playindex/wavs/2.wav"),
Buffer.read(s,"/home/development/supercollider/playindex/wavs/3.wav"),
Buffer.read(s,"/home/development/supercollider/playindex/wavs/4.wav"),
Buffer.read(s,"/home/development/supercollider/playindex/wavs/5.wav")
];
SynthDef(\sample, {|out= 0, buf, rate= 1|
Out.ar(out, PlayBuf.ar(1, buf, rate, doneAction:2)!2);
}).add;
s.sync;
// install an osc handler reacting to the playindex message; when an osc msg comes in, register the argumetn in ~next_index
n = NetAddr("127.0.0.1", 57120); // listen to messages on the local machine
OSCdef(\playindex, {
|msg, time, addr, recvPort|
~next_index = msg[1].asInteger;
~next_index.debug("Next index requested to play");
}, '/playindex', n); // def style
// in a thread, check if a new index is ready to be played
fork {
"Waiting for indices...".postln;
while ({true}) {
if (~next_index.notNil && ~prevent_next.not) {
var synth;
var index = ~next_index;
~prevent_next = true;
~next_index = nil;
index.debug("Start playing index");
synth = Synth(\sample, [\buf, b[index]]);
synth.onFree({
~prevent_next = false;
"Ready for new index to be played.".postln;
});
};
0.25.wait; // check every 0.25 seconds for a new buffer
};
};
});
)
// with the previous program running, we can send some messages to it to see if it works
// instead of sending things from inside supercollider, these could come from outside supercollider
(
m = NetAddr("127.0.0.1", 57120); // loopback
fork{
m.sendMsg("/playindex", 1);
1.wait;
m.sendMsg("/playindex", 4); // check that this one is overwritten by the next one
m.sendMsg("/playindex", 2);
5.wait;
m.sendMsg("/playindex", 0);
10.wait;
m.sendMsg("/playindex", 3);
};
)
1 Like
Thank you so much!
Now I have 2 other problems to solve:
-
All the buffers can be played in any time of the experience. The idea is to release some options according to the buffer played at the time;
-
I’m sending another OSC message that will be updating the audio rate. Writing the “synth.set” inside the “if” will only change the rate once, when the audio starts. How can I update it constantly?
Again: thank you so much for the help