Array of buses in superCollider - supercollider

I have a Synth generated with a do:
(
SynthDef(\siny, { arg freq, outBus=0; Out.ar( outBus, SinOsc.ar(freq!2,0,0.2) ) } ).send(s);
SynthDef(\filter, { arg cFreq,q=0.8, inBus; Out.ar( 0, BPF.ar(In.ar(inBus), cFreq!2, 1/q ) ) } ).send(s);
)
(
~sourceOut = Bus.audio(s);
~sine_Group = ParGroup.new;
z = [100,500,1000,1500,250];
{
z.do({ arg val; Synth.head(~sine_Group, \siny, [\freq: val, \outBus: ~sourceOut]) });
z.do({ arg val; Synth.after(~sine_Group, \filter, [\inBus: ~sourceOut, \cFreq: 200] ) });
}.play;
)
Right now, my understanding is that, output of multiple instances of Synth \siny get mixed in the bus ~sourceOut, and goes as an input into synth \filter
What i actually want to do is to have a one-to-one connection between the multiple instances of \siny and \filter.. Could I use an array of busses to connect them? If so, how do I do that?

Yes you can. Here I've modified your code minimally. First I made ~sourceOut an array of Busses rather than a single Bus. Second, inside the do loops I made use of the fact that the main iteration functions in SuperCollider can provide a second index argument as well as each item itself. Thirdly I use that index argument to select the desired Bus:
(
z = [100,500,1000,1500,250];
~sourceOut = z.collect{ Bus.audio(s) };
~sine_Group = ParGroup.new;
{
z.do({ arg val, index; Synth.head(~sine_Group, \siny, [\freq: val, \outBus: ~sourceOut[index]]) });
z.do({ arg val, index; Synth.after(~sine_Group, \filter, [\inBus: ~sourceOut[index], \cFreq: 200] ) });
}.play;
)
Depending on your needs, you might also like to look at NodeProxy which is useful for prototyping and live coding, and provides some tricks for plugging synths' output into each other.

Related

How to compare enum in arduino?

I am facing an issue with arduino, since I want to change the state of my device using an enum, but it doesn't seeem to work, my code looks like below. I am not entirely sure where it goes wrong, I think as well that the comparison between settingTo and toP2P could be wrong?
Thanks in advance!
String toP2P = "503250"
String toABP = "414250";
String settingTo = LoRa_Tx.dataRX.substring(indx);
if( settingTo == toP2P ) {
//switching to P2P
Serial.println("current mode 1 "+(String) LoRa_Tx.current_modeRxTx);
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaMod){
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaMod;
}
} else if(settingTo == toABP){
//switching to ABP
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaWan){
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaWan;}
}
}
My class has the enum defined as
typedef enum modeRxTx{LoRaMod, LoRaWan, Idle} ;
modeRxTx current_modeRxTx = Idle;
In general, you should avoid the String class, as it will eventually cause problems. However, given that the LoRa_Tx appears to have a String member, here is one way to watch for those two modes:
if ((indx > -1) && (LoRa_Tx.dataRx.length() >= indx+5)) {
const char *settingTo = &LoRa_Tx.dataRx.c_str()[ indx ];
if ( strncmp_P( settingTo, PSTR("503250"), 6 ) == 0 ) {
//switching to P2P
Serial.print( F("current mode 1 ") ); // <-- saves RAM!
Serial.println( LoRa_Tx.current_modeRxTx );
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaMod) {
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaMod;
}
} else if ( strncmp_P( settingTo, PSTR("414250"), 6 ) == 0 ) {
//switching to ABP
if(LoRa_Tx.current_modeRxTx != LoRa_Tx.LoRaWan) {
LoRa_Tx.current_modeRxTx = LoRa_Tx.LoRaWan;
}
}
}
Instead of creating a substring, it just makes a pointer to the actual characters of data_Rx. The c_str() function returns a pointer to the first character (zero-based index) or the String, and the [ indx ] is the first of the mode number characters. Finally, the & is a pointer to the first mode number character.
Next, it uses a standard library function, strncmp_P (documented here), to compare those mode number characters with the modes you are looking for, and it only compares up to 6 characters. You don't say if there's a delimiter after "503250", so I don't know if "50325076" is possible and should be rejected.
The strncmp_P expects to get a PROGMEM string as the second argument, not just a const char *, so that's what the PSTR macro does. This saves RAM because the PSTR will be stored and compared from FLASH memory (aka PROGMEM). The Serial.print statements should use the F() macro for the same reason.

