merge testing branch and osx updates into branch

This commit is contained in:
Tom Williams
2023-02-08 11:59:07 +00:00
35 changed files with 1747 additions and 631 deletions

55
.gitignore vendored
View File

@@ -1,29 +1,24 @@
*.log # XMOS bin files
*.dSYM
*/.build_*/*
*/bin/*
*.o
*.xe *.xe
*.vcd *.bin
*.swo */bin/*
# XMOS temp files
.build*
*.a
_build*
*.i
*.s *.s
*.xi *.xi
*.i *.o
*.bin */.build_*/*
*~
*.a # Temp files
*.swp
*.*~
*.pyc
.build*
.DS_Store .DS_Store
test_results.csv *.*~
_build* *.swp
**/.venv/** *~
**/.vscode/** *.swo
**.egg-info
*.pdf
*tests/logs/*
# waf build files # waf build files
.lock-waf_* .lock-waf_*
@@ -36,3 +31,19 @@ xscope.xmt
# Traces # Traces
*.gtkw *.gtkw
*.vcd *.vcd
# Host binaries
host_usb_mixer_control/xmos_mixer
# Documentation build
*.pdf
# Misc
*.log
*.dSYM
*.vcd
*.pyc
**/.venv/**
**/.vscode/**
**.egg-info
*tests/logs/*

View File

@@ -4,6 +4,9 @@ lib_xua Change Log
UNRELEASED UNRELEASED
---------- ----------
* ADDED: Unit tests for mixer functionalty
* ADDED: Host mixer control applicatons (for Win/macOS)
* CHANGED: Small tidies to mixer implementation
* FIXED: Exception on startup when USB input disabled * FIXED: Exception on startup when USB input disabled
3.3.1 3.3.1

View File

@@ -21,4 +21,3 @@ USED_MODULES = lib_xua lib_xud lib_i2c
XMOS_MAKE_PATH ?= ../.. XMOS_MAKE_PATH ?= ../..
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -20,4 +20,3 @@ USED_MODULES = lib_xua lib_xud lib_spdif
XMOS_MAKE_PATH ?= ../.. XMOS_MAKE_PATH ?= ../..
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -19,4 +19,3 @@ USED_MODULES = lib_xua lib_xud lib_mic_array
XMOS_MAKE_PATH ?= ../.. XMOS_MAKE_PATH ?= ../..
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -1,3 +1,2 @@
all: all:
g++ -g -o xmos_mixer OSX/usb_mixer.cpp mixer_app.cpp -I. -IOSX OSX/libusb-1.0.0.dylib -arch x86_64 g++ -g -o xmos_mixer OSX/usb_mixer.cpp mixer_app.cpp -I. -IOSX OSX/libusb-1.0.0.dylib -arch x86_64

View File

@@ -253,7 +253,7 @@ static double dev_get_mixer_value(unsigned int mixer, unsigned int nodeId)
{ {
// MU_MIXER_CONTROL 0x01 // MU_MIXER_CONTROL 0x01
short data; short data;
usb_audio_class_get(CUR, 0x01<<8, nodeId, usb_mixers->usb_mixer[mixer].id, 2,(unsigned char *) &data); usb_audio_class_get(CUR, ((unsigned char) (0x01<<8)), nodeId, usb_mixers->usb_mixer[mixer].id, 2,(unsigned char *) &data);
return ((double) data / 256); return ((double) data / 256);
} }
@@ -436,8 +436,17 @@ int addStrings(const unsigned char *data, int length, int mixer_index, int id, i
/* Returns the source of an mix sel output */ /* Returns the source of an mix sel output */
static unsigned char get_mixsel_value(unsigned int mixer, unsigned int channel) static unsigned char get_mixsel_value(unsigned int mixer, unsigned int channel)
{ {
unsigned char bRequest = CUR;
//unsigned cs = CS_XU_SEL;
unsigned char cs = 1; /* Note, currently the host app configures all mix sel's indentically, so if we get one they all should match */
unsigned char cn = channel;
unsigned short unitId = usb_mixers->usb_mixSel[mixer].id;
unsigned short wLength = 1;
unsigned char data[64]; unsigned char data[64];
usb_audio_class_get(CUR, CS_XU_SEL, channel, usb_mixers->usb_mixSel[mixer].id, 1, (unsigned char *)data);
usb_audio_class_get(CUR, cs, cn, unitId, wLength, (unsigned char *)data);
return data[0]; return data[0];
} }
@@ -796,11 +805,13 @@ int usb_mixsel_get_output_count(unsigned int mixer)
return usb_mixers->usb_mixSel[mixer].numOutputs; return usb_mixers->usb_mixSel[mixer].numOutputs;
} }
char *usb_mixer_get_input_name(unsigned int mixer, unsigned int input) { char *usb_mixer_get_input_name(unsigned int mixer, unsigned int input)
{
return usb_mixers->usb_mixer[mixer].input_names[input]; return usb_mixers->usb_mixer[mixer].input_names[input];
} }
char *usb_mixer_get_output_name(unsigned int mixer, unsigned int output) { char *usb_mixer_get_output_name(unsigned int mixer, unsigned int output)
{
return usb_mixers->usb_mixer[mixer].output_names[output]; return usb_mixers->usb_mixer[mixer].output_names[output];
} }
@@ -811,13 +822,19 @@ unsigned char usb_mixsel_get_state(unsigned int mixer, unsigned int channel)
void usb_mixsel_set_state(unsigned int mixer, unsigned int dst, unsigned int src) void usb_mixsel_set_state(unsigned int mixer, unsigned int dst, unsigned int src)
{ {
// write to device // Write to device
usb_audio_class_set(CUR, CS_XU_SEL, dst, usb_mixers->usb_mixSel[mixer].id, 1, (unsigned char *)&src); // Note, we are updating inputs to all mixers here with a hard-coded 0, though the device allows
// for separate input mapping per mixer
unsigned bRequest = CUR;
unsigned cs = 0;
unsigned cn = usb_mixers->usb_mixSel[mixer].id;
unsigned wLength = 1;
usb_audio_class_set(CUR, 0, dst, usb_mixers->usb_mixSel[mixer].id, wLength, (unsigned char *)&src);
// update object state // Update object state
usb_mixers->usb_mixSel[mixer].state[dst] = src; usb_mixers->usb_mixSel[mixer].state[dst] = src;
// update local object strings // Update local object strings
// TODO we don't really need to store strings since we can look them up...*/ // TODO we don't really need to store strings since we can look them up...*/
strcpy(usb_mixers->usb_mixer[mixer].input_names[dst], usb_mixers->usb_mixSel[mixer].inputStrings[src]); strcpy(usb_mixers->usb_mixer[mixer].input_names[dst], usb_mixers->usb_mixSel[mixer].inputStrings[src]);
} }

View File

@@ -1,4 +1,4 @@
The XMOS USB Audio L2 Reference Design contains an 18x8 mixer unit The XMOS USB Audio Reference Design, by default, contains an 18x8 mixer unit
(note that at sample rates above 96Khz only the first two outputs are (note that at sample rates above 96Khz only the first two outputs are
enabled). enabled).
@@ -29,7 +29,6 @@ should always be 0):
--help --help
--display-info --display-info
Show information about the device. Show information about the device.
@@ -106,10 +105,3 @@ Show the DAW output channel map sources.
--vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],... --vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],...

View File

