150 Commits

Author SHA1 Message Date
3d9006f5e7 将 Analogue 1~8 改为 Playback 1~8 2024-02-01 09:50:06 +08:00
Virgil_lai
460b5d11e0 修改字符串描述 2024-01-30 13:35:48 +08:00
Virgil_lai
b29e6ffa91 增加MAC电脑连接的指示 2023-12-28 22:13:33 +08:00
Virgil_lai
a336bec81b 改成得胜使用的hid描述 2023-12-12 09:14:49 +08:00
Virgil_lai
791c142c94 add pawpaw user_hid_ctrl api 2023-12-11 15:03:16 +08:00
Virgil_lai
487ab06213 add pawpaw hid code 2023-12-08 00:34:32 +08:00
Virgil_lai
def348a763 add EXTRA_I2S_ADC option 2023-12-06 11:10:45 +08:00
Virgil_lai
c9f7738efd add USER_UNSAFE_USE 2023-12-05 20:07:09 +08:00
Ross Owen
a485ffe41a 'Release: 3.5.1' 2023-06-21 12:21:02 +01:00
Ross Owen
f25a9eeade Merge branch 'develop' 2023-06-21 12:15:33 +01:00
Ross Owen
dff72573f8 Scripted changelog update 2023-06-21 12:14:34 +01:00
Ross Owen
f7331a1ed3 Merge branch 'develop' 2023-06-21 12:14:02 +01:00
Ross Owen
aaaf1e9652 Version bump 3.5.0 -> 3.5.1 2023-06-21 12:11:56 +01:00
Ross Owen
d6b23cf960 Merge pull request #337 from xross/develop
Respect I2S_CHANS_PER_FRAME when calculating bit-clock rates
2023-06-21 10:06:57 +01:00
Ross Owen
fa8329edaa Changelog update 2023-06-20 20:04:17 +01:00
Ross Owen
83d86e885f Respect I2S_CHANS_PER_FRAME when calculating bit-clock rates 2023-06-20 19:36:26 +01:00
Ross Owen
15036f2bcc 'Release: 3.5.0' 2023-06-15 12:45:03 +01:00
Ross Owen
fa5723947f xpd: Cleaned up whitespace 2023-06-15 12:44:02 +01:00
Ross Owen
b1b28f1005 Merge pull request #335 from xross/fix/258
bNumConfigurations changes from 2 to 1
2023-06-14 19:09:28 +01:00
Ross Owen
6d41cfcbea Merge pull request #336 from xross/fix/155
Removed application space HID related function prototype
2023-06-14 16:06:58 +01:00
Ross Owen
5404127dbf Removed application space HID related function prototype 2023-06-14 15:30:37 +01:00
Ross Owen
e5a270347a bNumConfigurations changes from 2 to 1 2023-06-14 14:36:39 +01:00
Ross Owen
f509a12e7d Merge pull request #334 from xross/release_prep
Release prep
2023-06-14 14:23:39 +01:00
Ross Owen
4528bed740 Readme, changelog and version update 2023-06-14 12:58:51 +01:00
Ross Owen
e812ca3e8b Merge remote-tracking branch 'upstream/develop' into release_prep 2023-06-14 12:39:17 +01:00
Ross Owen
2accc0429f Merge pull request #333 from danielpieczko/develop
Update copyright years
2023-06-14 10:30:29 +01:00
Daniel Pieczko
36d5201365 Update copyright years 2023-06-14 08:09:33 +01:00
Ross Owen
cea580ba48 Merge pull request #332 from henkmuller/feature/static-hid-descriptor
Enabling a static HID report descriptor
2023-06-13 16:46:14 +01:00
Ross Owen
6815f12a90 Update copyright comment 2023-06-12 17:16:56 +01:00
Ross Owen
799ad7ba86 Update copyright comment 2023-06-12 17:16:43 +01:00
Ross Owen
3d7e66bdc0 Update copyright comment 2023-06-12 17:16:26 +01:00
Ross Owen
a6387d5fef Update copyright comment 2023-06-12 17:16:11 +01:00
Ross Owen
5ca0738b02 Update copyright comment 2023-06-12 17:15:42 +01:00
Ross Owen
b0e732110d Update copyright comment 2023-06-12 17:15:21 +01:00
Ross Owen
1702078e7c Update copyright comment 2023-06-12 17:14:42 +01:00
Henk Muller
136ec2506c One of the intermediate XUA_HID_REQUIRED slipped through the refactoring 2023-06-12 09:20:43 +01:00
Henk Muller
45e5ef7702 Enabling a static HID report descriptor in addition to the built-in dynamically created one. This is required for AudioWeaver. This also enables the option of an OUT HID endpoint 2023-06-10 18:07:25 +01:00
Ross Owen
1ef5129fde Variable i2s bit width (#331)
- Add support for variable width I2S (via XUA_I2S_N_BITS)
- Add support for variable width TDM (again via XUD_I2S_N_BITS when XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM)
- Includes support for xcore as I2S/TDM master and slave
- Add testing of the the above to test_i2s_loopback
- Rationalised test config building in test_i2s_loopback
- Documentation updated
2023-06-08 15:31:12 +01:00
Ross Owen
b1fe49aff3 Conflicted merge 2023-06-02 14:06:13 +01:00
Brennan Magee
d3ad29e8a6 Merge pull request #330 from BrennanGit/fix/jenkins_windows_bat_sh
Use bat not sh for windows builds on Jenkins
2023-05-31 09:38:31 +01:00
Brennan Magee
17944ad908 Use bat not sh for windows builds on Jenkins
This was causing an issue where the windows workspaces could not be cleared.
2023-05-30 17:08:32 +01:00
danielpieczko
131dd252c0 Merge pull request #329 from danielpieczko/jenkins_windows_build_fix
Use withVS instead of runVS to use the latest Jenkins Windows agents
2023-05-19 09:20:11 +01:00
Daniel Pieczko
23d043630f Use withVS instead of runVS to use the latest Jenkins Windows agents 2023-05-19 09:03:33 +01:00
Ross Owen
761a33f5e4 Update CHANGELOG.rst 2023-05-18 10:07:25 +01:00
Ross Owen
12ec1d7536 module_build_info: lib_xud 2.2.2 -> 2.2.3 2023-05-18 10:05:30 +01:00
Ross Owen
2dba6dce36 Update CHANGELOG.rst 2023-05-18 10:04:36 +01:00
Ross Owen
9cf931898e Move check for XUA_USB_EN after include of xua.h (#325) 2023-05-17 14:55:37 +01:00
Ross Owen
9b104af8cf Merge branch 'develop' into develop 2023-05-17 14:00:38 +01:00
Ross Owen
c469dd6cde Changelog update 2023-05-17 13:58:56 +01:00
Ross Owen
b238196f74 Copyright comment only 2023-05-17 13:55:41 +01:00
Ross Owen
e9586b59d3 Move check for XUA_USB_EN after include of xua.h 2023-05-17 13:48:36 +01:00
Ross Owen
6d168b3209 Merge pull request #321 from TDW89/fix/SPDIF-api
SPDIF api fix
2023-05-17 11:05:57 +01:00
Ross Owen
d301fef6d7 Merge pull request #324 from xross/fix/sw_usb_audio_156
Fix for exception when entering DSD mode (also some tidies)
2023-05-15 10:24:47 +01:00
Ross Owen
1f4e9a99b8 Changelog update 2023-05-12 17:36:04 +01:00
Ross Owen
981ea78be7 Fix for exception when entering DSD mode (also some tidies) 2023-05-12 17:22:47 +01:00
Ross Owen
6cee90d876 Fix audio interrupt endpoint type
Note, this has no functional change
2023-04-17 12:23:27 +01:00
Tom Williams
79d14f8b59 changed to use spdif_rx from SpdifReceive 2023-04-05 17:34:33 +01:00
danielpieczko
05dcb8f3ab Merge pull request #323 from danielpieczko/fix/mixer_init
Fix memory corruption during initialisation of mixer weights
2023-04-04 14:54:57 +01:00
Daniel Pieczko
4e7ddb4036 Fix memory corruption during initialisation of mixer weights 2023-04-04 14:31:35 +01:00
Ross Owen
e8fcc80415 Merge pull request #322 from xross/fix/sw_usb_audio_152
Tidy up of volume control. Removal of xc_ptr.h in favour of built in xc pointers
2023-04-04 14:15:07 +01:00
Ross Owen
71a657dc9a Tidy up of volume control. Removal of xc_ptr.h in favour of built in xc pointers. 2023-04-04 12:37:59 +01:00
Tom Williams
ccfca90451 removed referance to outdated header file, changed for the api file 2023-03-22 15:56:28 +00:00
Ross Owen
cb379f5bfb 'Release: 3.4.0' 2023-03-15 13:02:04 +00:00
Ross Owen
e2c36a9a95 xpd: Cleaned up whitespace 2023-03-15 13:00:39 +00:00
Ross Owen
7e3ae59acc Changelog update and version bump 3.3.1 -> 3.4.0 2023-03-15 12:28:39 +00:00
Ross Owen
f1f453921b Merge pull request #320 from xross/fix/mixer_lock
Improve mixer control protocol to avoid deadlock
2023-03-14 12:52:44 +00:00
Ross Owen
7703fc1a7d Fixed build warning when mixer not enabled 2023-03-14 11:49:08 +00:00
Ross Owen
53a65344fc Improve mixer control protocol to avoid deadlock 2023-03-14 11:48:54 +00:00
Ross Owen
3b2814f8cb Merge pull request #319 from xross/fix/spdif_output_opts 2023-03-13 16:50:40 +00:00
Ross Owen
55a62cf589 - Fixed build issue with !FAST_MIXER
- Fixed issue with !OUT_VOLUME_AFTER_MIX not being respected
2023-03-13 15:50:45 +00:00
Ross Owen
4a84c3e1ec OUT_VOLUME_IN_MIXER enabled by default 2023-03-13 15:49:54 +00:00
Ross Owen
b17f585004 Decouple optimisation for when output slot size = 4 (note, trades off code size) 2023-03-13 14:33:22 +00:00
Ross Owen
57593bfea3 Fixed issue with STREAM_FORMAT_OUTPUT_RESOLUTION_32_BIT_USED be set incorrectly 2023-03-13 14:31:53 +00:00
Ross Owen
8dc77090bf Merge pull request #318 from xross/develop
Reinstate check for current samplerate before changing
2023-03-09 16:42:26 +00:00
Ross Owen
9c20fab216 Updated copyright comment 2023-03-09 15:32:15 +00:00
Ross Owen
cf1940245f Return value of XUD_DoSetRequestStatus in Samp freq change 2023-03-09 15:24:21 +00:00
Ross Owen
837b648bbc Reinstate check for current samplerate before changing 2023-03-09 15:22:58 +00:00
Ross Owen
c1159143ea Fastmix.S now uses defines from xua.h 2023-03-09 14:56:54 +00:00
Ross Owen
2964861b70 Fixed xua.h including in asm files 2023-03-09 14:51:32 +00:00
Ross Owen
208491fe51 Added mixer control unit tests (#316)
* Added test_mixer_routing_output_ctrl
* Added test_mixer_routing_input_ctrl 
* Some minor mixer test and code improvements
* Update lib_xud dep version requirement
2023-03-08 10:53:33 +00:00
TDW89
3fe4593b52 Mixer Host App: Multi device error handeling & device ID agnostic (#315)
Removed device product ID requirement from macOS and added error messages when multiple devices are connected
2023-03-02 16:01:17 +00:00
TDW89
49a116c705 Minor updates (#314)
* SDK location can now set in makefile
* Mixer requirements added to readme
* Uncommented previously broken mixer example from docs as this functionality is now working
* Fixed windows build & runtime info in README
2023-03-01 10:59:00 +00:00
Ross Owen
eee5b474a0 Merge pull request #312 from TDW89/unify_win_osx_code
Unify win osx code
2023-02-20 11:56:04 +00:00
Ross Owen
4655a07542 Merge pull request #313 from xross/develop 2023-02-17 14:04:14 +00:00
Ross Owen
c578bb92d5 Fix build issue with volume processing in mixer (missing xc_ptr func) 2023-02-17 12:10:51 +00:00
Tom Williams
d5a614df55 removed old usb_mixer files 2023-02-15 14:28:27 +00:00
Tom Williams
495140ab8d adding OSX\usb_mixer.cpp changes from mixer tests branch to the combined usb_mixer.cpp file 2023-02-15 13:12:28 +00:00
Tom Williams
f53c1bab09 fixed merge conflict in OSX makefile 2023-02-15 11:47:28 +00:00
Ross Owen
0c6d947e67 Merge pull request #307 from xross/feature/mixer_tests
Feature/mixer tests
2023-02-09 10:51:08 +00:00
Tom Williams
ee271e3769 fixed typos and build issues 2023-02-08 17:49:58 +00:00
Ross Owen
950beb55cb - Fixed ifndef check
- Fixed mix map update
2023-02-08 17:06:08 +00:00
Tom Williams
ca3276792a initial unified version of usb_mixer.cpp 2023-02-08 16:58:18 +00:00
Ross Owen
e26b934233 Conflicted merge from upstream/develop 2023-02-08 13:58:25 +00:00
Ross Owen
51629dba24 Merge pull request #310 from TDW89/host_usb_win
Host usb win pull_v2
2023-02-08 13:56:46 +00:00
Ross Owen
c5e944d73d Use of storeShort function in mixer weight read and comment updates 2023-02-08 13:18:28 +00:00
Ross Owen
22a3d5e043 Added array to size to extern to fix sizeof usage error 2023-02-08 12:20:42 +00:00
Ross Owen
58f691078d Added range checking when getting/setting mixer weights 2023-02-08 12:04:38 +00:00
Ross Owen
f80d7647e0 - Make usage (of lack of) of CS when setting/getting mixer weights more clear in the implementation
- Fix typo in IN_VOLUME_IN_MIXER define
2023-02-08 11:59:13 +00:00
Tom Williams
fe697929bc merge testing branch and osx updates into branch 2023-02-08 11:59:07 +00:00
Tom Williams
b265ccd8bf Merge remote-tracking branch 'xmos/develop' into develop
bringing personal fork up to date
2023-02-08 10:39:25 +00:00
Ross Owen
6c2e7e3042 Fixed issue setting mix maps (#308) 2023-02-08 10:02:32 +00:00
Ross Owen
15ca5ec281 Fixed unused var warning 2023-02-07 16:35:38 +00:00
Ross Owen
71aa64425d Added missing bounds checking when setting host and device maps in the mixer 2023-02-07 12:14:19 +00:00
Ross Owen
9080990234 Fixed typo in define check 2023-02-06 23:44:20 +00:00
Ross Owen
6d8cf9913f Increase timeout cycles for test_mixer_routing_output 2023-02-06 23:42:33 +00:00
Ross Owen
60040de58f Further build issue fixes and copyright comments 2023-02-06 21:08:47 +00:00
Ross Owen
27a59ab3bc - Fixed MIXER define usage in main
- Fixed unsafe pointer usage when MAX_MIX_COUNT=0
- Fixed syntax error building mixer when no features enabled relating to empty switch statement
2023-02-06 21:05:48 +00:00
Ross Owen
317e27e421 - Rationalised MIXER defines and usage
- Further removal of xc_ptr type usage in mixer in favour of native xc pointers
2023-02-06 20:28:29 +00:00
Ross Owen
035c20e01c Fixed build issue in mixer when FAST_MIXER not used 2023-02-06 18:14:48 +00:00
Ross Owen
ef97d667de Further moving of mixer from xc_ptr type to XC pointers 2023-02-06 18:09:33 +00:00
Ross Owen
0e07dc29bc Fix issue in mixer host app when retrieving mixer input strings. Also firmed up some usage error checking. 2023-02-03 11:09:43 +00:00
Ross Owen
43f77c177d Small updates to mixer control README 2023-02-03 11:08:23 +00:00
Ross Owen
6754f812c9 Fixed issues with setting mix map in mixer host app 2023-02-03 11:08:06 +00:00
Ross Owen
fc732b8512 Updated changelog 2023-02-03 11:06:40 +00:00
Ross Owen
39ed235476 Removed old module_description file 2023-02-03 11:06:23 +00:00
Ross Owen
0d7224bd6d Added -arch for to mixer host app makefile 2023-02-03 11:06:13 +00:00
Ross Owen
fd4dfd40a9 Tidy .gitignore 2023-02-03 11:05:21 +00:00
Ross Owen
3d50c96595 - Removed dead XTA pragmas and code from mixer
- Added some more asserts to mixer
2023-02-03 10:59:20 +00:00
Tom Williams
379e8eb54c changed jenkins file to use sh rather than runVS 2023-02-01 16:29:05 +00:00
Tom Williams
63763cf4f5 fixed progect file & typo in jenkinsfile 2023-02-01 15:50:42 +00:00
Tom Williams
b18c34fb0f OSX makefile changed to work on M1, VS project file changed to 2019 (toolset 142) and Jenkins file now builds and archives the binaries 2023-02-01 14:11:47 +00:00
Tom Williams
64d65afeaf project file fixes 2023-02-01 13:43:53 +00:00
Tom Williams
7a47d70229 Revert "added path variable to link project to sdk"
This reverts commit cffd35d146.
2023-02-01 13:40:54 +00:00
Ross Owen
ce8e5a6dbb Merge branch 'develop' into feature/mixer_tests 2023-02-01 12:01:47 +00:00
Ross Owen
bbed806aab Merge remote-tracking branch 'upstream' into develop 2023-02-01 12:01:21 +00:00
Ross Owen
9af31b8c70 Merge pull request #305 from TDW89/host_usb_mixer_control
host_usb_mixer_control_OSX_support
2023-02-01 12:00:45 +00:00
Ross Owen
73955c1a4c - Added mixer related defines to reduce use of magic numbers
- Increases debug output when DEBUG flag set
- Removed some dead code
- Increased alignment of asm mixer functions
- Removed some usages of “xc_ptr” type in favour of native pointers in XC
- Added some asserts to mixer
- Added test_mixer_routing_input
- Moved test_mixer_routing_output to use shared code
2023-02-01 11:54:48 +00:00
Tom Williams
cffd35d146 added path variable to link project to sdk 2023-01-25 16:31:05 +00:00
Tom Williams
ab535e0fb3 removed temporary debug code 2023-01-25 11:07:49 +00:00
Tom Williams
17b039dce8 licence updates 2023-01-25 10:48:44 +00:00
Tom Williams
7a0d0e1f97 Initial windows commit 2023-01-25 10:23:57 +00:00
Tom Williams
2f31260612 updated copyright headers 2023-01-18 16:51:47 +00:00
Tom Williams
9922190450 removed versioning and license files as they are now part of the top level. added the help option to the readme 2023-01-18 16:01:08 +00:00
Ross Owen
0ce91bec90 Copyright comment 2023-01-17 12:12:46 +00:00
Ross Owen
2404eaf35f Remove extern, mark static inline 2023-01-17 11:53:44 +00:00
Ross Owen
8966ad1bb9 Add external linkage to inline DoSampleTransfer 2023-01-17 11:39:22 +00:00
Ross Owen
513761ef5b Moved DoSampleTransfer to a header file so it can still be inlined (but also used in unit tests). Resolves fails in test_i2s_loopback 2023-01-17 11:33:52 +00:00
Ross Owen
da7c45500d - Added test_mixer_routing_output
- Various buffers no longer marked static to allow for easier unit testing 
- Added some comments and removed some dead code from the implementation
- Moved mixer control comms to functions for unit test convenience
2023-01-16 17:28:04 +00:00
Ross Owen
395c88cb22 - Removed unused mixer variable.
- Use of mixer defines rather than fixed values
2023-01-10 11:27:37 +00:00
Tom Williams
94e58edfaf documentation clarifications and some spelling / grammer fixes 2022-12-21 17:22:39 +00:00
Tom Williams
9f00f9159a improvements to documentation 2022-12-21 15:07:14 +00:00
Tom Williams
785a857ca8 moved mixer control to correct path 2022-12-01 09:37:20 +00:00
Tom Williams
3130088c91 Initial commit for host_usb_mixer_control 2022-11-23 17:53:47 +00:00
Ross Owen
c51ee0c460 Removed extra whitespace from example makefiles 2022-11-21 20:05:49 +00:00
danielpieczko
17ed636a74 Merge pull request #303 from danielpieczko/no_usb_chans_in
Avoid calling SetupZerosSendBuffer when there are no IN eps
2022-11-16 10:06:03 +00:00
Daniel Pieczko
0db1b08948 Add changelog entry 2022-11-11 08:56:20 +00:00
Daniel Pieczko
9c460f753f Avoid calling SetupZerosSendBuffer when there are no IN eps 2022-11-10 16:44:34 +00:00
danielpieczko
6a9537fb69 Merge pull request #302 from danielpieczko/develop
Revert TDM ADC clocking change from commit a1946f3
2022-11-07 14:29:16 +00:00
Daniel Pieczko
abfa3a2011 Revert TDM ADC clocking change from commit a1946f3 2022-11-07 08:59:56 +00:00
xross
a1946f340a Remove TDM ADC clocking on neg edge 2022-11-01 19:24:25 +00:00
87 changed files with 7013 additions and 1268 deletions

56
.gitignore vendored
View File

@@ -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/*

View File

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

@@ -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
}
}
}

View File

@@ -1,7 +1,8 @@
lib_xua
#######
:Latest release: 3.3.1
:Version: 3.5.1
:Vendor: XMOS
:Scope: General Use
@@ -40,9 +41,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 +53,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 +88,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

View File

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

View File

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

View File

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

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

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

View 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

View 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

Binary file not shown.

File diff suppressed because it is too large Load Diff

View 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],...

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

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

View File

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

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

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

View File

@@ -0,0 +1 @@
export DYLD_LIBRARY_PATH=$PWD/OSX:$DYLD_LIBRARY_PATH

File diff suppressed because it is too large Load Diff

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

View File

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

View File

@@ -1,9 +1,9 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#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"
@@ -80,4 +80,4 @@ void UserBufferManagementInit();
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
#endif // __XUA_AUDIOHUB_H__
#endif // _XUA_AUDIOHUB_H_

View File

@@ -50,6 +50,10 @@ void XUA_Buffer(
#if (HID_CONTROLS)
, chanend c_hid
#endif
#ifdef PAWPAW_INOUTHID
, chanend c_hid
, chanend c_hid_out
#endif//#ifdef PAWPAW_INOUTHID
, chanend c_aud
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || defined(__DOXYGEN__)
, client interface pll_ref_if i_pll_ref
@@ -78,6 +82,10 @@ void XUA_Buffer_Ep(chanend c_aud_out,
#if (HID_CONTROLS)
, chanend c_hid
#endif
#ifdef PAWPAW_INOUTHID
, chanend c_hid
, chanend c_hid_out
#endif //#ifdef PAWPAW_INOUTHID
#ifdef CHAN_BUFF_CTRL
, chanend c_buff_ctrl
#endif

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/*
* @brief Defines relating to device configuration and customisation of lib_xua
@@ -93,7 +93,11 @@
#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
@@ -193,6 +197,19 @@
#define I2S_DOWNSAMPLE_CHANS_IN I2S_CHANS_ADC
#endif
/**
* @brief Number of bits per channel for I2S/TDM. Supported values: 16/32-bit.
*
* Default: 32 bits
*/
#ifndef XUA_I2S_N_BITS
#define XUA_I2S_N_BITS (32)
#endif
#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
/**
* @brief Max supported sample frequency for device (Hz). Default: 192000
*/
@@ -431,6 +448,40 @@
#define HID_CONTROLS (0)
#endif
/**
* 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.
*
* 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.
*
* You must also supply your own function to deal with the HID endpoint(s)
* in this case.
*/
#if( 0 < HID_CONTROLS )
#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
/**
* @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks)
*
@@ -997,17 +1048,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 +1133,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 +1197,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 +1224,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 +1248,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 +1349,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

View File

@@ -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"

View File

@@ -1,8 +1,10 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#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

View File

@@ -50,6 +50,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
^^^^

View File

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

View File

@@ -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.

View File

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

View File

@@ -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 |
| +---------------------------------------------------------------------------------------------+

View File

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

View File

@@ -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 */

View File

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

View File

@@ -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 */

View File

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

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @file xua_audiohub.xc
@@ -15,6 +15,8 @@
#include <xclib.h>
#include <xs1_su.h>
#include <string.h>
#include <xassert.h>
#include "xua.h"
@@ -43,25 +45,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))
#define IN_CHAN_COUNT (I2S_CHANS_ADC + XUA_NUM_PDM_MICS + (8*XUA_ADAT_RX_EN) + (2*XUA_SPDIF_RX_EN) + EXTRA_I2S_ADC)
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 +65,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 +78,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 +113,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 +269,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 +305,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 +367,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 +407,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 +443,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 +483,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 +501,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 +558,6 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
}
}
}
#pragma xta endpoint "deliver_return"
return 0;
}
@@ -744,13 +715,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 +729,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 +759,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 +782,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;

