|
@@ -300,12 +300,17 @@ void IDN_OutputDestroy(laSynthNodeOutput* n){
|
|
|
int IDN_OutputVisit(laSynthNodeOutput* n, laNodeVisitInfo* vi){
|
|
|
if(LA_SRC_AND_PARENT(n->In)){ laBaseNode*bn=n->In->Source->Parent; LA_VISIT_NODE(bn,vi); }
|
|
|
LA_ADD_THIS_NODE(n,vi);
|
|
|
+ laAudioChannel* outchannel = laGetAudioChannel(SSTR(n->SendName));
|
|
|
+ memAssignRef(n,&n->Send,outchannel);
|
|
|
return LA_DAG_FLAG_PERM;
|
|
|
}
|
|
|
int IDN_OutputEval(laSynthNodeOutput* n){
|
|
|
- real* input; INPUTPACKET(input,n->In);
|
|
|
- if(input) memcpy(MAIN.Audio->AudioEvalSynth->AudioSamples,input,sizeof(real)*LA_SYNTH_PLEN);
|
|
|
- else memset(MAIN.Audio->AudioEvalSynth->AudioSamples,0,sizeof(real)*LA_SYNTH_PLEN);
|
|
|
+ if(!n->Send)return 1;
|
|
|
+ real* input; INPUTPACKET(input,n->In); if(!input) return 1;
|
|
|
+ real Samples[LA_SYNTH_PLEN];
|
|
|
+ for(int i=0;i<LA_SYNTH_PLEN;i++){
|
|
|
+ n->Send->Samples[i] += input[i];
|
|
|
+ }
|
|
|
return 1;
|
|
|
}
|
|
|
void IDN_OutputCopy(laSynthNodeOutput* new, laSynthNodeOutput* old, int DoRematch){
|
|
@@ -319,6 +324,8 @@ void laui_OutputNode(laUiList *uil, laPropPack *This, laPropPack *Extra, laColum
|
|
|
laUiItem* b=laBeginRow(uil,c,0,0);
|
|
|
laShowNodeSocket(uil,c,This,"in",0)->Flags|=LA_UI_SOCKET_LABEL_E;
|
|
|
laShowLabel(uil,c,"🕪",0,0);
|
|
|
+ laShowItemFull(uil,c,This,"send_channel_selector",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0)->Flags|=LA_UI_COLLECTION_SIMPLE_SELECTOR;
|
|
|
+ laShowItem(uil,c,This,"send_channel_name")->Expand = 1;
|
|
|
laEndRow(uil,b);
|
|
|
}
|
|
|
|
|
@@ -499,16 +506,22 @@ void laRebuildSynthGraphs(){
|
|
|
int laEvalSynthGraphs(){
|
|
|
laSynth* ss; int any=0;
|
|
|
memset(MAIN.Audio->AudioSamples,0,sizeof(real)*LA_SYNTH_PLEN);
|
|
|
+ for(laAudioChannel* ac=MAIN.Audio->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
+ memset(ac->Samples,0,sizeof(real)*LA_SYNTH_PLEN);
|
|
|
+ }
|
|
|
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; INITPACKET(ss->AudioSamples);
|
|
|
+ MAIN.Audio->AudioEvalSynth=ss; MAIN.Audio->AudioEvalTime=0;
|
|
|
laRunPage(ss->Page,1);
|
|
|
laSpinUnlock(&ss->Lock);
|
|
|
+ any=1;
|
|
|
+ }
|
|
|
+
|
|
|
+ for(laAudioChannel* ac=MAIN.Audio->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
for(int i=0;i<LA_SYNTH_PLEN;i++){
|
|
|
- MAIN.Audio->AudioSamples[i]+=ss->AudioSamples[i];
|
|
|
+ MAIN.Audio->AudioSamples[i] += ac->Samples[i]*(ac->Volume/10);
|
|
|
}
|
|
|
- any=1;
|
|
|
}
|
|
|
return any;
|
|
|
}
|
|
@@ -659,24 +672,20 @@ int OPINV_laSynthPlay(laOperator* a, laEvent* e){
|
|
|
return LA_FINISHED;
|
|
|
}
|
|
|
|
|
|
-void laAudioEnsureChannelPtr(){
|
|
|
- for(laAudioChannel* iac=MAIN.Audio->Channels.pFirst;iac;iac=iac->Item.pNext){
|
|
|
- TNS_CLAMP(iac->ID,0,31);
|
|
|
- MAIN.Audio->ChannelPtr[iac->ID]=iac;
|
|
|
- }
|
|
|
-}
|
|
|
laAudioChannel* laNewAudioChannel(char* Name){
|
|
|
laAudioChannel* ac=memAcquireHyper(sizeof(laAudioChannel)); lstAppendItem(&MAIN.Audio->Channels,ac);
|
|
|
- strSafeSet(&ac->Name,Name); int has=0,i;
|
|
|
- for(i=0;i<64;i++){
|
|
|
- for(laAudioChannel* iac=MAIN.Audio->Channels.pFirst;iac;iac=iac->Item.pNext){ if(iac->ID==i){ has=1; break; } }
|
|
|
- }
|
|
|
- if(!has){ac->ID = i;}else{ac->ID=0;}
|
|
|
- ac->Volume = 10.0f; laAudioEnsureChannelPtr();
|
|
|
+ strSafeSet(&ac->Name,Name);
|
|
|
+ ac->Volume = 10.0f;
|
|
|
}
|
|
|
void laRemoveAudioChannel(laAudioChannel* ac){
|
|
|
lstRemoveItem(&MAIN.Audio->Channels,ac); strSafeDestroy(&ac->Name);
|
|
|
- memFree(ac); laAudioEnsureChannelPtr();
|
|
|
+ memFree(ac);
|
|
|
+}
|
|
|
+laAudioChannel* laGetAudioChannel(char* Name){
|
|
|
+ for(laAudioChannel* ac=MAIN.Audio->Channels.pFirst;ac;ac=ac->Item.pNext){
|
|
|
+ if(strSame(SSTR(ac->Name),Name)) return ac;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
int OPCHK_IslaAudioChannel(laPropPack *This, laStringSplitor *ss){
|
|
@@ -685,7 +694,7 @@ int OPCHK_IslaAudioChannel(laPropPack *This, laStringSplitor *ss){
|
|
|
}
|
|
|
int OPINV_ShedNewAudioChannel(laOperator* a, laEvent* e){
|
|
|
laNewAudioChannel("Output");
|
|
|
- laNotifyInstanceUsers(MAIN.Audio); laRecordAndPush(0,"la.audio","New channel", 0); // TODO: hint for laAudioEnsureChannelPtr
|
|
|
+ laNotifyInstanceUsers(MAIN.Audio); laRecordAndPush(0,"la.audio","New channel", 0);
|
|
|
return LA_FINISHED;
|
|
|
}
|
|
|
int OPINV_ShedRemoveAudioChannel(laOperator* a, laEvent* e){
|
|
@@ -754,9 +763,9 @@ void laui_AudioChannel(laUiList *uil, laPropPack *This, laPropPack *Extra, laCol
|
|
|
|
|
|
laShowHeightAdjuster(uil,c1,This,"__move",0);
|
|
|
|
|
|
- laShowItem(uil,c2,This,"name");
|
|
|
b=laBeginRow(uil,c2,0,0);
|
|
|
- laShowItem(uil,c2,This,"id")->Expand=1; laShowItem(uil,c,This,"remove")->Flags|=LA_UI_FLAGS_ICON;
|
|
|
+ laShowItem(uil,c2,This,"name")->Expand=1;
|
|
|
+ laShowItem(uil,c,This,"remove")->Flags|=LA_UI_FLAGS_ICON;
|
|
|
laEndRow(uil,b);
|
|
|
laShowItem(uil,c2,This,"volume");
|
|
|
|
|
@@ -782,6 +791,9 @@ void* laget_FirstAudioDevice(void* unused1,void* unused2){
|
|
|
void* laget_FirstSynth(void* unused1,void* unused2){
|
|
|
return MAIN.Audio->Synths.pFirst;
|
|
|
}
|
|
|
+void* laget_FirstAudioChannel(void* unused1, void* unused2){
|
|
|
+ return MAIN.Audio->Channels.pFirst;
|
|
|
+}
|
|
|
void lapost_Synth(laSynth* ss){
|
|
|
laSpinInit(&ss->Lock);
|
|
|
}
|
|
@@ -796,17 +808,15 @@ void laset_CurrentSynth(laAudio* a,laSynth* s){
|
|
|
void laset_CurrentAudioDevice(laAudio* a,laAudioDevice* ad){
|
|
|
la_SelectAudioDevice(ad);
|
|
|
}
|
|
|
-void laget_OutputSendChannelName(laSynthNodeOutput* n, char* str, char** target){
|
|
|
- if(!MAIN.Audio||!MAIN.Audio->ChannelPtr[n->Send]) *target="-";
|
|
|
- *target = SSTR(MAIN.Audio->ChannelPtr[n->Send]->Name);
|
|
|
+void laset_OutputSendChannel(laSynthNodeOutput* n,laAudioChannel* ac){
|
|
|
+ if(ac){ strSafeSet(&n->SendName, SSTR(ac->Name)); } else { strSafeSet(&n->SendName,""); }
|
|
|
+ laAudioChannel* outchannel = laGetAudioChannel(SSTR(n->SendName));
|
|
|
+ memAssignRef(n,&n->Send,outchannel);
|
|
|
}
|
|
|
void laset_QuantizeEnabledKeys(laSynthNodeQuantize* n, int index, int val_UNUSED){
|
|
|
if(n->EnabledBits[index] & 0x1){ n->EnabledBits[index]=0; }
|
|
|
else{ n->EnabledBits[index]=1; }
|
|
|
}
|
|
|
-void laset_AudioChannelID(laAudioChannel* ac, int id){
|
|
|
- ac->ID=id; laAudioEnsureChannelPtr();
|
|
|
-}
|
|
|
void laset_AudioChannelMove(laAudioChannel* ac, int move){
|
|
|
if(move<0 && ac->Item.pPrev){ lstMoveUp(&MAIN.Audio->Channels, ac); laNotifyUsers("la.audio"); }
|
|
|
elif(move>0 && ac->Item.pNext){ lstMoveDown(&MAIN.Audio->Channels, ac); laNotifyUsers("la.audio"); }
|
|
@@ -858,8 +868,6 @@ void laInitAudio(){
|
|
|
pc = laAddPropertyContainer("la_audio_channel", "LaGUI Audio Channel", "LaGUI Audio Channel", 0,0,sizeof(laAudioChannel),0,0,2);{
|
|
|
LA_PC_CHANNEL=pc;
|
|
|
laAddStringProperty(pc,"name","Name","Name of the synthesizer",0,0,0,0,1,offsetof(laAudioChannel,Name),0,0,0,0,LA_AS_IDENTIFIER);
|
|
|
- laAddIntProperty(pc,"id","ID","Identifier of this channel",0,0,0,31,0,0,0,0,offsetof(laAudioChannel,ID),0,laset_AudioChannelID,0,0,0,0,0,0,0,0,0);
|
|
|
- //laAddIntProperty(pc,"id","ID","Identifier of this channel",0,0,0,31,0,0,0,0,offsetof(laAudioChannel,ID),0,laset_AudioChannelID,0,0,0,0,0,0,0,0,0);
|
|
|
laAddFloatProperty(pc,"volume","Volume","Volume of this channel",0,0,0,15,0,0.05,0,0,offsetof(laAudioChannel,Volume),0,0,0,0,0,0,0,0,0,0,0);
|
|
|
laAddOperatorProperty(pc,"remove","Remove Channel", "Remove this channel", "LA_remove_channel", L'🗴', 0);
|
|
|
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);
|
|
@@ -920,8 +928,8 @@ void laInitAudio(){
|
|
|
LA_PC_IDN_OUTPUT=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,"in", "Input","Input sound","la_in_socket",0,0,0,offsetof(laSynthNodeOutput,In),0,0,0,0,0,0,0,LA_UDF_SINGLE);
|
|
|
- laAddIntProperty(pc,"send","Send","Send to channel",0,0,0,128,0,0,0,0,offsetof(laSynthNodeOutput,Send),0,0,0,0,0,0,0,0,0,0,0);
|
|
|
- laAddStringProperty(pc,"send_channel_name","Channel Name","Channel name of this send target",0,0,0,0,0,-1,0,laget_OutputSendChannelName,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
|
|
|
+ laAddStringProperty(pc,"send_channel_name","Channel Name","Channel name of this send target",0,0,0,0,1,offsetof(laSynthNodeOutput,SendName),0,0,0,0,0);
|
|
|
+ laAddSubGroup(pc,"send_channel_selector","Send","Send to channel","la_audio_channel",0,0,0,-1,laget_FirstAudioChannel,0,laget_ListNext,laset_OutputSendChannel,0,0,0,0);
|
|
|
|
|
|
pc=laAddPropertyContainer("la_node_synth_envelope", "Envelope Node", "Sound envelope",0,laui_EnvelopeNode,sizeof(laSynthNodeEnvelope),lapost_Node,0,1);
|
|
|
LA_PC_IDN_ENVELOPE=pc; laPropContainerExtraFunctions(pc,0,0,0,0,laui_DefaultNodeOperationsPropUiDefine);
|