@@ -176,7 +176,6 @@ void display_available_mixer_sources(int mixIndex)
} }
} }
/* Gets the current mixer inputs from the device an displays them */ /* Gets the current mixer inputs from the device an displays them */
void display_mixer_sources(int mixerIndex) void display_mixer_sources(int mixerIndex)
{ {
@@ -191,7 +190,7 @@ void display_mixer_sources(int mixerIndex)
for(int i = 0; i < usb_mixsel_get_output_count(mixerIndex); i++) for(int i = 0; i < usb_mixsel_get_output_count(mixerIndex); i++)
{ {
int inputChan = (int)usb_mixsel_get_state(mixerIndex, i); int inputChan = (int)usb_mixsel_get_state(mixerIndex, i);
char *str = usb_mixer_get_input_name(mixerIndex,i); char *str = usb_mixer_get_input_name(mixerIndex,inputChan);
printf(" Mixer input %d: Source chan id: %d (%s)\n", i, inputChan, str); printf(" Mixer input %d: Source chan id: %d (%s)\n", i, inputChan, str);
} }
} }
@@ -565,13 +564,12 @@ int main (int argc, char **argv) {
{ {
display_daw_channel_map_sources(); display_daw_channel_map_sources();
} }
else if (strcmp(argv[1], "--set-aud-channel-map") == 0) else if (strcmp(argv[1], "--set-aud-channel-map") == 0)
{ {
unsigned int dst = 0; unsigned int dst = 0;
unsigned int src = 0; unsigned int src = 0;
if (argc < 4) { if (argc != 4)
{
usage_error(); usage_error();
return -1; return -1;
} }
@@ -580,12 +578,12 @@ int main (int argc, char **argv) {
usb_set_aud_channel_map(dst, src); usb_set_aud_channel_map(dst, src);
} }
else if (strcmp(argv[1], "--set-daw-channel-map") == 0) else if (strcmp(argv[1], "--set-daw-channel-map") == 0)
{ {
unsigned int dst = 0; unsigned int dst = 0;
unsigned int src = 0; unsigned int src = 0;
if (argc < 4) { if (argc != 4)
{
usage_error(); usage_error();
return -1; return -1;
} }
@@ -593,8 +591,6 @@ int main (int argc, char **argv) {
src = atoi(argv[3]); src = atoi(argv[3]);
usb_set_usb_channel_map(dst, src); usb_set_usb_channel_map(dst, src);
} }
else if(strcmp(argv[1], "--get-mixer-levels-input") == 0 || else if(strcmp(argv[1], "--get-mixer-levels-input") == 0 ||
strcmp(argv[1],"--get-mixer-levels-output") == 0) strcmp(argv[1],"--get-mixer-levels-output") == 0)

View File

@@ -1 +0,0 @@
Sample code for a host usb mixer app (not this is a host/pc program and cannot be built in the XDE)

View File

@@ -1,9 +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.
#ifndef __XUA_AUDIOHUB_H__ #ifndef _XUA_AUDIOHUB_H_
#define __XUA_AUDIOHUB_H__ #define _XUA_AUDIOHUB_H_
#if __XC__ #ifdef __XC__
#include "xccompat.h" #include "xccompat.h"
#include "xs1.h" #include "xs1.h"
@@ -80,4 +80,4 @@ void UserBufferManagementInit();
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]); void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
#endif // __XUA_AUDIOHUB_H__ #endif // _XUA_AUDIOHUB_H_

View File

@@ -1,4 +1,4 @@
// 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.
/* /*
* @brief Defines relating to device configuration and customisation of lib_xua * @brief Defines relating to device configuration and customisation of lib_xua
@@ -997,17 +997,12 @@
#define MIXER (0) #define MIXER (0)
#endif #endif
/* Tidy up old ifndef usage */
#if defined(MIXER) && (MIXER == 0)
#undef MIXER
#endif
/** /**
* @brief Number of seperate mixes to perform * @brief Number of seperate mixes to perform
* *
* Default: 8 if MIXER enabled, else 0 * Default: 8 if MIXER enabled, else 0
*/ */
#ifdef MIXER #if (MIXER)
#ifndef MAX_MIX_COUNT #ifndef MAX_MIX_COUNT
#define MAX_MIX_COUNT (8) #define MAX_MIX_COUNT (8)
#endif #endif
@@ -1087,44 +1082,24 @@
#define VOLUME_RES_MIXER (0x100) #define VOLUME_RES_MIXER (0x100)
#endif #endif
/* Handle out volume control in the mixer */ /* Handle out volume control in the mixer - disabled by default */
#if defined(OUT_VOLUME_IN_MIXER) && (OUT_VOLUME_IN_MIXER==0) #ifndef OUT_VOLUME_IN_MIXER
#undef OUT_VOLUME_IN_MIXER #define OUT_VOLUME_IN_MIXER (0)
#else
#if defined(MIXER)
// Disabled by default
//#define OUT_VOLUME_IN_MIXER
#endif
#endif #endif
/* Apply out volume controls after the mix */ /* Apply out volume controls after the mix. Only relevant when OUT_VOLUME_IN_MIXER enabled. Enabled by default */
#if defined(OUT_VOLUME_AFTER_MIX) && (OUT_VOLUME_AFTER_MIX==0) #ifndef OUT_VOLUME_AFTER_MIX
#undef OUT_VOLUME_AFTER_MIX #define OUT_VOLUME_AFTER_MIX (1)
#else
#if defined(MIXER) && defined(OUT_VOLUME_IN_MIXER)
// Enabled by default
#define OUT_VOLUME_AFTER_MIX
#endif
#endif #endif
/* Handle in volume control in the mixer */ /* Handle in volume control in the mixer - disabled by default */
#if defined(IN_VOLUME_IN_MIXER) && (IN_VOLUME_IN_MIXER==0) #ifdef IN_VOLUNE_IN_MIXER
#undef IN_VOLUME_IN_MIXER #define IN_VOLUME_IN_MIXER (0)
#else
#if defined(MIXER)
/* Disabled by default */
//#define IN_VOLUME_IN_MIXER
#endif
#endif #endif
/* Apply in volume controls after the mix */ /* Apply in volume controls after the mix. Only relebant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */
#if defined(IN_VOLUME_AFTER_MIX) && (IN_VOLUME_AFTER_MIX==0) #ifndef IN_VOLUME_AFTER_MIX
#undef IN_VOLUME_AFTER_MIX #define IN_VOLUME_AFTER_MIX (1)
#else
#if defined(MIXER) && defined(IN_VOLUME_IN_MIXER)
// Enabled by default
#define IN_VOLUME_AFTER_MIX
#endif
#endif #endif
/* Always enable explicit feedback EP, even when input stream is present */ /* Always enable explicit feedback EP, even when input stream is present */

View File

@@ -1,8 +1,10 @@
// 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.
#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

View File

@@ -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) \

View File

@@ -1,4 +1,4 @@
// 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.
/** /**
* @file xua_audiohub.xc * @file xua_audiohub.xc
@@ -43,12 +43,12 @@
#define MAX(x,y) ((x)>(y) ? (x) : (y)) #define MAX(x,y) ((x)>(y) ? (x) : (y))
static unsigned samplesOut[MAX(NUM_USB_CHAN_OUT, I2S_CHANS_DAC)]; unsigned samplesOut[MAX(NUM_USB_CHAN_OUT, I2S_CHANS_DAC)];
/* Two buffers for ADC data to allow for DAC and ADC I2S ports being offset */ /* Two buffers for ADC data to allow for DAC and ADC I2S ports being offset */
#define IN_CHAN_COUNT (I2S_CHANS_ADC + XUA_NUM_PDM_MICS + (8*XUA_ADAT_RX_EN) + (2*XUA_SPDIF_RX_EN)) #define IN_CHAN_COUNT (I2S_CHANS_ADC + XUA_NUM_PDM_MICS + (8*XUA_ADAT_RX_EN) + (2*XUA_SPDIF_RX_EN))
static unsigned samplesIn[2][MAX(NUM_USB_CHAN_IN, IN_CHAN_COUNT)]; unsigned samplesIn[2][MAX(NUM_USB_CHAN_IN, IN_CHAN_COUNT)];
#ifdef XTA_TIMING_AUDIO #ifdef XTA_TIMING_AUDIO
#pragma xta command "add exclusion received_command" #pragma xta command "add exclusion received_command"
@@ -89,69 +89,7 @@ unsigned dsdMode = DSD_MODE_OFF;
#if (XUA_ADAT_TX_EN) #if (XUA_ADAT_TX_EN)
#include "audiohub_adat.h" #include "audiohub_adat.h"
#endif #endif
#include "xua_audiohub_st.h"
#pragma unsafe arrays
static inline unsigned DoSampleTransfer(chanend ?c_out, const int readBuffNo, const unsigned underflowWord)
{
if(XUA_USB_EN)
{
outuint(c_out, underflowWord);
/* Check for sample freq change (or other command) or new samples from mixer*/
if(testct(c_out))
{
unsigned command = inct(c_out);
#ifndef CODEC_MASTER
if(dsdMode == DSD_MODE_OFF)
{
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
/* Set clocks low */
p_lrclk <: 0;
p_bclk <: 0;
#endif
}
else
{
#if(DSD_CHANS_DAC != 0)
/* DSD Clock might not be shared with lrclk or bclk... */
p_dsd_clk <: 0;
#endif
}
#endif
#if (DSD_CHANS_DAC > 0)
if(dsdMode == DSD_MODE_DOP)
dsdMode = DSD_MODE_OFF;
#endif
return command;
}
else
{
#if NUM_USB_CHAN_OUT > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
int tmp = inuint(c_out);
samplesOut[i] = tmp;
}
#else
inuint(c_out);
#endif
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
#if NUM_USB_CHAN_IN > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
outuint(c_out, samplesIn[readBuffNo][i]);
}
#endif
}
}
else
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
return 0;
}
static inline int HandleSampleClock(int frameCount, buffered _XUA_CLK_DIR port:32 p_lrclk) static inline int HandleSampleClock(int frameCount, buffered _XUA_CLK_DIR port:32 p_lrclk)
{ {

View File

@@ -0,0 +1,66 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#pragma unsafe arrays
static inline unsigned DoSampleTransfer(chanend ?c_out, const int readBuffNo, const unsigned underflowWord)
{
if(XUA_USB_EN)
{
outuint(c_out, underflowWord);
/* Check for sample freq change (or other command) or new samples from mixer*/
if(testct(c_out))
{
unsigned command = inct(c_out);
#ifndef CODEC_MASTER
if(dsdMode == DSD_MODE_OFF)
{
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
/* Set clocks low */
p_lrclk <: 0;
p_bclk <: 0;
#endif
}
else
{
#if(DSD_CHANS_DAC != 0)
/* DSD Clock might not be shared with lrclk or bclk... */
p_dsd_clk <: 0;
#endif
}
#endif
#if (DSD_CHANS_DAC > 0)
if(dsdMode == DSD_MODE_DOP)
dsdMode = DSD_MODE_OFF;
#endif
return command;
}
else
{
#if NUM_USB_CHAN_OUT > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
{
int tmp = inuint(c_out);
samplesOut[i] = tmp;
}
#else
inuint(c_out);
#endif
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
#if NUM_USB_CHAN_IN > 0
#pragma loop unroll
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
{
outuint(c_out, samplesIn[readBuffNo][i]);
}
#endif
}
}
else
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
return 0;
}

View File

@@ -1,4 +1,4 @@
// 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.
#include "xua.h" #include "xua.h"
@@ -58,11 +58,11 @@
#define IN_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_IN_HS, MAX_DEVICE_AUD_PACKET_SIZE_IN_FS)*2) #define IN_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_IN_HS, MAX_DEVICE_AUD_PACKET_SIZE_IN_FS)*2)
/* Volume and mute tables */ /* Volume and mute tables */
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1) #if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
unsigned int multOut[NUM_USB_CHAN_OUT + 1]; unsigned int multOut[NUM_USB_CHAN_OUT + 1];
static xc_ptr p_multOut; static xc_ptr p_multOut;
#endif #endif
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1) #if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
unsigned int multIn[NUM_USB_CHAN_IN + 1]; unsigned int multIn[NUM_USB_CHAN_IN + 1];
static xc_ptr p_multIn; static xc_ptr p_multIn;
#endif #endif
@@ -206,7 +206,7 @@ __builtin_unreachable();
g_aud_from_host_rdptr+=2; g_aud_from_host_rdptr+=2;
sample <<= 16; sample <<= 16;
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER) #if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i)); asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
{h, l} = macs(mult, sample, 0, 0); {h, l} = macs(mult, sample, 0, 0);
/* Note, in 2 byte subslot mode - ignore lower result of macs */ /* Note, in 2 byte subslot mode - ignore lower result of macs */
@@ -234,7 +234,7 @@ __builtin_unreachable();
read_via_xc_ptr(sample, g_aud_from_host_rdptr); read_via_xc_ptr(sample, g_aud_from_host_rdptr);
g_aud_from_host_rdptr+=4; g_aud_from_host_rdptr+=4;
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER) #if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i)); asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
{h, l} = macs(mult, sample, 0, 0); {h, l} = macs(mult, sample, 0, 0);
h <<= 3; h <<= 3;
@@ -289,7 +289,7 @@ __builtin_unreachable();
} }
unpackState++; unpackState++;
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER) #if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i)); asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
{h, l} = macs(mult, sample, 0, 0); {h, l} = macs(mult, sample, 0, 0);
h <<= 3; h <<= 3;
@@ -335,7 +335,7 @@ __builtin_unreachable();
/* Receive sample */ /* Receive sample */
int sample = inuint(c_mix_out); int sample = inuint(c_mix_out);
#if (INPUT_VOLUME_CONTROL == 1) #if (INPUT_VOLUME_CONTROL == 1)
#if !defined(IN_VOLUME_IN_MIXER) #if (!IN_VOLUME_IN_MIXER)
/* Apply volume */ /* Apply volume */
int mult; int mult;
int h; int h;
@@ -345,7 +345,7 @@ __builtin_unreachable();
sample = h << 3; sample = h << 3;
/* Note, in 2 byte sub slot - ignore lower bits of macs */ /* Note, in 2 byte sub slot - ignore lower bits of macs */
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX) #elif (IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
sample = sample << 3; sample = sample << 3;
#endif #endif
#endif #endif
@@ -365,7 +365,7 @@ __builtin_unreachable();
/* Receive sample */ /* Receive sample */
int sample = inuint(c_mix_out); int sample = inuint(c_mix_out);
#if(INPUT_VOLUME_CONTROL == 1) #if(INPUT_VOLUME_CONTROL == 1)
#if !defined(IN_VOLUME_IN_MIXER) #if (!IN_VOLUME_IN_MIXER)
/* Apply volume */ /* Apply volume */
int mult; int mult;
int h; int h;
@@ -376,7 +376,7 @@ __builtin_unreachable();
#if (STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED == 1) #if (STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED == 1)
sample |= (l >> 29) & 0x7; // Note, this step is not required if we assume sample depth is 24 (rather than 32) sample |= (l >> 29) & 0x7; // Note, this step is not required if we assume sample depth is 24 (rather than 32)
#endif #endif
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX) #elif (IN_VOLUME_IN_MIXER) && (IN_VOLUME_AFTER_MIX)
sample = sample << 3; sample = sample << 3;
#endif #endif
#endif #endif
@@ -396,7 +396,7 @@ __builtin_unreachable();
{ {
/* Receive sample */ /* Receive sample */
int sample = inuint(c_mix_out); int sample = inuint(c_mix_out);
#if (INPUT_VOLUME_CONTROL) && !defined(IN_VOLUME_IN_MIXER) #if (INPUT_VOLUME_CONTROL) && (!IN_VOLUME_IN_MIXER)
/* Apply volume */ /* Apply volume */
int mult; int mult;
int h; int h;
@@ -640,10 +640,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
int t = array_to_xc_ptr(outAudioBuff); int t = array_to_xc_ptr(outAudioBuff);
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1) #if (!OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
p_multOut = array_to_xc_ptr(multOut); p_multOut = array_to_xc_ptr(multOut);
#endif #endif
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1) #if (!IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
p_multIn = array_to_xc_ptr(multIn); p_multIn = array_to_xc_ptr(multIn);
#endif #endif
@@ -670,14 +670,14 @@ void XUA_Buffer_Decouple(chanend c_mix_out
xc_ptr aud_to_host_zeros = t; xc_ptr aud_to_host_zeros = t;
/* Init vol mult tables */ /* Init vol mult tables */
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1) #if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
for (int i = 0; i < NUM_USB_CHAN_OUT + 1; i++) for (int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
{ {
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multOut),"r"(i)); asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multOut),"r"(i));
} }
#endif #endif
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1) #if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
for (int i = 0; i < NUM_USB_CHAN_IN + 1; i++) for (int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
{ {
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multIn),"r"(i)); asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multIn),"r"(i));