View File

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

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#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)

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xua.h"
#if XUA_USB_EN
@@ -10,13 +10,20 @@
#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"
unsigned char g_hidData[HID_MAX_DATA_BYTES] = {0U};
#endif
#ifdef PAWPAW_INOUTHID
#include "user_hid_ctrl.h"
#include "stdio.h"
unsigned char g_hidData_in[PAWPAW_CFG_HID_IN_BUFSIZE] = {0};
unsigned char g_hidData_out[PAWPAW_CFG_HID_OUT_BUFSIZE] = {0};
#endif//#ifdef PAWPAW_INOUTHID
void GetADCCounts(unsigned samFreq, int &min, int &mid, int &max);
#define BUFFER_SIZE_OUT (1028 >> 2)
#define BUFFER_SIZE_IN (1028 >> 2)
@@ -103,6 +110,10 @@ void XUA_Buffer(
#if (HID_CONTROLS )
, chanend c_hid
#endif
#ifdef PAWPAW_INOUTHID
, chanend c_hid
, chanend c_hid_out
#endif//#ifdef PAWPAW_INOUTHID
, chanend c_aud
#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC)
, client interface pll_ref_if i_pll_ref
@@ -134,9 +145,14 @@ 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 PAWPAW_INOUTHID
, c_hid
, c_hid_out
#endif //#ifdef PAWPAW_INOUTHID
#ifdef CHAN_BUFF_CTRL
, c_buff_ctrl
#endif
@@ -187,6 +203,11 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#if(HID_CONTROLS)
, chanend c_hid
#endif
#ifdef PAWPAW_INOUTHID
, chanend c_hid
, chanend c_hid_out
#endif//#ifdef PAWPAW_INOUTHID
#ifdef CHAN_BUFF_CTRL
, chanend c_buff_ctrl
#endif
@@ -224,9 +245,15 @@ 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
#ifdef PAWPAW_INOUTHID
XUD_ep ep_hid = XUD_InitEp(c_hid);
XUD_ep ep_hid_out = XUD_InitEp(c_hid_out);//dwj+
#endif//#ifdef PAWPAW_INOUTHID
unsigned u_tmp;
unsigned sampleFreq = DEFAULT_FREQ;
unsigned masterClockFreq = DEFAULT_MCLK_FREQ;
@@ -332,7 +359,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
#endif
#endif
#if( 0 < HID_CONTROLS )
#if XUA_HID_ENABLED
while (!hidIsReportDescriptorPrepared())
;
@@ -365,6 +392,11 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
i_pll_ref.toggle();
#endif
#ifdef PAWPAW_INOUTHID
XUD_SetReady_In(ep_hid, g_hidData_in, 5);// 上行
XUD_SetReady_Out(ep_hid_out,g_hidData_out);// 下行
#endif //#ifdef d
while(1)
{
XUD_Result_t result;
@@ -897,8 +929,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;
@@ -910,6 +942,41 @@ void XUA_Buffer_Ep(register chanend c_aud_out,
break;
#endif
#ifdef PAWPAW_INOUTHID
case XUD_SetData_Select(c_hid, ep_hid, result):
{
// printf("HID IN\n");
if( hid_Buffer_exchange(BUF_XMOS_PC,g_hidData_in)){
}
XUD_SetReady_In(ep_hid, g_hidData_in, 5);
}
break;
#if (HID_OUT_REQUIRED)
case XUD_GetData_Select(c_hid_out, ep_hid_out,length, result):
{
XUD_SetReady_Out(ep_hid_out,g_hidData_out);
hid_Buffer_exchange(BUF_PC_XMOS,g_hidData_out);
// XMOS 获取到的HID数据
// g_hidData_out[0]...g_hidData_out[7]
// printf("g_hidData_out %d\n",length);
// for (size_t i = 0; i < 5; i++)
// {
// printf("%x ",g_hidData_out[i]);
// }
// printf("\n",length);
}
break;
#endif //#if (HID_OUT_REQUIRED)
#endif//#ifdef PAWPAW_INOUTHID
#ifdef MIDI
/* Received word from MIDI thread - Check for ACK or Data */
case midi_get_ack_or_data(c_midi, is_ack, datum):

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#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)

View File

@@ -10,7 +10,7 @@
#if (NUM_USB_CHAN_OUT > 1-1)
.outputChanStr_1 = ""
#if (1 < I2S_CHANS_DAC+1)
"Analogue 1"
"Playback 1"
#endif
#if ((1 < SPDIF_TX_INDEX+2+1) && (1 > SPDIF_TX_INDEX)) && (XUA_SPDIF_TX_EN)
#if (1 < I2S_CHANS_DAC+1)
@@ -50,7 +50,7 @@
#if (NUM_USB_CHAN_OUT > 2-1)
.outputChanStr_2 = ""
#if (2 < I2S_CHANS_DAC+1)
"Analogue 2"
"Playback 2"
#endif
#if ((2 < SPDIF_TX_INDEX+2+1) && (2 > SPDIF_TX_INDEX)) && (XUA_SPDIF_TX_EN)
#if (2 < I2S_CHANS_DAC+1)
@@ -90,7 +90,7 @@
#if (NUM_USB_CHAN_OUT > 3-1)
.outputChanStr_3 = ""
#if (3 < I2S_CHANS_DAC+1)
"Analogue 3"
"Playback 3"
#endif
#if ((3 < SPDIF_TX_INDEX+2+1) && (3 > SPDIF_TX_INDEX)) && (XUA_SPDIF_TX_EN)
#if (3 < I2S_CHANS_DAC+1)
@@ -130,7 +130,7 @@
#if (NUM_USB_CHAN_OUT > 4-1)
.outputChanStr_4 = ""
#if (4 < I2S_CHANS_DAC+1)
"Analogue 4"
"Playback 4"
#endif
#if ((4 < SPDIF_TX_INDEX+2+1) && (4 > SPDIF_TX_INDEX)) && (XUA_SPDIF_TX_EN)
#if (4 < I2S_CHANS_DAC+1)
@@ -170,7 +170,7 @@
#if (NUM_USB_CHAN_OUT > 5-1)
.outputChanStr_5 = ""
#if (5 < I2S_CHANS_DAC+1)
"Analogue 5"
"Playback 5"
#endif
#if ((5 < SPDIF_TX_INDEX+2+1) && (5 > SPDIF_TX_INDEX)) && (XUA_SPDIF_TX_EN)
#if (5 < I2S_CHANS_DAC+1)
@@ -210,7 +210,7 @@
#if (NUM_USB_CHAN_OUT > 6-1)
.outputChanStr_6 = ""
#if (6 < I2S_CHANS_DAC+1)
"Analogue 6"
"Playback 6"
#endif
#if ((6 < SPDIF_TX_INDEX+2+1) && (6 > SPDIF_TX_INDEX)) && (XUA_SPDIF_TX_EN)
#if (6 < I2S_CHANS_DAC+1)
@@ -250,7 +250,7 @@
#if (NUM_USB_CHAN_OUT > 7-1)
.outputChanStr_7 = ""
#if (7 < I2S_CHANS_DAC+1)
"Analogue 7"
"Playback 7"
#endif
#if ((7 < SPDIF_TX_INDEX+2+1) && (7 > SPDIF_TX_INDEX)) && (XUA_SPDIF_TX_EN)
#if (7 < I2S_CHANS_DAC+1)
@@ -290,7 +290,7 @@
#if (NUM_USB_CHAN_OUT > 8-1)
.outputChanStr_8 = ""
#if (8 < I2S_CHANS_DAC+1)
"Analogue 8"
"Playback 8"
#endif
#if ((8 < SPDIF_TX_INDEX+2+1) && (8 > SPDIF_TX_INDEX)) && (XUA_SPDIF_TX_EN)
#if (8 < I2S_CHANS_DAC+1)
@@ -330,7 +330,7 @@
#if (NUM_USB_CHAN_OUT > 9-1)
.outputChanStr_9 = ""
#if (9 < I2S_CHANS_DAC+1)
"Analogue 9"
" "
#endif
#if ((9 < SPDIF_TX_INDEX+2+1) && (9 > SPDIF_TX_INDEX)) && (XUA_SPDIF_TX_EN)
#if (9 < I2S_CHANS_DAC+1)
@@ -370,7 +370,7 @@
#if (NUM_USB_CHAN_OUT > 10-1)
.outputChanStr_10 = ""
#if (10 < I2S_CHANS_DAC+1)
"Analogue 10"
" "
#endif
#if ((10 < SPDIF_TX_INDEX+2+1) && (10 > SPDIF_TX_INDEX)) && (XUA_SPDIF_TX_EN)
#if (10 < I2S_CHANS_DAC+1)
@@ -1291,9 +1291,9 @@
#if (NUM_USB_CHAN_IN > 1-1)
.inputChanStr_1 = ""
.inputChanStr_1 = "Mic1"
#if (1 < I2S_CHANS_ADC+1)
"Analogue 1"
"Mix 1"
#endif
#if ((1 < SPDIF_RX_INDEX+2+1) && (1 > SPDIF_RX_INDEX)) && (XUA_SPDIF_RX_EN)
#if (1 < I2S_CHANS_ADC+1)
@@ -1331,7 +1331,7 @@
#endif
#if (NUM_USB_CHAN_IN > 2-1)
.inputChanStr_2 = ""
.inputChanStr_2 = "Mic2"
#if (2 < I2S_CHANS_ADC+1)
"Analogue 2"
#endif
@@ -1371,9 +1371,9 @@
#endif
#if (NUM_USB_CHAN_IN > 3-1)
.inputChanStr_3 = ""
.inputChanStr_3 = "OTG In 3"
#if (3 < I2S_CHANS_ADC+1)
"Analogue 3"
"OTG In 3"
#endif
#if ((3 < SPDIF_RX_INDEX+2+1) && (3 > SPDIF_RX_INDEX)) && (XUA_SPDIF_RX_EN)
#if (3 < I2S_CHANS_ADC+1)
@@ -1411,9 +1411,9 @@
#endif
#if (NUM_USB_CHAN_IN > 4-1)
.inputChanStr_4 = ""
.inputChanStr_4 = "OTG In 4"
#if (4 < I2S_CHANS_ADC+1)
"Analogue 4"
"OTG In 4"
#endif
#if ((4 < SPDIF_RX_INDEX+2+1) && (4 > SPDIF_RX_INDEX)) && (XUA_SPDIF_RX_EN)
#if (4 < I2S_CHANS_ADC+1)
@@ -1451,9 +1451,9 @@
#endif
#if (NUM_USB_CHAN_IN > 5-1)
.inputChanStr_5 = ""
.inputChanStr_5 = "Line In 5"
#if (5 < I2S_CHANS_ADC+1)
"Analogue 5"
"Line In 5"
#endif
#if ((5 < SPDIF_RX_INDEX+2+1) && (5 > SPDIF_RX_INDEX)) && (XUA_SPDIF_RX_EN)
#if (5 < I2S_CHANS_ADC+1)
@@ -1491,9 +1491,9 @@
#endif
#if (NUM_USB_CHAN_IN > 6-1)
.inputChanStr_6 = ""
.inputChanStr_6 = "Line In 6"
#if (6 < I2S_CHANS_ADC+1)
"Analogue 6"
"Line In 6"
#endif
#if ((6 < SPDIF_RX_INDEX+2+1) && (6 > SPDIF_RX_INDEX)) && (XUA_SPDIF_RX_EN)
#if (6 < I2S_CHANS_ADC+1)

View File

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

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @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,35 @@ 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
#ifdef PAWPAW_INOUTHID
#define hidReportDescriptorLength (sizeof(hidReportDescriptorPtr))
static unsigned char hidReportDescriptorPtr[] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop) //dwj cp 长沙西鲸
0x09, 0x00, // USAGE (0)
0xa1, 0x01, // COLLECTION (Application)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xff, // LOGICAL_MAXIMUM (255)
0x19, 0x01, // USAGE_MINIMUM (1)
0x29, 0x05, // USAGE_MAXIMUM (8) -dwj
0x95, 0x05, // REPORT_COUNT (8) -dwj
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x19, 0x01, // USAGE_MINIMUM (1)
0x29, 0x05, // USAGE_MAXIMUM (8) -dwj
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0xc0 // END_COLLECTION
};
#endif //#ifdef PAWPAW_INOUTHID
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 +479,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 +536,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 +559,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 +763,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 +778,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,12 +892,22 @@ 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);
}
#endif
#ifdef PAWPAW_INOUTHID
if (interfaceNum == INTERFACE_NUMBER_HID)
{
debug_printf("INTERFACE_NUMBER_HID");
extern XUD_Result_t HidInterfaceClassRequests_PAWPAW(XUD_ep c_ep0_out, XUD_ep c_ep0_in, USB_SetupPacket_t sp);
HidInterfaceClassRequests_PAWPAW(ep0_out, ep0_in, sp);
}
#endif//#ifdef PAWPAW_INOUTHID
/* Check for: - Audio CONTROL interface request - always 0, note we check for DFU first
* - Audio STREAMING interface request (In or Out)
* - Audio endpoint request (Audio 1.0 Sampling freq requests are sent to the endpoint)

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @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

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @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)
{
@@ -128,18 +117,11 @@ static unsigned longMul(unsigned a, unsigned b, int prec)
ret = (x << (32-prec) | (y >> prec));
return ret;
}
extern void sound_effect_set_pc_connect_status( int status);
/* 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));
unsafe
{
unsigned int * unsafe multOutPtr = multOut;
multOutPtr[i-1] = x;
}
#endif
}
}
@@ -177,18 +165,26 @@ 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];
#ifdef IN_VOLUME_IN_MIXER
int x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[i];
//mac
sound_effect_set_pc_connect_status(1);
#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 +198,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,38 +216,51 @@ 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;
}
case FU_USBIN:
{
//windows
/* 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 +269,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 +317,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 +352,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 +405,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 +571,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 +580,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 +666,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 +748,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 +768,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 +799,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 +807,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 +942,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 +979,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 +989,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 +998,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 +1024,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 +1041,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 +1065,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 +1134,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 +1152,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 +1214,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 +1233,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);
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2012-2022 XMOS LIMITED.
// Copyright 2012-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#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,7 +142,7 @@ 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)
@@ -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,
@@ -422,7 +316,7 @@ void usb_audio_io(chanend ?c_aud_in,
#endif
)
{
#ifdef MIXER
#if (MIXER)
chan c_mix_out;
#endif
@@ -446,7 +340,7 @@ void usb_audio_io(chanend ?c_aud_in,
par
{
#ifdef MIXER
#if (MIXER)
/* Mixer cores(s) */
{
thread_speed();
@@ -464,7 +358,7 @@ 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
@@ -511,6 +405,9 @@ void usb_audio_io(chanend ?c_aud_in,
#define USER_MAIN_CORES
#endif
#ifndef USER_UNSAFE_USE
#define USER_UNSAFE_USE
#endif
/* Main for USB Audio Applications */
int main()
@@ -531,7 +428,7 @@ int main()
#endif
#endif
#ifdef MIXER
#if (MIXER)
chan c_mix_ctl;
#endif
@@ -575,6 +472,20 @@ int main()
#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
interface pll_ref_if i_pll_ref;
#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
@@ -597,38 +508,95 @@ 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);
}
/* 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
#ifdef PAWPAW_INOUTHID
, c_xud_in[ENDPOINT_NUMBER_IN_HID]
, c_xud_out[ENDPOINT_NUMBER_OUT_HID]
#endif //#ifdef PAWPAW_INOUTHID
, 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 */
}
on tile[AUDIO_IO_TILE]:
{
/* Audio I/O task, includes mixing etc */
//user unsafe use
USER_UNSAFE_USE
usb_audio_io(c_mix_out
#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
@@ -685,7 +653,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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#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__*/

View File

@@ -1,4 +1,4 @@
// Copyright 2011-2022 XMOS LIMITED.
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#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);
}

View File

@@ -1,4 +1,4 @@
// Copyright 2013-2021 XMOS LIMITED.
// Copyright 2013-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
@@ -34,7 +34,7 @@ typedef struct hidEvent_t {
#define HID_MAX_DATA_BYTES ( 4 )
#define HID_EVENT_INVALID_ID ( 0x100 )
#if( 0 < HID_CONTROLS )
#if XUA_HID_ENABLED
/**
* \brief Get the data for the next HID Report
@@ -61,21 +61,5 @@ 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__ */

View File

@@ -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"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,23 @@
# Copyright 2022 XMOS LIMITED.
# Copyright 2022-2023 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
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):

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,45 @@
# Copyright 2023 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
import pytest
import Pyxsim
from Pyxsim import testers
import os
import sys
def do_test(options, capfd, test_file, test_seed):
testname, _ = os.path.splitext(os.path.basename(test_file))
binary = f"{testname}/bin/{testname}.xe"
tester = testers.ComparisonTester(open("pass.expect"))
max_cycles = 15000000
simargs = [
"--max-cycles",
str(max_cycles),
]
build_options = []
build_options += ["TEST_SEED=" + str(test_seed)]
result = Pyxsim.run_on_simulator(
binary,
tester=tester,
build_options=build_options,
simargs=simargs,
capfd=capfd,
instTracing=options.enabletracing,
vcdTracing=options.enablevcdtracing,
)
return result
def test_mixer_routing_input(options, capfd, test_file, test_seed):
result = do_test(options, capfd, test_file, test_seed)
assert result

View File

@@ -0,0 +1,19 @@
DEBUG ?= 0
ifeq ($(DEBUG),1)
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
else
TEST_DEBUG_FLAGS =
endif
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS)
XCC_FLAGS = -O3 $(TEST_FLAGS)
TARGET = test_xs3_600.xn
USED_MODULES = lib_xua lib_logging lib_random
XMOS_MAKE_PATH ?= ../..
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -0,0 +1,243 @@
// Copyright 2022-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/* Tests that routing of mixer inputs behaves as expected
*
* The device supports MAX_MIX_COUNT mixers each with MIX_INPUTS inputs.
*
* This test also assumes/checks that the default routing into each of the MIX_INPUTS inputs into
* each of the M mixer units is as follows:
*
* MIXER[0]:
* USB_FROM_HOST[0] -> MIXER[0].INPUT[0]
* USB_FROM_HOST[1] -> MIXER[0].INPUT[1]
* ...
USB_TO_HOST[0] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT]
USB_TO_HOST[1] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT+1]
...
* MIXER[MAX_MIX_COUNT-1]:
* USB_FROM_HOST[0] -> MIXER[MAX_MIX_COUNT-1].INPUT[0]
* USB_FROM_HOST[1] -> MIXER[MAX_MIX_COUNT-1].INPUT[1]
* ...
*
*/
#include <stdint.h>
#include <stddef.h>
#include "platform.h"
#include "xua.h"
#include "debug_print.h"
#include "assert.h"
#include "random.h"
#ifndef TEST_ITERATIONS
#define TEST_ITERATIONS (300)
#endif
#include "./../test_mixer_routing_output/src/mixer_test_shared.h"
struct ModelMixer
{
uint32_t deviceMap[NUM_USB_CHAN_OUT];
uint32_t hostMap[NUM_USB_CHAN_IN];
uint32_t mixMap_input[MAX_MIX_COUNT];
uint32_t mixMap_src[MAX_MIX_COUNT];
uint32_t mixOutput[MAX_MIX_COUNT];
};
void InitModel(struct ModelMixer &modelMixer)
{
for(size_t i = 0; i < NUM_USB_CHAN_OUT; i++)
{
modelMixer.deviceMap[i] = i;
}
for(size_t i = 0; i < NUM_USB_CHAN_IN; i++)
{
modelMixer.hostMap[i] = NUM_USB_CHAN_OUT+i;
}
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
{
// This test only allows for one "active" input to each mixer
modelMixer.mixMap_src[i] = i;
modelMixer.mixMap_input[i] = i;
uint32_t sample = i;
SET_SOURCE(sample, SRC_HOST);
SET_CHANNEL(sample, i);
modelMixer.mixOutput[i] = sample;
}
}
void GenExpectedSamples(struct ModelMixer &modelMixer,
uint32_t modelOut[NUM_USB_CHAN_OUT],
uint32_t modelIn[NUM_USB_CHAN_IN])
{
/* First generate model mix outputs - run MIX tiles to allow mix inputs derived from mix outputs to propagate */
for(int j = 0; j < MAX_MIX_COUNT; j++)
{
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
{
int src = modelMixer.mixMap_src[i];
modelMixer.mixOutput[i] = CreateSample(modelMixer.mixOutput, src);
}
}
for(size_t i = 0; i<NUM_USB_CHAN_OUT; i++)
{
int src = modelMixer.deviceMap[i];
modelOut[i] = CreateSample(modelMixer.mixOutput, src);
}
for(size_t i = 0; i<NUM_USB_CHAN_IN; i++)
{
int src = modelMixer.hostMap[i];
modelIn[i] = CreateSample(modelMixer.mixOutput, src);
}
}
void MapMixerInput(int mix, int input, int src, struct ModelMixer &modelMixer, chanend c_mix_ctl,
chanend c_stim_ah, chanend c_stim_de, uint32_t modelIn[], uint32_t modelOut[])
{
debug_printf("Mapping mix %d input %d", mix, input);
debug_printf(" from %d", src);
PrintSourceString(src);
debug_printf("\n");
/* This test only allows for one input to travel "untouched" to the mix output - since this test doesn't model the actual mixing.
* Because of this we must also mod the mixer weights, not just the mixer input map.
* If we simply just apply an update to the mixer input mapping it would not produce an observable difference on the mixer output
*/
/* Set previously "activated" input weight to 0 */
debug_printf("Setting mix %d, weight %d to 0\n", mix, modelMixer.mixMap_input[mix]);
SendTrigger(c_stim_ah, 1);
UpdateMixerWeight(c_mix_ctl, mix, modelMixer.mixMap_input[mix], 0);
/* Set new "activated" input wright to max (i.e. x1) */
debug_printf("Setting mix %d, weight %d to %x\n", mix, input, XUA_MIXER_MAX_MULT);
SendTrigger(c_stim_ah, 1);
UpdateMixerWeight(c_mix_ctl, mix, input, XUA_MIXER_MAX_MULT);
/* Update mixer input in model */
modelMixer.mixMap_src[mix] = src;
modelMixer.mixMap_input[mix] = input;
/* Run twice to allow mix inputs derived from mix outputs to propagate */
GenExpectedSamples(modelMixer, modelOut, modelIn);
/* Finally update the acutal mixer input map */
SendTrigger(c_stim_ah, 1);
UpdateMixMap(c_mix_ctl, mix, input, src);
SendTrigger(c_stim_ah, 1);
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
}
/* This task configures the routing and maintains a model of the expected routing output
* it provides this to the Fake AudioHub and Fake Decouple tasks such that they can self check
*/
void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
{
uint32_t modelOut[NUM_USB_CHAN_OUT];
uint32_t modelIn[NUM_USB_CHAN_IN];
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
struct ModelMixer modelMixer;
InitModel(modelMixer);
GenExpectedSamples(modelMixer, modelOut, modelIn);
/* There is single sample delay between the two mixer cores, so trigger twice to flush though a block
* of zero samples */
SendTrigger(c_stim_ah, 2);
/* Send expected samples to AH and DE and run checks */
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
/* Firstly route mixer outputs to the audio interfaces (we could have chosen host)
* such that we can observe and check the outputs from the mixer
*/
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
{
int map = SET_SAMPLES_TO_DEVICE_MAP;
assert(i < NUM_USB_CHAN_OUT);
int dst = i;
int src = NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN+i; // mix0, mix1..
debug_printf("Mapping output to AudioIF: %d ", dst);
PrintDestString(map, dst);
debug_printf(" from %d", src);
PrintSourceString(src);
debug_printf("\n");
SendTrigger(c_stim_ah, 1);
/* Update the mixer */
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
/* Update the model */
modelMixer.deviceMap[dst] = src;
}
/* Send expected samples to fake AudioHub and Decouple for checking */
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
{
/* Make a random update to the routing - route a random source to a random mix input */
unsigned mix = random_get_random_number(rg) % MAX_MIX_COUNT;
unsigned input = random_get_random_number(rg) % MIX_INPUTS;
/* Note, we don't currently support a mix input dervived from another mix
* This is not trivial to test since the current mixer implementation only allows for one
* config update per "trigger"
*/
unsigned src = random_get_random_number(rg) % NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT;
debug_printf("Iteration: %d\n", testIter);
MapMixerInput(mix, input, src, modelMixer, c_mix_ctl, c_stim_ah, c_stim_de, modelIn, modelOut);
}
/* Send kill messages to Fake AudioHub & Fake Decouple */
outct(c_stim_ah, XS1_CT_END);
inct(c_stim_ah);
outct(c_stim_de, XS1_CT_END);
inct(c_stim_de);
printstrln("PASS");
exit(0);
}
int main()
{
chan c_dec_mix;
chan c_mix_aud;
chan c_mix_ctl;
chan c_stim_ah;
chan c_stim_de;
par
{
Fake_XUA_Buffer_Decouple(c_dec_mix, c_stim_de);
Fake_XUA_AudioHub(c_mix_aud, c_stim_ah);
/* Mixer from lib_xua */
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
stim(c_stim_ah, c_stim_de, c_mix_ctl);
}
/* TODO to hit this we need to fully close down i.e. kill mixer */
return 0;
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Network xmlns="http://www.xmos.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
<Declarations>
<Declaration>tileref tile[2]</Declaration>
</Declarations>
<Packages>
<Package id="0" Type="XS3-UnA-1024-FB265">
<Nodes>
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
<Tile Number="0" Reference="tile[0]"/>
<Tile Number="1" Reference="tile[1]"/>
</Node>
</Nodes>
</Package>
</Packages>
<JTAGChain>
<JTAGDevice NodeId="0"/>
</JTAGChain>
</Network>

View File

@@ -0,0 +1,45 @@
// Copyright 2016-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _XUA_CONF_H_
#define _XUA_CONF_H_
#define NUM_USB_CHAN_OUT (10)
#define NUM_USB_CHAN_IN (10)
#define I2S_CHANS_DAC (10)
#define I2S_CHANS_ADC (10)
#define EXCLUDE_USB_AUDIO_MAIN
#define MIXER (1)
#define MAX_MIX_COUNT (8)
#define UAC_FORCE_FEEDBACK_EP (0)
#define XUA_NUM_PDM_MICS 0
#define XUD_TILE 1
#define AUDIO_IO_TILE 0
#ifndef MCLK_441
#define MCLK_441 (512 * 44100)
#endif
#ifndef MCLK_48
#define MCLK_48 (512 * 48000)
#endif
#define MIN_FREQ (44100)
#define MAX_FREQ (192000)
#define SPDIF_TX_INDEX 0
#define VENDOR_STR "XMOS"
#define VENDOR_ID 0x20B1
#define PRODUCT_STR_A2 "Test device"
#define PRODUCT_STR_A1 "Test device"
#define PID_AUDIO_1 1
#define PID_AUDIO_2 2
#define AUDIO_CLASS 2
#define AUDIO_CLASS_FALLBACK 0
#define BCD_DEVICE 0x1234
#define XUA_DFU_EN 0
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
#define XUA_MIC_FRAME_SIZE 240
#endif

View File

@@ -0,0 +1,45 @@
# Copyright 2023 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
import pytest
import Pyxsim
from Pyxsim import testers
import os
import sys
def do_test(options, capfd, test_file, test_seed):
testname, _ = os.path.splitext(os.path.basename(test_file))
binary = f"{testname}/bin/{testname}.xe"
tester = testers.ComparisonTester(open("pass.expect"))
max_cycles = 15000000
simargs = [
"--max-cycles",
str(max_cycles),
]
build_options = []
build_options += ["TEST_SEED=" + str(test_seed)]
result = Pyxsim.run_on_simulator(
binary,
tester=tester,
build_options=build_options,
simargs=simargs,
capfd=capfd,
instTracing=options.enabletracing,
vcdTracing=options.enablevcdtracing,
)
return result
def test_mixer_routing_output(options, capfd, test_file, test_seed):
result = do_test(options, capfd, test_file, test_seed)
assert result

View File

@@ -0,0 +1,19 @@
DEBUG ?= 0
ifeq ($(DEBUG),1)
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
else
TEST_DEBUG_FLAGS =
endif
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS) -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

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

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Network xmlns="http://www.xmos.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
<Declarations>
<Declaration>tileref tile[2]</Declaration>
</Declarations>
<Packages>
<Package id="0" Type="XS3-UnA-1024-FB265">
<Nodes>
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
<Tile Number="0" Reference="tile[0]"/>
<Tile Number="1" Reference="tile[1]"/>
</Node>
</Nodes>
</Package>
</Packages>
<JTAGChain>
<JTAGDevice NodeId="0"/>
</JTAGChain>
</Network>