Passing an argument to a SynthDef doesn't register when synth is initialized

I have a simple SynthDef where I want to use the CCIn class, like so:
(
SynthDef(\lfo_sin, {|bus, amp, myArg|
var m = CCIn.new;
var v = [300, 700, \exp].asSpec;
var sig = SinOsc.ar(m.kr(0, myArg, v), mul:amp);
Out.ar(bus, sig);
}).add;
)
When I instantiate it like so y = Synth(\lfo_sin, [\bus, 0, \amp, 1, \myArg, 71]);, to match with the MIDI CC on my MIDI controller, I am not able to use the CCIn.kr method like I should.
If I however directly type in the MIDI CC when I define the SynthDef like so:
(
SynthDef(\lfo_sin2, {|bus, amp|
var m = CCIn.new;
var v = [300, 700, \exp].asSpec;
var sig = SinOsc.ar(m.kr(0, 71, v), mul:amp);
Out.ar(bus, sig);
}).add;
)
everything runs like it should and I am able to control the frequency using my MIDI controller.
Why does this behavior happen and how can I modify my code so that I can pass in the MIDI CC when initializing the synth or setting the argument afterwards?
If you take a look at the source for CCIn, you can see it's doing something a bit more complex than an ordinary UGen:
kr { |chan = 0, num = 0, spec = \amp, lag = 0.05|
var outArray = [chan, num, spec, lag].flop.collect{ |args|
var ch, n, sp, lg;
# ch, n, sp, lg = args;
(sp.asSpec.map( In.kr(this.prGetBus(ch, n).index) ).lag3(lg))
};
if (outArray.size>1) {^outArray} {^(outArray[0])} //fix to work with muliout
Specifically, this...
this.prGetBus(ch, n)
is using the provided channel and number (ch and n) to look up the Bus from which it can read the MIDI data (see prGetBus). It's doing this lookup as part of BUILDING the SynthDef, not RUNNING the Synth, so once it's been built the bus it's reading from is pretty much fixed. The CCIn quark obscures some fairly complex things under the hood in order to behave as a simple UGen, so it's unlikely you'll easily be able to get the behavior you're looking for.
Here are a few alternatives.
1. Write your MIDI data to a bus yourself
// One for each cc number
~ccBusses = 127.collect({
Bus.control(s, 1);
});
// A midi responder that sets the value of the right bus
MIDIdef.cc(\cc, {
|value, cc|
~ccBusses[cc].set(value);
}, ccNum: (0..127) ) // meaning: all cc values
// Once those are set up, to map a cc to a new synth use:
Synth(\mySynth, args:[\freq, ~ccBusses[10].asMap]);
2. Using the Connection quark
// Create a value between 100..2400, controlled by MIDI
~freq = MIDIControlValue(spec:ControlSpec(100, 2400));
~freq.cc_(10); // cc number 10
// Run your synth
~note = Synth(\mySynth, args:[\freq, ~freq]);
// Connect the value of ~freq to the \freq argument of your synth. Now, MIDI changes will be broadcast to your synth.
~freq.signal(\value).connectTo(~note.argSlot(\freq));

Connecting multiple stages of parallel synths, with array of buses, in superCollider

When I have 2 stages of multiple parallel synths, I am able to connect it with an array of buses. (Thanks to Dan S for the answer to a previous question). When there is a 3 stage, this doesn't seem to work.
(
SynthDef(\siny, { arg freq, outBus=0; Out.ar( outBus, SinOsc.ar(freq!2,0,0.2) ) } ).send(s);
SynthDef(\filter, { arg cFreq,q=0.8, inBus, outBus=0; Out.ar( outBus, BPF.ar(In.ar(inBus), cFreq!2, 1/q ) ) } ).send(s);
)
(
var z = [100,500,1000,1500,200];
~sourceOut = z.collect{ Bus.audio(s) };
~sineOut = z.collect{ Bus.audio(s) };
~sine_Group = ParGroup.new;
~myGroup = ParGroup.new;
{
z.do({ arg val, index; Synth( \siny, [\freq: val, \outBus: ~sourceOut[index]], ~sine_Group ) });
z.do({ arg val, index; Synth.after(~sine_Group, \filter, [\inBus: ~sourceOut[index], \outBus: ~sineOut[index],\cFreq: 200, \q: 20 ], ~myGroup) });
z.do({ arg val, index; Synth.after(~myGroup, \filter, [\inBus: ~sineOut[index], \cFreq: 200, \q: 20]) });
}.play;
)
Another harm that I am doing here is, everytime I stop and run the synth, new instances of busses are created and eventually run out of audio buses. How can I solve this?
There are a number of issues with your code (some irrelevant with your question):
a. send(s) is a reminiscent of the past, these days simply add is preferable - you may consult the documentation for their differences.
b. it's not a good practice to mix local variables var with environmental ones (such as ~sourceOut) unless there is some good reason.
c. .collect(func) (or directly collect{/*function body here*/}) when send to an array results to another array where each element is the result of the func with the respective element of the original array passed as an argument. So here:
var z = [100,500,1000,1500,200];
~sourceOut = z.collect{ Bus.audio(s) };
~sineOut = z.collect{ Bus.audio(s) };
you don't use the original numbers anywhere, you just create two arrays containing 5 Audio buses each. Directly doing so would be less confusing and more explicit:
~sourceOut = Array.fill(5,{Bus.audio(s)});
~sineOut = Array.fill(5,{Bus.audio(s)});
d. there's no point in calling z.do three times.. you can call it just once and put the rest in the same function.
e. check you routings... You have two parallel groups and you're merely saying that I want these synths on that group and these others after that other group.. What you really want to say is that I want these Synths after those Synths on that group.
f. you don't free your Buses or your Synths when done... this is a memory leak :)
g. you call play on a function that want to evaluate really... you should call value instead.
This code does produces sound and cleans up everything when don, note however that the result is pretty boring because you've filtered all the higher-end.
s.waitForBoot({ // this is a routine
var frequencies = [100,500,1000,1500,200];
var sources = Array.fill(frequencies.size,{Bus.audio(s)});
var filters = Array.fill(frequencies.size,{Bus.audio(s)});
var parGroups = Array.fill(2,{ParGroup.new});
var sineSynths;
var firstOrderFilters;
var secondOrderFilters;
SynthDef(\siny, {
arg freq, outBus=0;
Out.ar( outBus, SinOsc.ar(freq!2,0,0.2));
}).add;
SynthDef(\filter, {
arg cFreq,q=0.8, inBus, outBus=0;
Out.ar( outBus, BPF.ar(In.ar(inBus), cFreq!2, 1/q ) )
}).add;
s.sync; // wait for the synthdefs to load
frequencies.do{ arg freq, index;
sineSynths = sineSynths.add( Synth(\siny, [\freq: freq.postln, \outBus: sources[index]],
parGroups[0])); // create synths and add them in the sineSynths Array
firstOrderFilters = firstOrderFilters.add(
Synth.after(sineSynths[index], \filter, [\inBus: sources[index],
\outBus: filters[index], \cFreq: 200, \q: 20 ], parGroups[1]));
secondOrderFilters = secondOrderFilters.add(
Synth.after(firstOrderFilters[index], \filter, [\inBus: filters[index],
\outBus: 0, \cFreq: 200, \q: 20 ], parGroups[1]));
};
10.wait; // wait 10 seconds;
// clean up everything
sineSynths.do{arg i; i.free};
firstOrderFilters.do{arg i; i.free};
secondOrderFilters.do{arg i; i.free};
sources.do{arg i; i.free};
filters.do{arg i; i.free};
});

'Open' - undeclared identifier

Does somebody know why this code inside a .mqh file throws the error 'Open' - undeclared identifier?
It seems like Open, Close, High, Low functions aren´t "detected" in my library. ( Other system functions like Print() are properly loaded ).
bool isBlueCandle( int candle ) export {
return Open[candle] < Close[candle];
}
Not exactly, neither 1:1 copy, nor any MODs, return any error:
//+------------------------------------------------------------------+
//| isBlueCandle TESTs MetaLang.exe: Build 1154 |
//+------------------------------------------------------------------+
bool isBlueCANDLE_TEST( int candle ) export
{
return Open[candle] < Close[candle];
}
bool isBlueCANDLE_TEST2( int candle ) export {
return Open[candle] < Close[candle];
}
bool isBlueCANDLE_TEST3( const int candle ) export {
return Open[candle] < Close[candle];
}
bool isBlueCANDLE_TEST4( const int candle ) export {
return( Open[candle] < Close[candle] );
}
As posted in the comment above, the missing context would help trace the root-cause for your stated issue.
Post a complete copy of the MetaLang.exe Error-description.
Use mouse-right-click + copy ( in MetaLang.exe-Toolbox window on [Error]-page + paste that complete description on StackOverflow )
As an example:
return value of 'OrderModify' should be checked
FOREX_SimpleSAR_EA_msMOD_0.00.mq4 227 19
Just for a clarity sake:
MQL4 recognises both functions ( Print() ) and other objects ( Open ) with specific access-protocol to work with them. In case of functions, one passes "arguments" compatible with the function´s expectations.
Open, High, Volume et al, are not functions, but Arrays, the more, these arrays are special and carefully constructed in the internal MT4-engine, so as to provide a very fast & very efficient manipulation.
MetaQuotes call this a TimeSeries-object, a reversed-stepping-index into
( otherwise normal ) array.
So, your function isBlueCandle() is indeed a function, however, internally it does not call a function, but it compares a cell-values of Open ( the [anIntIndexAsPtrIntoTimeSeriesOrderedARRAY]-*referenced cell )
against a value of Close ( namely the [anIntIndexAsPtrIntoTimeSeriesOrderedARRAY]-*referenced cell ) to construct a bool which the isBlueCandle() function is about to return.

STL Sort with no deal breaker

Our game engine uses STL sort for sorting a whole range of different objects using the template sort function. As I understand the requirements for the comparison logic is that you have to write it on the basis that it may internally do a reverse sort ( ie reverse the pairing eg. from (a,b) to (b,a) ).
So typically my compare functions looks like this:
bool CompareSubGroupReqsByDescendingFillPriority::operator()
( const ScenSubGroupReq& lhs,
const ScenSubGroupReq& rhs ) const
{
if( lhs.mFillPriority > rhs.mFillPriority ) return true;
else if( lhs.mFillPriority < rhs.mFillPriority ) return false;
else return lhs.mForceGroup->ObjectID() > rhs.mForceGroup->ObjectID();
}
I refer to the "else" statement as the "deal breaker" - ie. it must be able to resolve a case where both lhs and rhs are the same. I typically use the object ID where we are sorting persistent objects.
My question is how can you create a deal breaker when you are sorting non-persistent objects that are simple data types (eg shorts)?
Here is the example I am wrestling with:
bool
ComparePhaseLineIndexesByAscendingValue::operator() ( const short lhs,
const short rhs ) const
{
if( lhs < rhs ) return true;
else if( lhs > rhs ) return false;
else
{
// should never be here as no two phase lines should have the same index
FPAssert( false );
return false;
}
}
Trouble is I have been testing this and found a valid case where where I can have two phase lines with the same index. I don't care which of the entries with the same value ends up first.
What would you advise?
Technically the sort function takes the less than operator. What you are trying to do seems to have something to do with making sure that even equal objects are returned in a specific order. Generally you would just do
bool
ComparePhaseLineIndexesByAscendingValue::operator() ( const short lhs,
const short rhs ) const
{
return lhs < rhs;
}
Though generally a comparison function isn't required for builtin types (I think it's any type with a < operator specified).

Resources