C++ conditional operator conversion help [GPL Code!]

Just starting out? Need help? Post your questions and find answers here.
AndyMK
Enthusiast
Enthusiast
Posts: 540
Joined: Wed Jul 12, 2006 4:38 pm
Location: UK

C++ conditional operator conversion help [GPL Code!]

Post by AndyMK »

I am trying to conver this to PB.

Code: Select all

env = rt * env + (1 - at) * ((fabs - env > 0) ? fbs - env : 0)
I have this but i am not sure if its correct as the result is not what i expect.

Code: Select all

If fabs - env > 0
    env = (rt * env + (1 - at)) * (fabs - env)
  Else
    env = 0
  EndIf
Last edited by AndyMK on Sun Sep 11, 2022 7:24 am, edited 1 time in total.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: C++ conditional operator conversion help

Post by infratec »

Maybe:

Code: Select all

If fabs - env > 0
  env = rt * env + (1 - at) * (fabs - env)
Else
  env = rt * env
EndIf
because

Code: Select all

((fabs - env > 0) ? fabs - env : 0)
generates only the last part of the term.

And I think you last sometimes an 'a' at fbs.
AndyMK
Enthusiast
Enthusiast
Posts: 540
Joined: Wed Jul 12, 2006 4:38 pm
Location: UK

Re: C++ conditional operator conversion help

Post by AndyMK »

Still not working but it could be a problem somewhere else. Here is the original code and my conversion below it.

C++

Code: Select all

typedef struct  {
	double samplerate_;		// sample rate(Hz)		48000
	double attackTime_;		// attack time(seconds)	0.05
	double releaseTime_;	// release time(seconds)0.02
	double holdTime_;		// hold time(second)	0.0003
	double threshold_;		// threshold_(dB)		-24
	//======
	double holdTimeCount;	// hold time count (points)
	double linearThreshold;	// linear threshold
	double at;				// attack time smoothing coefficient
	double rt;				// release time smoothing coefficient

	double attactCounter = 0;					// hold counter for attack time
	double releaseCounter = 0;					// hold counter for release time
	double x_env = 0;
	double gca = 0;
	double gs[2] = { 0 };
}
NoiseGate_t;

NoiseGate_t* newNoiesGate() {
	NoiseGate_t* obj = (NoiseGate_t*)malloc(sizeof(NoiseGate_t));
	memset(obj, 0, sizeof(NoiseGate_t));
	if (!obj)
	{
		return NULL;
	}
	return obj;
}
void setNoiseGate(NoiseGate_t* obj,float attackTime, float releaseTime, float threshold,float holdTime,float samplerate) {
	// samplerate		sample rate (Hz)		48000
	// attackTime		attack time (seconds)	0.05
	// releaseTime		release time (seconds)	0.02
	// holdTime			hold time (second)		0.0003
	// threshold		threshold (dB)			-24
	obj->attackTime_ = attackTime;
	obj->releaseTime_ = releaseTime;
	obj->threshold_ = threshold;
	obj->samplerate_ = samplerate;
	obj->holdTime_ = holdTime;

	obj->holdTimeCount = obj->holdTime_ * obj->samplerate_;
	obj->linearThreshold = powf(10.0f, obj->threshold_ / 20.0f);
	obj->at = exp(-logf(9) / (obj->samplerate_ * obj->attackTime_));
	obj->rt = exp(-logf(9) / (obj->samplerate_ * obj->releaseTime_));
}
NoiseGate_t* createNoiseGate(float attackTime, float releaseTime, float threshold, float samplerate) {
	NoiseGate_t* obj = newNoiesGate();
	if (!obj) {
		return NULL;
	}
	setNoiseGate(obj, attackTime, releaseTime, threshold, 0.0003,samplerate);
	return obj;
}
float runNoiseGate( NoiseGate_t* obj, float in,float& out) {
	double x_abs = in > 0? in : -in;
	// envelop detector  at = 0.02;rt = 0.01;  0.9977 = exp(-log(9) / (samplerate * 0.02));
	//obj->x_env = 0.9977 * obj->x_env + (1 - 0.9553) * ((x_abs - obj->x_env > 0) ? x_abs - obj->x_env : 0);
	obj->x_env = obj->rt * obj->x_env + (1 - obj->at) * ((x_abs - obj->x_env > 0) ? x_abs - obj->x_env : 0);

	if (obj->x_env < obj->linearThreshold)
	{
		obj->gca = 0;
	}
	else
	{
		obj->gca = 1;
	}

	if (obj->gca < obj->gs[0]) 
	{
		// attack mode
		obj->releaseCounter = 0;
		if (++obj->attactCounter < obj->holdTimeCount) 
		{
			// hold mode
			obj->gs[0] = obj->gs[1];
		}
		else 
		{
			obj->gs[0] = obj->at * obj->gs[1] + (1 - obj->at) * obj->gca;
		}
		obj->gs[1] = obj->gs[0];

	}
	else {
		// release mode
		obj->attactCounter = 0;
		if (++obj->releaseCounter < obj->holdTimeCount) 
		{
			// hold mode
			obj->gs[0] = obj->gs[1];
		}
		else 
		{
			obj->gs[0] = obj->rt * obj->gs[1] + (1 - obj->rt) * obj->gca;
		}
		obj->gs[1] = obj->gs[0];
	}
	// apply gain
	out = obj->gs[0] * in;
	return (obj->gs[0] * in);

}
int freeNoiseGate(NoiseGate_t* obj) {
	if (!obj)
	{
		return -1;
	}
	free(obj);
	return 0;
}
PB:

