forked from PAWPAW-Mirror/lib_xua
Compare commits
155 Commits
v3.3.1
...
experiment
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd8d2675d3 | ||
|
|
7930a5d59c | ||
|
|
158d79335c | ||
|
|
ebc09e1c4f | ||
|
|
a7943a8859 | ||
|
|
77fad35497 | ||
|
|
50966dda90 | ||
|
|
e7b5faed66 | ||
|
|
7f72c4b842 | ||
|
|
d119755313 | ||
|
|
2228575e09 | ||
|
|
b6972295e9 | ||
|
|
39802f3620 | ||
|
|
5bf53fa453 | ||
|
|
2f11eda7d8 | ||
|
|
1574137dda | ||
|
|
c7e782179c | ||
|
|
badcb71c80 | ||
|
|
dff72573f8 | ||
|
|
aaaf1e9652 | ||
|
|
d6b23cf960 | ||
|
|
fa8329edaa | ||
|
|
83d86e885f | ||
|
|
b1b28f1005 | ||
|
|
6d41cfcbea | ||
|
|
5404127dbf | ||
|
|
e5a270347a | ||
|
|
f509a12e7d | ||
|
|
4528bed740 | ||
|
|
e812ca3e8b | ||
|
|
2accc0429f | ||
|
|
36d5201365 | ||
|
|
cea580ba48 | ||
|
|
6815f12a90 | ||
|
|
799ad7ba86 | ||
|
|
3d7e66bdc0 | ||
|
|
a6387d5fef | ||
|
|
5ca0738b02 | ||
|
|
b0e732110d | ||
|
|
1702078e7c | ||
|
|
136ec2506c | ||
|
|
45e5ef7702 | ||
|
|
1ef5129fde | ||
|
|
b1fe49aff3 | ||
|
|
d3ad29e8a6 | ||
|
|
17944ad908 | ||
|
|
131dd252c0 | ||
|
|
23d043630f | ||
|
|
761a33f5e4 | ||
|
|
12ec1d7536 | ||
|
|
2dba6dce36 | ||
|
|
9cf931898e | ||
|
|
9b104af8cf | ||
|
|
c469dd6cde | ||
|
|
b238196f74 | ||
|
|
e9586b59d3 | ||
|
|
6d168b3209 | ||
|
|
d301fef6d7 | ||
|
|
1f4e9a99b8 | ||
|
|
981ea78be7 | ||
|
|
6cee90d876 | ||
|
|
79d14f8b59 | ||
|
|
05dcb8f3ab | ||
|
|
4e7ddb4036 | ||
|
|
e8fcc80415 | ||
|
|
71a657dc9a | ||
|
|
ccfca90451 | ||
|
|
cb379f5bfb | ||
|
|
e2c36a9a95 | ||
|
|
7e3ae59acc | ||
|
|
f1f453921b | ||
|
|
7703fc1a7d | ||
|
|
53a65344fc | ||
|
|
3b2814f8cb | ||
|
|
55a62cf589 | ||
|
|
4a84c3e1ec | ||
|
|
b17f585004 | ||
|
|
57593bfea3 | ||
|
|
8dc77090bf | ||
|
|
9c20fab216 | ||
|
|
cf1940245f | ||
|
|
837b648bbc | ||
|
|
c1159143ea | ||
|
|
2964861b70 | ||
|
|
208491fe51 | ||
|
|
3fe4593b52 | ||
|
|
49a116c705 | ||
|
|
eee5b474a0 | ||
|
|
4655a07542 | ||
|
|
c578bb92d5 | ||
|
|
d5a614df55 | ||
|
|
495140ab8d | ||
|
|
f53c1bab09 | ||
|
|
0c6d947e67 | ||
|
|
ee271e3769 | ||
|
|
950beb55cb | ||
|
|
ca3276792a | ||
|
|
e26b934233 | ||
|
|
51629dba24 | ||
|
|
c5e944d73d | ||
|
|
22a3d5e043 | ||
|
|
58f691078d | ||
|
|
f80d7647e0 | ||
|
|
fe697929bc | ||
|
|
b265ccd8bf | ||
|
|
6c2e7e3042 | ||
|
|
15ca5ec281 | ||
|
|
71aa64425d | ||
|
|
9080990234 | ||
|
|
6d8cf9913f | ||
|
|
60040de58f | ||
|
|
27a59ab3bc | ||
|
|
317e27e421 | ||
|
|
035c20e01c | ||
|
|
ef97d667de | ||
|
|
0e07dc29bc | ||
|
|
43f77c177d | ||
|
|
6754f812c9 | ||
|
|
fc732b8512 | ||
|
|
39ed235476 | ||
|
|
0d7224bd6d | ||
|
|
fd4dfd40a9 | ||
|
|
3d50c96595 | ||
|
|
379e8eb54c | ||
|
|
63763cf4f5 | ||
|
|
b18c34fb0f | ||
|
|
64d65afeaf | ||
|
|
7a47d70229 | ||
|
|
ce8e5a6dbb | ||
|
|
bbed806aab | ||
|
|
9af31b8c70 | ||
|
|
73955c1a4c | ||
|
|
cffd35d146 | ||
|
|
ab535e0fb3 | ||
|
|
17b039dce8 | ||
|
|
7a0d0e1f97 | ||
|
|
2f31260612 | ||
|
|
9922190450 | ||
|
|
0ce91bec90 | ||
|
|
2404eaf35f | ||
|
|
8966ad1bb9 | ||
|
|
513761ef5b | ||
|
|
da7c45500d | ||
|
|
395c88cb22 | ||
|
|
94e58edfaf | ||
|
|
9f00f9159a | ||
|
|
785a857ca8 | ||
|
|
3130088c91 | ||
|
|
c51ee0c460 | ||
|
|
17ed636a74 | ||
|
|
0db1b08948 | ||
|
|
9c460f753f | ||
|
|
6a9537fb69 | ||
|
|
abfa3a2011 | ||
|
|
a1946f340a |
56
.gitignore
vendored
56
.gitignore
vendored
@@ -1,29 +1,25 @@
|
||||
*.log
|
||||
*.dSYM
|
||||
*/.build_*/*
|
||||
*/bin/*
|
||||
*.o
|
||||
# XMOS bin files
|
||||
*.xe
|
||||
*.vcd
|
||||
*.swo
|
||||
*.bin
|
||||
*/bin/*
|
||||
|
||||
# XMOS temp files
|
||||
.build*
|
||||
*.a
|
||||
_build*
|
||||
*.i
|
||||
*.s
|
||||
*.xi
|
||||
*.i
|
||||
*.bin
|
||||
*~
|
||||
*.a
|
||||
*.swp
|
||||
*.*~
|
||||
*.pyc
|
||||
.build*
|
||||
*.o
|
||||
*/.build_*/*
|
||||
|
||||
# Temp files
|
||||
.DS_Store
|
||||
test_results.csv
|
||||
_build*
|
||||
**/.venv/**
|
||||
**/.vscode/**
|
||||
**.egg-info
|
||||
*.pdf
|
||||
*tests/logs/*
|
||||
*.*~
|
||||
*.swp
|
||||
*.swn
|
||||
*~
|
||||
*.swo
|
||||
|
||||
# waf build files
|
||||
.lock-waf_*
|
||||
@@ -36,3 +32,19 @@ xscope.xmt
|
||||
# Traces
|
||||
*.gtkw
|
||||
*.vcd
|
||||
|
||||
# Host binaries
|
||||
host_usb_mixer_control/xmos_mixer
|
||||
|
||||
# Documentation build
|
||||
*.pdf
|
||||
|
||||
# Misc
|
||||
*.log
|
||||
*.dSYM
|
||||
*.vcd
|
||||
*.pyc
|
||||
**/.venv/**
|
||||
**/.vscode/**
|
||||
**.egg-info
|
||||
*tests/logs/*
|
||||
|
||||
@@ -1,6 +1,54 @@
|
||||
lib_xua Change Log
|
||||
==================
|
||||
|
||||
3.5.1
|
||||
-----
|
||||
|
||||
* FIXED: Respect I2S_CHANS_PER_FRAME when calculating bit-clock rates
|
||||
|
||||
* Changes to dependencies:
|
||||
|
||||
- lib_spdif: 5.0.0 -> 5.0.1
|
||||
|
||||
3.5.0
|
||||
-----
|
||||
|
||||
* ADDED: Configurable word-length for I2S/TDM via XUA_I2S_N_BITS
|
||||
* ADDED: Support for statically defined custom HID descriptor
|
||||
* CHANGED: Rearranged main() such that adding custom code that uses lib_xud
|
||||
is possible
|
||||
* CHANGED: bNumConfigurations changed from 2 to 1, removing a work-around to
|
||||
stop old Windows versions loading the composite driver
|
||||
* FIXED: Memory corruption due to erroneous initialisation of mixer
|
||||
weights when not in use (#152)
|
||||
* FIXED: UserHostActive() not being called as expected (#326)
|
||||
* FIXED: Exception when entering DSD mode (#327)
|
||||
|
||||
* Changes to dependencies:
|
||||
|
||||
- lib_spdif: 4.2.1 -> 5.0.0
|
||||
|
||||
- lib_xud: 2.2.2 -> 2.2.3
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
* ADDED: Unit tests for mixer functionality
|
||||
* ADDED: Host mixer control applications (for Win/macOS)
|
||||
* CHANGED: Small tidies to mixer implementation
|
||||
* CHANGED: Improved mixer control channel communication protocol to avoid
|
||||
deadlock situations
|
||||
* CHANGED: By default, output volume processing occurs in mixer task, if
|
||||
present. Previously occurred in decouple task
|
||||
* CHANGED: Some optimisations in sample transfer from decouple task
|
||||
* FIXED: Exception on startup when USB input disabled
|
||||
* FIXED: Full 32bit volume processing only applied when required
|
||||
* FIXED: Setting OUT_VOLUME_AFTER_MIX to zero now has the expected effect
|
||||
|
||||
* Changes to dependencies:
|
||||
|
||||
- lib_xud: 2.2.1 -> 2.2.2
|
||||
|
||||
3.3.1
|
||||
-----
|
||||
|
||||
|
||||
20
Jenkinsfile
vendored
20
Jenkinsfile
vendored
@@ -1,4 +1,4 @@
|
||||
@Library('xmos_jenkins_shared_library@v0.21.0') _
|
||||
@Library('xmos_jenkins_shared_library@v0.24.0') _
|
||||
|
||||
getApproval()
|
||||
|
||||
@@ -106,6 +106,12 @@ pipeline {
|
||||
dir("${REPO}/${REPO}/host/xmosdfu") {
|
||||
sh 'make -f Makefile.OSX64'
|
||||
}
|
||||
dir("${REPO}/host_usb_mixer_control") {
|
||||
sh 'make -f Makefile.OSX'
|
||||
sh 'mkdir OSX/x86'
|
||||
sh 'mv xmos_mixer OSX/x86/xmos_mixer'
|
||||
archiveArtifacts artifacts: "OSX/x86/xmos_mixer", fingerprint: true
|
||||
}
|
||||
}
|
||||
post {
|
||||
cleanup {
|
||||
@@ -139,7 +145,17 @@ pipeline {
|
||||
dir("${REPO}") {
|
||||
checkout scm
|
||||
dir("${REPO}/host/xmosdfu") {
|
||||
runVS('nmake /f Makefile.Win32')
|
||||
withVS("vcvars32.bat") {
|
||||
bat "nmake /f Makefile.Win32"
|
||||
}
|
||||
}
|
||||
dir("host_usb_mixer_control") {
|
||||
withVS() {
|
||||
bat 'msbuild host_usb_mixer_control.vcxproj /property:Configuration=Release /property:Platform=x64'
|
||||
}
|
||||
bat 'mkdir Win\\x64'
|
||||
bat 'mv bin/Release/x64/host_usb_mixer_control.exe Win/x64/xmos_mixer.exe'
|
||||
archiveArtifacts artifacts: "Win/x64/xmos_mixer.exe", fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
README.rst
25
README.rst
@@ -1,9 +1,8 @@
|
||||
lib_xua
|
||||
#######
|
||||
|
||||
:Latest release: 3.3.1
|
||||
|
||||
|
||||
:Version: 3.5.0
|
||||
:Vendor: XMOS
|
||||
:Scope: General Use
|
||||
|
||||
Summary
|
||||
@@ -40,9 +39,9 @@ Key features of the various components in this repository are as follows
|
||||
|
||||
- Synchronisation to external digital streams i.e. S/PDIF or ADAT (when in asynchronous mode)
|
||||
|
||||
- I2S slave & master modes
|
||||
- I2S (slave/master modes with configurable word-length)
|
||||
|
||||
- TDM slave & master modes
|
||||
- TDM (slave/master modes with configurable word-length)
|
||||
|
||||
- MIDI input/output (Compliant to USB Class Specification for MIDI devices)
|
||||
|
||||
@@ -52,6 +51,8 @@ Key features of the various components in this repository are as follows
|
||||
|
||||
- Simple playback controls via USB Human Interface Device (HID) Class
|
||||
|
||||
- Support for adding custom HID interfaces
|
||||
|
||||
Note, not all features may be supported at all sample frequencies, simultaneously or on all devices.
|
||||
Some features may also require specific host driver support.
|
||||
|
||||
@@ -85,11 +86,17 @@ Required Software (dependencies)
|
||||
* lib_mic_array (www.github.com/xmos/lib_mic_array)
|
||||
* lib_xassert (www.github.com/xmos/lib_xassert)
|
||||
* lib_dsp (www.github.com/xmos/lib_dsp)
|
||||
* lib_i2c (www.github.com/xmos/lib_i2c)
|
||||
* lib_i2s (www.github.com/xmos/lib_i2s)
|
||||
* lib_gpio (www.github.com/xmos/lib_gpio)
|
||||
* lib_mic_array_board_support (www.github.com/xmos/lib_mic_array_board_support)
|
||||
* lib_spdif (www.github.com/xmos/lib_spdif)
|
||||
* lib_xud (www.github.com/xmos/lib_xud)
|
||||
* lib_adat (www.github.com/xmos/lib_adat)
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
You can find the documentation for this software in the /doc directory of the package.
|
||||
|
||||
Support
|
||||
=======
|
||||
|
||||
This package is supported by XMOS Ltd. Issues can be raised against the software at: http://www.xmos.com/support
|
||||
|
||||
|
||||
@@ -21,4 +21,3 @@ USED_MODULES = lib_xua lib_xud lib_i2c
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright 2017-2022 XMOS LIMITED.
|
||||
// Copyright 2017-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <xs1.h>
|
||||
#include <platform.h>
|
||||
#include "xua.h"
|
||||
#include "../../shared/apppll.h"
|
||||
|
||||
on tile[0]: out port p_ctrl = XS1_PORT_8D;
|
||||
|
||||
@@ -35,11 +34,6 @@ void ctrlPort()
|
||||
void AudioHwInit()
|
||||
{
|
||||
/* Wait for power supply to come up */
|
||||
delay_milliseconds(100);
|
||||
|
||||
/* Use xCORE Secondary PLL to generate *fixed* master clock */
|
||||
AppPllEnable_SampleRate(DEFAULT_FREQ);
|
||||
|
||||
delay_milliseconds(100);
|
||||
|
||||
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
|
||||
@@ -48,9 +42,12 @@ void AudioHwInit()
|
||||
*/
|
||||
}
|
||||
|
||||
/* Configures the external audio hardware for the required sample frequency */
|
||||
/* Configures the external audio hardware for the required sample frequency
|
||||
* Note, the application PLL in xcore.ai will be configured to the correct master clock frequency
|
||||
* by lib_xua
|
||||
*/
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||
{
|
||||
AppPllEnable_SampleRate(samFreq);
|
||||
/* Nothing required since the DAC's will auto detect the sample rate from the clocks */
|
||||
}
|
||||
|
||||
|
||||
@@ -20,4 +20,3 @@ USED_MODULES = lib_xua lib_xud lib_spdif
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright 2017-2022 XMOS LIMITED.
|
||||
// Copyright 2017-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <xs1.h>
|
||||
#include <platform.h>
|
||||
#include "xua.h"
|
||||
#include "../../shared/apppll.h"
|
||||
|
||||
on tile[0]: out port p_ctrl = XS1_PORT_8D;
|
||||
|
||||
@@ -35,11 +34,6 @@ void ctrlPort()
|
||||
void AudioHwInit()
|
||||
{
|
||||
/* Wait for power supply to come up */
|
||||
delay_milliseconds(100);
|
||||
|
||||
/* Use xCORE Secondary PLL to generate *fixed* master clock */
|
||||
AppPllEnable_SampleRate(DEFAULT_FREQ);
|
||||
|
||||
delay_milliseconds(100);
|
||||
|
||||
/* DAC setup: For basic I2S input we don't need any register setup. DACs will clock auto detect etc.
|
||||
@@ -48,9 +42,12 @@ void AudioHwInit()
|
||||
*/
|
||||
}
|
||||
|
||||
/* Configures the external audio hardware for the required sample frequency */
|
||||
/* Configures the external audio hardware for the required sample frequency
|
||||
* Note, the application PLL in xcore.ai will be configured to the correct master clock frequency
|
||||
* by lib_xua
|
||||
*/
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||
{
|
||||
AppPllEnable_SampleRate(samFreq);
|
||||
/* Nothing required since the DAC's will auto detect the sample rate from the clocks */
|
||||
}
|
||||
|
||||
|
||||
@@ -19,4 +19,3 @@ USED_MODULES = lib_xua lib_xud lib_mic_array
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
// Copyright 2022 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <stdint.h>
|
||||
#include "xassert.h"
|
||||
|
||||
// App PLL setup
|
||||
#define APP_PLL_CTL_BYPASS (0) // 0 = no bypass, 1 = bypass.
|
||||
#define APP_PLL_CTL_INPUT_SEL (0) // 0 = XTAL, 1 = sysPLL
|
||||
#define APP_PLL_CTL_ENABLE (1) // 0 = disabled, 1 = enabled.
|
||||
|
||||
// 24MHz in, 24.576MHz out, integer mode
|
||||
// Found exact solution: IN 24000000.0, OUT 24576000.0, VCO 2457600000.0, RD 5, FD 512, OD 10, FOD 10
|
||||
#define APP_PLL_CTL_OD_48 (4) // Output divider = (OD+1)
|
||||
#define APP_PLL_CTL_F_48 (511) // FB divider = (F+1)/2
|
||||
#define APP_PLL_CTL_R_48 (4) // Ref divider = (R+1)
|
||||
|
||||
#define APP_PLL_CTL_48 ((APP_PLL_CTL_BYPASS << 29) | (APP_PLL_CTL_INPUT_SEL << 28) | (APP_PLL_CTL_ENABLE << 27) |\
|
||||
(APP_PLL_CTL_OD_48 << 23) | (APP_PLL_CTL_F_48 << 8) | APP_PLL_CTL_R_48)
|
||||
|
||||
// Fractional divide is M/N
|
||||
#define APP_PLL_FRAC_EN_48 (0) // 0 = disabled
|
||||
#define APP_PLL_FRAC_NPLUS1_CYCLES_48 (0) // M value is this reg value + 1.
|
||||
#define APP_PLL_FRAC_TOTAL_CYCLES_48 (0) // N value is this reg value + 1.
|
||||
#define APP_PLL_FRAC_48 ((APP_PLL_FRAC_EN_48 << 31) | (APP_PLL_FRAC_NPLUS1_CYCLES_48 << 8) | APP_PLL_FRAC_TOTAL_CYCLES_48)
|
||||
|
||||
// 24MHz in, 22.5792MHz out (44.1kHz * 512), frac mode
|
||||
// Found exact solution: IN 24000000.0, OUT 22579200.0, VCO 2257920000.0, RD 5, FD 470.400 (m = 2, n = 5), OD 5, FOD 10
|
||||
#define APP_PLL_CTL_OD_441 (4) // Output divider = (OD+1)
|
||||
#define APP_PLL_CTL_F_441 (469) // FB divider = (F+1)/2
|
||||
#define APP_PLL_CTL_R_441 (4) // Ref divider = (R+1)
|
||||
|
||||
#define APP_PLL_CTL_441 ((APP_PLL_CTL_BYPASS << 29) | (APP_PLL_CTL_INPUT_SEL << 28) | (APP_PLL_CTL_ENABLE << 27) |\
|
||||
(APP_PLL_CTL_OD_441 << 23) | (APP_PLL_CTL_F_441 << 8) | APP_PLL_CTL_R_441)
|
||||
|
||||
#define APP_PLL_FRAC_EN_44 (1) // 1 = enabled
|
||||
#define APP_PLL_FRAC_NPLUS1_CYCLES_44 (1) // M value is this reg value + 1.
|
||||
#define APP_PLL_FRAC_TOTAL_CYCLES_44 (4) // N value is this reg value + 1.define APP_PLL_CTL_R_441 (4) // Ref divider = (R+1)
|
||||
#define APP_PLL_FRAC_44 ((APP_PLL_FRAC_EN_44 << 31) | (APP_PLL_FRAC_NPLUS1_CYCLES_44 << 8) | APP_PLL_FRAC_TOTAL_CYCLES_44)
|
||||
|
||||
#define APP_PLL_DIV_INPUT_SEL (1) // 0 = sysPLL, 1 = app_PLL
|
||||
#define APP_PLL_DIV_DISABLE (0) // 1 = disabled (pin connected to X1D11), 0 = enabled divider output to pin.
|
||||
#define APP_PLL_DIV_VALUE (4) // Divide by N+1 - remember there's a /2 also afterwards for 50/50 duty cycle.
|
||||
#define APP_PLL_DIV ((APP_PLL_DIV_INPUT_SEL << 31) | (APP_PLL_DIV_DISABLE << 16) | APP_PLL_DIV_VALUE)
|
||||
|
||||
/* TODO support more than two freqs..*/
|
||||
void AppPllEnable(int32_t clkFreq_hz)
|
||||
{
|
||||
switch(clkFreq_hz)
|
||||
{
|
||||
case 44100*512:
|
||||
|
||||
// Disable the PLL
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_441 & 0xF7FFFFFF));
|
||||
// Enable the PLL to invoke a reset on the appPLL.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
|
||||
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
|
||||
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_441 & 0xF7FFFFFF));
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_441);
|
||||
|
||||
// Set the fractional divider if used
|
||||
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_44);
|
||||
|
||||
break;
|
||||
|
||||
case 48000*512:
|
||||
|
||||
// Disable the PLL
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_48 & 0xF7FFFFFF));
|
||||
// Enable the PLL to invoke a reset on the appPLL.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
|
||||
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
|
||||
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (APP_PLL_CTL_48 & 0xF7FFFFFF));
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_SS_APP_PLL_CTL_NUM, APP_PLL_CTL_48);
|
||||
|
||||
// Set the fractional divider if used
|
||||
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, APP_PLL_FRAC_48);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait for PLL output frequency to stabilise due to fractional divider enable
|
||||
delay_microseconds(100);
|
||||
|
||||
// Turn on the clock output
|
||||
write_node_config_reg(tile[0], XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, APP_PLL_DIV);
|
||||
}
|
||||
|
||||
void AppPllEnable_SampleRate(int32_t sampleRate_hz)
|
||||
{
|
||||
assert(sampleRate_hz >= 22050);
|
||||
|
||||
if(sampleRate_hz % 22050 == 0)
|
||||
{
|
||||
AppPllEnable(44100*512);
|
||||
}
|
||||
else
|
||||
{
|
||||
AppPllEnable(48000*512);
|
||||
}
|
||||
}
|
||||
|
||||
10
host_usb_mixer_control/.makefile
Normal file
10
host_usb_mixer_control/.makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
all:
|
||||
@echo =======================================================
|
||||
@echo Build complete [module only - cannot be run on its own]
|
||||
@echo =======================================================
|
||||
|
||||
clean:
|
||||
@echo =======================================================
|
||||
@echo Build clean [module only - cannot be run on its own]
|
||||
@echo =======================================================
|
||||
|
||||
77
host_usb_mixer_control/.project
Normal file
77
host_usb_mixer_control/.project
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>host_usb_mixer_control</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||
<triggers>clean,full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>?name?</key>
|
||||
<value></value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.append_environment</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
|
||||
<value>all</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildArguments</key>
|
||||
<value></value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildCommand</key>
|
||||
<value>xmake</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
|
||||
<value>clean</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.contents</key>
|
||||
<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
|
||||
<value>false</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableFullBuild</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
|
||||
<value>all</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.stopOnError</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
2
host_usb_mixer_control/Makefile.OSX
Normal file
2
host_usb_mixer_control/Makefile.OSX
Normal file
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
g++ -g -o xmos_mixer usb_mixer.cpp mixer_app.cpp -I. -IOSX OSX/libusb-1.0.0.dylib -arch x86_64
|
||||
5
host_usb_mixer_control/Makefile.Win
Normal file
5
host_usb_mixer_control/Makefile.Win
Normal file
@@ -0,0 +1,5 @@
|
||||
!if [set SDKPath=C:\Program^ Files\XMOS\tusbaudiosdk]
|
||||
!endif
|
||||
|
||||
all:
|
||||
msbuild host_usb_mixer_control.vcxproj /property:Configuration=Release /property:Platform=x64
|
||||
BIN
host_usb_mixer_control/OSX/libusb-1.0.0.dylib
Normal file
BIN
host_usb_mixer_control/OSX/libusb-1.0.0.dylib
Normal file
Binary file not shown.
1233
host_usb_mixer_control/OSX/libusb.h
Normal file
1233
host_usb_mixer_control/OSX/libusb.h
Normal file
File diff suppressed because it is too large
Load Diff
117
host_usb_mixer_control/README
Normal file
117
host_usb_mixer_control/README
Normal file
@@ -0,0 +1,117 @@
|
||||
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
|
||||
enabled).
|
||||
|
||||
----WINDOWS REQUIREMENTS----
|
||||
Building the mixer on Windows requires the tusbaudio SDK from Thesycon. The
|
||||
default location for the SDK is C:\Program Files\XMOS\tusbaudiosdk\
|
||||
If it can be found on a different path then this can be changed in
|
||||
Makefile.Win.
|
||||
|
||||
The mixer app on windows makes use of a USB dynamic library, also from Thesycon.
|
||||
If required please contact thesycon.de for support.
|
||||
----------------------------
|
||||
|
||||
This unit takes input takes 18 inputs: USB OUT channels 1..10 and
|
||||
DEVICE IN channels 1..6,9..10 and produces 8 outputs: Mixer Output
|
||||
1..8
|
||||
|
||||
Before the mixer there is an unit that allows the selection of the 18 mixer inputs
|
||||
from all the possible device inputs (DAW and physical audio). This is
|
||||
an extension unit with id 50 in the descriptors
|
||||
|
||||
After the mixer unit there is are channel map units for each output terminal:
|
||||
Each of these outputs can select a source from one of 28 channels sources: USB OUT
|
||||
channels 1..10, DEVICE IN channels 1..10 and Mixer Output 1..8
|
||||
|
||||
The channel map units are extension unit with init ids 51 and 52. This unit
|
||||
lets you implement arbitrary routings including loopbacks.
|
||||
|
||||
The mixer is controlled on macOS via the command line utility
|
||||
xmos_mixer. Running this application requires having the
|
||||
libusb-1.0.0.dylib in the dynamic library load path. Sourcing the
|
||||
setup.sh script will do this. Source code for the application is
|
||||
provided as a guide on how to communicate with the device.
|
||||
|
||||
Here are the commands for the mixer application (note that the USB
|
||||
audio reference design has only one unit so the mixer_id argument
|
||||
should always be 0):
|
||||
|
||||
--help
|
||||
|
||||
--display-info
|
||||
|
||||
Show information about the device.
|
||||
|
||||
--display-mixer-nodes mixer_id
|
||||
|
||||
Display all the weights of all the mixer nodes (and their id) of a particular mixer.
|
||||
|
||||
--display-min mixer_id
|
||||
|
||||
Display the minimum allowable weights of a particular mixer.
|
||||
|
||||
--display-max mixer_id
|
||||
|
||||
Display the maximum allowable weights of a particular mixer.
|
||||
|
||||
--display-res mixer_id
|
||||
|
||||
Display the resolution of a particular mixer.
|
||||
|
||||
--set-value mixer_id mixer_unit value
|
||||
|
||||
Set the weight value in the mixer. The second argument should
|
||||
correspond to the values shown by the --display-unit command. Values
|
||||
can range from -127db to +128db with the special value -inf for mute.
|
||||
|
||||
--get-value mixer_id mixer_unit
|
||||
|
||||
Get the weight value in the mixer. The second argument should
|
||||
correspond to the values shown by the --display-unit command. Values
|
||||
can range from -127db to +128db with the special value -inf for mute.
|
||||
|
||||
--set-mixer-source mixer_id, dst_channel_id, src_channel_id
|
||||
|
||||
Allows the selection of the mixer inputs. Sets mixer input (dst) to src
|
||||
|
||||
--display-current-mixer-sources mixer_id
|
||||
|
||||
Displays the current inputs to a particular mixer
|
||||
|
||||
--display-available-mixer-sources mixer_id
|
||||
|
||||
Displays all the input channels available that can be fed into the inputs of a particular mixer
|
||||
|
||||
--set-aud-channel-map dst src
|
||||
|
||||
Sets a channel map value for the device audio output
|
||||
|
||||
--display-aud-channel-map
|
||||
|
||||
Show audio output channel map i.e. for each audio output of the device what the source is.
|
||||
|
||||
--display-aud-channel-map-sources
|
||||
|
||||
Show the available audio output channel map sources.
|
||||
|
||||
--set-daw-channel-map dst src
|
||||
|
||||
Sets a channel map value for the DAW output to the host
|
||||
|
||||
--display-daw-channel-map
|
||||
|
||||
Show audio output channel map i.e. for each DAW output to host, what the source is.
|
||||
|
||||
--display-daw-channel-map-sources
|
||||
|
||||
Show the DAW output channel map sources.
|
||||
|
||||
--get-mixer-levels-input
|
||||
|
||||
--get-mixer-levels-output
|
||||
|
||||
--vendor-audio-request-get bRequest, ControlSelector, ChannelNumber, UnitId
|
||||
|
||||
--vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],...
|
||||
|
||||
48
host_usb_mixer_control/Win/global.h
Normal file
48
host_usb_mixer_control/Win/global.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/************************************************************************
|
||||
*
|
||||
* Module: global.h
|
||||
* Description:
|
||||
* APP global includes, constants, declarations, etc.
|
||||
*
|
||||
* Author(s):
|
||||
* Udo Eberhardt
|
||||
*
|
||||
* Companies:
|
||||
* Thesycon GmbH, Germany http://www.thesycon.de
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#ifndef __global_h__
|
||||
#define __global_h__
|
||||
|
||||
// define the Windows versions supported by the application
|
||||
#define _WIN32_WINNT 0x0500 //Windows 2000 or later
|
||||
//#define _WIN32_WINNT 0x0501 //Windows XP or later
|
||||
//#define _WIN32_WINNT 0x0600 //Windows Vista or later
|
||||
//#define _WIN32_WINNT 0x0A00 //Windows 10 or later
|
||||
|
||||
// exclude rarely-used stuff from Windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
|
||||
|
||||
// version defs
|
||||
//#include "version.h"
|
||||
|
||||
// libwn.h pulls in windows.h
|
||||
#include "libwn.h"
|
||||
// TUSBAUDIO driver API
|
||||
#include "tusbaudioapi.h"
|
||||
#include "TUsbAudioApiDll.h"
|
||||
|
||||
|
||||
#endif // __global_h__
|
||||
|
||||
/*************************** EOF **************************************/
|
||||
177
host_usb_mixer_control/host_usb_mixer_control.vcxproj
Normal file
177
host_usb_mixer_control/host_usb_mixer_control.vcxproj
Normal file
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{84eacf4f-e405-4909-b440-a04a84a3f8c8}</ProjectGuid>
|
||||
<RootNamespace>
|
||||
</RootNamespace>
|
||||
<SDKPath Condition="'$(SDKPath)' == ''">C:\Program Files\XMOS\tusbaudiosdk</SDKPath>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
<Import Project="$(SDKPath)\source\tusbaudioapi_inc\tusbaudioapi_inc_vs2019.vcxitems" Label="Shared" />
|
||||
<Import Project="$(SDKPath)\source\libwn_min\_libwn_min_vs2019.vcxitems" Label="Shared" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>.\bin\$(Configuration)\$(PlatformName)\</OutDir>
|
||||
<IntDir>$(Configuration)\$(PlatformName)_$(PlatformToolset)</IntDir>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>.\bin\$(Configuration)\$(PlatformName)\</OutDir>
|
||||
<IntDir>$(Configuration)\$(PlatformName)_$(PlatformToolset)</IntDir>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_AMD64;_CONSOLE;_UNICODE;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>.;.\Win;$(SDKPath)\source\shared;$(SDKPath)\source\inc;$(SDKPath)\source\libwn_min;$(SDKPath)\source\libwtl;$(SDKPath)\source\tusbaudioapi_inc</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<PrecompiledHeaderFile />
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<UACExecutionLevel />
|
||||
<UACUIAccess />
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<PreprocessorDefinitions>_AMD64;_CONSOLE;_UNICODE;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>.;.\Win;$(SDKPath)\source\shared;$(SDKPath)\source\inc;$(SDKPath)\source\libwn_min;$(SDKPath)\source\libwtl;$(SDKPath)\source\tusbaudioapi_inc</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<PrecompiledHeaderFile />
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<UACExecutionLevel />
|
||||
<UACUIAccess />
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="usb_mixer.h" />
|
||||
<ClInclude Include="Win\global.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mixer_app.cpp" />
|
||||
<ClCompile Include="usb_mixer.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="usb_mixer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Win\global.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mixer_app.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win\usb_mixer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
718
host_usb_mixer_control/mixer_app.cpp
Normal file
718
host_usb_mixer_control/mixer_app.cpp
Normal file
@@ -0,0 +1,718 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "usb_mixer.h"
|
||||
|
||||
#define MIXER_UNIT_DISPLAY_VALUE 2
|
||||
#define MIXER_UNIT_DISPLAY_MIN 3
|
||||
#define MIXER_UNIT_DISPLAY_MAX 4
|
||||
#define MIXER_UNIT_DISPLAY_RES 5
|
||||
|
||||
// TODO
|
||||
// res, min, max
|
||||
|
||||
int mixer_init(void)
|
||||
{
|
||||
/* Open the connection to the USB mixer */
|
||||
if (usb_mixer_connect() == USB_MIXER_FAILURE)
|
||||
{
|
||||
return USB_MIXER_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
int mixer_deinit(void) {
|
||||
// Close the connection to the USB mixer
|
||||
if (usb_mixer_disconnect() == USB_MIXER_FAILURE) {
|
||||
return USB_MIXER_FAILURE;
|
||||
}
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
int mixer_display(unsigned int mixer_index, unsigned int type) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
int num_inputs = usb_mixer_get_num_inputs(mixer_index);
|
||||
int num_outputs = usb_mixer_get_num_outputs(mixer_index);
|
||||
|
||||
|
||||
printf("\n");
|
||||
switch (type) {
|
||||
case MIXER_UNIT_DISPLAY_VALUE:
|
||||
//mixer_update_all_values(mixer_index);
|
||||
printf(" Mixer Values (%d)\n", mixer_index);
|
||||
printf(" ----------------\n\n");
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MIN:
|
||||
printf(" Mixer Ranges Min (%d)\n", mixer_index);
|
||||
printf(" --------------------\n\n");
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MAX:
|
||||
printf(" Mixer Ranges Max (%d)\n", mixer_index);
|
||||
printf(" --------------------\n\n");
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_RES:
|
||||
printf(" Mixer Ranges Res (%d)\n", mixer_index);
|
||||
printf(" --------------------\n\n");
|
||||
break;
|
||||
default:
|
||||
return USB_MIXER_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" \t\t\t");
|
||||
printf("Mixer Outputs\n");
|
||||
printf("\t\t ");
|
||||
for (i = 0; i < num_outputs; i++) {
|
||||
printf(" %d", i+1);
|
||||
}
|
||||
printf("\n");
|
||||
for (i = 0; i < num_inputs; i++) {
|
||||
printf(" %-20s", usb_mixer_get_input_name(mixer_index,i));
|
||||
for (j = 0; j < num_outputs; j++) {
|
||||
switch (type) {
|
||||
case MIXER_UNIT_DISPLAY_VALUE:
|
||||
{
|
||||
double mixNodeVal = usb_mixer_get_value(mixer_index, (i*num_outputs)+j);
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
|
||||
if (mixNodeVal <= -127.996)// todo shoud be < min
|
||||
{
|
||||
printf("\t%3d:[ %s ]", nodeid,"-inf");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t%3d:[%08.03f]", nodeid, mixNodeVal);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MIN:
|
||||
{
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_min(mixer_index, (i*num_outputs)+j)) ;
|
||||
}
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MAX:
|
||||
{
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_max(mixer_index, (i*num_outputs)+j)) ;
|
||||
}
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_RES:
|
||||
{
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_res(mixer_index, (i*num_outputs)+j)) ;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return USB_MIXER_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
/* Displays basic mixer information */
|
||||
int mixer_display_info(void)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
int num_mixers = usb_mixer_get_num_mixers();
|
||||
|
||||
printf("\n");
|
||||
printf(" Mixer Info\n");
|
||||
printf(" ----------\n\n");
|
||||
printf(" Mixers : %d\n\n", num_mixers);
|
||||
|
||||
for (i = 0; i < num_mixers; i++)
|
||||
{
|
||||
int num_inputs = usb_mixer_get_num_inputs(i);
|
||||
int num_outputs = usb_mixer_get_num_outputs(i);
|
||||
|
||||
|
||||
printf(" Mixer %d\n", i);
|
||||
printf(" -------\n");
|
||||
|
||||
printf(" Inputs : %d\n"
|
||||
" Outputs : %d\n\n", num_inputs, num_outputs);
|
||||
|
||||
printf(" Mixer Output Labels:\n");
|
||||
for(int j = 0; j < num_outputs; j++)
|
||||
{
|
||||
printf(" %d: %s\n", j,usb_mixer_get_output_name(i,j));
|
||||
}
|
||||
|
||||
//printf("\n Selectable Inputs (%d): \n", usb_mixsel_get_input_count(i));
|
||||
//for(int j = 0; j < usb_mixsel_get_input_count(i); j++)
|
||||
//{
|
||||
// printf(" %d: %s\n", j, usb_mixsel_get_input_string(i,j));
|
||||
//}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
void display_available_mixer_sources(int mixIndex)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Available Mixer Sources (%d)\n", mixIndex);
|
||||
printf(" -------------------------\n\n");
|
||||
|
||||
for(int j = 0; j < usb_mixsel_get_input_count(mixIndex); j++)
|
||||
{
|
||||
printf(" %d: %s\n", j, usb_mixsel_get_input_string(mixIndex,j));
|
||||
}
|
||||
}
|
||||
|
||||
/* Gets the current mixer inputs from the device an displays them */
|
||||
void display_mixer_sources(int mixerIndex)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Current Mixer Sources (%d)\n", mixerIndex);
|
||||
printf(" -------------------------\n\n");
|
||||
|
||||
/* Note, mixSel output cound and mixer input chan count should be the same! */
|
||||
printf(" Number of mixer sources: %d\n", usb_mixsel_get_output_count(mixerIndex));
|
||||
|
||||
/* Get the current channel number for every mixer input */
|
||||
for(int i = 0; i < usb_mixsel_get_output_count(mixerIndex); i++)
|
||||
{
|
||||
int inputChan = (int)usb_mixsel_get_state(mixerIndex, i);
|
||||
char *str = usb_mixer_get_input_name(mixerIndex,inputChan);
|
||||
printf(" Mixer input %d: Source chan id: %d (%s)\n", i, inputChan, str);
|
||||
}
|
||||
}
|
||||
|
||||
/* set mixer source */
|
||||
void set_mixer_source(unsigned mixerIndex, unsigned dst, unsigned src)
|
||||
{
|
||||
usb_mixsel_set_state(mixerIndex, dst, src);
|
||||
|
||||
/* String lookup */
|
||||
char *str = usb_mixer_get_input_name(mixerIndex, dst);
|
||||
int state = usb_mixsel_get_state(mixerIndex, dst);
|
||||
|
||||
printf("\n Set mixer(%d) input %d to device input %d (%s)\n", mixerIndex, dst, state, str);
|
||||
}
|
||||
|
||||
void display_aud_channel_map()
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Audio Output Channel Map\n");
|
||||
printf(" ------------------------\n\n");
|
||||
|
||||
for (int i=0;i<usb_get_aud_channel_map_num_outputs();i++)
|
||||
{
|
||||
int x = usb_get_aud_channel_map(i);
|
||||
printf("%d (DEVICE OUT - %s) source is ",i, usb_get_aud_channel_map_name(i));
|
||||
|
||||
switch (usb_get_aud_channel_map_type(x))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf(" %d (DAW OUT - %s)\n",x,usb_get_aud_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",x,usb_get_aud_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",x,usb_get_aud_channel_map_name(x));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void display_daw_channel_map()
|
||||
{
|
||||
printf("\n");
|
||||
printf(" DAW Output To Host Channel Map\n");
|
||||
printf(" ------------------------\n\n");
|
||||
|
||||
for (int i=0;i<usb_get_usb_channel_map_num_outputs();i++)
|
||||
{
|
||||
int x = usb_get_usb_channel_map(i);
|
||||
printf("%d (DAW IN - %s) source is ",i, usb_get_usb_channel_map_name(i + usb_get_aud_channel_map_num_outputs()));
|
||||
|
||||
switch (usb_get_usb_channel_map_type(x))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf(" %d (DAW OUT - %s)\n",x,usb_get_usb_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",x,usb_get_usb_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",x,usb_get_usb_channel_map_name(x));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display_aud_channel_map_sources(void)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Audio Output Channel Map Source List\n");
|
||||
printf(" ------------------------------------\n\n");
|
||||
for (int i=0;i<usb_get_aud_channel_map_num_inputs();i++) {
|
||||
switch (usb_get_aud_channel_map_type(i))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf("%d (DAW OUT - %s)\n",i,usb_get_aud_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",i,usb_get_aud_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",i,usb_get_aud_channel_map_name(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display_daw_channel_map_sources(void)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" DAW Output to Host Channel Map Source List\n");
|
||||
printf(" ------------------------------------------\n\n");
|
||||
for (int i=0;i<usb_get_usb_channel_map_num_inputs();i++) {
|
||||
switch (usb_get_usb_channel_map_type(i))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf("%d (DAW OUT - %s)\n",i,usb_get_usb_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",i,usb_get_usb_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",i,usb_get_usb_channel_map_name(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int usb_audio_request_get(unsigned bRequest, unsigned cs, unsigned cn, unsigned unitId, unsigned char *data)
|
||||
{
|
||||
char reqStr[] = "Custom";
|
||||
|
||||
if(bRequest == CUR)
|
||||
{
|
||||
strcpy(reqStr, "CUR");
|
||||
}
|
||||
else if(bRequest == RANGE)
|
||||
{
|
||||
strcpy(reqStr, "RANGE");
|
||||
}
|
||||
else if(bRequest == MEM)
|
||||
{
|
||||
strcpy(reqStr, "MEM");
|
||||
}
|
||||
|
||||
printf("Performing class GET request to Audio Interface:\n\
|
||||
bRequest: 0x%02x (%s)\n\
|
||||
wValue: 0x%04x (Control Sel: %d, Channel Number: %d)\n\
|
||||
wIndex: 0x%04x (Interface: 0, Entity: %d)\n\
|
||||
\n", bRequest, reqStr, (cs<<8)|cn, cs, cn, unitId<<8, unitId);
|
||||
|
||||
return usb_audio_class_get(bRequest, cs, cn, unitId, 64, data);
|
||||
}
|
||||
|
||||
int usb_audio_request_set(unsigned bRequest, unsigned cs, unsigned cn, unsigned unitId,
|
||||
unsigned char *data, int datalength)
|
||||
{
|
||||
char reqStr[] = "Custom";
|
||||
|
||||
if(bRequest == CUR)
|
||||
{
|
||||
strcpy(reqStr, "CUR");
|
||||
}
|
||||
else if(bRequest == RANGE)
|
||||
{
|
||||
strcpy(reqStr, "RANGE");
|
||||
}
|
||||
{
|
||||
strcpy(reqStr, "MEM");
|
||||
}
|
||||
|
||||
printf("Performing class SET request to Audio Interface:\n\
|
||||
bRequest: 0x%02x (%s)\n\
|
||||
wValue: 0x%04x (Control Sel: %d, Channel Number: %d)\n\
|
||||
wIndex: 0x%04x (Interface: 0, Entity: %d)\n\
|
||||
\n", bRequest, reqStr, (cs<<8)|cn, cs, cn, unitId<<8, unitId);
|
||||
|
||||
return usb_audio_class_set(bRequest, cs, cn, unitId, datalength, data);
|
||||
}
|
||||
|
||||
|
||||
int usb_audio_memreq_get(unsigned unitId, unsigned offset, unsigned char *data)
|
||||
{
|
||||
/* Mem requests dont have CS/CN, just an offset.. */
|
||||
return usb_audio_request_get(MEM, (offset>>8), offset&0xff, unitId, data);
|
||||
}
|
||||
|
||||
void print_levels(const char* levelTitle, unsigned char* levels, int levelBytes)
|
||||
{
|
||||
unsigned levelCount = levelBytes/2;
|
||||
unsigned short* levelData = (unsigned short*) levels;
|
||||
|
||||
printf("\n %s Level Data\n"
|
||||
" ----------------------\n\n"
|
||||
"%d bytes (%d channels) returned:\n"
|
||||
, levelTitle, levelBytes, levelCount);
|
||||
|
||||
for(int i = 0; i<levelCount; i++)
|
||||
{
|
||||
printf("%s %d: 0x%04x\n", levelTitle, i,levelData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mixer_display_usage(void) {
|
||||
fprintf(stderr, "Usage :\n");
|
||||
fprintf(stderr,
|
||||
" --display-info\n"
|
||||
" --display-mixer-nodes mixer_id\n"
|
||||
" --display-min mixer_id\n"
|
||||
" --display-max mixer_id\n"
|
||||
" --display-res mixer_id\n"
|
||||
" --set-value mixer_id, mixer_node, value\n"
|
||||
" --get-value mixer_id, mixer_node\n"
|
||||
"\n"
|
||||
" --set-mixer-source mixer_id dst channel_id, src_channel_id\n"
|
||||
" --display-current-mixer-sources mixer_id\n"
|
||||
" --display-available-mixer-sources mixer_id\n"
|
||||
"\n"
|
||||
" --set-aud-channel-map dst_channel_id, src_channel_id\n"
|
||||
" --display-aud-channel-map \n"
|
||||
" --display-aud-channel-map-sources\n"
|
||||
" --set-daw-channel-map dst_channel_id, src_channel_id\n"
|
||||
" --display-daw-channel-map \n"
|
||||
" --display-daw-channel-map-sources\n"
|
||||
"\n"
|
||||
" --get-mixer-levels-input mixer_id\n"
|
||||
" --get-mixer-levels-output mixer_id\n"
|
||||
" --vendor-audio-request-get bRequest, ControlSelector, ChannelNumber, UnitId\n"
|
||||
" --vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],...\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void usage_error()
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed. See --help\n");
|
||||
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
|
||||
unsigned int mixer_index = 0;
|
||||
unsigned int result = 0;
|
||||
|
||||
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "ERROR :: No options passed to mixer application\n");
|
||||
mixer_display_usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "--help") == 0) {
|
||||
mixer_display_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mixer_init() != USB_MIXER_SUCCESS) {
|
||||
fprintf(stderr, "ERROR :: Cannot connect\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "--display-info") == 0)
|
||||
{
|
||||
mixer_display_info();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-mixer-nodes") == 0)
|
||||
{
|
||||
if (argv[2])
|
||||
{
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
||||
} else if (strcmp(argv[1], "--display-mixer-nodes") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
||||
} else if (strcmp(argv[1], "--display-min") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MIN);
|
||||
} else if (strcmp(argv[1], "--display-max") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MAX);
|
||||
} else if (strcmp(argv[1], "--display-res") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_RES);
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-value") == 0) {
|
||||
unsigned int mixer_unit = 0;
|
||||
double value = 0;
|
||||
if (argc < 5) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_index = atoi(argv[2]);
|
||||
mixer_unit = atoi(argv[3]);
|
||||
if (strcmp(argv[4],"-inf")==0)
|
||||
value = -128;
|
||||
else
|
||||
value = atof(argv[4]);
|
||||
|
||||
usb_mixer_set_value(mixer_index, mixer_unit, value);
|
||||
} else if (strcmp(argv[1], "--get-value") == 0) {
|
||||
unsigned int mixer_unit = 0;
|
||||
double result = 0;
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_index = atoi(argv[2]);
|
||||
mixer_unit = atoi(argv[3]);
|
||||
|
||||
result = usb_mixer_get_value(mixer_index, mixer_unit);
|
||||
if (result <= -127.996)
|
||||
printf("%s\n", "-inf");
|
||||
else
|
||||
printf("%g\n",result);
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-current-mixer-sources") == 0)
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
display_mixer_sources(atoi(argv[2]));
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-available-mixer-sources") == 0)
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
display_available_mixer_sources(atoi(argv[2]));
|
||||
}
|
||||
else if(strcmp(argv[1], "--set-mixer-source") == 0)
|
||||
{
|
||||
if(argc < 5)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
set_mixer_source(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-aud-channel-map") == 0)
|
||||
{
|
||||
/* Display the channel mapping to the devices audio outputs */
|
||||
display_aud_channel_map();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-aud-channel-map-sources") == 0)
|
||||
{
|
||||
display_aud_channel_map_sources();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-daw-channel-map") == 0)
|
||||
{
|
||||
/* Display the channel mapping to the devices DAW output to host */
|
||||
display_daw_channel_map();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-daw-channel-map-sources") == 0)
|
||||
{
|
||||
display_daw_channel_map_sources();
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-aud-channel-map") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned int src = 0;
|
||||
if (argc != 4)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
dst = atoi(argv[2]);
|
||||
src = atoi(argv[3]);
|
||||
|
||||
usb_set_aud_channel_map(dst, src);
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-daw-channel-map") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned int src = 0;
|
||||
if (argc != 4)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
dst = atoi(argv[2]);
|
||||
src = atoi(argv[3]);
|
||||
|
||||
usb_set_usb_channel_map(dst, src);
|
||||
}
|
||||
else if(strcmp(argv[1], "--get-mixer-levels-input") == 0 ||
|
||||
strcmp(argv[1],"--get-mixer-levels-output") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned char levels[64];
|
||||
int datalength = 0;
|
||||
int offset = 0;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strcmp(argv[1],"--get-mixer-levels-output") == 0)
|
||||
offset = 1;
|
||||
|
||||
for(int i = 0; i < 64; i++)
|
||||
levels[i] = 0;
|
||||
|
||||
dst = atoi(argv[2]);
|
||||
|
||||
/* Mem request to mixer with offset of 0 gives input levels */
|
||||
datalength = usb_mixer_mem_get(dst, offset, levels);
|
||||
|
||||
if(datalength < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR in control request: %d\n", datalength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(offset)
|
||||
print_levels("Mixer Output", levels, datalength);
|
||||
else
|
||||
print_levels("Mixer Input", levels, datalength);
|
||||
|
||||
}
|
||||
else if(strcmp(argv[1], "--vendor-audio-request-get") == 0)
|
||||
{
|
||||
unsigned int bRequest = 0;
|
||||
unsigned int cs = 0;
|
||||
unsigned int cn = 0;
|
||||
unsigned int unitId = 0;
|
||||
int datalength = 0;
|
||||
unsigned char data[64];
|
||||
|
||||
if(argc < 6)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 64; i++)
|
||||
data[i] = 0;
|
||||
|
||||
bRequest = atoi(argv[2]);
|
||||
cs = atoi(argv[3]);
|
||||
cn = atoi(argv[4]);
|
||||
unitId = atoi(argv[5]);
|
||||
|
||||
/* Do request */
|
||||
datalength = usb_audio_request_get(bRequest, cs, cn, unitId, data);
|
||||
|
||||
/* Print result */
|
||||
if(datalength < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR in control request: %d\n", datalength);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Response (%d bytes):\n", datalength);
|
||||
for(int i = 0; i < datalength; i++)
|
||||
printf("0x%02x\n" ,data[i]);
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1], "--vendor-audio-request-set") == 0)
|
||||
{
|
||||
|
||||
unsigned int bRequest = 0;
|
||||
unsigned int cs = 0;
|
||||
unsigned int cn = 0;
|
||||
unsigned int unitId = 0;
|
||||
unsigned char data[64];
|
||||
|
||||
for(int i=0; i<64; i++)
|
||||
{
|
||||
data[i] = 0;
|
||||
}
|
||||
|
||||
if(argc < 7)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed - no data passed\n");
|
||||
return -1;
|
||||
}
|
||||
bRequest = atoi(argv[2]);
|
||||
cs = atoi(argv[3]);
|
||||
cn = atoi(argv[4]);
|
||||
unitId = atoi(argv[5]);
|
||||
|
||||
/* Get data */
|
||||
for(int i=0; i < argc-6; i++)
|
||||
{
|
||||
data[i] = atoi(argv[i+6]);
|
||||
}
|
||||
|
||||
result = usb_audio_request_set(bRequest, cs, cn, unitId, data, argc-6);
|
||||
|
||||
if(result < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: Error detected in Set request: %d\n", result);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR :: Invalid option passed to mixer application\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_deinit();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
1
host_usb_mixer_control/setup.sh
Normal file
1
host_usb_mixer_control/setup.sh
Normal file
@@ -0,0 +1 @@
|
||||
export DYLD_LIBRARY_PATH=$PWD/OSX:$DYLD_LIBRARY_PATH
|
||||
1042
host_usb_mixer_control/usb_mixer.cpp
Normal file
1042
host_usb_mixer_control/usb_mixer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
108
host_usb_mixer_control/usb_mixer.h
Normal file
108
host_usb_mixer_control/usb_mixer.h
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#define USB_MIXER_SUCCESS 0
|
||||
#define USB_MIXER_FAILURE -1
|
||||
|
||||
#define USB_MIXERS 1
|
||||
#define USB_MIXER_INPUTS 18
|
||||
#define USB_MIXER_OUTPUTS 8
|
||||
#define USB_MAX_CHANNEL_MAP_SIZE 40
|
||||
#define USB_MIXER_MAX_NAME_LEN 64
|
||||
|
||||
enum usb_chan_type {
|
||||
USB_CHAN_OUT=0,
|
||||
USB_CHAN_IN=1,
|
||||
USB_CHAN_MIXER=2
|
||||
};
|
||||
|
||||
/* A.14 Audio Class-Specific Request Codes */
|
||||
#define REQUEST_CODE_UNDEFINED 0x00
|
||||
#define CUR (1)
|
||||
#define RANGE (2)
|
||||
#define MEM (3)
|
||||
|
||||
int usb_mixer_connect();
|
||||
int usb_mixer_disconnect();
|
||||
|
||||
/* MIXER UNIT(s) INTERFACE */
|
||||
|
||||
/* Returns total number of mixers in device */
|
||||
int usb_mixer_get_num_mixers();
|
||||
|
||||
/* Returns number of inputs and outputs for a selected mixer */
|
||||
int usb_mixer_get_layout(unsigned int mixer, unsigned int *inputs, unsigned int *outputs);
|
||||
|
||||
/* Returns the name for a selected mixer input */
|
||||
char *usb_mixer_get_input_name(unsigned int mixer, unsigned int input);
|
||||
|
||||
/* Returns the name for a selected mixer output */
|
||||
char *usb_mixer_get_output_name(unsigned int mixer, unsigned int output);
|
||||
|
||||
/* Returns the current value of a selected mixer unit */
|
||||
double usb_mixer_get_value(unsigned int mixer, unsigned int mixer_unit);
|
||||
|
||||
/* Sets the current value for a selected mixer unit */
|
||||
int usb_mixer_set_value(unsigned int mixer, unsigned int mixer_unit, double val);
|
||||
|
||||
/* Returns the range values for a selected mixer unit */
|
||||
int usb_mixer_get_range(unsigned int mixer, unsigned int mixer_unit, double *min, double *max, double *res);
|
||||
|
||||
/* Returns the number of bytes read from a mem request, data is stored in data */
|
||||
int usb_mixer_mem_get(unsigned int mixer, unsigned offset, unsigned char *data);
|
||||
|
||||
|
||||
/* INPUT / OUTPUT / MIXER MAPPING UNIT INTERFACE */
|
||||
|
||||
/* Get the number of selectable inputs */
|
||||
int usb_mixsel_get_input_count(unsigned int mixer);
|
||||
|
||||
/* Get the string of a input */
|
||||
char *usb_mixsel_get_input_string(unsigned int mixer, unsigned int channel);
|
||||
|
||||
int usb_mixsel_get_output_count(unsigned int mixer);
|
||||
|
||||
int usb_mixer_get_num_outputs(unsigned int mixer);
|
||||
|
||||
int usb_mixer_get_num_inputs(unsigned int mixer);
|
||||
|
||||
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);
|
||||
|
||||
int usb_set_usb_channel_map(int channel, int val);
|
||||
|
||||
|
||||
/* Get the current map for a specified input / output / mixer channel */
|
||||
int usb_get_usb_channel_map(int channel);
|
||||
int usb_get_aud_channel_map(int channel);
|
||||
|
||||
/* Maps an input / output / mixer channel to another input / output / mixer channel */
|
||||
int usb_set_aud_channel_map(int channel, int val);
|
||||
int usb_set_usb_channel_map(int channel, int val);
|
||||
|
||||
/* Gets the name of a specified channel */
|
||||
char *usb_get_aud_channel_map_name(int channel);
|
||||
char *usb_get_usb_channel_map_name(int channel);
|
||||
|
||||
/* Get the type of a channel map */
|
||||
enum usb_chan_type usb_get_aud_channel_map_type(int channel);
|
||||
enum usb_chan_type usb_get_usb_channel_map_type(int channel);
|
||||
|
||||
int usb_get_aud_channel_map_num_outputs();
|
||||
int usb_get_usb_channel_map_num_outputs();
|
||||
|
||||
int usb_get_aud_channel_map_num_inputs();
|
||||
int usb_get_usb_channel_map_num_inputs();
|
||||
|
||||
/* CUSTOM/GENERIC AUDIO CLASS REQUESTS */
|
||||
|
||||
int usb_audio_class_get(unsigned char bRequest, unsigned char cs, unsigned char cn, unsigned short unitID, unsigned short wLength, unsigned char *data);
|
||||
|
||||
int usb_audio_class_set(unsigned char bRequest, unsigned char cs, unsigned char cn, unsigned short unitID, unsigned short wLength, unsigned char *data);
|
||||
|
||||
double usb_mixer_get_res(unsigned int mixer, unsigned int nodeId);
|
||||
|
||||
double usb_mixer_get_min(unsigned int mixer, unsigned int nodeId) ;
|
||||
|
||||
double usb_mixer_get_max(unsigned int mixer, unsigned int nodeId) ;
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2022 XMOS LIMITED.
|
||||
// Copyright 2017-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_H_
|
||||
#define _XUA_H_
|
||||
@@ -7,14 +7,14 @@
|
||||
|
||||
#include "xua_conf_full.h"
|
||||
|
||||
#if __XC__ || __STDC__
|
||||
#ifndef __ASSEMBLER__
|
||||
#include "xua_audiohub.h"
|
||||
#include "xua_endpoint0.h"
|
||||
#include "xua_buffer.h"
|
||||
#include "xua_mixer.h"
|
||||
#endif
|
||||
|
||||
#if __XC__
|
||||
#ifdef __XC__
|
||||
#include "xua_clocking.h"
|
||||
#include "xua_midi.h"
|
||||
#if XUA_NUM_PDM_MICS > 0
|
||||
|
||||
@@ -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.
|
||||
#ifndef __XUA_AUDIOHUB_H__
|
||||
#define __XUA_AUDIOHUB_H__
|
||||
#ifndef _XUA_AUDIOHUB_H_
|
||||
#define _XUA_AUDIOHUB_H_
|
||||
|
||||
#if __XC__
|
||||
#ifdef __XC__
|
||||
|
||||
#include "xccompat.h"
|
||||
#include "xs1.h"
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "dfu_interface.h"
|
||||
#endif
|
||||
|
||||
#include "xua_clocking.h"
|
||||
|
||||
/** The audio driver thread.
|
||||
*
|
||||
* This function drives I2S ports and handles samples to/from other digital
|
||||
@@ -34,6 +36,8 @@
|
||||
*
|
||||
* \param p_i2s_adc Nullable array of ports for I2S data input lines
|
||||
*
|
||||
* \param i_SoftPll Interface to software PLL task
|
||||
*
|
||||
* \param c_spdif_tx Channel connected to S/PDIF transmiter core from lib_spdif
|
||||
*
|
||||
* \param c_dig Channel connected to the clockGen() thread for
|
||||
@@ -47,6 +51,9 @@ void XUA_AudioHub(chanend ?c_aud,
|
||||
buffered _XUA_CLK_DIR port:32 ?p_bclk,
|
||||
buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
|
||||
buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC]
|
||||
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
|
||||
, client interface SoftPll_if i_SoftPll
|
||||
#endif
|
||||
#if (XUA_SPDIF_TX_EN) || defined(__DOXYGEN__)
|
||||
, chanend c_spdif_tx
|
||||
#endif
|
||||
@@ -63,21 +70,28 @@ void XUA_AudioHub(chanend ?c_aud,
|
||||
|
||||
void SpdifTxWrapper(chanend c_spdif_tx);
|
||||
|
||||
/* These functions must be implemented for the CODEC/ADC/DAC arrangement of a specific design */
|
||||
|
||||
/* Any required clocking and CODEC initialisation - run once at start up */
|
||||
/* TODO Provide default implementation of this */
|
||||
void AudioHwInit();
|
||||
|
||||
/* Configure audio hardware (clocking, CODECs etc) for a specific mClk/Sample frquency - run on every sample frequency change */
|
||||
/* TODO Provide default implementation of this */
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode,
|
||||
unsigned sampRes_DAC, unsigned sampRes_ADC);
|
||||
|
||||
#endif // __XC__
|
||||
|
||||
void UserBufferManagementInit();
|
||||
|
||||
/**
|
||||
* @brief User buffer management code
|
||||
*
|
||||
* This function is called at the sample rate of the USB Audio stack (e.g,. 48 kHz) and between the two parameter arrays
|
||||
* contain a full multi-channel audio-frame. The first array carries all the data that has been received from the USB host
|
||||
* and is to be presented to the audio interfaces. The second array carries all the data received from the interfaces and
|
||||
* is to be presented to the USB host. The user can chose to intercept and overwrite the samples stored in these arrays.
|
||||
*
|
||||
* \param sampsFromUsbToAudio Samples received from USB host and to be presented to audio interfaces
|
||||
*
|
||||
* \param sampsFromAudioToUsb Samples received from the audio interfaces and to be presented to the USB host
|
||||
*/
|
||||
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
|
||||
|
||||
#endif // __XUA_AUDIOHUB_H__
|
||||
/**
|
||||
* @brief User buffer managment init code
|
||||
*
|
||||
* This function is called once, before the first call to UserBufferManagement(), and can be used to initialise any
|
||||
* related user state
|
||||
*/
|
||||
void UserBufferManagementInit();
|
||||
|
||||
#endif // _XUA_AUDIOHUB_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef __XUA_BUFFER_H__
|
||||
#define __XUA_BUFFER_H__
|
||||
#ifndef _XUA_BUFFER_H_
|
||||
#define _XUA_BUFFER_H_
|
||||
|
||||
#if __XC__
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
* \param p_off_mclk A port that is clocked of the MCLK input (not the MCLK input itself)
|
||||
* \param c_aud Channel connected to XUA_AudioHub() core
|
||||
* \param i_pll_ref Interface to task that toggles reference pin to CS2100
|
||||
* \param c_swpll_update Channel connected to software PLL task. Expects master clock counts based on USB frames.
|
||||
*/
|
||||
void XUA_Buffer(
|
||||
chanend c_aud_out,
|
||||
@@ -51,8 +52,13 @@ void XUA_Buffer(
|
||||
, chanend c_hid
|
||||
#endif
|
||||
, chanend c_aud
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOXYGEN__)
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__)
|
||||
#if (!XUA_USE_APP_PLL) || defined(__DOXYGEN__)
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
|
||||
, chanend c_swpll_update
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
|
||||
@@ -81,10 +87,16 @@ void XUA_Buffer_Ep(chanend c_aud_out,
|
||||
#ifdef CHAN_BUFF_CTRL
|
||||
, chanend c_buff_ctrl
|
||||
#endif
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOXYGEN__)
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOYXGEN__)
|
||||
#if (!XUA_USE_APP_PLL) || defined(__DOXYGEN__)
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#if (XUA_USE_APP_PLL) || defined(__DOXYGEN__)
|
||||
, chanend c_swpll_update
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
);
|
||||
|
||||
|
||||
/** Manage the data transfer between the USB audio buffer and the
|
||||
* Audio I/O driver.
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#ifndef _CLOCKING_H_
|
||||
#define _CLOCKING_H_
|
||||
|
||||
#include <xs1.h>
|
||||
#include "xua.h"
|
||||
|
||||
interface pll_ref_if
|
||||
{
|
||||
@@ -28,5 +29,46 @@ void PllRefPinTask(server interface pll_ref_if i_pll_ref, out port p_sync);
|
||||
interrupts
|
||||
*/
|
||||
void clockGen(streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interface pll_ref_if i_pll_ref, chanend c_audio, chanend c_clk_ctl, chanend c_clk_int);
|
||||
|
||||
#if (XUA_USE_APP_PLL)
|
||||
struct SoftPllState
|
||||
{
|
||||
// Count we expect on MCLK port timer at SW PLL check point.
|
||||
// Note, we expect wrapping so this is essentiually a modulus
|
||||
unsigned expectedClkMod;
|
||||
unsigned initialSetting;
|
||||
unsigned initialErrorMult;
|
||||
unsigned setting;
|
||||
|
||||
int phaseError;
|
||||
|
||||
/* Integrated phase error */
|
||||
int phaseErrorInt;
|
||||
|
||||
/* IIR filter */
|
||||
int iir_y;
|
||||
|
||||
/* Delta sigma modulator */
|
||||
unsigned ds_in;
|
||||
int ds_x1;
|
||||
int ds_x2;
|
||||
int ds_x3;
|
||||
};
|
||||
|
||||
void AppPllEnable(tileref tile, int mclkFreq_hz);
|
||||
void AppPllGetSettings(int clkFreq_hz, struct SoftPllState &pllState);
|
||||
void AppPllUpdate(tileref tile, unsigned short mclk_pt, struct SoftPllState &pllState);
|
||||
|
||||
interface SoftPll_if
|
||||
{
|
||||
void init(int mclk_hz);
|
||||
};
|
||||
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
|
||||
[[distributable]]
|
||||
#endif
|
||||
void XUA_SoftPll(tileref tile, server interface SoftPll_if i_softPll, chanend c_update);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -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.
|
||||
/*
|
||||
* @brief Defines relating to device configuration and customisation of lib_xua
|
||||
@@ -11,7 +11,9 @@
|
||||
#include "xua_conf.h"
|
||||
#endif
|
||||
|
||||
/* Default tile arrangement */
|
||||
/*
|
||||
* Tile arrangement defines
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Location (tile) of audio I/O. Default: 0
|
||||
@@ -55,12 +57,9 @@
|
||||
#define PLL_REF_TILE AUDIO_IO_TILE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Disable USB functionalty just leaving AudioHub
|
||||
/*
|
||||
* Channel based defines
|
||||
*/
|
||||
#ifndef XUA_USB_EN
|
||||
#define XUA_USB_EN (1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of input channels (device to host). Default: NONE (Must be defined by app)
|
||||
@@ -79,7 +78,18 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of DSD output channels. Default: 0 (disabled)
|
||||
* @brief Number of PDM microphones in the design.
|
||||
*
|
||||
* Default: 0
|
||||
*/
|
||||
#ifndef XUA_NUM_PDM_MICS
|
||||
#define XUA_NUM_PDM_MICS (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of DSD output channels.
|
||||
*
|
||||
* Default: 0 (disabled)
|
||||
*/
|
||||
#if defined(DSD_CHANS_DAC) && (DSD_CHANS_DAC != 0)
|
||||
#if defined(NATIVE_DSD) && (NATIVE_DSD == 0)
|
||||
@@ -91,9 +101,41 @@
|
||||
#define DSD_CHANS_DAC 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of I2S channesl to DAC/CODEC. Must be a multiple of 2.
|
||||
*
|
||||
* Default: NONE (Must be defined by app)
|
||||
*/
|
||||
#ifndef I2S_CHANS_DAC
|
||||
#error I2S_CHANS_DAC not defined
|
||||
#define I2S_CHANS_DAC 2 /* Define anyway for doxygen */
|
||||
#else
|
||||
#define I2S_WIRES_DAC (I2S_CHANS_DAC / I2S_CHANS_PER_FRAME)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of I2S channels from ADC/CODEC. Must be a multiple of 2.
|
||||
*
|
||||
* Default: NONE (Must be defined by app)
|
||||
*/
|
||||
#ifndef I2S_CHANS_ADC
|
||||
#error I2S_CHANS_ADC not defined
|
||||
#define I2S_CHANS_ADC 2 /* Define anyway for doxygen */
|
||||
#else
|
||||
#define I2S_WIRES_ADC (I2S_CHANS_ADC / I2S_CHANS_PER_FRAME)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Defines relating to the interface to external audio hardware i.e. DAC/ADC
|
||||
*/
|
||||
|
||||
#define XUA_PCM_FORMAT_I2S (0)
|
||||
#define XUA_PCM_FORMAT_TDM (1)
|
||||
|
||||
/**
|
||||
* @brief Format of PCM audio interface. Should be set to XUA_PCM_FORMAT_I2S or XUA_PCM_FORMAT_TDM
|
||||
*
|
||||
* Default: XUA_PCM_FORMAT_I2S
|
||||
*/
|
||||
#ifdef XUA_PCM_FORMAT
|
||||
#if (XUA_PCM_FORMAT != XUA_PCM_FORMAT_I2S) && (XUA_PCM_FORMAT != XUA_PCM_FORMAT_TDM)
|
||||
#error Bad value for XUA_PCM_FORMAT
|
||||
@@ -116,30 +158,17 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Number of IS2 channesl to DAC/CODEC. Must be a multiple of 2.
|
||||
* @brief Number of bits per channel for I2S/TDM. Supported values: 16/32-bit.
|
||||
*
|
||||
* Default: NONE (Must be defined by app)
|
||||
* Default: 32 bits
|
||||
*/
|
||||
#ifndef I2S_CHANS_DAC
|
||||
#error I2S_CHANS_DAC not defined
|
||||
#define I2S_CHANS_DAC 2 /* Define anyway for doxygen */
|
||||
#else
|
||||
#define I2S_WIRES_DAC (I2S_CHANS_DAC / I2S_CHANS_PER_FRAME)
|
||||
#ifndef XUA_I2S_N_BITS
|
||||
#define XUA_I2S_N_BITS (32)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Number of I2S channels from ADC/CODEC. Must be a multiple of 2.
|
||||
*
|
||||
* Default: NONE (Must be defined by app)
|
||||
*/
|
||||
#ifndef I2S_CHANS_ADC
|
||||
#error I2S_CHANS_ADC not defined
|
||||
#define I2S_CHANS_ADC 2 /* Define anyway for doxygen */
|
||||
#else
|
||||
#define I2S_WIRES_ADC (I2S_CHANS_ADC / I2S_CHANS_PER_FRAME)
|
||||
#if (XUA_I2S_N_BITS != 16) && (XUA_I2S_N_BITS != 32)
|
||||
#error Unsupported value for XUA_I2S_N_BITS (only values 16/32 supported)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -193,22 +222,32 @@
|
||||
#define I2S_DOWNSAMPLE_CHANS_IN I2S_CHANS_ADC
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Clocking related defines
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Max supported sample frequency for device (Hz). Default: 192000
|
||||
* @brief Max supported sample frequency for device (Hz).
|
||||
*
|
||||
* Default: 192000Hz
|
||||
*/
|
||||
#ifndef MAX_FREQ
|
||||
#define MAX_FREQ (192000)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Min supported sample frequency for device (Hz). Default 44100
|
||||
* @brief Min supported sample frequency for device (Hz).
|
||||
*
|
||||
* Default: 44100Hz
|
||||
*/
|
||||
#ifndef MIN_FREQ
|
||||
#define MIN_FREQ (44100)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Master clock defines for 44100 rates (in Hz). Default: NONE (Must be defined by app)
|
||||
* @brief Master clock defines for 44100 rates (in Hz).
|
||||
*
|
||||
* Default: NONE (Must be defined by app)
|
||||
*/
|
||||
#ifndef MCLK_441
|
||||
#error MCLK_441 not defined
|
||||
@@ -216,7 +255,9 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Master clock defines for 48000 rates (in Hz). Default: NONE (Must be defined by app)
|
||||
* @brief Master clock defines for 48000 rates (in Hz).
|
||||
*
|
||||
* Default: NONE (Must be defined by app)
|
||||
*/
|
||||
#ifndef MCLK_48
|
||||
#error MCLK_48 not defined
|
||||
@@ -224,26 +265,66 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default device sample frequency. A safe default should be used. Default: MIN_FREQ
|
||||
* @brief Enable/disable the use of the secondary/application PLL for generating master-clocks.
|
||||
* Only available on xcore.ai devices.
|
||||
*
|
||||
* Default: Enabled (for xcore.ai devices)
|
||||
*/
|
||||
#ifndef XUA_USE_APP_PLL
|
||||
#if defined(__XS3A__)
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
/* Currently must use an external CS2100 device for syncing to external digital streams */
|
||||
#define XUA_USE_APP_PLL (0)
|
||||
#else
|
||||
#define XUA_USE_APP_PLL (1)
|
||||
#endif
|
||||
#else
|
||||
#define XUA_USE_APP_PLL (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default device sample frequency. A safe default should be used.
|
||||
*
|
||||
* Default: MIN_FREQ
|
||||
*/
|
||||
#ifndef DEFAULT_FREQ
|
||||
#define DEFAULT_FREQ (MIN_FREQ)
|
||||
#endif
|
||||
|
||||
/* Audio Class Defines */
|
||||
#define DEFAULT_MCLK (((DEFAULT_FREQ % 7350) == 0) ? MCLK_441 : MCLK_48)
|
||||
|
||||
/**
|
||||
* @brief USB Audio Class Version. Default: 2 (Audio Class version 2.0)
|
||||
* @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks)
|
||||
*
|
||||
* 0: XMOS is I2S master. 1: CODEC is I2s master.
|
||||
*
|
||||
* Default: 0 (XMOS is master)
|
||||
*/
|
||||
#ifndef CODEC_MASTER
|
||||
#define CODEC_MASTER (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Audio Class defines
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief USB Audio Class Version
|
||||
*
|
||||
* Default: 2 (Audio Class version 2.0)
|
||||
*/
|
||||
#ifndef AUDIO_CLASS
|
||||
#define AUDIO_CLASS 2
|
||||
#define AUDIO_CLASS (2)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Whether or not to fall back to Audio Class 1.0 in USB Full-speed. Default: 0 (Disabled)
|
||||
* @brief Enable/disable fall back to Audio Class 1.0 in USB Full-speed.
|
||||
*
|
||||
* Default: Disabled
|
||||
*/
|
||||
#ifndef AUDIO_CLASS_FALLBACK
|
||||
#define AUDIO_CLASS_FALLBACK 0 /* Default to not falling back to UAC 1 */
|
||||
#define AUDIO_CLASS_FALLBACK (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -272,14 +353,17 @@
|
||||
#error AUDIO_CLASS set to 1 and FULL_SPEED_AUDIO_2 enabled!
|
||||
#endif
|
||||
|
||||
|
||||
/* Feature defines */
|
||||
/*
|
||||
* Feature defines
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Number of PDM microphones in the design. Default: None
|
||||
* @brief Disable USB functionalty just leaving AudioHub
|
||||
*
|
||||
* Default: Enabled
|
||||
*/
|
||||
#ifndef XUA_NUM_PDM_MICS
|
||||
#define XUA_NUM_PDM_MICS (0)
|
||||
#ifndef XUA_USB_EN
|
||||
#define XUA_USB_EN (1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -432,14 +516,36 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks)
|
||||
* HID may be required in two forms: the built-in XUA-HID reports, or a
|
||||
* user-provided static HID. Some sections of code are always needed, they
|
||||
* are enclosed in XUA_OR_STATIC_HID_ENABLED; code specific to XUA-HID
|
||||
* reports are enclosed in XUA_HID_ENABLED.
|
||||
*
|
||||
* 0: XMOS is I2S master. 1: CODEC is I2s master.
|
||||
* HID_CONTROLS implies that the XUA_HID is used, and hence defines both.
|
||||
* In order to roll your own, do not enable HID_CONTROLS, but instead
|
||||
* create a file static_hid_report.h that contains the static descriptor.
|
||||
*
|
||||
* Default: 0 (XMOS is master)
|
||||
* You must also supply your own function to deal with the HID endpoint(s)
|
||||
* in this case.
|
||||
*/
|
||||
#ifndef CODEC_MASTER
|
||||
#define CODEC_MASTER (0)
|
||||
#if (HID_CONTROLS) || defined (__DOXYGEN__)
|
||||
#define XUA_HID_ENABLED (1)
|
||||
#define XUA_OR_STATIC_HID_ENABLED (1)
|
||||
#endif
|
||||
|
||||
#if defined(__static_hid_report_h_exists__)
|
||||
#define XUA_OR_STATIC_HID_ENABLED (1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable a HID OUT endpoint. Only use this if you supply your own HID control.
|
||||
*
|
||||
* 1 for enabled, 0 for disabled.
|
||||
*
|
||||
* Default 0 (Disabled)
|
||||
*/
|
||||
#ifndef HID_OUT_REQUIRED
|
||||
#define HID_OUT_REQUIRED (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -997,17 +1103,12 @@
|
||||
#define MIXER (0)
|
||||
#endif
|
||||
|
||||
/* Tidy up old ifndef usage */
|
||||
#if defined(MIXER) && (MIXER == 0)
|
||||
#undef MIXER
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of seperate mixes to perform
|
||||
*
|
||||
* Default: 8 if MIXER enabled, else 0
|
||||
*/
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
#ifndef MAX_MIX_COUNT
|
||||
#define MAX_MIX_COUNT (8)
|
||||
#endif
|
||||
@@ -1087,44 +1188,24 @@
|
||||
#define VOLUME_RES_MIXER (0x100)
|
||||
#endif
|
||||
|
||||
/* Handle out volume control in the mixer */
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && (OUT_VOLUME_IN_MIXER==0)
|
||||
#undef OUT_VOLUME_IN_MIXER
|
||||
#else
|
||||
#if defined(MIXER)
|
||||
// Disabled by default
|
||||
//#define OUT_VOLUME_IN_MIXER
|
||||
#endif
|
||||
/* Handle out volume control in the mixer - enabled by default */
|
||||
#ifndef OUT_VOLUME_IN_MIXER
|
||||
#define OUT_VOLUME_IN_MIXER (1)
|
||||
#endif
|
||||
|
||||
/* Apply out volume controls after the mix */
|
||||
#if defined(OUT_VOLUME_AFTER_MIX) && (OUT_VOLUME_AFTER_MIX==0)
|
||||
#undef OUT_VOLUME_AFTER_MIX
|
||||
#else
|
||||
#if defined(MIXER) && defined(OUT_VOLUME_IN_MIXER)
|
||||
// Enabled by default
|
||||
#define OUT_VOLUME_AFTER_MIX
|
||||
#endif
|
||||
/* Apply out volume controls after the mix. Only relevant when OUT_VOLUME_IN_MIXER enabled. Enabled by default */
|
||||
#ifndef OUT_VOLUME_AFTER_MIX
|
||||
#define OUT_VOLUME_AFTER_MIX (1)
|
||||
#endif
|
||||
|
||||
/* Handle in volume control in the mixer */
|
||||
#if defined(IN_VOLUME_IN_MIXER) && (IN_VOLUME_IN_MIXER==0)
|
||||
#undef IN_VOLUME_IN_MIXER
|
||||
#else
|
||||
#if defined(MIXER)
|
||||
/* Disabled by default */
|
||||
//#define IN_VOLUME_IN_MIXER
|
||||
#endif
|
||||
/* Handle in volume control in the mixer - disabled by default */
|
||||
#ifndef IN_VOLUME_IN_MIXER
|
||||
#define IN_VOLUME_IN_MIXER (0)
|
||||
#endif
|
||||
|
||||
/* Apply in volume controls after the mix */
|
||||
#if defined(IN_VOLUME_AFTER_MIX) && (IN_VOLUME_AFTER_MIX==0)
|
||||
#undef IN_VOLUME_AFTER_MIX
|
||||
#else
|
||||
#if defined(MIXER) && defined(IN_VOLUME_IN_MIXER)
|
||||
// Enabled by default
|
||||
#define IN_VOLUME_AFTER_MIX
|
||||
#endif
|
||||
/* Apply in volume controls after the mix. Only relebant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */
|
||||
#ifndef IN_VOLUME_AFTER_MIX
|
||||
#define IN_VOLUME_AFTER_MIX (1)
|
||||
#endif
|
||||
|
||||
/* Always enable explicit feedback EP, even when input stream is present */
|
||||
@@ -1171,7 +1252,7 @@ enum USBEndpointNumber_In
|
||||
#ifdef MIDI
|
||||
ENDPOINT_NUMBER_IN_MIDI,
|
||||
#endif
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
ENDPOINT_NUMBER_IN_HID,
|
||||
#endif
|
||||
#ifdef IAP
|
||||
@@ -1198,6 +1279,9 @@ enum USBEndpointNumber_Out
|
||||
#ifdef IAP_EA_NATIVE_TRANS
|
||||
ENDPOINT_NUMBER_OUT_IAP_EA_NATIVE_TRANS,
|
||||
#endif
|
||||
#endif
|
||||
#if XUA_OR_STATIC_HID_ENABLED && HID_OUT_REQUIRED
|
||||
ENDPOINT_NUMBER_OUT_HID,
|
||||
#endif
|
||||
XUA_ENDPOINT_COUNT_OUT /* End marker */
|
||||
};
|
||||
@@ -1219,7 +1303,8 @@ enum USBEndpointNumber_Out
|
||||
#define AUDIO_START_FROM_DFU (0x87654321)
|
||||
#define AUDIO_REBOOT_FROM_DFU (0xa5a5a5a5)
|
||||
|
||||
#define MAX_VOL (0x20000000)
|
||||
/* Result of db_to_mult(MAX_VOLUME, 8, 29) */
|
||||
#define MAX_VOLUME_MULT (0x20000000)
|
||||
|
||||
#if defined(LEVEL_METER_LEDS) && !defined(LEVEL_UPDATE_RATE)
|
||||
#define LEVEL_UPDATE_RATE (400000)
|
||||
@@ -1319,9 +1404,9 @@ enum USBEndpointNumber_Out
|
||||
/* Some defines that allow us to remove unused code */
|
||||
|
||||
/* Useful for dropping lower part of macs in volume processing... */
|
||||
#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \
|
||||
(FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || \
|
||||
(HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)
|
||||
#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \
|
||||
(((FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 1)) || \
|
||||
(((FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 2))
|
||||
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 1
|
||||
#else
|
||||
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2022 XMOS LIMITED.
|
||||
// Copyright 2017-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef __XUA_CONF_FULL_H__
|
||||
#define __XUA_CONF_FULL_H__
|
||||
#ifndef _XUA_CONF_FULL_H_
|
||||
#define _XUA_CONF_FULL_H_
|
||||
|
||||
#ifdef __xua_conf_h_exists__
|
||||
#include "xua_conf.h"
|
||||
|
||||
@@ -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.
|
||||
#ifndef _XUA_MIXER_H_
|
||||
#define _XUA_MIXER_H_
|
||||
|
||||
#include "xua.h"
|
||||
|
||||
enum mix_ctl_cmd {
|
||||
SET_SAMPLES_TO_HOST_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);
|
||||
|
||||
#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
|
||||
|
||||
@@ -8,9 +8,9 @@ An application using the USB audio framework needs to have defines set for confi
|
||||
Defaults for these defines are found in ``xua_conf_default.h``.
|
||||
|
||||
These defines should be over-ridden in an optional header file ``xua_conf.h`` file or in the ``Makefile``
|
||||
for a relevant build configuration.
|
||||
for a relevant build configuration.
|
||||
|
||||
This section fully documents all of the settable defines and their default values (where appropriate).
|
||||
This section fully documents all of the settable defines and their default values (where appropriate).
|
||||
|
||||
Code Location (tile)
|
||||
--------------------
|
||||
@@ -25,12 +25,12 @@ Code Location (tile)
|
||||
Channel Counts
|
||||
--------------
|
||||
|
||||
.. doxygendefine:: NUM_USB_CHAN_OUT
|
||||
.. doxygendefine:: NUM_USB_CHAN_IN
|
||||
.. doxygendefine:: I2S_CHANS_DAC
|
||||
.. doxygendefine:: I2S_CHANS_ADC
|
||||
.. doxygendefine:: NUM_USB_CHAN_OUT
|
||||
.. doxygendefine:: NUM_USB_CHAN_IN
|
||||
.. doxygendefine:: I2S_CHANS_DAC
|
||||
.. doxygendefine:: I2S_CHANS_ADC
|
||||
|
||||
Frequencies and Clocks
|
||||
Frequencies and Clocks
|
||||
----------------------
|
||||
|
||||
.. doxygendefine:: MAX_FREQ
|
||||
@@ -38,6 +38,7 @@ Frequencies and Clocks
|
||||
.. doxygendefine:: DEFAULT_FREQ
|
||||
.. doxygendefine:: MCLK_441
|
||||
.. doxygendefine:: MCLK_48
|
||||
.. doxygendefine:: XUA_USE_APP_PLL
|
||||
|
||||
Audio Class
|
||||
-----------
|
||||
@@ -50,6 +51,15 @@ Audio Class
|
||||
Feature Configuration
|
||||
---------------------
|
||||
|
||||
I2S/TDM
|
||||
^^^^^^^
|
||||
|
||||
.. doxygendefine:: I2S_CHANS_DAC
|
||||
.. doxygendefine:: I2S_CHANS_ADC
|
||||
.. doxygendefine:: CODEC_MASTER
|
||||
.. doxygendefine:: XUA_I2S_N_BITS
|
||||
.. doxygendefine:: XUA_PCM_FORMAT
|
||||
|
||||
MIDI
|
||||
^^^^
|
||||
|
||||
|
||||
@@ -1,74 +1,49 @@
|
||||
Required User Function Definitions
|
||||
==================================
|
||||
|newpage|
|
||||
|
||||
The following functions need to be defined by an application using the XMOS USB Audio framework.
|
||||
User Function Definitions
|
||||
=========================
|
||||
|
||||
The following functions can be defined by an application using `lib_xua`.
|
||||
|
||||
.. note:: Default, empty, implementations of these functions are provided in `lib_xua`. These are marked
|
||||
as weak symbols so the application can simply define its own version of them.
|
||||
|
||||
External Audio Hardware Configuration Functions
|
||||
-----------------------------------------------
|
||||
|
||||
.. c:function:: void AudioHwInit(chanend ?c_codec)
|
||||
The following functions can be optionally used by the design to configure external audio hardware.
|
||||
As a minimum, in most applications, it is expected that a implementation of `AudioHwConfig()` will need
|
||||
to be provided.
|
||||
|
||||
This function is called when the audio core starts after the
|
||||
device boots up and should initialize the external audio harware e.g. clocking, DAC, ADC etc
|
||||
.. doxygenfunction:: AudioHwInit
|
||||
.. doxygenfunction:: AudioHwConfig
|
||||
.. doxygenfunction:: AudioHwConfig_Mute
|
||||
.. doxygenfunction:: AudioHwConfig_UnMute
|
||||
|
||||
:param c_codec: An optional chanend that was original passed into
|
||||
:c:func:`audio` that can be used to communicate
|
||||
with other cores.
|
||||
|
||||
|
||||
.. c:function:: void AudioHwConfig(unsigned samFreq, unsigned mclk, chanend ?c_codec, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||
|
||||
This function is called when the audio core starts or changes
|
||||
sample rate. It should configure the extenal audio hardware to run at the specified
|
||||
sample rate given the supplied master clock frequency.
|
||||
|
||||
:param samFreq: The sample frequency in Hz that the hardware should be configured to (in Hz).
|
||||
|
||||
:param mclk: The master clock frequency that is required in Hz.
|
||||
|
||||
:param c_codec: An optional chanend that was original passed into
|
||||
:c:func:`audio` that can be used to communicate
|
||||
with other cores.
|
||||
|
||||
:param dsdMode: Signifies if the audio hardware should be configured for DSD operation
|
||||
|
||||
:param sampRes_DAC: The sample resolution of the DAC stream
|
||||
|
||||
:param sampRes_ADC: The sample resolution of the ADC stream
|
||||
|
||||
|
||||
Audio Streaming Functions
|
||||
-------------------------
|
||||
Audio Stream Start/Stop Functions
|
||||
---------------------------------
|
||||
|
||||
The following functions can be optionally used by the design. They can be useful for mute lines etc.
|
||||
|
||||
.. c:function:: void AudioStreamStart(void)
|
||||
.. doxygenfunction:: UserAudioStreamStart
|
||||
.. doxygenfunction:: UserAudioStreamStop
|
||||
.. doxygenfunction:: UserAudioInputStreamStart
|
||||
.. doxygenfunction:: UserAudioInputStreamStop
|
||||
.. doxygenfunction:: UserAudioOutputStreamStart
|
||||
.. doxygenfunction:: UserAudioOutputStreamStop
|
||||
|
||||
This function is called when the audio stream from device to host
|
||||
starts.
|
||||
|
||||
.. c:function:: void AudioStreamStop(void)
|
||||
|
||||
This function is called when the audio stream from device to host stops.
|
||||
|
||||
Host Active
|
||||
-----------
|
||||
Host Active Functions
|
||||
---------------------
|
||||
|
||||
The following function can be used to signal that the device is connected to a valid host.
|
||||
|
||||
This is called on a change in state.
|
||||
|
||||
.. c:function:: void AudioStreamStart(int active)
|
||||
|
||||
:param active: Indicates if the host is active or not. 1 for active else 0.
|
||||
|
||||
.. doxygenfunction:: UserHostActive
|
||||
|
||||
HID Controls
|
||||
------------
|
||||
|
||||
The following function is called when the device wishes to read physical user input (buttons etc).
|
||||
The function should write relevant HID bits into this array. The bit ordering and functionality is defined by the HID report descriptor used.
|
||||
|
||||
.. c:function:: void UserReadHIDButtons(unsigned char hidData[])
|
||||
|
||||
:param hidData: The function should write relevant HID bits into this array. The bit ordering and functionality is defined by the HID report descriptor used.
|
||||
|
||||
.. doxygenfunction:: UserHIDGetData
|
||||
|
||||
@@ -20,11 +20,11 @@ Finally, a channel for the output samples must be declared, note, this should be
|
||||
|
||||
The S/PDIF receiver should be called on the appropriate tile::
|
||||
|
||||
SpdifReceive(p_spdif_rx, c_spdif_rx, 1, clk_spd_rx);
|
||||
spdif_rx(c_spdif_rx,p_spdif_rx,clk_spd_rx,192000);
|
||||
|
||||
.. note::
|
||||
|
||||
It is recomended to use the value 1 for the ``initial_divider`` parameter
|
||||
It is recomended to use the value 192000 for the ``sample_freq_estimate`` parameter
|
||||
|
||||
With the steps above an S/PDIF stream can be captured by the xCORE. To be functionally useful the audio
|
||||
master clock must be able to synchronise to this external digital stream. Additionally, the host can be
|
||||
|
||||
@@ -23,11 +23,14 @@ The defines in :ref:`opt_i2s_defines` effect the I2S implementation.
|
||||
- The desired number of input channels via I2S (0 for disabled)
|
||||
- N/A (Must be defined)
|
||||
* - ``XUA_PCM_FORMAT``
|
||||
- Enabled either TDM or I2S mode
|
||||
- Enables either TDM or I2S mode
|
||||
- ``XUA_PCM_FORMAT_I2S``
|
||||
* - ``CODEC_MASTER``
|
||||
- Sets is xCORE is I2S master or slave
|
||||
- Sets if xCORE is I2S master or slave
|
||||
- ``0`` (xCORE is master)
|
||||
* - ``XUA_I2S_N_BITS``
|
||||
- I2S/TDM word length (16, 32-bit supported)
|
||||
- ``32``
|
||||
|
||||
The I2S code expects that the ports required for I2S (master clock, LR-clock, bit-clock and data lines) are be defined in the application XN file in the relevant `Tile``.
|
||||
For example::
|
||||
@@ -42,8 +45,16 @@ For example::
|
||||
<Port Location="XS1_PORT_1G" Name="PORT_I2S_ADC1"/>
|
||||
</Tile>
|
||||
|
||||
All of the I2S related ports must be 1-bit ports.
|
||||
All of the I2S/TDM related ports must be 1-bit ports.
|
||||
|
||||
.. note::
|
||||
|
||||
TDM mode allows 8 channels (rather than 2) to be supplied on each dataline.
|
||||
TDM mode allows 8 channels (rather than 2) to be supplied on each data-line.
|
||||
|
||||
.. note::
|
||||
|
||||
Data output/input is in "I2S" format, rather than, say "left-justified" or "right-justified" formats.
|
||||
I2S format specifies a single bit-clock delay after the LR-clock transition before sample-data is driven/received.
|
||||
This also applies to TDM mode. TDM support in ADC/DAC hardware is quite varied, an "offset" value may need to be programmed into
|
||||
the external device for compatible operation.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ full listing of these ``TILE`` defines.
|
||||
- Description
|
||||
- Default
|
||||
* - ``AUDIO_IO_TILE``
|
||||
- Tile on which I2S, ADAT Rx, S/PDIF Rx & mixer resides
|
||||
- Tile on which I2S/TDM, ADAT Rx, S/PDIF Rx & mixer resides
|
||||
- ``0``
|
||||
* - ``XUD_TILE``
|
||||
- Tile on which USB resides, including buffering for all USB interfaces/endppoints
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
|
||||
|newpage|
|
||||
|
||||
Synchronisation
|
||||
===============
|
||||
Synchronisation & Clocking
|
||||
==========================
|
||||
|
||||
The codebase supports "Synchronous" and "Asynchronous" modes for USB transfer as defined by the
|
||||
The codebase supports "Synchronous" and "Asynchronous" modes for USB transfer as defined by the
|
||||
USB specification(s).
|
||||
|
||||
Asynchronous mode (``XUA_SYNCMODE_ASYNC``) has the advantage that the device is clock-master. This means that
|
||||
a high-quality local master-clock source can be utilised. It also has the benefit that the device may
|
||||
synchronise it's master clock to an external digital input stream e.g. S/PDIF and thus avoiding sample-rate
|
||||
Asynchronous mode (``XUA_SYNCMODE_ASYNC``) has the advantage that the device is clock-master. This means that
|
||||
a high-quality local master-clock source can be utilised. It also has the benefit that the device may
|
||||
synchronise it's master clock to an external digital input stream e.g. S/PDIF thus avoiding sample-rate
|
||||
conversion.
|
||||
|
||||
The drawback of this mode is that it burdens the host with syncing to the device which some hosts
|
||||
The drawback of this mode is that it burdens the host with syncing to the device which some hosts
|
||||
may not support. This is especially pertinent to embedded hosts, however, most PC's and mobile devices
|
||||
will indeed support this mode.
|
||||
|
||||
Synchronous mode (``XUA_SYNCMODE_SYNC``) is an option if the target host does not support asynchronous mode
|
||||
or if it is desirable to synchronise many devices to a single host. It should be noted, however, that input
|
||||
or if it is desirable to synchronise many devices to a single host. It should be noted, however, that input
|
||||
from digital streams, such as S/PDIF, are not currently supported in this mode.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
The selection of synchronisation mode is done at build time and cannot be changed dynamically.
|
||||
|
||||
Setting the synchronisation mode of the device is done using the define in :ref:`opt_sync_defines`
|
||||
@@ -39,10 +39,17 @@ Setting the synchronisation mode of the device is done using the define in :ref:
|
||||
- USB synchronisation mode
|
||||
- ``XUA_SYNCMODE_ASYNC``
|
||||
|
||||
When operating in synchronous mode an external Cirrus Logic CS2100 device is required for master clock
|
||||
generation. The codebase expects to drive a synchronisation signal to this external device
|
||||
When operating in asynchronous mode xcore.ai based devices will be configured, by default, to use their internal
|
||||
"Applications" PLL to generated an appropriate master-clock signal. To disable this ``XUA_USE_APP_PLL`` should be
|
||||
set to ``0``. For all other devices the developer is expected to supply external master-clock generation circuitry.
|
||||
|
||||
The programmer should ensure the define in :ref:`opt_sync_ref_defines` is set appropriately.
|
||||
When operating in synchronous mode an xcore.ai based device, by default, will be configured to used it's internal
|
||||
"application" PLL to generate a master-clock synchronised to the USB host.
|
||||
|
||||
xcore-200 based devices do not have this application PLL and so an external Cirrus Logic CS2100 device is required
|
||||
for master clock generation. The codebase expects to drive a synchronisation signal to this external device.
|
||||
|
||||
In this case the developer should ensure the define in :ref:`opt_sync_ref_defines` is set appropriately.
|
||||
|
||||
.. _opt_sync_ref_defines:
|
||||
|
||||
@@ -57,10 +64,33 @@ The programmer should ensure the define in :ref:`opt_sync_ref_defines` is set ap
|
||||
- Tile location of reference to CS2100 device
|
||||
- ``AUDIO_IO_TILE``
|
||||
|
||||
The codebase expects this reference signal port to be defined in the application XN file as ``PORT_PLL_REF``.
|
||||
The codebase expects this reference signal port to be defined in the application XN file as ``PORT_PLL_REF``.
|
||||
This may be a port of any bit-width, however, connection to bit[0] is assumed::
|
||||
|
||||
<Port Location="XS1_PORT_1A" Name="PORT_PLL_REF"/>
|
||||
|
||||
Configuration of the external CS2100 device (typically via I2C) is beyond the scope of this document.
|
||||
|
||||
Note, in all cases the master-clocks are generated (when using the xcore.ai Application PLL) or should be generated
|
||||
(if using external circuitry) to match the defines in :ref:`opt_sync_mclk_defines`.
|
||||
|
||||
.. _opt_sync_mclk_defines:
|
||||
|
||||
.. list-table:: Master clock frequencies
|
||||
:header-rows: 1
|
||||
:widths: 20 80 20
|
||||
|
||||
* - Define
|
||||
- Description
|
||||
- Default
|
||||
* - ``MCLK_48``
|
||||
- Master clock frequency (in Hz)used for sample-rates related to 48KHz
|
||||
- NOTE
|
||||
* - ``MCLK_441``
|
||||
- Master clock frequency (in Hz) used for sample-rates related to 44.1KHz
|
||||
- NONE
|
||||
|
||||
.. note::
|
||||
|
||||
The master clock defines above are critical for proper operation and default values are not provided.
|
||||
If they are not defined by the devloper a build error will be emmited.
|
||||
|
||||
@@ -25,7 +25,7 @@ Overview
|
||||
| +---------------------------------------------------------------------------------------------+
|
||||
| | `USB Midi Device Class 1.0 <http://www.usb.org/developers/devclass_docs/midi10.pdf>`_ |
|
||||
+---------------------------------+---------------------------------------------------------------------------------------------+
|
||||
| Audio | I2S/TDM |
|
||||
| Audio | I2S/TDM (16/32-bit) |
|
||||
| +---------------------------------------------------------------------------------------------+
|
||||
| | S/PDIF |
|
||||
| +---------------------------------------------------------------------------------------------+
|
||||
|
||||
@@ -87,6 +87,9 @@ intended as an example of how you might add mixer control to your own control ap
|
||||
intended to be exposed to end users.
|
||||
|
||||
For details, consult the README file in the host_usb_mixer_control directory.
|
||||
A list of arguments can also be seen with::
|
||||
|
||||
$ ./xmos_mixer --help
|
||||
|
||||
The main requirements of this control utility are to
|
||||
|
||||
@@ -102,78 +105,147 @@ The main requirements of this control utility are to
|
||||
functionality to their end users.
|
||||
|
||||
Whilst using the XMOS Host control example application, consider the example of setting the
|
||||
mixer to perform a loop-back from analogue inputs 1 and 2 to analogue outputs 1 and 2.
|
||||
mixer to perform a loop-back from analogue inputs 1 & 2 to analogue outputs 1 & 2.
|
||||
|
||||
Firstly consider the inputs to the mixer. The following will displays which channels are mapped
|
||||
to which mixer inputs::
|
||||
.. note::
|
||||
|
||||
./xmos_mixer --display-aud-channel-map 0
|
||||
The command outputs shown are examples; the actual output will depend on the mixer configuration.
|
||||
|
||||
The following command will displays which channels could possibly be mapped to mixer inputs. Notice
|
||||
that analogue inputs 1 and 2 are on mixer inputs 10 and 11::
|
||||
The following will show the index for each device output along with which channel is currently mapped to it.
|
||||
In this example the analogue outputs 1 & 2 are 0 & 1 respectively::
|
||||
|
||||
./xmos_mixer --display-aud-channel-map-sources 0
|
||||
$ ./xmos_mixer --display-aud-channel-map
|
||||
|
||||
Now examine the audio output mapping using the following command::
|
||||
Audio Output Channel Map
|
||||
------------------------
|
||||
|
||||
0 (DEVICE OUT - Analogue 1) source is 0 (DAW OUT - Analogue 1)
|
||||
1 (DEVICE OUT - Analogue 2) source is 1 (DAW OUT - Analogue 2)
|
||||
2 (DEVICE OUT - SPDIF 1) source is 2 (DAW OUT - SPDIF 1)
|
||||
3 (DEVICE OUT - SPDIF 2) source is 3 (DAW OUT - SPDIF 2)
|
||||
$ _
|
||||
|
||||
./xmos_mixer --display-aud-channel-map 0
|
||||
The DAW Output Map can be seen with::
|
||||
|
||||
This displays which channels are mapped to which outputs. By default all
|
||||
of these bypass the mixer. We can also see what all the possible
|
||||
mappings are with the following command::
|
||||
$ ./xmos_mixer --display-daw-channel-map
|
||||
|
||||
./xmos_mixer --display-aud-channel-map-sources 0
|
||||
DAW Output To Host Channel Map
|
||||
------------------------
|
||||
|
||||
0 (DEVICE IN - Analogue 1) source is 4 (DEVICE IN - Analogue 1)
|
||||
1 (DEVICE IN - Analogue 2) source is 5 (DEVICE IN - Analogue 2)
|
||||
$ _
|
||||
|
||||
We will now map the first two mixer outputs to physical outputs 1 and 2::
|
||||
.. note::
|
||||
|
||||
./xmos_mixer --set-aud-channel-map 0 26
|
||||
./xmos_mixer --set-aud-channel-map 1 27
|
||||
In both cases, by default, these bypass the mixer.
|
||||
|
||||
The following command will list the channels which can be mapped to the device outputs from the
|
||||
Audio Output Channel Map. Note that, in this example, analogue inputs 1 & 2 are source 4 & 5 and
|
||||
Mix 1 & 2 are source 6 & 7::
|
||||
|
||||
$ ./xmos_mixer --display-aud-channel-map-sources
|
||||
|
||||
Audio Output Channel Map Source List
|
||||
------------------------------------
|
||||
|
||||
0 (DAW OUT - Analogue 1)
|
||||
1 (DAW OUT - Analogue 2)
|
||||
2 (DAW OUT - SPDIF 1)
|
||||
3 (DAW OUT - SPDIF 2)
|
||||
4 (DEVICE IN - Analogue 1)
|
||||
5 (DEVICE IN - Analogue 2)
|
||||
6 (MIX - Mix 1)
|
||||
7 (MIX - Mix 2)
|
||||
$ _
|
||||
|
||||
Using the indices from the previous commands, we will now re-map the first two mixer channels (Mix 1 & Mix 2) to device outputs 1 & 2::
|
||||
|
||||
$ ./xmos_mixer --set-aud-channel-map 0 6
|
||||
$ ./xmos_mixer --set-aud-channel-map 1 7
|
||||
$ _
|
||||
|
||||
You can confirm the effect of this by re-checking the map::
|
||||
|
||||
./xmos_mixer --display-aud-channel-map 0
|
||||
$ ./xmos_mixer --display-aud-channel-map
|
||||
|
||||
This now derives analogue outputs 1 and 2 from the mixer, rather than directly from USB. However,
|
||||
since the mixer is still mapped to pass the USB channels through to the outputs there will be no
|
||||
Audio Output Channel Map
|
||||
------------------------
|
||||
|
||||
0 (DEVICE OUT - Analogue 1) source is 6 (MIX - Mix 1)
|
||||
1 (DEVICE OUT - Analogue 2) source is 7 (MIX - Mix 2)
|
||||
2 (DEVICE OUT - SPDIF 1) source is 2 (DAW OUT - SPDIF 1)
|
||||
3 (DEVICE OUT - SPDIF 2) source is 3 (DAW OUT - SPDIF 2)
|
||||
$ _
|
||||
|
||||
This now derives analogue outputs 1 & 2 from the mixer, rather than directly from USB. However,
|
||||
since the mixer is mapped, by default, to just pass the USB channels through to the outputs there will be no
|
||||
functional change.
|
||||
|
||||
The mixer nodes need to be individually set. They can be displayed
|
||||
|
||||
.. note::
|
||||
|
||||
The USB audio reference design has only one unit so the mixer_id argument should always be 0.
|
||||
|
||||
The mixer nodes need to be individually set. The nodes in mixer_id 0 can be displayed
|
||||
with the following command::
|
||||
|
||||
./xmos_mixer --display-mixer-nodes 0
|
||||
$ ./xmos_mixer --display-mixer-nodes 0
|
||||
|
||||
To get the audio from the analogue inputs to outputs 1 and 2, nodes 80
|
||||
and 89 need to be set::
|
||||
Mixer Values (0)
|
||||
----------------
|
||||
|
||||
./xmos_mixer --set-value 0 80 0
|
||||
./xmos_mixer --set-value 0 89 0
|
||||
Mixer outputs
|
||||
1 2
|
||||
DAW - Analogue 1 0:[0000.000] 1:[ -inf ]
|
||||
DAW - Analogue 2 2:[ -inf ] 3:[0000.000]
|
||||
DAW - SPDIF 1 4:[ -inf ] 5:[ -inf ]
|
||||
DAW - SPDIF 2 6:[ -inf ] 7:[ -inf ]
|
||||
AUD - Analogue 1 8:[ -inf ] 9:[ -inf ]
|
||||
AUD - Analogue 2 10:[ -inf ] 11:[ -inf ]
|
||||
$ _
|
||||
|
||||
With mixer outputs 1 & 2 mapped to device outputs analogue 1 & 2; to get the audio from the analogue inputs to device
|
||||
outputs mixer_id 0 node 8 and node 11 need to be set to 0db::
|
||||
|
||||
$ ./xmos_mixer --set-value 0 8 0
|
||||
$ ./xmos_mixer --set-value 0 11 0
|
||||
$ _
|
||||
|
||||
At the same time, the original mixer outputs can be muted::
|
||||
|
||||
./xmos_mixer --set-value 0 0 -inf
|
||||
./xmos_mixer --set-value 0 9 -inf
|
||||
$ ./xmos_mixer --set-value 0 0 -inf
|
||||
$ ./xmos_mixer --set-value 0 3 -inf
|
||||
$ _
|
||||
|
||||
Now audio inputs on analogue 1/2 should be heard on outputs 1/2.
|
||||
Now audio inputs on analogue 1 and 2 should be heard on outputs 1 and 2 respectively.
|
||||
|
||||
As mentioned above, the flexibility of the mixer is such that there will be multiple ways to create
|
||||
a particular mix. Another option to create the same routing would be to change the mixer sources
|
||||
such that mixer 1/2 outputs come from the analogue inputs.
|
||||
such that mixer outputs 1 and 2 come from the analogue inputs 1 and 2.
|
||||
|
||||
To demonstrate this, firstly undo the changes above (or simply reset the device)::
|
||||
|
||||
./xmos_mixer --set-value 0 80 -inf
|
||||
./xmos_mixer --set-value 0 89 -inf
|
||||
./xmos_mixer --set-value 0 0 0
|
||||
./xmos_mixer --set-value 0 9 0
|
||||
$ ./xmos_mixer --set-value 0 8 -inf
|
||||
$ ./xmos_mixer --set-value 0 11 -inf
|
||||
$ ./xmos_mixer --set-value 0 0 0
|
||||
$ ./xmos_mixer --set-value 0 3 0
|
||||
$ _
|
||||
|
||||
The mixer should now have the default values. The sources for mixer 1/2 can now be changed::
|
||||
The mixer should now have the default values. The sources for mixer 0 output 1 and 2 can now be changed
|
||||
using indices from the Audio Output Channel Map Source List::
|
||||
|
||||
./xmos_mixer --set-mixer-source 0 0 10
|
||||
./xmos_mixer --set-mixer-source 0 1 11
|
||||
$ ./xmos_mixer --set-mixer-source 0 0 4
|
||||
|
||||
Set mixer(0) input 0 to device input 4 (AUD - Analogue 1)
|
||||
$ ./xmos_mixer --set-mixer-source 0 1 5
|
||||
|
||||
Set mixer(0) input 1 to device input 5 (AUD - Analogue 2)
|
||||
$ _
|
||||
|
||||
If you re-run the following command then the first column now has "AUD - Analogue 1 and 2" rather
|
||||
than "DAW (Digital Audio Workstation i.e. the host) - Analogue 1 and 2" confirming the new mapping.
|
||||
Again, by playing audio into analogue inputs 1/2 this can be heard looped through to analogue outputs 1/2::
|
||||
|
||||
./xmos_mixer --display-mixer-nodes 0
|
||||
$ ./xmos_mixer --display-mixer-nodes 0
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ I2S/TDM
|
||||
|
||||
I2S/TDM is typically fundamental to most products and is built into the ``XUA_AudioHub()`` core.
|
||||
|
||||
In order to enable I2S on must declare an array of ports for the data-lines (one for each direction)::
|
||||
In order to enable I2S/TDM on must declare an array of ports for the data-lines (one for each direction)::
|
||||
|
||||
/* Port declarations. Note, the defines come from the XN file */
|
||||
buffered out port:32 p_i2s_dac[] = {PORT_I2S_DAC0}; /* I2S Data-line(s) */
|
||||
@@ -22,7 +22,7 @@ Ports for the sample and bit clocks are also required::
|
||||
|
||||
These ports must then be passed to the ``XUA_AudioHub()`` task appropriately.
|
||||
|
||||
I2S functionality also requires two clock-blocks, one for bit and sample clock e.g.::
|
||||
I2S/TDM functionality also requires two clock-blocks, one for bit-clock and another for the master clock e.g.::
|
||||
|
||||
/* Clock-block declarations */
|
||||
clock clk_audio_bclk = on tile[0]: XS1_CLKBLK_4; /* Bit clock */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
XMOSNEWSTYLE = 2
|
||||
DOXYGEN_DIRS=../../api
|
||||
DOXYGEN_DIRS=../../api ../../src/core/user/audiostream ../../src/core/user/hostactive ../../src/core/user/hid ../../src/core/user/audiohw
|
||||
SOURCE_INCLUDE_DIRS=../../../lib_xua
|
||||
SPHINX_MASTER_DOC=lib_xua
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
VERSION = 3.3.1
|
||||
VERSION = 3.5.1
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
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
|
||||
DEBUG_FLAGS = -DXASSERT_DISABLE_ASSERTIONS_DECOUPLE=1
|
||||
DEBUG_FLAGS = -DXASSERT_ENABLE_ASSERTIONS=0 -DXASSERT_ENABLE_DEBUG=0 -DXASSERT_ENABLE_LINE_NUMBERS=0
|
||||
endif
|
||||
|
||||
DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
||||
lib_logging(>=3.1.1) \
|
||||
lib_mic_array(>=4.5.0) \
|
||||
lib_spdif(>=4.2.1) \
|
||||
lib_spdif(>=5.0.0) \
|
||||
lib_xassert(>=4.1.0) \
|
||||
lib_xud(>=2.2.1) \
|
||||
lib_xud(>=2.2.3) \
|
||||
lib_adat(>=1.0.0)
|
||||
|
||||
MODULE_XCC_FLAGS = $(XCC_FLAGS) \
|
||||
@@ -35,7 +35,7 @@ XCC_FLAGS_dfu.xc = $(MODULE_XCC_FLAGS) -Os -mno-dual-issue
|
||||
XCC_FLAGS_flash_interface.c = $(MODULE_XCC_FLAGS) -Os -mno-dual-issue
|
||||
XCC_FLAGS_flashlib_user.c = $(MODULE_XCC_FLAGS) -Os -mno-dual-issue
|
||||
|
||||
OPTIONAL_HEADERS += xua_conf.h
|
||||
OPTIONAL_HEADERS += xua_conf.h static_hid_report.h
|
||||
|
||||
EXPORT_INCLUDE_DIRS = api \
|
||||
src/core \
|
||||
@@ -55,6 +55,7 @@ INCLUDE_DIRS = $(EXPORT_INCLUDE_DIRS) \
|
||||
src/core/user/audiostream \
|
||||
src/core/user/hid \
|
||||
src/core/user/hostactive \
|
||||
src/core/user/audiohw \
|
||||
src/hid \
|
||||
src/midi
|
||||
|
||||
@@ -70,6 +71,7 @@ SOURCE_DIRS = src/core \
|
||||
src/core/support \
|
||||
src/core/user/audiostream \
|
||||
src/core/user/hostactive \
|
||||
src/core/user/audiohw \
|
||||
src/core/xuduser \
|
||||
src/dfu \
|
||||
src/hid \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2022 XMOS LIMITED.
|
||||
// Copyright 2018-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#if (DSD_CHANS_DAC != 0)
|
||||
@@ -52,7 +52,7 @@ static inline void DoDsdDop(int &everyOther, unsigned samplesOut[], unsigned &ds
|
||||
/* When DSD is enabled and streaming is standard PCM, this function checks for a series of DoP markers in the upper byte.
|
||||
If found it will exit deliver() with the command to restart in DoP mode.
|
||||
When in DoP mode, this function will check for a single absence of the DoP marker and exit deliver() with the command
|
||||
to restart in I2S mode. */
|
||||
to restart in I2S/PCM mode. */
|
||||
static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSamFreq, unsigned samplesOut[], unsigned &dsdMarker)
|
||||
{
|
||||
/* Check for DSD - note we only move into DoP mode if valid DoP Freq */
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2018-2022 XMOS LIMITED.
|
||||
// Copyright 2018-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include "xua.h"
|
||||
|
||||
#include "dsd_support.h"
|
||||
|
||||
#if (DSD_CHANS_DAC != 0)
|
||||
@@ -12,7 +11,7 @@ extern buffered out port:32 p_dsd_clk;
|
||||
extern unsigned dsdMode;
|
||||
|
||||
#if !CODEC_MASTER
|
||||
void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
|
||||
void InitPorts_master(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
|
||||
{
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
if(dsdMode == DSD_MODE_OFF)
|
||||
@@ -38,9 +37,13 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma xta endpoint "divide_1"
|
||||
unsigned tmp;
|
||||
p_lrclk <: 0 @ tmp;
|
||||
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_lrclk <: 0 @ tmp;
|
||||
else
|
||||
tmp = partout_timestamped(p_lrclk, XUA_I2S_N_BITS, 0);
|
||||
|
||||
tmp += 100;
|
||||
|
||||
/* Since BCLK is free-running, setup outputs/inputs at a known point in the future */
|
||||
@@ -48,19 +51,30 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
p_i2s_dac[i] @ tmp <: 0;
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_i2s_dac[i] @ tmp <: 0;
|
||||
else
|
||||
partout_timed(p_i2s_dac[i], XUA_I2S_N_BITS, 0, tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned lrClkVal = 0x7FFFFFFF;
|
||||
if(XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
|
||||
p_lrclk @ tmp <: 0x80000000;
|
||||
{
|
||||
lrClkVal = 0x80000000;
|
||||
}
|
||||
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_lrclk @ tmp <: lrClkVal;
|
||||
else
|
||||
p_lrclk @ tmp <: 0x7FFFFFFF;
|
||||
partout_timed(p_lrclk, XUA_I2S_N_BITS, lrClkVal, tmp);
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
|
||||
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
set_port_shift_count(p_i2s_adc[i], XUA_I2S_N_BITS);
|
||||
}
|
||||
#endif
|
||||
#endif /* (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) */
|
||||
@@ -76,7 +90,7 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
|
||||
void InitPorts_slave(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
|
||||
{
|
||||
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||
unsigned tmp;
|
||||
@@ -93,7 +107,7 @@ void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buf
|
||||
p_lrclk when pinseq(0) :> void @ tmp;
|
||||
#endif
|
||||
|
||||
tmp += (I2S_CHANS_PER_FRAME * 32) - 32 + 1 ;
|
||||
tmp += ((I2S_CHANS_PER_FRAME * XUA_I2S_N_BITS) - XUA_I2S_N_BITS + 1) ;
|
||||
/* E.g. 2 * 32 - 32 + 1 = 33 for stereo */
|
||||
/* E.g. 8 * 32 - 32 + 1 = 225 for 8 chan TDM */
|
||||
|
||||
@@ -101,7 +115,10 @@ void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buf
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
p_i2s_dac[i] @ tmp <: 0;
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_i2s_dac[i] @ tmp <: 0;
|
||||
else
|
||||
partout_timed(p_i2s_dac[i], XUA_I2S_N_BITS, 0, tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -109,11 +126,15 @@ void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buf
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
|
||||
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
set_port_shift_count(p_i2s_adc[i], XUA_I2S_N_BITS);
|
||||
}
|
||||
#endif
|
||||
|
||||
asm("setpt res[%0], %1"::"r"(p_lrclk),"r"(tmp-1));
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
set_port_shift_count(p_lrclk, XUA_I2S_N_BITS);
|
||||
#endif /* (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) */
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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.
|
||||
/**
|
||||
* @file xua_audiohub.xc
|
||||
@@ -15,9 +15,12 @@
|
||||
#include <xclib.h>
|
||||
#include <xs1_su.h>
|
||||
#include <string.h>
|
||||
#include <xassert.h>
|
||||
|
||||
#include "xua.h"
|
||||
|
||||
#include "audiohw.h"
|
||||
|
||||
#include "audioports.h"
|
||||
#include "mic_array_conf.h"
|
||||
#if (XUA_SPDIF_TX_EN)
|
||||
@@ -43,25 +46,12 @@
|
||||
|
||||
#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 */
|
||||
#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)];
|
||||
|
||||
#ifdef XTA_TIMING_AUDIO
|
||||
#pragma xta command "add exclusion received_command"
|
||||
#pragma xta command "analyse path i2s_output_l i2s_output_r"
|
||||
#pragma xta command "set required - 2000 ns"
|
||||
|
||||
#pragma xta command "add exclusion received_command"
|
||||
#pragma xta command "add exclusion received_underflow"
|
||||
#pragma xta command "add exclusion divide_1"
|
||||
#pragma xta command "add exclusion deliver_return"
|
||||
#pragma xta command "analyse path i2s_output_r i2s_output_l"
|
||||
#pragma xta command "set required - 2000 ns"
|
||||
#endif
|
||||
unsigned samplesIn[2][MAX(NUM_USB_CHAN_IN, IN_CHAN_COUNT)];
|
||||
|
||||
#if (XUA_ADAT_TX_EN)
|
||||
extern buffered out port:32 p_adat_tx;
|
||||
@@ -76,7 +66,7 @@ void InitPorts_slave
|
||||
#else
|
||||
void InitPorts_master
|
||||
#endif
|
||||
(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
|
||||
(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
|
||||
buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC]);
|
||||
|
||||
|
||||
@@ -89,76 +79,24 @@ unsigned dsdMode = DSD_MODE_OFF;
|
||||
#if (XUA_ADAT_TX_EN)
|
||||
#include "audiohub_adat.h"
|
||||
#endif
|
||||
|
||||
#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;
|
||||
}
|
||||
#include "xua_audiohub_st.h"
|
||||
|
||||
static inline int HandleSampleClock(int frameCount, buffered _XUA_CLK_DIR port:32 p_lrclk)
|
||||
{
|
||||
#if CODEC_MASTER
|
||||
unsigned syncError = 0;
|
||||
unsigned lrval = 0;
|
||||
p_lrclk :> lrval;
|
||||
const unsigned lrval_mask = (0xffffffff << (32 - XUA_I2S_N_BITS));
|
||||
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
{
|
||||
asm volatile("in %0, res[%1]":"=r"(lrval):"r"(p_lrclk):"memory");
|
||||
set_port_shift_count(p_lrclk, XUA_I2S_N_BITS);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_lrclk :> lrval;
|
||||
}
|
||||
|
||||
if(XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
|
||||
{
|
||||
@@ -176,30 +114,46 @@ static inline int HandleSampleClock(int frameCount, buffered _XUA_CLK_DIR port:3
|
||||
}
|
||||
else
|
||||
{
|
||||
if(frameCount == 0)
|
||||
syncError += (lrval != 0x80000000);
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
{
|
||||
if(frameCount == 0)
|
||||
syncError = (lrval != 0x80000000);
|
||||
else
|
||||
syncError = (lrval != 0x7FFFFFFF);
|
||||
}
|
||||
else
|
||||
syncError += (lrval != 0x7FFFFFFF);
|
||||
{
|
||||
if(frameCount == 0)
|
||||
syncError = ((lrval & lrval_mask) != 0x80000000);
|
||||
else
|
||||
syncError = ((lrval | (~lrval_mask)) != 0x7FFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
return syncError;
|
||||
|
||||
#else
|
||||
unsigned clkVal;
|
||||
if(XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
|
||||
{
|
||||
if(frameCount == (I2S_CHANS_PER_FRAME-1))
|
||||
p_lrclk <: 0x80000000;
|
||||
clkVal = 0x80000000;
|
||||
else
|
||||
p_lrclk <: 0x00000000;
|
||||
clkVal = 0x00000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(frameCount == 0)
|
||||
p_lrclk <: 0x80000000;
|
||||
clkVal = 0x80000000;
|
||||
else
|
||||
p_lrclk <: 0x7fffffff;
|
||||
clkVal = 0x7fffffff;
|
||||
}
|
||||
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_lrclk <: clkVal;
|
||||
else
|
||||
partout(p_lrclk, XUA_I2S_N_BITS, clkVal >> (32 - XUA_I2S_N_BITS));
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
@@ -316,9 +270,9 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
||||
if ((I2S_CHANS_DAC > 0 || I2S_CHANS_ADC > 0))
|
||||
{
|
||||
#if CODEC_MASTER
|
||||
InitPorts_slave(divide, p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc);
|
||||
InitPorts_slave(p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc);
|
||||
#else
|
||||
InitPorts_master(divide, p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc);
|
||||
InitPorts_master(p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -352,9 +306,17 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
||||
// p_i2s_adc[index++] :> sample;
|
||||
// Manual IN instruction since compiler generates an extra setc per IN (bug #15256)
|
||||
unsigned sample;
|
||||
asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++]));
|
||||
asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index]));
|
||||
|
||||
sample = bitrev(sample);
|
||||
int chanIndex = ((frameCount-2)&(I2S_CHANS_PER_FRAME-1))+i; // channels 0, 2, 4.. on each line.
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
{
|
||||
set_port_shift_count(p_i2s_adc[index], XUA_I2S_N_BITS);
|
||||
sample <<= (32 - XUA_I2S_N_BITS);
|
||||
}
|
||||
index++;
|
||||
|
||||
int chanIndex = ((frameCount-2) & (I2S_CHANS_PER_FRAME-1)) + i; // channels 0, 2, 4.. on each line.
|
||||
|
||||
#if (AUD_TO_USB_RATIO > 1)
|
||||
if ((AUD_TO_USB_RATIO - 1) == audioToUsbRatioCounter)
|
||||
@@ -406,7 +368,10 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
||||
src_ff3v_fir_coefs[2-audioToUsbRatioCounter]);
|
||||
}
|
||||
#endif /* (AUD_TO_USB_RATIO > 1) */
|
||||
p_i2s_dac[index++] <: bitrev(samplesOut[frameCount +i]);
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_i2s_dac[index++] <: bitrev(samplesOut[frameCount +i]);
|
||||
else
|
||||
partout(p_i2s_dac[index++], XUA_I2S_N_BITS, bitrev(samplesOut[frameCount +i]));
|
||||
}
|
||||
#endif // (I2S_CHANS_DAC != 0)
|
||||
|
||||
@@ -443,9 +408,8 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
||||
outuint(c_dig_rx, 0);
|
||||
#endif
|
||||
#if (XUA_SPDIF_TX_EN) && (NUM_USB_CHAN_OUT > 0)
|
||||
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward sample to S/PDIF Tx thread */
|
||||
unsigned sample = samplesOut[SPDIF_TX_INDEX + 1];
|
||||
outuint(c_spd_out, sample); /* Forward sample to S/PDIF Tx thread */
|
||||
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward samples to S/PDIF Tx thread */
|
||||
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX + 1]);
|
||||
#endif
|
||||
|
||||
#if (XUA_NUM_PDM_MICS > 0)
|
||||
@@ -480,8 +444,15 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
||||
{
|
||||
/* Manual IN instruction since compiler generates an extra setc per IN (bug #15256) */
|
||||
unsigned sample;
|
||||
asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++]));
|
||||
asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index]));
|
||||
sample = bitrev(sample);
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
{
|
||||
set_port_shift_count(p_i2s_adc[index], XUA_I2S_N_BITS);
|
||||
sample <<= (32 - XUA_I2S_N_BITS);
|
||||
}
|
||||
index++;
|
||||
|
||||
int chanIndex = ((frameCount-2)&(I2S_CHANS_PER_FRAME-1))+i; // channels 1, 3, 5.. on each line.
|
||||
#if (AUD_TO_USB_RATIO > 1 && !I2S_DOWNSAMPLE_MONO_IN)
|
||||
if ((AUD_TO_USB_RATIO - 1) == audioToUsbRatioCounter)
|
||||
@@ -513,7 +484,6 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
||||
#endif
|
||||
|
||||
index = 0;
|
||||
#pragma xta endpoint "i2s_output_r"
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
/* Output "odd" channel to DAC (i.e. right) */
|
||||
#pragma loop unroll
|
||||
@@ -532,7 +502,10 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
||||
src_ff3v_fir_coefs[2-audioToUsbRatioCounter]);
|
||||
}
|
||||
#endif /* (AUD_TO_USB_RATIO > 1) */
|
||||
p_i2s_dac[index++] <: bitrev(samplesOut[frameCount + i]);
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_i2s_dac[index++] <: bitrev(samplesOut[frameCount + i]);
|
||||
else
|
||||
partout(p_i2s_dac[index++], XUA_I2S_N_BITS, bitrev(samplesOut[frameCount + i]));
|
||||
}
|
||||
#endif // (I2S_CHANS_DAC != 0)
|
||||
|
||||
@@ -586,7 +559,6 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma xta endpoint "deliver_return"
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -664,6 +636,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
buffered _XUA_CLK_DIR port:32 ?p_bclk,
|
||||
buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC],
|
||||
buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC]
|
||||
#if (XUA_USE_APP_PLL)
|
||||
, client interface SoftPll_if i_softPll
|
||||
#endif
|
||||
#if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
, chanend c_spdif_out
|
||||
#endif
|
||||
@@ -691,6 +666,12 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
unsigned divide;
|
||||
unsigned firstRun = 1;
|
||||
|
||||
#if (XUA_USE_APP_PLL)
|
||||
/* Use xCORE.ai Secondary PLL to generate master clock
|
||||
* This could be "fixed" for async mode or adjusted if in sync mode */
|
||||
i_softPll.init(DEFAULT_MCLK);
|
||||
#endif
|
||||
|
||||
/* Clock master clock-block from master-clock port */
|
||||
/* Note, marked unsafe since other cores may be using this mclk port */
|
||||
configure_clock_src(clk_audio_mclk, p_mclk_in);
|
||||
@@ -716,6 +697,8 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Perform required CODEC/ADC/DAC initialisation */
|
||||
AudioHwInit();
|
||||
|
||||
@@ -744,13 +727,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
/* Calculate master clock to bit clock (or DSD clock) divide for current sample freq
|
||||
* e.g. 11.289600 / (176400 * 64) = 1 */
|
||||
{
|
||||
#if (XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
|
||||
/* I2S has 32 bits per sample. *8 as 8 channels */
|
||||
unsigned numBits = 256;
|
||||
#else
|
||||
/* I2S has 32 bits per sample. *2 as 2 channels */
|
||||
unsigned numBits = 64;
|
||||
#endif
|
||||
unsigned numBits = XUA_I2S_N_BITS * I2S_CHANS_PER_FRAME;
|
||||
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
if(dsdMode == DSD_MODE_DOP)
|
||||
@@ -764,17 +741,24 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
numBits = 32;
|
||||
}
|
||||
#endif
|
||||
divide = mClk / ( curSamFreq * numBits);
|
||||
divide = mClk / (curSamFreq * numBits);
|
||||
|
||||
//Do some checks
|
||||
xassert((divide > 0) && "Error: divider is 0, BCLK rate unachievable");
|
||||
|
||||
unsigned remainder = mClk % ( curSamFreq * numBits);
|
||||
xassert((!remainder) && "Error: MCLK not divisible into BCLK by an integer number");
|
||||
|
||||
unsigned divider_is_odd = divide & 0x1;
|
||||
xassert((!divider_is_odd) && "Error: divider is odd, clockblock cannot produce desired BCLK");
|
||||
|
||||
/* TODO; we should catch and handle the case when divide is 0. Currently design will lock up */
|
||||
}
|
||||
|
||||
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
if(dsdMode)
|
||||
{
|
||||
/* Configure audio ports */
|
||||
ConfigAudioPortsWrapper(
|
||||
/* Configure audio ports */
|
||||
ConfigAudioPortsWrapper(
|
||||
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)
|
||||
p_dsd_dac,
|
||||
DSD_CHANS_DAC,
|
||||
@@ -787,7 +771,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
null,
|
||||
p_dsd_clk,
|
||||
#endif
|
||||
p_mclk_in, clk_audio_bclk, divide, curSamFreq, dsdMode);
|
||||
p_mclk_in, clk_audio_bclk, divide, curSamFreq);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -810,9 +794,8 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
p_bclk,
|
||||
#endif
|
||||
#endif
|
||||
p_mclk_in, clk_audio_bclk, divide, curSamFreq, dsdMode);
|
||||
}
|
||||
|
||||
p_mclk_in, clk_audio_bclk, divide, curSamFreq);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned curFreq = curSamFreq;
|
||||
@@ -827,8 +810,19 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
curFreq *= 16;
|
||||
}
|
||||
#endif
|
||||
/* Configure Clocking/CODEC/DAC/ADC for SampleFreq/MClk */
|
||||
|
||||
/* User should mute audio hardware */
|
||||
AudioHwConfig_Mute();
|
||||
|
||||
#if (XUA_USE_APP_PLL)
|
||||
i_softPll.init(mClk);
|
||||
#endif
|
||||
|
||||
/* User code should configure audio harware for SampleFreq/MClk etc */
|
||||
AudioHwConfig(curFreq, mClk, dsdMode, curSamRes_DAC, curSamRes_ADC);
|
||||
|
||||
/* User should unmute audio hardware */
|
||||
AudioHwConfig_UnMute();
|
||||
}
|
||||
|
||||
if(!firstRun)
|
||||
|
||||
66
lib_xua/src/core/audiohub/xua_audiohub_st.h
Normal file
66
lib_xua/src/core/audiohub/xua_audiohub_st.h
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
#include "xua.h"
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
/*** BUFFER SIZES ***/
|
||||
|
||||
#define BUFFER_PACKET_COUNT 4 /* How many packets too allow for in buffer - minimum is 4 */
|
||||
#define BUFFER_PACKET_COUNT (4) /* How many packets too allow for in buffer - minimum is 4 */
|
||||
|
||||
#define BUFF_SIZE_OUT_HS MAX_DEVICE_AUD_PACKET_SIZE_OUT_HS * BUFFER_PACKET_COUNT
|
||||
#define BUFF_SIZE_OUT_FS MAX_DEVICE_AUD_PACKET_SIZE_OUT_FS * BUFFER_PACKET_COUNT
|
||||
@@ -55,18 +55,25 @@
|
||||
#define BUFF_SIZE_IN MAX(BUFF_SIZE_IN_HS, BUFF_SIZE_IN_FS)
|
||||
|
||||
#define OUT_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_OUT_HS, MAX_DEVICE_AUD_PACKET_SIZE_OUT_FS))
|
||||
#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 */
|
||||
#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];
|
||||
static xc_ptr p_multOut;
|
||||
unsafe
|
||||
{
|
||||
unsigned int volatile * unsafe multOutPtr = multOut;
|
||||
}
|
||||
#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];
|
||||
static xc_ptr p_multIn;
|
||||
unsafe
|
||||
{
|
||||
unsigned int volatile * unsafe multInPtr = multIn;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Default to something sensible but the following are setup at stream start (unless UAC1 only..) */
|
||||
#if (AUDIO_CLASS == 2)
|
||||
int g_numUsbChan_In = NUM_USB_CHAN_IN; /* Number of channels to/from the USB bus - initialised to HS for UAC2.0 */
|
||||
int g_numUsbChan_Out = NUM_USB_CHAN_OUT;
|
||||
@@ -143,7 +150,72 @@ unsigned unpackData = 0;
|
||||
unsigned packState = 0;
|
||||
unsigned packData = 0;
|
||||
|
||||
/* Default to something sensible but the following are setup at stream start (unless UAC1 only..) */
|
||||
static inline void SendSamples4(chanend c_mix_out)
|
||||
{
|
||||
/* Doing this checking allows us to unroll */
|
||||
if(g_numUsbChan_Out == NUM_USB_CHAN_OUT)
|
||||
{
|
||||
/* Buffering not underflow condition send out some samples...*/
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
|
||||
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
||||
g_aud_from_host_rdptr+=4;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||
unsafe
|
||||
{
|
||||
mult = multOutPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<= 3;
|
||||
#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)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
outuint(c_mix_out, h);
|
||||
#else
|
||||
outuint(c_mix_out, sample);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT_FS; i++)
|
||||
{
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
|
||||
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
||||
g_aud_from_host_rdptr+=4;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||
unsafe
|
||||
{
|
||||
mult = multOutPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<= 3;
|
||||
#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)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
outuint(c_mix_out, h);
|
||||
#else
|
||||
outuint(c_mix_out, sample);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma select handler
|
||||
#pragma unsafe arrays
|
||||
@@ -206,8 +278,11 @@ __builtin_unreachable();
|
||||
g_aud_from_host_rdptr+=2;
|
||||
sample <<= 16;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||
unsafe
|
||||
{
|
||||
mult = multOutPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
/* Note, in 2 byte subslot mode - ignore lower result of macs */
|
||||
h <<= 3;
|
||||
@@ -223,41 +298,17 @@ __builtin_unreachable();
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
/* Buffering not underflow condition send out some samples...*/
|
||||
for(int i = 0; i < g_numUsbChan_Out; i++)
|
||||
{
|
||||
#pragma xta endpoint "mixer_request"
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
|
||||
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
||||
g_aud_from_host_rdptr+=4;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<= 3;
|
||||
#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)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
outuint(c_mix_out, h);
|
||||
#else
|
||||
outuint(c_mix_out, sample);
|
||||
#endif
|
||||
}
|
||||
|
||||
SendSamples4(c_mix_out);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
#if (STREAM_FORMAT_OUTPUT_SUBSLOT_3_USED == 0)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
/* Buffering not underflow condition send out some samples...*/
|
||||
/* Note, in this case the unpacking of data is more of an overhead than the loop overhead
|
||||
* so we do not currently make attempts to unroll */
|
||||
for(int i = 0; i < g_numUsbChan_Out; i++)
|
||||
{
|
||||
#pragma xta endpoint "mixer_request"
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
@@ -289,19 +340,20 @@ __builtin_unreachable();
|
||||
}
|
||||
unpackState++;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||
unsafe
|
||||
{
|
||||
mult = multOutPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<= 3;
|
||||
outuint(c_mix_out, h);
|
||||
#else
|
||||
outuint(c_mix_out, sample);
|
||||
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
@@ -335,17 +387,20 @@ __builtin_unreachable();
|
||||
/* Receive sample */
|
||||
int sample = inuint(c_mix_out);
|
||||
#if (INPUT_VOLUME_CONTROL == 1)
|
||||
#if !defined(IN_VOLUME_IN_MIXER)
|
||||
#if (!IN_VOLUME_IN_MIXER)
|
||||
/* Apply volume */
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multIn),"r"(i));
|
||||
unsafe
|
||||
{
|
||||
mult = multInPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
sample = h << 3;
|
||||
|
||||
/* 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;
|
||||
#endif
|
||||
#endif
|
||||
@@ -365,18 +420,21 @@ __builtin_unreachable();
|
||||
/* Receive sample */
|
||||
int sample = inuint(c_mix_out);
|
||||
#if(INPUT_VOLUME_CONTROL == 1)
|
||||
#if !defined(IN_VOLUME_IN_MIXER)
|
||||
#if (!IN_VOLUME_IN_MIXER)
|
||||
/* Apply volume */
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multIn),"r"(i));
|
||||
unsafe
|
||||
{
|
||||
mult = multInPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
sample = h << 3;
|
||||
#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)
|
||||
#endif
|
||||
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
#elif (IN_VOLUME_IN_MIXER) && (IN_VOLUME_AFTER_MIX)
|
||||
sample = sample << 3;
|
||||
#endif
|
||||
#endif
|
||||
@@ -396,12 +454,15 @@ __builtin_unreachable();
|
||||
{
|
||||
/* Receive sample */
|
||||
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 */
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multIn),"r"(i));
|
||||
unsafe
|
||||
{
|
||||
mult = multInPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
sample = h << 3;
|
||||
#endif
|
||||
@@ -588,6 +649,7 @@ __builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Mark Endpoint (IN) ready with an appropriately sized zero buffer */
|
||||
static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned sampFreq, unsigned slotSize,
|
||||
xc_ptr aud_to_host_zeros)
|
||||
@@ -619,6 +681,7 @@ static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned samp
|
||||
|
||||
XUD_SetReady_InPtr(aud_to_host_usb_ep, aud_to_host_zeros+4, mid);
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma unsafe arrays
|
||||
void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
@@ -638,13 +701,6 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
|
||||
int t = array_to_xc_ptr(outAudioBuff);
|
||||
|
||||
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
p_multOut = array_to_xc_ptr(multOut);
|
||||
#endif
|
||||
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
|
||||
p_multIn = array_to_xc_ptr(multIn);
|
||||
#endif
|
||||
|
||||
aud_from_host_fifo_start = t;
|
||||
aud_from_host_fifo_end = aud_from_host_fifo_start + BUFF_SIZE_OUT;
|
||||
g_aud_from_host_wrptr = aud_from_host_fifo_start;
|
||||
@@ -668,17 +724,17 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
xc_ptr aud_to_host_zeros = t;
|
||||
|
||||
/* 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++)
|
||||
{
|
||||
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multOut),"r"(i));
|
||||
unsafe{
|
||||
multOutPtr[i] = MAX_VOLUME_MULT;
|
||||
}
|
||||
#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++)
|
||||
{
|
||||
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multIn),"r"(i));
|
||||
unsafe{
|
||||
multInPtr[i] = MAX_VOLUME_MULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -760,8 +816,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
/* Set buffer to send back to zeros buffer */
|
||||
aud_to_host_buffer = aud_to_host_zeros;
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Update size of zeros buffer (and sampsToWrite) */
|
||||
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
||||
#endif
|
||||
|
||||
/* Reset OUT buffer state */
|
||||
outUnderflow = 1;
|
||||
@@ -815,8 +873,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
/* Set buffer back to zeros buffer */
|
||||
aud_to_host_buffer = aud_to_host_zeros;
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Update size of zeros buffer (and sampsToWrite) */
|
||||
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
||||
#endif
|
||||
|
||||
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
|
||||
if (usbSpeed == XUD_SPEED_HS)
|
||||
|
||||
@@ -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.
|
||||
#include "xua.h"
|
||||
#if XUA_USB_EN
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "xud.h"
|
||||
#include "testct_byref.h"
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_HID_ENABLED
|
||||
#include "xua_hid_report.h"
|
||||
#include "user_hid.h"
|
||||
#include "xua_hid.h"
|
||||
@@ -105,7 +105,11 @@ void XUA_Buffer(
|
||||
#endif
|
||||
, chanend c_aud
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
#if(XUA_USE_APP_PLL)
|
||||
, chanend c_swpll_update
|
||||
#else
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
@@ -134,14 +138,18 @@ void XUA_Buffer(
|
||||
c_clk_int,
|
||||
#endif
|
||||
c_sof, c_aud_ctl, p_off_mclk
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_HID_ENABLED
|
||||
, c_hid
|
||||
#endif
|
||||
#ifdef CHAN_BUFF_CTRL
|
||||
, c_buff_ctrl
|
||||
#endif
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
, i_pll_ref
|
||||
#if(XUA_USE_APP_PLL)
|
||||
, c_swpll_update
|
||||
#else
|
||||
, i_pll_ref
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
|
||||
@@ -190,8 +198,12 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
#ifdef CHAN_BUFF_CTRL
|
||||
, chanend c_buff_ctrl
|
||||
#endif
|
||||
#if XUA_SYNCMODE == XUA_SYNCMODE_SYNC
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
#if (XUA_USE_APP_PLL)
|
||||
, chanend c_swpll_update
|
||||
#else
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#endif
|
||||
)
|
||||
{
|
||||
@@ -224,7 +236,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
XUD_ep ep_int = XUD_InitEp(c_ep_int);
|
||||
#endif
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_HID_ENABLED
|
||||
XUD_ep ep_hid = XUD_InitEp(c_hid);
|
||||
#endif
|
||||
unsigned u_tmp;
|
||||
@@ -247,7 +259,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
unsigned bufferIn = 1;
|
||||
#endif
|
||||
unsigned sofCount = 0;
|
||||
int sofCount = 0;
|
||||
int pllUpdate = 0;
|
||||
|
||||
unsigned mod_from_last_time = 0;
|
||||
#ifdef FB_TOLERANCE_TEST
|
||||
@@ -294,7 +307,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
unsigned iap_ea_native_interface_alt_setting = 0;
|
||||
unsigned iap_ea_native_control_to_send = 0;
|
||||
unsigned iap_ea_native_incoming = 0;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -332,7 +344,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_HID_ENABLED
|
||||
|
||||
while (!hidIsReportDescriptorPrepared())
|
||||
;
|
||||
@@ -357,12 +369,16 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
#ifndef LOCAL_CLOCK_MARGIN
|
||||
#define LOCAL_CLOCK_MARGIN (1000)
|
||||
#endif
|
||||
|
||||
#if (!XUA_USE_APP_PLL)
|
||||
timer t_sofCheck;
|
||||
unsigned timeLastEdge;
|
||||
unsigned timeNextEdge;
|
||||
t_sofCheck :> timeLastEdge;
|
||||
timeNextEdge + LOCAL_CLOCK_INCREMENT;
|
||||
i_pll_ref.toggle();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
while(1)
|
||||
@@ -427,7 +443,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
/* Reset FB */
|
||||
/* Note, Endpoint 0 will hold off host for a sufficient period to allow our feedback
|
||||
* to stabilise (i.e. sofCount == 128 to fire) */
|
||||
sofCount = 1;
|
||||
sofCount = 0;
|
||||
pllUpdate = 0;
|
||||
clocks = 0;
|
||||
clockcounter = 0;
|
||||
mod_from_last_time = 0;
|
||||
@@ -502,13 +519,13 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
}
|
||||
#endif
|
||||
/* Pass on sample freq change to decouple() via global flag (saves a chanend) */
|
||||
/* Note: freqChange flags now used to communicate other commands also */
|
||||
/* Note: freqChange_flag now used to communicate other commands also */
|
||||
SET_SHARED_GLOBAL0(g_freqChange, cmd); /* Set command */
|
||||
SET_SHARED_GLOBAL(g_freqChange_flag, cmd); /* Set Flag */
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_APP_PLL)
|
||||
case t_sofCheck when timerafter(timeNextEdge) :> void:
|
||||
i_pll_ref.toggle();
|
||||
timeLastEdge = timeNextEdge;
|
||||
@@ -528,7 +545,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
unsigned usbSpeed;
|
||||
int framesPerSec;
|
||||
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
|
||||
static int sofCount = 0;
|
||||
|
||||
framesPerSec = (usbSpeed == XUD_SPEED_HS) ? 8000 : 1000;
|
||||
|
||||
@@ -539,12 +555,27 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
sofCount += 1000;
|
||||
if (sofCount == framesPerSec)
|
||||
{
|
||||
sofCount = 0;
|
||||
pllUpdate++;
|
||||
#if (!XUA_USE_APP_PLL)
|
||||
/* Port is accessed via interface to allow flexibilty with location */
|
||||
i_pll_ref.toggle();
|
||||
t_sofCheck :> timeLastEdge;
|
||||
sofCount = 0;
|
||||
timeNextEdge = timeLastEdge + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||
#endif
|
||||
}
|
||||
#if (XUA_USE_APP_PLL)
|
||||
// Update PLL @ 100Hz
|
||||
if(pllUpdate == 10)
|
||||
{
|
||||
pllUpdate = 0;
|
||||
unsigned short mclk_pt;
|
||||
asm volatile("getts %0, res[%1]" : "=r" (mclk_pt) : "r" (p_off_mclk));
|
||||
outuint(c_swpll_update, mclk_pt);
|
||||
outct(c_swpll_update, XS1_CT_END);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
|
||||
|
||||
/* NOTE our feedback will be wrong for a couple of SOF's after a SF change due to
|
||||
@@ -646,7 +677,6 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
clockcounter = 0;
|
||||
}
|
||||
#else
|
||||
|
||||
/* Assuming 48kHz from a 24.576 master clock (0.0407uS period)
|
||||
* MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF.
|
||||
* expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format.
|
||||
@@ -897,8 +927,8 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
/* HID Report Data */
|
||||
#if (XUA_HID_ENABLED)
|
||||
/* HID Report Data */
|
||||
case XUD_SetData_Select(c_hid, ep_hid, result):
|
||||
hid_ready_flag = 0U;
|
||||
unsigned reportTime;
|
||||
@@ -911,7 +941,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
|
||||
#endif
|
||||
|
||||
#ifdef MIDI
|
||||
/* Received word from MIDI thread - Check for ACK or Data */
|
||||
/* Received word from MIDI thread - Check for ACK or Data */
|
||||
case midi_get_ack_or_data(c_midi, is_ack, datum):
|
||||
if (is_ack)
|
||||
{
|
||||
|
||||
457
lib_xua/src/core/clocking/apppll.xc
Normal file
457
lib_xua/src/core/clocking/apppll.xc
Normal file
@@ -0,0 +1,457 @@
|
||||
// Copyright 2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <print.h>
|
||||
#include <platform.h>
|
||||
#include "xua.h"
|
||||
#include "xassert.h"
|
||||
#include <stdio.h>
|
||||
#if (XUA_USE_APP_PLL)
|
||||
|
||||
/*
|
||||
* Functions for interacting with the secondary/application PLL
|
||||
*/
|
||||
|
||||
#ifndef __XS3A__
|
||||
#error App PLL not included in device
|
||||
#endif
|
||||
|
||||
/*
|
||||
* App PLL settings used for syncing to external clocks
|
||||
*/
|
||||
|
||||
// Define the PLL settings to generate the required frequencies.
|
||||
// All settings allow greater than +-1000ppm lock range.
|
||||
// Comment out the following line for 2us update.
|
||||
|
||||
//#define FAST_FRAC_REG_WRITE
|
||||
|
||||
// OPTION 1 - 1us register update rate - Lowest jitter
|
||||
// 10ps jitter 100Hz-40kHz. Low freq noise floor -100dBc
|
||||
|
||||
#ifdef FAST_FRAC_REG_WRITE
|
||||
|
||||
#define FRAC_REG_WRITE_DLY (100)
|
||||
|
||||
// Found solution: IN 24.000MHz, OUT 22.578947MHz, VCO 3251.37MHz, RD 1, FD 135.474 (m = 9, n = 19), OD 6, FOD 6, ERR -11.189ppm
|
||||
#define APP_PLL_CTL_SYNC_22M (0x0A808600)
|
||||
#define APP_PLL_DIV_SYNC_22M (0x80000005)
|
||||
#define APP_PLL_FRAC_SYNC_22M (0x80000812)
|
||||
#define APP_PLL_ERR_MULT_22M (627) // round(135(divider)*100Hz*1048576/22579200)
|
||||
#define APP_PLL_MOD_INIT_22M (498283)
|
||||
|
||||
// Fout = Fin*divider/(2*2*6*6) = (fin/144) * divider = (24/144) * divider. = 1/6 * divider.
|
||||
// To achieve frequency f, Fraction Setting = (6*f) - 135
|
||||
// So to achieve 22.5792MHz, Fraction Setting = (6*22.5792) - 135 = 0.4752
|
||||
// Numerical input = round((Fraction setting * 2^20) = 0.4752 * 1048576 = 498283
|
||||
|
||||
//Found solution: IN 24.000MHz, OUT 24.575758MHz, VCO 3538.91MHz, RD 1, FD 147.455 (m = 5, n = 11), OD 6, FOD 6, ERR -9.864ppm
|
||||
#define APP_PLL_CTL_SYNC_24M (0x0A809200)
|
||||
#define APP_PLL_DIV_SYNC_24M (0x80000005)
|
||||
#define APP_PLL_FRAC_SYNC_24M (0x8000040A)
|
||||
#define APP_PLL_ERR_MULT_24M (627) // round(147(divider)*100Hz*1048576/24576000)
|
||||
#define APP_PLL_MOD_INIT_24M (478151)
|
||||
|
||||
// Fout = Fin*divider/(2*2*6*6) = (fin/144) * divider = (24/144) * divider. = 1/6 * divider.
|
||||
// To achieve frequency f, Fraction Setting = (6*f) - 147
|
||||
// So to achieve 24.576MHz, Fraction Setting = (6*24.576) - 147 = 0.456
|
||||
// Numerical input = round((Fraction setting * 2^20) = 0.456 * 1048576 = 478151
|
||||
|
||||
#else
|
||||
|
||||
// OPTION 2 - 2us register update rate - Higher jitter
|
||||
// 50ps jitter 100Hz-40kHz. Low freq noise floor -93dBc
|
||||
|
||||
#define FRAC_REG_WRITE_DLY (200)
|
||||
|
||||
//Found solution: IN 24.000MHz, OUT 22.579186MHz, VCO 3522.35MHz, RD 2, FD 293.529 (m = 9, n = 17), OD 3, FOD 13, ERR -0.641ppm
|
||||
#define APP_PLL_CTL_SYNC_22M (0x09012401)
|
||||
#define APP_PLL_DIV_SYNC_22M (0x8000000C)
|
||||
#define APP_PLL_FRAC_SYNC_22M (0x80000810)
|
||||
#define APP_PLL_ERR_MULT_22M (1361) // round(293(divider)*100Hz*1048576/22579200)
|
||||
#define APP_PLL_MOD_INIT_22M (555326)
|
||||
|
||||
// Fout = (Fin/2)*divider/(2*2*3*13) = (fin/312) * divider = (24/312) * divider. = 1/13 * divider.
|
||||
// To achieve frequency f, Fraction Setting = (13*f) - 293
|
||||
// So to achieve 22.5792MHz, Fraction Setting = (13*22.5792) - 293 = 0.5296
|
||||
// Numerical input = round((Fraction setting * 2^20) = 0.5296 * 1048576 = 555326
|
||||
|
||||
//Found solution: IN 24.000MHz, OUT 24.576125MHz, VCO 3342.35MHz, RD 2, FD 278.529 (m = 9, n = 17), OD 2, FOD 17, ERR 5.069ppm - Runs VCO out fractionally out of spec at 835MHz
|
||||
#define APP_PLL_CTL_SYNC_24M (0x08811501)
|
||||
#define APP_PLL_DIV_SYNC_24M (0x80000010)
|
||||
#define APP_PLL_FRAC_SYNC_24M (0x80000810)
|
||||
#define APP_PLL_ERR_MULT_24M (1186) // round(278(divider)*100Hz*1048576/24576000)
|
||||
#define APP_PLL_MOD_INIT_24M (553648)
|
||||
|
||||
// Fout = (Fin/2)*divider/(2*2*2*17) = (fin/272) * divider = (24/272) * divider. = 3/34 * divider.
|
||||
// To achieve frequency f, Fraction Setting = ((34/3)*f) - 278
|
||||
// So to achieve 24.576MHz, Fraction Setting = ((34/3)*24.576) - 278 = 0.528
|
||||
// Numerical input = round((Fraction setting * 2^20) = 0.528 * 1048576 = 553648
|
||||
#endif
|
||||
|
||||
/*
|
||||
* App PLL settings used for low jitter fixed local clocks
|
||||
*/
|
||||
|
||||
//Found solution: IN 24.000MHz, OUT 49.151786MHz, VCO 3145.71MHz, RD 1, FD 131.071 (m = 1, n = 14), OD 8, FOD 2, ERR -4.36ppm
|
||||
// Measure: 100Hz-40kHz: ~7ps
|
||||
// 100Hz-1MHz: 70ps.
|
||||
// 100Hz high pass: 118ps.
|
||||
#define APP_PLL_CTL_FIXED_49M (0x0B808200)
|
||||
#define APP_PLL_DIV_FIXED_49M (0x80000001)
|
||||
#define APP_PLL_FRAC_FIXED_49M (0x8000000D)
|
||||
|
||||
//Found solution: IN 24.000MHz, OUT 45.157895MHz, VCO 2709.47MHz, RD 1, FD 112.895 (m = 17, n = 19), OD 5, FOD 3, ERR -11.19ppm
|
||||
// Measure: 100Hz-40kHz: 6.5ps
|
||||
// 100Hz-1MHz: 67ps.
|
||||
// 100Hz high pass: 215ps.
|
||||
#define APP_PLL_CTL_FIXED_45M (0x0A006F00)
|
||||
#define APP_PLL_DIV_FIXED_45M (0x80000002)
|
||||
#define APP_PLL_FRAC_FIXED_45M (0x80001012)
|
||||
|
||||
// Found solution: IN 24.000MHz, OUT 24.576000MHz, VCO 2457.60MHz, RD 1, FD 102.400 (m = 2, n = 5), OD 5, FOD 5, ERR 0.0ppm
|
||||
// Measure: 100Hz-40kHz: ~8ps
|
||||
// 100Hz-1MHz: 63ps.
|
||||
// 100Hz high pass: 127ps.
|
||||
#define APP_PLL_CTL_FIXED_24M (0x0A006500)
|
||||
#define APP_PLL_DIV_FIXED_24M (0x80000004)
|
||||
#define APP_PLL_FRAC_FIXED_24M (0x80000104)
|
||||
|
||||
// Found solution: IN 24.000MHz, OUT 22.579186MHz, VCO 3522.35MHz, RD 1, FD 146.765 (m = 13, n = 17), OD 3, FOD 13, ERR -0.641ppm
|
||||
// Measure: 100Hz-40kHz: 7ps
|
||||
// 100Hz-1MHz: 67ps.
|
||||
// 100Hz high pass: 260ps.
|
||||
#define APP_PLL_CTL_FIXED_22M (0x09009100)
|
||||
#define APP_PLL_DIV_FIXED_22M (0x8000000C)
|
||||
#define APP_PLL_FRAC_FIXED_22M (0x80000C10)
|
||||
|
||||
#define APP_PLL_CTL_FIXED_12M (0x0A006500)
|
||||
#define APP_PLL_DIV_FIXED_12M (0x80000009)
|
||||
#define APP_PLL_FRAC_FIXED_12M (0x80000104)
|
||||
|
||||
#define APP_PLL_CTL_FIXED_11M (0x09009100)
|
||||
#define APP_PLL_DIV_FIXED_11M (0x80000009)
|
||||
#define APP_PLL_FRAC_FIXED_11M (0x80000C10)
|
||||
|
||||
#define APP_PLL_CTL_ENABLE (1 << 27)
|
||||
#define APP_PLL_CLK_OUTPUT_ENABLE (1 << 16)
|
||||
|
||||
static void set_app_pll_init(tileref tile, int app_pll_ctrl)
|
||||
{
|
||||
// Disable the PLL
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (app_pll_ctrl & ~APP_PLL_CTL_ENABLE));
|
||||
|
||||
// Enable the PLL to invoke a reset on the appPLL.
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctrl);
|
||||
|
||||
// Must write the CTL register twice so that the F and R divider values are captured using a running clock.
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctrl);
|
||||
|
||||
// Now disable and re-enable the PLL so we get the full 5us reset time with the correct F and R values.
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, (app_pll_ctrl & 0xF7FFFFFF));
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, app_pll_ctrl);
|
||||
|
||||
// Wait for PLL to lock.
|
||||
delay_microseconds(500);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AppPllEnable(tileref tile, int clkFreq_hz)
|
||||
{
|
||||
unsigned app_pll_ctrl, app_pll_div, app_pll_frac;
|
||||
|
||||
/* Decide on App PLL settings */
|
||||
if(XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
{
|
||||
switch(clkFreq_hz)
|
||||
{
|
||||
case 44100 * 512:
|
||||
app_pll_ctrl = APP_PLL_CTL_SYNC_22M;
|
||||
app_pll_div = APP_PLL_DIV_SYNC_22M;
|
||||
app_pll_frac = APP_PLL_FRAC_SYNC_22M;
|
||||
break;
|
||||
|
||||
case 48000 * 512:
|
||||
app_pll_ctrl = APP_PLL_CTL_SYNC_24M;
|
||||
app_pll_div = APP_PLL_DIV_SYNC_24M;
|
||||
app_pll_frac = APP_PLL_FRAC_SYNC_24M;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(clkFreq_hz)
|
||||
{
|
||||
case 44100 * 256:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_11M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_11M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_11M;
|
||||
break;
|
||||
|
||||
case 48000 * 256:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_12M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_12M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_12M;
|
||||
break;
|
||||
|
||||
case 44100 * 512:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_22M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_22M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_22M;
|
||||
break;
|
||||
|
||||
case 48000 * 512:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_24M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_24M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_24M;
|
||||
break;
|
||||
|
||||
case 44100 * 1024:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_45M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_45M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_45M;
|
||||
break;
|
||||
|
||||
case 48000 * 1024:
|
||||
app_pll_ctrl = APP_PLL_CTL_FIXED_49M;
|
||||
app_pll_div = APP_PLL_DIV_FIXED_49M;
|
||||
app_pll_frac = APP_PLL_FRAC_FIXED_49M;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise the AppPLL and get it running.
|
||||
set_app_pll_init(tile, app_pll_ctrl);
|
||||
|
||||
// Write the fractional-n register, note, the top bit is set to enable the frac-n block.
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, app_pll_frac);
|
||||
|
||||
// And then write the clock divider register to enable the output
|
||||
write_node_config_reg(tile, XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, app_pll_div);
|
||||
|
||||
// Wait for PLL output frequency to stabilise due to fractional divider enable
|
||||
delay_microseconds(100);
|
||||
}
|
||||
|
||||
void SoftPllInit(int clkFreq_hz, struct SoftPllState &pllState)
|
||||
{
|
||||
switch(clkFreq_hz)
|
||||
{
|
||||
case 44100 * 512:
|
||||
pllState.expectedClkMod = 29184; // Count we expect on MCLK port timer at SW PLL check point. For 100Hz, 10ms.
|
||||
pllState.initialSetting = APP_PLL_MOD_INIT_22M;
|
||||
pllState.initialErrorMult = APP_PLL_ERR_MULT_22M;
|
||||
break;
|
||||
|
||||
case 48000 * 512:
|
||||
pllState.expectedClkMod = 49152;
|
||||
pllState.initialSetting = APP_PLL_MOD_INIT_24M;
|
||||
pllState.initialErrorMult = APP_PLL_ERR_MULT_24M;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
pllState.ds_in = pllState.initialSetting;
|
||||
pllState.ds_x1 = 0;
|
||||
pllState.ds_x2 = 0;
|
||||
pllState.ds_x3 = 0;
|
||||
pllState.iir_y = 0;
|
||||
pllState.phaseError = 0;
|
||||
pllState.phaseErrorInt = 0;
|
||||
}
|
||||
|
||||
int SoftPllUpdate(tileref tile, unsigned short mclk_pt, unsigned short mclk_pt_last, struct SoftPllState &pllState, int fastLock)
|
||||
{
|
||||
int freq_error, error_p, error_i;
|
||||
|
||||
unsigned expectedClksMod = pllState.expectedClkMod;
|
||||
unsigned initialSetting = pllState.initialSetting;
|
||||
unsigned init_err_mult = pllState.initialErrorMult;
|
||||
|
||||
int newSetting;
|
||||
unsigned short expectedPt;
|
||||
|
||||
int set = -1;
|
||||
int diff;
|
||||
|
||||
// expectedClkMod is the value of the port counter that we expect given the desired MCLK in the 10ms time period we are running at.
|
||||
expectedPt = mclk_pt_last + expectedClksMod;
|
||||
|
||||
// Handle wrapping
|
||||
if (porttimeafter(mclk_pt, expectedPt))
|
||||
{
|
||||
diff = -(short)(expectedPt - mclk_pt);
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = (short)(mclk_pt - expectedPt);
|
||||
}
|
||||
|
||||
// TODO Add a bounds checker on diff to make sure it's roughly where we expect.
|
||||
// If it isn't we should ignore it as it's either a glitch or from clock start/stop.
|
||||
|
||||
if(fastLock) // Fast lock - set DCO based on measured frequency error in first cycle
|
||||
{
|
||||
initialSetting = initialSetting - (diff * init_err_mult); // init_err_mult is the dco input change to cause an output frequency offset equating to a measured input freq error of 1.
|
||||
diff = 0; // reset diff to zero so following code does not see any error in this cycle.
|
||||
}
|
||||
|
||||
// Absolute frequency error for last measurement cycle. If diff is positive, port timer was beyond where it should have been, so MCLK was too fast. So this needs to describe a negative error.
|
||||
freq_error = -diff;
|
||||
|
||||
// Phase error is the integral of frequency error.
|
||||
pllState.phaseError += freq_error;
|
||||
|
||||
// Integral of phase error for use in PI loop below.
|
||||
pllState.phaseErrorInt += pllState.phaseError;
|
||||
|
||||
error_p = (pllState.phaseError << 5); // << 5 => Kp = 32
|
||||
error_i = (pllState.phaseErrorInt >> 2); // >> 2 => Ki = 0.25
|
||||
|
||||
// input to filter (x) is output of PI controller
|
||||
int x = (error_p + error_i);
|
||||
|
||||
// Filter some noise into DCO to reduce jitter
|
||||
// First order IIR, make A=0.125
|
||||
// y = y + A(x-y)
|
||||
pllState.iir_y += ((x-pllState.iir_y)>>3);
|
||||
|
||||
newSetting = pllState.iir_y;
|
||||
|
||||
// Only output new frequency tune value if different to the previous setting
|
||||
if (newSetting != pllState.setting)
|
||||
{
|
||||
set = (initialSetting + newSetting); // init_set is our calculation of the setting required after measuring one cycle, should be accurate to +- 1MCLK.
|
||||
|
||||
if (set < 0)
|
||||
set = 0;
|
||||
else if (set > 0xFFFFF)
|
||||
set = 0xFFFFF;
|
||||
}
|
||||
|
||||
pllState.setting = newSetting;
|
||||
|
||||
// Return the setting to the NCO thread. -1 means no update
|
||||
return set;
|
||||
}
|
||||
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
|
||||
[[distributable]]
|
||||
#endif
|
||||
void XUA_SoftPll(tileref tile, server interface SoftPll_if i_softPll, chanend c_update)
|
||||
{
|
||||
#if (XUA_SYNCMODE != XUA_SYNCMODE_ASYNC)
|
||||
unsigned frac_val;
|
||||
int ds_out;
|
||||
timer tmr;
|
||||
int time;
|
||||
unsigned mclk_pt;
|
||||
unsigned short mclk_pt_last;
|
||||
tmr :> time;
|
||||
#endif
|
||||
struct SoftPllState pllState;
|
||||
int running = 0;
|
||||
int firstUpdate = 1;
|
||||
int fastLock = 1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
select
|
||||
{
|
||||
/* Interface used for basic frequency setting such that it can be distributed
|
||||
* when the update code is not required */
|
||||
case i_softPll.init(int mclk_hz):
|
||||
AppPllEnable(tile, mclk_hz);
|
||||
SoftPllInit(mclk_hz, pllState);
|
||||
running = 1;
|
||||
firstUpdate = 1;
|
||||
fastLock = 1;
|
||||
break;
|
||||
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_ASYNC)
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Channel used for update such that other side is not blocked */
|
||||
/* TODO add CT handshake before opening route */
|
||||
case inuint_byref(c_update, mclk_pt):
|
||||
inct(c_update);
|
||||
|
||||
if(firstUpdate)
|
||||
{
|
||||
firstUpdate = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int setting = SoftPllUpdate(tile, (unsigned short) mclk_pt, mclk_pt_last, pllState, fastLock);
|
||||
|
||||
fastLock = 0;
|
||||
|
||||
if(setting != -1)
|
||||
{
|
||||
pllState.ds_in = setting;
|
||||
// Limit input range for modulator stability.
|
||||
if(pllState.ds_in > 980000)
|
||||
pllState.ds_in = 980000;
|
||||
if(pllState.ds_in < 60000)
|
||||
pllState.ds_in = 60000;
|
||||
}
|
||||
}
|
||||
|
||||
mclk_pt_last = (unsigned short) mclk_pt;
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Third order, 9 level output delta sigma. 20 bit unsigned input.
|
||||
ds_out = ((pllState.ds_x3<<4) + (pllState.ds_x3<<1)) >> 13;
|
||||
if (ds_out > 8)
|
||||
ds_out = 8;
|
||||
if (ds_out < 0)
|
||||
ds_out = 0;
|
||||
pllState.ds_x3 += (pllState.ds_x2>>5) - (ds_out<<9) - (ds_out<<8);
|
||||
pllState.ds_x2 += (pllState.ds_x1>>5) - (ds_out<<14);
|
||||
pllState.ds_x1 += pllState.ds_in - (ds_out<<17);
|
||||
|
||||
if (ds_out == 0)
|
||||
frac_val = 0x00000007; // 0/8
|
||||
else
|
||||
frac_val = ((ds_out - 1) << 8) | 0x80000007; // 1/8 to 8/8
|
||||
|
||||
// Now write the register.
|
||||
// We need to write the register at a specific period at a fast rate.
|
||||
// This period needs to be (div ref clk period (ns) * how many times we repeat same value)
|
||||
// In this case, div ref clk = 24/3 = 8MHz. So div ref clk period = 125ns.
|
||||
// We're using fraction denominators of 8, so these repeat every 8*125ns = 1us.
|
||||
// So minimum period we could use is 1us and multiples thereof.
|
||||
// The slower we write, the higher our jitter will be.
|
||||
|
||||
time += FRAC_REG_WRITE_DLY; // Time the reg write.
|
||||
tmr when timerafter(time) :> void;
|
||||
|
||||
// Write the register. Because we are timing the reg writes accurately we do not need to use reg write with ack.
|
||||
// This saves a lot of time. Additionally, apparently we can shorten the time for this reg write by only setting up the channel once and just doing a few instructions to do the write each time.
|
||||
// We can hard code this in assembler.
|
||||
if(running)
|
||||
{
|
||||
write_node_config_reg_no_ack(tile, XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, frac_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -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.
|
||||
|
||||
#include <xs1.h>
|
||||
@@ -13,14 +13,14 @@
|
||||
#include "spdif.h"
|
||||
#endif
|
||||
|
||||
#define LOCAL_CLOCK_INCREMENT 166667
|
||||
#define LOCAL_CLOCK_MARGIN 1666
|
||||
#define LOCAL_CLOCK_INCREMENT (166667)
|
||||
#define LOCAL_CLOCK_MARGIN (1666)
|
||||
|
||||
#define MAX_SAMPLES 64 /* Must be power of 2 */
|
||||
#define MAX_SAMPLES (64) /* Must be power of 2 */
|
||||
#define MAX_SPDIF_SAMPLES (2 * MAX_SAMPLES) /* Must be power of 2 */
|
||||
#define MAX_ADAT_SAMPLES (8 * MAX_SAMPLES) /* Must be power of 2 */
|
||||
|
||||
#define SPDIF_FRAME_ERRORS_THRESH 40
|
||||
#define SPDIF_FRAME_ERRORS_THRESH (40)
|
||||
|
||||
unsigned g_digData[10];
|
||||
|
||||
@@ -241,12 +241,7 @@ extern int samples_to_host_inputs_buff[NUM_USB_CHAN_IN];
|
||||
int VendorAudCoreReqs(unsigned cmd, chanend c);
|
||||
|
||||
#pragma unsafe arrays
|
||||
//#if (AUDIO_IO_TILE == PLL_REF_TILE)
|
||||
#if 0
|
||||
void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, out port p, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int)
|
||||
#else
|
||||
void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interface pll_ref_if i_pll_ref, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int)
|
||||
#endif
|
||||
{
|
||||
timer t_local;
|
||||
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
|
||||
@@ -723,7 +718,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
|
||||
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
/* Mixer requests data */
|
||||
/* AudioHub requests data */
|
||||
case inuint_byref(c_dig_rx, tmp):
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
if(spdifUnderflow)
|
||||
|
||||
398
lib_xua/src/core/clocking/fractions_80_top.h
Normal file
398
lib_xua/src/core/clocking/fractions_80_top.h
Normal file
@@ -0,0 +1,398 @@
|
||||
// Copyright 2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
// Header file listing fraction options searched
|
||||
// These values to go in the bottom 16 bits of the secondary PLL fractional-n divider register.
|
||||
short frac_values_80[391] = {
|
||||
0x3C4B, // Index: 0 Fraction: 61/76 = 0.8026
|
||||
0x3846, // Index: 1 Fraction: 57/71 = 0.8028
|
||||
0x3441, // Index: 2 Fraction: 53/66 = 0.8030
|
||||
0x303C, // Index: 3 Fraction: 49/61 = 0.8033
|
||||
0x2C37, // Index: 4 Fraction: 45/56 = 0.8036
|
||||
0x2832, // Index: 5 Fraction: 41/51 = 0.8039
|
||||
0x242D, // Index: 6 Fraction: 37/46 = 0.8043
|
||||
0x2028, // Index: 7 Fraction: 33/41 = 0.8049
|
||||
0x3D4C, // Index: 8 Fraction: 62/77 = 0.8052
|
||||
0x1C23, // Index: 9 Fraction: 29/36 = 0.8056
|
||||
0x3542, // Index: 10 Fraction: 54/67 = 0.8060
|
||||
0x181E, // Index: 11 Fraction: 25/31 = 0.8065
|
||||
0x2D38, // Index: 12 Fraction: 46/57 = 0.8070
|
||||
0x1419, // Index: 13 Fraction: 21/26 = 0.8077
|
||||
0x3A48, // Index: 14 Fraction: 59/73 = 0.8082
|
||||
0x252E, // Index: 15 Fraction: 38/47 = 0.8085
|
||||
0x3643, // Index: 16 Fraction: 55/68 = 0.8088
|
||||
0x1014, // Index: 17 Fraction: 17/21 = 0.8095
|
||||
0x3F4E, // Index: 18 Fraction: 64/79 = 0.8101
|
||||
0x2E39, // Index: 19 Fraction: 47/58 = 0.8103
|
||||
0x1D24, // Index: 20 Fraction: 30/37 = 0.8108
|
||||
0x2A34, // Index: 21 Fraction: 43/53 = 0.8113
|
||||
0x3744, // Index: 22 Fraction: 56/69 = 0.8116
|
||||
0x0C0F, // Index: 23 Fraction: 13/16 = 0.8125
|
||||
0x3C4A, // Index: 24 Fraction: 61/75 = 0.8133
|
||||
0x2F3A, // Index: 25 Fraction: 48/59 = 0.8136
|
||||
0x222A, // Index: 26 Fraction: 35/43 = 0.8140
|
||||
0x3845, // Index: 27 Fraction: 57/70 = 0.8143
|
||||
0x151A, // Index: 28 Fraction: 22/27 = 0.8148
|
||||
0x3440, // Index: 29 Fraction: 53/65 = 0.8154
|
||||
0x1E25, // Index: 30 Fraction: 31/38 = 0.8158
|
||||
0x2730, // Index: 31 Fraction: 40/49 = 0.8163
|
||||
0x303B, // Index: 32 Fraction: 49/60 = 0.8167
|
||||
0x3946, // Index: 33 Fraction: 58/71 = 0.8169
|
||||
0x080A, // Index: 34 Fraction: 9/11 = 0.8182
|
||||
0x3A47, // Index: 35 Fraction: 59/72 = 0.8194
|
||||
0x313C, // Index: 36 Fraction: 50/61 = 0.8197
|
||||
0x2831, // Index: 37 Fraction: 41/50 = 0.8200
|
||||
0x1F26, // Index: 38 Fraction: 32/39 = 0.8205
|
||||
0x3642, // Index: 39 Fraction: 55/67 = 0.8209
|
||||
0x161B, // Index: 40 Fraction: 23/28 = 0.8214
|
||||
0x3B48, // Index: 41 Fraction: 60/73 = 0.8219
|
||||
0x242C, // Index: 42 Fraction: 37/45 = 0.8222
|
||||
0x323D, // Index: 43 Fraction: 51/62 = 0.8226
|
||||
0x404E, // Index: 44 Fraction: 65/79 = 0.8228
|
||||
0x0D10, // Index: 45 Fraction: 14/17 = 0.8235
|
||||
0x3C49, // Index: 46 Fraction: 61/74 = 0.8243
|
||||
0x2E38, // Index: 47 Fraction: 47/57 = 0.8246
|
||||
0x2027, // Index: 48 Fraction: 33/40 = 0.8250
|
||||
0x333E, // Index: 49 Fraction: 52/63 = 0.8254
|
||||
0x1216, // Index: 50 Fraction: 19/23 = 0.8261
|
||||
0x3D4A, // Index: 51 Fraction: 62/75 = 0.8267
|
||||
0x2A33, // Index: 52 Fraction: 43/52 = 0.8269
|
||||
0x171C, // Index: 53 Fraction: 24/29 = 0.8276
|
||||
0x343F, // Index: 54 Fraction: 53/64 = 0.8281
|
||||
0x1C22, // Index: 55 Fraction: 29/35 = 0.8286
|
||||
0x3E4B, // Index: 56 Fraction: 63/76 = 0.8289
|
||||
0x2128, // Index: 57 Fraction: 34/41 = 0.8293
|
||||
0x262E, // Index: 58 Fraction: 39/47 = 0.8298
|
||||
0x2B34, // Index: 59 Fraction: 44/53 = 0.8302
|
||||
0x303A, // Index: 60 Fraction: 49/59 = 0.8305
|
||||
0x3540, // Index: 61 Fraction: 54/65 = 0.8308
|
||||
0x3A46, // Index: 62 Fraction: 59/71 = 0.8310
|
||||
0x3F4C, // Index: 63 Fraction: 64/77 = 0.8312
|
||||
0x0405, // Index: 64 Fraction: 5/6 = 0.8333
|
||||
0x414E, // Index: 65 Fraction: 66/79 = 0.8354
|
||||
0x3C48, // Index: 66 Fraction: 61/73 = 0.8356
|
||||
0x3742, // Index: 67 Fraction: 56/67 = 0.8358
|
||||
0x323C, // Index: 68 Fraction: 51/61 = 0.8361
|
||||
0x2D36, // Index: 69 Fraction: 46/55 = 0.8364
|
||||
0x2830, // Index: 70 Fraction: 41/49 = 0.8367
|
||||
0x232A, // Index: 71 Fraction: 36/43 = 0.8372
|
||||
0x424F, // Index: 72 Fraction: 67/80 = 0.8375
|
||||
0x1E24, // Index: 73 Fraction: 31/37 = 0.8378
|
||||
0x3843, // Index: 74 Fraction: 57/68 = 0.8382
|
||||
0x191E, // Index: 75 Fraction: 26/31 = 0.8387
|
||||
0x2E37, // Index: 76 Fraction: 47/56 = 0.8393
|
||||
0x1418, // Index: 77 Fraction: 21/25 = 0.8400
|
||||
0x3944, // Index: 78 Fraction: 58/69 = 0.8406
|
||||
0x242B, // Index: 79 Fraction: 37/44 = 0.8409
|
||||
0x343E, // Index: 80 Fraction: 53/63 = 0.8413
|
||||
0x0F12, // Index: 81 Fraction: 16/19 = 0.8421
|
||||
0x3A45, // Index: 82 Fraction: 59/70 = 0.8429
|
||||
0x2A32, // Index: 83 Fraction: 43/51 = 0.8431
|
||||
0x1A1F, // Index: 84 Fraction: 27/32 = 0.8438
|
||||
0x404C, // Index: 85 Fraction: 65/77 = 0.8442
|
||||
0x252C, // Index: 86 Fraction: 38/45 = 0.8444
|
||||
0x3039, // Index: 87 Fraction: 49/58 = 0.8448
|
||||
0x3B46, // Index: 88 Fraction: 60/71 = 0.8451
|
||||
0x0A0C, // Index: 89 Fraction: 11/13 = 0.8462
|
||||
0x3C47, // Index: 90 Fraction: 61/72 = 0.8472
|
||||
0x313A, // Index: 91 Fraction: 50/59 = 0.8475
|
||||
0x262D, // Index: 92 Fraction: 39/46 = 0.8478
|
||||
0x424E, // Index: 93 Fraction: 67/79 = 0.8481
|
||||
0x1B20, // Index: 94 Fraction: 28/33 = 0.8485
|
||||
0x2C34, // Index: 95 Fraction: 45/53 = 0.8491
|
||||
0x3D48, // Index: 96 Fraction: 62/73 = 0.8493
|
||||
0x1013, // Index: 97 Fraction: 17/20 = 0.8500
|
||||
0x3842, // Index: 98 Fraction: 57/67 = 0.8507
|
||||
0x272E, // Index: 99 Fraction: 40/47 = 0.8511
|
||||
0x3E49, // Index: 100 Fraction: 63/74 = 0.8514
|
||||
0x161A, // Index: 101 Fraction: 23/27 = 0.8519
|
||||
0x333C, // Index: 102 Fraction: 52/61 = 0.8525
|
||||
0x1C21, // Index: 103 Fraction: 29/34 = 0.8529
|
||||
0x3F4A, // Index: 104 Fraction: 64/75 = 0.8533
|
||||
0x2228, // Index: 105 Fraction: 35/41 = 0.8537
|
||||
0x282F, // Index: 106 Fraction: 41/48 = 0.8542
|
||||
0x2E36, // Index: 107 Fraction: 47/55 = 0.8545
|
||||
0x343D, // Index: 108 Fraction: 53/62 = 0.8548
|
||||
0x3A44, // Index: 109 Fraction: 59/69 = 0.8551
|
||||
0x404B, // Index: 110 Fraction: 65/76 = 0.8553
|
||||
0x0506, // Index: 111 Fraction: 6/7 = 0.8571
|
||||
0x424D, // Index: 112 Fraction: 67/78 = 0.8590
|
||||
0x3C46, // Index: 113 Fraction: 61/71 = 0.8592
|
||||
0x363F, // Index: 114 Fraction: 55/64 = 0.8594
|
||||
0x3038, // Index: 115 Fraction: 49/57 = 0.8596
|
||||
0x2A31, // Index: 116 Fraction: 43/50 = 0.8600
|
||||
0x242A, // Index: 117 Fraction: 37/43 = 0.8605
|
||||
0x434E, // Index: 118 Fraction: 68/79 = 0.8608
|
||||
0x1E23, // Index: 119 Fraction: 31/36 = 0.8611
|
||||
0x3740, // Index: 120 Fraction: 56/65 = 0.8615
|
||||
0x181C, // Index: 121 Fraction: 25/29 = 0.8621
|
||||
0x444F, // Index: 122 Fraction: 69/80 = 0.8625
|
||||
0x2B32, // Index: 123 Fraction: 44/51 = 0.8627
|
||||
0x3E48, // Index: 124 Fraction: 63/73 = 0.8630
|
||||
0x1215, // Index: 125 Fraction: 19/22 = 0.8636
|
||||
0x323A, // Index: 126 Fraction: 51/59 = 0.8644
|
||||
0x1F24, // Index: 127 Fraction: 32/37 = 0.8649
|
||||
0x2C33, // Index: 128 Fraction: 45/52 = 0.8654
|
||||
0x3942, // Index: 129 Fraction: 58/67 = 0.8657
|
||||
0x0C0E, // Index: 130 Fraction: 13/15 = 0.8667
|
||||
0x3A43, // Index: 131 Fraction: 59/68 = 0.8676
|
||||
0x2D34, // Index: 132 Fraction: 46/53 = 0.8679
|
||||
0x2025, // Index: 133 Fraction: 33/38 = 0.8684
|
||||
0x343C, // Index: 134 Fraction: 53/61 = 0.8689
|
||||
0x1316, // Index: 135 Fraction: 20/23 = 0.8696
|
||||
0x424C, // Index: 136 Fraction: 67/77 = 0.8701
|
||||
0x2E35, // Index: 137 Fraction: 47/54 = 0.8704
|
||||
0x1A1E, // Index: 138 Fraction: 27/31 = 0.8710
|
||||
0x3C45, // Index: 139 Fraction: 61/70 = 0.8714
|
||||
0x2126, // Index: 140 Fraction: 34/39 = 0.8718
|
||||
0x282E, // Index: 141 Fraction: 41/47 = 0.8723
|
||||
0x2F36, // Index: 142 Fraction: 48/55 = 0.8727
|
||||
0x363E, // Index: 143 Fraction: 55/63 = 0.8730
|
||||
0x3D46, // Index: 144 Fraction: 62/71 = 0.8732
|
||||
0x444E, // Index: 145 Fraction: 69/79 = 0.8734
|
||||
0x0607, // Index: 146 Fraction: 7/8 = 0.8750
|
||||
0x3F48, // Index: 147 Fraction: 64/73 = 0.8767
|
||||
0x3840, // Index: 148 Fraction: 57/65 = 0.8769
|
||||
0x3138, // Index: 149 Fraction: 50/57 = 0.8772
|
||||
0x2A30, // Index: 150 Fraction: 43/49 = 0.8776
|
||||
0x2328, // Index: 151 Fraction: 36/41 = 0.8780
|
||||
0x4049, // Index: 152 Fraction: 65/74 = 0.8784
|
||||
0x1C20, // Index: 153 Fraction: 29/33 = 0.8788
|
||||
0x3239, // Index: 154 Fraction: 51/58 = 0.8793
|
||||
0x1518, // Index: 155 Fraction: 22/25 = 0.8800
|
||||
0x3A42, // Index: 156 Fraction: 59/67 = 0.8806
|
||||
0x2429, // Index: 157 Fraction: 37/42 = 0.8810
|
||||
0x333A, // Index: 158 Fraction: 52/59 = 0.8814
|
||||
0x424B, // Index: 159 Fraction: 67/76 = 0.8816
|
||||
0x0E10, // Index: 160 Fraction: 15/17 = 0.8824
|
||||
0x434C, // Index: 161 Fraction: 68/77 = 0.8831
|
||||
0x343B, // Index: 162 Fraction: 53/60 = 0.8833
|
||||
0x252A, // Index: 163 Fraction: 38/43 = 0.8837
|
||||
0x3C44, // Index: 164 Fraction: 61/69 = 0.8841
|
||||
0x1619, // Index: 165 Fraction: 23/26 = 0.8846
|
||||
0x353C, // Index: 166 Fraction: 54/61 = 0.8852
|
||||
0x1E22, // Index: 167 Fraction: 31/35 = 0.8857
|
||||
0x454E, // Index: 168 Fraction: 70/79 = 0.8861
|
||||
0x262B, // Index: 169 Fraction: 39/44 = 0.8864
|
||||
0x2E34, // Index: 170 Fraction: 47/53 = 0.8868
|
||||
0x363D, // Index: 171 Fraction: 55/62 = 0.8871
|
||||
0x3E46, // Index: 172 Fraction: 63/71 = 0.8873
|
||||
0x464F, // Index: 173 Fraction: 71/80 = 0.8875
|
||||
0x0708, // Index: 174 Fraction: 8/9 = 0.8889
|
||||
0x4048, // Index: 175 Fraction: 65/73 = 0.8904
|
||||
0x383F, // Index: 176 Fraction: 57/64 = 0.8906
|
||||
0x3036, // Index: 177 Fraction: 49/55 = 0.8909
|
||||
0x282D, // Index: 178 Fraction: 41/46 = 0.8913
|
||||
0x2024, // Index: 179 Fraction: 33/37 = 0.8919
|
||||
0x3940, // Index: 180 Fraction: 58/65 = 0.8923
|
||||
0x181B, // Index: 181 Fraction: 25/28 = 0.8929
|
||||
0x424A, // Index: 182 Fraction: 67/75 = 0.8933
|
||||
0x292E, // Index: 183 Fraction: 42/47 = 0.8936
|
||||
0x3A41, // Index: 184 Fraction: 59/66 = 0.8939
|
||||
0x1012, // Index: 185 Fraction: 17/19 = 0.8947
|
||||
0x3B42, // Index: 186 Fraction: 60/67 = 0.8955
|
||||
0x2A2F, // Index: 187 Fraction: 43/48 = 0.8958
|
||||
0x444C, // Index: 188 Fraction: 69/77 = 0.8961
|
||||
0x191C, // Index: 189 Fraction: 26/29 = 0.8966
|
||||
0x3C43, // Index: 190 Fraction: 61/68 = 0.8971
|
||||
0x2226, // Index: 191 Fraction: 35/39 = 0.8974
|
||||
0x2B30, // Index: 192 Fraction: 44/49 = 0.8980
|
||||
0x343A, // Index: 193 Fraction: 53/59 = 0.8983
|
||||
0x3D44, // Index: 194 Fraction: 62/69 = 0.8986
|
||||
0x464E, // Index: 195 Fraction: 71/79 = 0.8987
|
||||
0x0809, // Index: 196 Fraction: 9/10 = 0.9000
|
||||
0x3F46, // Index: 197 Fraction: 64/71 = 0.9014
|
||||
0x363C, // Index: 198 Fraction: 55/61 = 0.9016
|
||||
0x2D32, // Index: 199 Fraction: 46/51 = 0.9020
|
||||
0x2428, // Index: 200 Fraction: 37/41 = 0.9024
|
||||
0x4047, // Index: 201 Fraction: 65/72 = 0.9028
|
||||
0x1B1E, // Index: 202 Fraction: 28/31 = 0.9032
|
||||
0x2E33, // Index: 203 Fraction: 47/52 = 0.9038
|
||||
0x4148, // Index: 204 Fraction: 66/73 = 0.9041
|
||||
0x1214, // Index: 205 Fraction: 19/21 = 0.9048
|
||||
0x4249, // Index: 206 Fraction: 67/74 = 0.9054
|
||||
0x2F34, // Index: 207 Fraction: 48/53 = 0.9057
|
||||
0x1C1F, // Index: 208 Fraction: 29/32 = 0.9062
|
||||
0x434A, // Index: 209 Fraction: 68/75 = 0.9067
|
||||
0x262A, // Index: 210 Fraction: 39/43 = 0.9070
|
||||
0x3035, // Index: 211 Fraction: 49/54 = 0.9074
|
||||
0x3A40, // Index: 212 Fraction: 59/65 = 0.9077
|
||||
0x444B, // Index: 213 Fraction: 69/76 = 0.9079
|
||||
0x090A, // Index: 214 Fraction: 10/11 = 0.9091
|
||||
0x464D, // Index: 215 Fraction: 71/78 = 0.9103
|
||||
0x3C42, // Index: 216 Fraction: 61/67 = 0.9104
|
||||
0x3237, // Index: 217 Fraction: 51/56 = 0.9107
|
||||
0x282C, // Index: 218 Fraction: 41/45 = 0.9111
|
||||
0x474E, // Index: 219 Fraction: 72/79 = 0.9114
|
||||
0x1E21, // Index: 220 Fraction: 31/34 = 0.9118
|
||||
0x3338, // Index: 221 Fraction: 52/57 = 0.9123
|
||||
0x484F, // Index: 222 Fraction: 73/80 = 0.9125
|
||||
0x1416, // Index: 223 Fraction: 21/23 = 0.9130
|
||||
0x3439, // Index: 224 Fraction: 53/58 = 0.9138
|
||||
0x1F22, // Index: 225 Fraction: 32/35 = 0.9143
|
||||
0x2A2E, // Index: 226 Fraction: 43/47 = 0.9149
|
||||
0x353A, // Index: 227 Fraction: 54/59 = 0.9153
|
||||
0x4046, // Index: 228 Fraction: 65/71 = 0.9155
|
||||
0x0A0B, // Index: 229 Fraction: 11/12 = 0.9167
|
||||
0x4248, // Index: 230 Fraction: 67/73 = 0.9178
|
||||
0x373C, // Index: 231 Fraction: 56/61 = 0.9180
|
||||
0x2C30, // Index: 232 Fraction: 45/49 = 0.9184
|
||||
0x2124, // Index: 233 Fraction: 34/37 = 0.9189
|
||||
0x383D, // Index: 234 Fraction: 57/62 = 0.9194
|
||||
0x1618, // Index: 235 Fraction: 23/25 = 0.9200
|
||||
0x393E, // Index: 236 Fraction: 58/63 = 0.9206
|
||||
0x2225, // Index: 237 Fraction: 35/38 = 0.9211
|
||||
0x2E32, // Index: 238 Fraction: 47/51 = 0.9216
|
||||
0x3A3F, // Index: 239 Fraction: 59/64 = 0.9219
|
||||
0x464C, // Index: 240 Fraction: 71/77 = 0.9221
|
||||
0x0B0C, // Index: 241 Fraction: 12/13 = 0.9231
|
||||
0x484E, // Index: 242 Fraction: 73/79 = 0.9241
|
||||
0x3C41, // Index: 243 Fraction: 61/66 = 0.9242
|
||||
0x3034, // Index: 244 Fraction: 49/53 = 0.9245
|
||||
0x2427, // Index: 245 Fraction: 37/40 = 0.9250
|
||||
0x3D42, // Index: 246 Fraction: 62/67 = 0.9254
|
||||
0x181A, // Index: 247 Fraction: 25/27 = 0.9259
|
||||
0x3E43, // Index: 248 Fraction: 63/68 = 0.9265
|
||||
0x2528, // Index: 249 Fraction: 38/41 = 0.9268
|
||||
0x3236, // Index: 250 Fraction: 51/55 = 0.9273
|
||||
0x3F44, // Index: 251 Fraction: 64/69 = 0.9275
|
||||
0x0C0D, // Index: 252 Fraction: 13/14 = 0.9286
|
||||
0x4146, // Index: 253 Fraction: 66/71 = 0.9296
|
||||
0x3438, // Index: 254 Fraction: 53/57 = 0.9298
|
||||
0x272A, // Index: 255 Fraction: 40/43 = 0.9302
|
||||
0x4247, // Index: 256 Fraction: 67/72 = 0.9306
|
||||
0x1A1C, // Index: 257 Fraction: 27/29 = 0.9310
|
||||
0x4348, // Index: 258 Fraction: 68/73 = 0.9315
|
||||
0x282B, // Index: 259 Fraction: 41/44 = 0.9318
|
||||
0x363A, // Index: 260 Fraction: 55/59 = 0.9322
|
||||
0x4449, // Index: 261 Fraction: 69/74 = 0.9324
|
||||
0x0D0E, // Index: 262 Fraction: 14/15 = 0.9333
|
||||
0x464B, // Index: 263 Fraction: 71/76 = 0.9342
|
||||
0x383C, // Index: 264 Fraction: 57/61 = 0.9344
|
||||
0x2A2D, // Index: 265 Fraction: 43/46 = 0.9348
|
||||
0x474C, // Index: 266 Fraction: 72/77 = 0.9351
|
||||
0x1C1E, // Index: 267 Fraction: 29/31 = 0.9355
|
||||
0x484D, // Index: 268 Fraction: 73/78 = 0.9359
|
||||
0x2B2E, // Index: 269 Fraction: 44/47 = 0.9362
|
||||
0x3A3E, // Index: 270 Fraction: 59/63 = 0.9365
|
||||
0x494E, // Index: 271 Fraction: 74/79 = 0.9367
|
||||
0x0E0F, // Index: 272 Fraction: 15/16 = 0.9375
|
||||
0x3C40, // Index: 273 Fraction: 61/65 = 0.9385
|
||||
0x2D30, // Index: 274 Fraction: 46/49 = 0.9388
|
||||
0x1E20, // Index: 275 Fraction: 31/33 = 0.9394
|
||||
0x2E31, // Index: 276 Fraction: 47/50 = 0.9400
|
||||
0x3E42, // Index: 277 Fraction: 63/67 = 0.9403
|
||||
0x0F10, // Index: 278 Fraction: 16/17 = 0.9412
|
||||
0x4044, // Index: 279 Fraction: 65/69 = 0.9420
|
||||
0x3033, // Index: 280 Fraction: 49/52 = 0.9423
|
||||
0x2022, // Index: 281 Fraction: 33/35 = 0.9429
|
||||
0x3134, // Index: 282 Fraction: 50/53 = 0.9434
|
||||
0x4246, // Index: 283 Fraction: 67/71 = 0.9437
|
||||
0x1011, // Index: 284 Fraction: 17/18 = 0.9444
|
||||
0x4448, // Index: 285 Fraction: 69/73 = 0.9452
|
||||
0x3336, // Index: 286 Fraction: 52/55 = 0.9455
|
||||
0x2224, // Index: 287 Fraction: 35/37 = 0.9459
|
||||
0x3437, // Index: 288 Fraction: 53/56 = 0.9464
|
||||
0x464A, // Index: 289 Fraction: 71/75 = 0.9467
|
||||
0x1112, // Index: 290 Fraction: 18/19 = 0.9474
|
||||
0x484C, // Index: 291 Fraction: 73/77 = 0.9481
|
||||
0x3639, // Index: 292 Fraction: 55/58 = 0.9483
|
||||
0x2426, // Index: 293 Fraction: 37/39 = 0.9487
|
||||
0x373A, // Index: 294 Fraction: 56/59 = 0.9492
|
||||
0x4A4E, // Index: 295 Fraction: 75/79 = 0.9494
|
||||
0x1213, // Index: 296 Fraction: 19/20 = 0.9500
|
||||
0x393C, // Index: 297 Fraction: 58/61 = 0.9508
|
||||
0x2628, // Index: 298 Fraction: 39/41 = 0.9512
|
||||
0x3A3D, // Index: 299 Fraction: 59/62 = 0.9516
|
||||
0x1314, // Index: 300 Fraction: 20/21 = 0.9524
|
||||
0x3C3F, // Index: 301 Fraction: 61/64 = 0.9531
|
||||
0x282A, // Index: 302 Fraction: 41/43 = 0.9535
|
||||
0x3D40, // Index: 303 Fraction: 62/65 = 0.9538
|
||||
0x1415, // Index: 304 Fraction: 21/22 = 0.9545
|
||||
0x3F42, // Index: 305 Fraction: 64/67 = 0.9552
|
||||
0x2A2C, // Index: 306 Fraction: 43/45 = 0.9556
|
||||
0x4043, // Index: 307 Fraction: 65/68 = 0.9559
|
||||
0x1516, // Index: 308 Fraction: 22/23 = 0.9565
|
||||
0x4245, // Index: 309 Fraction: 67/70 = 0.9571
|
||||
0x2C2E, // Index: 310 Fraction: 45/47 = 0.9574
|
||||
0x4346, // Index: 311 Fraction: 68/71 = 0.9577
|
||||
0x1617, // Index: 312 Fraction: 23/24 = 0.9583
|
||||
0x4548, // Index: 313 Fraction: 70/73 = 0.9589
|
||||
0x2E30, // Index: 314 Fraction: 47/49 = 0.9592
|
||||
0x4649, // Index: 315 Fraction: 71/74 = 0.9595
|
||||
0x1718, // Index: 316 Fraction: 24/25 = 0.9600
|
||||
0x484B, // Index: 317 Fraction: 73/76 = 0.9605
|
||||
0x3032, // Index: 318 Fraction: 49/51 = 0.9608
|
||||
0x494C, // Index: 319 Fraction: 74/77 = 0.9610
|
||||
0x1819, // Index: 320 Fraction: 25/26 = 0.9615
|
||||
0x4B4E, // Index: 321 Fraction: 76/79 = 0.9620
|
||||
0x3234, // Index: 322 Fraction: 51/53 = 0.9623
|
||||
0x4C4F, // Index: 323 Fraction: 77/80 = 0.9625
|
||||
0x191A, // Index: 324 Fraction: 26/27 = 0.9630
|
||||
0x3436, // Index: 325 Fraction: 53/55 = 0.9636
|
||||
0x1A1B, // Index: 326 Fraction: 27/28 = 0.9643
|
||||
0x3638, // Index: 327 Fraction: 55/57 = 0.9649
|
||||
0x1B1C, // Index: 328 Fraction: 28/29 = 0.9655
|
||||
0x383A, // Index: 329 Fraction: 57/59 = 0.9661
|
||||
0x1C1D, // Index: 330 Fraction: 29/30 = 0.9667
|
||||
0x3A3C, // Index: 331 Fraction: 59/61 = 0.9672
|
||||
0x1D1E, // Index: 332 Fraction: 30/31 = 0.9677
|
||||
0x3C3E, // Index: 333 Fraction: 61/63 = 0.9683
|
||||
0x1E1F, // Index: 334 Fraction: 31/32 = 0.9688
|
||||
0x3E40, // Index: 335 Fraction: 63/65 = 0.9692
|
||||
0x1F20, // Index: 336 Fraction: 32/33 = 0.9697
|
||||
0x4042, // Index: 337 Fraction: 65/67 = 0.9701
|
||||
0x2021, // Index: 338 Fraction: 33/34 = 0.9706
|
||||
0x4244, // Index: 339 Fraction: 67/69 = 0.9710
|
||||
0x2122, // Index: 340 Fraction: 34/35 = 0.9714
|
||||
0x4446, // Index: 341 Fraction: 69/71 = 0.9718
|
||||
0x2223, // Index: 342 Fraction: 35/36 = 0.9722
|
||||
0x4648, // Index: 343 Fraction: 71/73 = 0.9726
|
||||
0x2324, // Index: 344 Fraction: 36/37 = 0.9730
|
||||
0x484A, // Index: 345 Fraction: 73/75 = 0.9733
|
||||
0x2425, // Index: 346 Fraction: 37/38 = 0.9737
|
||||
0x4A4C, // Index: 347 Fraction: 75/77 = 0.9740
|
||||
0x2526, // Index: 348 Fraction: 38/39 = 0.9744
|
||||
0x4C4E, // Index: 349 Fraction: 77/79 = 0.9747
|
||||
0x2627, // Index: 350 Fraction: 39/40 = 0.9750
|
||||
0x2728, // Index: 351 Fraction: 40/41 = 0.9756
|
||||
0x2829, // Index: 352 Fraction: 41/42 = 0.9762
|
||||
0x292A, // Index: 353 Fraction: 42/43 = 0.9767
|
||||
0x2A2B, // Index: 354 Fraction: 43/44 = 0.9773
|
||||
0x2B2C, // Index: 355 Fraction: 44/45 = 0.9778
|
||||
0x2C2D, // Index: 356 Fraction: 45/46 = 0.9783
|
||||
0x2D2E, // Index: 357 Fraction: 46/47 = 0.9787
|
||||
0x2E2F, // Index: 358 Fraction: 47/48 = 0.9792
|
||||
0x2F30, // Index: 359 Fraction: 48/49 = 0.9796
|
||||
0x3031, // Index: 360 Fraction: 49/50 = 0.9800
|
||||
0x3132, // Index: 361 Fraction: 50/51 = 0.9804
|
||||
0x3233, // Index: 362 Fraction: 51/52 = 0.9808
|
||||
0x3334, // Index: 363 Fraction: 52/53 = 0.9811
|
||||
0x3435, // Index: 364 Fraction: 53/54 = 0.9815
|
||||
0x3536, // Index: 365 Fraction: 54/55 = 0.9818
|
||||
0x3637, // Index: 366 Fraction: 55/56 = 0.9821
|
||||
0x3738, // Index: 367 Fraction: 56/57 = 0.9825
|
||||
0x3839, // Index: 368 Fraction: 57/58 = 0.9828
|
||||
0x393A, // Index: 369 Fraction: 58/59 = 0.9831
|
||||
0x3A3B, // Index: 370 Fraction: 59/60 = 0.9833
|
||||
0x3B3C, // Index: 371 Fraction: 60/61 = 0.9836
|
||||
0x3C3D, // Index: 372 Fraction: 61/62 = 0.9839
|
||||
0x3D3E, // Index: 373 Fraction: 62/63 = 0.9841
|
||||
0x3E3F, // Index: 374 Fraction: 63/64 = 0.9844
|
||||
0x3F40, // Index: 375 Fraction: 64/65 = 0.9846
|
||||
0x4041, // Index: 376 Fraction: 65/66 = 0.9848
|
||||
0x4142, // Index: 377 Fraction: 66/67 = 0.9851
|
||||
0x4243, // Index: 378 Fraction: 67/68 = 0.9853
|
||||
0x4344, // Index: 379 Fraction: 68/69 = 0.9855
|
||||
0x4445, // Index: 380 Fraction: 69/70 = 0.9857
|
||||
0x4546, // Index: 381 Fraction: 70/71 = 0.9859
|
||||
0x4647, // Index: 382 Fraction: 71/72 = 0.9861
|
||||
0x4748, // Index: 383 Fraction: 72/73 = 0.9863
|
||||
0x4849, // Index: 384 Fraction: 73/74 = 0.9865
|
||||
0x494A, // Index: 385 Fraction: 74/75 = 0.9867
|
||||
0x4A4B, // Index: 386 Fraction: 75/76 = 0.9868
|
||||
0x4B4C, // Index: 387 Fraction: 76/77 = 0.9870
|
||||
0x4C4D, // Index: 388 Fraction: 77/78 = 0.9872
|
||||
0x4D4E, // Index: 389 Fraction: 78/79 = 0.9873
|
||||
0x4E4F, // Index: 390 Fraction: 79/80 = 0.9875
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2021 XMOS LIMITED.
|
||||
// Copyright 2015-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#ifndef __DESCRIPTOR_DEFS_H__
|
||||
@@ -33,6 +33,7 @@
|
||||
#define ENDPOINT_ADDRESS_OUT_MIDI (ENDPOINT_NUMBER_OUT_MIDI)
|
||||
#define ENDPOINT_ADDRESS_OUT_IAP (ENDPOINT_NUMBER_OUT_IAP)
|
||||
#define ENDPOINT_ADDRESS_OUT_IAP_EA_NATIVE_TRANS (ENDPOINT_NUMBER_OUT_IAP_EA_NATIVE_TRANS)
|
||||
#define ENDPOINT_ADDRESS_OUT_HID (ENDPOINT_NUMBER_OUT_HID)
|
||||
|
||||
/* Interface numbers enum */
|
||||
enum USBInterfaceNumber
|
||||
@@ -60,7 +61,7 @@ enum USBInterfaceNumber
|
||||
INTERFACE_NUMBER_IAP_EA_NATIVE_TRANS,
|
||||
#endif
|
||||
#endif
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
INTERFACE_NUMBER_HID,
|
||||
#endif
|
||||
INTERFACE_COUNT /* End marker */
|
||||
@@ -70,4 +71,8 @@ enum USBInterfaceNumber
|
||||
#define ENDPOINT_INT_INTERVAL_IN_HID 0x08
|
||||
#endif
|
||||
|
||||
#ifndef ENDPOINT_INT_INTERVAL_OUT_HID
|
||||
#define ENDPOINT_INT_INTERVAL_OUT_HID 0x08
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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.
|
||||
/**
|
||||
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "xc_ptr.h"
|
||||
#include "xua_ep0_uacreqs.h"
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#include "hid.h"
|
||||
#include "xua_hid.h"
|
||||
#include "xua_hid_report.h"
|
||||
@@ -106,13 +106,17 @@ unsigned int mutesOut[NUM_USB_CHAN_OUT + 1];
|
||||
int volsIn[NUM_USB_CHAN_IN + 1];
|
||||
unsigned int mutesIn[NUM_USB_CHAN_IN + 1];
|
||||
|
||||
#ifdef MIXER
|
||||
unsigned char mixer1Crossbar[18];
|
||||
short mixer1Weights[18*8];
|
||||
#if (MIXER)
|
||||
short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
|
||||
|
||||
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];
|
||||
|
||||
/* Mapping of channels to USB host */
|
||||
unsigned char channelMapUsb[NUM_USB_CHAN_IN];
|
||||
|
||||
/* Mapping of channels to Mixer(s) */
|
||||
unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
#endif
|
||||
|
||||
@@ -262,6 +266,44 @@ void XUA_Endpoint0_setVendorId(unsigned short vid) {
|
||||
#endif // AUDIO_CLASS == 1}
|
||||
}
|
||||
|
||||
#if (MIXER)
|
||||
void InitLocalMixerState()
|
||||
{
|
||||
for (int i = 0; i < MIX_INPUTS * MAX_MIX_COUNT; i++)
|
||||
{
|
||||
mixer1Weights[i] = 0x8001; //-inf
|
||||
}
|
||||
|
||||
/* Configure default connections */
|
||||
for (int i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
mixer1Weights[(i * MAX_MIX_COUNT) + i] = 0;
|
||||
}
|
||||
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
/* Setup up audio output channel mapping */
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
channelMapAud[i] = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
channelMapUsb[i] = i + NUM_USB_CHAN_OUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Init mixer inputs */
|
||||
for(int j = 0; j < MAX_MIX_COUNT; j++)
|
||||
for(int i = 0; i < MIX_INPUTS; i++)
|
||||
{
|
||||
mixSel[j][i] = i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void concatenateAndCopyStrings(char* string1, char* string2, char* string_buffer) {
|
||||
debug_printf("concatenateAndCopyStrings() for \"%s\" and \"%s\"\n", string1, string2);
|
||||
|
||||
@@ -400,6 +442,15 @@ void XUA_Endpoint0_setBcdDevice(unsigned short bcd) {
|
||||
#endif // AUDIO_CLASS == 1}
|
||||
}
|
||||
|
||||
#if defined(__static_hid_report_h_exists__)
|
||||
#define hidReportDescriptorLength (sizeof(hidReportDescriptorPtr))
|
||||
static unsigned char hidReportDescriptorPtr[] = {
|
||||
#include "static_hid_report.h"
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(chanend, c_audioControl),
|
||||
chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_)
|
||||
{
|
||||
@@ -408,75 +459,11 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
|
||||
|
||||
XUA_Endpoint0_setStrTable();
|
||||
|
||||
#if 0
|
||||
/* Dont need to init globals.. */
|
||||
/* Init tables for volumes (+ 1 for master) */
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
|
||||
{
|
||||
volsOut[i] = 0;
|
||||
mutesOut[i] = 0;
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
|
||||
{
|
||||
volsIn[i] = 0;
|
||||
mutesIn[i] = 0;
|
||||
}
|
||||
#endif
|
||||
VendorRequests_Init(VENDOR_REQUESTS_PARAMS);
|
||||
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
/* Set up mixer default state */
|
||||
for (int i = 0; i < 18*8; i++)
|
||||
{
|
||||
mixer1Weights[i] = 0x8001; //-inf
|
||||
}
|
||||
|
||||
/* Configure default connections */
|
||||
mixer1Weights[0] = 0;
|
||||
mixer1Weights[9] = 0;
|
||||
mixer1Weights[18] = 0;
|
||||
mixer1Weights[27] = 0;
|
||||
mixer1Weights[36] = 0;
|
||||
mixer1Weights[45] = 0;
|
||||
mixer1Weights[54] = 0;
|
||||
mixer1Weights[63] = 0;
|
||||
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
/* Setup up audio output channel mapping */
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
channelMapAud[i] = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
channelMapUsb[i] = i + NUM_USB_CHAN_OUT;
|
||||
}
|
||||
#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 */
|
||||
for(int j = 0; j < MAX_MIX_COUNT; j++)
|
||||
for(int i = 0; i < MIX_INPUTS; i++)
|
||||
{
|
||||
mixSel[j][i] = i;
|
||||
}
|
||||
InitLocalMixerState();
|
||||
#endif
|
||||
|
||||
#ifdef VENDOR_AUDIO_REQS
|
||||
@@ -529,18 +516,19 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
|
||||
cfgDesc_Audio1[USB_AS_OUT_INTERFACE_DESCRIPTOR_OFFSET_FREQ + 3*i + 2] = (get_usb_to_device_rate() & 0xff0000)>> 16;
|
||||
}
|
||||
|
||||
|
||||
cfgDesc_Audio1[USB_AS_OUT_EP_DESCRIPTOR_OFFSET_MAXPACKETSIZE] = ((get_usb_to_device_bit_res() >> 3) * MAX_PACKET_SIZE_MULT_OUT_FS) & 0xff; //max packet size
|
||||
cfgDesc_Audio1[USB_AS_OUT_EP_DESCRIPTOR_OFFSET_MAXPACKETSIZE + 1] = (((get_usb_to_device_bit_res() >> 3) * MAX_PACKET_SIZE_MULT_OUT_FS) & 0xff00) >> 8; //max packet size
|
||||
#endif // NUM_USB_CHAN_OUT
|
||||
|
||||
#endif // XUA_USB_DESCRIPTOR_OVERWRITE_RATE_RES
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#if XUA_HID_ENABLED
|
||||
hidReportInit();
|
||||
hidPrepareReportDescriptor();
|
||||
|
||||
size_t hidReportDescriptorLength = hidGetReportDescriptorLength();
|
||||
#endif
|
||||
unsigned char hidReportDescriptorLengthLo = hidReportDescriptorLength & 0xFF;
|
||||
unsigned char hidReportDescriptorLengthHi = (hidReportDescriptorLength & 0xFF00) >> 8;
|
||||
|
||||
@@ -551,6 +539,7 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
|
||||
|
||||
hidDescriptor[HID_DESCRIPTOR_LENGTH_FIELD_OFFSET ] = hidReportDescriptorLengthLo;
|
||||
hidDescriptor[HID_DESCRIPTOR_LENGTH_FIELD_OFFSET + 1] = hidReportDescriptorLengthHi;
|
||||
|
||||
#endif // 0 < HID_CONTROLS
|
||||
|
||||
}
|
||||
@@ -754,7 +743,7 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0
|
||||
|
||||
switch(sp.bRequest)
|
||||
{
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
case USB_GET_DESCRIPTOR:
|
||||
|
||||
/* Check what inteface request is for */
|
||||
@@ -769,15 +758,17 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0
|
||||
{
|
||||
/* Return HID Descriptor */
|
||||
result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor,
|
||||
sizeof(hidDescriptor), sp.wLength);
|
||||
hidDescriptor[0], sp.wLength);
|
||||
}
|
||||
break;
|
||||
case HID_REPORT:
|
||||
{
|
||||
/* Return HID report descriptor */
|
||||
#if XUA_HID_ENABLED
|
||||
unsigned char* hidReportDescriptorPtr;
|
||||
hidReportDescriptorPtr = hidGetReportDescriptor();
|
||||
size_t hidReportDescriptorLength = hidGetReportDescriptorLength();
|
||||
#endif
|
||||
result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptorPtr,
|
||||
hidReportDescriptorLength, sp.wLength);
|
||||
}
|
||||
@@ -881,7 +872,7 @@ void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_HID_ENABLED
|
||||
if (interfaceNum == INTERFACE_NUMBER_HID)
|
||||
{
|
||||
result = HidInterfaceClassRequests(ep0_out, ep0_in, &sp);
|
||||
|
||||
@@ -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.
|
||||
/**
|
||||
* @file xua_ep0_descriptors.h
|
||||
@@ -308,28 +308,28 @@ typedef struct
|
||||
#error NUM_USB_CHAN > 32
|
||||
#endif
|
||||
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
STR_TABLE_ENTRY(mixOutStr_1);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 1)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 1)
|
||||
STR_TABLE_ENTRY(mixOutStr_2);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 2)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 2)
|
||||
STR_TABLE_ENTRY(mixOutStr_3);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 3)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 3)
|
||||
STR_TABLE_ENTRY(mixOutStr_4);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 4)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 4)
|
||||
STR_TABLE_ENTRY(mixOutStr_5);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 5)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 5)
|
||||
STR_TABLE_ENTRY(mixOutStr_6);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 6)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 6)
|
||||
STR_TABLE_ENTRY(mixOutStr_7);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 7)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 7)
|
||||
STR_TABLE_ENTRY(mixOutStr_8);
|
||||
#endif
|
||||
#ifdef IAP
|
||||
@@ -391,31 +391,31 @@ StringDescTable_t g_strTable =
|
||||
#error NUM_USB_CHAN_IN > 32
|
||||
#endif
|
||||
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
.mixOutStr_1 = "Mix 1",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 1)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 1)
|
||||
.mixOutStr_2 = "Mix 2",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 2)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 2)
|
||||
.mixOutStr_3 = "Mix 3",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 3)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 3)
|
||||
.mixOutStr_4 = "Mix 4",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 4)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 4)
|
||||
.mixOutStr_5 = "Mix 5",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 5)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 5)
|
||||
.mixOutStr_6 = "Mix 6",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 6)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 6)
|
||||
.mixOutStr_7 = "Mix 7",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 7)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 7)
|
||||
.mixOutStr_8 = "Mix 8",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 8)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 8)
|
||||
#error
|
||||
#endif
|
||||
#ifdef IAP
|
||||
@@ -481,7 +481,7 @@ USB_Descriptor_Device_t devDesc_Audio2 =
|
||||
.iManufacturer = offsetof(StringDescTable_t, vendorStr)/sizeof(char *),
|
||||
.iProduct = offsetof(StringDescTable_t, productStr_Audio2)/sizeof(char *),
|
||||
.iSerialNumber = offsetof(StringDescTable_t, serialStr)/sizeof(char *),
|
||||
.bNumConfigurations = 0x02 /* Set to 2 such that windows does not load composite driver */
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
/* Device Descriptor for Null Device */
|
||||
@@ -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.
|
||||
#define AUDIO_PATH_XUS
|
||||
#endif
|
||||
@@ -575,7 +575,7 @@ unsigned char devQualDesc_Null[] =
|
||||
#define DFU_LENGTH (0)
|
||||
#endif
|
||||
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
#define MIX_BMCONTROLS_LEN_TMP ((MAX_MIX_COUNT * MIX_INPUTS) / 8)
|
||||
|
||||
#if ((MAX_MIX_COUNT * MIX_INPUTS)%8)==0
|
||||
@@ -666,7 +666,7 @@ typedef struct
|
||||
#if (NUM_USB_CHAN_OUT > 0)
|
||||
/* Output path */
|
||||
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;
|
||||
#endif
|
||||
#if(OUTPUT_VOLUME_CONTROL == 1)
|
||||
@@ -677,7 +677,7 @@ typedef struct
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Input path */
|
||||
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;
|
||||
#endif
|
||||
#if(INPUT_VOLUME_CONTROL == 1)
|
||||
@@ -685,7 +685,7 @@ typedef struct
|
||||
#endif
|
||||
USB_Descriptor_Audio_OutputTerminal_t Audio_In_OutputTerminal;
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
USB_Descriptor_Audio_ExtensionUnit2_t Audio_Mix_ExtensionUnit;
|
||||
// Currently no struct for mixer unit
|
||||
// USB_Descriptor_Audio_MixerUnit_t Audio_MixerUnit;
|
||||
@@ -787,10 +787,13 @@ typedef struct
|
||||
#endif
|
||||
#endif // IAP
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
USB_Descriptor_Interface_t HID_Interface;
|
||||
USB_HID_Descriptor_t HID_Descriptor;
|
||||
USB_Descriptor_Endpoint_t HID_In_Endpoint;
|
||||
#if HID_OUT_REQUIRED
|
||||
USB_Descriptor_Endpoint_t HID_Out_Endpoint;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}__attribute__((packed)) USB_Config_Descriptor_Audio2_t;
|
||||
@@ -1168,7 +1171,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
UAC_CS_DESCTYPE_INTERFACE, /* 1 bDescriptorType: CS_INTERFACE */
|
||||
UAC_CS_AC_INTERFACE_SUBTYPE_FEATURE_UNIT, /* 2 bDescriptorSubType: FEATURE_UNIT */
|
||||
FU_USBIN, /* 3 bUnitID */
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
ID_XU_IN, /* 4 bSourceID */
|
||||
#else
|
||||
ID_IT_AUD, /* 4 bSourceID */
|
||||
@@ -1300,7 +1303,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
},
|
||||
#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) */
|
||||
.Audio_Mix_ExtensionUnit =
|
||||
{
|
||||
@@ -1392,7 +1395,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
0x00, /* bmControls */
|
||||
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)
|
||||
/* Standard AS Interrupt Endpoint Descriptor (4.8.2.1): */
|
||||
@@ -2208,14 +2211,14 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
#endif
|
||||
#endif /* IAP */
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#include "xua_hid_descriptors.h"
|
||||
#endif
|
||||
|
||||
};
|
||||
#endif /* (AUDIO_CLASS == 2) */
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#if (AUDIO_CLASS ==1 )
|
||||
unsigned char hidDescriptor[] =
|
||||
{
|
||||
@@ -2330,14 +2333,14 @@ const unsigned num_freqs_a1 = MAX(3, (0
|
||||
#define DFU_INTERFACES_A1 0
|
||||
#endif
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
/*
|
||||
* The value of HID_INTERFACE_BYTES must match the length of the descriptors defined in
|
||||
* - xua_hid_descriptor_contents.h
|
||||
* - xua_hid_endpoint_descriptor_contents.h and
|
||||
* - xua_hid_interface_descriptor_contents.h
|
||||
*/
|
||||
#define HID_INTERFACE_BYTES ( 9 + 9 + 7 )
|
||||
#define HID_INTERFACE_BYTES ( 9 + 9 + (7 * (1 + HID_OUT_REQUIRED))) // always IN
|
||||
#define HID_INTERFACES_A1 1
|
||||
#else
|
||||
#define HID_INTERFACE_BYTES 0
|
||||
@@ -2379,7 +2382,7 @@ const unsigned num_freqs_a1 = MAX(3, (0
|
||||
|
||||
#endif
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#define USB_HID_DESCRIPTOR_OFFSET (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + INTERFACE_DESCRIPTOR_BYTES)
|
||||
#endif
|
||||
|
||||
@@ -2893,7 +2896,7 @@ unsigned char cfgDesc_Audio1[] =
|
||||
offsetof(StringDescTable_t, ctrlStr)/sizeof(char *), /* 8 iInterface */
|
||||
#endif
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#include "xua_hid_descriptors.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -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.
|
||||
/**
|
||||
* @brief Implements relevant requests from the USB Audio 2.0 Specification
|
||||
@@ -14,26 +14,29 @@
|
||||
#include "usbaudio10.h"
|
||||
#include "dbcalc.h"
|
||||
#include "xua_commands.h"
|
||||
#include "xc_ptr.h"
|
||||
|
||||
#define CS_XU_MIXSEL (0x06)
|
||||
|
||||
/* From decouple.xc */
|
||||
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
extern unsigned int multOut[NUM_USB_CHAN_OUT + 1];
|
||||
#endif
|
||||
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
|
||||
extern unsigned int multIn[NUM_USB_CHAN_IN + 1];
|
||||
#endif
|
||||
|
||||
extern int interfaceAlt[];
|
||||
|
||||
/* Global volume and mute tables */
|
||||
/* Global volume and mute tables - from xua_endpoint0.c */
|
||||
extern int volsOut[];
|
||||
extern unsigned int mutesOut[];
|
||||
|
||||
extern int volsIn[];
|
||||
extern unsigned int mutesIn[];
|
||||
|
||||
/* Mixer settings */
|
||||
#ifdef MIXER
|
||||
extern unsigned char mixer1Crossbar[];
|
||||
extern short mixer1Weights[];
|
||||
#if (MIXER)
|
||||
/* Mixer weights */
|
||||
extern short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
|
||||
|
||||
/* Device channel mapping */
|
||||
extern unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
||||
@@ -102,20 +105,6 @@ void FeedbackStabilityDelay()
|
||||
t when timerafter(time + delay):> void;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Original feedback implementation */
|
||||
unsafe
|
||||
{
|
||||
unsigned * unsafe curSamFreqMultiplier = &g_curSamFreqMultiplier;
|
||||
|
||||
static void setG_curSamFreqMultiplier(unsigned x)
|
||||
{
|
||||
// asm(" stw %0, dp[g_curSamFreqMultiplier]" :: "r"(x));
|
||||
*curSamFreqMultiplier = x;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) || (INPUT_VOLUME_CONTROL == 1)
|
||||
static unsigned longMul(unsigned a, unsigned b, int prec)
|
||||
{
|
||||
@@ -130,16 +119,9 @@ static unsigned longMul(unsigned a, unsigned b, int prec)
|
||||
}
|
||||
|
||||
/* Update master volume i.e. i.e update weights for all channels */
|
||||
static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
||||
static void updateMasterVol(int unitID, chanend ?c_mix_ctl)
|
||||
{
|
||||
int x;
|
||||
#ifndef OUT_VOLUME_IN_MIXER
|
||||
xc_ptr p_multOut = array_to_xc_ptr(multOut);
|
||||
#endif
|
||||
#ifndef IN_VOLUME_IN_MIXER
|
||||
xc_ptr p_multIn = array_to_xc_ptr(multIn);
|
||||
#endif
|
||||
switch( unitID)
|
||||
switch(unitID)
|
||||
{
|
||||
case FU_USBOUT:
|
||||
{
|
||||
@@ -151,18 +133,24 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
||||
/* 0x8000 is a special value representing -inf (i.e. mute) */
|
||||
unsigned vol = volsOut[i] == 0x8000 ? 0 : db_to_mult(volsOut[i], 8, 29);
|
||||
|
||||
x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[i];
|
||||
int 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))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_OUT_VOL);
|
||||
outuint(c_mix_ctl, i-1);
|
||||
outuint(c_mix_ctl, x);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
#else
|
||||
asm("stw %0, %1[%2]"::"r"(x),"r"(p_multOut),"r"(i-1));
|
||||
#else
|
||||
unsafe
|
||||
{
|
||||
unsigned int * unsafe multOutPtr = multOut;
|
||||
multOutPtr[i-1] = x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -177,18 +165,24 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
||||
/* 0x8000 is a special value representing -inf (i.e. mute) */
|
||||
unsigned vol = volsIn[i] == 0x8000 ? 0 : db_to_mult(volsIn[i], 8, 29);
|
||||
|
||||
x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[i];
|
||||
int 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))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_IN_VOL);
|
||||
outuint(c_mix_ctl, i-1);
|
||||
outuint(c_mix_ctl, x);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
#else
|
||||
asm("stw %0, %1[%2]"::"r"(x),"r"(p_multIn),"r"(i-1));
|
||||
unsafe
|
||||
{
|
||||
unsigned int * unsafe multInPtr = multIn;
|
||||
multInPtr[i-1] = x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -202,12 +196,6 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
||||
static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
||||
{
|
||||
int x;
|
||||
#ifndef OUT_VOLUME_IN_MIXER
|
||||
xc_ptr p_multOut = array_to_xc_ptr(multOut);
|
||||
#endif
|
||||
#ifndef IN_VOLUME_IN_MIXER
|
||||
xc_ptr p_multIn = array_to_xc_ptr(multIn);
|
||||
#endif
|
||||
/* Check for master volume update */
|
||||
if (channel == 0)
|
||||
{
|
||||
@@ -226,16 +214,22 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
||||
|
||||
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))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_OUT_VOL);
|
||||
outuint(c_mix_ctl, channel-1);
|
||||
outuint(c_mix_ctl, x);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
#else
|
||||
asm("stw %0, %1[%2]"::"r"(x),"r"(p_multOut),"r"(channel-1));
|
||||
unsafe
|
||||
{
|
||||
unsigned int * unsafe multOutPtr = multOut;
|
||||
multOutPtr[channel-1] = x;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -244,20 +238,26 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
||||
/* Calc multipliers with 29 fractional bits from a db value with 8 fractional bits */
|
||||
/* 0x8000 is a special value representing -inf (i.e. mute) */
|
||||
unsigned master_vol = volsIn[0] == 0x8000 ? 0 : db_to_mult(volsIn[0], 8, 29);
|
||||
unsigned vol = volsIn[channel] == 0x8000 ? 0 : db_to_mult(volsIn[channel], 8, 29);
|
||||
unsigned vol = volsIn[channel] == 0x8000 ? 0 : db_to_mult(volsIn[channel], 8, 29);
|
||||
|
||||
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))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_IN_VOL);
|
||||
outuint(c_mix_ctl, channel-1);
|
||||
outuint(c_mix_ctl, x);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
#else
|
||||
asm("stw %0, %1[%2]"::"r"(x),"r"(p_multIn),"r"(channel-1));
|
||||
unsafe
|
||||
{
|
||||
unsigned int * unsafe multInPtr = multIn;
|
||||
multInPtr[channel-1] = x;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -266,6 +266,38 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
||||
}
|
||||
#endif
|
||||
|
||||
void UpdateMixerOutputRouting(chanend c_mix_ctl, unsigned map, unsigned dst, unsigned src)
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
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)
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
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 mult)
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_MULT);
|
||||
outuint(c_mix_ctl, mix);
|
||||
outuint(c_mix_ctl, index);
|
||||
outuint(c_mix_ctl, mult);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
|
||||
/* Handles the audio class specific requests
|
||||
* returns: XUD_RES_OKAY if request dealt with successfully without error,
|
||||
* XUD_RES_RST for device reset
|
||||
@@ -282,7 +314,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
/* Inspect request, NOTE: these are class specific requests */
|
||||
switch( sp.bRequest )
|
||||
{
|
||||
|
||||
/* CUR Request*/
|
||||
case CUR:
|
||||
{
|
||||
@@ -318,7 +349,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
int newSampleRate = buffer[0];
|
||||
|
||||
/* Instruct audio thread to change sample freq (if change required) */
|
||||
//if(newSampleRate != g_curSamFreq)
|
||||
if(newSampleRate != g_curSamFreq)
|
||||
{
|
||||
int newMasterClock;
|
||||
|
||||
@@ -371,7 +402,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
}
|
||||
#endif /* MAX_FREQ != MIN_FREQ */
|
||||
/* Send 0 Length as status stage */
|
||||
int x = XUD_DoSetRequestStatus(ep0_in);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
/* Direction: Device-to-host: Send Current Sample Freq */
|
||||
else
|
||||
@@ -537,7 +568,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
if ((sp.wValue & 0xff) <= NUM_USB_CHAN_OUT)
|
||||
{
|
||||
volsOut[ sp.wValue&0xff ] = (buffer, unsigned char[])[0] | (((int) (signed char) (buffer, unsigned char[])[1]) << 8);
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
}
|
||||
@@ -546,7 +577,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
if ((sp.wValue & 0xff) <= NUM_USB_CHAN_IN)
|
||||
{
|
||||
volsIn[ sp.wValue&0xff ] = (buffer, unsigned char[])[0] | (((int) (signed char) (buffer, unsigned char[])[1]) << 8);
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
}
|
||||
@@ -632,85 +663,76 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
break; /* FU_USBIN */
|
||||
#endif
|
||||
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if ((MIXER) && (MAX_MIX_COUNT > 0))
|
||||
case ID_XU_OUT:
|
||||
{
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
unsigned volume = 0;
|
||||
int c = sp.wValue & 0xff;
|
||||
int dst = sp.wValue & 0xff;
|
||||
|
||||
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
channelMapAud[c] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
if (c < NUM_USB_CHAN_OUT)
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
{
|
||||
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 */
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (dst < NUM_USB_CHAN_OUT)
|
||||
{
|
||||
channelMapAud[dst] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_DEVICE_MAP, dst, channelMapAud[dst]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send 0 Length as status stage */
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
else
|
||||
{
|
||||
(buffer, unsigned char[])[0] = channelMapAud[dst];
|
||||
(buffer, unsigned char[])[1] = 0;
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
(buffer, unsigned char[])[0] = channelMapAud[sp.wValue & 0xff];
|
||||
(buffer, unsigned char[])[1] = 0;
|
||||
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_XU_IN:
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
unsigned volume = 0;
|
||||
int c = sp.wValue & 0xff;
|
||||
int dst = sp.wValue & 0xff;
|
||||
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
channelMapUsb[c] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
|
||||
if (c < NUM_USB_CHAN_IN)
|
||||
{
|
||||
if (!isnull(c_mix_ctl))
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
{
|
||||
outuint(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP);
|
||||
outuint(c_mix_ctl, c);
|
||||
outuint(c_mix_ctl, channelMapUsb[c]);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (dst < NUM_USB_CHAN_IN)
|
||||
{
|
||||
channelMapUsb[dst] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP, dst, channelMapUsb[dst]);
|
||||
}
|
||||
}
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Direction: Device-to-host */
|
||||
(buffer, unsigned char[])[0] = channelMapUsb[dst];
|
||||
(buffer, unsigned char[])[1] = 0;
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Direction: Device-to-host */
|
||||
(buffer, unsigned char[])[0] = channelMapUsb[sp.wValue & 0xff];
|
||||
(buffer, unsigned char[])[1] = 0;
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_XU_MIXSEL:
|
||||
{
|
||||
int cs = sp.wValue >> 8; /* Control Selector */
|
||||
int cn = sp.wValue & 0xff; /* Channel number */
|
||||
int cn = sp.wValue & 0xff; /* Channel Number */
|
||||
|
||||
/* Check for Get or Set */
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D)
|
||||
@@ -723,21 +745,19 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
|
||||
if(datalength > 0)
|
||||
{
|
||||
/* cn bounds check for safety..*/
|
||||
/* CN bounds check for safety..*/
|
||||
if(cn < MIX_INPUTS)
|
||||
{
|
||||
//if(cs == CS_XU_MIXSEL)
|
||||
/* cs now contains mix number */
|
||||
if(cs < (MAX_MIX_COUNT + 1))
|
||||
{
|
||||
int source = (buffer, unsigned char[])[0];
|
||||
|
||||
/* 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
mixSel[cs][cn] = (buffer, unsigned char[])[0];
|
||||
source = (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
|
||||
}
|
||||
|
||||
if(cs == 0)
|
||||
@@ -745,21 +765,17 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
/* Update all mix maps */
|
||||
for (int i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
outuint(c_mix_ctl, SET_MIX_MAP);
|
||||
outuint(c_mix_ctl, i); /* Mix bus */
|
||||
outuint(c_mix_ctl, cn); /* Mixer input */
|
||||
outuint(c_mix_ctl, (int) mixSel[cn]); /* Source */
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
/* i : Mix bus */
|
||||
/* cn: Mixer input */
|
||||
mixSel[i][cn] = source;
|
||||
UpdateMixMap(c_mix_ctl, i, cn, mixSel[i][cn]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update relevant mix map */
|
||||
outuint(c_mix_ctl, SET_MIX_MAP); /* Command */
|
||||
outuint(c_mix_ctl, (cs-1)); /* Mix bus */
|
||||
outuint(c_mix_ctl, cn); /* Mixer input */
|
||||
outuint(c_mix_ctl, (int) mixSel[cs][cn]); /* Source */
|
||||
outct(c_mix_ctl, XS1_CT_END); /* Wait for handshake back */
|
||||
mixSel[cs-1][cn] = source;
|
||||
UpdateMixMap(c_mix_ctl, cs-1, cn, mixSel[cs-1][cn]);
|
||||
}
|
||||
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
@@ -780,7 +796,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
if((cs > 0) && (cs < (MAX_MIX_COUNT+1)))
|
||||
{
|
||||
(buffer, unsigned char[])[0] = mixSel[cs-1][cn];
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, 1 );
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -788,49 +804,53 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
}
|
||||
|
||||
case ID_MIXER_1:
|
||||
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
unsigned volume = 0;
|
||||
int cs = sp.wValue >> 8; /* Control Selector - currently unused */
|
||||
int cn = sp.wValue & 0xff; /* Channel number - used for mixer node index */
|
||||
|
||||
/* Expect OUT here with mute */
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
return result;
|
||||
}
|
||||
unsigned weightMult = 0;
|
||||
|
||||
mixer1Weights[sp.wValue & 0xff] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
/* Expect OUT here with weight */
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (mixer1Weights[sp.wValue & 0xff] == 0x8000)
|
||||
{
|
||||
volume = 0;
|
||||
if(cn < sizeof(mixer1Weights)/sizeof(mixer1Weights[0]))
|
||||
{
|
||||
mixer1Weights[cn] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
|
||||
if (mixer1Weights[cn] != 0x8000)
|
||||
{
|
||||
weightMult = db_to_mult(mixer1Weights[cn], XUA_MIXER_DB_FRAC_BITS, XUA_MIXER_MULT_FRAC_BITS);
|
||||
}
|
||||
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
UpdateMixerWeight(c_mix_ctl, (cn) % 8, (cn) / 8, weightMult);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send 0 Length as status stage */
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
else
|
||||
{
|
||||
volume = db_to_mult(mixer1Weights[sp.wValue & 0xff], 8, 25);
|
||||
}
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
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, volume);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
short weight = 0x8000;
|
||||
|
||||
/* Send 0 Length as status stage */
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
else
|
||||
{
|
||||
short weight = mixer1Weights[sp.wValue & 0xff];
|
||||
(buffer, unsigned char[])[0] = weight & 0xff;
|
||||
(buffer, unsigned char[])[1] = (weight >> 8) & 0xff;
|
||||
if(cn < sizeof(mixer1Weights)/sizeof(mixer1Weights[0]))
|
||||
{
|
||||
weight = mixer1Weights[cn];
|
||||
}
|
||||
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
storeShort((buffer, unsigned char[]), 0, weight);
|
||||
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
#endif
|
||||
default:
|
||||
/* We dont have a unit with this ID! */
|
||||
@@ -919,7 +939,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
num_freqs++;
|
||||
}
|
||||
#endif
|
||||
|
||||
storeShort((buffer, unsigned char[]), 0, num_freqs);
|
||||
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), i, sp.wLength);
|
||||
@@ -957,7 +976,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
/* Mixer Unit */
|
||||
case ID_MIXER_1:
|
||||
storeShort((buffer, unsigned char[]), 0, 1);
|
||||
@@ -967,7 +986,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
/* Unknown Unit ID in Range Request selector for FU */
|
||||
break;
|
||||
@@ -977,7 +995,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
break; /* case: RANGE */
|
||||
}
|
||||
|
||||
#if defined (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if ((MIXER) && (MAX_MIX_COUNT > 0))
|
||||
case MEM: /* Memory Requests (5.2.7.1) */
|
||||
|
||||
unitID = sp.wIndex >> 8;
|
||||
@@ -1003,6 +1021,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
{
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, GET_STREAM_LEVELS);
|
||||
outuint(c_mix_ctl, i);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
@@ -1018,6 +1038,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
{
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, GET_INPUT_LEVELS);
|
||||
outuint(c_mix_ctl, (i - NUM_USB_CHAN_OUT));
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
@@ -1040,6 +1062,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
{
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, GET_OUTPUT_LEVELS);
|
||||
outuint(c_mix_ctl, i);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
@@ -1107,13 +1131,10 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp
|
||||
|
||||
if(newSampleRate != g_curSamFreq)
|
||||
{
|
||||
int curSamFreq44100Family;
|
||||
int curSamFreq48000Family;
|
||||
|
||||
/* Windows Audio Class driver has a nice habbit of sending invalid SF's (e.g. 48001Hz)
|
||||
* when under stress. Lets double check it here and ignore if not valid. */
|
||||
curSamFreq48000Family = MCLK_48 % newSampleRate == 0;
|
||||
curSamFreq44100Family = MCLK_441 % newSampleRate == 0;
|
||||
int curSamFreq48000Family = MCLK_48 % newSampleRate == 0;
|
||||
int curSamFreq44100Family = MCLK_441 % newSampleRate == 0;
|
||||
|
||||
if(curSamFreq48000Family || curSamFreq44100Family)
|
||||
{
|
||||
@@ -1128,7 +1149,7 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp
|
||||
|
||||
/* Allow time for the change - feedback to stabilise */
|
||||
FeedbackStabilityDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
return XUD_SetBuffer(ep0_in, (buffer, unsigned char[]), 0);
|
||||
}
|
||||
@@ -1190,12 +1211,12 @@ XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket
|
||||
{
|
||||
case FU_USBOUT:
|
||||
volsOut[ sp.wValue & 0xff ] = buffer[0] | (((int) (signed char) buffer[1]) << 8);
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
|
||||
case FU_USBIN:
|
||||
volsIn[ sp.wValue & 0xff ] = buffer[0] | (((int) (signed char) buffer[1]) << 8);
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
}
|
||||
@@ -1209,12 +1230,12 @@ XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket
|
||||
{
|
||||
case FU_USBOUT:
|
||||
mutesOut[ sp.wValue & 0xff ] = buffer[0];
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
|
||||
case FU_USBIN:
|
||||
mutesIn[ sp.wValue & 0xff ] = buffer[0];
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
#include "xua.h" /* Device specific defines */
|
||||
@@ -31,7 +31,7 @@
|
||||
#endif
|
||||
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
#include "SpdifReceive.h"
|
||||
#include "spdif.h"
|
||||
#endif
|
||||
|
||||
#if (XUA_ADAT_RX_EN)
|
||||
@@ -142,10 +142,10 @@ on stdcore[XUD_TILE] : buffered in port:32 p_adat_rx = PORT_ADAT_IN;
|
||||
#endif
|
||||
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
on tile[XUD_TILE] : buffered in port:4 p_spdif_rx = PORT_SPDIF_IN;
|
||||
on tile[XUD_TILE] : in port p_spdif_rx = PORT_SPDIF_IN;
|
||||
#endif
|
||||
|
||||
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN) || (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN) || ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && (!XUA_USE_APP_PLL))
|
||||
/* Reference to external clock multiplier */
|
||||
on tile[PLL_REF_TILE] : out port p_pll_ref = PORT_PLL_REF;
|
||||
#endif
|
||||
@@ -213,6 +213,9 @@ XUD_EpType epTypeTableOut[ENDPOINT_COUNT_OUT] = { XUD_EPTYPE_CTL | XUD_STATUS_EN
|
||||
#ifdef MIDI
|
||||
XUD_EPTYPE_BUL, /* MIDI */
|
||||
#endif
|
||||
#if HID_OUT_REQUIRED
|
||||
XUD_EPTYPE_INT,
|
||||
#endif
|
||||
#ifdef IAP
|
||||
XUD_EPTYPE_BUL, /* iAP */
|
||||
#ifdef IAP_EA_NATIVE_TRANS
|
||||
@@ -228,12 +231,12 @@ XUD_EpType epTypeTableIn[ENDPOINT_COUNT_IN] = { XUD_EPTYPE_CTL | XUD_STATUS_ENAB
|
||||
XUD_EPTYPE_ISO, /* Async feedback endpoint */
|
||||
#endif
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
XUD_EPTYPE_BUL,
|
||||
XUD_EPTYPE_INT,
|
||||
#endif
|
||||
#ifdef MIDI
|
||||
XUD_EPTYPE_BUL,
|
||||
#endif
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
XUD_EPTYPE_INT,
|
||||
#endif
|
||||
#ifdef IAP
|
||||
@@ -267,115 +270,6 @@ void xscope_user_init()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if XUA_USB_EN
|
||||
/* Core USB Audio functions - must be called on the Tile connected to the USB Phy */
|
||||
void usb_audio_core(chanend c_mix_out
|
||||
#ifdef MIDI
|
||||
, chanend c_midi
|
||||
#endif
|
||||
#ifdef MIXER
|
||||
, chanend c_mix_ctl
|
||||
#endif
|
||||
, chanend ?c_clk_int
|
||||
, chanend ?c_clk_ctl
|
||||
, client interface i_dfu ?dfuInterface
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
VENDOR_REQUESTS_PARAMS_DEC_
|
||||
)
|
||||
{
|
||||
chan c_sof;
|
||||
chan c_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */
|
||||
chan c_xud_in[ENDPOINT_COUNT_IN];
|
||||
chan c_aud_ctl;
|
||||
|
||||
#ifndef MIXER
|
||||
#define c_mix_ctl null
|
||||
#endif
|
||||
|
||||
#ifdef IAP_EA_NATIVE_TRANS
|
||||
chan c_EANativeTransport_ctrl;
|
||||
#else
|
||||
#define c_EANativeTransport_ctrl null
|
||||
#endif
|
||||
|
||||
par
|
||||
{
|
||||
{
|
||||
#ifdef XUD_PRIORITY_HIGH
|
||||
set_core_high_priority_on();
|
||||
#endif
|
||||
|
||||
/* Run UAC2.0 at high-speed, UAC1.0 at full-speed */
|
||||
unsigned usbSpeed = (AUDIO_CLASS == 2) ? XUD_SPEED_HS : XUD_SPEED_FS;
|
||||
|
||||
unsigned xudPwrCfg = (XUA_POWERMODE == XUA_POWERMODE_SELF) ? XUD_PWR_SELF : XUD_PWR_BUS;
|
||||
|
||||
/* USB interface core */
|
||||
XUD_Main(c_xud_out, ENDPOINT_COUNT_OUT, c_xud_in, ENDPOINT_COUNT_IN,
|
||||
c_sof, epTypeTableOut, epTypeTableIn, usbSpeed, xudPwrCfg);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned x;
|
||||
thread_speed();
|
||||
|
||||
/* Attach mclk count port to mclk clock-block (for feedback) */
|
||||
//set_port_clock(p_for_mclk_count, clk_audio_mclk);
|
||||
#if(AUDIO_IO_TILE != XUD_TILE)
|
||||
set_clock_src(clk_audio_mclk_usb, p_mclk_in_usb);
|
||||
set_port_clock(p_for_mclk_count, clk_audio_mclk_usb);
|
||||
start_clock(clk_audio_mclk_usb);
|
||||
#else
|
||||
/* Clock port from same clock-block as I2S */
|
||||
/* TODO remove asm() */
|
||||
asm("ldw %0, dp[clk_audio_mclk]":"=r"(x));
|
||||
asm("setclk res[%0], %1"::"r"(p_for_mclk_count), "r"(x));
|
||||
#endif
|
||||
/* Endpoint & audio buffering cores */
|
||||
XUA_Buffer(c_xud_out[ENDPOINT_NUMBER_OUT_AUDIO],/* Audio Out*/
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
|
||||
c_xud_in[ENDPOINT_NUMBER_IN_AUDIO], /* Audio In */
|
||||
#endif
|
||||
#if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP)
|
||||
c_xud_in[ENDPOINT_NUMBER_IN_FEEDBACK], /* Audio FB */
|
||||
#endif
|
||||
#ifdef MIDI
|
||||
c_xud_out[ENDPOINT_NUMBER_OUT_MIDI], /* MIDI Out */ // 2
|
||||
c_xud_in[ENDPOINT_NUMBER_IN_MIDI], /* MIDI In */ // 4
|
||||
c_midi,
|
||||
#endif
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
/* Audio Interrupt - only used for interrupts on external clock change */
|
||||
c_xud_in[ENDPOINT_NUMBER_IN_INTERRUPT],
|
||||
c_clk_int,
|
||||
#endif
|
||||
c_sof, c_aud_ctl, p_for_mclk_count
|
||||
#if (HID_CONTROLS)
|
||||
, c_xud_in[ENDPOINT_NUMBER_IN_HID]
|
||||
#endif
|
||||
, c_mix_out
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
, i_pll_ref
|
||||
#endif
|
||||
);
|
||||
//:
|
||||
}
|
||||
|
||||
/* Endpoint 0 Core */
|
||||
{
|
||||
thread_speed();
|
||||
XUA_Endpoint0( c_xud_out[0], c_xud_in[0], c_aud_ctl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_);
|
||||
}
|
||||
|
||||
//:
|
||||
}
|
||||
}
|
||||
#endif /* XUA_USB_EN */
|
||||
|
||||
|
||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
void SpdifTxWrapper(chanend c_spdif_tx)
|
||||
{
|
||||
@@ -401,7 +295,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
chanend c_spdif_tx,
|
||||
#endif
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
chanend c_mix_ctl,
|
||||
#endif
|
||||
streaming chanend ?c_spdif_rx,
|
||||
@@ -420,9 +314,12 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
, client interface pll_ref_if i_pll_ref
|
||||
#endif
|
||||
#if (XUA_USE_APP_PLL)
|
||||
, client interface SoftPll_if i_softPll
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
chan c_mix_out;
|
||||
#endif
|
||||
|
||||
@@ -446,7 +343,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
|
||||
par
|
||||
{
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
/* Mixer cores(s) */
|
||||
{
|
||||
thread_speed();
|
||||
@@ -464,12 +361,15 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
/* Audio I/O core (pars additional S/PDIF TX Core) */
|
||||
{
|
||||
thread_speed();
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
#define AUDIO_CHANNEL c_mix_out
|
||||
#else
|
||||
#define AUDIO_CHANNEL c_aud_in
|
||||
#endif
|
||||
XUA_AudioHub(AUDIO_CHANNEL, clk_audio_mclk, clk_audio_bclk, p_mclk_in, p_lrclk, p_bclk, p_i2s_dac, p_i2s_adc
|
||||
#if (XUA_USE_APP_PLL)
|
||||
, i_softPll
|
||||
#endif
|
||||
#if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
, c_spdif_tx
|
||||
#endif
|
||||
@@ -531,7 +431,7 @@ int main()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
chan c_mix_ctl;
|
||||
#endif
|
||||
|
||||
@@ -573,17 +473,36 @@ int main()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && !XUA_USE_APP_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
interface pll_ref_if i_pll_ref;
|
||||
#endif
|
||||
|
||||
#if (XUA_USE_APP_PLL)
|
||||
interface SoftPll_if i_softPll;
|
||||
chan c_swpll_update;
|
||||
#endif
|
||||
chan c_sof;
|
||||
chan c_xud_out[ENDPOINT_COUNT_OUT]; /* Endpoint channels for XUD */
|
||||
chan c_xud_in[ENDPOINT_COUNT_IN];
|
||||
chan c_aud_ctl;
|
||||
|
||||
#if (!MIXER)
|
||||
#define c_mix_ctl null
|
||||
#endif
|
||||
|
||||
#ifdef IAP_EA_NATIVE_TRANS
|
||||
chan c_EANativeTransport_ctrl;
|
||||
#else
|
||||
#define c_EANativeTransport_ctrl null
|
||||
#endif
|
||||
|
||||
USER_MAIN_DECLARATIONS
|
||||
|
||||
par
|
||||
{
|
||||
USER_MAIN_CORES
|
||||
|
||||
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) && XYA_USE_APP_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
on tile[PLL_REF_TILE]: PllRefPinTask(i_pll_ref, p_pll_ref);
|
||||
#endif
|
||||
on tile[XUD_TILE]:
|
||||
@@ -597,30 +516,91 @@ int main()
|
||||
#endif
|
||||
#endif
|
||||
#if XUA_USB_EN
|
||||
/* Core USB audio task, buffering, USB etc */
|
||||
usb_audio_core(c_mix_out
|
||||
#ifdef MIDI
|
||||
, c_midi
|
||||
#endif
|
||||
#ifdef IAP
|
||||
, c_iap
|
||||
#ifdef IAP_EA_NATIVE_TRANS
|
||||
, c_ea_data
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MIXER
|
||||
, c_mix_ctl
|
||||
#endif
|
||||
, c_clk_int, c_clk_ctl, dfuInterface
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
, i_pll_ref
|
||||
#endif
|
||||
VENDOR_REQUESTS_PARAMS_
|
||||
|
||||
);
|
||||
/* Core USB task, buffering, USB etc */
|
||||
{
|
||||
#ifdef XUD_PRIORITY_HIGH
|
||||
set_core_high_priority_on();
|
||||
#endif
|
||||
|
||||
/* Run UAC2.0 at high-speed, UAC1.0 at full-speed */
|
||||
unsigned usbSpeed = (AUDIO_CLASS == 2) ? XUD_SPEED_HS : XUD_SPEED_FS;
|
||||
|
||||
unsigned xudPwrCfg = (XUA_POWERMODE == XUA_POWERMODE_SELF) ? XUD_PWR_SELF : XUD_PWR_BUS;
|
||||
|
||||
/* USB interface core */
|
||||
XUD_Main(c_xud_out, ENDPOINT_COUNT_OUT, c_xud_in, ENDPOINT_COUNT_IN,
|
||||
c_sof, epTypeTableOut, epTypeTableIn, usbSpeed, xudPwrCfg);
|
||||
}
|
||||
|
||||
#if (XUA_USE_APP_PLL)
|
||||
//XUA_SoftPll(tile[0], i_softPll, c_swpll_update);
|
||||
#endif
|
||||
|
||||
/* Core USB audio task, buffering, USB etc */
|
||||
{
|
||||
unsigned x;
|
||||
thread_speed();
|
||||
|
||||
/* Attach mclk count port to mclk clock-block (for feedback) */
|
||||
//set_port_clock(p_for_mclk_count, clk_audio_mclk);
|
||||
#if(AUDIO_IO_TILE != XUD_TILE)
|
||||
set_clock_src(clk_audio_mclk_usb, p_mclk_in_usb);
|
||||
set_port_clock(p_for_mclk_count, clk_audio_mclk_usb);
|
||||
start_clock(clk_audio_mclk_usb);
|
||||
#else
|
||||
/* Clock port from same clock-block as I2S */
|
||||
/* TODO remove asm() */
|
||||
asm("ldw %0, dp[clk_audio_mclk]":"=r"(x));
|
||||
asm("setclk res[%0], %1"::"r"(p_for_mclk_count), "r"(x));
|
||||
#endif
|
||||
/* Endpoint & audio buffering cores */
|
||||
XUA_Buffer(c_xud_out[ENDPOINT_NUMBER_OUT_AUDIO],/* Audio Out*/
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
|
||||
c_xud_in[ENDPOINT_NUMBER_IN_AUDIO], /* Audio In */
|
||||
#endif
|
||||
#if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP)
|
||||
c_xud_in[ENDPOINT_NUMBER_IN_FEEDBACK], /* Audio FB */
|
||||
#endif
|
||||
#ifdef MIDI
|
||||
c_xud_out[ENDPOINT_NUMBER_OUT_MIDI], /* MIDI Out */ // 2
|
||||
c_xud_in[ENDPOINT_NUMBER_IN_MIDI], /* MIDI In */ // 4
|
||||
c_midi,
|
||||
#endif
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
/* Audio Interrupt - only used for interrupts on external clock change */
|
||||
c_xud_in[ENDPOINT_NUMBER_IN_INTERRUPT],
|
||||
c_clk_int,
|
||||
#endif
|
||||
c_sof, c_aud_ctl, p_for_mclk_count
|
||||
#if (XUA_HID_ENABLED)
|
||||
, c_xud_in[ENDPOINT_NUMBER_IN_HID]
|
||||
#endif
|
||||
, c_mix_out
|
||||
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
|
||||
#if (!XUA_USE_APP_PLL)
|
||||
, i_pll_ref
|
||||
#else
|
||||
, c_swpll_update
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
//:
|
||||
}
|
||||
|
||||
/* Endpoint 0 Core */
|
||||
{
|
||||
thread_speed();
|
||||
XUA_Endpoint0( c_xud_out[0], c_xud_in[0], c_aud_ctl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_);
|
||||
}
|
||||
|
||||
#endif /* XUA_USB_EN */
|
||||
}
|
||||
|
||||
#if(XUA_USE_APP_PLL)
|
||||
on tile[AUDIO_IO_TILE]: XUA_SoftPll(tile[0], i_softPll, c_swpll_update);
|
||||
#endif
|
||||
on tile[AUDIO_IO_TILE]:
|
||||
{
|
||||
/* Audio I/O task, includes mixing etc */
|
||||
@@ -628,7 +608,7 @@ int main()
|
||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
, c_spdif_tx
|
||||
#endif
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
, c_mix_ctl
|
||||
#endif
|
||||
, c_spdif_rx, c_adat_rx, c_clk_ctl, c_clk_int
|
||||
@@ -643,6 +623,9 @@ int main()
|
||||
#endif
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
, i_pll_ref
|
||||
#endif
|
||||
#if (XUA_USE_APP_PLL)
|
||||
, i_softPll
|
||||
#endif
|
||||
);
|
||||
}
|
||||
@@ -685,7 +668,7 @@ int main()
|
||||
on tile[XUD_TILE]:
|
||||
{
|
||||
thread_speed();
|
||||
SpdifReceive(p_spdif_rx, c_spdif_rx, 1, clk_spd_rx);
|
||||
spdif_rx(c_spdif_rx,p_spdif_rx,clk_spd_rx,192000);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
// Copyright 2018-2021 XMOS LIMITED.
|
||||
// Copyright 2018-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#define MAX_MIX_COUNT 8
|
||||
#define MIX_INPUTS 18
|
||||
#include "xua.h"
|
||||
|
||||
#ifndef MAX_MIX_COUNT
|
||||
#error
|
||||
#endif
|
||||
|
||||
#ifndef MIX_INPUTS
|
||||
#error
|
||||
#endif
|
||||
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
|
||||
#define DOMIX_TOP(i) \
|
||||
.cc_top doMix##i.function,doMix##i; \
|
||||
.align 4 ;\
|
||||
.align 16 ;\
|
||||
.globl doMix##i ;\
|
||||
.type doMix##i, @function ;\
|
||||
.globl doMix##i##.nstackwords ;\
|
||||
@@ -124,7 +133,7 @@ DOMIX_BOT(7)
|
||||
#undef BODY
|
||||
#define N MAX_MIX_COUNT
|
||||
.cc_top setPtr.function,setPtr;
|
||||
.align 4 ;
|
||||
.align 16 ;
|
||||
.globl setPtr;
|
||||
.type setPtr, @function
|
||||
.globl setPtr.nstackwords;
|
||||
@@ -173,5 +182,5 @@ setPtr_go:
|
||||
#undef N
|
||||
#undef BODY
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,25 +1,39 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// 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 <print.h>
|
||||
#include "xua.h"
|
||||
#include "xc_ptr.h"
|
||||
#include "xua_commands.h"
|
||||
#include "dbcalc.h"
|
||||
|
||||
#ifdef MIXER
|
||||
/* FAST_MIXER has a bit of a nasty implentation but is more efficient */
|
||||
#ifndef FAST_MIXER
|
||||
#define FAST_MIXER (1)
|
||||
#endif
|
||||
|
||||
/* FAST_MIXER has a bit of a nasty implentation but is more effcient */
|
||||
#define FAST_MIXER 1
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) || !FAST_MIXER
|
||||
#include "xc_ptr.h"
|
||||
#endif
|
||||
|
||||
//#ifdef OUT_VOLUME_IN_MIXER
|
||||
#if (MIXER)
|
||||
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
static unsigned int multOut_array[NUM_USB_CHAN_OUT + 1];
|
||||
static xc_ptr multOut;
|
||||
//#endif
|
||||
//#ifdef IN_VOLUME_IN_MIXER
|
||||
unsafe
|
||||
{
|
||||
unsigned int volatile * unsafe multOut = multOut_array;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
static unsigned int multIn_array[NUM_USB_CHAN_IN + 1];
|
||||
static xc_ptr multIn;
|
||||
//#endif
|
||||
unsafe
|
||||
{
|
||||
unsigned int volatile * unsafe multIn = multIn_array;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
||||
static unsigned abs(int x)
|
||||
@@ -35,35 +49,38 @@ static unsigned abs(int x)
|
||||
}
|
||||
#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" */
|
||||
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
|
||||
{
|
||||
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];
|
||||
|
||||
int samples_to_host_map_array[NUM_USB_CHAN_IN];
|
||||
xc_ptr samples_to_host_map;
|
||||
|
||||
int samples_to_device_map_array[NUM_USB_CHAN_OUT];
|
||||
xc_ptr samples_to_device_map;
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
int mix_mult_array[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
xc_ptr mix_mult;
|
||||
#define write_word_to_mix_mult(x,y,val) write_via_xc_ptr_indexed(mix_mult,((x)*MIX_INPUTS)+(y), val)
|
||||
#define mix_mult_slice(x) (mix_mult + x * MIX_INPUTS * sizeof(int))
|
||||
#ifndef FAST_MIXER
|
||||
int mix_map_array[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
xc_ptr mix_map;
|
||||
#define write_word_to_mix_map(x,y,val) write_via_xc_ptr_indexed(mix_map,((x)*MIX_INPUTS)+(y), val)
|
||||
#define mix_map_slice(x) (mix_map + x * MIX_INPUTS * sizeof(int))
|
||||
#endif
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
int mix_mult_array[MAX_MIX_COUNT * MIX_INPUTS];
|
||||
#if (FAST_MIXER == 0)
|
||||
int mix_map_array[MAX_MIX_COUNT * MIX_INPUTS];
|
||||
#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 */
|
||||
int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. device inputs */
|
||||
xc_ptr samples_to_host_inputs_ptr;
|
||||
@@ -77,19 +94,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 */
|
||||
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)
|
||||
{
|
||||
int x;
|
||||
@@ -108,42 +112,40 @@ static inline void ComputeMixerLevel(int sample, int i)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef FAST_MIXER
|
||||
|
||||
#if (FAST_MIXER)
|
||||
void setPtr(int src, int dst, int mix);
|
||||
int doMix0(xc_ptr samples, xc_ptr mult);
|
||||
int doMix1(xc_ptr samples, xc_ptr mult);
|
||||
int doMix2(xc_ptr samples, xc_ptr mult);
|
||||
int doMix3(xc_ptr samples, xc_ptr mult);
|
||||
int doMix4(xc_ptr samples, xc_ptr mult);
|
||||
int doMix5(xc_ptr samples, xc_ptr mult);
|
||||
int doMix6(xc_ptr samples, xc_ptr mult);
|
||||
int doMix7(xc_ptr samples, xc_ptr mult);
|
||||
int doMix8(xc_ptr samples, xc_ptr mult);
|
||||
int doMix0(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix1(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix2(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix3(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix4(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix5(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix6(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix7(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
#else
|
||||
/* DO NOT inline, causes 10.4.2 tools to add extra loads in loop */
|
||||
/* At 18 x 12dB we could get 64 x bigger */
|
||||
#pragma unsafe arrays
|
||||
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 l=0;
|
||||
|
||||
/* By breaking up the loop we keep things in the encoding for ldw (0-11) */
|
||||
#pragma loop unroll
|
||||
for (int i=0; i<MIX_INPUTS; i++)
|
||||
{
|
||||
int sample;
|
||||
int index;
|
||||
int m;
|
||||
read_via_xc_ptr_indexed(index, ptr, i);
|
||||
read_via_xc_ptr_indexed(sample,samples,index);
|
||||
read_via_xc_ptr_indexed(m, mult, i);
|
||||
{h,l} = macs(sample, m, h, l);
|
||||
unsafe{
|
||||
int sample;
|
||||
int source;
|
||||
int weight;
|
||||
read_via_xc_ptr_indexed(source, mixMap, i);
|
||||
sample = samples[source];
|
||||
read_via_xc_ptr_indexed(weight, mult, i);
|
||||
|
||||
|
||||
{h,l} = macs(sample, weight, h, l);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* Perform saturation */
|
||||
l = sext(h, 25);
|
||||
l = sext(h, XUA_MIXER_MULT_FRAC_BITS);
|
||||
|
||||
if(l != h)
|
||||
{
|
||||
@@ -152,15 +154,14 @@ static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
|
||||
else
|
||||
h = (0x7fffff00>>7);
|
||||
}
|
||||
#endif
|
||||
return h<<7;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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 h;
|
||||
unsigned l;
|
||||
@@ -170,23 +171,26 @@ static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
int sample;
|
||||
int index;
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
read_via_xc_ptr_indexed(index,ptr,i);
|
||||
#else
|
||||
index = i + NUM_USB_CHAN_OUT;
|
||||
#endif
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
unsafe
|
||||
{
|
||||
//read_via_xc_ptr_indexed(sample,samples,index);
|
||||
sample = ptr_samples[index];
|
||||
sample = ptr_samples[hostMap[i]];
|
||||
}
|
||||
#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
|
||||
//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 <<= 3 done on other side */
|
||||
@@ -209,7 +213,7 @@ static inline void GetSamplesFromHost(chanend c)
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
unsafe {
|
||||
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 h;
|
||||
unsigned l;
|
||||
@@ -226,50 +230,47 @@ static inline void GetSamplesFromHost(chanend c)
|
||||
}
|
||||
#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
|
||||
read_via_xc_ptr_indexed(mult, multOut, i);
|
||||
mult = multOut[i];
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h<<=3;
|
||||
#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)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
sample = h;
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(multOut, index, val);
|
||||
write_via_xc_ptr_indexed(samples_array, i, h);
|
||||
#else
|
||||
ptr_samples[i] = sample;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#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);
|
||||
#else
|
||||
#pragma loop unroll
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
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 h;
|
||||
unsigned l;
|
||||
#endif
|
||||
int index;
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
/* If mixer turned on sort out the channel mapping */
|
||||
|
||||
/* Read pointer to sample from the map */
|
||||
read_via_xc_ptr_indexed(index, ptr, i);
|
||||
|
||||
/* Read the actual sample value */
|
||||
read_via_xc_ptr_indexed(sample, samples, index);
|
||||
unsafe
|
||||
{
|
||||
/* Read index to sample from the map then Read the actual sample value */
|
||||
sample = ptr_samples[deviceMap[i]];
|
||||
}
|
||||
#else
|
||||
unsafe
|
||||
{
|
||||
@@ -278,16 +279,19 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
||||
}
|
||||
#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 */
|
||||
#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<<=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)
|
||||
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
|
||||
outuint(c, h);
|
||||
#else
|
||||
@@ -300,14 +304,14 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
||||
#pragma unsafe arrays
|
||||
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 h;
|
||||
unsigned l;
|
||||
#endif
|
||||
|
||||
#pragma loop unroll
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
int sample;
|
||||
int x;
|
||||
@@ -327,22 +331,24 @@ static inline void GetSamplesFromDevice(chanend c)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
|
||||
/* Read relevant multiplier */
|
||||
read_via_xc_ptr_indexed(mult, multIn, i);
|
||||
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||
/* Volume processing - read relevant multiplier */
|
||||
unsafe
|
||||
{
|
||||
mult = multIn[i];
|
||||
}
|
||||
|
||||
/* Do the multiply */
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<=3;
|
||||
write_via_xc_ptr_indexed(samples_array, NUM_USB_CHAN_OUT+i, h);
|
||||
#else
|
||||
/* No volume processing */
|
||||
h <<= 3;
|
||||
sample = h;
|
||||
#endif
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mixer1_mix2_flag = (DEFAULT_FREQ > 96000);
|
||||
@@ -353,12 +359,14 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
int mixed;
|
||||
#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 char ct;
|
||||
#endif
|
||||
unsigned request = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
#pragma xta endpoint "mixer1_req"
|
||||
/* Request from audio()/mixer2() */
|
||||
request = inuint(c_mixer2);
|
||||
|
||||
@@ -369,28 +377,62 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
/* Sync */
|
||||
outuint(c_mixer2, 0);
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
{
|
||||
case inuint_byref(c_mix_ctl, cmd):
|
||||
/* Check if EP0 intends to send us a control command */
|
||||
case inct_byref(c_mix_ctl, ct):
|
||||
{
|
||||
int mix, index, val;
|
||||
|
||||
/* Handshake back to tell EP0 we are ready for an update */
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
|
||||
/* Receive command from EP0 */
|
||||
cmd = inuint(c_mix_ctl);
|
||||
|
||||
/* Interpret control command */
|
||||
switch (cmd)
|
||||
{
|
||||
#if MAX_MIX_COUNT > 0
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
case SET_SAMPLES_TO_HOST_MAP:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
write_via_xc_ptr_indexed(samples_to_host_map, index, val);
|
||||
{
|
||||
int dst = inuint(c_mix_ctl);
|
||||
int src = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
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;
|
||||
|
||||
case SET_SAMPLES_TO_DEVICE_MAP:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
write_via_xc_ptr_indexed(samples_to_device_map,index,val);
|
||||
{
|
||||
int dst = inuint(c_mix_ctl);
|
||||
int src = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
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;
|
||||
|
||||
case SET_MIX_MULT:
|
||||
@@ -399,40 +441,80 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
val = inuint(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;
|
||||
|
||||
case SET_MIX_MAP:
|
||||
mix = inuint(c_mix_ctl);
|
||||
index = inuint(c_mix_ctl); /* mixer input */
|
||||
val = inuint(c_mix_ctl); /* source */
|
||||
inct(c_mix_ctl);
|
||||
#ifdef FAST_MIXER
|
||||
setPtr(index, val, mix);
|
||||
{
|
||||
unsigned mix = inuint(c_mix_ctl);
|
||||
unsigned input = inuint(c_mix_ctl); /* mixer input */
|
||||
unsigned source = inuint(c_mix_ctl); /* source */
|
||||
inct(c_mix_ctl);
|
||||
|
||||
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
|
||||
write_word_to_mix_map(mix, index, val);
|
||||
unsafe
|
||||
{
|
||||
mix_map[(mix * MIX_INPUTS) + input] = source;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* if MAX_MIX_COUNT > 0 */
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
case SET_MIX_IN_VOL:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
write_via_xc_ptr_indexed(multIn, index, val);
|
||||
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;
|
||||
#endif
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
case SET_MIX_OUT_VOL:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
write_via_xc_ptr_indexed(multOut, index, val);
|
||||
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;
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
/* Peak samples of stream from host to device (via USB) */
|
||||
case GET_STREAM_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
@@ -441,42 +523,6 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
samples_from_host_streams[index] = 0;
|
||||
break;
|
||||
|
||||
case GET_INPUT_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
chkct(c_mix_ctl, XS1_CT_END);
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
/* Level LEDS process reseting samples_to_host_inputs
|
||||
* Other side makes sure we don't miss a peak */
|
||||
//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
|
||||
}
|
||||
break;
|
||||
@@ -484,14 +530,13 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
default:
|
||||
/* Select default */
|
||||
break;
|
||||
}
|
||||
|
||||
} // select
|
||||
#endif
|
||||
|
||||
/* Get response from decouple */
|
||||
if(testct(c_host))
|
||||
{
|
||||
int sampFreq;
|
||||
#pragma xta endpoint "mixer1_rate_change"
|
||||
unsigned command = inct(c_host);
|
||||
|
||||
switch(command)
|
||||
@@ -520,9 +565,8 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
|
||||
#pragma loop unroll
|
||||
/* 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
|
||||
{
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
||||
@@ -535,21 +579,24 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if MAX_MIX_COUNT > 0
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
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) */
|
||||
outuint(c_mixer2, 0);
|
||||
inuint(c_mixer2);
|
||||
|
||||
/* Do the mixing */
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix0(samples, mix_mult_slice(0));
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix0(ptr_samples, slice(mix_mult, 0));
|
||||
#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
|
||||
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)
|
||||
ComputeMixerLevel(mixed, 0);
|
||||
@@ -560,40 +607,46 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
#endif
|
||||
{
|
||||
|
||||
#if MAX_MIX_COUNT > 2
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix2(samples, mix_mult_slice(2));
|
||||
#if (MAX_MIX_COUNT > 2)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix2(ptr_samples, slice(mix_mult, 2));
|
||||
#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
|
||||
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)
|
||||
ComputeMixerLevel(mixed, 2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 4
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix4(samples, mix_mult_slice(4));
|
||||
#if (MAX_MIX_COUNT > 4)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix4(ptr_samples, slice(mix_mult, 4));
|
||||
#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
|
||||
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)
|
||||
ComputeMixerLevel(mixed, 4);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 6
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix6(samples, mix_mult_slice(6));
|
||||
#if (MAX_MIX_COUNT > 6)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix6(ptr_samples, slice(mix_mult, 6));
|
||||
#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
|
||||
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)
|
||||
ComputeMixerLevel(mixed, 6);
|
||||
#endif
|
||||
@@ -601,10 +654,10 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
}
|
||||
#else /* IF MAX_MIX_COUNT > 0 */
|
||||
/* 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);
|
||||
GetSamplesFromHost(c_host);
|
||||
GiveSamplesToHost(c_host, samples_to_host_map, multIn);
|
||||
GiveSamplesToHost(c_host, samples_to_host_map);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -621,7 +674,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
|
||||
while (1)
|
||||
{
|
||||
#pragma xta endpoint "mixer2_req"
|
||||
request = inuint(c_audio);
|
||||
|
||||
/* Forward the request on */
|
||||
@@ -633,7 +685,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
if(testct(c_mixer1))
|
||||
{
|
||||
int sampFreq;
|
||||
#pragma xta endpoint "mixer2_rate_change"
|
||||
unsigned command = inct(c_mixer1);
|
||||
|
||||
switch(command)
|
||||
@@ -660,8 +711,8 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
}
|
||||
|
||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
|
||||
unsafe{
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
||||
}
|
||||
|
||||
/* Wait for handshake and pass on */
|
||||
@@ -670,7 +721,7 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
}
|
||||
else
|
||||
{
|
||||
GiveSamplesToDevice(c_audio, samples_to_device_map, multOut);
|
||||
GiveSamplesToDevice(c_audio, samples_to_device_map);
|
||||
GetSamplesFromDevice(c_audio);
|
||||
|
||||
/* Sync with mixer 1 (once it has swapped samples with the buffering sub-system) */
|
||||
@@ -678,61 +729,67 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
outuint(c_mixer1, 0);
|
||||
|
||||
/* Do the mixing */
|
||||
#if MAX_MIX_COUNT > 1
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix1(samples, mix_mult_slice(1));
|
||||
#if (MAX_MIX_COUNT > 1)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix1(ptr_samples, slice(mix_mult, 1));
|
||||
#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
|
||||
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1), mixed);
|
||||
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if (MAX_FREQ > 96000)
|
||||
/* Fewer mixes when running higher than 96kHz */
|
||||
if (!mixer2_mix2_flag)
|
||||
#endif
|
||||
{
|
||||
#if MAX_MIX_COUNT > 3
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix3(samples, mix_mult_slice(3));
|
||||
#if (MAX_MIX_COUNT > 3)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix3(ptr_samples, slice(mix_mult, 3));
|
||||
#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
|
||||
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3), mixed);
|
||||
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 5
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix5(samples, mix_mult_slice(5));
|
||||
#if (MAX_MIX_COUNT > 5)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix5(ptr_samples, slice(mix_mult, 5));
|
||||
#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
|
||||
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)
|
||||
ComputeMixerLevel(mixed, 5);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 7
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix7(samples, mix_mult_slice(7));
|
||||
#if (MAX_MIX_COUNT > 7)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix7(ptr_samples, slice(mix_mult, 7));
|
||||
#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
|
||||
|
||||
write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7, mixed);
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 7);
|
||||
#endif
|
||||
@@ -748,68 +805,52 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
chan c;
|
||||
#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[]));
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
samples_to_host_inputs_buff_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
|
||||
#endif
|
||||
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
|
||||
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
|
||||
unsafe {
|
||||
//write_via_xc_ptr_indexed(samples,i,0);
|
||||
ptr_samples[i] = 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int num_mixes = DEFAULT_FREQ > 96000 ? 2 : MAX_MIX_COUNT;
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||
{
|
||||
//samples_to_device_map_array[i] = i;
|
||||
asm("stw %0, %1[%2]":: "r"(i), "r"(samples_to_device_map), "r"(i));
|
||||
}
|
||||
samples_to_device_map_array[i] = i;
|
||||
}
|
||||
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(multOut, i, MAX_VOL);
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
unsafe{
|
||||
multOut[i] = MAX_VOLUME_MULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(multIn, i, MAX_VOL);
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
unsafe{
|
||||
multIn[i] = MAX_VOLUME_MULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(samples_to_host_map, i, NUM_USB_CHAN_OUT + i);
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
unsafe{
|
||||
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 j=0;j<MIX_INPUTS;j++)
|
||||
{
|
||||
#ifndef FAST_MIXER
|
||||
write_word_to_mix_map(i,j, j < 16 ? j : j + 2);
|
||||
unsafe{
|
||||
#if (FAST_MIXER == 0)
|
||||
mix_map[i * MIX_INPUTS + j] = (j < 16 ? j : j + 2);
|
||||
#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
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013-2022 XMOS LIMITED.
|
||||
// Copyright 2013-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <xs1.h>
|
||||
@@ -9,17 +9,17 @@
|
||||
#include "xua.h"
|
||||
|
||||
/* Note since DSD ports could be reused for I2S ports we do all the setup manually in C */
|
||||
#if DSD_CHANS_DAC > 0
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
port p_dsd_dac[DSD_CHANS_DAC] = {
|
||||
PORT_DSD_DAC0,
|
||||
#endif
|
||||
#if DSD_CHANS_DAC > 1
|
||||
#if (DSD_CHANS_DAC > 1)
|
||||
PORT_DSD_DAC1,
|
||||
#endif
|
||||
#if DSD_CHANS_DAC > 2
|
||||
#if (DSD_CHANS_DAC > 2)
|
||||
#error > 2 DSD chans currently not supported
|
||||
#endif
|
||||
#if DSD_CHANS_DAC > 0
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
};
|
||||
port p_dsd_clk = PORT_DSD_CLK;
|
||||
#endif
|
||||
@@ -45,7 +45,7 @@ void ConfigAudioPortsWrapper(
|
||||
port p_lrclk,
|
||||
port p_bclk,
|
||||
#endif
|
||||
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq, unsigned int dsdMode)
|
||||
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq)
|
||||
{
|
||||
ConfigAudioPorts(
|
||||
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)
|
||||
|
||||
@@ -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.
|
||||
#ifndef _AUDIOPORTS_H_
|
||||
#define _AUDIOPORTS_H_
|
||||
@@ -79,7 +79,7 @@ void ConfigAudioPortsWrapper(
|
||||
buffered in port:32 p_bclk,
|
||||
#endif
|
||||
#endif
|
||||
in port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq, unsigned int dsdMode);
|
||||
in port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq);
|
||||
#else
|
||||
|
||||
void ConfigAudioPortsWrapper(
|
||||
@@ -95,7 +95,7 @@ void ConfigAudioPortsWrapper(
|
||||
port p_lrclk,
|
||||
port p_bclk,
|
||||
#endif
|
||||
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq, unsigned int dsdMode);
|
||||
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq);
|
||||
|
||||
|
||||
#endif /* __XC__*/
|
||||
|
||||
@@ -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.
|
||||
#include <xs1.h>
|
||||
#include <platform.h>
|
||||
@@ -6,9 +6,7 @@
|
||||
#include "xua.h"
|
||||
#include "audioports.h"
|
||||
|
||||
//extern in port p_mclk_in;
|
||||
extern clock clk_audio_mclk;
|
||||
//extern clock clk_audio_bclk;
|
||||
|
||||
void ConfigAudioPorts(
|
||||
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)
|
||||
@@ -58,7 +56,7 @@ void ConfigAudioPorts(
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
#if (I2S_CHANS_DAC != 0)|| (DSD_CHANS_DAC != 0)
|
||||
for(int i = 0; i < numPortsDac; i++)
|
||||
{
|
||||
clearbuf(p_i2s_dac[i]);
|
||||
@@ -82,7 +80,7 @@ void ConfigAudioPorts(
|
||||
/* Some adustments for timing. Sample ADC lines on negative edge and add some delay */
|
||||
if(XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
|
||||
{
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
for(int i = 0; i < numPortsAdc; i++)
|
||||
{
|
||||
set_port_sample_delay(p_i2s_adc[i]);
|
||||
set_pad_delay(p_i2s_adc[i], 4);
|
||||
@@ -91,7 +89,6 @@ void ConfigAudioPorts(
|
||||
#endif
|
||||
|
||||
#elif (CODEC_MASTER)
|
||||
|
||||
/* Stop bit and master clock blocks */
|
||||
stop_clock(clk_audio_bclk);
|
||||
|
||||
@@ -103,20 +100,18 @@ void ConfigAudioPorts(
|
||||
/* Do some clocking shifting to get data in the valid window */
|
||||
/* E.g. Only shift when running at 88.2+ kHz TDM slave */
|
||||
int bClkDelay_fall = 0;
|
||||
if(curSamFreq * I2S_CHANS_PER_FRAME * 32 >= 20000000)
|
||||
if(curSamFreq * I2S_CHANS_PER_FRAME * XUA_I2S_N_BITS >= 20000000)
|
||||
{
|
||||
/* 18 * 2ns = 36ns. This results in a -4ns (36 - 40) shift at 96KHz and -8ns (36 - 44) at 88.4KHz */
|
||||
bClkDelay_fall = 18;
|
||||
}
|
||||
|
||||
set_clock_fall_delay(clk_audio_bclk, bClkDelay_fall);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
/* Clock I2S output data ports from b-clock clock block */
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)
|
||||
/* Clock I2S/DSD output data ports from b-clock clock block */
|
||||
for(int i = 0; i < numPortsDac; i++)
|
||||
{
|
||||
configure_out_port_no_ready(p_i2s_dac[i], clk_audio_bclk, 0);
|
||||
}
|
||||
@@ -124,7 +119,7 @@ void ConfigAudioPorts(
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
/* Clock I2S input data ports from clock block */
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
for(int i = 0; i < numPortsAdc; i++)
|
||||
{
|
||||
configure_in_port_no_ready(p_i2s_adc[i], clk_audio_bclk);
|
||||
}
|
||||
|
||||
29
lib_xua/src/core/user/audiohw/audiohw.c
Normal file
29
lib_xua/src/core/user/audiohw/audiohw.c
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright 2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/* Default implementations of AudioHwInit(), AudioHwConfig(), AudioHwConfig_Mute() and AudioHwConfig_UnMute() */
|
||||
|
||||
void AudioHwInit() __attribute__ ((weak));
|
||||
void AudioHwInit()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC) __attribute__ ((weak));
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void AudioHwConfig_Mute() __attribute__ ((weak));
|
||||
void AudioHwConfig_Mute()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void AudioHwConfig_UnMute() __attribute__ ((weak));
|
||||
void AudioHwConfig_UnMute()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
54
lib_xua/src/core/user/audiohw/audiohw.h
Normal file
54
lib_xua/src/core/user/audiohw/audiohw.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _AUDIO_HW_H_
|
||||
#define _AUDIO_HW_H_
|
||||
|
||||
/* The functions below should be implemented for the external audio hardware arrangement of a specific design.
|
||||
* Note, default (empty) implementations of these are provided in audiohub_user.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief User audio hardware initialisation code
|
||||
*
|
||||
* This function is called when the device starts up and should contain user code to perform any required audio hardware initialisation
|
||||
*/
|
||||
void AudioHwInit(void);
|
||||
|
||||
/**
|
||||
* @brief User audio hardware configuration code
|
||||
*
|
||||
* This function is called when on sample rate change and should contain user code to configure audio hardware
|
||||
* (clocking, CODECs etc) for a specific mClk/Sample frequency
|
||||
*
|
||||
* \param samFreq The new sample frequency (in Hz)
|
||||
*
|
||||
* \param mClk The new master clock frequency (in Hz)
|
||||
*
|
||||
* \param dsdMode DSD mode, DSD_MODE_NATIVE, DSD_MODE_DOP or DSD_MODE_OFF
|
||||
*
|
||||
* \param sampRes_DAC Playback sample resolution (in bits)
|
||||
*
|
||||
* \param sampRes_ADC Record sample resolution (in bits)
|
||||
*/
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC);
|
||||
|
||||
/**
|
||||
* @brief User code mute audio hardware
|
||||
*
|
||||
* This function is called before AudioHwConfig() and should contain user code to mute audio hardware before a
|
||||
* sample rate change in order to reduced audible pops/clicks
|
||||
*
|
||||
* Note, if using the application PLL of a xcore.ai device this function will be called before the master-clock is
|
||||
* changed
|
||||
*/
|
||||
void AudioHwConfig_Mute(void);
|
||||
|
||||
/**
|
||||
* @brief User code to un-mute audio hardware
|
||||
*
|
||||
* This function is called after AudioHwConfig() and should contain user code to un-mute audio hardware after a
|
||||
* sample rate change
|
||||
*/
|
||||
void AudioHwConfig_UnMute(void);
|
||||
|
||||
#endif
|
||||
@@ -1,30 +1,51 @@
|
||||
// Copyright 2011-2021 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _AUDIOSTREAM_H_
|
||||
#define _AUDIOSTREAM_H_
|
||||
|
||||
/* Functions that handle functions that must occur on stream start/stop e.g. DAC mute/un-mute
|
||||
*
|
||||
* THESE NEED IMPLEMENTING FOR A SPECIFIC DESIGN
|
||||
*
|
||||
* */
|
||||
/* Functions that handle functionality that occur on stream start/stop e.g. DAC mute/un-mute.
|
||||
* They should be implemented for the external audio hardware arrangement of a specific design.
|
||||
*/
|
||||
|
||||
/* Any actions required for stream start e.g. DAC un-mute - run every stream start */
|
||||
/**
|
||||
* @brief User stream start code
|
||||
*
|
||||
* User code to perform any actions required at every stream start - either input or output
|
||||
*/
|
||||
void UserAudioStreamStart(void);
|
||||
|
||||
/* Any actions required on stream stop e.g. DAC mute - run every steam stop */
|
||||
/**
|
||||
* @brief User stream stop code
|
||||
*
|
||||
* User code to perform any actions required on every stream stop - either input or output*/
|
||||
void UserAudioStreamStop(void);
|
||||
|
||||
/* Any actions required on input stream start */
|
||||
/**
|
||||
* @brief User input stream stop code
|
||||
*
|
||||
* User code to perform any actions required on input stream start i.e. device to host
|
||||
*/
|
||||
void UserAudioInputStreamStart(void);
|
||||
|
||||
/* Any actions required on input stream stop */
|
||||
/**
|
||||
* @brief User input stream stop code
|
||||
*
|
||||
* User code to perform any actions required on input stream stop i.e. device to host
|
||||
*/
|
||||
void UserAudioInputStreamStop(void);
|
||||
|
||||
/* Any actions required on output stream start */
|
||||
/**
|
||||
* @brief User output stream start code
|
||||
*
|
||||
* User code to perform any actions required on output stream start i.e. host to device
|
||||
*/
|
||||
void UserAudioOutputStreamStart(void);
|
||||
|
||||
/* Any actions required on output stream stop */
|
||||
/**
|
||||
* @brief User output stream stop code
|
||||
*
|
||||
* User code to perfrom any actions required on output stream stop i.e. host to device
|
||||
*/
|
||||
void UserAudioOutputStreamStop(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
// Copyright 2013-2021 XMOS LIMITED.
|
||||
// Copyright 2013-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/**
|
||||
* @brief Human Interface Device (HID) API
|
||||
*
|
||||
* This file defines the Application Programming Interface (API) used to record HID
|
||||
* events and retrieve a HID Report for sending to a host.
|
||||
* events and retrieve a HID Report for sending to a host.
|
||||
* The using application has the responsibility to fulfill this API.
|
||||
* Document section numbers refer to the HID Device Class Definition, version 1.11.
|
||||
*/
|
||||
|
||||
#ifndef __USER_HID_H__
|
||||
#define __USER_HID_H__
|
||||
#ifndef _USER_HID_H_
|
||||
#define _USER_HID_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -34,22 +34,16 @@ typedef struct hidEvent_t {
|
||||
#define HID_MAX_DATA_BYTES ( 4 )
|
||||
#define HID_EVENT_INVALID_ID ( 0x100 )
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
|
||||
/**
|
||||
* \brief Get the data for the next HID Report
|
||||
*
|
||||
* \note This function returns the HID data as a list of unsigned char because the
|
||||
* \c XUD_SetReady_In() accepts data for transmission to the USB Host using
|
||||
* this type.
|
||||
*
|
||||
* \param[in] id The HID Report ID (see 5.6, 6.2.2.7, 8.1 and 8.2)
|
||||
* Set to zero if the application provides only one HID Report
|
||||
* which does not include a Report ID
|
||||
* which does not include a Report ID
|
||||
* \param[out] hidData The HID data
|
||||
* If using Report IDs, this function places the Report ID in
|
||||
* the first element; otherwise the first element holds the
|
||||
* first byte of HID event data.
|
||||
* the first element; otherwise the first element holds the
|
||||
* first byte of HID event data.
|
||||
*
|
||||
* \returns The length of the HID Report in the \a hidData argument
|
||||
* \retval Zero means no new HID event data has been recorded for the given \a id
|
||||
@@ -61,21 +55,4 @@ size_t UserHIDGetData( const unsigned id, unsigned char hidData[ HID_MAX_DATA_BY
|
||||
*/
|
||||
void UserHIDInit( void );
|
||||
|
||||
/**
|
||||
* \brief Record that a HID event has occurred
|
||||
*
|
||||
* \param[in] hidEvent A list of events which have occurred.
|
||||
* Each element specifies a HID Report ID, a bit and byte
|
||||
* within the HID Report and the value for it.
|
||||
* Set the Report ID to zero if not using Report IDs
|
||||
* (see 5.6, 6.2.2.7, 8.1 and 8.2).
|
||||
* \param[in] hidEventCnt The length of the \a hidEvent list.
|
||||
*
|
||||
* \returns The index of the first unrecorded event in \a hidEvent
|
||||
* \retval Zero indicates no events were recorded
|
||||
* \retval \a hidEventCnt indicates all events were recorded
|
||||
*/
|
||||
size_t UserHIDRecordEvent( const hidEvent_t hidEvent[], const size_t hidEventCnt );
|
||||
|
||||
#endif /* ( 0 < HID_CONTROLS ) */
|
||||
#endif /* __USER_HID_H__ */
|
||||
#endif /* _USER_HID_H_ */
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
// Copyright 2013-2021 XMOS LIMITED.
|
||||
// Copyright 2013-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/**
|
||||
* @brief User host active code
|
||||
*
|
||||
* This function can be used to perform user defined actions based on host present/not-present events.
|
||||
* This function is called on a change in state.
|
||||
*
|
||||
* \param active Indicates if the host is active or not. 1 for active, else 0
|
||||
*/
|
||||
void UserHostActive(int active);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2013-2021 XMOS LIMITED.
|
||||
// Copyright 2013-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/*
|
||||
Warnings relating to configuration defines located in this XC source file rather than the devicedefines.h header file in order to avoid multiple warnings being issued when the devicedefines.h header file is included in multiple files.
|
||||
Warnings relating to configuration defines located in this XC source file rather than the xua_conf.h header file in order to avoid multiple warnings being issued when the xua_conf.h header file is included in multiple files.
|
||||
*/
|
||||
|
||||
#include "xua_conf_full.h"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// Copyright 2013-2021 XMOS LIMITED.
|
||||
// Copyright 2013-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#if XUA_USB_EN
|
||||
#include "xua.h"
|
||||
#if XUA_USB_EN
|
||||
#include "hostactive.h"
|
||||
#include "audiostream.h"
|
||||
|
||||
/* Implementations over-riding empty versions in lib_xud/sec/core/XUD_User.c */
|
||||
|
||||
void XUD_UserSuspend(void) __attribute__ ((weak));
|
||||
void XUD_UserSuspend(void)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2022 XMOS LIMITED.
|
||||
// Copyright 2019-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <stdint.h>
|
||||
#include <xs1.h>
|
||||
@@ -13,7 +13,7 @@
|
||||
#define DEBUG_PRINT_ENABLE_HID_XC 0
|
||||
#include "debug_print.h"
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_HID_ENABLED
|
||||
static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod );
|
||||
static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime );
|
||||
static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod );
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021-2022 XMOS LIMITED.
|
||||
// Copyright 2021-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include "xua_conf_full.h"
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_HID_ENABLED
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 XMOS LIMITED.
|
||||
// Copyright 2021-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/**
|
||||
@@ -31,6 +31,19 @@
|
||||
HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_HI, /* 5 wMaxPacketSize */
|
||||
ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */
|
||||
|
||||
#if (HID_OUT_REQUIRED)
|
||||
|
||||
/* HID Endpoint descriptor (OUT) */
|
||||
HID_ENDPOINT_DESCRIPTOR_LENGTH, /* 0 bLength */
|
||||
HID_ENDPOINT_DESCRIPTOR_TYPE, /* 1 bDescriptorType */
|
||||
ENDPOINT_ADDRESS_OUT_HID, /* 2 bEndpointAddress */
|
||||
HID_ENDPOINT_ATTRIBUTES, /* 3 bmAttributes (INTERRUPT) */
|
||||
HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_LO, /* 4 wMaxPacketSize */
|
||||
HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_HI, /* 5 wMaxPacketSize */
|
||||
ENDPOINT_INT_INTERVAL_OUT_HID, /* 6 bInterval */
|
||||
|
||||
#endif
|
||||
|
||||
#elif (AUDIO_CLASS == 2)
|
||||
|
||||
.HID_In_Endpoint =
|
||||
@@ -44,6 +57,21 @@
|
||||
.bInterval = ENDPOINT_INT_INTERVAL_IN_HID,
|
||||
},
|
||||
|
||||
#if (HID_OUT_REQUIRED)
|
||||
|
||||
.HID_Out_Endpoint =
|
||||
{
|
||||
/* Endpoint descriptor (OUT) */
|
||||
.bLength = sizeof(USB_Descriptor_Endpoint_t),
|
||||
.bDescriptorType = HID_ENDPOINT_DESCRIPTOR_TYPE,
|
||||
.bEndpointAddress = ENDPOINT_ADDRESS_OUT_HID,
|
||||
.bmAttributes = HID_ENDPOINT_ATTRIBUTES,
|
||||
.wMaxPacketSize = HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_LO,
|
||||
.bInterval = ENDPOINT_INT_INTERVAL_OUT_HID,
|
||||
},
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "Unknown Audio Class"
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 XMOS LIMITED.
|
||||
// Copyright 2021-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/**
|
||||
@@ -15,7 +15,8 @@
|
||||
#define HID_INTERFACE_DESCRIPTOR_LENGTH ( 0x09 ) /* Size of descriptor in Bytes */
|
||||
#define HID_INTERFACE_DESCRIPTOR_TYPE ( 0x04 ) /* Interface 0x04 */
|
||||
#define HID_INTERFACE_ALTERNATE_SETTING ( 0x00 ) /* Value used alternate interfaces using SetInterface Request */
|
||||
#define HID_INTERFACE_NUMBER_OF_ENDPOINTS ( 0x01 ) /* Number of endpoitns for this interface (excluding 0) */
|
||||
#define HID_INTERFACE_NUMBER_OF_ENDPOINTS ( 0x01 + HID_OUT_REQUIRED )
|
||||
/* Number of endpoints for this interface (excluding 0) */
|
||||
#define HID_INTERFACE_CLASS ( 0x03 )
|
||||
#define HID_INTERFACE_SUBCLASS ( 0x00 ) /* No boot device */
|
||||
#define HID_INTERFACE_PROTOCOL ( 0x00 )
|
||||
|
||||
@@ -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.
|
||||
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):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2018-2022 XMOS LIMITED.
|
||||
# Copyright 2018-2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import Pyxsim
|
||||
@@ -11,16 +11,21 @@ import sys
|
||||
def test_file(request):
|
||||
return str(request.node.fspath)
|
||||
|
||||
|
||||
def do_test(
|
||||
pcm_format, i2s_role, channel_count, sample_rate, test_file, options, capfd
|
||||
pcm_format, i2s_role, channel_count, sample_rate, word_length, test_file, options, capfd
|
||||
):
|
||||
|
||||
build_options = []
|
||||
output = []
|
||||
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||
|
||||
desc = f"simulation_{pcm_format}_{i2s_role}_{channel_count}in_{channel_count}out_{sample_rate}"
|
||||
build_options += [f"pcm_format={pcm_format}"]
|
||||
build_options += [f"i2s_role={i2s_role}"]
|
||||
build_options += [f"channel_count={channel_count}"]
|
||||
build_options += [f"sample_rate={sample_rate}"]
|
||||
build_options += [f"word_length={word_length}"]
|
||||
|
||||
desc = f"simulation_{pcm_format}_{i2s_role}_{channel_count}in_{channel_count}out_{sample_rate}_{word_length}bit"
|
||||
binary = f"{testname}/bin/{desc}/{testname}_{desc}.xe"
|
||||
|
||||
tester = testers.ComparisonTester(open("pass.expect"))
|
||||
@@ -52,6 +57,7 @@ def do_test(
|
||||
|
||||
result = Pyxsim.run_on_simulator(
|
||||
binary,
|
||||
build_options=build_options,
|
||||
tester=tester,
|
||||
simargs=simargs,
|
||||
capfd=capfd,
|
||||
@@ -65,25 +71,26 @@ def do_test(
|
||||
@pytest.mark.parametrize("i2s_role", ["master", "slave"])
|
||||
@pytest.mark.parametrize("pcm_format", ["i2s", "tdm"])
|
||||
@pytest.mark.parametrize("channel_count", [2, 8, 16])
|
||||
@pytest.mark.parametrize("sample_rate", ["48khz", "96khz", "192khz"])
|
||||
@pytest.mark.parametrize("word_length", [16, 32]) # I2S world length in bits
|
||||
@pytest.mark.parametrize("sample_rate", [48000, 96000, 192000])
|
||||
def test_i2s_loopback(
|
||||
i2s_role, pcm_format, channel_count, sample_rate, test_file, options, capfd
|
||||
i2s_role, pcm_format, channel_count, sample_rate, word_length, test_file, options, capfd
|
||||
):
|
||||
|
||||
if pcm_format == "i2s" and channel_count == 16:
|
||||
pytest.skip("Invalid parameter combination")
|
||||
|
||||
if pcm_format == "i2s" and sample_rate not in ["48khz", "192khz"]:
|
||||
if pcm_format == "i2s" and sample_rate not in [48000, 192000]:
|
||||
pytest.skip("Invalid parameter combination")
|
||||
|
||||
if pcm_format == "tdm" and channel_count == 2:
|
||||
pytest.skip("Invalid parameter combination")
|
||||
|
||||
if pcm_format == "tdm" and sample_rate == "192khz":
|
||||
if pcm_format == "tdm" and sample_rate == 192000:
|
||||
pytest.skip("Invalid parameter combination")
|
||||
|
||||
result = do_test(
|
||||
pcm_format, i2s_role, channel_count, sample_rate, test_file, options, capfd
|
||||
pcm_format, i2s_role, channel_count, sample_rate, word_length, test_file, options, capfd
|
||||
)
|
||||
|
||||
assert result
|
||||
|
||||
@@ -1,126 +1,44 @@
|
||||
TARGET = xk-audio-216-mc.xn
|
||||
USED_MODULES = lib_xua lib_i2c lib_logging
|
||||
|
||||
BUILD_FLAGS = -O0 -g -lflash -DXUD_CORE_CLOCK=600 -fxscope -save-temps -march=xs2a -DUSB_TILE=tile[1]
|
||||
BUILD_FLAGS = -O3 -g -lflash -DXUD_CORE_CLOCK=600 -fxscope -save-temps -march=xs2a -DUSB_TILE=tile[1] \
|
||||
-DXUA_ADAT_RX_EN=0 -DXUA_ADAT_TX_EN=0 -DXUA_SPDIF_RX_EN=0 -DXUA_SPDIF_TX_EN=0 -DMIDI=0 \
|
||||
-DSIMULATION=1
|
||||
|
||||
BUILD_FLAGS_i2s_master_2in_2out_48khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -DI2S_CHANS_ADC=2 -DI2S_CHANS_DAC=2 \
|
||||
-D DEFAULT_FREQ=48000
|
||||
ifndef pcm_format
|
||||
$(error pcm_format is not set)
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_slave_2in_2out_48khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -DI2S_CHANS_ADC=2 -DI2S_CHANS_DAC=2 \
|
||||
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1
|
||||
ifndef i2s_role
|
||||
$(error i2s_role is not set)
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_master_2in_2out_192khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -D I2S_CHANS_ADC=2 -D I2S_CHANS_DAC=2 \
|
||||
-D DEFAULT_FREQ=192000
|
||||
ifndef channel_count
|
||||
$(error channel_count is not set)
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_slave_2in_2out_192khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -DI2S_CHANS_ADC=2 -DI2S_CHANS_DAC=2 \
|
||||
-D DEFAULT_FREQ=192000 -DCODEC_MASTER=1
|
||||
ifndef sample_rate
|
||||
$(error sample_rate is not set)
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_master_8in_8out_48khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=48000
|
||||
ifndef word_length
|
||||
$(error word_length is not set)
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_slave_8in_8out_48khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1
|
||||
ifeq ($(pcm_format),tdm)
|
||||
BUILD_FLAGS += -DXUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM
|
||||
endif
|
||||
ifeq ($(i2s_role),slave)
|
||||
BUILD_FLAGS += -DCODEC_MASTER=1
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_master_8in_8out_192khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=192000 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_i2s_slave_8in_8out_192khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=192000 -DCODEC_MASTER=1 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_master_8in_8out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=48000 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_master_8in_8out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=96000 \
|
||||
-O3 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_slave_8in_8out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_slave_8in_8out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=96000 -DCODEC_MASTER=1 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_master_16in_16out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
|
||||
-D DEFAULT_FREQ=48000 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_master_16in_16out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
|
||||
-D DEFAULT_FREQ=96000 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_slave_16in_16out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
|
||||
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_slave_16in_16out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
|
||||
-D DEFAULT_FREQ=96000 -DCODEC_MASTER=1 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
|
||||
#XCC_FLAGS_hardware_i2s_master_2in_2out_48khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_2in_2out_48khz)
|
||||
#XCC_FLAGS_hardware_i2s_master_2in_2out_192khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_2in_2out_192khz)
|
||||
#XCC_FLAGS_hardware_i2s_master_8in_8out_48khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_8in_8out_48khz)
|
||||
#XCC_FLAGS_hardware_i2s_master_8in_8out_192khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_8in_8out_192khz)
|
||||
#XCC_FLAGS_hardware_tdm_master_8in_8out_48khz = -D HARDWARE $(BUILD_FLAGS_tdm_master_8in_8out_48khz)
|
||||
|
||||
XCC_FLAGS_simulation_i2s_master_2in_2out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_2in_2out_48khz)
|
||||
XCC_FLAGS_simulation_i2s_slave_2in_2out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_2in_2out_48khz)
|
||||
|
||||
XCC_FLAGS_simulation_i2s_master_2in_2out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_2in_2out_192khz)
|
||||
XCC_FLAGS_simulation_i2s_slave_2in_2out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_2in_2out_192khz)
|
||||
|
||||
XCC_FLAGS_simulation_i2s_master_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_8in_8out_48khz)
|
||||
XCC_FLAGS_simulation_i2s_slave_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_8in_8out_48khz)
|
||||
|
||||
XCC_FLAGS_simulation_i2s_master_8in_8out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_8in_8out_192khz)
|
||||
XCC_FLAGS_simulation_i2s_slave_8in_8out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_8in_8out_192khz)
|
||||
|
||||
XCC_FLAGS_simulation_tdm_master_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_8in_8out_48khz)
|
||||
XCC_FLAGS_simulation_tdm_master_8in_8out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_8in_8out_96khz)
|
||||
XCC_FLAGS_simulation_tdm_slave_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_8in_8out_48khz)
|
||||
XCC_FLAGS_simulation_tdm_slave_8in_8out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_8in_8out_96khz)
|
||||
|
||||
XCC_FLAGS_simulation_tdm_master_16in_16out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_16in_16out_48khz)
|
||||
XCC_FLAGS_simulation_tdm_master_16in_16out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_16in_16out_96khz)
|
||||
XCC_FLAGS_simulation_tdm_slave_16in_16out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_16in_16out_48khz)
|
||||
XCC_FLAGS_simulation_tdm_slave_16in_16out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_16in_16out_96khz)
|
||||
XCC_FLAGS_simulation_${pcm_format}_${i2s_role}_$(channel_count)in_$(channel_count)out_$(sample_rate)_$(word_length)bit = $(BUILD_FLAGS) \
|
||||
-DNUM_USB_CHAN_IN=${channel_count} \
|
||||
-DNUM_USB_CHAN_OUT=${channel_count} \
|
||||
-DI2S_CHANS_DAC=${channel_count} \
|
||||
-DI2S_CHANS_ADC=${channel_count} \
|
||||
-DDEFAULT_FREQ=${sample_rate} \
|
||||
-DXUA_I2S_N_BITS=${word_length}
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016-2022 XMOS LIMITED.
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <platform.h>
|
||||
#include <stdlib.h>
|
||||
@@ -9,7 +9,6 @@
|
||||
#define DEBUG_UNIT MAIN
|
||||
#include "debug_print.h"
|
||||
|
||||
|
||||
/* Port declarations. Note, the defines come from the xn file */
|
||||
#if I2S_WIRES_DAC > 0
|
||||
on tile[AUDIO_IO_TILE] : buffered out port:32 p_i2s_dac[I2S_WIRES_DAC] =
|
||||
@@ -92,9 +91,10 @@ clock clk_audio_mclk = on tile[AUDIO_IO_TILE]: XS1_CLKBLK_2; /*
|
||||
#define TOTAL_TEST_FRAMES (5 * DEFAULT_FREQ)
|
||||
#endif
|
||||
|
||||
#define SAMPLE(frame_count, channel_num) (((frame_count) << 8) | ((channel_num) & 0xFF))
|
||||
#define SAMPLE_FRAME_NUM(test_word) ((test_word) >> 8)
|
||||
#define SAMPLE_CHANNEL_NUM(test_word) ((test_word) & 0xFF)
|
||||
#define SHIFT (16) /* Note, we shift samples up such that we can test down to 16bit I2S */
|
||||
#define SAMPLE(frame_count, channel_num) ((((frame_count) << 8) | ((channel_num) & 0xFF))<<SHIFT)
|
||||
#define SAMPLE_FRAME_NUM(test_word) ((test_word>>SHIFT) >> 8)
|
||||
#define SAMPLE_CHANNEL_NUM(test_word) ((test_word>>SHIFT) & 0xFF)
|
||||
|
||||
void generator(chanend c_checker, chanend c_out)
|
||||
{
|
||||
@@ -105,7 +105,6 @@ void generator(chanend c_checker, chanend c_out)
|
||||
|
||||
frame_count = 0;
|
||||
|
||||
|
||||
while (1) {
|
||||
underflow_word = inuint(c_out);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016-2022 XMOS LIMITED.
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifdef SIMULATION
|
||||
|
||||
@@ -41,7 +41,7 @@ extern out port p_lrclk_gen;
|
||||
extern clock clk_audio_lrclk_gen;
|
||||
|
||||
void slave_mode_clk_setup(const unsigned samFreq, const unsigned chans_per_frame){
|
||||
const unsigned data_bits = 32;
|
||||
const unsigned data_bits = XUA_I2S_N_BITS;
|
||||
const unsigned mclk_freq = 24576000;
|
||||
|
||||
const unsigned mclk_bclk_ratio = mclk_freq / (chans_per_frame * samFreq * data_bits);
|
||||
@@ -61,5 +61,4 @@ void slave_mode_clk_setup(const unsigned samFreq, const unsigned chans_per_frame
|
||||
master_mode_clk_setup();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
45
tests/test_mixer_routing_input.py
Normal file
45
tests/test_mixer_routing_input.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright 2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import Pyxsim
|
||||
from Pyxsim import testers
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def do_test(options, capfd, test_file, test_seed):
|
||||
|
||||
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||
|
||||
binary = f"{testname}/bin/{testname}.xe"
|
||||
|
||||
tester = testers.ComparisonTester(open("pass.expect"))
|
||||
|
||||
max_cycles = 15000000
|
||||
|
||||
simargs = [
|
||||
"--max-cycles",
|
||||
str(max_cycles),
|
||||
]
|
||||
|
||||
build_options = []
|
||||
build_options += ["TEST_SEED=" + str(test_seed)]
|
||||
|
||||
result = Pyxsim.run_on_simulator(
|
||||
binary,
|
||||
tester=tester,
|
||||
build_options=build_options,
|
||||
simargs=simargs,
|
||||
capfd=capfd,
|
||||
instTracing=options.enabletracing,
|
||||
vcdTracing=options.enablevcdtracing,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def test_mixer_routing_input(options, capfd, test_file, test_seed):
|
||||
|
||||
result = do_test(options, capfd, test_file, test_seed)
|
||||
|
||||
assert result
|
||||
19
tests/test_mixer_routing_input/Makefile
Normal file
19
tests/test_mixer_routing_input/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
|
||||
else
|
||||
TEST_DEBUG_FLAGS =
|
||||
endif
|
||||
|
||||
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS)
|
||||
|
||||
XCC_FLAGS = -O3 $(TEST_FLAGS)
|
||||
|
||||
TARGET = test_xs3_600.xn
|
||||
|
||||
USED_MODULES = lib_xua lib_logging lib_random
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
243
tests/test_mixer_routing_input/src/main.xc
Normal file
243
tests/test_mixer_routing_input/src/main.xc
Normal file
@@ -0,0 +1,243 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/* Tests that routing of mixer inputs behaves as expected
|
||||
*
|
||||
* The device supports MAX_MIX_COUNT mixers each with MIX_INPUTS inputs.
|
||||
*
|
||||
* This test also assumes/checks that the default routing into each of the MIX_INPUTS inputs into
|
||||
* each of the M mixer units is as follows:
|
||||
*
|
||||
* MIXER[0]:
|
||||
* USB_FROM_HOST[0] -> MIXER[0].INPUT[0]
|
||||
* USB_FROM_HOST[1] -> MIXER[0].INPUT[1]
|
||||
* ...
|
||||
USB_TO_HOST[0] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT]
|
||||
USB_TO_HOST[1] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT+1]
|
||||
...
|
||||
|
||||
* MIXER[MAX_MIX_COUNT-1]:
|
||||
* USB_FROM_HOST[0] -> MIXER[MAX_MIX_COUNT-1].INPUT[0]
|
||||
* USB_FROM_HOST[1] -> MIXER[MAX_MIX_COUNT-1].INPUT[1]
|
||||
* ...
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "platform.h"
|
||||
#include "xua.h"
|
||||
#include "debug_print.h"
|
||||
#include "assert.h"
|
||||
#include "random.h"
|
||||
|
||||
#ifndef TEST_ITERATIONS
|
||||
#define TEST_ITERATIONS (300)
|
||||
#endif
|
||||
|
||||
#include "./../test_mixer_routing_output/src/mixer_test_shared.h"
|
||||
|
||||
struct ModelMixer
|
||||
{
|
||||
uint32_t deviceMap[NUM_USB_CHAN_OUT];
|
||||
uint32_t hostMap[NUM_USB_CHAN_IN];
|
||||
uint32_t mixMap_input[MAX_MIX_COUNT];
|
||||
uint32_t mixMap_src[MAX_MIX_COUNT];
|
||||
uint32_t mixOutput[MAX_MIX_COUNT];
|
||||
};
|
||||
|
||||
void InitModel(struct ModelMixer &modelMixer)
|
||||
{
|
||||
for(size_t i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
modelMixer.deviceMap[i] = i;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
modelMixer.hostMap[i] = NUM_USB_CHAN_OUT+i;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
// This test only allows for one "active" input to each mixer
|
||||
modelMixer.mixMap_src[i] = i;
|
||||
modelMixer.mixMap_input[i] = i;
|
||||
|
||||
uint32_t sample = i;
|
||||
SET_SOURCE(sample, SRC_HOST);
|
||||
SET_CHANNEL(sample, i);
|
||||
modelMixer.mixOutput[i] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void GenExpectedSamples(struct ModelMixer &modelMixer,
|
||||
uint32_t modelOut[NUM_USB_CHAN_OUT],
|
||||
uint32_t modelIn[NUM_USB_CHAN_IN])
|
||||
{
|
||||
/* First generate model mix outputs - run MIX tiles to allow mix inputs derived from mix outputs to propagate */
|
||||
for(int j = 0; j < MAX_MIX_COUNT; j++)
|
||||
{
|
||||
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
int src = modelMixer.mixMap_src[i];
|
||||
modelMixer.mixOutput[i] = CreateSample(modelMixer.mixOutput, src);
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i<NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int src = modelMixer.deviceMap[i];
|
||||
modelOut[i] = CreateSample(modelMixer.mixOutput, src);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i<NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
int src = modelMixer.hostMap[i];
|
||||
modelIn[i] = CreateSample(modelMixer.mixOutput, src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MapMixerInput(int mix, int input, int src, struct ModelMixer &modelMixer, chanend c_mix_ctl,
|
||||
chanend c_stim_ah, chanend c_stim_de, uint32_t modelIn[], uint32_t modelOut[])
|
||||
{
|
||||
debug_printf("Mapping mix %d input %d", mix, input);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
|
||||
/* This test only allows for one input to travel "untouched" to the mix output - since this test doesn't model the actual mixing.
|
||||
* Because of this we must also mod the mixer weights, not just the mixer input map.
|
||||
* If we simply just apply an update to the mixer input mapping it would not produce an observable difference on the mixer output
|
||||
*/
|
||||
|
||||
/* Set previously "activated" input weight to 0 */
|
||||
debug_printf("Setting mix %d, weight %d to 0\n", mix, modelMixer.mixMap_input[mix]);
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
UpdateMixerWeight(c_mix_ctl, mix, modelMixer.mixMap_input[mix], 0);
|
||||
|
||||
/* Set new "activated" input wright to max (i.e. x1) */
|
||||
debug_printf("Setting mix %d, weight %d to %x\n", mix, input, XUA_MIXER_MAX_MULT);
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
UpdateMixerWeight(c_mix_ctl, mix, input, XUA_MIXER_MAX_MULT);
|
||||
|
||||
/* Update mixer input in model */
|
||||
modelMixer.mixMap_src[mix] = src;
|
||||
modelMixer.mixMap_input[mix] = input;
|
||||
|
||||
/* Run twice to allow mix inputs derived from mix outputs to propagate */
|
||||
GenExpectedSamples(modelMixer, modelOut, modelIn);
|
||||
|
||||
/* Finally update the acutal mixer input map */
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
UpdateMixMap(c_mix_ctl, mix, input, src);
|
||||
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
|
||||
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||
}
|
||||
|
||||
|
||||
/* This task configures the routing and maintains a model of the expected routing output
|
||||
* it provides this to the Fake AudioHub and Fake Decouple tasks such that they can self check
|
||||
*/
|
||||
void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
|
||||
{
|
||||
uint32_t modelOut[NUM_USB_CHAN_OUT];
|
||||
uint32_t modelIn[NUM_USB_CHAN_IN];
|
||||
|
||||
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
|
||||
|
||||
struct ModelMixer modelMixer;
|
||||
|
||||
InitModel(modelMixer);
|
||||
|
||||
GenExpectedSamples(modelMixer, modelOut, modelIn);
|
||||
|
||||
/* There is single sample delay between the two mixer cores, so trigger twice to flush though a block
|
||||
* of zero samples */
|
||||
SendTrigger(c_stim_ah, 2);
|
||||
|
||||
/* Send expected samples to AH and DE and run checks */
|
||||
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||
|
||||
/* Firstly route mixer outputs to the audio interfaces (we could have chosen host)
|
||||
* such that we can observe and check the outputs from the mixer
|
||||
*/
|
||||
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
int map = SET_SAMPLES_TO_DEVICE_MAP;
|
||||
assert(i < NUM_USB_CHAN_OUT);
|
||||
int dst = i;
|
||||
int src = NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN+i; // mix0, mix1..
|
||||
debug_printf("Mapping output to AudioIF: %d ", dst);
|
||||
|
||||
PrintDestString(map, dst);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
|
||||
/* Update the mixer */
|
||||
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
|
||||
|
||||
/* Update the model */
|
||||
modelMixer.deviceMap[dst] = src;
|
||||
}
|
||||
|
||||
/* Send expected samples to fake AudioHub and Decouple for checking */
|
||||
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||
|
||||
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
|
||||
{
|
||||
/* Make a random update to the routing - route a random source to a random mix input */
|
||||
unsigned mix = random_get_random_number(rg) % MAX_MIX_COUNT;
|
||||
unsigned input = random_get_random_number(rg) % MIX_INPUTS;
|
||||
|
||||
/* Note, we don't currently support a mix input dervived from another mix
|
||||
* This is not trivial to test since the current mixer implementation only allows for one
|
||||
* config update per "trigger"
|
||||
*/
|
||||
unsigned src = random_get_random_number(rg) % NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT;
|
||||
|
||||
debug_printf("Iteration: %d\n", testIter);
|
||||
MapMixerInput(mix, input, src, modelMixer, c_mix_ctl, c_stim_ah, c_stim_de, modelIn, modelOut);
|
||||
}
|
||||
|
||||
/* Send kill messages to Fake AudioHub & Fake Decouple */
|
||||
outct(c_stim_ah, XS1_CT_END);
|
||||
inct(c_stim_ah);
|
||||
|
||||
outct(c_stim_de, XS1_CT_END);
|
||||
inct(c_stim_de);
|
||||
|
||||
printstrln("PASS");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chan c_dec_mix;
|
||||
chan c_mix_aud;
|
||||
chan c_mix_ctl;
|
||||
chan c_stim_ah;
|
||||
chan c_stim_de;
|
||||
|
||||
par
|
||||
{
|
||||
Fake_XUA_Buffer_Decouple(c_dec_mix, c_stim_de);
|
||||
Fake_XUA_AudioHub(c_mix_aud, c_stim_ah);
|
||||
|
||||
/* Mixer from lib_xua */
|
||||
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
|
||||
|
||||
stim(c_stim_ah, c_stim_de, c_mix_ctl);
|
||||
}
|
||||
|
||||
/* TODO to hit this we need to fully close down i.e. kill mixer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
tests/test_mixer_routing_input/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_input/src/test_xs3_600.xn
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Network xmlns="http://www.xmos.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
|
||||
<Declarations>
|
||||
<Declaration>tileref tile[2]</Declaration>
|
||||
</Declarations>
|
||||
|
||||
<Packages>
|
||||
<Package id="0" Type="XS3-UnA-1024-FB265">
|
||||
<Nodes>
|
||||
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
|
||||
<Tile Number="0" Reference="tile[0]"/>
|
||||
<Tile Number="1" Reference="tile[1]"/>
|
||||
</Node>
|
||||
</Nodes>
|
||||
</Package>
|
||||
</Packages>
|
||||
|
||||
<JTAGChain>
|
||||
<JTAGDevice NodeId="0"/>
|
||||
</JTAGChain>
|
||||
|
||||
</Network>
|
||||
45
tests/test_mixer_routing_input/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_input/src/xua_conf.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_CONF_H_
|
||||
#define _XUA_CONF_H_
|
||||
|
||||
#define NUM_USB_CHAN_OUT (10)
|
||||
#define NUM_USB_CHAN_IN (10)
|
||||
#define I2S_CHANS_DAC (10)
|
||||
#define I2S_CHANS_ADC (10)
|
||||
|
||||
#define EXCLUDE_USB_AUDIO_MAIN
|
||||
|
||||
#define MIXER (1)
|
||||
#define MAX_MIX_COUNT (8)
|
||||
|
||||
#define UAC_FORCE_FEEDBACK_EP (0)
|
||||
#define XUA_NUM_PDM_MICS 0
|
||||
#define XUD_TILE 1
|
||||
#define AUDIO_IO_TILE 0
|
||||
|
||||
#ifndef MCLK_441
|
||||
#define MCLK_441 (512 * 44100)
|
||||
#endif
|
||||
|
||||
#ifndef MCLK_48
|
||||
#define MCLK_48 (512 * 48000)
|
||||
#endif
|
||||
|
||||
#define MIN_FREQ (44100)
|
||||
#define MAX_FREQ (192000)
|
||||
#define SPDIF_TX_INDEX 0
|
||||
#define VENDOR_STR "XMOS"
|
||||
#define VENDOR_ID 0x20B1
|
||||
#define PRODUCT_STR_A2 "Test device"
|
||||
#define PRODUCT_STR_A1 "Test device"
|
||||
#define PID_AUDIO_1 1
|
||||
#define PID_AUDIO_2 2
|
||||
#define AUDIO_CLASS 2
|
||||
#define AUDIO_CLASS_FALLBACK 0
|
||||
#define BCD_DEVICE 0x1234
|
||||
#define XUA_DFU_EN 0
|
||||
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
|
||||
#define XUA_MIC_FRAME_SIZE 240
|
||||
|
||||
#endif
|
||||
45
tests/test_mixer_routing_input_ctrl.py
Normal file
45
tests/test_mixer_routing_input_ctrl.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright 2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import Pyxsim
|
||||
from Pyxsim import testers
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def do_test(options, capfd, test_file, test_seed):
|
||||
|
||||
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||
|
||||
binary = f"{testname}/bin/{testname}.xe"
|
||||
|
||||
tester = testers.ComparisonTester(open("pass.expect"))
|
||||
|
||||
max_cycles = 15000000
|
||||
|
||||
simargs = [
|
||||
"--max-cycles",
|
||||
str(max_cycles),
|
||||
]
|
||||
|
||||
build_options = []
|
||||
build_options += ["TEST_SEED=" + str(test_seed)]
|
||||
|
||||
result = Pyxsim.run_on_simulator(
|
||||
binary,
|
||||
tester=tester,
|
||||
build_options=build_options,
|
||||
simargs=simargs,
|
||||
capfd=capfd,
|
||||
instTracing=options.enabletracing,
|
||||
vcdTracing=options.enablevcdtracing,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def test_mixer_routing_output(options, capfd, test_file, test_seed):
|
||||
|
||||
result = do_test(options, capfd, test_file, test_seed)
|
||||
|
||||
assert result
|
||||
19
tests/test_mixer_routing_input_ctrl/Makefile
Normal file
19
tests/test_mixer_routing_input_ctrl/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
|
||||
else
|
||||
TEST_DEBUG_FLAGS =
|
||||
endif
|
||||
|
||||
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS) -DXUD_WEAK_API=1
|
||||
|
||||
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
|
||||
200
tests/test_mixer_routing_input_ctrl/src/main.xc
Normal file
200
tests/test_mixer_routing_input_ctrl/src/main.xc
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/* This tests checks the parsing of control requests to endpoint 0 cause the correct changes in mixer output routing */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "platform.h"
|
||||
#include "xua.h"
|
||||
#include "debug_print.h"
|
||||
#include "assert.h"
|
||||
#include "xud.h"
|
||||
#include "usbaudio20.h"
|
||||
#include "random.h"
|
||||
|
||||
#ifndef TEST_ITERATIONS
|
||||
#define TEST_ITERATIONS (100)
|
||||
#endif
|
||||
|
||||
#include "./../test_mixer_routing_output/src/mixer_test_shared.h"
|
||||
|
||||
/* Mixer input mapping - from xua_endpoint0.c */
|
||||
extern unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
|
||||
/* From xua_ep0_uacreqs.xc */
|
||||
int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
|
||||
|
||||
/* From xua_endpoint0.c */
|
||||
void InitLocalMixerState();
|
||||
|
||||
int g_src = 0;
|
||||
|
||||
/* Override func in lib_xud/src/user/client/XUD_EpFunctions.c for testing purposes */
|
||||
XUD_Result_t XUD_GetBuffer(XUD_ep ep_out, unsigned char buffer[], REFERENCE_PARAM(unsigned, length))
|
||||
{
|
||||
buffer[0] = g_src;
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in)
|
||||
{
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax)
|
||||
{
|
||||
assert(g_src == buffer[0]);
|
||||
assert(datalength == 1);
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
extern int volatile * const unsafe samples_to_device_map;
|
||||
extern int volatile * const unsafe samples_to_host_map;
|
||||
}
|
||||
|
||||
void Fake_Endpoint0(chanend c_mix_ctl)
|
||||
{
|
||||
XUD_ep ep0_out; /* Never initialised but not used */
|
||||
XUD_ep ep0_in; /* Never initialised but not used */
|
||||
USB_SetupPacket_t sp;
|
||||
|
||||
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
|
||||
|
||||
InitLocalMixerState();
|
||||
|
||||
sp.bmRequestType.Type = USB_BM_REQTYPE_TYPE_CLASS; // Note, parsing of this won't be tested since we call AudioClassRequests directly
|
||||
sp.bmRequestType.Recipient = USB_BM_REQTYPE_RECIP_INTER; // Note, parsing of this won't be tested since we call AudioClassRequests directly
|
||||
|
||||
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
|
||||
{
|
||||
int unitId = ID_XU_MIXSEL;
|
||||
unsigned mix = (random_get_random_number(rg) % (MAX_MIX_COUNT + 1)); // Mixs indexed from 1
|
||||
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("Mapping mix %d input %d", mix, input);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
|
||||
/* Create Control request data for routing change */
|
||||
int cs = mix;
|
||||
int cn = input;
|
||||
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_H2D;
|
||||
sp.bRequest = CUR;
|
||||
sp.wValue = cn | (cs << 8);
|
||||
sp.wIndex = (unitId << 8);
|
||||
sp.wLength = 1;
|
||||
|
||||
g_src = src; /* This will get picked up by out implementation of XUD_GetBuffer */
|
||||
|
||||
/* Call the function used by Endpoint0 to parse the control data and update the mixer output routing */
|
||||
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
|
||||
|
||||
/* Note, there is a race risk here. This could be resolved by adding a handshake to UpdateMixerOutputRouting() etc */
|
||||
|
||||
/* Now check the mixer setting have been modified as expected. To do this we inspect "internal"
|
||||
* mixer and endpoint 0 state.
|
||||
*
|
||||
* Going forward we might wish to enhance the mixer API such that it can be tested as a black box.
|
||||
* This would require the addition of "GET" API over it's ctrl channel
|
||||
*/
|
||||
|
||||
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_D2H;
|
||||
|
||||
if(mix == 0)
|
||||
{
|
||||
/* If mix is 0 then we need to check that all mixers have been updated */
|
||||
for(int i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
assert(g_src == mixSel[i][cn]);
|
||||
|
||||
/* Need to read back from each mixer individually */
|
||||
sp.wValue = cn | ((i + 1)<< 8);
|
||||
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(g_src == mixSel[cs-1][cn]);
|
||||
|
||||
/* Test read back. Note, the checking is in our overridden implementation of XUD_SetBuffer_EpMax*/
|
||||
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
printstrln("PASS");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void Fake_XUA_AudioHub_CtrlTest(chanend c_mix_aud)
|
||||
{
|
||||
int readBuffNo = 0;
|
||||
unsigned underflowWord = 0;
|
||||
|
||||
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
|
||||
while(1)
|
||||
{
|
||||
unsigned command = DoSampleTransfer(c_mix_aud, readBuffNo, underflowWord);
|
||||
}
|
||||
}
|
||||
|
||||
void Fake_XUA_Buffer_Decouple_CtrlTest(chanend c_dec_mix)
|
||||
{
|
||||
unsigned samplesIn[NUM_USB_CHAN_IN];
|
||||
unsigned underflowSample;
|
||||
|
||||
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
|
||||
while(1)
|
||||
{
|
||||
select
|
||||
{
|
||||
case inuint_byref(c_dec_mix, underflowSample):
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
outuint(c_dec_mix, 0);
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
samplesIn[i] = inuint(c_dec_mix);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chan c_dec_mix;
|
||||
chan c_mix_aud;
|
||||
chan c_mix_ctl;
|
||||
|
||||
par
|
||||
{
|
||||
/* We need "fake" versions of the AudioHub and Decouple to keep the mixer running and taking updates via
|
||||
* it's control channel */
|
||||
Fake_XUA_Buffer_Decouple_CtrlTest(c_dec_mix);
|
||||
Fake_XUA_AudioHub_CtrlTest(c_mix_aud);
|
||||
|
||||
/* Mixer from lib_xua */
|
||||
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
|
||||
|
||||
Fake_Endpoint0(c_mix_ctl);
|
||||
}
|
||||
|
||||
/* TODO to hit this we need to fully close down i.e. kill mixer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
tests/test_mixer_routing_input_ctrl/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_input_ctrl/src/test_xs3_600.xn
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Network xmlns="http://www.xmos.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
|
||||
<Declarations>
|
||||
<Declaration>tileref tile[2]</Declaration>
|
||||
</Declarations>
|
||||
|
||||
<Packages>
|
||||
<Package id="0" Type="XS3-UnA-1024-FB265">
|
||||
<Nodes>
|
||||
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
|
||||
<Tile Number="0" Reference="tile[0]"/>
|
||||
<Tile Number="1" Reference="tile[1]"/>
|
||||
</Node>
|
||||
</Nodes>
|
||||
</Package>
|
||||
</Packages>
|
||||
|
||||
<JTAGChain>
|
||||
<JTAGDevice NodeId="0"/>
|
||||
</JTAGChain>
|
||||
|
||||
</Network>
|
||||
45
tests/test_mixer_routing_input_ctrl/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_input_ctrl/src/xua_conf.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_CONF_H_
|
||||
#define _XUA_CONF_H_
|
||||
|
||||
#define NUM_USB_CHAN_OUT (10)
|
||||
#define NUM_USB_CHAN_IN (10)
|
||||
#define I2S_CHANS_DAC (10)
|
||||
#define I2S_CHANS_ADC (10)
|
||||
|
||||
#define EXCLUDE_USB_AUDIO_MAIN
|
||||
|
||||
#define MIXER (1)
|
||||
#define MAX_MIX_COUNT (8)
|
||||
|
||||
#define UAC_FORCE_FEEDBACK_EP (0)
|
||||
#define XUA_NUM_PDM_MICS 0
|
||||
#define XUD_TILE 1
|
||||
#define AUDIO_IO_TILE 0
|
||||
|
||||
#ifndef MCLK_441
|
||||
#define MCLK_441 (512 * 44100)
|
||||
#endif
|
||||
|
||||
#ifndef MCLK_48
|
||||
#define MCLK_48 (512 * 48000)
|
||||
#endif
|
||||
|
||||
#define MIN_FREQ (44100)
|
||||
#define MAX_FREQ (192000)
|
||||
#define SPDIF_TX_INDEX 0
|
||||
#define VENDOR_STR "XMOS"
|
||||
#define VENDOR_ID 0x20B1
|
||||
#define PRODUCT_STR_A2 "Test device"
|
||||
#define PRODUCT_STR_A1 "Test device"
|
||||
#define PID_AUDIO_1 1
|
||||
#define PID_AUDIO_2 2
|
||||
#define AUDIO_CLASS 2
|
||||
#define AUDIO_CLASS_FALLBACK 0
|
||||
#define BCD_DEVICE 0x1234
|
||||
#define XUA_DFU_EN 0
|
||||
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
|
||||
#define XUA_MIC_FRAME_SIZE 240
|
||||
|
||||
#endif
|
||||
45
tests/test_mixer_routing_output.py
Normal file
45
tests/test_mixer_routing_output.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright 2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import Pyxsim
|
||||
from Pyxsim import testers
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def do_test(options, capfd, test_file, test_seed):
|
||||
|
||||
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||
|
||||
binary = f"{testname}/bin/{testname}.xe"
|
||||
|
||||
tester = testers.ComparisonTester(open("pass.expect"))
|
||||
|
||||
max_cycles = 15000000
|
||||
|
||||
simargs = [
|
||||
"--max-cycles",
|
||||
str(max_cycles),
|
||||
]
|
||||
|
||||
build_options = []
|
||||
build_options += ["TEST_SEED=" + str(test_seed)]
|
||||
|
||||
result = Pyxsim.run_on_simulator(
|
||||
binary,
|
||||
tester=tester,
|
||||
build_options=build_options,
|
||||
simargs=simargs,
|
||||
capfd=capfd,
|
||||
instTracing=options.enabletracing,
|
||||
vcdTracing=options.enablevcdtracing,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def test_mixer_routing_output(options, capfd, test_file, test_seed):
|
||||
|
||||
result = do_test(options, capfd, test_file, test_seed)
|
||||
|
||||
assert result
|
||||
19
tests/test_mixer_routing_output/Makefile
Normal file
19
tests/test_mixer_routing_output/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
|
||||
else
|
||||
TEST_DEBUG_FLAGS =
|
||||
endif
|
||||
|
||||
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS)
|
||||
|
||||
XCC_FLAGS = -O3 $(TEST_FLAGS)
|
||||
|
||||
TARGET = test_xs3_600.xn
|
||||
|
||||
USED_MODULES = lib_xua lib_logging lib_random
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
224
tests/test_mixer_routing_output/src/main.xc
Normal file
224
tests/test_mixer_routing_output/src/main.xc
Normal 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[CHANNEL_MAP_USB_SIZE];
|
||||
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; // TODO this should be CHANNEL_MAP_USB_SIZE for SET_SAMPLES_TO_HOST_MAP
|
||||
unsigned src = random_get_random_number(rg) % (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
325
tests/test_mixer_routing_output/src/mixer_test_shared.h
Normal file
325
tests/test_mixer_routing_output/src/mixer_test_shared.h
Normal file
@@ -0,0 +1,325 @@
|
||||
// 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
|
||||
|
||||
#define CHANNEL_MAP_USB_SIZE NUM_USB_CHAN_IN
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
24
tests/test_mixer_routing_output/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_output/src/test_xs3_600.xn
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Network xmlns="http://www.xmos.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
|
||||
<Declarations>
|
||||
<Declaration>tileref tile[2]</Declaration>
|
||||
</Declarations>
|
||||
|
||||
<Packages>
|
||||
<Package id="0" Type="XS3-UnA-1024-FB265">
|
||||
<Nodes>
|
||||
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
|
||||
<Tile Number="0" Reference="tile[0]"/>
|
||||
<Tile Number="1" Reference="tile[1]"/>
|
||||
</Node>
|
||||
</Nodes>
|
||||
</Package>
|
||||
</Packages>
|
||||
|
||||
<JTAGChain>
|
||||
<JTAGDevice NodeId="0"/>
|
||||
</JTAGChain>
|
||||
|
||||
</Network>
|
||||
45
tests/test_mixer_routing_output/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_output/src/xua_conf.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_CONF_H_
|
||||
#define _XUA_CONF_H_
|
||||
|
||||
#define NUM_USB_CHAN_OUT (10)
|
||||
#define NUM_USB_CHAN_IN (10)
|
||||
#define I2S_CHANS_DAC (10)
|
||||
#define I2S_CHANS_ADC (10)
|
||||
|
||||
#define EXCLUDE_USB_AUDIO_MAIN
|
||||
|
||||
#define MIXER (1)
|
||||
#define MAX_MIX_COUNT (8)
|
||||
|
||||
#define UAC_FORCE_FEEDBACK_EP (0)
|
||||
#define XUA_NUM_PDM_MICS 0
|
||||
#define XUD_TILE 1
|
||||
#define AUDIO_IO_TILE 0
|
||||
|
||||
#ifndef MCLK_441
|
||||
#define MCLK_441 (512 * 44100)
|
||||
#endif
|
||||
|
||||
#ifndef MCLK_48
|
||||
#define MCLK_48 (512 * 48000)
|
||||
#endif
|
||||
|
||||
#define MIN_FREQ (44100)
|
||||
#define MAX_FREQ (192000)
|
||||
#define SPDIF_TX_INDEX 0
|
||||
#define VENDOR_STR "XMOS"
|
||||
#define VENDOR_ID 0x20B1
|
||||
#define PRODUCT_STR_A2 "Test device"
|
||||
#define PRODUCT_STR_A1 "Test device"
|
||||
#define PID_AUDIO_1 1
|
||||
#define PID_AUDIO_2 2
|
||||
#define AUDIO_CLASS 2
|
||||
#define AUDIO_CLASS_FALLBACK 0
|
||||
#define BCD_DEVICE 0x1234
|
||||
#define XUA_DFU_EN 0
|
||||
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
|
||||
#define XUA_MIC_FRAME_SIZE 240
|
||||
|
||||
#endif
|
||||
45
tests/test_mixer_routing_output_ctrl.py
Normal file
45
tests/test_mixer_routing_output_ctrl.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright 2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import Pyxsim
|
||||
from Pyxsim import testers
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def do_test(options, capfd, test_file, test_seed):
|
||||
|
||||
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||
|
||||
binary = f"{testname}/bin/{testname}.xe"
|
||||
|
||||
tester = testers.ComparisonTester(open("pass.expect"))
|
||||
|
||||
max_cycles = 15000000
|
||||
|
||||
simargs = [
|
||||
"--max-cycles",
|
||||
str(max_cycles),
|
||||
]
|
||||
|
||||
build_options = []
|
||||
build_options += ["TEST_SEED=" + str(test_seed)]
|
||||
|
||||
result = Pyxsim.run_on_simulator(
|
||||
binary,
|
||||
tester=tester,
|
||||
build_options=build_options,
|
||||
simargs=simargs,
|
||||
capfd=capfd,
|
||||
instTracing=options.enabletracing,
|
||||
vcdTracing=options.enablevcdtracing,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def test_mixer_routing_output(options, capfd, test_file, test_seed):
|
||||
|
||||
result = do_test(options, capfd, test_file, test_seed)
|
||||
|
||||
assert result
|
||||
19
tests/test_mixer_routing_output_ctrl/Makefile
Normal file
19
tests/test_mixer_routing_output_ctrl/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
|
||||
else
|
||||
TEST_DEBUG_FLAGS =
|
||||
endif
|
||||
|
||||
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS) -DXUD_WEAK_API=1
|
||||
|
||||
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
|
||||
221
tests/test_mixer_routing_output_ctrl/src/main.xc
Normal file
221
tests/test_mixer_routing_output_ctrl/src/main.xc
Normal file
@@ -0,0 +1,221 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/* This tests checks the parsing of control requests to endpoint 0 cause the correct changes in mixer output routing */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "platform.h"
|
||||
#include "xua.h"
|
||||
#include "debug_print.h"
|
||||
#include "assert.h"
|
||||
#include "xud.h"
|
||||
#include "usbaudio20.h"
|
||||
#include "random.h"
|
||||
|
||||
#ifndef TEST_ITERATIONS
|
||||
#define TEST_ITERATIONS (100)
|
||||
#endif
|
||||
|
||||
#include "./../test_mixer_routing_output/src/mixer_test_shared.h"
|
||||
|
||||
/* Device channel mapping */
|
||||
extern unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
||||
extern unsigned char channelMapUsb[NUM_USB_CHAN_IN];
|
||||
|
||||
/* From xua_ep0_uacreqs.xc */
|
||||
int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
|
||||
|
||||
/* From xua_endpoint0.c */
|
||||
void InitLocalMixerState();
|
||||
|
||||
int g_src = 0;
|
||||
|
||||
/* Override func in lib_xud/src/user/client/XUD_EpFunctions.c for testing purposes */
|
||||
XUD_Result_t XUD_GetBuffer(XUD_ep ep_out, unsigned char buffer[], REFERENCE_PARAM(unsigned, length))
|
||||
{
|
||||
buffer[0] = g_src;
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in)
|
||||
{
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax)
|
||||
{
|
||||
assert(g_src == buffer[0]);
|
||||
assert(datalength == 1);
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
extern int volatile * const unsafe samples_to_device_map;
|
||||
extern int volatile * const unsafe samples_to_host_map;
|
||||
}
|
||||
|
||||
void Fake_Endpoint0(chanend c_mix_ctl)
|
||||
{
|
||||
XUD_ep ep0_out; /* Never initialised but not used */
|
||||
XUD_ep ep0_in; /* Never initialised but not used */
|
||||
unsigned unitIds[] = {ID_XU_OUT, ID_XU_IN};
|
||||
USB_SetupPacket_t sp;
|
||||
|
||||
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
|
||||
|
||||
InitLocalMixerState();
|
||||
|
||||
sp.bmRequestType.Type = USB_BM_REQTYPE_TYPE_CLASS; // Note, parsing of this won't be tested since we call AudioClassRequests directly
|
||||
sp.bmRequestType.Recipient = USB_BM_REQTYPE_RECIP_INTER; // Note, parsing of this won't be tested since we call AudioClassRequests directly
|
||||
|
||||
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
|
||||
{
|
||||
int unitId = unitIds[random_get_random_number(rg) % (sizeof(unitIds)/sizeof(unitIds[0]))];
|
||||
unsigned dst = random_get_random_number(rg);
|
||||
|
||||
/* Note, we don't currently support a mix input derived from another mix
|
||||
* This is not trivial to test since the current mixer implementation only allows for one
|
||||
* config update per "trigger"
|
||||
*/
|
||||
int src = random_get_random_number(rg) % NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT;
|
||||
|
||||
switch(unitId)
|
||||
{
|
||||
case ID_XU_OUT:
|
||||
dst %= CHANNEL_MAP_AUD_SIZE;
|
||||
debug_printf("Mapping output to AudioIF: %d", dst);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
break;
|
||||
|
||||
case ID_XU_IN:
|
||||
dst %= CHANNEL_MAP_USB_SIZE;
|
||||
debug_printf("Mapping output to Host : %d", dst);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printstr("ERROR: Bad cmd in stim(): ");
|
||||
printintln(unitId);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Create Control request data for routing change */
|
||||
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_H2D;
|
||||
sp.bRequest = CUR;
|
||||
sp.wValue = dst & 0xff;
|
||||
sp.wIndex = (unitId << 8);
|
||||
sp.wLength = 1;
|
||||
|
||||
g_src = src; /* This will get picked up by out implementation of XUD_GetBuffer */
|
||||
|
||||
/* Call the function used by Endpoint0() to parse the control data and update the mixer output routing */
|
||||
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
|
||||
|
||||
/* Note, there is a race risk here. This could be resolved by adding a handshake to UpdateMixerOutputRouting() etc */
|
||||
|
||||
/* Now check the mixer setting have been modified as expected. To do this we inspect "internal"
|
||||
* mixer and endpoint 0 state.
|
||||
*
|
||||
* Going forward we might wish to enhance the mixer API such that it can be tested as a black box.
|
||||
* This would require the addition of "GET" API over it's ctrl channel
|
||||
*/
|
||||
switch(unitId)
|
||||
{
|
||||
case ID_XU_OUT:
|
||||
assert(g_src == channelMapAud[dst]);
|
||||
unsafe
|
||||
{
|
||||
assert(g_src == samples_to_device_map[dst]);
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_XU_IN:
|
||||
assert(g_src == channelMapUsb[dst]);
|
||||
unsafe
|
||||
{
|
||||
assert(g_src == samples_to_host_map[dst]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Test read back. Note, the checking is our overridden implementation of XUD_SetBuffer_EpMax*/
|
||||
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_D2H;
|
||||
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
|
||||
}
|
||||
|
||||
printstrln("PASS");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void Fake_XUA_AudioHub_CtrlTest(chanend c_mix_aud)
|
||||
{
|
||||
int readBuffNo = 0;
|
||||
unsigned underflowWord = 0;
|
||||
|
||||
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
|
||||
while(1)
|
||||
{
|
||||
unsigned command = DoSampleTransfer(c_mix_aud, readBuffNo, underflowWord);
|
||||
}
|
||||
}
|
||||
|
||||
void Fake_XUA_Buffer_Decouple_CtrlTest(chanend c_dec_mix)
|
||||
{
|
||||
unsigned samplesIn[NUM_USB_CHAN_IN];
|
||||
unsigned underflowSample;
|
||||
|
||||
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
|
||||
while(1)
|
||||
{
|
||||
select
|
||||
{
|
||||
case inuint_byref(c_dec_mix, underflowSample):
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
outuint(c_dec_mix, 0);
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
samplesIn[i] = inuint(c_dec_mix);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chan c_dec_mix;
|
||||
chan c_mix_aud;
|
||||
chan c_mix_ctl;
|
||||
|
||||
par
|
||||
{
|
||||
/* We need "fake" versions of the AudioHub and Decouple to keep the mixer running and taking updates via
|
||||
* it's control channel */
|
||||
Fake_XUA_Buffer_Decouple_CtrlTest(c_dec_mix);
|
||||
Fake_XUA_AudioHub_CtrlTest(c_mix_aud);
|
||||
|
||||
/* Mixer from lib_xua */
|
||||
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
|
||||
|
||||
Fake_Endpoint0(c_mix_ctl);
|
||||
}
|
||||
|
||||
/* TODO to hit this we need to fully close down i.e. kill mixer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
tests/test_mixer_routing_output_ctrl/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_output_ctrl/src/test_xs3_600.xn
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Network xmlns="http://www.xmos.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
|
||||
<Declarations>
|
||||
<Declaration>tileref tile[2]</Declaration>
|
||||
</Declarations>
|
||||
|
||||
<Packages>
|
||||
<Package id="0" Type="XS3-UnA-1024-FB265">
|
||||
<Nodes>
|
||||
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
|
||||
<Tile Number="0" Reference="tile[0]"/>
|
||||
<Tile Number="1" Reference="tile[1]"/>
|
||||
</Node>
|
||||
</Nodes>
|
||||
</Package>
|
||||
</Packages>
|
||||
|
||||
<JTAGChain>
|
||||
<JTAGDevice NodeId="0"/>
|
||||
</JTAGChain>
|
||||
|
||||
</Network>
|
||||
45
tests/test_mixer_routing_output_ctrl/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_output_ctrl/src/xua_conf.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_CONF_H_
|
||||
#define _XUA_CONF_H_
|
||||
|
||||
#define NUM_USB_CHAN_OUT (10)
|
||||
#define NUM_USB_CHAN_IN (10)
|
||||
#define I2S_CHANS_DAC (10)
|
||||
#define I2S_CHANS_ADC (10)
|
||||
|
||||
#define EXCLUDE_USB_AUDIO_MAIN
|
||||
|
||||
#define MIXER (1)
|
||||
#define MAX_MIX_COUNT (8)
|
||||
|
||||
#define UAC_FORCE_FEEDBACK_EP (0)
|
||||
#define XUA_NUM_PDM_MICS 0
|
||||
#define XUD_TILE 1
|
||||
#define AUDIO_IO_TILE 0
|
||||
|
||||
#ifndef MCLK_441
|
||||
#define MCLK_441 (512 * 44100)
|
||||
#endif
|
||||
|
||||
#ifndef MCLK_48
|
||||
#define MCLK_48 (512 * 48000)
|
||||
#endif
|
||||
|
||||
#define MIN_FREQ (44100)
|
||||
#define MAX_FREQ (192000)
|
||||
#define SPDIF_TX_INDEX 0
|
||||
#define VENDOR_STR "XMOS"
|
||||
#define VENDOR_ID 0x20B1
|
||||
#define PRODUCT_STR_A2 "Test device"
|
||||
#define PRODUCT_STR_A1 "Test device"
|
||||
#define PID_AUDIO_1 1
|
||||
#define PID_AUDIO_2 2
|
||||
#define AUDIO_CLASS 2
|
||||
#define AUDIO_CLASS_FALLBACK 0
|
||||
#define BCD_DEVICE 0x1234
|
||||
#define XUA_DFU_EN 0
|
||||
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
|
||||
#define XUA_MIC_FRAME_SIZE 240
|
||||
|
||||
#endif
|
||||
@@ -3,10 +3,12 @@ TEST_FLAGS ?=
|
||||
|
||||
XCC_FLAGS_HS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \
|
||||
-DBUS_SPEED=2 \
|
||||
-DXUA_USE_APP_PLL=0 \
|
||||
$(TEST_FLAGS)
|
||||
|
||||
XCC_FLAGS_FS = -O3 -g -DXUD_CORE_CLOCK=600 -save-temps -DUSB_TILE=tile[0] -DLOCAL_CLOCK_INCREMENT=10000 -DLOCAL_CLOCK_MARGIN=100 \
|
||||
-DBUS_SPEED=1 \
|
||||
-DXUA_USE_APP_PLL=0 \
|
||||
$(TEST_FLAGS)
|
||||
|
||||
TARGET = test_xs3_600.xn
|
||||
|
||||
Reference in New Issue
Block a user