View File

@@ -0,0 +1,45 @@
// Copyright 2016-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _XUA_CONF_H_
#define _XUA_CONF_H_
#define NUM_USB_CHAN_OUT (10)
#define NUM_USB_CHAN_IN (10)
#define I2S_CHANS_DAC (10)
#define I2S_CHANS_ADC (10)
#define EXCLUDE_USB_AUDIO_MAIN
#define MIXER (1)
#define MAX_MIX_COUNT (8)
#define UAC_FORCE_FEEDBACK_EP (0)
#define XUA_NUM_PDM_MICS 0
#define XUD_TILE 1
#define AUDIO_IO_TILE 0
#ifndef MCLK_441
#define MCLK_441 (512 * 44100)
#endif
#ifndef MCLK_48
#define MCLK_48 (512 * 48000)
#endif
#define MIN_FREQ (44100)
#define MAX_FREQ (192000)
#define SPDIF_TX_INDEX 0
#define VENDOR_STR "XMOS"
#define VENDOR_ID 0x20B1
#define PRODUCT_STR_A2 "Test device"
#define PRODUCT_STR_A1 "Test device"
#define PID_AUDIO_1 1
#define PID_AUDIO_2 2
#define AUDIO_CLASS 2
#define AUDIO_CLASS_FALLBACK 0
#define BCD_DEVICE 0x1234
#define XUA_DFU_EN 0
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
#define XUA_MIC_FRAME_SIZE 240
#endif