View File

@@ -1,4 +1,4 @@
// 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.
/** /**
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device * @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
@@ -106,13 +106,17 @@ unsigned int mutesOut[NUM_USB_CHAN_OUT + 1];
int volsIn[NUM_USB_CHAN_IN + 1]; int volsIn[NUM_USB_CHAN_IN + 1];
unsigned int mutesIn[NUM_USB_CHAN_IN + 1]; unsigned int mutesIn[NUM_USB_CHAN_IN + 1];
#ifdef MIXER #if (MIXER)
unsigned char mixer1Crossbar[18]; short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
short mixer1Weights[18*8];
unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT]; //unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
/* Mapping of channels to output audio interfaces */
unsigned char channelMapAud[NUM_USB_CHAN_OUT]; unsigned char channelMapAud[NUM_USB_CHAN_OUT];
/* Mapping of channels to USB host */
unsigned char channelMapUsb[NUM_USB_CHAN_IN]; unsigned char channelMapUsb[NUM_USB_CHAN_IN];
/* Mapping of channels to Mixer(s) */
unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS]; unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
#endif #endif
@@ -425,14 +429,15 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
#endif #endif
VendorRequests_Init(VENDOR_REQUESTS_PARAMS); VendorRequests_Init(VENDOR_REQUESTS_PARAMS);
#ifdef MIXER #if (MIXER)
/* Set up mixer default state */ /* Set up mixer default state */
for (int i = 0; i < 18*8; i++) for (int i = 0; i < MIX_INPUTS * MAX_MIX_COUNT; i++)
{ {
mixer1Weights[i] = 0x8001; //-inf mixer1Weights[i] = 0x8001; //-inf
} }
/* Configure default connections */ /* Configure default connections */
// TODO this should be a loop using defines.
mixer1Weights[0] = 0; mixer1Weights[0] = 0;
mixer1Weights[9] = 0; mixer1Weights[9] = 0;
mixer1Weights[18] = 0; mixer1Weights[18] = 0;
@@ -457,20 +462,6 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
} }
#endif #endif
/* Set up channel mapping default */
for (int i = 0; i < NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN; i++)
{
channelMap[i] = i;
}
#if MAX_MIX_COUNT > 0
/* Mixer outputs mapping defaults */
for (int i = 0; i < MAX_MIX_COUNT; i++)
{
channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = i;
}
#endif
/* Init mixer inputs */ /* Init mixer inputs */
for(int j = 0; j < MAX_MIX_COUNT; j++) for(int j = 0; j < MAX_MIX_COUNT; j++)
for(int i = 0; i < MIX_INPUTS; i++) for(int i = 0; i < MIX_INPUTS; i++)

View File