Code: Select all

Structure noisegate
	samplerate.f;		// sample rate(Hz)		48000
	attackTime.f;		// attack time(seconds)	0.05
	releaseTime.f;	// release time(seconds)0.02
	holdTime.f;		// hold time(second)	0.0003
	threshold.f;		// threshold_(dB)		-24
	;//======
	holdTimeCount.f;	// hold time count (points)
	linearThreshold.f;	// linear threshold
	at.f;				// attack time smoothing coefficient
	rt.f;				// release time smoothing coefficient

	attactCounter.f; = 0;					// hold counter for attack time
	releaseCounter.f; = 0;					// hold counter for release time
	x_env.f; = 0;
	gca.f; = 0;
	gs.f[2]; = { 0 };
EndStructure

Procedure setNoiseGate(*obj.noisegate, attackTime.f, releaseTime.f, threshold.f, holdTime.f, samplerate.f)
	
  *obj\attackTime = attackTime
	*obj\releaseTime = releaseTime
	*obj\threshold = threshold
	*obj\samplerate = samplerate
	*obj\holdTime = holdTime

	*obj\holdTimeCount = *obj\holdTime * *obj\samplerate
	*obj\linearThreshold = Pow(10.0, *obj\threshold / 20.0)
	*obj\at = Exp(-Log(9) / (*obj\samplerate * *obj\attackTime))
	*obj\rt = Exp(-Log(9) / (*obj\samplerate * *obj\releaseTime))
	
EndProcedure

Procedure.l createNoiseGate(attackTime.f, releaseTime.f, threshold.f, samplerate.f)
  
  *obj = AllocateStructure(noisegate)
  
	If Not *obj
		ProcedureReturn #False
	EndIf
	
	setNoiseGate(*obj, attackTime, releaseTime, threshold, 0.0003, samplerate)
	ProcedureReturn *obj
	
EndProcedure

