forked from PAWPAW-Mirror/lib_xua
Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
# XMOS bin files
|
||||||
*.dSYM
|
|
||||||
*/.build_*/*
|
|
||||||
*/bin/*
|
|
||||||
*.o
|
|
||||||
*.xe
|
*.xe
|
||||||
*.vcd
|
*.bin
|
||||||
*.swo
|
*/bin/*
|
||||||
|
|
||||||
|
# XMOS temp files
|
||||||
|
.build*
|
||||||
|
*.a
|
||||||
|
_build*
|
||||||
|
*.i
|
||||||
*.s
|
*.s
|
||||||
*.xi
|
*.xi
|
||||||
*.i
|
*.o
|
||||||
*.bin
|
*/.build_*/*
|
||||||
*~
|
|
||||||
*.a
|
# Temp files
|
||||||
*.swp
|
|
||||||
*.*~
|
|
||||||
*.pyc
|
|
||||||
.build*
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
test_results.csv
|
*.*~
|
||||||
_build*
|
*.swp
|
||||||
**/.venv/**
|
*.swn
|
||||||
**/.vscode/**
|
*~
|
||||||
**.egg-info
|
*.swo
|
||||||
*.pdf
|
|
||||||
*tests/logs/*
|
|
||||||
|
|
||||||
# waf build files
|
# waf build files
|
||||||
.lock-waf_*
|
.lock-waf_*
|
||||||
@@ -36,3 +32,19 @@ xscope.xmt
|
|||||||
# Traces
|
# Traces
|
||||||
*.gtkw
|
*.gtkw
|
||||||
*.vcd
|
*.vcd
|
||||||
|
|
||||||
|
# Host binaries
|
||||||
|
host_usb_mixer_control/xmos_mixer
|
||||||
|
|
||||||
|
# Documentation build
|
||||||
|
*.pdf
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
*.log
|
||||||
|
*.dSYM
|
||||||
|
*.vcd
|
||||||
|
*.pyc
|
||||||
|
**/.venv/**
|
||||||
|
**/.vscode/**
|
||||||
|
**.egg-info
|
||||||
|
*tests/logs/*
|
||||||
|
|||||||
@@ -1,6 +1,25 @@
|
|||||||
lib_xua Change Log
|
lib_xua Change Log
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
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
|
3.3.1
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|||||||
12
Jenkinsfile
vendored
12
Jenkinsfile
vendored
@@ -106,6 +106,12 @@ pipeline {
|
|||||||
dir("${REPO}/${REPO}/host/xmosdfu") {
|
dir("${REPO}/${REPO}/host/xmosdfu") {
|
||||||
sh 'make -f Makefile.OSX64'
|
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 {
|
post {
|
||||||
cleanup {
|
cleanup {
|
||||||
@@ -141,6 +147,12 @@ pipeline {
|
|||||||
dir("${REPO}/host/xmosdfu") {
|
dir("${REPO}/host/xmosdfu") {
|
||||||
runVS('nmake /f Makefile.Win32')
|
runVS('nmake /f Makefile.Win32')
|
||||||
}
|
}
|
||||||
|
dir("host_usb_mixer_control") {
|
||||||
|
runVS('msbuild host_usb_mixer_control.vcxproj /property:Configuration=Release /property:Platform=x64')
|
||||||
|
sh 'mkdir Win/x64'
|
||||||
|
sh 'mv bin/Release/x64/host_usb_mixer_control.exe Win/x64/xmos_mixer.exe'
|
||||||
|
archiveArtifacts artifacts: "Win/x64/xmos_mixer.exe", fingerprint: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
|
|||||||
17
README.rst
17
README.rst
@@ -1,7 +1,8 @@
|
|||||||
lib_xua
|
lib_xua
|
||||||
#######
|
#######
|
||||||
|
|
||||||
:Latest release: 3.3.1
|
:Version: 3.4.0
|
||||||
|
:Vendor: XMOS
|
||||||
|
|
||||||
|
|
||||||
:Scope: General Use
|
:Scope: General Use
|
||||||
@@ -85,11 +86,17 @@ Required Software (dependencies)
|
|||||||
* lib_mic_array (www.github.com/xmos/lib_mic_array)
|
* lib_mic_array (www.github.com/xmos/lib_mic_array)
|
||||||
* lib_xassert (www.github.com/xmos/lib_xassert)
|
* lib_xassert (www.github.com/xmos/lib_xassert)
|
||||||
* lib_dsp (www.github.com/xmos/lib_dsp)
|
* 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_spdif (www.github.com/xmos/lib_spdif)
|
||||||
* lib_xud (www.github.com/xmos/lib_xud)
|
* lib_xud (www.github.com/xmos/lib_xud)
|
||||||
* lib_adat (www.github.com/xmos/lib_adat)
|
* 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 ?= ../..
|
XMOS_MAKE_PATH ?= ../..
|
||||||
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
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 ?= ../..
|
XMOS_MAKE_PATH ?= ../..
|
||||||
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
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 ?= ../..
|
XMOS_MAKE_PATH ?= ../..
|
||||||
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
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.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#ifndef _XUA_H_
|
#ifndef _XUA_H_
|
||||||
#define _XUA_H_
|
#define _XUA_H_
|
||||||
@@ -7,14 +7,14 @@
|
|||||||
|
|
||||||
#include "xua_conf_full.h"
|
#include "xua_conf_full.h"
|
||||||
|
|
||||||
#if __XC__ || __STDC__
|
#ifndef __ASSEMBLER__
|
||||||
#include "xua_audiohub.h"
|
#include "xua_audiohub.h"
|
||||||
#include "xua_endpoint0.h"
|
#include "xua_endpoint0.h"
|
||||||
#include "xua_buffer.h"
|
#include "xua_buffer.h"
|
||||||
#include "xua_mixer.h"
|
#include "xua_mixer.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __XC__
|
#ifdef __XC__
|
||||||
#include "xua_clocking.h"
|
#include "xua_clocking.h"
|
||||||
#include "xua_midi.h"
|
#include "xua_midi.h"
|
||||||
#if XUA_NUM_PDM_MICS > 0
|
#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.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#ifndef __XUA_AUDIOHUB_H__
|
#ifndef _XUA_AUDIOHUB_H_
|
||||||
#define __XUA_AUDIOHUB_H__
|
#define _XUA_AUDIOHUB_H_
|
||||||
|
|
||||||
#if __XC__
|
#ifdef __XC__
|
||||||
|
|
||||||
#include "xccompat.h"
|
#include "xccompat.h"
|
||||||
#include "xs1.h"
|
#include "xs1.h"
|
||||||
@@ -80,4 +80,4 @@ void UserBufferManagementInit();
|
|||||||
|
|
||||||
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
|
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
|
||||||
|
|
||||||
#endif // __XUA_AUDIOHUB_H__
|
#endif // _XUA_AUDIOHUB_H_
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2022 XMOS LIMITED.
|
// Copyright 2011-2023 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
/*
|
/*
|
||||||
* @brief Defines relating to device configuration and customisation of lib_xua
|
* @brief Defines relating to device configuration and customisation of lib_xua
|
||||||
@@ -997,17 +997,12 @@
|
|||||||
#define MIXER (0)
|
#define MIXER (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Tidy up old ifndef usage */
|
|
||||||
#if defined(MIXER) && (MIXER == 0)
|
|
||||||
#undef MIXER
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Number of seperate mixes to perform
|
* @brief Number of seperate mixes to perform
|
||||||
*
|
*
|
||||||
* Default: 8 if MIXER enabled, else 0
|
* Default: 8 if MIXER enabled, else 0
|
||||||
*/
|
*/
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
#ifndef MAX_MIX_COUNT
|
#ifndef MAX_MIX_COUNT
|
||||||
#define MAX_MIX_COUNT (8)
|
#define MAX_MIX_COUNT (8)
|
||||||
#endif
|
#endif
|
||||||
@@ -1087,44 +1082,24 @@
|
|||||||
#define VOLUME_RES_MIXER (0x100)
|
#define VOLUME_RES_MIXER (0x100)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Handle out volume control in the mixer */
|
/* Handle out volume control in the mixer - enabled by default */
|
||||||
#if defined(OUT_VOLUME_IN_MIXER) && (OUT_VOLUME_IN_MIXER==0)
|
#ifndef OUT_VOLUME_IN_MIXER
|
||||||
#undef OUT_VOLUME_IN_MIXER
|
#define OUT_VOLUME_IN_MIXER (1)
|
||||||
#else
|
|
||||||
#if defined(MIXER)
|
|
||||||
// Disabled by default
|
|
||||||
//#define OUT_VOLUME_IN_MIXER
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Apply out volume controls after the mix */
|
/* Apply out volume controls after the mix. Only relevant when OUT_VOLUME_IN_MIXER enabled. Enabled by default */
|
||||||
#if defined(OUT_VOLUME_AFTER_MIX) && (OUT_VOLUME_AFTER_MIX==0)
|
#ifndef OUT_VOLUME_AFTER_MIX
|
||||||
#undef OUT_VOLUME_AFTER_MIX
|
#define OUT_VOLUME_AFTER_MIX (1)
|
||||||
#else
|
|
||||||
#if defined(MIXER) && defined(OUT_VOLUME_IN_MIXER)
|
|
||||||
// Enabled by default
|
|
||||||
#define OUT_VOLUME_AFTER_MIX
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Handle in volume control in the mixer */
|
/* Handle in volume control in the mixer - disabled by default */
|
||||||
#if defined(IN_VOLUME_IN_MIXER) && (IN_VOLUME_IN_MIXER==0)
|
#ifndef IN_VOLUME_IN_MIXER
|
||||||
#undef IN_VOLUME_IN_MIXER
|
#define IN_VOLUME_IN_MIXER (0)
|
||||||
#else
|
|
||||||
#if defined(MIXER)
|
|
||||||
/* Disabled by default */
|
|
||||||
//#define IN_VOLUME_IN_MIXER
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Apply in volume controls after the mix */
|
/* Apply in volume controls after the mix. Only relebant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */
|
||||||
#if defined(IN_VOLUME_AFTER_MIX) && (IN_VOLUME_AFTER_MIX==0)
|
#ifndef IN_VOLUME_AFTER_MIX
|
||||||
#undef IN_VOLUME_AFTER_MIX
|
#define IN_VOLUME_AFTER_MIX (1)
|
||||||
#else
|
|
||||||
#if defined(MIXER) && defined(IN_VOLUME_IN_MIXER)
|
|
||||||
// Enabled by default
|
|
||||||
#define IN_VOLUME_AFTER_MIX
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Always enable explicit feedback EP, even when input stream is present */
|
/* Always enable explicit feedback EP, even when input stream is present */
|
||||||
@@ -1319,9 +1294,9 @@ enum USBEndpointNumber_Out
|
|||||||
/* Some defines that allow us to remove unused code */
|
/* Some defines that allow us to remove unused code */
|
||||||
|
|
||||||
/* Useful for dropping lower part of macs in volume processing... */
|
/* 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) || \
|
#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \
|
||||||
(FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || \
|
(((FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 1)) || \
|
||||||
(HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)
|
(((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
|
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 1
|
||||||
#else
|
#else
|
||||||
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 0
|
#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.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#ifndef __XUA_CONF_FULL_H__
|
#ifndef _XUA_CONF_FULL_H_
|
||||||
#define __XUA_CONF_FULL_H__
|
#define _XUA_CONF_FULL_H_
|
||||||
|
|
||||||
#ifdef __xua_conf_h_exists__
|
#ifdef __xua_conf_h_exists__
|
||||||
#include "xua_conf.h"
|
#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.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#ifndef _XUA_MIXER_H_
|
#ifndef _XUA_MIXER_H_
|
||||||
#define _XUA_MIXER_H_
|
#define _XUA_MIXER_H_
|
||||||
|
|
||||||
|
#include "xua.h"
|
||||||
|
|
||||||
enum mix_ctl_cmd {
|
enum mix_ctl_cmd {
|
||||||
SET_SAMPLES_TO_HOST_MAP,
|
SET_SAMPLES_TO_HOST_MAP,
|
||||||
SET_SAMPLES_TO_DEVICE_MAP,
|
SET_SAMPLES_TO_DEVICE_MAP,
|
||||||
@@ -31,4 +33,14 @@ enum mix_ctl_cmd {
|
|||||||
*/
|
*/
|
||||||
void mixer(chanend c_to_host, chanend c_to_audio, chanend c_mix_ctl);
|
void mixer(chanend c_to_host, chanend c_to_audio, chanend c_mix_ctl);
|
||||||
|
|
||||||
|
#define XUA_MIXER_OFFSET_OUT (0)
|
||||||
|
#define XUA_MIXER_OFFSET_IN (NUM_USB_CHAN_OUT)
|
||||||
|
#define XUA_MIXER_OFFSET_MIX (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN)
|
||||||
|
#define XUA_MIXER_OFFSET_OFF (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT)
|
||||||
|
|
||||||
|
/* Defines uses for DB to actual muliplier conversion */
|
||||||
|
#define XUA_MIXER_MULT_FRAC_BITS (25)
|
||||||
|
#define XUA_MIXER_DB_FRAC_BITS (8)
|
||||||
|
#define XUA_MIXER_MAX_MULT (1<<XUA_MIXER_MULT_FRAC_BITS) /* i.e. multiply by 0 */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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.
|
intended to be exposed to end users.
|
||||||
|
|
||||||
For details, consult the README file in the host_usb_mixer_control directory.
|
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
|
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.
|
functionality to their end users.
|
||||||
|
|
||||||
Whilst using the XMOS Host control example application, consider the example of setting the
|
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
|
.. note::
|
||||||
to which mixer inputs::
|
|
||||||
|
|
||||||
./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
|
The following will show the index for each device output along with which channel is currently mapped to it.
|
||||||
that analogue inputs 1 and 2 are on mixer inputs 10 and 11::
|
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
|
$ ./xmos_mixer --display-daw-channel-map
|
||||||
of these bypass the mixer. We can also see what all the possible
|
|
||||||
mappings are with the following command::
|
|
||||||
|
|
||||||
./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
|
In both cases, by default, these bypass the mixer.
|
||||||
./xmos_mixer --set-aud-channel-map 1 27
|
|
||||||
|
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::
|
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,
|
Audio Output Channel Map
|
||||||
since the mixer is still mapped to pass the USB channels through to the outputs there will be no
|
------------------------
|
||||||
|
|
||||||
|
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.
|
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::
|
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
|
Mixer Values (0)
|
||||||
and 89 need to be set::
|
----------------
|
||||||
|
|
||||||
./xmos_mixer --set-value 0 80 0
|
Mixer outputs
|
||||||
./xmos_mixer --set-value 0 89 0
|
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::
|
At the same time, the original mixer outputs can be muted::
|
||||||
|
|
||||||
./xmos_mixer --set-value 0 0 -inf
|
$ ./xmos_mixer --set-value 0 0 -inf
|
||||||
./xmos_mixer --set-value 0 9 -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
|
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
|
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)::
|
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 8 -inf
|
||||||
./xmos_mixer --set-value 0 89 -inf
|
$ ./xmos_mixer --set-value 0 11 -inf
|
||||||
./xmos_mixer --set-value 0 0 0
|
$ ./xmos_mixer --set-value 0 0 0
|
||||||
./xmos_mixer --set-value 0 9 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 0 4
|
||||||
./xmos_mixer --set-mixer-source 0 1 11
|
|
||||||
|
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
|
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.
|
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::
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
VERSION = 3.3.1
|
VERSION = 3.4.0
|
||||||
|
|
||||||
DEBUG ?= 0
|
DEBUG ?= 0
|
||||||
|
|
||||||
ifeq ($(DEBUG),1)
|
ifeq ($(DEBUG),1)
|
||||||
DEBUG_FLAGS = -g -DXASSERT_ENABLE_ASSERTIONS_DECOUPLE=1
|
DEBUG_FLAGS = -g -DXASSERT_ENABLE_ASSERTIONS=1 -DXASSERT_ENABLE_DEBUG=1 -DXASSERT_ENABLE_LINE_NUMBERS=1
|
||||||
else
|
else
|
||||||
DEBUG_FLAGS = -DXASSERT_DISABLE_ASSERTIONS_DECOUPLE=1
|
DEBUG_FLAGS = -DXASSERT_ENABLE_ASSERTIONS=0 -DXASSERT_ENABLE_DEBUG=0 -DXASSERT_ENABLE_LINE_NUMBERS=0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
||||||
@@ -13,7 +13,7 @@ DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
|||||||
lib_mic_array(>=4.5.0) \
|
lib_mic_array(>=4.5.0) \
|
||||||
lib_spdif(>=4.2.1) \
|
lib_spdif(>=4.2.1) \
|
||||||
lib_xassert(>=4.1.0) \
|
lib_xassert(>=4.1.0) \
|
||||||
lib_xud(>=2.2.1) \
|
lib_xud(>=2.2.2) \
|
||||||
lib_adat(>=1.0.0)
|
lib_adat(>=1.0.0)
|
||||||
|
|
||||||
MODULE_XCC_FLAGS = $(XCC_FLAGS) \
|
MODULE_XCC_FLAGS = $(XCC_FLAGS) \
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#pragma xta endpoint "divide_1"
|
|
||||||
unsigned tmp;
|
unsigned tmp;
|
||||||
p_lrclk <: 0 @ tmp;
|
p_lrclk <: 0 @ tmp;
|
||||||
tmp += 100;
|
tmp += 100;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2022 XMOS LIMITED.
|
// Copyright 2011-2023 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
/**
|
/**
|
||||||
* @file xua_audiohub.xc
|
* @file xua_audiohub.xc
|
||||||
@@ -43,12 +43,12 @@
|
|||||||
|
|
||||||
#define MAX(x,y) ((x)>(y) ? (x) : (y))
|
#define MAX(x,y) ((x)>(y) ? (x) : (y))
|
||||||
|
|
||||||
static unsigned samplesOut[MAX(NUM_USB_CHAN_OUT, I2S_CHANS_DAC)];
|
unsigned samplesOut[MAX(NUM_USB_CHAN_OUT, I2S_CHANS_DAC)];
|
||||||
|
|
||||||
/* Two buffers for ADC data to allow for DAC and ADC I2S ports being offset */
|
/* Two buffers for ADC data to allow for DAC and ADC I2S ports being offset */
|
||||||
#define IN_CHAN_COUNT (I2S_CHANS_ADC + XUA_NUM_PDM_MICS + (8*XUA_ADAT_RX_EN) + (2*XUA_SPDIF_RX_EN))
|
#define IN_CHAN_COUNT (I2S_CHANS_ADC + XUA_NUM_PDM_MICS + (8*XUA_ADAT_RX_EN) + (2*XUA_SPDIF_RX_EN))
|
||||||
|
|
||||||
static unsigned samplesIn[2][MAX(NUM_USB_CHAN_IN, IN_CHAN_COUNT)];
|
unsigned samplesIn[2][MAX(NUM_USB_CHAN_IN, IN_CHAN_COUNT)];
|
||||||
|
|
||||||
#ifdef XTA_TIMING_AUDIO
|
#ifdef XTA_TIMING_AUDIO
|
||||||
#pragma xta command "add exclusion received_command"
|
#pragma xta command "add exclusion received_command"
|
||||||
@@ -89,69 +89,7 @@ unsigned dsdMode = DSD_MODE_OFF;
|
|||||||
#if (XUA_ADAT_TX_EN)
|
#if (XUA_ADAT_TX_EN)
|
||||||
#include "audiohub_adat.h"
|
#include "audiohub_adat.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "xua_audiohub_st.h"
|
||||||
#pragma unsafe arrays
|
|
||||||
static inline unsigned DoSampleTransfer(chanend ?c_out, const int readBuffNo, const unsigned underflowWord)
|
|
||||||
{
|
|
||||||
if(XUA_USB_EN)
|
|
||||||
{
|
|
||||||
outuint(c_out, underflowWord);
|
|
||||||
|
|
||||||
/* Check for sample freq change (or other command) or new samples from mixer*/
|
|
||||||
if(testct(c_out))
|
|
||||||
{
|
|
||||||
unsigned command = inct(c_out);
|
|
||||||
#ifndef CODEC_MASTER
|
|
||||||
if(dsdMode == DSD_MODE_OFF)
|
|
||||||
{
|
|
||||||
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
|
||||||
/* Set clocks low */
|
|
||||||
p_lrclk <: 0;
|
|
||||||
p_bclk <: 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if(DSD_CHANS_DAC != 0)
|
|
||||||
/* DSD Clock might not be shared with lrclk or bclk... */
|
|
||||||
p_dsd_clk <: 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if (DSD_CHANS_DAC > 0)
|
|
||||||
if(dsdMode == DSD_MODE_DOP)
|
|
||||||
dsdMode = DSD_MODE_OFF;
|
|
||||||
#endif
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if NUM_USB_CHAN_OUT > 0
|
|
||||||
#pragma loop unroll
|
|
||||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
|
||||||
{
|
|
||||||
int tmp = inuint(c_out);
|
|
||||||
samplesOut[i] = tmp;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
inuint(c_out);
|
|
||||||
#endif
|
|
||||||
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
|
|
||||||
|
|
||||||
#if NUM_USB_CHAN_IN > 0
|
|
||||||
#pragma loop unroll
|
|
||||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
|
||||||
{
|
|
||||||
outuint(c_out, samplesIn[readBuffNo][i]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int HandleSampleClock(int frameCount, buffered _XUA_CLK_DIR port:32 p_lrclk)
|
static inline int HandleSampleClock(int frameCount, buffered _XUA_CLK_DIR port:32 p_lrclk)
|
||||||
{
|
{
|
||||||
@@ -443,9 +381,8 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
|||||||
outuint(c_dig_rx, 0);
|
outuint(c_dig_rx, 0);
|
||||||
#endif
|
#endif
|
||||||
#if (XUA_SPDIF_TX_EN) && (NUM_USB_CHAN_OUT > 0)
|
#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 */
|
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward samples to S/PDIF Tx thread */
|
||||||
unsigned sample = samplesOut[SPDIF_TX_INDEX + 1];
|
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX + 1]);
|
||||||
outuint(c_spd_out, sample); /* Forward sample to S/PDIF Tx thread */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (XUA_NUM_PDM_MICS > 0)
|
#if (XUA_NUM_PDM_MICS > 0)
|
||||||
|
|||||||
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.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
#include "xua.h"
|
#include "xua.h"
|
||||||
|
|
||||||
@@ -58,15 +58,16 @@
|
|||||||
#define IN_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_IN_HS, MAX_DEVICE_AUD_PACKET_SIZE_IN_FS)*2)
|
#define IN_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_IN_HS, MAX_DEVICE_AUD_PACKET_SIZE_IN_FS)*2)
|
||||||
|
|
||||||
/* Volume and mute tables */
|
/* Volume and mute tables */
|
||||||
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
|
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||||
unsigned int multOut[NUM_USB_CHAN_OUT + 1];
|
unsigned int multOut[NUM_USB_CHAN_OUT + 1];
|
||||||
static xc_ptr p_multOut;
|
static xc_ptr p_multOut;
|
||||||
#endif
|
#endif
|
||||||
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
|
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
|
||||||
unsigned int multIn[NUM_USB_CHAN_IN + 1];
|
unsigned int multIn[NUM_USB_CHAN_IN + 1];
|
||||||
static xc_ptr p_multIn;
|
static xc_ptr p_multIn;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Default to something sensible but the following are setup at stream start (unless UAC1 only..) */
|
||||||
#if (AUDIO_CLASS == 2)
|
#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_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;
|
int g_numUsbChan_Out = NUM_USB_CHAN_OUT;
|
||||||
@@ -143,7 +144,66 @@ unsigned unpackData = 0;
|
|||||||
unsigned packState = 0;
|
unsigned packState = 0;
|
||||||
unsigned packData = 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)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma select handler
|
#pragma select handler
|
||||||
#pragma unsafe arrays
|
#pragma unsafe arrays
|
||||||
@@ -206,7 +266,7 @@ __builtin_unreachable();
|
|||||||
g_aud_from_host_rdptr+=2;
|
g_aud_from_host_rdptr+=2;
|
||||||
sample <<= 16;
|
sample <<= 16;
|
||||||
|
|
||||||
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
|
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
||||||
{h, l} = macs(mult, sample, 0, 0);
|
{h, l} = macs(mult, sample, 0, 0);
|
||||||
/* Note, in 2 byte subslot mode - ignore lower result of macs */
|
/* Note, in 2 byte subslot mode - ignore lower result of macs */
|
||||||
@@ -223,41 +283,17 @@ __builtin_unreachable();
|
|||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
#endif
|
#endif
|
||||||
/* Buffering not underflow condition send out some samples...*/
|
/* Buffering not underflow condition send out some samples...*/
|
||||||
for(int i = 0; i < g_numUsbChan_Out; i++)
|
SendSamples4(c_mix_out);
|
||||||
{
|
|
||||||
#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
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
#if (STREAM_FORMAT_OUTPUT_SUBSLOT_3_USED == 0)
|
#if (STREAM_FORMAT_OUTPUT_SUBSLOT_3_USED == 0)
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
#endif
|
#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++)
|
for(int i = 0; i < g_numUsbChan_Out; i++)
|
||||||
{
|
{
|
||||||
#pragma xta endpoint "mixer_request"
|
|
||||||
int sample;
|
int sample;
|
||||||
int mult;
|
int mult;
|
||||||
int h;
|
int h;
|
||||||
@@ -289,7 +325,7 @@ __builtin_unreachable();
|
|||||||
}
|
}
|
||||||
unpackState++;
|
unpackState++;
|
||||||
|
|
||||||
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
|
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
||||||
{h, l} = macs(mult, sample, 0, 0);
|
{h, l} = macs(mult, sample, 0, 0);
|
||||||
h <<= 3;
|
h <<= 3;
|
||||||
@@ -335,7 +371,7 @@ __builtin_unreachable();
|
|||||||
/* Receive sample */
|
/* Receive sample */
|
||||||
int sample = inuint(c_mix_out);
|
int sample = inuint(c_mix_out);
|
||||||
#if (INPUT_VOLUME_CONTROL == 1)
|
#if (INPUT_VOLUME_CONTROL == 1)
|
||||||
#if !defined(IN_VOLUME_IN_MIXER)
|
#if (!IN_VOLUME_IN_MIXER)
|
||||||
/* Apply volume */
|
/* Apply volume */
|
||||||
int mult;
|
int mult;
|
||||||
int h;
|
int h;
|
||||||
@@ -345,7 +381,7 @@ __builtin_unreachable();
|
|||||||
sample = h << 3;
|
sample = h << 3;
|
||||||
|
|
||||||
/* Note, in 2 byte sub slot - ignore lower bits of macs */
|
/* Note, in 2 byte sub slot - ignore lower bits of macs */
|
||||||
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
#elif (IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||||
sample = sample << 3;
|
sample = sample << 3;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -365,7 +401,7 @@ __builtin_unreachable();
|
|||||||
/* Receive sample */
|
/* Receive sample */
|
||||||
int sample = inuint(c_mix_out);
|
int sample = inuint(c_mix_out);
|
||||||
#if(INPUT_VOLUME_CONTROL == 1)
|
#if(INPUT_VOLUME_CONTROL == 1)
|
||||||
#if !defined(IN_VOLUME_IN_MIXER)
|
#if (!IN_VOLUME_IN_MIXER)
|
||||||
/* Apply volume */
|
/* Apply volume */
|
||||||
int mult;
|
int mult;
|
||||||
int h;
|
int h;
|
||||||
@@ -376,7 +412,7 @@ __builtin_unreachable();
|
|||||||
#if (STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED == 1)
|
#if (STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED == 1)
|
||||||
sample |= (l >> 29) & 0x7; // Note, this step is not required if we assume sample depth is 24 (rather than 32)
|
sample |= (l >> 29) & 0x7; // Note, this step is not required if we assume sample depth is 24 (rather than 32)
|
||||||
#endif
|
#endif
|
||||||
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
#elif (IN_VOLUME_IN_MIXER) && (IN_VOLUME_AFTER_MIX)
|
||||||
sample = sample << 3;
|
sample = sample << 3;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -396,7 +432,7 @@ __builtin_unreachable();
|
|||||||
{
|
{
|
||||||
/* Receive sample */
|
/* Receive sample */
|
||||||
int sample = inuint(c_mix_out);
|
int sample = inuint(c_mix_out);
|
||||||
#if (INPUT_VOLUME_CONTROL) && !defined(IN_VOLUME_IN_MIXER)
|
#if (INPUT_VOLUME_CONTROL) && (!IN_VOLUME_IN_MIXER)
|
||||||
/* Apply volume */
|
/* Apply volume */
|
||||||
int mult;
|
int mult;
|
||||||
int h;
|
int h;
|
||||||
@@ -588,6 +624,7 @@ __builtin_unreachable();
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (NUM_USB_CHAN_IN > 0)
|
||||||
/* Mark Endpoint (IN) ready with an appropriately sized zero buffer */
|
/* 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,
|
static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned sampFreq, unsigned slotSize,
|
||||||
xc_ptr aud_to_host_zeros)
|
xc_ptr aud_to_host_zeros)
|
||||||
@@ -619,6 +656,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);
|
XUD_SetReady_InPtr(aud_to_host_usb_ep, aud_to_host_zeros+4, mid);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#pragma unsafe arrays
|
#pragma unsafe arrays
|
||||||
void XUA_Buffer_Decouple(chanend c_mix_out
|
void XUA_Buffer_Decouple(chanend c_mix_out
|
||||||
@@ -638,10 +676,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
|||||||
|
|
||||||
int t = array_to_xc_ptr(outAudioBuff);
|
int t = array_to_xc_ptr(outAudioBuff);
|
||||||
|
|
||||||
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
|
#if (!OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||||
p_multOut = array_to_xc_ptr(multOut);
|
p_multOut = array_to_xc_ptr(multOut);
|
||||||
#endif
|
#endif
|
||||||
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
|
#if (!IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
|
||||||
p_multIn = array_to_xc_ptr(multIn);
|
p_multIn = array_to_xc_ptr(multIn);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -668,14 +706,14 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
|||||||
xc_ptr aud_to_host_zeros = t;
|
xc_ptr aud_to_host_zeros = t;
|
||||||
|
|
||||||
/* Init vol mult tables */
|
/* Init vol mult tables */
|
||||||
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
|
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||||
for (int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
|
for (int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
|
||||||
{
|
{
|
||||||
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multOut),"r"(i));
|
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multOut),"r"(i));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
|
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
|
||||||
for (int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
|
for (int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
|
||||||
{
|
{
|
||||||
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multIn),"r"(i));
|
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multIn),"r"(i));
|
||||||
@@ -760,8 +798,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
|||||||
/* Set buffer to send back to zeros buffer */
|
/* Set buffer to send back to zeros buffer */
|
||||||
aud_to_host_buffer = aud_to_host_zeros;
|
aud_to_host_buffer = aud_to_host_zeros;
|
||||||
|
|
||||||
|
#if (NUM_USB_CHAN_IN > 0)
|
||||||
/* Update size of zeros buffer (and sampsToWrite) */
|
/* Update size of zeros buffer (and sampsToWrite) */
|
||||||
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Reset OUT buffer state */
|
/* Reset OUT buffer state */
|
||||||
outUnderflow = 1;
|
outUnderflow = 1;
|
||||||
@@ -815,8 +855,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
|||||||
/* Set buffer back to zeros buffer */
|
/* Set buffer back to zeros buffer */
|
||||||
aud_to_host_buffer = aud_to_host_zeros;
|
aud_to_host_buffer = aud_to_host_zeros;
|
||||||
|
|
||||||
|
#if (NUM_USB_CHAN_IN > 0)
|
||||||
/* Update size of zeros buffer (and sampsToWrite) */
|
/* Update size of zeros buffer (and sampsToWrite) */
|
||||||
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
||||||
|
#endif
|
||||||
|
|
||||||
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
|
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
|
||||||
if (usbSpeed == XUD_SPEED_HS)
|
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.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
#include <xs1.h>
|
#include <xs1.h>
|
||||||
@@ -13,14 +13,14 @@
|
|||||||
#include "spdif.h"
|
#include "spdif.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LOCAL_CLOCK_INCREMENT 166667
|
#define LOCAL_CLOCK_INCREMENT (166667)
|
||||||
#define LOCAL_CLOCK_MARGIN 1666
|
#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_SPDIF_SAMPLES (2 * MAX_SAMPLES) /* Must be power of 2 */
|
||||||
#define MAX_ADAT_SAMPLES (8 * 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];
|
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);
|
int VendorAudCoreReqs(unsigned cmd, chanend c);
|
||||||
|
|
||||||
#pragma unsafe arrays
|
#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)
|
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;
|
timer t_local;
|
||||||
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
|
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)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
/* Mixer requests data */
|
/* AudioHub requests data */
|
||||||
case inuint_byref(c_dig_rx, tmp):
|
case inuint_byref(c_dig_rx, tmp):
|
||||||
#if (XUA_SPDIF_RX_EN)
|
#if (XUA_SPDIF_RX_EN)
|
||||||
if(spdifUnderflow)
|
if(spdifUnderflow)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2022 XMOS LIMITED.
|
// Copyright 2011-2023 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
/**
|
/**
|
||||||
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
|
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
|
||||||
@@ -106,13 +106,17 @@ unsigned int mutesOut[NUM_USB_CHAN_OUT + 1];
|
|||||||
int volsIn[NUM_USB_CHAN_IN + 1];
|
int volsIn[NUM_USB_CHAN_IN + 1];
|
||||||
unsigned int mutesIn[NUM_USB_CHAN_IN + 1];
|
unsigned int mutesIn[NUM_USB_CHAN_IN + 1];
|
||||||
|
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
unsigned char mixer1Crossbar[18];
|
short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
|
||||||
short mixer1Weights[18*8];
|
|
||||||
|
|
||||||
unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
//unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
||||||
|
/* Mapping of channels to output audio interfaces */
|
||||||
unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
||||||
|
|
||||||
|
/* Mapping of channels to USB host */
|
||||||
unsigned char channelMapUsb[NUM_USB_CHAN_IN];
|
unsigned char channelMapUsb[NUM_USB_CHAN_IN];
|
||||||
|
|
||||||
|
/* Mapping of channels to Mixer(s) */
|
||||||
unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
|
unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -262,6 +266,49 @@ void XUA_Endpoint0_setVendorId(unsigned short vid) {
|
|||||||
#endif // AUDIO_CLASS == 1}
|
#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 */
|
||||||
|
// TODO this should be a loop using defines.
|
||||||
|
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
|
||||||
|
|
||||||
|
/* 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) {
|
void concatenateAndCopyStrings(char* string1, char* string2, char* string_buffer) {
|
||||||
debug_printf("concatenateAndCopyStrings() for \"%s\" and \"%s\"\n", string1, string2);
|
debug_printf("concatenateAndCopyStrings() for \"%s\" and \"%s\"\n", string1, string2);
|
||||||
|
|
||||||
@@ -408,75 +455,11 @@ void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, NULLABLE_RESOURCE(c
|
|||||||
|
|
||||||
XUA_Endpoint0_setStrTable();
|
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);
|
VendorRequests_Init(VENDOR_REQUESTS_PARAMS);
|
||||||
|
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
/* Set up mixer default state */
|
/* Set up mixer default state */
|
||||||
for (int i = 0; i < 18*8; i++)
|
InitLocalMixerState();
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef VENDOR_AUDIO_REQS
|
#ifdef VENDOR_AUDIO_REQS
|
||||||
@@ -529,7 +512,6 @@ 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_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] = ((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
|
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 // NUM_USB_CHAN_OUT
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2022 XMOS LIMITED.
|
// Copyright 2011-2023 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
/**
|
/**
|
||||||
* @file xua_ep0_descriptors.h
|
* @file xua_ep0_descriptors.h
|
||||||
@@ -308,28 +308,28 @@ typedef struct
|
|||||||
#error NUM_USB_CHAN > 32
|
#error NUM_USB_CHAN > 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||||
STR_TABLE_ENTRY(mixOutStr_1);
|
STR_TABLE_ENTRY(mixOutStr_1);
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 1)
|
#if (MIXER) && (MAX_MIX_COUNT > 1)
|
||||||
STR_TABLE_ENTRY(mixOutStr_2);
|
STR_TABLE_ENTRY(mixOutStr_2);
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 2)
|
#if (MIXER) && (MAX_MIX_COUNT > 2)
|
||||||
STR_TABLE_ENTRY(mixOutStr_3);
|
STR_TABLE_ENTRY(mixOutStr_3);
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 3)
|
#if (MIXER) && (MAX_MIX_COUNT > 3)
|
||||||
STR_TABLE_ENTRY(mixOutStr_4);
|
STR_TABLE_ENTRY(mixOutStr_4);
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 4)
|
#if (MIXER) && (MAX_MIX_COUNT > 4)
|
||||||
STR_TABLE_ENTRY(mixOutStr_5);
|
STR_TABLE_ENTRY(mixOutStr_5);
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 5)
|
#if (MIXER) && (MAX_MIX_COUNT > 5)
|
||||||
STR_TABLE_ENTRY(mixOutStr_6);
|
STR_TABLE_ENTRY(mixOutStr_6);
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 6)
|
#if (MIXER) && (MAX_MIX_COUNT > 6)
|
||||||
STR_TABLE_ENTRY(mixOutStr_7);
|
STR_TABLE_ENTRY(mixOutStr_7);
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 7)
|
#if (MIXER) && (MAX_MIX_COUNT > 7)
|
||||||
STR_TABLE_ENTRY(mixOutStr_8);
|
STR_TABLE_ENTRY(mixOutStr_8);
|
||||||
#endif
|
#endif
|
||||||
#ifdef IAP
|
#ifdef IAP
|
||||||
@@ -391,31 +391,31 @@ StringDescTable_t g_strTable =
|
|||||||
#error NUM_USB_CHAN_IN > 32
|
#error NUM_USB_CHAN_IN > 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||||
.mixOutStr_1 = "Mix 1",
|
.mixOutStr_1 = "Mix 1",
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 1)
|
#if (MIXER) && (MAX_MIX_COUNT > 1)
|
||||||
.mixOutStr_2 = "Mix 2",
|
.mixOutStr_2 = "Mix 2",
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 2)
|
#if (MIXER) && (MAX_MIX_COUNT > 2)
|
||||||
.mixOutStr_3 = "Mix 3",
|
.mixOutStr_3 = "Mix 3",
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 3)
|
#if (MIXER) && (MAX_MIX_COUNT > 3)
|
||||||
.mixOutStr_4 = "Mix 4",
|
.mixOutStr_4 = "Mix 4",
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 4)
|
#if (MIXER) && (MAX_MIX_COUNT > 4)
|
||||||
.mixOutStr_5 = "Mix 5",
|
.mixOutStr_5 = "Mix 5",
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 5)
|
#if (MIXER) && (MAX_MIX_COUNT > 5)
|
||||||
.mixOutStr_6 = "Mix 6",
|
.mixOutStr_6 = "Mix 6",
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 6)
|
#if (MIXER) && (MAX_MIX_COUNT > 6)
|
||||||
.mixOutStr_7 = "Mix 7",
|
.mixOutStr_7 = "Mix 7",
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 7)
|
#if (MIXER) && (MAX_MIX_COUNT > 7)
|
||||||
.mixOutStr_8 = "Mix 8",
|
.mixOutStr_8 = "Mix 8",
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 8)
|
#if (MIXER) && (MAX_MIX_COUNT > 8)
|
||||||
#error
|
#error
|
||||||
#endif
|
#endif
|
||||||
#ifdef IAP
|
#ifdef IAP
|
||||||
@@ -558,7 +558,7 @@ unsigned char devQualDesc_Null[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#if defined(MIXER) && !defined(AUDIO_PATH_XUS) && (MAX_MIX_COUNT > 0)
|
#if (MIXER) && !defined(AUDIO_PATH_XUS) && (MAX_MIX_COUNT > 0)
|
||||||
//#warning Extension units on the audio path are required for mixer. Enabling them now.
|
//#warning Extension units on the audio path are required for mixer. Enabling them now.
|
||||||
#define AUDIO_PATH_XUS
|
#define AUDIO_PATH_XUS
|
||||||
#endif
|
#endif
|
||||||
@@ -575,7 +575,7 @@ unsigned char devQualDesc_Null[] =
|
|||||||
#define DFU_LENGTH (0)
|
#define DFU_LENGTH (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
#define MIX_BMCONTROLS_LEN_TMP ((MAX_MIX_COUNT * MIX_INPUTS) / 8)
|
#define MIX_BMCONTROLS_LEN_TMP ((MAX_MIX_COUNT * MIX_INPUTS) / 8)
|
||||||
|
|
||||||
#if ((MAX_MIX_COUNT * MIX_INPUTS)%8)==0
|
#if ((MAX_MIX_COUNT * MIX_INPUTS)%8)==0
|
||||||
@@ -666,7 +666,7 @@ typedef struct
|
|||||||
#if (NUM_USB_CHAN_OUT > 0)
|
#if (NUM_USB_CHAN_OUT > 0)
|
||||||
/* Output path */
|
/* Output path */
|
||||||
USB_Descriptor_Audio_InputTerminal_t Audio_Out_InputTerminal;
|
USB_Descriptor_Audio_InputTerminal_t Audio_Out_InputTerminal;
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||||
USB_Descriptor_Audio_ExtensionUnit_t Audio_Out_ExtensionUnit;
|
USB_Descriptor_Audio_ExtensionUnit_t Audio_Out_ExtensionUnit;
|
||||||
#endif
|
#endif
|
||||||
#if(OUTPUT_VOLUME_CONTROL == 1)
|
#if(OUTPUT_VOLUME_CONTROL == 1)
|
||||||
@@ -677,7 +677,7 @@ typedef struct
|
|||||||
#if (NUM_USB_CHAN_IN > 0)
|
#if (NUM_USB_CHAN_IN > 0)
|
||||||
/* Input path */
|
/* Input path */
|
||||||
USB_Descriptor_Audio_InputTerminal_t Audio_In_InputTerminal;
|
USB_Descriptor_Audio_InputTerminal_t Audio_In_InputTerminal;
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||||
USB_Descriptor_Audio_ExtensionUnit_t Audio_In_ExtensionUnit;
|
USB_Descriptor_Audio_ExtensionUnit_t Audio_In_ExtensionUnit;
|
||||||
#endif
|
#endif
|
||||||
#if(INPUT_VOLUME_CONTROL == 1)
|
#if(INPUT_VOLUME_CONTROL == 1)
|
||||||
@@ -685,7 +685,7 @@ typedef struct
|
|||||||
#endif
|
#endif
|
||||||
USB_Descriptor_Audio_OutputTerminal_t Audio_In_OutputTerminal;
|
USB_Descriptor_Audio_OutputTerminal_t Audio_In_OutputTerminal;
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||||
USB_Descriptor_Audio_ExtensionUnit2_t Audio_Mix_ExtensionUnit;
|
USB_Descriptor_Audio_ExtensionUnit2_t Audio_Mix_ExtensionUnit;
|
||||||
// Currently no struct for mixer unit
|
// Currently no struct for mixer unit
|
||||||
// USB_Descriptor_Audio_MixerUnit_t Audio_MixerUnit;
|
// USB_Descriptor_Audio_MixerUnit_t Audio_MixerUnit;
|
||||||
@@ -1168,7 +1168,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
|||||||
UAC_CS_DESCTYPE_INTERFACE, /* 1 bDescriptorType: CS_INTERFACE */
|
UAC_CS_DESCTYPE_INTERFACE, /* 1 bDescriptorType: CS_INTERFACE */
|
||||||
UAC_CS_AC_INTERFACE_SUBTYPE_FEATURE_UNIT, /* 2 bDescriptorSubType: FEATURE_UNIT */
|
UAC_CS_AC_INTERFACE_SUBTYPE_FEATURE_UNIT, /* 2 bDescriptorSubType: FEATURE_UNIT */
|
||||||
FU_USBIN, /* 3 bUnitID */
|
FU_USBIN, /* 3 bUnitID */
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||||
ID_XU_IN, /* 4 bSourceID */
|
ID_XU_IN, /* 4 bSourceID */
|
||||||
#else
|
#else
|
||||||
ID_IT_AUD, /* 4 bSourceID */
|
ID_IT_AUD, /* 4 bSourceID */
|
||||||
@@ -1300,7 +1300,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
|||||||
},
|
},
|
||||||
#endif /* (NUM_USB_CHAN_IN > 0) */
|
#endif /* (NUM_USB_CHAN_IN > 0) */
|
||||||
|
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||||
/* Extension Unit Descriptor (4.7.2.12) */
|
/* Extension Unit Descriptor (4.7.2.12) */
|
||||||
.Audio_Mix_ExtensionUnit =
|
.Audio_Mix_ExtensionUnit =
|
||||||
{
|
{
|
||||||
@@ -1392,7 +1392,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
|||||||
0x00, /* bmControls */
|
0x00, /* bmControls */
|
||||||
0 /* Mixer unit string descriptor index */
|
0 /* Mixer unit string descriptor index */
|
||||||
},
|
},
|
||||||
#endif /* defined(MIXER) && (MAX_MIX_COUNT > 0) */
|
#endif /* (MIXER) && (MAX_MIX_COUNT > 0) */
|
||||||
|
|
||||||
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN)
|
||||||
/* Standard AS Interrupt Endpoint Descriptor (4.8.2.1): */
|
/* Standard AS Interrupt Endpoint Descriptor (4.8.2.1): */
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2011-2022 XMOS LIMITED.
|
// Copyright 2011-2023 XMOS LIMITED.
|
||||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
/**
|
/**
|
||||||
* @brief Implements relevant requests from the USB Audio 2.0 Specification
|
* @brief Implements relevant requests from the USB Audio 2.0 Specification
|
||||||
@@ -30,10 +30,9 @@ extern unsigned int mutesOut[];
|
|||||||
extern int volsIn[];
|
extern int volsIn[];
|
||||||
extern unsigned int mutesIn[];
|
extern unsigned int mutesIn[];
|
||||||
|
|
||||||
/* Mixer settings */
|
#if (MIXER)
|
||||||
#ifdef MIXER
|
/* Mixer weights */
|
||||||
extern unsigned char mixer1Crossbar[];
|
extern short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
|
||||||
extern short mixer1Weights[];
|
|
||||||
|
|
||||||
/* Device channel mapping */
|
/* Device channel mapping */
|
||||||
extern unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
extern unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
||||||
@@ -130,16 +129,16 @@ static unsigned longMul(unsigned a, unsigned b, int prec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update master volume i.e. i.e update weights for all channels */
|
/* 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;
|
int x;
|
||||||
#ifndef OUT_VOLUME_IN_MIXER
|
#if (OUT_VOLUME_IN_MIXER == 0)
|
||||||
xc_ptr p_multOut = array_to_xc_ptr(multOut);
|
xc_ptr p_multOut = array_to_xc_ptr(multOut);
|
||||||
#endif
|
#endif
|
||||||
#ifndef IN_VOLUME_IN_MIXER
|
#if (IN_VOLUME_IN_MIXER == 0)
|
||||||
xc_ptr p_multIn = array_to_xc_ptr(multIn);
|
xc_ptr p_multIn = array_to_xc_ptr(multIn);
|
||||||
#endif
|
#endif
|
||||||
switch( unitID)
|
switch(unitID)
|
||||||
{
|
{
|
||||||
case FU_USBOUT:
|
case FU_USBOUT:
|
||||||
{
|
{
|
||||||
@@ -153,9 +152,11 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
|||||||
|
|
||||||
x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[i];
|
x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[i];
|
||||||
|
|
||||||
#ifdef OUT_VOLUME_IN_MIXER
|
#if (OUT_VOLUME_IN_MIXER)
|
||||||
if (!isnull(c_mix_ctl))
|
if (!isnull(c_mix_ctl))
|
||||||
{
|
{
|
||||||
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
|
inct(c_mix_ctl);
|
||||||
outuint(c_mix_ctl, SET_MIX_OUT_VOL);
|
outuint(c_mix_ctl, SET_MIX_OUT_VOL);
|
||||||
outuint(c_mix_ctl, i-1);
|
outuint(c_mix_ctl, i-1);
|
||||||
outuint(c_mix_ctl, x);
|
outuint(c_mix_ctl, x);
|
||||||
@@ -179,9 +180,11 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
|||||||
|
|
||||||
x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[i];
|
x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[i];
|
||||||
|
|
||||||
#ifdef IN_VOLUME_IN_MIXER
|
#if (IN_VOLUME_IN_MIXER)
|
||||||
if (!isnull(c_mix_ctl))
|
if (!isnull(c_mix_ctl))
|
||||||
{
|
{
|
||||||
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
|
inct(c_mix_ctl);
|
||||||
outuint(c_mix_ctl, SET_MIX_IN_VOL);
|
outuint(c_mix_ctl, SET_MIX_IN_VOL);
|
||||||
outuint(c_mix_ctl, i-1);
|
outuint(c_mix_ctl, i-1);
|
||||||
outuint(c_mix_ctl, x);
|
outuint(c_mix_ctl, x);
|
||||||
@@ -202,10 +205,10 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
|||||||
static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
#ifndef OUT_VOLUME_IN_MIXER
|
#if (OUT_VOLUME_IN_MIXER == 0)
|
||||||
xc_ptr p_multOut = array_to_xc_ptr(multOut);
|
xc_ptr p_multOut = array_to_xc_ptr(multOut);
|
||||||
#endif
|
#endif
|
||||||
#ifndef IN_VOLUME_IN_MIXER
|
#if (IN_VOLUME_IN_MIXER == 0)
|
||||||
xc_ptr p_multIn = array_to_xc_ptr(multIn);
|
xc_ptr p_multIn = array_to_xc_ptr(multIn);
|
||||||
#endif
|
#endif
|
||||||
/* Check for master volume update */
|
/* Check for master volume update */
|
||||||
@@ -226,9 +229,11 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
|||||||
|
|
||||||
x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[channel];
|
x = longMul(master_vol, vol, 29) * !mutesOut[0] * !mutesOut[channel];
|
||||||
|
|
||||||
#ifdef OUT_VOLUME_IN_MIXER
|
#if (OUT_VOLUME_IN_MIXER)
|
||||||
if (!isnull(c_mix_ctl))
|
if (!isnull(c_mix_ctl))
|
||||||
{
|
{
|
||||||
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
|
inct(c_mix_ctl);
|
||||||
outuint(c_mix_ctl, SET_MIX_OUT_VOL);
|
outuint(c_mix_ctl, SET_MIX_OUT_VOL);
|
||||||
outuint(c_mix_ctl, channel-1);
|
outuint(c_mix_ctl, channel-1);
|
||||||
outuint(c_mix_ctl, x);
|
outuint(c_mix_ctl, x);
|
||||||
@@ -244,13 +249,15 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
|||||||
/* Calc multipliers with 29 fractional bits from a db value with 8 fractional bits */
|
/* Calc multipliers with 29 fractional bits from a db value with 8 fractional bits */
|
||||||
/* 0x8000 is a special value representing -inf (i.e. mute) */
|
/* 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 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];
|
x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[channel];
|
||||||
|
|
||||||
#ifdef IN_VOLUME_IN_MIXER
|
#if (IN_VOLUME_IN_MIXER)
|
||||||
if (!isnull(c_mix_ctl))
|
if (!isnull(c_mix_ctl))
|
||||||
{
|
{
|
||||||
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
|
inct(c_mix_ctl);
|
||||||
outuint(c_mix_ctl, SET_MIX_IN_VOL);
|
outuint(c_mix_ctl, SET_MIX_IN_VOL);
|
||||||
outuint(c_mix_ctl, channel-1);
|
outuint(c_mix_ctl, channel-1);
|
||||||
outuint(c_mix_ctl, x);
|
outuint(c_mix_ctl, x);
|
||||||
@@ -266,6 +273,38 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void UpdateMixerOutputRouting(chanend c_mix_ctl, unsigned map, unsigned dst, unsigned src)
|
||||||
|
{
|
||||||
|
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
|
/* Handles the audio class specific requests
|
||||||
* returns: XUD_RES_OKAY if request dealt with successfully without error,
|
* returns: XUD_RES_OKAY if request dealt with successfully without error,
|
||||||
* XUD_RES_RST for device reset
|
* XUD_RES_RST for device reset
|
||||||
@@ -282,7 +321,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 */
|
/* Inspect request, NOTE: these are class specific requests */
|
||||||
switch( sp.bRequest )
|
switch( sp.bRequest )
|
||||||
{
|
{
|
||||||
|
|
||||||
/* CUR Request*/
|
/* CUR Request*/
|
||||||
case CUR:
|
case CUR:
|
||||||
{
|
{
|
||||||
@@ -318,7 +356,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
int newSampleRate = buffer[0];
|
int newSampleRate = buffer[0];
|
||||||
|
|
||||||
/* Instruct audio thread to change sample freq (if change required) */
|
/* Instruct audio thread to change sample freq (if change required) */
|
||||||
//if(newSampleRate != g_curSamFreq)
|
if(newSampleRate != g_curSamFreq)
|
||||||
{
|
{
|
||||||
int newMasterClock;
|
int newMasterClock;
|
||||||
|
|
||||||
@@ -371,7 +409,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
}
|
}
|
||||||
#endif /* MAX_FREQ != MIN_FREQ */
|
#endif /* MAX_FREQ != MIN_FREQ */
|
||||||
/* Send 0 Length as status stage */
|
/* 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 */
|
/* Direction: Device-to-host: Send Current Sample Freq */
|
||||||
else
|
else
|
||||||
@@ -537,7 +575,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)
|
if ((sp.wValue & 0xff) <= NUM_USB_CHAN_OUT)
|
||||||
{
|
{
|
||||||
volsOut[ sp.wValue&0xff ] = (buffer, unsigned char[])[0] | (((int) (signed char) (buffer, unsigned char[])[1]) << 8);
|
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);
|
return XUD_DoSetRequestStatus(ep0_in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -546,7 +584,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)
|
if ((sp.wValue & 0xff) <= NUM_USB_CHAN_IN)
|
||||||
{
|
{
|
||||||
volsIn[ sp.wValue&0xff ] = (buffer, unsigned char[])[0] | (((int) (signed char) (buffer, unsigned char[])[1]) << 8);
|
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);
|
return XUD_DoSetRequestStatus(ep0_in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -632,85 +670,76 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
break; /* FU_USBIN */
|
break; /* FU_USBIN */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
#if ((MIXER) && (MAX_MIX_COUNT > 0))
|
||||||
case ID_XU_OUT:
|
case ID_XU_OUT:
|
||||||
{
|
|
||||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
|
||||||
{
|
{
|
||||||
unsigned volume = 0;
|
int dst = sp.wValue & 0xff;
|
||||||
int c = sp.wValue & 0xff;
|
|
||||||
|
|
||||||
|
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
|
||||||
{
|
{
|
||||||
return result;
|
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||||
}
|
|
||||||
|
|
||||||
channelMapAud[c] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
|
||||||
|
|
||||||
if (!isnull(c_mix_ctl))
|
|
||||||
{
|
|
||||||
if (c < NUM_USB_CHAN_OUT)
|
|
||||||
{
|
{
|
||||||
outuint(c_mix_ctl, SET_SAMPLES_TO_DEVICE_MAP);
|
return result;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
case ID_XU_IN:
|
case ID_XU_IN:
|
||||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
|
||||||
{
|
{
|
||||||
unsigned volume = 0;
|
int dst = sp.wValue & 0xff;
|
||||||
int c = 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;
|
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||||
}
|
|
||||||
|
|
||||||
channelMapUsb[c] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
|
||||||
|
|
||||||
if (c < NUM_USB_CHAN_IN)
|
|
||||||
{
|
|
||||||
if (!isnull(c_mix_ctl))
|
|
||||||
{
|
{
|
||||||
outuint(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP);
|
return result;
|
||||||
outuint(c_mix_ctl, c);
|
|
||||||
outuint(c_mix_ctl, channelMapUsb[c]);
|
|
||||||
outct(c_mix_ctl, XS1_CT_END);
|
|
||||||
return XUD_DoSetRequestStatus(ep0_in);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
case ID_XU_MIXSEL:
|
case ID_XU_MIXSEL:
|
||||||
{
|
{
|
||||||
int cs = sp.wValue >> 8; /* Control Selector */
|
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 */
|
/* Check for Get or Set */
|
||||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D)
|
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D)
|
||||||
@@ -723,21 +752,19 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
|
|
||||||
if(datalength > 0)
|
if(datalength > 0)
|
||||||
{
|
{
|
||||||
/* cn bounds check for safety..*/
|
/* CN bounds check for safety..*/
|
||||||
if(cn < MIX_INPUTS)
|
if(cn < MIX_INPUTS)
|
||||||
{
|
{
|
||||||
//if(cs == CS_XU_MIXSEL)
|
//if(cs == CS_XU_MIXSEL)
|
||||||
/* cs now contains mix number */
|
/* cs now contains mix number */
|
||||||
if(cs < (MAX_MIX_COUNT + 1))
|
if(cs < (MAX_MIX_COUNT + 1))
|
||||||
{
|
{
|
||||||
|
int source = (buffer, unsigned char[])[0];
|
||||||
|
|
||||||
/* Check for "off" - update local state */
|
/* Check for "off" - update local state */
|
||||||
if((buffer, unsigned char[])[0] == 0xFF)
|
if(source == 0xFF)
|
||||||
{
|
{
|
||||||
mixSel[cs][cn] = (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
|
source = (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mixSel[cs][cn] = (buffer, unsigned char[])[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cs == 0)
|
if(cs == 0)
|
||||||
@@ -745,21 +772,17 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
/* Update all mix maps */
|
/* Update all mix maps */
|
||||||
for (int i = 0; i < MAX_MIX_COUNT; i++)
|
for (int i = 0; i < MAX_MIX_COUNT; i++)
|
||||||
{
|
{
|
||||||
outuint(c_mix_ctl, SET_MIX_MAP);
|
/* i : Mix bus */
|
||||||
outuint(c_mix_ctl, i); /* Mix bus */
|
/* cn: Mixer input */
|
||||||
outuint(c_mix_ctl, cn); /* Mixer input */
|
mixSel[i][cn] = source;
|
||||||
outuint(c_mix_ctl, (int) mixSel[cn]); /* Source */
|
UpdateMixMap(c_mix_ctl, i, cn, mixSel[i][cn]);
|
||||||
outct(c_mix_ctl, XS1_CT_END);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Update relevant mix map */
|
/* Update relevant mix map */
|
||||||
outuint(c_mix_ctl, SET_MIX_MAP); /* Command */
|
mixSel[cs-1][cn] = source;
|
||||||
outuint(c_mix_ctl, (cs-1)); /* Mix bus */
|
UpdateMixMap(c_mix_ctl, cs-1, cn, mixSel[cs-1][cn]);
|
||||||
outuint(c_mix_ctl, cn); /* Mixer input */
|
|
||||||
outuint(c_mix_ctl, (int) mixSel[cs][cn]); /* Source */
|
|
||||||
outct(c_mix_ctl, XS1_CT_END); /* Wait for handshake back */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return XUD_DoSetRequestStatus(ep0_in);
|
return XUD_DoSetRequestStatus(ep0_in);
|
||||||
@@ -780,7 +803,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)))
|
if((cs > 0) && (cs < (MAX_MIX_COUNT+1)))
|
||||||
{
|
{
|
||||||
(buffer, unsigned char[])[0] = mixSel[cs-1][cn];
|
(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 +811,53 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ID_MIXER_1:
|
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(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
|
||||||
{
|
{
|
||||||
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)
|
if(cn < sizeof(mixer1Weights)/sizeof(mixer1Weights[0]))
|
||||||
{
|
{
|
||||||
volume = 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
|
else
|
||||||
{
|
{
|
||||||
volume = db_to_mult(mixer1Weights[sp.wValue & 0xff], 8, 25);
|
short weight = 0x8000;
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send 0 Length as status stage */
|
if(cn < sizeof(mixer1Weights)/sizeof(mixer1Weights[0]))
|
||||||
return XUD_DoSetRequestStatus(ep0_in);
|
{
|
||||||
}
|
weight = mixer1Weights[cn];
|
||||||
else
|
}
|
||||||
{
|
|
||||||
short weight = mixer1Weights[sp.wValue & 0xff];
|
|
||||||
(buffer, unsigned char[])[0] = weight & 0xff;
|
|
||||||
(buffer, unsigned char[])[1] = (weight >> 8) & 0xff;
|
|
||||||
|
|
||||||
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;
|
break;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
/* We dont have a unit with this ID! */
|
/* We dont have a unit with this ID! */
|
||||||
@@ -919,7 +946,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
num_freqs++;
|
num_freqs++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
storeShort((buffer, unsigned char[]), 0, num_freqs);
|
storeShort((buffer, unsigned char[]), 0, num_freqs);
|
||||||
|
|
||||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), i, sp.wLength);
|
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), i, sp.wLength);
|
||||||
@@ -957,7 +983,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
/* Mixer Unit */
|
/* Mixer Unit */
|
||||||
case ID_MIXER_1:
|
case ID_MIXER_1:
|
||||||
storeShort((buffer, unsigned char[]), 0, 1);
|
storeShort((buffer, unsigned char[]), 0, 1);
|
||||||
@@ -967,7 +993,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);
|
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Unknown Unit ID in Range Request selector for FU */
|
/* Unknown Unit ID in Range Request selector for FU */
|
||||||
break;
|
break;
|
||||||
@@ -977,7 +1002,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
break; /* case: RANGE */
|
break; /* case: RANGE */
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined (MIXER) && (MAX_MIX_COUNT > 0)
|
#if ((MIXER) && (MAX_MIX_COUNT > 0))
|
||||||
case MEM: /* Memory Requests (5.2.7.1) */
|
case MEM: /* Memory Requests (5.2.7.1) */
|
||||||
|
|
||||||
unitID = sp.wIndex >> 8;
|
unitID = sp.wIndex >> 8;
|
||||||
@@ -1003,6 +1028,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
{
|
{
|
||||||
if (!isnull(c_mix_ctl))
|
if (!isnull(c_mix_ctl))
|
||||||
{
|
{
|
||||||
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
|
inct(c_mix_ctl);
|
||||||
outuint(c_mix_ctl, GET_STREAM_LEVELS);
|
outuint(c_mix_ctl, GET_STREAM_LEVELS);
|
||||||
outuint(c_mix_ctl, i);
|
outuint(c_mix_ctl, i);
|
||||||
outct(c_mix_ctl, XS1_CT_END);
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
@@ -1018,6 +1045,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
{
|
{
|
||||||
if (!isnull(c_mix_ctl))
|
if (!isnull(c_mix_ctl))
|
||||||
{
|
{
|
||||||
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
|
inct(c_mix_ctl);
|
||||||
outuint(c_mix_ctl, GET_INPUT_LEVELS);
|
outuint(c_mix_ctl, GET_INPUT_LEVELS);
|
||||||
outuint(c_mix_ctl, (i - NUM_USB_CHAN_OUT));
|
outuint(c_mix_ctl, (i - NUM_USB_CHAN_OUT));
|
||||||
outct(c_mix_ctl, XS1_CT_END);
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
@@ -1040,6 +1069,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
|||||||
{
|
{
|
||||||
if (!isnull(c_mix_ctl))
|
if (!isnull(c_mix_ctl))
|
||||||
{
|
{
|
||||||
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
|
inct(c_mix_ctl);
|
||||||
outuint(c_mix_ctl, GET_OUTPUT_LEVELS);
|
outuint(c_mix_ctl, GET_OUTPUT_LEVELS);
|
||||||
outuint(c_mix_ctl, i);
|
outuint(c_mix_ctl, i);
|
||||||
outct(c_mix_ctl, XS1_CT_END);
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
@@ -1107,13 +1138,10 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp
|
|||||||
|
|
||||||
if(newSampleRate != g_curSamFreq)
|
if(newSampleRate != g_curSamFreq)
|
||||||
{
|
{
|
||||||
int curSamFreq44100Family;
|
|
||||||
int curSamFreq48000Family;
|
|
||||||
|
|
||||||
/* Windows Audio Class driver has a nice habbit of sending invalid SF's (e.g. 48001Hz)
|
/* 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. */
|
* when under stress. Lets double check it here and ignore if not valid. */
|
||||||
curSamFreq48000Family = MCLK_48 % newSampleRate == 0;
|
int curSamFreq48000Family = MCLK_48 % newSampleRate == 0;
|
||||||
curSamFreq44100Family = MCLK_441 % newSampleRate == 0;
|
int curSamFreq44100Family = MCLK_441 % newSampleRate == 0;
|
||||||
|
|
||||||
if(curSamFreq48000Family || curSamFreq44100Family)
|
if(curSamFreq48000Family || curSamFreq44100Family)
|
||||||
{
|
{
|
||||||
@@ -1128,7 +1156,7 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp
|
|||||||
|
|
||||||
/* Allow time for the change - feedback to stabilise */
|
/* Allow time for the change - feedback to stabilise */
|
||||||
FeedbackStabilityDelay();
|
FeedbackStabilityDelay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return XUD_SetBuffer(ep0_in, (buffer, unsigned char[]), 0);
|
return XUD_SetBuffer(ep0_in, (buffer, unsigned char[]), 0);
|
||||||
}
|
}
|
||||||
@@ -1190,12 +1218,12 @@ XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket
|
|||||||
{
|
{
|
||||||
case FU_USBOUT:
|
case FU_USBOUT:
|
||||||
volsOut[ sp.wValue & 0xff ] = buffer[0] | (((int) (signed char) buffer[1]) << 8);
|
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);
|
return XUD_DoSetRequestStatus(ep0_in);
|
||||||
|
|
||||||
case FU_USBIN:
|
case FU_USBIN:
|
||||||
volsIn[ sp.wValue & 0xff ] = buffer[0] | (((int) (signed char) buffer[1]) << 8);
|
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);
|
return XUD_DoSetRequestStatus(ep0_in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1209,12 +1237,12 @@ XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket
|
|||||||
{
|
{
|
||||||
case FU_USBOUT:
|
case FU_USBOUT:
|
||||||
mutesOut[ sp.wValue & 0xff ] = buffer[0];
|
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);
|
return XUD_DoSetRequestStatus(ep0_in);
|
||||||
|
|
||||||
case FU_USBIN:
|
case FU_USBIN:
|
||||||
mutesIn[ sp.wValue & 0xff ] = buffer[0];
|
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);
|
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.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
#include "xua.h" /* Device specific defines */
|
#include "xua.h" /* Device specific defines */
|
||||||
@@ -273,7 +273,7 @@ void usb_audio_core(chanend c_mix_out
|
|||||||
#ifdef MIDI
|
#ifdef MIDI
|
||||||
, chanend c_midi
|
, chanend c_midi
|
||||||
#endif
|
#endif
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
, chanend c_mix_ctl
|
, chanend c_mix_ctl
|
||||||
#endif
|
#endif
|
||||||
, chanend ?c_clk_int
|
, chanend ?c_clk_int
|
||||||
@@ -290,7 +290,7 @@ VENDOR_REQUESTS_PARAMS_DEC_
|
|||||||
chan c_xud_in[ENDPOINT_COUNT_IN];
|
chan c_xud_in[ENDPOINT_COUNT_IN];
|
||||||
chan c_aud_ctl;
|
chan c_aud_ctl;
|
||||||
|
|
||||||
#ifndef MIXER
|
#if (!MIXER)
|
||||||
#define c_mix_ctl null
|
#define c_mix_ctl null
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -401,7 +401,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
|||||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||||
chanend c_spdif_tx,
|
chanend c_spdif_tx,
|
||||||
#endif
|
#endif
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
chanend c_mix_ctl,
|
chanend c_mix_ctl,
|
||||||
#endif
|
#endif
|
||||||
streaming chanend ?c_spdif_rx,
|
streaming chanend ?c_spdif_rx,
|
||||||
@@ -422,7 +422,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
|||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
chan c_mix_out;
|
chan c_mix_out;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -446,7 +446,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
|||||||
|
|
||||||
par
|
par
|
||||||
{
|
{
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
/* Mixer cores(s) */
|
/* Mixer cores(s) */
|
||||||
{
|
{
|
||||||
thread_speed();
|
thread_speed();
|
||||||
@@ -464,7 +464,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
|||||||
/* Audio I/O core (pars additional S/PDIF TX Core) */
|
/* Audio I/O core (pars additional S/PDIF TX Core) */
|
||||||
{
|
{
|
||||||
thread_speed();
|
thread_speed();
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
#define AUDIO_CHANNEL c_mix_out
|
#define AUDIO_CHANNEL c_mix_out
|
||||||
#else
|
#else
|
||||||
#define AUDIO_CHANNEL c_aud_in
|
#define AUDIO_CHANNEL c_aud_in
|
||||||
@@ -531,7 +531,7 @@ int main()
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
chan c_mix_ctl;
|
chan c_mix_ctl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -608,7 +608,7 @@ int main()
|
|||||||
, c_ea_data
|
, c_ea_data
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
, c_mix_ctl
|
, c_mix_ctl
|
||||||
#endif
|
#endif
|
||||||
, c_clk_int, c_clk_ctl, dfuInterface
|
, c_clk_int, c_clk_ctl, dfuInterface
|
||||||
@@ -628,7 +628,7 @@ int main()
|
|||||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||||
, c_spdif_tx
|
, c_spdif_tx
|
||||||
#endif
|
#endif
|
||||||
#ifdef MIXER
|
#if (MIXER)
|
||||||
, c_mix_ctl
|
, c_mix_ctl
|
||||||
#endif
|
#endif
|
||||||
, c_spdif_rx, c_adat_rx, c_clk_ctl, c_clk_int
|
, c_spdif_rx, c_adat_rx, c_clk_ctl, c_clk_int
|
||||||
|
|||||||
@@ -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.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
|
||||||
#define MAX_MIX_COUNT 8
|
#include "xua.h"
|
||||||
#define MIX_INPUTS 18
|
|
||||||
|
#ifndef MAX_MIX_COUNT
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIX_INPUTS
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (MAX_MIX_COUNT > 0)
|
||||||
|
|
||||||
#define DOMIX_TOP(i) \
|
#define DOMIX_TOP(i) \
|
||||||
.cc_top doMix##i.function,doMix##i; \
|
.cc_top doMix##i.function,doMix##i; \
|
||||||
.align 4 ;\
|
.align 16 ;\
|
||||||
.globl doMix##i ;\
|
.globl doMix##i ;\
|
||||||
.type doMix##i, @function ;\
|
.type doMix##i, @function ;\
|
||||||
.globl doMix##i##.nstackwords ;\
|
.globl doMix##i##.nstackwords ;\
|
||||||
@@ -124,7 +133,7 @@ DOMIX_BOT(7)
|
|||||||
#undef BODY
|
#undef BODY
|
||||||
#define N MAX_MIX_COUNT
|
#define N MAX_MIX_COUNT
|
||||||
.cc_top setPtr.function,setPtr;
|
.cc_top setPtr.function,setPtr;
|
||||||
.align 4 ;
|
.align 16 ;
|
||||||
.globl setPtr;
|
.globl setPtr;
|
||||||
.type setPtr, @function
|
.type setPtr, @function
|
||||||
.globl setPtr.nstackwords;
|
.globl setPtr.nstackwords;
|
||||||
@@ -173,5 +182,5 @@ setPtr_go:
|
|||||||
#undef N
|
#undef N
|
||||||
#undef BODY
|
#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.
|
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
|
#define XASSERT_UNIT MIXER
|
||||||
|
#include "xassert.h"
|
||||||
|
|
||||||
#include <xs1.h>
|
#include <xs1.h>
|
||||||
#include <print.h>
|
|
||||||
#include "xua.h"
|
#include "xua.h"
|
||||||
#include "xc_ptr.h"
|
|
||||||
#include "xua_commands.h"
|
#include "xua_commands.h"
|
||||||
#include "dbcalc.h"
|
#include "dbcalc.h"
|
||||||
|
|
||||||
#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 */
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) || !FAST_MIXER
|
||||||
#define FAST_MIXER 1
|
#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 unsigned int multOut_array[NUM_USB_CHAN_OUT + 1];
|
||||||
static xc_ptr multOut;
|
unsafe
|
||||||
//#endif
|
{
|
||||||
//#ifdef IN_VOLUME_IN_MIXER
|
int volatile * unsafe multOut = multOut_array;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (IN_VOLUME_IN_MIXER)
|
||||||
static unsigned int multIn_array[NUM_USB_CHAN_IN + 1];
|
static unsigned int multIn_array[NUM_USB_CHAN_IN + 1];
|
||||||
static xc_ptr multIn;
|
unsafe
|
||||||
//#endif
|
{
|
||||||
|
int volatile * unsafe multIn = multIn_array;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
||||||
static unsigned abs(int x)
|
static unsigned abs(int x)
|
||||||
@@ -35,35 +49,38 @@ static unsigned abs(int x)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const int SOURCE_COUNT = NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1;
|
||||||
|
|
||||||
static int samples_array[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1]; /* One larger for an "off" channel for mixer sources" */
|
static int samples_array[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1]; /* One larger for an "off" channel for mixer sources" */
|
||||||
xc_ptr samples;
|
static int samples_to_host_map_array[NUM_USB_CHAN_IN];
|
||||||
|
static int samples_to_device_map_array[NUM_USB_CHAN_OUT];
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
static int volatile * const unsafe ptr_samples = samples_array;
|
int volatile * const unsafe ptr_samples = samples_array;
|
||||||
|
int volatile * const unsafe samples_to_host_map = samples_to_host_map_array;
|
||||||
|
int volatile * const unsafe samples_to_device_map = samples_to_device_map_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
int savedsamples2[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
#if (MAX_MIX_COUNT > 0)
|
||||||
|
int mix_mult_array[MAX_MIX_COUNT * MIX_INPUTS];
|
||||||
int samples_to_host_map_array[NUM_USB_CHAN_IN];
|
#if (FAST_MIXER == 0)
|
||||||
xc_ptr samples_to_host_map;
|
int mix_map_array[MAX_MIX_COUNT * MIX_INPUTS];
|
||||||
|
|
||||||
int samples_to_device_map_array[NUM_USB_CHAN_OUT];
|
|
||||||
xc_ptr samples_to_device_map;
|
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 0
|
|
||||||
int mix_mult_array[MAX_MIX_COUNT][MIX_INPUTS];
|
|
||||||
xc_ptr mix_mult;
|
|
||||||
#define write_word_to_mix_mult(x,y,val) write_via_xc_ptr_indexed(mix_mult,((x)*MIX_INPUTS)+(y), val)
|
|
||||||
#define mix_mult_slice(x) (mix_mult + x * MIX_INPUTS * sizeof(int))
|
|
||||||
#ifndef FAST_MIXER
|
|
||||||
int mix_map_array[MAX_MIX_COUNT][MIX_INPUTS];
|
|
||||||
xc_ptr mix_map;
|
|
||||||
#define write_word_to_mix_map(x,y,val) write_via_xc_ptr_indexed(mix_map,((x)*MIX_INPUTS)+(y), val)
|
|
||||||
#define mix_map_slice(x) (mix_map + x * MIX_INPUTS * sizeof(int))
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
int volatile * const unsafe mix_mult = mix_mult_array;
|
||||||
|
#if (FAST_MIXER == 0)
|
||||||
|
int volatile * const unsafe mix_map = mix_map_array;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define slice(a, i) (a + i * MIX_INPUTS)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
/* Arrays for level data */
|
/* Arrays for level data */
|
||||||
int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. device inputs */
|
int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. device inputs */
|
||||||
xc_ptr samples_to_host_inputs_ptr;
|
xc_ptr samples_to_host_inputs_ptr;
|
||||||
@@ -77,19 +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 */
|
static int samples_mixer_outputs[MAX_MIX_COUNT]; /* Peak samples out of the mixer */
|
||||||
xc_ptr samples_mixer_outputs_ptr;
|
xc_ptr samples_mixer_outputs_ptr;
|
||||||
|
|
||||||
#if 0
|
|
||||||
#pragma xta command "add exclusion mixer1_rate_change"
|
|
||||||
#pragma xta command "analyse path mixer1_req mixer1_req"
|
|
||||||
#pragma xta command "set required - 10400 ns" /* 96kHz */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
#pragma xta command "add exclusion mixer2_rate_change"
|
|
||||||
#pragma xta command "analyse path mixer2_req mixer2_req"
|
|
||||||
#pragma xta command "set required - 10400 ns" /* 96kHz */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
|
||||||
static inline void ComputeMixerLevel(int sample, int i)
|
static inline void ComputeMixerLevel(int sample, int i)
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
@@ -108,42 +112,40 @@ static inline void ComputeMixerLevel(int sample, int i)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef FAST_MIXER
|
|
||||||
|
#if (FAST_MIXER)
|
||||||
void setPtr(int src, int dst, int mix);
|
void setPtr(int src, int dst, int mix);
|
||||||
int doMix0(xc_ptr samples, xc_ptr mult);
|
int doMix0(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||||
int doMix1(xc_ptr samples, xc_ptr mult);
|
int doMix1(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||||
int doMix2(xc_ptr samples, xc_ptr mult);
|
int doMix2(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||||
int doMix3(xc_ptr samples, xc_ptr mult);
|
int doMix3(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||||
int doMix4(xc_ptr samples, xc_ptr mult);
|
int doMix4(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||||
int doMix5(xc_ptr samples, xc_ptr mult);
|
int doMix5(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||||
int doMix6(xc_ptr samples, xc_ptr mult);
|
int doMix6(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||||
int doMix7(xc_ptr samples, xc_ptr mult);
|
int doMix7(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||||
int doMix8(xc_ptr samples, xc_ptr mult);
|
|
||||||
#else
|
#else
|
||||||
/* DO NOT inline, causes 10.4.2 tools to add extra loads in loop */
|
|
||||||
/* At 18 x 12dB we could get 64 x bigger */
|
|
||||||
#pragma unsafe arrays
|
#pragma unsafe arrays
|
||||||
static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
|
static inline int doMix(volatile int * unsafe samples, volatile int * unsafe const mixMap, volatile int * const unsafe mult)
|
||||||
{
|
{
|
||||||
int h=0;
|
int h=0;
|
||||||
int l=0;
|
int l=0;
|
||||||
|
|
||||||
/* By breaking up the loop we keep things in the encoding for ldw (0-11) */
|
|
||||||
#pragma loop unroll
|
#pragma loop unroll
|
||||||
for (int i=0; i<MIX_INPUTS; i++)
|
for (int i=0; i<MIX_INPUTS; i++)
|
||||||
{
|
unsafe{
|
||||||
int sample;
|
int sample;
|
||||||
int index;
|
int source;
|
||||||
int m;
|
int weight;
|
||||||
read_via_xc_ptr_indexed(index, ptr, i);
|
read_via_xc_ptr_indexed(source, mixMap, i);
|
||||||
read_via_xc_ptr_indexed(sample,samples,index);
|
sample = samples[source];
|
||||||
read_via_xc_ptr_indexed(m, mult, i);
|
read_via_xc_ptr_indexed(weight, mult, i);
|
||||||
{h,l} = macs(sample, m, h, l);
|
|
||||||
|
|
||||||
|
{h,l} = macs(sample, weight, h, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
|
||||||
/* Perform saturation */
|
/* Perform saturation */
|
||||||
l = sext(h, 25);
|
l = sext(h, XUA_MIXER_MULT_FRAC_BITS);
|
||||||
|
|
||||||
if(l != h)
|
if(l != h)
|
||||||
{
|
{
|
||||||
@@ -152,15 +154,14 @@ static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
|
|||||||
else
|
else
|
||||||
h = (0x7fffff00>>7);
|
h = (0x7fffff00>>7);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return h<<7;
|
return h<<7;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#pragma unsafe arrays
|
#pragma unsafe arrays
|
||||||
static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
|
static inline void GiveSamplesToHost(chanend c, volatile int * unsafe hostMap)
|
||||||
{
|
{
|
||||||
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||||
int mult;
|
int mult;
|
||||||
int h;
|
int h;
|
||||||
unsigned l;
|
unsigned l;
|
||||||
@@ -170,23 +171,26 @@ static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
|
|||||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||||
{
|
{
|
||||||
int sample;
|
int sample;
|
||||||
int index;
|
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 0
|
#if (MAX_MIX_COUNT > 0)
|
||||||
read_via_xc_ptr_indexed(index,ptr,i);
|
|
||||||
#else
|
|
||||||
index = i + NUM_USB_CHAN_OUT;
|
|
||||||
#endif
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
//read_via_xc_ptr_indexed(sample,samples,index);
|
sample = ptr_samples[hostMap[i]];
|
||||||
sample = ptr_samples[index];
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
sample = ptr_samples[i + NUM_USB_CHAN_OUT];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||||
#warning IN Vols in mixer, AFTER mix & map
|
#warning IN Vols in mixer, AFTER mix & map
|
||||||
//asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i));
|
|
||||||
read_via_xc_ptr_indexed(mult, multIn, i);
|
unsafe
|
||||||
|
{
|
||||||
|
mult = multIn[i];
|
||||||
|
}
|
||||||
{h, l} = macs(mult, sample, 0, 0);
|
{h, l} = macs(mult, sample, 0, 0);
|
||||||
|
|
||||||
//h <<= 3 done on other side */
|
//h <<= 3 done on other side */
|
||||||
@@ -209,7 +213,7 @@ static inline void GetSamplesFromHost(chanend c)
|
|||||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||||
unsafe {
|
unsafe {
|
||||||
int sample, x;
|
int sample, x;
|
||||||
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
|
#if (OUT_VOLUME_IN_MIXER && !OUT_VOLUME_AFTER_MIX)
|
||||||
int mult;
|
int mult;
|
||||||
int h;
|
int h;
|
||||||
unsigned l;
|
unsigned l;
|
||||||
@@ -226,50 +230,47 @@ static inline void GetSamplesFromHost(chanend c)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
|
#if (OUT_VOLUME_IN_MIXER && !OUT_VOLUME_AFTER_MIX)
|
||||||
#warning OUT Vols in mixer, BEFORE mix & map
|
#warning OUT Vols in mixer, BEFORE mix & map
|
||||||
read_via_xc_ptr_indexed(mult, multOut, i);
|
mult = multOut[i];
|
||||||
{h, l} = macs(mult, sample, 0, 0);
|
{h, l} = macs(mult, sample, 0, 0);
|
||||||
h<<=3;
|
h<<=3;
|
||||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||||
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||||
// Note: We need all 32bits for Native DSD
|
// Note: We need all 32bits for Native DSD
|
||||||
|
#endif
|
||||||
|
sample = h;
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(multOut, index, val);
|
|
||||||
write_via_xc_ptr_indexed(samples_array, i, h);
|
|
||||||
#else
|
|
||||||
ptr_samples[i] = sample;
|
ptr_samples[i] = sample;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma unsafe arrays
|
#pragma unsafe arrays
|
||||||
static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
static inline void GiveSamplesToDevice(chanend c, volatile int * unsafe deviceMap)
|
||||||
{
|
{
|
||||||
#if(NUM_USB_CHAN_OUT == 0)
|
#if (NUM_USB_CHAN_OUT == 0)
|
||||||
outuint(c, 0);
|
outuint(c, 0);
|
||||||
#else
|
#else
|
||||||
#pragma loop unroll
|
#pragma loop unroll
|
||||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||||
{
|
{
|
||||||
int sample, x;
|
int sample, x;
|
||||||
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
|
#if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
|
||||||
int mult;
|
int mult;
|
||||||
int h;
|
int h;
|
||||||
unsigned l;
|
unsigned l;
|
||||||
#endif
|
#endif
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 0
|
#if (MAX_MIX_COUNT > 0)
|
||||||
/* If mixer turned on sort out the channel mapping */
|
/* If mixer turned on sort out the channel mapping */
|
||||||
|
unsafe
|
||||||
/* Read pointer to sample from the map */
|
{
|
||||||
read_via_xc_ptr_indexed(index, ptr, i);
|
/* Read index to sample from the map then Read the actual sample value */
|
||||||
|
sample = ptr_samples[deviceMap[i]];
|
||||||
/* Read the actual sample value */
|
}
|
||||||
read_via_xc_ptr_indexed(sample, samples, index);
|
|
||||||
#else
|
#else
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
@@ -278,16 +279,19 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
|
#if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
|
||||||
/* Do volume control processing */
|
/* Do volume control processing */
|
||||||
#warning OUT Vols in mixer, AFTER mix & map
|
#warning OUT Vols in mixer, AFTER mix & map
|
||||||
read_via_xc_ptr_indexed(mult, multOut, i);
|
unsafe
|
||||||
|
{
|
||||||
|
mult = multOut[i];
|
||||||
|
}
|
||||||
|
|
||||||
{h, l} = macs(mult, sample, 0, 0);
|
{h, l} = macs(mult, sample, 0, 0);
|
||||||
h<<=3; // Shift used to be done in audio thread but now done here incase of 32bit support
|
h<<=3; // Shift used to be done in audio thread but now done here incase of 32bit support
|
||||||
#error
|
|
||||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||||
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||||
// Note: We need all 32bits for Native DSD
|
// Note: We need all 32bits for Native DSD
|
||||||
#endif
|
#endif
|
||||||
outuint(c, h);
|
outuint(c, h);
|
||||||
#else
|
#else
|
||||||
@@ -300,14 +304,14 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
|||||||
#pragma unsafe arrays
|
#pragma unsafe arrays
|
||||||
static inline void GetSamplesFromDevice(chanend c)
|
static inline void GetSamplesFromDevice(chanend c)
|
||||||
{
|
{
|
||||||
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
|
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||||
int mult;
|
int mult;
|
||||||
int h;
|
int h;
|
||||||
unsigned l;
|
unsigned l;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#pragma loop unroll
|
#pragma loop unroll
|
||||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||||
{
|
{
|
||||||
int sample;
|
int sample;
|
||||||
int x;
|
int x;
|
||||||
@@ -327,22 +331,24 @@ static inline void GetSamplesFromDevice(chanend c)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
|
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||||
/* Read relevant multiplier */
|
/* Volume processing - read relevant multiplier */
|
||||||
read_via_xc_ptr_indexed(mult, multIn, i);
|
unsafe
|
||||||
|
{
|
||||||
|
mult = multIn[i];
|
||||||
|
}
|
||||||
|
|
||||||
/* Do the multiply */
|
/* Do the multiply */
|
||||||
{h, l} = macs(mult, sample, 0, 0);
|
{h, l} = macs(mult, sample, 0, 0);
|
||||||
h <<=3;
|
h <<= 3;
|
||||||
write_via_xc_ptr_indexed(samples_array, NUM_USB_CHAN_OUT+i, h);
|
sample = h;
|
||||||
#else
|
#endif
|
||||||
/* No volume processing */
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
ptr_samples[NUM_USB_CHAN_OUT + i] = sample;
|
assert((XUA_MIXER_OFFSET_IN + i) < (NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT));
|
||||||
|
ptr_samples[XUA_MIXER_OFFSET_IN + i] = sample;
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mixer1_mix2_flag = (DEFAULT_FREQ > 96000);
|
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)
|
#if (MAX_MIX_COUNT > 0)
|
||||||
int mixed;
|
int mixed;
|
||||||
#endif
|
#endif
|
||||||
|
#if (MAX_MIX_COUNT > 0) || (IN_VOLUME_IN_MIXER) || (OUT_VOLUME_IN_MIXER) || defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
unsigned cmd;
|
unsigned cmd;
|
||||||
|
unsigned char ct;
|
||||||
|
#endif
|
||||||
unsigned request = 0;
|
unsigned request = 0;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
#pragma xta endpoint "mixer1_req"
|
|
||||||
/* Request from audio()/mixer2() */
|
/* Request from audio()/mixer2() */
|
||||||
request = inuint(c_mixer2);
|
request = inuint(c_mixer2);
|
||||||
|
|
||||||
@@ -369,28 +377,62 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
/* Sync */
|
/* Sync */
|
||||||
outuint(c_mixer2, 0);
|
outuint(c_mixer2, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Between request to decouple and response ~ 400nS latency for interrupt to fire */
|
/* Between request to decouple and response ~ 400nS latency for interrupt to fire */
|
||||||
|
|
||||||
|
#if (MAX_MIX_COUNT > 0) || (IN_VOLUME_IN_MIXER) || (OUT_VOLUME_IN_MIXER) || defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
select
|
select
|
||||||
{
|
{
|
||||||
case inuint_byref(c_mix_ctl, cmd):
|
/* Check if EP0 intends to send us a control command */
|
||||||
|
case inct_byref(c_mix_ctl, ct):
|
||||||
{
|
{
|
||||||
int mix, index, val;
|
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)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
#if MAX_MIX_COUNT > 0
|
#if (MAX_MIX_COUNT > 0)
|
||||||
case SET_SAMPLES_TO_HOST_MAP:
|
case SET_SAMPLES_TO_HOST_MAP:
|
||||||
index = inuint(c_mix_ctl);
|
{
|
||||||
val = inuint(c_mix_ctl);
|
int dst = inuint(c_mix_ctl);
|
||||||
inct(c_mix_ctl);
|
int src = inuint(c_mix_ctl);
|
||||||
write_via_xc_ptr_indexed(samples_to_host_map, index, val);
|
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;
|
break;
|
||||||
|
|
||||||
case SET_SAMPLES_TO_DEVICE_MAP:
|
case SET_SAMPLES_TO_DEVICE_MAP:
|
||||||
index = inuint(c_mix_ctl);
|
{
|
||||||
val = inuint(c_mix_ctl);
|
int dst = inuint(c_mix_ctl);
|
||||||
inct(c_mix_ctl);
|
int src = inuint(c_mix_ctl);
|
||||||
write_via_xc_ptr_indexed(samples_to_device_map,index,val);
|
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;
|
break;
|
||||||
|
|
||||||
case SET_MIX_MULT:
|
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);
|
val = inuint(c_mix_ctl);
|
||||||
inct(c_mix_ctl);
|
inct(c_mix_ctl);
|
||||||
|
|
||||||
write_word_to_mix_mult(mix, index, val);
|
assert((mix < MAX_MIX_COUNT) && msg("Mix mult mix out of range"));
|
||||||
|
assert((index < MIX_INPUTS) && msg("Mix mult index out of range"));
|
||||||
|
|
||||||
|
if((index < MIX_INPUTS) && (mix < MAX_MIX_COUNT))
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
mix_mult[(mix * MIX_INPUTS) + index] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SET_MIX_MAP:
|
case SET_MIX_MAP:
|
||||||
mix = inuint(c_mix_ctl);
|
{
|
||||||
index = inuint(c_mix_ctl); /* mixer input */
|
unsigned mix = inuint(c_mix_ctl);
|
||||||
val = inuint(c_mix_ctl); /* source */
|
unsigned input = inuint(c_mix_ctl); /* mixer input */
|
||||||
inct(c_mix_ctl);
|
unsigned source = inuint(c_mix_ctl); /* source */
|
||||||
#ifdef FAST_MIXER
|
inct(c_mix_ctl);
|
||||||
setPtr(index, val, mix);
|
|
||||||
|
assert((mix < MAX_MIX_COUNT) && msg("Mix map mix out of range"));
|
||||||
|
assert((input < MIX_INPUTS) && msg("Mix map index out of range"));
|
||||||
|
assert((source < SOURCE_COUNT) && msg("Mix map source out of range"));
|
||||||
|
|
||||||
|
if((input < MIX_INPUTS) && (mix < MAX_MIX_COUNT) && (source < SOURCE_COUNT))
|
||||||
|
{
|
||||||
|
#if (FAST_MIXER)
|
||||||
|
setPtr(input, source, mix);
|
||||||
#else
|
#else
|
||||||
write_word_to_mix_map(mix, index, val);
|
unsafe
|
||||||
|
{
|
||||||
|
mix_map[(mix * MIX_INPUTS) + input] = source;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* if MAX_MIX_COUNT > 0 */
|
#endif /* if MAX_MIX_COUNT > 0 */
|
||||||
#ifdef IN_VOLUME_IN_MIXER
|
|
||||||
|
#if (IN_VOLUME_IN_MIXER)
|
||||||
case SET_MIX_IN_VOL:
|
case SET_MIX_IN_VOL:
|
||||||
index = inuint(c_mix_ctl);
|
index = inuint(c_mix_ctl);
|
||||||
val = inuint(c_mix_ctl);
|
val = inuint(c_mix_ctl);
|
||||||
inct(c_mix_ctl);
|
inct(c_mix_ctl);
|
||||||
|
|
||||||
write_via_xc_ptr_indexed(multIn, index, val);
|
assert((index < (NUM_USB_CHAN_IN + 1)) && msg("In volume index out of range"));
|
||||||
|
|
||||||
|
if(index < NUM_USB_CHAN_IN + 1)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
multIn[index] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef OUT_VOLUME_IN_MIXER
|
#if (OUT_VOLUME_IN_MIXER)
|
||||||
case SET_MIX_OUT_VOL:
|
case SET_MIX_OUT_VOL:
|
||||||
index = inuint(c_mix_ctl);
|
index = inuint(c_mix_ctl);
|
||||||
val = inuint(c_mix_ctl);
|
val = inuint(c_mix_ctl);
|
||||||
inct(c_mix_ctl);
|
inct(c_mix_ctl);
|
||||||
|
|
||||||
write_via_xc_ptr_indexed(multOut, index, val);
|
assert((index < (NUM_USB_CHAN_OUT + 1)) && msg("Out volume index out of range"));
|
||||||
|
|
||||||
|
if(index < NUM_USB_CHAN_OUT + 1)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
multOut[index] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
/* Peak samples of stream from host to device (via USB) */
|
/* Peak samples of stream from host to device (via USB) */
|
||||||
case GET_STREAM_LEVELS:
|
case GET_STREAM_LEVELS:
|
||||||
index = inuint(c_mix_ctl);
|
index = inuint(c_mix_ctl);
|
||||||
@@ -441,42 +523,6 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
outct(c_mix_ctl, XS1_CT_END);
|
outct(c_mix_ctl, XS1_CT_END);
|
||||||
samples_from_host_streams[index] = 0;
|
samples_from_host_streams[index] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GET_INPUT_LEVELS:
|
|
||||||
index = inuint(c_mix_ctl);
|
|
||||||
chkct(c_mix_ctl, XS1_CT_END);
|
|
||||||
#ifdef LEVEL_METER_LEDS
|
|
||||||
/* Level LEDS process reseting samples_to_host_inputs
|
|
||||||
* Other side makes sure we don't miss a peak */
|
|
||||||
//val = samples_to_host_inputs_buff[index];
|
|
||||||
//samples_to_host_inputs_buff[index] = 0;
|
|
||||||
/* Access funcs used to avoid disjointness check */
|
|
||||||
read_via_xc_ptr_indexed(val, samples_to_host_inputs_buff_ptr, index);
|
|
||||||
write_via_xc_ptr_indexed(samples_to_host_inputs_buff_ptr, index, 0);
|
|
||||||
#else
|
|
||||||
/* We dont have a level LEDs process, so reset ourselves */
|
|
||||||
//val = samples_to_host_inputs[index];
|
|
||||||
//samples_to_host_inputs[index] = 0;
|
|
||||||
/* Access funcs used to avoid disjointness check */
|
|
||||||
read_via_xc_ptr_indexed(val, samples_to_host_inputs_ptr, index);
|
|
||||||
write_via_xc_ptr_indexed(samples_to_host_inputs_ptr, index, 0);
|
|
||||||
#endif
|
|
||||||
outuint(c_mix_ctl, val);
|
|
||||||
outct(c_mix_ctl, XS1_CT_END);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if (MAX_MIX_COUNT > 0)
|
|
||||||
/* Peak samples of the mixer outputs */
|
|
||||||
case GET_OUTPUT_LEVELS:
|
|
||||||
index = inuint(c_mix_ctl);
|
|
||||||
chkct(c_mix_ctl, XS1_CT_END);
|
|
||||||
read_via_xc_ptr_indexed(val, samples_mixer_outputs, index);
|
|
||||||
write_via_xc_ptr_indexed(samples_mixer_outputs, index, 0);
|
|
||||||
//val = samples_mixer_outputs[index];
|
|
||||||
//samples_mixer_outputs[index] = 0;
|
|
||||||
outuint(c_mix_ctl, val);
|
|
||||||
outct(c_mix_ctl, XS1_CT_END);
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -484,14 +530,13 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
default:
|
default:
|
||||||
/* Select default */
|
/* Select default */
|
||||||
break;
|
break;
|
||||||
}
|
} // select
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Get response from decouple */
|
/* Get response from decouple */
|
||||||
if(testct(c_host))
|
if(testct(c_host))
|
||||||
{
|
{
|
||||||
int sampFreq;
|
int sampFreq;
|
||||||
#pragma xta endpoint "mixer1_rate_change"
|
|
||||||
unsigned command = inct(c_host);
|
unsigned command = inct(c_host);
|
||||||
|
|
||||||
switch(command)
|
switch(command)
|
||||||
@@ -520,9 +565,8 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
|
|
||||||
#pragma loop unroll
|
#pragma loop unroll
|
||||||
/* Reset the mix values back to 0 */
|
/* Reset the mix values back to 0 */
|
||||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
for (int i=0; i<MAX_MIX_COUNT; i++)
|
||||||
{
|
{
|
||||||
//write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
||||||
@@ -535,21 +579,24 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if MAX_MIX_COUNT > 0
|
#if (MAX_MIX_COUNT > 0)
|
||||||
GetSamplesFromHost(c_host);
|
GetSamplesFromHost(c_host);
|
||||||
GiveSamplesToHost(c_host, samples_to_host_map, multIn);
|
GiveSamplesToHost(c_host, samples_to_host_map);
|
||||||
|
|
||||||
/* Sync with mixer 2 (once it has swapped samples with audiohub) */
|
/* Sync with mixer 2 (once it has swapped samples with audiohub) */
|
||||||
outuint(c_mixer2, 0);
|
outuint(c_mixer2, 0);
|
||||||
inuint(c_mixer2);
|
inuint(c_mixer2);
|
||||||
|
|
||||||
/* Do the mixing */
|
/* Do the mixing */
|
||||||
#ifdef FAST_MIXER
|
unsafe
|
||||||
mixed = doMix0(samples, mix_mult_slice(0));
|
{
|
||||||
|
#if (FAST_MIXER)
|
||||||
|
mixed = doMix0(ptr_samples, slice(mix_mult, 0));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(0),mix_mult_slice(0));
|
mixed = doMix(ptr_samples, slice(mix_map, 0), slice(mix_mult, 0));
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0), mixed);
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0] = mixed;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 0);
|
ComputeMixerLevel(mixed, 0);
|
||||||
@@ -560,40 +607,46 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 2
|
#if (MAX_MIX_COUNT > 2)
|
||||||
#ifdef FAST_MIXER
|
unsafe
|
||||||
mixed = doMix2(samples, mix_mult_slice(2));
|
{
|
||||||
|
#if (FAST_MIXER)
|
||||||
|
mixed = doMix2(ptr_samples, slice(mix_mult, 2));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(2),mix_mult_slice(2));
|
mixed = doMix(ptr_samples, slice(mix_map, 2), slice(mix_mult, 2));
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2), mixed);
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2] = mixed;
|
||||||
|
}
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 2);
|
ComputeMixerLevel(mixed, 2);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 4
|
#if (MAX_MIX_COUNT > 4)
|
||||||
#ifdef FAST_MIXER
|
unsafe
|
||||||
mixed = doMix4(samples, mix_mult_slice(4));
|
{
|
||||||
|
#if (FAST_MIXER)
|
||||||
|
mixed = doMix4(ptr_samples, slice(mix_mult, 4));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(4),mix_mult_slice(4));
|
mixed = doMix(ptr_samples, slice(mix_map, 4), slice(mix_mult, 4));
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 4), mixed);
|
ptr_samples[XUA_MIXER_OFFSET_MIX + 4] = mixed;
|
||||||
|
}
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 4);
|
ComputeMixerLevel(mixed, 4);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 6
|
#if (MAX_MIX_COUNT > 6)
|
||||||
#ifdef FAST_MIXER
|
unsafe
|
||||||
mixed = doMix6(samples, mix_mult_slice(6));
|
{
|
||||||
|
#if (FAST_MIXER)
|
||||||
|
mixed = doMix6(ptr_samples, slice(mix_mult, 6));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(6),mix_mult_slice(6));
|
mixed = doMix(ptr_samples, slice(mix_map, 6), slice(mix_mult, 6));
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 6), mixed);
|
ptr_samples[XUA_MIXER_OFFSET_MIX + 6] = mixed;
|
||||||
|
}
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 6);
|
ComputeMixerLevel(mixed, 6);
|
||||||
#endif
|
#endif
|
||||||
@@ -601,10 +654,10 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
|||||||
}
|
}
|
||||||
#else /* IF MAX_MIX_COUNT > 0 */
|
#else /* IF MAX_MIX_COUNT > 0 */
|
||||||
/* No mixes, this thread runs on its own doing just volume */
|
/* No mixes, this thread runs on its own doing just volume */
|
||||||
GiveSamplesToDevice(c_mixer2, samples_to_device_map, multOut);
|
GiveSamplesToDevice(c_mixer2, samples_to_device_map);
|
||||||
GetSamplesFromDevice(c_mixer2);
|
GetSamplesFromDevice(c_mixer2);
|
||||||
GetSamplesFromHost(c_host);
|
GetSamplesFromHost(c_host);
|
||||||
GiveSamplesToHost(c_host, samples_to_host_map, multIn);
|
GiveSamplesToHost(c_host, samples_to_host_map);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -621,7 +674,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
#pragma xta endpoint "mixer2_req"
|
|
||||||
request = inuint(c_audio);
|
request = inuint(c_audio);
|
||||||
|
|
||||||
/* Forward the request on */
|
/* Forward the request on */
|
||||||
@@ -633,7 +685,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
|||||||
if(testct(c_mixer1))
|
if(testct(c_mixer1))
|
||||||
{
|
{
|
||||||
int sampFreq;
|
int sampFreq;
|
||||||
#pragma xta endpoint "mixer2_rate_change"
|
|
||||||
unsigned command = inct(c_mixer1);
|
unsigned command = inct(c_mixer1);
|
||||||
|
|
||||||
switch(command)
|
switch(command)
|
||||||
@@ -660,8 +711,8 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||||
{
|
unsafe{
|
||||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for handshake and pass on */
|
/* Wait for handshake and pass on */
|
||||||
@@ -670,7 +721,7 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GiveSamplesToDevice(c_audio, samples_to_device_map, multOut);
|
GiveSamplesToDevice(c_audio, samples_to_device_map);
|
||||||
GetSamplesFromDevice(c_audio);
|
GetSamplesFromDevice(c_audio);
|
||||||
|
|
||||||
/* Sync with mixer 1 (once it has swapped samples with the buffering sub-system) */
|
/* Sync with mixer 1 (once it has swapped samples with the buffering sub-system) */
|
||||||
@@ -678,61 +729,67 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
|||||||
outuint(c_mixer1, 0);
|
outuint(c_mixer1, 0);
|
||||||
|
|
||||||
/* Do the mixing */
|
/* Do the mixing */
|
||||||
#if MAX_MIX_COUNT > 1
|
#if (MAX_MIX_COUNT > 1)
|
||||||
#ifdef FAST_MIXER
|
unsafe
|
||||||
mixed = doMix1(samples, mix_mult_slice(1));
|
{
|
||||||
|
#if (FAST_MIXER)
|
||||||
|
mixed = doMix1(ptr_samples, slice(mix_mult, 1));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(1),mix_mult_slice(1));
|
mixed = doMix(ptr_samples, slice(mix_map, 1), slice(mix_mult, 1));
|
||||||
#endif
|
#endif
|
||||||
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1] = mixed;
|
||||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1), mixed);
|
}
|
||||||
|
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 1);
|
ComputeMixerLevel(mixed, 1);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if (MAX_FREQ > 96000)
|
#if (MAX_FREQ > 96000)
|
||||||
/* Fewer mixes when running higher than 96kHz */
|
/* Fewer mixes when running higher than 96kHz */
|
||||||
if (!mixer2_mix2_flag)
|
if (!mixer2_mix2_flag)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if MAX_MIX_COUNT > 3
|
#if (MAX_MIX_COUNT > 3)
|
||||||
#ifdef FAST_MIXER
|
unsafe
|
||||||
mixed = doMix3(samples, mix_mult_slice(3));
|
{
|
||||||
|
#if (FAST_MIXER)
|
||||||
|
mixed = doMix3(ptr_samples, slice(mix_mult, 3));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(3),mix_mult_slice(3));
|
mixed = doMix(ptr_samples, slice(mix_map, 3), slice(mix_mult, 3));
|
||||||
#endif
|
#endif
|
||||||
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3] = mixed;
|
||||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3), mixed);
|
}
|
||||||
|
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 3);
|
ComputeMixerLevel(mixed, 3);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 5
|
#if (MAX_MIX_COUNT > 5)
|
||||||
#ifdef FAST_MIXER
|
unsafe
|
||||||
mixed = doMix5(samples, mix_mult_slice(5));
|
{
|
||||||
|
#if (FAST_MIXER)
|
||||||
|
mixed = doMix5(ptr_samples, slice(mix_mult, 5));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(5),mix_mult_slice(5));
|
mixed = doMix(ptr_samples, slice(mix_map, 5), slice(mix_mult, 5));
|
||||||
#endif
|
#endif
|
||||||
write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5, mixed);
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5] = mixed;
|
||||||
|
|
||||||
|
}
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 5);
|
ComputeMixerLevel(mixed, 5);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MAX_MIX_COUNT > 7
|
#if (MAX_MIX_COUNT > 7)
|
||||||
#ifdef FAST_MIXER
|
unsafe
|
||||||
mixed = doMix7(samples, mix_mult_slice(7));
|
{
|
||||||
|
#if (FAST_MIXER)
|
||||||
|
mixed = doMix7(ptr_samples, slice(mix_mult, 7));
|
||||||
#else
|
#else
|
||||||
mixed = doMix(samples, mix_map_slice(7),mix_mult_slice(7));
|
mixed = doMix(ptr_samples, slice(mix_map, 7), slice(mix_mult, 7));
|
||||||
#endif
|
#endif
|
||||||
|
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7] = mixed;
|
||||||
write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7, mixed);
|
}
|
||||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
ComputeMixerLevel(mixed, 7);
|
ComputeMixerLevel(mixed, 7);
|
||||||
#endif
|
#endif
|
||||||
@@ -748,68 +805,52 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
|
|||||||
#if (MAX_MIX_COUNT > 0)
|
#if (MAX_MIX_COUNT > 0)
|
||||||
chan c;
|
chan c;
|
||||||
#endif
|
#endif
|
||||||
multOut = array_to_xc_ptr((multOut_array,unsigned[]));
|
|
||||||
multIn = array_to_xc_ptr((multIn_array,unsigned[]));
|
|
||||||
|
|
||||||
samples = array_to_xc_ptr((samples_array,unsigned[]));
|
|
||||||
samples_to_host_map = array_to_xc_ptr((samples_to_host_map_array,unsigned[]));
|
|
||||||
samples_to_device_map = array_to_xc_ptr((samples_to_device_map_array,unsigned[]));
|
|
||||||
|
|
||||||
|
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||||
samples_to_host_inputs_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
|
samples_to_host_inputs_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
|
||||||
#ifdef LEVEL_METER_LEDS
|
#ifdef LEVEL_METER_LEDS
|
||||||
samples_to_host_inputs_buff_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
|
samples_to_host_inputs_buff_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
|
||||||
#endif
|
#endif
|
||||||
samples_mixer_outputs_ptr = array_to_xc_ptr((samples_mixer_outputs, unsigned[]));
|
samples_mixer_outputs_ptr = array_to_xc_ptr((samples_mixer_outputs, unsigned[]));
|
||||||
|
|
||||||
#if MAX_MIX_COUNT >0
|
|
||||||
mix_mult = array_to_xc_ptr((mix_mult_array,unsigned[]));
|
|
||||||
#ifndef FAST_MIXER
|
|
||||||
mix_map = array_to_xc_ptr((mix_map_array,unsigned[]));
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
|
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
|
||||||
unsafe {
|
unsafe {
|
||||||
//write_via_xc_ptr_indexed(samples,i,0);
|
|
||||||
ptr_samples[i] = 0;
|
ptr_samples[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||||
{
|
{
|
||||||
int num_mixes = DEFAULT_FREQ > 96000 ? 2 : MAX_MIX_COUNT;
|
samples_to_device_map_array[i] = i;
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef OUT_VOLUME_IN_MIXER
|
#if (OUT_VOLUME_IN_MIXER)
|
||||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||||
{
|
unsafe{
|
||||||
write_via_xc_ptr_indexed(multOut, i, MAX_VOL);
|
multOut[i] = MAX_VOL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef IN_VOLUME_IN_MIXER
|
#if (IN_VOLUME_IN_MIXER)
|
||||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||||
{
|
unsafe{
|
||||||
write_via_xc_ptr_indexed(multIn, i, MAX_VOL);
|
multIn[i] = MAX_VOL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||||
{
|
unsafe{
|
||||||
write_via_xc_ptr_indexed(samples_to_host_map, i, NUM_USB_CHAN_OUT + i);
|
samples_to_host_map[i] = XUA_MIXER_OFFSET_IN + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MAX_MIX_COUNT> 0
|
#if (MAX_MIX_COUNT> 0)
|
||||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||||
for (int j=0;j<MIX_INPUTS;j++)
|
for (int j=0;j<MIX_INPUTS;j++)
|
||||||
{
|
unsafe{
|
||||||
#ifndef FAST_MIXER
|
#if (FAST_MIXER == 0)
|
||||||
write_word_to_mix_map(i,j, j < 16 ? j : j + 2);
|
mix_map[i * MIX_INPUTS + j] = (j < 16 ? j : j + 2);
|
||||||
#endif
|
#endif
|
||||||
write_word_to_mix_mult(i,j, i==j ? db_to_mult(0, 8, 25) : 0);
|
mix_mult[i * MIX_INPUTS + j] = (i==j ? db_to_mult(0, XUA_MIXER_DB_FRAC_BITS, XUA_MIXER_MULT_FRAC_BITS) : 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -110,10 +110,8 @@ void ConfigAudioPorts(
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_clock_fall_delay(clk_audio_bclk, bClkDelay_fall);
|
set_clock_fall_delay(clk_audio_bclk, bClkDelay_fall);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if (I2S_CHANS_DAC != 0)
|
#if (I2S_CHANS_DAC != 0)
|
||||||
/* Clock I2S output data ports from b-clock clock block */
|
/* Clock I2S output data ports from b-clock clock block */
|
||||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||||
|
|||||||
@@ -1,6 +1,23 @@
|
|||||||
# Copyright 2022 XMOS LIMITED.
|
# Copyright 2022-2023 XMOS LIMITED.
|
||||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||||
import pytest
|
import pytest
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def test_file(request):
|
||||||
|
return str(request.node.fspath)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session") # Use same seed for whole run
|
||||||
|
def test_seed(request):
|
||||||
|
|
||||||
|
seed = str(int(time.time()))
|
||||||
|
# We dont need the following since pytest will print the values of our fixtures on a failure
|
||||||
|
# capmanager = request.config.pluginmanager.getplugin("capturemanager")
|
||||||
|
# with capmanager.global_and_fixture_disabled():
|
||||||
|
# print("Using seed: "+ seed)
|
||||||
|
return seed
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
|
|||||||
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