@@ -1,4 +1,4 @@
// 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.
/** /**
* @file xua_ep0_descriptors.h * @file xua_ep0_descriptors.h
@@ -308,28 +308,28 @@ typedef struct
#error NUM_USB_CHAN > 32 #error NUM_USB_CHAN > 32
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 0) #if (MIXER) && (MAX_MIX_COUNT > 0)
STR_TABLE_ENTRY(mixOutStr_1); STR_TABLE_ENTRY(mixOutStr_1);
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 1) #if (MIXER) && (MAX_MIX_COUNT > 1)
STR_TABLE_ENTRY(mixOutStr_2); STR_TABLE_ENTRY(mixOutStr_2);
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 2) #if (MIXER) && (MAX_MIX_COUNT > 2)
STR_TABLE_ENTRY(mixOutStr_3); STR_TABLE_ENTRY(mixOutStr_3);
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 3) #if (MIXER) && (MAX_MIX_COUNT > 3)
STR_TABLE_ENTRY(mixOutStr_4); STR_TABLE_ENTRY(mixOutStr_4);
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 4) #if (MIXER) && (MAX_MIX_COUNT > 4)
STR_TABLE_ENTRY(mixOutStr_5); STR_TABLE_ENTRY(mixOutStr_5);
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 5) #if (MIXER) && (MAX_MIX_COUNT > 5)
STR_TABLE_ENTRY(mixOutStr_6); STR_TABLE_ENTRY(mixOutStr_6);
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 6) #if (MIXER) && (MAX_MIX_COUNT > 6)
STR_TABLE_ENTRY(mixOutStr_7); STR_TABLE_ENTRY(mixOutStr_7);
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 7) #if (MIXER) && (MAX_MIX_COUNT > 7)
STR_TABLE_ENTRY(mixOutStr_8); STR_TABLE_ENTRY(mixOutStr_8);
#endif #endif
#ifdef IAP #ifdef IAP
@@ -391,31 +391,31 @@ StringDescTable_t g_strTable =
#error NUM_USB_CHAN_IN > 32 #error NUM_USB_CHAN_IN > 32
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 0) #if (MIXER) && (MAX_MIX_COUNT > 0)
.mixOutStr_1 = "Mix 1", .mixOutStr_1 = "Mix 1",
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 1) #if (MIXER) && (MAX_MIX_COUNT > 1)
.mixOutStr_2 = "Mix 2", .mixOutStr_2 = "Mix 2",
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 2) #if (MIXER) && (MAX_MIX_COUNT > 2)
.mixOutStr_3 = "Mix 3", .mixOutStr_3 = "Mix 3",
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 3) #if (MIXER) && (MAX_MIX_COUNT > 3)
.mixOutStr_4 = "Mix 4", .mixOutStr_4 = "Mix 4",
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 4) #if (MIXER) && (MAX_MIX_COUNT > 4)
.mixOutStr_5 = "Mix 5", .mixOutStr_5 = "Mix 5",
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 5) #if (MIXER) && (MAX_MIX_COUNT > 5)
.mixOutStr_6 = "Mix 6", .mixOutStr_6 = "Mix 6",
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 6) #if (MIXER) && (MAX_MIX_COUNT > 6)
.mixOutStr_7 = "Mix 7", .mixOutStr_7 = "Mix 7",
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 7) #if (MIXER) && (MAX_MIX_COUNT > 7)
.mixOutStr_8 = "Mix 8", .mixOutStr_8 = "Mix 8",
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 8) #if (MIXER) && (MAX_MIX_COUNT > 8)
#error #error
#endif #endif
#ifdef IAP #ifdef IAP
@@ -558,7 +558,7 @@ unsigned char devQualDesc_Null[] =
}; };
#if defined(MIXER) && !defined(AUDIO_PATH_XUS) && (MAX_MIX_COUNT > 0) #if (MIXER) && !defined(AUDIO_PATH_XUS) && (MAX_MIX_COUNT > 0)
//#warning Extension units on the audio path are required for mixer. Enabling them now. //#warning Extension units on the audio path are required for mixer. Enabling them now.
#define AUDIO_PATH_XUS #define AUDIO_PATH_XUS
#endif #endif
@@ -575,7 +575,7 @@ unsigned char devQualDesc_Null[] =
#define DFU_LENGTH (0) #define DFU_LENGTH (0)
#endif #endif
#ifdef MIXER #if (MIXER)
#define MIX_BMCONTROLS_LEN_TMP ((MAX_MIX_COUNT * MIX_INPUTS) / 8) #define MIX_BMCONTROLS_LEN_TMP ((MAX_MIX_COUNT * MIX_INPUTS) / 8)
#if ((MAX_MIX_COUNT * MIX_INPUTS)%8)==0 #if ((MAX_MIX_COUNT * MIX_INPUTS)%8)==0
@@ -666,7 +666,7 @@ typedef struct
#if (NUM_USB_CHAN_OUT > 0) #if (NUM_USB_CHAN_OUT > 0)
/* Output path */ /* Output path */
USB_Descriptor_Audio_InputTerminal_t Audio_Out_InputTerminal; USB_Descriptor_Audio_InputTerminal_t Audio_Out_InputTerminal;
#if defined(MIXER) && (MAX_MIX_COUNT > 0) #if (MIXER) && (MAX_MIX_COUNT > 0)
USB_Descriptor_Audio_ExtensionUnit_t Audio_Out_ExtensionUnit; USB_Descriptor_Audio_ExtensionUnit_t Audio_Out_ExtensionUnit;
#endif #endif
#if(OUTPUT_VOLUME_CONTROL == 1) #if(OUTPUT_VOLUME_CONTROL == 1)
@@ -677,7 +677,7 @@ typedef struct
#if (NUM_USB_CHAN_IN > 0) #if (NUM_USB_CHAN_IN > 0)
/* Input path */ /* Input path */
USB_Descriptor_Audio_InputTerminal_t Audio_In_InputTerminal; USB_Descriptor_Audio_InputTerminal_t Audio_In_InputTerminal;
#if defined(MIXER) && (MAX_MIX_COUNT > 0) #if (MIXER) && (MAX_MIX_COUNT > 0)
USB_Descriptor_Audio_ExtensionUnit_t Audio_In_ExtensionUnit; USB_Descriptor_Audio_ExtensionUnit_t Audio_In_ExtensionUnit;
#endif #endif
#if(INPUT_VOLUME_CONTROL == 1) #if(INPUT_VOLUME_CONTROL == 1)
@@ -685,7 +685,7 @@ typedef struct
#endif #endif
USB_Descriptor_Audio_OutputTerminal_t Audio_In_OutputTerminal; USB_Descriptor_Audio_OutputTerminal_t Audio_In_OutputTerminal;
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 0) #if (MIXER) && (MAX_MIX_COUNT > 0)
USB_Descriptor_Audio_ExtensionUnit2_t Audio_Mix_ExtensionUnit; USB_Descriptor_Audio_ExtensionUnit2_t Audio_Mix_ExtensionUnit;
// Currently no struct for mixer unit // Currently no struct for mixer unit
// USB_Descriptor_Audio_MixerUnit_t Audio_MixerUnit; // USB_Descriptor_Audio_MixerUnit_t Audio_MixerUnit;
@@ -1168,7 +1168,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
UAC_CS_DESCTYPE_INTERFACE, /* 1 bDescriptorType: CS_INTERFACE */ UAC_CS_DESCTYPE_INTERFACE, /* 1 bDescriptorType: CS_INTERFACE */
UAC_CS_AC_INTERFACE_SUBTYPE_FEATURE_UNIT, /* 2 bDescriptorSubType: FEATURE_UNIT */ UAC_CS_AC_INTERFACE_SUBTYPE_FEATURE_UNIT, /* 2 bDescriptorSubType: FEATURE_UNIT */
FU_USBIN, /* 3 bUnitID */ FU_USBIN, /* 3 bUnitID */
#if defined(MIXER) && (MAX_MIX_COUNT > 0) #if (MIXER) && (MAX_MIX_COUNT > 0)
ID_XU_IN, /* 4 bSourceID */ ID_XU_IN, /* 4 bSourceID */
#else #else
ID_IT_AUD, /* 4 bSourceID */ ID_IT_AUD, /* 4 bSourceID */
@@ -1300,7 +1300,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
}, },
#endif /* (NUM_USB_CHAN_IN > 0) */ #endif /* (NUM_USB_CHAN_IN > 0) */
#if defined(MIXER) && (MAX_MIX_COUNT > 0) #if (MIXER) && (MAX_MIX_COUNT > 0)
/* Extension Unit Descriptor (4.7.2.12) */ /* Extension Unit Descriptor (4.7.2.12) */
.Audio_Mix_ExtensionUnit = .Audio_Mix_ExtensionUnit =
{ {
@@ -1392,7 +1392,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
0x00, /* bmControls */ 0x00, /* bmControls */
0 /* Mixer unit string descriptor index */ 0 /* Mixer unit string descriptor index */
}, },
#endif /* defined(MIXER) && (MAX_MIX_COUNT > 0) */ #endif /* (MIXER) && (MAX_MIX_COUNT > 0) */
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN) #if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN)
/* Standard AS Interrupt Endpoint Descriptor (4.8.2.1): */ /* Standard AS Interrupt Endpoint Descriptor (4.8.2.1): */

View File