View File

@@ -0,0 +1,45 @@
# Copyright 2023 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
import pytest
import Pyxsim
from Pyxsim import testers
import os
import sys
def do_test(options, capfd, test_file, test_seed):
testname, _ = os.path.splitext(os.path.basename(test_file))
binary = f"{testname}/bin/{testname}.xe"
tester = testers.ComparisonTester(open("pass.expect"))
max_cycles = 15000000
simargs = [
"--max-cycles",
str(max_cycles),
]
build_options = []
build_options += ["TEST_SEED=" + str(test_seed)]
result = Pyxsim.run_on_simulator(
binary,
tester=tester,
build_options=build_options,
simargs=simargs,
capfd=capfd,
instTracing=options.enabletracing,
vcdTracing=options.enablevcdtracing,
)
return result
def test_mixer_routing_output(options, capfd, test_file, test_seed):
result = do_test(options, capfd, test_file, test_seed)
assert result

View File

@@ -0,0 +1,19 @@
DEBUG ?= 0
ifeq ($(DEBUG),1)
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
else
TEST_DEBUG_FLAGS =
endif
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS)
XCC_FLAGS = -O3 $(TEST_FLAGS)
TARGET = test_xs3_600.xn
USED_MODULES = lib_xua lib_logging lib_random
XMOS_MAKE_PATH ?= ../..
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common