Procedure.f runNoiseGate(*obj.noisegate, in.f)
  
  x_abs.f = Abs(in)
  
	;// envelop detector  at = 0.02;rt = 0.01;  0.9977 = exp(-log(9) / (samplerate * 0.02));
  ;//obj->x_env = 0.9977 * obj->x_env + (1 - 0.9553) * ((x_abs - obj->x_env > 0) ? x_abs - obj->x_env : 0);
    
  If x_abs - *obj\x_env > 0
    *obj\x_env = (*obj\rt * *obj\x_env + (1 - *obj\at)) * (x_abs - *obj\x_env)
  Else
    *obj\x_env = *obj\rt * *obj\x_env
  EndIf
      
  If *obj\x_env < *obj\linearThreshold
    *obj\gca = 0
  Else
    *obj\gca = 1
  EndIf
  
  If *obj\gca < *obj\gs[0]
    ;// attack mode
    *obj\releaseCounter = 0
    If *obj\attactCounter+1 < *obj\holdTimeCount
      ;// hold mode
      *obj\gs[0] = *obj\gs[1]
    Else 
      *obj\gs[0] = *obj\at * *obj\gs[1] + (1 - *obj\at) * *obj\gca
    EndIf
    *obj\gs[1] = *obj\gs[0]
  Else
    ;// release mode
    *obj\attactCounter = 0
    If *obj\releaseCounter+1 < *obj\holdTimeCount
      ;// hold mode
      *obj\gs[0] = *obj\gs[1]
    Else 
      *obj\gs[0] = *obj\rt * *obj\gs[1] + (1 - *obj\rt) * *obj\gca
    EndIf
    *obj\gs[1] = *obj\gs[0]
  EndIf
  ;// apply gain
  out.f = *obj\gs[0] * in
    
  ProcedureReturn *obj\gs[0] * in

EndProcedure

Procedure.l freeNoiseGate(*obj.noisegate)
  
	If Not *obj
		ProcedureReturn #False
	EndIf
	
	FreeMemory(*obj)
	ProcedureReturn #True
	
EndProcedure
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: C++ conditional operator conversion help

Post by infratec »

My version:

Code: Select all

Structure NoiseGate
  samplerate.d      ; sample rate(Hz)		48000
  attackTime.d      ; attack time(seconds)	0.05
  releaseTime.d     ; release time(seconds)0.02
  holdTime.d        ; hold time(second)	0.0003
  threshold.d       ; threshold_(dB)		-24
                    ;======
  holdTimeCount.d   ;	hold time count (points)
  linearThreshold.d ;	linear threshold
  at.d              ; attack time smoothing coefficient
  rt.d              ; release time smoothing coefficient
  
  attactCounter.d   ;	hold counter for attack time
  releaseCounter.d  ; hold counter for release time
  x_env.d           ;
  gca.d             ;
  gs.d[2]           ;
EndStructure




Procedure.i newNoiesGate()
  
  Protected *obj.NoiseGate
  
  
  *obj = AllocateStructure(NoiseGate)
  
  ProcedureReturn *obj
  
EndProcedure




Procedure setNoiseGate(*obj.noisegate, attackTime.f, releaseTime.f, threshold.f, holdTime.f, samplerate.f)
  
  *obj\attackTime = attackTime
  *obj\releaseTime = releaseTime
  *obj\threshold = threshold
  *obj\samplerate = samplerate
  *obj\holdTime = holdTime
  
  *obj\holdTimeCount = *obj\holdTime * *obj\samplerate
  *obj\linearThreshold = Pow(10.0, *obj\threshold / 20.0)
  *obj\at = Exp(-Log(9) / (*obj\samplerate * *obj\attackTime))
  *obj\rt = Exp(-Log(9) / (*obj\samplerate * *obj\releaseTime))
  
EndProcedure




Procedure.i createNoiseGate(attackTime.f, releaseTime.f, threshold.f, samplerate.f)
  
  *obj = newNoiesGate()
  
  If Not *obj
    ProcedureReturn #Null
  EndIf
  
  setNoiseGate(*obj, attackTime, releaseTime, threshold, 0.0003, samplerate)
  ProcedureReturn *obj
  
EndProcedure




