|
@@ -29,6 +29,7 @@ laPropContainer* LA_PC_CHANNEL;
|
|
|
laNodeCategory* LA_NODE_CATEGORY_SYNTHESIZER;
|
|
|
laNodeCategory* LA_NODE_CATEGORY_SYSTEM_SOUND;
|
|
|
|
|
|
+laBaseNodeType LA_IDN_INPUT;
|
|
|
laBaseNodeType LA_IDN_FM;
|
|
|
laBaseNodeType LA_IDN_VCA;
|
|
|
laBaseNodeType LA_IDN_NOISE;
|
|
@@ -37,6 +38,7 @@ laBaseNodeType LA_IDN_SCOPE;
|
|
|
laBaseNodeType LA_IDN_ENVELOPE;
|
|
|
laBaseNodeType LA_IDN_QUANTIZE;
|
|
|
|
|
|
+laPropContainer* LA_PC_IDN_INPUT;
|
|
|
laPropContainer* LA_PC_IDN_FM;
|
|
|
laPropContainer* LA_PC_IDN_VCA;
|
|
|
laPropContainer* LA_PC_IDN_NOISE;
|
|
@@ -69,6 +71,47 @@ laPropContainer* LA_PC_IDN_QUANTIZE;
|
|
|
|
|
|
#define SAMPLE_RATE (MAIN.Audio->AudioSampleRate)
|
|
|
|
|
|
+void IDN_InputInit(laSynthNodeInput* n, int NoCreate){
|
|
|
+ INITPACKET(n->rTime); INITPACKET(n->rTrigger);
|
|
|
+ if(NoCreate){ return; }
|
|
|
+ n->OutTime=laCreateOutSocket(n,"TIME",LA_PROP_FLOAT|LA_PROP_ARRAY);
|
|
|
+ n->OutTrigger=laCreateOutSocket(n,"TRIGGER",LA_PROP_FLOAT|LA_PROP_ARRAY);
|
|
|
+ strSafeSet(&n->Base.Name,"Input");
|
|
|
+}
|
|
|
+void IDN_InputDestroy(laSynthNodeInput* n){
|
|
|
+ laDestroyOutSocket(n->OutTime); laDestroyOutSocket(n->OutTrigger); strSafeDestroy(&n->Base.Name); memFree(n->rTime); memFree(n->rTrigger);
|
|
|
+}
|
|
|
+int IDN_InputVisit(laSynthNodeInput* n, laNodeVisitInfo* vi){
|
|
|
+ LA_GUARD_THIS_NODE(n,vi);
|
|
|
+ LA_ADD_THIS_NODE(n,vi);
|
|
|
+ return LA_DAG_FLAG_PERM;
|
|
|
+}
|
|
|
+int IDN_InputEval(laSynthNodeInput* n){
|
|
|
+ laSynth*ss=MAIN.Audio->AudioEvalSynth;
|
|
|
+ real time=ss->EvalTime,target_time=time+(real)LA_SYNTH_PLEN/(real)MAIN.Audio->AudioSampleRate;
|
|
|
+ for(int i=0;i<LA_SYNTH_PLEN;i++){
|
|
|
+ real fac=(real)i/(real)LA_SYNTH_PLEN;
|
|
|
+ n->rTime[i] = tnsLinearItp(time,target_time,fac);
|
|
|
+ }
|
|
|
+ if(ss->EvalSamples==0){ n->rTrigger[0] = 10; }else{ n->rTrigger[0]=0; }
|
|
|
+ n->OutTime->Data=n->rTime; n->OutTrigger->Data=n->rTrigger; n->OutTime->ArrLen=LA_SYNTH_PLEN; n->OutTrigger->ArrLen=LA_SYNTH_PLEN;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+void IDN_InputCopy(laSynthNodeInput* new, laSynthNodeInput* old, int DoRematch){
|
|
|
+ if(DoRematch){ return; }
|
|
|
+ LA_IDN_OLD_DUPL(OutTime); LA_IDN_OLD_DUPL(OutTrigger);
|
|
|
+}
|
|
|
+void laui_InputNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
|
|
|
+ laColumn* c=laFirstColumn(uil); laSynthNodeInput*n=This->EndInstance;
|
|
|
+ LA_BASE_NODE_HEADER(uil,c,This);
|
|
|
+
|
|
|
+ laUiItem* b=laBeginRow(uil,c,0,0);
|
|
|
+ laUiItem* ui=laShowLabel(uil,c,"Synth",0,0); ui->Expand=1; ui->Flags|=LA_TEXT_ALIGN_RIGHT;
|
|
|
+ laShowNodeSocket(uil,c,This,"out_time",0)->Flags|=LA_UI_SOCKET_LABEL_E;
|
|
|
+ laShowNodeSocket(uil,c,This,"out_trigger",0)->Flags|=LA_UI_SOCKET_LABEL_E;
|
|
|
+ laEndRow(uil,b);
|
|
|
+}
|
|
|
+
|
|
|
void IDN_FMInit(laSynthNodeFM* n, int NoCreate){
|
|
|
INITPACKET(n->OutSamples);
|
|
|
if(NoCreate){ return; }
|
|
@@ -138,7 +181,7 @@ int IDN_VCAEval(laSynthNodeVCA* n){
|
|
|
n->Out->Data=n->OutSamples; n->Out->ArrLen=LA_SYNTH_PLEN;
|
|
|
if(!input){ memset(n->OutSamples,0,sizeof(real)*LA_SYNTH_PLEN); return 0; }
|
|
|
for(int i=0;i<LA_SYNTH_PLEN;i++){
|
|
|
- real useA=(inputamp?(inputamp[i]*n->rInfluence/10):1)*constamp;
|
|
|
+ real useA= inputamp?tnsInterpolate(1.0f,inputamp[i]/10.0f,n->rInfluence)*constamp:constamp;
|
|
|
n->OutSamples[i]= input[i]*useA;
|
|
|
}
|
|
|
return 1;
|
|
@@ -340,6 +383,7 @@ void IDN_EnvelopeInit(laSynthNodeEnvelope* n, int NoCreate){
|
|
|
n->Time=20; n->rAttack=1; n->rDelay=5; n->rSustain=5; n->rRelease=7; n->rGate=5;
|
|
|
}
|
|
|
if(!n->Gate){ n->Gate=laCreateInSocket("GATE",0); }
|
|
|
+ if(!n->Restart){ n->Restart=laCreateInSocket("RESTART",0); }
|
|
|
if(!n->OutSamples){ n->OutSamples=memAcquireSimple(sizeof(real)*LA_SYNTH_PLEN); }
|
|
|
n->Out->Data = n->OutSamples; n->Out->DataType = LA_PROP_FLOAT|LA_PROP_ARRAY; n->Out->ArrLen=LA_SYNTH_PLEN;
|
|
|
}
|
|
@@ -357,12 +401,14 @@ int IDN_EnvelopeVisit(laSynthNodeEnvelope* n, laNodeVisitInfo* vi){
|
|
|
if(LA_SRC_AND_PARENT(n->Sustain)){ laBaseNode*bn=n->Sustain->Source->Parent; LA_VISIT_NODE(bn,vi); }
|
|
|
if(LA_SRC_AND_PARENT(n->Release)){ laBaseNode*bn=n->Release->Source->Parent; LA_VISIT_NODE(bn,vi); }
|
|
|
if(LA_SRC_AND_PARENT(n->Trigger)){ laBaseNode*bn=n->Trigger->Source->Parent; LA_VISIT_NODE(bn,vi); }
|
|
|
+ if(LA_SRC_AND_PARENT(n->Restart)){ laBaseNode*bn=n->Restart->Source->Parent; LA_VISIT_NODE(bn,vi); }
|
|
|
LA_ADD_THIS_NODE(n,vi);
|
|
|
return LA_DAG_FLAG_PERM;
|
|
|
}
|
|
|
int IDN_EnvelopeEval(laSynthNodeEnvelope* n){
|
|
|
- int trigger_at=-1; real trig=n->bTrigger?n->bTrigger*100:-100;
|
|
|
+ int trigger_at=-1; real trig=n->bTrigger?n->bTrigger*100:-100; real res=0;
|
|
|
real* trigger; INPUTPACKET(trigger,n->Trigger); if(!trigger){ LA_GET_SRC_AS_VALUE(trig,n->Trigger); }
|
|
|
+ real* restart; INPUTPACKET(restart,n->Restart); if(!restart){ LA_GET_SRC_AS_VALUE(res,n->Restart); }
|
|
|
real *att,*del,*sus,*rel,*gat;
|
|
|
real attack=n->rAttack,delay=n->rDelay,sustain=n->rSustain,release=n->rRelease;
|
|
|
real gate = n->rGate; INPUTPACKET(gat,n->Gate); if(!gat) LA_GET_SRC_AS_VALUE(gate,n->Gate);
|
|
@@ -372,11 +418,12 @@ int IDN_EnvelopeEval(laSynthNodeEnvelope* n){
|
|
|
INPUTPACKET(rel,n->Release); if(!rel) LA_GET_SRC_AS_VALUE(release,n->Release);
|
|
|
attack=attack?pow(attack/10,2):0; delay=delay?pow(delay/10,2):0; release=release?pow(release/10,2):0;
|
|
|
for(int i=0;i<LA_SYNTH_PLEN;i++){
|
|
|
- if(trigger){ trig=trigger[i]; } if(gat){ gate=gat[i]; }
|
|
|
+ if(trigger){ trig=trigger[i]; } if(gat){ gate=gat[i]; } if(restart){ res=restart[i]; }
|
|
|
if(att){ attack=att[i]*n->iAttack+n->rAttack; }
|
|
|
if(del){ delay=del[i]*n->iDelay+n->rDelay; }
|
|
|
if(sus){ sustain=sus[i]*n->iSustain+n->rSustain; }
|
|
|
if(rel){ release=rel[i]*n->iRelease+n->rRelease; }
|
|
|
+ if(res){ n->Time=0; n->ReleaseTime=-10000; n->Triggered=0;}
|
|
|
if(!n->Triggered){ if(trig > gate){ n->Triggered = 1; n->Time = 0; n->ReleaseTime=10000; n->AtLevel=0; } }
|
|
|
else{ if(trig < gate-0.0001f){ n->Triggered = 0; n->ReleaseTime = n->Time; } }
|
|
|
if(n->Time < n->ReleaseTime){
|
|
@@ -430,6 +477,7 @@ void laui_EnvelopeNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laCol
|
|
|
laEndRow(uil,b);
|
|
|
b=laBeginRow(uil,c,0,0);
|
|
|
laShowSeparator(uil,c)->Expand=1;
|
|
|
+ laShowItem(uil,c,This,"in_restart")->Flags|=LA_UI_SOCKET_LABEL_E;
|
|
|
laShowItem(uil,c,This,"trigger")->Flags|=LA_UI_FLAGS_MOMENTARY|LA_UI_FLAGS_HIGHLIGHT;
|
|
|
laShowItem(uil,c,This,"out")->Flags|=LA_UI_SOCKET_LABEL_W;
|
|
|
laEndRow(uil,b);
|
|
@@ -521,8 +569,10 @@ int laEvalSynthGraphs(){
|
|
|
for(ss=MAIN.Audio->Synths.pFirst;ss;ss=ss->Item.pNext){
|
|
|
laSpinLock(&ss->Lock);
|
|
|
if(!ss->Playing){ laSpinUnlock(&ss->Lock); continue; }
|
|
|
- MAIN.Audio->AudioEvalSynth=ss; MAIN.Audio->AudioEvalTime=0;
|
|
|
+ MAIN.Audio->AudioEvalSynth=ss;
|
|
|
laRunPage(ss->Page,1);
|
|
|
+ ss->EvalSamples += LA_SYNTH_PLEN;
|
|
|
+ ss->EvalTime = (real)ss->EvalSamples/MAIN.Audio->AudioSampleRate;
|
|
|
laSpinUnlock(&ss->Lock);
|
|
|
any=1;
|
|
|
}
|
|
@@ -677,7 +727,9 @@ int OPINV_laSynthPlay(laOperator* a, laEvent* e){
|
|
|
|
|
|
laRebuildPageEval(ss->Page);
|
|
|
|
|
|
- laSpinLock(&ss->Lock); ss->Playing=play; laSpinUnlock(&ss->Lock);
|
|
|
+ laSpinLock(&ss->Lock);
|
|
|
+ ss->Playing=play; if(!play){ ss->EvalSamples=0; ss->EvalTime=0; }
|
|
|
+ laSpinUnlock(&ss->Lock);
|
|
|
|
|
|
ma_device_start(&MAIN.Audio->AudioDevice); laNotifyInstanceUsers(ss);
|
|
|
return LA_FINISHED;
|
|
@@ -890,6 +942,12 @@ void laInitAudio(){
|
|
|
laAddIntProperty(pc,"__move","Move Slider","Move Slider",LA_WIDGET_HEIGHT_ADJUSTER,0,0,0,0,0,0,0,0,0,laset_AudioChannelMove,0,0,0,0,0,0,0,0,LA_UDF_IGNORE);
|
|
|
}
|
|
|
|
|
|
+ pc=laAddPropertyContainer("la_node_synth_input", "Synth Input Node", "Synthesizer time and trigger input",0,laui_InputNode,sizeof(laSynthNodeInput),lapost_Node,0,1);
|
|
|
+ LA_PC_IDN_INPUT=pc; laPropContainerExtraFunctions(pc,0,0,0,0,laui_DefaultNodeOperationsPropUiDefine);
|
|
|
+ laAddSubGroup(pc,"base","Base","Base node","la_base_node",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
|
|
|
+ laAddSubGroup(pc,"out_time", "Out Time","Time output","la_out_socket",0,0,0,offsetof(laSynthNodeInput,OutTime),0,0,0,0,0,0,0,LA_UDF_SINGLE);
|
|
|
+ laAddSubGroup(pc,"out_trigger", "Out Trigger","Trigger output","la_out_socket",0,0,0,offsetof(laSynthNodeInput,OutTrigger),0,0,0,0,0,0,0,LA_UDF_SINGLE);
|
|
|
+
|
|
|
pc=laAddPropertyContainer("la_node_synth_fm", "FM OSC Node", "Osilliator node with frequency modulation",0,laui_FMNode,sizeof(laSynthNodeFM),lapost_Node,0,1);
|
|
|
LA_PC_IDN_FM=pc; laPropContainerExtraFunctions(pc,0,0,0,0,laui_DefaultNodeOperationsPropUiDefine);
|
|
|
laAddSubGroup(pc,"base","Base","Base node","la_base_node",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
|
|
@@ -957,6 +1015,7 @@ void laInitAudio(){
|
|
|
laAddSubGroup(pc,"in_sustain", "Sustain","Sustain input","la_in_socket",0,0,0,offsetof(laSynthNodeEnvelope,Sustain),0,0,0,0,0,0,0,LA_UDF_SINGLE);
|
|
|
laAddSubGroup(pc,"in_release", "Release","Release input","la_in_socket",0,0,0,offsetof(laSynthNodeEnvelope,Release),0,0,0,0,0,0,0,LA_UDF_SINGLE);
|
|
|
laAddSubGroup(pc,"in_trigger", "Trigger","Trigger input","la_in_socket",0,0,0,offsetof(laSynthNodeEnvelope,Trigger),0,0,0,0,0,0,0,LA_UDF_SINGLE);
|
|
|
+ laAddSubGroup(pc,"in_restart", "Restart","Restart input","la_in_socket",0,0,0,offsetof(laSynthNodeEnvelope,Restart),0,0,0,0,0,0,0,LA_UDF_SINGLE);
|
|
|
laAddSubGroup(pc,"out", "Output","Envelope output","la_out_socket",0,0,0,offsetof(laSynthNodeEnvelope,Out),0,0,0,0,0,0,0,LA_UDF_SINGLE);
|
|
|
laAddFloatProperty(pc,"gate","Gate","Gate for the trigger",0,0,0,10,-10,0.01,0,0,offsetof(laSynthNodeEnvelope,rGate),0,0,0,0,0,0,0,0,0,0,0);
|
|
|
laAddFloatProperty(pc,"attack","Attack","Attack value",0,0,0,10,0,0.01,0,0,offsetof(laSynthNodeEnvelope,rAttack),0,0,0,0,0,0,0,0,0,0,0);
|
|
@@ -981,6 +1040,7 @@ void laInitAudio(){
|
|
|
laAddEnumItemAs(p,"ENABLED","Enabled","Key is enabled",1,' ');
|
|
|
laAddEnumItemAs(p,"OUTPUT","Outputting","Key is Outputting",3,U'🌑');
|
|
|
|
|
|
+ LA_IDN_REGISTER("Inputs",U'🔌',LA_IDN_INPUT, LA_PC_IDN_INPUT, IDN_Input, laSynthNodeInput);
|
|
|
LA_IDN_REGISTER("VCO",'f',LA_IDN_FM, LA_PC_IDN_FM, IDN_FM, laSynthNodeFM);
|
|
|
LA_IDN_REGISTER("VCA",'a',LA_IDN_VCA, LA_PC_IDN_VCA, IDN_VCA, laSynthNodeVCA);
|
|
|
LA_IDN_REGISTER("Noise",'~',LA_IDN_NOISE, LA_PC_IDN_NOISE, IDN_Noise, laSynthNodeNoise);
|
|
@@ -992,7 +1052,7 @@ void laInitAudio(){
|
|
|
LA_NODE_CATEGORY_SYNTHESIZER=laAddNodeCategory("OSC",0,LA_RACK_TYPE_AUDIO);
|
|
|
LA_NODE_CATEGORY_SYSTEM_SOUND=laAddNodeCategory("System",0,LA_RACK_TYPE_AUDIO);
|
|
|
|
|
|
- laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_SYNTHESIZER, &LA_IDN_FM,&LA_IDN_NOISE,&LA_IDN_VCA,&LA_IDN_ENVELOPE,&LA_IDN_QUANTIZE,&LA_IDN_SCOPE,0);
|
|
|
+ laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_SYNTHESIZER, &LA_IDN_INPUT,&LA_IDN_FM,&LA_IDN_NOISE,&LA_IDN_VCA,&LA_IDN_ENVELOPE,&LA_IDN_QUANTIZE,&LA_IDN_SCOPE,0);
|
|
|
laNodeCategoryAddNodeTypes(LA_NODE_CATEGORY_SYSTEM_SOUND, &LA_IDN_OUTPUT,0);
|
|
|
}
|
|
|
|