View File

@@ -0,0 +1,224 @@
// Copyright 2022-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/* Tests that routing of mixer outputs behaves as expected
*
* "Outputs" from the device are to the USB host of one of the various audio interaces supported.
* This test assumes/checks the default routing for the USB host & audio interfaces is as follows:
*
* USB_FROM_HOST[0] -> AUD_INTERFACE_OUTPUT[0]
* USB_FROM_HOST[1] -> AUD_INTERFACE_OUTPUT[1]
* ...
* USB_TO_HOST[0] <- AUD_INTERFACE_INPUT[0]
* USB_TO_HOST[1] <- AUD_INTERFACE_INPUT[1]
* ...
*
* This test also assumes/checks that the default routing into each of the MIX_INPUTS inputs into
* each of the M mixer units is as follows:
*
* MIXER[0]:
* USB_FROM_HOST[0] -> MIXER[0].INPUT[0]
* USB_FROM_HOST[1] -> MIXER[0].INPUT[1]
* ...
USB_TO_HOST[0] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT]
USB_TO_HOST[1] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT+1]
...
* MIXER[MAX_MIX_COUNT-1]:
* USB_FROM_HOST[0] -> MIXER[MAX_MIX_COUNT-1].INPUT[0]
* USB_FROM_HOST[1] -> MIXER[MAX_MIX_COUNT-1].INPUT[1]
* ...
*
* (If the number of mixer inputs > NUM_USB_CHAN_OUT then see ordering in comment regarding
* SOURCE_COUNT below)
*
* By default none of the MAX_MIX_COUNT output from the mixers are routed anywwhere, but this test ensures
* that they can be.
*
* This test assumes that none of the mixer weights are changed.
* This test does not test changing the inputs to the mixer.
*/
#include <stdint.h>
#include <stddef.h>
#include "platform.h"
#include "xua.h"
#include "debug_print.h"
#include "assert.h"
#include "random.h"
#ifndef TEST_ITERATIONS
#define TEST_ITERATIONS (100)
#endif
#include "./mixer_test_shared.h"
void UpdateModel(uint32_t modelOut[CHANNEL_MAP_AUD_SIZE], uint32_t modelMixerOut[MAX_MIX_COUNT], uint32_t modelIn[NUM_USB_CHAN_IN],
int map, int dst, int src)
{
unsigned sample = 0;
if(src == (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT))
{
SET_SOURCE(sample, SRC_OFF);
}
else if(src >= (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN))
{
src -= (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN);
sample = modelMixerOut[src];
}
else if (src >= NUM_USB_CHAN_IN)
{
SET_SOURCE(sample, SRC_AUDIF);
src -= NUM_USB_CHAN_OUT;
SET_CHANNEL(sample, src);
}
else
{
SET_SOURCE(sample, SRC_HOST);
SET_CHANNEL(sample, src);
}
switch(map)
{
case SET_SAMPLES_TO_DEVICE_MAP:
modelOut[dst] = sample;
break;
case SET_SAMPLES_TO_HOST_MAP:
modelIn[dst] = sample;
break;
default:
assert(0);
break;
}
}
/* This task configures the routing and maintains a model of the expected routing output
* it provides this to the Fake AudioHub and Fake Decouple tasks such that they can self check
*/
void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
{
uint32_t modelOut[CHANNEL_MAP_AUD_SIZE];
uint32_t modelIn[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;
}

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

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Network xmlns="http://www.xmos.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
<Declarations>
<Declaration>tileref tile[2]</Declaration>
</Declarations>
<Packages>
<Package id="0" Type="XS3-UnA-1024-FB265">
<Nodes>
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
<Tile Number="0" Reference="tile[0]"/>
<Tile Number="1" Reference="tile[1]"/>
</Node>
</Nodes>
</Package>
</Packages>
<JTAGChain>
<JTAGDevice NodeId="0"/>
</JTAGChain>
</Network>

View File

@@ -0,0 +1,45 @@
// Copyright 2016-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _XUA_CONF_H_
#define _XUA_CONF_H_
#define NUM_USB_CHAN_OUT (10)
#define NUM_USB_CHAN_IN (10)
#define I2S_CHANS_DAC (10)
#define I2S_CHANS_ADC (10)
#define EXCLUDE_USB_AUDIO_MAIN
#define MIXER (1)
#define MAX_MIX_COUNT (8)
#define UAC_FORCE_FEEDBACK_EP (0)
#define XUA_NUM_PDM_MICS 0
#define XUD_TILE 1
#define AUDIO_IO_TILE 0
#ifndef MCLK_441
#define MCLK_441 (512 * 44100)
#endif
#ifndef MCLK_48
#define MCLK_48 (512 * 48000)
#endif
#define MIN_FREQ (44100)
#define MAX_FREQ (192000)
#define SPDIF_TX_INDEX 0
#define VENDOR_STR "XMOS"
#define VENDOR_ID 0x20B1
#define PRODUCT_STR_A2 "Test device"
#define PRODUCT_STR_A1 "Test device"
#define PID_AUDIO_1 1
#define PID_AUDIO_2 2
#define AUDIO_CLASS 2
#define AUDIO_CLASS_FALLBACK 0
#define BCD_DEVICE 0x1234
#define XUA_DFU_EN 0
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
#define XUA_MIC_FRAME_SIZE 240
#endif

View File

@@ -0,0 +1,45 @@
# Copyright 2023 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
import pytest
import Pyxsim
from Pyxsim import testers
import os
import sys
def do_test(options, capfd, test_file, test_seed):
testname, _ = os.path.splitext(os.path.basename(test_file))
binary = f"{testname}/bin/{testname}.xe"
tester = testers.ComparisonTester(open("pass.expect"))
max_cycles = 15000000
simargs = [
"--max-cycles",
str(max_cycles),
]
build_options = []
build_options += ["TEST_SEED=" + str(test_seed)]
result = Pyxsim.run_on_simulator(
binary,
tester=tester,
build_options=build_options,
simargs=simargs,
capfd=capfd,
instTracing=options.enabletracing,
vcdTracing=options.enablevcdtracing,
)
return result
def test_mixer_routing_output(options, capfd, test_file, test_seed):
result = do_test(options, capfd, test_file, test_seed)
assert result

View File

@@ -0,0 +1,19 @@
DEBUG ?= 0
ifeq ($(DEBUG),1)
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
else
TEST_DEBUG_FLAGS =
endif
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS) -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

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

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Network xmlns="http://www.xmos.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
<Declarations>
<Declaration>tileref tile[2]</Declaration>
</Declarations>
<Packages>
<Package id="0" Type="XS3-UnA-1024-FB265">
<Nodes>
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
<Tile Number="0" Reference="tile[0]"/>
<Tile Number="1" Reference="tile[1]"/>
</Node>
</Nodes>
</Package>
</Packages>
<JTAGChain>
<JTAGDevice NodeId="0"/>
</JTAGChain>
</Network>

