Thanks a lot for your quick answer.
Why do you want to move the project out of SC ? Do you want to use another language ? I love the fact that it uses SC
The idea is to have Alga
as its own language with its own TUI / GUI paradigms, syntax, interface, etcâŚ
This is not going to happen anytime soon, and I am already very satisfied with SC as the âbackendâ for this project. One other option to consider is to ship custom scsynth
/ sclang
builds with an alga
language frontend. This might be the next step for the project, weâll see how it evolves!
Good luck for this awesole project ! I really find it easier to grasp than JITLib and my colleagues are starting to love it too !
New release: version 1.2.
This one comes up with the much anticipated feature of time interpolation! It is now in fact possible to interpolate the dur
parameter of an AlgaPattern
, or the entire tempo
of Alga
with the global Alga.interpTempo
method.
Also, lots of other features. Here is the full CHANGELOG
:
1.2
New features
-
AlgaPattern
: it is now possible to interpolate the'dur'
parameter!( Alga.boot({ //Pattern to modify a = AP(( def: { SinOsc.ar * EnvPerc.ar(release: 0.1) * 0.5 }, dur: 0.5 )).play(chans:2); //Metronome b = AP(( def: { EnvPerc.ar(release: SampleDur.ir); Impulse.ar(0) }, dur: 1 )).play(chans:2); }) ) //Using Env and resync a.interpDur(0.1, time: 5, shape: Env([0, 1, 0.5, 1], [2, 3, 4])) //No resync a.interpDur(0.5, time: 3, resync: false) //With resync + reset a.interpDur(Pseq([0.25, 0.25, 0.125], inf), time: 5, reset: true) //Other time params work too! a.interpStretch(0.5, time: 3, shape: Env([0, 1, 0.5, 1], [2, 3, 4]))
-
AlgaPattern
now supports scalar parameters. This is now the preferred way of interfacing withBuffer
parameters (checkExamples/AlgaPattern/03_Buffers.scd
).
Also, scalar parameters can be used for optimization reasons for parameters that need to be set only once at the trigger of theSynth
instance, without the overhead of the interpolator.( Alga.boot({ a = AP(( def: { SinOsc.ar(\f.ir) * EnvPerc.ar }, f: Pseq([440, 880], inf) )).play(chans: 2) }) ) //Change at next step a.from(Pseq([330, 660], inf), \f, sched: AlgaStep()) //Change at next beat a.from(Pseq([220, 440, 880], inf), \f, sched: 1)
-
AlgaPattern
andAlgaPatternPlayer
now supportPfunc
andPkey
.
All scalar and non-SynthDef parameters are now retrievable from any parameter. These are ordered alphabetically:( Alga.boot({ a = AP(( def: { SinOsc.ar(\f.kr) * EnvPerc.ar }, _f: 440, f: Pfunc { | e | e[\_f] } )).play(chans: 2) }) ) //Interpolation still works a.from(Pfunc { | e | e[\_f] * 2 }, \f, time: 3) //These can be changed anytime a.from(880, \_f, sched: AlgaStep())
-
AlgaPattern
: added thelf
annotator for functions in order for them to be declared asLiteralFunctions
.
These are used forkeys
that would interpret allFunctions
asUGen Functions
, while they however could represent aPfunc
orPif
entry:( Alga.boot({ a = AP(( //.lf is needed or it's interpreted as a UGen func def: Pif(Pfunc( { 0.5.coin }.lf ), { SinOsc.ar(\freq.kr(440)) * EnvPerc.ar }, { Saw.ar(\freq.kr(440)) * EnvPerc.ar * 0.5 } ), //No need to .lf here as 'freq' does not expect UGen functions like 'def' does freq: Pif( Pfunc { 0.5.coin }, AT({ LFNoise0.kr(10) }, scale: [440, 880]), Pseq([ AT { DC.kr(220) }, AT { DC.kr(440) }], inf) ) )).play(chans:2) }) )
-
AlgaSynthDef
: can now correctly store and retrieveAlgaSynthDefs
with thewrite
/load
/
store
calls. By default, these are saved in theAlgaSynthDefs
folder in theAlgaLib
folder,
but it can be changed to wherever. The definitions inAlgaSynthDefs
are automatically read at
the booting ofAlga
. Other definitions can be read with theAlga.readAll
/Alga.readDef
calls.
Bug fixes
- Major parser rewrite that leads to more predictable results and a larger amount of patterns supported.
Wow ! Another major release ! Congrats !
hi and thx @vitreo12.
Iâve got some questions about AlgaPattern inside AlgaProxySpace.
-
Iâm still not fully understand of whatâs going on under the hood of AP since itâs using an event instead of a habitual Pbind. Is it possible to use something like Plambda/Ppar/Plet/Pget combo or .collect({ |event| ⌠} chain to share data between patterns in Alga?
-
I found out that simple value sharing can be achieved with AlgaPatternPlayer, but I still canât figure out how to setup it correctly inside of an AlgaProxySpace. A .from method in the example below not working as it supposed to (according to Alga examples):
Server.killAll;
t = TempoClock(1).permanent_(true);
p = AlgaProxySpace.boot(clock: t);
(
AlgaSynthDef(\fb, {
var sig;
sig = SinOscFB.ar(\freq.kr(100), \fb.kr(0.5))!2;
sig = sig * Env.perc(\atk.kr(0.01), \rel.kr(0.5), 1.0, \crv.kr(-5.0)).kr(2);
}, sampleAccurate: true).add;
)
(
~app = AlgaPatternPlayer((
dur: Pwhite(0.1, 0.5, inf),
freq: Pseq([100, 300, 400, 500], inf),
fb: Pseq([0.0, 0.5, 1.0], inf)
)).play;
)
(
~p = AP((
def: \fb,
freq: ~app[\freq],
fb: ~app[\fb]
), player: ~app).play;
)
~app.from(0.5, \dur);
~app.stop;
~p.stop;
- Can you give an advice or share some examples of key/value sharing techniques between patterns in AlgaProxySpace?
Hello @wehrk!
Each AlgaPattern
has its own internal state, which cannot be shared as easily as you would with standard Pbinds
. AlgaPatternPlayer
is th only current way of sharing values across patterns.
I believe you are using an old version of Alga, cause your code actually works on the latest master. It is in fact possible to assign any class to environment variables of an AlgaProxySpace
, while it previously only allowed classes that were used as arguments for an AlgaNode
(Symbol, Function
) or AlgaPattern
(Event
). If you pull from master, youâll be fine with that code.
Regarding the AlgaPatternPlayer
, as said, is the only class that can be used to share values across AlgaPattern
s. Regardless, you can use Pfuncs
to retrieve values from anywhere in SC, so you can have your own âoutside of Algaâ way of dealing with values sharing.
thx @vitreo12 for the detailed response
Some points have become much clearer. Some not. The thing Iâm trying to do is to integrate AlgaPatternPlayer into AlgaProxySpace and make it possible to easily update any keys and re-evaluate the whole Pattern-Pbind/AlgaPattern-Event to instantly see/hear results. But when I re-evaluate the related AlgaPattern/AlgaPatternPlayer everything gets stuck. So it seems like the only option is to use .from messages if youâre working with AlgaPatternPlayer in AlgaProxySpace? Like that:
(
t = TempoClock(1).permanent_(true);
p = AlgaProxySpace.boot(server: s, clock: t);
)
(
AlgaSynthDef(\fb, {
var sig;
sig = SinOscFB.ar(\freq.kr(100), \fb.kr(0.5))!2;
sig = sig * Env.perc(\atk.kr(0.01), \rel.kr(0.5), 1.0, \crv.kr(-5.0)).kr(2);
}, sampleAccurate: true).add;
)
(
~app = AlgaPatternPlayer((
dur: 1
));
~app.play;
)
// update AlgaPatternPlayer keys here â´
(
~app.time = 5;
~app <<.dur 0.1;
~app <<.freq Pseq([100, 200, 300, 400, 500], inf);
)
(
~p = AP((
def: \fb
), sched: AlgaQuant(4), player: ~app);
~p.play;
)
// update AlgaPattern keys here â´
(
~p.it = 5;
~p <<.freq ~app.read({ | freq, fb | freq.postln; fb.postln; freq }, inf); // test to see what values i can extract from ~app
~p <<.amp 0.1;
)
What do you mean by âoutside of Algaâ? I can try this, but it only returns âdefaultâ key/value pairs â ( âlegatoâ: 0, âdurâ: 0.2, âdefâ: fb ). I can assume that you mean something more complex and non-trivial.
(
~p = (
def: \fb,
dur: 0.2,
freq: Pseq([100, 200, 300, 400, 500], inf),
amp: 0.1,
share: Pfunc({ | ev | ev.postln }) // returns only ( 'legato': 0, 'dur': 0.2, 'def': fb )
);
)
There is a misconception here about AlgaPatternPlayer
. It currently cannot be assigned new parameters if they were not declared in its body, this is why the code wonât work. Youâd have to provide an initial freq
entry for it:
(
~app = AlgaPatternPlayer((
dur: 1,
freq: 440
));
~app.play;
)
What I mean is that with a Pfunc
you can retrieve any value from SC:
(
~freqStream = Pseq([220, 440, 880], inf).asStream;
~p = AP((
def: \fb,
freq: Pfunc { ~freqStream.next }
));
~p.play;
)
I have actually pushed a change on develop
that will now allow you to define new entries even if they were not declared in the original Event
body. Your code now works without changes
Actually, this code works on my machine even if I donât provide an initial freq
. But it will only act like that if I specify .time for the whole AlgaPatternPlayer before providing new entries.
Got it. At first I thought of something else. Thank you!
New release: 1.3.0.
This one comes up with the new objects AlgaMonoPattern
and AlgaSequencer
. These allows to create monophonic sequencers to be used as modulation sources for AlgaNodes
and AlgaPatterns
. Check the help files for more information!
Hereâs the CHANGELOG
:
1.3.0
New features
-
AlgaMonoPattern
: a new class that implements a monophonic interpolated sequencer:( Alga.boot({ //Mono sequencer featuring AlgaTemps modulating at audio rate ~freqSeq = AlgaMonoPattern(( rate: \audio, chans: 2, in: Pseq([ AlgaTemp({ SinOsc.ar([Rand(1, 100), Rand(1, 100)]) }, scale: [Pwhite(220, 440), Pwhite(440, 880)]), [440, 660], 880 ], inf), time: Pwhite(0.01, 1), dur: Prand([0.125, 0.25, 0.5, 1], inf) )); //Mono sequencer featuring AlgaTemps modulating at audio rate ~ampSeq = AlgaMonoPattern(( rate: \audio, in: AlgaTemp({ SinOsc.ar(Rand(1, 1000)) }), time: Pwhite(0.01, 1), dur: Prand([0.5, 1, 2], inf) )); //The AlgaNode to modulate using both FM and AM ~sine = AlgaNode({ SinOsc.ar(\freq.ar(440!2)) }, [\freq, ~freqSeq, \amp, ~ampSeq]).play; }); )
-
AlgaSequencer
: a new class that implements a sequence ofAlgaMonoPatterns
:( Alga.boot({ //Poly sequencer featuring AlgaTemps modulating at audio rate ~seq = AlgaSequencer(( freq: ( rate: \audio, chans: 2, in: Pseq([ AlgaTemp({ SinOsc.ar([Rand(1, 100), Rand(1, 100)]) }, scale: [Pwhite(220, 440), Pwhite(440, 880)]), [440, 660], 880 ], inf), time: Pwhite(0.01, 1) ), amp: ( rate: \audio, in: AlgaTemp({ SinOsc.ar(Rand(1, 1000)) }), time: Pwhite(0.01, 1), ), dur: Prand([0.5, 1, 2], inf) )); //The AlgaNode to modulate using both FM and AM ~sine = AlgaNode({ SinOsc.ar(\freq.ar(440!2)) }, [\freq, ~seq.freq, \amp, ~seq.amp]).play; }); )
-
AlgaPattern
:'def'
now supportsArray
entries to create stacked voices:( Alga.boot({ a = AlgaPattern(( def: [{ SinOsc.ar(\freq.kr) }, { Saw.ar(\freq.kr * 0.25) }], amp: AlgaTemp({ EnvPerc.ar }), freq: Pseq([220, 440, 880], inf), dur: 0.5 )).play(2) }) )
-
AlgaNode
: trigger rate parameters are now supported:( Alga.boot({ z = AlgaNode({ var env = Env.perc(0.01, 1).kr(0, \trig.tr(1)); SinOsc.ar(440) * env; }).play(2) }) ) z <<.trig 1
hi, @vitreo12
Since the last update I cannot boot any of Alga
environments via
Alga.boot
and AlgaProxySpace.boot
. Right after generating definitions Iâm getting these messages:
(...)
-> Done!
-> an AlgaProxySpace
Booting server 'localhost' on address 127.0.0.1:57110.
NetAddr-Connect failed with exception: connect: Connection refused
NetAddr-Connect failed with exception: connect: Connection refused
NetAddr-Connect failed with exception: connect: Connection refused
(...)
WARNING: Couldn't connect to TCP address 127.0.0.1:57110
After the warning sign the Server
seems to be stuck in the booting phase. I tried to restart the machine, killing all servers, re-installing AlgaLib
, switching modes between UDP/TCP, but the error does not go away. While everything else works.
Iâm also noted that this behaviour happened before in the 1.2 versions, but evaluating Server.killAll
before the booting helped to resolve this behaviour. In the 1.3 versions killing the servers before booting wonât work.
I think this might be a problem with my system and not Alga
, but it happens only with AlgaLib
. I will be grateful for any help tips!
Hey! That hanging bug often happens when rebuilding the AlgaSynthDefs
on boot. I have pushed a fix on master that should take care of not rebuilding the definitions on every boot. Could you try it out?
Also, Alga
provides a forceBoot
function that will execute the Server.killAll
command for you before booting.
Thanks! The problem is gone with and without .forceBoot
.