@@ -1,4 +1,4 @@
// 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.
/** /**
* @brief Implements relevant requests from the USB Audio 2.0 Specification * @brief Implements relevant requests from the USB Audio 2.0 Specification
@@ -31,8 +31,7 @@ extern int volsIn[];
extern unsigned int mutesIn[]; extern unsigned int mutesIn[];
/* Mixer settings */ /* Mixer settings */
#ifdef MIXER #if (MIXER)
extern unsigned char mixer1Crossbar[];
extern short mixer1Weights[]; extern short mixer1Weights[];
/* Device channel mapping */ /* Device channel mapping */
@@ -133,10 +132,10 @@ static unsigned longMul(unsigned a, unsigned b, int prec)
static void updateMasterVol( int unitID, chanend ?c_mix_ctl) static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
{ {
int x; int x;
#ifndef OUT_VOLUME_IN_MIXER #if (OUT_VOLUME_IN_MIXER == 0)
xc_ptr p_multOut = array_to_xc_ptr(multOut); xc_ptr p_multOut = array_to_xc_ptr(multOut);
#endif #endif
#ifndef IN_VOLUME_IN_MIXER #if (IN_VOLUME_IN_MIXER == 0)
xc_ptr p_multIn = array_to_xc_ptr(multIn); xc_ptr p_multIn = array_to_xc_ptr(multIn);
#endif #endif
switch( unitID) switch( unitID)
@@ -153,7 +152,7 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[i]; x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[i];
#ifdef OUT_VOLUME_IN_MIXER #if (OUT_VOLUME_IN_MIXER)
if (!isnull(c_mix_ctl)) if (!isnull(c_mix_ctl))
{ {
outuint(c_mix_ctl, SET_MIX_OUT_VOL); outuint(c_mix_ctl, SET_MIX_OUT_VOL);
@@ -179,7 +178,7 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[i]; x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[i];
#ifdef IN_VOLUME_IN_MIXER #if (IN_VOLUME_IN_MIXER)
if (!isnull(c_mix_ctl)) if (!isnull(c_mix_ctl))
{ {
outuint(c_mix_ctl, SET_MIX_IN_VOL); outuint(c_mix_ctl, SET_MIX_IN_VOL);
@@ -202,10 +201,10 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
static void updateVol(int unitID, int channel, chanend ?c_mix_ctl) static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
{ {
int x; int x;
#ifndef OUT_VOLUME_IN_MIXER #if (OUT_VOLUME_IN_MIXER == 0)
xc_ptr p_multOut = array_to_xc_ptr(multOut); xc_ptr p_multOut = array_to_xc_ptr(multOut);
#endif #endif
#ifndef IN_VOLUME_IN_MIXER #if (IN_VOLUME_IN_MIXER == 0)
xc_ptr p_multIn = array_to_xc_ptr(multIn); xc_ptr p_multIn = array_to_xc_ptr(multIn);
#endif #endif
/* Check for master volume update */ /* Check for master volume update */
@@ -226,7 +225,7 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[channel]; x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[channel];
#ifdef OUT_VOLUME_IN_MIXER #if (OUT_VOLUME_IN_MIXER)
if (!isnull(c_mix_ctl)) if (!isnull(c_mix_ctl))
{ {
outuint(c_mix_ctl, SET_MIX_OUT_VOL); outuint(c_mix_ctl, SET_MIX_OUT_VOL);
@@ -248,7 +247,7 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[channel]; x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[channel];
#ifdef IN_VOLUME_IN_MIXER #if (IN_VOLUME_IN_MIXER)
if (!isnull(c_mix_ctl)) if (!isnull(c_mix_ctl))
{ {
outuint(c_mix_ctl, SET_MIX_IN_VOL); outuint(c_mix_ctl, SET_MIX_IN_VOL);
@@ -266,6 +265,32 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
} }
#endif #endif
void UpdateMixerOutputRouting(chanend c_mix_ctl, unsigned map, unsigned dst, unsigned src)
{
outuint(c_mix_ctl, map);
outuint(c_mix_ctl, dst);
outuint(c_mix_ctl, src);
outct(c_mix_ctl, XS1_CT_END);
}
void UpdateMixMap(chanend c_mix_ctl, int mix, int input, int src)
{
outuint(c_mix_ctl, SET_MIX_MAP);
outuint(c_mix_ctl, mix); /* Mix bus */
outuint(c_mix_ctl, input); /* Mixer input (cn) */
outuint(c_mix_ctl, src); /* Source (mixSel[cn]) */
outct(c_mix_ctl, XS1_CT_END);
}
void UpdateMixerWeight(chanend c_mix_ctl, int mix, int index, unsigned val)
{
outuint(c_mix_ctl, SET_MIX_MULT);
outuint(c_mix_ctl, mix);
outuint(c_mix_ctl, index);
outuint(c_mix_ctl, val);
outct(c_mix_ctl, XS1_CT_END);
}
/* Handles the audio class specific requests /* Handles the audio class specific requests
* returns: XUD_RES_OKAY if request dealt with successfully without error, * returns: XUD_RES_OKAY if request dealt with successfully without error,
* XUD_RES_RST for device reset * XUD_RES_RST for device reset
@@ -632,79 +657,70 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
break; /* FU_USBIN */ break; /* FU_USBIN */
#endif #endif
#if defined(MIXER) && (MAX_MIX_COUNT > 0) #if ((MIXER) && (MAX_MIX_COUNT > 0))
case ID_XU_OUT: case ID_XU_OUT:
{ {
int dst = sp.wValue & 0xff;
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */ if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
{ {
unsigned volume = 0;
int c = sp.wValue & 0xff;
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY) if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
{ {
return result; return result;
} }
channelMapAud[c] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8; if (dst < NUM_USB_CHAN_OUT)
{
channelMapAud[dst] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
if (!isnull(c_mix_ctl)) if (!isnull(c_mix_ctl))
{ {
if (c < NUM_USB_CHAN_OUT) UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_DEVICE_MAP, dst, channelMapAud[dst]);
{ }
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);
/* Send 0 Length as status stage */ /* Send 0 Length as status stage */
return XUD_DoSetRequestStatus(ep0_in); return XUD_DoSetRequestStatus(ep0_in);
} }
}
}
else else
{ {
(buffer, unsigned char[])[0] = channelMapAud[sp.wValue & 0xff]; (buffer, unsigned char[])[0] = channelMapAud[dst];
(buffer, unsigned char[])[1] = 0; (buffer, unsigned char[])[1] = 0;
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength); return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
} }
} }
break; break;
case ID_XU_IN: case ID_XU_IN:
{
int dst = sp.wValue & 0xff;
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */ if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
{ {
unsigned volume = 0;
int c = sp.wValue & 0xff;
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY) if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
{ {
return result; return result;
} }
channelMapUsb[c] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8; if (dst < NUM_USB_CHAN_IN)
if (c < NUM_USB_CHAN_IN)
{ {
channelMapUsb[dst] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
if (!isnull(c_mix_ctl)) if (!isnull(c_mix_ctl))
{ {
outuint(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP); UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP, dst, channelMapUsb[dst]);
outuint(c_mix_ctl, c); }
outuint(c_mix_ctl, channelMapUsb[c]); }
outct(c_mix_ctl, XS1_CT_END);
return XUD_DoSetRequestStatus(ep0_in); return XUD_DoSetRequestStatus(ep0_in);
} }
}
}
else else
{ {
/* Direction: Device-to-host */ /* Direction: Device-to-host */
(buffer, unsigned char[])[0] = channelMapUsb[sp.wValue & 0xff]; (buffer, unsigned char[])[0] = channelMapUsb[dst];
(buffer, unsigned char[])[1] = 0; (buffer, unsigned char[])[1] = 0;
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength); return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
} }
}
break; break;
case ID_XU_MIXSEL: case ID_XU_MIXSEL:
@@ -730,14 +746,12 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
/* cs now contains mix number */ /* cs now contains mix number */
if(cs < (MAX_MIX_COUNT + 1)) if(cs < (MAX_MIX_COUNT + 1))
{ {
int source = (buffer, unsigned char[])[0];
/* Check for "off" - update local state */ /* Check for "off" - update local state */
if((buffer, unsigned char[])[0] == 0xFF) if(source == 0xFF)
{ {
mixSel[cs][cn] = (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT); source = (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
}
else
{
mixSel[cs][cn] = (buffer, unsigned char[])[0];
} }
if(cs == 0) if(cs == 0)
@@ -745,21 +759,17 @@ 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 */ UpdateMixMap(c_mix_ctl, i, cn, mixSel[i][cn]);
outct(c_mix_ctl, XS1_CT_END);
} }
} }
else else
{ {
/* Update relevant mix map */ /* Update relevant mix map */
outuint(c_mix_ctl, SET_MIX_MAP); /* Command */ mixSel[cn-1][cn] = source;
outuint(c_mix_ctl, (cs-1)); /* Mix bus */ UpdateMixMap(c_mix_ctl, cs-1, cn, mixSel[cs-1][cn]);
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 */
} }
return XUD_DoSetRequestStatus(ep0_in); return XUD_DoSetRequestStatus(ep0_in);
@@ -807,15 +817,16 @@ 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))
{ {
outuint(c_mix_ctl, SET_MIX_MULT); //outuint(c_mix_ctl, SET_MIX_MULT);
outuint(c_mix_ctl, (sp.wValue & 0xff) % 8); //outuint(c_mix_ctl, (sp.wValue & 0xff) % 8);
outuint(c_mix_ctl, (sp.wValue & 0xff) / 8); //outuint(c_mix_ctl, (sp.wValue & 0xff) / 8);
outuint(c_mix_ctl, volume); //outuint(c_mix_ctl, volume);
outct(c_mix_ctl, XS1_CT_END); //outct(c_mix_ctl, XS1_CT_END);
UpdateMixerWeight(c_mix_ctl, (sp.wValue & 0xff) % 8, (sp.wValue & 0xff) / 8, volume);
} }
/* Send 0 Length as status stage */ /* Send 0 Length as status stage */
@@ -957,7 +968,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
} }
break; break;
#ifdef MIXER #if (MIXER)
/* Mixer Unit */ /* Mixer Unit */
case ID_MIXER_1: case ID_MIXER_1:
storeShort((buffer, unsigned char[]), 0, 1); storeShort((buffer, unsigned char[]), 0, 1);
@@ -977,7 +988,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
break; /* case: RANGE */ break; /* case: RANGE */
} }
#if defined (MIXER) && (MAX_MIX_COUNT > 0) #if ((MIXER) && (MAX_MIX_COUNT > 0))
case MEM: /* Memory Requests (5.2.7.1) */ case MEM: /* Memory Requests (5.2.7.1) */
unitID = sp.wIndex >> 8; unitID = sp.wIndex >> 8;

View File