View File

@@ -0,0 +1,45 @@
// Copyright 2016-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _XUA_CONF_H_
#define _XUA_CONF_H_
#define NUM_USB_CHAN_OUT (10)
#define NUM_USB_CHAN_IN (10)
#define I2S_CHANS_DAC (10)
#define I2S_CHANS_ADC (10)
#define EXCLUDE_USB_AUDIO_MAIN
#define MIXER (1)
#define MAX_MIX_COUNT (8)
#define UAC_FORCE_FEEDBACK_EP (0)
#define XUA_NUM_PDM_MICS 0
#define XUD_TILE 1
#define AUDIO_IO_TILE 0
#ifndef MCLK_441
#define MCLK_441 (512 * 44100)
#endif
#ifndef MCLK_48
#define MCLK_48 (512 * 48000)
#endif
#define MIN_FREQ (44100)
#define MAX_FREQ (192000)
#define SPDIF_TX_INDEX 0
#define VENDOR_STR "XMOS"
#define VENDOR_ID 0x20B1
#define PRODUCT_STR_A2 "Test device"
#define PRODUCT_STR_A1 "Test device"
#define PID_AUDIO_1 1
#define PID_AUDIO_2 2
#define AUDIO_CLASS 2
#define AUDIO_CLASS_FALLBACK 0
#define BCD_DEVICE 0x1234
#define XUA_DFU_EN 0
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
#define XUA_MIC_FRAME_SIZE 240
#endif