Procedure.f runNoiseGate(*obj.noisegate, in.f, *out.Float)
  
  Protected x_abs.d
  
  
  x_abs = Abs(in)
  
  ;// envelop detector  at = 0.02;rt = 0.01;  0.9977 = exp(-log(9) / (samplerate * 0.02));
  ;//obj->x_env = 0.9977 * obj->x_env + (1 - 0.9553) * ((x_abs - obj->x_env > 0) ? x_abs - obj->x_env : 0);
  If x_abs - *obj\x_env > 0
    *obj\x_env = *obj\rt * *obj\x_env + (1 - *obj\at) * (x_abs - *obj\x_env)
  Else
    *obj\x_env = *obj\rt * *obj\x_env
  EndIf
  
  If *obj\x_env < *obj\linearThreshold
    *obj\gca = 0
  Else
    *obj\gca = 1
  EndIf
  
  If *obj\gca < *obj\gs[0]
    ;// attack mode
    *obj\releaseCounter = 0
    *obj\attactCounter + 1
    If *obj\attactCounter < *obj\holdTimeCount
      ;// hold mode
      *obj\gs[0] = *obj\gs[1]
    Else 
      *obj\gs[0] = *obj\at * *obj\gs[1] + (1 - *obj\at) * *obj\gca
    EndIf
    *obj\gs[1] = *obj\gs[0]
  Else
    ;// release mode
    *obj\attactCounter = 0
    *obj\releaseCounter + 1
    If *obj\releaseCounter < *obj\holdTimeCount
      ;// hold mode
      *obj\gs[0] = *obj\gs[1]
    Else 
      *obj\gs[0] = *obj\rt * *obj\gs[1] + (1 - *obj\rt) * *obj\gca
    EndIf
    *obj\gs[1] = *obj\gs[0]
  EndIf
  ;// apply gain
  *out\f = *obj\gs[0] * in
  
  ProcedureReturn *obj\gs[0] * in
  
EndProcedure




Procedure.i freeNoiseGate(*obj.noisegate)
  
  If Not *obj
    ProcedureReturn #False
  EndIf
  
  FreeStructure(*obj)
  
  ProcedureReturn #True
  
EndProcedure
AndyMK
Enthusiast
Enthusiast
Posts: 540
Joined: Wed Jul 12, 2006 4:38 pm
Location: UK

Re: C++ conditional operator conversion help

Post by AndyMK »

:)

Thanks. I removed the second parameter from the runnoisegate function and return the result. It works fine. I'm checking to see where i went wrong.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: C++ conditional operator conversion help

Post by infratec »

My hint:

Code: Select all

if (++obj->attactCounter < obj->holdTimeCount)
You have to do + 1 before the if. Else it is not really added.
AndyMK
Enthusiast
Enthusiast
Posts: 540
Joined: Wed Jul 12, 2006 4:38 pm
Location: UK

Re: C++ conditional operator conversion help

Post by AndyMK »

I already tried that before i posted :lol:
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: C++ conditional operator conversion help

Post by idle »

shouldn't that be

Code: Select all

	
	If  x_abs - *obj\x_env > 0 
	  *obj\x_env = *obj\rt * *obj\x_env + (1 - *obj\at) * (x_abs - *obj\x_env)
	Else 
	  *obj\x_env = 0
	EndIf 


infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: C++ conditional operator conversion help

Post by infratec »

Why ?

Code: Select all

env = rt * env + (1 - at) * ((fabs - env > 0) ? fbs - env : 0)
Has 2 posibilities:

Code: Select all

env = rt * env + (1 - at) * (fbs - env)
And

Code: Select all

env = rt * env + (1 - at) * (0)
The second case can be reduced to:

Code: Select all

