#include #include #include "mixer.h" #include "devicedefines.h" #include "xc_ptr.h" #ifdef MIXER #define FAST_MIXER 1 #warning USING FAST MIXER #ifdef OUT_VOLUME_IN_MIXER static unsigned int multOut_array[NUM_USB_CHAN_OUT + 1]; static xc_ptr multOut; #endif #ifdef IN_VOLUME_IN_MIXER unsigned int multIn_array[NUM_USB_CHAN_IN + 1]; static xc_ptr multIn; #endif #if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST) static unsigned abs(int x) { #if 0 if (x < 0) return x*-1; return x; #else int const mask = x >> sizeof(int) * 8 - 1; return (x + mask) ^ mask; #endif } #endif int samples_array[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1]; /* One larger for an "off" channel for mixer sources" */ xc_ptr samples; int savedsamples2[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT]; int samples_to_host_map_array[NUM_USB_CHAN_IN]; xc_ptr samples_to_host_map; int samples_to_device_map_array[NUM_USB_CHAN_OUT]; xc_ptr samples_to_device_map; #if MAX_MIX_COUNT > 0 int mix_mult_array[MAX_MIX_COUNT][MIX_INPUTS]; xc_ptr mix_mult; #define write_word_to_mix_mult(x,y,val) write_via_xc_ptr_indexed(mix_mult,((x)*MIX_INPUTS)+(y), val) #define mix_mult_slice(x) (mix_mult + x * MIX_INPUTS * sizeof(int)) #ifndef FAST_MIXER int mix_map_array[MAX_MIX_COUNT][MIX_INPUTS]; xc_ptr mix_map; #define write_word_to_mix_map(x,y,val) write_via_xc_ptr_indexed(mix_map,((x)*MIX_INPUTS)+(y), val) #define mix_map_slice(x) (mix_map + x * MIX_INPUTS * sizeof(int)) #endif #endif /* Arrays for level data */ int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. dev inputs */ #ifdef LEVEL_METER_LEDS int samples_to_host_inputs_buff[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. dev inputs */ #endif static int samples_to_host_streams[NUM_USB_CHAN_OUT]; /* Audio stream to host from host */ static int samples_to_host_outputs[NUM_USB_CHAN_OUT]; /* Device outputs */ #if 0 #pragma xta command "add exclusion mixer1_rate_change" #pragma xta command "analyse path mixer1_req mixer1_req" #pragma xta command "set required - 10400 ns" /* 96kHz */ #endif #if 0 #pragma xta command "add exclusion mixer2_rate_change" #pragma xta command "analyse path mixer2_req mixer2_req" #pragma xta command "set required - 10400 ns" /* 96kHz */ #endif #if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST) static inline void ComputeMixerLevel(int sample, int i) { int x; int y; xc_ptr ptr; x = abs(sample); /* y = samples_to_host_outputs[i] */ asm("ldaw %0, dp[samples_to_host_outputs]":"=r"(ptr):); /* Might want to hoist this */ asm("ldw %0, %1[%2]":"=r"(y):"r"(ptr),"r"(i)); if(x > y) { /* samples_to_host_outputs[i] = x; */ write_via_xc_ptr_indexed(ptr,i,y); //asm("stw %0, %1[%2]"::"r"(y),"r"(ptr),"r"(i)); } } #endif #ifdef FAST_MIXER void setPtr(int src, int dst, int mix); int doMix0(xc_ptr samples, xc_ptr mult); int doMix1(xc_ptr samples, xc_ptr mult); int doMix2(xc_ptr samples, xc_ptr mult); int doMix3(xc_ptr samples, xc_ptr mult); int doMix4(xc_ptr samples, xc_ptr mult); int doMix5(xc_ptr samples, xc_ptr mult); int doMix6(xc_ptr samples, xc_ptr mult); int doMix7(xc_ptr samples, xc_ptr mult); int doMix8(xc_ptr samples, xc_ptr mult); #else /* DO NOT inline, causes 10.4.2 tools to add extra loads in loop */ /* At 18 x 12dB we could get 64 x bigger */ #pragma unsafe arrays int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult) { int h=0; int l=0; /* By breaking up the loop we keep things in the encoding for ldw (0-11) */ #pragma loop unroll for (int i=0; i>32) h = (0x80000000>>7); else h = (0x7fffff00>>7); } #endif return h<<7; } #endif #pragma unsafe arrays void giveSamplesToHost(chanend c, xc_ptr samples, xc_ptr ptr, xc_ptr multIn) { #if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX) int mult; int h; unsigned l; #endif #pragma loop unroll for (int i=0;i samples_to_host_streams[i]) samples_to_host_streams[i] = x; #endif #if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX) #warning OUT Vols in mixer, BEFORE mix & map read_via_xc_ptr_indexed(mult, multOut, i); {h, l} = macs(mult, sample, 0, 0); h<<=3; write_via_xc_ptr_indexed(multOut, index, val); write_via_xc_ptr_indexed(samples,base+i,h); #else write_via_xc_ptr_indexed(samples,base+i,sample); #endif } } #pragma unsafe arrays void giveSamplesToDevice(chanend c, xc_ptr samples, xc_ptr ptr, xc_ptr multOut) { #pragma loop unroll for (int i=0;i samples_to_host_inputs[i]) samples_to_host_inputs[i] = x; #endif #if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX) read_via_xc_ptr_indexed(mult, multIn, i); {h, l} = macs(mult, sample, 0, 0); h <<=3; write_via_xc_ptr_indexed(samples,base+i,h); #else write_via_xc_ptr_indexed(samples,base+i,sample); #endif } } int mixer1_mix2_flag = (DEFAULT_FREQ > 96000); #pragma unsafe arrays void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2) { int mixed; unsigned cmd; while (1) { #pragma xta endpoint "mixer1_req" inuint(c_mixer2); /* Request data from decouple thread */ outuint(c_host, 0); /* Between request to decouple and respose ~ 400nS latency for interrupt to fire */ select { case inuint_byref(c_mix_ctl, cmd): { int mix, index, val; switch (cmd) { #if MAX_MIX_COUNT > 0 case SET_SAMPLES_TO_HOST_MAP: index = inuint(c_mix_ctl); val = inuint(c_mix_ctl); inct(c_mix_ctl); write_via_xc_ptr_indexed(samples_to_host_map, index, val); break; case SET_SAMPLES_TO_DEVICE_MAP: index = inuint(c_mix_ctl); val = inuint(c_mix_ctl); inct(c_mix_ctl); write_via_xc_ptr_indexed(samples_to_device_map,index,val); break; case SET_MIX_MULT: mix = inuint(c_mix_ctl); index = inuint(c_mix_ctl); val = inuint(c_mix_ctl); inct(c_mix_ctl); write_word_to_mix_mult(mix, index, val); break; case SET_MIX_MAP: mix = inuint(c_mix_ctl); index = inuint(c_mix_ctl); /* mixer input */ val = inuint(c_mix_ctl); /* source */ inct(c_mix_ctl); #ifdef FAST_MIXER setPtr(index, val, mix); #else write_word_to_mix_map(mix, index, val); #endif break; #endif /* if MAX_MIX_COUNT > 0 */ #ifdef IN_VOLUME_IN_MIXER case SET_MIX_IN_VOL: index = inuint(c_mix_ctl); val = inuint(c_mix_ctl); inct(c_mix_ctl); write_via_xc_ptr_indexed(multIn, index, val); break; #endif #ifdef OUT_VOLUME_IN_MIXER case SET_MIX_OUT_VOL: index = inuint(c_mix_ctl); val = inuint(c_mix_ctl); inct(c_mix_ctl); write_via_xc_ptr_indexed(multOut, index, val); break; #endif case GET_STREAM_LEVELS: index = inuint(c_mix_ctl); chkct(c_mix_ctl, XS1_CT_END); outuint(c_mix_ctl, samples_to_host_streams[index]); outct(c_mix_ctl, XS1_CT_END); samples_to_host_streams[index] = 0; break; case GET_INPUT_LEVELS: index = inuint(c_mix_ctl); chkct(c_mix_ctl, XS1_CT_END); #ifdef LEVEL_METER_LEDS /* Level LEDS process reseting samples_to_host_inputs * Other side makes sure we don't miss a peak */ read_via_xc_ptr_indexed(val, samples_to_host_inputs_buff, index); write_via_xc_ptr_indexed(samples_to_host_inputs_buff, index, 0); #else /* We dont have a level LEDs process, so reset ourselves */ read_via_xc_ptr_indexed(val, samples_to_host_inputs, index); write_via_xc_ptr_indexed(samples_to_host_inputs, index, 0); #endif outuint(c_mix_ctl, val); outct(c_mix_ctl, XS1_CT_END); break; #if MAX_MIX_COUNT > 0 case GET_OUTPUT_LEVELS: index = inuint(c_mix_ctl); chkct(c_mix_ctl, XS1_CT_END); read_via_xc_ptr_indexed(val, samples_to_host_outputs, index); write_via_xc_ptr_indexed(samples_to_host_outputs, index, mix); outuint(c_mix_ctl, val); outct(c_mix_ctl, XS1_CT_END); break; #endif } break; } default: /* Select default */ break; } /* Get response from decouple */ if(testct(c_host)) { int sampFreq; #pragma xta endpoint "mixer1_rate_change" inct(c_host); sampFreq = inuint(c_host); mixer1_mix2_flag = sampFreq > 96000; #pragma loop unroll for (int i=0;i 0 outuint(c_mixer2, 0); giveSamplesToHost(c_host, samples, samples_to_host_map, multIn); outuint(c_mixer2, 0); inuint(c_mixer2); getSamplesFromHost(c_host, samples, 0); outuint(c_mixer2, 0); inuint(c_mixer2); #ifdef FAST_MIXER mixed = doMix0(samples, mix_mult_slice(0)); #else mixed = doMix(samples,mix_map_slice(0),mix_mult_slice(0)); #endif write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0), mixed); #if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) ComputeMixerLevel(mixed, 0); #endif #if (MAX_FREQ > 96000) if (!mixer1_mix2_flag) #endif { #if MAX_MIX_COUNT > 2 #ifdef FAST_MIXER mixed = doMix2(samples, mix_mult_slice(2)); #else mixed = doMix(samples,mix_map_slice(2),mix_mult_slice(2)); #endif write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2), mixed); #if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) ComputeMixerLevel(mixed, 2); #endif #endif #if MAX_MIX_COUNT > 4 #ifdef FAST_MIXER mixed = doMix4(samples, mix_mult_slice(4)); #else mixed = doMix(samples,mix_map_slice(4),mix_mult_slice(4)); #endif write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 4), mixed); #if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) ComputeMixerLevel(mixed, 4); #endif #endif #if MAX_MIX_COUNT > 6 #ifdef FAST_MIXER mixed = doMix6(samples, mix_mult_slice(6)); #else mixed = doMix(samples,mix_map_slice(6),mix_mult_slice(6)); #endif write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 6), mixed); #if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) ComputeMixerLevel(mixed, 6); #endif #endif } #else /* IF MAX_MIX_COUNT > 0 */ /* No mixes, this thread runs on its own doing just volume */ giveSamplesToDevice(c_mixer2, samples, samples_to_device_map, multOut); getSamplesFromDevice(c_mixer2, samples, NUM_USB_CHAN_OUT); giveSamplesToHost(c_host, samples, samples_to_host_map, multIn); getSamplesFromHost(c_host, samples, 0); #endif } } } int mixer2_mix2_flag = (DEFAULT_FREQ > 96000); #pragma unsafe arrays void mixer2(chanend c_mixer1, chanend c_audio) { int mixed; while (1) { outuint(c_mixer1, 0); #pragma xta endpoint "mixer2_req" inuint(c_audio); if(testct(c_mixer1)) { int sampFreq; #pragma xta endpoint "mixer2_rate_change" inct(c_mixer1); sampFreq = inuint(c_mixer1); mixer2_mix2_flag = sampFreq > 96000; for (int i=0;i 1 #ifdef FAST_MIXER mixed = doMix1(samples, mix_mult_slice(1)); #else mixed = doMix(samples,mix_map_slice(1),mix_mult_slice(1)); #endif write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1), mixed); #if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) ComputeMixerLevel(mixed, 1); #endif #endif #if (MAX_FREQ > 96000) if (!mixer2_mix2_flag) #endif { #if MAX_MIX_COUNT > 3 #ifdef FAST_MIXER mixed = doMix3(samples, mix_mult_slice(3)); #else mixed = doMix(samples,mix_map_slice(3),mix_mult_slice(3)); #endif write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3), mixed); #if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) ComputeMixerLevel(mixed, 3); #endif #endif #if MAX_MIX_COUNT > 5 #ifdef FAST_MIXER mixed = doMix5(samples, mix_mult_slice(5)); #else mixed = doMix(samples,mix_map_slice(5),mix_mult_slice(5)); #endif write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5, mixed); #if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) ComputeMixerLevel(mixed, 5); #endif #endif #if MAX_MIX_COUNT > 7 #ifdef FAST_MIXER mixed = doMix7(samples, mix_mult_slice(7)); #else mixed = doMix(samples,mix_map_slice(7),mix_mult_slice(7)); #endif write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7, mixed); #if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) ComputeMixerLevel(mixed, 7); #endif #endif } } } } void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl) { chan c; multOut = array_to_xc_ptr((multOut_array,unsigned[])); multIn = array_to_xc_ptr((multIn_array,unsigned[])); samples = array_to_xc_ptr((samples_array,unsigned[])); samples_to_host_map = array_to_xc_ptr((samples_to_host_map_array,unsigned[])); samples_to_device_map = array_to_xc_ptr((samples_to_device_map_array,unsigned[])); #if MAX_MIX_COUNT >0 mix_mult = array_to_xc_ptr((mix_mult_array,unsigned[])); #ifndef FAST_MIXER mix_map = array_to_xc_ptr((mix_map_array,unsigned[])); #endif #endif for (int i=0;i 96000 ? 2 : MAX_MIX_COUNT; for (int i=0;i 0 for (int i=0;i> 3 : 0); } #endif par { #if (MAX_MIX_COUNT > 0) mixer1(c_mix_in, c_mix_ctl, c); mixer2(c, c_mix_out); #else mixer1(c_mix_in, c_mix_ctl, c_mix_out); #endif } } #endif