forked from PAWPAW-Mirror/lib_xua
Compare commits
150 Commits
v3.3.1
...
takstar_us
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d9006f5e7 | |||
|
|
460b5d11e0 | ||
|
|
b29e6ffa91 | ||
|
|
a336bec81b | ||
|
|
791c142c94 | ||
|
|
487ab06213 | ||
|
|
def348a763 | ||
|
|
c9f7738efd | ||
|
|
a485ffe41a | ||
|
|
f25a9eeade | ||
|
|
dff72573f8 | ||
|
|
f7331a1ed3 | ||
|
|
aaaf1e9652 | ||
|
|
d6b23cf960 | ||
|
|
fa8329edaa | ||
|
|
83d86e885f | ||
|
|
15036f2bcc | ||
|
|
fa5723947f | ||
|
|
b1b28f1005 | ||
|
|
6d41cfcbea | ||
|
|
5404127dbf | ||
|
|
e5a270347a | ||
|
|
f509a12e7d | ||
|
|
4528bed740 | ||
|
|
e812ca3e8b | ||
|
|
2accc0429f | ||
|
|
36d5201365 | ||
|
|
cea580ba48 | ||
|
|
6815f12a90 | ||
|
|
799ad7ba86 | ||
|
|
3d7e66bdc0 | ||
|
|
a6387d5fef | ||
|
|
5ca0738b02 | ||
|
|
b0e732110d | ||
|
|
1702078e7c | ||
|
|
136ec2506c | ||
|
|
45e5ef7702 | ||
|
|
1ef5129fde | ||
|
|
b1fe49aff3 | ||
|
|
d3ad29e8a6 | ||
|
|
17944ad908 | ||
|
|
131dd252c0 | ||
|
|
23d043630f | ||
|
|
761a33f5e4 | ||
|
|
12ec1d7536 | ||
|
|
2dba6dce36 | ||
|
|
9cf931898e | ||
|
|
9b104af8cf | ||
|
|
c469dd6cde | ||
|
|
b238196f74 | ||
|
|
e9586b59d3 | ||
|
|
6d168b3209 | ||
|
|
d301fef6d7 | ||
|
|
1f4e9a99b8 | ||
|
|
981ea78be7 | ||
|
|
6cee90d876 | ||
|
|
79d14f8b59 | ||
|
|
05dcb8f3ab | ||
|
|
4e7ddb4036 | ||
|
|
e8fcc80415 | ||
|
|
71a657dc9a | ||
|
|
ccfca90451 | ||
|
|
cb379f5bfb | ||
|
|
e2c36a9a95 | ||
|
|
7e3ae59acc | ||
|
|
f1f453921b | ||
|
|
7703fc1a7d | ||
|
|
53a65344fc | ||
|
|
3b2814f8cb | ||
|
|
55a62cf589 | ||
|
|
4a84c3e1ec | ||
|
|
b17f585004 | ||
|
|
57593bfea3 | ||
|
|
8dc77090bf | ||
|
|
9c20fab216 | ||
|
|
cf1940245f | ||
|
|
837b648bbc | ||
|
|
c1159143ea | ||
|
|
2964861b70 | ||
|
|
208491fe51 | ||
|
|
3fe4593b52 | ||
|
|
49a116c705 | ||
|
|
eee5b474a0 | ||
|
|
4655a07542 | ||
|
|
c578bb92d5 | ||
|
|
d5a614df55 | ||
|
|
495140ab8d | ||
|
|
f53c1bab09 | ||
|
|
0c6d947e67 | ||
|
|
ee271e3769 | ||
|
|
950beb55cb | ||
|
|
ca3276792a | ||
|
|
e26b934233 | ||
|
|
51629dba24 | ||
|
|
c5e944d73d | ||
|
|
22a3d5e043 | ||
|
|
58f691078d | ||
|
|
f80d7647e0 | ||
|
|
fe697929bc | ||
|
|
b265ccd8bf | ||
|
|
6c2e7e3042 | ||
|
|
15ca5ec281 | ||
|
|
71aa64425d | ||
|
|
9080990234 | ||
|
|
6d8cf9913f | ||
|
|
60040de58f | ||
|
|
27a59ab3bc | ||
|
|
317e27e421 | ||
|
|
035c20e01c | ||
|
|
ef97d667de | ||
|
|
0e07dc29bc | ||
|
|
43f77c177d | ||
|
|
6754f812c9 | ||
|
|
fc732b8512 | ||
|
|
39ed235476 | ||
|
|
0d7224bd6d | ||
|
|
fd4dfd40a9 | ||
|
|
3d50c96595 | ||
|
|
379e8eb54c | ||
|
|
63763cf4f5 | ||
|
|
b18c34fb0f | ||
|
|
64d65afeaf | ||
|
|
7a47d70229 | ||
|
|
ce8e5a6dbb | ||
|
|
bbed806aab | ||
|
|
9af31b8c70 | ||
|
|
73955c1a4c | ||
|
|
cffd35d146 | ||
|
|
ab535e0fb3 | ||
|
|
17b039dce8 | ||
|
|
7a0d0e1f97 | ||
|
|
2f31260612 | ||
|
|
9922190450 | ||
|
|
0ce91bec90 | ||
|
|
2404eaf35f | ||
|
|
8966ad1bb9 | ||
|
|
513761ef5b | ||
|
|
da7c45500d | ||
|
|
395c88cb22 | ||
|
|
94e58edfaf | ||
|
|
9f00f9159a | ||
|
|
785a857ca8 | ||
|
|
3130088c91 | ||
|
|
c51ee0c460 | ||
|
|
17ed636a74 | ||
|
|
0db1b08948 | ||
|
|
9c460f753f | ||
|
|
6a9537fb69 | ||
|
|
abfa3a2011 | ||
|
|
a1946f340a |
56
.gitignore
vendored
56
.gitignore
vendored
@@ -1,29 +1,25 @@
|
||||
*.log
|
||||
*.dSYM
|
||||
*/.build_*/*
|
||||
*/bin/*
|
||||
*.o
|
||||
# XMOS bin files
|
||||
*.xe
|
||||
*.vcd
|
||||
*.swo
|
||||
*.bin
|
||||
*/bin/*
|
||||
|
||||
# XMOS temp files
|
||||
.build*
|
||||
*.a
|
||||
_build*
|
||||
*.i
|
||||
*.s
|
||||
*.xi
|
||||
*.i
|
||||
*.bin
|
||||
*~
|
||||
*.a
|
||||
*.swp
|
||||
*.*~
|
||||
*.pyc
|
||||
.build*
|
||||
*.o
|
||||
*/.build_*/*
|
||||
|
||||
# Temp files
|
||||
.DS_Store
|
||||
test_results.csv
|
||||
_build*
|
||||
**/.venv/**
|
||||
**/.vscode/**
|
||||
**.egg-info
|
||||
*.pdf
|
||||
*tests/logs/*
|
||||
*.*~
|
||||
*.swp
|
||||
*.swn
|
||||
*~
|
||||
*.swo
|
||||
|
||||
# waf build files
|
||||
.lock-waf_*
|
||||
@@ -36,3 +32,19 @@ xscope.xmt
|
||||
# Traces
|
||||
*.gtkw
|
||||
*.vcd
|
||||
|
||||
# Host binaries
|
||||
host_usb_mixer_control/xmos_mixer
|
||||
|
||||
# Documentation build
|
||||
*.pdf
|
||||
|
||||
# Misc
|
||||
*.log
|
||||
*.dSYM
|
||||
*.vcd
|
||||
*.pyc
|
||||
**/.venv/**
|
||||
**/.vscode/**
|
||||
**.egg-info
|
||||
*tests/logs/*
|
||||
|
||||
@@ -1,6 +1,54 @@
|
||||
lib_xua Change Log
|
||||
==================
|
||||
|
||||
3.5.1
|
||||
-----
|
||||
|
||||
* FIXED: Respect I2S_CHANS_PER_FRAME when calculating bit-clock rates
|
||||
|
||||
* Changes to dependencies:
|
||||
|
||||
- lib_spdif: 5.0.0 -> 5.0.1
|
||||
|
||||
3.5.0
|
||||
-----
|
||||
|
||||
* ADDED: Configurable word-length for I2S/TDM via XUA_I2S_N_BITS
|
||||
* ADDED: Support for statically defined custom HID descriptor
|
||||
* CHANGED: Rearranged main() such that adding custom code that uses lib_xud
|
||||
is possible
|
||||
* CHANGED: bNumConfigurations changed from 2 to 1, removing a work-around to
|
||||
stop old Windows versions loading the composite driver
|
||||
* FIXED: Memory corruption due to erroneous initialisation of mixer
|
||||
weights when not in use (#152)
|
||||
* FIXED: UserHostActive() not being called as expected (#326)
|
||||
* FIXED: Exception when entering DSD mode (#327)
|
||||
|
||||
* Changes to dependencies:
|
||||
|
||||
- lib_spdif: 4.2.1 -> 5.0.0
|
||||
|
||||
- lib_xud: 2.2.2 -> 2.2.3
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
* ADDED: Unit tests for mixer functionality
|
||||
* ADDED: Host mixer control applications (for Win/macOS)
|
||||
* CHANGED: Small tidies to mixer implementation
|
||||
* CHANGED: Improved mixer control channel communication protocol to avoid
|
||||
deadlock situations
|
||||
* CHANGED: By default, output volume processing occurs in mixer task, if
|
||||
present. Previously occurred in decouple task
|
||||
* CHANGED: Some optimisations in sample transfer from decouple task
|
||||
* FIXED: Exception on startup when USB input disabled
|
||||
* FIXED: Full 32bit volume processing only applied when required
|
||||
* FIXED: Setting OUT_VOLUME_AFTER_MIX to zero now has the expected effect
|
||||
|
||||
* Changes to dependencies:
|
||||
|
||||
- lib_xud: 2.2.1 -> 2.2.2
|
||||
|
||||
3.3.1
|
||||
-----
|
||||
|
||||
|
||||
20
Jenkinsfile
vendored
20
Jenkinsfile
vendored
@@ -1,4 +1,4 @@
|
||||
@Library('xmos_jenkins_shared_library@v0.21.0') _
|
||||
@Library('xmos_jenkins_shared_library@v0.24.0') _
|
||||
|
||||
getApproval()
|
||||
|
||||
@@ -106,6 +106,12 @@ pipeline {
|
||||
dir("${REPO}/${REPO}/host/xmosdfu") {
|
||||
sh 'make -f Makefile.OSX64'
|
||||
}
|
||||
dir("${REPO}/host_usb_mixer_control") {
|
||||
sh 'make -f Makefile.OSX'
|
||||
sh 'mkdir OSX/x86'
|
||||
sh 'mv xmos_mixer OSX/x86/xmos_mixer'
|
||||
archiveArtifacts artifacts: "OSX/x86/xmos_mixer", fingerprint: true
|
||||
}
|
||||
}
|
||||
post {
|
||||
cleanup {
|
||||
@@ -139,7 +145,17 @@ pipeline {
|
||||
dir("${REPO}") {
|
||||
checkout scm
|
||||
dir("${REPO}/host/xmosdfu") {
|
||||
runVS('nmake /f Makefile.Win32')
|
||||
withVS("vcvars32.bat") {
|
||||
bat "nmake /f Makefile.Win32"
|
||||
}
|
||||
}
|
||||
dir("host_usb_mixer_control") {
|
||||
withVS() {
|
||||
bat 'msbuild host_usb_mixer_control.vcxproj /property:Configuration=Release /property:Platform=x64'
|
||||
}
|
||||
bat 'mkdir Win\\x64'
|
||||
bat 'mv bin/Release/x64/host_usb_mixer_control.exe Win/x64/xmos_mixer.exe'
|
||||
archiveArtifacts artifacts: "Win/x64/xmos_mixer.exe", fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
README.rst
23
README.rst
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
10
host_usb_mixer_control/.makefile
Normal file
10
host_usb_mixer_control/.makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
all:
|
||||
@echo =======================================================
|
||||
@echo Build complete [module only - cannot be run on its own]
|
||||
@echo =======================================================
|
||||
|
||||
clean:
|
||||
@echo =======================================================
|
||||
@echo Build clean [module only - cannot be run on its own]
|
||||
@echo =======================================================
|
||||
|
||||
77
host_usb_mixer_control/.project
Normal file
77
host_usb_mixer_control/.project
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>host_usb_mixer_control</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||
<triggers>clean,full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>?name?</key>
|
||||
<value></value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.append_environment</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
|
||||
<value>all</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildArguments</key>
|
||||
<value></value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildCommand</key>
|
||||
<value>xmake</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
|
||||
<value>clean</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.contents</key>
|
||||
<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
|
||||
<value>false</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableFullBuild</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
|
||||
<value>all</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.stopOnError</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
2
host_usb_mixer_control/Makefile.OSX
Normal file
2
host_usb_mixer_control/Makefile.OSX
Normal file
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
g++ -g -o xmos_mixer usb_mixer.cpp mixer_app.cpp -I. -IOSX OSX/libusb-1.0.0.dylib -arch x86_64
|
||||
5
host_usb_mixer_control/Makefile.Win
Normal file
5
host_usb_mixer_control/Makefile.Win
Normal file
@@ -0,0 +1,5 @@
|
||||
!if [set SDKPath=C:\Program^ Files\XMOS\tusbaudiosdk]
|
||||
!endif
|
||||
|
||||
all:
|
||||
msbuild host_usb_mixer_control.vcxproj /property:Configuration=Release /property:Platform=x64
|
||||
BIN
host_usb_mixer_control/OSX/libusb-1.0.0.dylib
Normal file
BIN
host_usb_mixer_control/OSX/libusb-1.0.0.dylib
Normal file
Binary file not shown.
1233
host_usb_mixer_control/OSX/libusb.h
Normal file
1233
host_usb_mixer_control/OSX/libusb.h
Normal file
File diff suppressed because it is too large
Load Diff
117
host_usb_mixer_control/README
Normal file
117
host_usb_mixer_control/README
Normal file
@@ -0,0 +1,117 @@
|
||||
The XMOS USB Audio Reference Design, by default, contains an 18x8 mixer unit
|
||||
(note that at sample rates above 96Khz only the first two outputs are
|
||||
enabled).
|
||||
|
||||
----WINDOWS REQUIREMENTS----
|
||||
Building the mixer on Windows requires the tusbaudio SDK from Thesycon. The
|
||||
default location for the SDK is C:\Program Files\XMOS\tusbaudiosdk\
|
||||
If it can be found on a different path then this can be changed in
|
||||
Makefile.Win.
|
||||
|
||||
The mixer app on windows makes use of a USB dynamic library, also from Thesycon.
|
||||
If required please contact thesycon.de for support.
|
||||
----------------------------
|
||||
|
||||
This unit takes input takes 18 inputs: USB OUT channels 1..10 and
|
||||
DEVICE IN channels 1..6,9..10 and produces 8 outputs: Mixer Output
|
||||
1..8
|
||||
|
||||
Before the mixer there is an unit that allows the selection of the 18 mixer inputs
|
||||
from all the possible device inputs (DAW and physical audio). This is
|
||||
an extension unit with id 50 in the descriptors
|
||||
|
||||
After the mixer unit there is are channel map units for each output terminal:
|
||||
Each of these outputs can select a source from one of 28 channels sources: USB OUT
|
||||
channels 1..10, DEVICE IN channels 1..10 and Mixer Output 1..8
|
||||
|
||||
The channel map units are extension unit with init ids 51 and 52. This unit
|
||||
lets you implement arbitrary routings including loopbacks.
|
||||
|
||||
The mixer is controlled on macOS via the command line utility
|
||||
xmos_mixer. Running this application requires having the
|
||||
libusb-1.0.0.dylib in the dynamic library load path. Sourcing the
|
||||
setup.sh script will do this. Source code for the application is
|
||||
provided as a guide on how to communicate with the device.
|
||||
|
||||
Here are the commands for the mixer application (note that the USB
|
||||
audio reference design has only one unit so the mixer_id argument
|
||||
should always be 0):
|
||||
|
||||
--help
|
||||
|
||||
--display-info
|
||||
|
||||
Show information about the device.
|
||||
|
||||
--display-mixer-nodes mixer_id
|
||||
|
||||
Display all the weights of all the mixer nodes (and their id) of a particular mixer.
|
||||
|
||||
--display-min mixer_id
|
||||
|
||||
Display the minimum allowable weights of a particular mixer.
|
||||
|
||||
--display-max mixer_id
|
||||
|
||||
Display the maximum allowable weights of a particular mixer.
|
||||
|
||||
--display-res mixer_id
|
||||
|
||||
Display the resolution of a particular mixer.
|
||||
|
||||
--set-value mixer_id mixer_unit value
|
||||
|
||||
Set the weight value in the mixer. The second argument should
|
||||
correspond to the values shown by the --display-unit command. Values
|
||||
can range from -127db to +128db with the special value -inf for mute.
|
||||
|
||||
--get-value mixer_id mixer_unit
|
||||
|
||||
Get the weight value in the mixer. The second argument should
|
||||
correspond to the values shown by the --display-unit command. Values
|
||||
can range from -127db to +128db with the special value -inf for mute.
|
||||
|
||||
--set-mixer-source mixer_id, dst_channel_id, src_channel_id
|
||||
|
||||
Allows the selection of the mixer inputs. Sets mixer input (dst) to src
|
||||
|
||||
--display-current-mixer-sources mixer_id
|
||||
|
||||
Displays the current inputs to a particular mixer
|
||||
|
||||
--display-available-mixer-sources mixer_id
|
||||
|
||||
Displays all the input channels available that can be fed into the inputs of a particular mixer
|
||||
|
||||
--set-aud-channel-map dst src
|
||||
|
||||
Sets a channel map value for the device audio output
|
||||
|
||||
--display-aud-channel-map
|
||||
|
||||
Show audio output channel map i.e. for each audio output of the device what the source is.
|
||||
|
||||
--display-aud-channel-map-sources
|
||||
|
||||
Show the available audio output channel map sources.
|
||||
|
||||
--set-daw-channel-map dst src
|
||||
|
||||
Sets a channel map value for the DAW output to the host
|
||||
|
||||
--display-daw-channel-map
|
||||
|
||||
Show audio output channel map i.e. for each DAW output to host, what the source is.
|
||||
|
||||
--display-daw-channel-map-sources
|
||||
|
||||
Show the DAW output channel map sources.
|
||||
|
||||
--get-mixer-levels-input
|
||||
|
||||
--get-mixer-levels-output
|
||||
|
||||
--vendor-audio-request-get bRequest, ControlSelector, ChannelNumber, UnitId
|
||||
|
||||
--vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],...
|
||||
|
||||
48
host_usb_mixer_control/Win/global.h
Normal file
48
host_usb_mixer_control/Win/global.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/************************************************************************
|
||||
*
|
||||
* Module: global.h
|
||||
* Description:
|
||||
* APP global includes, constants, declarations, etc.
|
||||
*
|
||||
* Author(s):
|
||||
* Udo Eberhardt
|
||||
*
|
||||
* Companies:
|
||||
* Thesycon GmbH, Germany http://www.thesycon.de
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#ifndef __global_h__
|
||||
#define __global_h__
|
||||
|
||||
// define the Windows versions supported by the application
|
||||
#define _WIN32_WINNT 0x0500 //Windows 2000 or later
|
||||
//#define _WIN32_WINNT 0x0501 //Windows XP or later
|
||||
//#define _WIN32_WINNT 0x0600 //Windows Vista or later
|
||||
//#define _WIN32_WINNT 0x0A00 //Windows 10 or later
|
||||
|
||||
// exclude rarely-used stuff from Windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
|
||||
|
||||
// version defs
|
||||
//#include "version.h"
|
||||
|
||||
// libwn.h pulls in windows.h
|
||||
#include "libwn.h"
|
||||
// TUSBAUDIO driver API
|
||||
#include "tusbaudioapi.h"
|
||||
#include "TUsbAudioApiDll.h"
|
||||
|
||||
|
||||
#endif // __global_h__
|
||||
|
||||
/*************************** EOF **************************************/
|
||||
177
host_usb_mixer_control/host_usb_mixer_control.vcxproj
Normal file
177
host_usb_mixer_control/host_usb_mixer_control.vcxproj
Normal file
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{84eacf4f-e405-4909-b440-a04a84a3f8c8}</ProjectGuid>
|
||||
<RootNamespace>
|
||||
</RootNamespace>
|
||||
<SDKPath Condition="'$(SDKPath)' == ''">C:\Program Files\XMOS\tusbaudiosdk</SDKPath>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
<Import Project="$(SDKPath)\source\tusbaudioapi_inc\tusbaudioapi_inc_vs2019.vcxitems" Label="Shared" />
|
||||
<Import Project="$(SDKPath)\source\libwn_min\_libwn_min_vs2019.vcxitems" Label="Shared" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>.\bin\$(Configuration)\$(PlatformName)\</OutDir>
|
||||
<IntDir>$(Configuration)\$(PlatformName)_$(PlatformToolset)</IntDir>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>.\bin\$(Configuration)\$(PlatformName)\</OutDir>
|
||||
<IntDir>$(Configuration)\$(PlatformName)_$(PlatformToolset)</IntDir>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_AMD64;_CONSOLE;_UNICODE;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>.;.\Win;$(SDKPath)\source\shared;$(SDKPath)\source\inc;$(SDKPath)\source\libwn_min;$(SDKPath)\source\libwtl;$(SDKPath)\source\tusbaudioapi_inc</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<PrecompiledHeaderFile />
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<UACExecutionLevel />
|
||||
<UACUIAccess />
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<PreprocessorDefinitions>_AMD64;_CONSOLE;_UNICODE;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>.;.\Win;$(SDKPath)\source\shared;$(SDKPath)\source\inc;$(SDKPath)\source\libwn_min;$(SDKPath)\source\libwtl;$(SDKPath)\source\tusbaudioapi_inc</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<PrecompiledHeaderFile />
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<UACExecutionLevel />
|
||||
<UACUIAccess />
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="usb_mixer.h" />
|
||||
<ClInclude Include="Win\global.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mixer_app.cpp" />
|
||||
<ClCompile Include="usb_mixer.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="usb_mixer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Win\global.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mixer_app.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win\usb_mixer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
718
host_usb_mixer_control/mixer_app.cpp
Normal file
718
host_usb_mixer_control/mixer_app.cpp
Normal file
@@ -0,0 +1,718 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "usb_mixer.h"
|
||||
|
||||
#define MIXER_UNIT_DISPLAY_VALUE 2
|
||||
#define MIXER_UNIT_DISPLAY_MIN 3
|
||||
#define MIXER_UNIT_DISPLAY_MAX 4
|
||||
#define MIXER_UNIT_DISPLAY_RES 5
|
||||
|
||||
// TODO
|
||||
// res, min, max
|
||||
|
||||
int mixer_init(void)
|
||||
{
|
||||
/* Open the connection to the USB mixer */
|
||||
if (usb_mixer_connect() == USB_MIXER_FAILURE)
|
||||
{
|
||||
return USB_MIXER_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
int mixer_deinit(void) {
|
||||
// Close the connection to the USB mixer
|
||||
if (usb_mixer_disconnect() == USB_MIXER_FAILURE) {
|
||||
return USB_MIXER_FAILURE;
|
||||
}
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
int mixer_display(unsigned int mixer_index, unsigned int type) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
int num_inputs = usb_mixer_get_num_inputs(mixer_index);
|
||||
int num_outputs = usb_mixer_get_num_outputs(mixer_index);
|
||||
|
||||
|
||||
printf("\n");
|
||||
switch (type) {
|
||||
case MIXER_UNIT_DISPLAY_VALUE:
|
||||
//mixer_update_all_values(mixer_index);
|
||||
printf(" Mixer Values (%d)\n", mixer_index);
|
||||
printf(" ----------------\n\n");
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MIN:
|
||||
printf(" Mixer Ranges Min (%d)\n", mixer_index);
|
||||
printf(" --------------------\n\n");
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MAX:
|
||||
printf(" Mixer Ranges Max (%d)\n", mixer_index);
|
||||
printf(" --------------------\n\n");
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_RES:
|
||||
printf(" Mixer Ranges Res (%d)\n", mixer_index);
|
||||
printf(" --------------------\n\n");
|
||||
break;
|
||||
default:
|
||||
return USB_MIXER_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" \t\t\t");
|
||||
printf("Mixer Outputs\n");
|
||||
printf("\t\t ");
|
||||
for (i = 0; i < num_outputs; i++) {
|
||||
printf(" %d", i+1);
|
||||
}
|
||||
printf("\n");
|
||||
for (i = 0; i < num_inputs; i++) {
|
||||
printf(" %-20s", usb_mixer_get_input_name(mixer_index,i));
|
||||
for (j = 0; j < num_outputs; j++) {
|
||||
switch (type) {
|
||||
case MIXER_UNIT_DISPLAY_VALUE:
|
||||
{
|
||||
double mixNodeVal = usb_mixer_get_value(mixer_index, (i*num_outputs)+j);
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
|
||||
if (mixNodeVal <= -127.996)// todo shoud be < min
|
||||
{
|
||||
printf("\t%3d:[ %s ]", nodeid,"-inf");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t%3d:[%08.03f]", nodeid, mixNodeVal);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MIN:
|
||||
{
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_min(mixer_index, (i*num_outputs)+j)) ;
|
||||
}
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MAX:
|
||||
{
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_max(mixer_index, (i*num_outputs)+j)) ;
|
||||
}
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_RES:
|
||||
{
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_res(mixer_index, (i*num_outputs)+j)) ;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return USB_MIXER_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
/* Displays basic mixer information */
|
||||
int mixer_display_info(void)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
int num_mixers = usb_mixer_get_num_mixers();
|
||||
|
||||
printf("\n");
|
||||
printf(" Mixer Info\n");
|
||||
printf(" ----------\n\n");
|
||||
printf(" Mixers : %d\n\n", num_mixers);
|
||||
|
||||
for (i = 0; i < num_mixers; i++)
|
||||
{
|
||||
int num_inputs = usb_mixer_get_num_inputs(i);
|
||||
int num_outputs = usb_mixer_get_num_outputs(i);
|
||||
|
||||
|
||||
printf(" Mixer %d\n", i);
|
||||
printf(" -------\n");
|
||||
|
||||
printf(" Inputs : %d\n"
|
||||
" Outputs : %d\n\n", num_inputs, num_outputs);
|
||||
|
||||
printf(" Mixer Output Labels:\n");
|
||||
for(int j = 0; j < num_outputs; j++)
|
||||
{
|
||||
printf(" %d: %s\n", j,usb_mixer_get_output_name(i,j));
|
||||
}
|
||||
|
||||
//printf("\n Selectable Inputs (%d): \n", usb_mixsel_get_input_count(i));
|
||||
//for(int j = 0; j < usb_mixsel_get_input_count(i); j++)
|
||||
//{
|
||||
// printf(" %d: %s\n", j, usb_mixsel_get_input_string(i,j));
|
||||
//}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
void display_available_mixer_sources(int mixIndex)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Available Mixer Sources (%d)\n", mixIndex);
|
||||
printf(" -------------------------\n\n");
|
||||
|
||||
for(int j = 0; j < usb_mixsel_get_input_count(mixIndex); j++)
|
||||
{
|
||||
printf(" %d: %s\n", j, usb_mixsel_get_input_string(mixIndex,j));
|
||||
}
|
||||
}
|
||||
|
||||
/* Gets the current mixer inputs from the device an displays them */
|
||||
void display_mixer_sources(int mixerIndex)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Current Mixer Sources (%d)\n", mixerIndex);
|
||||
printf(" -------------------------\n\n");
|
||||
|
||||
/* Note, mixSel output cound and mixer input chan count should be the same! */
|
||||
printf(" Number of mixer sources: %d\n", usb_mixsel_get_output_count(mixerIndex));
|
||||
|
||||
/* Get the current channel number for every mixer input */
|
||||
for(int i = 0; i < usb_mixsel_get_output_count(mixerIndex); i++)
|
||||
{
|
||||
int inputChan = (int)usb_mixsel_get_state(mixerIndex, i);
|
||||
char *str = usb_mixer_get_input_name(mixerIndex,inputChan);
|
||||
printf(" Mixer input %d: Source chan id: %d (%s)\n", i, inputChan, str);
|
||||
}
|
||||
}
|
||||
|
||||
/* set mixer source */
|
||||
void set_mixer_source(unsigned mixerIndex, unsigned dst, unsigned src)
|
||||
{
|
||||
usb_mixsel_set_state(mixerIndex, dst, src);
|
||||
|
||||
/* String lookup */
|
||||
char *str = usb_mixer_get_input_name(mixerIndex, dst);
|
||||
int state = usb_mixsel_get_state(mixerIndex, dst);
|
||||
|
||||
printf("\n Set mixer(%d) input %d to device input %d (%s)\n", mixerIndex, dst, state, str);
|
||||
}
|
||||
|
||||
void display_aud_channel_map()
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Audio Output Channel Map\n");
|
||||
printf(" ------------------------\n\n");
|
||||
|
||||
for (int i=0;i<usb_get_aud_channel_map_num_outputs();i++)
|
||||
{
|
||||
int x = usb_get_aud_channel_map(i);
|
||||
printf("%d (DEVICE OUT - %s) source is ",i, usb_get_aud_channel_map_name(i));
|
||||
|
||||
switch (usb_get_aud_channel_map_type(x))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf(" %d (DAW OUT - %s)\n",x,usb_get_aud_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",x,usb_get_aud_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",x,usb_get_aud_channel_map_name(x));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void display_daw_channel_map()
|
||||
{
|
||||
printf("\n");
|
||||
printf(" DAW Output To Host Channel Map\n");
|
||||
printf(" ------------------------\n\n");
|
||||
|
||||
for (int i=0;i<usb_get_usb_channel_map_num_outputs();i++)
|
||||
{
|
||||
int x = usb_get_usb_channel_map(i);
|
||||
printf("%d (DAW IN - %s) source is ",i, usb_get_usb_channel_map_name(i + usb_get_aud_channel_map_num_outputs()));
|
||||
|
||||
switch (usb_get_usb_channel_map_type(x))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf(" %d (DAW OUT - %s)\n",x,usb_get_usb_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",x,usb_get_usb_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",x,usb_get_usb_channel_map_name(x));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display_aud_channel_map_sources(void)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Audio Output Channel Map Source List\n");
|
||||
printf(" ------------------------------------\n\n");
|
||||
for (int i=0;i<usb_get_aud_channel_map_num_inputs();i++) {
|
||||
switch (usb_get_aud_channel_map_type(i))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf("%d (DAW OUT - %s)\n",i,usb_get_aud_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",i,usb_get_aud_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",i,usb_get_aud_channel_map_name(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display_daw_channel_map_sources(void)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" DAW Output to Host Channel Map Source List\n");
|
||||
printf(" ------------------------------------------\n\n");
|
||||
for (int i=0;i<usb_get_usb_channel_map_num_inputs();i++) {
|
||||
switch (usb_get_usb_channel_map_type(i))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf("%d (DAW OUT - %s)\n",i,usb_get_usb_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",i,usb_get_usb_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",i,usb_get_usb_channel_map_name(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int usb_audio_request_get(unsigned bRequest, unsigned cs, unsigned cn, unsigned unitId, unsigned char *data)
|
||||
{
|
||||
char reqStr[] = "Custom";
|
||||
|
||||
if(bRequest == CUR)
|
||||
{
|
||||
strcpy(reqStr, "CUR");
|
||||
}
|
||||
else if(bRequest == RANGE)
|
||||
{
|
||||
strcpy(reqStr, "RANGE");
|
||||
}
|
||||
else if(bRequest == MEM)
|
||||
{
|
||||
strcpy(reqStr, "MEM");
|
||||
}
|
||||
|
||||
printf("Performing class GET request to Audio Interface:\n\
|
||||
bRequest: 0x%02x (%s)\n\
|
||||
wValue: 0x%04x (Control Sel: %d, Channel Number: %d)\n\
|
||||
wIndex: 0x%04x (Interface: 0, Entity: %d)\n\
|
||||
\n", bRequest, reqStr, (cs<<8)|cn, cs, cn, unitId<<8, unitId);
|
||||
|
||||
return usb_audio_class_get(bRequest, cs, cn, unitId, 64, data);
|
||||
}
|
||||
|
||||
int usb_audio_request_set(unsigned bRequest, unsigned cs, unsigned cn, unsigned unitId,
|
||||
unsigned char *data, int datalength)
|
||||
{
|
||||
char reqStr[] = "Custom";
|
||||
|
||||
if(bRequest == CUR)
|
||||
{
|
||||
strcpy(reqStr, "CUR");
|
||||
}
|
||||
else if(bRequest == RANGE)
|
||||
{
|
||||
strcpy(reqStr, "RANGE");
|
||||
}
|
||||
{
|
||||
strcpy(reqStr, "MEM");
|
||||
}
|
||||
|
||||
printf("Performing class SET request to Audio Interface:\n\
|
||||
bRequest: 0x%02x (%s)\n\
|
||||
wValue: 0x%04x (Control Sel: %d, Channel Number: %d)\n\
|
||||
wIndex: 0x%04x (Interface: 0, Entity: %d)\n\
|
||||
\n", bRequest, reqStr, (cs<<8)|cn, cs, cn, unitId<<8, unitId);
|
||||
|
||||
return usb_audio_class_set(bRequest, cs, cn, unitId, datalength, data);
|
||||
}
|
||||
|
||||
|
||||
int usb_audio_memreq_get(unsigned unitId, unsigned offset, unsigned char *data)
|
||||
{
|
||||
/* Mem requests dont have CS/CN, just an offset.. */
|
||||
return usb_audio_request_get(MEM, (offset>>8), offset&0xff, unitId, data);
|
||||
}
|
||||
|
||||
void print_levels(const char* levelTitle, unsigned char* levels, int levelBytes)
|
||||
{
|
||||
unsigned levelCount = levelBytes/2;
|
||||
unsigned short* levelData = (unsigned short*) levels;
|
||||
|
||||
printf("\n %s Level Data\n"
|
||||
" ----------------------\n\n"
|
||||
"%d bytes (%d channels) returned:\n"
|
||||
, levelTitle, levelBytes, levelCount);
|
||||
|
||||
for(int i = 0; i<levelCount; i++)
|
||||
{
|
||||
printf("%s %d: 0x%04x\n", levelTitle, i,levelData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mixer_display_usage(void) {
|
||||
fprintf(stderr, "Usage :\n");
|
||||
fprintf(stderr,
|
||||
" --display-info\n"
|
||||
" --display-mixer-nodes mixer_id\n"
|
||||
" --display-min mixer_id\n"
|
||||
" --display-max mixer_id\n"
|
||||
" --display-res mixer_id\n"
|
||||
" --set-value mixer_id, mixer_node, value\n"
|
||||
" --get-value mixer_id, mixer_node\n"
|
||||
"\n"
|
||||
" --set-mixer-source mixer_id dst channel_id, src_channel_id\n"
|
||||
" --display-current-mixer-sources mixer_id\n"
|
||||
" --display-available-mixer-sources mixer_id\n"
|
||||
"\n"
|
||||
" --set-aud-channel-map dst_channel_id, src_channel_id\n"
|
||||
" --display-aud-channel-map \n"
|
||||
" --display-aud-channel-map-sources\n"
|
||||
" --set-daw-channel-map dst_channel_id, src_channel_id\n"
|
||||
" --display-daw-channel-map \n"
|
||||
" --display-daw-channel-map-sources\n"
|
||||
"\n"
|
||||
" --get-mixer-levels-input mixer_id\n"
|
||||
" --get-mixer-levels-output mixer_id\n"
|
||||
" --vendor-audio-request-get bRequest, ControlSelector, ChannelNumber, UnitId\n"
|
||||
" --vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],...\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void usage_error()
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed. See --help\n");
|
||||
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
|
||||
unsigned int mixer_index = 0;
|
||||
unsigned int result = 0;
|
||||
|
||||
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "ERROR :: No options passed to mixer application\n");
|
||||
mixer_display_usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "--help") == 0) {
|
||||
mixer_display_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mixer_init() != USB_MIXER_SUCCESS) {
|
||||
fprintf(stderr, "ERROR :: Cannot connect\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "--display-info") == 0)
|
||||
{
|
||||
mixer_display_info();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-mixer-nodes") == 0)
|
||||
{
|
||||
if (argv[2])
|
||||
{
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
||||
} else if (strcmp(argv[1], "--display-mixer-nodes") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
||||
} else if (strcmp(argv[1], "--display-min") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MIN);
|
||||
} else if (strcmp(argv[1], "--display-max") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MAX);
|
||||
} else if (strcmp(argv[1], "--display-res") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_RES);
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-value") == 0) {
|
||||
unsigned int mixer_unit = 0;
|
||||
double value = 0;
|
||||
if (argc < 5) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_index = atoi(argv[2]);
|
||||
mixer_unit = atoi(argv[3]);
|
||||
if (strcmp(argv[4],"-inf")==0)
|
||||
value = -128;
|
||||
else
|
||||
value = atof(argv[4]);
|
||||
|
||||
usb_mixer_set_value(mixer_index, mixer_unit, value);
|
||||
} else if (strcmp(argv[1], "--get-value") == 0) {
|
||||
unsigned int mixer_unit = 0;
|
||||
double result = 0;
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_index = atoi(argv[2]);
|
||||
mixer_unit = atoi(argv[3]);
|
||||
|
||||
result = usb_mixer_get_value(mixer_index, mixer_unit);
|
||||
if (result <= -127.996)
|
||||
printf("%s\n", "-inf");
|
||||
else
|
||||
printf("%g\n",result);
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-current-mixer-sources") == 0)
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
display_mixer_sources(atoi(argv[2]));
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-available-mixer-sources") == 0)
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
display_available_mixer_sources(atoi(argv[2]));
|
||||
}
|
||||
else if(strcmp(argv[1], "--set-mixer-source") == 0)
|
||||
{
|
||||
if(argc < 5)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
set_mixer_source(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-aud-channel-map") == 0)
|
||||
{
|
||||
/* Display the channel mapping to the devices audio outputs */
|
||||
display_aud_channel_map();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-aud-channel-map-sources") == 0)
|
||||
{
|
||||
display_aud_channel_map_sources();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-daw-channel-map") == 0)
|
||||
{
|
||||
/* Display the channel mapping to the devices DAW output to host */
|
||||
display_daw_channel_map();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-daw-channel-map-sources") == 0)
|
||||
{
|
||||
display_daw_channel_map_sources();
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-aud-channel-map") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned int src = 0;
|
||||
if (argc != 4)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
dst = atoi(argv[2]);
|
||||
src = atoi(argv[3]);
|
||||
|
||||
usb_set_aud_channel_map(dst, src);
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-daw-channel-map") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned int src = 0;
|
||||
if (argc != 4)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
dst = atoi(argv[2]);
|
||||
src = atoi(argv[3]);
|
||||
|
||||
usb_set_usb_channel_map(dst, src);
|
||||
}
|
||||
else if(strcmp(argv[1], "--get-mixer-levels-input") == 0 ||
|
||||
strcmp(argv[1],"--get-mixer-levels-output") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned char levels[64];
|
||||
int datalength = 0;
|
||||
int offset = 0;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strcmp(argv[1],"--get-mixer-levels-output") == 0)
|
||||
offset = 1;
|
||||
|
||||
for(int i = 0; i < 64; i++)
|
||||
levels[i] = 0;
|
||||
|
||||
dst = atoi(argv[2]);
|
||||
|
||||
/* Mem request to mixer with offset of 0 gives input levels */
|
||||
datalength = usb_mixer_mem_get(dst, offset, levels);
|
||||
|
||||
if(datalength < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR in control request: %d\n", datalength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(offset)
|
||||
print_levels("Mixer Output", levels, datalength);
|
||||
else
|
||||
print_levels("Mixer Input", levels, datalength);
|
||||
|
||||
}
|
||||
else if(strcmp(argv[1], "--vendor-audio-request-get") == 0)
|
||||
{
|
||||
unsigned int bRequest = 0;
|
||||
unsigned int cs = 0;
|
||||
unsigned int cn = 0;
|
||||
unsigned int unitId = 0;
|
||||
int datalength = 0;
|
||||
unsigned char data[64];
|
||||
|
||||
if(argc < 6)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 64; i++)
|
||||
data[i] = 0;
|
||||
|
||||
bRequest = atoi(argv[2]);
|
||||
cs = atoi(argv[3]);
|
||||
cn = atoi(argv[4]);
|
||||
unitId = atoi(argv[5]);
|
||||
|
||||
/* Do request */
|
||||
datalength = usb_audio_request_get(bRequest, cs, cn, unitId, data);
|
||||
|
||||
/* Print result */
|
||||
if(datalength < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR in control request: %d\n", datalength);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Response (%d bytes):\n", datalength);
|
||||
for(int i = 0; i < datalength; i++)
|
||||
printf("0x%02x\n" ,data[i]);
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1], "--vendor-audio-request-set") == 0)
|
||||
{
|
||||
|
||||
unsigned int bRequest = 0;
|
||||
unsigned int cs = 0;
|
||||
unsigned int cn = 0;
|
||||
unsigned int unitId = 0;
|
||||
unsigned char data[64];
|
||||
|
||||
for(int i=0; i<64; i++)
|
||||
{
|
||||
data[i] = 0;
|
||||
}
|
||||
|
||||
if(argc < 7)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed - no data passed\n");
|
||||
return -1;
|
||||
}
|
||||
bRequest = atoi(argv[2]);
|
||||
cs = atoi(argv[3]);
|
||||
cn = atoi(argv[4]);
|
||||
unitId = atoi(argv[5]);
|
||||
|
||||
/* Get data */
|
||||
for(int i=0; i < argc-6; i++)
|
||||
{
|
||||
data[i] = atoi(argv[i+6]);
|
||||
}
|
||||
|
||||
result = usb_audio_request_set(bRequest, cs, cn, unitId, data, argc-6);
|
||||
|
||||
if(result < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: Error detected in Set request: %d\n", result);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR :: Invalid option passed to mixer application\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_deinit();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
1
host_usb_mixer_control/setup.sh
Normal file
1
host_usb_mixer_control/setup.sh
Normal file
@@ -0,0 +1 @@
|
||||
export DYLD_LIBRARY_PATH=$PWD/OSX:$DYLD_LIBRARY_PATH
|
||||
1042
host_usb_mixer_control/usb_mixer.cpp
Normal file
1042
host_usb_mixer_control/usb_mixer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
108
host_usb_mixer_control/usb_mixer.h
Normal file
108
host_usb_mixer_control/usb_mixer.h
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#define USB_MIXER_SUCCESS 0
|
||||
#define USB_MIXER_FAILURE -1
|
||||
|
||||
#define USB_MIXERS 1
|
||||
#define USB_MIXER_INPUTS 18
|
||||
#define USB_MIXER_OUTPUTS 8
|
||||
#define USB_MAX_CHANNEL_MAP_SIZE 40
|
||||
#define USB_MIXER_MAX_NAME_LEN 64
|
||||
|
||||
enum usb_chan_type {
|
||||
USB_CHAN_OUT=0,
|
||||
USB_CHAN_IN=1,
|
||||
USB_CHAN_MIXER=2
|
||||
};
|
||||
|
||||
/* A.14 Audio Class-Specific Request Codes */
|
||||
#define REQUEST_CODE_UNDEFINED 0x00
|
||||
#define CUR (1)
|
||||
#define RANGE (2)
|
||||
#define MEM (3)
|
||||
|
||||
int usb_mixer_connect();
|
||||
int usb_mixer_disconnect();
|
||||
|
||||
/* MIXER UNIT(s) INTERFACE */
|
||||
|
||||
/* Returns total number of mixers in device */
|
||||
int usb_mixer_get_num_mixers();
|
||||
|
||||
/* Returns number of inputs and outputs for a selected mixer */
|
||||
int usb_mixer_get_layout(unsigned int mixer, unsigned int *inputs, unsigned int *outputs);
|
||||
|
||||
/* Returns the name for a selected mixer input */
|
||||
char *usb_mixer_get_input_name(unsigned int mixer, unsigned int input);
|
||||
|
||||
/* Returns the name for a selected mixer output */
|
||||
char *usb_mixer_get_output_name(unsigned int mixer, unsigned int output);
|
||||
|
||||
/* Returns the current value of a selected mixer unit */
|
||||
double usb_mixer_get_value(unsigned int mixer, unsigned int mixer_unit);
|
||||
|
||||
/* Sets the current value for a selected mixer unit */
|
||||
int usb_mixer_set_value(unsigned int mixer, unsigned int mixer_unit, double val);
|
||||
|
||||
/* Returns the range values for a selected mixer unit */
|
||||
int usb_mixer_get_range(unsigned int mixer, unsigned int mixer_unit, double *min, double *max, double *res);
|
||||
|
||||
/* Returns the number of bytes read from a mem request, data is stored in data */
|
||||
int usb_mixer_mem_get(unsigned int mixer, unsigned offset, unsigned char *data);
|
||||
|
||||
|
||||
/* INPUT / OUTPUT / MIXER MAPPING UNIT INTERFACE */
|
||||
|
||||
/* Get the number of selectable inputs */
|
||||
int usb_mixsel_get_input_count(unsigned int mixer);
|
||||
|
||||
/* Get the string of a input */
|
||||
char *usb_mixsel_get_input_string(unsigned int mixer, unsigned int channel);
|
||||
|
||||
int usb_mixsel_get_output_count(unsigned int mixer);
|
||||
|
||||
int usb_mixer_get_num_outputs(unsigned int mixer);
|
||||
|
||||
int usb_mixer_get_num_inputs(unsigned int mixer);
|
||||
|
||||
unsigned char usb_mixsel_get_state(unsigned int mixer, unsigned int channel);
|
||||
|
||||
void usb_mixsel_set_state(unsigned int mixer, unsigned int dst, unsigned int src);
|
||||
|
||||
int usb_set_usb_channel_map(int channel, int val);
|
||||
|
||||
|
||||
/* Get the current map for a specified input / output / mixer channel */
|
||||
int usb_get_usb_channel_map(int channel);
|
||||
int usb_get_aud_channel_map(int channel);
|
||||
|
||||
/* Maps an input / output / mixer channel to another input / output / mixer channel */
|
||||
int usb_set_aud_channel_map(int channel, int val);
|
||||
int usb_set_usb_channel_map(int channel, int val);
|
||||
|
||||
/* Gets the name of a specified channel */
|
||||
char *usb_get_aud_channel_map_name(int channel);
|
||||
char *usb_get_usb_channel_map_name(int channel);
|
||||
|
||||
/* Get the type of a channel map */
|
||||
enum usb_chan_type usb_get_aud_channel_map_type(int channel);
|
||||
enum usb_chan_type usb_get_usb_channel_map_type(int channel);
|
||||
|
||||
int usb_get_aud_channel_map_num_outputs();
|
||||
int usb_get_usb_channel_map_num_outputs();
|
||||
|
||||
int usb_get_aud_channel_map_num_inputs();
|
||||
int usb_get_usb_channel_map_num_inputs();
|
||||
|
||||
/* CUSTOM/GENERIC AUDIO CLASS REQUESTS */
|
||||
|
||||
int usb_audio_class_get(unsigned char bRequest, unsigned char cs, unsigned char cn, unsigned short unitID, unsigned short wLength, unsigned char *data);
|
||||
|
||||
int usb_audio_class_set(unsigned char bRequest, unsigned char cs, unsigned char cn, unsigned short unitID, unsigned short wLength, unsigned char *data);
|
||||
|
||||
double usb_mixer_get_res(unsigned int mixer, unsigned int nodeId);
|
||||
|
||||
double usb_mixer_get_min(unsigned int mixer, unsigned int nodeId) ;
|
||||
|
||||
double usb_mixer_get_max(unsigned int mixer, unsigned int nodeId) ;
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2022 XMOS LIMITED.
|
||||
// Copyright 2017-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_H_
|
||||
#define _XUA_H_
|
||||
@@ -7,14 +7,14 @@
|
||||
|
||||
#include "xua_conf_full.h"
|
||||
|
||||
#if __XC__ || __STDC__
|
||||
#ifndef __ASSEMBLER__
|
||||
#include "xua_audiohub.h"
|
||||
#include "xua_endpoint0.h"
|
||||
#include "xua_buffer.h"
|
||||
#include "xua_mixer.h"
|
||||
#endif
|
||||
|
||||
#if __XC__
|
||||
#ifdef __XC__
|
||||
#include "xua_clocking.h"
|
||||
#include "xua_midi.h"
|
||||
#if XUA_NUM_PDM_MICS > 0
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef __XUA_AUDIOHUB_H__
|
||||
#define __XUA_AUDIOHUB_H__
|
||||
#ifndef _XUA_AUDIOHUB_H_
|
||||
#define _XUA_AUDIOHUB_H_
|
||||
|
||||
#if __XC__
|
||||
#ifdef __XC__
|
||||
|
||||
#include "xccompat.h"
|
||||
#include "xs1.h"
|
||||
@@ -80,4 +80,4 @@ void UserBufferManagementInit();
|
||||
|
||||
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
|
||||
|
||||
#endif // __XUA_AUDIOHUB_H__
|
||||
#endif // _XUA_AUDIOHUB_H_
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2022 XMOS LIMITED.
|
||||
// Copyright 2017-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef __XUA_CONF_FULL_H__
|
||||
#define __XUA_CONF_FULL_H__
|
||||
#ifndef _XUA_CONF_FULL_H_
|
||||
#define _XUA_CONF_FULL_H_
|
||||
|
||||
#ifdef __xua_conf_h_exists__
|
||||
#include "xua_conf.h"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_MIXER_H_
|
||||
#define _XUA_MIXER_H_
|
||||
|
||||
#include "xua.h"
|
||||
|
||||
enum mix_ctl_cmd {
|
||||
SET_SAMPLES_TO_HOST_MAP,
|
||||
SET_SAMPLES_TO_DEVICE_MAP,
|
||||
@@ -31,4 +33,14 @@ enum mix_ctl_cmd {
|
||||
*/
|
||||
void mixer(chanend c_to_host, chanend c_to_audio, chanend c_mix_ctl);
|
||||
|
||||
#define XUA_MIXER_OFFSET_OUT (0)
|
||||
#define XUA_MIXER_OFFSET_IN (NUM_USB_CHAN_OUT)
|
||||
#define XUA_MIXER_OFFSET_MIX (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN)
|
||||
#define XUA_MIXER_OFFSET_OFF (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT)
|
||||
|
||||
/* Defines uses for DB to actual muliplier conversion */
|
||||
#define XUA_MIXER_MULT_FRAC_BITS (25)
|
||||
#define XUA_MIXER_DB_FRAC_BITS (8)
|
||||
#define XUA_MIXER_MAX_MULT (1<<XUA_MIXER_MULT_FRAC_BITS) /* i.e. multiply by 0 */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
^^^^
|
||||
|
||||
|
||||
@@ -20,11 +20,11 @@ Finally, a channel for the output samples must be declared, note, this should be
|
||||
|
||||
The S/PDIF receiver should be called on the appropriate tile::
|
||||
|
||||
SpdifReceive(p_spdif_rx, c_spdif_rx, 1, clk_spd_rx);
|
||||
spdif_rx(c_spdif_rx,p_spdif_rx,clk_spd_rx,192000);
|
||||
|
||||
.. note::
|
||||
|
||||
It is recomended to use the value 1 for the ``initial_divider`` parameter
|
||||
It is recomended to use the value 192000 for the ``sample_freq_estimate`` parameter
|
||||
|
||||
With the steps above an S/PDIF stream can be captured by the xCORE. To be functionally useful the audio
|
||||
master clock must be able to synchronise to this external digital stream. Additionally, the host can be
|
||||
|
||||
@@ -23,11 +23,14 @@ The defines in :ref:`opt_i2s_defines` effect the I2S implementation.
|
||||
- The desired number of input channels via I2S (0 for disabled)
|
||||
- N/A (Must be defined)
|
||||
* - ``XUA_PCM_FORMAT``
|
||||
- Enabled either TDM or I2S mode
|
||||
- Enables either TDM or I2S mode
|
||||
- ``XUA_PCM_FORMAT_I2S``
|
||||
* - ``CODEC_MASTER``
|
||||
- Sets is xCORE is I2S master or slave
|
||||
- Sets if xCORE is I2S master or slave
|
||||
- ``0`` (xCORE is master)
|
||||
* - ``XUA_I2S_N_BITS``
|
||||
- I2S/TDM word length (16, 32-bit supported)
|
||||
- ``32``
|
||||
|
||||
The I2S code expects that the ports required for I2S (master clock, LR-clock, bit-clock and data lines) are be defined in the application XN file in the relevant `Tile``.
|
||||
For example::
|
||||
@@ -42,8 +45,16 @@ For example::
|
||||
<Port Location="XS1_PORT_1G" Name="PORT_I2S_ADC1"/>
|
||||
</Tile>
|
||||
|
||||
All of the I2S related ports must be 1-bit ports.
|
||||
All of the I2S/TDM related ports must be 1-bit ports.
|
||||
|
||||
.. note::
|
||||
|
||||
TDM mode allows 8 channels (rather than 2) to be supplied on each dataline.
|
||||
TDM mode allows 8 channels (rather than 2) to be supplied on each data-line.
|
||||
|
||||
.. note::
|
||||
|
||||
Data output/input is in "I2S" format, rather than, say "left-justified" or "right-justified" formats.
|
||||
I2S format specifies a single bit-clock delay after the LR-clock transition before sample-data is driven/received.
|
||||
This also applies to TDM mode. TDM support in ADC/DAC hardware is quite varied, an "offset" value may need to be programmed into
|
||||
the external device for compatible operation.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ full listing of these ``TILE`` defines.
|
||||
- Description
|
||||
- Default
|
||||
* - ``AUDIO_IO_TILE``
|
||||
- Tile on which I2S, ADAT Rx, S/PDIF Rx & mixer resides
|
||||
- Tile on which I2S/TDM, ADAT Rx, S/PDIF Rx & mixer resides
|
||||
- ``0``
|
||||
* - ``XUD_TILE``
|
||||
- Tile on which USB resides, including buffering for all USB interfaces/endppoints
|
||||
|
||||
@@ -25,7 +25,7 @@ Overview
|
||||
| +---------------------------------------------------------------------------------------------+
|
||||
| | `USB Midi Device Class 1.0 <http://www.usb.org/developers/devclass_docs/midi10.pdf>`_ |
|
||||
+---------------------------------+---------------------------------------------------------------------------------------------+
|
||||
| Audio | I2S/TDM |
|
||||
| Audio | I2S/TDM (16/32-bit) |
|
||||
| +---------------------------------------------------------------------------------------------+
|
||||
| | S/PDIF |
|
||||
| +---------------------------------------------------------------------------------------------+
|
||||
|
||||
@@ -87,6 +87,9 @@ intended as an example of how you might add mixer control to your own control ap
|
||||
intended to be exposed to end users.
|
||||
|
||||
For details, consult the README file in the host_usb_mixer_control directory.
|
||||
A list of arguments can also be seen with::
|
||||
|
||||
$ ./xmos_mixer --help
|
||||
|
||||
The main requirements of this control utility are to
|
||||
|
||||
@@ -102,78 +105,147 @@ The main requirements of this control utility are to
|
||||
functionality to their end users.
|
||||
|
||||
Whilst using the XMOS Host control example application, consider the example of setting the
|
||||
mixer to perform a loop-back from analogue inputs 1 and 2 to analogue outputs 1 and 2.
|
||||
mixer to perform a loop-back from analogue inputs 1 & 2 to analogue outputs 1 & 2.
|
||||
|
||||
Firstly consider the inputs to the mixer. The following will displays which channels are mapped
|
||||
to which mixer inputs::
|
||||
.. note::
|
||||
|
||||
./xmos_mixer --display-aud-channel-map 0
|
||||
The command outputs shown are examples; the actual output will depend on the mixer configuration.
|
||||
|
||||
The following command will displays which channels could possibly be mapped to mixer inputs. Notice
|
||||
that analogue inputs 1 and 2 are on mixer inputs 10 and 11::
|
||||
The following will show the index for each device output along with which channel is currently mapped to it.
|
||||
In this example the analogue outputs 1 & 2 are 0 & 1 respectively::
|
||||
|
||||
./xmos_mixer --display-aud-channel-map-sources 0
|
||||
$ ./xmos_mixer --display-aud-channel-map
|
||||
|
||||
Now examine the audio output mapping using the following command::
|
||||
Audio Output Channel Map
|
||||
------------------------
|
||||
|
||||
0 (DEVICE OUT - Analogue 1) source is 0 (DAW OUT - Analogue 1)
|
||||
1 (DEVICE OUT - Analogue 2) source is 1 (DAW OUT - Analogue 2)
|
||||
2 (DEVICE OUT - SPDIF 1) source is 2 (DAW OUT - SPDIF 1)
|
||||
3 (DEVICE OUT - SPDIF 2) source is 3 (DAW OUT - SPDIF 2)
|
||||
$ _
|
||||
|
||||
./xmos_mixer --display-aud-channel-map 0
|
||||
The DAW Output Map can be seen with::
|
||||
|
||||
This displays which channels are mapped to which outputs. By default all
|
||||
of these bypass the mixer. We can also see what all the possible
|
||||
mappings are with the following command::
|
||||
$ ./xmos_mixer --display-daw-channel-map
|
||||
|
||||
./xmos_mixer --display-aud-channel-map-sources 0
|
||||
DAW Output To Host Channel Map
|
||||
------------------------
|
||||
|
||||
0 (DEVICE IN - Analogue 1) source is 4 (DEVICE IN - Analogue 1)
|
||||
1 (DEVICE IN - Analogue 2) source is 5 (DEVICE IN - Analogue 2)
|
||||
$ _
|
||||
|
||||
We will now map the first two mixer outputs to physical outputs 1 and 2::
|
||||
.. note::
|
||||
|
||||
./xmos_mixer --set-aud-channel-map 0 26
|
||||
./xmos_mixer --set-aud-channel-map 1 27
|
||||
In both cases, by default, these bypass the mixer.
|
||||
|
||||
The following command will list the channels which can be mapped to the device outputs from the
|
||||
Audio Output Channel Map. Note that, in this example, analogue inputs 1 & 2 are source 4 & 5 and
|
||||
Mix 1 & 2 are source 6 & 7::
|
||||
|
||||
$ ./xmos_mixer --display-aud-channel-map-sources
|
||||
|
||||
Audio Output Channel Map Source List
|
||||
------------------------------------
|
||||
|
||||
0 (DAW OUT - Analogue 1)
|
||||
1 (DAW OUT - Analogue 2)
|
||||
2 (DAW OUT - SPDIF 1)
|
||||
3 (DAW OUT - SPDIF 2)
|
||||
4 (DEVICE IN - Analogue 1)
|
||||
5 (DEVICE IN - Analogue 2)
|
||||
6 (MIX - Mix 1)
|
||||
7 (MIX - Mix 2)
|
||||
$ _
|
||||
|
||||
Using the indices from the previous commands, we will now re-map the first two mixer channels (Mix 1 & Mix 2) to device outputs 1 & 2::
|
||||
|
||||
$ ./xmos_mixer --set-aud-channel-map 0 6
|
||||
$ ./xmos_mixer --set-aud-channel-map 1 7
|
||||
$ _
|
||||
|
||||
You can confirm the effect of this by re-checking the map::
|
||||
|
||||
./xmos_mixer --display-aud-channel-map 0
|
||||
$ ./xmos_mixer --display-aud-channel-map
|
||||
|
||||
This now derives analogue outputs 1 and 2 from the mixer, rather than directly from USB. However,
|
||||
since the mixer is still mapped to pass the USB channels through to the outputs there will be no
|
||||
Audio Output Channel Map
|
||||
------------------------
|
||||
|
||||
0 (DEVICE OUT - Analogue 1) source is 6 (MIX - Mix 1)
|
||||
1 (DEVICE OUT - Analogue 2) source is 7 (MIX - Mix 2)
|
||||
2 (DEVICE OUT - SPDIF 1) source is 2 (DAW OUT - SPDIF 1)
|
||||
3 (DEVICE OUT - SPDIF 2) source is 3 (DAW OUT - SPDIF 2)
|
||||
$ _
|
||||
|
||||
This now derives analogue outputs 1 & 2 from the mixer, rather than directly from USB. However,
|
||||
since the mixer is mapped, by default, to just pass the USB channels through to the outputs there will be no
|
||||
functional change.
|
||||
|
||||
The mixer nodes need to be individually set. They can be displayed
|
||||
|
||||
.. note::
|
||||
|
||||
The USB audio reference design has only one unit so the mixer_id argument should always be 0.
|
||||
|
||||
The mixer nodes need to be individually set. The nodes in mixer_id 0 can be displayed
|
||||
with the following command::
|
||||
|
||||
./xmos_mixer --display-mixer-nodes 0
|
||||
$ ./xmos_mixer --display-mixer-nodes 0
|
||||
|
||||
To get the audio from the analogue inputs to outputs 1 and 2, nodes 80
|
||||
and 89 need to be set::
|
||||
Mixer Values (0)
|
||||
----------------
|
||||
|
||||
./xmos_mixer --set-value 0 80 0
|
||||
./xmos_mixer --set-value 0 89 0
|
||||
Mixer outputs
|
||||
1 2
|
||||
DAW - Analogue 1 0:[0000.000] 1:[ -inf ]
|
||||
DAW - Analogue 2 2:[ -inf ] 3:[0000.000]
|
||||
DAW - SPDIF 1 4:[ -inf ] 5:[ -inf ]
|
||||
DAW - SPDIF 2 6:[ -inf ] 7:[ -inf ]
|
||||
AUD - Analogue 1 8:[ -inf ] 9:[ -inf ]
|
||||
AUD - Analogue 2 10:[ -inf ] 11:[ -inf ]
|
||||
$ _
|
||||
|
||||
With mixer outputs 1 & 2 mapped to device outputs analogue 1 & 2; to get the audio from the analogue inputs to device
|
||||
outputs mixer_id 0 node 8 and node 11 need to be set to 0db::
|
||||
|
||||
$ ./xmos_mixer --set-value 0 8 0
|
||||
$ ./xmos_mixer --set-value 0 11 0
|
||||
$ _
|
||||
|
||||
At the same time, the original mixer outputs can be muted::
|
||||
|
||||
./xmos_mixer --set-value 0 0 -inf
|
||||
./xmos_mixer --set-value 0 9 -inf
|
||||
$ ./xmos_mixer --set-value 0 0 -inf
|
||||
$ ./xmos_mixer --set-value 0 3 -inf
|
||||
$ _
|
||||
|
||||
Now audio inputs on analogue 1/2 should be heard on outputs 1/2.
|
||||
Now audio inputs on analogue 1 and 2 should be heard on outputs 1 and 2 respectively.
|
||||
|
||||
As mentioned above, the flexibility of the mixer is such that there will be multiple ways to create
|
||||
a particular mix. Another option to create the same routing would be to change the mixer sources
|
||||
such that mixer 1/2 outputs come from the analogue inputs.
|
||||
such that mixer outputs 1 and 2 come from the analogue inputs 1 and 2.
|
||||
|
||||
To demonstrate this, firstly undo the changes above (or simply reset the device)::
|
||||
|
||||
./xmos_mixer --set-value 0 80 -inf
|
||||
./xmos_mixer --set-value 0 89 -inf
|
||||
./xmos_mixer --set-value 0 0 0
|
||||
./xmos_mixer --set-value 0 9 0
|
||||
$ ./xmos_mixer --set-value 0 8 -inf
|
||||
$ ./xmos_mixer --set-value 0 11 -inf
|
||||
$ ./xmos_mixer --set-value 0 0 0
|
||||
$ ./xmos_mixer --set-value 0 3 0
|
||||
$ _
|
||||
|
||||
The mixer should now have the default values. The sources for mixer 1/2 can now be changed::
|
||||
The mixer should now have the default values. The sources for mixer 0 output 1 and 2 can now be changed
|
||||
using indices from the Audio Output Channel Map Source List::
|
||||
|
||||
./xmos_mixer --set-mixer-source 0 0 10
|
||||
./xmos_mixer --set-mixer-source 0 1 11
|
||||
$ ./xmos_mixer --set-mixer-source 0 0 4
|
||||
|
||||
Set mixer(0) input 0 to device input 4 (AUD - Analogue 1)
|
||||
$ ./xmos_mixer --set-mixer-source 0 1 5
|
||||
|
||||
Set mixer(0) input 1 to device input 5 (AUD - Analogue 2)
|
||||
$ _
|
||||
|
||||
If you re-run the following command then the first column now has "AUD - Analogue 1 and 2" rather
|
||||
than "DAW (Digital Audio Workstation i.e. the host) - Analogue 1 and 2" confirming the new mapping.
|
||||
Again, by playing audio into analogue inputs 1/2 this can be heard looped through to analogue outputs 1/2::
|
||||
|
||||
./xmos_mixer --display-mixer-nodes 0
|
||||
$ ./xmos_mixer --display-mixer-nodes 0
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ I2S/TDM
|
||||
|
||||
I2S/TDM is typically fundamental to most products and is built into the ``XUA_AudioHub()`` core.
|
||||
|
||||
In order to enable I2S on must declare an array of ports for the data-lines (one for each direction)::
|
||||
In order to enable I2S/TDM on must declare an array of ports for the data-lines (one for each direction)::
|
||||
|
||||
/* Port declarations. Note, the defines come from the XN file */
|
||||
buffered out port:32 p_i2s_dac[] = {PORT_I2S_DAC0}; /* I2S Data-line(s) */
|
||||
@@ -22,7 +22,7 @@ Ports for the sample and bit clocks are also required::
|
||||
|
||||
These ports must then be passed to the ``XUA_AudioHub()`` task appropriately.
|
||||
|
||||
I2S functionality also requires two clock-blocks, one for bit and sample clock e.g.::
|
||||
I2S/TDM functionality also requires two clock-blocks, one for bit-clock and another for the master clock e.g.::
|
||||
|
||||
/* Clock-block declarations */
|
||||
clock clk_audio_bclk = on tile[0]: XS1_CLKBLK_4; /* Bit clock */
|
||||
|
||||
@@ -1,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 \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2018-2022 XMOS LIMITED.
|
||||
// Copyright 2018-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#if (DSD_CHANS_DAC != 0)
|
||||
@@ -52,7 +52,7 @@ static inline void DoDsdDop(int &everyOther, unsigned samplesOut[], unsigned &ds
|
||||
/* When DSD is enabled and streaming is standard PCM, this function checks for a series of DoP markers in the upper byte.
|
||||
If found it will exit deliver() with the command to restart in DoP mode.
|
||||
When in DoP mode, this function will check for a single absence of the DoP marker and exit deliver() with the command
|
||||
to restart in I2S mode. */
|
||||
to restart in I2S/PCM mode. */
|
||||
static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSamFreq, unsigned samplesOut[], unsigned &dsdMarker)
|
||||
{
|
||||
/* Check for DSD - note we only move into DoP mode if valid DoP Freq */
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2018-2022 XMOS LIMITED.
|
||||
// Copyright 2018-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include "xua.h"
|
||||
|
||||
#include "dsd_support.h"
|
||||
|
||||
#if (DSD_CHANS_DAC != 0)
|
||||
@@ -12,7 +11,7 @@ extern buffered out port:32 p_dsd_clk;
|
||||
extern unsigned dsdMode;
|
||||
|
||||
#if !CODEC_MASTER
|
||||
void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
|
||||
void InitPorts_master(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
|
||||
{
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
if(dsdMode == DSD_MODE_OFF)
|
||||
@@ -38,9 +37,13 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma xta endpoint "divide_1"
|
||||
unsigned tmp;
|
||||
p_lrclk <: 0 @ tmp;
|
||||
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_lrclk <: 0 @ tmp;
|
||||
else
|
||||
tmp = partout_timestamped(p_lrclk, XUA_I2S_N_BITS, 0);
|
||||
|
||||
tmp += 100;
|
||||
|
||||
/* Since BCLK is free-running, setup outputs/inputs at a known point in the future */
|
||||
@@ -48,19 +51,30 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
p_i2s_dac[i] @ tmp <: 0;
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_i2s_dac[i] @ tmp <: 0;
|
||||
else
|
||||
partout_timed(p_i2s_dac[i], XUA_I2S_N_BITS, 0, tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned lrClkVal = 0x7FFFFFFF;
|
||||
if(XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
|
||||
p_lrclk @ tmp <: 0x80000000;
|
||||
{
|
||||
lrClkVal = 0x80000000;
|
||||
}
|
||||
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_lrclk @ tmp <: lrClkVal;
|
||||
else
|
||||
p_lrclk @ tmp <: 0x7FFFFFFF;
|
||||
partout_timed(p_lrclk, XUA_I2S_N_BITS, lrClkVal, tmp);
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
|
||||
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
set_port_shift_count(p_i2s_adc[i], XUA_I2S_N_BITS);
|
||||
}
|
||||
#endif
|
||||
#endif /* (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) */
|
||||
@@ -76,7 +90,7 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
|
||||
void InitPorts_slave(buffered _XUA_CLK_DIR port:32 p_lrclk, buffered _XUA_CLK_DIR port:32 p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC])
|
||||
{
|
||||
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||
unsigned tmp;
|
||||
@@ -93,7 +107,7 @@ void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buf
|
||||
p_lrclk when pinseq(0) :> void @ tmp;
|
||||
#endif
|
||||
|
||||
tmp += (I2S_CHANS_PER_FRAME * 32) - 32 + 1 ;
|
||||
tmp += ((I2S_CHANS_PER_FRAME * XUA_I2S_N_BITS) - XUA_I2S_N_BITS + 1) ;
|
||||
/* E.g. 2 * 32 - 32 + 1 = 33 for stereo */
|
||||
/* E.g. 8 * 32 - 32 + 1 = 225 for 8 chan TDM */
|
||||
|
||||
@@ -101,7 +115,10 @@ void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buf
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
{
|
||||
p_i2s_dac[i] @ tmp <: 0;
|
||||
if(XUA_I2S_N_BITS == 32)
|
||||
p_i2s_dac[i] @ tmp <: 0;
|
||||
else
|
||||
partout_timed(p_i2s_dac[i], XUA_I2S_N_BITS, 0, tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -109,11 +126,15 @@ void InitPorts_slave(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, buf
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
{
|
||||
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
|
||||
asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1));
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
set_port_shift_count(p_i2s_adc[i], XUA_I2S_N_BITS);
|
||||
}
|
||||
#endif
|
||||
|
||||
asm("setpt res[%0], %1"::"r"(p_lrclk),"r"(tmp-1));
|
||||
if(XUA_I2S_N_BITS != 32)
|
||||
set_port_shift_count(p_lrclk, XUA_I2S_N_BITS);
|
||||
#endif /* (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) */
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
/**
|
||||
* @file xua_audiohub.xc
|
||||
@@ -15,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;
|
||||
|
||||
66
lib_xua/src/core/audiohub/xua_audiohub_st.h
Normal file
66
lib_xua/src/core/audiohub/xua_audiohub_st.h
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#pragma unsafe arrays
|
||||
static inline unsigned DoSampleTransfer(chanend ?c_out, const int readBuffNo, const unsigned underflowWord)
|
||||
{
|
||||
if(XUA_USB_EN)
|
||||
{
|
||||
outuint(c_out, underflowWord);
|
||||
|
||||
/* Check for sample freq change (or other command) or new samples from mixer*/
|
||||
if(testct(c_out))
|
||||
{
|
||||
unsigned command = inct(c_out);
|
||||
#ifndef CODEC_MASTER
|
||||
if(dsdMode == DSD_MODE_OFF)
|
||||
{
|
||||
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||
/* Set clocks low */
|
||||
p_lrclk <: 0;
|
||||
p_bclk <: 0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if(DSD_CHANS_DAC != 0)
|
||||
/* DSD Clock might not be shared with lrclk or bclk... */
|
||||
p_dsd_clk <: 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
if(dsdMode == DSD_MODE_DOP)
|
||||
dsdMode = DSD_MODE_OFF;
|
||||
#endif
|
||||
return command;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int tmp = inuint(c_out);
|
||||
samplesOut[i] = tmp;
|
||||
}
|
||||
#else
|
||||
inuint(c_out);
|
||||
#endif
|
||||
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
outuint(c_out, samplesIn[readBuffNo][i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include "xua.h"
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
/*** BUFFER SIZES ***/
|
||||
|
||||
#define BUFFER_PACKET_COUNT 4 /* How many packets too allow for in buffer - minimum is 4 */
|
||||
#define BUFFER_PACKET_COUNT (4) /* How many packets too allow for in buffer - minimum is 4 */
|
||||
|
||||
#define BUFF_SIZE_OUT_HS MAX_DEVICE_AUD_PACKET_SIZE_OUT_HS * BUFFER_PACKET_COUNT
|
||||
#define BUFF_SIZE_OUT_FS MAX_DEVICE_AUD_PACKET_SIZE_OUT_FS * BUFFER_PACKET_COUNT
|
||||
@@ -55,18 +55,25 @@
|
||||
#define BUFF_SIZE_IN MAX(BUFF_SIZE_IN_HS, BUFF_SIZE_IN_FS)
|
||||
|
||||
#define OUT_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_OUT_HS, MAX_DEVICE_AUD_PACKET_SIZE_OUT_FS))
|
||||
#define IN_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_IN_HS, MAX_DEVICE_AUD_PACKET_SIZE_IN_FS)*2)
|
||||
#define IN_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_IN_HS, MAX_DEVICE_AUD_PACKET_SIZE_IN_FS)*2)
|
||||
|
||||
/* Volume and mute tables */
|
||||
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
unsigned int multOut[NUM_USB_CHAN_OUT + 1];
|
||||
static xc_ptr p_multOut;
|
||||
unsafe
|
||||
{
|
||||
unsigned int volatile * unsafe multOutPtr = multOut;
|
||||
}
|
||||
#endif
|
||||
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
|
||||
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
|
||||
unsigned int multIn[NUM_USB_CHAN_IN + 1];
|
||||
static xc_ptr p_multIn;
|
||||
unsafe
|
||||
{
|
||||
unsigned int volatile * unsafe multInPtr = multIn;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Default to something sensible but the following are setup at stream start (unless UAC1 only..) */
|
||||
#if (AUDIO_CLASS == 2)
|
||||
int g_numUsbChan_In = NUM_USB_CHAN_IN; /* Number of channels to/from the USB bus - initialised to HS for UAC2.0 */
|
||||
int g_numUsbChan_Out = NUM_USB_CHAN_OUT;
|
||||
@@ -143,7 +150,72 @@ unsigned unpackData = 0;
|
||||
unsigned packState = 0;
|
||||
unsigned packData = 0;
|
||||
|
||||
/* Default to something sensible but the following are setup at stream start (unless UAC1 only..) */
|
||||
static inline void SendSamples4(chanend c_mix_out)
|
||||
{
|
||||
/* Doing this checking allows us to unroll */
|
||||
if(g_numUsbChan_Out == NUM_USB_CHAN_OUT)
|
||||
{
|
||||
/* Buffering not underflow condition send out some samples...*/
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
|
||||
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
||||
g_aud_from_host_rdptr+=4;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||
unsafe
|
||||
{
|
||||
mult = multOutPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<= 3;
|
||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||
h |= (l >>29) & 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
outuint(c_mix_out, h);
|
||||
#else
|
||||
outuint(c_mix_out, sample);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT_FS; i++)
|
||||
{
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
|
||||
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
||||
g_aud_from_host_rdptr+=4;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||
unsafe
|
||||
{
|
||||
mult = multOutPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<= 3;
|
||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||
h |= (l >>29) & 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
outuint(c_mix_out, h);
|
||||
#else
|
||||
outuint(c_mix_out, sample);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma select handler
|
||||
#pragma unsafe arrays
|
||||
@@ -206,8 +278,11 @@ __builtin_unreachable();
|
||||
g_aud_from_host_rdptr+=2;
|
||||
sample <<= 16;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||
unsafe
|
||||
{
|
||||
mult = multOutPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
/* Note, in 2 byte subslot mode - ignore lower result of macs */
|
||||
h <<= 3;
|
||||
@@ -223,41 +298,17 @@ __builtin_unreachable();
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
/* Buffering not underflow condition send out some samples...*/
|
||||
for(int i = 0; i < g_numUsbChan_Out; i++)
|
||||
{
|
||||
#pragma xta endpoint "mixer_request"
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
|
||||
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
||||
g_aud_from_host_rdptr+=4;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<= 3;
|
||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
outuint(c_mix_out, h);
|
||||
#else
|
||||
outuint(c_mix_out, sample);
|
||||
#endif
|
||||
}
|
||||
|
||||
SendSamples4(c_mix_out);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
#if (STREAM_FORMAT_OUTPUT_SUBSLOT_3_USED == 0)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
/* Buffering not underflow condition send out some samples...*/
|
||||
/* Note, in this case the unpacking of data is more of an overhead than the loop overhead
|
||||
* so we do not currently make attempts to unroll */
|
||||
for(int i = 0; i < g_numUsbChan_Out; i++)
|
||||
{
|
||||
#pragma xta endpoint "mixer_request"
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
@@ -289,19 +340,20 @@ __builtin_unreachable();
|
||||
}
|
||||
unpackState++;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||
unsafe
|
||||
{
|
||||
mult = multOutPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<= 3;
|
||||
outuint(c_mix_out, h);
|
||||
#else
|
||||
outuint(c_mix_out, sample);
|
||||
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
@@ -335,17 +387,20 @@ __builtin_unreachable();
|
||||
/* Receive sample */
|
||||
int sample = inuint(c_mix_out);
|
||||
#if (INPUT_VOLUME_CONTROL == 1)
|
||||
#if !defined(IN_VOLUME_IN_MIXER)
|
||||
#if (!IN_VOLUME_IN_MIXER)
|
||||
/* Apply volume */
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multIn),"r"(i));
|
||||
unsafe
|
||||
{
|
||||
mult = multInPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
sample = h << 3;
|
||||
|
||||
/* Note, in 2 byte sub slot - ignore lower bits of macs */
|
||||
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
#elif (IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
sample = sample << 3;
|
||||
#endif
|
||||
#endif
|
||||
@@ -365,18 +420,21 @@ __builtin_unreachable();
|
||||
/* Receive sample */
|
||||
int sample = inuint(c_mix_out);
|
||||
#if(INPUT_VOLUME_CONTROL == 1)
|
||||
#if !defined(IN_VOLUME_IN_MIXER)
|
||||
#if (!IN_VOLUME_IN_MIXER)
|
||||
/* Apply volume */
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multIn),"r"(i));
|
||||
unsafe
|
||||
{
|
||||
mult = multInPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
sample = h << 3;
|
||||
#if (STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED == 1)
|
||||
sample |= (l >> 29) & 0x7; // Note, this step is not required if we assume sample depth is 24 (rather than 32)
|
||||
#endif
|
||||
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
#elif (IN_VOLUME_IN_MIXER) && (IN_VOLUME_AFTER_MIX)
|
||||
sample = sample << 3;
|
||||
#endif
|
||||
#endif
|
||||
@@ -396,12 +454,15 @@ __builtin_unreachable();
|
||||
{
|
||||
/* Receive sample */
|
||||
int sample = inuint(c_mix_out);
|
||||
#if (INPUT_VOLUME_CONTROL) && !defined(IN_VOLUME_IN_MIXER)
|
||||
#if (INPUT_VOLUME_CONTROL) && (!IN_VOLUME_IN_MIXER)
|
||||
/* Apply volume */
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multIn),"r"(i));
|
||||
unsafe
|
||||
{
|
||||
mult = multInPtr[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
sample = h << 3;
|
||||
#endif
|
||||
@@ -588,6 +649,7 @@ __builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Mark Endpoint (IN) ready with an appropriately sized zero buffer */
|
||||
static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned sampFreq, unsigned slotSize,
|
||||
xc_ptr aud_to_host_zeros)
|
||||
@@ -619,6 +681,7 @@ static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned samp
|
||||
|
||||
XUD_SetReady_InPtr(aud_to_host_usb_ep, aud_to_host_zeros+4, mid);
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma unsafe arrays
|
||||
void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
@@ -638,13 +701,6 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
|
||||
int t = array_to_xc_ptr(outAudioBuff);
|
||||
|
||||
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
p_multOut = array_to_xc_ptr(multOut);
|
||||
#endif
|
||||
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
|
||||
p_multIn = array_to_xc_ptr(multIn);
|
||||
#endif
|
||||
|
||||
aud_from_host_fifo_start = t;
|
||||
aud_from_host_fifo_end = aud_from_host_fifo_start + BUFF_SIZE_OUT;
|
||||
g_aud_from_host_wrptr = aud_from_host_fifo_start;
|
||||
@@ -668,17 +724,17 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
xc_ptr aud_to_host_zeros = t;
|
||||
|
||||
/* Init vol mult tables */
|
||||
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
for (int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
|
||||
{
|
||||
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multOut),"r"(i));
|
||||
unsafe{
|
||||
multOutPtr[i] = MAX_VOLUME_MULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
|
||||
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
|
||||
for (int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
|
||||
{
|
||||
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multIn),"r"(i));
|
||||
unsafe{
|
||||
multInPtr[i] = MAX_VOLUME_MULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -760,8 +816,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
/* Set buffer to send back to zeros buffer */
|
||||
aud_to_host_buffer = aud_to_host_zeros;
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Update size of zeros buffer (and sampsToWrite) */
|
||||
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
||||
#endif
|
||||
|
||||
/* Reset OUT buffer state */
|
||||
outUnderflow = 1;
|
||||
@@ -815,8 +873,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
/* Set buffer back to zeros buffer */
|
||||
aud_to_host_buffer = aud_to_host_zeros;
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Update size of zeros buffer (and sampsToWrite) */
|
||||
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
||||
#endif
|
||||
|
||||
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
|
||||
if (usbSpeed == XUD_SPEED_HS)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include "xua.h"
|
||||
#if XUA_USB_EN
|
||||
@@ -10,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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2021 XMOS LIMITED.
|
||||
// Copyright 2015-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#ifndef __DESCRIPTOR_DEFS_H__
|
||||
@@ -33,6 +33,7 @@
|
||||
#define ENDPOINT_ADDRESS_OUT_MIDI (ENDPOINT_NUMBER_OUT_MIDI)
|
||||
#define ENDPOINT_ADDRESS_OUT_IAP (ENDPOINT_NUMBER_OUT_IAP)
|
||||
#define ENDPOINT_ADDRESS_OUT_IAP_EA_NATIVE_TRANS (ENDPOINT_NUMBER_OUT_IAP_EA_NATIVE_TRANS)
|
||||
#define ENDPOINT_ADDRESS_OUT_HID (ENDPOINT_NUMBER_OUT_HID)
|
||||
|
||||
/* Interface numbers enum */
|
||||
enum USBInterfaceNumber
|
||||
@@ -60,7 +61,7 @@ enum USBInterfaceNumber
|
||||
INTERFACE_NUMBER_IAP_EA_NATIVE_TRANS,
|
||||
#endif
|
||||
#endif
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
INTERFACE_NUMBER_HID,
|
||||
#endif
|
||||
INTERFACE_COUNT /* End marker */
|
||||
@@ -70,4 +71,8 @@ enum USBInterfaceNumber
|
||||
#define ENDPOINT_INT_INTERVAL_IN_HID 0x08
|
||||
#endif
|
||||
|
||||
#ifndef ENDPOINT_INT_INTERVAL_OUT_HID
|
||||
#define ENDPOINT_INT_INTERVAL_OUT_HID 0x08
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
/**
|
||||
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "xc_ptr.h"
|
||||
#include "xua_ep0_uacreqs.h"
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#include "hid.h"
|
||||
#include "xua_hid.h"
|
||||
#include "xua_hid_report.h"
|
||||
@@ -106,13 +106,17 @@ unsigned int mutesOut[NUM_USB_CHAN_OUT + 1];
|
||||
int volsIn[NUM_USB_CHAN_IN + 1];
|
||||
unsigned int mutesIn[NUM_USB_CHAN_IN + 1];
|
||||
|
||||
#ifdef MIXER
|
||||
unsigned char mixer1Crossbar[18];
|
||||
short mixer1Weights[18*8];
|
||||
#if (MIXER)
|
||||
short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
|
||||
|
||||
unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
||||
//unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
||||
/* Mapping of channels to output audio interfaces */
|
||||
unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
||||
|
||||
/* Mapping of channels to USB host */
|
||||
unsigned char channelMapUsb[NUM_USB_CHAN_IN];
|
||||
|
||||
/* Mapping of channels to Mixer(s) */
|
||||
unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
#endif
|
||||
|
||||
@@ -262,6 +266,44 @@ void XUA_Endpoint0_setVendorId(unsigned short vid) {
|
||||
#endif // AUDIO_CLASS == 1}
|
||||
}
|
||||
|
||||
#if (MIXER)
|
||||
void InitLocalMixerState()
|
||||
{
|
||||
for (int i = 0; i < MIX_INPUTS * MAX_MIX_COUNT; i++)
|
||||
{
|
||||
mixer1Weights[i] = 0x8001; //-inf
|
||||
}
|
||||
|
||||
/* Configure default connections */
|
||||
for (int i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
mixer1Weights[(i * MAX_MIX_COUNT) + i] = 0;
|
||||
}
|
||||
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
/* Setup up audio output channel mapping */
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
channelMapAud[i] = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
channelMapUsb[i] = i + NUM_USB_CHAN_OUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Init mixer inputs */
|
||||
for(int j = 0; j < MAX_MIX_COUNT; j++)
|
||||
for(int i = 0; i < MIX_INPUTS; i++)
|
||||
{
|
||||
mixSel[j][i] = i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void concatenateAndCopyStrings(char* string1, char* string2, char* string_buffer) {
|
||||
debug_printf("concatenateAndCopyStrings() for \"%s\" and \"%s\"\n", string1, string2);
|
||||
|
||||
@@ -400,6 +442,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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
/**
|
||||
* @file xua_ep0_descriptors.h
|
||||
@@ -308,28 +308,28 @@ typedef struct
|
||||
#error NUM_USB_CHAN > 32
|
||||
#endif
|
||||
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
STR_TABLE_ENTRY(mixOutStr_1);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 1)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 1)
|
||||
STR_TABLE_ENTRY(mixOutStr_2);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 2)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 2)
|
||||
STR_TABLE_ENTRY(mixOutStr_3);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 3)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 3)
|
||||
STR_TABLE_ENTRY(mixOutStr_4);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 4)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 4)
|
||||
STR_TABLE_ENTRY(mixOutStr_5);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 5)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 5)
|
||||
STR_TABLE_ENTRY(mixOutStr_6);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 6)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 6)
|
||||
STR_TABLE_ENTRY(mixOutStr_7);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 7)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 7)
|
||||
STR_TABLE_ENTRY(mixOutStr_8);
|
||||
#endif
|
||||
#ifdef IAP
|
||||
@@ -391,31 +391,31 @@ StringDescTable_t g_strTable =
|
||||
#error NUM_USB_CHAN_IN > 32
|
||||
#endif
|
||||
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
.mixOutStr_1 = "Mix 1",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 1)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 1)
|
||||
.mixOutStr_2 = "Mix 2",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 2)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 2)
|
||||
.mixOutStr_3 = "Mix 3",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 3)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 3)
|
||||
.mixOutStr_4 = "Mix 4",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 4)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 4)
|
||||
.mixOutStr_5 = "Mix 5",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 5)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 5)
|
||||
.mixOutStr_6 = "Mix 6",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 6)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 6)
|
||||
.mixOutStr_7 = "Mix 7",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 7)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 7)
|
||||
.mixOutStr_8 = "Mix 8",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 8)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 8)
|
||||
#error
|
||||
#endif
|
||||
#ifdef IAP
|
||||
@@ -481,7 +481,7 @@ USB_Descriptor_Device_t devDesc_Audio2 =
|
||||
.iManufacturer = offsetof(StringDescTable_t, vendorStr)/sizeof(char *),
|
||||
.iProduct = offsetof(StringDescTable_t, productStr_Audio2)/sizeof(char *),
|
||||
.iSerialNumber = offsetof(StringDescTable_t, serialStr)/sizeof(char *),
|
||||
.bNumConfigurations = 0x02 /* Set to 2 such that windows does not load composite driver */
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
/* Device Descriptor for Null Device */
|
||||
@@ -558,7 +558,7 @@ unsigned char devQualDesc_Null[] =
|
||||
};
|
||||
|
||||
|
||||
#if defined(MIXER) && !defined(AUDIO_PATH_XUS) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && !defined(AUDIO_PATH_XUS) && (MAX_MIX_COUNT > 0)
|
||||
//#warning Extension units on the audio path are required for mixer. Enabling them now.
|
||||
#define AUDIO_PATH_XUS
|
||||
#endif
|
||||
@@ -575,7 +575,7 @@ unsigned char devQualDesc_Null[] =
|
||||
#define DFU_LENGTH (0)
|
||||
#endif
|
||||
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
#define MIX_BMCONTROLS_LEN_TMP ((MAX_MIX_COUNT * MIX_INPUTS) / 8)
|
||||
|
||||
#if ((MAX_MIX_COUNT * MIX_INPUTS)%8)==0
|
||||
@@ -666,7 +666,7 @@ typedef struct
|
||||
#if (NUM_USB_CHAN_OUT > 0)
|
||||
/* Output path */
|
||||
USB_Descriptor_Audio_InputTerminal_t Audio_Out_InputTerminal;
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
USB_Descriptor_Audio_ExtensionUnit_t Audio_Out_ExtensionUnit;
|
||||
#endif
|
||||
#if(OUTPUT_VOLUME_CONTROL == 1)
|
||||
@@ -677,7 +677,7 @@ typedef struct
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Input path */
|
||||
USB_Descriptor_Audio_InputTerminal_t Audio_In_InputTerminal;
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
USB_Descriptor_Audio_ExtensionUnit_t Audio_In_ExtensionUnit;
|
||||
#endif
|
||||
#if(INPUT_VOLUME_CONTROL == 1)
|
||||
@@ -685,7 +685,7 @@ typedef struct
|
||||
#endif
|
||||
USB_Descriptor_Audio_OutputTerminal_t Audio_In_OutputTerminal;
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
USB_Descriptor_Audio_ExtensionUnit2_t Audio_Mix_ExtensionUnit;
|
||||
// Currently no struct for mixer unit
|
||||
// USB_Descriptor_Audio_MixerUnit_t Audio_MixerUnit;
|
||||
@@ -787,10 +787,13 @@ typedef struct
|
||||
#endif
|
||||
#endif // IAP
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
USB_Descriptor_Interface_t HID_Interface;
|
||||
USB_HID_Descriptor_t HID_Descriptor;
|
||||
USB_Descriptor_Endpoint_t HID_In_Endpoint;
|
||||
#if HID_OUT_REQUIRED
|
||||
USB_Descriptor_Endpoint_t HID_Out_Endpoint;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}__attribute__((packed)) USB_Config_Descriptor_Audio2_t;
|
||||
@@ -1168,7 +1171,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
UAC_CS_DESCTYPE_INTERFACE, /* 1 bDescriptorType: CS_INTERFACE */
|
||||
UAC_CS_AC_INTERFACE_SUBTYPE_FEATURE_UNIT, /* 2 bDescriptorSubType: FEATURE_UNIT */
|
||||
FU_USBIN, /* 3 bUnitID */
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
ID_XU_IN, /* 4 bSourceID */
|
||||
#else
|
||||
ID_IT_AUD, /* 4 bSourceID */
|
||||
@@ -1300,7 +1303,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
},
|
||||
#endif /* (NUM_USB_CHAN_IN > 0) */
|
||||
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
/* Extension Unit Descriptor (4.7.2.12) */
|
||||
.Audio_Mix_ExtensionUnit =
|
||||
{
|
||||
@@ -1392,7 +1395,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
0x00, /* bmControls */
|
||||
0 /* Mixer unit string descriptor index */
|
||||
},
|
||||
#endif /* defined(MIXER) && (MAX_MIX_COUNT > 0) */
|
||||
#endif /* (MIXER) && (MAX_MIX_COUNT > 0) */
|
||||
|
||||
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN)
|
||||
/* Standard AS Interrupt Endpoint Descriptor (4.8.2.1): */
|
||||
@@ -2208,14 +2211,14 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
#endif
|
||||
#endif /* IAP */
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#include "xua_hid_descriptors.h"
|
||||
#endif
|
||||
|
||||
};
|
||||
#endif /* (AUDIO_CLASS == 2) */
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#if (AUDIO_CLASS ==1 )
|
||||
unsigned char hidDescriptor[] =
|
||||
{
|
||||
@@ -2330,14 +2333,14 @@ const unsigned num_freqs_a1 = MAX(3, (0
|
||||
#define DFU_INTERFACES_A1 0
|
||||
#endif
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
/*
|
||||
* The value of HID_INTERFACE_BYTES must match the length of the descriptors defined in
|
||||
* - xua_hid_descriptor_contents.h
|
||||
* - xua_hid_endpoint_descriptor_contents.h and
|
||||
* - xua_hid_interface_descriptor_contents.h
|
||||
*/
|
||||
#define HID_INTERFACE_BYTES ( 9 + 9 + 7 )
|
||||
#define HID_INTERFACE_BYTES ( 9 + 9 + (7 * (1 + HID_OUT_REQUIRED))) // always IN
|
||||
#define HID_INTERFACES_A1 1
|
||||
#else
|
||||
#define HID_INTERFACE_BYTES 0
|
||||
@@ -2379,7 +2382,7 @@ const unsigned num_freqs_a1 = MAX(3, (0
|
||||
|
||||
#endif
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#define USB_HID_DESCRIPTOR_OFFSET (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + INTERFACE_DESCRIPTOR_BYTES)
|
||||
#endif
|
||||
|
||||
@@ -2893,7 +2896,7 @@ unsigned char cfgDesc_Audio1[] =
|
||||
offsetof(StringDescTable_t, ctrlStr)/sizeof(char *), /* 8 iInterface */
|
||||
#endif
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_OR_STATIC_HID_ENABLED
|
||||
#include "xua_hid_descriptors.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
/**
|
||||
* @brief Implements relevant requests from the USB Audio 2.0 Specification
|
||||
@@ -14,26 +14,29 @@
|
||||
#include "usbaudio10.h"
|
||||
#include "dbcalc.h"
|
||||
#include "xua_commands.h"
|
||||
#include "xc_ptr.h"
|
||||
|
||||
#define CS_XU_MIXSEL (0x06)
|
||||
|
||||
/* From decouple.xc */
|
||||
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
extern unsigned int multOut[NUM_USB_CHAN_OUT + 1];
|
||||
#endif
|
||||
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
|
||||
extern unsigned int multIn[NUM_USB_CHAN_IN + 1];
|
||||
#endif
|
||||
|
||||
extern int interfaceAlt[];
|
||||
|
||||
/* Global volume and mute tables */
|
||||
/* Global volume and mute tables - from xua_endpoint0.c */
|
||||
extern int volsOut[];
|
||||
extern unsigned int mutesOut[];
|
||||
|
||||
extern int volsIn[];
|
||||
extern unsigned int mutesIn[];
|
||||
|
||||
/* Mixer settings */
|
||||
#ifdef MIXER
|
||||
extern unsigned char mixer1Crossbar[];
|
||||
extern short mixer1Weights[];
|
||||
#if (MIXER)
|
||||
/* Mixer weights */
|
||||
extern short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
|
||||
|
||||
/* Device channel mapping */
|
||||
extern unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
||||
@@ -102,20 +105,6 @@ void FeedbackStabilityDelay()
|
||||
t when timerafter(time + delay):> void;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Original feedback implementation */
|
||||
unsafe
|
||||
{
|
||||
unsigned * unsafe curSamFreqMultiplier = &g_curSamFreqMultiplier;
|
||||
|
||||
static void setG_curSamFreqMultiplier(unsigned x)
|
||||
{
|
||||
// asm(" stw %0, dp[g_curSamFreqMultiplier]" :: "r"(x));
|
||||
*curSamFreqMultiplier = x;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) || (INPUT_VOLUME_CONTROL == 1)
|
||||
static unsigned longMul(unsigned a, unsigned b, int prec)
|
||||
{
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
// Copyright 2018-2021 XMOS LIMITED.
|
||||
// Copyright 2018-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#define MAX_MIX_COUNT 8
|
||||
#define MIX_INPUTS 18
|
||||
#include "xua.h"
|
||||
|
||||
#ifndef MAX_MIX_COUNT
|
||||
#error
|
||||
#endif
|
||||
|
||||
#ifndef MIX_INPUTS
|
||||
#error
|
||||
#endif
|
||||
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
|
||||
#define DOMIX_TOP(i) \
|
||||
.cc_top doMix##i.function,doMix##i; \
|
||||
.align 4 ;\
|
||||
.align 16 ;\
|
||||
.globl doMix##i ;\
|
||||
.type doMix##i, @function ;\
|
||||
.globl doMix##i##.nstackwords ;\
|
||||
@@ -124,7 +133,7 @@ DOMIX_BOT(7)
|
||||
#undef BODY
|
||||
#define N MAX_MIX_COUNT
|
||||
.cc_top setPtr.function,setPtr;
|
||||
.align 4 ;
|
||||
.align 16 ;
|
||||
.globl setPtr;
|
||||
.type setPtr, @function
|
||||
.globl setPtr.nstackwords;
|
||||
@@ -173,5 +182,5 @@ setPtr_go:
|
||||
#undef N
|
||||
#undef BODY
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,25 +1,39 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#define XASSERT_UNIT MIXER
|
||||
#include "xassert.h"
|
||||
|
||||
#include <xs1.h>
|
||||
#include <print.h>
|
||||
#include "xua.h"
|
||||
#include "xc_ptr.h"
|
||||
#include "xua_commands.h"
|
||||
#include "dbcalc.h"
|
||||
|
||||
#ifdef MIXER
|
||||
/* FAST_MIXER has a bit of a nasty implentation but is more efficient */
|
||||
#ifndef FAST_MIXER
|
||||
#define FAST_MIXER (1)
|
||||
#endif
|
||||
|
||||
/* FAST_MIXER has a bit of a nasty implentation but is more effcient */
|
||||
#define FAST_MIXER 1
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) || !FAST_MIXER
|
||||
#include "xc_ptr.h"
|
||||
#endif
|
||||
|
||||
//#ifdef OUT_VOLUME_IN_MIXER
|
||||
#if (MIXER)
|
||||
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
static unsigned int multOut_array[NUM_USB_CHAN_OUT + 1];
|
||||
static xc_ptr multOut;
|
||||
//#endif
|
||||
//#ifdef IN_VOLUME_IN_MIXER
|
||||
unsafe
|
||||
{
|
||||
unsigned int volatile * unsafe multOut = multOut_array;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
static unsigned int multIn_array[NUM_USB_CHAN_IN + 1];
|
||||
static xc_ptr multIn;
|
||||
//#endif
|
||||
unsafe
|
||||
{
|
||||
unsigned int volatile * unsafe multIn = multIn_array;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
||||
static unsigned abs(int x)
|
||||
@@ -35,35 +49,38 @@ static unsigned abs(int x)
|
||||
}
|
||||
#endif
|
||||
|
||||
static const int SOURCE_COUNT = NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1;
|
||||
|
||||
static int samples_array[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1]; /* One larger for an "off" channel for mixer sources" */
|
||||
xc_ptr samples;
|
||||
static int samples_to_host_map_array[NUM_USB_CHAN_IN];
|
||||
static int samples_to_device_map_array[NUM_USB_CHAN_OUT];
|
||||
|
||||
unsafe
|
||||
{
|
||||
static int volatile * const unsafe ptr_samples = samples_array;
|
||||
int volatile * const unsafe ptr_samples = samples_array;
|
||||
int volatile * const unsafe samples_to_host_map = samples_to_host_map_array;
|
||||
int volatile * const unsafe samples_to_device_map = samples_to_device_map_array;
|
||||
}
|
||||
|
||||
int savedsamples2[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
||||
|
||||
int samples_to_host_map_array[NUM_USB_CHAN_IN];
|
||||
xc_ptr samples_to_host_map;
|
||||
|
||||
int samples_to_device_map_array[NUM_USB_CHAN_OUT];
|
||||
xc_ptr samples_to_device_map;
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
int mix_mult_array[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
xc_ptr mix_mult;
|
||||
#define write_word_to_mix_mult(x,y,val) write_via_xc_ptr_indexed(mix_mult,((x)*MIX_INPUTS)+(y), val)
|
||||
#define mix_mult_slice(x) (mix_mult + x * MIX_INPUTS * sizeof(int))
|
||||
#ifndef FAST_MIXER
|
||||
int mix_map_array[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
xc_ptr mix_map;
|
||||
#define write_word_to_mix_map(x,y,val) write_via_xc_ptr_indexed(mix_map,((x)*MIX_INPUTS)+(y), val)
|
||||
#define mix_map_slice(x) (mix_map + x * MIX_INPUTS * sizeof(int))
|
||||
#endif
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
int mix_mult_array[MAX_MIX_COUNT * MIX_INPUTS];
|
||||
#if (FAST_MIXER == 0)
|
||||
int mix_map_array[MAX_MIX_COUNT * MIX_INPUTS];
|
||||
#endif
|
||||
|
||||
unsafe
|
||||
{
|
||||
int volatile * const unsafe mix_mult = mix_mult_array;
|
||||
#if (FAST_MIXER == 0)
|
||||
int volatile * const unsafe mix_map = mix_map_array;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define slice(a, i) (a + i * MIX_INPUTS)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
/* Arrays for level data */
|
||||
int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. device inputs */
|
||||
xc_ptr samples_to_host_inputs_ptr;
|
||||
@@ -77,19 +94,6 @@ static int samples_from_host_streams[NUM_USB_CHAN_OUT]; /* Peak samples for audi
|
||||
static int samples_mixer_outputs[MAX_MIX_COUNT]; /* Peak samples out of the mixer */
|
||||
xc_ptr samples_mixer_outputs_ptr;
|
||||
|
||||
#if 0
|
||||
#pragma xta command "add exclusion mixer1_rate_change"
|
||||
#pragma xta command "analyse path mixer1_req mixer1_req"
|
||||
#pragma xta command "set required - 10400 ns" /* 96kHz */
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#pragma xta command "add exclusion mixer2_rate_change"
|
||||
#pragma xta command "analyse path mixer2_req mixer2_req"
|
||||
#pragma xta command "set required - 10400 ns" /* 96kHz */
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
||||
static inline void ComputeMixerLevel(int sample, int i)
|
||||
{
|
||||
int x;
|
||||
@@ -108,42 +112,40 @@ static inline void ComputeMixerLevel(int sample, int i)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef FAST_MIXER
|
||||
|
||||
#if (FAST_MIXER)
|
||||
void setPtr(int src, int dst, int mix);
|
||||
int doMix0(xc_ptr samples, xc_ptr mult);
|
||||
int doMix1(xc_ptr samples, xc_ptr mult);
|
||||
int doMix2(xc_ptr samples, xc_ptr mult);
|
||||
int doMix3(xc_ptr samples, xc_ptr mult);
|
||||
int doMix4(xc_ptr samples, xc_ptr mult);
|
||||
int doMix5(xc_ptr samples, xc_ptr mult);
|
||||
int doMix6(xc_ptr samples, xc_ptr mult);
|
||||
int doMix7(xc_ptr samples, xc_ptr mult);
|
||||
int doMix8(xc_ptr samples, xc_ptr mult);
|
||||
int doMix0(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix1(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix2(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix3(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix4(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix5(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix6(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix7(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
#else
|
||||
/* DO NOT inline, causes 10.4.2 tools to add extra loads in loop */
|
||||
/* At 18 x 12dB we could get 64 x bigger */
|
||||
#pragma unsafe arrays
|
||||
static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
|
||||
static inline int doMix(volatile int * unsafe samples, volatile int * unsafe const mixMap, volatile int * const unsafe mult)
|
||||
{
|
||||
int h=0;
|
||||
int l=0;
|
||||
|
||||
/* By breaking up the loop we keep things in the encoding for ldw (0-11) */
|
||||
#pragma loop unroll
|
||||
for (int i=0; i<MIX_INPUTS; i++)
|
||||
{
|
||||
int sample;
|
||||
int index;
|
||||
int m;
|
||||
read_via_xc_ptr_indexed(index, ptr, i);
|
||||
read_via_xc_ptr_indexed(sample,samples,index);
|
||||
read_via_xc_ptr_indexed(m, mult, i);
|
||||
{h,l} = macs(sample, m, h, l);
|
||||
unsafe{
|
||||
int sample;
|
||||
int source;
|
||||
int weight;
|
||||
read_via_xc_ptr_indexed(source, mixMap, i);
|
||||
sample = samples[source];
|
||||
read_via_xc_ptr_indexed(weight, mult, i);
|
||||
|
||||
|
||||
{h,l} = macs(sample, weight, h, l);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* Perform saturation */
|
||||
l = sext(h, 25);
|
||||
l = sext(h, XUA_MIXER_MULT_FRAC_BITS);
|
||||
|
||||
if(l != h)
|
||||
{
|
||||
@@ -152,15 +154,14 @@ static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
|
||||
else
|
||||
h = (0x7fffff00>>7);
|
||||
}
|
||||
#endif
|
||||
return h<<7;
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma unsafe arrays
|
||||
static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
|
||||
static inline void GiveSamplesToHost(chanend c, volatile int * unsafe hostMap)
|
||||
{
|
||||
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
@@ -170,23 +171,26 @@ static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
int sample;
|
||||
int index;
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
read_via_xc_ptr_indexed(index,ptr,i);
|
||||
#else
|
||||
index = i + NUM_USB_CHAN_OUT;
|
||||
#endif
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
unsafe
|
||||
{
|
||||
//read_via_xc_ptr_indexed(sample,samples,index);
|
||||
sample = ptr_samples[index];
|
||||
sample = ptr_samples[hostMap[i]];
|
||||
}
|
||||
#else
|
||||
unsafe
|
||||
{
|
||||
sample = ptr_samples[i + NUM_USB_CHAN_OUT];
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||
#warning IN Vols in mixer, AFTER mix & map
|
||||
//asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i));
|
||||
read_via_xc_ptr_indexed(mult, multIn, i);
|
||||
|
||||
unsafe
|
||||
{
|
||||
mult = multIn[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
|
||||
//h <<= 3 done on other side */
|
||||
@@ -209,7 +213,7 @@ static inline void GetSamplesFromHost(chanend c)
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
unsafe {
|
||||
int sample, x;
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
|
||||
#if (OUT_VOLUME_IN_MIXER && !OUT_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
@@ -226,50 +230,47 @@ static inline void GetSamplesFromHost(chanend c)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
|
||||
#if (OUT_VOLUME_IN_MIXER && !OUT_VOLUME_AFTER_MIX)
|
||||
#warning OUT Vols in mixer, BEFORE mix & map
|
||||
read_via_xc_ptr_indexed(mult, multOut, i);
|
||||
mult = multOut[i];
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h<<=3;
|
||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
sample = h;
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(multOut, index, val);
|
||||
write_via_xc_ptr_indexed(samples_array, i, h);
|
||||
#else
|
||||
ptr_samples[i] = sample;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma unsafe arrays
|
||||
static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
||||
static inline void GiveSamplesToDevice(chanend c, volatile int * unsafe deviceMap)
|
||||
{
|
||||
#if(NUM_USB_CHAN_OUT == 0)
|
||||
#if (NUM_USB_CHAN_OUT == 0)
|
||||
outuint(c, 0);
|
||||
#else
|
||||
#pragma loop unroll
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int sample, x;
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
|
||||
#if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
#endif
|
||||
int index;
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
/* If mixer turned on sort out the channel mapping */
|
||||
|
||||
/* Read pointer to sample from the map */
|
||||
read_via_xc_ptr_indexed(index, ptr, i);
|
||||
|
||||
/* Read the actual sample value */
|
||||
read_via_xc_ptr_indexed(sample, samples, index);
|
||||
unsafe
|
||||
{
|
||||
/* Read index to sample from the map then Read the actual sample value */
|
||||
sample = ptr_samples[deviceMap[i]];
|
||||
}
|
||||
#else
|
||||
unsafe
|
||||
{
|
||||
@@ -278,16 +279,19 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
|
||||
#if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
|
||||
/* Do volume control processing */
|
||||
#warning OUT Vols in mixer, AFTER mix & map
|
||||
read_via_xc_ptr_indexed(mult, multOut, i);
|
||||
unsafe
|
||||
{
|
||||
mult = multOut[i];
|
||||
}
|
||||
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h<<=3; // Shift used to be done in audio thread but now done here incase of 32bit support
|
||||
#error
|
||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
outuint(c, h);
|
||||
#else
|
||||
@@ -300,14 +304,14 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
||||
#pragma unsafe arrays
|
||||
static inline void GetSamplesFromDevice(chanend c)
|
||||
{
|
||||
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
|
||||
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
#endif
|
||||
|
||||
#pragma loop unroll
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
int sample;
|
||||
int x;
|
||||
@@ -327,22 +331,24 @@ static inline void GetSamplesFromDevice(chanend c)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
|
||||
/* Read relevant multiplier */
|
||||
read_via_xc_ptr_indexed(mult, multIn, i);
|
||||
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||
/* Volume processing - read relevant multiplier */
|
||||
unsafe
|
||||
{
|
||||
mult = multIn[i];
|
||||
}
|
||||
|
||||
/* Do the multiply */
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<=3;
|
||||
write_via_xc_ptr_indexed(samples_array, NUM_USB_CHAN_OUT+i, h);
|
||||
#else
|
||||
/* No volume processing */
|
||||
h <<= 3;
|
||||
sample = h;
|
||||
#endif
|
||||
unsafe
|
||||
{
|
||||
ptr_samples[NUM_USB_CHAN_OUT + i] = sample;
|
||||
assert((XUA_MIXER_OFFSET_IN + i) < (NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT));
|
||||
ptr_samples[XUA_MIXER_OFFSET_IN + i] = sample;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mixer1_mix2_flag = (DEFAULT_FREQ > 96000);
|
||||
@@ -353,12 +359,14 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
int mixed;
|
||||
#endif
|
||||
#if (MAX_MIX_COUNT > 0) || (IN_VOLUME_IN_MIXER) || (OUT_VOLUME_IN_MIXER) || defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
unsigned cmd;
|
||||
unsigned char ct;
|
||||
#endif
|
||||
unsigned request = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
#pragma xta endpoint "mixer1_req"
|
||||
/* Request from audio()/mixer2() */
|
||||
request = inuint(c_mixer2);
|
||||
|
||||
@@ -369,28 +377,62 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
/* Sync */
|
||||
outuint(c_mixer2, 0);
|
||||
#endif
|
||||
|
||||
/* Between request to decouple and response ~ 400nS latency for interrupt to fire */
|
||||
|
||||
#if (MAX_MIX_COUNT > 0) || (IN_VOLUME_IN_MIXER) || (OUT_VOLUME_IN_MIXER) || defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
select
|
||||
{
|
||||
case inuint_byref(c_mix_ctl, cmd):
|
||||
/* Check if EP0 intends to send us a control command */
|
||||
case inct_byref(c_mix_ctl, ct):
|
||||
{
|
||||
int mix, index, val;
|
||||
|
||||
/* Handshake back to tell EP0 we are ready for an update */
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
|
||||
/* Receive command from EP0 */
|
||||
cmd = inuint(c_mix_ctl);
|
||||
|
||||
/* Interpret control command */
|
||||
switch (cmd)
|
||||
{
|
||||
#if MAX_MIX_COUNT > 0
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
case SET_SAMPLES_TO_HOST_MAP:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
write_via_xc_ptr_indexed(samples_to_host_map, index, val);
|
||||
{
|
||||
int dst = inuint(c_mix_ctl);
|
||||
int src = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
assert((dst < NUM_USB_CHAN_IN) && msg("Host map destination out of range"));
|
||||
assert((src < SOURCE_COUNT) && msg("Host map source out of range"));
|
||||
|
||||
if((dst < NUM_USB_CHAN_IN) && (src < SOURCE_COUNT))
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
samples_to_host_map[dst] = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_SAMPLES_TO_DEVICE_MAP:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
write_via_xc_ptr_indexed(samples_to_device_map,index,val);
|
||||
{
|
||||
int dst = inuint(c_mix_ctl);
|
||||
int src = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
assert((dst < NUM_USB_CHAN_OUT) && msg("Device map destination out of range"));
|
||||
assert((src < SOURCE_COUNT) && msg("Device map source out of range"));
|
||||
|
||||
if((dst < NUM_USB_CHAN_OUT) && (src < SOURCE_COUNT))
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
samples_to_device_map[dst] = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_MIX_MULT:
|
||||
@@ -399,40 +441,80 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
write_word_to_mix_mult(mix, index, val);
|
||||
assert((mix < MAX_MIX_COUNT) && msg("Mix mult mix out of range"));
|
||||
assert((index < MIX_INPUTS) && msg("Mix mult index out of range"));
|
||||
|
||||
if((index < MIX_INPUTS) && (mix < MAX_MIX_COUNT))
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
mix_mult[(mix * MIX_INPUTS) + index] = val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_MIX_MAP:
|
||||
mix = inuint(c_mix_ctl);
|
||||
index = inuint(c_mix_ctl); /* mixer input */
|
||||
val = inuint(c_mix_ctl); /* source */
|
||||
inct(c_mix_ctl);
|
||||
#ifdef FAST_MIXER
|
||||
setPtr(index, val, mix);
|
||||
{
|
||||
unsigned mix = inuint(c_mix_ctl);
|
||||
unsigned input = inuint(c_mix_ctl); /* mixer input */
|
||||
unsigned source = inuint(c_mix_ctl); /* source */
|
||||
inct(c_mix_ctl);
|
||||
|
||||
assert((mix < MAX_MIX_COUNT) && msg("Mix map mix out of range"));
|
||||
assert((input < MIX_INPUTS) && msg("Mix map index out of range"));
|
||||
assert((source < SOURCE_COUNT) && msg("Mix map source out of range"));
|
||||
|
||||
if((input < MIX_INPUTS) && (mix < MAX_MIX_COUNT) && (source < SOURCE_COUNT))
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
setPtr(input, source, mix);
|
||||
#else
|
||||
write_word_to_mix_map(mix, index, val);
|
||||
unsafe
|
||||
{
|
||||
mix_map[(mix * MIX_INPUTS) + input] = source;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* if MAX_MIX_COUNT > 0 */
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
case SET_MIX_IN_VOL:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
write_via_xc_ptr_indexed(multIn, index, val);
|
||||
assert((index < (NUM_USB_CHAN_IN + 1)) && msg("In volume index out of range"));
|
||||
|
||||
if(index < NUM_USB_CHAN_IN + 1)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
multIn[index] = val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
case SET_MIX_OUT_VOL:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
write_via_xc_ptr_indexed(multOut, index, val);
|
||||
assert((index < (NUM_USB_CHAN_OUT + 1)) && msg("Out volume index out of range"));
|
||||
|
||||
if(index < NUM_USB_CHAN_OUT + 1)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
multOut[index] = val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
/* Peak samples of stream from host to device (via USB) */
|
||||
case GET_STREAM_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
@@ -441,42 +523,6 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
samples_from_host_streams[index] = 0;
|
||||
break;
|
||||
|
||||
case GET_INPUT_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
chkct(c_mix_ctl, XS1_CT_END);
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
/* Level LEDS process reseting samples_to_host_inputs
|
||||
* Other side makes sure we don't miss a peak */
|
||||
//val = samples_to_host_inputs_buff[index];
|
||||
//samples_to_host_inputs_buff[index] = 0;
|
||||
/* Access funcs used to avoid disjointness check */
|
||||
read_via_xc_ptr_indexed(val, samples_to_host_inputs_buff_ptr, index);
|
||||
write_via_xc_ptr_indexed(samples_to_host_inputs_buff_ptr, index, 0);
|
||||
#else
|
||||
/* We dont have a level LEDs process, so reset ourselves */
|
||||
//val = samples_to_host_inputs[index];
|
||||
//samples_to_host_inputs[index] = 0;
|
||||
/* Access funcs used to avoid disjointness check */
|
||||
read_via_xc_ptr_indexed(val, samples_to_host_inputs_ptr, index);
|
||||
write_via_xc_ptr_indexed(samples_to_host_inputs_ptr, index, 0);
|
||||
#endif
|
||||
outuint(c_mix_ctl, val);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
break;
|
||||
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
/* Peak samples of the mixer outputs */
|
||||
case GET_OUTPUT_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
chkct(c_mix_ctl, XS1_CT_END);
|
||||
read_via_xc_ptr_indexed(val, samples_mixer_outputs, index);
|
||||
write_via_xc_ptr_indexed(samples_mixer_outputs, index, 0);
|
||||
//val = samples_mixer_outputs[index];
|
||||
//samples_mixer_outputs[index] = 0;
|
||||
outuint(c_mix_ctl, val);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
@@ -484,14 +530,13 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
default:
|
||||
/* Select default */
|
||||
break;
|
||||
}
|
||||
|
||||
} // select
|
||||
#endif
|
||||
|
||||
/* Get response from decouple */
|
||||
if(testct(c_host))
|
||||
{
|
||||
int sampFreq;
|
||||
#pragma xta endpoint "mixer1_rate_change"
|
||||
unsigned command = inct(c_host);
|
||||
|
||||
switch(command)
|
||||
@@ -520,9 +565,8 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
|
||||
#pragma loop unroll
|
||||
/* Reset the mix values back to 0 */
|
||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||
for (int i=0; i<MAX_MIX_COUNT; i++)
|
||||
{
|
||||
//write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
|
||||
unsafe
|
||||
{
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
||||
@@ -535,21 +579,24 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if MAX_MIX_COUNT > 0
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
GetSamplesFromHost(c_host);
|
||||
GiveSamplesToHost(c_host, samples_to_host_map, multIn);
|
||||
GiveSamplesToHost(c_host, samples_to_host_map);
|
||||
|
||||
/* Sync with mixer 2 (once it has swapped samples with audiohub) */
|
||||
outuint(c_mixer2, 0);
|
||||
inuint(c_mixer2);
|
||||
|
||||
/* Do the mixing */
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix0(samples, mix_mult_slice(0));
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix0(ptr_samples, slice(mix_mult, 0));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(0),mix_mult_slice(0));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 0), slice(mix_mult, 0));
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0), mixed);
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0] = mixed;
|
||||
}
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 0);
|
||||
@@ -560,40 +607,46 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
#endif
|
||||
{
|
||||
|
||||
#if MAX_MIX_COUNT > 2
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix2(samples, mix_mult_slice(2));
|
||||
#if (MAX_MIX_COUNT > 2)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix2(ptr_samples, slice(mix_mult, 2));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(2),mix_mult_slice(2));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 2), slice(mix_mult, 2));
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2), mixed);
|
||||
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 4
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix4(samples, mix_mult_slice(4));
|
||||
#if (MAX_MIX_COUNT > 4)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix4(ptr_samples, slice(mix_mult, 4));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(4),mix_mult_slice(4));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 4), slice(mix_mult, 4));
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 4), mixed);
|
||||
|
||||
ptr_samples[XUA_MIXER_OFFSET_MIX + 4] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 4);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 6
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix6(samples, mix_mult_slice(6));
|
||||
#if (MAX_MIX_COUNT > 6)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix6(ptr_samples, slice(mix_mult, 6));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(6),mix_mult_slice(6));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 6), slice(mix_mult, 6));
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 6), mixed);
|
||||
|
||||
ptr_samples[XUA_MIXER_OFFSET_MIX + 6] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 6);
|
||||
#endif
|
||||
@@ -601,10 +654,10 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
}
|
||||
#else /* IF MAX_MIX_COUNT > 0 */
|
||||
/* No mixes, this thread runs on its own doing just volume */
|
||||
GiveSamplesToDevice(c_mixer2, samples_to_device_map, multOut);
|
||||
GiveSamplesToDevice(c_mixer2, samples_to_device_map);
|
||||
GetSamplesFromDevice(c_mixer2);
|
||||
GetSamplesFromHost(c_host);
|
||||
GiveSamplesToHost(c_host, samples_to_host_map, multIn);
|
||||
GiveSamplesToHost(c_host, samples_to_host_map);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -621,7 +674,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
|
||||
while (1)
|
||||
{
|
||||
#pragma xta endpoint "mixer2_req"
|
||||
request = inuint(c_audio);
|
||||
|
||||
/* Forward the request on */
|
||||
@@ -633,7 +685,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
if(testct(c_mixer1))
|
||||
{
|
||||
int sampFreq;
|
||||
#pragma xta endpoint "mixer2_rate_change"
|
||||
unsigned command = inct(c_mixer1);
|
||||
|
||||
switch(command)
|
||||
@@ -660,8 +711,8 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
}
|
||||
|
||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
|
||||
unsafe{
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
||||
}
|
||||
|
||||
/* Wait for handshake and pass on */
|
||||
@@ -670,7 +721,7 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
}
|
||||
else
|
||||
{
|
||||
GiveSamplesToDevice(c_audio, samples_to_device_map, multOut);
|
||||
GiveSamplesToDevice(c_audio, samples_to_device_map);
|
||||
GetSamplesFromDevice(c_audio);
|
||||
|
||||
/* Sync with mixer 1 (once it has swapped samples with the buffering sub-system) */
|
||||
@@ -678,61 +729,67 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
outuint(c_mixer1, 0);
|
||||
|
||||
/* Do the mixing */
|
||||
#if MAX_MIX_COUNT > 1
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix1(samples, mix_mult_slice(1));
|
||||
#if (MAX_MIX_COUNT > 1)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix1(ptr_samples, slice(mix_mult, 1));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(1),mix_mult_slice(1));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 1), slice(mix_mult, 1));
|
||||
#endif
|
||||
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1), mixed);
|
||||
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if (MAX_FREQ > 96000)
|
||||
/* Fewer mixes when running higher than 96kHz */
|
||||
if (!mixer2_mix2_flag)
|
||||
#endif
|
||||
{
|
||||
#if MAX_MIX_COUNT > 3
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix3(samples, mix_mult_slice(3));
|
||||
#if (MAX_MIX_COUNT > 3)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix3(ptr_samples, slice(mix_mult, 3));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(3),mix_mult_slice(3));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 3), slice(mix_mult, 3));
|
||||
#endif
|
||||
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3), mixed);
|
||||
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 5
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix5(samples, mix_mult_slice(5));
|
||||
#if (MAX_MIX_COUNT > 5)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix5(ptr_samples, slice(mix_mult, 5));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(5),mix_mult_slice(5));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 5), slice(mix_mult, 5));
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5, mixed);
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5] = mixed;
|
||||
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 5);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 7
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix7(samples, mix_mult_slice(7));
|
||||
#if (MAX_MIX_COUNT > 7)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix7(ptr_samples, slice(mix_mult, 7));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(7),mix_mult_slice(7));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 7), slice(mix_mult, 7));
|
||||
#endif
|
||||
|
||||
write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7, mixed);
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 7);
|
||||
#endif
|
||||
@@ -748,68 +805,52 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
chan c;
|
||||
#endif
|
||||
multOut = array_to_xc_ptr((multOut_array,unsigned[]));
|
||||
multIn = array_to_xc_ptr((multIn_array,unsigned[]));
|
||||
|
||||
samples = array_to_xc_ptr((samples_array,unsigned[]));
|
||||
samples_to_host_map = array_to_xc_ptr((samples_to_host_map_array,unsigned[]));
|
||||
samples_to_device_map = array_to_xc_ptr((samples_to_device_map_array,unsigned[]));
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
samples_to_host_inputs_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
samples_to_host_inputs_buff_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
|
||||
#endif
|
||||
samples_mixer_outputs_ptr = array_to_xc_ptr((samples_mixer_outputs, unsigned[]));
|
||||
|
||||
#if MAX_MIX_COUNT >0
|
||||
mix_mult = array_to_xc_ptr((mix_mult_array,unsigned[]));
|
||||
#ifndef FAST_MIXER
|
||||
mix_map = array_to_xc_ptr((mix_map_array,unsigned[]));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
|
||||
unsafe {
|
||||
//write_via_xc_ptr_indexed(samples,i,0);
|
||||
ptr_samples[i] = 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int num_mixes = DEFAULT_FREQ > 96000 ? 2 : MAX_MIX_COUNT;
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||
{
|
||||
//samples_to_device_map_array[i] = i;
|
||||
asm("stw %0, %1[%2]":: "r"(i), "r"(samples_to_device_map), "r"(i));
|
||||
}
|
||||
samples_to_device_map_array[i] = i;
|
||||
}
|
||||
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(multOut, i, MAX_VOL);
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
unsafe{
|
||||
multOut[i] = MAX_VOLUME_MULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(multIn, i, MAX_VOL);
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
unsafe{
|
||||
multIn[i] = MAX_VOLUME_MULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(samples_to_host_map, i, NUM_USB_CHAN_OUT + i);
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
unsafe{
|
||||
samples_to_host_map[i] = XUA_MIXER_OFFSET_IN + i;
|
||||
}
|
||||
|
||||
#if MAX_MIX_COUNT> 0
|
||||
#if (MAX_MIX_COUNT> 0)
|
||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||
for (int j=0;j<MIX_INPUTS;j++)
|
||||
{
|
||||
#ifndef FAST_MIXER
|
||||
write_word_to_mix_map(i,j, j < 16 ? j : j + 2);
|
||||
unsafe{
|
||||
#if (FAST_MIXER == 0)
|
||||
mix_map[i * MIX_INPUTS + j] = (j < 16 ? j : j + 2);
|
||||
#endif
|
||||
write_word_to_mix_mult(i,j, i==j ? db_to_mult(0, 8, 25) : 0);
|
||||
mix_mult[i * MIX_INPUTS + j] = (i==j ? db_to_mult(0, XUA_MIXER_DB_FRAC_BITS, XUA_MIXER_MULT_FRAC_BITS) : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013-2022 XMOS LIMITED.
|
||||
// Copyright 2013-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <xs1.h>
|
||||
@@ -9,17 +9,17 @@
|
||||
#include "xua.h"
|
||||
|
||||
/* Note since DSD ports could be reused for I2S ports we do all the setup manually in C */
|
||||
#if DSD_CHANS_DAC > 0
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
port p_dsd_dac[DSD_CHANS_DAC] = {
|
||||
PORT_DSD_DAC0,
|
||||
#endif
|
||||
#if DSD_CHANS_DAC > 1
|
||||
#if (DSD_CHANS_DAC > 1)
|
||||
PORT_DSD_DAC1,
|
||||
#endif
|
||||
#if DSD_CHANS_DAC > 2
|
||||
#if (DSD_CHANS_DAC > 2)
|
||||
#error > 2 DSD chans currently not supported
|
||||
#endif
|
||||
#if DSD_CHANS_DAC > 0
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
};
|
||||
port p_dsd_clk = PORT_DSD_CLK;
|
||||
#endif
|
||||
@@ -45,7 +45,7 @@ void ConfigAudioPortsWrapper(
|
||||
port p_lrclk,
|
||||
port p_bclk,
|
||||
#endif
|
||||
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq, unsigned int dsdMode)
|
||||
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq)
|
||||
{
|
||||
ConfigAudioPorts(
|
||||
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _AUDIOPORTS_H_
|
||||
#define _AUDIOPORTS_H_
|
||||
@@ -79,7 +79,7 @@ void ConfigAudioPortsWrapper(
|
||||
buffered in port:32 p_bclk,
|
||||
#endif
|
||||
#endif
|
||||
in port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq, unsigned int dsdMode);
|
||||
in port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq);
|
||||
#else
|
||||
|
||||
void ConfigAudioPortsWrapper(
|
||||
@@ -95,7 +95,7 @@ void ConfigAudioPortsWrapper(
|
||||
port p_lrclk,
|
||||
port p_bclk,
|
||||
#endif
|
||||
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq, unsigned int dsdMode);
|
||||
port p_mclk_in, clock clk_audio_bclk, unsigned int divide, unsigned curSamFreq);
|
||||
|
||||
|
||||
#endif /* __XC__*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <xs1.h>
|
||||
#include <platform.h>
|
||||
@@ -6,9 +6,7 @@
|
||||
#include "xua.h"
|
||||
#include "audioports.h"
|
||||
|
||||
//extern in port p_mclk_in;
|
||||
extern clock clk_audio_mclk;
|
||||
//extern clock clk_audio_bclk;
|
||||
|
||||
void ConfigAudioPorts(
|
||||
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)
|
||||
@@ -58,7 +56,7 @@ void ConfigAudioPorts(
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
#if (I2S_CHANS_DAC != 0)|| (DSD_CHANS_DAC != 0)
|
||||
for(int i = 0; i < numPortsDac; i++)
|
||||
{
|
||||
clearbuf(p_i2s_dac[i]);
|
||||
@@ -82,7 +80,7 @@ void ConfigAudioPorts(
|
||||
/* Some adustments for timing. Sample ADC lines on negative edge and add some delay */
|
||||
if(XUA_PCM_FORMAT == XUA_PCM_FORMAT_TDM)
|
||||
{
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
for(int i = 0; i < numPortsAdc; i++)
|
||||
{
|
||||
set_port_sample_delay(p_i2s_adc[i]);
|
||||
set_pad_delay(p_i2s_adc[i], 4);
|
||||
@@ -91,7 +89,6 @@ void ConfigAudioPorts(
|
||||
#endif
|
||||
|
||||
#elif (CODEC_MASTER)
|
||||
|
||||
/* Stop bit and master clock blocks */
|
||||
stop_clock(clk_audio_bclk);
|
||||
|
||||
@@ -103,20 +100,18 @@ void ConfigAudioPorts(
|
||||
/* Do some clocking shifting to get data in the valid window */
|
||||
/* E.g. Only shift when running at 88.2+ kHz TDM slave */
|
||||
int bClkDelay_fall = 0;
|
||||
if(curSamFreq * I2S_CHANS_PER_FRAME * 32 >= 20000000)
|
||||
if(curSamFreq * I2S_CHANS_PER_FRAME * XUA_I2S_N_BITS >= 20000000)
|
||||
{
|
||||
/* 18 * 2ns = 36ns. This results in a -4ns (36 - 40) shift at 96KHz and -8ns (36 - 44) at 88.4KHz */
|
||||
bClkDelay_fall = 18;
|
||||
}
|
||||
|
||||
set_clock_fall_delay(clk_audio_bclk, bClkDelay_fall);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
/* Clock I2S output data ports from b-clock clock block */
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
#if (I2S_CHANS_DAC != 0) || (DSD_CHANS_DAC != 0)
|
||||
/* Clock I2S/DSD output data ports from b-clock clock block */
|
||||
for(int i = 0; i < numPortsDac; i++)
|
||||
{
|
||||
configure_out_port_no_ready(p_i2s_dac[i], clk_audio_bclk, 0);
|
||||
}
|
||||
@@ -124,7 +119,7 @@ void ConfigAudioPorts(
|
||||
|
||||
#if (I2S_CHANS_ADC != 0)
|
||||
/* Clock I2S input data ports from clock block */
|
||||
for(int i = 0; i < I2S_WIRES_ADC; i++)
|
||||
for(int i = 0; i < numPortsAdc; i++)
|
||||
{
|
||||
configure_in_port_no_ready(p_i2s_adc[i], clk_audio_bclk);
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2013-2021 XMOS LIMITED.
|
||||
// Copyright 2013-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/*
|
||||
Warnings relating to configuration defines located in this XC source file rather than the devicedefines.h header file in order to avoid multiple warnings being issued when the devicedefines.h header file is included in multiple files.
|
||||
Warnings relating to configuration defines located in this XC source file rather than the xua_conf.h header file in order to avoid multiple warnings being issued when the xua_conf.h header file is included in multiple files.
|
||||
*/
|
||||
|
||||
#include "xua_conf_full.h"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// Copyright 2013-2021 XMOS LIMITED.
|
||||
// Copyright 2013-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#if XUA_USB_EN
|
||||
#include "xua.h"
|
||||
#if XUA_USB_EN
|
||||
#include "hostactive.h"
|
||||
#include "audiostream.h"
|
||||
|
||||
/* Implementations over-riding empty versions in lib_xud/sec/core/XUD_User.c */
|
||||
|
||||
void XUD_UserSuspend(void) __attribute__ ((weak));
|
||||
void XUD_UserSuspend(void)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2022 XMOS LIMITED.
|
||||
// Copyright 2019-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <stdint.h>
|
||||
#include <xs1.h>
|
||||
@@ -13,7 +13,7 @@
|
||||
#define DEBUG_PRINT_ENABLE_HID_XC 0
|
||||
#include "debug_print.h"
|
||||
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_HID_ENABLED
|
||||
static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod );
|
||||
static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime );
|
||||
static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod );
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021-2022 XMOS LIMITED.
|
||||
// Copyright 2021-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include "xua_conf_full.h"
|
||||
#if( 0 < HID_CONTROLS )
|
||||
#if XUA_HID_ENABLED
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 XMOS LIMITED.
|
||||
// Copyright 2021-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/**
|
||||
@@ -31,6 +31,19 @@
|
||||
HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_HI, /* 5 wMaxPacketSize */
|
||||
ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */
|
||||
|
||||
#if (HID_OUT_REQUIRED)
|
||||
|
||||
/* HID Endpoint descriptor (OUT) */
|
||||
HID_ENDPOINT_DESCRIPTOR_LENGTH, /* 0 bLength */
|
||||
HID_ENDPOINT_DESCRIPTOR_TYPE, /* 1 bDescriptorType */
|
||||
ENDPOINT_ADDRESS_OUT_HID, /* 2 bEndpointAddress */
|
||||
HID_ENDPOINT_ATTRIBUTES, /* 3 bmAttributes (INTERRUPT) */
|
||||
HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_LO, /* 4 wMaxPacketSize */
|
||||
HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_HI, /* 5 wMaxPacketSize */
|
||||
ENDPOINT_INT_INTERVAL_OUT_HID, /* 6 bInterval */
|
||||
|
||||
#endif
|
||||
|
||||
#elif (AUDIO_CLASS == 2)
|
||||
|
||||
.HID_In_Endpoint =
|
||||
@@ -44,6 +57,21 @@
|
||||
.bInterval = ENDPOINT_INT_INTERVAL_IN_HID,
|
||||
},
|
||||
|
||||
#if (HID_OUT_REQUIRED)
|
||||
|
||||
.HID_Out_Endpoint =
|
||||
{
|
||||
/* Endpoint descriptor (OUT) */
|
||||
.bLength = sizeof(USB_Descriptor_Endpoint_t),
|
||||
.bDescriptorType = HID_ENDPOINT_DESCRIPTOR_TYPE,
|
||||
.bEndpointAddress = ENDPOINT_ADDRESS_OUT_HID,
|
||||
.bmAttributes = HID_ENDPOINT_ATTRIBUTES,
|
||||
.wMaxPacketSize = HID_ENDPOINT_DESCRIPTOR_PACKET_SIZE_LO,
|
||||
.bInterval = ENDPOINT_INT_INTERVAL_OUT_HID,
|
||||
},
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "Unknown Audio Class"
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 XMOS LIMITED.
|
||||
// Copyright 2021-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/**
|
||||
@@ -15,7 +15,8 @@
|
||||
#define HID_INTERFACE_DESCRIPTOR_LENGTH ( 0x09 ) /* Size of descriptor in Bytes */
|
||||
#define HID_INTERFACE_DESCRIPTOR_TYPE ( 0x04 ) /* Interface 0x04 */
|
||||
#define HID_INTERFACE_ALTERNATE_SETTING ( 0x00 ) /* Value used alternate interfaces using SetInterface Request */
|
||||
#define HID_INTERFACE_NUMBER_OF_ENDPOINTS ( 0x01 ) /* Number of endpoitns for this interface (excluding 0) */
|
||||
#define HID_INTERFACE_NUMBER_OF_ENDPOINTS ( 0x01 + HID_OUT_REQUIRED )
|
||||
/* Number of endpoints for this interface (excluding 0) */
|
||||
#define HID_INTERFACE_CLASS ( 0x03 )
|
||||
#define HID_INTERFACE_SUBCLASS ( 0x00 ) /* No boot device */
|
||||
#define HID_INTERFACE_PROTOCOL ( 0x00 )
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
# Copyright 2022 XMOS LIMITED.
|
||||
# Copyright 2022-2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import time
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def test_file(request):
|
||||
return str(request.node.fspath)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session") # Use same seed for whole run
|
||||
def test_seed(request):
|
||||
|
||||
seed = str(int(time.time()))
|
||||
# We dont need the following since pytest will print the values of our fixtures on a failure
|
||||
# capmanager = request.config.pluginmanager.getplugin("capturemanager")
|
||||
# with capmanager.global_and_fixture_disabled():
|
||||
# print("Using seed: "+ seed)
|
||||
return seed
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2018-2022 XMOS LIMITED.
|
||||
# Copyright 2018-2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import Pyxsim
|
||||
@@ -11,16 +11,21 @@ import sys
|
||||
def test_file(request):
|
||||
return str(request.node.fspath)
|
||||
|
||||
|
||||
def do_test(
|
||||
pcm_format, i2s_role, channel_count, sample_rate, test_file, options, capfd
|
||||
pcm_format, i2s_role, channel_count, sample_rate, word_length, test_file, options, capfd
|
||||
):
|
||||
|
||||
build_options = []
|
||||
output = []
|
||||
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||
|
||||
desc = f"simulation_{pcm_format}_{i2s_role}_{channel_count}in_{channel_count}out_{sample_rate}"
|
||||
build_options += [f"pcm_format={pcm_format}"]
|
||||
build_options += [f"i2s_role={i2s_role}"]
|
||||
build_options += [f"channel_count={channel_count}"]
|
||||
build_options += [f"sample_rate={sample_rate}"]
|
||||
build_options += [f"word_length={word_length}"]
|
||||
|
||||
desc = f"simulation_{pcm_format}_{i2s_role}_{channel_count}in_{channel_count}out_{sample_rate}_{word_length}bit"
|
||||
binary = f"{testname}/bin/{desc}/{testname}_{desc}.xe"
|
||||
|
||||
tester = testers.ComparisonTester(open("pass.expect"))
|
||||
@@ -52,6 +57,7 @@ def do_test(
|
||||
|
||||
result = Pyxsim.run_on_simulator(
|
||||
binary,
|
||||
build_options=build_options,
|
||||
tester=tester,
|
||||
simargs=simargs,
|
||||
capfd=capfd,
|
||||
@@ -65,25 +71,26 @@ def do_test(
|
||||
@pytest.mark.parametrize("i2s_role", ["master", "slave"])
|
||||
@pytest.mark.parametrize("pcm_format", ["i2s", "tdm"])
|
||||
@pytest.mark.parametrize("channel_count", [2, 8, 16])
|
||||
@pytest.mark.parametrize("sample_rate", ["48khz", "96khz", "192khz"])
|
||||
@pytest.mark.parametrize("word_length", [16, 32]) # I2S world length in bits
|
||||
@pytest.mark.parametrize("sample_rate", [48000, 96000, 192000])
|
||||
def test_i2s_loopback(
|
||||
i2s_role, pcm_format, channel_count, sample_rate, test_file, options, capfd
|
||||
i2s_role, pcm_format, channel_count, sample_rate, word_length, test_file, options, capfd
|
||||
):
|
||||
|
||||
if pcm_format == "i2s" and channel_count == 16:
|
||||
pytest.skip("Invalid parameter combination")
|
||||
|
||||
if pcm_format == "i2s" and sample_rate not in ["48khz", "192khz"]:
|
||||
if pcm_format == "i2s" and sample_rate not in [48000, 192000]:
|
||||
pytest.skip("Invalid parameter combination")
|
||||
|
||||
if pcm_format == "tdm" and channel_count == 2:
|
||||
pytest.skip("Invalid parameter combination")
|
||||
|
||||
if pcm_format == "tdm" and sample_rate == "192khz":
|
||||
if pcm_format == "tdm" and sample_rate == 192000:
|
||||
pytest.skip("Invalid parameter combination")
|
||||
|
||||
result = do_test(
|
||||
pcm_format, i2s_role, channel_count, sample_rate, test_file, options, capfd
|
||||
pcm_format, i2s_role, channel_count, sample_rate, word_length, test_file, options, capfd
|
||||
)
|
||||
|
||||
assert result
|
||||
|
||||
@@ -1,126 +1,44 @@
|
||||
TARGET = xk-audio-216-mc.xn
|
||||
USED_MODULES = lib_xua lib_i2c lib_logging
|
||||
|
||||
BUILD_FLAGS = -O0 -g -lflash -DXUD_CORE_CLOCK=600 -fxscope -save-temps -march=xs2a -DUSB_TILE=tile[1]
|
||||
BUILD_FLAGS = -O3 -g -lflash -DXUD_CORE_CLOCK=600 -fxscope -save-temps -march=xs2a -DUSB_TILE=tile[1] \
|
||||
-DXUA_ADAT_RX_EN=0 -DXUA_ADAT_TX_EN=0 -DXUA_SPDIF_RX_EN=0 -DXUA_SPDIF_TX_EN=0 -DMIDI=0 \
|
||||
-DSIMULATION=1
|
||||
|
||||
BUILD_FLAGS_i2s_master_2in_2out_48khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -DI2S_CHANS_ADC=2 -DI2S_CHANS_DAC=2 \
|
||||
-D DEFAULT_FREQ=48000
|
||||
ifndef pcm_format
|
||||
$(error pcm_format is not set)
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_slave_2in_2out_48khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -DI2S_CHANS_ADC=2 -DI2S_CHANS_DAC=2 \
|
||||
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1
|
||||
ifndef i2s_role
|
||||
$(error i2s_role is not set)
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_master_2in_2out_192khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -D I2S_CHANS_ADC=2 -D I2S_CHANS_DAC=2 \
|
||||
-D DEFAULT_FREQ=192000
|
||||
ifndef channel_count
|
||||
$(error channel_count is not set)
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_slave_2in_2out_192khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=2 -D NUM_USB_CHAN_OUT=2 -DI2S_CHANS_ADC=2 -DI2S_CHANS_DAC=2 \
|
||||
-D DEFAULT_FREQ=192000 -DCODEC_MASTER=1
|
||||
ifndef sample_rate
|
||||
$(error sample_rate is not set)
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_master_8in_8out_48khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=48000
|
||||
ifndef word_length
|
||||
$(error word_length is not set)
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_slave_8in_8out_48khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1
|
||||
ifeq ($(pcm_format),tdm)
|
||||
BUILD_FLAGS += -DXUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM
|
||||
endif
|
||||
ifeq ($(i2s_role),slave)
|
||||
BUILD_FLAGS += -DCODEC_MASTER=1
|
||||
endif
|
||||
|
||||
BUILD_FLAGS_i2s_master_8in_8out_192khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=192000 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_i2s_slave_8in_8out_192khz = $(BUILD_FLAGS) \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=192000 -DCODEC_MASTER=1 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_master_8in_8out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=48000 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_master_8in_8out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=96000 \
|
||||
-O3 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_slave_8in_8out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_slave_8in_8out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=8 -D NUM_USB_CHAN_OUT=8 -D I2S_CHANS_ADC=8 -D I2S_CHANS_DAC=8 \
|
||||
-D DEFAULT_FREQ=96000 -DCODEC_MASTER=1 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_master_16in_16out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
|
||||
-D DEFAULT_FREQ=48000 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_master_16in_16out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
|
||||
-D DEFAULT_FREQ=96000 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_slave_16in_16out_48khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
|
||||
-D DEFAULT_FREQ=48000 -DCODEC_MASTER=1 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
BUILD_FLAGS_tdm_slave_16in_16out_96khz = $(BUILD_FLAGS) -D XUA_PCM_FORMAT=XUA_PCM_FORMAT_TDM \
|
||||
-D XUA_ADAT_RX_EN=0 -D XUA_ADAT_TX_EN=0 -D XUA_SPDIF_RX_EN=0 -D XUA_SPDIF_TX_EN=0 -D MIDI=0 \
|
||||
-D NUM_USB_CHAN_IN=16 -D NUM_USB_CHAN_OUT=16 -D I2S_CHANS_ADC=16 -D I2S_CHANS_DAC=16 \
|
||||
-D DEFAULT_FREQ=96000 -DCODEC_MASTER=1 \
|
||||
-O2 # optimisations to meet timing
|
||||
|
||||
|
||||
#XCC_FLAGS_hardware_i2s_master_2in_2out_48khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_2in_2out_48khz)
|
||||
#XCC_FLAGS_hardware_i2s_master_2in_2out_192khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_2in_2out_192khz)
|
||||
#XCC_FLAGS_hardware_i2s_master_8in_8out_48khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_8in_8out_48khz)
|
||||
#XCC_FLAGS_hardware_i2s_master_8in_8out_192khz = -D HARDWARE $(BUILD_FLAGS_i2s_master_8in_8out_192khz)
|
||||
#XCC_FLAGS_hardware_tdm_master_8in_8out_48khz = -D HARDWARE $(BUILD_FLAGS_tdm_master_8in_8out_48khz)
|
||||
|
||||
XCC_FLAGS_simulation_i2s_master_2in_2out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_2in_2out_48khz)
|
||||
XCC_FLAGS_simulation_i2s_slave_2in_2out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_2in_2out_48khz)
|
||||
|
||||
XCC_FLAGS_simulation_i2s_master_2in_2out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_2in_2out_192khz)
|
||||
XCC_FLAGS_simulation_i2s_slave_2in_2out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_2in_2out_192khz)
|
||||
|
||||
XCC_FLAGS_simulation_i2s_master_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_8in_8out_48khz)
|
||||
XCC_FLAGS_simulation_i2s_slave_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_8in_8out_48khz)
|
||||
|
||||
XCC_FLAGS_simulation_i2s_master_8in_8out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_master_8in_8out_192khz)
|
||||
XCC_FLAGS_simulation_i2s_slave_8in_8out_192khz = -D SIMULATION $(BUILD_FLAGS_i2s_slave_8in_8out_192khz)
|
||||
|
||||
XCC_FLAGS_simulation_tdm_master_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_8in_8out_48khz)
|
||||
XCC_FLAGS_simulation_tdm_master_8in_8out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_8in_8out_96khz)
|
||||
XCC_FLAGS_simulation_tdm_slave_8in_8out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_8in_8out_48khz)
|
||||
XCC_FLAGS_simulation_tdm_slave_8in_8out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_8in_8out_96khz)
|
||||
|
||||
XCC_FLAGS_simulation_tdm_master_16in_16out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_16in_16out_48khz)
|
||||
XCC_FLAGS_simulation_tdm_master_16in_16out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_master_16in_16out_96khz)
|
||||
XCC_FLAGS_simulation_tdm_slave_16in_16out_48khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_16in_16out_48khz)
|
||||
XCC_FLAGS_simulation_tdm_slave_16in_16out_96khz = -D SIMULATION $(BUILD_FLAGS_tdm_slave_16in_16out_96khz)
|
||||
XCC_FLAGS_simulation_${pcm_format}_${i2s_role}_$(channel_count)in_$(channel_count)out_$(sample_rate)_$(word_length)bit = $(BUILD_FLAGS) \
|
||||
-DNUM_USB_CHAN_IN=${channel_count} \
|
||||
-DNUM_USB_CHAN_OUT=${channel_count} \
|
||||
-DI2S_CHANS_DAC=${channel_count} \
|
||||
-DI2S_CHANS_ADC=${channel_count} \
|
||||
-DDEFAULT_FREQ=${sample_rate} \
|
||||
-DXUA_I2S_N_BITS=${word_length}
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016-2022 XMOS LIMITED.
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include <platform.h>
|
||||
#include <stdlib.h>
|
||||
@@ -9,7 +9,6 @@
|
||||
#define DEBUG_UNIT MAIN
|
||||
#include "debug_print.h"
|
||||
|
||||
|
||||
/* Port declarations. Note, the defines come from the xn file */
|
||||
#if I2S_WIRES_DAC > 0
|
||||
on tile[AUDIO_IO_TILE] : buffered out port:32 p_i2s_dac[I2S_WIRES_DAC] =
|
||||
@@ -92,9 +91,10 @@ clock clk_audio_mclk = on tile[AUDIO_IO_TILE]: XS1_CLKBLK_2; /*
|
||||
#define TOTAL_TEST_FRAMES (5 * DEFAULT_FREQ)
|
||||
#endif
|
||||
|
||||
#define SAMPLE(frame_count, channel_num) (((frame_count) << 8) | ((channel_num) & 0xFF))
|
||||
#define SAMPLE_FRAME_NUM(test_word) ((test_word) >> 8)
|
||||
#define SAMPLE_CHANNEL_NUM(test_word) ((test_word) & 0xFF)
|
||||
#define SHIFT (16) /* Note, we shift samples up such that we can test down to 16bit I2S */
|
||||
#define SAMPLE(frame_count, channel_num) ((((frame_count) << 8) | ((channel_num) & 0xFF))<<SHIFT)
|
||||
#define SAMPLE_FRAME_NUM(test_word) ((test_word>>SHIFT) >> 8)
|
||||
#define SAMPLE_CHANNEL_NUM(test_word) ((test_word>>SHIFT) & 0xFF)
|
||||
|
||||
void generator(chanend c_checker, chanend c_out)
|
||||
{
|
||||
@@ -105,7 +105,6 @@ void generator(chanend c_checker, chanend c_out)
|
||||
|
||||
frame_count = 0;
|
||||
|
||||
|
||||
while (1) {
|
||||
underflow_word = inuint(c_out);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016-2022 XMOS LIMITED.
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifdef SIMULATION
|
||||
|
||||
@@ -41,7 +41,7 @@ extern out port p_lrclk_gen;
|
||||
extern clock clk_audio_lrclk_gen;
|
||||
|
||||
void slave_mode_clk_setup(const unsigned samFreq, const unsigned chans_per_frame){
|
||||
const unsigned data_bits = 32;
|
||||
const unsigned data_bits = XUA_I2S_N_BITS;
|
||||
const unsigned mclk_freq = 24576000;
|
||||
|
||||
const unsigned mclk_bclk_ratio = mclk_freq / (chans_per_frame * samFreq * data_bits);
|
||||
@@ -61,5 +61,4 @@ void slave_mode_clk_setup(const unsigned samFreq, const unsigned chans_per_frame
|
||||
master_mode_clk_setup();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
45
tests/test_mixer_routing_input.py
Normal file
45
tests/test_mixer_routing_input.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright 2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import Pyxsim
|
||||
from Pyxsim import testers
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def do_test(options, capfd, test_file, test_seed):
|
||||
|
||||
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||
|
||||
binary = f"{testname}/bin/{testname}.xe"
|
||||
|
||||
tester = testers.ComparisonTester(open("pass.expect"))
|
||||
|
||||
max_cycles = 15000000
|
||||
|
||||
simargs = [
|
||||
"--max-cycles",
|
||||
str(max_cycles),
|
||||
]
|
||||
|
||||
build_options = []
|
||||
build_options += ["TEST_SEED=" + str(test_seed)]
|
||||
|
||||
result = Pyxsim.run_on_simulator(
|
||||
binary,
|
||||
tester=tester,
|
||||
build_options=build_options,
|
||||
simargs=simargs,
|
||||
capfd=capfd,
|
||||
instTracing=options.enabletracing,
|
||||
vcdTracing=options.enablevcdtracing,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def test_mixer_routing_input(options, capfd, test_file, test_seed):
|
||||
|
||||
result = do_test(options, capfd, test_file, test_seed)
|
||||
|
||||
assert result
|
||||
19
tests/test_mixer_routing_input/Makefile
Normal file
19
tests/test_mixer_routing_input/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
|
||||
else
|
||||
TEST_DEBUG_FLAGS =
|
||||
endif
|
||||
|
||||
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS)
|
||||
|
||||
XCC_FLAGS = -O3 $(TEST_FLAGS)
|
||||
|
||||
TARGET = test_xs3_600.xn
|
||||
|
||||
USED_MODULES = lib_xua lib_logging lib_random
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
243
tests/test_mixer_routing_input/src/main.xc
Normal file
243
tests/test_mixer_routing_input/src/main.xc
Normal file
@@ -0,0 +1,243 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/* Tests that routing of mixer inputs behaves as expected
|
||||
*
|
||||
* The device supports MAX_MIX_COUNT mixers each with MIX_INPUTS inputs.
|
||||
*
|
||||
* This test also assumes/checks that the default routing into each of the MIX_INPUTS inputs into
|
||||
* each of the M mixer units is as follows:
|
||||
*
|
||||
* MIXER[0]:
|
||||
* USB_FROM_HOST[0] -> MIXER[0].INPUT[0]
|
||||
* USB_FROM_HOST[1] -> MIXER[0].INPUT[1]
|
||||
* ...
|
||||
USB_TO_HOST[0] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT]
|
||||
USB_TO_HOST[1] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT+1]
|
||||
...
|
||||
|
||||
* MIXER[MAX_MIX_COUNT-1]:
|
||||
* USB_FROM_HOST[0] -> MIXER[MAX_MIX_COUNT-1].INPUT[0]
|
||||
* USB_FROM_HOST[1] -> MIXER[MAX_MIX_COUNT-1].INPUT[1]
|
||||
* ...
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "platform.h"
|
||||
#include "xua.h"
|
||||
#include "debug_print.h"
|
||||
#include "assert.h"
|
||||
#include "random.h"
|
||||
|
||||
#ifndef TEST_ITERATIONS
|
||||
#define TEST_ITERATIONS (300)
|
||||
#endif
|
||||
|
||||
#include "./../test_mixer_routing_output/src/mixer_test_shared.h"
|
||||
|
||||
struct ModelMixer
|
||||
{
|
||||
uint32_t deviceMap[NUM_USB_CHAN_OUT];
|
||||
uint32_t hostMap[NUM_USB_CHAN_IN];
|
||||
uint32_t mixMap_input[MAX_MIX_COUNT];
|
||||
uint32_t mixMap_src[MAX_MIX_COUNT];
|
||||
uint32_t mixOutput[MAX_MIX_COUNT];
|
||||
};
|
||||
|
||||
void InitModel(struct ModelMixer &modelMixer)
|
||||
{
|
||||
for(size_t i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
modelMixer.deviceMap[i] = i;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
modelMixer.hostMap[i] = NUM_USB_CHAN_OUT+i;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
// This test only allows for one "active" input to each mixer
|
||||
modelMixer.mixMap_src[i] = i;
|
||||
modelMixer.mixMap_input[i] = i;
|
||||
|
||||
uint32_t sample = i;
|
||||
SET_SOURCE(sample, SRC_HOST);
|
||||
SET_CHANNEL(sample, i);
|
||||
modelMixer.mixOutput[i] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void GenExpectedSamples(struct ModelMixer &modelMixer,
|
||||
uint32_t modelOut[NUM_USB_CHAN_OUT],
|
||||
uint32_t modelIn[NUM_USB_CHAN_IN])
|
||||
{
|
||||
/* First generate model mix outputs - run MIX tiles to allow mix inputs derived from mix outputs to propagate */
|
||||
for(int j = 0; j < MAX_MIX_COUNT; j++)
|
||||
{
|
||||
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
int src = modelMixer.mixMap_src[i];
|
||||
modelMixer.mixOutput[i] = CreateSample(modelMixer.mixOutput, src);
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i<NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int src = modelMixer.deviceMap[i];
|
||||
modelOut[i] = CreateSample(modelMixer.mixOutput, src);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i<NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
int src = modelMixer.hostMap[i];
|
||||
modelIn[i] = CreateSample(modelMixer.mixOutput, src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MapMixerInput(int mix, int input, int src, struct ModelMixer &modelMixer, chanend c_mix_ctl,
|
||||
chanend c_stim_ah, chanend c_stim_de, uint32_t modelIn[], uint32_t modelOut[])
|
||||
{
|
||||
debug_printf("Mapping mix %d input %d", mix, input);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
|
||||
/* This test only allows for one input to travel "untouched" to the mix output - since this test doesn't model the actual mixing.
|
||||
* Because of this we must also mod the mixer weights, not just the mixer input map.
|
||||
* If we simply just apply an update to the mixer input mapping it would not produce an observable difference on the mixer output
|
||||
*/
|
||||
|
||||
/* Set previously "activated" input weight to 0 */
|
||||
debug_printf("Setting mix %d, weight %d to 0\n", mix, modelMixer.mixMap_input[mix]);
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
UpdateMixerWeight(c_mix_ctl, mix, modelMixer.mixMap_input[mix], 0);
|
||||
|
||||
/* Set new "activated" input wright to max (i.e. x1) */
|
||||
debug_printf("Setting mix %d, weight %d to %x\n", mix, input, XUA_MIXER_MAX_MULT);
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
UpdateMixerWeight(c_mix_ctl, mix, input, XUA_MIXER_MAX_MULT);
|
||||
|
||||
/* Update mixer input in model */
|
||||
modelMixer.mixMap_src[mix] = src;
|
||||
modelMixer.mixMap_input[mix] = input;
|
||||
|
||||
/* Run twice to allow mix inputs derived from mix outputs to propagate */
|
||||
GenExpectedSamples(modelMixer, modelOut, modelIn);
|
||||
|
||||
/* Finally update the acutal mixer input map */
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
UpdateMixMap(c_mix_ctl, mix, input, src);
|
||||
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
|
||||
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||
}
|
||||
|
||||
|
||||
/* This task configures the routing and maintains a model of the expected routing output
|
||||
* it provides this to the Fake AudioHub and Fake Decouple tasks such that they can self check
|
||||
*/
|
||||
void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
|
||||
{
|
||||
uint32_t modelOut[NUM_USB_CHAN_OUT];
|
||||
uint32_t modelIn[NUM_USB_CHAN_IN];
|
||||
|
||||
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
|
||||
|
||||
struct ModelMixer modelMixer;
|
||||
|
||||
InitModel(modelMixer);
|
||||
|
||||
GenExpectedSamples(modelMixer, modelOut, modelIn);
|
||||
|
||||
/* There is single sample delay between the two mixer cores, so trigger twice to flush though a block
|
||||
* of zero samples */
|
||||
SendTrigger(c_stim_ah, 2);
|
||||
|
||||
/* Send expected samples to AH and DE and run checks */
|
||||
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||
|
||||
/* Firstly route mixer outputs to the audio interfaces (we could have chosen host)
|
||||
* such that we can observe and check the outputs from the mixer
|
||||
*/
|
||||
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
int map = SET_SAMPLES_TO_DEVICE_MAP;
|
||||
assert(i < NUM_USB_CHAN_OUT);
|
||||
int dst = i;
|
||||
int src = NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN+i; // mix0, mix1..
|
||||
debug_printf("Mapping output to AudioIF: %d ", dst);
|
||||
|
||||
PrintDestString(map, dst);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
|
||||
/* Update the mixer */
|
||||
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
|
||||
|
||||
/* Update the model */
|
||||
modelMixer.deviceMap[dst] = src;
|
||||
}
|
||||
|
||||
/* Send expected samples to fake AudioHub and Decouple for checking */
|
||||
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||
|
||||
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
|
||||
{
|
||||
/* Make a random update to the routing - route a random source to a random mix input */
|
||||
unsigned mix = random_get_random_number(rg) % MAX_MIX_COUNT;
|
||||
unsigned input = random_get_random_number(rg) % MIX_INPUTS;
|
||||
|
||||
/* Note, we don't currently support a mix input dervived from another mix
|
||||
* This is not trivial to test since the current mixer implementation only allows for one
|
||||
* config update per "trigger"
|
||||
*/
|
||||
unsigned src = random_get_random_number(rg) % NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT;
|
||||
|
||||
debug_printf("Iteration: %d\n", testIter);
|
||||
MapMixerInput(mix, input, src, modelMixer, c_mix_ctl, c_stim_ah, c_stim_de, modelIn, modelOut);
|
||||
}
|
||||
|
||||
/* Send kill messages to Fake AudioHub & Fake Decouple */
|
||||
outct(c_stim_ah, XS1_CT_END);
|
||||
inct(c_stim_ah);
|
||||
|
||||
outct(c_stim_de, XS1_CT_END);
|
||||
inct(c_stim_de);
|
||||
|
||||
printstrln("PASS");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chan c_dec_mix;
|
||||
chan c_mix_aud;
|
||||
chan c_mix_ctl;
|
||||
chan c_stim_ah;
|
||||
chan c_stim_de;
|
||||
|
||||
par
|
||||
{
|
||||
Fake_XUA_Buffer_Decouple(c_dec_mix, c_stim_de);
|
||||
Fake_XUA_AudioHub(c_mix_aud, c_stim_ah);
|
||||
|
||||
/* Mixer from lib_xua */
|
||||
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
|
||||
|
||||
stim(c_stim_ah, c_stim_de, c_mix_ctl);
|
||||
}
|
||||
|
||||
/* TODO to hit this we need to fully close down i.e. kill mixer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
tests/test_mixer_routing_input/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_input/src/test_xs3_600.xn
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Network xmlns="http://www.xmos.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
|
||||
<Declarations>
|
||||
<Declaration>tileref tile[2]</Declaration>
|
||||
</Declarations>
|
||||
|
||||
<Packages>
|
||||
<Package id="0" Type="XS3-UnA-1024-FB265">
|
||||
<Nodes>
|
||||
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
|
||||
<Tile Number="0" Reference="tile[0]"/>
|
||||
<Tile Number="1" Reference="tile[1]"/>
|
||||
</Node>
|
||||
</Nodes>
|
||||
</Package>
|
||||
</Packages>
|
||||
|
||||
<JTAGChain>
|
||||
<JTAGDevice NodeId="0"/>
|
||||
</JTAGChain>
|
||||
|
||||
</Network>
|
||||
45
tests/test_mixer_routing_input/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_input/src/xua_conf.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_CONF_H_
|
||||
#define _XUA_CONF_H_
|
||||
|
||||
#define NUM_USB_CHAN_OUT (10)
|
||||
#define NUM_USB_CHAN_IN (10)
|
||||
#define I2S_CHANS_DAC (10)
|
||||
#define I2S_CHANS_ADC (10)
|
||||
|
||||
#define EXCLUDE_USB_AUDIO_MAIN
|
||||
|
||||
#define MIXER (1)
|
||||
#define MAX_MIX_COUNT (8)
|
||||
|
||||
#define UAC_FORCE_FEEDBACK_EP (0)
|
||||
#define XUA_NUM_PDM_MICS 0
|
||||
#define XUD_TILE 1
|
||||
#define AUDIO_IO_TILE 0
|
||||
|
||||
#ifndef MCLK_441
|
||||
#define MCLK_441 (512 * 44100)
|
||||
#endif
|
||||
|
||||
#ifndef MCLK_48
|
||||
#define MCLK_48 (512 * 48000)
|
||||
#endif
|
||||
|
||||
#define MIN_FREQ (44100)
|
||||
#define MAX_FREQ (192000)
|
||||
#define SPDIF_TX_INDEX 0
|
||||
#define VENDOR_STR "XMOS"
|
||||
#define VENDOR_ID 0x20B1
|
||||
#define PRODUCT_STR_A2 "Test device"
|
||||
#define PRODUCT_STR_A1 "Test device"
|
||||
#define PID_AUDIO_1 1
|
||||
#define PID_AUDIO_2 2
|
||||
#define AUDIO_CLASS 2
|
||||
#define AUDIO_CLASS_FALLBACK 0
|
||||
#define BCD_DEVICE 0x1234
|
||||
#define XUA_DFU_EN 0
|
||||
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
|
||||
#define XUA_MIC_FRAME_SIZE 240
|
||||
|
||||
#endif
|
||||
45
tests/test_mixer_routing_input_ctrl.py
Normal file
45
tests/test_mixer_routing_input_ctrl.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright 2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import Pyxsim
|
||||
from Pyxsim import testers
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def do_test(options, capfd, test_file, test_seed):
|
||||
|
||||
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||
|
||||
binary = f"{testname}/bin/{testname}.xe"
|
||||
|
||||
tester = testers.ComparisonTester(open("pass.expect"))
|
||||
|
||||
max_cycles = 15000000
|
||||
|
||||
simargs = [
|
||||
"--max-cycles",
|
||||
str(max_cycles),
|
||||
]
|
||||
|
||||
build_options = []
|
||||
build_options += ["TEST_SEED=" + str(test_seed)]
|
||||
|
||||
result = Pyxsim.run_on_simulator(
|
||||
binary,
|
||||
tester=tester,
|
||||
build_options=build_options,
|
||||
simargs=simargs,
|
||||
capfd=capfd,
|
||||
instTracing=options.enabletracing,
|
||||
vcdTracing=options.enablevcdtracing,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def test_mixer_routing_output(options, capfd, test_file, test_seed):
|
||||
|
||||
result = do_test(options, capfd, test_file, test_seed)
|
||||
|
||||
assert result
|
||||
19
tests/test_mixer_routing_input_ctrl/Makefile
Normal file
19
tests/test_mixer_routing_input_ctrl/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
|
||||
else
|
||||
TEST_DEBUG_FLAGS =
|
||||
endif
|
||||
|
||||
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS) -DXUD_WEAK_API=1
|
||||
|
||||
XCC_FLAGS = -O3 $(TEST_FLAGS)
|
||||
|
||||
TARGET = test_xs3_600.xn
|
||||
|
||||
USED_MODULES = lib_xua lib_logging lib_random
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
200
tests/test_mixer_routing_input_ctrl/src/main.xc
Normal file
200
tests/test_mixer_routing_input_ctrl/src/main.xc
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/* This tests checks the parsing of control requests to endpoint 0 cause the correct changes in mixer output routing */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "platform.h"
|
||||
#include "xua.h"
|
||||
#include "debug_print.h"
|
||||
#include "assert.h"
|
||||
#include "xud.h"
|
||||
#include "usbaudio20.h"
|
||||
#include "random.h"
|
||||
|
||||
#ifndef TEST_ITERATIONS
|
||||
#define TEST_ITERATIONS (100)
|
||||
#endif
|
||||
|
||||
#include "./../test_mixer_routing_output/src/mixer_test_shared.h"
|
||||
|
||||
/* Mixer input mapping - from xua_endpoint0.c */
|
||||
extern unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
|
||||
/* From xua_ep0_uacreqs.xc */
|
||||
int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
|
||||
|
||||
/* From xua_endpoint0.c */
|
||||
void InitLocalMixerState();
|
||||
|
||||
int g_src = 0;
|
||||
|
||||
/* Override func in lib_xud/src/user/client/XUD_EpFunctions.c for testing purposes */
|
||||
XUD_Result_t XUD_GetBuffer(XUD_ep ep_out, unsigned char buffer[], REFERENCE_PARAM(unsigned, length))
|
||||
{
|
||||
buffer[0] = g_src;
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in)
|
||||
{
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax)
|
||||
{
|
||||
assert(g_src == buffer[0]);
|
||||
assert(datalength == 1);
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
extern int volatile * const unsafe samples_to_device_map;
|
||||
extern int volatile * const unsafe samples_to_host_map;
|
||||
}
|
||||
|
||||
void Fake_Endpoint0(chanend c_mix_ctl)
|
||||
{
|
||||
XUD_ep ep0_out; /* Never initialised but not used */
|
||||
XUD_ep ep0_in; /* Never initialised but not used */
|
||||
USB_SetupPacket_t sp;
|
||||
|
||||
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
|
||||
|
||||
InitLocalMixerState();
|
||||
|
||||
sp.bmRequestType.Type = USB_BM_REQTYPE_TYPE_CLASS; // Note, parsing of this won't be tested since we call AudioClassRequests directly
|
||||
sp.bmRequestType.Recipient = USB_BM_REQTYPE_RECIP_INTER; // Note, parsing of this won't be tested since we call AudioClassRequests directly
|
||||
|
||||
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
|
||||
{
|
||||
int unitId = ID_XU_MIXSEL;
|
||||
unsigned mix = (random_get_random_number(rg) % (MAX_MIX_COUNT + 1)); // Mixs indexed from 1
|
||||
unsigned input = random_get_random_number(rg) % MIX_INPUTS;
|
||||
|
||||
/* Note, we don't currently support a mix input dervived from another mix
|
||||
* This is not trivial to test since the current mixer implementation only allows for one
|
||||
* config update per "trigger"
|
||||
*/
|
||||
unsigned src = random_get_random_number(rg) % (NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT);
|
||||
|
||||
debug_printf("Mapping mix %d input %d", mix, input);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
|
||||
/* Create Control request data for routing change */
|
||||
int cs = mix;
|
||||
int cn = input;
|
||||
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_H2D;
|
||||
sp.bRequest = CUR;
|
||||
sp.wValue = cn | (cs << 8);
|
||||
sp.wIndex = (unitId << 8);
|
||||
sp.wLength = 1;
|
||||
|
||||
g_src = src; /* This will get picked up by out implementation of XUD_GetBuffer */
|
||||
|
||||
/* Call the function used by Endpoint0 to parse the control data and update the mixer output routing */
|
||||
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
|
||||
|
||||
/* Note, there is a race risk here. This could be resolved by adding a handshake to UpdateMixerOutputRouting() etc */
|
||||
|
||||
/* Now check the mixer setting have been modified as expected. To do this we inspect "internal"
|
||||
* mixer and endpoint 0 state.
|
||||
*
|
||||
* Going forward we might wish to enhance the mixer API such that it can be tested as a black box.
|
||||
* This would require the addition of "GET" API over it's ctrl channel
|
||||
*/
|
||||
|
||||
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_D2H;
|
||||
|
||||
if(mix == 0)
|
||||
{
|
||||
/* If mix is 0 then we need to check that all mixers have been updated */
|
||||
for(int i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
assert(g_src == mixSel[i][cn]);
|
||||
|
||||
/* Need to read back from each mixer individually */
|
||||
sp.wValue = cn | ((i + 1)<< 8);
|
||||
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(g_src == mixSel[cs-1][cn]);
|
||||
|
||||
/* Test read back. Note, the checking is in our overridden implementation of XUD_SetBuffer_EpMax*/
|
||||
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
printstrln("PASS");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void Fake_XUA_AudioHub_CtrlTest(chanend c_mix_aud)
|
||||
{
|
||||
int readBuffNo = 0;
|
||||
unsigned underflowWord = 0;
|
||||
|
||||
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
|
||||
while(1)
|
||||
{
|
||||
unsigned command = DoSampleTransfer(c_mix_aud, readBuffNo, underflowWord);
|
||||
}
|
||||
}
|
||||
|
||||
void Fake_XUA_Buffer_Decouple_CtrlTest(chanend c_dec_mix)
|
||||
{
|
||||
unsigned samplesIn[NUM_USB_CHAN_IN];
|
||||
unsigned underflowSample;
|
||||
|
||||
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
|
||||
while(1)
|
||||
{
|
||||
select
|
||||
{
|
||||
case inuint_byref(c_dec_mix, underflowSample):
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
outuint(c_dec_mix, 0);
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
samplesIn[i] = inuint(c_dec_mix);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chan c_dec_mix;
|
||||
chan c_mix_aud;
|
||||
chan c_mix_ctl;
|
||||
|
||||
par
|
||||
{
|
||||
/* We need "fake" versions of the AudioHub and Decouple to keep the mixer running and taking updates via
|
||||
* it's control channel */
|
||||
Fake_XUA_Buffer_Decouple_CtrlTest(c_dec_mix);
|
||||
Fake_XUA_AudioHub_CtrlTest(c_mix_aud);
|
||||
|
||||
/* Mixer from lib_xua */
|
||||
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
|
||||
|
||||
Fake_Endpoint0(c_mix_ctl);
|
||||
}
|
||||
|
||||
/* TODO to hit this we need to fully close down i.e. kill mixer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
tests/test_mixer_routing_input_ctrl/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_input_ctrl/src/test_xs3_600.xn
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Network xmlns="http://www.xmos.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
|
||||
<Declarations>
|
||||
<Declaration>tileref tile[2]</Declaration>
|
||||
</Declarations>
|
||||
|
||||
<Packages>
|
||||
<Package id="0" Type="XS3-UnA-1024-FB265">
|
||||
<Nodes>
|
||||
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
|
||||
<Tile Number="0" Reference="tile[0]"/>
|
||||
<Tile Number="1" Reference="tile[1]"/>
|
||||
</Node>
|
||||
</Nodes>
|
||||
</Package>
|
||||
</Packages>
|
||||
|
||||
<JTAGChain>
|
||||
<JTAGDevice NodeId="0"/>
|
||||
</JTAGChain>
|
||||
|
||||
</Network>
|
||||
45
tests/test_mixer_routing_input_ctrl/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_input_ctrl/src/xua_conf.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_CONF_H_
|
||||
#define _XUA_CONF_H_
|
||||
|
||||
#define NUM_USB_CHAN_OUT (10)
|
||||
#define NUM_USB_CHAN_IN (10)
|
||||
#define I2S_CHANS_DAC (10)
|
||||
#define I2S_CHANS_ADC (10)
|
||||
|
||||
#define EXCLUDE_USB_AUDIO_MAIN
|
||||
|
||||
#define MIXER (1)
|
||||
#define MAX_MIX_COUNT (8)
|
||||
|
||||
#define UAC_FORCE_FEEDBACK_EP (0)
|
||||
#define XUA_NUM_PDM_MICS 0
|
||||
#define XUD_TILE 1
|
||||
#define AUDIO_IO_TILE 0
|
||||
|
||||
#ifndef MCLK_441
|
||||
#define MCLK_441 (512 * 44100)
|
||||
#endif
|
||||
|
||||
#ifndef MCLK_48
|
||||
#define MCLK_48 (512 * 48000)
|
||||
#endif
|
||||
|
||||
#define MIN_FREQ (44100)
|
||||
#define MAX_FREQ (192000)
|
||||
#define SPDIF_TX_INDEX 0
|
||||
#define VENDOR_STR "XMOS"
|
||||
#define VENDOR_ID 0x20B1
|
||||
#define PRODUCT_STR_A2 "Test device"
|
||||
#define PRODUCT_STR_A1 "Test device"
|
||||
#define PID_AUDIO_1 1
|
||||
#define PID_AUDIO_2 2
|
||||
#define AUDIO_CLASS 2
|
||||
#define AUDIO_CLASS_FALLBACK 0
|
||||
#define BCD_DEVICE 0x1234
|
||||
#define XUA_DFU_EN 0
|
||||
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
|
||||
#define XUA_MIC_FRAME_SIZE 240
|
||||
|
||||
#endif
|
||||
45
tests/test_mixer_routing_output.py
Normal file
45
tests/test_mixer_routing_output.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright 2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import Pyxsim
|
||||
from Pyxsim import testers
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def do_test(options, capfd, test_file, test_seed):
|
||||
|
||||
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||
|
||||
binary = f"{testname}/bin/{testname}.xe"
|
||||
|
||||
tester = testers.ComparisonTester(open("pass.expect"))
|
||||
|
||||
max_cycles = 15000000
|
||||
|
||||
simargs = [
|
||||
"--max-cycles",
|
||||
str(max_cycles),
|
||||
]
|
||||
|
||||
build_options = []
|
||||
build_options += ["TEST_SEED=" + str(test_seed)]
|
||||
|
||||
result = Pyxsim.run_on_simulator(
|
||||
binary,
|
||||
tester=tester,
|
||||
build_options=build_options,
|
||||
simargs=simargs,
|
||||
capfd=capfd,
|
||||
instTracing=options.enabletracing,
|
||||
vcdTracing=options.enablevcdtracing,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def test_mixer_routing_output(options, capfd, test_file, test_seed):
|
||||
|
||||
result = do_test(options, capfd, test_file, test_seed)
|
||||
|
||||
assert result
|
||||
19
tests/test_mixer_routing_output/Makefile
Normal file
19
tests/test_mixer_routing_output/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
|
||||
else
|
||||
TEST_DEBUG_FLAGS =
|
||||
endif
|
||||
|
||||
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS)
|
||||
|
||||
XCC_FLAGS = -O3 $(TEST_FLAGS)
|
||||
|
||||
TARGET = test_xs3_600.xn
|
||||
|
||||
USED_MODULES = lib_xua lib_logging lib_random
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
224
tests/test_mixer_routing_output/src/main.xc
Normal file
224
tests/test_mixer_routing_output/src/main.xc
Normal file
@@ -0,0 +1,224 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/* Tests that routing of mixer outputs behaves as expected
|
||||
*
|
||||
* "Outputs" from the device are to the USB host of one of the various audio interaces supported.
|
||||
|
||||
* This test assumes/checks the default routing for the USB host & audio interfaces is as follows:
|
||||
*
|
||||
* USB_FROM_HOST[0] -> AUD_INTERFACE_OUTPUT[0]
|
||||
* USB_FROM_HOST[1] -> AUD_INTERFACE_OUTPUT[1]
|
||||
* ...
|
||||
* USB_TO_HOST[0] <- AUD_INTERFACE_INPUT[0]
|
||||
* USB_TO_HOST[1] <- AUD_INTERFACE_INPUT[1]
|
||||
* ...
|
||||
*
|
||||
* This test also assumes/checks that the default routing into each of the MIX_INPUTS inputs into
|
||||
* each of the M mixer units is as follows:
|
||||
*
|
||||
* MIXER[0]:
|
||||
* USB_FROM_HOST[0] -> MIXER[0].INPUT[0]
|
||||
* USB_FROM_HOST[1] -> MIXER[0].INPUT[1]
|
||||
* ...
|
||||
USB_TO_HOST[0] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT]
|
||||
USB_TO_HOST[1] -> MIXER[0].INPUT[NUM_USB_CHAN_OUT+1]
|
||||
...
|
||||
|
||||
* MIXER[MAX_MIX_COUNT-1]:
|
||||
* USB_FROM_HOST[0] -> MIXER[MAX_MIX_COUNT-1].INPUT[0]
|
||||
* USB_FROM_HOST[1] -> MIXER[MAX_MIX_COUNT-1].INPUT[1]
|
||||
* ...
|
||||
*
|
||||
* (If the number of mixer inputs > NUM_USB_CHAN_OUT then see ordering in comment regarding
|
||||
* SOURCE_COUNT below)
|
||||
*
|
||||
* By default none of the MAX_MIX_COUNT output from the mixers are routed anywwhere, but this test ensures
|
||||
* that they can be.
|
||||
*
|
||||
* This test assumes that none of the mixer weights are changed.
|
||||
* This test does not test changing the inputs to the mixer.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "platform.h"
|
||||
#include "xua.h"
|
||||
#include "debug_print.h"
|
||||
#include "assert.h"
|
||||
#include "random.h"
|
||||
|
||||
#ifndef TEST_ITERATIONS
|
||||
#define TEST_ITERATIONS (100)
|
||||
#endif
|
||||
|
||||
#include "./mixer_test_shared.h"
|
||||
|
||||
void UpdateModel(uint32_t modelOut[CHANNEL_MAP_AUD_SIZE], uint32_t modelMixerOut[MAX_MIX_COUNT], uint32_t modelIn[NUM_USB_CHAN_IN],
|
||||
int map, int dst, int src)
|
||||
{
|
||||
unsigned sample = 0;
|
||||
if(src == (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT))
|
||||
{
|
||||
SET_SOURCE(sample, SRC_OFF);
|
||||
}
|
||||
else if(src >= (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN))
|
||||
{
|
||||
src -= (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN);
|
||||
sample = modelMixerOut[src];
|
||||
}
|
||||
else if (src >= NUM_USB_CHAN_IN)
|
||||
{
|
||||
SET_SOURCE(sample, SRC_AUDIF);
|
||||
src -= NUM_USB_CHAN_OUT;
|
||||
SET_CHANNEL(sample, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_SOURCE(sample, SRC_HOST);
|
||||
SET_CHANNEL(sample, src);
|
||||
}
|
||||
|
||||
switch(map)
|
||||
{
|
||||
case SET_SAMPLES_TO_DEVICE_MAP:
|
||||
modelOut[dst] = sample;
|
||||
break;
|
||||
|
||||
case SET_SAMPLES_TO_HOST_MAP:
|
||||
modelIn[dst] = sample;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* This task configures the routing and maintains a model of the expected routing output
|
||||
* it provides this to the Fake AudioHub and Fake Decouple tasks such that they can self check
|
||||
*/
|
||||
void stim(chanend c_stim_ah, chanend c_stim_de, chanend c_mix_ctl)
|
||||
{
|
||||
uint32_t modelOut[CHANNEL_MAP_AUD_SIZE];
|
||||
uint32_t modelIn[CHANNEL_MAP_USB_SIZE];
|
||||
uint32_t modelMixerOut[MAX_MIX_COUNT];
|
||||
uint32_t testCmd[] = {SET_SAMPLES_TO_HOST_MAP, SET_SAMPLES_TO_DEVICE_MAP};
|
||||
|
||||
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
|
||||
|
||||
/* By default the mixer should output samples from USB host unmodified
|
||||
* See mixer.xc L780
|
||||
*/
|
||||
for(size_t i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
uint32_t sample = 0;
|
||||
SET_SOURCE(sample, SRC_HOST);
|
||||
SET_CHANNEL(sample, i);
|
||||
modelMixerOut[i] = sample;
|
||||
}
|
||||
|
||||
/* Init modelOut for default routing */
|
||||
/* Default routing is USB[0] -> AUD_IF[0] etc */
|
||||
for(size_t i = 0; i < CHANNEL_MAP_AUD_SIZE; i++)
|
||||
{
|
||||
uint32_t sample = 0;
|
||||
SET_SOURCE(sample, SRC_HOST);
|
||||
SET_CHANNEL(sample, i);
|
||||
modelOut[i] = sample;
|
||||
}
|
||||
|
||||
/* Init modelIn for default routing */
|
||||
/* Default routing is AUD_IF[0] -> USB[0] etc */
|
||||
for(size_t i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
uint32_t sample = 0;
|
||||
SET_SOURCE(sample, SRC_AUDIF);
|
||||
SET_CHANNEL(sample, i);
|
||||
modelIn[i] = sample;
|
||||
}
|
||||
|
||||
/* Check default routing */
|
||||
/* Send expected to AudioHub */
|
||||
SendTrigger(c_stim_ah, 2);
|
||||
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||
|
||||
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
|
||||
{
|
||||
/* Make a random update to the routing - route a random source to a random destination */
|
||||
unsigned map = testCmd[random_get_random_number(rg) % (sizeof(testCmd)/sizeof(testCmd[0]))];
|
||||
unsigned dst = random_get_random_number(rg) % CHANNEL_MAP_AUD_SIZE; // TODO this should be CHANNEL_MAP_USB_SIZE for SET_SAMPLES_TO_HOST_MAP
|
||||
unsigned src = random_get_random_number(rg) % (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
|
||||
|
||||
switch(map)
|
||||
{
|
||||
case SET_SAMPLES_TO_DEVICE_MAP:
|
||||
debug_printf("Mapping output to AudioIF: %d", dst);
|
||||
PrintDestString(map, dst);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
|
||||
/* Update the mixer */
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
|
||||
break;
|
||||
|
||||
case SET_SAMPLES_TO_HOST_MAP:
|
||||
debug_printf("Mapping output to Host : %d", dst);
|
||||
PrintDestString(map, dst);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
|
||||
/* Update the mixer */
|
||||
SendTrigger(c_stim_ah, 1);
|
||||
UpdateMixerOutputRouting(c_mix_ctl, map, dst, src);
|
||||
break;
|
||||
|
||||
default:
|
||||
printstr("ERROR: Bad cmd in stim(): ");
|
||||
printintln(map);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update the model */
|
||||
UpdateModel(modelOut, modelMixerOut, modelIn, map, dst, src);
|
||||
|
||||
SendExpected(c_stim_ah, c_stim_de, modelOut, modelIn);
|
||||
|
||||
}
|
||||
|
||||
/* Send kill messages to Fake AudioHub & Fake Decouple */
|
||||
outct(c_stim_ah, XS1_CT_END);
|
||||
inct(c_stim_ah);
|
||||
|
||||
outct(c_stim_de, XS1_CT_END);
|
||||
inct(c_stim_de);
|
||||
|
||||
printstrln("PASS");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chan c_dec_mix;
|
||||
chan c_mix_aud;
|
||||
chan c_mix_ctl;
|
||||
chan c_stim_ah;
|
||||
chan c_stim_de;
|
||||
|
||||
par
|
||||
{
|
||||
Fake_XUA_Buffer_Decouple(c_dec_mix, c_stim_de);
|
||||
Fake_XUA_AudioHub(c_mix_aud, c_stim_ah);
|
||||
|
||||
/* Mixer from lib_xua */
|
||||
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
|
||||
|
||||
stim(c_stim_ah, c_stim_de, c_mix_ctl);
|
||||
}
|
||||
|
||||
/* TODO to hit this we need to fully close down i.e. kill mixer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
325
tests/test_mixer_routing_output/src/mixer_test_shared.h
Normal file
325
tests/test_mixer_routing_output/src/mixer_test_shared.h
Normal file
@@ -0,0 +1,325 @@
|
||||
// Copyright 2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef TEST_SEED
|
||||
#error TEST_SEED must be defined!
|
||||
#endif
|
||||
|
||||
/* A limitation of the design is that the number of routable output destinations cannot be larger than NUM_USB_CHAN_OUT.
|
||||
* This is due to the transfer samples from Mixer to AudioHub tasks being in blocks of NUM_USB_CHAN_OUT.
|
||||
* This is not normally an issue - since every physical output interface channel on the device is normally derived from a
|
||||
* USB channel from the host, but it certainly is a restriction.
|
||||
*/
|
||||
#define CHANNEL_MAP_AUD_SIZE NUM_USB_CHAN_OUT
|
||||
|
||||
#define CHANNEL_MAP_USB_SIZE NUM_USB_CHAN_IN
|
||||
|
||||
/* Number of channel sources, the channel ordering is as follows
|
||||
* i.e.
|
||||
* [0:NUM_USB_CHAN_OUT-1] : Channels from USB Host
|
||||
* [NUM_USB_CHAN_OUT:NUM_USB_CHAN_IN-1] : Channels from Audio Interfaces
|
||||
* [NUM_USB_CHAN_N:MAX_MIX_COUNT-1] : Channels from Mixers
|
||||
* [MAX_MIX_COUNT]: "Off" (Essentially samples always 0)
|
||||
*/
|
||||
/* Note, One larger for an "off" channel for mixer sources" */
|
||||
#define SOURCE_COUNT (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1)
|
||||
|
||||
#define SET_EXPECTED (9)
|
||||
#define TRIGGER (7)
|
||||
|
||||
// Test sample format:
|
||||
// byte[0]: Sample counter
|
||||
// byte[1]: Channel
|
||||
// byte[3]: Source (HOST:1/AUD IF:0)
|
||||
#define SRC_HOST (2)
|
||||
#define SRC_AUDIF (1)
|
||||
#define SRC_OFF (0) // Important that this is 0 since mixer will generate 0 samples for 'off'
|
||||
|
||||
#define GET_COUNT(x) ((x>>8) & 0xff)
|
||||
#define GET_CHANNEL(x) ((x >> 16) & 0xff)
|
||||
#define GET_SOURCE(x) ((x >> 24) & 0xff)
|
||||
|
||||
#define SET_COUNT(x, y) y = y & 0xff; x = x | (y<<8);
|
||||
#define SET_CHANNEL(x, y) y = y & 0xff; x = x | (y<<16);
|
||||
#define SET_SOURCE(x, y) x = x | (y<<24);
|
||||
|
||||
void exit(int);
|
||||
|
||||
#pragma select handler
|
||||
static inline void testct_byref(chanend c, unsigned &isCt)
|
||||
{
|
||||
isCt = testct(c);
|
||||
}
|
||||
|
||||
void SendTrigger(chanend c_stim_ah, int count)
|
||||
{
|
||||
for(int i = 0; i < count; i++)
|
||||
outuint(c_stim_ah, TRIGGER);
|
||||
}
|
||||
|
||||
uint32_t CreateSample(uint32_t modelMixerOutput[], int src)
|
||||
{
|
||||
uint32_t sample = 0;
|
||||
|
||||
if(src == (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT))
|
||||
{
|
||||
SET_SOURCE(sample, SRC_OFF);
|
||||
}
|
||||
else if(src >= (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN))
|
||||
{
|
||||
src -= (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN);
|
||||
sample = modelMixerOutput[src];
|
||||
}
|
||||
else if (src >= NUM_USB_CHAN_IN)
|
||||
{
|
||||
SET_SOURCE(sample, SRC_AUDIF);
|
||||
src -= NUM_USB_CHAN_OUT;
|
||||
SET_CHANNEL(sample, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_SOURCE(sample, SRC_HOST);
|
||||
SET_CHANNEL(sample, src);
|
||||
}
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
void PrintSourceString(unsigned source)
|
||||
{
|
||||
debug_printf(" ");
|
||||
if(source < NUM_USB_CHAN_OUT)
|
||||
{
|
||||
debug_printf("(DEVICE IN - HOST%d)", source);
|
||||
}
|
||||
else if(source < (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN))
|
||||
{
|
||||
debug_printf("(DEVICE IN - AudioIF %d)", source - NUM_USB_CHAN_OUT);
|
||||
}
|
||||
else if(source < (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT))
|
||||
{
|
||||
debug_printf("(MIX %d)", source - NUM_USB_CHAN_OUT - NUM_USB_CHAN_IN);
|
||||
}
|
||||
else
|
||||
debug_printf("(off)");
|
||||
debug_printf(" ");
|
||||
}
|
||||
|
||||
void PrintDestString(unsigned map, unsigned dest)
|
||||
{
|
||||
switch(map)
|
||||
{
|
||||
case SET_SAMPLES_TO_DEVICE_MAP:
|
||||
debug_printf("(DEVICE OUT - AudioIF)");
|
||||
break;
|
||||
case SET_SAMPLES_TO_HOST_MAP:
|
||||
debug_printf("(DEVICE OUT - HOST)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintSample(unsigned sample)
|
||||
{
|
||||
debug_printf("SOURCE: ");
|
||||
if(GET_SOURCE(sample) == SRC_HOST)
|
||||
debug_printf("HOST ");
|
||||
else if(GET_SOURCE(sample) == SRC_AUDIF)
|
||||
debug_printf("AUDIF ");
|
||||
else if(GET_SOURCE(sample) == SRC_OFF)
|
||||
debug_printf("OFF ");
|
||||
else
|
||||
debug_printf("UNKNOWN ");
|
||||
|
||||
debug_printf("CHANNEL: %d", GET_CHANNEL(sample));
|
||||
}
|
||||
|
||||
/* Required by lib_xua */
|
||||
void AudioHwInit()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Required by lib_xua */
|
||||
void AudioHwConfig(unsigned samFreq, unsigned mClk, unsigned dsdMode, unsigned sampRes_DAC, unsigned sampRes_ADC)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* From xua_ep0_uacreqs.xc */
|
||||
void UpdateMixerOutputRouting(chanend c_mix_ctl, unsigned map, unsigned dst, unsigned src);
|
||||
void UpdateMixMap(chanend c_mix_ctl, int mix, int input, int src);
|
||||
void UpdateMixerWeight(chanend c_mix_ctl, int mix, int index, unsigned val);
|
||||
|
||||
void CheckBlock(unsigned samplesOut[], uint32_t expectedOut[], size_t len)
|
||||
{
|
||||
int fail = 0;;
|
||||
for(int j = 0; j < len; j++)
|
||||
{
|
||||
debug_printf("%d: Expected: ", j);
|
||||
PrintSample(expectedOut[j]);
|
||||
debug_printf("\n");
|
||||
if(expectedOut[j] != samplesOut[j])
|
||||
{
|
||||
printstr("ERROR: Actual: ");
|
||||
PrintSample(samplesOut[j]);
|
||||
debug_printf(" (%x)", samplesOut[j]);
|
||||
printstr("\n");
|
||||
fail = 1;
|
||||
}
|
||||
//assert(expectedOut[j] == samplesOut[j]);
|
||||
}
|
||||
assert(!fail);
|
||||
}
|
||||
|
||||
/* Sending expected also causes fake_audiohub and fake_decouple to run sample checks */
|
||||
void SendExpected(chanend c_stim_ah, chanend c_stim_de, uint32_t modelOut[], uint32_t modelIn[])
|
||||
{
|
||||
/* Send expected to AudioHub */
|
||||
outuint(c_stim_ah, SET_EXPECTED);
|
||||
|
||||
for(int i = 0; i < CHANNEL_MAP_AUD_SIZE; i++)
|
||||
{
|
||||
outuint(c_stim_ah, modelOut[i]);
|
||||
}
|
||||
|
||||
/* Wait for handshake back and move on to next test */
|
||||
inuint(c_stim_ah);
|
||||
|
||||
/* Send expected to Decouple */
|
||||
outuint(c_stim_de, SET_EXPECTED);
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
outuint(c_stim_de, modelIn[i]);
|
||||
}
|
||||
|
||||
/* Wait for handshake back and move on to next test */
|
||||
inuint(c_stim_de);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* From xua_audiohub.xc */
|
||||
extern unsigned samplesOut[NUM_USB_CHAN_OUT];
|
||||
extern unsigned samplesIn[2][NUM_USB_CHAN_IN];
|
||||
#include "xua_audiohub_st.h"
|
||||
|
||||
int Fake_XUA_AudioHub(chanend c_mix_aud, chanend c_stim)
|
||||
{
|
||||
int readBuffNo = 0;
|
||||
unsigned underflowWord = 0;
|
||||
uint32_t expectedOut[NUM_USB_CHAN_OUT];
|
||||
unsigned ct = 0;
|
||||
unsigned cmd = 0;
|
||||
|
||||
for(size_t i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
/* Note, we only used readBufNo = 0 */
|
||||
unsigned sample = 0;
|
||||
SET_SOURCE(sample, SRC_AUDIF);
|
||||
SET_CHANNEL(sample, i);
|
||||
samplesIn[0][i] = sample;
|
||||
}
|
||||
|
||||
while(!ct)
|
||||
{
|
||||
|
||||
select
|
||||
{
|
||||
case testct_byref(c_stim, ct):
|
||||
|
||||
if(!ct)
|
||||
{
|
||||
cmd = inuint(c_stim);
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case SET_EXPECTED:
|
||||
|
||||
for(int j = 0; j < NUM_USB_CHAN_OUT; j++)
|
||||
{
|
||||
expectedOut[j] = inuint(c_stim);
|
||||
}
|
||||
|
||||
debug_printf("AudioHub:\n");
|
||||
CheckBlock(samplesOut, expectedOut, NUM_USB_CHAN_OUT);
|
||||
/* Handshake back */
|
||||
outuint(c_stim, 0);
|
||||
break;
|
||||
|
||||
case TRIGGER:
|
||||
/* This will populate samplesOut and send out samplesIn[readBuffNo] */
|
||||
unsigned command = DoSampleTransfer(c_mix_aud, readBuffNo, underflowWord);
|
||||
break;
|
||||
|
||||
default:
|
||||
printstr("ERROR: bad cmd in Fake_XUA_AudioHub: ");
|
||||
printintln(cmd);
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
outct(c_stim, XS1_CT_END);
|
||||
inct(c_stim);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Fake_XUA_Buffer_Decouple(chanend c_dec_mix, chanend c_stim)
|
||||
{
|
||||
uint32_t expectedSamplesIn[NUM_USB_CHAN_IN];
|
||||
unsigned samplesIn[NUM_USB_CHAN_IN];
|
||||
unsigned ct;
|
||||
unsigned underflowSample;
|
||||
|
||||
while(!ct)
|
||||
{
|
||||
select
|
||||
{
|
||||
case inuint_byref(c_dec_mix, underflowSample):
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
unsigned sample = 0;
|
||||
SET_SOURCE(sample, SRC_HOST);
|
||||
SET_CHANNEL(sample, i);
|
||||
outuint(c_dec_mix, sample);
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
samplesIn[i] = inuint(c_dec_mix);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case testct_byref(c_stim, ct):
|
||||
|
||||
if(!ct)
|
||||
{
|
||||
inuint(c_stim); // TODO don't really need this
|
||||
|
||||
/* Get expected */
|
||||
for(int j = 0; j < NUM_USB_CHAN_IN; j++)
|
||||
{
|
||||
expectedSamplesIn[j] = inuint(c_stim);
|
||||
}
|
||||
|
||||
debug_printf("Decouple:\n");
|
||||
CheckBlock(samplesIn, expectedSamplesIn, NUM_USB_CHAN_IN);
|
||||
|
||||
/* Handshake back */
|
||||
outuint(c_stim, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
outct(c_stim, XS1_CT_END);
|
||||
inct(c_stim);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
24
tests/test_mixer_routing_output/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_output/src/test_xs3_600.xn
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Network xmlns="http://www.xmos.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
|
||||
<Declarations>
|
||||
<Declaration>tileref tile[2]</Declaration>
|
||||
</Declarations>
|
||||
|
||||
<Packages>
|
||||
<Package id="0" Type="XS3-UnA-1024-FB265">
|
||||
<Nodes>
|
||||
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
|
||||
<Tile Number="0" Reference="tile[0]"/>
|
||||
<Tile Number="1" Reference="tile[1]"/>
|
||||
</Node>
|
||||
</Nodes>
|
||||
</Package>
|
||||
</Packages>
|
||||
|
||||
<JTAGChain>
|
||||
<JTAGDevice NodeId="0"/>
|
||||
</JTAGChain>
|
||||
|
||||
</Network>
|
||||
45
tests/test_mixer_routing_output/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_output/src/xua_conf.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_CONF_H_
|
||||
#define _XUA_CONF_H_
|
||||
|
||||
#define NUM_USB_CHAN_OUT (10)
|
||||
#define NUM_USB_CHAN_IN (10)
|
||||
#define I2S_CHANS_DAC (10)
|
||||
#define I2S_CHANS_ADC (10)
|
||||
|
||||
#define EXCLUDE_USB_AUDIO_MAIN
|
||||
|
||||
#define MIXER (1)
|
||||
#define MAX_MIX_COUNT (8)
|
||||
|
||||
#define UAC_FORCE_FEEDBACK_EP (0)
|
||||
#define XUA_NUM_PDM_MICS 0
|
||||
#define XUD_TILE 1
|
||||
#define AUDIO_IO_TILE 0
|
||||
|
||||
#ifndef MCLK_441
|
||||
#define MCLK_441 (512 * 44100)
|
||||
#endif
|
||||
|
||||
#ifndef MCLK_48
|
||||
#define MCLK_48 (512 * 48000)
|
||||
#endif
|
||||
|
||||
#define MIN_FREQ (44100)
|
||||
#define MAX_FREQ (192000)
|
||||
#define SPDIF_TX_INDEX 0
|
||||
#define VENDOR_STR "XMOS"
|
||||
#define VENDOR_ID 0x20B1
|
||||
#define PRODUCT_STR_A2 "Test device"
|
||||
#define PRODUCT_STR_A1 "Test device"
|
||||
#define PID_AUDIO_1 1
|
||||
#define PID_AUDIO_2 2
|
||||
#define AUDIO_CLASS 2
|
||||
#define AUDIO_CLASS_FALLBACK 0
|
||||
#define BCD_DEVICE 0x1234
|
||||
#define XUA_DFU_EN 0
|
||||
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
|
||||
#define XUA_MIC_FRAME_SIZE 240
|
||||
|
||||
#endif
|
||||
45
tests/test_mixer_routing_output_ctrl.py
Normal file
45
tests/test_mixer_routing_output_ctrl.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright 2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import Pyxsim
|
||||
from Pyxsim import testers
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def do_test(options, capfd, test_file, test_seed):
|
||||
|
||||
testname, _ = os.path.splitext(os.path.basename(test_file))
|
||||
|
||||
binary = f"{testname}/bin/{testname}.xe"
|
||||
|
||||
tester = testers.ComparisonTester(open("pass.expect"))
|
||||
|
||||
max_cycles = 15000000
|
||||
|
||||
simargs = [
|
||||
"--max-cycles",
|
||||
str(max_cycles),
|
||||
]
|
||||
|
||||
build_options = []
|
||||
build_options += ["TEST_SEED=" + str(test_seed)]
|
||||
|
||||
result = Pyxsim.run_on_simulator(
|
||||
binary,
|
||||
tester=tester,
|
||||
build_options=build_options,
|
||||
simargs=simargs,
|
||||
capfd=capfd,
|
||||
instTracing=options.enabletracing,
|
||||
vcdTracing=options.enablevcdtracing,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def test_mixer_routing_output(options, capfd, test_file, test_seed):
|
||||
|
||||
result = do_test(options, capfd, test_file, test_seed)
|
||||
|
||||
assert result
|
||||
19
tests/test_mixer_routing_output_ctrl/Makefile
Normal file
19
tests/test_mixer_routing_output_ctrl/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
TEST_DEBUG_FLAGS = -g -DDEBUG_PRINT_ENABLE=1
|
||||
else
|
||||
TEST_DEBUG_FLAGS =
|
||||
endif
|
||||
|
||||
TEST_FLAGS = -DTEST_SEED=$(TEST_SEED) $(TEST_DEBUG_FLAGS) -DXUD_WEAK_API=1
|
||||
|
||||
XCC_FLAGS = -O3 $(TEST_FLAGS)
|
||||
|
||||
TARGET = test_xs3_600.xn
|
||||
|
||||
USED_MODULES = lib_xua lib_logging lib_random
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
221
tests/test_mixer_routing_output_ctrl/src/main.xc
Normal file
221
tests/test_mixer_routing_output_ctrl/src/main.xc
Normal file
@@ -0,0 +1,221 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/* This tests checks the parsing of control requests to endpoint 0 cause the correct changes in mixer output routing */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "platform.h"
|
||||
#include "xua.h"
|
||||
#include "debug_print.h"
|
||||
#include "assert.h"
|
||||
#include "xud.h"
|
||||
#include "usbaudio20.h"
|
||||
#include "random.h"
|
||||
|
||||
#ifndef TEST_ITERATIONS
|
||||
#define TEST_ITERATIONS (100)
|
||||
#endif
|
||||
|
||||
#include "./../test_mixer_routing_output/src/mixer_test_shared.h"
|
||||
|
||||
/* Device channel mapping */
|
||||
extern unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
||||
extern unsigned char channelMapUsb[NUM_USB_CHAN_IN];
|
||||
|
||||
/* From xua_ep0_uacreqs.xc */
|
||||
int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl);
|
||||
|
||||
/* From xua_endpoint0.c */
|
||||
void InitLocalMixerState();
|
||||
|
||||
int g_src = 0;
|
||||
|
||||
/* Override func in lib_xud/src/user/client/XUD_EpFunctions.c for testing purposes */
|
||||
XUD_Result_t XUD_GetBuffer(XUD_ep ep_out, unsigned char buffer[], REFERENCE_PARAM(unsigned, length))
|
||||
{
|
||||
buffer[0] = g_src;
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in)
|
||||
{
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax)
|
||||
{
|
||||
assert(g_src == buffer[0]);
|
||||
assert(datalength == 1);
|
||||
return XUD_RES_OKAY;
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
extern int volatile * const unsafe samples_to_device_map;
|
||||
extern int volatile * const unsafe samples_to_host_map;
|
||||
}
|
||||
|
||||
void Fake_Endpoint0(chanend c_mix_ctl)
|
||||
{
|
||||
XUD_ep ep0_out; /* Never initialised but not used */
|
||||
XUD_ep ep0_in; /* Never initialised but not used */
|
||||
unsigned unitIds[] = {ID_XU_OUT, ID_XU_IN};
|
||||
USB_SetupPacket_t sp;
|
||||
|
||||
random_generator_t rg = random_create_generator_from_seed(TEST_SEED);
|
||||
|
||||
InitLocalMixerState();
|
||||
|
||||
sp.bmRequestType.Type = USB_BM_REQTYPE_TYPE_CLASS; // Note, parsing of this won't be tested since we call AudioClassRequests directly
|
||||
sp.bmRequestType.Recipient = USB_BM_REQTYPE_RECIP_INTER; // Note, parsing of this won't be tested since we call AudioClassRequests directly
|
||||
|
||||
for(int testIter = 0; testIter < TEST_ITERATIONS; testIter++)
|
||||
{
|
||||
int unitId = unitIds[random_get_random_number(rg) % (sizeof(unitIds)/sizeof(unitIds[0]))];
|
||||
unsigned dst = random_get_random_number(rg);
|
||||
|
||||
/* Note, we don't currently support a mix input derived from another mix
|
||||
* This is not trivial to test since the current mixer implementation only allows for one
|
||||
* config update per "trigger"
|
||||
*/
|
||||
int src = random_get_random_number(rg) % NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT;
|
||||
|
||||
switch(unitId)
|
||||
{
|
||||
case ID_XU_OUT:
|
||||
dst %= CHANNEL_MAP_AUD_SIZE;
|
||||
debug_printf("Mapping output to AudioIF: %d", dst);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
break;
|
||||
|
||||
case ID_XU_IN:
|
||||
dst %= CHANNEL_MAP_USB_SIZE;
|
||||
debug_printf("Mapping output to Host : %d", dst);
|
||||
debug_printf(" from %d", src);
|
||||
PrintSourceString(src);
|
||||
debug_printf("\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printstr("ERROR: Bad cmd in stim(): ");
|
||||
printintln(unitId);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Create Control request data for routing change */
|
||||
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_H2D;
|
||||
sp.bRequest = CUR;
|
||||
sp.wValue = dst & 0xff;
|
||||
sp.wIndex = (unitId << 8);
|
||||
sp.wLength = 1;
|
||||
|
||||
g_src = src; /* This will get picked up by out implementation of XUD_GetBuffer */
|
||||
|
||||
/* Call the function used by Endpoint0() to parse the control data and update the mixer output routing */
|
||||
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
|
||||
|
||||
/* Note, there is a race risk here. This could be resolved by adding a handshake to UpdateMixerOutputRouting() etc */
|
||||
|
||||
/* Now check the mixer setting have been modified as expected. To do this we inspect "internal"
|
||||
* mixer and endpoint 0 state.
|
||||
*
|
||||
* Going forward we might wish to enhance the mixer API such that it can be tested as a black box.
|
||||
* This would require the addition of "GET" API over it's ctrl channel
|
||||
*/
|
||||
switch(unitId)
|
||||
{
|
||||
case ID_XU_OUT:
|
||||
assert(g_src == channelMapAud[dst]);
|
||||
unsafe
|
||||
{
|
||||
assert(g_src == samples_to_device_map[dst]);
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_XU_IN:
|
||||
assert(g_src == channelMapUsb[dst]);
|
||||
unsafe
|
||||
{
|
||||
assert(g_src == samples_to_host_map[dst]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Test read back. Note, the checking is our overridden implementation of XUD_SetBuffer_EpMax*/
|
||||
sp.bmRequestType.Direction = USB_BM_REQTYPE_DIRECTION_D2H;
|
||||
AudioClassRequests_2(ep0_out, ep0_in, sp, null, c_mix_ctl, null);
|
||||
}
|
||||
|
||||
printstrln("PASS");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void Fake_XUA_AudioHub_CtrlTest(chanend c_mix_aud)
|
||||
{
|
||||
int readBuffNo = 0;
|
||||
unsigned underflowWord = 0;
|
||||
|
||||
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
|
||||
while(1)
|
||||
{
|
||||
unsigned command = DoSampleTransfer(c_mix_aud, readBuffNo, underflowWord);
|
||||
}
|
||||
}
|
||||
|
||||
void Fake_XUA_Buffer_Decouple_CtrlTest(chanend c_dec_mix)
|
||||
{
|
||||
unsigned samplesIn[NUM_USB_CHAN_IN];
|
||||
unsigned underflowSample;
|
||||
|
||||
/* Continually send/receive samples to/from mixer, no checking of samples since this is purely a control test */
|
||||
while(1)
|
||||
{
|
||||
select
|
||||
{
|
||||
case inuint_byref(c_dec_mix, underflowSample):
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
outuint(c_dec_mix, 0);
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
samplesIn[i] = inuint(c_dec_mix);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chan c_dec_mix;
|
||||
chan c_mix_aud;
|
||||
chan c_mix_ctl;
|
||||
|
||||
par
|
||||
{
|
||||
/* We need "fake" versions of the AudioHub and Decouple to keep the mixer running and taking updates via
|
||||
* it's control channel */
|
||||
Fake_XUA_Buffer_Decouple_CtrlTest(c_dec_mix);
|
||||
Fake_XUA_AudioHub_CtrlTest(c_mix_aud);
|
||||
|
||||
/* Mixer from lib_xua */
|
||||
mixer(c_dec_mix, c_mix_aud, c_mix_ctl);
|
||||
|
||||
Fake_Endpoint0(c_mix_ctl);
|
||||
}
|
||||
|
||||
/* TODO to hit this we need to fully close down i.e. kill mixer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
tests/test_mixer_routing_output_ctrl/src/test_xs3_600.xn
Normal file
24
tests/test_mixer_routing_output_ctrl/src/test_xs3_600.xn
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Network xmlns="http://www.xmos.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.xmos.com http://www.xmos.com">
|
||||
<Declarations>
|
||||
<Declaration>tileref tile[2]</Declaration>
|
||||
</Declarations>
|
||||
|
||||
<Packages>
|
||||
<Package id="0" Type="XS3-UnA-1024-FB265">
|
||||
<Nodes>
|
||||
<Node Id="0" InPackageId="0" Type="XS3-L16A-1024" Oscillator="24MHz" SystemFrequency="600MHz" ReferenceFrequency="100MHz">
|
||||
<Tile Number="0" Reference="tile[0]"/>
|
||||
<Tile Number="1" Reference="tile[1]"/>
|
||||
</Node>
|
||||
</Nodes>
|
||||
</Package>
|
||||
</Packages>
|
||||
|
||||
<JTAGChain>
|
||||
<JTAGDevice NodeId="0"/>
|
||||
</JTAGChain>
|
||||
|
||||
</Network>
|
||||
45
tests/test_mixer_routing_output_ctrl/src/xua_conf.h
Normal file
45
tests/test_mixer_routing_output_ctrl/src/xua_conf.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2016-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_CONF_H_
|
||||
#define _XUA_CONF_H_
|
||||
|
||||
#define NUM_USB_CHAN_OUT (10)
|
||||
#define NUM_USB_CHAN_IN (10)
|
||||
#define I2S_CHANS_DAC (10)
|
||||
#define I2S_CHANS_ADC (10)
|
||||
|
||||
#define EXCLUDE_USB_AUDIO_MAIN
|
||||
|
||||
#define MIXER (1)
|
||||
#define MAX_MIX_COUNT (8)
|
||||
|
||||
#define UAC_FORCE_FEEDBACK_EP (0)
|
||||
#define XUA_NUM_PDM_MICS 0
|
||||
#define XUD_TILE 1
|
||||
#define AUDIO_IO_TILE 0
|
||||
|
||||
#ifndef MCLK_441
|
||||
#define MCLK_441 (512 * 44100)
|
||||
#endif
|
||||
|
||||
#ifndef MCLK_48
|
||||
#define MCLK_48 (512 * 48000)
|
||||
#endif
|
||||
|
||||
#define MIN_FREQ (44100)
|
||||
#define MAX_FREQ (192000)
|
||||
#define SPDIF_TX_INDEX 0
|
||||
#define VENDOR_STR "XMOS"
|
||||
#define VENDOR_ID 0x20B1
|
||||
#define PRODUCT_STR_A2 "Test device"
|
||||
#define PRODUCT_STR_A1 "Test device"
|
||||
#define PID_AUDIO_1 1
|
||||
#define PID_AUDIO_2 2
|
||||
#define AUDIO_CLASS 2
|
||||
#define AUDIO_CLASS_FALLBACK 0
|
||||
#define BCD_DEVICE 0x1234
|
||||
#define XUA_DFU_EN 0
|
||||
#define MIC_DUAL_ENABLED 1 //Use single thread, dual PDM mic
|
||||
#define XUA_MIC_FRAME_SIZE 240
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user