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
|
||||
*.dSYM
|
||||
*/.build_*/*
|
||||
*/bin/*
|
||||
*.o
|
||||
# XMOS bin files
|
||||
*.xe
|
||||
*.vcd
|
||||
*.swo
|
||||
*.bin
|
||||
*/bin/*
|
||||
|
||||
# XMOS temp files
|
||||
.build*
|
||||
*.a
|
||||
_build*
|
||||
*.i
|
||||
*.s
|
||||
*.xi
|
||||
*.i
|
||||
*.bin
|
||||
*~
|
||||
*.a
|
||||
*.swp
|
||||
*.*~
|
||||
*.pyc
|
||||
.build*
|
||||
*.o
|
||||
*/.build_*/*
|
||||
|
||||
# Temp files
|
||||
.DS_Store
|
||||
test_results.csv
|
||||
_build*
|
||||
**/.venv/**
|
||||
**/.vscode/**
|
||||
**.egg-info
|
||||
*.pdf
|
||||
*tests/logs/*
|
||||
*.*~
|
||||
*.swp
|
||||
*.swn
|
||||
*~
|
||||
*.swo
|
||||
|
||||
# waf build files
|
||||
.lock-waf_*
|
||||
@@ -36,3 +32,19 @@ xscope.xmt
|
||||
# Traces
|
||||
*.gtkw
|
||||
*.vcd
|
||||
|
||||
# Host binaries
|
||||
host_usb_mixer_control/xmos_mixer
|
||||
|
||||
# Documentation build
|
||||
*.pdf
|
||||
|
||||
# Misc
|
||||
*.log
|
||||
*.dSYM
|
||||
*.vcd
|
||||
*.pyc
|
||||
**/.venv/**
|
||||
**/.vscode/**
|
||||
**.egg-info
|
||||
*tests/logs/*
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
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
|
||||
-----
|
||||
|
||||
|
||||
12
Jenkinsfile
vendored
12
Jenkinsfile
vendored
@@ -106,6 +106,12 @@ pipeline {
|
||||
dir("${REPO}/${REPO}/host/xmosdfu") {
|
||||
sh 'make -f Makefile.OSX64'
|
||||
}
|
||||
dir("${REPO}/host_usb_mixer_control") {
|
||||
sh 'make -f Makefile.OSX'
|
||||
sh 'mkdir OSX/x86'
|
||||
sh 'mv xmos_mixer OSX/x86/xmos_mixer'
|
||||
archiveArtifacts artifacts: "OSX/x86/xmos_mixer", fingerprint: true
|
||||
}
|
||||
}
|
||||
post {
|
||||
cleanup {
|
||||
@@ -141,6 +147,12 @@ pipeline {
|
||||
dir("${REPO}/host/xmosdfu") {
|
||||
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 {
|
||||
|
||||
17
README.rst
17
README.rst
@@ -1,7 +1,8 @@
|
||||
lib_xua
|
||||
#######
|
||||
|
||||
:Latest release: 3.3.1
|
||||
:Version: 3.4.0
|
||||
:Vendor: XMOS
|
||||
|
||||
|
||||
:Scope: General Use
|
||||
@@ -85,11 +86,17 @@ Required Software (dependencies)
|
||||
* lib_mic_array (www.github.com/xmos/lib_mic_array)
|
||||
* lib_xassert (www.github.com/xmos/lib_xassert)
|
||||
* lib_dsp (www.github.com/xmos/lib_dsp)
|
||||
* lib_i2c (www.github.com/xmos/lib_i2c)
|
||||
* lib_i2s (www.github.com/xmos/lib_i2s)
|
||||
* lib_gpio (www.github.com/xmos/lib_gpio)
|
||||
* lib_mic_array_board_support (www.github.com/xmos/lib_mic_array_board_support)
|
||||
* lib_spdif (www.github.com/xmos/lib_spdif)
|
||||
* lib_xud (www.github.com/xmos/lib_xud)
|
||||
* lib_adat (www.github.com/xmos/lib_adat)
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
You can find the documentation for this software in the /doc directory of the package.
|
||||
|
||||
Support
|
||||
=======
|
||||
|
||||
This package is supported by XMOS Ltd. Issues can be raised against the software at: http://www.xmos.com/support
|
||||
|
||||
|
||||
@@ -21,4 +21,3 @@ USED_MODULES = lib_xua lib_xud lib_i2c
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
|
||||
|
||||
@@ -20,4 +20,3 @@ USED_MODULES = lib_xua lib_xud lib_spdif
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
|
||||
|
||||
@@ -19,4 +19,3 @@ USED_MODULES = lib_xua lib_xud lib_mic_array
|
||||
|
||||
XMOS_MAKE_PATH ?= ../..
|
||||
include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
|
||||
|
||||
|
||||
10
host_usb_mixer_control/.makefile
Normal file
10
host_usb_mixer_control/.makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
all:
|
||||
@echo =======================================================
|
||||
@echo Build complete [module only - cannot be run on its own]
|
||||
@echo =======================================================
|
||||
|
||||
clean:
|
||||
@echo =======================================================
|
||||
@echo Build clean [module only - cannot be run on its own]
|
||||
@echo =======================================================
|
||||
|
||||
77
host_usb_mixer_control/.project
Normal file
77
host_usb_mixer_control/.project
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>host_usb_mixer_control</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||
<triggers>clean,full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>?name?</key>
|
||||
<value></value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.append_environment</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
|
||||
<value>all</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildArguments</key>
|
||||
<value></value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildCommand</key>
|
||||
<value>xmake</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
|
||||
<value>clean</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.contents</key>
|
||||
<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
|
||||
<value>false</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableFullBuild</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
|
||||
<value>all</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.stopOnError</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
2
host_usb_mixer_control/Makefile.OSX
Normal file
2
host_usb_mixer_control/Makefile.OSX
Normal file
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
g++ -g -o xmos_mixer usb_mixer.cpp mixer_app.cpp -I. -IOSX OSX/libusb-1.0.0.dylib -arch x86_64
|
||||
5
host_usb_mixer_control/Makefile.Win
Normal file
5
host_usb_mixer_control/Makefile.Win
Normal file
@@ -0,0 +1,5 @@
|
||||
!if [set SDKPath=C:\Program^ Files\XMOS\tusbaudiosdk]
|
||||
!endif
|
||||
|
||||
all:
|
||||
msbuild host_usb_mixer_control.vcxproj /property:Configuration=Release /property:Platform=x64
|
||||
BIN
host_usb_mixer_control/OSX/libusb-1.0.0.dylib
Normal file
BIN
host_usb_mixer_control/OSX/libusb-1.0.0.dylib
Normal file
Binary file not shown.
1233
host_usb_mixer_control/OSX/libusb.h
Normal file
1233
host_usb_mixer_control/OSX/libusb.h
Normal file
File diff suppressed because it is too large
Load Diff
117
host_usb_mixer_control/README
Normal file
117
host_usb_mixer_control/README
Normal file
@@ -0,0 +1,117 @@
|
||||
The XMOS USB Audio Reference Design, by default, contains an 18x8 mixer unit
|
||||
(note that at sample rates above 96Khz only the first two outputs are
|
||||
enabled).
|
||||
|
||||
----WINDOWS REQUIREMENTS----
|
||||
Building the mixer on Windows requires the tusbaudio SDK from Thesycon. The
|
||||
default location for the SDK is C:\Program Files\XMOS\tusbaudiosdk\
|
||||
If it can be found on a different path then this can be changed in
|
||||
Makefile.Win.
|
||||
|
||||
The mixer app on windows makes use of a USB dynamic library, also from Thesycon.
|
||||
If required please contact thesycon.de for support.
|
||||
----------------------------
|
||||
|
||||
This unit takes input takes 18 inputs: USB OUT channels 1..10 and
|
||||
DEVICE IN channels 1..6,9..10 and produces 8 outputs: Mixer Output
|
||||
1..8
|
||||
|
||||
Before the mixer there is an unit that allows the selection of the 18 mixer inputs
|
||||
from all the possible device inputs (DAW and physical audio). This is
|
||||
an extension unit with id 50 in the descriptors
|
||||
|
||||
After the mixer unit there is are channel map units for each output terminal:
|
||||
Each of these outputs can select a source from one of 28 channels sources: USB OUT
|
||||
channels 1..10, DEVICE IN channels 1..10 and Mixer Output 1..8
|
||||
|
||||
The channel map units are extension unit with init ids 51 and 52. This unit
|
||||
lets you implement arbitrary routings including loopbacks.
|
||||
|
||||
The mixer is controlled on macOS via the command line utility
|
||||
xmos_mixer. Running this application requires having the
|
||||
libusb-1.0.0.dylib in the dynamic library load path. Sourcing the
|
||||
setup.sh script will do this. Source code for the application is
|
||||
provided as a guide on how to communicate with the device.
|
||||
|
||||
Here are the commands for the mixer application (note that the USB
|
||||
audio reference design has only one unit so the mixer_id argument
|
||||
should always be 0):
|
||||
|
||||
--help
|
||||
|
||||
--display-info
|
||||
|
||||
Show information about the device.
|
||||
|
||||
--display-mixer-nodes mixer_id
|
||||
|
||||
Display all the weights of all the mixer nodes (and their id) of a particular mixer.
|
||||
|
||||
--display-min mixer_id
|
||||
|
||||
Display the minimum allowable weights of a particular mixer.
|
||||
|
||||
--display-max mixer_id
|
||||
|
||||
Display the maximum allowable weights of a particular mixer.
|
||||
|
||||
--display-res mixer_id
|
||||
|
||||
Display the resolution of a particular mixer.
|
||||
|
||||
--set-value mixer_id mixer_unit value
|
||||
|
||||
Set the weight value in the mixer. The second argument should
|
||||
correspond to the values shown by the --display-unit command. Values
|
||||
can range from -127db to +128db with the special value -inf for mute.
|
||||
|
||||
--get-value mixer_id mixer_unit
|
||||
|
||||
Get the weight value in the mixer. The second argument should
|
||||
correspond to the values shown by the --display-unit command. Values
|
||||
can range from -127db to +128db with the special value -inf for mute.
|
||||
|
||||
--set-mixer-source mixer_id, dst_channel_id, src_channel_id
|
||||
|
||||
Allows the selection of the mixer inputs. Sets mixer input (dst) to src
|
||||
|
||||
--display-current-mixer-sources mixer_id
|
||||
|
||||
Displays the current inputs to a particular mixer
|
||||
|
||||
--display-available-mixer-sources mixer_id
|
||||
|
||||
Displays all the input channels available that can be fed into the inputs of a particular mixer
|
||||
|
||||
--set-aud-channel-map dst src
|
||||
|
||||
Sets a channel map value for the device audio output
|
||||
|
||||
--display-aud-channel-map
|
||||
|
||||
Show audio output channel map i.e. for each audio output of the device what the source is.
|
||||
|
||||
--display-aud-channel-map-sources
|
||||
|
||||
Show the available audio output channel map sources.
|
||||
|
||||
--set-daw-channel-map dst src
|
||||
|
||||
Sets a channel map value for the DAW output to the host
|
||||
|
||||
--display-daw-channel-map
|
||||
|
||||
Show audio output channel map i.e. for each DAW output to host, what the source is.
|
||||
|
||||
--display-daw-channel-map-sources
|
||||
|
||||
Show the DAW output channel map sources.
|
||||
|
||||
--get-mixer-levels-input
|
||||
|
||||
--get-mixer-levels-output
|
||||
|
||||
--vendor-audio-request-get bRequest, ControlSelector, ChannelNumber, UnitId
|
||||
|
||||
--vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],...
|
||||
|
||||
48
host_usb_mixer_control/Win/global.h
Normal file
48
host_usb_mixer_control/Win/global.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
/************************************************************************
|
||||
*
|
||||
* Module: global.h
|
||||
* Description:
|
||||
* APP global includes, constants, declarations, etc.
|
||||
*
|
||||
* Author(s):
|
||||
* Udo Eberhardt
|
||||
*
|
||||
* Companies:
|
||||
* Thesycon GmbH, Germany http://www.thesycon.de
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#ifndef __global_h__
|
||||
#define __global_h__
|
||||
|
||||
// define the Windows versions supported by the application
|
||||
#define _WIN32_WINNT 0x0500 //Windows 2000 or later
|
||||
//#define _WIN32_WINNT 0x0501 //Windows XP or later
|
||||
//#define _WIN32_WINNT 0x0600 //Windows Vista or later
|
||||
//#define _WIN32_WINNT 0x0A00 //Windows 10 or later
|
||||
|
||||
// exclude rarely-used stuff from Windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
|
||||
|
||||
// version defs
|
||||
//#include "version.h"
|
||||
|
||||
// libwn.h pulls in windows.h
|
||||
#include "libwn.h"
|
||||
// TUSBAUDIO driver API
|
||||
#include "tusbaudioapi.h"
|
||||
#include "TUsbAudioApiDll.h"
|
||||
|
||||
|
||||
#endif // __global_h__
|
||||
|
||||
/*************************** EOF **************************************/
|
||||
177
host_usb_mixer_control/host_usb_mixer_control.vcxproj
Normal file
177
host_usb_mixer_control/host_usb_mixer_control.vcxproj
Normal file
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{84eacf4f-e405-4909-b440-a04a84a3f8c8}</ProjectGuid>
|
||||
<RootNamespace>
|
||||
</RootNamespace>
|
||||
<SDKPath Condition="'$(SDKPath)' == ''">C:\Program Files\XMOS\tusbaudiosdk</SDKPath>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
<Import Project="$(SDKPath)\source\tusbaudioapi_inc\tusbaudioapi_inc_vs2019.vcxitems" Label="Shared" />
|
||||
<Import Project="$(SDKPath)\source\libwn_min\_libwn_min_vs2019.vcxitems" Label="Shared" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>.\bin\$(Configuration)\$(PlatformName)\</OutDir>
|
||||
<IntDir>$(Configuration)\$(PlatformName)_$(PlatformToolset)</IntDir>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>.\bin\$(Configuration)\$(PlatformName)\</OutDir>
|
||||
<IntDir>$(Configuration)\$(PlatformName)_$(PlatformToolset)</IntDir>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_AMD64;_CONSOLE;_UNICODE;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>.;.\Win;$(SDKPath)\source\shared;$(SDKPath)\source\inc;$(SDKPath)\source\libwn_min;$(SDKPath)\source\libwtl;$(SDKPath)\source\tusbaudioapi_inc</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<PrecompiledHeaderFile />
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<UACExecutionLevel />
|
||||
<UACUIAccess />
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<SDLCheck>
|
||||
</SDLCheck>
|
||||
<PreprocessorDefinitions>_AMD64;_CONSOLE;_UNICODE;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>.;.\Win;$(SDKPath)\source\shared;$(SDKPath)\source\inc;$(SDKPath)\source\libwn_min;$(SDKPath)\source\libwtl;$(SDKPath)\source\tusbaudioapi_inc</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<PrecompiledHeaderFile />
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<UACExecutionLevel />
|
||||
<UACUIAccess />
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="usb_mixer.h" />
|
||||
<ClInclude Include="Win\global.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mixer_app.cpp" />
|
||||
<ClCompile Include="usb_mixer.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="usb_mixer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Win\global.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mixer_app.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win\usb_mixer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
718
host_usb_mixer_control/mixer_app.cpp
Normal file
718
host_usb_mixer_control/mixer_app.cpp
Normal file
@@ -0,0 +1,718 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "usb_mixer.h"
|
||||
|
||||
#define MIXER_UNIT_DISPLAY_VALUE 2
|
||||
#define MIXER_UNIT_DISPLAY_MIN 3
|
||||
#define MIXER_UNIT_DISPLAY_MAX 4
|
||||
#define MIXER_UNIT_DISPLAY_RES 5
|
||||
|
||||
// TODO
|
||||
// res, min, max
|
||||
|
||||
int mixer_init(void)
|
||||
{
|
||||
/* Open the connection to the USB mixer */
|
||||
if (usb_mixer_connect() == USB_MIXER_FAILURE)
|
||||
{
|
||||
return USB_MIXER_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
int mixer_deinit(void) {
|
||||
// Close the connection to the USB mixer
|
||||
if (usb_mixer_disconnect() == USB_MIXER_FAILURE) {
|
||||
return USB_MIXER_FAILURE;
|
||||
}
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
int mixer_display(unsigned int mixer_index, unsigned int type) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
int num_inputs = usb_mixer_get_num_inputs(mixer_index);
|
||||
int num_outputs = usb_mixer_get_num_outputs(mixer_index);
|
||||
|
||||
|
||||
printf("\n");
|
||||
switch (type) {
|
||||
case MIXER_UNIT_DISPLAY_VALUE:
|
||||
//mixer_update_all_values(mixer_index);
|
||||
printf(" Mixer Values (%d)\n", mixer_index);
|
||||
printf(" ----------------\n\n");
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MIN:
|
||||
printf(" Mixer Ranges Min (%d)\n", mixer_index);
|
||||
printf(" --------------------\n\n");
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MAX:
|
||||
printf(" Mixer Ranges Max (%d)\n", mixer_index);
|
||||
printf(" --------------------\n\n");
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_RES:
|
||||
printf(" Mixer Ranges Res (%d)\n", mixer_index);
|
||||
printf(" --------------------\n\n");
|
||||
break;
|
||||
default:
|
||||
return USB_MIXER_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" \t\t\t");
|
||||
printf("Mixer Outputs\n");
|
||||
printf("\t\t ");
|
||||
for (i = 0; i < num_outputs; i++) {
|
||||
printf(" %d", i+1);
|
||||
}
|
||||
printf("\n");
|
||||
for (i = 0; i < num_inputs; i++) {
|
||||
printf(" %-20s", usb_mixer_get_input_name(mixer_index,i));
|
||||
for (j = 0; j < num_outputs; j++) {
|
||||
switch (type) {
|
||||
case MIXER_UNIT_DISPLAY_VALUE:
|
||||
{
|
||||
double mixNodeVal = usb_mixer_get_value(mixer_index, (i*num_outputs)+j);
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
|
||||
if (mixNodeVal <= -127.996)// todo shoud be < min
|
||||
{
|
||||
printf("\t%3d:[ %s ]", nodeid,"-inf");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\t%3d:[%08.03f]", nodeid, mixNodeVal);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MIN:
|
||||
{
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_min(mixer_index, (i*num_outputs)+j)) ;
|
||||
}
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_MAX:
|
||||
{
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_max(mixer_index, (i*num_outputs)+j)) ;
|
||||
}
|
||||
break;
|
||||
case MIXER_UNIT_DISPLAY_RES:
|
||||
{
|
||||
int nodeid = (i*num_outputs)+j;
|
||||
printf("\t%3d:[%08.03f]", nodeid, usb_mixer_get_res(mixer_index, (i*num_outputs)+j)) ;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return USB_MIXER_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
/* Displays basic mixer information */
|
||||
int mixer_display_info(void)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
int num_mixers = usb_mixer_get_num_mixers();
|
||||
|
||||
printf("\n");
|
||||
printf(" Mixer Info\n");
|
||||
printf(" ----------\n\n");
|
||||
printf(" Mixers : %d\n\n", num_mixers);
|
||||
|
||||
for (i = 0; i < num_mixers; i++)
|
||||
{
|
||||
int num_inputs = usb_mixer_get_num_inputs(i);
|
||||
int num_outputs = usb_mixer_get_num_outputs(i);
|
||||
|
||||
|
||||
printf(" Mixer %d\n", i);
|
||||
printf(" -------\n");
|
||||
|
||||
printf(" Inputs : %d\n"
|
||||
" Outputs : %d\n\n", num_inputs, num_outputs);
|
||||
|
||||
printf(" Mixer Output Labels:\n");
|
||||
for(int j = 0; j < num_outputs; j++)
|
||||
{
|
||||
printf(" %d: %s\n", j,usb_mixer_get_output_name(i,j));
|
||||
}
|
||||
|
||||
//printf("\n Selectable Inputs (%d): \n", usb_mixsel_get_input_count(i));
|
||||
//for(int j = 0; j < usb_mixsel_get_input_count(i); j++)
|
||||
//{
|
||||
// printf(" %d: %s\n", j, usb_mixsel_get_input_string(i,j));
|
||||
//}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return USB_MIXER_SUCCESS;
|
||||
}
|
||||
|
||||
void display_available_mixer_sources(int mixIndex)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Available Mixer Sources (%d)\n", mixIndex);
|
||||
printf(" -------------------------\n\n");
|
||||
|
||||
for(int j = 0; j < usb_mixsel_get_input_count(mixIndex); j++)
|
||||
{
|
||||
printf(" %d: %s\n", j, usb_mixsel_get_input_string(mixIndex,j));
|
||||
}
|
||||
}
|
||||
|
||||
/* Gets the current mixer inputs from the device an displays them */
|
||||
void display_mixer_sources(int mixerIndex)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Current Mixer Sources (%d)\n", mixerIndex);
|
||||
printf(" -------------------------\n\n");
|
||||
|
||||
/* Note, mixSel output cound and mixer input chan count should be the same! */
|
||||
printf(" Number of mixer sources: %d\n", usb_mixsel_get_output_count(mixerIndex));
|
||||
|
||||
/* Get the current channel number for every mixer input */
|
||||
for(int i = 0; i < usb_mixsel_get_output_count(mixerIndex); i++)
|
||||
{
|
||||
int inputChan = (int)usb_mixsel_get_state(mixerIndex, i);
|
||||
char *str = usb_mixer_get_input_name(mixerIndex,inputChan);
|
||||
printf(" Mixer input %d: Source chan id: %d (%s)\n", i, inputChan, str);
|
||||
}
|
||||
}
|
||||
|
||||
/* set mixer source */
|
||||
void set_mixer_source(unsigned mixerIndex, unsigned dst, unsigned src)
|
||||
{
|
||||
usb_mixsel_set_state(mixerIndex, dst, src);
|
||||
|
||||
/* String lookup */
|
||||
char *str = usb_mixer_get_input_name(mixerIndex, dst);
|
||||
int state = usb_mixsel_get_state(mixerIndex, dst);
|
||||
|
||||
printf("\n Set mixer(%d) input %d to device input %d (%s)\n", mixerIndex, dst, state, str);
|
||||
}
|
||||
|
||||
void display_aud_channel_map()
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Audio Output Channel Map\n");
|
||||
printf(" ------------------------\n\n");
|
||||
|
||||
for (int i=0;i<usb_get_aud_channel_map_num_outputs();i++)
|
||||
{
|
||||
int x = usb_get_aud_channel_map(i);
|
||||
printf("%d (DEVICE OUT - %s) source is ",i, usb_get_aud_channel_map_name(i));
|
||||
|
||||
switch (usb_get_aud_channel_map_type(x))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf(" %d (DAW OUT - %s)\n",x,usb_get_aud_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",x,usb_get_aud_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",x,usb_get_aud_channel_map_name(x));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void display_daw_channel_map()
|
||||
{
|
||||
printf("\n");
|
||||
printf(" DAW Output To Host Channel Map\n");
|
||||
printf(" ------------------------\n\n");
|
||||
|
||||
for (int i=0;i<usb_get_usb_channel_map_num_outputs();i++)
|
||||
{
|
||||
int x = usb_get_usb_channel_map(i);
|
||||
printf("%d (DAW IN - %s) source is ",i, usb_get_usb_channel_map_name(i + usb_get_aud_channel_map_num_outputs()));
|
||||
|
||||
switch (usb_get_usb_channel_map_type(x))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf(" %d (DAW OUT - %s)\n",x,usb_get_usb_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",x,usb_get_usb_channel_map_name(x));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",x,usb_get_usb_channel_map_name(x));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display_aud_channel_map_sources(void)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" Audio Output Channel Map Source List\n");
|
||||
printf(" ------------------------------------\n\n");
|
||||
for (int i=0;i<usb_get_aud_channel_map_num_inputs();i++) {
|
||||
switch (usb_get_aud_channel_map_type(i))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf("%d (DAW OUT - %s)\n",i,usb_get_aud_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",i,usb_get_aud_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",i,usb_get_aud_channel_map_name(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display_daw_channel_map_sources(void)
|
||||
{
|
||||
printf("\n");
|
||||
printf(" DAW Output to Host Channel Map Source List\n");
|
||||
printf(" ------------------------------------------\n\n");
|
||||
for (int i=0;i<usb_get_usb_channel_map_num_inputs();i++) {
|
||||
switch (usb_get_usb_channel_map_type(i))
|
||||
{
|
||||
case USB_CHAN_OUT:
|
||||
printf("%d (DAW OUT - %s)\n",i,usb_get_usb_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_IN:
|
||||
printf("%d (DEVICE IN - %s)\n",i,usb_get_usb_channel_map_name(i));
|
||||
break;
|
||||
case USB_CHAN_MIXER:
|
||||
printf("%d (%s)\n",i,usb_get_usb_channel_map_name(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int usb_audio_request_get(unsigned bRequest, unsigned cs, unsigned cn, unsigned unitId, unsigned char *data)
|
||||
{
|
||||
char reqStr[] = "Custom";
|
||||
|
||||
if(bRequest == CUR)
|
||||
{
|
||||
strcpy(reqStr, "CUR");
|
||||
}
|
||||
else if(bRequest == RANGE)
|
||||
{
|
||||
strcpy(reqStr, "RANGE");
|
||||
}
|
||||
else if(bRequest == MEM)
|
||||
{
|
||||
strcpy(reqStr, "MEM");
|
||||
}
|
||||
|
||||
printf("Performing class GET request to Audio Interface:\n\
|
||||
bRequest: 0x%02x (%s)\n\
|
||||
wValue: 0x%04x (Control Sel: %d, Channel Number: %d)\n\
|
||||
wIndex: 0x%04x (Interface: 0, Entity: %d)\n\
|
||||
\n", bRequest, reqStr, (cs<<8)|cn, cs, cn, unitId<<8, unitId);
|
||||
|
||||
return usb_audio_class_get(bRequest, cs, cn, unitId, 64, data);
|
||||
}
|
||||
|
||||
int usb_audio_request_set(unsigned bRequest, unsigned cs, unsigned cn, unsigned unitId,
|
||||
unsigned char *data, int datalength)
|
||||
{
|
||||
char reqStr[] = "Custom";
|
||||
|
||||
if(bRequest == CUR)
|
||||
{
|
||||
strcpy(reqStr, "CUR");
|
||||
}
|
||||
else if(bRequest == RANGE)
|
||||
{
|
||||
strcpy(reqStr, "RANGE");
|
||||
}
|
||||
{
|
||||
strcpy(reqStr, "MEM");
|
||||
}
|
||||
|
||||
printf("Performing class SET request to Audio Interface:\n\
|
||||
bRequest: 0x%02x (%s)\n\
|
||||
wValue: 0x%04x (Control Sel: %d, Channel Number: %d)\n\
|
||||
wIndex: 0x%04x (Interface: 0, Entity: %d)\n\
|
||||
\n", bRequest, reqStr, (cs<<8)|cn, cs, cn, unitId<<8, unitId);
|
||||
|
||||
return usb_audio_class_set(bRequest, cs, cn, unitId, datalength, data);
|
||||
}
|
||||
|
||||
|
||||
int usb_audio_memreq_get(unsigned unitId, unsigned offset, unsigned char *data)
|
||||
{
|
||||
/* Mem requests dont have CS/CN, just an offset.. */
|
||||
return usb_audio_request_get(MEM, (offset>>8), offset&0xff, unitId, data);
|
||||
}
|
||||
|
||||
void print_levels(const char* levelTitle, unsigned char* levels, int levelBytes)
|
||||
{
|
||||
unsigned levelCount = levelBytes/2;
|
||||
unsigned short* levelData = (unsigned short*) levels;
|
||||
|
||||
printf("\n %s Level Data\n"
|
||||
" ----------------------\n\n"
|
||||
"%d bytes (%d channels) returned:\n"
|
||||
, levelTitle, levelBytes, levelCount);
|
||||
|
||||
for(int i = 0; i<levelCount; i++)
|
||||
{
|
||||
printf("%s %d: 0x%04x\n", levelTitle, i,levelData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mixer_display_usage(void) {
|
||||
fprintf(stderr, "Usage :\n");
|
||||
fprintf(stderr,
|
||||
" --display-info\n"
|
||||
" --display-mixer-nodes mixer_id\n"
|
||||
" --display-min mixer_id\n"
|
||||
" --display-max mixer_id\n"
|
||||
" --display-res mixer_id\n"
|
||||
" --set-value mixer_id, mixer_node, value\n"
|
||||
" --get-value mixer_id, mixer_node\n"
|
||||
"\n"
|
||||
" --set-mixer-source mixer_id dst channel_id, src_channel_id\n"
|
||||
" --display-current-mixer-sources mixer_id\n"
|
||||
" --display-available-mixer-sources mixer_id\n"
|
||||
"\n"
|
||||
" --set-aud-channel-map dst_channel_id, src_channel_id\n"
|
||||
" --display-aud-channel-map \n"
|
||||
" --display-aud-channel-map-sources\n"
|
||||
" --set-daw-channel-map dst_channel_id, src_channel_id\n"
|
||||
" --display-daw-channel-map \n"
|
||||
" --display-daw-channel-map-sources\n"
|
||||
"\n"
|
||||
" --get-mixer-levels-input mixer_id\n"
|
||||
" --get-mixer-levels-output mixer_id\n"
|
||||
" --vendor-audio-request-get bRequest, ControlSelector, ChannelNumber, UnitId\n"
|
||||
" --vendor-audio-request-set bRequest, ControlSelector, ChannelNumber, UnitId, Data[0], Data[1],...\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void usage_error()
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed. See --help\n");
|
||||
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
|
||||
unsigned int mixer_index = 0;
|
||||
unsigned int result = 0;
|
||||
|
||||
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "ERROR :: No options passed to mixer application\n");
|
||||
mixer_display_usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "--help") == 0) {
|
||||
mixer_display_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mixer_init() != USB_MIXER_SUCCESS) {
|
||||
fprintf(stderr, "ERROR :: Cannot connect\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "--display-info") == 0)
|
||||
{
|
||||
mixer_display_info();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-mixer-nodes") == 0)
|
||||
{
|
||||
if (argv[2])
|
||||
{
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
||||
} else if (strcmp(argv[1], "--display-mixer-nodes") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_VALUE);
|
||||
} else if (strcmp(argv[1], "--display-min") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MIN);
|
||||
} else if (strcmp(argv[1], "--display-max") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_MAX);
|
||||
} else if (strcmp(argv[1], "--display-res") == 0) {
|
||||
if (argv[2]) {
|
||||
mixer_index = atoi(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR :: No mixer index supplied\n");
|
||||
return -1;
|
||||
}
|
||||
mixer_display(mixer_index, MIXER_UNIT_DISPLAY_RES);
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-value") == 0) {
|
||||
unsigned int mixer_unit = 0;
|
||||
double value = 0;
|
||||
if (argc < 5) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_index = atoi(argv[2]);
|
||||
mixer_unit = atoi(argv[3]);
|
||||
if (strcmp(argv[4],"-inf")==0)
|
||||
value = -128;
|
||||
else
|
||||
value = atof(argv[4]);
|
||||
|
||||
usb_mixer_set_value(mixer_index, mixer_unit, value);
|
||||
} else if (strcmp(argv[1], "--get-value") == 0) {
|
||||
unsigned int mixer_unit = 0;
|
||||
double result = 0;
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_index = atoi(argv[2]);
|
||||
mixer_unit = atoi(argv[3]);
|
||||
|
||||
result = usb_mixer_get_value(mixer_index, mixer_unit);
|
||||
if (result <= -127.996)
|
||||
printf("%s\n", "-inf");
|
||||
else
|
||||
printf("%g\n",result);
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-current-mixer-sources") == 0)
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
display_mixer_sources(atoi(argv[2]));
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-available-mixer-sources") == 0)
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
display_available_mixer_sources(atoi(argv[2]));
|
||||
}
|
||||
else if(strcmp(argv[1], "--set-mixer-source") == 0)
|
||||
{
|
||||
if(argc < 5)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
set_mixer_source(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-aud-channel-map") == 0)
|
||||
{
|
||||
/* Display the channel mapping to the devices audio outputs */
|
||||
display_aud_channel_map();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-aud-channel-map-sources") == 0)
|
||||
{
|
||||
display_aud_channel_map_sources();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-daw-channel-map") == 0)
|
||||
{
|
||||
/* Display the channel mapping to the devices DAW output to host */
|
||||
display_daw_channel_map();
|
||||
}
|
||||
else if (strcmp(argv[1], "--display-daw-channel-map-sources") == 0)
|
||||
{
|
||||
display_daw_channel_map_sources();
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-aud-channel-map") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned int src = 0;
|
||||
if (argc != 4)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
dst = atoi(argv[2]);
|
||||
src = atoi(argv[3]);
|
||||
|
||||
usb_set_aud_channel_map(dst, src);
|
||||
}
|
||||
else if (strcmp(argv[1], "--set-daw-channel-map") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned int src = 0;
|
||||
if (argc != 4)
|
||||
{
|
||||
usage_error();
|
||||
return -1;
|
||||
}
|
||||
dst = atoi(argv[2]);
|
||||
src = atoi(argv[3]);
|
||||
|
||||
usb_set_usb_channel_map(dst, src);
|
||||
}
|
||||
else if(strcmp(argv[1], "--get-mixer-levels-input") == 0 ||
|
||||
strcmp(argv[1],"--get-mixer-levels-output") == 0)
|
||||
{
|
||||
unsigned int dst = 0;
|
||||
unsigned char levels[64];
|
||||
int datalength = 0;
|
||||
int offset = 0;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strcmp(argv[1],"--get-mixer-levels-output") == 0)
|
||||
offset = 1;
|
||||
|
||||
for(int i = 0; i < 64; i++)
|
||||
levels[i] = 0;
|
||||
|
||||
dst = atoi(argv[2]);
|
||||
|
||||
/* Mem request to mixer with offset of 0 gives input levels */
|
||||
datalength = usb_mixer_mem_get(dst, offset, levels);
|
||||
|
||||
if(datalength < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR in control request: %d\n", datalength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(offset)
|
||||
print_levels("Mixer Output", levels, datalength);
|
||||
else
|
||||
print_levels("Mixer Input", levels, datalength);
|
||||
|
||||
}
|
||||
else if(strcmp(argv[1], "--vendor-audio-request-get") == 0)
|
||||
{
|
||||
unsigned int bRequest = 0;
|
||||
unsigned int cs = 0;
|
||||
unsigned int cn = 0;
|
||||
unsigned int unitId = 0;
|
||||
int datalength = 0;
|
||||
unsigned char data[64];
|
||||
|
||||
if(argc < 6)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 64; i++)
|
||||
data[i] = 0;
|
||||
|
||||
bRequest = atoi(argv[2]);
|
||||
cs = atoi(argv[3]);
|
||||
cn = atoi(argv[4]);
|
||||
unitId = atoi(argv[5]);
|
||||
|
||||
/* Do request */
|
||||
datalength = usb_audio_request_get(bRequest, cs, cn, unitId, data);
|
||||
|
||||
/* Print result */
|
||||
if(datalength < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR in control request: %d\n", datalength);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Response (%d bytes):\n", datalength);
|
||||
for(int i = 0; i < datalength; i++)
|
||||
printf("0x%02x\n" ,data[i]);
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1], "--vendor-audio-request-set") == 0)
|
||||
{
|
||||
|
||||
unsigned int bRequest = 0;
|
||||
unsigned int cs = 0;
|
||||
unsigned int cn = 0;
|
||||
unsigned int unitId = 0;
|
||||
unsigned char data[64];
|
||||
|
||||
for(int i=0; i<64; i++)
|
||||
{
|
||||
data[i] = 0;
|
||||
}
|
||||
|
||||
if(argc < 7)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: incorrect number of arguments passed - no data passed\n");
|
||||
return -1;
|
||||
}
|
||||
bRequest = atoi(argv[2]);
|
||||
cs = atoi(argv[3]);
|
||||
cn = atoi(argv[4]);
|
||||
unitId = atoi(argv[5]);
|
||||
|
||||
/* Get data */
|
||||
for(int i=0; i < argc-6; i++)
|
||||
{
|
||||
data[i] = atoi(argv[i+6]);
|
||||
}
|
||||
|
||||
result = usb_audio_request_set(bRequest, cs, cn, unitId, data, argc-6);
|
||||
|
||||
if(result < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR :: Error detected in Set request: %d\n", result);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR :: Invalid option passed to mixer application\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer_deinit();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
1
host_usb_mixer_control/setup.sh
Normal file
1
host_usb_mixer_control/setup.sh
Normal file
@@ -0,0 +1 @@
|
||||
export DYLD_LIBRARY_PATH=$PWD/OSX:$DYLD_LIBRARY_PATH
|
||||
1042
host_usb_mixer_control/usb_mixer.cpp
Normal file
1042
host_usb_mixer_control/usb_mixer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
108
host_usb_mixer_control/usb_mixer.h
Normal file
108
host_usb_mixer_control/usb_mixer.h
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#define USB_MIXER_SUCCESS 0
|
||||
#define USB_MIXER_FAILURE -1
|
||||
|
||||
#define USB_MIXERS 1
|
||||
#define USB_MIXER_INPUTS 18
|
||||
#define USB_MIXER_OUTPUTS 8
|
||||
#define USB_MAX_CHANNEL_MAP_SIZE 40
|
||||
#define USB_MIXER_MAX_NAME_LEN 64
|
||||
|
||||
enum usb_chan_type {
|
||||
USB_CHAN_OUT=0,
|
||||
USB_CHAN_IN=1,
|
||||
USB_CHAN_MIXER=2
|
||||
};
|
||||
|
||||
/* A.14 Audio Class-Specific Request Codes */
|
||||
#define REQUEST_CODE_UNDEFINED 0x00
|
||||
#define CUR (1)
|
||||
#define RANGE (2)
|
||||
#define MEM (3)
|
||||
|
||||
int usb_mixer_connect();
|
||||
int usb_mixer_disconnect();
|
||||
|
||||
/* MIXER UNIT(s) INTERFACE */
|
||||
|
||||
/* Returns total number of mixers in device */
|
||||
int usb_mixer_get_num_mixers();
|
||||
|
||||
/* Returns number of inputs and outputs for a selected mixer */
|
||||
int usb_mixer_get_layout(unsigned int mixer, unsigned int *inputs, unsigned int *outputs);
|
||||
|
||||
/* Returns the name for a selected mixer input */
|
||||
char *usb_mixer_get_input_name(unsigned int mixer, unsigned int input);
|
||||
|
||||
/* Returns the name for a selected mixer output */
|
||||
char *usb_mixer_get_output_name(unsigned int mixer, unsigned int output);
|
||||
|
||||
/* Returns the current value of a selected mixer unit */
|
||||
double usb_mixer_get_value(unsigned int mixer, unsigned int mixer_unit);
|
||||
|
||||
/* Sets the current value for a selected mixer unit */
|
||||
int usb_mixer_set_value(unsigned int mixer, unsigned int mixer_unit, double val);
|
||||
|
||||
/* Returns the range values for a selected mixer unit */
|
||||
int usb_mixer_get_range(unsigned int mixer, unsigned int mixer_unit, double *min, double *max, double *res);
|
||||
|
||||
/* Returns the number of bytes read from a mem request, data is stored in data */
|
||||
int usb_mixer_mem_get(unsigned int mixer, unsigned offset, unsigned char *data);
|
||||
|
||||
|
||||
/* INPUT / OUTPUT / MIXER MAPPING UNIT INTERFACE */
|
||||
|
||||
/* Get the number of selectable inputs */
|
||||
int usb_mixsel_get_input_count(unsigned int mixer);
|
||||
|
||||
/* Get the string of a input */
|
||||
char *usb_mixsel_get_input_string(unsigned int mixer, unsigned int channel);
|
||||
|
||||
int usb_mixsel_get_output_count(unsigned int mixer);
|
||||
|
||||
int usb_mixer_get_num_outputs(unsigned int mixer);
|
||||
|
||||
int usb_mixer_get_num_inputs(unsigned int mixer);
|
||||
|
||||
unsigned char usb_mixsel_get_state(unsigned int mixer, unsigned int channel);
|
||||
|
||||
void usb_mixsel_set_state(unsigned int mixer, unsigned int dst, unsigned int src);
|
||||
|
||||
int usb_set_usb_channel_map(int channel, int val);
|
||||
|
||||
|
||||
/* Get the current map for a specified input / output / mixer channel */
|
||||
int usb_get_usb_channel_map(int channel);
|
||||
int usb_get_aud_channel_map(int channel);
|
||||
|
||||
/* Maps an input / output / mixer channel to another input / output / mixer channel */
|
||||
int usb_set_aud_channel_map(int channel, int val);
|
||||
int usb_set_usb_channel_map(int channel, int val);
|
||||
|
||||
/* Gets the name of a specified channel */
|
||||
char *usb_get_aud_channel_map_name(int channel);
|
||||
char *usb_get_usb_channel_map_name(int channel);
|
||||
|
||||
/* Get the type of a channel map */
|
||||
enum usb_chan_type usb_get_aud_channel_map_type(int channel);
|
||||
enum usb_chan_type usb_get_usb_channel_map_type(int channel);
|
||||
|
||||
int usb_get_aud_channel_map_num_outputs();
|
||||
int usb_get_usb_channel_map_num_outputs();
|
||||
|
||||
int usb_get_aud_channel_map_num_inputs();
|
||||
int usb_get_usb_channel_map_num_inputs();
|
||||
|
||||
/* CUSTOM/GENERIC AUDIO CLASS REQUESTS */
|
||||
|
||||
int usb_audio_class_get(unsigned char bRequest, unsigned char cs, unsigned char cn, unsigned short unitID, unsigned short wLength, unsigned char *data);
|
||||
|
||||
int usb_audio_class_set(unsigned char bRequest, unsigned char cs, unsigned char cn, unsigned short unitID, unsigned short wLength, unsigned char *data);
|
||||
|
||||
double usb_mixer_get_res(unsigned int mixer, unsigned int nodeId);
|
||||
|
||||
double usb_mixer_get_min(unsigned int mixer, unsigned int nodeId) ;
|
||||
|
||||
double usb_mixer_get_max(unsigned int mixer, unsigned int nodeId) ;
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2022 XMOS LIMITED.
|
||||
// Copyright 2017-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_H_
|
||||
#define _XUA_H_
|
||||
@@ -7,14 +7,14 @@
|
||||
|
||||
#include "xua_conf_full.h"
|
||||
|
||||
#if __XC__ || __STDC__
|
||||
#ifndef __ASSEMBLER__
|
||||
#include "xua_audiohub.h"
|
||||
#include "xua_endpoint0.h"
|
||||
#include "xua_buffer.h"
|
||||
#include "xua_mixer.h"
|
||||
#endif
|
||||
|
||||
#if __XC__
|
||||
#ifdef __XC__
|
||||
#include "xua_clocking.h"
|
||||
#include "xua_midi.h"
|
||||
#if XUA_NUM_PDM_MICS > 0
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef __XUA_AUDIOHUB_H__
|
||||
#define __XUA_AUDIOHUB_H__
|
||||
#ifndef _XUA_AUDIOHUB_H_
|
||||
#define _XUA_AUDIOHUB_H_
|
||||
|
||||
#if __XC__
|
||||
#ifdef __XC__
|
||||
|
||||
#include "xccompat.h"
|
||||
#include "xs1.h"
|
||||
@@ -80,4 +80,4 @@ void UserBufferManagementInit();
|
||||
|
||||
void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudioToUsb[]);
|
||||
|
||||
#endif // __XUA_AUDIOHUB_H__
|
||||
#endif // _XUA_AUDIOHUB_H_
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
/*
|
||||
* @brief Defines relating to device configuration and customisation of lib_xua
|
||||
@@ -997,17 +997,12 @@
|
||||
#define MIXER (0)
|
||||
#endif
|
||||
|
||||
/* Tidy up old ifndef usage */
|
||||
#if defined(MIXER) && (MIXER == 0)
|
||||
#undef MIXER
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of seperate mixes to perform
|
||||
*
|
||||
* Default: 8 if MIXER enabled, else 0
|
||||
*/
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
#ifndef MAX_MIX_COUNT
|
||||
#define MAX_MIX_COUNT (8)
|
||||
#endif
|
||||
@@ -1087,44 +1082,24 @@
|
||||
#define VOLUME_RES_MIXER (0x100)
|
||||
#endif
|
||||
|
||||
/* Handle out volume control in the mixer */
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && (OUT_VOLUME_IN_MIXER==0)
|
||||
#undef OUT_VOLUME_IN_MIXER
|
||||
#else
|
||||
#if defined(MIXER)
|
||||
// Disabled by default
|
||||
//#define OUT_VOLUME_IN_MIXER
|
||||
#endif
|
||||
/* Handle out volume control in the mixer - enabled by default */
|
||||
#ifndef OUT_VOLUME_IN_MIXER
|
||||
#define OUT_VOLUME_IN_MIXER (1)
|
||||
#endif
|
||||
|
||||
/* Apply out volume controls after the mix */
|
||||
#if defined(OUT_VOLUME_AFTER_MIX) && (OUT_VOLUME_AFTER_MIX==0)
|
||||
#undef OUT_VOLUME_AFTER_MIX
|
||||
#else
|
||||
#if defined(MIXER) && defined(OUT_VOLUME_IN_MIXER)
|
||||
// Enabled by default
|
||||
#define OUT_VOLUME_AFTER_MIX
|
||||
#endif
|
||||
/* Apply out volume controls after the mix. Only relevant when OUT_VOLUME_IN_MIXER enabled. Enabled by default */
|
||||
#ifndef OUT_VOLUME_AFTER_MIX
|
||||
#define OUT_VOLUME_AFTER_MIX (1)
|
||||
#endif
|
||||
|
||||
/* Handle in volume control in the mixer */
|
||||
#if defined(IN_VOLUME_IN_MIXER) && (IN_VOLUME_IN_MIXER==0)
|
||||
#undef IN_VOLUME_IN_MIXER
|
||||
#else
|
||||
#if defined(MIXER)
|
||||
/* Disabled by default */
|
||||
//#define IN_VOLUME_IN_MIXER
|
||||
#endif
|
||||
/* Handle in volume control in the mixer - disabled by default */
|
||||
#ifndef IN_VOLUME_IN_MIXER
|
||||
#define IN_VOLUME_IN_MIXER (0)
|
||||
#endif
|
||||
|
||||
/* Apply in volume controls after the mix */
|
||||
#if defined(IN_VOLUME_AFTER_MIX) && (IN_VOLUME_AFTER_MIX==0)
|
||||
#undef IN_VOLUME_AFTER_MIX
|
||||
#else
|
||||
#if defined(MIXER) && defined(IN_VOLUME_IN_MIXER)
|
||||
// Enabled by default
|
||||
#define IN_VOLUME_AFTER_MIX
|
||||
#endif
|
||||
/* Apply in volume controls after the mix. Only relebant when IN_VOLUMNE_IN MIXER enabled. Enabled by default */
|
||||
#ifndef IN_VOLUME_AFTER_MIX
|
||||
#define IN_VOLUME_AFTER_MIX (1)
|
||||
#endif
|
||||
|
||||
/* Always enable explicit feedback EP, even when input stream is present */
|
||||
@@ -1319,9 +1294,9 @@ enum USBEndpointNumber_Out
|
||||
/* Some defines that allow us to remove unused code */
|
||||
|
||||
/* Useful for dropping lower part of macs in volume processing... */
|
||||
#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \
|
||||
(FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || \
|
||||
(HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)
|
||||
#if (FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || \
|
||||
(((FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 1)) || \
|
||||
(((FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24) || (HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS > 24)) && (OUTPUT_FORMAT_COUNT > 2))
|
||||
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 1
|
||||
#else
|
||||
#define STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2022 XMOS LIMITED.
|
||||
// Copyright 2017-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef __XUA_CONF_FULL_H__
|
||||
#define __XUA_CONF_FULL_H__
|
||||
#ifndef _XUA_CONF_FULL_H_
|
||||
#define _XUA_CONF_FULL_H_
|
||||
|
||||
#ifdef __xua_conf_h_exists__
|
||||
#include "xua_conf.h"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#ifndef _XUA_MIXER_H_
|
||||
#define _XUA_MIXER_H_
|
||||
|
||||
#include "xua.h"
|
||||
|
||||
enum mix_ctl_cmd {
|
||||
SET_SAMPLES_TO_HOST_MAP,
|
||||
SET_SAMPLES_TO_DEVICE_MAP,
|
||||
@@ -31,4 +33,14 @@ enum mix_ctl_cmd {
|
||||
*/
|
||||
void mixer(chanend c_to_host, chanend c_to_audio, chanend c_mix_ctl);
|
||||
|
||||
#define XUA_MIXER_OFFSET_OUT (0)
|
||||
#define XUA_MIXER_OFFSET_IN (NUM_USB_CHAN_OUT)
|
||||
#define XUA_MIXER_OFFSET_MIX (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN)
|
||||
#define XUA_MIXER_OFFSET_OFF (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT)
|
||||
|
||||
/* Defines uses for DB to actual muliplier conversion */
|
||||
#define XUA_MIXER_MULT_FRAC_BITS (25)
|
||||
#define XUA_MIXER_DB_FRAC_BITS (8)
|
||||
#define XUA_MIXER_MAX_MULT (1<<XUA_MIXER_MULT_FRAC_BITS) /* i.e. multiply by 0 */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -87,6 +87,9 @@ intended as an example of how you might add mixer control to your own control ap
|
||||
intended to be exposed to end users.
|
||||
|
||||
For details, consult the README file in the host_usb_mixer_control directory.
|
||||
A list of arguments can also be seen with::
|
||||
|
||||
$ ./xmos_mixer --help
|
||||
|
||||
The main requirements of this control utility are to
|
||||
|
||||
@@ -102,78 +105,147 @@ The main requirements of this control utility are to
|
||||
functionality to their end users.
|
||||
|
||||
Whilst using the XMOS Host control example application, consider the example of setting the
|
||||
mixer to perform a loop-back from analogue inputs 1 and 2 to analogue outputs 1 and 2.
|
||||
mixer to perform a loop-back from analogue inputs 1 & 2 to analogue outputs 1 & 2.
|
||||
|
||||
Firstly consider the inputs to the mixer. The following will displays which channels are mapped
|
||||
to which mixer inputs::
|
||||
.. note::
|
||||
|
||||
./xmos_mixer --display-aud-channel-map 0
|
||||
The command outputs shown are examples; the actual output will depend on the mixer configuration.
|
||||
|
||||
The following command will displays which channels could possibly be mapped to mixer inputs. Notice
|
||||
that analogue inputs 1 and 2 are on mixer inputs 10 and 11::
|
||||
The following will show the index for each device output along with which channel is currently mapped to it.
|
||||
In this example the analogue outputs 1 & 2 are 0 & 1 respectively::
|
||||
|
||||
./xmos_mixer --display-aud-channel-map-sources 0
|
||||
$ ./xmos_mixer --display-aud-channel-map
|
||||
|
||||
Now examine the audio output mapping using the following command::
|
||||
Audio Output Channel Map
|
||||
------------------------
|
||||
|
||||
0 (DEVICE OUT - Analogue 1) source is 0 (DAW OUT - Analogue 1)
|
||||
1 (DEVICE OUT - Analogue 2) source is 1 (DAW OUT - Analogue 2)
|
||||
2 (DEVICE OUT - SPDIF 1) source is 2 (DAW OUT - SPDIF 1)
|
||||
3 (DEVICE OUT - SPDIF 2) source is 3 (DAW OUT - SPDIF 2)
|
||||
$ _
|
||||
|
||||
./xmos_mixer --display-aud-channel-map 0
|
||||
The DAW Output Map can be seen with::
|
||||
|
||||
This displays which channels are mapped to which outputs. By default all
|
||||
of these bypass the mixer. We can also see what all the possible
|
||||
mappings are with the following command::
|
||||
$ ./xmos_mixer --display-daw-channel-map
|
||||
|
||||
./xmos_mixer --display-aud-channel-map-sources 0
|
||||
DAW Output To Host Channel Map
|
||||
------------------------
|
||||
|
||||
0 (DEVICE IN - Analogue 1) source is 4 (DEVICE IN - Analogue 1)
|
||||
1 (DEVICE IN - Analogue 2) source is 5 (DEVICE IN - Analogue 2)
|
||||
$ _
|
||||
|
||||
We will now map the first two mixer outputs to physical outputs 1 and 2::
|
||||
.. note::
|
||||
|
||||
./xmos_mixer --set-aud-channel-map 0 26
|
||||
./xmos_mixer --set-aud-channel-map 1 27
|
||||
In both cases, by default, these bypass the mixer.
|
||||
|
||||
The following command will list the channels which can be mapped to the device outputs from the
|
||||
Audio Output Channel Map. Note that, in this example, analogue inputs 1 & 2 are source 4 & 5 and
|
||||
Mix 1 & 2 are source 6 & 7::
|
||||
|
||||
$ ./xmos_mixer --display-aud-channel-map-sources
|
||||
|
||||
Audio Output Channel Map Source List
|
||||
------------------------------------
|
||||
|
||||
0 (DAW OUT - Analogue 1)
|
||||
1 (DAW OUT - Analogue 2)
|
||||
2 (DAW OUT - SPDIF 1)
|
||||
3 (DAW OUT - SPDIF 2)
|
||||
4 (DEVICE IN - Analogue 1)
|
||||
5 (DEVICE IN - Analogue 2)
|
||||
6 (MIX - Mix 1)
|
||||
7 (MIX - Mix 2)
|
||||
$ _
|
||||
|
||||
Using the indices from the previous commands, we will now re-map the first two mixer channels (Mix 1 & Mix 2) to device outputs 1 & 2::
|
||||
|
||||
$ ./xmos_mixer --set-aud-channel-map 0 6
|
||||
$ ./xmos_mixer --set-aud-channel-map 1 7
|
||||
$ _
|
||||
|
||||
You can confirm the effect of this by re-checking the map::
|
||||
|
||||
./xmos_mixer --display-aud-channel-map 0
|
||||
$ ./xmos_mixer --display-aud-channel-map
|
||||
|
||||
This now derives analogue outputs 1 and 2 from the mixer, rather than directly from USB. However,
|
||||
since the mixer is still mapped to pass the USB channels through to the outputs there will be no
|
||||
Audio Output Channel Map
|
||||
------------------------
|
||||
|
||||
0 (DEVICE OUT - Analogue 1) source is 6 (MIX - Mix 1)
|
||||
1 (DEVICE OUT - Analogue 2) source is 7 (MIX - Mix 2)
|
||||
2 (DEVICE OUT - SPDIF 1) source is 2 (DAW OUT - SPDIF 1)
|
||||
3 (DEVICE OUT - SPDIF 2) source is 3 (DAW OUT - SPDIF 2)
|
||||
$ _
|
||||
|
||||
This now derives analogue outputs 1 & 2 from the mixer, rather than directly from USB. However,
|
||||
since the mixer is mapped, by default, to just pass the USB channels through to the outputs there will be no
|
||||
functional change.
|
||||
|
||||
The mixer nodes need to be individually set. They can be displayed
|
||||
|
||||
.. note::
|
||||
|
||||
The USB audio reference design has only one unit so the mixer_id argument should always be 0.
|
||||
|
||||
The mixer nodes need to be individually set. The nodes in mixer_id 0 can be displayed
|
||||
with the following command::
|
||||
|
||||
./xmos_mixer --display-mixer-nodes 0
|
||||
$ ./xmos_mixer --display-mixer-nodes 0
|
||||
|
||||
To get the audio from the analogue inputs to outputs 1 and 2, nodes 80
|
||||
and 89 need to be set::
|
||||
Mixer Values (0)
|
||||
----------------
|
||||
|
||||
./xmos_mixer --set-value 0 80 0
|
||||
./xmos_mixer --set-value 0 89 0
|
||||
Mixer outputs
|
||||
1 2
|
||||
DAW - Analogue 1 0:[0000.000] 1:[ -inf ]
|
||||
DAW - Analogue 2 2:[ -inf ] 3:[0000.000]
|
||||
DAW - SPDIF 1 4:[ -inf ] 5:[ -inf ]
|
||||
DAW - SPDIF 2 6:[ -inf ] 7:[ -inf ]
|
||||
AUD - Analogue 1 8:[ -inf ] 9:[ -inf ]
|
||||
AUD - Analogue 2 10:[ -inf ] 11:[ -inf ]
|
||||
$ _
|
||||
|
||||
With mixer outputs 1 & 2 mapped to device outputs analogue 1 & 2; to get the audio from the analogue inputs to device
|
||||
outputs mixer_id 0 node 8 and node 11 need to be set to 0db::
|
||||
|
||||
$ ./xmos_mixer --set-value 0 8 0
|
||||
$ ./xmos_mixer --set-value 0 11 0
|
||||
$ _
|
||||
|
||||
At the same time, the original mixer outputs can be muted::
|
||||
|
||||
./xmos_mixer --set-value 0 0 -inf
|
||||
./xmos_mixer --set-value 0 9 -inf
|
||||
$ ./xmos_mixer --set-value 0 0 -inf
|
||||
$ ./xmos_mixer --set-value 0 3 -inf
|
||||
$ _
|
||||
|
||||
Now audio inputs on analogue 1/2 should be heard on outputs 1/2.
|
||||
Now audio inputs on analogue 1 and 2 should be heard on outputs 1 and 2 respectively.
|
||||
|
||||
As mentioned above, the flexibility of the mixer is such that there will be multiple ways to create
|
||||
a particular mix. Another option to create the same routing would be to change the mixer sources
|
||||
such that mixer 1/2 outputs come from the analogue inputs.
|
||||
such that mixer outputs 1 and 2 come from the analogue inputs 1 and 2.
|
||||
|
||||
To demonstrate this, firstly undo the changes above (or simply reset the device)::
|
||||
|
||||
./xmos_mixer --set-value 0 80 -inf
|
||||
./xmos_mixer --set-value 0 89 -inf
|
||||
./xmos_mixer --set-value 0 0 0
|
||||
./xmos_mixer --set-value 0 9 0
|
||||
$ ./xmos_mixer --set-value 0 8 -inf
|
||||
$ ./xmos_mixer --set-value 0 11 -inf
|
||||
$ ./xmos_mixer --set-value 0 0 0
|
||||
$ ./xmos_mixer --set-value 0 3 0
|
||||
$ _
|
||||
|
||||
The mixer should now have the default values. The sources for mixer 1/2 can now be changed::
|
||||
The mixer should now have the default values. The sources for mixer 0 output 1 and 2 can now be changed
|
||||
using indices from the Audio Output Channel Map Source List::
|
||||
|
||||
./xmos_mixer --set-mixer-source 0 0 10
|
||||
./xmos_mixer --set-mixer-source 0 1 11
|
||||
$ ./xmos_mixer --set-mixer-source 0 0 4
|
||||
|
||||
Set mixer(0) input 0 to device input 4 (AUD - Analogue 1)
|
||||
$ ./xmos_mixer --set-mixer-source 0 1 5
|
||||
|
||||
Set mixer(0) input 1 to device input 5 (AUD - Analogue 2)
|
||||
$ _
|
||||
|
||||
If you re-run the following command then the first column now has "AUD - Analogue 1 and 2" rather
|
||||
than "DAW (Digital Audio Workstation i.e. the host) - Analogue 1 and 2" confirming the new mapping.
|
||||
Again, by playing audio into analogue inputs 1/2 this can be heard looped through to analogue outputs 1/2::
|
||||
|
||||
./xmos_mixer --display-mixer-nodes 0
|
||||
$ ./xmos_mixer --display-mixer-nodes 0
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
VERSION = 3.3.1
|
||||
VERSION = 3.4.0
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
DEBUG_FLAGS = -g -DXASSERT_ENABLE_ASSERTIONS_DECOUPLE=1
|
||||
DEBUG_FLAGS = -g -DXASSERT_ENABLE_ASSERTIONS=1 -DXASSERT_ENABLE_DEBUG=1 -DXASSERT_ENABLE_LINE_NUMBERS=1
|
||||
else
|
||||
DEBUG_FLAGS = -DXASSERT_DISABLE_ASSERTIONS_DECOUPLE=1
|
||||
DEBUG_FLAGS = -DXASSERT_ENABLE_ASSERTIONS=0 -DXASSERT_ENABLE_DEBUG=0 -DXASSERT_ENABLE_LINE_NUMBERS=0
|
||||
endif
|
||||
|
||||
DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
||||
@@ -13,7 +13,7 @@ DEPENDENT_MODULES = lib_locks(>=2.1.0) \
|
||||
lib_mic_array(>=4.5.0) \
|
||||
lib_spdif(>=4.2.1) \
|
||||
lib_xassert(>=4.1.0) \
|
||||
lib_xud(>=2.2.1) \
|
||||
lib_xud(>=2.2.2) \
|
||||
lib_adat(>=1.0.0)
|
||||
|
||||
MODULE_XCC_FLAGS = $(XCC_FLAGS) \
|
||||
|
||||
@@ -38,7 +38,6 @@ void InitPorts_master(unsigned divide, buffered _XUA_CLK_DIR port:32 p_lrclk, bu
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma xta endpoint "divide_1"
|
||||
unsigned tmp;
|
||||
p_lrclk <: 0 @ tmp;
|
||||
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.
|
||||
/**
|
||||
* @file xua_audiohub.xc
|
||||
@@ -43,12 +43,12 @@
|
||||
|
||||
#define MAX(x,y) ((x)>(y) ? (x) : (y))
|
||||
|
||||
static unsigned samplesOut[MAX(NUM_USB_CHAN_OUT, I2S_CHANS_DAC)];
|
||||
unsigned samplesOut[MAX(NUM_USB_CHAN_OUT, I2S_CHANS_DAC)];
|
||||
|
||||
/* Two buffers for ADC data to allow for DAC and ADC I2S ports being offset */
|
||||
#define IN_CHAN_COUNT (I2S_CHANS_ADC + XUA_NUM_PDM_MICS + (8*XUA_ADAT_RX_EN) + (2*XUA_SPDIF_RX_EN))
|
||||
|
||||
static unsigned samplesIn[2][MAX(NUM_USB_CHAN_IN, IN_CHAN_COUNT)];
|
||||
unsigned samplesIn[2][MAX(NUM_USB_CHAN_IN, IN_CHAN_COUNT)];
|
||||
|
||||
#ifdef XTA_TIMING_AUDIO
|
||||
#pragma xta command "add exclusion received_command"
|
||||
@@ -89,69 +89,7 @@ unsigned dsdMode = DSD_MODE_OFF;
|
||||
#if (XUA_ADAT_TX_EN)
|
||||
#include "audiohub_adat.h"
|
||||
#endif
|
||||
|
||||
#pragma unsafe arrays
|
||||
static inline unsigned DoSampleTransfer(chanend ?c_out, const int readBuffNo, const unsigned underflowWord)
|
||||
{
|
||||
if(XUA_USB_EN)
|
||||
{
|
||||
outuint(c_out, underflowWord);
|
||||
|
||||
/* Check for sample freq change (or other command) or new samples from mixer*/
|
||||
if(testct(c_out))
|
||||
{
|
||||
unsigned command = inct(c_out);
|
||||
#ifndef CODEC_MASTER
|
||||
if(dsdMode == DSD_MODE_OFF)
|
||||
{
|
||||
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||
/* Set clocks low */
|
||||
p_lrclk <: 0;
|
||||
p_bclk <: 0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if(DSD_CHANS_DAC != 0)
|
||||
/* DSD Clock might not be shared with lrclk or bclk... */
|
||||
p_dsd_clk <: 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
if(dsdMode == DSD_MODE_DOP)
|
||||
dsdMode = DSD_MODE_OFF;
|
||||
#endif
|
||||
return command;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int tmp = inuint(c_out);
|
||||
samplesOut[i] = tmp;
|
||||
}
|
||||
#else
|
||||
inuint(c_out);
|
||||
#endif
|
||||
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
outuint(c_out, samplesIn[readBuffNo][i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#include "xua_audiohub_st.h"
|
||||
|
||||
static inline int HandleSampleClock(int frameCount, buffered _XUA_CLK_DIR port:32 p_lrclk)
|
||||
{
|
||||
@@ -443,9 +381,8 @@ unsigned static AudioHub_MainLoop(chanend ?c_out, chanend ?c_spd_out
|
||||
outuint(c_dig_rx, 0);
|
||||
#endif
|
||||
#if (XUA_SPDIF_TX_EN) && (NUM_USB_CHAN_OUT > 0)
|
||||
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward sample to S/PDIF Tx thread */
|
||||
unsigned sample = samplesOut[SPDIF_TX_INDEX + 1];
|
||||
outuint(c_spd_out, sample); /* Forward sample to S/PDIF Tx thread */
|
||||
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward samples to S/PDIF Tx thread */
|
||||
outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX + 1]);
|
||||
#endif
|
||||
|
||||
#if (XUA_NUM_PDM_MICS > 0)
|
||||
|
||||
66
lib_xua/src/core/audiohub/xua_audiohub_st.h
Normal file
66
lib_xua/src/core/audiohub/xua_audiohub_st.h
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#pragma unsafe arrays
|
||||
static inline unsigned DoSampleTransfer(chanend ?c_out, const int readBuffNo, const unsigned underflowWord)
|
||||
{
|
||||
if(XUA_USB_EN)
|
||||
{
|
||||
outuint(c_out, underflowWord);
|
||||
|
||||
/* Check for sample freq change (or other command) or new samples from mixer*/
|
||||
if(testct(c_out))
|
||||
{
|
||||
unsigned command = inct(c_out);
|
||||
#ifndef CODEC_MASTER
|
||||
if(dsdMode == DSD_MODE_OFF)
|
||||
{
|
||||
#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0)
|
||||
/* Set clocks low */
|
||||
p_lrclk <: 0;
|
||||
p_bclk <: 0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if(DSD_CHANS_DAC != 0)
|
||||
/* DSD Clock might not be shared with lrclk or bclk... */
|
||||
p_dsd_clk <: 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if (DSD_CHANS_DAC > 0)
|
||||
if(dsdMode == DSD_MODE_DOP)
|
||||
dsdMode = DSD_MODE_OFF;
|
||||
#endif
|
||||
return command;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int tmp = inuint(c_out);
|
||||
samplesOut[i] = tmp;
|
||||
}
|
||||
#else
|
||||
inuint(c_out);
|
||||
#endif
|
||||
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
outuint(c_out, samplesIn[readBuffNo][i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
UserBufferManagement(samplesOut, samplesIn[readBuffNo]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#include "xua.h"
|
||||
|
||||
@@ -58,15 +58,16 @@
|
||||
#define IN_BUFFER_PREFILL (MAX(MAX_DEVICE_AUD_PACKET_SIZE_IN_HS, MAX_DEVICE_AUD_PACKET_SIZE_IN_FS)*2)
|
||||
|
||||
/* Volume and mute tables */
|
||||
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
unsigned int multOut[NUM_USB_CHAN_OUT + 1];
|
||||
static xc_ptr p_multOut;
|
||||
#endif
|
||||
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
|
||||
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
|
||||
unsigned int multIn[NUM_USB_CHAN_IN + 1];
|
||||
static xc_ptr p_multIn;
|
||||
#endif
|
||||
|
||||
/* Default to something sensible but the following are setup at stream start (unless UAC1 only..) */
|
||||
#if (AUDIO_CLASS == 2)
|
||||
int g_numUsbChan_In = NUM_USB_CHAN_IN; /* Number of channels to/from the USB bus - initialised to HS for UAC2.0 */
|
||||
int g_numUsbChan_Out = NUM_USB_CHAN_OUT;
|
||||
@@ -143,7 +144,66 @@ unsigned unpackData = 0;
|
||||
unsigned packState = 0;
|
||||
unsigned packData = 0;
|
||||
|
||||
/* Default to something sensible but the following are setup at stream start (unless UAC1 only..) */
|
||||
static inline void SendSamples4(chanend c_mix_out)
|
||||
{
|
||||
/* Doing this checking allows us to unroll */
|
||||
if(g_numUsbChan_Out == NUM_USB_CHAN_OUT)
|
||||
{
|
||||
/* Buffering not underflow condition send out some samples...*/
|
||||
#pragma loop unroll
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
|
||||
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
||||
g_aud_from_host_rdptr+=4;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && (!OUT_VOLUME_IN_MIXER)
|
||||
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 unsafe arrays
|
||||
@@ -206,7 +266,7 @@ __builtin_unreachable();
|
||||
g_aud_from_host_rdptr+=2;
|
||||
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));
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
/* Note, in 2 byte subslot mode - ignore lower result of macs */
|
||||
@@ -223,41 +283,17 @@ __builtin_unreachable();
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
/* Buffering not underflow condition send out some samples...*/
|
||||
for(int i = 0; i < g_numUsbChan_Out; i++)
|
||||
{
|
||||
#pragma xta endpoint "mixer_request"
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
|
||||
read_via_xc_ptr(sample, g_aud_from_host_rdptr);
|
||||
g_aud_from_host_rdptr+=4;
|
||||
|
||||
#if (OUTPUT_VOLUME_CONTROL == 1) && !defined(OUT_VOLUME_IN_MIXER)
|
||||
asm volatile("ldw %0, %1[%2]":"=r"(mult):"r"(p_multOut),"r"(i));
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<= 3;
|
||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
outuint(c_mix_out, h);
|
||||
#else
|
||||
outuint(c_mix_out, sample);
|
||||
#endif
|
||||
}
|
||||
|
||||
SendSamples4(c_mix_out);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
#if (STREAM_FORMAT_OUTPUT_SUBSLOT_3_USED == 0)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
/* Buffering not underflow condition send out some samples...*/
|
||||
/* Note, in this case the unpacking of data is more of an overhead than the loop overhead
|
||||
* so we do not currently make attempts to unroll */
|
||||
for(int i = 0; i < g_numUsbChan_Out; i++)
|
||||
{
|
||||
#pragma xta endpoint "mixer_request"
|
||||
int sample;
|
||||
int mult;
|
||||
int h;
|
||||
@@ -289,7 +325,7 @@ __builtin_unreachable();
|
||||
}
|
||||
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));
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<= 3;
|
||||
@@ -335,7 +371,7 @@ __builtin_unreachable();
|
||||
/* Receive sample */
|
||||
int sample = inuint(c_mix_out);
|
||||
#if (INPUT_VOLUME_CONTROL == 1)
|
||||
#if !defined(IN_VOLUME_IN_MIXER)
|
||||
#if (!IN_VOLUME_IN_MIXER)
|
||||
/* Apply volume */
|
||||
int mult;
|
||||
int h;
|
||||
@@ -345,7 +381,7 @@ __builtin_unreachable();
|
||||
sample = h << 3;
|
||||
|
||||
/* Note, in 2 byte sub slot - ignore lower bits of macs */
|
||||
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
#elif (IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
sample = sample << 3;
|
||||
#endif
|
||||
#endif
|
||||
@@ -365,7 +401,7 @@ __builtin_unreachable();
|
||||
/* Receive sample */
|
||||
int sample = inuint(c_mix_out);
|
||||
#if(INPUT_VOLUME_CONTROL == 1)
|
||||
#if !defined(IN_VOLUME_IN_MIXER)
|
||||
#if (!IN_VOLUME_IN_MIXER)
|
||||
/* Apply volume */
|
||||
int mult;
|
||||
int h;
|
||||
@@ -376,7 +412,7 @@ __builtin_unreachable();
|
||||
#if (STREAM_FORMAT_INPUT_RESOLUTION_32BIT_USED == 1)
|
||||
sample |= (l >> 29) & 0x7; // Note, this step is not required if we assume sample depth is 24 (rather than 32)
|
||||
#endif
|
||||
#elif defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
#elif (IN_VOLUME_IN_MIXER) && (IN_VOLUME_AFTER_MIX)
|
||||
sample = sample << 3;
|
||||
#endif
|
||||
#endif
|
||||
@@ -396,7 +432,7 @@ __builtin_unreachable();
|
||||
{
|
||||
/* Receive sample */
|
||||
int sample = inuint(c_mix_out);
|
||||
#if (INPUT_VOLUME_CONTROL) && !defined(IN_VOLUME_IN_MIXER)
|
||||
#if (INPUT_VOLUME_CONTROL) && (!IN_VOLUME_IN_MIXER)
|
||||
/* Apply volume */
|
||||
int mult;
|
||||
int h;
|
||||
@@ -588,6 +624,7 @@ __builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Mark Endpoint (IN) ready with an appropriately sized zero buffer */
|
||||
static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned sampFreq, unsigned slotSize,
|
||||
xc_ptr aud_to_host_zeros)
|
||||
@@ -619,6 +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);
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma unsafe arrays
|
||||
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);
|
||||
|
||||
#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);
|
||||
#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);
|
||||
#endif
|
||||
|
||||
@@ -668,14 +706,14 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
xc_ptr aud_to_host_zeros = t;
|
||||
|
||||
/* Init vol mult tables */
|
||||
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
#if (OUT_VOLUME_IN_MIXER == 0) && (OUTPUT_VOLUME_CONTROL == 1)
|
||||
for (int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
|
||||
{
|
||||
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multOut),"r"(i));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(IN_VOLUME_IN_MIXER) && (INPUT_VOLUME_CONTROL == 1)
|
||||
#if (IN_VOLUME_IN_MIXER == 0) && (INPUT_VOLUME_CONTROL == 1)
|
||||
for (int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
|
||||
{
|
||||
asm volatile("stw %0, %1[%2]"::"r"(MAX_VOL),"r"(p_multIn),"r"(i));
|
||||
@@ -760,8 +798,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
/* Set buffer to send back to zeros buffer */
|
||||
aud_to_host_buffer = aud_to_host_zeros;
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Update size of zeros buffer (and sampsToWrite) */
|
||||
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
||||
#endif
|
||||
|
||||
/* Reset OUT buffer state */
|
||||
outUnderflow = 1;
|
||||
@@ -815,8 +855,10 @@ void XUA_Buffer_Decouple(chanend c_mix_out
|
||||
/* Set buffer back to zeros buffer */
|
||||
aud_to_host_buffer = aud_to_host_zeros;
|
||||
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Update size of zeros buffer (and sampsToWrite) */
|
||||
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
|
||||
#endif
|
||||
|
||||
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
|
||||
if (usbSpeed == XUD_SPEED_HS)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <xs1.h>
|
||||
@@ -13,14 +13,14 @@
|
||||
#include "spdif.h"
|
||||
#endif
|
||||
|
||||
#define LOCAL_CLOCK_INCREMENT 166667
|
||||
#define LOCAL_CLOCK_MARGIN 1666
|
||||
#define LOCAL_CLOCK_INCREMENT (166667)
|
||||
#define LOCAL_CLOCK_MARGIN (1666)
|
||||
|
||||
#define MAX_SAMPLES 64 /* Must be power of 2 */
|
||||
#define MAX_SAMPLES (64) /* Must be power of 2 */
|
||||
#define MAX_SPDIF_SAMPLES (2 * MAX_SAMPLES) /* Must be power of 2 */
|
||||
#define MAX_ADAT_SAMPLES (8 * MAX_SAMPLES) /* Must be power of 2 */
|
||||
|
||||
#define SPDIF_FRAME_ERRORS_THRESH 40
|
||||
#define SPDIF_FRAME_ERRORS_THRESH (40)
|
||||
|
||||
unsigned g_digData[10];
|
||||
|
||||
@@ -241,12 +241,7 @@ extern int samples_to_host_inputs_buff[NUM_USB_CHAN_IN];
|
||||
int VendorAudCoreReqs(unsigned cmd, chanend c);
|
||||
|
||||
#pragma unsafe arrays
|
||||
//#if (AUDIO_IO_TILE == PLL_REF_TILE)
|
||||
#if 0
|
||||
void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, out port p, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int)
|
||||
#else
|
||||
void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interface pll_ref_if i_pll_ref, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int)
|
||||
#endif
|
||||
{
|
||||
timer t_local;
|
||||
unsigned timeNextEdge, timeLastEdge, timeNextClockDetection;
|
||||
@@ -723,7 +718,7 @@ void clockGen (streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, client interfa
|
||||
|
||||
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
/* Mixer requests data */
|
||||
/* AudioHub requests data */
|
||||
case inuint_byref(c_dig_rx, tmp):
|
||||
#if (XUA_SPDIF_RX_EN)
|
||||
if(spdifUnderflow)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
/**
|
||||
* @brief Implements endpoint zero for an USB Audio 1.0/2.0 device
|
||||
@@ -106,13 +106,17 @@ unsigned int mutesOut[NUM_USB_CHAN_OUT + 1];
|
||||
int volsIn[NUM_USB_CHAN_IN + 1];
|
||||
unsigned int mutesIn[NUM_USB_CHAN_IN + 1];
|
||||
|
||||
#ifdef MIXER
|
||||
unsigned char mixer1Crossbar[18];
|
||||
short mixer1Weights[18*8];
|
||||
#if (MIXER)
|
||||
short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
|
||||
|
||||
unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
||||
//unsigned char channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
||||
/* Mapping of channels to output audio interfaces */
|
||||
unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
||||
|
||||
/* Mapping of channels to USB host */
|
||||
unsigned char channelMapUsb[NUM_USB_CHAN_IN];
|
||||
|
||||
/* Mapping of channels to Mixer(s) */
|
||||
unsigned char mixSel[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
#endif
|
||||
|
||||
@@ -262,6 +266,49 @@ void XUA_Endpoint0_setVendorId(unsigned short vid) {
|
||||
#endif // AUDIO_CLASS == 1}
|
||||
}
|
||||
|
||||
#if (MIXER)
|
||||
void InitLocalMixerState()
|
||||
{
|
||||
for (int i = 0; i < MIX_INPUTS * MAX_MIX_COUNT; i++)
|
||||
{
|
||||
mixer1Weights[i] = 0x8001; //-inf
|
||||
}
|
||||
|
||||
/* Configure default connections */
|
||||
// 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) {
|
||||
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();
|
||||
|
||||
#if 0
|
||||
/* Dont need to init globals.. */
|
||||
/* Init tables for volumes (+ 1 for master) */
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT + 1; i++)
|
||||
{
|
||||
volsOut[i] = 0;
|
||||
mutesOut[i] = 0;
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN + 1; i++)
|
||||
{
|
||||
volsIn[i] = 0;
|
||||
mutesIn[i] = 0;
|
||||
}
|
||||
#endif
|
||||
VendorRequests_Init(VENDOR_REQUESTS_PARAMS);
|
||||
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
/* Set up mixer default state */
|
||||
for (int i = 0; i < 18*8; i++)
|
||||
{
|
||||
mixer1Weights[i] = 0x8001; //-inf
|
||||
}
|
||||
|
||||
/* Configure default connections */
|
||||
mixer1Weights[0] = 0;
|
||||
mixer1Weights[9] = 0;
|
||||
mixer1Weights[18] = 0;
|
||||
mixer1Weights[27] = 0;
|
||||
mixer1Weights[36] = 0;
|
||||
mixer1Weights[45] = 0;
|
||||
mixer1Weights[54] = 0;
|
||||
mixer1Weights[63] = 0;
|
||||
|
||||
#if NUM_USB_CHAN_OUT > 0
|
||||
/* Setup up audio output channel mapping */
|
||||
for(int i = 0; i < NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
channelMapAud[i] = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NUM_USB_CHAN_IN > 0
|
||||
for(int i = 0; i < NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
channelMapUsb[i] = i + NUM_USB_CHAN_OUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set up channel mapping default */
|
||||
for (int i = 0; i < NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
channelMap[i] = i;
|
||||
}
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
/* Mixer outputs mapping defaults */
|
||||
for (int i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
channelMap[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Init mixer inputs */
|
||||
for(int j = 0; j < MAX_MIX_COUNT; j++)
|
||||
for(int i = 0; i < MIX_INPUTS; i++)
|
||||
{
|
||||
mixSel[j][i] = i;
|
||||
}
|
||||
InitLocalMixerState();
|
||||
#endif
|
||||
|
||||
#ifdef VENDOR_AUDIO_REQS
|
||||
@@ -529,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_EP_DESCRIPTOR_OFFSET_MAXPACKETSIZE] = ((get_usb_to_device_bit_res() >> 3) * MAX_PACKET_SIZE_MULT_OUT_FS) & 0xff; //max packet size
|
||||
cfgDesc_Audio1[USB_AS_OUT_EP_DESCRIPTOR_OFFSET_MAXPACKETSIZE + 1] = (((get_usb_to_device_bit_res() >> 3) * MAX_PACKET_SIZE_MULT_OUT_FS) & 0xff00) >> 8; //max packet size
|
||||
#endif // NUM_USB_CHAN_OUT
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
/**
|
||||
* @file xua_ep0_descriptors.h
|
||||
@@ -308,28 +308,28 @@ typedef struct
|
||||
#error NUM_USB_CHAN > 32
|
||||
#endif
|
||||
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
STR_TABLE_ENTRY(mixOutStr_1);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 1)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 1)
|
||||
STR_TABLE_ENTRY(mixOutStr_2);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 2)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 2)
|
||||
STR_TABLE_ENTRY(mixOutStr_3);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 3)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 3)
|
||||
STR_TABLE_ENTRY(mixOutStr_4);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 4)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 4)
|
||||
STR_TABLE_ENTRY(mixOutStr_5);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 5)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 5)
|
||||
STR_TABLE_ENTRY(mixOutStr_6);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 6)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 6)
|
||||
STR_TABLE_ENTRY(mixOutStr_7);
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 7)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 7)
|
||||
STR_TABLE_ENTRY(mixOutStr_8);
|
||||
#endif
|
||||
#ifdef IAP
|
||||
@@ -391,31 +391,31 @@ StringDescTable_t g_strTable =
|
||||
#error NUM_USB_CHAN_IN > 32
|
||||
#endif
|
||||
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
.mixOutStr_1 = "Mix 1",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 1)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 1)
|
||||
.mixOutStr_2 = "Mix 2",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 2)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 2)
|
||||
.mixOutStr_3 = "Mix 3",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 3)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 3)
|
||||
.mixOutStr_4 = "Mix 4",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 4)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 4)
|
||||
.mixOutStr_5 = "Mix 5",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 5)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 5)
|
||||
.mixOutStr_6 = "Mix 6",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 6)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 6)
|
||||
.mixOutStr_7 = "Mix 7",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 7)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 7)
|
||||
.mixOutStr_8 = "Mix 8",
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 8)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 8)
|
||||
#error
|
||||
#endif
|
||||
#ifdef IAP
|
||||
@@ -558,7 +558,7 @@ unsigned char devQualDesc_Null[] =
|
||||
};
|
||||
|
||||
|
||||
#if defined(MIXER) && !defined(AUDIO_PATH_XUS) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && !defined(AUDIO_PATH_XUS) && (MAX_MIX_COUNT > 0)
|
||||
//#warning Extension units on the audio path are required for mixer. Enabling them now.
|
||||
#define AUDIO_PATH_XUS
|
||||
#endif
|
||||
@@ -575,7 +575,7 @@ unsigned char devQualDesc_Null[] =
|
||||
#define DFU_LENGTH (0)
|
||||
#endif
|
||||
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
#define MIX_BMCONTROLS_LEN_TMP ((MAX_MIX_COUNT * MIX_INPUTS) / 8)
|
||||
|
||||
#if ((MAX_MIX_COUNT * MIX_INPUTS)%8)==0
|
||||
@@ -666,7 +666,7 @@ typedef struct
|
||||
#if (NUM_USB_CHAN_OUT > 0)
|
||||
/* Output path */
|
||||
USB_Descriptor_Audio_InputTerminal_t Audio_Out_InputTerminal;
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
USB_Descriptor_Audio_ExtensionUnit_t Audio_Out_ExtensionUnit;
|
||||
#endif
|
||||
#if(OUTPUT_VOLUME_CONTROL == 1)
|
||||
@@ -677,7 +677,7 @@ typedef struct
|
||||
#if (NUM_USB_CHAN_IN > 0)
|
||||
/* Input path */
|
||||
USB_Descriptor_Audio_InputTerminal_t Audio_In_InputTerminal;
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
USB_Descriptor_Audio_ExtensionUnit_t Audio_In_ExtensionUnit;
|
||||
#endif
|
||||
#if(INPUT_VOLUME_CONTROL == 1)
|
||||
@@ -685,7 +685,7 @@ typedef struct
|
||||
#endif
|
||||
USB_Descriptor_Audio_OutputTerminal_t Audio_In_OutputTerminal;
|
||||
#endif
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
USB_Descriptor_Audio_ExtensionUnit2_t Audio_Mix_ExtensionUnit;
|
||||
// Currently no struct for mixer unit
|
||||
// USB_Descriptor_Audio_MixerUnit_t Audio_MixerUnit;
|
||||
@@ -1168,7 +1168,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
UAC_CS_DESCTYPE_INTERFACE, /* 1 bDescriptorType: CS_INTERFACE */
|
||||
UAC_CS_AC_INTERFACE_SUBTYPE_FEATURE_UNIT, /* 2 bDescriptorSubType: FEATURE_UNIT */
|
||||
FU_USBIN, /* 3 bUnitID */
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
ID_XU_IN, /* 4 bSourceID */
|
||||
#else
|
||||
ID_IT_AUD, /* 4 bSourceID */
|
||||
@@ -1300,7 +1300,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
},
|
||||
#endif /* (NUM_USB_CHAN_IN > 0) */
|
||||
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
/* Extension Unit Descriptor (4.7.2.12) */
|
||||
.Audio_Mix_ExtensionUnit =
|
||||
{
|
||||
@@ -1392,7 +1392,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2=
|
||||
0x00, /* bmControls */
|
||||
0 /* Mixer unit string descriptor index */
|
||||
},
|
||||
#endif /* defined(MIXER) && (MAX_MIX_COUNT > 0) */
|
||||
#endif /* (MIXER) && (MAX_MIX_COUNT > 0) */
|
||||
|
||||
#if (XUA_SPDIF_RX_EN) || (XUA_ADAT_RX_EN)
|
||||
/* Standard AS Interrupt Endpoint Descriptor (4.8.2.1): */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
/**
|
||||
* @brief Implements relevant requests from the USB Audio 2.0 Specification
|
||||
@@ -30,10 +30,9 @@ extern unsigned int mutesOut[];
|
||||
extern int volsIn[];
|
||||
extern unsigned int mutesIn[];
|
||||
|
||||
/* Mixer settings */
|
||||
#ifdef MIXER
|
||||
extern unsigned char mixer1Crossbar[];
|
||||
extern short mixer1Weights[];
|
||||
#if (MIXER)
|
||||
/* Mixer weights */
|
||||
extern short mixer1Weights[MIX_INPUTS * MAX_MIX_COUNT];
|
||||
|
||||
/* Device channel mapping */
|
||||
extern unsigned char channelMapAud[NUM_USB_CHAN_OUT];
|
||||
@@ -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 */
|
||||
static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
||||
static void updateMasterVol(int unitID, chanend ?c_mix_ctl)
|
||||
{
|
||||
int x;
|
||||
#ifndef OUT_VOLUME_IN_MIXER
|
||||
#if (OUT_VOLUME_IN_MIXER == 0)
|
||||
xc_ptr p_multOut = array_to_xc_ptr(multOut);
|
||||
#endif
|
||||
#ifndef IN_VOLUME_IN_MIXER
|
||||
#if (IN_VOLUME_IN_MIXER == 0)
|
||||
xc_ptr p_multIn = array_to_xc_ptr(multIn);
|
||||
#endif
|
||||
switch( unitID)
|
||||
switch(unitID)
|
||||
{
|
||||
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];
|
||||
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_OUT_VOL);
|
||||
outuint(c_mix_ctl, i-1);
|
||||
outuint(c_mix_ctl, x);
|
||||
@@ -179,9 +180,11 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
||||
|
||||
x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[i];
|
||||
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_IN_VOL);
|
||||
outuint(c_mix_ctl, i-1);
|
||||
outuint(c_mix_ctl, x);
|
||||
@@ -202,10 +205,10 @@ static void updateMasterVol( int unitID, chanend ?c_mix_ctl)
|
||||
static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
||||
{
|
||||
int x;
|
||||
#ifndef OUT_VOLUME_IN_MIXER
|
||||
#if (OUT_VOLUME_IN_MIXER == 0)
|
||||
xc_ptr p_multOut = array_to_xc_ptr(multOut);
|
||||
#endif
|
||||
#ifndef IN_VOLUME_IN_MIXER
|
||||
#if (IN_VOLUME_IN_MIXER == 0)
|
||||
xc_ptr p_multIn = array_to_xc_ptr(multIn);
|
||||
#endif
|
||||
/* 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];
|
||||
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_OUT_VOL);
|
||||
outuint(c_mix_ctl, channel-1);
|
||||
outuint(c_mix_ctl, x);
|
||||
@@ -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 */
|
||||
/* 0x8000 is a special value representing -inf (i.e. mute) */
|
||||
unsigned master_vol = volsIn[0] == 0x8000 ? 0 : db_to_mult(volsIn[0], 8, 29);
|
||||
unsigned vol = volsIn[channel] == 0x8000 ? 0 : db_to_mult(volsIn[channel], 8, 29);
|
||||
unsigned vol = volsIn[channel] == 0x8000 ? 0 : db_to_mult(volsIn[channel], 8, 29);
|
||||
|
||||
x = longMul(master_vol, vol, 29) * !mutesIn[0] * !mutesIn[channel];
|
||||
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_IN_VOL);
|
||||
outuint(c_mix_ctl, channel-1);
|
||||
outuint(c_mix_ctl, x);
|
||||
@@ -266,6 +273,38 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl)
|
||||
}
|
||||
#endif
|
||||
|
||||
void UpdateMixerOutputRouting(chanend c_mix_ctl, unsigned map, unsigned dst, unsigned src)
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, map);
|
||||
outuint(c_mix_ctl, dst);
|
||||
outuint(c_mix_ctl, src);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
|
||||
void UpdateMixMap(chanend c_mix_ctl, int mix, int input, int src)
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_MAP);
|
||||
outuint(c_mix_ctl, mix); /* Mix bus */
|
||||
outuint(c_mix_ctl, input); /* Mixer input (cn) */
|
||||
outuint(c_mix_ctl, src); /* Source (mixSel[cn]) */
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
|
||||
void UpdateMixerWeight(chanend c_mix_ctl, int mix, int index, unsigned mult)
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, SET_MIX_MULT);
|
||||
outuint(c_mix_ctl, mix);
|
||||
outuint(c_mix_ctl, index);
|
||||
outuint(c_mix_ctl, mult);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
|
||||
/* Handles the audio class specific requests
|
||||
* returns: XUD_RES_OKAY if request dealt with successfully without error,
|
||||
* XUD_RES_RST for device reset
|
||||
@@ -282,7 +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 */
|
||||
switch( sp.bRequest )
|
||||
{
|
||||
|
||||
/* CUR Request*/
|
||||
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];
|
||||
|
||||
/* Instruct audio thread to change sample freq (if change required) */
|
||||
//if(newSampleRate != g_curSamFreq)
|
||||
if(newSampleRate != g_curSamFreq)
|
||||
{
|
||||
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 */
|
||||
/* Send 0 Length as status stage */
|
||||
int x = XUD_DoSetRequestStatus(ep0_in);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
/* Direction: Device-to-host: Send Current Sample Freq */
|
||||
else
|
||||
@@ -537,7 +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)
|
||||
{
|
||||
volsOut[ sp.wValue&0xff ] = (buffer, unsigned char[])[0] | (((int) (signed char) (buffer, unsigned char[])[1]) << 8);
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
}
|
||||
@@ -546,7 +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)
|
||||
{
|
||||
volsIn[ sp.wValue&0xff ] = (buffer, unsigned char[])[0] | (((int) (signed char) (buffer, unsigned char[])[1]) << 8);
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
}
|
||||
@@ -632,85 +670,76 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
break; /* FU_USBIN */
|
||||
#endif
|
||||
|
||||
#if defined(MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if ((MIXER) && (MAX_MIX_COUNT > 0))
|
||||
case ID_XU_OUT:
|
||||
{
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
unsigned volume = 0;
|
||||
int c = sp.wValue & 0xff;
|
||||
int dst = sp.wValue & 0xff;
|
||||
|
||||
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
channelMapAud[c] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
if (c < NUM_USB_CHAN_OUT)
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
{
|
||||
outuint(c_mix_ctl, SET_SAMPLES_TO_DEVICE_MAP);
|
||||
outuint(c_mix_ctl, c);
|
||||
outuint(c_mix_ctl, channelMapAud[c]);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
/* Send 0 Length as status stage */
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (dst < NUM_USB_CHAN_OUT)
|
||||
{
|
||||
channelMapAud[dst] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_DEVICE_MAP, dst, channelMapAud[dst]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send 0 Length as status stage */
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
else
|
||||
{
|
||||
(buffer, unsigned char[])[0] = channelMapAud[dst];
|
||||
(buffer, unsigned char[])[1] = 0;
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
(buffer, unsigned char[])[0] = channelMapAud[sp.wValue & 0xff];
|
||||
(buffer, unsigned char[])[1] = 0;
|
||||
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_XU_IN:
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
unsigned volume = 0;
|
||||
int c = sp.wValue & 0xff;
|
||||
int dst = sp.wValue & 0xff;
|
||||
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
channelMapUsb[c] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
|
||||
if (c < NUM_USB_CHAN_IN)
|
||||
{
|
||||
if (!isnull(c_mix_ctl))
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
{
|
||||
outuint(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP);
|
||||
outuint(c_mix_ctl, c);
|
||||
outuint(c_mix_ctl, channelMapUsb[c]);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (dst < NUM_USB_CHAN_IN)
|
||||
{
|
||||
channelMapUsb[dst] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
UpdateMixerOutputRouting(c_mix_ctl, SET_SAMPLES_TO_HOST_MAP, dst, channelMapUsb[dst]);
|
||||
}
|
||||
}
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Direction: Device-to-host */
|
||||
(buffer, unsigned char[])[0] = channelMapUsb[dst];
|
||||
(buffer, unsigned char[])[1] = 0;
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Direction: Device-to-host */
|
||||
(buffer, unsigned char[])[0] = channelMapUsb[sp.wValue & 0xff];
|
||||
(buffer, unsigned char[])[1] = 0;
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_XU_MIXSEL:
|
||||
{
|
||||
int cs = sp.wValue >> 8; /* Control Selector */
|
||||
int cn = sp.wValue & 0xff; /* Channel number */
|
||||
int cn = sp.wValue & 0xff; /* Channel Number */
|
||||
|
||||
/* Check for Get or Set */
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D)
|
||||
@@ -723,21 +752,19 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
|
||||
if(datalength > 0)
|
||||
{
|
||||
/* cn bounds check for safety..*/
|
||||
/* CN bounds check for safety..*/
|
||||
if(cn < MIX_INPUTS)
|
||||
{
|
||||
//if(cs == CS_XU_MIXSEL)
|
||||
/* cs now contains mix number */
|
||||
if(cs < (MAX_MIX_COUNT + 1))
|
||||
{
|
||||
int source = (buffer, unsigned char[])[0];
|
||||
|
||||
/* Check for "off" - update local state */
|
||||
if((buffer, unsigned char[])[0] == 0xFF)
|
||||
if(source == 0xFF)
|
||||
{
|
||||
mixSel[cs][cn] = (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
|
||||
}
|
||||
else
|
||||
{
|
||||
mixSel[cs][cn] = (buffer, unsigned char[])[0];
|
||||
source = (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT);
|
||||
}
|
||||
|
||||
if(cs == 0)
|
||||
@@ -745,21 +772,17 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
/* Update all mix maps */
|
||||
for (int i = 0; i < MAX_MIX_COUNT; i++)
|
||||
{
|
||||
outuint(c_mix_ctl, SET_MIX_MAP);
|
||||
outuint(c_mix_ctl, i); /* Mix bus */
|
||||
outuint(c_mix_ctl, cn); /* Mixer input */
|
||||
outuint(c_mix_ctl, (int) mixSel[cn]); /* Source */
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
/* i : Mix bus */
|
||||
/* cn: Mixer input */
|
||||
mixSel[i][cn] = source;
|
||||
UpdateMixMap(c_mix_ctl, i, cn, mixSel[i][cn]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update relevant mix map */
|
||||
outuint(c_mix_ctl, SET_MIX_MAP); /* Command */
|
||||
outuint(c_mix_ctl, (cs-1)); /* Mix bus */
|
||||
outuint(c_mix_ctl, cn); /* Mixer input */
|
||||
outuint(c_mix_ctl, (int) mixSel[cs][cn]); /* Source */
|
||||
outct(c_mix_ctl, XS1_CT_END); /* Wait for handshake back */
|
||||
mixSel[cs-1][cn] = source;
|
||||
UpdateMixMap(c_mix_ctl, cs-1, cn, mixSel[cs-1][cn]);
|
||||
}
|
||||
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
@@ -780,7 +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)))
|
||||
{
|
||||
(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:
|
||||
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
unsigned volume = 0;
|
||||
int cs = sp.wValue >> 8; /* Control Selector - currently unused */
|
||||
int cn = sp.wValue & 0xff; /* Channel number - used for mixer node index */
|
||||
|
||||
/* Expect OUT here with mute */
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
if(sp.bmRequestType.Direction == USB_BM_REQTYPE_DIRECTION_H2D) /* Direction: Host-to-device */
|
||||
{
|
||||
return result;
|
||||
}
|
||||
unsigned weightMult = 0;
|
||||
|
||||
mixer1Weights[sp.wValue & 0xff] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
/* Expect OUT here with weight */
|
||||
if((result = XUD_GetBuffer(ep0_out, (buffer, unsigned char[]), datalength)) != XUD_RES_OKAY)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (mixer1Weights[sp.wValue & 0xff] == 0x8000)
|
||||
{
|
||||
volume = 0;
|
||||
if(cn < sizeof(mixer1Weights)/sizeof(mixer1Weights[0]))
|
||||
{
|
||||
mixer1Weights[cn] = (buffer, unsigned char[])[0] | (buffer, unsigned char[])[1] << 8;
|
||||
|
||||
if (mixer1Weights[cn] != 0x8000)
|
||||
{
|
||||
weightMult = db_to_mult(mixer1Weights[cn], XUA_MIXER_DB_FRAC_BITS, XUA_MIXER_MULT_FRAC_BITS);
|
||||
}
|
||||
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
UpdateMixerWeight(c_mix_ctl, (cn) % 8, (cn) / 8, weightMult);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send 0 Length as status stage */
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
else
|
||||
{
|
||||
volume = db_to_mult(mixer1Weights[sp.wValue & 0xff], 8, 25);
|
||||
}
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outuint(c_mix_ctl, SET_MIX_MULT);
|
||||
outuint(c_mix_ctl, (sp.wValue & 0xff) % 8);
|
||||
outuint(c_mix_ctl, (sp.wValue & 0xff) / 8);
|
||||
outuint(c_mix_ctl, volume);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
}
|
||||
short weight = 0x8000;
|
||||
|
||||
/* Send 0 Length as status stage */
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
else
|
||||
{
|
||||
short weight = mixer1Weights[sp.wValue & 0xff];
|
||||
(buffer, unsigned char[])[0] = weight & 0xff;
|
||||
(buffer, unsigned char[])[1] = (weight >> 8) & 0xff;
|
||||
if(cn < sizeof(mixer1Weights)/sizeof(mixer1Weights[0]))
|
||||
{
|
||||
weight = mixer1Weights[cn];
|
||||
}
|
||||
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
storeShort((buffer, unsigned char[]), 0, weight);
|
||||
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), sp.wLength, sp.wLength);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
#endif
|
||||
default:
|
||||
/* We dont have a unit with this ID! */
|
||||
@@ -919,7 +946,6 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
num_freqs++;
|
||||
}
|
||||
#endif
|
||||
|
||||
storeShort((buffer, unsigned char[]), 0, num_freqs);
|
||||
|
||||
return XUD_DoGetRequest(ep0_out, ep0_in, (buffer, unsigned char[]), i, sp.wLength);
|
||||
@@ -957,7 +983,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
/* Mixer Unit */
|
||||
case ID_MIXER_1:
|
||||
storeShort((buffer, unsigned char[]), 0, 1);
|
||||
@@ -967,7 +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);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
/* Unknown Unit ID in Range Request selector for FU */
|
||||
break;
|
||||
@@ -977,7 +1002,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
break; /* case: RANGE */
|
||||
}
|
||||
|
||||
#if defined (MIXER) && (MAX_MIX_COUNT > 0)
|
||||
#if ((MIXER) && (MAX_MIX_COUNT > 0))
|
||||
case MEM: /* Memory Requests (5.2.7.1) */
|
||||
|
||||
unitID = sp.wIndex >> 8;
|
||||
@@ -1003,6 +1028,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
{
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, GET_STREAM_LEVELS);
|
||||
outuint(c_mix_ctl, i);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
@@ -1018,6 +1045,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
{
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, GET_INPUT_LEVELS);
|
||||
outuint(c_mix_ctl, (i - NUM_USB_CHAN_OUT));
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
@@ -1040,6 +1069,8 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c
|
||||
{
|
||||
if (!isnull(c_mix_ctl))
|
||||
{
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
inct(c_mix_ctl);
|
||||
outuint(c_mix_ctl, GET_OUTPUT_LEVELS);
|
||||
outuint(c_mix_ctl, i);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
@@ -1107,13 +1138,10 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp
|
||||
|
||||
if(newSampleRate != g_curSamFreq)
|
||||
{
|
||||
int curSamFreq44100Family;
|
||||
int curSamFreq48000Family;
|
||||
|
||||
/* Windows Audio Class driver has a nice habbit of sending invalid SF's (e.g. 48001Hz)
|
||||
* when under stress. Lets double check it here and ignore if not valid. */
|
||||
curSamFreq48000Family = MCLK_48 % newSampleRate == 0;
|
||||
curSamFreq44100Family = MCLK_441 % newSampleRate == 0;
|
||||
int curSamFreq48000Family = MCLK_48 % newSampleRate == 0;
|
||||
int curSamFreq44100Family = MCLK_441 % newSampleRate == 0;
|
||||
|
||||
if(curSamFreq48000Family || curSamFreq44100Family)
|
||||
{
|
||||
@@ -1128,7 +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 */
|
||||
FeedbackStabilityDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
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:
|
||||
volsOut[ sp.wValue & 0xff ] = buffer[0] | (((int) (signed char) buffer[1]) << 8);
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
|
||||
case FU_USBIN:
|
||||
volsIn[ sp.wValue & 0xff ] = buffer[0] | (((int) (signed char) buffer[1]) << 8);
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
}
|
||||
@@ -1209,12 +1237,12 @@ XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket
|
||||
{
|
||||
case FU_USBOUT:
|
||||
mutesOut[ sp.wValue & 0xff ] = buffer[0];
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
|
||||
case FU_USBIN:
|
||||
mutesIn[ sp.wValue & 0xff ] = buffer[0];
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl );
|
||||
updateVol( unitID, ( sp.wValue & 0xff ), c_mix_ctl);
|
||||
return XUD_DoSetRequestStatus(ep0_in);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2012-2022 XMOS LIMITED.
|
||||
// Copyright 2012-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include "xua.h" /* Device specific defines */
|
||||
@@ -273,7 +273,7 @@ void usb_audio_core(chanend c_mix_out
|
||||
#ifdef MIDI
|
||||
, chanend c_midi
|
||||
#endif
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
, chanend c_mix_ctl
|
||||
#endif
|
||||
, chanend ?c_clk_int
|
||||
@@ -290,7 +290,7 @@ VENDOR_REQUESTS_PARAMS_DEC_
|
||||
chan c_xud_in[ENDPOINT_COUNT_IN];
|
||||
chan c_aud_ctl;
|
||||
|
||||
#ifndef MIXER
|
||||
#if (!MIXER)
|
||||
#define c_mix_ctl null
|
||||
#endif
|
||||
|
||||
@@ -401,7 +401,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
chanend c_spdif_tx,
|
||||
#endif
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
chanend c_mix_ctl,
|
||||
#endif
|
||||
streaming chanend ?c_spdif_rx,
|
||||
@@ -422,7 +422,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
chan c_mix_out;
|
||||
#endif
|
||||
|
||||
@@ -446,7 +446,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
|
||||
par
|
||||
{
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
/* Mixer cores(s) */
|
||||
{
|
||||
thread_speed();
|
||||
@@ -464,7 +464,7 @@ void usb_audio_io(chanend ?c_aud_in,
|
||||
/* Audio I/O core (pars additional S/PDIF TX Core) */
|
||||
{
|
||||
thread_speed();
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
#define AUDIO_CHANNEL c_mix_out
|
||||
#else
|
||||
#define AUDIO_CHANNEL c_aud_in
|
||||
@@ -531,7 +531,7 @@ int main()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
chan c_mix_ctl;
|
||||
#endif
|
||||
|
||||
@@ -608,7 +608,7 @@ int main()
|
||||
, c_ea_data
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
, c_mix_ctl
|
||||
#endif
|
||||
, c_clk_int, c_clk_ctl, dfuInterface
|
||||
@@ -628,7 +628,7 @@ int main()
|
||||
#if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE)
|
||||
, c_spdif_tx
|
||||
#endif
|
||||
#ifdef MIXER
|
||||
#if (MIXER)
|
||||
, c_mix_ctl
|
||||
#endif
|
||||
, c_spdif_rx, c_adat_rx, c_clk_ctl, c_clk_int
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
// Copyright 2018-2021 XMOS LIMITED.
|
||||
// Copyright 2018-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#define MAX_MIX_COUNT 8
|
||||
#define MIX_INPUTS 18
|
||||
#include "xua.h"
|
||||
|
||||
#ifndef MAX_MIX_COUNT
|
||||
#error
|
||||
#endif
|
||||
|
||||
#ifndef MIX_INPUTS
|
||||
#error
|
||||
#endif
|
||||
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
|
||||
#define DOMIX_TOP(i) \
|
||||
.cc_top doMix##i.function,doMix##i; \
|
||||
.align 4 ;\
|
||||
.align 16 ;\
|
||||
.globl doMix##i ;\
|
||||
.type doMix##i, @function ;\
|
||||
.globl doMix##i##.nstackwords ;\
|
||||
@@ -124,7 +133,7 @@ DOMIX_BOT(7)
|
||||
#undef BODY
|
||||
#define N MAX_MIX_COUNT
|
||||
.cc_top setPtr.function,setPtr;
|
||||
.align 4 ;
|
||||
.align 16 ;
|
||||
.globl setPtr;
|
||||
.type setPtr, @function
|
||||
.globl setPtr.nstackwords;
|
||||
@@ -173,5 +182,5 @@ setPtr_go:
|
||||
#undef N
|
||||
#undef BODY
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,25 +1,39 @@
|
||||
// Copyright 2011-2022 XMOS LIMITED.
|
||||
// Copyright 2011-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
#define XASSERT_UNIT MIXER
|
||||
#include "xassert.h"
|
||||
|
||||
#include <xs1.h>
|
||||
#include <print.h>
|
||||
#include "xua.h"
|
||||
#include "xc_ptr.h"
|
||||
#include "xua_commands.h"
|
||||
#include "dbcalc.h"
|
||||
|
||||
#ifdef MIXER
|
||||
/* FAST_MIXER has a bit of a nasty implentation but is more efficient */
|
||||
#ifndef FAST_MIXER
|
||||
#define FAST_MIXER (1)
|
||||
#endif
|
||||
|
||||
/* FAST_MIXER has a bit of a nasty implentation but is more effcient */
|
||||
#define FAST_MIXER 1
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS) || !FAST_MIXER
|
||||
#include "xc_ptr.h"
|
||||
#endif
|
||||
|
||||
//#ifdef OUT_VOLUME_IN_MIXER
|
||||
#if (MIXER)
|
||||
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
static unsigned int multOut_array[NUM_USB_CHAN_OUT + 1];
|
||||
static xc_ptr multOut;
|
||||
//#endif
|
||||
//#ifdef IN_VOLUME_IN_MIXER
|
||||
unsafe
|
||||
{
|
||||
int volatile * unsafe multOut = multOut_array;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
static unsigned int multIn_array[NUM_USB_CHAN_IN + 1];
|
||||
static xc_ptr multIn;
|
||||
//#endif
|
||||
unsafe
|
||||
{
|
||||
int volatile * unsafe multIn = multIn_array;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
||||
static unsigned abs(int x)
|
||||
@@ -35,35 +49,38 @@ static unsigned abs(int x)
|
||||
}
|
||||
#endif
|
||||
|
||||
static const int SOURCE_COUNT = NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1;
|
||||
|
||||
static int samples_array[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT + 1]; /* One larger for an "off" channel for mixer sources" */
|
||||
xc_ptr samples;
|
||||
static int samples_to_host_map_array[NUM_USB_CHAN_IN];
|
||||
static int samples_to_device_map_array[NUM_USB_CHAN_OUT];
|
||||
|
||||
unsafe
|
||||
{
|
||||
static int volatile * const unsafe ptr_samples = samples_array;
|
||||
int volatile * const unsafe ptr_samples = samples_array;
|
||||
int volatile * const unsafe samples_to_host_map = samples_to_host_map_array;
|
||||
int volatile * const unsafe samples_to_device_map = samples_to_device_map_array;
|
||||
}
|
||||
|
||||
int savedsamples2[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT];
|
||||
|
||||
int samples_to_host_map_array[NUM_USB_CHAN_IN];
|
||||
xc_ptr samples_to_host_map;
|
||||
|
||||
int samples_to_device_map_array[NUM_USB_CHAN_OUT];
|
||||
xc_ptr samples_to_device_map;
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
int mix_mult_array[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
xc_ptr mix_mult;
|
||||
#define write_word_to_mix_mult(x,y,val) write_via_xc_ptr_indexed(mix_mult,((x)*MIX_INPUTS)+(y), val)
|
||||
#define mix_mult_slice(x) (mix_mult + x * MIX_INPUTS * sizeof(int))
|
||||
#ifndef FAST_MIXER
|
||||
int mix_map_array[MAX_MIX_COUNT][MIX_INPUTS];
|
||||
xc_ptr mix_map;
|
||||
#define write_word_to_mix_map(x,y,val) write_via_xc_ptr_indexed(mix_map,((x)*MIX_INPUTS)+(y), val)
|
||||
#define mix_map_slice(x) (mix_map + x * MIX_INPUTS * sizeof(int))
|
||||
#endif
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
int mix_mult_array[MAX_MIX_COUNT * MIX_INPUTS];
|
||||
#if (FAST_MIXER == 0)
|
||||
int mix_map_array[MAX_MIX_COUNT * MIX_INPUTS];
|
||||
#endif
|
||||
|
||||
unsafe
|
||||
{
|
||||
int volatile * const unsafe mix_mult = mix_mult_array;
|
||||
#if (FAST_MIXER == 0)
|
||||
int volatile * const unsafe mix_map = mix_map_array;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define slice(a, i) (a + i * MIX_INPUTS)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
/* Arrays for level data */
|
||||
int samples_to_host_inputs[NUM_USB_CHAN_IN]; /* Audio transmitted to host i.e. device inputs */
|
||||
xc_ptr samples_to_host_inputs_ptr;
|
||||
@@ -77,19 +94,6 @@ static int samples_from_host_streams[NUM_USB_CHAN_OUT]; /* Peak samples for audi
|
||||
static int samples_mixer_outputs[MAX_MIX_COUNT]; /* Peak samples out of the mixer */
|
||||
xc_ptr samples_mixer_outputs_ptr;
|
||||
|
||||
#if 0
|
||||
#pragma xta command "add exclusion mixer1_rate_change"
|
||||
#pragma xta command "analyse path mixer1_req mixer1_req"
|
||||
#pragma xta command "set required - 10400 ns" /* 96kHz */
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#pragma xta command "add exclusion mixer2_rate_change"
|
||||
#pragma xta command "analyse path mixer2_req mixer2_req"
|
||||
#pragma xta command "set required - 10400 ns" /* 96kHz */
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_LEDS) || defined (LEVEL_METER_HOST)
|
||||
static inline void ComputeMixerLevel(int sample, int i)
|
||||
{
|
||||
int x;
|
||||
@@ -108,42 +112,40 @@ static inline void ComputeMixerLevel(int sample, int i)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef FAST_MIXER
|
||||
|
||||
#if (FAST_MIXER)
|
||||
void setPtr(int src, int dst, int mix);
|
||||
int doMix0(xc_ptr samples, xc_ptr mult);
|
||||
int doMix1(xc_ptr samples, xc_ptr mult);
|
||||
int doMix2(xc_ptr samples, xc_ptr mult);
|
||||
int doMix3(xc_ptr samples, xc_ptr mult);
|
||||
int doMix4(xc_ptr samples, xc_ptr mult);
|
||||
int doMix5(xc_ptr samples, xc_ptr mult);
|
||||
int doMix6(xc_ptr samples, xc_ptr mult);
|
||||
int doMix7(xc_ptr samples, xc_ptr mult);
|
||||
int doMix8(xc_ptr samples, xc_ptr mult);
|
||||
int doMix0(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix1(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix2(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix3(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix4(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix5(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix6(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
int doMix7(volatile int * const unsafe samples, volatile int * const unsafe mult);
|
||||
#else
|
||||
/* DO NOT inline, causes 10.4.2 tools to add extra loads in loop */
|
||||
/* At 18 x 12dB we could get 64 x bigger */
|
||||
#pragma unsafe arrays
|
||||
static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
|
||||
static inline int doMix(volatile int * unsafe samples, volatile int * unsafe const mixMap, volatile int * const unsafe mult)
|
||||
{
|
||||
int h=0;
|
||||
int l=0;
|
||||
|
||||
/* By breaking up the loop we keep things in the encoding for ldw (0-11) */
|
||||
#pragma loop unroll
|
||||
for (int i=0; i<MIX_INPUTS; i++)
|
||||
{
|
||||
int sample;
|
||||
int index;
|
||||
int m;
|
||||
read_via_xc_ptr_indexed(index, ptr, i);
|
||||
read_via_xc_ptr_indexed(sample,samples,index);
|
||||
read_via_xc_ptr_indexed(m, mult, i);
|
||||
{h,l} = macs(sample, m, h, l);
|
||||
unsafe{
|
||||
int sample;
|
||||
int source;
|
||||
int weight;
|
||||
read_via_xc_ptr_indexed(source, mixMap, i);
|
||||
sample = samples[source];
|
||||
read_via_xc_ptr_indexed(weight, mult, i);
|
||||
|
||||
|
||||
{h,l} = macs(sample, weight, h, l);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* Perform saturation */
|
||||
l = sext(h, 25);
|
||||
l = sext(h, XUA_MIXER_MULT_FRAC_BITS);
|
||||
|
||||
if(l != h)
|
||||
{
|
||||
@@ -152,15 +154,14 @@ static inline int doMix(xc_ptr samples, xc_ptr ptr, xc_ptr mult)
|
||||
else
|
||||
h = (0x7fffff00>>7);
|
||||
}
|
||||
#endif
|
||||
return h<<7;
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma unsafe arrays
|
||||
static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
|
||||
static inline void GiveSamplesToHost(chanend c, volatile int * unsafe hostMap)
|
||||
{
|
||||
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
@@ -170,23 +171,26 @@ static inline void GiveSamplesToHost(chanend c, xc_ptr ptr, xc_ptr multIn)
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
int sample;
|
||||
int index;
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
read_via_xc_ptr_indexed(index,ptr,i);
|
||||
#else
|
||||
index = i + NUM_USB_CHAN_OUT;
|
||||
#endif
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
unsafe
|
||||
{
|
||||
//read_via_xc_ptr_indexed(sample,samples,index);
|
||||
sample = ptr_samples[index];
|
||||
sample = ptr_samples[hostMap[i]];
|
||||
}
|
||||
#else
|
||||
unsafe
|
||||
{
|
||||
sample = ptr_samples[i + NUM_USB_CHAN_OUT];
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IN_VOLUME_IN_MIXER) && defined(IN_VOLUME_AFTER_MIX)
|
||||
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||
#warning IN Vols in mixer, AFTER mix & map
|
||||
//asm("ldw %0, %1[%2]":"=r"(mult):"r"(multIn),"r"(i));
|
||||
read_via_xc_ptr_indexed(mult, multIn, i);
|
||||
|
||||
unsafe
|
||||
{
|
||||
mult = multIn[i];
|
||||
}
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
|
||||
//h <<= 3 done on other side */
|
||||
@@ -209,7 +213,7 @@ static inline void GetSamplesFromHost(chanend c)
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
unsafe {
|
||||
int sample, x;
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
|
||||
#if (OUT_VOLUME_IN_MIXER && !OUT_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
@@ -226,50 +230,47 @@ static inline void GetSamplesFromHost(chanend c)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && !defined(OUT_VOLUME_AFTER_MIX)
|
||||
#if (OUT_VOLUME_IN_MIXER && !OUT_VOLUME_AFTER_MIX)
|
||||
#warning OUT Vols in mixer, BEFORE mix & map
|
||||
read_via_xc_ptr_indexed(mult, multOut, i);
|
||||
mult = multOut[i];
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h<<=3;
|
||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
sample = h;
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(multOut, index, val);
|
||||
write_via_xc_ptr_indexed(samples_array, i, h);
|
||||
#else
|
||||
ptr_samples[i] = sample;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma unsafe arrays
|
||||
static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
||||
static inline void GiveSamplesToDevice(chanend c, volatile int * unsafe deviceMap)
|
||||
{
|
||||
#if(NUM_USB_CHAN_OUT == 0)
|
||||
#if (NUM_USB_CHAN_OUT == 0)
|
||||
outuint(c, 0);
|
||||
#else
|
||||
#pragma loop unroll
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int sample, x;
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
|
||||
#if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
#endif
|
||||
int index;
|
||||
|
||||
#if MAX_MIX_COUNT > 0
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
/* If mixer turned on sort out the channel mapping */
|
||||
|
||||
/* Read pointer to sample from the map */
|
||||
read_via_xc_ptr_indexed(index, ptr, i);
|
||||
|
||||
/* Read the actual sample value */
|
||||
read_via_xc_ptr_indexed(sample, samples, index);
|
||||
unsafe
|
||||
{
|
||||
/* Read index to sample from the map then Read the actual sample value */
|
||||
sample = ptr_samples[deviceMap[i]];
|
||||
}
|
||||
#else
|
||||
unsafe
|
||||
{
|
||||
@@ -278,16 +279,19 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OUT_VOLUME_IN_MIXER) && defined(OUT_VOLUME_AFTER_MIX)
|
||||
#if (OUT_VOLUME_IN_MIXER && OUT_VOLUME_AFTER_MIX)
|
||||
/* Do volume control processing */
|
||||
#warning OUT Vols in mixer, AFTER mix & map
|
||||
read_via_xc_ptr_indexed(mult, multOut, i);
|
||||
unsafe
|
||||
{
|
||||
mult = multOut[i];
|
||||
}
|
||||
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h<<=3; // Shift used to be done in audio thread but now done here incase of 32bit support
|
||||
#error
|
||||
#if (STREAM_FORMAT_OUTPUT_RESOLUTION_32BIT_USED == 1)
|
||||
h |= (l >>29)& 0x7; // Note: This step is not required if we assume sample depth is 24bit (rather than 32bit)
|
||||
// Note: We need all 32bits for Native DSD
|
||||
// Note: We need all 32bits for Native DSD
|
||||
#endif
|
||||
outuint(c, h);
|
||||
#else
|
||||
@@ -300,14 +304,14 @@ static inline void GiveSamplesToDevice(chanend c, xc_ptr ptr, xc_ptr multOut)
|
||||
#pragma unsafe arrays
|
||||
static inline void GetSamplesFromDevice(chanend c)
|
||||
{
|
||||
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
|
||||
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||
int mult;
|
||||
int h;
|
||||
unsigned l;
|
||||
#endif
|
||||
|
||||
#pragma loop unroll
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
{
|
||||
int sample;
|
||||
int x;
|
||||
@@ -327,22 +331,24 @@ static inline void GetSamplesFromDevice(chanend c)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IN_VOLUME_IN_MIXER) && !defined(IN_VOLUME_AFTER_MIX)
|
||||
/* Read relevant multiplier */
|
||||
read_via_xc_ptr_indexed(mult, multIn, i);
|
||||
#if (IN_VOLUME_IN_MIXER && IN_VOLUME_AFTER_MIX)
|
||||
/* Volume processing - read relevant multiplier */
|
||||
unsafe
|
||||
{
|
||||
mult = multIn[i];
|
||||
}
|
||||
|
||||
/* Do the multiply */
|
||||
{h, l} = macs(mult, sample, 0, 0);
|
||||
h <<=3;
|
||||
write_via_xc_ptr_indexed(samples_array, NUM_USB_CHAN_OUT+i, h);
|
||||
#else
|
||||
/* No volume processing */
|
||||
h <<= 3;
|
||||
sample = h;
|
||||
#endif
|
||||
unsafe
|
||||
{
|
||||
ptr_samples[NUM_USB_CHAN_OUT + i] = sample;
|
||||
assert((XUA_MIXER_OFFSET_IN + i) < (NUM_USB_CHAN_IN + NUM_USB_CHAN_OUT));
|
||||
ptr_samples[XUA_MIXER_OFFSET_IN + i] = sample;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mixer1_mix2_flag = (DEFAULT_FREQ > 96000);
|
||||
@@ -353,12 +359,14 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
int mixed;
|
||||
#endif
|
||||
#if (MAX_MIX_COUNT > 0) || (IN_VOLUME_IN_MIXER) || (OUT_VOLUME_IN_MIXER) || defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
unsigned cmd;
|
||||
unsigned char ct;
|
||||
#endif
|
||||
unsigned request = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
#pragma xta endpoint "mixer1_req"
|
||||
/* Request from audio()/mixer2() */
|
||||
request = inuint(c_mixer2);
|
||||
|
||||
@@ -369,28 +377,62 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
/* Sync */
|
||||
outuint(c_mixer2, 0);
|
||||
#endif
|
||||
|
||||
/* Between request to decouple and response ~ 400nS latency for interrupt to fire */
|
||||
|
||||
#if (MAX_MIX_COUNT > 0) || (IN_VOLUME_IN_MIXER) || (OUT_VOLUME_IN_MIXER) || defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
select
|
||||
{
|
||||
case inuint_byref(c_mix_ctl, cmd):
|
||||
/* Check if EP0 intends to send us a control command */
|
||||
case inct_byref(c_mix_ctl, ct):
|
||||
{
|
||||
int mix, index, val;
|
||||
|
||||
/* Handshake back to tell EP0 we are ready for an update */
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
|
||||
/* Receive command from EP0 */
|
||||
cmd = inuint(c_mix_ctl);
|
||||
|
||||
/* Interpret control command */
|
||||
switch (cmd)
|
||||
{
|
||||
#if MAX_MIX_COUNT > 0
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
case SET_SAMPLES_TO_HOST_MAP:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
write_via_xc_ptr_indexed(samples_to_host_map, index, val);
|
||||
{
|
||||
int dst = inuint(c_mix_ctl);
|
||||
int src = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
assert((dst < NUM_USB_CHAN_IN) && msg("Host map destination out of range"));
|
||||
assert((src < SOURCE_COUNT) && msg("Host map source out of range"));
|
||||
|
||||
if((dst < NUM_USB_CHAN_IN) && (src < SOURCE_COUNT))
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
samples_to_host_map[dst] = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_SAMPLES_TO_DEVICE_MAP:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
write_via_xc_ptr_indexed(samples_to_device_map,index,val);
|
||||
{
|
||||
int dst = inuint(c_mix_ctl);
|
||||
int src = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
assert((dst < NUM_USB_CHAN_OUT) && msg("Device map destination out of range"));
|
||||
assert((src < SOURCE_COUNT) && msg("Device map source out of range"));
|
||||
|
||||
if((dst < NUM_USB_CHAN_OUT) && (src < SOURCE_COUNT))
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
samples_to_device_map[dst] = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_MIX_MULT:
|
||||
@@ -399,40 +441,80 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
write_word_to_mix_mult(mix, index, val);
|
||||
assert((mix < MAX_MIX_COUNT) && msg("Mix mult mix out of range"));
|
||||
assert((index < MIX_INPUTS) && msg("Mix mult index out of range"));
|
||||
|
||||
if((index < MIX_INPUTS) && (mix < MAX_MIX_COUNT))
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
mix_mult[(mix * MIX_INPUTS) + index] = val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_MIX_MAP:
|
||||
mix = inuint(c_mix_ctl);
|
||||
index = inuint(c_mix_ctl); /* mixer input */
|
||||
val = inuint(c_mix_ctl); /* source */
|
||||
inct(c_mix_ctl);
|
||||
#ifdef FAST_MIXER
|
||||
setPtr(index, val, mix);
|
||||
{
|
||||
unsigned mix = inuint(c_mix_ctl);
|
||||
unsigned input = inuint(c_mix_ctl); /* mixer input */
|
||||
unsigned source = inuint(c_mix_ctl); /* source */
|
||||
inct(c_mix_ctl);
|
||||
|
||||
assert((mix < MAX_MIX_COUNT) && msg("Mix map mix out of range"));
|
||||
assert((input < MIX_INPUTS) && msg("Mix map index out of range"));
|
||||
assert((source < SOURCE_COUNT) && msg("Mix map source out of range"));
|
||||
|
||||
if((input < MIX_INPUTS) && (mix < MAX_MIX_COUNT) && (source < SOURCE_COUNT))
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
setPtr(input, source, mix);
|
||||
#else
|
||||
write_word_to_mix_map(mix, index, val);
|
||||
unsafe
|
||||
{
|
||||
mix_map[(mix * MIX_INPUTS) + input] = source;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* if MAX_MIX_COUNT > 0 */
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
case SET_MIX_IN_VOL:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
write_via_xc_ptr_indexed(multIn, index, val);
|
||||
assert((index < (NUM_USB_CHAN_IN + 1)) && msg("In volume index out of range"));
|
||||
|
||||
if(index < NUM_USB_CHAN_IN + 1)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
multIn[index] = val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
case SET_MIX_OUT_VOL:
|
||||
index = inuint(c_mix_ctl);
|
||||
val = inuint(c_mix_ctl);
|
||||
inct(c_mix_ctl);
|
||||
|
||||
write_via_xc_ptr_indexed(multOut, index, val);
|
||||
assert((index < (NUM_USB_CHAN_OUT + 1)) && msg("Out volume index out of range"));
|
||||
|
||||
if(index < NUM_USB_CHAN_OUT + 1)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
multOut[index] = val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
/* Peak samples of stream from host to device (via USB) */
|
||||
case GET_STREAM_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
@@ -441,42 +523,6 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
samples_from_host_streams[index] = 0;
|
||||
break;
|
||||
|
||||
case GET_INPUT_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
chkct(c_mix_ctl, XS1_CT_END);
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
/* Level LEDS process reseting samples_to_host_inputs
|
||||
* Other side makes sure we don't miss a peak */
|
||||
//val = samples_to_host_inputs_buff[index];
|
||||
//samples_to_host_inputs_buff[index] = 0;
|
||||
/* Access funcs used to avoid disjointness check */
|
||||
read_via_xc_ptr_indexed(val, samples_to_host_inputs_buff_ptr, index);
|
||||
write_via_xc_ptr_indexed(samples_to_host_inputs_buff_ptr, index, 0);
|
||||
#else
|
||||
/* We dont have a level LEDs process, so reset ourselves */
|
||||
//val = samples_to_host_inputs[index];
|
||||
//samples_to_host_inputs[index] = 0;
|
||||
/* Access funcs used to avoid disjointness check */
|
||||
read_via_xc_ptr_indexed(val, samples_to_host_inputs_ptr, index);
|
||||
write_via_xc_ptr_indexed(samples_to_host_inputs_ptr, index, 0);
|
||||
#endif
|
||||
outuint(c_mix_ctl, val);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
break;
|
||||
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
/* Peak samples of the mixer outputs */
|
||||
case GET_OUTPUT_LEVELS:
|
||||
index = inuint(c_mix_ctl);
|
||||
chkct(c_mix_ctl, XS1_CT_END);
|
||||
read_via_xc_ptr_indexed(val, samples_mixer_outputs, index);
|
||||
write_via_xc_ptr_indexed(samples_mixer_outputs, index, 0);
|
||||
//val = samples_mixer_outputs[index];
|
||||
//samples_mixer_outputs[index] = 0;
|
||||
outuint(c_mix_ctl, val);
|
||||
outct(c_mix_ctl, XS1_CT_END);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
@@ -484,14 +530,13 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
default:
|
||||
/* Select default */
|
||||
break;
|
||||
}
|
||||
|
||||
} // select
|
||||
#endif
|
||||
|
||||
/* Get response from decouple */
|
||||
if(testct(c_host))
|
||||
{
|
||||
int sampFreq;
|
||||
#pragma xta endpoint "mixer1_rate_change"
|
||||
unsigned command = inct(c_host);
|
||||
|
||||
switch(command)
|
||||
@@ -520,9 +565,8 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
|
||||
#pragma loop unroll
|
||||
/* Reset the mix values back to 0 */
|
||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||
for (int i=0; i<MAX_MIX_COUNT; i++)
|
||||
{
|
||||
//write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
|
||||
unsafe
|
||||
{
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
||||
@@ -535,21 +579,24 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if MAX_MIX_COUNT > 0
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
GetSamplesFromHost(c_host);
|
||||
GiveSamplesToHost(c_host, samples_to_host_map, multIn);
|
||||
GiveSamplesToHost(c_host, samples_to_host_map);
|
||||
|
||||
/* Sync with mixer 2 (once it has swapped samples with audiohub) */
|
||||
outuint(c_mixer2, 0);
|
||||
inuint(c_mixer2);
|
||||
|
||||
/* Do the mixing */
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix0(samples, mix_mult_slice(0));
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix0(ptr_samples, slice(mix_mult, 0));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(0),mix_mult_slice(0));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 0), slice(mix_mult, 0));
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0), mixed);
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 0] = mixed;
|
||||
}
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 0);
|
||||
@@ -560,40 +607,46 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
#endif
|
||||
{
|
||||
|
||||
#if MAX_MIX_COUNT > 2
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix2(samples, mix_mult_slice(2));
|
||||
#if (MAX_MIX_COUNT > 2)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix2(ptr_samples, slice(mix_mult, 2));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(2),mix_mult_slice(2));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 2), slice(mix_mult, 2));
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2), mixed);
|
||||
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 2] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 4
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix4(samples, mix_mult_slice(4));
|
||||
#if (MAX_MIX_COUNT > 4)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix4(ptr_samples, slice(mix_mult, 4));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(4),mix_mult_slice(4));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 4), slice(mix_mult, 4));
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(samples_array, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 4), mixed);
|
||||
|
||||
ptr_samples[XUA_MIXER_OFFSET_MIX + 4] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 4);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 6
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix6(samples, mix_mult_slice(6));
|
||||
#if (MAX_MIX_COUNT > 6)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix6(ptr_samples, slice(mix_mult, 6));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(6),mix_mult_slice(6));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 6), slice(mix_mult, 6));
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 6), mixed);
|
||||
|
||||
ptr_samples[XUA_MIXER_OFFSET_MIX + 6] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 6);
|
||||
#endif
|
||||
@@ -601,10 +654,10 @@ static void mixer1(chanend c_host, chanend c_mix_ctl, chanend c_mixer2)
|
||||
}
|
||||
#else /* IF MAX_MIX_COUNT > 0 */
|
||||
/* No mixes, this thread runs on its own doing just volume */
|
||||
GiveSamplesToDevice(c_mixer2, samples_to_device_map, multOut);
|
||||
GiveSamplesToDevice(c_mixer2, samples_to_device_map);
|
||||
GetSamplesFromDevice(c_mixer2);
|
||||
GetSamplesFromHost(c_host);
|
||||
GiveSamplesToHost(c_host, samples_to_host_map, multIn);
|
||||
GiveSamplesToHost(c_host, samples_to_host_map);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -621,7 +674,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
|
||||
while (1)
|
||||
{
|
||||
#pragma xta endpoint "mixer2_req"
|
||||
request = inuint(c_audio);
|
||||
|
||||
/* Forward the request on */
|
||||
@@ -633,7 +685,6 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
if(testct(c_mixer1))
|
||||
{
|
||||
int sampFreq;
|
||||
#pragma xta endpoint "mixer2_rate_change"
|
||||
unsigned command = inct(c_mixer1);
|
||||
|
||||
switch(command)
|
||||
@@ -660,8 +711,8 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
}
|
||||
|
||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i), 0);
|
||||
unsafe{
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + i] = 0;
|
||||
}
|
||||
|
||||
/* Wait for handshake and pass on */
|
||||
@@ -670,7 +721,7 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
}
|
||||
else
|
||||
{
|
||||
GiveSamplesToDevice(c_audio, samples_to_device_map, multOut);
|
||||
GiveSamplesToDevice(c_audio, samples_to_device_map);
|
||||
GetSamplesFromDevice(c_audio);
|
||||
|
||||
/* Sync with mixer 1 (once it has swapped samples with the buffering sub-system) */
|
||||
@@ -678,61 +729,67 @@ static void mixer2(chanend c_mixer1, chanend c_audio)
|
||||
outuint(c_mixer1, 0);
|
||||
|
||||
/* Do the mixing */
|
||||
#if MAX_MIX_COUNT > 1
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix1(samples, mix_mult_slice(1));
|
||||
#if (MAX_MIX_COUNT > 1)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix1(ptr_samples, slice(mix_mult, 1));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(1),mix_mult_slice(1));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 1), slice(mix_mult, 1));
|
||||
#endif
|
||||
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1), mixed);
|
||||
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 1] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if (MAX_FREQ > 96000)
|
||||
/* Fewer mixes when running higher than 96kHz */
|
||||
if (!mixer2_mix2_flag)
|
||||
#endif
|
||||
{
|
||||
#if MAX_MIX_COUNT > 3
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix3(samples, mix_mult_slice(3));
|
||||
#if (MAX_MIX_COUNT > 3)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix3(ptr_samples, slice(mix_mult, 3));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(3),mix_mult_slice(3));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 3), slice(mix_mult, 3));
|
||||
#endif
|
||||
|
||||
write_via_xc_ptr_indexed(samples, (NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3), mixed);
|
||||
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 3] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 5
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix5(samples, mix_mult_slice(5));
|
||||
#if (MAX_MIX_COUNT > 5)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix5(ptr_samples, slice(mix_mult, 5));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(5),mix_mult_slice(5));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 5), slice(mix_mult, 5));
|
||||
#endif
|
||||
write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5, mixed);
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 5] = mixed;
|
||||
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 5);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MAX_MIX_COUNT > 7
|
||||
#ifdef FAST_MIXER
|
||||
mixed = doMix7(samples, mix_mult_slice(7));
|
||||
#if (MAX_MIX_COUNT > 7)
|
||||
unsafe
|
||||
{
|
||||
#if (FAST_MIXER)
|
||||
mixed = doMix7(ptr_samples, slice(mix_mult, 7));
|
||||
#else
|
||||
mixed = doMix(samples, mix_map_slice(7),mix_mult_slice(7));
|
||||
mixed = doMix(ptr_samples, slice(mix_map, 7), slice(mix_mult, 7));
|
||||
#endif
|
||||
|
||||
write_via_xc_ptr_indexed(samples, NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7, mixed);
|
||||
ptr_samples[NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + 7] = mixed;
|
||||
}
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
ComputeMixerLevel(mixed, 7);
|
||||
#endif
|
||||
@@ -748,68 +805,52 @@ void mixer(chanend c_mix_in, chanend c_mix_out, chanend c_mix_ctl)
|
||||
#if (MAX_MIX_COUNT > 0)
|
||||
chan c;
|
||||
#endif
|
||||
multOut = array_to_xc_ptr((multOut_array,unsigned[]));
|
||||
multIn = array_to_xc_ptr((multIn_array,unsigned[]));
|
||||
|
||||
samples = array_to_xc_ptr((samples_array,unsigned[]));
|
||||
samples_to_host_map = array_to_xc_ptr((samples_to_host_map_array,unsigned[]));
|
||||
samples_to_device_map = array_to_xc_ptr((samples_to_device_map_array,unsigned[]));
|
||||
|
||||
#if defined (LEVEL_METER_HOST) || defined(LEVEL_METER_LEDS)
|
||||
samples_to_host_inputs_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
|
||||
#ifdef LEVEL_METER_LEDS
|
||||
samples_to_host_inputs_buff_ptr = array_to_xc_ptr((samples_to_host_inputs, unsigned[]));
|
||||
#endif
|
||||
samples_mixer_outputs_ptr = array_to_xc_ptr((samples_mixer_outputs, unsigned[]));
|
||||
|
||||
#if MAX_MIX_COUNT >0
|
||||
mix_mult = array_to_xc_ptr((mix_mult_array,unsigned[]));
|
||||
#ifndef FAST_MIXER
|
||||
mix_map = array_to_xc_ptr((mix_map_array,unsigned[]));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT + NUM_USB_CHAN_IN + MAX_MIX_COUNT;i++)
|
||||
unsafe {
|
||||
//write_via_xc_ptr_indexed(samples,i,0);
|
||||
ptr_samples[i] = 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
{
|
||||
int num_mixes = DEFAULT_FREQ > 96000 ? 2 : MAX_MIX_COUNT;
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||
{
|
||||
//samples_to_device_map_array[i] = i;
|
||||
asm("stw %0, %1[%2]":: "r"(i), "r"(samples_to_device_map), "r"(i));
|
||||
}
|
||||
samples_to_device_map_array[i] = i;
|
||||
}
|
||||
|
||||
#ifdef OUT_VOLUME_IN_MIXER
|
||||
for (int i=0;i<NUM_USB_CHAN_OUT;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(multOut, i, MAX_VOL);
|
||||
#if (OUT_VOLUME_IN_MIXER)
|
||||
for (int i=0; i<NUM_USB_CHAN_OUT; i++)
|
||||
unsafe{
|
||||
multOut[i] = MAX_VOL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IN_VOLUME_IN_MIXER
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(multIn, i, MAX_VOL);
|
||||
#if (IN_VOLUME_IN_MIXER)
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
unsafe{
|
||||
multIn[i] = MAX_VOL;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i=0;i<NUM_USB_CHAN_IN;i++)
|
||||
{
|
||||
write_via_xc_ptr_indexed(samples_to_host_map, i, NUM_USB_CHAN_OUT + i);
|
||||
for (int i=0; i<NUM_USB_CHAN_IN; i++)
|
||||
unsafe{
|
||||
samples_to_host_map[i] = XUA_MIXER_OFFSET_IN + i;
|
||||
}
|
||||
|
||||
#if MAX_MIX_COUNT> 0
|
||||
#if (MAX_MIX_COUNT> 0)
|
||||
for (int i=0;i<MAX_MIX_COUNT;i++)
|
||||
for (int j=0;j<MIX_INPUTS;j++)
|
||||
{
|
||||
#ifndef FAST_MIXER
|
||||
write_word_to_mix_map(i,j, j < 16 ? j : j + 2);
|
||||
unsafe{
|
||||
#if (FAST_MIXER == 0)
|
||||
mix_map[i * MIX_INPUTS + j] = (j < 16 ? j : j + 2);
|
||||
#endif
|
||||
write_word_to_mix_mult(i,j, i==j ? db_to_mult(0, 8, 25) : 0);
|
||||
mix_mult[i * MIX_INPUTS + j] = (i==j ? db_to_mult(0, XUA_MIXER_DB_FRAC_BITS, XUA_MIXER_MULT_FRAC_BITS) : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -110,10 +110,8 @@ void ConfigAudioPorts(
|
||||
}
|
||||
|
||||
set_clock_fall_delay(clk_audio_bclk, bClkDelay_fall);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if (I2S_CHANS_DAC != 0)
|
||||
/* Clock I2S output data ports from b-clock clock block */
|
||||
for(int i = 0; i < I2S_WIRES_DAC; i++)
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
# Copyright 2022 XMOS LIMITED.
|
||||
# Copyright 2022-2023 XMOS LIMITED.
|
||||
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
import pytest
|
||||
import time
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def test_file(request):
|
||||
return str(request.node.fspath)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session") # Use same seed for whole run
|
||||
def test_seed(request):
|
||||
|
||||
seed = str(int(time.time()))
|
||||
# We dont need the following since pytest will print the values of our fixtures on a failure
|
||||
# capmanager = request.config.pluginmanager.getplugin("capturemanager")
|
||||
# with capmanager.global_and_fixture_disabled():
|
||||
# print("Using seed: "+ seed)
|
||||
return seed
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
|
||||
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