@@ -1,4 +1,4 @@
// Copyright 2012-2022 XMOS LIMITED. // Copyright 2012-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.
#include "xua.h" /* Device specific defines */ #include "xua.h" /* Device specific defines */
@@ -273,7 +273,7 @@ void usb_audio_core(chanend c_mix_out
#ifdef MIDI #ifdef MIDI
, chanend c_midi , chanend c_midi
#endif #endif
#ifdef MIXER #if (MIXER)
, chanend c_mix_ctl , chanend c_mix_ctl
#endif #endif
, chanend ?c_clk_int , chanend ?c_clk_int
@@ -290,7 +290,7 @@ VENDOR_REQUESTS_PARAMS_DEC_
chan c_xud_in[ENDPOINT_COUNT_IN]; chan c_xud_in[ENDPOINT_COUNT_IN];
chan c_aud_ctl; chan c_aud_ctl;
#ifndef MIXER #if (!MIXER)
#define c_mix_ctl null #define c_mix_ctl null
#endif #endif
@@ -401,7 +401,7 @@ void usb_audio_io(chanend ?c_aud_in,
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE) #if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
chanend c_spdif_tx, chanend c_spdif_tx,
#endif #endif
#ifdef MIXER #if (MIXER)
chanend c_mix_ctl, chanend c_mix_ctl,
#endif #endif
streaming chanend ?c_spdif_rx, streaming chanend ?c_spdif_rx,
@@ -422,7 +422,7 @@ void usb_audio_io(chanend ?c_aud_in,
#endif #endif
) )
{ {
#ifdef MIXER #if (MIXER)
chan c_mix_out; chan c_mix_out;
#endif #endif
@@ -446,7 +446,7 @@ void usb_audio_io(chanend ?c_aud_in,
par par
{ {
#ifdef MIXER #if (MIXER)
/* Mixer cores(s) */ /* Mixer cores(s) */
{ {
thread_speed(); thread_speed();
@@ -464,7 +464,7 @@ void usb_audio_io(chanend ?c_aud_in,
/* Audio I/O core (pars additional S/PDIF TX Core) */ /* Audio I/O core (pars additional S/PDIF TX Core) */
{ {
thread_speed(); thread_speed();
#ifdef MIXER #if (MIXER)
#define AUDIO_CHANNEL c_mix_out #define AUDIO_CHANNEL c_mix_out
#else #else
#define AUDIO_CHANNEL c_aud_in #define AUDIO_CHANNEL c_aud_in
@@ -531,7 +531,7 @@ int main()
#endif #endif
#endif #endif
#ifdef MIXER #if (MIXER)
chan c_mix_ctl; chan c_mix_ctl;
#endif #endif
@@ -608,7 +608,7 @@ int main()
, c_ea_data , c_ea_data
#endif #endif
#endif #endif
#ifdef MIXER #if (MIXER)
, c_mix_ctl , c_mix_ctl
#endif #endif
, c_clk_int, c_clk_ctl, dfuInterface , c_clk_int, c_clk_ctl, dfuInterface
@@ -628,7 +628,7 @@ int main()
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE) #if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
, c_spdif_tx , c_spdif_tx
#endif #endif
#ifdef MIXER #if (MIXER)
, c_mix_ctl , c_mix_ctl
#endif #endif
, c_spdif_rx, c_adat_rx, c_clk_ctl, c_clk_int , c_spdif_rx, c_adat_rx, c_clk_ctl, c_clk_int

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 XMOS LIMITED. // Copyright 2018-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 MAX_MIX_COUNT 8 #define MAX_MIX_COUNT 8
@@ -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;

View File

@@ -1,25 +1,40 @@
// 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 "xua_commands.h" #include "xua_commands.h"
#include "dbcalc.h" #include "dbcalc.h"
#include "print.h"
#ifdef MIXER #if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
#include "xc_ptr.h"
#endif
#if (MIXER)
/* FAST_MIXER has a bit of a nasty implentation but is more effcient */ /* FAST_MIXER has a bit of a nasty implentation but is more effcient */
#define FAST_MIXER 1 #ifndef FAST_MIXER
#define FAST_MIXER (1)
#endif
//#ifdef OUT_VOLUME_IN_MIXER #if (OUT_VOLUME_IN_MIXER)
static unsigned int multOut_array[NUM_USB_CHAN_OUT + 1]; static unsigned int multOut_array[NUM_USB_CHAN_OUT + 1];
static xc_ptr multOut; unsafe
//#endif {
//#ifdef IN_VOLUME_IN_MIXER int volatile * unsafe multOut = multOut_array;
}
#endif
#if (IN_VOLUME_IN_MIXER)
static unsigned int multIn_array[NUM_USB_CHAN_IN + 1]; static unsigned int multIn_array[NUM_USB_CHAN_IN + 1];
static xc_ptr multIn; unsafe
//#endif {
int volatile * unsafe multIn = multIn_array;
}
#endif
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST) #if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
static unsigned abs(int x) static unsigned abs(int x)
@@ -35,35 +50,38 @@ static unsigned abs(int x)
} }
#endif #endif
static const int SOURCE_COUNT = NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1;
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; static int samples_to_host_map_array[NUM_USB_CHAN_IN];
static int samples_to_device_map_array[NUM_USB_CHAN_OUT];
unsafe unsafe
{ {
static int volatile * const unsafe ptr_samples = samples_array; int volatile * const unsafe ptr_samples = samples_array;
int volatile * const unsafe samples_to_host_map = samples_to_host_map_array;
int volatile * const unsafe samples_to_device_map = samples_to_device_map_array;
} }
int savedsamples2[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT]; #if (MAX_MIX_COUNT > 0)
int mix_mult_array[MAX_MIX_COUNT * MIX_INPUTS];
int samples_to_host_map_array[NUM_USB_CHAN_IN]; #if (FAST_MIXER == 0)
xc_ptr samples_to_host_map; int mix_map_array[MAX_MIX_COUNT * MIX_INPUTS];
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 #endif
unsafe
{
int volatile * const unsafe mix_mult = mix_mult_array;
#if (FAST_MIXER == 0)
int volatile * const unsafe mix_map = mix_map_array;
#endif
}
#define slice(a, i) (a + i * MIX_INPUTS)
#endif
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
/* Arrays for level data */ /* Arrays for level data */
int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. device inputs */ int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. device inputs */
xc_ptr samples_to_host_inputs_ptr; xc_ptr samples_to_host_inputs_ptr;
@@ -77,19 +95,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)
static inline void ComputeMixerLevel(int sample, int i) static inline void ComputeMixerLevel(int sample, int i)
{ {
int x; int x;
@@ -108,22 +113,22 @@ static inline void ComputeMixerLevel(int sample, int i)
} }
} }
#endif #endif
#ifdef FAST_MIXER
#if (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(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix1(xc_ptr samples, xc_ptr mult); int doMix1(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix2(xc_ptr samples, xc_ptr mult); int doMix2(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix3(xc_ptr samples, xc_ptr mult); int doMix3(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix4(xc_ptr samples, xc_ptr mult); int doMix4(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix5(xc_ptr samples, xc_ptr mult); int doMix5(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix6(xc_ptr samples, xc_ptr mult); int doMix6(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix7(xc_ptr samples, xc_ptr mult); int doMix7(volatile int * const unsafe samples, volatile int * const unsafe mult);
int doMix8(xc_ptr 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(volatile int * unsafe samples, volatile int * unsafe const mixMap, volatile int * const unsafe mult)
{ {
int h=0; int h=0;
int l=0; int l=0;
@@ -131,19 +136,18 @@ static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
/* By breaking up the loop we keep things in the encoding for ldw (0-11) */ /* By breaking up the loop we keep things in the encoding for ldw (0-11) */
#pragma loop unroll #pragma loop unroll
for (int i=0; i<MIX_INPUTS; i++) for (int i=0; i<MIX_INPUTS; i++)
{ unsafe{
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, mixMap, i);
read_via_xc_ptr_indexed(sample,samples,index); sample = samples[source];
read_via_xc_ptr_indexed(m, mult, i); read_via_xc_ptr_indexed(weight, mult, 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,15 +156,14 @@ 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
#pragma unsafe arrays #pragma unsafe arrays
static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn) static inline void GiveSamplesToHost(chanend c, volatile int * unsafe hostMap)
{ {
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX) #if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
int mult; int mult;
int h; int h;
unsigned l; unsigned l;
@@ -170,23 +173,26 @@ static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
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 index;
#if MAX_MIX_COUNT > 0 #if (MAX_MIX_COUNT > 0)
read_via_xc_ptr_indexed(index,ptr,i);
#else
index = i + NUM_USB_CHAN_OUT;
#endif
unsafe unsafe
{ {
//read_via_xc_ptr_indexed(sample,samples,index); sample = ptr_samples[hostMap[i]];
sample = ptr_samples[index];
} }
#else
unsafe
{
sample = ptr_samples[i + NUM_USB_CHAN_OUT];
}
#endif
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX) #if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
#warning IN Vols in mixer, AFTER mix & map #warning IN Vols in mixer, AFTER mix & map
//asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i));
read_via_xc_ptr_indexed(mult, multIn, i); unsafe
{
mult = multIn[i];
}
{h, l} = macs(mult, sample, 0, 0); {h, l} = macs(mult, sample, 0, 0);
//h <<= 3 done on other side */ //h <<= 3 done on other side */
@@ -209,7 +215,7 @@ static inline void GetSamplesFromHost(chanend c)
for (int i=0; i<NUM_USB_CHAN_OUT; i++) for (int i=0; i<NUM_USB_CHAN_OUT; i++)
unsafe { unsafe {
int sample, x; int sample, x;
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX) #if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
int mult; int mult;
int h; int h;
unsigned l; unsigned l;
@@ -226,16 +232,15 @@ static inline void GetSamplesFromHost(chanend c)
} }
#endif #endif
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX) #if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
#warning OUT Vols in mixer, BEFORE mix & map #warning OUT Vols in mixer, BEFORE mix & map
read_via_xc_ptr_indexed(mult, multOut, i); mult = multOut[i];
{h, l} = macs(mult, sample, 0, 0); {h, l} = macs(mult, sample, 0, 0);
h<<=3; h<<=3;
#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
#endif #endif
write_via_xc_ptr_indexed(multOut, index, val);
write_via_xc_ptr_indexed(samples_array, i, h); write_via_xc_ptr_indexed(samples_array, i, h);
#else #else
ptr_samples[i] = sample; ptr_samples[i] = sample;
@@ -246,7 +251,7 @@ static inline void GetSamplesFromHost(chanend c)
} }
#pragma unsafe arrays #pragma unsafe arrays
static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut) static inline void GiveSamplesToDevice(chanend c, volatile int * unsafe deviceMap)
{ {
#if (NUM_USB_CHAN_OUT == 0) #if (NUM_USB_CHAN_OUT == 0)
outuint(c, 0); outuint(c, 0);
@@ -255,21 +260,20 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
for (int i=0; i<NUM_USB_CHAN_OUT; i++) for (int i=0; i<NUM_USB_CHAN_OUT; i++)
{ {
int sample, x; int sample, x;
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX) #if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
int mult; int mult;
int h; int h;
unsigned l; unsigned l;
#endif #endif
int index; int index;
#if MAX_MIX_COUNT > 0 #if (MAX_MIX_COUNT > 0)
/* If mixer turned on sort out the channel mapping */ /* If mixer turned on sort out the channel mapping */
unsafe
/* Read pointer to sample from the map */ {
read_via_xc_ptr_indexed(index, ptr, i); /* Read index to sample from the map then Read the actual sample value */
sample = ptr_samples[deviceMap[i]];
/* Read the actual sample value */ }
read_via_xc_ptr_indexed(sample, samples, index);
#else #else
unsafe unsafe
{ {
@@ -278,13 +282,16 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
} }
#endif #endif
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX) #if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
/* Do volume control processing */ /* Do volume control processing */
#warning OUT Vols in mixer, AFTER mix & map #warning OUT Vols in mixer, AFTER mix & map
read_via_xc_ptr_indexed(mult, multOut, i); unsafe
{
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
@@ -300,7 +307,7 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
#pragma unsafe arrays #pragma unsafe arrays
static inline void GetSamplesFromDevice(chanend c) static inline void GetSamplesFromDevice(chanend c)
{ {
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX) #if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
int mult; int mult;
int h; int h;
unsigned l; unsigned l;
@@ -327,19 +334,23 @@ static inline void GetSamplesFromDevice(chanend c)
} }
#endif #endif
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX) #if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
/* Read relevant multiplier */ /* Read relevant multiplier */
read_via_xc_ptr_indexed(mult, multIn, i); unsafe
{
mult = multIn[i];
}
/* 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
} }
@@ -353,12 +364,13 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
#if (MAX_MIX_COUNT > 0) #if (MAX_MIX_COUNT > 0)
int mixed; int mixed;
#endif #endif
#if (MAX_MIX_COUNT > 0) || (IN_VOLUME_IN_MIXER) || (OUT_VOLUME_IN_MIXER) || defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
unsigned cmd; unsigned cmd;
#endif
unsigned request = 0; unsigned request = 0;
while (1) while (1)
{ {
#pragma xta endpoint "mixer1_req"
/* Request from audio()/mixer2() */ /* Request from audio()/mixer2() */
request = inuint(c_mixer2); request = inuint(c_mixer2);
@@ -369,8 +381,9 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
/* Sync */ /* Sync */
outuint(c_mixer2, 0); outuint(c_mixer2, 0);
#endif #endif
/* Between request to decouple and response ~ 400nS latency for interrupt to fire */ /* Between request to decouple and response ~ 400nS latency for interrupt to fire */
#if (MAX_MIX_COUNT > 0) || (IN_VOLUME_IN_MIXER) || (OUT_VOLUME_IN_MIXER) || defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
select select
{ {
case inuint_byref(c_mix_ctl, cmd): case inuint_byref(c_mix_ctl, cmd):
@@ -378,19 +391,43 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
int mix, index, val; int mix, index, val;
switch (cmd) switch (cmd)
{ {
#if MAX_MIX_COUNT > 0 #if (MAX_MIX_COUNT > 0)
case SET_SAMPLES_TO_HOST_MAP: case SET_SAMPLES_TO_HOST_MAP:
index = inuint(c_mix_ctl); {
val = inuint(c_mix_ctl); int dst = inuint(c_mix_ctl);
int src = inuint(c_mix_ctl);
inct(c_mix_ctl); inct(c_mix_ctl);
write_via_xc_ptr_indexed(samples_to_host_map, index, val);
assert((dst < NUM_USB_CHAN_IN) && msg("Host map destination out of range"));
assert((src < SOURCE_COUNT) && msg("Host map source out of range"));
if((dst < NUM_USB_CHAN_IN) && (src < SOURCE_COUNT))
{
unsafe
{
samples_to_host_map[dst] = src;
}
}
}
break; break;
case SET_SAMPLES_TO_DEVICE_MAP: case SET_SAMPLES_TO_DEVICE_MAP:
index = inuint(c_mix_ctl); {
val = inuint(c_mix_ctl); int dst = inuint(c_mix_ctl);
int src = inuint(c_mix_ctl);
inct(c_mix_ctl); inct(c_mix_ctl);
write_via_xc_ptr_indexed(samples_to_device_map,index,val);
assert((dst < NUM_USB_CHAN_OUT) && msg("Device map destination out of range"));
assert((src < SOURCE_COUNT) && msg("Device map source out of range"));
if((dst < NUM_USB_CHAN_OUT) && (src < SOURCE_COUNT))
{
unsafe
{
samples_to_device_map[dst] = src;
}
}
}
break; break;
case SET_MIX_MULT: case SET_MIX_MULT:
@@ -399,40 +436,80 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
val = inuint(c_mix_ctl); val = inuint(c_mix_ctl);
inct(c_mix_ctl); inct(c_mix_ctl);
write_word_to_mix_mult(mix, index, val); assert((mix < MAX_MIX_COUNT) && msg("Mix mult mix out of range"));
assert((index < MIX_INPUTS) && msg("Mix mult index out of range"));
if((index < MIX_INPUTS) && (mix < MAX_MIX_COUNT))
{
unsafe
{
mix_mult[(mix * MIX_INPUTS) + index] = val;
}
}
break; break;
case SET_MIX_MAP: case SET_MIX_MAP:
mix = inuint(c_mix_ctl); {
index = inuint(c_mix_ctl); /* mixer input */ unsigned mix = inuint(c_mix_ctl);
val = inuint(c_mix_ctl); /* source */ unsigned input = inuint(c_mix_ctl); /* mixer input */
unsigned source = inuint(c_mix_ctl); /* source */
inct(c_mix_ctl); inct(c_mix_ctl);
#ifdef FAST_MIXER
setPtr(index, val, mix); assert((mix < MAX_MIX_COUNT) && msg("Mix map mix out of range"));
assert((input < MIX_INPUTS) && msg("Mix map index out of range"));
assert((source < SOURCE_COUNT) && msg("Mix map source out of range"));
if((input < MIX_INPUTS) && (mix < MAX_MIX_COUNT) && (source < SOURCE_COUNT))
{
#if (FAST_MIXER)
setPtr(input, source, mix);
#else #else
write_word_to_mix_map(mix, index, val); unsafe
{
mix_map[(mix * MIX_INPUTS) + input] = source;
}
#endif #endif
}
}
break; break;
#endif /* if MAX_MIX_COUNT > 0 */ #endif /* if MAX_MIX_COUNT > 0 */
#ifdef IN_VOLUME_IN_MIXER
#if (IN_VOLUME_IN_MIXER)
case SET_MIX_IN_VOL: case SET_MIX_IN_VOL:
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);
write_via_xc_ptr_indexed(multIn, index, val); assert((index < (NUM_USB_CHAN_IN + 1)) && msg("In volume index out of range"));
if(index < NUM_USB_CHAN_IN + 1)
{
unsafe
{
multIn[index] = val;
}
}
break; break;
#endif #endif
#ifdef OUT_VOLUME_IN_MIXER #if (OUT_VOLUME_IN_MIXER)
case SET_MIX_OUT_VOL: case SET_MIX_OUT_VOL:
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);
write_via_xc_ptr_indexed(multOut, index, val); assert((index < (NUM_USB_CHAN_OUT + 1)) && msg("Out volume index out of range"));
if(index < NUM_USB_CHAN_OUT + 1)
{
unsafe
{
multOut[index] = val;
}
}
break; break;
#endif #endif
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
/* Peak samples of stream from host to device (via USB) */ /* Peak samples of stream from host to device (via USB) */
case GET_STREAM_LEVELS: case GET_STREAM_LEVELS:
index = inuint(c_mix_ctl); index = inuint(c_mix_ctl);
@@ -441,42 +518,6 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
outct(c_mix_ctl, XS1_CT_END); outct(c_mix_ctl, XS1_CT_END);
samples_from_host_streams[index] = 0; samples_from_host_streams[index] = 0;
break; 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 */
//val = samples_to_host_inputs_buff[index];
//samples_to_host_inputs_buff[index] = 0;
/* Access funcs used to avoid disjointness check */
read_via_xc_ptr_indexed(val, samples_to_host_inputs_buff_ptr, index);
write_via_xc_ptr_indexed(samples_to_host_inputs_buff_ptr, index, 0);
#else
/* We dont have a level LEDs process, so reset ourselves */
//val = samples_to_host_inputs[index];
//samples_to_host_inputs[index] = 0;
/* Access funcs used to avoid disjointness check */
read_via_xc_ptr_indexed(val, samples_to_host_inputs_ptr, index);
write_via_xc_ptr_indexed(samples_to_host_inputs_ptr, index, 0);
#endif
outuint(c_mix_ctl, val);
outct(c_mix_ctl, XS1_CT_END);
break;
#if (MAX_MIX_COUNT > 0)
/* Peak samples of the mixer outputs */
case GET_OUTPUT_LEVELS:
index = inuint(c_mix_ctl);
chkct(c_mix_ctl, XS1_CT_END);
read_via_xc_ptr_indexed(val, samples_mixer_outputs, index);
write_via_xc_ptr_indexed(samples_mixer_outputs, index, 0);
//val = samples_mixer_outputs[index];
//samples_mixer_outputs[index] = 0;
outuint(c_mix_ctl, val);
outct(c_mix_ctl, XS1_CT_END);
break;
#endif #endif
} }
break; break;
@@ -484,14 +525,13 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
default: default:
/* Select default */ /* Select default */
break; break;
} } // select
#endif
/* Get response from decouple */ /* Get response from decouple */
if(testct(c_host)) if(testct(c_host))
{ {
int sampFreq; int sampFreq;
#pragma xta endpoint "mixer1_rate_change"
unsigned command = inct(c_host); unsigned command = inct(c_host);
switch(command) switch(command)
@@ -522,7 +562,6 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
/* 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;
@@ -535,21 +574,24 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
} }
else else
{ {
#if MAX_MIX_COUNT > 0 #if (MAX_MIX_COUNT > 0)
GetSamplesFromHost(c_host); GetSamplesFromHost(c_host);
GiveSamplesToHost(c_host, samples_to_host_map, multIn); GiveSamplesToHost(c_host, samples_to_host_map);
/* Sync with mixer 2 (once it has swapped samples with audiohub) */ /* Sync with mixer 2 (once it has swapped samples with audiohub) */
outuint(c_mixer2, 0); outuint(c_mixer2, 0);
inuint(c_mixer2); inuint(c_mixer2);
/* Do the mixing */ /* Do the mixing */
#ifdef FAST_MIXER unsafe
mixed = doMix0(samples, mix_mult_slice(0)); {
#if (FAST_MIXER)
mixed = doMix0(ptr_samples, slice(mix_mult, 0));
#else #else
mixed = doMix(samples, mix_map_slice(0),mix_mult_slice(0)); mixed = doMix(ptr_samples, slice(mix_map, 0), slice(mix_mult, 0));
#endif #endif
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0), mixed); ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 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);
@@ -560,40 +602,46 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
#endif #endif
{ {
#if MAX_MIX_COUNT > 2 #if (MAX_MIX_COUNT > 2)
#ifdef FAST_MIXER unsafe
mixed = doMix2(samples, mix_mult_slice(2)); {
#if (FAST_MIXER)
mixed = doMix2(ptr_samples, slice(mix_mult, 2));
#else #else
mixed = doMix(samples, mix_map_slice(2),mix_mult_slice(2)); mixed = doMix(ptr_samples, slice(mix_map, 2), slice(mix_mult, 2));
#endif #endif
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2), mixed); ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 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);
#endif #endif
#endif #endif
#if MAX_MIX_COUNT > 4 #if (MAX_MIX_COUNT > 4)
#ifdef FAST_MIXER unsafe
mixed = doMix4(samples, mix_mult_slice(4)); {
#if (FAST_MIXER)
mixed = doMix4(ptr_samples, slice(mix_mult, 4));
#else #else
mixed = doMix(samples, mix_map_slice(4),mix_mult_slice(4)); mixed = doMix(ptr_samples, slice(mix_map, 4), slice(mix_mult, 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)
#ifdef FAST_MIXER unsafe
mixed = doMix6(samples, mix_mult_slice(6)); {
#if (FAST_MIXER)
mixed = doMix6(ptr_samples, slice(mix_mult, 6));
#else #else
mixed = doMix(samples, mix_map_slice(6),mix_mult_slice(6)); mixed = doMix(ptr_samples, slice(mix_map, 6), slice(mix_mult, 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
@@ -601,10 +649,10 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
} }
#else /* IF MAX_MIX_COUNT > 0 */ #else /* IF MAX_MIX_COUNT > 0 */
/* No mixes, this thread runs on its own doing just volume */ /* No mixes, this thread runs on its own doing just volume */
GiveSamplesToDevice(c_mixer2, samples_to_device_map, multOut); GiveSamplesToDevice(c_mixer2, samples_to_device_map);
GetSamplesFromDevice(c_mixer2); GetSamplesFromDevice(c_mixer2);
GetSamplesFromHost(c_host); GetSamplesFromHost(c_host);
GiveSamplesToHost(c_host, samples_to_host_map, multIn); GiveSamplesToHost(c_host, samples_to_host_map);
#endif #endif
} }
} }
@@ -621,7 +669,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
while (1) while (1)
{ {
#pragma xta endpoint "mixer2_req"
request = inuint(c_audio); request = inuint(c_audio);
/* Forward the request on */ /* Forward the request on */
@@ -633,7 +680,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
if(testct(c_mixer1)) if(testct(c_mixer1))
{ {
int sampFreq; int sampFreq;
#pragma xta endpoint "mixer2_rate_change"
unsigned command = inct(c_mixer1); unsigned command = inct(c_mixer1);
switch(command) switch(command)
@@ -660,8 +706,8 @@ 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++)
{ unsafe{
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0); ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
} }
/* Wait for handshake and pass on */ /* Wait for handshake and pass on */
@@ -670,7 +716,7 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
} }
else else
{ {
GiveSamplesToDevice(c_audio, samples_to_device_map, multOut); GiveSamplesToDevice(c_audio, samples_to_device_map);
GetSamplesFromDevice(c_audio); GetSamplesFromDevice(c_audio);
/* Sync with mixer 1 (once it has swapped samples with the buffering sub-system) */ /* Sync with mixer 1 (once it has swapped samples with the buffering sub-system) */
@@ -678,61 +724,67 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
outuint(c_mixer1, 0); outuint(c_mixer1, 0);
/* Do the mixing */ /* Do the mixing */
#if MAX_MIX_COUNT > 1 #if (MAX_MIX_COUNT > 1)
#ifdef FAST_MIXER unsafe
mixed = doMix1(samples, mix_mult_slice(1)); {
#if (FAST_MIXER)
mixed = doMix1(ptr_samples, slice(mix_mult, 1));
#else #else
mixed = doMix(samples, mix_map_slice(1),mix_mult_slice(1)); mixed = doMix(ptr_samples, slice(mix_map, 1), slice(mix_mult, 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)
#ifdef FAST_MIXER unsafe
mixed = doMix3(samples, mix_mult_slice(3)); {
#if (FAST_MIXER)
mixed = doMix3(ptr_samples, slice(mix_mult, 3));
#else #else
mixed = doMix(samples, mix_map_slice(3),mix_mult_slice(3)); mixed = doMix(ptr_samples, slice(mix_map, 3), slice(mix_mult, 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)
#ifdef FAST_MIXER unsafe
mixed = doMix5(samples, mix_mult_slice(5)); {
#if (FAST_MIXER)
mixed = doMix5(ptr_samples, slice(mix_mult, 5));
#else #else
mixed = doMix(samples, mix_map_slice(5),mix_mult_slice(5)); mixed = doMix(ptr_samples, slice(mix_map, 5), slice(mix_mult, 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)
#ifdef FAST_MIXER unsafe
mixed = doMix7(samples, mix_mult_slice(7)); {
#if (FAST_MIXER)
mixed = doMix7(ptr_samples, slice(mix_mult, 7));
#else #else
mixed = doMix(samples, mix_map_slice(7),mix_mult_slice(7)); mixed = doMix(ptr_samples, slice(mix_map, 7), slice(mix_mult, 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
@@ -748,68 +800,52 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
#if (MAX_MIX_COUNT > 0) #if (MAX_MIX_COUNT > 0)
chan c; chan c;
#endif #endif
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 defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
samples_to_host_inputs_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[])); samples_to_host_inputs_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
#ifdef LEVEL_METER_LEDS #ifdef LEVEL_METER_LEDS
samples_to_host_inputs_buff_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[])); samples_to_host_inputs_buff_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
#endif #endif
samples_mixer_outputs_ptr = array_to_xc_ptr((samples_mixer_outputs, unsigned[])); samples_mixer_outputs_ptr = array_to_xc_ptr((samples_mixer_outputs, 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 #endif
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;
} }
{
int num_mixes = DEFAULT_FREQ > 96000 ? 2 : MAX_MIX_COUNT;
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));
}
} }
#ifdef OUT_VOLUME_IN_MIXER #if (OUT_VOLUME_IN_MIXER)
for (int i=0; i<NUM_USB_CHAN_OUT; i++) for (int i=0; i<NUM_USB_CHAN_OUT; i++)
{ unsafe{
write_via_xc_ptr_indexed(multOut, i, MAX_VOL); multOut[i] = MAX_VOL;
} }
#endif #endif
#ifdef IN_VOLUME_IN_MIXER #if (IN_VOLUME_IN_MIXER)
for (int i=0; i<NUM_USB_CHAN_IN; i++) for (int i=0; i<NUM_USB_CHAN_IN; i++)
{ unsafe{
write_via_xc_ptr_indexed(multIn, i, MAX_VOL); multIn[i] = MAX_VOL;
} }
#endif #endif
for (int i=0; i<NUM_USB_CHAN_IN; i++) for (int i=0; i<NUM_USB_CHAN_IN; i++)
{ unsafe{
write_via_xc_ptr_indexed(samples_to_host_map, i, NUM_USB_CHAN_OUT + i); samples_to_host_map[i] = XUA_MIXER_OFFSET_IN + i;
} }
#if MAX_MIX_COUNT> 0 #if (MAX_MIX_COUNT> 0)
for (int i=0;i<MAX_MIX_COUNT;i++) for (int i=0;i<MAX_MIX_COUNT;i++)
for (int j=0;j<MIX_INPUTS;j++) for (int j=0;j<MIX_INPUTS;j++)
{ unsafe{
#ifndef FAST_MIXER #if (FAST_MIXER == 0)
write_word_to_mix_map(i,j, j < 16 ? j : j + 2); mix_map[i * MIX_INPUTS + j] = (j < 16 ? j : j + 2);
#endif #endif
write_word_to_mix_mult(i,j, i==j ? db_to_mult(0, 8, 25) : 0); mix_mult[i * MIX_INPUTS + j] = (i==j ? db_to_mult(0, XUA_MIXER_DB_FRAC_BITS, XUA_MIXER_MULT_FRAC_BITS) : 0);
} }
#endif #endif

View File

@@ -1,6 +1,23 @@
# Copyright 2022 XMOS LIMITED. # Copyright 2022-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.
import pytest import pytest
import time
@pytest.fixture()
def test_file(request):
return str(request.node.fspath)
@pytest.fixture(scope="session") # Use same seed for whole run
def test_seed(request):
seed = str(int(time.time()))
# We dont need the following since pytest will print the values of our fixtures on a failure
# capmanager = request.config.pluginmanager.getplugin("capturemanager")
# with capmanager.global_and_fixture_disabled():
# print("Using seed: "+ seed)
return seed
def pytest_addoption(parser): def pytest_addoption(parser):

View 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

View 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

View 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;
}

View 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>

View 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

View 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_output(options, capfd, test_file, test_seed):
result = do_test(options, capfd, test_file, test_seed)
assert result

View 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

View File

@@ -0,0 +1,224 @@
// Copyright 2022-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/* Tests that routing of mixer outputs behaves as expected
*
* "Outputs" from the device are to the USB host of one of the various audio interaces supported.
* This test assumes/checks the default routing for the USB host & audio interfaces is as follows:
*
* USB_FROM_HOST[0] -> AUD_INTERFACE_OUTPUT[0]
* USB_FROM_HOST[1] -> AUD_INTERFACE_OUTPUT[1]
* ...
* USB_TO_HOST[0] <- AUD_INTERFACE_INPUT[0]
* USB_TO_HOST[1] <- AUD_INTERFACE_INPUT[1]
* ...
*
* 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]
* ...
*
* (If the number of mixer inputs > NUM_USB_CHAN_OUT then see ordering in comment regarding
* SOURCE_COUNT below)
*
* By default none of the MAX_MIX_COUNT output from the mixers are routed anywwhere, but this test ensures
* that they can be.
*
* This test assumes that none of the mixer weights are changed.
* This test does not test changing the inputs to the mixer.
*/
#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 (100)
#endif
#include "./mixer_test_shared.h"
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)
{
unsigned 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 = modelMixerOut[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);
}
switch(map)
{
case SET_SAMPLES_TO_DEVICE_MAP:
modelOut[dst] = sample;
break;
case SET_SAMPLES_TO_HOST_MAP:
modelIn[dst] = sample;
break;
default:
assert(0);
break;
}
}
/* 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[CHANNEL_MAP_AUD_SIZE];
uint32_t modelIn[NUM_USB_CHAN_IN];
uint32_t modelMixerOut[MAX_MIX_COUNT];
uint32_t testCmd[] = {SET_SAMPLES_TO_HOST_MAP, SET_SAMPLES_TO_DEVICE_MAP};
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
/* By default the mixer should output samples from USB host unmodified
* See mixer.xc L780
*/
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
{
uint32_t sample = 0;
SET_SOURCE(sample, SRC_HOST);
SET_CHANNEL(sample, i);
modelMixerOut[i] = sample;
}
/* Init modelOut for default routing */
/* Default routing is USB[0] -> AUD_IF[0] etc */
for(size_t i = 0; i < CHANNEL_MAP_AUD_SIZE; i++)
{
uint32_t sample = 0;
SET_SOURCE(sample, SRC_HOST);
SET_CHANNEL(sample, i);
modelOut[i] = sample;
}
/* Init modelIn for default routing */
/* Default routing is AUD_IF[0] -> USB[0] etc */
for(size_t i = 0; i < NUM_USB_CHAN_IN; i++)
{
uint32_t sample = 0;
SET_SOURCE(sample, SRC_AUDIF);
SET_CHANNEL(sample, i);
modelIn[i] = sample;
}
/* Check default routing */
/* Send expected to AudioHub */
SendTrigger(c_stim_ah, 2);
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 destination */
unsigned map = testCmd[random_get_random_number(rg) % (sizeof(testCmd)/sizeof(testCmd[0]))];
unsigned dst = random_get_random_number(rg) % CHANNEL_MAP_AUD_SIZE;
unsigned src = random_get_random_number(rg) % NUM_USB_CHAN_OUT;
switch(map)
{
case SET_SAMPLES_TO_DEVICE_MAP:
debug_printf("Mapping output to AudioIF: %d", dst);
PrintDestString(map, dst);
debug_printf(" from %d", src);
PrintSourceString(src);
debug_printf("\n");
/* Update the mixer */
SendTrigger(c_stim_ah, 1);
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
break;
case SET_SAMPLES_TO_HOST_MAP:
debug_printf("Mapping output to Host : %d", dst);
PrintDestString(map, dst);
debug_printf(" from %d", src);
PrintSourceString(src);
debug_printf("\n");
/* Update the mixer */
SendTrigger(c_stim_ah, 1);
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
break;
default:
printstr("ERROR: Bad cmd in stim(): ");
printintln(map);
break;
}
/* Update the model */
UpdateModel(modelOut, modelMixerOut, modelIn, map, dst, src);
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
}
/* 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;
}

View 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;
}

View 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>

View 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