env = rt * env
(In my opinion, I didn't checked it with a C compiler.
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: C++ conditional operator conversion help

Post by Olli »

(inserted... I Did not see infratec)
After having read the infratec message, after a read of ms doc page and after having read idle syntax, below is my version (to be nested in a With *obj: EndWith part)

Code: Select all

\x_env * \rt + (1 - \at) * Bool(x_abs > \x_env) * (x_abs - \x_env)
(and after checked 'at' field type... oosh... headaches...)

Shorter version :

Code: Select all

env * rt + (1 - at) * Bool(fabs > env) * (fabs - env)
Note : the operator 'a ? b : c' is not unable to be transformed in macro and/or procedure. In this exemple, yes, we can, because fabs (*obj\x_abs) is not used after this source code line. But if we would need this value after this, the cpp 'a ? b : c' operator returns a result and also changes the variable. This requires a Shared directive, as we are not able to get which variable is in the procedure argument and might be so modified. Also a macro does not allow us to nest a variable modifier op in an arithmetic or boolean expression.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: C++ conditional operator conversion help

Post by infratec »

Bool() is dangerous, because it is not guaranteed that #True is 1 and #False is 0.
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: C++ conditional operator conversion help

Post by mk-soft »

infratec wrote: Sat Sep 10, 2022 10:41 am Bool() is dangerous, because it is not guaranteed that #True is 1 and #False is 0.
The Bool() function had always returned 1 for true. This is also the case with C-Backend.

Code: Select all


x = 10
a = Bool(x >= 10)
Debug a

; ASM
;  x = 10
;   MOV    qword [v_x],10
; ; a = Bool(x >= 10)
;   MOV    r15,qword [v_x]
;   CMP    r15,10
; _Bool0:
;   JL    .False
;   MOV    rax,1
;   JMP   .True
; .False:
;   XOR    rax,rax
; .True:
;   MOV    qword [v_a],rax
; ;

; C-Backend
; // x = 10
; v_x=10;
; // a = Bool(x >= 10)
; v_a=(((v_x>=10))?1:0);
; /
And #True is defined as '1'

PB-Help
Syntax
Bool(<boolean expression>)
Description
Bool can be used to evaluate a boolean expression outside of regular conditional operator like If, While, Until etc. If the boolean expression is true, it will return #True, otherwise it will return #False.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: C++ conditional operator conversion help

Post by Olli »

I think infratec wanted to be careful to this :

Code: Select all

Macro EquToIf(a, b) ; if a is true returns b eval
Bool(a) * (b) ; the parenthesis over b
EndMacro
And, for sure, concerning the floating point types...

Code: Select all

Bool(a.d)
... is dangerous (if allowed by the compiler)as

Code: Select all

Bool(a.d = b.d) ; dangerous also
Bool(a.d <> b.d) ; dangerous also
Equ ('a=b') and unequ ('a<>b') ops treat only derivable (continous function, without geometric breakthrough) expression.

However...

Code: Select all

Bool(a.d < b.d)
; or
Bool(a.d > b.d)
... allows us to compare and handle the result of Bool(), but only if the general algo does not require precision.

Code: Select all

Bool(a.d < b.d) ; returns 1 if a is near below b, else returns 0.
So, what is really dangerous for equalities test is sometimes no dangerous for unequalities.

Searching the english version of ms doc page, that Microsoft prevents it to be changed, I went to w3school very few commercial, and better than Microsoft.

w3school allowed me to check my conclusion above (last message) is false and cpp 'a ? b : c' operator can be converted to a pureBasic macro.

Code: Select all

Macro Ternary(a, b, c)
Bool(a) * (b) + (1 - Bool(a) ) * (c)
EndMacro
Other version :

Code: Select all

Macro iTernary(a, b, c) ; only for integers !!!
(0 - Bool(a) ) & (b) | (Bool(a) - 1) & (c)
EndMacro
Last edited by Olli on Sat Sep 10, 2022 11:46 am, edited 4 times in total.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: C++ conditional operator conversion help

Post by infratec »

@mk-soft
Yes, and exactly this is the point:

Bool() returns always #True and #False.
But it is no where written that #True is always and for ever 1 and #False is always and for ever 0.
Else you could read in the help:
If the boolean expression is true, it will return 1, otherwise it will return 0.
But it is not.
#True and #False are constants and why? Because the real value of them maybe changed.
Maybe like in C, where a positive return value is 0 and -1 is an error. Who knows.
And therefore it is unsafe to use Bool() as 1 or 0. Doesn't matter what there current value represents.

Btw. have you ever used something like that:

Code: Select all

while x < 100
 x + #True
wend
Why not?
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: C++ conditional operator conversion help

Post by Olli »

@infratec

What you say is not false.

Code: Select all

#cTrue = ~0
Debug Bool(#cTrue) ; returns 1 (Long term support)
And, if a C boolean result should appear, maybe cBool() or other would be added.
A true set to 1 is better mixed with doubles (mul op : x*1)
While a true set to -1 is better mixed with integers (bitwise and op : x&(-1) ).

I would do the note that 1 in a signed bit is -1.
Post Reply