void glPassThrough(GLfloat token) { ERROR_IN_BLOCK(); if (feedback_overflow(2)) return; feedback_push(GL_PASS_THROUGH_TOKEN); feedback_push(token); state.feedback.values -= 1; }
static void feedback_vertex(block_t *block, int i) { static GLfloat color[] = {0, 0, 0, 1}; static GLfloat tex[] = {0, 0, 0, 0}; GLfloat v[4], *c, *t; c = block->color ?: color; // glFeedbackBuffer returns only the texture coordinate of texture unit GL_TEXTURE0. t = block->tex[0] ?: tex; // TODO: this will be called extra times on stuff like triangle strips gl_transform_vertex(v, &block->vert[i * 3]); switch (state.feedback.type) { case GL_2D: feedback_push_n(v, 2); break; case GL_3D: feedback_push_n(v, 3); break; case GL_3D_COLOR: feedback_push_n(v, 3); feedback_push_n(c, 4); break; case GL_3D_COLOR_TEXTURE: feedback_push_n(v, 3); feedback_push_n(c, 4); feedback_push_n(t, 2); // we only store 2d texture coordinates for now feedback_push(0.0f); feedback_push(0.0f); break; case GL_4D_COLOR_TEXTURE: feedback_push_n(v, 3); // our vertices are already normalized, so W is redundant here feedback_push(1.0f); feedback_push_n(c, 4); feedback_push_n(t, 4); break; } }
static void feedback_push_n(GLfloat *values, int length) { for (int i = 0; i < length; i++) { feedback_push(values[i]); } }
static void feedback_polygon(int n) { feedback_push(GL_POLYGON_TOKEN); feedback_push(n); }
/* called only by playback thread */ time_linkage *mix_read(time_linkage *in, time_linkage *inA, // reverb channel time_linkage *inB){ // reverb channel int i,j,k,outch=ms.out.channels; int outactive[outch]; float peak[MIX_BLOCKS+5][input_ch]; float rms[MIX_BLOCKS+5][input_ch]; int bypass=1; if(in->samples==0){ ms.out.samples=0; return &ms.out; } memset(outactive,0,sizeof(outactive)); memset(peak,0,sizeof(peak)); memset(rms,0,sizeof(rms)); /* eliminate asynch change possibility */ memcpy(ms.curr,mix_set,sizeof(*mix_set)*input_ch); /* fillstate here is only used for lazy initialization/reset */ if(ms.fillstate==0){ /* zero the cache */ for(i=0;i<input_ch;i++){ memset(ms.cacheP[i],0,sizeof(**ms.cacheP)*input_size); memset(ms.cachePP[i],0,sizeof(**ms.cachePP)*input_size); memset(ms.cachePA[i],0,sizeof(**ms.cachePA)*input_size); memset(ms.cachePPA[i],0,sizeof(**ms.cachePPA)*input_size); memset(ms.cachePB[i],0,sizeof(**ms.cachePB)*input_size); memset(ms.cachePPB[i],0,sizeof(**ms.cachePPB)*input_size); } memcpy(ms.prev,ms.curr,sizeof(*mix_set)*input_ch); ms.fillstate=1; } /* zero the output block; we'll me mixing into it input-by-input */ for(i=0;i<outch;i++) memset(ms.out.data[i],0,sizeof(**ms.out.data)*input_size); /* a bit of laziness that may actually save CPU time by avoiding special-cases later */ for(i=0;i<input_ch;i++){ if(mute_channel_muted(in->active,i)) memset(in->data[i],0,sizeof(**in->data)*input_size); if(mute_channel_muted(inA->active,i)) memset(inA->data[i],0,sizeof(**inA->data)*input_size); if(mute_channel_muted(inB->active,i)) memset(inB->data[i],0,sizeof(**inB->data)*input_size); } /* input-by-input */ for(i=0;i<input_ch;i++){ int feedit=mixpanel_visible[i]; int feeditM=atten_visible; /* master feedback is a bit of a pain; the metrics we need aren't produced by any of the mixdowns below. Do it by hand */ if(feeditM){ float mix[input_size]; float att=fromdB(ms.curr[i].master_att * .1); int del=rint(ms.curr[i].master_delay*.00001*input_rate); float acc=0.; if(!mute_channel_muted(in->active,i)){ memset(mix,0,sizeof(mix)); mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i], mix,att,del,0,att,del,0); bypass=0; for(j=0;j<input_size;j++){ float val=mix[j]*mix[j]; if(val>peak[0][i])peak[0][i]=val; acc+=val; } rms[0][i]=acc/input_size; } acc=0.; if(inA && !mute_channel_muted(inA->active,i)){ memset(mix,0,sizeof(mix)); mixwork(inA->data[i],ms.cachePA[i],ms.cachePPA[i], mix,att,del,0,att,del,0); bypass=0; for(j=0;j<input_size;j++){ float val=mix[j]*mix[j]; if(val>peak[1][i])peak[1][i]=val; acc+=val; } rms[1][i]=acc/input_size; } acc=0.; if(inB && !mute_channel_muted(inB->active,i)){ memset(mix,0,sizeof(mix)); mixwork(inB->data[i],ms.cachePB[i],ms.cachePPB[i], mix,att,del,0,att,del,0); bypass=0; for(j=0;j<input_size;j++){ float val=mix[j]*mix[j]; if(val>peak[2][i])peak[2][i]=val; acc+=val; } rms[2][i]=acc/input_size; } } /* placer settings; translate to final numbers */ int placer=ms.curr[i].placer_place; int placerP=ms.prev[i].placer_place; /* place mix */ { int mixedA=0,mixedB=0; float mixA[input_size],mixB[input_size]; for(j=0;j<OUTPUT_CHANNELS;j++){ int destA=ms.curr[i].placer_destA[j]; int destAP=ms.prev[i].placer_destA[j]; int destB=ms.curr[i].placer_destB[j]; int destBP=ms.prev[i].placer_destB[j]; if(destA || destAP){ outactive[j]=1; if(!mixedA){ float relA=(placer>100 ? placer*.01-1. : 0.); float relAP=(placerP>100 ? placerP*.01-1. : 0.); float attA=fromdB((ms.curr[i].master_att + ms.curr[i].placer_att * relA)*.1); float attAP=fromdB((ms.prev[i].master_att + ms.prev[i].placer_att * relAP)*.1); int delA=rint((ms.curr[i].master_delay + ms.curr[i].placer_delay * relA)*.00001*input_rate); int delAP=rint((ms.prev[i].master_delay + ms.prev[i].placer_delay * relAP)*.00001*input_rate); float attA_r=fromdB(ms.curr[i].master_att*.1); float attAP_r=fromdB(ms.prev[i].master_att*.1); int delA_r=rint(ms.curr[i].master_delay*.00001*input_rate); int delAP_r=rint(ms.prev[i].master_delay*.00001*input_rate); memset(mixA,0,sizeof(mixA)); mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i], mixA,attA,delA,0,attAP,delAP,0); mixwork(inA->data[i],ms.cachePA[i],ms.cachePPA[i], mixA,attA_r,delA_r,0,attAP_r,delAP_r,0); mixedA=1; } mixadd(mixA,ms.out.data[j],destA,destAP); } if(destB || destBP){ outactive[j]=1; if(!mixedB){ float relB=(placer<100 ? 1.-placer*.01 : 0.); float relBP=(placerP<100 ? 1.-placerP*.01 : 0.); float attB=fromdB((ms.curr[i].master_att + ms.curr[i].placer_att * relB)*.1); float attBP=fromdB((ms.prev[i].master_att + ms.prev[i].placer_att * relBP)*.1); int delB=rint((ms.curr[i].master_delay + ms.curr[i].placer_delay * relB)*.00001*input_rate); int delBP= rint((ms.prev[i].master_delay + ms.prev[i].placer_delay * relBP)*.00001*input_rate); float attB_r=fromdB(ms.curr[i].master_att*.1); float attBP_r=fromdB(ms.prev[i].master_att*.1); int delB_r=rint(ms.curr[i].master_delay*.00001*input_rate); int delBP_r= rint(ms.prev[i].master_delay*.00001*input_rate); memset(mixB,0,sizeof(mixB)); mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i], mixB,attB,delB,0,attBP,delBP,0); mixwork(inB->data[i],ms.cachePB[i],ms.cachePPB[i], mixB,attB_r,delB_r,0,attBP_r,delBP_r,0); mixedB=1; } mixadd(mixB,ms.out.data[j],destB,destBP); } } /* feedback for A */ if(feedit){ float acc=0.; bypass=0; if(mixedA){ for(j=0;j<input_size;j++){ float val=mixA[j]*mixA[j]; if(val>peak[3][i])peak[3][i]=val; acc+=val; } peak[3][i]=peak[3][i]; rms[3][i]=acc/input_size; } } /* feedback for B */ if(feedit){ float acc=0.; bypass=0; if(mixedB){ for(j=0;j<input_size;j++){ float val=mixB[j]*mixB[j]; if(val>peak[4][i])peak[4][i]=val; acc+=val; } peak[4][i]=peak[4][i]; rms[4][i]=acc/input_size; } } } /* direct block mix */ for(k=0;k<MIX_BLOCKS;k++){ float mix[input_size]; int sourceM=ms.curr[i].insert_source[k][0]; int sourceMP=ms.prev[i].insert_source[k][0]; int sourceA=ms.curr[i].insert_source[k][1]; int sourceAP=ms.prev[i].insert_source[k][1]; int sourceB=ms.curr[i].insert_source[k][2]; int sourceBP=ms.prev[i].insert_source[k][2]; float att= fromdB((ms.curr[i].master_att + ms.curr[i].insert_att[k])*.1); int del= rint((ms.curr[i].master_delay + ms.curr[i].insert_delay[k])*.00001*input_rate); float attP= fromdB((ms.prev[i].master_att + ms.prev[i].insert_att[k])*.1); int delP= rint((ms.prev[i].master_delay + ms.prev[i].insert_delay[k])*.00001*input_rate); if(sourceM || sourceMP || sourceA || sourceAP || sourceB || sourceBP){ memset(mix,0,sizeof(mix)); /* master */ if(sourceM || sourceMP) mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i], mix, (sourceM ? att : 0), del,ms.curr[i].insert_invert[k], (sourceMP ? attP : 0), delP,ms.prev[i].insert_invert[k]); /* reverbA */ if(sourceA || sourceAP) if(inA) mixwork(inA->data[i],ms.cachePA[i],ms.cachePPA[i], mix, (sourceA ? att : 0), del,ms.curr[i].insert_invert[k], (sourceAP ? attP : 0), delP,ms.prev[i].insert_invert[k]); /* reverbB */ if(sourceB || sourceBP) if(inB) mixwork(inB->data[i],ms.cachePB[i],ms.cachePPB[i], mix, (sourceB ? att : 0), del,ms.curr[i].insert_invert[k], (sourceBP ? attP : 0), delP,ms.prev[i].insert_invert[k]); /* mix into output */ for(j=0;j<OUTPUT_CHANNELS;j++){ int dest=ms.curr[i].insert_dest[k][j]; int destP=ms.prev[i].insert_dest[k][j]; if(dest || destP){ outactive[j]=1; mixadd(mix,ms.out.data[j],dest,destP); } } /* feedback */ if(feedit){ float acc=0.; bypass=0; for(j=0;j<input_size;j++){ float val=mix[j]*mix[j]; if(val>peak[5+k][i])peak[5+k][i]=val; acc+=val; } peak[5+k][i]=peak[5+k][i]; rms[5+k][i]=acc/input_size; } } } /* rotate data cache */ { float *temp=ms.cachePP[i]; ms.cachePP[i]=ms.cacheP[i]; ms.cacheP[i]=in->data[i]; in->data[i]=temp; if(inA){ temp=ms.cachePPA[i]; ms.cachePPA[i]=ms.cachePA[i]; ms.cachePA[i]=inA->data[i]; inA->data[i]=temp; } if(inB){ temp=ms.cachePPB[i]; ms.cachePPB[i]=ms.cachePB[i]; ms.cachePB[i]=inB->data[i]; inB->data[i]=temp; } } } /* finish output data */ ms.out.samples=in->samples; ms.out.active=0; for(i=0;i<OUTPUT_CHANNELS;i++) if(outactive[i]) ms.out.active|=(1<<i); /* rotate settings cache */ { mix_settings *temp=ms.curr; ms.curr=ms.prev; ms.prev=temp; } /* push feedback */ if(bypass){ mix_feedback *mf= (mix_feedback *)feedback_new(&ms.feedpool,new_mix_feedback); mf->bypass=1; feedback_push(&ms.feedpool,(feedback_generic *)mf); }else{ mix_feedback *mf= (mix_feedback *)feedback_new(&ms.feedpool,new_mix_feedback); if(!mf->peak){ mf->peak=malloc((MIX_BLOCKS+5)*sizeof(*mf->peak)); mf->rms=malloc((MIX_BLOCKS+5)*sizeof(*mf->rms)); for(i=0;i<MIX_BLOCKS+5;i++) mf->rms[i]=malloc(input_ch*sizeof(**mf->rms)); for(i=0;i<MIX_BLOCKS+5;i++) mf->peak[i]=malloc(input_ch*sizeof(**mf->peak)); } for(i=0;i<MIX_BLOCKS+5;i++){ memcpy(mf->peak[i],peak[i],input_ch*sizeof(**peak)); memcpy(mf->rms[i],rms[i],input_ch*sizeof(**rms)); } mf->bypass=0; feedback_push(&ms.feedpool,(feedback_generic *)mf); } return &ms.out; }