forked from PAWPAW-Mirror/lib_xua
- Added mixer related defines to reduce use of magic numbers
- Increases debug output when DEBUG flag set - Removed some dead code - Increased alignment of asm mixer functions - Removed some usages of “xc_ptr” type in favour of native pointers in XC - Added some asserts to mixer - Added test_mixer_routing_input - Moved test_mixer_routing_output to use shared code
This commit is contained in:
@@ -3,6 +3,8 @@
|
|||||||
#ifndef _XUA_MIXER_H_
|
#ifndef _XUA_MIXER_H_
|
||||||
#define _XUA_MIXER_H_
|
#define _XUA_MIXER_H_
|
||||||
|
|
||||||
|
#include "xua.h"
|
||||||
|
|
||||||
enum mix_ctl_cmd {
|
enum mix_ctl_cmd {
|
||||||
SET_SAMPLES_TO_HOST_MAP,
|
SET_SAMPLES_TO_HOST_MAP,
|
||||||
SET_SAMPLES_TO_DEVICE_MAP,
|
SET_SAMPLES_TO_DEVICE_MAP,
|
||||||
@@ -31,4 +33,14 @@ enum mix_ctl_cmd {
|
|||||||
*/
|
*/
|
||||||
void mixer(chanend c_to_host, chanend c_to_audio, chanend c_mix_ctl);
|
void mixer(chanend c_to_host, chanend c_to_audio, chanend c_mix_ctl);
|
||||||
|
|
||||||
|
#define XUA_MIXER_OFFSET_OUT (0)
|
||||||
|
#define XUA_MIXER_OFFSET_IN (NUM_USB_CHAN_OUT)
|
||||||
|
#define XUA_MIXER_OFFSET_MIX (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN)
|
||||||
|
#define XUA_MIXER_OFFSET_OFF (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT)
|
||||||
|
|
||||||
|
/* Defines uses for DB to actual muliplier conversion */
|
||||||
|
#define XUA_MIXER_MULT_FRAC_BITS (25)
|
||||||
|
#define XUA_MIXER_DB_FRAC_BITS (8)
|
||||||
|
#define XUA_MIXER_MAX_MULT (1<<XUA_MIXER_MULT_FRAC_BITS) /* i.e. multiply by 0 */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ VERSION = 3.3.1
|
|||||||
DEBUG ?= 0
|
DEBUG ?= 0
|
||||||
|
|
||||||
ifeq ($(DEBUG),1)
|
ifeq ($(DEBUG),1)
|
||||||
DEBUG_FLAGS = -g -DXASSERT_ENABLE_ASSERTIONS_DECOUPLE=1
|
DEBUG_FLAGS = -g -DXASSERT_ENABLE_ASSERTIONS=1 -DXASSERT_ENABLE_DEBUG=1 -DXASSERT_ENABLE_LINE_NUMBERS=1
|
||||||
else
|
else
|
||||||
DEBUG_FLAGS = -DXASSERT_DISABLE_ASSERTIONS_DECOUPLE=1
|
DEBUG_FLAGS = -DXASSERT_ENABLE_ASSERTIONS=0 -DXASSERT_ENABLE_DEBUG=0 -DXASSERT_ENABLE_LINE_NUMBERS=0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
||||||
|
|||||||
@@ -677,10 +677,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
{
|
{
|
||||||
if (c < NUM_USB_CHAN_OUT)
|
if (c < NUM_USB_CHAN_OUT)
|
||||||
{
|
{
|
||||||
//outuint(c_mix_ctl, SET_SAMPLES_TO_DEVICE_MAP);
|
|
||||||
//outuint(c_mix_ctl, c);
|
|
||||||
//outuint(c_mix_ctl, channelMapAud[c]);
|
|
||||||
//outct(c_mix_ctl, XS1_CT_END);
|
|
||||||
UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_DEVICE_MAP, c, channelMapAud[c]);
|
UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_DEVICE_MAP, c, channelMapAud[c]);
|
||||||
|
|
||||||
/* Send 0 Length as status stage */
|
/* Send 0 Length as status stage */
|
||||||
@@ -717,10 +713,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
{
|
{
|
||||||
if (!isnull(c_mix_ctl))
|
if (!isnull(c_mix_ctl))
|
||||||
{
|
{
|
||||||
//outuint(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP);
|
|
||||||
//outuint(c_mix_ctl, c);
|
|
||||||
//outuint(c_mix_ctl, channelMapUsb[c]);
|
|
||||||
//outct(c_mix_ctl, XS1_CT_END);
|
|
||||||
UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP, c, channelMapUsb[c]);
|
UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP, c, channelMapUsb[c]);
|
||||||
|
|
||||||
return XUD_DoSetRequestStatus(ep0_in);
|
return XUD_DoSetRequestStatus(ep0_in);
|
||||||
@@ -774,22 +766,15 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
/* Update all mix maps */
|
/* Update all mix maps */
|
||||||
for (int i = 0; i < MAX_MIX_COUNT; i++)
|
for (int i = 0; i < MAX_MIX_COUNT; i++)
|
||||||
{
|
{
|
||||||
//outuint(c_mix_ctl, SET_MIX_MAP);
|
/* i : Mix bus */
|
||||||
//outuint(c_mix_ctl, i); /* Mix bus */
|
/* cn: Mixer input */
|
||||||
//outuint(c_mix_ctl, cn); /* Mixer input */
|
/* mixSel[i][cn]): Source */
|
||||||
//outuint(c_mix_ctl, (int) mixSel[cn]); /* Source */
|
|
||||||
//outct(c_mix_ctl, XS1_CT_END);
|
|
||||||
UpdateMixMap(c_mix_ctl, i, cn, (int) mixSel[cn]);
|
UpdateMixMap(c_mix_ctl, i, cn, (int) mixSel[cn]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Update relevant mix map */
|
/* Update relevant mix map */
|
||||||
//outuint(c_mix_ctl, SET_MIX_MAP); /* Command */
|
|
||||||
//outuint(c_mix_ctl, (cs-1)); /* Mix bus */
|
|
||||||
//outuint(c_mix_ctl, cn); /* Mixer input */
|
|
||||||
//outuint(c_mix_ctl, (int) mixSel[cs][cn]); /* Source */
|
|
||||||
//outct(c_mix_ctl, XS1_CT_END); /* Wait for handshake back */
|
|
||||||
UpdateMixMap(c_mix_ctl, cs-1, cn, (int) mixSel[cs][cn]);
|
UpdateMixMap(c_mix_ctl, cs-1, cn, (int) mixSel[cs][cn]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -838,7 +823,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
volume = db_to_mult(mixer1Weights[sp.wValue & 0xff], 8, 25);
|
volume = db_to_mult(mixer1Weights[sp.wValue & 0xff], XUA_MIXER_DB_FRAC_BITS, XUA_MIXER_MULT_FRAC_BITS);
|
||||||
}
|
}
|
||||||
if (!isnull(c_mix_ctl))
|
if (!isnull(c_mix_ctl))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#define DOMIX_TOP(i) \
|
#define DOMIX_TOP(i) \
|
||||||
.cc_top doMix##i.function,doMix##i; \
|
.cc_top doMix##i.function,doMix##i; \
|
||||||
.align 4 ;\
|
.align 16 ;\
|
||||||
.globl doMix##i ;\
|
.globl doMix##i ;\
|
||||||
.type doMix##i, @function ;\
|
.type doMix##i, @function ;\
|
||||||
.globl doMix##i##.nstackwords ;\
|
.globl doMix##i##.nstackwords ;\
|
||||||
@@ -124,7 +124,7 @@ DOMIX_BOT(7)
|
|||||||
#undef BODY
|
#undef BODY
|
||||||
#define N MAX_MIX_COUNT
|
#define N MAX_MIX_COUNT
|
||||||
.cc_top setPtr.function,setPtr;
|
.cc_top setPtr.function,setPtr;
|
||||||
.align 4 ;
|
.align 16 ;
|
||||||
.globl setPtr;
|
.globl setPtr;
|
||||||
.type setPtr, @function
|
.type setPtr, @function
|
||||||
.globl setPtr.nstackwords;
|
.globl setPtr.nstackwords;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
// Copyright 2011-2022 XMOS LIMITED.
|
// Copyright 2011-2023 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
#define XASSERT_UNIT MIXER
|
||||||
|
#include "xassert.h"
|
||||||
|
|
||||||
#include <xs1.h>
|
#include <xs1.h>
|
||||||
#include <print.h>
|
|
||||||
#include "xua.h"
|
#include "xua.h"
|
||||||
#include "xc_ptr.h"
|
#include "xc_ptr.h"
|
||||||
#include "xua_commands.h"
|
#include "xua_commands.h"
|
||||||
@@ -36,15 +38,12 @@ static unsigned abs(int x)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int samples_array[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1]; /* One larger for an "off" channel for mixer sources" */
|
static 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;
|
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
static int volatile * const unsafe ptr_samples = samples_array;
|
static int volatile * const unsafe ptr_samples = samples_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
int savedsamples2[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
|
||||||
|
|
||||||
int samples_to_host_map_array[NUM_USB_CHAN_IN];
|
int samples_to_host_map_array[NUM_USB_CHAN_IN];
|
||||||
xc_ptr samples_to_host_map;
|
xc_ptr samples_to_host_map;
|
||||||
|
|
||||||
@@ -77,18 +76,6 @@ static int samples_from_host_streams[NUM_USB_CHAN_OUT]; /* Peak samples for audi
|
|||||||
static int samples_mixer_outputs[MAX_MIX_COUNT]; /* Peak samples out of the mixer */
|
static int samples_mixer_outputs[MAX_MIX_COUNT]; /* Peak samples out of the mixer */
|
||||||
xc_ptr samples_mixer_outputs_ptr;
|
xc_ptr samples_mixer_outputs_ptr;
|
||||||
|
|
||||||
#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)
|
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
||||||
static inline void ComputeMixerLevel(int sample, int i)
|
static inline void ComputeMixerLevel(int sample, int i)
|
||||||
{
|
{
|
||||||
@@ -110,20 +97,20 @@ static inline void ComputeMixerLevel(int sample, int i)
|
|||||||
#endif
|
#endif
|
||||||
#ifdef FAST_MIXER
|
#ifdef FAST_MIXER
|
||||||
void setPtr(int src, int dst, int mix);
|
void setPtr(int src, int dst, int mix);
|
||||||
int doMix0(xc_ptr samples, xc_ptr mult);
|
int doMix0(int * unsafe samples, xc_ptr mult);
|
||||||
int doMix1(xc_ptr samples, xc_ptr mult);
|
int doMix1(int * unsafe samples, xc_ptr mult);
|
||||||
int doMix2(xc_ptr samples, xc_ptr mult);
|
int doMix2(int * unsafe samples, xc_ptr mult);
|
||||||
int doMix3(xc_ptr samples, xc_ptr mult);
|
int doMix3(int * unsafe samples, xc_ptr mult);
|
||||||
int doMix4(xc_ptr samples, xc_ptr mult);
|
int doMix4(int * unsafe samples, xc_ptr mult);
|
||||||
int doMix5(xc_ptr samples, xc_ptr mult);
|
int doMix5(int * unsafe samples, xc_ptr mult);
|
||||||
int doMix6(xc_ptr samples, xc_ptr mult);
|
int doMix6(int * unsafe samples, xc_ptr mult);
|
||||||
int doMix7(xc_ptr samples, xc_ptr mult);
|
int doMix7(int * unsafe samples, xc_ptr mult);
|
||||||
int doMix8(xc_ptr samples, xc_ptr mult);
|
int doMix8(int * unsafe samples, xc_ptr mult);
|
||||||
#else
|
#else
|
||||||
/* DO NOT inline, causes 10.4.2 tools to add extra loads in loop */
|
/* DO NOT inline, causes 10.4.2 tools to add extra loads in loop */
|
||||||
/* At 18 x 12dB we could get 64 x bigger */
|
/* At 18 x 12dB we could get 64 x bigger */
|
||||||
#pragma unsafe arrays
|
#pragma unsafe arrays
|
||||||
static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
|
static inline int doMix(xc_ptr samples, xc_ptr mixMapSlice, xc_ptr mixMultSlice)
|
||||||
{
|
{
|
||||||
int h=0;
|
int h=0;
|
||||||
int l=0;
|
int l=0;
|
||||||
@@ -133,17 +120,16 @@ static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
|
|||||||
for (int i=0; i<MIX_INPUTS; i++)
|
for (int i=0; i<MIX_INPUTS; i++)
|
||||||
{
|
{
|
||||||
int sample;
|
int sample;
|
||||||
int index;
|
int source;
|
||||||
int m;
|
int weight;
|
||||||
read_via_xc_ptr_indexed(index, ptr, i);
|
read_via_xc_ptr_indexed(source, mixMapSlice, i);
|
||||||
read_via_xc_ptr_indexed(sample,samples,index);
|
read_via_xc_ptr_indexed(sample, samples, source);
|
||||||
read_via_xc_ptr_indexed(m, mult, i);
|
read_via_xc_ptr_indexed(weight, mixMultSlice, i);
|
||||||
{h,l} = macs(sample, m, h, l);
|
{h,l} = macs(sample, weight, h, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
|
||||||
/* Perform saturation */
|
/* Perform saturation */
|
||||||
l = sext(h, 25);
|
l = sext(h, XUA_MIXER_MULT_FRAC_BITS);
|
||||||
|
|
||||||
if(l != h)
|
if(l != h)
|
||||||
{
|
{
|
||||||
@@ -152,7 +138,6 @@ static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
|
|||||||
else
|
else
|
||||||
h = (0x7fffff00>>7);
|
h = (0x7fffff00>>7);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return h<<7;
|
return h<<7;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -179,7 +164,6 @@ static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
|
|||||||
#endif
|
#endif
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
//read_via_xc_ptr_indexed(sample,samples,index);
|
|
||||||
sample = ptr_samples[index];
|
sample = ptr_samples[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +253,12 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
|||||||
read_via_xc_ptr_indexed(index, ptr, i);
|
read_via_xc_ptr_indexed(index, ptr, i);
|
||||||
|
|
||||||
/* Read the actual sample value */
|
/* Read the actual sample value */
|
||||||
read_via_xc_ptr_indexed(sample, samples, index);
|
//read_via_xc_ptr_indexed(sample, samples, index);
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
/* Read the actual sample value */
|
||||||
|
sample = ptr_samples[index];
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
@@ -284,7 +273,6 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
|||||||
read_via_xc_ptr_indexed(mult, multOut, i);
|
read_via_xc_ptr_indexed(mult, multOut, i);
|
||||||
{h, l} = macs(mult, sample, 0, 0);
|
{h, l} = macs(mult, sample, 0, 0);
|
||||||
h<<=3; // Shift used to be done in audio thread but now done here incase of 32bit support
|
h<<=3; // Shift used to be done in audio thread but now done here incase of 32bit support
|
||||||
#error
|
|
||||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||||
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||||
// Note: We need all 32bits for Native DSD
|
// Note: We need all 32bits for Native DSD
|
||||||
@@ -307,7 +295,7 @@ static inline void GetSamplesFromDevice(chanend c)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#pragma loop unroll
|
#pragma loop unroll
|
||||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||||
{
|
{
|
||||||
int sample;
|
int sample;
|
||||||
int x;
|
int x;
|
||||||
@@ -334,12 +322,13 @@ static inline void GetSamplesFromDevice(chanend c)
|
|||||||
/* Do the multiply */
|
/* Do the multiply */
|
||||||
{h, l} = macs(mult, sample, 0, 0);
|
{h, l} = macs(mult, sample, 0, 0);
|
||||||
h <<=3;
|
h <<=3;
|
||||||
write_via_xc_ptr_indexed(samples_array, NUM_USB_CHAN_OUT+i, h);
|
write_via_xc_ptr_indexed(samples_array, XUA_MIXER_OFFSET_IN+i, h);
|
||||||
#else
|
#else
|
||||||
/* No volume processing */
|
/* No volume processing */
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
ptr_samples[NUM_USB_CHAN_OUT + i] = sample;
|
assert((XUA_MIXER_OFFSET_IN + i) < (NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT));
|
||||||
|
ptr_samples[XUA_MIXER_OFFSET_IN + i] = sample;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -394,12 +383,19 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SET_MIX_MULT:
|
case SET_MIX_MULT:
|
||||||
|
|
||||||
mix = inuint(c_mix_ctl);
|
mix = inuint(c_mix_ctl);
|
||||||
index = inuint(c_mix_ctl);
|
index = inuint(c_mix_ctl);
|
||||||
val = inuint(c_mix_ctl);
|
val = inuint(c_mix_ctl);
|
||||||
inct(c_mix_ctl);
|
inct(c_mix_ctl);
|
||||||
|
|
||||||
|
if((index < MIX_INPUTS) && (mix < MAX_MIX_COUNT))
|
||||||
|
{
|
||||||
write_word_to_mix_mult(mix, index, val);
|
write_word_to_mix_mult(mix, index, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert((index < MIX_INPUTS) && (mix < MAX_MIX_COUNT) && msg("Mix mult index out of range"));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SET_MIX_MAP:
|
case SET_MIX_MAP:
|
||||||
@@ -520,9 +516,8 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
|
|
||||||
#pragma loop unroll
|
#pragma loop unroll
|
||||||
/* Reset the mix values back to 0 */
|
/* Reset the mix values back to 0 */
|
||||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
for (int i=0; i<MAX_MIX_COUNT; i++)
|
||||||
{
|
{
|
||||||
//write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
||||||
@@ -544,13 +539,15 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
inuint(c_mixer2);
|
inuint(c_mixer2);
|
||||||
|
|
||||||
/* Do the mixing */
|
/* Do the mixing */
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
#ifdef FAST_MIXER
|
#ifdef FAST_MIXER
|
||||||
mixed = doMix0(samples, mix_mult_slice(0));
|
mixed = doMix0(ptr_samples, mix_mult_slice(0));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(0),mix_mult_slice(0));
|
mixed = doMix(ptr_samples, mix_map_slice(0), mix_mult_slice(0));
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0), mixed);
|
ptr_samples[XUA_MIXER_OFFSET_MIX + 0] = mixed;
|
||||||
|
}
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 0);
|
ComputeMixerLevel(mixed, 0);
|
||||||
#endif
|
#endif
|
||||||
@@ -559,14 +556,16 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
if (!mixer1_mix2_flag)
|
if (!mixer1_mix2_flag)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 2
|
#if MAX_MIX_COUNT > 2
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
#ifdef FAST_MIXER
|
#ifdef FAST_MIXER
|
||||||
mixed = doMix2(samples, mix_mult_slice(2));
|
mixed = doMix2(ptr_samples, mix_mult_slice(2));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(2),mix_mult_slice(2));
|
mixed = doMix(ptr_samples, mix_map_slice(2), mix_mult_slice(2));
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2), mixed);
|
ptr_samples[XUA_MIXER_OFFSET_MIX + 2] = mixed;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 2);
|
ComputeMixerLevel(mixed, 2);
|
||||||
@@ -574,26 +573,30 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 4
|
#if MAX_MIX_COUNT > 4
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
#ifdef FAST_MIXER
|
#ifdef FAST_MIXER
|
||||||
mixed = doMix4(samples, mix_mult_slice(4));
|
mixed = doMix4(ptr_samples, mix_mult_slice(4));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(4),mix_mult_slice(4));
|
mixed = doMix(samples, mix_map_slice(4), mix_mult_slice(4));
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 4), mixed);
|
ptr_samples[XUA_MIXER_OFFSET_MIX + 4] = mixed;
|
||||||
|
}
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 4);
|
ComputeMixerLevel(mixed, 4);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 6
|
#if MAX_MIX_COUNT > 6
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
#ifdef FAST_MIXER
|
#ifdef FAST_MIXER
|
||||||
mixed = doMix6(samples, mix_mult_slice(6));
|
mixed = doMix6(ptr_samples, mix_mult_slice(6));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(6),mix_mult_slice(6));
|
mixed = doMix(samples, mix_map_slice(6), mix_mult_slice(6));
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 6), mixed);
|
ptr_samples[XUA_MIXER_OFFSET_MIX + 6] = mixed;
|
||||||
|
}
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 6);
|
ComputeMixerLevel(mixed, 6);
|
||||||
#endif
|
#endif
|
||||||
@@ -661,7 +664,10 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
|||||||
|
|
||||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||||
{
|
{
|
||||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
|
unsafe
|
||||||
|
{
|
||||||
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for handshake and pass on */
|
/* Wait for handshake and pass on */
|
||||||
@@ -679,60 +685,65 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
|||||||
|
|
||||||
/* Do the mixing */
|
/* Do the mixing */
|
||||||
#if MAX_MIX_COUNT > 1
|
#if MAX_MIX_COUNT > 1
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
#ifdef FAST_MIXER
|
#ifdef FAST_MIXER
|
||||||
mixed = doMix1(samples, mix_mult_slice(1));
|
mixed = doMix1(ptr_samples, mix_mult_slice(1));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(1),mix_mult_slice(1));
|
mixed = doMix(samples, mix_map_slice(1), mix_mult_slice(1));
|
||||||
#endif
|
#endif
|
||||||
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1] = mixed;
|
||||||
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)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 1);
|
ComputeMixerLevel(mixed, 1);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if (MAX_FREQ > 96000)
|
#if (MAX_FREQ > 96000)
|
||||||
/* Fewer mixes when running higher than 96kHz */
|
/* Fewer mixes when running higher than 96kHz */
|
||||||
if (!mixer2_mix2_flag)
|
if (!mixer2_mix2_flag)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if MAX_MIX_COUNT > 3
|
#if MAX_MIX_COUNT > 3
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
#ifdef FAST_MIXER
|
#ifdef FAST_MIXER
|
||||||
mixed = doMix3(samples, mix_mult_slice(3));
|
mixed = doMix3(ptr_samples, mix_mult_slice(3));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(3),mix_mult_slice(3));
|
mixed = doMix(samples, mix_map_slice(3), mix_mult_slice(3));
|
||||||
#endif
|
#endif
|
||||||
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3] = mixed;
|
||||||
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)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 3);
|
ComputeMixerLevel(mixed, 3);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 5
|
#if MAX_MIX_COUNT > 5
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
#ifdef FAST_MIXER
|
#ifdef FAST_MIXER
|
||||||
mixed = doMix5(samples, mix_mult_slice(5));
|
mixed = doMix5(ptr_samples, mix_mult_slice(5));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(5),mix_mult_slice(5));
|
mixed = doMix(samples, mix_map_slice(5), mix_mult_slice(5));
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5, mixed);
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5] = mixed;
|
||||||
|
}
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 5);
|
ComputeMixerLevel(mixed, 5);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 7
|
#if MAX_MIX_COUNT > 7
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
#ifdef FAST_MIXER
|
#ifdef FAST_MIXER
|
||||||
mixed = doMix7(samples, mix_mult_slice(7));
|
mixed = doMix7(ptr_samples, mix_mult_slice(7));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(7),mix_mult_slice(7));
|
mixed = doMix(samples, mix_map_slice(7), mix_mult_slice(7));
|
||||||
#endif
|
#endif
|
||||||
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7] = mixed;
|
||||||
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)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 7);
|
ComputeMixerLevel(mixed, 7);
|
||||||
#endif
|
#endif
|
||||||
@@ -751,7 +762,7 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
|
|||||||
multOut = array_to_xc_ptr((multOut_array,unsigned[]));
|
multOut = array_to_xc_ptr((multOut_array,unsigned[]));
|
||||||
multIn = array_to_xc_ptr((multIn_array,unsigned[]));
|
multIn = array_to_xc_ptr((multIn_array,unsigned[]));
|
||||||
|
|
||||||
samples = array_to_xc_ptr((samples_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_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[]));
|
samples_to_device_map = array_to_xc_ptr((samples_to_device_map_array,unsigned[]));
|
||||||
|
|
||||||
@@ -770,7 +781,6 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
|
|||||||
|
|
||||||
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
|
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
|
||||||
unsafe {
|
unsafe {
|
||||||
//write_via_xc_ptr_indexed(samples,i,0);
|
|
||||||
ptr_samples[i] = 0;
|
ptr_samples[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,7 +789,7 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
|
|||||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||||
{
|
{
|
||||||
//samples_to_device_map_array[i] = i;
|
//samples_to_device_map_array[i] = i;
|
||||||
asm("stw %0, %1[%2]":: "r"(i), "r"(samples_to_device_map), "r"(i));
|
asm("stw %0, %1[%2]":: "r"(i), "r"(samples_to_device_map), "r"(XUA_MIXER_OFFSET_OUT+i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -799,7 +809,7 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
|
|||||||
|
|
||||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||||
{
|
{
|
||||||
write_via_xc_ptr_indexed(samples_to_host_map, i, NUM_USB_CHAN_OUT + i);
|
write_via_xc_ptr_indexed(samples_to_host_map, i, XUA_MIXER_OFFSET_IN + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MAX_MIX_COUNT> 0
|
#if MAX_MIX_COUNT> 0
|
||||||
@@ -809,7 +819,7 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
|
|||||||
#ifndef FAST_MIXER
|
#ifndef FAST_MIXER
|
||||||
write_word_to_mix_map(i,j, j < 16 ? j : j + 2);
|
write_word_to_mix_map(i,j, j < 16 ? j : j + 2);
|
||||||
#endif
|
#endif
|
||||||
write_word_to_mix_mult(i,j, i==j ? db_to_mult(0, 8, 25) : 0);
|
write_word_to_mix_mult(i,j, i==j ? db_to_mult(0, XUA_MIXER_DB_FRAC_BITS, XUA_MIXER_MULT_FRAC_BITS) : 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
45
tests/test_mixer_routing_input.py
Normal file
45
tests/test_mixer_routing_input.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Copyright 2023 XMOS LIMITED.
|
||||||
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
import pytest
|
||||||
|
import Pyxsim
|
||||||
|
from Pyxsim import testers
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def do_test(options, capfd, test_file, test_seed):
|
||||||
|
|
||||||
|
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||||
|
|
||||||
|
binary = f"{testname}/bin/{testname}.xe"
|
||||||
|
|
||||||
|
tester = testers.ComparisonTester(open("pass.expect"))
|
||||||
|
|
||||||
|
max_cycles = 15000000
|
||||||
|
|
||||||
|
simargs = [
|
||||||
|
"--max-cycles",
|
||||||
|
str(max_cycles),
|
||||||
|
]
|
||||||
|
|
||||||
|
build_options = []
|
||||||
|
build_options += ["TEST_SEED=" + str(test_seed)]
|
||||||
|
|
||||||
|
result = Pyxsim.run_on_simulator(
|
||||||
|
binary,
|
||||||
|
tester=tester,
|
||||||
|
build_options=build_options,
|
||||||
|
simargs=simargs,
|
||||||
|
capfd=capfd,
|
||||||
|
instTracing=options.enabletracing,
|
||||||
|
vcdTracing=options.enablevcdtracing,
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def test_mixer_routing_input(options, capfd, test_file, test_seed):
|
||||||
|
|
||||||
|
result = do_test(options, capfd, test_file, test_seed)
|
||||||
|
|
||||||
|
assert result
|
||||||
19
tests/test_mixer_routing_input/Makefile
Normal file
19
tests/test_mixer_routing_input/Makefile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
DEBUG ?= 0
|
||||||
|
|
||||||
|
ifeq ($(DEBUG),1)
|
||||||
|
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
|
||||||
|
else
|
||||||
|
TEST_DEBUG_FLAGS =
|
||||||
|
endif
|
||||||
|
|
||||||
|
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS)
|
||||||
|
|
||||||
|
XCC_FLAGS = -O3 $(TEST_FLAGS)
|
||||||
|
|
||||||
|
TARGET = test_xs3_600.xn
|
||||||
|
|
||||||
|
USED_MODULES = lib_xua lib_logging lib_random
|
||||||
|
|
||||||
|
XMOS_MAKE_PATH ?= ../..
|
||||||
|
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||||
243
tests/test_mixer_routing_input/src/main.xc
Normal file
243
tests/test_mixer_routing_input/src/main.xc
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
// Copyright 2022-2023 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
|
/* Tests that routing of mixer inputs behaves as expected
|
||||||
|
*
|
||||||
|
* The device supports MAX_MIX_COUNT mixers each with MIX_INPUTS inputs.
|
||||||
|
*
|
||||||
|
* This test also assumes/checks that the default routing into each of the MIX_INPUTS inputs into
|
||||||
|
* each of the M mixer units is as follows:
|
||||||
|
*
|
||||||
|
* MIXER[0]:
|
||||||
|
* USB_FROM_HOST[0] -> MIXER[0].INPUT[0]
|
||||||
|
* USB_FROM_HOST[1] -> MIXER[0].INPUT[1]
|
||||||
|
* ...
|
||||||
|
USB_TO_HOST[0] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT]
|
||||||
|
USB_TO_HOST[1] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT+1]
|
||||||
|
...
|
||||||
|
|
||||||
|
* MIXER[MAX_MIX_COUNT-1]:
|
||||||
|
* USB_FROM_HOST[0] -> MIXER[MAX_MIX_COUNT-1].INPUT[0]
|
||||||
|
* USB_FROM_HOST[1] -> MIXER[MAX_MIX_COUNT-1].INPUT[1]
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "platform.h"
|
||||||
|
#include "xua.h"
|
||||||
|
#include "debug_print.h"
|
||||||
|
#include "assert.h"
|
||||||
|
#include "random.h"
|
||||||
|
|
||||||
|
#ifndef TEST_ITERATIONS
|
||||||
|
#define TEST_ITERATIONS (300)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "./../test_mixer_routing_output/src/mixer_test_shared.h"
|
||||||
|
|
||||||
|
struct ModelMixer
|
||||||
|
{
|
||||||
|
uint32_t deviceMap[NUM_USB_CHAN_OUT];
|
||||||
|
uint32_t hostMap[NUM_USB_CHAN_IN];
|
||||||
|
uint32_t mixMap_input[MAX_MIX_COUNT];
|
||||||
|
uint32_t mixMap_src[MAX_MIX_COUNT];
|
||||||
|
uint32_t mixOutput[MAX_MIX_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
void InitModel(struct ModelMixer &modelMixer)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||||
|
{
|
||||||
|
modelMixer.deviceMap[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||||
|
{
|
||||||
|
modelMixer.hostMap[i] = NUM_USB_CHAN_OUT+i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
|
||||||
|
{
|
||||||
|
// This test only allows for one "active" input to each mixer
|
||||||
|
modelMixer.mixMap_src[i] = i;
|
||||||
|
modelMixer.mixMap_input[i] = i;
|
||||||
|
|
||||||
|
uint32_t sample = i;
|
||||||
|
SET_SOURCE(sample, SRC_HOST);
|
||||||
|
SET_CHANNEL(sample, i);
|
||||||
|
modelMixer.mixOutput[i] = sample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenExpectedSamples(struct ModelMixer &modelMixer,
|
||||||
|
uint32_t modelOut[NUM_USB_CHAN_OUT],
|
||||||
|
uint32_t modelIn[NUM_USB_CHAN_IN])
|
||||||
|
{
|
||||||
|
/* First generate model mix outputs - run MIX tiles to allow mix inputs derived from mix outputs to propagate */
|
||||||
|
for(int j = 0; j < MAX_MIX_COUNT; j++)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
|
||||||
|
{
|
||||||
|
int src = modelMixer.mixMap_src[i];
|
||||||
|
modelMixer.mixOutput[i] = CreateSample(modelMixer.mixOutput, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i<NUM_USB_CHAN_OUT; i++)
|
||||||
|
{
|
||||||
|
int src = modelMixer.deviceMap[i];
|
||||||
|
modelOut[i] = CreateSample(modelMixer.mixOutput, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i<NUM_USB_CHAN_IN; i++)
|
||||||
|
{
|
||||||
|
int src = modelMixer.hostMap[i];
|
||||||
|
modelIn[i] = CreateSample(modelMixer.mixOutput, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MapMixerInput(int mix, int input, int src, struct ModelMixer &modelMixer, chanend c_mix_ctl,
|
||||||
|
chanend c_stim_ah, chanend c_stim_de, uint32_t modelIn[], uint32_t modelOut[])
|
||||||
|
{
|
||||||
|
debug_printf("Mapping mix %d input %d", mix, input);
|
||||||
|
debug_printf(" from %d", src);
|
||||||
|
PrintSourceString(src);
|
||||||
|
debug_printf("\n");
|
||||||
|
|
||||||
|
/* This test only allows for one input to travel "untouched" to the mix output - since this test doesn't model the actual mixing.
|
||||||
|
* Because of this we must also mod the mixer weights, not just the mixer input map.
|
||||||
|
* If we simply just apply an update to the mixer input mapping it would not produce an observable difference on the mixer output
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Set previously "activated" input weight to 0 */
|
||||||
|
debug_printf("Setting mix %d, weight %d to 0\n", mix, modelMixer.mixMap_input[mix]);
|
||||||
|
SendTrigger(c_stim_ah, 1);
|
||||||
|
UpdateMixerWeight(c_mix_ctl, mix, modelMixer.mixMap_input[mix], 0);
|
||||||
|
|
||||||
|
/* Set new "activated" input wright to max (i.e. x1) */
|
||||||
|
debug_printf("Setting mix %d, weight %d to %x\n", mix, input, XUA_MIXER_MAX_MULT);
|
||||||
|
SendTrigger(c_stim_ah, 1);
|
||||||
|
UpdateMixerWeight(c_mix_ctl, mix, input, XUA_MIXER_MAX_MULT);
|
||||||
|
|
||||||
|
/* Update mixer input in model */
|
||||||
|
modelMixer.mixMap_src[mix] = src;
|
||||||
|
modelMixer.mixMap_input[mix] = input;
|
||||||
|
|
||||||
|
/* Run twice to allow mix inputs derived from mix outputs to propagate */
|
||||||
|
GenExpectedSamples(modelMixer, modelOut, modelIn);
|
||||||
|
|
||||||
|
/* Finally update the acutal mixer input map */
|
||||||
|
SendTrigger(c_stim_ah, 1);
|
||||||
|
UpdateMixMap(c_mix_ctl, mix, input, src);
|
||||||
|
|
||||||
|
SendTrigger(c_stim_ah, 1);
|
||||||
|
|
||||||
|
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This task configures the routing and maintains a model of the expected routing output
|
||||||
|
* it provides this to the Fake AudioHub and Fake Decouple tasks such that they can self check
|
||||||
|
*/
|
||||||
|
void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
|
||||||
|
{
|
||||||
|
uint32_t modelOut[NUM_USB_CHAN_OUT];
|
||||||
|
uint32_t modelIn[NUM_USB_CHAN_IN];
|
||||||
|
|
||||||
|
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
|
||||||
|
|
||||||
|
struct ModelMixer modelMixer;
|
||||||
|
|
||||||
|
InitModel(modelMixer);
|
||||||
|
|
||||||
|
GenExpectedSamples(modelMixer, modelOut, modelIn);
|
||||||
|
|
||||||
|
/* There is single sample delay between the two mixer cores, so trigger twice to flush though a block
|
||||||
|
* of zero samples */
|
||||||
|
SendTrigger(c_stim_ah, 2);
|
||||||
|
|
||||||
|
/* Send expected samples to AH and DE and run checks */
|
||||||
|
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||||
|
|
||||||
|
/* Firstly route mixer outputs to the audio interfaces (we could have chosen host)
|
||||||
|
* such that we can observe and check the outputs from the mixer
|
||||||
|
*/
|
||||||
|
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
|
||||||
|
{
|
||||||
|
int map = SET_SAMPLES_TO_DEVICE_MAP;
|
||||||
|
assert(i < NUM_USB_CHAN_OUT);
|
||||||
|
int dst = i;
|
||||||
|
int src = NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN+i; // mix0, mix1..
|
||||||
|
debug_printf("Mapping output to AudioIF: %d ", dst);
|
||||||
|
|
||||||
|
PrintDestString(map, dst);
|
||||||
|
debug_printf(" from %d", src);
|
||||||
|
PrintSourceString(src);
|
||||||
|
debug_printf("\n");
|
||||||
|
|
||||||
|
SendTrigger(c_stim_ah, 1);
|
||||||
|
|
||||||
|
/* Update the mixer */
|
||||||
|
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
|
||||||
|
|
||||||
|
/* Update the model */
|
||||||
|
modelMixer.deviceMap[dst] = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send expected samples to fake AudioHub and Decouple for checking */
|
||||||
|
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||||
|
|
||||||
|
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
|
||||||
|
{
|
||||||
|
/* Make a random update to the routing - route a random source to a random mix input */
|
||||||
|
unsigned mix = random_get_random_number(rg) % MAX_MIX_COUNT;
|
||||||
|
unsigned input = random_get_random_number(rg) % MIX_INPUTS;
|
||||||
|
|
||||||
|
/* Note, we don't currently support a mix input dervived from another mix
|
||||||
|
* This is not trivial to test since the current mixer implementation only allows for one
|
||||||
|
* config update per "trigger"
|
||||||
|
*/
|
||||||
|
unsigned src = random_get_random_number(rg) % NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT;
|
||||||
|
|
||||||
|
debug_printf("Iteration: %d\n", testIter);
|
||||||
|
MapMixerInput(mix, input, src, modelMixer, c_mix_ctl, c_stim_ah, c_stim_de, modelIn, modelOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send kill messages to Fake AudioHub & Fake Decouple */
|
||||||
|
outct(c_stim_ah, XS1_CT_END);
|
||||||
|
inct(c_stim_ah);
|
||||||
|
|
||||||
|
outct(c_stim_de, XS1_CT_END);
|
||||||
|
inct(c_stim_de);
|
||||||
|
|
||||||
|
printstrln("PASS");
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
chan c_dec_mix;
|
||||||
|
chan c_mix_aud;
|
||||||
|
chan c_mix_ctl;
|
||||||
|
chan c_stim_ah;
|
||||||
|
chan c_stim_de;
|
||||||
|
|
||||||
|
par
|
||||||
|
{
|
||||||
|
Fake_XUA_Buffer_Decouple(c_dec_mix, c_stim_de);
|
||||||
|
Fake_XUA_AudioHub(c_mix_aud, c_stim_ah);
|
||||||
|
|
||||||
|
/* Mixer from lib_xua */
|
||||||
|
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
|
||||||
|
|
||||||
|
stim(c_stim_ah, c_stim_de, c_mix_ctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO to hit this we need to fully close down i.e. kill mixer */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
24
tests/test_mixer_routing_input/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_input/src/test_xs3_600.xn
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Network xmlns="http://www.xmos.com"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
|
||||||
|
<Declarations>
|
||||||
|
<Declaration>tileref tile[2]</Declaration>
|
||||||
|
</Declarations>
|
||||||
|
|
||||||
|
<Packages>
|
||||||
|
<Package id="0" Type="XS3-UnA-1024-FB265">
|
||||||
|
<Nodes>
|
||||||
|
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
|
||||||
|
<Tile Number="0" Reference="tile[0]"/>
|
||||||
|
<Tile Number="1" Reference="tile[1]"/>
|
||||||
|
</Node>
|
||||||
|
</Nodes>
|
||||||
|
</Package>
|
||||||
|
</Packages>
|
||||||
|
|
||||||
|
<JTAGChain>
|
||||||
|
<JTAGDevice NodeId="0"/>
|
||||||
|
</JTAGChain>
|
||||||
|
|
||||||
|
</Network>
|
||||||
45
tests/test_mixer_routing_input/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_input/src/xua_conf.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright 2016-2023 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
#ifndef _XUA_CONF_H_
|
||||||
|
#define _XUA_CONF_H_
|
||||||
|
|
||||||
|
#define NUM_USB_CHAN_OUT (10)
|
||||||
|
#define NUM_USB_CHAN_IN (10)
|
||||||
|
#define I2S_CHANS_DAC (10)
|
||||||
|
#define I2S_CHANS_ADC (10)
|
||||||
|
|
||||||
|
#define EXCLUDE_USB_AUDIO_MAIN
|
||||||
|
|
||||||
|
#define MIXER (1)
|
||||||
|
#define MAX_MIX_COUNT (8)
|
||||||
|
|
||||||
|
#define UAC_FORCE_FEEDBACK_EP (0)
|
||||||
|
#define XUA_NUM_PDM_MICS 0
|
||||||
|
#define XUD_TILE 1
|
||||||
|
#define AUDIO_IO_TILE 0
|
||||||
|
|
||||||
|
#ifndef MCLK_441
|
||||||
|
#define MCLK_441 (512 * 44100)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MCLK_48
|
||||||
|
#define MCLK_48 (512 * 48000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MIN_FREQ (44100)
|
||||||
|
#define MAX_FREQ (192000)
|
||||||
|
#define SPDIF_TX_INDEX 0
|
||||||
|
#define VENDOR_STR "XMOS"
|
||||||
|
#define VENDOR_ID 0x20B1
|
||||||
|
#define PRODUCT_STR_A2 "Test device"
|
||||||
|
#define PRODUCT_STR_A1 "Test device"
|
||||||
|
#define PID_AUDIO_1 1
|
||||||
|
#define PID_AUDIO_2 2
|
||||||
|
#define AUDIO_CLASS 2
|
||||||
|
#define AUDIO_CLASS_FALLBACK 0
|
||||||
|
#define BCD_DEVICE 0x1234
|
||||||
|
#define XUA_DFU_EN 0
|
||||||
|
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
|
||||||
|
#define XUA_MIC_FRAME_SIZE 240
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,7 +1,15 @@
|
|||||||
|
|
||||||
TEST_FLAGS ?= -DTEST_SEED=$(TEST_SEED)
|
DEBUG ?= 0
|
||||||
|
|
||||||
XCC_FLAGS = -O3 -g -DDEBUG_PRINT_ENABLE_main=0 $(TEST_FLAGS)
|
ifeq ($(DEBUG),1)
|
||||||
|
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
|
||||||
|
else
|
||||||
|
TEST_DEBUG_FLAGS =
|
||||||
|
endif
|
||||||
|
|
||||||
|
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS)
|
||||||
|
|
||||||
|
XCC_FLAGS = -O3 $(TEST_FLAGS)
|
||||||
|
|
||||||
TARGET = test_xs3_600.xn
|
TARGET = test_xs3_600.xn
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "xua.h"
|
#include "xua.h"
|
||||||
#define DEBUG_UNIT main
|
|
||||||
#include "debug_print.h"
|
#include "debug_print.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
@@ -52,115 +51,7 @@
|
|||||||
#define TEST_ITERATIONS (100)
|
#define TEST_ITERATIONS (100)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TEST_SEED
|
#include "./mixer_test_shared.h"
|
||||||
#error TEST_SEED must be defined!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void exit(int);
|
|
||||||
|
|
||||||
// Test sample format:
|
|
||||||
// byte[0]: Sample counter
|
|
||||||
// byte[1]: Channel
|
|
||||||
// byte[3]: Source (HOST:1/AUD IF:0)
|
|
||||||
#define SRC_HOST (2)
|
|
||||||
#define SRC_AUDIF (1)
|
|
||||||
#define SRC_OFF (0) // Important that this is 0 since mixer will generate 0 samples for 'off'
|
|
||||||
|
|
||||||
#define GET_COUNT(x) (x & 0xff)
|
|
||||||
#define GET_CHANNEL(x) ((x >> 8) & 0xff)
|
|
||||||
#define GET_SOURCE(x) ((x >> 16) & 0xff)
|
|
||||||
|
|
||||||
#define SET_COUNT(x, y) y = y & 0xff; x = x | y;
|
|
||||||
#define SET_CHANNEL(x, y) y = y & 0xff; x = x | (y<<8);
|
|
||||||
#define SET_SOURCE(x, y) x = x | (y<<16);
|
|
||||||
|
|
||||||
/* A limitation of the design is that the number of routable output destinations cannot be larger than NUM_USB_CHAN_OUT.
|
|
||||||
* This is due to the transfer samples from Mixer to AudioHub tasks being in blocks of NUM_USB_CHAN_OUT.
|
|
||||||
* This is not normally an issue - since every physical output interface channel on the device is normally derived from a
|
|
||||||
* USB channel from the host, but it certainly is a restriction.
|
|
||||||
*/
|
|
||||||
#define CHANNEL_MAP_AUD_SIZE NUM_USB_CHAN_OUT
|
|
||||||
|
|
||||||
/* Number of channel sources, the channel ordering is as follows
|
|
||||||
* i.e.
|
|
||||||
* [0:NUM_USB_CHAN_OUT-1] : Channels from USB Host
|
|
||||||
* [NUM_USB_CHAN_OUT:NUM_USB_CHAN_IN-1] : Channels from Audio Interfaces
|
|
||||||
* [NUM_USB_CHAN_N:MAX_MIX_COUNT-1] : Channels from Mixers
|
|
||||||
* [MAX_MIX_COUNT]: "Off" (Essentially samples always 0)
|
|
||||||
*/
|
|
||||||
/* Note, One larger for an "off" channel for mixer sources" */
|
|
||||||
#define SOURCE_COUNT (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1)
|
|
||||||
|
|
||||||
#pragma select handler
|
|
||||||
static inline void testct_byref(chanend c, unsigned &isCt)
|
|
||||||
{
|
|
||||||
isCt = testct(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintSourceString(unsigned source)
|
|
||||||
{
|
|
||||||
debug_printf(" ");
|
|
||||||
if(source < NUM_USB_CHAN_OUT)
|
|
||||||
{
|
|
||||||
debug_printf("(DEVICE IN - HOST%d)", source);
|
|
||||||
}
|
|
||||||
else if(source < (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN))
|
|
||||||
{
|
|
||||||
debug_printf("(DEVICE IN - AudioIF %d)", source - NUM_USB_CHAN_OUT);
|
|
||||||
}
|
|
||||||
else if(source < (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT))
|
|
||||||
{
|
|
||||||
debug_printf("(MIX %d)", source - NUM_USB_CHAN_OUT - NUM_USB_CHAN_IN);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
debug_printf("(off)");
|
|
||||||
debug_printf(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintDestString(unsigned map, unsigned dest)
|
|
||||||
{
|
|
||||||
switch(map)
|
|
||||||
{
|
|
||||||
case SET_SAMPLES_TO_DEVICE_MAP:
|
|
||||||
debug_printf("(DEVICE OUT - AudioIF)");
|
|
||||||
break;
|
|
||||||
case SET_SAMPLES_TO_HOST_MAP:
|
|
||||||
debug_printf("(DEVICE OUT - HOST)");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintSample(unsigned sample)
|
|
||||||
{
|
|
||||||
debug_printf("SOURCE: ");
|
|
||||||
if(GET_SOURCE(sample) == SRC_HOST)
|
|
||||||
debug_printf("HOST ");
|
|
||||||
else if(GET_SOURCE(sample) == SRC_AUDIF)
|
|
||||||
debug_printf("AUDIF ");
|
|
||||||
else if(GET_SOURCE(sample) == SRC_OFF)
|
|
||||||
debug_printf("OFF ");
|
|
||||||
else
|
|
||||||
debug_printf("UNKNOWN ");
|
|
||||||
|
|
||||||
debug_printf("CHANNEL: %d", GET_CHANNEL(sample));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Required by lib_xua */
|
|
||||||
void AudioHwInit()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Required by lib_xua */
|
|
||||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* From xua_ep0_uacreqs.xc */
|
|
||||||
void UpdateMixerOutputRouting(chanend c_mix_ctl, unsigned map, unsigned dst, unsigned src);
|
|
||||||
void UpdateMixMap(chanend c_mix_ctl, int mix, int input, int src);
|
|
||||||
void UpdateMixerWeight(chanend c_mix_ctl, int mix, int index, unsigned val);
|
|
||||||
|
|
||||||
void UpdateModel(uint32_t modelOut[CHANNEL_MAP_AUD_SIZE], uint32_t modelMixerOut[MAX_MIX_COUNT], uint32_t modelIn[NUM_USB_CHAN_IN],
|
void UpdateModel(uint32_t modelOut[CHANNEL_MAP_AUD_SIZE], uint32_t modelMixerOut[MAX_MIX_COUNT], uint32_t modelIn[NUM_USB_CHAN_IN],
|
||||||
int map, int dst, int src)
|
int map, int dst, int src)
|
||||||
@@ -214,7 +105,6 @@ void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
|
|||||||
uint32_t testCmd[] = {SET_SAMPLES_TO_HOST_MAP, SET_SAMPLES_TO_DEVICE_MAP};
|
uint32_t testCmd[] = {SET_SAMPLES_TO_HOST_MAP, SET_SAMPLES_TO_DEVICE_MAP};
|
||||||
|
|
||||||
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
|
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
|
||||||
//assert(NUM_USB_CHAN_OUT >= MIX_INPUTS);
|
|
||||||
|
|
||||||
/* By default the mixer should output samples from USB host unmodified
|
/* By default the mixer should output samples from USB host unmodified
|
||||||
* See mixer.xc L780
|
* See mixer.xc L780
|
||||||
@@ -247,17 +137,10 @@ void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
|
|||||||
modelIn[i] = sample;
|
modelIn[i] = sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
outuint(c_stim_ah, 0);
|
|
||||||
|
|
||||||
/* Check default routing */
|
/* Check default routing */
|
||||||
/* Send expected to AudioHub */
|
/* Send expected to AudioHub */
|
||||||
for(int i = 0; i < CHANNEL_MAP_AUD_SIZE; i++)
|
SendTrigger(c_stim_ah, 2);
|
||||||
{
|
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||||
outuint(c_stim_ah, modelOut[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for handshake back and move on to next test */
|
|
||||||
inuint(c_stim_ah);
|
|
||||||
|
|
||||||
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
|
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
|
||||||
{
|
{
|
||||||
@@ -276,6 +159,7 @@ void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
|
|||||||
debug_printf("\n");
|
debug_printf("\n");
|
||||||
|
|
||||||
/* Update the mixer */
|
/* Update the mixer */
|
||||||
|
SendTrigger(c_stim_ah, 1);
|
||||||
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
|
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -287,43 +171,23 @@ void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
|
|||||||
debug_printf("\n");
|
debug_printf("\n");
|
||||||
|
|
||||||
/* Update the mixer */
|
/* Update the mixer */
|
||||||
|
SendTrigger(c_stim_ah, 1);
|
||||||
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
|
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printstrln("ERROR BAD CMD");
|
printstr("ERROR: Bad cmd in stim(): ");
|
||||||
|
printintln(map);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the model */
|
/* Update the model */
|
||||||
UpdateModel(modelOut, modelMixerOut, modelIn, map, dst, src);
|
UpdateModel(modelOut, modelMixerOut, modelIn, map, dst, src);
|
||||||
|
|
||||||
/* Send expected to AudioHub */
|
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||||
outuint(c_stim_ah, 0);
|
|
||||||
for(int i = 0; i < CHANNEL_MAP_AUD_SIZE; i++)
|
|
||||||
{
|
|
||||||
outuint(c_stim_ah, modelOut[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for handshake back and move on to next test */
|
|
||||||
inuint(c_stim_ah);
|
|
||||||
|
|
||||||
/* Send expected to Decouple */
|
|
||||||
outuint(c_stim_de, 0);
|
|
||||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
|
||||||
{
|
|
||||||
outuint(c_stim_de, modelIn[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for handshake back and move on to next test */
|
|
||||||
inuint(c_stim_de);
|
|
||||||
}
|
|
||||||
|
|
||||||
timer t;
|
|
||||||
unsigned time;
|
|
||||||
t :> time;
|
|
||||||
t when timerafter(time+10000) :> void;
|
|
||||||
|
|
||||||
/* Send kill messages to Fake AudioHub & Fake Decouple */
|
/* Send kill messages to Fake AudioHub & Fake Decouple */
|
||||||
outct(c_stim_ah, XS1_CT_END);
|
outct(c_stim_ah, XS1_CT_END);
|
||||||
inct(c_stim_ah);
|
inct(c_stim_ah);
|
||||||
@@ -335,136 +199,6 @@ void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckBlock(unsigned samplesOut[], uint32_t expectedOut[], size_t len)
|
|
||||||
{
|
|
||||||
for(int j = 0; j < len; j++)
|
|
||||||
{
|
|
||||||
debug_printf("%d: Expected: ", j);
|
|
||||||
PrintSample(expectedOut[j]);
|
|
||||||
debug_printf("\n");
|
|
||||||
if(expectedOut[j] != samplesOut[j])
|
|
||||||
{
|
|
||||||
printstr("ERROR: Actual: ");
|
|
||||||
PrintSample(samplesOut[j]);
|
|
||||||
}
|
|
||||||
assert(expectedOut[j] == samplesOut[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* From xua_audiohub.xc */
|
|
||||||
extern unsigned samplesOut[NUM_USB_CHAN_OUT];
|
|
||||||
extern unsigned samplesIn[2][NUM_USB_CHAN_IN];
|
|
||||||
#include "xua_audiohub_st.h"
|
|
||||||
|
|
||||||
int Fake_XUA_AudioHub(chanend c_mix_aud, chanend c_stim)
|
|
||||||
{
|
|
||||||
int readBuffNo = 0;
|
|
||||||
unsigned underflowWord = 0;
|
|
||||||
uint32_t expectedOut[NUM_USB_CHAN_OUT];
|
|
||||||
unsigned ct = 0;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < NUM_USB_CHAN_IN; i++)
|
|
||||||
{
|
|
||||||
/* Note, we only used readBufNo = 0 */
|
|
||||||
unsigned sample = 0;
|
|
||||||
SET_SOURCE(sample, SRC_AUDIF);
|
|
||||||
SET_CHANNEL(sample, i);
|
|
||||||
samplesIn[0][i] = sample;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(!ct)
|
|
||||||
{
|
|
||||||
/* This will populate samplesOut and send out samplesIn[readBuffNo] */
|
|
||||||
unsigned command = DoSampleTransfer(c_mix_aud, readBuffNo, underflowWord);
|
|
||||||
|
|
||||||
select
|
|
||||||
{
|
|
||||||
case testct_byref(c_stim, ct):
|
|
||||||
|
|
||||||
if(!ct)
|
|
||||||
{
|
|
||||||
inuint(c_stim); // TODO don't really need this
|
|
||||||
|
|
||||||
/* Get expected */
|
|
||||||
for(int j = 0; j < NUM_USB_CHAN_OUT; j++)
|
|
||||||
{
|
|
||||||
expectedOut[j] = inuint(c_stim);
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckBlock(samplesOut, expectedOut, NUM_USB_CHAN_OUT);
|
|
||||||
|
|
||||||
/* Handshake back */
|
|
||||||
outuint(c_stim, 0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outct(c_stim, XS1_CT_END);
|
|
||||||
inct(c_stim);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Fake_XUA_Buffer_Decouple(chanend c_dec_mix, chanend c_stim)
|
|
||||||
{
|
|
||||||
unsigned tmp;
|
|
||||||
uint32_t expectedSamplesIn[NUM_USB_CHAN_IN];
|
|
||||||
unsigned samplesIn[NUM_USB_CHAN_IN];
|
|
||||||
unsigned ct;
|
|
||||||
unsigned underflowSample;
|
|
||||||
|
|
||||||
while(!ct)
|
|
||||||
{
|
|
||||||
select
|
|
||||||
{
|
|
||||||
case inuint_byref(c_dec_mix, underflowSample):
|
|
||||||
|
|
||||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
|
||||||
{
|
|
||||||
unsigned sample = 0;
|
|
||||||
SET_SOURCE(sample, SRC_HOST);
|
|
||||||
SET_CHANNEL(sample, i);
|
|
||||||
outuint(c_dec_mix, sample);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
|
||||||
{
|
|
||||||
samplesIn[i] = inuint(c_dec_mix);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case testct_byref(c_stim, ct):
|
|
||||||
|
|
||||||
if(!ct)
|
|
||||||
{
|
|
||||||
inuint(c_stim); // TODO don't really need this
|
|
||||||
|
|
||||||
/* Get expected */
|
|
||||||
for(int j = 0; j < NUM_USB_CHAN_IN; j++)
|
|
||||||
{
|
|
||||||
expectedSamplesIn[j] = inuint(c_stim);
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckBlock(samplesIn, expectedSamplesIn, NUM_USB_CHAN_IN);
|
|
||||||
|
|
||||||
/* Handshake back */
|
|
||||||
outuint(c_stim, 0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outct(c_stim, XS1_CT_END);
|
|
||||||
inct(c_stim);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
chan c_dec_mix;
|
chan c_dec_mix;
|
||||||
@@ -487,3 +221,4 @@ int main()
|
|||||||
/* TODO to hit this we need to fully close down i.e. kill mixer */
|
/* TODO to hit this we need to fully close down i.e. kill mixer */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
323
tests/test_mixer_routing_output/src/mixer_test_shared.h
Normal file
323
tests/test_mixer_routing_output/src/mixer_test_shared.h
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
// Copyright 2023 XMOS LIMITED.
|
||||||
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
#ifndef TEST_SEED
|
||||||
|
#error TEST_SEED must be defined!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A limitation of the design is that the number of routable output destinations cannot be larger than NUM_USB_CHAN_OUT.
|
||||||
|
* This is due to the transfer samples from Mixer to AudioHub tasks being in blocks of NUM_USB_CHAN_OUT.
|
||||||
|
* This is not normally an issue - since every physical output interface channel on the device is normally derived from a
|
||||||
|
* USB channel from the host, but it certainly is a restriction.
|
||||||
|
*/
|
||||||
|
#define CHANNEL_MAP_AUD_SIZE NUM_USB_CHAN_OUT
|
||||||
|
|
||||||
|
/* Number of channel sources, the channel ordering is as follows
|
||||||
|
* i.e.
|
||||||
|
* [0:NUM_USB_CHAN_OUT-1] : Channels from USB Host
|
||||||
|
* [NUM_USB_CHAN_OUT:NUM_USB_CHAN_IN-1] : Channels from Audio Interfaces
|
||||||
|
* [NUM_USB_CHAN_N:MAX_MIX_COUNT-1] : Channels from Mixers
|
||||||
|
* [MAX_MIX_COUNT]: "Off" (Essentially samples always 0)
|
||||||
|
*/
|
||||||
|
/* Note, One larger for an "off" channel for mixer sources" */
|
||||||
|
#define SOURCE_COUNT (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1)
|
||||||
|
|
||||||
|
#define SET_EXPECTED (9)
|
||||||
|
#define TRIGGER (7)
|
||||||
|
|
||||||
|
// Test sample format:
|
||||||
|
// byte[0]: Sample counter
|
||||||
|
// byte[1]: Channel
|
||||||
|
// byte[3]: Source (HOST:1/AUD IF:0)
|
||||||
|
#define SRC_HOST (2)
|
||||||
|
#define SRC_AUDIF (1)
|
||||||
|
#define SRC_OFF (0) // Important that this is 0 since mixer will generate 0 samples for 'off'
|
||||||
|
|
||||||
|
#define GET_COUNT(x) ((x>>8) & 0xff)
|
||||||
|
#define GET_CHANNEL(x) ((x >> 16) & 0xff)
|
||||||
|
#define GET_SOURCE(x) ((x >> 24) & 0xff)
|
||||||
|
|
||||||
|
#define SET_COUNT(x, y) y = y & 0xff; x = x | (y<<8);
|
||||||
|
#define SET_CHANNEL(x, y) y = y & 0xff; x = x | (y<<16);
|
||||||
|
#define SET_SOURCE(x, y) x = x | (y<<24);
|
||||||
|
|
||||||
|
void exit(int);
|
||||||
|
|
||||||
|
#pragma select handler
|
||||||
|
static inline void testct_byref(chanend c, unsigned &isCt)
|
||||||
|
{
|
||||||
|
isCt = testct(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendTrigger(chanend c_stim_ah, int count)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < count; i++)
|
||||||
|
outuint(c_stim_ah, TRIGGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t CreateSample(uint32_t modelMixerOutput[], int src)
|
||||||
|
{
|
||||||
|
uint32_t sample = 0;
|
||||||
|
|
||||||
|
if(src == (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT))
|
||||||
|
{
|
||||||
|
SET_SOURCE(sample, SRC_OFF);
|
||||||
|
}
|
||||||
|
else if(src >= (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN))
|
||||||
|
{
|
||||||
|
src -= (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN);
|
||||||
|
sample = modelMixerOutput[src];
|
||||||
|
}
|
||||||
|
else if (src >= NUM_USB_CHAN_IN)
|
||||||
|
{
|
||||||
|
SET_SOURCE(sample, SRC_AUDIF);
|
||||||
|
src -= NUM_USB_CHAN_OUT;
|
||||||
|
SET_CHANNEL(sample, src);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SET_SOURCE(sample, SRC_HOST);
|
||||||
|
SET_CHANNEL(sample, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintSourceString(unsigned source)
|
||||||
|
{
|
||||||
|
debug_printf(" ");
|
||||||
|
if(source < NUM_USB_CHAN_OUT)
|
||||||
|
{
|
||||||
|
debug_printf("(DEVICE IN - HOST%d)", source);
|
||||||
|
}
|
||||||
|
else if(source < (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN))
|
||||||
|
{
|
||||||
|
debug_printf("(DEVICE IN - AudioIF %d)", source - NUM_USB_CHAN_OUT);
|
||||||
|
}
|
||||||
|
else if(source < (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT))
|
||||||
|
{
|
||||||
|
debug_printf("(MIX %d)", source - NUM_USB_CHAN_OUT - NUM_USB_CHAN_IN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug_printf("(off)");
|
||||||
|
debug_printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintDestString(unsigned map, unsigned dest)
|
||||||
|
{
|
||||||
|
switch(map)
|
||||||
|
{
|
||||||
|
case SET_SAMPLES_TO_DEVICE_MAP:
|
||||||
|
debug_printf("(DEVICE OUT - AudioIF)");
|
||||||
|
break;
|
||||||
|
case SET_SAMPLES_TO_HOST_MAP:
|
||||||
|
debug_printf("(DEVICE OUT - HOST)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintSample(unsigned sample)
|
||||||
|
{
|
||||||
|
debug_printf("SOURCE: ");
|
||||||
|
if(GET_SOURCE(sample) == SRC_HOST)
|
||||||
|
debug_printf("HOST ");
|
||||||
|
else if(GET_SOURCE(sample) == SRC_AUDIF)
|
||||||
|
debug_printf("AUDIF ");
|
||||||
|
else if(GET_SOURCE(sample) == SRC_OFF)
|
||||||
|
debug_printf("OFF ");
|
||||||
|
else
|
||||||
|
debug_printf("UNKNOWN ");
|
||||||
|
|
||||||
|
debug_printf("CHANNEL: %d", GET_CHANNEL(sample));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Required by lib_xua */
|
||||||
|
void AudioHwInit()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Required by lib_xua */
|
||||||
|
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* From xua_ep0_uacreqs.xc */
|
||||||
|
void UpdateMixerOutputRouting(chanend c_mix_ctl, unsigned map, unsigned dst, unsigned src);
|
||||||
|
void UpdateMixMap(chanend c_mix_ctl, int mix, int input, int src);
|
||||||
|
void UpdateMixerWeight(chanend c_mix_ctl, int mix, int index, unsigned val);
|
||||||
|
|
||||||
|
void CheckBlock(unsigned samplesOut[], uint32_t expectedOut[], size_t len)
|
||||||
|
{
|
||||||
|
int fail = 0;;
|
||||||
|
for(int j = 0; j < len; j++)
|
||||||
|
{
|
||||||
|
debug_printf("%d: Expected: ", j);
|
||||||
|
PrintSample(expectedOut[j]);
|
||||||
|
debug_printf("\n");
|
||||||
|
if(expectedOut[j] != samplesOut[j])
|
||||||
|
{
|
||||||
|
printstr("ERROR: Actual: ");
|
||||||
|
PrintSample(samplesOut[j]);
|
||||||
|
debug_printf(" (%x)", samplesOut[j]);
|
||||||
|
printstr("\n");
|
||||||
|
fail = 1;
|
||||||
|
}
|
||||||
|
//assert(expectedOut[j] == samplesOut[j]);
|
||||||
|
}
|
||||||
|
assert(!fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sending expected also causes fake_audiohub and fake_decouple to run sample checks */
|
||||||
|
void SendExpected(chanend c_stim_ah, chanend c_stim_de, uint32_t modelOut[], uint32_t modelIn[])
|
||||||
|
{
|
||||||
|
/* Send expected to AudioHub */
|
||||||
|
outuint(c_stim_ah, SET_EXPECTED);
|
||||||
|
|
||||||
|
for(int i = 0; i < CHANNEL_MAP_AUD_SIZE; i++)
|
||||||
|
{
|
||||||
|
outuint(c_stim_ah, modelOut[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for handshake back and move on to next test */
|
||||||
|
inuint(c_stim_ah);
|
||||||
|
|
||||||
|
/* Send expected to Decouple */
|
||||||
|
outuint(c_stim_de, SET_EXPECTED);
|
||||||
|
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||||
|
{
|
||||||
|
outuint(c_stim_de, modelIn[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for handshake back and move on to next test */
|
||||||
|
inuint(c_stim_de);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* From xua_audiohub.xc */
|
||||||
|
extern unsigned samplesOut[NUM_USB_CHAN_OUT];
|
||||||
|
extern unsigned samplesIn[2][NUM_USB_CHAN_IN];
|
||||||
|
#include "xua_audiohub_st.h"
|
||||||
|
|
||||||
|
int Fake_XUA_AudioHub(chanend c_mix_aud, chanend c_stim)
|
||||||
|
{
|
||||||
|
int readBuffNo = 0;
|
||||||
|
unsigned underflowWord = 0;
|
||||||
|
uint32_t expectedOut[NUM_USB_CHAN_OUT];
|
||||||
|
unsigned ct = 0;
|
||||||
|
unsigned cmd = 0;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||||
|
{
|
||||||
|
/* Note, we only used readBufNo = 0 */
|
||||||
|
unsigned sample = 0;
|
||||||
|
SET_SOURCE(sample, SRC_AUDIF);
|
||||||
|
SET_CHANNEL(sample, i);
|
||||||
|
samplesIn[0][i] = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!ct)
|
||||||
|
{
|
||||||
|
|
||||||
|
select
|
||||||
|
{
|
||||||
|
case testct_byref(c_stim, ct):
|
||||||
|
|
||||||
|
if(!ct)
|
||||||
|
{
|
||||||
|
cmd = inuint(c_stim);
|
||||||
|
|
||||||
|
switch(cmd)
|
||||||
|
{
|
||||||
|
case SET_EXPECTED:
|
||||||
|
|
||||||
|
for(int j = 0; j < NUM_USB_CHAN_OUT; j++)
|
||||||
|
{
|
||||||
|
expectedOut[j] = inuint(c_stim);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_printf("AudioHub:\n");
|
||||||
|
CheckBlock(samplesOut, expectedOut, NUM_USB_CHAN_OUT);
|
||||||
|
/* Handshake back */
|
||||||
|
outuint(c_stim, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRIGGER:
|
||||||
|
/* This will populate samplesOut and send out samplesIn[readBuffNo] */
|
||||||
|
unsigned command = DoSampleTransfer(c_mix_aud, readBuffNo, underflowWord);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printstr("ERROR: bad cmd in Fake_XUA_AudioHub: ");
|
||||||
|
printintln(cmd);
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outct(c_stim, XS1_CT_END);
|
||||||
|
inct(c_stim);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Fake_XUA_Buffer_Decouple(chanend c_dec_mix, chanend c_stim)
|
||||||
|
{
|
||||||
|
uint32_t expectedSamplesIn[NUM_USB_CHAN_IN];
|
||||||
|
unsigned samplesIn[NUM_USB_CHAN_IN];
|
||||||
|
unsigned ct;
|
||||||
|
unsigned underflowSample;
|
||||||
|
|
||||||
|
while(!ct)
|
||||||
|
{
|
||||||
|
select
|
||||||
|
{
|
||||||
|
case inuint_byref(c_dec_mix, underflowSample):
|
||||||
|
|
||||||
|
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||||
|
{
|
||||||
|
unsigned sample = 0;
|
||||||
|
SET_SOURCE(sample, SRC_HOST);
|
||||||
|
SET_CHANNEL(sample, i);
|
||||||
|
outuint(c_dec_mix, sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||||
|
{
|
||||||
|
samplesIn[i] = inuint(c_dec_mix);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case testct_byref(c_stim, ct):
|
||||||
|
|
||||||
|
if(!ct)
|
||||||
|
{
|
||||||
|
inuint(c_stim); // TODO don't really need this
|
||||||
|
|
||||||
|
/* Get expected */
|
||||||
|
for(int j = 0; j < NUM_USB_CHAN_IN; j++)
|
||||||
|
{
|
||||||
|
expectedSamplesIn[j] = inuint(c_stim);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_printf("Decouple:\n");
|
||||||
|
CheckBlock(samplesIn, expectedSamplesIn, NUM_USB_CHAN_IN);
|
||||||
|
|
||||||
|
/* Handshake back */
|
||||||
|
outuint(c_stim, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outct(c_stim, XS1_CT_END);
|
||||||
|
inct(c_stim);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user