Merge commit '6157e899e21792885766c018a6c579122eea502d'
Merge commit corresponding to SOF v0.5 release.
BUG=b:112528390, b:110025789
TEST=cros deploy <BOARD> sof-topoogy and verify that the DSP
boots on an octopus board.
Change-Id: I7c2837fc2563278f5e1ced999482b07f63eb7726
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..023e264
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+*.o
+*.in
+*~
+autom4te*
+*.Po
+*.swp
+Makefile
+config.*
+configure
+depcomp
+install-sh
+missing
+stamp-h1
+aclocal.m4
+compile
+ltmain.sh
+rimage/rimage
+rmbox/rmbox
+rwav/rwav
+*.tplg
+topology/*.conf
+topology/test/*.conf
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..12533d1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,14 @@
+sudo: required
+
+language: c
+
+services:
+ - docker
+
+before_install:
+ - docker pull xiulipan/sof
+ - echo -e '#!/bin/bash \n./autogen.sh && ./configure && make' > quickbuild.sh
+ - chmod 755 quickbuild.sh
+
+script:
+ - docker run -it -v `pwd`:/home/sof/work/sof.git --user `id -u` xiulipan/sof ./quickbuild.sh
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..902f0e9
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = rmbox topology
+TESTDIR = topology/test
+
+tests:
+ $(MAKE) -C $(TESTDIR)
diff --git a/README b/README
new file mode 100644
index 0000000..a8f818b
--- /dev/null
+++ b/README
@@ -0,0 +1,42 @@
+Sound Open Firmware Tools
+=========================
+
+This is a collection of open source tools used to develop open source audio
+DSP firmwares for ALSA.
+
+Building and Installing
+=======================
+
+./autogen.sh (only needed first time)
+./configure
+make
+make install
+
+
+rimage
+======
+
+rimage is used to convert ELF executable firmware files to the firmware file
+formats used by the kernel drivers.
+
+e.g.
+
+rimage -i elf_file -o kernel_file -m machine
+
+rimage can also convert kernel firmware formats to flat binaries formats to
+assist in debugging :-
+
+e.g. convert to flat binary, then ELF then dissasemble
+
+rimage -i /lib/firmware/intel/reef-byt.ri -o image.bin -b -m byt
+
+xtensa-byt-elf-objcopy -I binary -O elf32-xtensa-le -B xtensa image.bin image.bin.elf
+
+xtensa-byt-elf-objdump -D image.bin.elf > image.dis.txt
+
+tests
+=====
+
+To generate all test configuration files:
+
+make tests
\ No newline at end of file
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..3b379b6
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+libtoolize -c --force
+aclocal -I m4 --install
+autoconf -Wall
+autoheader
+automake -a --copy --foreign --add-missing
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..0336378
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,36 @@
+
+AC_PREREQ([2.69])
+AC_INIT([sof-tools], [1.0.1])
+AM_INIT_AUTOMAKE([foreign])
+AC_CONFIG_SRCDIR([rmbox/rmbox.c])
+AC_CONFIG_HEADERS([config.h])
+AC_CHECK_HEADER([sof/uapi/abi.h])
+AC_CHECK_PROG([XARGS], xargs, "yes", "no", [$PATH])
+AM_CONDITIONAL(XARGS, test "$XARGS" = "yes")
+
+AC_CANONICAL_HOST
+
+dnl Initialize maintainer mode
+AM_MAINTAINER_MODE([enable])
+
+AC_PROG_CC
+
+AC_OUTPUT([
+ Makefile
+ rmbox/Makefile
+ topology/Makefile
+ topology/common/Makefile
+ topology/platform/Makefile
+ topology/platform/intel/Makefile
+ topology/platform/common/Makefile
+ topology/m4/Makefile
+ topology/sof/Makefile
+ topology/test/Makefile
+])
+
+echo "
+
+prefix: ${prefix}
+Compiler: ${CC}
+CFLAGS: ${CFLAGS}
+"
diff --git a/kmod_scripts/sof_bootloop.sh b/kmod_scripts/sof_bootloop.sh
new file mode 100755
index 0000000..da9296d
--- /dev/null
+++ b/kmod_scripts/sof_bootloop.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+MAXLOOPS=100
+COUNTER=0
+
+while [ $COUNTER -lt $MAXLOOPS ]; do
+ echo "test $COUNTER"
+ ./sof_bootone.sh
+ dmesg > boot_$COUNTER.bootlog
+ let COUNTER+=1
+done
diff --git a/kmod_scripts/sof_bootone.sh b/kmod_scripts/sof_bootone.sh
new file mode 100755
index 0000000..92071fa
--- /dev/null
+++ b/kmod_scripts/sof_bootone.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+dmesg -C
+./sof_remove.sh
+./sof_insert.sh
+sleep 1
+
+unset FW_BOOT
+unset ERROR
+FW_BOOT=$(dmesg | grep sof-audio | grep "boot complete")
+ERROR=$(dmesg | grep sof-audio | grep -v "DSP trace buffer overflow" | grep "error")
+TIMEOUT=$(dmesg | grep sof-audio | grep "ipc timed out")
+
+if [ ! -z "$ERROR" ] || [ -z "$FW_BOOT" ] || [ ! -z "$TIMEOUT" ]
+then
+ dmesg > boot_fail.log
+ echo "boot failed, see boot_fail.log for details"
+ exit 1
+else
+ echo "boot success"
+fi
+
diff --git a/kmod_scripts/sof_insert.sh b/kmod_scripts/sof_insert.sh
new file mode 100755
index 0000000..6075310
--- /dev/null
+++ b/kmod_scripts/sof_insert.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+modprobe snd_soc_rt5670
+modprobe snd_soc_rt5645
+modprobe snd_soc_rt5651
+modprobe snd_soc_rt5640
+modprobe snd_soc_da7213
+modprobe snd_soc_pcm512x_i2c
+modprobe snd_soc_tdf8532
+modprobe snd_soc_rt274
+
+modprobe sof_acpi_dev
+modprobe sof_pci_dev
+
+
diff --git a/kmod_scripts/sof_remove.sh b/kmod_scripts/sof_remove.sh
new file mode 100755
index 0000000..8f0b49c
--- /dev/null
+++ b/kmod_scripts/sof_remove.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+remove_module() {
+
+ MODULE="$1"
+
+ if lsmod | grep "$MODULE" &> /dev/null ; then
+ echo "Removing $MODULE"
+ rmmod $MODULE
+ else
+ echo "skipping $MODULE, not loaded"
+ fi
+}
+
+remove_module sof_pci_dev
+remove_module sof_acpi_dev
+remove_module snd_soc_acpi_intel_match
+remove_module snd_sof_intel_byt
+remove_module snd_sof_intel_hsw
+remove_module snd_sof_intel_bdw
+remove_module snd_sof_intel_hda_common
+remove_module snd_sof_xtensa_dsp
+
+remove_module snd_soc_sst_bytcr_rt5640
+remove_module snd_soc_sst_bytcr_rt5651
+remove_module snd_soc_sst_cht_bsw_rt5645
+remove_module snd_soc_sst_cht_bsw_rt5670
+remove_module snd_soc_sst_byt_cht_da7213
+remove_module snd_soc_sst_bxt_pcm512x
+remove_module snd_soc_sst_bxt_tdf8532
+remove_module snd_soc_cnl_rt274
+remove_module snd_sof_nocodec
+remove_module snd_sof
+
+remove_module snd_soc_rt5670
+remove_module snd_soc_rt5645
+remove_module snd_soc_rt5651
+remove_module snd_soc_rt5640
+remove_module snd_soc_rl6231
+remove_module snd_soc_da7213
+remove_module snd_soc_pcm512x_i2c
+remove_module snd_soc_pcm512x
+remove_module snd_soc_tdf8532
+remove_module snd_soc_rt274
+remove_module snd_soc_acpi
diff --git a/logger/logger.c b/logger/logger.c
new file mode 100644
index 0000000..fbfd054
--- /dev/null
+++ b/logger/logger.c
@@ -0,0 +1,294 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include "/usr/local/include/sof/uapi/logging.h"
+
+#define CEIL(a, b) ((a+b-1)/b)
+
+/* elf signature params */
+#define SND_SOF_LOGS_SIG_SIZE 4
+#define SND_SOF_LOGS_SIG "Logs"
+
+struct snd_sof_logs_header {
+ /* "Logs" */
+ unsigned char sig[SND_SOF_LOGS_SIG_SIZE];
+ /* address of log entries section */
+ uint32_t base_address;
+ /* amount of bytes following this header */
+ uint32_t data_length;
+ /* offset to first entry in this file */
+ uint32_t data_offset;
+};
+
+struct ldc_entry_header {
+ uint32_t level;
+ uint32_t component_id;
+ uint32_t params_num;
+ uint32_t line_idx;
+ uint32_t file_name_len;
+};
+
+struct ldc_entry {
+ struct ldc_entry_header header;
+ char *file_name;
+ uint32_t text_len;
+ char *text;
+ uint32_t *params;
+};
+
+struct dma_log {
+ struct log_entry_header header;
+ uint32_t address;
+};
+
+static int fetch_entry(FILE *f_ldc, FILE *f_dma, uint32_t base_address,
+ uint32_t data_offset, struct dma_log dma_log);
+static void print_table_header(void);
+static void print_entry_params(struct dma_log dma_log, struct ldc_entry);
+static void usage(char *name);
+
+static inline void print_table_header(void)
+{
+ fprintf(stdout, "%10s %8s %8s %14s %16s %24s\t%s\n",
+ "ADDRESS",
+ "CORE_ID",
+ "LEVEL",
+ "COMPONENT_ID",
+ "TIMESTAMP",
+ "FILE_NAME",
+ "CONTENT");
+}
+
+static void print_entry_params(struct dma_log dma_log,
+ struct ldc_entry entry)
+{
+ fprintf(stdout, "%10x %8u %8u %14u %16lu %20s:%u\t",
+ dma_log.address,
+ dma_log.header.core_id,
+ entry.header.level,
+ entry.header.component_id,
+ dma_log.header.timestamp,
+ entry.file_name,
+ entry.header.line_idx);
+
+ switch (entry.header.params_num){
+ case 0:
+ fprintf(stdout, "%s", entry.text);
+ break;
+ case 1:
+ fprintf(stdout, entry.text, entry.params[0]);
+ break;
+ case 2:
+ fprintf(stdout, entry.text, entry.params[0],
+ entry.params[1]);
+ break;
+ case 3:
+ fprintf(stdout, entry.text, entry.params[0], entry.params[1],
+ entry.params[2]);
+ break;
+ }
+ fprintf(stdout, "\n");
+}
+
+static void usage(char *name)
+{
+ fprintf(stdout, "Usage %s <file(s)>\n", name);
+ fprintf(stdout, "%s:\t Parse traces logs\n", name);
+ fprintf(stdout, "%s:\t -l *.ldc_file\t-d dma_dump_file\n", name);
+ exit(0);
+}
+
+
+static int fetch_entry(FILE *f_ldc, FILE *f_dma, uint32_t base_address,
+ uint32_t data_offset, struct dma_log dma_log)
+{
+
+ struct ldc_entry entry;
+ long int padding;
+
+ uint32_t entry_offset;
+ uint32_t text_len;
+
+ int ret;
+
+ entry.file_name = NULL;
+ entry.text = NULL;
+ entry.params = NULL;
+
+ /* evaluate entry offset in input file */
+ entry_offset = dma_log.address - base_address;
+
+ /* set file position to beginning of processed entry */
+ fseek(f_ldc, entry_offset + data_offset, SEEK_SET);
+
+ /* fetching elf header params */
+ ret = fread(&entry.header, sizeof(entry.header), 1, f_ldc);
+ if (!ret) {
+ ret = -ferror(f_ldc);
+ goto out;
+ }
+
+ entry.file_name = (char *) malloc(entry.header.file_name_len);
+ if (!entry.file_name){
+ fprintf(stderr, "error: can't allocate %d byte for "
+ "entry.file_name\n", entry.header.file_name_len);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = fread(entry.file_name, sizeof(char), entry.header.file_name_len,
+ f_ldc);
+ if (ret != entry.header.file_name_len) {
+ ret = -ferror(f_ldc);
+ goto out;
+ }
+
+ /* padding - sequences of chars are aligned to DWORDS */
+ fseek(f_ldc, CEIL(entry.header.file_name_len, sizeof(uint32_t)) *
+ sizeof(uint32_t) - entry.header.file_name_len, SEEK_CUR);
+
+ /* fetching text length */
+ ret = fread(&entry.text_len, sizeof(entry.text_len), 1, f_ldc);
+ if (!ret) {
+ ret = -ferror(f_ldc);
+ goto out;
+ }
+
+ /* fetching text */
+ entry.text = (char *) malloc(entry.text_len);
+ if (entry.text == NULL) {
+ fprintf(stderr, "error: can't allocate %d byte for "
+ "entry.text\n", entry.text_len);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = fread(entry.text, sizeof(char), entry.text_len, f_ldc);
+ if (ret != entry.text_len) {
+ ret = -ferror(f_ldc);
+ goto out;
+ }
+
+ /* fetching entry params from dma dump */
+ entry.params = (uint32_t *) malloc(sizeof(uint32_t) *
+ entry.header.params_num);
+ ret = fread(entry.params, sizeof(uint32_t), entry.header.params_num,
+ f_dma);
+ if (ret != entry.header.params_num) {
+ ret = -ferror(f_dma);
+ goto out;
+ }
+
+ /* printing entry content */
+ print_entry_params(dma_log, entry);
+
+ /* set f_ldc file position to the beginning */
+ rewind(f_ldc);
+
+ ret = 0;
+out:
+ /* free alocated memory */
+ free(entry.params);
+ free(entry.text);
+ free(entry.file_name);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ struct dma_log dma_log;
+ struct snd_sof_logs_header snd;
+
+ int ret;
+ int opt;
+
+ const char *ldc_dir = NULL;
+ const char *dma_dump = NULL;
+
+ while ((opt = getopt(argc, argv, "l:d:")) != -1) {
+ switch (opt) {
+ case 'l':
+ ldc_dir = optarg;
+ break;
+ case 'd':
+ dma_dump = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (!ldc_dir) {
+ fprintf(stderr, "error: invalid ldc file.\n");
+ return -EINVAL;
+ }
+ if (!dma_dump) {
+ fprintf(stderr, "error: invalid dma_dump file.\n");
+ return -EINVAL;
+ }
+
+ FILE *f_ldc = fopen(ldc_dir, "r");
+ FILE *f_dma = fopen(dma_dump, "r");
+
+ if (f_ldc == NULL) {
+ fprintf(stderr, "Error while opening %s. \n", ldc_dir);
+ ret = errno;
+ goto out;
+ }
+
+ if (f_dma == NULL) {
+ fprintf(stderr, "Error while opening %s. \n", dma_dump);
+ ret = errno;
+ goto out;
+ }
+
+ /* set file positions to the beginning */
+ rewind(f_ldc);
+ rewind(f_dma);
+
+ /* veryfing ldc signature */
+ ret = fread(&snd, sizeof(snd), 1, f_ldc);
+ if (!ret) {
+ ret = -ferror(f_ldc);
+ goto out;
+ }
+
+ if (strncmp(snd.sig, SND_SOF_LOGS_SIG, SND_SOF_LOGS_SIG_SIZE)) {
+ fprintf(stderr, "Error: Invalid ldc file signature. \n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ print_table_header();
+
+ while (!feof(f_dma)) {
+
+ /* getting entry parameters from dma dump */
+ ret = fread(&dma_log, sizeof(dma_log), 1, f_dma);
+ if (!ret) {
+ ret = -ferror(f_dma);
+ goto out;
+ }
+
+ /* checking log address */
+ if ((dma_log.address < snd.base_address) ||
+ (dma_log.address > (snd.base_address + snd.data_length)))
+ continue;
+
+ /* fetching entry from elf dump*/
+ ret = fetch_entry(f_ldc, f_dma, snd.base_address,
+ snd.data_offset, dma_log);
+ if (ret) goto out;
+ }
+
+ ret = 0;
+out:
+ if (f_dma) fclose(f_dma);
+ if (f_ldc) fclose(f_ldc);
+
+ return ret;
+}
diff --git a/rimage/keys/Makefile.am b/rimage/keys/Makefile.am
new file mode 100644
index 0000000..06fe307
--- /dev/null
+++ b/rimage/keys/Makefile.am
@@ -0,0 +1,9 @@
+install-data-local:
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(PEM_KEY_PREFIX);
+ $(INSTALL_DATA) otc_private_key.pem $(PEM_KEY_PREFIX)
+ $(INSTALL_DATA) otc_public_key.pem $(PEM_KEY_PREFIX)
+
+EXTRA_DIST = \
+ otc_private_key.pem \
+ otc_public_key.pem
\ No newline at end of file
diff --git a/rimage/keys/README b/rimage/keys/README
new file mode 100644
index 0000000..3ece70c
--- /dev/null
+++ b/rimage/keys/README
@@ -0,0 +1,34 @@
+About
+=====
+
+Firmware binary signing is for audio DSP is mandatory on Intel products from
+Skylake onwards. i.e. no code signing on Baytrail, Cherrytrail, Braswell,
+Haswell and Broadwell but mandatory on Skylake, Kabylake, Apollolake and
+Cannonlake.
+
+rimage can now sign firmware binaries for Apollolake and Cannonlake targets.
+This is done automatically as part of the "make bin" part of the build.
+
+
+Key Pairs
+=========
+
+The key included here is the Intel OTC (Opensource Technology Center) community
+development key. It can be freely used by anyone and is intended for reference
+board makers and firmware developers.
+
+** This key is NOT intended for locking down firmware on end user production
+devices since the "private" key has been published here. A new key pair must
+be genrated for securing firmware ! **
+
+RSA Private and Public keys are generated as follows :-
+
+openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
+openssl rsa -pubout -in private_key.pem -out public_key.pem
+
+The public key needs to be programmed into the OEM Key manifest (cavsManifest0)
+within the BIOS in order to verify code signed with the private key.
+Intel supplies tools to board makers to stitch the public key into the BIOS.
+
+The private key is used by rimage to sign the SOF binary. It should be kept
+secret and secure for production signing.
\ No newline at end of file
diff --git a/rimage/keys/otc_private_key.pem b/rimage/keys/otc_private_key.pem
new file mode 100644
index 0000000..03ad749
--- /dev/null
+++ b/rimage/keys/otc_private_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC5Q68ZJyiWWrXb
+TSjlj4I/UmgusmIfv5+MCtinahekLPasIvoBhmEAr/TBizlfhj2/VN4FKNsqy7HR
+QGn+iLhqnVrzpEVug4EQIpkFxTnycKMQPSDvpIqq8VL9pUCvKokSMub0oTCwoxjJ
+V81wJy+NE2AnamjtnuJEXqim9U5CGjsnVNSktv/YPbso/LYFjH658Fz5QGgWfbgi
+BPNFwMvemSFOIXw2J2B91ayP9ZJeI2tLyEP9EMeQqU3Gd8T5LfHIUmibpPFe1JDM
+s4HmIEs7Iay03EfwjEWLVd0P/fxv9I9YNTZAi+7o8IyrTNRHDsH55efW7V58GwfS
+66po4QCFAgMBAAECggEBALf7IlktTR47iRv2/WUz5hnyQWoWVmHHD6+oWc2wCzhM
+Os9pkLOQ+qYPF1ZZZ6mYi5uFsVKYZ0aRsM3oVRqkNdgS2m7YtObyC2q1oRdc7JX6
+C8Wlnx69XcQzEcK4qIsMB8Gd8UQBC3RvE79nxanaEFveYP/jqb5IqdVR19SuCYCU
+EZurwwAnYeLg0VSSdVQHSGVMlHkDwhgVAvp5NryPXhml51pT0gzUwnvJOsUcrc0m
+tqUa2yu7/Qju1/JtFL98RgW4x3mSo4TZO3B/d664pWPOxL72zCt7bD9s06ILZmga
+z1oMLMwTaNaeYIBaRvjmssKOqLXmDvfc415V82SwMYUCgYEA2p2At6acrD8Xx5GO
+GeCeUbZzm0Ke9zql1W+Diq89UroFX/i9XO9Mb/ZfwouC+5n3iLjyCG7jIaIwYAyV
+2qim9sINeieepM54HqYz0235nX5CqLHPDobYLn5tsbNYvXYBWiyjRppG+cnprMBk
+O6vLNXNc4sRemgbcmwT3sEYLLo8CgYEA2PInWZx0JoEXriEgefv/IZeyCjpaS9uH
+OOaPVAJTJPaaZhazA4ANV2bzrQAigiXbOgzPkXyldy7T7d/gHfVYnHbyhGwMEa6u
+WMnj5qFXPI0hYOOrJbqXofbfGkKC996eoQybnvE0WdIwscySIki1zAenE/5nVdCJ
+HLwK9xXMKasCgYA/ZxSQrsqbjgTYhVdgG+vuqOqoac7uxtyXpSrSSvaPCpJKfjp1
+PJW/lwW4x3tqewH2biUL2xUWiRJcmOnRK76YrDj6Z4k0JQljYjJ/rFKLobW1dTQm
+82a5PUOVGP2wnQvRWkbUUCQrh6q0xmuLfsyFqPqUbf090KWkc/Fd90KA8wKBgG6C
+q9jSAbi7ebyR02FQJJ6QD3l2UBjkMvWhPNGmfYQOuofWeEoIKMOlBevSbcGuVwYz
+EGkj/YXArOQ3borUN9c8ID2kbGF1ggpojVcmSLHnkmEwmDYX3rX6c5uE1gI9vMB9
+E6jbZbd7gqKPesFMGI9eNpXQugLUv4OLpmpHCEERAoGAMF5P9jSe3JirlZ7WaH7A
+I1I23L3oZfkmrcxP7B860k1ZLHDtx/MtWLkb609fq1Q2lqRuvdoaur1kW+Rv9IHS
+Db8cznu9jIz3OzmJ735lHDpomylzt0+nxL5rrUnoTyMsDK0kIWs03JhPYc0+S2Ip
+lkkvYQHB1eUUCxMnTgzWRr4=
+-----END PRIVATE KEY-----
diff --git a/rimage/keys/otc_public_key.pem b/rimage/keys/otc_public_key.pem
new file mode 100644
index 0000000..b8662bd
--- /dev/null
+++ b/rimage/keys/otc_public_key.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuUOvGScollq1200o5Y+C
+P1JoLrJiH7+fjArYp2oXpCz2rCL6AYZhAK/0wYs5X4Y9v1TeBSjbKsux0UBp/oi4
+ap1a86RFboOBECKZBcU58nCjED0g76SKqvFS/aVAryqJEjLm9KEwsKMYyVfNcCcv
+jRNgJ2po7Z7iRF6opvVOQho7J1TUpLb/2D27KPy2BYx+ufBc+UBoFn24IgTzRcDL
+3pkhTiF8NidgfdWsj/WSXiNrS8hD/RDHkKlNxnfE+S3xyFJom6TxXtSQzLOB5iBL
+OyGstNxH8IxFi1XdD/38b/SPWDU2QIvu6PCMq0zURw7B+eXn1u1efBsH0uuqaOEA
+hQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/rmbox/Makefile.am b/rmbox/Makefile.am
new file mode 100644
index 0000000..bfeb184
--- /dev/null
+++ b/rmbox/Makefile.am
@@ -0,0 +1,4 @@
+bin_PROGRAMS = rmbox
+
+rmbox_SOURCES = \
+ rmbox.c
\ No newline at end of file
diff --git a/rmbox/rmbox.c b/rmbox/rmbox.c
new file mode 100644
index 0000000..913249b
--- /dev/null
+++ b/rmbox/rmbox.c
@@ -0,0 +1,422 @@
+/*
+ * mbox dump to debug log convertor.
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#define KNRM "\x1B[0m"
+#define KRED "\x1B[31m"
+
+// TODO: include all this stuff
+
+#define TRACE_CLASS_IRQ (1 << 24)
+#define TRACE_CLASS_IPC (2 << 24)
+#define TRACE_CLASS_PIPE (3 << 24)
+#define TRACE_CLASS_HOST (4 << 24)
+#define TRACE_CLASS_DAI (5 << 24)
+#define TRACE_CLASS_DMA (6 << 24)
+#define TRACE_CLASS_SSP (7 << 24)
+#define TRACE_CLASS_COMP (8 << 24)
+#define TRACE_CLASS_WAIT (9 << 24)
+#define TRACE_CLASS_LOCK (10 << 24)
+#define TRACE_CLASS_MEM (11 << 24)
+#define TRACE_CLASS_MIXER (12 << 24)
+#define TRACE_CLASS_BUFFER (13 << 24)
+#define TRACE_CLASS_VOLUME (14 << 24)
+#define TRACE_CLASS_SWITCH (15 << 24)
+#define TRACE_CLASS_MUX (16 << 24)
+#define TRACE_CLASS_SRC (17 << 24)
+#define TRACE_CLASS_TONE (18 << 24)
+#define TRACE_CLASS_EQ_FIR (19 << 24)
+#define TRACE_CLASS_EQ_IIR (20 << 24)
+#define TRACE_CLASS_SA (21 << 24)
+#define TRACE_CLASS_DMIC (22 << 24)
+#define TRACE_CLASS_POWER (23 << 24)
+
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+
+#define TRACE_BLOCK_SIZE 8
+
+static inline char get_char(uint32_t val, int idx)
+{
+ char c = (val >> (idx * 8)) & 0xff;
+ if (c < '0' || c > 'z')
+ return '.';
+ else
+ return c;
+}
+
+static void usage(char *name)
+{
+ fprintf(stdout, "Usage %s <option(s)> <file(s)>\n", name);
+ fprintf(stdout, "%s:\t \t\t\tDisplay mailbox contents\n", name);
+ fprintf(stdout, "%s:\t -i infile -o outfile\tDump infile contents to outfile\n", name);
+ fprintf(stdout, "%s:\t -c\t\t\tSet timestamp clock in MHz\n", name);
+ fprintf(stdout, "%s:\t -s\t\t\tTake a snapshot of state\n", name);
+ fprintf(stdout, "%s:\t -t\t\t\tDisplay trace data\n", name);
+ exit(0);
+}
+
+static double to_usecs(uint64_t time, double clk)
+{
+ /* trace timestamp uses CPU system clock at default 25MHz ticks */
+ // TODO: support variable clock rates
+ return (double)time / clk;
+}
+
+static void show_trace(uint64_t val, uint64_t addr, uint64_t *timestamp, double clk)
+{
+ const char *trace;
+ uint32_t class;
+ uint64_t delta = val - *timestamp;
+ double fdelta = to_usecs(delta, clk);
+ double us = 0.0f;
+
+ /* timestamp or value ? */
+ if ((addr % (TRACE_BLOCK_SIZE * 2)) == 0) {
+
+ delta = val - *timestamp;
+ fdelta = to_usecs(delta, clk);
+
+ /* 64-bit timestamp */
+ us = to_usecs(val, clk);
+
+ /* empty data ? */
+ if (val == 0) {
+ *timestamp = 0;
+ return;
+ }
+
+ /* detect wrap around */
+ if (fdelta < 1000.0 * 1000.0 * 1000.0)
+ printf("0x%lx [%6.6f]\tdelta [%6.6f]\t", addr,
+ us / 1000000.0 , fdelta / 1000000.0);
+ else
+ printf("0x%lx [%6.6f]\tdelta [********]\t", addr,
+ us / 1000000.0);
+
+ *timestamp = val;
+ return;
+ } else if (*timestamp == 0)
+ return;
+
+ /* check for printable values - otherwise it's a value */
+ if (!isprint((char)(val >> 16)) || !isprint((char)(val >> 8)) || !isprint((char)val)) {
+ printf("value 0x%16.16lx\n", val);
+ return;
+ }
+
+ class = val & 0xff000000;
+ if (class == TRACE_CLASS_IRQ)
+ trace = "irq";
+ else if (class == TRACE_CLASS_IPC)
+ trace = "ipc";
+ else if (class == TRACE_CLASS_PIPE)
+ trace = "pipe";
+ else if (class == TRACE_CLASS_HOST)
+ trace = "host";
+ else if (class == TRACE_CLASS_DAI)
+ trace = "dai";
+ else if (class == TRACE_CLASS_DMA)
+ trace = "dma";
+ else if (class == TRACE_CLASS_SSP)
+ trace = "ssp";
+ else if (class == TRACE_CLASS_COMP)
+ trace = "comp";
+ else if (class == TRACE_CLASS_WAIT)
+ trace = "wait";
+ else if (class == TRACE_CLASS_LOCK)
+ trace = "lock";
+ else if (class == TRACE_CLASS_MEM)
+ trace = "mem";
+ else if (class == TRACE_CLASS_MIXER)
+ trace = "mixer";
+ else if (class == TRACE_CLASS_BUFFER)
+ trace = "buffer";
+ else if (class == TRACE_CLASS_VOLUME)
+ trace = "volume";
+ else if (class == TRACE_CLASS_SWITCH)
+ trace = "switch";
+ else if (class == TRACE_CLASS_MUX)
+ trace = "mux";
+ else if (class == TRACE_CLASS_SRC)
+ trace = "src";
+ else if (class == TRACE_CLASS_TONE)
+ trace = "tone";
+ else if (class == TRACE_CLASS_EQ_FIR)
+ trace = "eq-fir";
+ else if (class == TRACE_CLASS_EQ_IIR)
+ trace = "eq-iir";
+ else if (class == TRACE_CLASS_SA)
+ trace = "sa";
+ else if (class == TRACE_CLASS_DMIC)
+ trace = "dmic";
+ else if (class == TRACE_CLASS_POWER)
+ trace = "pm";
+ else {
+ printf("value 0x%8.8x\n", (uint32_t)val);
+ return;
+ }
+
+ switch ((char)(val >> 16)) {
+ case 'e':
+ case 'E':
+ case 'x':
+ case 'X':
+ printf("%s%s %c%c%c%s\n", KRED, trace,
+ (char)(val >> 16), (char)(val >> 8), (char)val, KNRM);
+ break;
+ default:
+ printf("%s %c%c%c\n", trace,
+ (char)(val >> 16), (char)(val >> 8), (char)val);
+ break;
+ }
+}
+
+static int trace_read(const char *in_file, const char *out_file, double clk)
+{
+ int count, i;
+ FILE *in_fd = NULL, *out_fd = NULL;
+ char c, tmp[TRACE_BLOCK_SIZE] = {0};
+ uint64_t addr = 0, val, timestamp = 0;
+
+ in_fd = fopen(in_file, "r");
+ if (in_fd == NULL) {
+ fprintf(stderr, "error: unable to open %s for reading %d\n",
+ in_file, errno);
+ return -EIO;
+ }
+
+ if (out_file == NULL)
+ goto trace;
+
+ out_fd = fopen(out_file, "w");
+ if (out_fd == NULL) {
+ fprintf(stderr, "error: unable to open %s for writing %d\n",
+ out_file, errno);
+ }
+
+trace:
+ fprintf(stdout, "using %2.2fMHz timestamp clock\n", clk);
+
+ while (1) {
+ count = fread(&tmp[0], 1, TRACE_BLOCK_SIZE, in_fd);
+ if (count != TRACE_BLOCK_SIZE)
+ break;
+
+ val = *((uint64_t*)tmp);
+
+ for (i = 0; i < TRACE_BLOCK_SIZE / 2; i++) {
+ c = tmp[i];
+ tmp[i] = tmp[TRACE_BLOCK_SIZE - i - 1];
+ tmp[TRACE_BLOCK_SIZE - i - 1] = c;
+ }
+
+ show_trace(val, addr, ×tamp, clk);
+
+ if (out_fd) {
+ count = fwrite(&tmp[0], 1, TRACE_BLOCK_SIZE, out_fd);
+ if (count != TRACE_BLOCK_SIZE)
+ break;
+ }
+
+ addr += TRACE_BLOCK_SIZE;
+ }
+
+ fclose(in_fd);
+ if (out_fd)
+ fclose(out_fd);
+
+ return 0;
+}
+
+static void show_data(uint32_t val, uint32_t addr)
+{
+ printf("data: 0x%x = \t0x%8.8x \t(%8.8d) \t|%c%c%c%c|\n",
+ (unsigned int)addr,
+ val, val,
+ get_char(val, 3), get_char(val, 2),
+ get_char(val, 1), get_char(val, 0));
+}
+
+
+static const char *debugfs[] = {
+ "dmac0", "dmac1", "ssp0", "ssp1",
+ "ssp2", "iram", "dram", "shim",
+ "mbox", "etrace",
+};
+
+static int snapshot(const char *name)
+{
+ const char *path = "/sys/kernel/debug/sof";
+ uint32_t val, addr;
+ char pinname[64], poutname[64], buffer[128];
+ FILE *in_fd, *out_fd;
+ int i, count;
+
+ if (name == NULL) {
+ fprintf(stderr, "error: need snapshot name\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(debugfs); i++) {
+
+ sprintf(pinname, "%s/%s", path, debugfs[i]);
+ sprintf(poutname, "%s.%s.txt", name, debugfs[i]);
+
+ /* open debugfs for reading */
+ in_fd = fopen(pinname, "r");
+ if (in_fd == NULL) {
+ fprintf(stderr, "error: unable to open %s for reading %d\n",
+ pinname, errno);
+ continue;
+ }
+
+ /* open outfile for reading */
+ out_fd = fopen(poutname, "w");
+ if (out_fd == NULL) {
+ fprintf(stderr, "error: unable to open %s for writing %d\n",
+ poutname, errno);
+ fclose(in_fd);
+ continue;
+ }
+
+ fprintf(stdout, "processing %s...\n", pinname);
+ addr = 0;
+
+ while (1) {
+ count = fread(&val, 1, 4, in_fd);
+ if (count != 4)
+ break;
+
+ sprintf(buffer, "0x%6.6x: 0x%8.8x\n", addr, val);
+
+ count = fwrite(buffer, 1, strlen(buffer), out_fd);
+
+ addr += 4;
+ }
+
+ fclose(in_fd);
+ fclose(out_fd);
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int opt, count, trace = 0;
+ const char * out_file = NULL, *in_file = NULL;
+ FILE *in_fd = NULL, *out_fd = NULL;
+ char c, tmp[8] = {0};
+ uint64_t addr = 0, val, timestamp = 0, align = 4, i;
+ double clk = 19.2;
+
+ while ((opt = getopt(argc, argv, "ho:i:s:m:c:t")) != -1) {
+ switch (opt) {
+ case 'o':
+ out_file = optarg;
+ break;
+ case 'i':
+ in_file = optarg;
+ break;
+ case 't':
+ trace = 1;
+ break;
+ case 'c':
+ clk = atof(optarg);
+ break;
+ case 's':
+ return snapshot(optarg);
+ case 'h':
+ default: /* '?' */
+ usage(argv[0]);
+ }
+ }
+
+ /* trace requested ? */
+ if (trace)
+ return trace_read("/sys/kernel/debug/sof/trace",
+ out_file, clk);
+
+ /* default option with no infile is to dump errors/debug data */
+ if (in_file == NULL) {
+ fprintf(stdout, "\nError log:\n");
+ return trace_read("/sys/kernel/debug/sof/etrace",
+ out_file, clk);
+ }
+
+ /* open infile for reading */
+ in_fd = fopen(in_file, "r");
+ if (in_fd == NULL) {
+ fprintf(stderr, "error: unable to open %s for reading %d\n",
+ in_file, errno);
+ return -EIO;
+ }
+
+ /* open outfile for writing */
+ if (out_file == NULL)
+ goto convert;
+
+ out_fd = fopen(out_file, "w");
+ if (out_fd == NULL) {
+ fprintf(stderr, "error: unable to open %s for writing %d\n",
+ out_file, errno);
+ fclose(in_fd);
+ return -EIO;
+ }
+
+ /* start to converting mailbox */
+convert:
+ fprintf(stdout, "using %2.2fMHz timestamp clock\n", clk);
+
+ while (1) {
+ count = fread(&tmp[0], 1, align, in_fd);
+ if (count != align)
+ break;
+
+ val = *((uint64_t*)tmp);
+
+ for (i = 0; i < align / 2; i++) {
+ c = tmp[i];
+ tmp[i] = tmp[align - i - 1];
+ tmp[align - i - 1] = c;
+ }
+
+ show_data(val, addr);
+
+ if (out_fd) {
+ count = fwrite(&tmp[0], 1, align, out_fd);
+ if (count != align)
+ break;
+ }
+
+ addr += align;
+ }
+
+ /* close files */
+ fclose(in_fd);
+ if (out_fd)
+ fclose(out_fd);
+
+ return 0;
+}
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..488005a
--- /dev/null
+++ b/test/README
@@ -0,0 +1,64 @@
+SOF Audio Processing Components Tests
+=====================================
+
+This is a set of test scripts to test that performance requirements
+are met. The tests are currently for measured audio objective quality
+parameters. The used criteria for performance is only an initial
+assumption and need to be adjusted for various applications needs.
+
+The scripts support currently support the next list of objective
+quality parameters. The test scripts need Matlab(R) [2] or GNU Octave
+scientific programming language [3].
+
+ - Gain
+ - Frequency Response
+ - THD+N vs. Frequency
+ - Dynamic Range
+ - Attenuation of Alias Products
+ - Attenuation of Image Products
+
+Note: The metric is an effort to follow AES17 [1] recommendation for
+parameters and test procedures. This was created to help developers to
+quickly check their work but has not been verified to be
+compliant. Professional equipment and formal calibration process is
+recommended for professional applications where both accurate absolute
+and relative metric is needed.
+
+Note: The test bench uses by default raw binary data files. It is
+possible to convert with SoX (v14.4.1) [4] the raw data to e.g. wav
+format for other audio tools and subjective listening.
+
+$ sox -b 32 -c 2 -r 48000 -L -e signed-integer fr_test_out.raw fr_test_out.wav
+
+For debugging purposes it is possible to switch from test scripts the
+test vectors format to txt for easy manual data creation and
+inspection.
+
+
+Tests for component SRC
+-----------------------
+
+The top level shell script to launch tests is src_test.sh. See script
+src_run.sh for assumed install location of SOF host test bench
+executable and component libraries. Exit code 0 indicates success and
+exit code 1 indicates failed test cases.
+
+The default in/out rates matrix to test is defined in the beginning of
+script src_test.m. The matrix can be also passed from calling function
+src_test_top.m if need.
+
+The key objective quality parameters requiremements are in the
+beginning of script src_test.m as well under comment Generic test
+pass/fail criteria.
+
+Test run creates plots into directory "plots". Brief text format
+reports are placed to directory "reports".
+
+
+References
+----------
+
+[1] AES17-1015 standard, http://www.aes.org/publications/standards/search.cfm?docID=21
+[2] Matlab(R), https://www.mathworks.com/products/matlab.html
+[3] GNU Octave, https://www.gnu.org/software/octave/
+[4] SoX - Sound eXchange, http://sox.sourceforge.net/
diff --git a/test/src_run.sh b/test/src_run.sh
new file mode 100755
index 0000000..670dc44
--- /dev/null
+++ b/test/src_run.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+# SRC specifics
+COMP=src
+BITS_IN=$1
+BITS_OUT=$2
+FS1=$3
+FS2=$4
+FN_IN=$5
+FN_OUT=$6
+
+# The HOST_ROOT path need to be retrived from SOFT .configure command
+HOST_ROOT=../../host-root
+HOST_EXE=$HOST_ROOT/bin/testbench
+HOST_LIB=$HOST_ROOT/lib
+
+# Topology
+INFMT=s${BITS_IN}le
+OUTFMT=s${BITS_IN}le
+MCLK=24576k
+TPLG=../topology/test/test-playback-ssp2-mclk-0-I2S-${COMP}-${INFMT}-${OUTFMT}-48k-${MCLK}-nocodec.tplg
+
+# If binary test vectors
+if [ ${FN_IN: -4} == ".raw" ]; then
+ CMDFMT="-b S${BITS_IN}_LE"
+else
+ CMDFMT=""
+fi
+
+# Run command
+CMD0=$HOST_EXE
+CMD1="-d -r $FS1 -R $FS2 -i $FN_IN -o $FN_OUT -t $TPLG -a src=libsof_${COMP}.so $CMDFMT"
+CMD="$CMD0 $CMD1"
+export LD_LIBRARY_PATH=$HOST_LIB
+
+# Run test bench
+echo "Command: $CMD0"
+echo "Arg: $CMD1"
+$CMD
diff --git a/test/src_test.m b/test/src_test.m
new file mode 100644
index 0000000..bad2206
--- /dev/null
+++ b/test/src_test.m
@@ -0,0 +1,609 @@
+function [n_fail, n_pass, n_na] = src_test(bits_in, bits_out, fs_in_list, fs_out_list)
+
+%%
+% src_test - test with SRC test bench objective audio quality parameters
+%
+% src_test(bits_in, bits_out, fs_in, fs_out)
+%
+% bits_in - input word length
+% bits_out - output word length
+% fs_in - vector of rates in
+% fs_out - vector of rates out
+%
+% A default in-out matrix with 32 bits data is tested if the
+% paremeters are omitted.
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+addpath('std_utils');
+addpath('test_utils');
+addpath('../tune/src');
+mkdir_check('plots');
+mkdir_check('reports');
+
+%% Defaults for call parameters
+if nargin < 1
+ bits_in = 32;
+end
+if nargin < 2
+ bits_out = 32;
+end
+if nargin < 3
+ fs_in_list = [8e3 11025 12e3 16e3 18900 22050 24e3 32e3 44100 48e3 ...
+ 64e3 88.2e3 96e3 176400 192e3];
+end
+if nargin < 4
+ fs_out_list = [8e3 11025 12e3 16e3 18900 22050 24e3 32e3 44100 48e3];
+end
+
+%% Generic test pass/fail criteria
+% Note that AAP and AIP are relaxed a bit from THD+N due to inclusion
+% of point Fs/2 to test. The stopband of kaiser FIR is not equiripple
+% and there's sufficient amount of attnuation at higher frequencies to
+% meet THD+N requirement.
+t.g_db_tol = 0.1;
+t.thdnf_db_max = -80;
+t.dr_db_min = 100;
+t.aap_db_max = -60;
+t.aip_db_max = -60;
+
+%% Defaults for test
+t.fmt = 'raw'; % Can be 'raw' (fast binary) or 'txt' (debug)
+t.nch = 2; % Number of channels
+t.ch = 0; % 1..nch. With value 0 test a randomly selected channel.
+t.bits_in = bits_in; % Input word length
+t.bits_out = bits_out; % Output word length
+t.full_test = 1; % 0 is quick check only, 1 is full set
+
+%% Show graphics or not. With visible plot windows Octave may freeze if too
+% many windows are kept open. As workaround setting close windows to
+% 1 shows only flashing windows while the test proceeds. With
+% visibility set to to 0 only console text is seen. The plots are
+% exported into plots directory in png format and can be viewed from
+% there.
+t.close_plot_windows = 0; % Workaround for visible windows if Octave hangs
+t.visible = 'off'; % Use off for batch tests and on for interactive
+t.delete = 1; % Set to 0 to inspect the audio data files
+
+%% Init for test loop
+n_test = 7; % We have next seven test cases for SRC
+n_fsi = length(fs_in_list);
+n_fso = length(fs_out_list);
+r.fs_in_list = fs_in_list;
+r.fs_out_list = fs_out_list;
+r.g = NaN(n_fsi, n_fso);
+r.dr = NaN(n_fsi, n_fso);
+r.fr_db = NaN(n_fsi, n_fso);
+r.fr_hz = NaN(n_fsi, n_fso, 2);
+r.fr3db_hz = NaN(n_fsi, n_fso);
+r.thdnf = NaN(n_fsi, n_fso);
+r.aap = NaN(n_fsi, n_fso);
+r.aip = NaN(n_fsi, n_fso);
+r.pf = NaN(n_fsi, n_fso, n_test);
+r.n_fail = 0;
+r.n_pass = 0;
+r.n_skipped = 0;
+r.n_na = 0;
+%% Loop all modes to test
+for b = 1:n_fso
+ for a = 1:n_fsi
+ v = -ones(n_test,1); % Set pass/fail test verdict to not executed
+ tn = 1;
+ t.fs1 = fs_in_list(a);
+ t.fs2 = fs_out_list(b);
+ v(1) = chirp_test(t);
+ if v(1) ~= -1 && t.full_test == 1
+ %% Chirp was processed so this in/out Fs is supported
+ [v(2), r.g(a,b)] = g_test(t);
+ [v(3), r.fr_db(a,b), r.fr_hz(a,b,:), r.fr3db_hz(a,b)] = fr_test(t);
+ [v(4), r.thdnf(a,b)] = thdnf_test(t);
+ [v(5), r.dr(a,b)] = dr_test(t);
+ [v(6), r.aap(a,b)] = aap_test(t);
+ [v(7), r.aip(a,b)] = aip_test(t);
+ end
+ %% Done, store pass/fail
+ r.pf(a, b, :) = v;
+ if v(1) ~= -1
+ idx = find(v > 0);
+ r.n_fail = r.n_fail + length(idx);
+ idx = find(v == 0);
+ r.n_pass = r.n_pass + length(idx);
+ idx = find(v == -1);
+ r.n_skipped = r.n_skipped + length(idx);
+ idx = find(v == -2);
+ r.n_na = r.n_na + length(idx);
+ end
+ end
+end
+
+%% Print table with test summary: Gain
+fn = 'reports/g_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.g, r.pf, 'Gain dB');
+
+%% Print table with test summary: FR
+fn = 'reports/fr_src.txt';
+print_fr(fn, fs_in_list, fs_out_list, r.fr_db, r.fr_hz, r.pf);
+
+%% Print table with test summary: FR
+fn = 'reports/fr_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.fr3db_hz/1e3, r.pf, ...
+ 'Frequency response -3 dB 0 - X kHz');
+
+%% Print table with test summary: THD+N vs. frequency
+fn = 'reports/thdnf_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.thdnf, r.pf, ...
+ 'Worst-case THD+N vs. frequency');
+
+%% Print table with test summary: DR
+fn = 'reports/dr_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.dr, r.pf, ...
+ 'Dynamic range dB (CCIR-RMS)');
+
+%% Print table with test summary: AAP
+fn = 'reports/aap_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.aap, r.pf, ...
+ 'Attenuation of alias products dB');
+
+%% Print table with test summary: AIP
+fn = 'reports/aip_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.aip, r.pf, ...
+ 'Attenuation of image products dB');
+
+
+%% Print table with test summary: pass/fail
+fn = 'reports/pf_src.txt';
+print_pf(fn, fs_in_list, fs_out_list, r.pf);
+
+fprintf('\n');
+fprintf('Number of passed tests = %d\n', r.n_pass);
+fprintf('Number of failed tests = %d\n', r.n_fail);
+fprintf('Number of non-applicable tests = %d\n', r.n_na);
+fprintf('Number of skipped tests = %d\n', r.n_skipped);
+
+
+if r.n_fail > 0 || r.n_pass < 1
+ fprintf('\nERROR: TEST FAILED!!!\n');
+else
+ fprintf('\nTest passed.\n');
+end
+
+n_fail = r.n_fail;
+n_pass = r.n_pass;
+n_na = r.n_na;
+
+end
+
+
+%%
+%% Test execution with help of common functions
+%%
+
+function [fail, g_db] = g_test(t)
+
+%% Reference: AES17 6.2.2 Gain
+test = test_defaults_src(t);
+prm = src_param(t.fs1, t.fs2, test.coef_bits);
+test.fu = prm.c_pb*min(t.fs1,t.fs2);
+test.g_db_tol = t.g_db_tol;
+test.g_db_expect = 0;
+
+%% Create input file
+test = g_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test = g_test_measure(test);
+
+%% Get output parameters
+fail = test.fail;
+g_db = test.g_db;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+end
+
+function [fail, pm_range_db, range_hz, fr3db_hz] = fr_test(t)
+
+%% Reference: AES17 6.2.3 Frequency response
+test = test_defaults_src(t);
+prm = src_param(t.fs1, t.fs2, test.coef_bits);
+
+test.rp_max = prm.rp_tot; % Max. ripple +/- dB allowed
+test.f_lo = 20; % For response reporting, measure from 20 Hz
+test.f_hi = min(t.fs1,t.fs2)*prm.c_pb; % to designed filter upper frequency
+test.f_max = min(t.fs1/2, t.fs2/2); % Measure up to Nyquist frequency
+
+%% Create input file
+test = fr_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test = fr_test_measure(test);
+
+fail = test.fail;
+pm_range_db = test.rp;
+range_hz = [test.f_lo test.f_hi];
+fr3db_hz = test.fr3db_hz;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+%% Print
+src_test_result_print(t, 'Frequency response', 'FR', test.ph);
+
+end
+
+function [fail, thdnf] = thdnf_test(t)
+
+%% Reference: AES17 6.3.2 THD+N ratio vs. frequency
+test = test_defaults_src(t);
+
+prm = src_param(t.fs1, t.fs2, test.coef_bits);
+test.f_start = 20;
+test.f_end = prm.c_pb*min(t.fs1, t.fs2);
+test.fu = prm.c_pb*min(t.fs1, t.fs2);
+%test.f_end = 0.4535*min(t.fs1, t.fs2);
+%test.fu = 0.4535*min(t.fs1, t.fs2);
+
+%% Create input file
+test = thdnf_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test.thdnf_max = t.thdnf_db_max;
+test = thdnf_test_measure(test);
+thdnf = max(max(test.thdnf));
+fail = test.fail;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+%% Print
+src_test_result_print(t, 'THD+N ratio vs. frequency', 'THDNF');
+
+end
+
+function [fail, dr_db] = dr_test(t)
+
+%% Reference: AES17 6.4.1 Dynamic range
+test = test_defaults_src(t);
+test.dr_db_min = t.dr_db_min;
+
+%% Create input file
+test = dr_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test = dr_test_measure(test);
+
+%% Get output parameters
+fail = test.fail;
+dr_db = test.dr_db;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+end
+
+
+function [fail, aap_db] = aap_test(t)
+
+%% Reference: AES17 6.6.6 Attenuation of alias products
+test = test_defaults_src(t);
+test.aap_max = t.aap_db_max;
+
+if t.fs1 <= t.fs2
+ %% Internal rate must be lower than input
+ fail = -2;
+ aap_db = NaN;
+ return;
+end
+
+test.f_start = 0.5*t.fs1;
+test.f_end = 0.5*t.fs2;
+
+%% Create input file
+test = aap_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test = aap_test_measure(test);
+aap_db = test.aap;
+fail = test.fail;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+%% Print
+src_test_result_print(t, 'Attenuation of alias products', 'AAP');
+
+end
+
+function [fail, aip_db] = aip_test(t)
+
+%% Reference: AES17 6.6.7 Attenuation of image products
+test = test_defaults_src(t);
+test.aip_max = t.aip_db_max;
+if t.fs1 >= t.fs2
+ %% Internal rate must be higher than input
+ fail = -2;
+ aip_db = NaN;
+ return;
+%%
+end
+
+%% Create input file
+test.f_end = t.fs1/2;
+test = aip_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test = aip_test_measure(test);
+aip_db = test.aip;
+fail = test.fail;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+%% Print
+src_test_result_print(t, 'Attenuation of image products', 'AIP');
+
+end
+
+%% Chirp spectrogram test. This is a visual check only. Aliasing is visible
+% in the plot as additional freqiencies than main linear up sweep. The aliasing
+% can be a line, few lines, or lattice pattern depending the SRC conversion
+% to test. The main sweep line should be steady level and extend from near
+% zero freqeuncy to near Nyquist (Fs/2).
+
+function fail = chirp_test(t)
+
+fprintf('Spectrogram test %d -> %d ...\n', t.fs1, t.fs2);
+
+%% Create input file
+test = test_defaults_src(t);
+test = chirp_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Analyze
+test.fs = t.fs2;
+test = chirp_test_analyze(test);
+src_test_result_print(t, 'Chirp', 'chirpf');
+
+% Delete files unless e.g. debugging and need data to run
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+fail = test.fail;
+end
+
+
+%% Some SRC test specific utility functions
+%%
+
+function test = test_defaults_src(t)
+test.fmt = t.fmt;
+test.bits_in = t.bits_in;
+test.bits_out = t.bits_out;
+test.nch = t.nch;
+test.ch = t.ch;
+test.fs = t.fs1;
+test.fs1 = t.fs1;
+test.fs2 = t.fs2;
+test.mask_f = [];
+test.mask_lo = [];
+test.mask_hi = [];
+test.coef_bits = 24; % No need to use actual word length in test
+test.visible = t.visible;
+end
+
+function test = test_run_src(test, t)
+test.ex = './src_run.sh';
+test.arg = { num2str(t.bits_in), num2str(t.bits_out), num2str(t.fs1), num2str(t.fs2), test.fn_in, test.fn_out};
+delete_check(1, test.fn_out);
+test = test_run(test);
+end
+
+function src_test_result_print(t, testverbose, testacronym, ph)
+tstr = sprintf('%s SRC %d, %d', testverbose, t.fs1, t.fs2);
+if nargin > 3
+ title(ph, tstr);
+else
+ title(tstr);
+end
+pfn = sprintf('plots/%s_src_%d_%d.png', testacronym, t.fs1, t.fs2);
+% The print command caused a strange error with __osmesa_print__
+% so disable it for now until solved.
+%print(pfn, '-dpng');
+if t.close_plot_windows
+ close all;
+end
+end
+
+%% The next are results printing functions
+
+function print_val(fn, fs_in_list, fs_out_list, val, pf, valstr)
+n_fsi = length(fs_in_list);
+n_fso = length(fs_out_list);
+fh = fopen(fn,'w');
+fprintf(fh,'\n');
+fprintf(fh,'SRC test result: %s\n', valstr);
+fprintf(fh,'%8s, ', 'in \ out');
+for a = 1:n_fso-1
+ fprintf(fh,'%8.1f, ', fs_out_list(a)/1e3);
+end
+fprintf(fh,'%8.1f', fs_out_list(n_fso)/1e3);
+fprintf(fh,'\n');
+for a = 1:n_fsi
+ fprintf(fh,'%8.1f, ', fs_in_list(a)/1e3);
+ for b = 1:n_fso
+ if pf(a,b,1) < 0
+ cstr = 'x';
+ else
+ if isnan(val(a,b))
+ cstr = '-';
+ else
+ cstr = sprintf('%8.2f', val(a,b));
+ end
+ end
+ if b < n_fso
+ fprintf(fh,'%8s, ', cstr);
+ else
+ fprintf(fh,'%8s', cstr);
+ end
+ end
+ fprintf(fh,'\n');
+end
+fclose(fh);
+type(fn);
+end
+
+function print_fr(fn, fs_in_list, fs_out_list, fr_db, fr_hz, pf)
+n_fsi = length(fs_in_list);
+n_fso = length(fs_out_list);
+fh = fopen(fn,'w');
+fprintf(fh,'\n');
+fprintf(fh,'SRC test result: Frequency response +/- X.XX dB (YY.Y kHz) \n');
+fprintf(fh,'%8s, ', 'in \ out');
+for a = 1:n_fso-1
+ fprintf(fh,'%12.1f, ', fs_out_list(a)/1e3);
+end
+fprintf(fh,'%12.1f', fs_out_list(n_fso)/1e3);
+fprintf(fh,'\n');
+for a = 1:n_fsi
+ fprintf(fh,'%8.1f, ', fs_in_list(a)/1e3);
+ for b = 1:n_fso
+ if pf(a,b,1) < 0
+ cstr = 'x';
+ else
+ cstr = sprintf('%4.2f (%4.1f)', fr_db(a,b), fr_hz(a,b,2)/1e3);
+ end
+ if b < n_fso
+ fprintf(fh,'%12s, ', cstr);
+ else
+ fprintf(fh,'%12s', cstr);
+ end
+ end
+ fprintf(fh,'\n');
+end
+fclose(fh);
+type(fn);
+end
+
+function print_fr3db(fn, fs_in_list, fs_out_list, fr3db_hz, pf)
+n_fsi = length(fs_in_list);
+n_fso = length(fs_out_list);
+fh = fopen(fn,'w');
+fprintf(fh,'\n');
+fprintf(fh,'SRC test result: Frequency response -3dB 0 - X.XX kHz\n');
+fprintf(fh,'%8s, ', 'in \ out');
+for a = 1:n_fso-1
+ fprintf(fh,'%8.1f, ', fs_out_list(a)/1e3);
+end
+fprintf(fh,'%8.1f', fs_out_list(n_fso)/1e3);
+fprintf(fh,'\n');
+for a = 1:n_fsi
+ fprintf(fh,'%8.1f, ', fs_in_list(a)/1e3);
+ for b = 1:n_fso
+ if pf(a,b,1) < 0
+ cstr = 'x';
+ else
+ cstr = sprintf('%4.1f', fr3db_hz(a,b)/1e3);
+ end
+ if b < n_fso
+ fprintf(fh,'%8s, ', cstr);
+ else
+ fprintf(fh,'%8s', cstr);
+ end
+ end
+ fprintf(fh,'\n');
+end
+fclose(fh);
+type(fn);
+end
+
+
+function print_pf(fn, fs_in_list, fs_out_list, pf)
+n_fsi = length(fs_in_list);
+n_fso = length(fs_out_list);
+fh = fopen(fn,'w');
+fprintf(fh,'\n');
+fprintf(fh,'SRC test result: Fails\n');
+fprintf(fh,'%8s, ', 'in \ out');
+for a = 1:n_fso-1
+ fprintf(fh,'%14.1f, ', fs_out_list(a)/1e3);
+end
+fprintf(fh,'%14.1f', fs_out_list(n_fso)/1e3);
+fprintf(fh,'\n');
+spf = size(pf);
+npf = spf(3);
+for a = 1:n_fsi
+ fprintf(fh,'%8.1f, ', fs_in_list(a)/1e3);
+ for b = 1:n_fso
+ if pf(a,b,1) < 0
+ cstr = 'x';
+ else
+ cstr = sprintf('%d', pf(a,b,1));
+ for n=2:npf
+ if pf(a,b,n) < 0
+ cstr = sprintf('%s/x', cstr);
+ else
+ cstr = sprintf('%s/%d', cstr,pf(a,b,n));
+ end
+ end
+ end
+ if b < n_fso
+ fprintf(fh,'%14s, ', cstr);
+ else
+ fprintf(fh,'%14s', cstr);
+ end
+ end
+ fprintf(fh,'\n');
+end
+fclose(fh);
+type(fn);
+end
diff --git a/test/src_test.sh b/test/src_test.sh
new file mode 100755
index 0000000..84e88c9
--- /dev/null
+++ b/test/src_test.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# Copyright (c) 2017, Intel Corporation
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the Intel Corporation nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+#
+
+octave --no-gui src_test_top.m
+if [ $? -eq 0 ]; then
+ echo "Test passed."
+ exit 0
+else
+ echo "Test failed." >&2
+ exit 1
+fi
diff --git a/test/src_test_top.m b/test/src_test_top.m
new file mode 100644
index 0000000..a0bf826
--- /dev/null
+++ b/test/src_test_top.m
@@ -0,0 +1,42 @@
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+[n_fail, n_pass] = src_test(24, 24);
+if n_fail > 0 || n_pass < 1
+ fprintf('Error: SRC test with 24 bits data failed.\n');
+ quit(1)
+end
+[n_fail, n_pass] = src_test(32, 32);
+if n_fail > 0 || n_pass < 1
+ fprintf('Error: SRC test with 32 bits data failed.\n');
+ quit(1)
+end
+
+fprintf('Success: SRC test with 24 and 32 bits data passed.\n');
diff --git a/test/std_utils/aap_test_input.m b/test/std_utils/aap_test_input.m
new file mode 100644
index 0000000..0a969c6
--- /dev/null
+++ b/test/std_utils/aap_test_input.m
@@ -0,0 +1,103 @@
+function test = aap_test_input(test)
+
+%% t = aap_test_input(t)
+%
+% Create frequency sweep data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.f_start - start frequency
+% t.f_end - end frequency
+% t.fs - sample rate
+% t.bits_in - number of bits in signal
+% t.ch - mix test signal to channel ch
+% t.nch - total number of channels in data
+%
+% Output parameters
+% t.fn_in - created input file name
+% t.fn_out - proposed output file name for captured output
+% t.f - frequencies in sweep
+% t.nf - number of frequencies
+% t.tl - tone length in seconds
+% t.ts - tone start times
+% t.tr - tone gain ramp length in seconds
+% t.ti - ignore time from tone start and end, must be ti > tr
+% t.a - tone amplitude (lin)
+% t.a_db - tone amplitude (dB)
+% t.mark_t - length of marker tone in seconds
+% t.mark_a - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.6.6 Attenuation of alias products
+% http://www.aes.org/publications/standards/
+
+if nargin < 1
+ error('This function must be called with argunment.');
+end
+
+if test.ch == 0
+ test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fstart=%d Hz, Fend=%d Hz, Fs=%.1f kHz, bits_in=%d, ch=%d, nch=%d\n', ...
+ test.f_start, test.f_end, test.fs, test.bits_in, test.ch, test.nch);
+
+
+test.fn_in = sprintf('aap_test_in.%s', test.fmt);
+test.fn_out = sprintf('aap_test_out.%s', test.fmt);
+f_first = 997;
+f_max = max(test.f_start, test.f_end);
+f_min = min(test.f_start, test.f_end);
+n_third = ceil(log(f_max/f_min)/log(2)*3); % max 1/3 octave step
+steps = max(n_third, 50); % Min 50 steps
+test.f = [f_first logspace(log10(test.f_start), log10(test.f_end), steps) ];
+
+%% Tone sweep parameters
+test.is = 20e-3; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.3; % Error if marker positions delta is greater than 0.3s
+test.tc = 20; % Min. 20 cycles of sine wave for a frequency
+t_min = 0.2;
+test.a_db = -20;
+test.a = 10^(test.a_db/20);
+% Use t_min or min cycles count as tone length
+test.tl = max(test.tc*1/min(test.f),t_min);
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/aap_test_measure.m b/test/std_utils/aap_test_measure.m
new file mode 100644
index 0000000..a61dadf
--- /dev/null
+++ b/test/std_utils/aap_test_measure.m
@@ -0,0 +1,77 @@
+function test = aap_test_measure(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.6.6 Attenuation of alias products
+% http://www.aes.org/publications/standards/
+
+%% Load output file
+[x, nx] = load_test_output(test);
+if nx == 0
+ test.fail = 1;
+ return
+end
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(x, test);
+
+%% Measure
+win = hamming(nt_use);
+m0 = zeros(test.nf,1);
+for n=1:test.nf
+ fprintf('Measuring %.0f Hz ...\n', test.f(n));
+ i1 = d+(n-1)*nt+nt_skip;
+ i2 = i1+nt_use-1;
+ m0(n) = level_dbfs(x(i1:i2).*win);
+end
+
+%% Calculate levels relative to first 997 Hz frequency,
+% remove it from result, sort to ascinding order for plot
+m_ref = m0(1);
+test.m = m0(2:end)-m0(1);
+[test.f, idx] = sort(test.f(2:end));
+test.m = test.m(idx);
+test.aap = max(test.m); % Worst-case
+
+if test.aap > test.aap_max
+ test.fail = 1;
+else
+ test.fail = 0;
+end
+
+test.fh = figure('visible', test.visible);
+semilogx(test.f, test.m);
+grid on;
+xlabel('Frequency (Hz)');
+ylabel('Relative level (dB)');
+grid on;
+
+end
diff --git a/test/std_utils/aip_test_input.m b/test/std_utils/aip_test_input.m
new file mode 100644
index 0000000..a946c96
--- /dev/null
+++ b/test/std_utils/aip_test_input.m
@@ -0,0 +1,101 @@
+function test = aip_test_input(test)
+
+%% t = aap_test_input(t)
+%
+% Create frequency sweep data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.f_start - start frequency
+% t.f_end - end frequency
+% t.fs - sample rate
+% t.bits_in - number of bits in signal
+% t.ch - mix test signal to channel ch
+% t.nch - total number of channels in data
+%
+% Output parameters
+% t.fn_in - created input file name
+% t.fn_out - proposed output file name for captured output
+% t.f - frequencies in sweep
+% t.nf - number of frequencies
+% t.tl - tone length in seconds
+% t.ts - tone start times
+% t.tr - tone gain ramp length in seconds
+% t.ti - ignore time from tone start and end, must be ti > tr
+% t.a - tone amplitude (lin)
+% t.a_db - tone amplitude (dB)
+% t.mark_t - length of marker tone in seconds
+% t.mark_a - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.6.7 Attenuation of image products
+% http://www.aes.org/publications/standards/
+
+if nargin < 1
+ error('This function must be called with argument.');
+end
+
+if test.ch == 0
+ test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fend=%d Hz, Fs=%.1f kHz, bits_in=%d, ch=%d, nch=%d\n', ...
+ test.f_end, test.fs, test.bits_in, test.ch, test.nch);
+
+test.fn_in = sprintf('aip_test_in.%s', test.fmt);
+test.fn_out = sprintf('aip_test_out.%s', test.fmt);
+f_first = 997;
+test.f_start = 20;
+f_min = min(test.f_start, test.f_end);
+f_max = max(test.f_start, test.f_end);
+test.fu = f_max;
+n_thirdoct = ceil(log(f_max/f_min)/log(2)*3); % max 1/3 octave step
+steps = n_thirdoct;
+test.f = [f_first logspace(log10(test.f_start), log10(test.f_end), steps) ];
+
+%% Tone sweep parameters
+test.is = 20e-3; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.1; % Error if marker positions delta is greater than 0.1s
+test.tl = 3;
+test.a_db = -20;
+test.a = 10^(test.a_db/20);
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/aip_test_measure.m b/test/std_utils/aip_test_measure.m
new file mode 100644
index 0000000..56aee93
--- /dev/null
+++ b/test/std_utils/aip_test_measure.m
@@ -0,0 +1,84 @@
+function test = aip_test_measure(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.6.7 Attenuation of image products
+% http://www.aes.org/publications/standards/
+
+%% Load output file
+[x, nx] = load_test_output(test);
+if nx == 0
+ test.g_db = NaN;
+ test.fail = 1;
+ return
+end
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(x, test);
+
+%% Measure all test frequencies
+t_skip = 1.0;
+ml = zeros(test.nf,1);
+mn = zeros(test.nf,1);
+b_lpf = stdlpf_get(test.fu, test.fs); % Get LPF coef
+b_hpf = stdhpf_get(test.fu, test.fs); % Get HPF coef
+for n=1:test.nf
+ fprintf('Measuring %.0f Hz ...\n', test.f(n));
+ % Get notch coef for this frequency
+ [b_notch, a_notch] = stdnotch_get(test.f(n), test.fs);
+ i1 = d+(n-1)*nt+nt_skip;
+ i2 = i1+nt_use-1;
+ x_lpf = filter(b_lpf, 1, x(i1:i2)); % Standard LPF, need for 997 Hz only
+ x_notch = filter(b_notch, a_notch, x(i1:i2)); % Standard notch
+ x_hpf = filter(b_hpf, 1, x_notch); % Standard HPF
+ ml(n) = level_dbfs(x_lpf(round(t_skip*test.fs):end));
+ mn(n) = level_dbfs(x_hpf(round(t_skip*test.fs):end));
+end
+
+%% Calculate levels relative to first 997 Hz frequency,
+% remove it from result, sort to ascinding order for plot
+test.f = test.f(2:end);
+test.m = mn(2:end)-ml(1);
+test.aip = max(test.m); % Worst-case
+if test.aip > test.aip_max
+ test.fail = 1;
+else
+ test.fail = 0;
+end
+
+test.fh = figure('visible', test.visible);
+semilogx(test.f, test.m);
+grid on;
+xlabel('Frequency (Hz)');
+ylabel('Relative level (dB)');
+grid on;
+
+end
diff --git a/test/std_utils/dr_test_input.m b/test/std_utils/dr_test_input.m
new file mode 100644
index 0000000..396d7d0
--- /dev/null
+++ b/test/std_utils/dr_test_input.m
@@ -0,0 +1,91 @@
+function test = dr_test_input(test)
+
+%% t = dr_test_input(t)
+%
+% Create tone data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.fs - sample rate
+% t.bits_in - signal word length
+% t.ch - mix test signal to channel ch
+% t.nch - total number of channels in data
+%
+% Output parameters
+% t.fn_in - created input file name
+% t.fn_out - proposed output file name for captured output
+% t.f - test signal frequency
+% t.tl - tone length in seconds
+% t.ts - tone start time
+% t.tr - tone gain ramp length in seconds
+% t.ti - ignore time from tone start and end, must be ti > tr
+% t.a - tone amplitude (lin)
+% t.a_db - tone amplitude (dB)
+% t.mark_t - length of marker tone in seconds
+% t.mark_a - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.2.3 Frequency response
+
+if nargin < 1
+ fprintf('Warning, using default parameters!\n');
+ test.fs = 48e3; test.bits_in=32; test.ch=1; test.nch=1;
+end
+
+if test.ch == 0
+ test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fs=%.1f, bits=%d, ch=%d, Nch=%d\n', ...
+ test.fs/1e3, test.bits_in, test.ch, test.nch );
+
+%% Test tone parameters
+test.fn_in = sprintf('dr_test_in.%s', test.fmt);
+test.fn_out = sprintf('dr_test_out.%s', test.fmt);
+test.f = 997;
+test.a_db = -60;
+test.a = 10^(test.a_db/20);
+test.is = 1.0; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.3; % Error if marker positions delta is greater than 0.3s
+test.tc = 25; % Min. 20 cycles of sine wave for a frequency
+test.tl = 3; % 3 seconds tone
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/dr_test_measure.m b/test/std_utils/dr_test_measure.m
new file mode 100644
index 0000000..6e8634f
--- /dev/null
+++ b/test/std_utils/dr_test_measure.m
@@ -0,0 +1,76 @@
+function test = dr_test_measure(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Load output file
+[x, nx] = load_test_output(test);
+if nx == 0
+ test.dr_db = NaN;
+ test.fail = 1;
+ return
+end
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(x, test);
+
+%% Notch filter
+y0n = stdnotch(x, test.f, test.fs);
+
+%% CCIR-RMS weighting filter
+y0w = stdweight(y0n, test.fs);
+
+%% Trim sample by removing first 1s to let the notch to apply
+i1 = d+nt_skip;
+i2 = i1+nt_use-1;
+y = x(i1:i2);
+y_n = y0w(i1:i2);
+
+%% Gain, SNR
+level_in = test.a_db;
+level_out = level_dbfs(y);
+level_final = level_dbfs(y_n);
+test.dr_db = level_out-level_final-test.a_db;
+fprintf('DR = %5.1f dB\n', test.dr_db);
+if 0
+ plot(y);
+ hold on
+ plot(y_n,'g');
+ hold off
+end
+
+%% Check pass/fail
+test.fail = 0;
+if test.dr_db < test.dr_db_min
+ fprintf('Failed DR %f dB (min %f dB)\n', test.dr_db, test.dr_db_min);
+ test.fail = 1;
+end
+
+end
diff --git a/test/std_utils/fr_test_input.m b/test/std_utils/fr_test_input.m
new file mode 100644
index 0000000..5471bf7
--- /dev/null
+++ b/test/std_utils/fr_test_input.m
@@ -0,0 +1,123 @@
+function test = fr_test_input(test)
+
+%% t = fr_test_input(t)
+%
+% Create frequency sweep data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.f_max - maximum frequency of sweep, set e.g. to 0.99*fs/2
+% t.fs - sample rate
+% t.bits_in - number of bits in signal
+% t.ch - mix test signal to channel ch, e.g. set to [1 2] to measure
+% two channels
+% t.nch - total number of channels in data
+%
+% Output parameters
+% t.fn_in - Created input file name
+% t.fn_out - Proposed output file name for captured output
+% t.f_ref - Reference frequency used to report deviation (997 Hz)
+% t.f_min - Sweep start frequency
+% t.f - Frequencies in sweep
+% t.is - Ignore signal from tone start
+% t.ie - Ignore signal from tone end
+% t.tr - tone gain ramp length in seconds
+% t.sm - Seek start marker this time length from start
+% t.em - Seek end marker this time length from end
+% t.mt - Error if marker positions delta is greater than this
+% t.tc - Min cycles of sine wave per frequency
+% t.tl - Tone length in seconds
+% t.a_db - Tone amplitude (dB)
+% t.a - Tone amplitude (lin)
+% t.nt - Number of samples per tone
+% t.nf - Number of frequencies
+% t.na - Number of amplitudes
+% t.mark_t - Length of marker tone in seconds
+% t.mark_a - Amplitude max of marker tone (lin)
+% t.mark_a_db - Amplitude max of marker tone (dB)
+% t.ts - Tone start times
+%
+% E.g.
+% t.fs=48e3; t.f_max=20e3; t.bits_in=16; t.ch=1; t.nch=2; t = fr_test_input(t);
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.2.3 Frequency response
+% http://www.aes.org/publications/standards/
+
+if nargin < 1
+ fprintf('Warning, using default parameters!\n');
+ test.fs = 48e3; test.f_max = 0.99*test.fs/2; test.ch=1; test.nch=1;
+ test.bits_in=32;
+end
+
+if test.ch == 0
+ test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fmax=%.1f kHz, Fs=%.1f, ch=%d, Nch=%d, bits_in=%d\n', ...
+ test.f_max/1e3, test.fs/1e3, test.ch, test.nch, test.bits_in);
+
+test.fn_in = sprintf('fr_test_in.%s', test.fmt);
+test.fn_out = sprintf('fr_test_out.%s', test.fmt);
+test.f_ref = 997;
+test.f_min = 20;
+
+%% Use a dense frequency grid to see -3 dB point well
+n_oct = ceil(log(test.f_max/test.f_ref)/log(2)*35);
+f = logspace(log10(test.f_ref), log10(test.f_max), n_oct);
+c = f(1)/f(2);
+f_next = test.f_ref*c;
+while (f_next > test.f_min)
+ f = [f_next f];
+ f_next = f_next*c;
+end
+test.f = f;
+
+%% Tone sweep parameters
+test.is = 20e-3; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.1; % Error if marker positions delta is greater than 0.1s
+test.tc = 10; % Min. 10 cycles of sine wave for a frequency
+t_min = 0.2;
+% Use t_min or min cycles count as tone length
+test.tl = max(test.tc*1/min(f),t_min);
+test.a_db = -20;
+test.a = 10.^(test.a_db/20);
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/fr_test_measure.m b/test/std_utils/fr_test_measure.m
new file mode 100644
index 0000000..e7156fe
--- /dev/null
+++ b/test/std_utils/fr_test_measure.m
@@ -0,0 +1,173 @@
+function test = fr_test_measure(test)
+
+%% t = fr_test_measure(t)
+%
+% Measure frequency response from captured frequency sweep created by
+% fr_test_input() that sets most of the input struct fiels. The output
+% is read from file t.fn_out.
+%
+% Input parameters
+% t.f_lo - Measure ripple start frequency
+% t.f_hi - Measure ripple end frequency
+% t.rp_max - Max. ripple +/- dB
+% t.mask_f - Frequencies for mask
+% t.mask_lo - Upper limits of mask
+% t.mask_hi - Lower limits of mask
+%
+% Output parameters
+% t.m - Measured frequency response
+% t.rp - Measured ripple +/- dB
+% t.fr3db_hz - Bandwidth in Hz for -3 dB attenuated response
+% t.fail - Returns zero for passed
+% t.fh - Figure handle
+% t.ph - Plot handle
+%
+% E.g.
+% t.fs=48e3; t.f_max=20e3; t.bits_out=16; t.ch=1; t.nch=2; t=fr_test_input(t);
+% t.fn_out=t.fn_in; t.f_lo=20; t.f_hi=20e3; t.rp_max=[]; t.mask_f=[];
+% t=fr_test_measure(t);
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.2.3 Frequency response
+% http://www.aes.org/publications/standards/
+
+[x, nx] = load_test_output(test);
+
+j = 1;
+for channel = test.ch
+
+ if nx == 0
+ test.rp(j) = NaN;
+ test.fr3db_hz(j) = NaN;
+ test.fail = 1;
+ return
+ end
+
+ %% Find sync
+ [d, nt, nt_use, nt_skip] = find_test_signal(x(:,j), test);
+
+ win = hamming(nt_use);
+ m0 = zeros(test.nf,1);
+ for n=1:test.nf
+ fprintf('Measuring %.0f Hz ...\n', test.f(n));
+ i1 = d+(n-1)*nt+nt_skip;
+ i2 = i1+nt_use-1;
+ m0(n) = level_dbfs(x(i1:i2,j).*win) -test.a_db;
+ end
+
+ %% Scale 997 Hz point as 0 dB
+ df = test.f - test.f_ref;
+ [~,i997] = min(abs(df));
+ m_offs = m0(i997);
+ test.m(:,j) = m0 - m_offs;
+
+ %% Check pass/fail
+ idx0 = find(test.f < test.f_hi);
+ idx1 = find(test.f(idx0) > test.f_lo);
+ range_db = max(test.m(idx1,j))-min(test.m(idx1,j));
+ test.rp(j) = range_db/2;
+ test.fail = 0;
+ if ~isempty(test.rp_max)
+ if test.rp > test.rp_max
+ fprintf('Failed response +/- %f dBpp (max +/- %f dB)\n', ...
+ test.rp, test.rp_max);
+ test.fail = 1;
+ end
+ end
+
+ %% Find frequency response 3 dB 0-X Hz
+ idx3 = find(test.m(:,j) > -3);
+ test.fr3db_hz(j) = test.f(idx3(end));
+
+ %% Interpolate mask in logaritmic frequencies, check
+ if ~isempty(test.mask_f)
+ f_log = log(test.f);
+ mask_hi = interp1(log(test.mask_f), test.mask_hi(:,j), ...
+ f_log, 'linear');
+ mask_lo = interp1(log(test.mask_f), test.mask_lo(:,j), ...
+ f_log, 'linear');
+ over_mask = test.m(:,j)-mask_hi';
+ under_mask = mask_lo'-test.m(:,j);
+ idx = find(isnan(over_mask) == 0);
+ [m_over_mask, io] = max(over_mask(idx));
+ idx = find(isnan(under_mask) == 0);
+ [m_under_mask, iu] = max(under_mask(idx));
+ if m_over_mask > 0
+ fprintf('Failed upper response mask around %.0f Hz\n', ...
+ test.f(io));
+ test.fail = 1;
+ end
+ if m_under_mask > 0
+ fprintf('Failed lower response mask around %.0f Hz\n', ...
+ test.f(iu));
+ test.fail = 1;
+ end
+ end
+
+ test.fh(j) = figure('visible', test.visible);
+ subplot(1,1,1);
+ test.ph(j) = subplot(1,1,1);
+ %semilogx(test.f, test.m(:,j));
+ plot(test.f, test.m(:,j));
+ grid on;
+ xlabel('Frequency (Hz)');
+ ylabel('Magnitude (dB)');
+ if length(test.mask_f) > 0
+ hold on;
+ plot(test.f, mask_hi, 'r--');
+ plot(test.f, mask_lo, 'r--');
+ hold off;
+ end
+ ax = axis();
+ axis([ax(1:2) -4 1]);
+ if max(max(test.m(idx1,j))-min(test.m(idx1,j))) < 1
+ axes('Position', [ 0.2 0.2 0.4 0.2]);
+ box on;
+ plot(test.f(idx1), test.m(idx1,j));
+ if ~isempty(test.rp_max)
+ hold on;
+ plot([test.f_lo test.f_hi], ...
+ [-test.rp_max/2 -test.rp_max/2], 'r--');
+ plot([test.f_lo test.f_hi], ...
+ [ test.rp_max/2 test.rp_max/2], 'r--');
+ hold off;
+ end
+ grid on;
+ axis([0 test.f_hi -0.1 0.1]);
+ end
+
+ %% Next channel to measure
+ j=j+1;
+end
+
+end
diff --git a/test/std_utils/g_test_input.m b/test/std_utils/g_test_input.m
new file mode 100644
index 0000000..bc0e19b
--- /dev/null
+++ b/test/std_utils/g_test_input.m
@@ -0,0 +1,97 @@
+function test = g_test_input(test)
+
+%% t = dr_test_input(t)
+%
+% Create tone data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.fs - sample rate
+% t.bits_in - signal word length
+% t.ch - mix test signal to channel ch
+% t.nch - total number of channels in data
+%
+% Output parameters
+% t.fn_in - created input file name
+% t.fn_out - proposed output file name for captured output
+% t.f - test signal frequency
+% t.tl - tone length in seconds
+% t.ts - tone start time
+% t.tr - tone gain ramp length in seconds
+% t.ti - ignore time from tone start and end, must be ti > tr
+% t.a - tone amplitude (lin)
+% t.a_db - tone amplitude (dB)
+% t.mark_t - length of marker tone in seconds
+% t.mark_a - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.2.2 Gain
+% http://www.aes.org/publications/standards/
+
+
+if nargin < 1
+ fprintf('Warning, using default parameters!\n');
+ test.fs = 48e3; test.bits=32; test.ch=1; test.nch=1;
+end
+
+if test.ch == 0
+ test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fs=%.1f, bits_in=%d', test.fs/1e3, test.bits_in);
+fprintf(', ch=%d', test.ch );
+fprintf(', Nch=%d\n', test.nch );
+
+test.fn_in = sprintf('g_test_in.%s', test.fmt);
+test.fn_out = sprintf('g_test_out.%s', test.fmt);
+test.f = 997;
+
+
+%% Tone sweep parameters
+test.is = 20e-3; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.3; % Error if marker positions delta is greater than 0.3s
+test.tc = 25; % Min. 20 cycles of sine wave for a frequency
+test.a_db = -20; % -20 dBFS level
+test.a = 10^(test.a_db/20);
+% 0.5 seconds tone, this will be adjusted to be integer number of samples
+test.tl = 0.5;
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/g_test_measure.m b/test/std_utils/g_test_measure.m
new file mode 100644
index 0000000..40c9871
--- /dev/null
+++ b/test/std_utils/g_test_measure.m
@@ -0,0 +1,70 @@
+function test = g_test_measure(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.2.2 Gain
+% http://www.aes.org/publications/standards/
+
+%% Load output file
+[x, nx] = load_test_output(test);
+
+if nx == 0
+ test.g_db = NaN;
+ test.fail = 1;
+ return
+end
+
+%% Standard low-pass
+y0 = stdlpf(x, test.fu, test.fs);
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(y0, test);
+
+%% Trim sample by removing first 1s to let the notch to apply
+i1 = d+nt_skip;
+i2 = i1+nt_use-1;
+y = y0(i1:i2);
+
+%% Gain, SNR
+level_in = test.a_db;
+level_out = level_dbfs(y);
+test.g_db = level_out-level_in;
+fprintf('Gain = %6.3f dB (expecting %6.3f dB)\n', test.g_db, test.g_db_expect);
+
+%% Check pass/fail
+test.fail = 0;
+if abs(test.g_db_expect-test.g_db) > test.g_db_tol
+ fprintf('Failed gain %f dB (max %f dB)\n', test.g_db, test.g_db_tol);
+ test.fail = 1;
+end
+
+end
+
diff --git a/test/std_utils/level_dbfs.m b/test/std_utils/level_dbfs.m
new file mode 100644
index 0000000..73cdded
--- /dev/null
+++ b/test/std_utils/level_dbfs.m
@@ -0,0 +1,46 @@
+function dbfs = level_dbfs(x)
+
+%% dbfs = level_dbfs(x)
+%
+% Input
+% x - signal
+%
+% Output
+% dbfs - sigmal level in dBFS
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference AES 17 3.12.3
+level_ms = mean(x.^2);
+dbfs = 10*log10(level_ms) + 20*log10(sqrt(2));
+
+end
diff --git a/test/std_utils/stdhpf.m b/test/std_utils/stdhpf.m
new file mode 100644
index 0000000..bf855a0
--- /dev/null
+++ b/test/std_utils/stdhpf.m
@@ -0,0 +1,54 @@
+function y = stdhpf(x, fu, fs)
+
+%% y = stdhpf(x, fu, fs)
+%
+% Standard high-pass filter
+%
+% Input
+% x - input signal
+% fu - upper band-edge frequency
+% fs - sample rate
+%
+% Output
+% y - filtered signal
+%
+% Reference AES17 5.2.6
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Design filter
+b = stdhpf_get(fu, fs);
+
+%% Filter
+y = filter(b, 1, x);
+
+
+end
diff --git a/test/std_utils/stdhpf_get.m b/test/std_utils/stdhpf_get.m
new file mode 100644
index 0000000..367a39b
--- /dev/null
+++ b/test/std_utils/stdhpf_get.m
@@ -0,0 +1,68 @@
+function b = stdhpf_get(fu, fs)
+
+%% y = stdhpf(x, fu, fs)
+%
+% Standard high-pass filter
+%
+% Input
+% x - input signal
+% fu - upper band-edge frequency
+% fs - sample rate
+%
+% Output
+% y - filtered signal
+%
+% Reference AES17 5.2.6
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Design filter
+rp = 0.5;
+rs = -50; % Some margin vs. requirement
+a = [0 1];
+fc = min(1.3*fu, 0.99*fs/2);
+f = [fu fc];
+dev = [ 10^(rs/20) (10^(rp/20)-1)/(10^(rp/20)+1) ];
+[n, wn, beta, ftype] = kaiserord(f, a, dev, fs);
+b = fir1(n, wn, ftype, kaiser(n+1,beta));
+
+if 0
+ f = linspace(0, fs/2, 1000);
+ h = freqz(b,1, f, fs);
+ figure
+ plot(f, 20*log10(abs(h)))
+ hold on;
+ plot( [0 fu], [-40 -40], 'r', [fc fs/2], [-0.5 -0.5], 'r', [fc fs/2], [0.5 0.5], 'r');
+ hold off;
+ grid on;
+end
+
+end
diff --git a/test/std_utils/stdlpf.m b/test/std_utils/stdlpf.m
new file mode 100644
index 0000000..56fdc5a
--- /dev/null
+++ b/test/std_utils/stdlpf.m
@@ -0,0 +1,54 @@
+function y = stdlpf(x, fu, fs)
+
+%% y = stdhpf(x, fu, fs)
+%
+% Standard high-pass filter
+%
+% Input
+% x - input signal
+% fu - upper band-edge frequency
+% fs - sample rate
+%
+% Output
+% y - filtered signal
+%
+% Reference AES17 5.2.5
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Design filter
+b = stdlpf_get(fu, fs);
+
+%% Filter
+y = filter(b, 1, x);
+
+
+end
diff --git a/test/std_utils/stdlpf_get.m b/test/std_utils/stdlpf_get.m
new file mode 100644
index 0000000..ac344d1
--- /dev/null
+++ b/test/std_utils/stdlpf_get.m
@@ -0,0 +1,70 @@
+function b = stdlpf_get(fu, fs)
+
+%% b = stdlpf_get(fu, fs)
+%
+% Standard loww-pass filter
+%
+% Input
+% fu - upper band-edge frequency
+% fs - sample rate
+%
+% Output
+% b - coefficients for FIR filter
+%
+% Reference AES17 5.2.5
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Design filter
+rp = 0.001; % Since this may need to be in frequency response measurement the ripple must be very small
+rs = -65; % Some margin vs. requirement
+a = [1 0];
+% Note: The fc-fu for digital low-pass is not feasible. Use of fu*1.2 instead
+% results to example 24 kHz for 20 kHz upper band-edge. This could be a mistake
+% in specification.
+fc = min(fu*1.2, 0.99*fs/2);
+f = [fu fc];
+dev = [ (10^(rp/20)-1)/(10^(rp/20)+1) 10^(rs/20) ];
+[n, wn, beta, ftype] = kaiserord(f, a, dev, fs);
+b = fir1(n, wn, ftype, kaiser(n+1,beta));
+
+if 0
+ f = linspace(0, fs/2, 1000);
+ h = freqz(b,1, f, fs);
+ figure
+ plot(f, 20*log10(abs(h)))
+ hold on;
+ plot( [fc fs/2], [-60 -60], 'r', [0 fu], [-0.1 -0.1], 'r', [0 fu], [0.1 0.1], 'r');
+ hold off;
+ grid on;
+end
+
+end
diff --git a/test/std_utils/stdnotch.m b/test/std_utils/stdnotch.m
new file mode 100644
index 0000000..51d00d2
--- /dev/null
+++ b/test/std_utils/stdnotch.m
@@ -0,0 +1,47 @@
+function y = stdnotch(x, fn, fs)
+
+%% y = stdnotch(x, fn, fs)
+%
+% Input
+% x - input signal
+% fn - notch frequency
+% fs - sample rate
+%
+% Output
+% y - filtered signal
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+[b, a] = stdnotch_get(fn, fs);
+y = filter(b, a, x);
+
+end
diff --git a/test/std_utils/stdnotch_get.m b/test/std_utils/stdnotch_get.m
new file mode 100644
index 0000000..5213fa8
--- /dev/null
+++ b/test/std_utils/stdnotch_get.m
@@ -0,0 +1,70 @@
+function [b, a] = stdnotch_get(fn, fs)
+
+%% [b, a] = stdnotch_get(fn, fs)
+%
+% Input
+% fn - notch frequency
+% fs - sample rate
+%
+% Output
+% b - coefficients for filter zeros
+% a - coefficients for filter poles
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+target_q = 2.1;
+bw = (2*fn/fs)/target_q;
+if exist('iirnotch.m') == 2
+ [b, a] = iirnotch(2*fn/fs, bw);
+else
+ [b, a] = pei_tseng_notch(2*fn/fs, bw);
+end
+if 0
+ %% In AES17 5.2.8 standard notch must have Q 1.2-3.0
+ % Quality factor is ratio of of center frequency to
+ % differenence between -3 dB frequencies.
+ figure;
+ f = linspace(0.2*fn, min(2*fn,fs/2), 5000);
+ h = freqz(b, a, f, fs);
+ m = 20*log10(abs(h));
+ plot(f, m); grid on;
+ idx = find(m < -3);
+ f1 = f(idx(1));
+ f2 = f(idx(end));
+ q = fn/(f2-f1);
+ if (q < 1.2) || (q > 3.0)
+ fprintf('Required Q value failed, Q = %5.2f\n', q);
+ else
+ fprintf('Q = %5.2f\n', q);
+ end
+end
+end
diff --git a/test/std_utils/stdweight.m b/test/std_utils/stdweight.m
new file mode 100644
index 0000000..92e3a3c
--- /dev/null
+++ b/test/std_utils/stdweight.m
@@ -0,0 +1,86 @@
+function y = stdweight(x, fs)
+
+%% y = stdweight(x, fs)
+%
+% Input
+% x - input signal
+% fs - sample rate
+%
+% Output
+% y - filtered signal
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Frequency grid for FIR design
+f = linspace(0, fs/2, 6000);
+
+%% From https://en.wikipedia.org/wiki/ITU-R_468_noise_weighting
+h1 = -4.737338981378384e-24*f.^6 +2.043828333606125e-15*f.^4 -1.363894795463638e-7*f.^2 +1;
+h2 = 1.306612257412824e-19*f.^5 -2.118150887518656e-11*f.^3 +5.559488023498642e-4*f;
+RITU = 1.246332637532143e-4*f./sqrt(h1.^2+h2.^2);
+ITU = 18.2+20*log10(RITU)-5.63; % AES17 CCIR-RMS
+fc = [ 31.5 63 100 200 400 800 1000 2000 3150 4000 5000 6300 7100 8000 9000 10000 12500 14000 16000 20000 31500];
+ga = [-35.5 -29.5 -25.4 -19.4 -13.4 -7.5 -5.6 0 3.4 4.9 6.1 6.6 6.4 5.8 4.5 2.5 -5.6 -10.9 -17.3 -27.8 -48.3];
+tu = [ 2.0 1.4 1.0 0.85 0.70 0.55 0.50 0.50 0.50 0.50 0.50 0.01 0.20 0.40 0.60 0.80 1.2 1.4 1.6 2.0 2.8];
+tl = [ -2.0 -1.4 -1.0 -0.85 -0.70 -0.55 -0.50 -0.50 -0.50 -0.50 -0.50 -0.01 -0.20 -0.40 -0.60 -0.80 -1.2 -1.4 -1.6 -2.0 NaN];
+
+%% Fine tune the 6300Hz, 6.6 dB point
+if fs > 2*6300
+ idx = find(f > 6300, 1, 'first');
+ ITU = ITU + 6.6-ITU(idx);
+else
+ idx = find(f > 3150, 1, 'first');
+ ITU = ITU + 3.4-ITU(idx);
+end
+
+m_fir = 10.^(ITU/20);
+f_fir = 2*f/fs;
+n_fir = 4000; % Sufficient up to 192 kHz
+if (fs < 96001)
+ n_fir = 2000;
+end
+if (fs < 48001)
+ n_fir = 1000;
+end
+if (fs < 16001)
+ n_fir = 400;
+end
+bz = fir2(n_fir, f_fir, m_fir);
+y = filter(bz, 1, x);
+if 0
+ h = freqz(bz, 1, f, fs);
+ my_w_db = 20*log10(abs(h));
+ figure;
+ semilogx(f,ITU,fc,ga,'x',fc,ga+tu,fc,ga+tl, f, my_w_db );
+ grid on; xlabel('Hz'); ylabel('dB');
+end
+end
diff --git a/test/std_utils/thdnf_test_input.m b/test/std_utils/thdnf_test_input.m
new file mode 100644
index 0000000..b07f21f
--- /dev/null
+++ b/test/std_utils/thdnf_test_input.m
@@ -0,0 +1,95 @@
+function test = thdnf_test_input(test)
+
+%% t = dr_test_input(t)
+%
+% Create tone data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.fs - sample rate
+% t.bits_in - signal word length
+% t.ch - mix test signal to channel ch
+% t.nch - total number of channels in data
+%
+% Output parameters
+% t.fn_in - created input file name
+% t.fn_out - proposed output file name for captured output
+% t.f - test signal frequency
+% t.tl - tone length in seconds
+% t.ts - tone start time
+% t.tr - tone gain ramp length in seconds
+% t.ti - ignore time from tone start and end, must be ti > tr
+% t.a - tone amplitude (lin)
+% t.a_db - tone amplitude (dB)
+% t.mark_t - length of marker tone in seconds
+% t.mark_a - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.3.2 THD+N ratio vs frequency
+% http://www.aes.org/publications/standards/
+
+if nargin < 1
+ fprintf('Warning, using default parameters!\n');
+ test.fs = 48e3; test.f_start=20; test.f_end=20e3; test.bits_in=32; test.ch=1; test.nch=1;
+end
+
+if test.ch == 0
+ test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fstart=%.0f Hz, Fend=%.0f Hz, Fs=%.1f Hz, bits_in=%d, ch=%d, Nch=%d\n', ...
+ test.f_start, test.f_end, test.fs/1e3, test.bits_in, test.ch, test.nch );
+
+test.fn_in = sprintf('thdnf_test_in.%s', test.fmt);
+test.fn_out = sprintf('thdnf_test_out.%s', test.fmt);
+noct = ceil(log(test.f_end/test.f_start)/log(2)); % Max 1 octave steps
+test.f = logspace(log10(test.f_start),log10(test.f_end), noct);
+
+
+%% Tone sweep parameters
+test.is = 20e-3; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.1; % Error if marker positions delta is greater than 0.1s
+test.a_db = [-1 -20]; % -1 and -20 dBFS levels
+test.a = 10.^(test.a_db/20);
+test.tl = 4; % 3 seconds tone
+test.nst = 2; % Wait 1 seconds for frequency specific notch output to settle
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/thdnf_test_measure.m b/test/std_utils/thdnf_test_measure.m
new file mode 100644
index 0000000..6e10f17
--- /dev/null
+++ b/test/std_utils/thdnf_test_measure.m
@@ -0,0 +1,83 @@
+function test = thdnf_test_measure(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.3.2 THD+N ratio vs frequency
+% http://www.aes.org/publications/standards/
+
+%% Load output file
+[x, nx] = load_test_output(test);
+if nx == 0
+ test.g_db = NaN;
+ test.fail = 1;
+ return
+end
+
+%% Standard low-pass
+y0 = stdlpf(x, test.fu, test.fs);
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(y0, test);
+
+%% Measure all test frequencies
+ml = zeros(test.nf,test.na);
+mn = zeros(test.nf,test.na);
+n_notch_settle = round(test.fs*test.nst);
+nn = 1;
+for m=1:test.na
+ for n=1:test.nf
+ fprintf('Measuring %.0f Hz ...\n', test.f(n));
+ i1 = d+(nn-1)*nt+nt_skip;
+ i2 = i1+nt_use-1;
+ nn = nn+1;
+ y0n = stdnotch(y0(i1:i2), test.f(n), test.fs);
+ ml(n,m) = level_dbfs(y0(i1:i2));
+ mn(n,m) = level_dbfs(y0n(n_notch_settle:end));
+ end
+end
+
+test.thdnf = mn - ml;
+test.thdnf_high = test.thdnf(:,1);
+test.thdnf_low = test.thdnf(:,2);
+if max(max(test.thdnf)) > test.thdnf_max
+ test.fail = 1;
+else
+ test.fail = 0;
+end
+
+test.fh = figure('visible', test.visible);
+semilogx(test.f, test.thdnf(:,1), 'b', test.f, test.thdnf(:,2), 'g--');
+grid on;
+xlabel('Frequency (Hz)');
+ylabel('THD+N (dB)');
+legend('-1 dBFS','-20 dBFS');
+
+end
diff --git a/test/test_utils/chirp_test_analyze.m b/test/test_utils/chirp_test_analyze.m
new file mode 100644
index 0000000..e7026f6
--- /dev/null
+++ b/test/test_utils/chirp_test_analyze.m
@@ -0,0 +1,91 @@
+function test = chirp_test_analyze(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Load output file
+[x, nx] = load_test_output(test);
+if nx < 1
+ test.fail = -1; % No data
+ return;
+end
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(x(:,test.ch(1)), test);
+
+%% Trim sample
+i1 = d+nt_skip;
+i2 = i1+nt_use-1;
+z = x(i1:i2, :);
+y = z(:,test.ch);
+s = sum(z,2);
+
+%% Quick check length, RMS, offset, and channels sum
+sz = size(z);
+tz = sz(1)/test.fs;
+et = abs(test.cl-tz)/test.cl;
+rms_db = 10*log10(mean(z.^2)) + 20*log10(sqrt(2));
+offs_db = 20*log10(abs(mean(z)));
+sum_max_db = 20*log10(max(abs(s)));
+% Check for proper ratio of out/in samples, minimum level, maximum offset
+% and maximum of sum of channels. The input is such that the channels should
+% sum to zero. A phase difference in channels would cause non-zero output
+% for channels sum. Dithered input causes a small non-zero sum value.
+
+if et > 0.05
+ fail = 1;
+ fprintf('Failed output chirp length, err=%f, t=%f.\n', et, tz);
+else if (min(rms_db) < -3) && (test.fs2 + 1 > test.fs1)
+ fail = 1;
+ fprintf('Failed output chirp level.\n');
+ else if max(offs_db) > -40
+ fail = 1;
+ fprintf('Failed output chirp DC offset.\n');
+ else if (sum_max_db > -100) && (mod(test.nch, 2) == 0)
+ fail = 1;
+ fprintf('Failed output chirp channels phase.\n');
+ else
+ fail = 0;
+ end
+ end
+ end
+end
+
+test.fh = figure('visible', test.visible);
+ns = 1024;
+no = round(0.9*ns);
+specgram(y(:,1), ns, test.fs, kaiser(ns,27), no);
+colormap('jet');
+caxis([-150 0]);
+colorbar('EastOutside');
+
+test.fail = fail;
+
+end
diff --git a/test/test_utils/chirp_test_input.m b/test/test_utils/chirp_test_input.m
new file mode 100644
index 0000000..89b2861
--- /dev/null
+++ b/test/test_utils/chirp_test_input.m
@@ -0,0 +1,96 @@
+function test = chirp_test_input(test)
+
+%% t = dr_test_input(t)
+%
+% Create tone data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.fs - sample rate
+% t.bits_in - signal word length
+% t.ch - mix test signal to channel ch
+% t.nch - total number of channels in data
+%
+% Output parameters
+% t.fn_in - created input file name
+% t.fn_out - proposed output file name for captured output
+% t.f - test signal frequency
+% t.tl - tone length in seconds
+% t.ts - tone start time
+% t.tr - tone gain ramp length in seconds
+% t.ti - ignore time from tone start and end, must be ti > tr
+% t.a - tone amplitude (lin)
+% t.a_db - tone amplitude (dB)
+% t.mark_t - length of marker tone in seconds
+% t.mark_a - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 1
+ fprintf('Warning, using default parameters!\n');
+ test.fs = 48e3; test.bits=32; test.ch=1; test.nch=1;
+end
+
+if test.ch == 0
+ test.ch = 1:test.nch; % Test all channels 1..Nch
+end
+
+fprintf('Using parameters Fs=%.1f, bits_in=%d', test.fs/1e3, test.bits_in);
+fprintf(', ch=%d', test.ch );
+fprintf(', Nch=%d\n', test.nch );
+
+test.fn_in = sprintf('chirp_test_in.%s', test.fmt);
+test.fn_out = sprintf('chirp_test_out.%s', test.fmt);
+
+
+%% Chirp parameters
+test.a_db = -0.1; % Near full scale
+test.a = 10^(test.a_db/20);
+test.f_min = 20;
+test.f_max = 0.99*test.fs/2;
+test.cl = 2.0;
+
+
+%% Parameters to find signal between markers
+test.nf = 1;
+test.na = 1;
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.3; % Error if marker positions delta is greater than 0.3s
+test.is = 0; % Ignore signal from tone start
+test.ie = 0; % Ignore signal from tone end
+
+%% Mix the input file for test and write output
+test = mix_chirp(test);
+
+end
diff --git a/test/test_utils/delete_check.m b/test/test_utils/delete_check.m
new file mode 100644
index 0000000..b3e1c82
--- /dev/null
+++ b/test/test_utils/delete_check.m
@@ -0,0 +1,35 @@
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function delete_check(really, f)
+if really && exist(f) == 2
+ delete(f);
+end
+end
diff --git a/test/test_utils/dither_and_quantize.m b/test/test_utils/dither_and_quantize.m
new file mode 100644
index 0000000..56a2a58
--- /dev/null
+++ b/test/test_utils/dither_and_quantize.m
@@ -0,0 +1,61 @@
+%% xq = dither_and_quantize(x, bits)
+%
+% Input
+% x - input signal
+% bits - number of bits
+%
+% Output
+% (int32) xq - scaled, dithered and quantized signal
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function xq = dither_and_quantize(x, bits)
+
+if (bits > 32) || (bits < 1)
+ error('This function supports max 32 bits quantization!');
+end
+
+scale = 2^(bits-1);
+smax = scale-1;
+smin = -scale;
+sx = size(x);
+nx = sx(1);
+nch = sx(2);
+
+xq = int32(floor( scale*x + randn(nx,nch) - randn(nx,nch) -0.5)); % TPDF dither
+%xq = int32(round( scale*x )); % Omit dither
+idx = find(xq > smax);
+xq(idx) = smax;
+idx = find(xq < smin);
+xq(idx) = smin;
+
+end
diff --git a/test/test_utils/find_test_signal.m b/test/test_utils/find_test_signal.m
new file mode 100644
index 0000000..fee52d5
--- /dev/null
+++ b/test/test_utils/find_test_signal.m
@@ -0,0 +1,76 @@
+function [d, nt, nt_use, nt_skip] = find_test_signal(x, test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Find start marker
+fprintf('Finding test start marker...\n');
+s = sync_chirp(test.fs, 'up');
+nx = length(x);
+n_seek = round(test.fs*(test.idle_t + test.mark_t));
+n = min(round(test.fs*test.sm), n_seek);
+y = x(1:n);
+[r, lags] = xcorr(y, s);
+[r_max, idx] = max(r);
+d_start = lags(idx);
+
+%% Find end marker
+fprintf('Finding test end marker...\n');
+s = sync_chirp(test.fs, 'down');
+n_seek = round(test.fs*(2*test.idle_t + test.mark_t));
+n = min(round(test.fs*test.em),n_seek);
+y = x(end-n+1:end);
+[r, lags] = xcorr(y, s);
+[r_max, idx] = max(r);
+d_end = nx-n+lags(idx);
+
+%% Check correct length of signal
+len = d_end-d_start;
+len_s = len/test.fs;
+ref_s = test.mark_t+test.nf*test.na*test.tl;
+if abs(len_s-ref_s) > test.mt
+ len_s
+ ref_s
+ error('Start and end markers were not found. Test play or capture quality may be poor');
+end
+
+%% Delay to first tone, length of tone in samples
+d = d_start + round(test.mark_t*test.fs);
+if (d < 0)
+ error('Invalid negative delay seen. Test play or capture quality may be poor');
+end
+nt = round(test.tl*test.fs);
+nt_use = nt -round(test.is*test.fs) -round(test.ie*test.fs);
+if nt_use < 0
+ error('Test signal length parameters must be wrong!');
+end
+nt_skip = round(test.is*test.fs);
+
+end
diff --git a/test/test_utils/load_test_output.m b/test/test_utils/load_test_output.m
new file mode 100644
index 0000000..320a4d6
--- /dev/null
+++ b/test/test_utils/load_test_output.m
@@ -0,0 +1,87 @@
+function [x, nx] = load_test_output(test)
+
+%% [x, n] = load_test_output(t)
+%
+% Input
+% t.fn_out - file name to load
+% t.bits_out - word length of data
+% t.fmt - file format 'raw' or 'txt
+% t.ch - channel to extract
+% t.nch - number of channels in (interleaved) data
+%
+% Output
+% x - samples
+% n - number of samples
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Integer type for binary files
+switch test.bits_out
+ case 16
+ bfmt = 'int16';
+ case 24
+ bfmt = 'int32';
+ case 32
+ bfmt = 'int32';
+ otherwise
+ error('Bits_out must be 16, 24, or 32.');
+end
+
+%% Check that output file exists
+if exist(test.fn_out)
+ fprintf('Reading output data file %s...\n', test.fn_out);
+ switch lower(test.fmt)
+ case 'txt'
+ out = load(test.fn_out);
+ case 'raw'
+ fh = fopen(test.fn_out, 'r');
+ out = fread(fh, inf, bfmt);
+ fclose(fh);
+ otherwise
+ error('Fmt must be raw or txt.');
+ end
+else
+ out = [];
+end
+
+%% Exctract channels to measure
+scale = 1/2^(test.bits_out-1);
+lout = length(out);
+nx = floor(lout/test.nch);
+x = zeros(nx,length(test.ch));
+j = 1;
+for ch = test.ch
+ x(:,j) = out(ch:test.nch:end)*scale;
+ j = j + 1;
+end
+
+end
diff --git a/test/test_utils/mix_chirp.m b/test/test_utils/mix_chirp.m
new file mode 100644
index 0000000..9b57f2c
--- /dev/null
+++ b/test/test_utils/mix_chirp.m
@@ -0,0 +1,82 @@
+function test = mix_chirp(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Adjust tone length to integer number of samples
+test.nt = round(test.cl*test.fs); % Make number of samples per tone
+test.tl = test.nt/test.fs; % an integer by adjusting tl.
+
+%% Test start and end marker tones
+[h1, mark_start] = sync_chirp(test.fs, 'up');
+[h2, mark_end] = sync_chirp(test.fs, 'down');
+test.mark_t = mark_start.t;
+test.mark_a = mark_start.a;
+test.mark_a_db = mark_start.a_db;
+test.ts = mark_start.t;
+
+%% Idle time to start and end
+test.idle_t = 0.5;
+n_idle = round(test.fs*test.idle_t);
+t_idle = n_idle/test.fs;
+x = zeros(test.nt + mark_start.n + mark_end.n +2*n_idle, test.nch, 'int32');
+
+%% Add markers
+idx1 = n_idle+1;
+idx2 = length(x)-n_idle-mark_end.n;
+for ch=test.ch
+ x(idx1:idx1+mark_start.n-1, ch) = dither_and_quantize(h1, test.bits_in);
+ x(idx2:idx2+mark_end.n-1, ch) = dither_and_quantize(h2, test.bits_in);
+end
+
+%% Dither also idle parts
+x(1:n_idle) = dither_and_quantize(zeros(n_idle,1), test.bits_in);
+x(end-n_idle+1:end) = dither_and_quantize(zeros(n_idle,1), test.bits_in);
+
+%% Add Chirp
+i1 = n_idle+mark_start.n+1;
+i2 = i1+test.nt-1;
+fprintf('Mixing %.1f dBFS chirp ...\n', test.a_db);
+tc = ((1:round(test.cl*test.fs))-1)/test.fs;
+s = test.a * chirp(tc, test.f_min, test.tl, test.f_max, 'linear', 90);
+sign = 1;
+for ch=test.ch
+ x(i1:i2, ch) = dither_and_quantize(sign * s, test.bits_in);
+ sign = -sign;
+end
+
+test.signal = x;
+
+%% Output
+fprintf('Writing output data file %s...\n', test.fn_in);
+write_test_data(x, test.fn_in, test.bits_in, test.fmt);
+fprintf('Done.\n')
+
+end
diff --git a/test/test_utils/mix_sweep.m b/test/test_utils/mix_sweep.m
new file mode 100644
index 0000000..1b76437
--- /dev/null
+++ b/test/test_utils/mix_sweep.m
@@ -0,0 +1,103 @@
+function test = mix_sweep(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Adjust tone lengt to integer number of samples
+test.nt = round(test.tl*test.fs); % Make number of samples per tone
+test.tl = test.nt/test.fs; % an integer by adjusting tl.
+test.nf = length(test.f); % Number of frequencies
+test.na = length(test.a); % Number of amplitudes
+
+%% Test start and end marker tones
+[h1, mark_start] = sync_chirp(test.fs, 'up');
+[h2, mark_end] = sync_chirp(test.fs, 'down');
+test.mark_t = mark_start.t;
+test.mark_a = mark_start.a;
+test.mark_a_db = mark_start.a_db;
+test.ts = mark_start.t;
+
+%% Idle time to start and end
+test.idle_t = 0.5;
+n_idle = round(test.fs*test.idle_t);
+t_idle = n_idle/test.fs;
+x = zeros(test.nf*test.na*test.nt +mark_start.n +mark_end.n +2*n_idle, ...
+ test.nch, 'int32');
+
+%% Add markers
+idx1 = n_idle+1;
+idx2 = length(x)-n_idle-mark_end.n;
+for ch=test.ch
+ x(idx1:idx1+mark_start.n-1, ch) = dither_and_quantize(h1, test.bits_in);
+ x(idx2:idx2+mark_end.n-1, ch) = dither_and_quantize(h2, test.bits_in);
+end
+
+%% Dither also idle parts
+x(1:n_idle) = dither_and_quantize(zeros(n_idle,1), test.bits_in);
+x(end-n_idle+1:end) = dither_and_quantize(zeros(n_idle,1), test.bits_in);
+
+%% Add discrete frequencies sweep
+n_r = round(test.fs*test.tr);
+win = ones(test.nt,1);
+win(1:n_r) = linspace(0,1,n_r);
+win(end-n_r+1:end) = linspace(1,0,n_r);
+i0 = n_idle+mark_start.n+1;
+nn = 1;
+for m=1:test.na
+ for n=1:test.nf
+ i1 = i0 + (nn-1)*test.nt+1;
+ i2 = i1+test.nt-1;
+ nn = nn+1;
+ if length(test.f) > 1
+ f = test.f(n);
+ else
+ f = test.f;
+ end
+ if length(test.a) > 1
+ a = test.a(m);
+ else
+ a = test.a;
+ end
+ fprintf('Mixing %.0f Hz %.1f dBFS sine ...\n', f, 20*log10(a));
+ s = multitone(test.fs, f, a, test.tl);
+ for ch=test.ch
+ x(i1:i2, ch) = dither_and_quantize(s.*win, test.bits_in);
+ end
+ end
+end
+
+test.signal = x;
+
+%% Output
+fprintf('Writing output data file %s...\n', test.fn_in);
+write_test_data(x, test.fn_in, test.bits_in, test.fmt);
+fprintf('Done.\n')
+
+end
diff --git a/test/test_utils/mkdir_check.m b/test/test_utils/mkdir_check.m
new file mode 100644
index 0000000..b453d0b
--- /dev/null
+++ b/test/test_utils/mkdir_check.m
@@ -0,0 +1,35 @@
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function d = mkdir_check(d)
+if exist(d) ~= 7
+ mkdir(d);
+end
+end
diff --git a/test/test_utils/multitone.m b/test/test_utils/multitone.m
new file mode 100644
index 0000000..7f3faa3
--- /dev/null
+++ b/test/test_utils/multitone.m
@@ -0,0 +1,61 @@
+function x = multitone( fs, f, amp, tlength )
+
+%%
+% Create single or multiple sine wave(s)
+%
+% x = multitone(fs, f, a, t);
+%
+% fs - Sample rate
+% f - Frequency (Hz)
+% a - Amplitude (lin)
+% t - Lenght in seconds
+%
+% Example:
+% x = multitone(48000, [997 1997], 10.^([-26 -46]/20), 1.0);
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+n = round(fs*tlength);
+t = (0:n-1)/fs;
+nf = length(f);
+if nf > 1
+ ph = rand(nf, 1)*2*pi;
+else
+ ph = 0;
+end
+
+x = amp(1)*sin(2*pi*f(1)*t');
+for i=2:length(f)
+ x = x + amp(i)*sin(2*pi*f(i)*t+ph(i));
+end
+
+end
diff --git a/test/test_utils/sync_chirp.m b/test/test_utils/sync_chirp.m
new file mode 100644
index 0000000..513a426
--- /dev/null
+++ b/test/test_utils/sync_chirp.m
@@ -0,0 +1,68 @@
+function [y, mark]= sync_chirp(fs, direction)
+
+%% [y, mark]= sync_chirp(fs, direction)
+%
+% Returns a chirp signal that can be used to mark end and beginning of audio
+% tests to syncronize input and captured output accurately.
+%
+% Input
+% fs - sample rate
+% direction - direction of frequency sweep 'up' or 'down'
+%
+% Output
+% y - windowed chirp signal
+% mark - struct with parameters for chirp
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+mark.a_db = -10;
+mark.a = 10^(mark.a_db/20);
+mark.fs = fs;
+mark.t = 0.2; % Short, to not consume much test time
+switch lower(direction)
+ case 'up'
+ mark.f0 = 200; % Should work with any speaker
+ mark.f1 = 3500; % Should work with any speaker
+ case 'down'
+ mark.f1 = 200; % Should work with any speaker
+ mark.f0 = 3500; % Should work with any speaker
+ otherwise
+ error('Parameter direction must be ''up'' or ''down''');
+end
+
+mark.n = round(mark.t*fs);
+t_vec = (0:mark.n-1)/fs;
+w = hanning(mark.n);
+x = chirp(t_vec, mark.f0, mark.t, mark.f1, 'linear')';
+y = x .* w * mark.a;
+
+end
diff --git a/test/test_utils/test_run.m b/test/test_utils/test_run.m
new file mode 100644
index 0000000..1eb3405
--- /dev/null
+++ b/test/test_utils/test_run.m
@@ -0,0 +1,53 @@
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function test = test_run(test)
+
+if exist(test.ex) == 2
+ %fcmd = sprintf('file %s', test.ex);
+ %[status, output]=system(fcmd);
+ %if findstr(output, "Tensilica Xtensa")
+ % ex = sprintf('xt-run --turbo --summary %s', test.ex);
+ %else
+ ex = test.ex;
+ %end
+else
+ error('Can''t find executable %s', test.ex);
+end
+test.narg = length(test.arg);
+arg = '';
+for n=1:test.narg
+ arg = sprintf('%s %s', arg, char(test.arg(n)));
+end
+rcmd = sprintf('%s %s', ex, arg);
+fprintf('Running ''%s''...\n', rcmd);
+system(rcmd);
+
+end
diff --git a/test/test_utils/write_test_data.m b/test/test_utils/write_test_data.m
new file mode 100644
index 0000000..e998fff
--- /dev/null
+++ b/test/test_utils/write_test_data.m
@@ -0,0 +1,71 @@
+function write_test_data(x, fn, bits, fmt)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+switch lower(fmt)
+ case 'raw'
+ fh = fopen(fn, 'wb');
+ case 'txt'
+ fh = fopen(fn, 'w');
+ otherwise
+ error('The file format must be raw or txt');
+end
+switch bits
+ case 16
+ bfmt = 'int16';
+ case 24
+ bfmt = 'int32';
+ case 32
+ bfmt = 'int32';
+ otherwise
+ error('The bits must be set to 16, 24, or 32');
+end
+
+%% Interleave the channels if two or more
+sx = size(x);
+xi = zeros(sx(1)*sx(2), 1, bfmt);
+if sx(2) > 1
+ for n=1:sx(2)
+ xi(n:sx(2):end) = x(:,n);
+ end
+else
+ xi(1:end) = x;
+end
+
+%% Write file and close
+if strcmp(lower(fmt), 'raw')
+ fwrite(fh, xi, bfmt);
+else
+ fprintf(fh,'%d\n', xi);
+end
+fclose(fh);
+
+end
diff --git a/topology/Makefile.am b/topology/Makefile.am
new file mode 100644
index 0000000..207e520
--- /dev/null
+++ b/topology/Makefile.am
@@ -0,0 +1,74 @@
+
+#
+# Dependencies
+#
+
+SUBDIRS = m4 sof common platform
+
+DEPS = \
+ platform/intel/*.m4 \
+ platform/common/*.m4 \
+ common/*.m4 \
+ m4/*.m4 \
+ sof/*.m4
+
+#
+# Machines
+#
+
+MACHINES = \
+ sof-cht-nocodec.tplg \
+ sof-cht-max98090.tplg \
+ sof-apl-hdmi.tplg \
+ sof-apl-nocodec.tplg \
+ sof-byt-nocodec.tplg \
+ sof-bdw-rt286.tplg \
+ sof-bdw-rt5640.tplg \
+ sof-byt-rt5640.tplg \
+ sof-byt-rt5645.tplg \
+ sof-byt-rt5651.tplg \
+ sof-byt-da7213.tplg \
+ sof-cnl-rt274.tplg \
+ sof-hsw-rt5640.tplg \
+ sof-apl-tdf8532.tplg \
+ sof-apl-pcm512x.tplg \
+ sof-apl-wm8804.tplg \
+ sof-apl-da7219.tplg \
+ sof-glk-da7219.tplg \
+ sof-icl-nocodec.tplg
+
+# Uncomment the following line if you want to debug conf files
+.PRECIOUS: %.conf
+
+%.conf : %.m4 ${DEPS}
+ m4 -I m4 -I common -I platform/common $< > $@
+
+%.tplg : %.conf
+ alsatplg -v 1 -c $< -o $@
+
+all: ${MACHINES}
+
+clean-local:
+ rm -f *.conf
+ rm -f *.tplg
+
+EXTRA_DIST = \
+ sof-cht-nocodec.m4 \
+ sof-cht-max98090.m4 \
+ sof-apl-hdmi.m4 \
+ sof-apl-nocodec.m4 \
+ sof-byt-nocodec.m4 \
+ sof-bdw-rt286.m4 \
+ sof-bdw-rt5640.m4 \
+ sof-byt-rt5640.m4 \
+ sof-byt-rt5645.m4 \
+ sof-byt-rt5651.m4 \
+ sof-byt-da7213.m4 \
+ sof-cnl-rt274.m4 \
+ sof-hsw-rt5640.m4 \
+ sof-apl-tdf8532.m4 \
+ sof-apl-pcm512x.m4 \
+ sof-apl-wm8804.m4 \
+ sof-apl-da7219.m4 \
+ sof-glk-da7219.m4 \
+ sof-icl-nocodec.m4
diff --git a/topology/common/Makefile.am b/topology/common/Makefile.am
new file mode 100644
index 0000000..7e207a7
--- /dev/null
+++ b/topology/common/Makefile.am
@@ -0,0 +1,4 @@
+EXTRA_DIST = \
+ tlv.m4 \
+ memory.m4
+
diff --git a/topology/common/memory.m4 b/topology/common/memory.m4
new file mode 100644
index 0000000..0852dff
--- /dev/null
+++ b/topology/common/memory.m4
@@ -0,0 +1,15 @@
+dnl
+dnl Memory capabilities.
+dnl
+dnl These are ORed together to create a capability mask that's sent to the
+dnl SOF firmware when creating buffer or allocating other memory resources.
+dnl
+dnl ** Must match SOF_MEM_CAPS_ values in ipc.h **
+
+define(`MEM_CAP_RAM', eval(1 << 0))
+define(`MEM_CAP_ROM', eval(1 << 1))
+define(`MEM_CAP_EXT', eval(1 << 2))
+define(`MEM_CAP_LP', eval(1 << 3))
+define(`MEM_CAP_HP', eval(1 << 4))
+define(`MEM_CAP_DMA', eval(1 << 5))
+define(`MEM_CAP_CACHE', eval(1 << 6))
diff --git a/topology/common/tlv.m4 b/topology/common/tlv.m4
new file mode 100644
index 0000000..f1a9eff
--- /dev/null
+++ b/topology/common/tlv.m4
@@ -0,0 +1,14 @@
+# TLV
+#
+# Common TLV control ranges
+#
+
+SectionTLV."vtlv_m90s3" {
+ Comment "-64dB step 2dB"
+
+ scale {
+ min "-6400"
+ step "200"
+ mute "1"
+ }
+}
diff --git a/topology/m4/Makefile.am b/topology/m4/Makefile.am
new file mode 100644
index 0000000..4d74cef
--- /dev/null
+++ b/topology/m4/Makefile.am
@@ -0,0 +1,12 @@
+EXTRA_DIST = \
+ buffer.m4 \
+ dai.m4 \
+ hda.m4 \
+ mixer.m4 \
+ mixercontrol.m4 \
+ pcm.m4 \
+ pga.m4 \
+ pipeline.m4 \
+ src.m4 \
+ tone.m4 \
+ utils.m4
diff --git a/topology/m4/buffer.m4 b/topology/m4/buffer.m4
new file mode 100644
index 0000000..55dd065
--- /dev/null
+++ b/topology/m4/buffer.m4
@@ -0,0 +1,32 @@
+divert(-1)
+
+dnl Define the macro for buffer widget
+
+dnl Buffer name)
+define(`N_BUFFER', `BUF'PIPELINE_ID`.'$1)
+
+dnl W_BUFFER(name, size, capabilities)
+define(`W_BUFFER',
+`SectionVendorTuples."'N_BUFFER($1)`_tuples" {'
+` tokens "sof_buffer_tokens"'
+` tuples."word" {'
+` SOF_TKN_BUF_SIZE' STR($2)
+` SOF_TKN_BUF_CAPS' STR($3)
+` }'
+`}'
+`SectionData."'N_BUFFER($1)`_data" {'
+` tuples "'N_BUFFER($1)`_tuples"'
+`}'
+`SectionWidget."'N_BUFFER($1)`" {'
+` index "'PIPELINE_ID`"'
+` type "buffer"'
+` no_pm "true"'
+` data ['
+` "'N_BUFFER($1)`_data"'
+` ]'
+`}')
+
+dnl COMP_BUFFER_SIZE( num_periods, sample_size, channels, fmames)
+define(`COMP_BUFFER_SIZE', `eval(`$1 * $2 * $3 * $4')')
+
+divert(0)dnl
diff --git a/topology/m4/dai.m4 b/topology/m4/dai.m4
new file mode 100644
index 0000000..7471718
--- /dev/null
+++ b/topology/m4/dai.m4
@@ -0,0 +1,199 @@
+divert(-1)
+
+include(`debug.m4')
+
+dnl Define macros for DAI IN/OUT widgets and DAI config
+
+dnl DAI name)
+define(`N_DAI', DAI_NAME)
+define(`N_DAI_OUT', DAI_NAME`.OUT')
+define(`N_DAI_IN', DAI_NAME`.IN')
+
+dnl W_DAI_OUT(type, index, dai_link, format, periods_sink, periods_source, preload)
+define(`W_DAI_OUT',
+`SectionVendorTuples."'N_DAI_OUT($2)`_tuples_w_comp" {'
+` tokens "sof_comp_tokens"'
+` tuples."word" {'
+` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($5)
+` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($6)
+` SOF_TKN_COMP_PRELOAD_COUNT' STR($7)
+` }'
+`}'
+`SectionData."'N_DAI_OUT($2)`_data_w_comp" {'
+` tuples "'N_DAI_OUT($2)`_tuples_w_comp"'
+`}'
+`SectionVendorTuples."'N_DAI_OUT($2)`_tuples_w" {'
+` tokens "sof_dai_tokens"'
+` tuples."word" {'
+` SOF_TKN_DAI_INDEX' $2
+` }'
+`}'
+`SectionData."'N_DAI_OUT($2)`_data_w" {'
+` tuples "'N_DAI_OUT($2)`_tuples_w"'
+`}'
+`SectionVendorTuples."'N_DAI_OUT($2)`_tuples_str" {'
+` tokens "sof_dai_tokens"'
+` tuples."string" {'
+` SOF_TKN_DAI_TYPE' $1
+` }'
+`}'
+`SectionData."'N_DAI_OUT($2)`_data_str" {'
+` tuples "'N_DAI_OUT($2)`_tuples_str"'
+`}'
+`SectionVendorTuples."'N_DAI_OUT($2)`_tuples_comp_str" {'
+` tokens "sof_comp_tokens"'
+` tuples."string" {'
+` SOF_TKN_COMP_FORMAT' STR($4)
+` }'
+`}'
+`SectionData."'N_DAI_OUT($2)`_data_comp_str" {'
+` tuples "'N_DAI_OUT($2)`_tuples_comp_str"'
+`}'
+`SectionWidget."'N_DAI_OUT`" {'
+` index "'PIPELINE_ID`"'
+` type "dai_in"'
+` stream_name' STR($3)
+` no_pm "true"'
+` data ['
+` "'N_DAI_OUT($2)`_data_w"'
+` "'N_DAI_OUT($2)`_data_w_comp"'
+` "'N_DAI_OUT($2)`_data_str"'
+` "'N_DAI_OUT($2)`_data_comp_str"'
+` ]'
+`}')
+
+dnl W_DAI_IN(type, index, dai_link, format, periods_sink, periods_source, preload)
+define(`W_DAI_IN',
+`SectionVendorTuples."'N_DAI_IN($2)`_tuples_w_comp" {'
+` tokens "sof_comp_tokens"'
+` tuples."word" {'
+` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($5)
+` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($6)
+` SOF_TKN_COMP_PRELOAD_COUNT' STR($7)
+` }'
+`}'
+`SectionData."'N_DAI_IN($2)`_data_w_comp" {'
+` tuples "'N_DAI_IN($2)`_tuples_w_comp"'
+`}'
+`SectionVendorTuples."'N_DAI_IN($2)`_tuples_w" {'
+` tokens "sof_dai_tokens"'
+` tuples."word" {'
+` SOF_TKN_DAI_INDEX' $2
+` }'
+`}'
+`SectionData."'N_DAI_IN($2)`_data_w" {'
+` tuples "'N_DAI_IN($2)`_tuples_w"'
+`}'
+`SectionVendorTuples."'N_DAI_IN($2)`_tuples_str" {'
+` tokens "sof_dai_tokens"'
+` tuples."string" {'
+` SOF_TKN_DAI_TYPE' $1
+` }'
+`}'
+`SectionData."'N_DAI_IN($2)`_data_str" {'
+` tuples "'N_DAI_IN($2)`_tuples_str"'
+`}'
+`SectionVendorTuples."'N_DAI_IN($2)`_tuples_comp_str" {'
+` tokens "sof_comp_tokens"'
+` tuples."string" {'
+` SOF_TKN_COMP_FORMAT' STR($4)
+` }'
+`}'
+`SectionData."'N_DAI_IN($2)`_data_comp_str" {'
+` tuples "'N_DAI_IN($2)`_tuples_comp_str"'
+`}'
+`SectionWidget."'N_DAI_IN`" {'
+` index "'PIPELINE_ID`"'
+` type "dai_out"'
+` stream_name' STR($3)
+` no_pm "true"'
+` data ['
+` "'N_DAI_IN($2)`_data_w"'
+` "'N_DAI_IN($2)`_data_w_comp"'
+` "'N_DAI_IN($2)`_data_str"'
+` "'N_DAI_IN($2)`_data_comp_str"'
+` ]'
+`}')
+
+dnl D_DAI(id, playback, capture, data))
+define(`D_DAI', `SectionDAI."'N_DAI`" {'
+` index "'PIPELINE_ID`"'
+` id "'$1`"'
+` playback "'$2`"'
+` capture "'$3`"'
+`}')
+
+dnl DAI Config)
+define(`N_DAI_CONFIG', `DAICONFIG.'$1)
+
+dnl DAI_CONFIG(type, idx, link_id, name, ssp_config/dmic_config)
+define(`DAI_CONFIG',
+`SectionHWConfig."'$1$2`" {'
+`'
+` id "'$3`"'
+`'
+` ifelse($1, `SSP', $5, `}')'
+`ifelse($1, `DMIC', $5, `')'
+`SectionVendorTuples."'N_DAI_CONFIG($1$2)`_tuples_common" {'
+` tokens "sof_dai_tokens"'
+` tuples."string" {'
+` SOF_TKN_DAI_TYPE' STR($1)
+` }'
+` tuples."word" {'
+` SOF_TKN_DAI_INDEX' STR($2)
+` }'
+`}'
+`SectionData."'N_DAI_CONFIG($1$2)`_data_common" {'
+` tuples "'N_DAI_CONFIG($1$2)`_tuples_common"'
+`}'
+`'
+`SectionBE."'$4`" {'
+` id "'$3`"'
+` index "0"'
+` default_hw_conf_id "'$3`"'
+`'
+` hw_configs ['
+` "'$1$2`"'
+` ]'
+` data ['
+` "'N_DAI_CONFIG($1$2)`_data"'
+` "'N_DAI_CONFIG($1$2)`_data_common"'
+`ifelse($1, `DMIC',` "'N_DAI_CONFIG($1$2)`_pdm_data"', `')'
+` ]'
+`}'
+`DEBUG_DAI_CONFIG($1, $3)'
+)
+
+dnl DAI_ADD(pipeline,
+dnl pipe id, dai type, dai_index, dai_be,
+dnl buffer, periods, format,
+dnl frames, deadline, priority, core)
+define(`DAI_ADD',
+`undefine(`PIPELINE_ID')'
+`undefine(`DAI_TYPE')'
+`undefine(`DAI_INDEX')'
+`undefine(`DAI_BE')'
+`undefine(`DAI_BUF')'
+`undefine(`DAI_PERIODS')'
+`undefine(`DAI_FORMAT')'
+`undefine(`SCHEDULE_FRAMES')'
+`undefine(`SCHEDULE_DEADLINE')'
+`undefine(`SCHEDULE_PRIORITY')'
+`undefine(`SCHEDULE_CORE')'
+`define(`PIPELINE_ID', $2)'
+`define(`DAI_TYPE', STR($3))'
+`define(`DAI_INDEX', STR($4))'
+`define(`DAI_BE', $5)'
+`define(`DAI_BUF', $6)'
+`define(`DAI_NAME', $3$4)'
+`define(`DAI_PERIODS', $7)'
+`define(`DAI_FORMAT', $8)'
+`define(`SCHEDULE_FRAMES', $9)'
+`define(`SCHEDULE_DEADLINE', $10)'
+`define(`SCHEDULE_PRIORITY', $11)'
+`define(`SCHEDULE_CORE', $12)'
+`include($1)'
+`DEBUG_DAI($3, $4)'
+)
+
+divert(0)dnl
diff --git a/topology/m4/debug.m4 b/topology/m4/debug.m4
new file mode 100644
index 0000000..6cd16c8
--- /dev/null
+++ b/topology/m4/debug.m4
@@ -0,0 +1,29 @@
+divert(-1)
+
+define(`DEBUG_START',
+`ifdef(`GRAPH', `errprint(`digraph topology {
+node [color=Red,fontname=Courier]
+edge [color=Blue, style=dashed]'
+)')')
+
+define(`DEBUG_END',
+`ifdef(`GRAPH', `errprint(`}'
+)')')
+
+define(`DEBUG_GRAPH',
+`ifdef(`GRAPH', `errprint("$2"->"$1"
+)')')
+
+define(`DEBUG_DAI',
+`ifdef(`INFO', `errprint(/* note: $1 DAI ADD dai_index $2 should match the member (index) in struct dai array (firmware platform specific, usually in dai.c) */
+)')')
+
+define(`DEBUG_DAI_CONFIG',
+`ifdef(`INFO', `errprint(/* note: $1 DAI CONFIG id $2 should match the member (id) in struct snd_soc_dai_link in kernel machine driver (usually under linux/sound/soc/intel/boards/) */
+)')')
+
+define(`DEBUG_PCM_ADD',
+`ifdef(`INFO', `errprint(/* note: PCM ADD for $1 id $2 should be unique within playback or capture pcm ids*/
+)')')
+
+divert(0)dnl
diff --git a/topology/m4/hda.m4 b/topology/m4/hda.m4
new file mode 100644
index 0000000..dcce69f
--- /dev/null
+++ b/topology/m4/hda.m4
@@ -0,0 +1,22 @@
+dnl HDA_DAI_CONFIG(idx, link_id, name)
+define(`HDA_DAI_CONFIG',
+`SectionVendorTuples."'N_DAI_CONFIG(HDA$1)`_tuples_common" {'
+` tokens "sof_dai_tokens"'
+` tuples."string" {'
+` SOF_TKN_DAI_TYPE "HDA"'
+` }'
+` tuples."word" {'
+` SOF_TKN_DAI_INDEX' STR($1)
+` }'
+`}'
+`SectionData."'N_DAI_CONFIG(HDA$1)`_data_common" {'
+` tuples "'N_DAI_CONFIG(HDA$1)`_tuples_common"'
+`}'
+`'
+`SectionBE."'$3`" {'
+` id "'$2`"'
+` index "0"'
+` data ['
+` "'N_DAI_CONFIG(HDA$1)`_data_common"'
+` ]'
+`}')
diff --git a/topology/m4/mixer.m4 b/topology/m4/mixer.m4
new file mode 100644
index 0000000..1f2376e
--- /dev/null
+++ b/topology/m4/mixer.m4
@@ -0,0 +1,43 @@
+divert(-1)
+
+dnl Define macro for Mixer widget
+
+dnl Mixer Name)
+define(`N_MIXER', `MIXER'PIPELINE_ID`.'$1)
+
+dnl Pipe Buffer name in pipeline (pipeline, buffer)
+define(`NPIPELINE_MIXER', `MIXER'$1`.'$2)
+
+dnl W_MIXER(name, format, periods_sink, periods_source, preload)
+define(`W_MIXER',
+`SectionVendorTuples."'N_MIXER($1)`_tuples_w" {'
+` tokens "sof_comp_tokens"'
+` tuples."word" {'
+` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($3)
+` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($4)
+` SOF_TKN_COMP_PRELOAD_COUNT' STR($5)
+` }'
+`}'
+`SectionData."'N_MIXER($1)`_data_w" {'
+` tuples "'N_MIXER($1)`_tuples_w"'
+`}'
+`SectionVendorTuples."'N_MIXER($1)`_tuples_str" {'
+` tokens "sof_comp_tokens"'
+` tuples."string" {'
+` SOF_TKN_COMP_FORMAT' STR($2)
+` }'
+`}'
+`SectionData."'N_MIXER($1)`_data_str" {'
+` tuples "'N_MIXER($1)`_tuples_str"'
+`}'
+`SectionWidget."'N_MIXER($1)`" {'
+` index "'PIPELINE_ID`"'
+` type "mixer"'
+` no_pm "true"'
+` data ['
+` "'N_MIXER($1)`_data_w"'
+` "'N_MIXER($1)`_data_str"'
+` ]'
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/mixercontrol.m4 b/topology/m4/mixercontrol.m4
new file mode 100644
index 0000000..a3423c3
--- /dev/null
+++ b/topology/m4/mixercontrol.m4
@@ -0,0 +1,49 @@
+divert(-1)
+
+dnl Define macro for mixer control
+
+dnl KCONTROL_CHANNEL(name, reg, shift)
+define(`KCONTROL_CHANNEL',
+`channel.STR($1) {'
+` reg STR($2)'
+` shift STR($3)'
+` }')
+
+dnl CONTROLMIXER_MAX(comment, value)
+define(`CONTROLMIXER_MAX',
+`#$1'
+` max STR($2)')
+
+dnl CONTROLMIXER_TLV(comment, value)
+define(`CONTROLMIXER_TLV',
+`#$1'
+` tlv STR($2)')
+
+dnl CONTROLMIXER_OPS(info, comment, get, put)
+define(`CONTROLMIXER_OPS',
+`ops."ctl" {'
+` info STR($1)'
+` #$2'
+` get STR($3)'
+` put STR($4)'
+` }')
+
+dnl C_CONTROLMIXER(name, index, ops, max, invert, tlv, KCONTROL_CHANNELS)
+define(`C_CONTROLMIXER',
+`SectionControlMixer."$1 PIPELINE_ID" {'
+`'
+` # control belongs to this index group'
+` index STR($2)'
+`'
+` #$7'
+` $8'
+` # control uses bespoke driver get/put/info ID'
+` $3'
+`'
+` $4'
+` invert STR($5)'
+` $6'
+
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/pcm.m4 b/topology/m4/pcm.m4
new file mode 100644
index 0000000..f8b4ee6
--- /dev/null
+++ b/topology/m4/pcm.m4
@@ -0,0 +1,130 @@
+divert(-1)
+
+dnl Define the macro for PCM playback/capture/capabilities
+
+dnl PCM name)
+define(`N_PCMP', `PCM'$1`P')
+define(`N_PCMC', `PCM'$1`C')
+
+dnl W_PCM_PLAYBACK(pcm, stream, periods_sink, periods_source, preload)
+dnl PCM platform configuration
+define(`W_PCM_PLAYBACK',
+`SectionVendorTuples."'N_PCMP($1)`_tuples_w_comp" {'
+` tokens "sof_comp_tokens"'
+` tuples."word" {'
+` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($3)
+` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($4)
+` SOF_TKN_COMP_PRELOAD_COUNT' STR($5)
+` }'
+`}'
+`SectionData."'N_PCMP($1)`_data_w_comp" {'
+` tuples "'N_PCMP($1)`_tuples_w_comp"'
+`}'
+`SectionWidget."'N_PCMP($1)`" {'
+` index "'PIPELINE_ID`"'
+` type "aif_in"'
+` no_pm "true"'
+` stream_name "'$2` '$1`"'
+` data ['
+` "'N_PCMP($1)`_data_w_comp"'
+` ]'
+`}')
+
+
+dnl W_PCM_CAPTURE(pcm, stream, periods_sink, periods_source, preload)
+define(`W_PCM_CAPTURE',
+`SectionVendorTuples."'N_PCMC($1)`_tuples_w_comp" {'
+` tokens "sof_comp_tokens"'
+` tuples."word" {'
+` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($3)
+` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($4)
+` SOF_TKN_COMP_PRELOAD_COUNT' STR($5)
+` }'
+`}'
+`SectionData."'N_PCMC($1)`_data_w_comp" {'
+` tuples "'N_PCMC($1)`_tuples_w_comp"'
+`}'
+`SectionWidget."'N_PCMC($1)`" {'
+` index "'PIPELINE_ID`"'
+` type "aif_out"'
+` no_pm "true"'
+` stream_name "'$2` '$1`"'
+` data ['
+` "'N_PCMC($1)`_data_w_comp"'
+` ]'
+`}')
+
+dnl PCM_CAPABILITIES(name, formats, rate_min, rate_max, channels_min, channels_max, periods_min, periods_max, period_size_min, period_size_max, buffer_size_min, buffer_size_max)
+define(`PCM_CAPABILITIES',
+`SectionPCMCapabilities.STR($1) {'
+`'
+` formats "$2"'
+` rate_min STR($3)'
+` rate_max STR($4)'
+` channels_min STR($5)'
+` channels_max STR($6)'
+` periods_min STR($7)'
+` periods_max STR($8)'
+` period_size_min STR($9)'
+` period_size_max STR($10)'
+` buffer_size_min STR($11)'
+` buffer_size_max STR($12)'
+`}')
+
+dnl PCM_PLAYBACK_ADD(name, pcm_id, playback)
+define(`PCM_PLAYBACK_ADD',
+`SectionPCM.STR($1) {'
+`'
+` # used for binding to the PCM'
+` id STR($2)'
+`'
+` dai.STR($1 $2) {'
+` id STR($2)'
+` }'
+`'
+` pcm."playback" {'
+`'
+` capabilities STR($3)'
+` }'
+`}')
+
+dnl PCM_CAPTURE_ADD(name, pcm_id, capture)
+define(`PCM_CAPTURE_ADD',
+`SectionPCM.STR($1) {'
+`'
+` # used for binding to the PCM'
+` id STR($2)'
+`'
+` dai.STR($1 $2) {'
+` id STR($2)'
+` }'
+`'
+` pcm."capture" {'
+`'
+` capabilities STR($3)'
+` }'
+`}')
+
+dnl PCM_DUPLEX_ADD(name, pcm_id, playback, capture)
+define(`PCM_DUPLEX_ADD',
+`SectionPCM.STR($1) {'
+`'
+` # used for binding to the PCM'
+` id STR($2)'
+`'
+` dai.STR($1 $2) {'
+` id STR($2)'
+` }'
+`'
+` pcm."capture" {'
+`'
+` capabilities STR($4)'
+` }'
+`'
+` pcm."playback" {'
+`'
+` capabilities STR($3)'
+` }'
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/pga.m4 b/topology/m4/pga.m4
new file mode 100644
index 0000000..f38f820
--- /dev/null
+++ b/topology/m4/pga.m4
@@ -0,0 +1,44 @@
+divert(-1)
+
+dnl Define macro for PGA widget
+
+dnl PGA name)
+define(`N_PGA', `PGA'PIPELINE_ID`.'$1)
+
+dnl W_PGA(name, format, periods_sink, periods_source, preload, kcontrol0. kcontrol1...etc)
+define(`W_PGA',
+`SectionVendorTuples."'N_PGA($1)`_tuples_w" {'
+` tokens "sof_comp_tokens"'
+` tuples."word" {'
+` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($3)
+` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($4)
+` SOF_TKN_COMP_PRELOAD_COUNT' STR($5)
+` }'
+`}'
+`SectionData."'N_PGA($1)`_data_w" {'
+` tuples "'N_PGA($1)`_tuples_w"'
+`}'
+`SectionVendorTuples."'N_PGA($1)`_tuples_str" {'
+` tokens "sof_comp_tokens"'
+` tuples."string" {'
+` SOF_TKN_COMP_FORMAT' STR($2)
+` }'
+`}'
+`SectionData."'N_PGA($1)`_data_str" {'
+` tuples "'N_PGA($1)`_tuples_str"'
+`}'
+`SectionWidget."'N_PGA($1)`" {'
+` index "'PIPELINE_ID`"'
+` type "pga"'
+` no_pm "true"'
+` data ['
+` "'N_PGA($1)`_data_w"'
+` "'N_PGA($1)`_data_str"'
+` ]'
+` mixer ['
+ $6
+` ]'
+
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/pipeline.m4 b/topology/m4/pipeline.m4
new file mode 100644
index 0000000..7c1f307
--- /dev/null
+++ b/topology/m4/pipeline.m4
@@ -0,0 +1,112 @@
+divert(-1)
+
+dnl Define macro for pipeline widget
+
+dnl Pipeline name)
+define(`N_PIPELINE', `PIPELINE.'PIPELINE_ID`.'$1)
+
+dnl W_PIPELINE(stream, deadline, priority, frames, core, timer, platform)
+define(`W_PIPELINE',
+`SectionVendorTuples."'N_PIPELINE($1)`_tuples" {'
+` tokens "sof_sched_tokens"'
+` tuples."word" {'
+` SOF_TKN_SCHED_DEADLINE' STR($2)
+` SOF_TKN_SCHED_PRIORITY' STR($3)
+` SOF_TKN_SCHED_CORE' STR($5)
+` SOF_TKN_SCHED_FRAMES' STR($4)
+` SOF_TKN_SCHED_TIMER' STR($6)
+` }'
+`}'
+`SectionData."'N_PIPELINE($1)`_data" {'
+` tuples "'N_PIPELINE($1)`_tuples"'
+`}'
+`SectionWidget."'N_PIPELINE($1)`" {'
+` index "'PIPELINE_ID`"'
+` type "scheduler"'
+` no_pm "true"'
+` stream_name "'$1`"'
+` data ['
+` "'N_PIPELINE($1)`_data"'
+` "'$7`"'
+` ]'
+`}')
+
+dnl PIPELINE_PCM_ADD(pipeline,
+dnl pipe id, pcm, max channels, format,
+dnl frames, deadline, priority, core)
+define(`PIPELINE_PCM_ADD',
+`undefine(`PCM_ID')'
+`undefine(`PIPELINE_ID')'
+`undefine(`PIPELINE_CHANNELS')'
+`undefine(`PIPELINE_FORMAT')'
+`undefine(`SCHEDULE_FRAMES')'
+`undefine(`SCHEDULE_DEADLINE')'
+`undefine(`SCHEDULE_PRIORITY')'
+`undefine(`SCHEDULE_CORE')'
+`define(`PIPELINE_ID', $2)'
+`define(`PCM_ID', $3)'
+`define(`PIPELINE_CHANNELS', $4)'
+`define(`PIPELINE_FORMAT', $5)'
+`define(`SCHEDULE_FRAMES', $6)'
+`define(`SCHEDULE_DEADLINE', $7)'
+`define(`SCHEDULE_PRIORITY', $8)'
+`define(`SCHEDULE_CORE', $9)'
+`include($1)'
+`DEBUG_PCM_ADD($1, $3)'
+)
+
+dnl PIPELINE_PCM_DAI_ADD(pipeline,
+dnl pipe id, pcm, max channels, format,
+dnl frames, deadline, priority, core,
+dnl dai type, dai_index, dai format, periods)
+define(`PIPELINE_PCM_DAI_ADD',
+`undefine(`PCM_ID')'
+`undefine(`PIPELINE_ID')'
+`undefine(`PIPELINE_CHANNELS')'
+`undefine(`PIPELINE_FORMAT')'
+`undefine(`SCHEDULE_FRAMES')'
+`undefine(`SCHEDULE_DEADLINE')'
+`undefine(`SCHEDULE_PRIORITY')'
+`undefine(`SCHEDULE_CORE')'
+`undefine(`DAI_TYPE')'
+`undefine(`DAI_INDEX')'
+`undefine(`DAI_FORMAT')'
+`undefine(`DAI_PERIODS')'
+`define(`PIPELINE_ID', $2)'
+`define(`PCM_ID', $3)'
+`define(`PIPELINE_CHANNELS', $4)'
+`define(`PIPELINE_FORMAT', $5)'
+`define(`SCHEDULE_FRAMES', $6)'
+`define(`SCHEDULE_DEADLINE', $7)'
+`define(`SCHEDULE_PRIORITY', $8)'
+`define(`SCHEDULE_CORE', $9)'
+`define(`DAI_TYPE', STR($10))'
+`define(`DAI_INDEX', STR($11))'
+`define(`DAI_FORMAT', $12)'
+`define(`DAI_PERIODS', $13)'
+`define(`DAI_NAME', $10$11)'
+`include($1)'
+)
+
+dnl PIPELINE_ADD(pipeline,
+dnl pipe id, max channels, format,
+dnl frames, deadline, priority, core)
+define(`PIPELINE_ADD',
+`undefine(`PIPELINE_ID')'
+`undefine(`PIPELINE_CHANNELS')'
+`undefine(`PIPELINE_FORMAT')'
+`undefine(`SCHEDULE_FRAMES')'
+`undefine(`SCHEDULE_DEADLINE')'
+`undefine(`SCHEDULE_PRIORITY')'
+`undefine(`SCHEDULE_CORE')'
+`define(`PIPELINE_ID', $2)'
+`define(`PIPELINE_CHANNELS', $3)'
+`define(`PIPELINE_FORMAT', $4)'
+`define(`SCHEDULE_FRAMES', $5)'
+`define(`SCHEDULE_DEADLINE', $6)'
+`define(`SCHEDULE_PRIORITY', $7)'
+`define(`SCHEDULE_CORE', $8)'
+`include($1)'
+)
+
+divert(0)dnl
diff --git a/topology/m4/src.m4 b/topology/m4/src.m4
new file mode 100644
index 0000000..aca18e3
--- /dev/null
+++ b/topology/m4/src.m4
@@ -0,0 +1,41 @@
+divert(-1)
+
+dnl Defines the macro for SRC widget
+
+dnl SRC name)
+define(`N_SRC', `SRC'PIPELINE_ID`.'$1)
+
+dnl W_SRC(name, format, periods_sink, periods_source, data, preload)
+define(`W_SRC',
+`SectionVendorTuples."'N_SRC($1)`_tuples_w" {'
+` tokens "sof_comp_tokens"'
+` tuples."word" {'
+` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($3)
+` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($4)
+` SOF_TKN_COMP_PRELOAD_COUNT' STR($6)
+` }'
+`}'
+`SectionData."'N_SRC($1)`_data_w" {'
+` tuples "'N_SRC($1)`_tuples_w"'
+`}'
+`SectionVendorTuples."'N_SRC($1)`_tuples_str" {'
+` tokens "sof_comp_tokens"'
+` tuples."string" {'
+` SOF_TKN_COMP_FORMAT' STR($2)
+` }'
+`}'
+`SectionData."'N_SRC($1)`_data_str" {'
+` tuples "'N_SRC($1)`_tuples_str"'
+`}'
+`SectionWidget."'N_SRC($1)`" {'
+` index "'PIPELINE_ID`"'
+` type "src"'
+` no_pm "true"'
+` data ['
+` "'N_SRC($1)`_data_w"'
+` "'N_SRC($1)`_data_str"'
+` "'$5`"'
+` ]'
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/tone.m4 b/topology/m4/tone.m4
new file mode 100644
index 0000000..583134c
--- /dev/null
+++ b/topology/m4/tone.m4
@@ -0,0 +1,50 @@
+divert(-1)
+
+dnl Define macro for siggen widget
+
+dnl Tone name)
+define(`N_TONE', `TONE'PIPELINE_ID`.'$1)
+
+dnl W_TONE(name, format, periods_sink, periods_source, preload, kcontrols_list)
+define(`W_TONE',
+`SectionVendorTuples."'N_TONE($1)`_tuples_w" {'
+` tokens "sof_comp_tokens"'
+` tuples."word" {'
+` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($3)
+` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($4)
+` SOF_TKN_COMP_PRELOAD_COUNT' STR($5)
+` }'
+`}'
+`SectionVendorTuples."'N_TONE($1)`_tone_tuples_w" {'
+` tokens "sof_tone_tokens"'
+` tuples."word" {'
+` SOF_TKN_TONE_SAMPLE_RATE' ifdef(TONE_SAMPLE_RATE, STR(TONE_SAMPLE_RATE), "48000")
+` }'
+`}'
+`SectionData."'N_TONE($1)`_data_w" {'
+` tuples "'N_TONE($1)`_tuples_w"'
+` tuples "'N_TONE($1)`_tone_tuples_w"'
+`}'
+`SectionVendorTuples."'N_TONE($1)`_tuples_str" {'
+` tokens "sof_comp_tokens"'
+` tuples."string" {'
+` SOF_TKN_COMP_FORMAT' STR($2)
+` }'
+`}'
+`SectionData."'N_TONE($1)`_data_str" {'
+` tuples "'N_TONE($1)`_tuples_str"'
+`}'
+`SectionWidget."'N_TONE($1)`" {'
+` index "'PIPELINE_ID`"'
+` type "siggen"'
+` no_pm "true"'
+` data ['
+` "'N_TONE($1)`_data_w"'
+` "'N_TONE($1)`_data_str"'
+` ]'
+` mixer ['
+ $6
+` ]'
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/utils.m4 b/topology/m4/utils.m4
new file mode 100644
index 0000000..a1fe94b
--- /dev/null
+++ b/topology/m4/utils.m4
@@ -0,0 +1,114 @@
+divert(-1)
+
+include(`debug.m4')
+
+define(`concat',`$1$2')
+
+define(`STR', `"'$1`"')
+
+dnl Argument iterator.
+define(`argn', `ifelse(`$1', 1, ``$2'',
+ `argn(decr(`$1'), shift(shift($@)))')')
+
+dnl Defines a list of items from a variable number of params.
+dnl Use as last argument in a macro.
+dnl The first argument specifies the number of tabs to be added for formatting
+define(`LIST_LOOP', `argn(j,$@)
+$1ifelse(i,`2', `', `define(`i', decr(i))define(`j', incr(j))$0($@)')')
+
+define(`LIST', `pushdef(`i', $#)pushdef(`j', `2')LIST_LOOP($@)popdef(i)popdef(j)')
+
+dnl Sums a list of variable arguments. Use as last argument in macro.
+define(`SUM_LOOP', `eval(argn(j,$@)
+ ifelse(i,`1', `', `define(`i', decr(i)) define(`j', incr(j)) + $0($@)'))')
+
+dnl Memory capabilities
+define(`MEMCAPS', `pushdef(`i', $#) pushdef(`j', `1') SUM_LOOP($@)')
+
+dnl create direct DAPM/pipeline link between 2 widgets)
+define(`dapm', `"$1, , $2"'`DEBUG_GRAPH($1, $2)')
+
+dnl COMP_SAMPLE_SIZE(FMT)
+define(`COMP_SAMPLE_SIZE',
+`ifelse(
+ $1, `s16le', `2',
+ $1, `s24_4le', `4',
+ $1, `s32le', `4',
+ $1, `float', `4',
+ `4')')
+
+dnl COMP_FORMAT_NAME(FMT)
+define(`COMP_FORMAT_NAME',
+`ifelse(
+ $1, `s16le', `S16_LE',
+ $1, `s24le', `S24_LE',
+ $1, `s32le', `S32_LE',
+ $1, `float', `FLOAT_LE',
+ )')
+
+dnl P_GRAPH(name, CONNECTIONS)
+define(`P_GRAPH',
+`SectionGraph.STR($1) {'
+` index STR($2)'
+`'
+` lines ['
+` $3'
+` ]'
+`}')
+
+dnl W_VENDORTUPLES(name, tokens, RATE_OUT)
+define(`W_VENDORTUPLES',
+`SectionVendorTuples.STR($1) {'
+` tokens STR($2)'
+`'
+` tuples."word" {'
+` $3'
+` }'
+`}')
+
+dnl W_DATA(name, tuples)
+define(`W_DATA',
+`SectionData.STR($1) {'
+` tuples STR($2)'
+`}')
+
+dnl VIRTUAL_DAPM_ROUTE_OUT(name, dai type, dai index, direction, index)
+define(`VIRTUAL_DAPM_ROUTE_OUT',
+`SectionWidget.STR($1) {'
+` index STR($5)'
+` type "output"'
+` no_pm "true"'
+`}'
+`SectionGraph.STR($2) {'
+` index STR($5)'
+`'
+` lines ['
+` dapm($1,$2$3.$4)'
+` ]'
+`}')
+
+dnl VIRTUAL_DAPM_ROUTE_IN(name, dai type, dai index, direction, index)
+define(`VIRTUAL_DAPM_ROUTE_IN',
+`SectionWidget.STR($1) {'
+` index STR($5)'
+` type "input"'
+` no_pm "true"'
+`}'
+`SectionGraph.STR($2) {'
+` index STR($5)'
+`'
+` lines ['
+` dapm($2$3.$4, $1)'
+` ]'
+`}')
+
+dnl VIRTUAL_WIDGET(name, index)
+define(`VIRTUAL_WIDGET',
+`SectionWidget.STR($1) {'
+` index STR($2)'
+` type "out_drv"'
+` no_pm "true"'
+`}')
+
+divert(0) dnl
+
diff --git a/topology/platform/Makefile.am b/topology/platform/Makefile.am
new file mode 100644
index 0000000..011ff9e
--- /dev/null
+++ b/topology/platform/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = intel common
diff --git a/topology/platform/common/Makefile.am b/topology/platform/common/Makefile.am
new file mode 100644
index 0000000..a8576d5
--- /dev/null
+++ b/topology/platform/common/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = \
+ ssp.m4
diff --git a/topology/platform/common/ssp.m4 b/topology/platform/common/ssp.m4
new file mode 100644
index 0000000..f3c7862
--- /dev/null
+++ b/topology/platform/common/ssp.m4
@@ -0,0 +1,46 @@
+divert(-1)
+
+dnl SSP related macros
+
+dnl SSP_CLOCK(clock, freq, codec_master)
+define(`SSP_CLOCK',
+ $1 STR($3)
+ $1_freq STR($2))
+
+
+dnl SSP_TDM(slots, width, tx_mask, rx_mask)
+define(`SSP_TDM',
+`tdm_slots 'STR($1)
+` tdm_slot_width 'STR($2)
+` tx_slots 'STR($3)
+` rx_slots 'STR($4)
+)
+dnl SSP_CONFIG(format, mclk, bclk, fsync, tdm, ssp_config_data)
+define(`SSP_CONFIG',
+` format "'$1`"'
+` '$2
+` '$3
+` '$4
+` '$5
+`}'
+$6
+)
+
+dnl SSP_CONFIG_DATA(type, idx, valid bits, mclk_id)
+dnl mclk_id is optional
+define(`SSP_CONFIG_DATA',
+`SectionVendorTuples."'N_DAI_CONFIG($1$2)`_tuples" {'
+` tokens "sof_ssp_tokens"'
+` tuples."word" {'
+` SOF_TKN_INTEL_SSP_SAMPLE_BITS' STR($3)
+` }'
+` tuples."short" {'
+` SOF_TKN_INTEL_SSP_MCLK_ID' ifelse($4, `', "0", STR($4))
+` }'
+`}'
+`SectionData."'N_DAI_CONFIG($1$2)`_data" {'
+` tuples "'N_DAI_CONFIG($1$2)`_tuples"'
+`}'
+)
+
+divert(0)dnl
diff --git a/topology/platform/intel/Makefile.am b/topology/platform/intel/Makefile.am
new file mode 100644
index 0000000..bc56971
--- /dev/null
+++ b/topology/platform/intel/Makefile.am
@@ -0,0 +1,9 @@
+EXTRA_DIST = \
+ bdw.m4 \
+ bxt.m4 \
+ byt.m4 \
+ cht.m4 \
+ hsw.m4 \
+ cnl.m4 \
+ dmic.m4
+
diff --git a/topology/platform/intel/bdw.m4 b/topology/platform/intel/bdw.m4
new file mode 100644
index 0000000..1af6699
--- /dev/null
+++ b/topology/platform/intel/bdw.m4
@@ -0,0 +1,31 @@
+#
+# Broadwell differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Broadwell
+define(`PLATFORM_DAI_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_HOST_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_PASS_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/bxt.m4 b/topology/platform/intel/bxt.m4
new file mode 100644
index 0000000..7626513
--- /dev/null
+++ b/topology/platform/intel/bxt.m4
@@ -0,0 +1,34 @@
+#
+# Broxton differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Baytrail
+define(`PLATFORM_DAI_MEM_CAP',
+ MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_HOST_MEM_CAP',
+ MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_PASS_MEM_CAP',
+ MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/byt.m4 b/topology/platform/intel/byt.m4
new file mode 100644
index 0000000..a25d993
--- /dev/null
+++ b/topology/platform/intel/byt.m4
@@ -0,0 +1,31 @@
+#
+# Baytrail differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Baytrail
+define(`PLATFORM_DAI_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_HOST_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_PASS_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/cht.m4 b/topology/platform/intel/cht.m4
new file mode 100644
index 0000000..b6317cd
--- /dev/null
+++ b/topology/platform/intel/cht.m4
@@ -0,0 +1,31 @@
+#
+# Cherrytrail differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Cherrytrail
+define(`PLATFORM_DAI_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_HOST_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_PASS_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/cnl.m4 b/topology/platform/intel/cnl.m4
new file mode 100644
index 0000000..96bf6de
--- /dev/null
+++ b/topology/platform/intel/cnl.m4
@@ -0,0 +1,35 @@
+#
+# Broxton differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Cannonlake
+define(`PLATFORM_DAI_MEM_CAP',
+ MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_HOST_MEM_CAP',
+ MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_PASS_MEM_CAP',
+ MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/dmic.m4 b/topology/platform/intel/dmic.m4
new file mode 100644
index 0000000..7a93069
--- /dev/null
+++ b/topology/platform/intel/dmic.m4
@@ -0,0 +1,69 @@
+divert(-1)
+
+dnl DMIC related macros
+
+dnl PDM_TUPLES(pdm ctrl id, mic_a_enable, mic_b_enable, polarity_a, polarity_b,
+dnl clk_egde, skew)
+define(`PDM_TUPLES',
+` tuples."short.pdm$1" {'
+` SOF_TKN_INTEL_DMIC_PDM_CTRL_ID' STR($1)
+` SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable' STR($2)
+` SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable' STR($3)
+` SOF_TKN_INTEL_DMIC_PDM_POLARITY_A' STR($4)
+` SOF_TKN_INTEL_DMIC_PDM_POLARITY_B' STR($5)
+` SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE' STR($6)
+` SOF_TKN_INTEL_DMIC_PDM_SKEW' STR($7)
+` }'
+)
+
+dnl PDM_CONFIG(type, idx, num pdm active, pdm tuples list)
+define(`PDM_CONFIG',
+` SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE' STR($3)
+` }'
+`}'
+`SectionVendorTuples."'N_DAI_CONFIG($1$2)`_pdm_tuples" {'
+` tokens "sof_dmic_pdm_tokens"'
+$4
+`}'
+)
+
+dnl DMIC currently only supports 16 bit or 32-bit word length
+dnl DMIC_WORD_LENGTH(frame format)
+define(`DMIC_WORD_LENGTH',
+`ifelse($1, `s16le', 16, $1, `s32le', 32, `')')
+
+dnl DMIC_CONFIG(driver_version, clk_min, clk_mac, duty_min, duty_max,
+dnl sample_rate,
+dnl fifo word length, type, idx, pdm controller config)
+define(`DMIC_CONFIG',
+`SectionVendorTuples."'N_DAI_CONFIG($8$9)`_dmic_tuples" {'
+` tokens "sof_dmic_tokens"'
+` tuples."word" {'
+` SOF_TKN_INTEL_DMIC_DRIVER_VERSION' STR($1)
+` SOF_TKN_INTEL_DMIC_CLK_MIN' STR($2)
+` SOF_TKN_INTEL_DMIC_CLK_MAX' STR($3)
+` SOF_TKN_INTEL_DMIC_DUTY_MIN' STR($4)
+` SOF_TKN_INTEL_DMIC_DUTY_MAX' STR($5)
+` SOF_TKN_INTEL_DMIC_SAMPLE_RATE' STR($6)
+` SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH' STR($7)
+dnl PDM config for the number of active PDM controllers
+$10
+`SectionData."'N_DAI_CONFIG($8$9)`_pdm_data" {'
+` tuples "'N_DAI_CONFIG($8$9)`_pdm_tuples"'
+`}'
+`SectionData."'N_DAI_CONFIG($8$9)`_data" {'
+` tuples "'N_DAI_CONFIG($8$9)`_dmic_tuples"'
+
+`}'
+)
+
+dnl DMIC PDM configurations
+dnl macros to get the number of active pdm's and their config
+define(`MONO_PDM0_MICA', `1, LIST(`', PDM_TUPLES(0, 1, 0, 0, 0, 0, 0))')
+define(`MONO_PDM0_MICB', `1, LIST(`', PDM_TUPLES(0, 0, 1, 0, 0, 0, 0))')
+define(`STEREO_PDM0', `1, LIST(`', PDM_TUPLES(0, 1, 1, 0, 0, 0, 0))')
+define(`STEREO_PDM1', `1, LIST(`', PDM_TUPLES(1, 1, 1, 0, 0, 0, 0))')
+define(`FOUR_CH_PDM0_PDM1',
+ `2, LIST(`', PDM_TUPLES(0, 1, 1, 0, 0, 0, 0), PDM_TUPLES(1, 1, 1, 0, 0, 0, 0))')
+
+divert(0)dnl
diff --git a/topology/platform/intel/hsw.m4 b/topology/platform/intel/hsw.m4
new file mode 100644
index 0000000..c096732
--- /dev/null
+++ b/topology/platform/intel/hsw.m4
@@ -0,0 +1,31 @@
+#
+# Haswell differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Haswell
+define(`PLATFORM_DAI_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_HOST_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_PASS_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/icl.m4 b/topology/platform/intel/icl.m4
new file mode 100644
index 0000000..9671289
--- /dev/null
+++ b/topology/platform/intel/icl.m4
@@ -0,0 +1,38 @@
+#
+# Icelake differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for different buffer types on Icelake
+define(`PLATFORM_DAI_MEM_CAP',
+ MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_HOST_MEM_CAP',
+ MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_PASS_MEM_CAP',
+ MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens,
+ LIST(` ', `SOF_TKN_SCHED_MIPS "50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens,
+ LIST(` ', `SOF_TKN_SCHED_MIPS "100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens,
+ LIST(` ', `SOF_TKN_SCHED_MIPS "200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens,
+ LIST(` ', `SOF_TKN_SCHED_MIPS "5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/sof-apl-da7219.m4 b/topology/sof-apl-da7219.m4
new file mode 100644
index 0000000..0c102fe
--- /dev/null
+++ b/topology/sof-apl-da7219.m4
@@ -0,0 +1,143 @@
+#
+# Topology for AppoloLake with headset on SSP1, spk on SSP5 and DMIC capture
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include bxt DSP configuration
+include(`platform/intel/bxt.m4')
+include(`platform/intel/dmic.m4')
+
+DEBUG_START
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> SSP5 (speaker - maxim98357a)
+# PCM1 <---> volume <----> SSP1 (headset - da7219)
+# PCM99 <---- volume <----- DMIC0 (dmic capture)
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 2 on PCM 1 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 2, 1, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+ 3, 1, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 4 on PCM 0 using max 4 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+#PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4,
+ 4, 99, 4, s32le,
+ 48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+# playback DAI is SSP5 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 5, SSP5-Codec,
+ PIPELINE_SOURCE_1, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 2, SSP, 1, SSP1-Codec,
+ PIPELINE_SOURCE_2, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 3, SSP, 1, SSP1-Codec,
+ PIPELINE_SINK_3, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is DMIC0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 4, DMIC, 0, dmic01,
+ PIPELINE_SINK_4, 2, s32le,
+ 48, 1000, 0, 0)
+
+PCM_PLAYBACK_ADD(Speakers, 0, PIPELINE_PCM_1)
+PCM_DUPLEX_ADD(Headset, 1, PIPELINE_PCM_2, PIPELINE_PCM_3)
+PCM_CAPTURE_ADD(DMIC01, 99, PIPELINE_PCM_4)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+#SSP 5 (ID: 0) with 19.2 MHz mclk with MCLK_ID 0 (unused), 1.536 MHz blck
+DAI_CONFIG(SSP, 5, 0, SSP5-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 5, 16, 0)))
+
+#SSP 1 (ID: 1) with 19.2 MHz mclk with MCLK_ID 0, 1.92 MHz bclk
+DAI_CONFIG(SSP, 1, 1, SSP1-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1920000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 20, 3, 3),
+ SSP_CONFIG_DATA(SSP, 1, 16, 0)))
+
+# dmic01 (id: 2)
+DAI_CONFIG(DMIC, 0, 2, dmic01,
+ DMIC_CONFIG(1, 500000, 4800000, 40, 60, 48000,
+ DMIC_WORD_LENGTH(s32le), DMIC, 0,
+ # FIXME: what is the right configuration
+ # PDM_CONFIG(DMIC, 0, FOUR_CH_PDM0_PDM1)))
+ PDM_CONFIG(DMIC, 0, STEREO_PDM0)))
+
+## remove warnings with SST hard-coded routes (FIXME)
+
+VIRTUAL_WIDGET(ssp5 Tx, 0)
+VIRTUAL_WIDGET(ssp1 Rx, 1)
+VIRTUAL_WIDGET(ssp1 Tx, 2)
+VIRTUAL_WIDGET(DMIC01 Rx, 3)
+VIRTUAL_WIDGET(DMic, 4)
+VIRTUAL_WIDGET(dmic01_hifi, 5)
+VIRTUAL_WIDGET(hif5-0 Output, 6)
+VIRTUAL_WIDGET(hif6-0 Output, 7)
+VIRTUAL_WIDGET(hif7-0 Output, 8)
+VIRTUAL_WIDGET(hifi1, 9)
+VIRTUAL_WIDGET(hifi2, 10)
+VIRTUAL_WIDGET(hifi3, 11)
+
+VIRTUAL_DAPM_ROUTE_OUT(codec0_out, SSP, 0, OUT, 12)
+VIRTUAL_DAPM_ROUTE_OUT(codec1_out, SSP, 0, OUT, 13)
+VIRTUAL_DAPM_ROUTE_OUT(ssp1 Tx, SSP, 0, OUT, 14)
+VIRTUAL_DAPM_ROUTE_IN(ssp1 Rx, SSP, 0, IN, 15)
+VIRTUAL_DAPM_ROUTE_OUT(Capture, SSP, 0, OUT, 16)
+VIRTUAL_DAPM_ROUTE_OUT(SoC DMIC, SSP, 0, OUT, 17)
+VIRTUAL_DAPM_ROUTE_IN(codec0_in, SSP, 0, IN, 18)
+
+DEBUG_END
diff --git a/topology/sof-apl-hdmi.m4 b/topology/sof-apl-hdmi.m4
new file mode 100644
index 0000000..00d7c68
--- /dev/null
+++ b/topology/sof-apl-hdmi.m4
@@ -0,0 +1,93 @@
+#
+# Topology for generic Apollolake board with no codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`hda.m4')
+include(`ssp.m4')
+include(`pipeline.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/bxt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> iDisp1
+# PCM1 ----> Volume -----> iDisp2
+# PCM2 ----> volume -----> iDisp3
+
+dnl PIPELINE_PCM_ADD(pipeline,
+dnl pipe id, pcm, max channels, format,
+dnl frames, deadline, priority, core)
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 1, 0, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 2 on PCM 1 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 2, 1, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 3 on PCM 2 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 3, 2, 2, s16le,
+ 48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+dnl DAI_ADD(pipeline,
+dnl pipe id, dai type, dai_index, dai_be,
+dnl buffer, periods, format,
+dnl frames, deadline, priority, core)
+
+# playback DAI is iDisp1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, HDA, 0, iDisp1,
+ PIPELINE_SOURCE_1, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is iDisp2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 2, HDA, 1, iDisp2,
+ PIPELINE_SOURCE_2, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is iDisp3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 3, HDA, 2, iDisp3,
+ PIPELINE_SOURCE_3, 2, s16le,
+ 48, 1000, 0, 0)
+
+
+dnl PCM_PLAYBACK_ADD(name, pcm_id, playback)
+PCM_PLAYBACK_ADD(HDMI1, 0, PIPELINE_PCM_1)
+PCM_PLAYBACK_ADD(HDMI2, 1, PIPELINE_PCM_2)
+PCM_PLAYBACK_ADD(HDMI3, 2, PIPELINE_PCM_3)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+dnl HDA_DAI_CONFIG(dai_index, link_id, name)
+HDA_DAI_CONFIG(0, 1, iDisp1)
+HDA_DAI_CONFIG(1, 2, iDisp2)
+HDA_DAI_CONFIG(2, 3, iDisp3)
diff --git a/topology/sof-apl-nocodec.m4 b/topology/sof-apl-nocodec.m4
new file mode 100644
index 0000000..da61ece
--- /dev/null
+++ b/topology/sof-apl-nocodec.m4
@@ -0,0 +1,290 @@
+#
+# Topology for generic Apollolake board with no codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`ssp.m4')
+include(`pipeline.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/bxt.m4')
+include(`platform/intel/dmic.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> SSP0
+# <---- volume <----- SSP0
+# PCM1 ----> Volume <----- SSP1
+# <---- Volume <----- SSP1
+# PCM2 ----> volume -----> SSP2
+# <---- Volume <----- SSP2
+# PCM3 ----> volume -----> SSP3
+# <---- volume <----- SSP3
+# PCM4 ----> volume -----> SSP4
+# <---- Volume <----- SSP4
+# PCM5 ----> volume -----> SSP5
+# <---- volume <----- SSP5
+# PCM6 <---- volume <----- DMIC6 (DMIC01)
+#
+
+dnl PIPELINE_PCM_ADD(pipeline,
+dnl pipe id, pcm, max channels, format,
+dnl frames, deadline, priority, core)
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 1, 0, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+ 2, 0, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 3 on PCM 1 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 3, 1, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 4 on PCM 1 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+ 4, 1, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 5 on PCM 2 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 5, 2, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 6 on PCM 2 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+ 6, 2, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 7 on PCM 3 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 7, 3, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 8 on PCM 3 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+ 8, 3, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 9 on PCM 4 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 9, 4, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 10 on PCM 4 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+ 10, 4, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 11 on PCM 5 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 11, 5, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 12 on PCM 5 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+ 12, 5, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Passthrough capture pipeline 13 on PCM 6 using max 4 channels.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4,
+ 13, 6, 4, s32le,
+ 48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+dnl DAI_ADD(pipeline,
+dnl pipe id, dai type, dai_index, dai_be,
+dnl buffer, periods, format,
+dnl frames, deadline, priority, core)
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 0, NoCodec-0,
+ PIPELINE_SOURCE_1, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 0, NoCodec-0,
+ PIPELINE_SINK_2, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 3, SSP, 1, NoCodec-1,
+ PIPELINE_SOURCE_3, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 4, SSP, 1, NoCodec-1,
+ PIPELINE_SINK_4, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 5, SSP, 2, NoCodec-2,
+ PIPELINE_SOURCE_5, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 6, SSP, 2, NoCodec-2,
+ PIPELINE_SINK_6, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 7, SSP, 3, NoCodec-3,
+ PIPELINE_SOURCE_7, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 8, SSP, 3, NoCodec-3,
+ PIPELINE_SINK_8, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP4 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 9, SSP, 4, NoCodec-4,
+ PIPELINE_SOURCE_9, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP4 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 10, SSP, 4, NoCodec-4,
+ PIPELINE_SINK_10, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP5 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 11, SSP, 5, NoCodec-5,
+ PIPELINE_SOURCE_11, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP5 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 12, SSP, 5, NoCodec-5,
+ PIPELINE_SINK_12, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is DMIC 0 using 2 periods
+# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 13, DMIC, 0, NoCodec-6,
+ PIPELINE_SINK_13, 2, s32le,
+ 48, 1000, 0, 0)
+
+dnl PCM_DUPLEX_ADD(name, pcm_id, playback, capture)
+PCM_DUPLEX_ADD(Port0, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+PCM_DUPLEX_ADD(Port1, 1, PIPELINE_PCM_3, PIPELINE_PCM_4)
+PCM_DUPLEX_ADD(Port2, 2, PIPELINE_PCM_5, PIPELINE_PCM_6)
+PCM_DUPLEX_ADD(Port3, 3, PIPELINE_PCM_7, PIPELINE_PCM_8)
+PCM_DUPLEX_ADD(Port4, 4, PIPELINE_PCM_9, PIPELINE_PCM_10)
+PCM_DUPLEX_ADD(Port5, 5, PIPELINE_PCM_11, PIPELINE_PCM_12)
+dnl PCM_CAPTURE_ADD(name, pipeline, capture)
+PCM_CAPTURE_ADD(DMIC01, 6, PIPELINE_PCM_13)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+dnl DAI_CONFIG(type, dai_index, link_id, name, ssp_config/dmic_config)
+DAI_CONFIG(SSP, 0, 0, NoCodec-0,
+ dnl SSP_CONFIG(format, mclk, bclk, fsync, tdm, ssp_config_data)
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ dnl SSP_CONFIG_DATA(type, dai_index, valid bits, mclk_id)
+ SSP_CONFIG_DATA(SSP, 0, 16)))
+
+DAI_CONFIG(SSP, 1, 1, NoCodec-1,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 1, 16)))
+
+DAI_CONFIG(SSP, 2, 2, NoCodec-2,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 2, 16)))
+
+DAI_CONFIG(SSP, 3, 3, NoCodec-3,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 3, 16)))
+
+DAI_CONFIG(SSP, 4, 4, NoCodec-4,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 4, 16)))
+
+DAI_CONFIG(SSP, 5, 5, NoCodec-5,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 5, 16)))
+
+DAI_CONFIG(DMIC, 0, 6, NoCodec-6,
+ dnl DMIC_CONFIG(driver_version, clk_min, clk_mac, duty_min, duty_max,
+ dnl sample_rate,
+ dnl fifo word length, type, dai_index, pdm controller config)
+ DMIC_CONFIG(1, 500000, 4800000, 40, 60, 48000,
+ dnl DMIC_WORD_LENGTH(frame_format)
+ DMIC_WORD_LENGTH(s32le), DMIC, 0,
+ dnl PDM_CONFIG(type, dai_index, num pdm active, pdm tuples list)
+ dnl STEREO_PDM0 is a pre-defined pdm config for stereo capture
+ PDM_CONFIG(DMIC, 0, STEREO_PDM0)))
+
diff --git a/topology/sof-apl-pcm512x.m4 b/topology/sof-apl-pcm512x.m4
new file mode 100644
index 0000000..48257ae
--- /dev/null
+++ b/topology/sof-apl-pcm512x.m4
@@ -0,0 +1,59 @@
+#
+# Topology for generic Apollolake UP^2 with pcm512x codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/bxt.m4')
+
+DEBUG_START
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> SSP5 (pcm512x)
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+# playback DAI is SSP5 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 5, SSP5-Codec,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency, id 0
+PCM_PLAYBACK_ADD(Port5, 0, PIPELINE_PCM_1)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+DAI_CONFIG(SSP, 5, 0, SSP5-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 3072000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 32, 3, 3),
+ SSP_CONFIG_DATA(SSP, 5, 24)))
+
+DEBUG_END
diff --git a/topology/sof-apl-tdf8532.m4 b/topology/sof-apl-tdf8532.m4
new file mode 100644
index 0000000..c82c1f0
--- /dev/null
+++ b/topology/sof-apl-tdf8532.m4
@@ -0,0 +1,245 @@
+#
+# Topology for generic Apollolake board with TDF8532
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/bxt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> SSP4
+# PCM1 ----> volume -----> SSP2(Dirana Pb)
+# <---- Volume <----- SSP2(Dirana Cp)
+# PCM2 ----> volume -----> SSP0(BT HFP out)
+# <---- volume <----- SSP0(BT HFP in)
+# PCM3 <---- Volume <----- SSP1(HDMI in)
+# PCM4 ----> volume -----> SSP3(Modem out)
+# <---- volume <----- SSP3(Modem in)
+# PCM5 ----> volume -----> SSP5(TestPin out)
+# <---- volume <----- SSP3(TestPin in)
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 4 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+ 1, 0, 4, s32le,
+ 48, 1000, 0, 0, SSP, 4, s32le, 2)
+
+# Low Latency playback pipeline 2 on PCM 1 using max 8 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+ 2, 1, 8, s32le,
+ 48, 1000, 0, 0, SSP, 2, s32le, 2)
+
+# Low Latency capture pipeline 3 on PCM 1 using max 8 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+ 3, 1, 8, s32le,
+ 48, 1000, 0, 0, SSP, 2, s32le, 2)
+
+# Low Latency playback pipeline 4 on PCM 2 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+ 4, 2, 2, s16le,
+ 48, 1000, 0, 0, SSP, 0, s16le, 2)
+
+# Low Latency capture pipeline 5 on PCM 2 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+ 5, 2, 2, s16le,
+ 48, 1000, 0, 0, SSP, 0, s16le, 2)
+
+# Low Latency capture pipeline 6 on PCM 3 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+ 6, 3, 2, s16le,
+ 48, 1000, 0, 0, SSP, 1, s16le, 2)
+
+# Low Latency playback pipeline 7 on PCM 4 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+ 7, 4, 2, s16le,
+ 48, 1000, 0, 0, SSP, 3, s16le, 2)
+
+# Low Latency capture pipeline 8 on PCM 4 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+ 8, 4, 2, s16le,
+ 48, 1000, 0, 0, SSP, 3, s16le, 2)
+
+# Low Latency playback pipeline 9 on PCM 5 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+ 9, 5, 2, s16le,
+ 48, 1000, 0, 0, SSP, 5, s16le, 2)
+
+# Low Latency capture pipeline 10 on PCM 5 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+ 10, 5, 2, s16le,
+ 48, 1000, 0, 0, SSP, 5, s16le, 2)
+
+
+#
+# DAIs configuration
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 4, SSP, 0, SSP0-Codec,
+ PIPELINE_SOURCE_4, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 5, SSP, 0, SSP0-Codec,
+ PIPELINE_SINK_5, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 6, SSP, 1, SSP1-Codec,
+ PIPELINE_SINK_6, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 2, SSP, 2, SSP2-Codec,
+ PIPELINE_SOURCE_2, 2, s32le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 3, SSP, 2, SSP2-Codec,
+ PIPELINE_SINK_3, 2, s32le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 7, SSP, 3, SSP3-Codec,
+ PIPELINE_SOURCE_7, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 8, SSP, 3, SSP3-Codec,
+ PIPELINE_SINK_8, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP4 using 2 periods
+# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 4, SSP4-Codec,
+ PIPELINE_SOURCE_1, 2, s32le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP5 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 9, SSP, 5, SSP5-Codec,
+ PIPELINE_SOURCE_9, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP5 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 10, SSP, 5, SSP5-Codec,
+ PIPELINE_SINK_10, 2, s16le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency, id 0
+PCM_DUPLEX_ADD(Port0, 2, PIPELINE_PCM_4, PIPELINE_PCM_5)
+PCM_CAPTURE_ADD(Port1, 3, PIPELINE_PCM_6)
+PCM_DUPLEX_ADD(Port2, 1, PIPELINE_PCM_2, PIPELINE_PCM_3)
+PCM_DUPLEX_ADD(Port3, 4, PIPELINE_PCM_7, PIPELINE_PCM_8)
+PCM_PLAYBACK_ADD(Port4, 0, PIPELINE_PCM_1)
+PCM_DUPLEX_ADD(Port5, 5, PIPELINE_PCM_9, PIPELINE_PCM_10)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 0, SSP0-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 0, 16)))
+
+DAI_CONFIG(SSP, 1, 1, SSP1-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 1, 16)))
+
+DAI_CONFIG(SSP, 2, 2, SSP2-Codec,
+ SSP_CONFIG(DSP_B, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 12288000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(8, 32, 255, 255),
+ SSP_CONFIG_DATA(SSP, 2, 32)))
+
+DAI_CONFIG(SSP, 3, 3, SSP3-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 3, 16)))
+
+DAI_CONFIG(SSP, 4, 4, SSP4-Codec,
+ SSP_CONFIG(DSP_B, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 12288000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(8, 32, 15, 15),
+ SSP_CONFIG_DATA(SSP, 4, 32)))
+
+DAI_CONFIG(SSP, 5, 5, SSP5-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 5, 16)))
+
+
+VIRTUAL_DAPM_ROUTE_IN(BtHfp_ssp0_in, SSP, 0, IN, 0)
+VIRTUAL_DAPM_ROUTE_OUT(BtHfp_ssp0_out, SSP, 0, OUT, 1)
+VIRTUAL_DAPM_ROUTE_IN(hdmi_ssp1_in, SSP, 1, IN, 2)
+VIRTUAL_DAPM_ROUTE_IN(dirana_in, SSP, 2, IN, 3)
+VIRTUAL_DAPM_ROUTE_IN(dirana_aux_in, SSP, 2, IN, 4)
+VIRTUAL_DAPM_ROUTE_IN(dirana_tuner_in, SSP, 2, IN, 5)
+VIRTUAL_DAPM_ROUTE_OUT(dirana_out, SSP, 2, OUT, 6)
+VIRTUAL_DAPM_ROUTE_IN(Modem_ssp3_in, SSP, 3, IN, 7)
+VIRTUAL_DAPM_ROUTE_OUT(Modem_ssp3_out, SSP, 3, OUT, 8)
+VIRTUAL_DAPM_ROUTE_OUT(codec0_out, SSP, 4, OUT, 9)
+VIRTUAL_DAPM_ROUTE_IN(TestPin_ssp5_in, SSP, 5, IN, 10)
+VIRTUAL_DAPM_ROUTE_OUT(TestPin_ssp5_out, SSP, 5, OUT, 11)
+VIRTUAL_WIDGET(ssp0 Tx, 12)
+VIRTUAL_WIDGET(ssp0 Rx, 13)
+VIRTUAL_WIDGET(ssp1 Rx, 14)
+VIRTUAL_WIDGET(ssp2 Tx, 15)
+VIRTUAL_WIDGET(ssp2 Rx, 16)
+VIRTUAL_WIDGET(ssp3 Tx, 17)
+VIRTUAL_WIDGET(ssp3 Rx, 18)
+VIRTUAL_WIDGET(ssp4 Tx, 19)
+VIRTUAL_WIDGET(ssp5 Tx, 20)
+VIRTUAL_WIDGET(ssp5 Rx, 21)
diff --git a/topology/sof-apl-wm8804.m4 b/topology/sof-apl-wm8804.m4
new file mode 100644
index 0000000..4dc15eb
--- /dev/null
+++ b/topology/sof-apl-wm8804.m4
@@ -0,0 +1,55 @@
+#
+# Topology for generic Apollolake UP^2 with wm8804 codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/bxt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> SSP5 (wm8804)
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+# playback DAI is SSP5 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 5, SSP5-Codec,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency, id 0
+PCM_PLAYBACK_ADD(Port5, 0, PIPELINE_PCM_1)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+DAI_CONFIG(SSP, 5, 0, SSP5-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+ SSP_CLOCK(bclk, 3072000, codec_master),
+ SSP_CLOCK(fsync, 48000, codec_master),
+ SSP_TDM(2, 32, 3, 3),
+ SSP_CONFIG_DATA(SSP, 5, 24)))
diff --git a/topology/sof-bdw-rt286.m4 b/topology/sof-bdw-rt286.m4
new file mode 100644
index 0000000..a750344
--- /dev/null
+++ b/topology/sof-bdw-rt286.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Broadwell board with no codec.
+#
+
+# Include topology builder
+include(`pipeline.m4')
+include(`utils.m4')
+include(`dai.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Broadwell DSP configuration
+include(`platform/intel/bdw.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+# |--low latency mixer ----> volume ----> SSP2
+# PCM2 ----> SRC -----> volume ----+
+# |
+# Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP0
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+ 2, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 96 frames per 2000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+ 3, 1, 2, s32le,
+ 96, 2000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, s32le,
+ 192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-bdw-rt286" {
+ index "0"
+
+ lines [
+ # media 0
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+ #tone
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+ ]
+}
+
+#
+# DAI configuration
+#
+# SSP port 0 is our only pipeline DAI
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 0, Codec,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 0, Codec,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 0, Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24000000, codec_mclk_in),
+ SSP_CLOCK(bclk, 2400000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 0, 24)))
diff --git a/topology/sof-bdw-rt5640.m4 b/topology/sof-bdw-rt5640.m4
new file mode 100644
index 0000000..454e050
--- /dev/null
+++ b/topology/sof-bdw-rt5640.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Broadwell board with no codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Broadwell DSP configuration
+include(`platform/intel/bdw.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+# |--low latency mixer ----> volume ----> SSP2
+# PCM2 ----> SRC -----> volume ----+
+# |
+# Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP0
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+ 2, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 96 frames per 2000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+ 3, 1, 2, s32le,
+ 96, 2000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, s32le,
+ 192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-bdw-rt5640" {
+ index "0"
+
+ lines [
+ # media 0
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+ #tone
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+ ]
+}
+
+#
+# DAI configuration
+#
+# SSP port 0 is our only pipeline DAI
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 0, Codec,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 0, Codec,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 0, Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24000000, codec_mclk_in),
+ SSP_CLOCK(bclk, 2400000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 0, 24)))
diff --git a/topology/sof-byt-da7213.m4 b/topology/sof-byt-da7213.m4
new file mode 100644
index 0000000..6008ff0
--- /dev/null
+++ b/topology/sof-byt-da7213.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Baytrail board with DA7213 codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`platform/intel/byt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+# |--low latency mixer ----> volume ----> SSP2
+# PCM2 ----> SRC -----> volume ----+
+# |
+# Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+ 2, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+ 3, 1, 2, s32le,
+ 192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, s32le,
+ 192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-byt-da7212" {
+ index "0"
+
+ lines [
+ # media 0
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+ #tone
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+ ]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 2, SSP2-Codec,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 2, SSP2-Codec,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, SSP2-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 2400000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-byt-nocodec.m4 b/topology/sof-byt-nocodec.m4
new file mode 100644
index 0000000..6df25ca
--- /dev/null
+++ b/topology/sof-byt-nocodec.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Baytrail board with no codec.
+#
+
+# Include topology builder
+include(`pipeline.m4')
+include(`utils.m4')
+include(`dai.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`platform/intel/byt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+# |--low latency mixer ----> volume ----> SSP2
+# PCM2 ----> SRC -----> volume ----+
+# |
+# Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+ 2, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+ 3, 1, 2, s32le,
+ 192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, s32le,
+ 192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-byt-nocodec" {
+ index "0"
+
+ lines [
+ # media 0
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+ #tone
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+ ]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 2, NoCodec-2,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 2, NoCodec-2,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 2, NoCodec-2,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 2400000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-byt-rt5640.m4 b/topology/sof-byt-rt5640.m4
new file mode 100644
index 0000000..2177fe3
--- /dev/null
+++ b/topology/sof-byt-rt5640.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Baytrail board with RT5640.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`platform/intel/byt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+# |--low latency mixer ----> volume ----> SSP2
+# PCM2 ----> SRC -----> volume ----+
+# |
+# Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+ 2, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+ 3, 1, 2, s32le,
+ 192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, s32le,
+ 192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-byt-rt5640" {
+ index "0"
+
+ lines [
+ # media 0
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+ #tone
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+ ]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 2, SSP2-Codec,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 2, SSP2-Codec,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, SSP2-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 2400000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-byt-rt5645.m4 b/topology/sof-byt-rt5645.m4
new file mode 100644
index 0000000..23f1a75
--- /dev/null
+++ b/topology/sof-byt-rt5645.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Baytrail board with no codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`platform/intel/byt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+# |--low latency mixer ----> volume ----> SSP2
+# PCM2 ----> SRC -----> volume ----+
+# |
+# Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+ 2, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+ 3, 1, 2, s32le,
+ 192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, s32le,
+ 192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-byt-rt5645" {
+ index "0"
+
+ lines [
+ # media 0
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+ #tone
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+ ]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 2, SSP2-Codec,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 2, SSP2-Codec,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, SSP2-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 2400000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-byt-rt5651.m4 b/topology/sof-byt-rt5651.m4
new file mode 100644
index 0000000..724c34e
--- /dev/null
+++ b/topology/sof-byt-rt5651.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Baytrail board with no RT5651.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`platform/intel/byt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+# |--low latency mixer ----> volume ----> SSP2
+# PCM2 ----> SRC -----> volume ----+
+# |
+# Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+ 2, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+ 3, 1, 2, s32le,
+ 192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, s32le,
+ 192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-byt-rt5651" {
+ index "0"
+
+ lines [
+ # media 0
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+ #tone
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+ ]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 2, SSP2-Codec,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 2, SSP2-Codec,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, SSP2-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 2400000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-cht-max98090.m4 b/topology/sof-cht-max98090.m4
new file mode 100644
index 0000000..627181f
--- /dev/null
+++ b/topology/sof-cht-max98090.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic CHT/BSW board with Maxim 98090 codec
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Cherrytrail DSP configuration
+include(`platform/intel/cht.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+# |--low latency mixer ----> volume ----> SSP2
+# PCM2 ----> SRC -----> volume ----+
+# |
+# Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+ 2, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+ 3, 1, 2, s32le,
+ 192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, s32le,
+ 192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-cht-max98090" {
+ index "0"
+
+ lines [
+ # media 0
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+ #tone
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+ ]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 2, SSP2-Codec,
+ PIPELINE_SOURCE_1, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 2, SSP2-Codec,
+ PIPELINE_SINK_2, 2, s16le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, SSP2-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1920000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 20, 3, 3),
+ SSP_CONFIG_DATA(SSP, 2, 16)))
diff --git a/topology/sof-cht-nocodec.m4 b/topology/sof-cht-nocodec.m4
new file mode 100644
index 0000000..dae6dca
--- /dev/null
+++ b/topology/sof-cht-nocodec.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic CherryTrail board with no codec.
+#
+
+# Include topology builder
+include(`pipeline.m4')
+include(`utils.m4')
+include(`dai.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include CherryTrail DSP configuration
+include(`platform/intel/cht.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+# |--low latency mixer ----> volume ----> SSP2
+# PCM2 ----> SRC -----> volume ----+
+# |
+# Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+ 2, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+ 3, 1, 2, s32le,
+ 192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, s32le,
+ 192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-cht-nocodec" {
+ index "0"
+
+ lines [
+ # media 0
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+ #tone
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+ ]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 2, NoCodec-2,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 2, NoCodec-2,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, NoCodec-2,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 2400000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-cnl-rt274.m4 b/topology/sof-cnl-rt274.m4
new file mode 100644
index 0000000..d40efc1
--- /dev/null
+++ b/topology/sof-cnl-rt274.m4
@@ -0,0 +1,92 @@
+#
+# Topology for generic Cannonlake board with RT274
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/cnl.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> volume ----> SSP0
+#
+# PCM1 <---- Volume <---- SSP0
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+ 1, 0, 2, s24le,
+ 48, 1000, 0, 0, SSP, 0, s24le, 2)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+ 2, 0, 2, s24le,
+ 48, 1000, 0, 0, SSP, 0, s24le, 2)
+
+#
+# DAI configuration
+#
+# SSP port 0 is our only pipeline DAI
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 0, SSP0-Codec,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 0, SSP0-Codec,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Passthrough, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 1, SSP0-Codec,
+ SSP_CONFIG(DSP_B, SSP_CLOCK(mclk, 24000000, codec_mclk_in),
+ SSP_CLOCK(bclk, 4800000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(4, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 0, 24)))
+
+VIRTUAL_DAPM_ROUTE_OUT(codec0_out, SSP, 0, OUT, 0)
+VIRTUAL_DAPM_ROUTE_OUT(codec1_out, SSP, 0, OUT, 1)
+VIRTUAL_DAPM_ROUTE_OUT(ssp0 Tx, SSP, 0, OUT, 2)
+VIRTUAL_DAPM_ROUTE_OUT(Capture, SSP, 0, OUT, 3)
+VIRTUAL_DAPM_ROUTE_OUT(SoC DMIC, SSP, 0, OUT, 4)
+VIRTUAL_DAPM_ROUTE_IN(codec0_in, SSP, 0, IN, 5)
+VIRTUAL_DAPM_ROUTE_OUT(ssp2_out, SSP, 0, OUT, 6)
+VIRTUAL_DAPM_ROUTE_IN(ssp2_in, SSP, 0, IN, 7)
+VIRTUAL_DAPM_ROUTE_OUT(ssp1_out, SSP, 0, OUT, 8)
+VIRTUAL_WIDGET(DMIC01 Rx, 9)
+VIRTUAL_WIDGET(DMic, 10)
+VIRTUAL_WIDGET(dmic01_hifi, 11)
+VIRTUAL_WIDGET(ssp0 Rx, 12)
+VIRTUAL_WIDGET(ssp1_out, 13)
+VIRTUAL_WIDGET(ssp2_out, 14)
+VIRTUAL_WIDGET(ssp2_in, 15)
+VIRTUAL_WIDGET(ssp2 Rx, 16)
+VIRTUAL_WIDGET(ssp2 Tx, 17)
+VIRTUAL_WIDGET(Dummy Playback, 18)
+VIRTUAL_WIDGET(Dummy Capture, 19)
diff --git a/topology/sof-glk-da7219.m4 b/topology/sof-glk-da7219.m4
new file mode 100644
index 0000000..a2ac09f
--- /dev/null
+++ b/topology/sof-glk-da7219.m4
@@ -0,0 +1,195 @@
+#
+# Topology for AppoloLake with headset on SSP2, spk on SSP1 and DMIC capture
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+include(`hda.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include bxt DSP configuration
+include(`platform/intel/bxt.m4')
+include(`platform/intel/dmic.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume (pipe 1) -----> SSP1 (speaker - maxim98357a, BE link 0)
+# PCM1 <---> volume (pipe 2,3) <----> SSP2 (headset - da7219, BE link 1)
+# PCM99 <---- volume (pipe 4) <----- DMIC0 (dmic capture, BE link 2)
+# PCM5 ----> volume (pipe 5) -----> iDisp1 (HDMI/DP playback, BE link 3)
+# PCM6 ----> Volume (pipe 6) -----> iDisp2 (HDMI/DP playback, BE link 4)
+# PCM7 ----> volume (pipe 7) -----> iDisp3 (HDMI/DP playback, BE link 5)
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 2 on PCM 1 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 2, 1, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+ 3, 1, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 4 on PCM 99 using max 4 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+#PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4,
+ 4, 99, 4, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 5 on PCM 5 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+# PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4,
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 5, 5, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 6 on PCM 6 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+# PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4,
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 6, 6, 2, s16le,
+ 48, 1000, 0, 0)
+
+# Low Latency playback pipeline 7 on PCM 7 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+# PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4,
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+ 7, 7, 2, s16le,
+ 48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+# playback DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 1, SSP1-Codec,
+ PIPELINE_SOURCE_1, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 2, SSP, 2, SSP2-Codec,
+ PIPELINE_SOURCE_2, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 3, SSP, 2, SSP2-Codec,
+ PIPELINE_SINK_3, 2, s16le,
+ 48, 1000, 0, 0)
+
+# capture DAI is DMIC0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 4, DMIC, 0, dmic01,
+ PIPELINE_SINK_4, 2, s32le,
+ 48, 1000, 0, 0)
+
+# playback DAI is iDisp1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 5, HDA, 3, iDisp1,
+ PIPELINE_SOURCE_5, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is iDisp2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 6, HDA, 4, iDisp2,
+ PIPELINE_SOURCE_6, 2, s16le,
+ 48, 1000, 0, 0)
+
+# playback DAI is iDisp3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 7, HDA, 5, iDisp3,
+ PIPELINE_SOURCE_7, 2, s16le,
+ 48, 1000, 0, 0)
+
+PCM_PLAYBACK_ADD(Speakers, 0, PIPELINE_PCM_1)
+PCM_DUPLEX_ADD(Headset, 1, PIPELINE_PCM_2, PIPELINE_PCM_3)
+PCM_CAPTURE_ADD(DMIC01, 99, PIPELINE_PCM_4)
+PCM_PLAYBACK_ADD(HDMI1, 5, PIPELINE_PCM_5)
+PCM_PLAYBACK_ADD(HDMI2, 6, PIPELINE_PCM_6)
+PCM_PLAYBACK_ADD(HDMI3, 7, PIPELINE_PCM_7)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+#SSP 1 (ID: 0) with 19.2 MHz mclk with MCLK_ID 1 (unused), 1.536 MHz blck
+DAI_CONFIG(SSP, 1, 0, SSP1-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1536000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 16, 3, 3),
+ SSP_CONFIG_DATA(SSP, 1, 16, 1)))
+
+#SSP 2 (ID: 1) with 19.2 MHz mclk with MCLK_ID 1, 1.92 MHz bclk
+DAI_CONFIG(SSP, 2, 1, SSP2-Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+ SSP_CLOCK(bclk, 1920000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 20, 3, 3),
+ SSP_CONFIG_DATA(SSP, 2, 16, 1)))
+
+# dmic01 (id: 2)
+DAI_CONFIG(DMIC, 0, 2, dmic01,
+ DMIC_CONFIG(1, 500000, 4800000, 40, 60, 48000,
+ DMIC_WORD_LENGTH(s32le), DMIC, 0,
+ # FIXME: what is the right configuration
+ # PDM_CONFIG(DMIC, 0, FOUR_CH_PDM0_PDM1)))
+ PDM_CONFIG(DMIC, 0, STEREO_PDM0)))
+
+# 3 HDMI/DP outputs (ID: 3,4,5)
+HDA_DAI_CONFIG(3, 3, iDisp1)
+HDA_DAI_CONFIG(4, 4, iDisp2)
+HDA_DAI_CONFIG(5, 5, iDisp3)
+
+## remove warnings with SST hard-coded routes (FIXME)
+
+VIRTUAL_WIDGET(ssp5 Tx, 0)
+VIRTUAL_WIDGET(ssp1 Rx, 1)
+VIRTUAL_WIDGET(ssp1 Tx, 2)
+VIRTUAL_WIDGET(DMIC01 Rx, 3)
+VIRTUAL_WIDGET(DMic, 4)
+VIRTUAL_WIDGET(dmic01_hifi, 5)
+VIRTUAL_WIDGET(hif5-0 Output, 6)
+VIRTUAL_WIDGET(hif6-0 Output, 7)
+VIRTUAL_WIDGET(hif7-0 Output, 8)
+
+VIRTUAL_DAPM_ROUTE_OUT(codec0_out, SSP, 0, OUT, 12)
+VIRTUAL_DAPM_ROUTE_OUT(codec1_out, SSP, 0, OUT, 13)
+VIRTUAL_DAPM_ROUTE_OUT(ssp1 Tx, SSP, 0, OUT, 14)
+VIRTUAL_DAPM_ROUTE_IN(ssp1 Rx, SSP, 0, IN, 15)
+VIRTUAL_DAPM_ROUTE_OUT(Capture, SSP, 0, OUT, 16)
+VIRTUAL_DAPM_ROUTE_OUT(SoC DMIC, SSP, 0, OUT, 17)
+VIRTUAL_DAPM_ROUTE_IN(codec0_in, SSP, 0, IN, 18)
+
+
+
+
+
diff --git a/topology/sof-hsw-rt5640.m4 b/topology/sof-hsw-rt5640.m4
new file mode 100644
index 0000000..272cb15
--- /dev/null
+++ b/topology/sof-hsw-rt5640.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Haswell board with no codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Haswell DSP configuration
+include(`platform/intel/hsw.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+# |--low latency mixer ----> volume ----> SSP2
+# PCM2 ----> SRC -----> volume ----+
+# |
+# Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP0
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+ 1, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+ 2, 0, 2, s32le,
+ 48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+ 3, 1, 2, s32le,
+ 192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, s32le,
+ 192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-hsw-rt5640" {
+ index "0"
+
+ lines [
+ # media 0
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+ #tone
+ dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+ ]
+}
+
+#
+# DAI configuration
+#
+# SSP port 0 is our only pipeline DAI
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 0, Codec,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 0, Codec,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 0, Codec,
+ SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24000000, codec_mclk_in),
+ SSP_CLOCK(bclk, 2400000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 0, 24)))
diff --git a/topology/sof-icl-nocodec.m4 b/topology/sof-icl-nocodec.m4
new file mode 100644
index 0000000..1dffe18
--- /dev/null
+++ b/topology/sof-icl-nocodec.m4
@@ -0,0 +1,71 @@
+#
+# Topology for generic Icelake board with nocodec
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Icelake DSP configuration
+include(`platform/intel/icl.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> Volume ----> SSP0
+#
+# PCM1 <---- Volume <---- SSP0
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+ 1, 0, 2, s24le,
+ 48, 1000, 0, 0, SSP, 0, s24le, 2)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+ 2, 0, 2, s24le,
+ 48, 1000, 0, 0, SSP, 0, s24le, 2)
+
+#
+# DAI configuration
+#
+# SSP port 0 is our only pipeline DAI
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, SSP, 0, NoCodec-0,
+ PIPELINE_SOURCE_1, 2, s24le,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, SSP, 0, NoCodec-0,
+ PIPELINE_SINK_2, 2, s24le,
+ 48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Passthrough, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 0, NoCodec-0,
+ SSP_CONFIG(DSP_B, SSP_CLOCK(mclk, 38400000, codec_mclk_in),
+ SSP_CLOCK(bclk, 2400000, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, 25, 3, 3),
+ SSP_CONFIG_DATA(SSP, 0, 24)))
diff --git a/topology/sof/Makefile.am b/topology/sof/Makefile.am
new file mode 100644
index 0000000..fc92591
--- /dev/null
+++ b/topology/sof/Makefile.am
@@ -0,0 +1,14 @@
+EXTRA_DIST = \
+ pipe-dai-capture.m4 \
+ pipe-dai-playback.m4 \
+ pipe-low-latency-capture.m4 \
+ pipe-low-latency-playback.m4 \
+ pipe-passthrough-capture.m4 \
+ pipe-passthrough-playback.m4 \
+ pipe-pcm-media.m4 \
+ pipe-src-capture.m4 \
+ pipe-src-playback.m4 \
+ pipe-tone.m4 \
+ pipe-volume-capture.m4 \
+ pipe-volume-playback.m4 \
+ tokens.m4
diff --git a/topology/sof/pipe-dai-capture.m4 b/topology/sof/pipe-dai-capture.m4
new file mode 100644
index 0000000..c69d586
--- /dev/null
+++ b/topology/sof/pipe-dai-capture.m4
@@ -0,0 +1,22 @@
+# DAI Capture connector
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# DAI definitions
+#
+W_DAI_IN(DAI_TYPE, DAI_INDEX, DAI_BE, DAI_FORMAT, 2, 0, 0)
+
+#
+# DAI pipeline - always use 0 for DAIs
+#
+W_PIPELINE(N_DAI_IN, SCHEDULE_DEADLINE, SCHEDULE_PRIORITY, SCHEDULE_FRAMES, SCHEDULE_CORE, 0, pipe_dai_schedule_plat)
+
+#
+# Graph connections to pipelines
+
+P_GRAPH(DAI_NAME, PIPELINE_ID,
+ LIST(` ', `dapm(DAI_BUF, N_DAI_IN)'))
diff --git a/topology/sof/pipe-dai-playback.m4 b/topology/sof/pipe-dai-playback.m4
new file mode 100644
index 0000000..804b180
--- /dev/null
+++ b/topology/sof/pipe-dai-playback.m4
@@ -0,0 +1,22 @@
+# DAI Playback connector
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# DAI definitions
+#
+W_DAI_OUT(DAI_TYPE, DAI_INDEX, DAI_BE, DAI_FORMAT, 0, 2, 2)
+
+#
+# DAI pipeline - always use 0 for DAIs
+#
+W_PIPELINE(N_DAI_OUT, SCHEDULE_DEADLINE, SCHEDULE_PRIORITY, SCHEDULE_FRAMES, SCHEDULE_CORE, 0, pipe_dai_schedule_plat)
+
+#
+# Graph connections to pipelines
+
+P_GRAPH(DAI_NAME, PIPELINE_ID,
+ LIST(` ', `dapm(N_DAI_OUT, DAI_BUF)'))
diff --git a/topology/sof/pipe-low-latency-capture.m4 b/topology/sof/pipe-low-latency-capture.m4
new file mode 100644
index 0000000..39c2cce
--- /dev/null
+++ b/topology/sof/pipe-low-latency-capture.m4
@@ -0,0 +1,67 @@
+# Low Latency Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+# host PCM_C <--B5-- volume(0C) <--B4-- source DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`pga.m4')
+include(`mixercontrol.m4')
+
+#
+# Controls
+#
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(PCM PCM_ID Capture Volume, PIPELINE_ID,
+ CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+ CONTROLMIXER_MAX(, 40),
+ false,
+ CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+ Channel register and shift for Front Left/Right,
+ LIST(` ', KCONTROL_CHANNEL(FL, 0, 0), KCONTROL_CHANNEL(FR, 0, 1)))
+
+#
+# Components and Buffers
+#
+
+# Host "Low Latency Capture" PCM
+# with 0 sink and 2 source periods
+W_PCM_CAPTURE(PCM_ID, Low Latency Capture, 0, 2, 0)
+
+# "Capture Volume" has 2 sink and source periods for host and DAI ping-pong
+W_PGA(0, PIPELINE_FORMAT, 2, 2, 0, LIST(` ', "PCM PCM_ID Capture Volume PIPELINE_ID"))
+
+# Capture Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_DAI_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_HOST_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+# host PCM <--B1-- volume <--B0-- source DAI0
+
+P_GRAPH(pipe-ll-capture-PIPELINE_ID, PIPELINE_ID,
+ LIST(` ',
+ `dapm(Low Latency Capture PCM_ID, N_PCMC(PCM_ID))',
+ `dapm(N_PCMC(PCM_ID), N_BUFFER(1))',
+ `dapm(N_BUFFER(1), N_PGA(0))',
+ `dapm(N_PGA(0), N_BUFFER(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SINK_', PIPELINE_ID), N_BUFFER(0))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Low Latency Capture PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Low Latency Capture PCM_ID, `S32_LE,S24_LE,S16_LE', 48000, 48000, 2, 4, 2, 4, 192, 16384, 65536, 65536)
diff --git a/topology/sof/pipe-low-latency-playback.m4 b/topology/sof/pipe-low-latency-playback.m4
new file mode 100644
index 0000000..8cfe5e4
--- /dev/null
+++ b/topology/sof/pipe-low-latency-playback.m4
@@ -0,0 +1,119 @@
+# Low Latency Pipeline
+#
+# Low Latency Playback PCM mixed into single sink pipe.
+# Low latency Capture PCM.
+#
+# Pipeline Endpoints for connection are :-
+#
+# LL Playback Mixer (Mixer)
+# LL Capture Volume B4 (DAI buffer)
+# LL Playback Volume B3 (DAI buffer)
+#
+#
+# host PCM_P --B0--> volume(0P) --B1--+
+# |--ll mixer(M) --B2--> volume(LL) ---B3--> sink DAI0
+# pipeline n+1 >---+
+# |
+# pipeline n+2 >---+
+# |
+# pipeline n+3 >---+ .....etc....more pipes can be mixed here
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`pga.m4')
+include(`mixer.m4')
+include(`mixercontrol.m4')
+
+#
+# Controls
+#
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(PCM PCM_ID Playback Volume, PIPELINE_ID,
+ CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+ CONTROLMIXER_MAX(, 32),
+ false,
+ CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+ Channel register and shift for Front Left/Right,
+ LIST(KCONTROL_CHANNEL(FL, 0, 0), KCONTROL_CHANNEL(FR, 0, 1)))
+
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(Master Playback Volume, PIPELINE_ID,
+ CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+ CONTROLMIXER_MAX(, 32),
+ false,
+ CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+ Channel register and shift for Front Left/Right,
+ LIST(` ', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
+
+#
+# Components and Buffers
+#
+
+# Host "Low latency Playback" PCM
+# with 2 sink and 0 source periods
+W_PCM_PLAYBACK(PCM_ID, Low Latency Playback, 2, 0, 2)
+
+# "Playback Volume" has 1 sink period and 2 source periods for host ping-pong
+W_PGA(0, PIPELINE_FORMAT, 1, 2, 1, LIST(` ', "PCM PCM_ID Playback Volume PIPELINE_ID"))
+
+# "Master Playback Volume" has 1 source and 2 sink periods for DAI ping-pong
+W_PGA(1, PIPELINE_FORMAT, 2, 1, 1, LIST(` ', "Master Playback Volume PIPELINE_ID"))
+
+# Mixer 0 has 1 sink and source periods.
+W_MIXER(0, PIPELINE_FORMAT, 1, 1, 1)
+
+# Low Latency Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(1,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS,SCHEDULE_FRAMES),
+ PLATFORM_COMP_MEM_CAP)
+W_BUFFER(2, COMP_BUFFER_SIZE(1,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_COMP_MEM_CAP)
+W_BUFFER(3, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_DAI_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+# host PCM_P --B0--> volume(0P) --B1--+
+# |--ll mixer(M) --B2--> volume(LL) ---B3--> sink DAI0
+# pipeline n+1 >---+
+# |
+# pipeline n+2 >---+
+# |
+# pipeline n+3 >---+ .....etc....more pipes can be mixed here
+#
+
+P_GRAPH(pipe-ll-playback-PIPELINE_ID, PIPELINE_ID,
+ LIST(` ',
+ `dapm(N_PCMP(PCM_ID), Low Latency Playback PCM_ID)',
+ `dapm(N_BUFFER(0), N_PCMP(PCM_ID))',
+ `dapm(N_PGA(0), N_BUFFER(0))',
+ `dapm(N_BUFFER(1), N_PGA(0))',
+ `dapm(N_MIXER(0), N_BUFFER(1))',
+ `dapm(N_BUFFER(2), N_MIXER(0))',
+ `dapm(N_PGA(1), N_BUFFER(2))',
+ `dapm(N_BUFFER(3), N_PGA(1))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(3))
+indir(`define', concat(`PIPELINE_MIXER_', PIPELINE_ID), N_MIXER(0))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Low Latency Playback PCM_ID)
+
+#
+# PCM Configuration
+#
+
+
+# PCM capabilities supported by FW
+PCM_CAPABILITIES(Low Latency Playback PCM_ID, `S32_LE,S24_LE,S16_LE', 48000, 48000, 2, 2, 2, 16, 192, 16384, 65536, 65536)
+
diff --git a/topology/sof/pipe-passthrough-capture.m4 b/topology/sof/pipe-passthrough-capture.m4
new file mode 100644
index 0000000..4614083
--- /dev/null
+++ b/topology/sof/pipe-passthrough-capture.m4
@@ -0,0 +1,47 @@
+# Capture Passthrough Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+# host PCM_C <-- B0 <-- sink DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Capture" PCM
+# with 0 sink and 2 source periods
+W_PCM_CAPTURE(PCM_ID, Passthrough Capture, 0, 2, 2)
+
+# Capture Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_PASS_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+# host PCM_C <-- B0 <-- sink DAI0
+
+P_GRAPH(pipe-pass-capture-PIPELINE_ID, PIPELINE_ID,
+ LIST(` ',
+ `dapm(Passthrough Capture PCM_ID, N_PCMC(PCM_ID))',
+ `dapm(N_PCMC(PCM_ID), N_BUFFER(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SINK_', PIPELINE_ID), N_BUFFER(0))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Capture PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Passthrough Capture PCM_ID, COMP_FORMAT_NAME(PIPELINE_FORMAT), 8000, 192000, 1, 16, 2, 16, 192, 16384, 65536, 65536)
diff --git a/topology/sof/pipe-passthrough-playback.m4 b/topology/sof/pipe-passthrough-playback.m4
new file mode 100644
index 0000000..c7c1237
--- /dev/null
+++ b/topology/sof/pipe-passthrough-playback.m4
@@ -0,0 +1,47 @@
+# Low Latency Passthrough Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+# host PCM_P --> B0 --> sink DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Playback" PCM
+# with 2 sink and 0 source periods
+W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, 2, 0, 2)
+
+# Playback Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_PASS_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+# host PCM_P --> B0 --> sink DAI0
+
+P_GRAPH(pipe-pass-playback-PIPELINE_ID, PIPELINE_ID,
+ LIST(` ',
+ `dapm(N_PCMP(PCM_ID), Passthrough Playback PCM_ID)',
+ `dapm(N_BUFFER(0), N_PCMP(PCM_ID))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(0))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Playback PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Passthrough Playback PCM_ID, COMP_FORMAT_NAME(PIPELINE_FORMAT), 48000, 48000, 2, 4, 2, 16, 192, 16384, 65536, 65536)
diff --git a/topology/sof/pipe-pcm-media.m4 b/topology/sof/pipe-pcm-media.m4
new file mode 100644
index 0000000..b526e43
--- /dev/null
+++ b/topology/sof/pipe-pcm-media.m4
@@ -0,0 +1,117 @@
+# Low Power PCM Media Pipeline
+#
+# Low power PCM media playback with SRC and volume.
+#
+# Pipeline Endpoints for connection are :-
+#
+# host PCM_P --B0--> volume(0P) --B1--> SRC -- B2 --> Endpoint Pipeline
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`src.m4')
+include(`buffer.m4')
+include(`pga.m4')
+include(`mixercontrol.m4')
+include(`pipeline.m4')
+include(`pcm.m4')
+
+#
+# Controls
+#
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(PCM PCM_ID Playback Volume, PIPELINE_ID,
+ CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+ CONTROLMIXER_MAX(, 32),
+ false,
+ CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+ Channel register and shift for Front Left/Right,
+ LIST(` ', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
+
+#
+# SRC Configuration
+#
+
+W_VENDORTUPLES(media_src_tokens, sof_src_tokens, LIST(` ', `SOF_TKN_SRC_RATE_OUT "48000"'))
+
+W_DATA(media_src_conf, media_src_tokens)
+
+#
+# Components and Buffers
+#
+
+# Host "Low latency Playback" PCM
+# with 2 sink and 0 source periods
+W_PCM_PLAYBACK(PCM_ID, Media Playback, 2, 0, 2)
+
+# "Playback Volume" has 2 sink period and 2 source periods for host ping-pong
+W_PGA(0, PIPELINE_FORMAT, 2, 2, 2, LIST(` ', "PCM PCM_ID Playback Volume PIPELINE_ID"))
+
+# "SRC 0" has 2 sink and source periods.
+W_SRC(0, PIPELINE_FORMAT, 2, 2, media_src_conf, 2)
+
+# Media Source Buffers to SRC, make them big enough to deal with 2 * rate.
+W_BUFFER(0, COMP_BUFFER_SIZE(4,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1,COMP_BUFFER_SIZE(4,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_COMP_MEM_CAP)
+
+# Buffer B2 is on fixed rate sink side of SRC. Set it 1.5 * rate.
+W_BUFFER(2, COMP_BUFFER_SIZE(3,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_COMP_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+# PCM --B0--> volume --B1--> SRC --> B2 --> Endpoint Pipeline
+#
+
+P_GRAPH(pipe-media-PIPELINE_ID, PIPELINE_ID,
+ LIST(` ',
+ `dapm(N_PCMP(PCM_ID), Media Playback PCM_ID)',
+ `dapm(N_BUFFER(0), N_PCMP(PCM_ID))',
+ `dapm(N_PGA(0), N_BUFFER(0))',
+ `dapm(N_BUFFER(1), N_PGA(0))',
+ `dapm(N_SRC(0), N_BUFFER(1))'
+ `dapm(N_BUFFER(2), N_SRC(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(2))
+
+#
+# Pipeline Configuration.
+#
+
+W_PIPELINE(N_SRC(0), SCHEDULE_DEADLINE, SCHEDULE_PRIORITY, SCHEDULE_FRAMES, SCHEDULE_CORE, 1, pipe_media_schedule_plat)
+
+#
+# PCM Configuration
+#
+
+# PCM capabilities supported by FW
+
+PCM_CAPABILITIES(Media Playback PCM_ID, `S32_LE,S24_LE,S16_LE', 8000, 192000, 2, 2, 2, 32, 192, 262144, 8388608, 8388608)
+
+# PCM Low Latency Playback and Capture
+SectionPCM.STR(Media Playback PCM_ID) {
+
+ index STR(PIPELINE_ID)
+
+ # used for binding to the PCM
+ id STR(PCM_ID)
+
+ dai.STR(Media Playback PCM_ID) {
+ id STR(PCM_ID)
+ }
+
+ # Playback and Capture Configuration
+ pcm."playback" {
+
+ capabilities STR(Media Playback PCM_ID)
+ }
+}
diff --git a/topology/sof/pipe-src-capture.m4 b/topology/sof/pipe-src-capture.m4
new file mode 100644
index 0000000..e0a68e4
--- /dev/null
+++ b/topology/sof/pipe-src-capture.m4
@@ -0,0 +1,64 @@
+# Low Latency Passthrough with volume Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+# host PCM_P --> SRC --> sink DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`src.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Capture" PCM
+# with 4 sink and 0 source periods
+W_PCM_CAPTURE(PCM_ID, Passthrough Capture, 4, 0, 2)
+
+#
+# SRC Configuration
+#
+
+W_VENDORTUPLES(media_src_tokens, sof_src_tokens, LIST(` ', `SOF_TKN_SRC_RATE_OUT "48000"'))
+
+W_DATA(media_src_conf, media_src_tokens)
+
+# "SRC" has 4 source and 4 sink periods
+W_SRC(0, PIPELINE_FORMAT, 4, 4, media_src_conf, 2)
+
+# Capture Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(4,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(4,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_DAI_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+# host PCM_P <-- B0 <-- SRC 0 <-- B1 <-- sink DAI0
+
+P_GRAPH(pipe-pass-src-capture-PIPELINE_ID, PIPELINE_ID,
+ LIST(` ',
+ `dapm(Passthrough Capture PCM_ID, N_PCMC(PCM_ID))',
+ `dapm(N_PCMC(PCM_ID), N_BUFFER(0))',
+ `dapm(N_BUFFER(0), N_SRC(0))',
+ `dapm(N_SRC(0), N_BUFFER(1))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SINK_', PIPELINE_ID), N_BUFFER(1))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Capture PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Passthrough Capture PCM_ID, `S32_LE,S24_LE,S16_LE', 8000, 96000, 2, 4, 2, 16, 192, 16384, 65536, 65536)
diff --git a/topology/sof/pipe-src-playback.m4 b/topology/sof/pipe-src-playback.m4
new file mode 100644
index 0000000..ce05b94
--- /dev/null
+++ b/topology/sof/pipe-src-playback.m4
@@ -0,0 +1,65 @@
+# Low Latency Passthrough with volume Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+# host PCM_P --> SRC --> sink DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`src.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Playback" PCM
+# with 3 sink and 0 source periods
+W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, 3, 0, 2)
+
+#
+# SRC Configuration
+#
+
+W_VENDORTUPLES(media_src_tokens, sof_src_tokens, LIST(` ', `SOF_TKN_SRC_RATE_OUT "48000"'))
+
+W_DATA(media_src_conf, media_src_tokens)
+
+# "SRC" has 3 source and 3 sink periods
+W_SRC(0, PIPELINE_FORMAT, 3, 3, media_src_conf, 2)
+
+# Playback Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(3,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(3,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_DAI_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+# host PCM_P --> B0 --> SRC 0 --> B1 --> sink DAI0
+
+P_GRAPH(pipe-pass-src-playback-PIPELINE_ID, PIPELINE_ID,
+ LIST(` ',
+ `dapm(N_PCMP(PCM_ID), Passthrough Playback PCM_ID)',
+ `dapm(N_BUFFER(0), N_PCMP(PCM_ID))',
+ `dapm(N_SRC(0), N_BUFFER(0))',
+ `dapm(N_BUFFER(1), N_SRC(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(1))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Playback PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Passthrough Playback PCM_ID, `S32_LE,S24_LE,S16_LE', 8000, 192000, 2, 8, 2, 16, 192, 16384, 65536, 65536)
+
diff --git a/topology/sof/pipe-tone.m4 b/topology/sof/pipe-tone.m4
new file mode 100644
index 0000000..fc5eb00
--- /dev/null
+++ b/topology/sof/pipe-tone.m4
@@ -0,0 +1,80 @@
+# Tone Generator
+#
+# Multi Frequency Tone Generator.
+#
+# Pipeline Endpoints for connection are :-
+#
+# Tone --B0--> volume --B1--> Endpoint Pipeline
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pga.m4')
+include(`tone.m4')
+include(`mixercontrol.m4')
+include(`pipeline.m4')
+
+#
+# Controls
+#
+
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(Tone Volume, PIPELINE_ID,
+ CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+ CONTROLMIXER_MAX(, 32),
+ false,
+ CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+ Channel register and shift for Front Left/Right,
+ LIST(` ', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
+
+# Switch type Mixer Control with max value of 1
+C_CONTROLMIXER(Tone Switch, PIPELINE_ID,
+ CONTROLMIXER_OPS(volsw, 259 binds the mixer control to switch get/put handlers, 259, 259),
+ CONTROLMIXER_MAX(max 1 indicates switch type control, 1),
+ false,
+ ,
+ Channel register and shift for Front Left/Right,
+ LIST(` ', KCONTROL_CHANNEL(FL, 2, 0), KCONTROL_CHANNEL(FR, 2, 1)))
+
+#
+# Components and Buffers
+#
+
+# "Tone 0" has 2 sink period and 0 source periods
+W_TONE(0, PIPELINE_FORMAT, 2, 0, 0, LIST(` ', "Tone Switch PIPELINE_ID"))
+
+# "Tone Volume" has 2 sink period and 2 source periods
+W_PGA(0, PIPELINE_FORMAT, 2, 2, 0, LIST(` ', "Tone Volume PIPELINE_ID"))
+
+# Low Latency Buffers
+W_BUFFER(0,COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_COMP_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_COMP_MEM_CAP)
+
+
+#
+# Pipeline Graph
+#
+# Tone --B0--> volume --B1--> Endpoint Pipeline
+#
+
+P_GRAPH(pipe-tone-PIPELINE_ID, PIPELINE_ID,
+ LIST(` ',
+ `dapm(N_BUFFER(0), N_TONE(0))',
+ `dapm(N_PGA(0), N_BUFFER(0))',
+ `dapm(N_BUFFER(1), N_PGA(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(1))
+
+#
+# Pipeline Configuration.
+#
+
+W_PIPELINE(N_TONE(0), SCHEDULE_DEADLINE, SCHEDULE_PRIORITY, SCHEDULE_FRAMES, SCHEDULE_CORE, 0, pipe_tone_schedule_plat)
diff --git a/topology/sof/pipe-volume-capture.m4 b/topology/sof/pipe-volume-capture.m4
new file mode 100644
index 0000000..820b745
--- /dev/null
+++ b/topology/sof/pipe-volume-capture.m4
@@ -0,0 +1,70 @@
+# Passthrough with volume Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+# host PCM_C <-- B0 <-- Volume 0 <-- B1 <-- source DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`pga.m4')
+include(`dai.m4')
+include(`mixercontrol.m4')
+include(`pipeline.m4')
+
+#
+# Controls
+#
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(Master Capture Volume, PIPELINE_ID,
+ CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+ CONTROLMIXER_MAX(, 32),
+ false,
+ CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+ Channel register and shift for Front Left/Right,
+ LIST(` ', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Capture" PCM
+# with 0 sink and 2 source periods
+W_PCM_CAPTURE(PCM_ID, Passthrough Capture, 0, 2, 2)
+
+# "Volume" has 2 source and 2 sink periods
+W_PGA(0, PIPELINE_FORMAT, 2, 2, 2, LIST(` ', "Master Capture Volume PIPELINE_ID"))
+
+# Capture Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(DAI_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_DAI_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+# host PCM_P <-- B0 <-- Volume 0 <-- B1 <-- sink DAI0
+
+P_GRAPH(pipe-pass-vol-capture-PIPELINE_ID, PIPELINE_ID,
+ LIST(` ',
+ `dapm(Passthrough Capture PCM_ID, N_PCMC(PCM_ID))',
+ `dapm(N_PCMC(PCM_ID), N_BUFFER(0))',
+ `dapm(N_BUFFER(0), N_PGA(0))',
+ `dapm(N_PGA(0), N_BUFFER(1))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SINK_', PIPELINE_ID), N_BUFFER(1))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Capture PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Passthrough Capture PCM_ID, `S32_LE,S24_LE,S16_LE', 48000, 48000, 2, 8, 2, 16, 192, 16384, 65536, 65536)
+
diff --git a/topology/sof/pipe-volume-playback.m4 b/topology/sof/pipe-volume-playback.m4
new file mode 100644
index 0000000..4ebd02d
--- /dev/null
+++ b/topology/sof/pipe-volume-playback.m4
@@ -0,0 +1,71 @@
+# Low Latency Passthrough with volume Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+# host PCM_P --> B0 --> Volume 0 --> B1 --> sink DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`pga.m4')
+include(`dai.m4')
+include(`mixercontrol.m4')
+include(`pipeline.m4')
+
+#
+# Controls
+#
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(Master Playback Volume, PIPELINE_ID,
+ CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+ CONTROLMIXER_MAX(, 32),
+ false,
+ CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+ Channel register and shift for Front Left/Right,
+ LIST(` ', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Playback" PCM
+# with 2 sink and 0 source periods
+W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, 2, 0, 2)
+
+# "Volume" has 2 source and 2 sink periods
+W_PGA(0, PIPELINE_FORMAT, 2, 2, 2, LIST(` ', "Master Playback Volume PIPELINE_ID"))
+
+# Playback Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(2,
+ COMP_SAMPLE_SIZE(DAI_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+ PLATFORM_DAI_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+# host PCM_P --> B0 --> Volume 0 --> B1 --> sink DAI0
+
+P_GRAPH(pipe-pass-vol-playback-PIPELINE_ID, PIPELINE_ID,
+ LIST(` ',
+ `dapm(N_PCMP(PCM_ID), Passthrough Playback PCM_ID)',
+ `dapm(N_BUFFER(0), N_PCMP(PCM_ID))',
+ `dapm(N_PGA(0), N_BUFFER(0))',
+ `dapm(N_BUFFER(1), N_PGA(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(1))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Playback PCM_ID)
+
+
+#
+# PCM Configuration
+
+#
+PCM_CAPABILITIES(Passthrough Playback PCM_ID, `S32_LE,S24_LE,S16_LE', 48000, 48000, 2, 8, 2, 16, 192, 16384, 65536, 65536)
+
diff --git a/topology/sof/tokens.m4 b/topology/sof/tokens.m4
new file mode 100644
index 0000000..4aa2fea
--- /dev/null
+++ b/topology/sof/tokens.m4
@@ -0,0 +1,84 @@
+
+#
+# SOF Tokens for differentiation.
+#
+# Differentiation can be done at the platform and machine level.
+#
+# Tokens are GUIDs
+
+# TODO: pre-process this with UAPI headers GNU cpp.
+
+
+SectionVendorTokens."sof_buffer_tokens" {
+ SOF_TKN_BUF_SIZE "100"
+ SOF_TKN_BUF_CAPS "101"
+}
+
+SectionVendorTokens."sof_dai_tokens" {
+ SOF_TKN_DAI_DMAC_CONFIG "153"
+ SOF_TKN_DAI_TYPE "154"
+ SOF_TKN_DAI_INDEX "155"
+}
+
+SectionVendorTokens."sof_sched_tokens" {
+ SOF_TKN_SCHED_DEADLINE "200"
+ SOF_TKN_SCHED_PRIORITY "201"
+ SOF_TKN_SCHED_MIPS "202"
+ SOF_TKN_SCHED_CORE "203"
+ SOF_TKN_SCHED_FRAMES "204"
+ SOF_TKN_SCHED_TIMER "205"
+}
+
+SectionVendorTokens."sof_volume_tokens" {
+ SOF_TKN_VOLUME_RAMP_STEP_TYPE "250"
+ SOF_TKN_VOLUME_RAMP_STEP_MS "251"
+}
+
+SectionVendorTokens."sof_src_tokens" {
+ SOF_TKN_SRC_RATE_IN "300"
+ SOF_TKN_SRC_RATE_OUT "301"
+}
+
+SectionVendorTokens."sof_pcm_tokens" {
+ SOF_TKN_PCM_DMAC_CONFIG "353"
+}
+
+SectionVendorTokens."sof_comp_tokens" {
+ SOF_TKN_COMP_PERIOD_SINK_COUNT "400"
+ SOF_TKN_COMP_PERIOD_SOURCE_COUNT "401"
+ SOF_TKN_COMP_FORMAT "402"
+ SOF_TKN_COMP_PRELOAD_COUNT "403"
+}
+
+SectionVendorTokens."sof_ssp_tokens" {
+ SOF_TKN_INTEL_SSP_MCLK_KEEP_ACTIVE "500"
+ SOF_TKN_INTEL_SSP_BCLK_KEEP_ACTIVE "501"
+ SOF_TKN_INTEL_SSP_FS_KEEP_ACTIVE "502"
+ SOF_TKN_INTEL_SSP_MCLK_ID "503"
+ SOF_TKN_INTEL_SSP_SAMPLE_BITS "504"
+}
+
+SectionVendorTokens."sof_dmic_tokens" {
+ SOF_TKN_INTEL_DMIC_DRIVER_VERSION "600"
+ SOF_TKN_INTEL_DMIC_CLK_MIN "601"
+ SOF_TKN_INTEL_DMIC_CLK_MAX "602"
+ SOF_TKN_INTEL_DMIC_DUTY_MIN "603"
+ SOF_TKN_INTEL_DMIC_DUTY_MAX "604"
+ SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE "605"
+ SOF_TKN_INTEL_DMIC_SAMPLE_RATE "608"
+ SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH "609"
+}
+
+SectionVendorTokens."sof_dmic_pdm_tokens" {
+ SOF_TKN_INTEL_DMIC_PDM_CTRL_ID "700"
+ SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable "701"
+ SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable "702"
+ SOF_TKN_INTEL_DMIC_PDM_POLARITY_A "703"
+ SOF_TKN_INTEL_DMIC_PDM_POLARITY_B "704"
+ SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE "705"
+ SOF_TKN_INTEL_DMIC_PDM_SKEW "706"
+}
+
+SectionVendorTokens."sof_tone_tokens" {
+ SOF_TKN_TONE_SAMPLE_RATE "800"
+}
diff --git a/topology/test/Makefile.am b/topology/test/Makefile.am
new file mode 100644
index 0000000..3a613e8
--- /dev/null
+++ b/topology/test/Makefile.am
@@ -0,0 +1,32 @@
+
+#
+# Dependencies
+#
+
+if XARGS
+export USE_XARGS=yes
+endif
+
+DEPS = \
+ ../platform/intel/*.m4 \
+ ../common/*.m4 \
+ ../m4/*.m4 \
+ ../sof/*.m4
+
+# Uncomment the following line if you want to debug conf files
+.PRECIOUS: %.conf
+
+all : *.m4 ${DEPS}
+ ./tplg-build.sh
+
+clean-local:
+ rm -f *.conf
+ rm -f *.tplg
+
+
+EXTRA_DIST = \
+ test-capture.m4 \
+ test-playback.m4 \
+ test-tone-playback.m4 \
+ test-all.m4 \
+ tplg-build.sh
diff --git a/topology/test/test-all.m4 b/topology/test/test-all.m4
new file mode 100644
index 0000000..518c909
--- /dev/null
+++ b/topology/test/test-all.m4
@@ -0,0 +1,97 @@
+#
+# Topology for pass through pipeline
+#
+
+# Include topology builder
+include(`dai.m4')
+include(`ssp.m4')
+include(`utils.m4')
+include(`pipeline.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`byt.m4')
+
+#
+# Machine Specific Config - !! MUST BE SET TO MATCH TEST MACHINE DRIVER !!
+#
+# TEST_PIPE_NAME - Pipe name
+# TEST_DAI_LINK_NAME - BE DAI link name e.g. "NoCodec"
+# TEST_DAI_PORT - SSP port number e.g. 2
+# TEST_DAI_FORMAT - SSP data format e.g s16le
+# TEST_PIPE_FORMAT - Pipeline format e.g. s16le
+# TEST_SSP_MCLK - SSP BCLK in Hz
+# TEST_SSP_BCLK - SSP BCLK in Hz
+# TEST_SSP_PHY_BITS - SSP physical slot size
+# TEST_SSP_DATA_BITS - SSP data slot size
+# TEST_SSP_MODE - SSP mode e.g. I2S, LEFT_J, DSP_A and DSP_B
+#
+
+#
+# Define the pipeline
+#
+# PCM0 <-- TEST_PIPE_NAME pipe --> SSP TEST_DAI_PORT
+#
+
+# Passthrough playback pipeline 1 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+
+PIPELINE_PCM_DAI_ADD(sof/pipe-TEST_PIPE_NAME-playback.m4,
+ 1, 0, 2, TEST_PIPE_FORMAT,
+ 48, 1000, 0, 0,
+ TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_FORMAT, 2)
+
+
+# Passthrough playback pipeline 2 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+
+PIPELINE_PCM_DAI_ADD(sof/pipe-TEST_PIPE_NAME-capture.m4,
+ 2, 0, 2, TEST_PIPE_FORMAT,
+ 48, 1000, 0, 0,
+ TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_FORMAT, 2)
+
+#
+# DAI configuration
+#
+# SSP port TEST_DAI_PORT is our only pipeline DAI
+#
+
+# playback DAI is SSP TEST_DAI_PORT using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+ PIPELINE_SOURCE_1, 2, TEST_DAI_FORMAT,
+ 48, 1000, 0, 0)
+
+# capture DAI is SSP TEST_DAI_PORT using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+ PIPELINE_SINK_2, 2, TEST_DAI_FORMAT,
+ 48, 1000, 0, 0)
+
+# PCM Passthrough
+PCM_DUPLEX_ADD(Passthrough, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+# Clocks masters wrt codec
+#
+# TEST_SSP_DATA_BITS bit I2S using TEST_SSP_PHY_BITS bit sample conatiner on SSP TEST_DAI_PORT
+#
+DAI_CONFIG(TEST_DAI_TYPE, TEST_DAI_PORT,
+ ifelse(index(TEST_DAI_LINK_NAME, NoCodec), -1, 0 ,TEST_DAI_PORT),
+ TEST_DAI_LINK_NAME,
+ SSP_CONFIG(TEST_SSP_MODE,
+ SSP_CLOCK(mclk, TEST_SSP_MCLK, codec_mclk_in),
+ SSP_CLOCK(bclk, TEST_SSP_BCLK, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, TEST_SSP_PHY_BITS, 3, 3),
+ SSP_CONFIG_DATA(TEST_DAI_TYPE, TEST_DAI_PORT,
+ TEST_SSP_DATA_BITS, TEST_SSP_MCLK_ID)))
diff --git a/topology/test/test-capture.m4 b/topology/test/test-capture.m4
new file mode 100644
index 0000000..4e10d3d
--- /dev/null
+++ b/topology/test/test-capture.m4
@@ -0,0 +1,89 @@
+#
+# Topology for pass through pipeline
+#
+
+# Include topology builder
+include(`dai.m4')
+include(`ssp.m4')
+include(`dmic.m4')
+include(`utils.m4')
+include(`pipeline.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`byt.m4')
+
+#
+# Machine Specific Config - !! MUST BE SET TO MATCH TEST MACHINE DRIVER !!
+#
+# TEST_PIPE_NAME - Pipe name
+# TEST_DAI_LINK_NAME - BE DAI link name e.g. "NoCodec"
+# TEST_DAI_PORT - SSP port number e.g. 2
+# TEST_DAI_FORMAT - SSP data format e.g s16le
+# TEST_PIPE_FORMAT - Pipeline format e.g. s16le
+# TEST_SSP_MCLK - SSP MCLK in Hz
+# TEST_SSP_BCLK - SSP BCLK in Hz
+# TEST_SSP_PHY_BITS - SSP physical slot size
+# TEST_SSP_DATA_BITS - SSP data slot size
+# TEST_SSP_MODE - SSP mode e.g. I2S, LEFT_J, DSP_A and DSP_B
+#
+
+#
+# Define the pipeline
+#
+# PCM0 <---> SSP TEST_DAI_PORT
+#
+
+# Passthrough capture pipeline 2 on PCM 0 using max 4 channels.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+
+PIPELINE_PCM_DAI_ADD(sof/pipe-TEST_PIPE_NAME-capture.m4,
+ 2, 0, 4, TEST_PIPE_FORMAT,
+ 48, 1000, 0, 0,
+ TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_FORMAT, 2)
+
+#
+# DAI configuration
+#
+# SSP port TEST_DAI_PORT is our only pipeline DAI
+#
+# capture DAI is SSP TEST_DAI_PORT using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+ 2, TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+ PIPELINE_SINK_2, 2, TEST_DAI_FORMAT,
+ 48, 1000, 0, 0)
+
+# PCM Passthrough
+PCM_CAPTURE_ADD(Passthrough, 0, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+# Clocks masters wrt codec
+#
+# TEST_SSP_DATA_BITS bit I2S using TEST_SSP_PHY_BITS bit sample conatiner on SSP TEST_DAI_PORT
+#
+DAI_CONFIG(TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+ ifelse(TEST_DAI_TYPE, `SSP',
+ SSP_CONFIG(TEST_SSP_MODE,
+ SSP_CLOCK(mclk, TEST_SSP_MCLK, codec_mclk_in),
+ SSP_CLOCK(bclk, TEST_SSP_BCLK, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, TEST_SSP_PHY_BITS, 3, 3),
+ SSP_CONFIG_DATA(TEST_DAI_TYPE, TEST_DAI_PORT,
+ TEST_SSP_DATA_BITS, TEST_SSP_MCLK_ID)),
+ TEST_DAI_TYPE, `DMIC',
+ DMIC_CONFIG(TEST_DMIC_DRIVER_VERSION, TEST_DMIC_CLK_MIN,
+ TEST_DMIC_CLK_MAX, TEST_DMIC_DUTY_MIN,
+ TEST_DMIC_DUTY_MAX, TEST_DMIC_SAMPLE_RATE,
+ DMIC_WORD_LENGTH(TEST_DAI_FORMAT),
+ TEST_DAI_TYPE, TEST_DAI_PORT,
+ PDM_CONFIG(TEST_DAI_TYPE, TEST_DAI_PORT,
+ TEST_DMIC_PDM_CONFIG)),
+ `'))
diff --git a/topology/test/test-playback.m4 b/topology/test/test-playback.m4
new file mode 100644
index 0000000..9833ea9
--- /dev/null
+++ b/topology/test/test-playback.m4
@@ -0,0 +1,78 @@
+#
+# Topology for pass through pipeline
+#
+
+# Include topology builder
+include(`pipeline.m4')
+include(`dai.m4')
+include(`ssp.m4')
+include(`utils.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`byt.m4')
+
+#
+# Machine Specific Config - !! MUST BE SET TO MATCH TEST MACHINE DRIVER !!
+#
+# TEST_PIPE_NAME - Pipe name
+# TEST_DAI_LINK_NAME - BE DAI link name e.g. "NoCodec"
+# TEST_DAI_PORT - SSP port number e.g. 2
+# TEST_DAI_FORMAT - SSP data format e.g s16le
+# TEST_PIPE_FORMAT - Pipeline format e.g. s16le
+# TEST_SSP_MCLK - SSP MCLK in Hz
+# TEST_SSP_BCLK - SSP BCLK in Hz
+# TEST_SSP_PHY_BITS - SSP physical slot size
+# TEST_SSP_DATA_BITS - SSP data slot size
+# TEST_SSP_MODE - SSP mode e.g. I2S, LEFT_J, DSP_A and DSP_B
+#
+
+#
+# Define the pipeline
+#
+# PCM0 <---> SSP TEST_DAI_PORT
+#
+
+# Passthrough playback pipeline 1 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+
+PIPELINE_PCM_DAI_ADD(sof/pipe-TEST_PIPE_NAME-playback.m4,
+ 1, 0, 2, TEST_PIPE_FORMAT,
+ 48, 1000, 0, 0,
+ TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_FORMAT, 2)
+#
+# DAI configuration
+#
+# SSP port TEST_DAI_PORT is our only pipeline DAI
+#
+
+# playback DAI is SSP TEST_DAI_PORT using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 1, TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+ PIPELINE_SOURCE_1, 2, TEST_DAI_FORMAT,
+ 48, 1000, 0, 0)
+
+# PCM Passthrough
+PCM_PLAYBACK_ADD(Passthrough, 0, PIPELINE_PCM_1)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+# Clocks masters wrt codec
+#
+# TEST_SSP_DATA_BITS bit I2S using TEST_SSP_PHY_BITS bit sample conatiner on SSP TEST_DAI_PORT
+#
+DAI_CONFIG(TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+ SSP_CONFIG(TEST_SSP_MODE,
+ SSP_CLOCK(mclk, TEST_SSP_MCLK, codec_slave),
+ SSP_CLOCK(bclk, TEST_SSP_BCLK, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, TEST_SSP_PHY_BITS, 3, 3),
+ SSP_CONFIG_DATA(TEST_DAI_TYPE, TEST_DAI_PORT,
+ TEST_SSP_DATA_BITS, TEST_SSP_MCLK_ID)))
diff --git a/topology/test/test-tone-playback.m4 b/topology/test/test-tone-playback.m4
new file mode 100644
index 0000000..77db4d1
--- /dev/null
+++ b/topology/test/test-tone-playback.m4
@@ -0,0 +1,70 @@
+#
+# Topology for Tone Generator Playback
+#
+
+# Include topology builder
+include(`pipeline.m4')
+include(`dai.m4')
+include(`ssp.m4')
+include(`utils.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`byt.m4')
+
+#
+# Machine Specific Config - !! MUST BE SET TO MATCH TEST MACHINE DRIVER !!
+#
+# TEST_PIPE_NAME - Pipe name
+# TEST_DAI_LINK_NAME - BE DAI link name e.g. "NoCodec"
+# TEST_DAI_PORT - SSP port number e.g. 2
+# TEST_DAI_FORMAT - SSP data format e.g s16le
+# TEST_PIPE_FORMAT - Pipeline format e.g. s16le
+# TEST_SSP_MCLK - SSP MCLK in Hz
+# TEST_SSP_BCLK - SSP BCLK in Hz
+# TEST_SSP_PHY_BITS - SSP physical slot size
+# TEST_SSP_DATA_BITS - SSP data slot size
+#
+
+#
+# Define the pipeline
+#
+# Tone --B0--> volume --B1--> SSP2
+#
+
+# Set sample rate for tone
+define(`TONE_SAMPLE_RATE', 48000)
+
+# Tone Playback pipeline 5 using max 2 channels of TEST_PIPE_FORMAT.
+# Schedule with 48 frame per 1000us deadline on core 0 with priority 0
+PIPELINE_ADD(sof/pipe-tone.m4,
+ 5, 2, TEST_PIPE_FORMAT,
+ 48, 1000, 0, 0)
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use TEST_DAI_FORMAT format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+ 5, TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+ PIPELINE_SOURCE_5, 2, TEST_DAI_FORMAT,
+ 48, 1000, 2, 0)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+# Clocks masters wrt codec
+#
+# TEST_SSP_DATA_BITS bit I2S using TEST_SSP_PHY_BITS bit sample conatiner on SSP TEST_DAI_PORT
+#
+DAI_CONFIG(TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+ SSP_CONFIG(TEST_SSP_MODE,
+ SSP_CLOCK(mclk, TEST_SSP_MCLK, codec_mclk_in),
+ SSP_CLOCK(bclk, TEST_SSP_BCLK, codec_slave),
+ SSP_CLOCK(fsync, 48000, codec_slave),
+ SSP_TDM(2, TEST_SSP_PHY_BITS, 3, 3),
+ SSP_CONFIG_DATA(TEST_DAI_TYPE, TEST_DAI_PORT,
+ TEST_SSP_DATA_BITS, TEST_SSP_MCLK_ID)))
diff --git a/topology/test/tplg-build.sh b/topology/test/tplg-build.sh
new file mode 100755
index 0000000..bd50593
--- /dev/null
+++ b/topology/test/tplg-build.sh
@@ -0,0 +1,252 @@
+#!/bin/bash
+
+# Utility script to pre-process and compile topology sources into topology test
+# binaries. Currently supports simple PCM <-> component <-> SSP style tests
+# using simple_test()
+
+# fail immediately on any errors
+set -e
+
+# M4 preprocessor flags
+export M4PATH="../:../m4:../common:../platform/intel:../platform/common"
+
+# Simple component test cases
+# can be used on components with 1 sink and 1 source.
+SIMPLE_TESTS=(test-all test-capture test-playback)
+TONE_TEST=test-tone-playback
+DMIC_TEST=test-capture
+TEST_STRINGS=""
+M4_STRINGS=""
+# process m4 simple tests -
+# simple_test(name, pipe_name, be_name, format, dai_id, dai_format, dai_phy_bits, dai_data_bits dai_bclk)
+# 1) name - test filename suffix
+# 2) pipe_name - test component pipeline filename in sof/
+# 3) be_name - BE DAI link name in machine driver, used for matching
+# 4) format - PCM sample format
+# 5) dai_type - dai type e.g. SSP/DMIC
+# 5) dai_id - SSP port number
+# 6) dai_format - SSP sample format
+# 7) dai_phy_bits - SSP physical number of BLKCs per slot/channel
+# 8) dai_data_bits - SSP number of valid data bits per slot/channel
+# 9) dai_bclk - SSP BCLK in HZ
+# 10) dai_mclk - SSP MCLK in HZ
+# 11) SSP mode - SSP mode e.g. I2S, LEFT_J, DSP_A and DSP_B
+# 12) SSP mclk_id
+# 13) Test pipelines
+#
+
+function simple_test {
+ if [ $5 == "SSP" ]
+ then
+ TESTS=("${!14}")
+ elif [ $5 == "DMIC" ]
+ then
+ TESTS=("${!15}")
+ fi
+ for i in ${TESTS[@]}
+ do
+ if [ $5 == "DMIC" ]
+ then
+ TFILE="$i-dmic$6-${14}-$2-$4-$7-$((${13} / 1000))k-$1"
+ echo "M4 pre-processing test $i -> ${TFILE}"
+ m4 ${M4_FLAGS} \
+ -DTEST_PIPE_NAME="$2" \
+ -DTEST_DAI_LINK_NAME="$3" \
+ -DTEST_DAI_PORT=$6 \
+ -DTEST_DAI_FORMAT=$7 \
+ -DTEST_PIPE_FORMAT=$4 \
+ -DTEST_DAI_TYPE=$5 \
+ -DTEST_DMIC_DRIVER_VERSION=$8 \
+ -DTEST_DMIC_CLK_MIN=$9 \
+ -DTEST_DMIC_CLK_MAX=${10} \
+ -DTEST_DMIC_DUTY_MIN=${11} \
+ -DTEST_DMIC_DUTY_MAX=${12} \
+ -DTEST_DMIC_SAMPLE_RATE=${13} \
+ -DTEST_DMIC_PDM_CONFIG=${14} \
+ $i.m4 > ${TFILE}.conf
+ echo "Compiling test $i -> ${TFILE}.tplg"
+ alsatplg -v 1 -c ${TFILE}.conf -o ${TFILE}.tplg
+ else
+ if [ "$USE_XARGS" == "yes" ]
+ then
+ #if DAI type is SSP, define the SSP specific params
+ if [ $5 == "SSP" ]
+ then
+ if [ $i == "test-all" ]
+ then
+ TFILE="test-ssp$6-mclk-${13}-${12}-$2-$4-$7-48k-$((${11} / 1000))k-$1"
+ else
+ TFILE="$i-ssp$6-mclk-${13}-${12}-$2-$4-$7-48k-$((${11} / 1000))k-$1"
+ fi
+ #create input string for batch m4 processing
+ M4_STRINGS+="-DTEST_PIPE_NAME=$2,-DTEST_DAI_LINK_NAME=$3\
+ -DTEST_DAI_PORT=$6,-DTEST_DAI_FORMAT=$7\
+ -DTEST_PIPE_FORMAT=$4,-DTEST_SSP_BCLK=${10}\
+ -DTEST_SSP_MCLK=${11},-DTEST_SSP_PHY_BITS=$8\
+ -DTEST_SSP_DATA_BITS=$9,-DTEST_SSP_MODE=${12}\
+ -DTEST_SSP_MCLK_ID=${13},-DTEST_DAI_TYPE=$5\
+ $i.m4,${TFILE},"
+ #create input string for batch processing of conf files
+ TEST_STRINGS+=${TFILE}","
+ fi
+ else
+ #if DAI type is SSP, define the SSP specific params
+ if [ $5 == "SSP" ]
+ then
+ if [ $i == "test-all" ]
+ then
+ TFILE="test-ssp$6-mclk-${13}-${12}-$2-$4-$7-48k-$((${11} / 1000))k-$1"
+ else
+ TFILE="$i-ssp$6-mclk-${13}-${12}-$2-$4-$7-48k-$((${11} / 1000))k-$1"
+ fi
+ echo "M4 pre-processing test $i -> ${TFILE}"
+ m4 ${M4_FLAGS} \
+ -DTEST_PIPE_NAME="$2" \
+ -DTEST_DAI_LINK_NAME="$3" \
+ -DTEST_DAI_PORT=$6 \
+ -DTEST_DAI_FORMAT=$7 \
+ -DTEST_PIPE_FORMAT=$4 \
+ -DTEST_SSP_BCLK=${10} \
+ -DTEST_SSP_MCLK=${11} \
+ -DTEST_SSP_PHY_BITS=$8 \
+ -DTEST_SSP_DATA_BITS=$9 \
+ -DTEST_SSP_MODE=${12} \
+ -DTEST_SSP_MCLK_ID=${13} \
+ -DTEST_DAI_TYPE=$5 \
+ $i.m4 > ${TFILE}.conf
+ echo "Compiling test $i -> ${TFILE}.tplg"
+ alsatplg -v 1 -c ${TFILE}.conf -o ${TFILE}.tplg
+ fi
+ fi
+ fi
+ done
+}
+
+echo "Preparing topology build input..."
+
+# Pre-process the simple tests
+simple_test nocodec passthrough "NoCodec-2" s16le SSP 2 s16le 20 16 1920000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec passthrough "NoCodec-2" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s16le SSP 2 s16le 20 16 1920000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s16le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec src "NoCodec-2" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+
+simple_test codec passthrough "SSP2-Codec" s16le SSP 2 s16le 20 16 1920000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec passthrough "SSP2-Codec" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec volume "SSP2-Codec" s16le SSP 2 s16le 20 16 1920000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec volume "SSP2-Codec" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec volume "SSP2-Codec" s24le SSP 2 s16le 20 16 1920000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec volume "SSP2-Codec" s16le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec src "SSP2-Codec" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+
+# for APL
+APL_PROTOCOL_TESTS=(I2S LEFT_J DSP_A DSP_B)
+APL_SSP_TESTS=(0 1 2 3 4 5)
+APL_MODE_TESTS=(volume src)
+APL_FORMAT_TESTS=(s16le s24le s32le)
+MCLK_IDS=(0 1)
+
+for protocol in ${APL_PROTOCOL_TESTS[@]}
+do
+ for ssp in ${APL_SSP_TESTS[@]}
+ do
+ for mode in ${APL_MODE_TESTS[@]}
+ do
+ for format in ${APL_FORMAT_TESTS[@]}
+ do
+ for mclk_id in ${MCLK_IDS[@]}
+ do
+ simple_test nocodec $mode "NoCodec-${ssp}" $format SSP $ssp s16le 16 16 1536000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+ simple_test nocodec $mode "NoCodec-${ssp}" $format SSP $ssp s24le 32 24 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+ simple_test nocodec $mode "NoCodec-${ssp}" $format SSP $ssp s32le 32 32 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+
+ simple_test codec $mode "SSP${ssp}-Codec" $format SSP $ssp s16le 16 16 1536000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+ simple_test codec $mode "SSP${ssp}-Codec" $format SSP $ssp s24le 32 24 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+ simple_test codec $mode "SSP${ssp}-Codec" $format SSP $ssp s32le 32 32 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+ done
+ done
+ done
+ for mclk_id in ${MCLK_IDS[@]}
+ do
+ simple_test nocodec passthrough "NoCodec-${ssp}" s16le SSP $ssp s16le 16 16 1536000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+ simple_test nocodec passthrough "NoCodec-${ssp}" s24le SSP $ssp s24le 32 24 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+ simple_test nocodec passthrough "NoCodec-${ssp}" s32le SSP $ssp s32le 32 32 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+
+ simple_test codec passthrough "SSP${ssp}-Codec" s16le SSP $ssp s16le 16 16 1536000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+ simple_test codec passthrough "SSP${ssp}-Codec" s24le SSP $ssp s24le 32 24 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+ simple_test codec passthrough "SSP${ssp}-Codec" s32le SSP $ssp s32le 32 32 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+ done
+ done
+done
+
+for protocol in ${APL_PROTOCOL_TESTS[@]}
+do
+ for ssp in ${APL_SSP_TESTS[@]}
+ do
+ for mode in ${APL_MODE_TESTS[@]}
+ do
+ for format in ${APL_FORMAT_TESTS[@]}
+ do
+ simple_test nocodec $mode "NoCodec-${ssp}" $format SSP $ssp s16le 20 16 1920000 19200000 $protocol 0 SIMPLE_TESTS[@]
+ simple_test nocodec $mode "NoCodec-${ssp}" $format SSP $ssp s24le 25 24 2400000 19200000 $protocol 0 SIMPLE_TESTS[@]
+
+ simple_test codec $mode "SSP${ssp}-Codec" $format SSP $ssp s16le 20 16 1920000 19200000 $protocol 0 SIMPLE_TESTS[@]
+ simple_test codec $mode "SSP${ssp}-Codec" $format SSP $ssp s24le 25 24 2400000 19200000 $protocol 0 SIMPLE_TESTS[@]
+ done
+ done
+ simple_test nocodec passthrough "NoCodec-${ssp}" s16le SSP $ssp s16le 20 16 1920000 19200000 $protocol 0 SIMPLE_TESTS[@]
+ simple_test nocodec passthrough "NoCodec-${ssp}" s24le SSP $ssp s24le 25 24 2400000 19200000 $protocol 0 SIMPLE_TESTS[@]
+
+ simple_test codec passthrough "SSP${ssp}-Codec" s16le SSP $ssp s16le 20 16 1920000 19200000 $protocol 0 SIMPLE_TESTS[@]
+ simple_test codec passthrough "SSP${ssp}-Codec" s24le SSP $ssp s24le 25 24 2400000 19200000 $protocol 0 SIMPLE_TESTS[@]
+ done
+done
+
+# for CNL
+simple_test nocodec passthrough "NoCodec-2" s16le SSP 2 s16le 25 16 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec passthrough "NoCodec-2" s24le SSP 2 s24le 25 24 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s16le SSP 2 s16le 25 16 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s16le SSP 2 s24le 25 24 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s24le SSP 2 s24le 25 24 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s24le SSP 2 s16le 25 16 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec src "NoCodec-4" s24le SSP 4 s24le 25 24 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+
+# Tone test: Tone component only supports s32le currently
+simple_test codec tone "SSP2-Codec" s32le SSP 2 s16le 20 16 1920000 19200000 I2S 0 TONE_TEST[@]
+#Tone Test for APL
+simple_test codec tone "SSP5-Codec" s32le SSP 5 s24le 32 24 3072000 24576000 I2S 0 TONE_TEST[@]
+simple_test codec tone "SSP5-Codec" s32le SSP 5 s32le 32 32 3072000 24576000 I2S 0 TONE_TEST[@]
+
+# DMIC Test Topologies for APL/GLK
+DMIC_PDM_CONFIGS=(MONO_PDM0_MICA MONO_PDM0_MICB STEREO_PDM0 STEREO_PDM1 FOUR_CH_PDM0_PDM1)
+DMIC_SAMPLE_RATE=(8000 16000 24000 32000 48000 64000 96000)
+DMIC_SAMPLE_FORMATS=(s16le s32le)
+
+for pdm in ${DMIC_PDM_CONFIGS[@]}
+do
+ for rate in ${DMIC_SAMPLE_RATE[@]}
+ do
+ for format in ${DMIC_SAMPLE_FORMATS[@]}
+ do
+ simple_test nocodec passthrough "DMIC0" $format DMIC 0\
+ $format 1 500000 4800000 40 60 $rate $pdm\
+ DMIC_TEST[@]
+ done
+ done
+done
+
+if [ "$USE_XARGS" == "yes" ]
+then
+ echo "Batch processing m4 files..."
+ M4_STRINGS=${M4_STRINGS%?}
+ #m4 processing
+ echo $M4_STRINGS | tr " " "," | tr '\n' '\0' | xargs -P0 -d ',' -n14 bash -c 'm4 "${@:1:${#}-1}" > ${14}.conf' m4
+
+ #execute alsatplg to create topology binary
+ TEST_STRINGS=${TEST_STRINGS%?}
+ echo $TEST_STRINGS | tr '\n' ',' |\
+ xargs -d ',' -P0 -n1 -I string alsatplg -v 1 -c\
+ string".conf" -o string".tplg"
+fi
+
diff --git a/tune/eq/eq_align.m b/tune/eq/eq_align.m
new file mode 100644
index 0000000..71edfd6
--- /dev/null
+++ b/tune/eq/eq_align.m
@@ -0,0 +1,52 @@
+function [am, offs, p] = eq_align(f, m, f_align, m_align)
+
+%% [am, offs, p] = eq_align(f, m, f_align, m_align)
+%
+% Move by adding/subtracting an offset to frequency response
+% curve to cross desired frequency and magnitude, usually 997 Hz, 0 dB
+%
+% Input
+% f - frequencies
+% m - magnitude response
+%
+% Output
+% am - aligned magnitude resposne
+% offs - offset (gain) in decibels used
+% p - index of f_align in f
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+p = find(f < f_align, 1, 'last')+1;
+offs = m_align-m(p);
+am = m+offs;
+
+end
diff --git a/tune/eq/eq_alsactl_write.m b/tune/eq/eq_alsactl_write.m
new file mode 100644
index 0000000..56b7988
--- /dev/null
+++ b/tune/eq/eq_alsactl_write.m
@@ -0,0 +1,56 @@
+function eq_alsactl_write(fn, blob8)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Write blob
+fh = fopen(fn, 'w');
+
+%% Pad blob length to multiple of four bytes
+n_orig = length(blob8);
+n_new = ceil(n_orig/4);
+blob8_new = zeros(1, n_new*4);
+blob8_new(1:n_orig) = blob8;
+
+%% Convert to 32 bit
+blob32 = zeros(1, n_new, 'uint32');
+k = 2.^[0 8 16 24];
+for i=1:n_new
+ j = (i-1)*4;
+ blob32(i) = blob8_new(j+1)*k(1) + blob8_new(j+2)*k(2) ...
+ + blob8_new(j+3)*k(3) + blob8_new(j+4)*k(4);
+end
+for i=1:n_new-1
+ fprintf(fh, '%ld,', blob32(i));
+end
+fprintf(fh, '%ld,\n', blob32(end));
+fclose(fh);
+
+end
diff --git a/tune/eq/eq_blob_write.m b/tune/eq/eq_blob_write.m
new file mode 100644
index 0000000..95f8385
--- /dev/null
+++ b/tune/eq/eq_blob_write.m
@@ -0,0 +1,49 @@
+function eq_blob_write(fn, blob8)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Write blob
+fh = fopen(fn, 'wb');
+fwrite(fh, blob8, 'uint8');
+fclose(fh);
+
+%% Print as 8 bit hex
+nb = length(blob8);
+nl = ceil(nb/16);
+for i = 1:nl
+ m = min(16, nb-(i-1)*16);
+ for j = 1:m
+ fprintf(1, "%02x ", blob8((i-1)*16 + j));
+ end
+ fprintf(1, "\n");
+end
+
+end
diff --git a/tune/eq/eq_coef_quant.m b/tune/eq/eq_coef_quant.m
new file mode 100644
index 0000000..e56efca
--- /dev/null
+++ b/tune/eq/eq_coef_quant.m
@@ -0,0 +1,50 @@
+function qc = eq_coef_quant(c, bits, qf)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+scale = 2^qf;
+cmax = 2^(bits-1)-1;
+cmin = -2^(bits-1);
+qc = int64(round(c*scale));
+idx = find(qc > cmax);
+if ~isempty(idx)
+ fprintf('Warning: Max. value of Q format is exceeded: %d (%d)\n', ...
+ qc(idx(1)), cmax);
+ qc(idx) = cmax;
+end
+idx = find(qc < cmin);
+if ~isempty(idx)
+ fprintf('Warning: Min. value of Q format is exceeded: %d (%d)\n', ...
+ qc(idx(1)), cmin);
+ qc(idx) = cmin;
+end
+
+end
diff --git a/tune/eq/eq_compute.m b/tune/eq/eq_compute.m
new file mode 100644
index 0000000..57a6293
--- /dev/null
+++ b/tune/eq/eq_compute.m
@@ -0,0 +1,462 @@
+function eq = eq_compute( eq )
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Sanity checks
+if eq.enable_iir == 0 && eq.enable_fir == 0
+ fprintf('Warning: Nothing to do. Please enable FIR or IIR!\n');
+end
+
+%% Extrapolate response to 0..fs/2, convert to logaritmic grid, and smooth
+% with 1/N octave filter
+eq = preprocess_responses(eq);
+
+%% Define target (e.g. speaker) response as parametric filter. This could also
+% be numerical data interpolated to the grid.
+if length(eq.parametric_target_response) > 0
+ [eq.t_z, eq.t_p, eq.t_k] = eq_define_parametric_eq( ...
+ eq.parametric_target_response, eq.fs);
+ eq.t_db = eq_compute_response(eq.t_z, eq.t_p, eq.t_k, eq.f, eq.fs);
+end
+
+if isempty(eq.t_db)
+ fprintf('Warning: No target response is defined.\n');
+end
+
+%% Align responses at some frequency and dB
+[eq.m_db_s, offs] = eq_align(eq.f, eq.m_db_s, eq.f_align, eq.db_align);
+eq.raw_m_db = eq.raw_m_db + offs;
+eq.m_db = eq.m_db + offs;
+eq.t_db = eq_align(eq.f, eq.t_db, eq.f_align, eq.db_align);
+
+%% Error to equalize = target - raw response, apply 1/N octave smoothing to
+% soften the EQ shape
+eq.err_db = eq.t_db - eq.m_db;
+[eq.err_db_s, eq.logsmooth_noct] = logsmooth(eq.f, eq.err_db, eq.logsmooth_eq);
+
+%% Parametric IIR EQ definition
+if eq.enable_iir
+ [eq.p_z, eq.p_p, eq.p_k] = eq_define_parametric_eq(eq.peq, eq.fs);
+ if max(length(eq.p_z), length(eq.p_p)) > 2*eq.iir_biquads_max
+ error('Maximum number of IIR biquads is exceeded');
+ end
+else
+ [eq.p_z, eq.p_p, eq.p_k] = tf2zp(1, 1);
+end
+[eq.iir_eq_db, eq.iir_eq_ph, eq.iir_eq_gd] = eq_compute_response(eq.p_z, ...
+ eq.p_p, eq.p_k, eq.f, eq.fs);
+
+
+%% FIR EQ computation
+% Find remaining responses error ater IIR for FIR to handle
+if eq.fir_compensate_iir
+ eq.err2_db = eq.err_db_s-eq.iir_eq_db;
+else
+ eq.err2_db = eq.err_db_s;
+end
+
+if eq.enable_fir
+ [eq.t_fir_db, eq.fmin_fir, eq.fmax_fir] = ...
+ get_fir_target(eq.f, eq.err2_db, eq.fmin_fir, eq.fmax_fir, ...
+ eq.amin_fir, eq.amax_fir, eq.logsmooth_noct, eq.fir_autoband);
+
+ if eq.fir_minph
+ eq.b_fir = compute_minph_fir(eq.f, eq.t_fir_db, ...
+ eq.fir_length, eq.fs, eq.fir_beta);
+ else
+ eq.b_fir = compute_linph_fir(eq.f, eq.t_fir_db, ...
+ eq.fir_length, eq.fs, eq.fir_beta);
+ end
+else
+ eq.b_fir = 1;
+ eq.tfirdb = zeros(1,length(eq.f));
+end
+
+%% Update all responses
+eq = eq_compute_tot_response(eq);
+
+%% Normalize
+eq = eq_norm(eq);
+
+end
+
+function eq = preprocess_responses(eq)
+%% Usually too narrow measurement without the lowest and highest frequencies
+[f0, m0, gd0] = fix_response_dcnyquist_mult(eq.raw_f, eq.raw_m_db, ...
+ eq.raw_gd_s, eq.fs);
+
+%% Create dense logarithmic frequency grid, then average possible multiple
+% measurements
+[eq.f, eq.m_db, eq.gd_s, eq.num_responses] = map_to_logfreq_mult(f0, m0, ...
+ gd0, 1, eq.fs/2, eq.np_fine);
+
+%% Smooth response with 1/N octave filter for plotting
+eq.m_db_s = logsmooth(eq.f, eq.m_db, eq.logsmooth_plot);
+
+if length(eq.target_m_db) > 0
+ % Use target_m_db as dummy group delay, ignore other than magnitude
+ [f0, m0, ~] = fix_response_dcnyquist_mult(eq.target_f, ...
+ eq.target_m_db, [], eq.fs);
+ [~, eq.t_db, ~, ~] = map_to_logfreq_mult(f0, m0, [], 1, ...
+ eq.fs/2, eq.np_fine);
+end
+end
+
+
+function [f_hz, m_db, gd_s] = fix_response_dcnyquist(f_hz0, m_db0, gd_s0, fs)
+%% Append DC and Fs/2 if missing
+f_hz = f_hz0;
+m_db = m_db0;
+gd_s = gd_s0;
+if min(f_hz) > 0
+ f_hz = [0 f_hz];
+ m_db = [m_db(1) m_db]; % DC the same as 1st measured point
+ if length(gd_s) > 0
+ gd_s = [gd_s(1) gd_s]; % DC the same as 1st measured point
+ end
+end
+if max(f_hz) < fs/2
+ f_hz = [f_hz fs/2];
+ m_db = [m_db m_db(end)]; % Fs/2 the same as last measured point
+ if length(gd_s) > 0
+ gd_s = [gd_s gd_s(end)]; % Fs/2 the same as last measured point
+ end
+end
+end
+
+function [f_hz, m_db, gd_s] = fix_response_dcnyquist_mult(f_hz0, m_db0, ...
+ gd_s0, fs)
+
+if iscolumn(f_hz0)
+ f_hz0 = f_hz0.';
+end
+if iscolumn(m_db0)
+ m_db0 = m_db0.';
+end
+if iscolumn(gd_s0)
+ gd_s0 = gd_s0.';
+end
+
+s1 = size(f_hz0);
+s2 = size(m_db0);
+s3 = size(gd_s0);
+
+if s1(1) == 0
+ error('Frequencies vector is empty');
+end
+if (s1(1) ~= s2(1))
+ error('There must be equal number of frequency and magnitude data');
+end
+if (s1(2) ~= s2(2))
+ error('There must be equal number of points in frequency, magnitude, and group delay data');
+end
+if sum(s3) == 0
+ gd_s0 = zeros(s2(1),s2(2));
+end
+for i=1:s1(1)
+ [f_hz(i,:), m_db(i,:), gd_s(i,:)] = fix_response_dcnyquist(...
+ f_hz0(i,:), m_db0(i,:), gd_s0(i,:), fs);
+end
+
+end
+
+function [f_hz, m_db, gd_s] = map_to_logfreq(f_hz0, m_db0, gd_s0, f1, f2, np)
+%% Create logarithmic frequency vector and interpolate
+f_hz = logspace(log10(f1),log10(f2), np);
+m_db = interp1(f_hz0, m_db0, f_hz);
+gd_s = interp1(f_hz0, gd_s0, f_hz);
+m_db(end) = m_db(end-1); % Fix NaN in the end
+gd_s(end) = gd_s(end-1); % Fix NaN in the end
+end
+
+function [f_hz, mm_db, mgd_s, num] = map_to_logfreq_mult(f_hz0, m_db0, ...
+ gd_s0, f1, f2, np)
+
+s1 = size(f_hz0);
+s2 = size(m_db0);
+s3 = size(gd_s0);
+if (s1(1) ~= s2(1))
+ error('There must be equal number of frequency and magnitude data sets');
+end
+if (s1(2) ~= s2(2))
+ error('There must be equal number of points in frequency and magnitude data');
+end
+num = s1(1);
+if sum(s3) == 0
+ gd_s0 = zeros(s2(1),s2(2));
+end
+for i=1:num
+ [f_hz, m_db(i,:), gd_s(i,:)] = map_to_logfreq(f_hz0(i,:), ...
+ m_db0(i,:), gd_s0(i,:), f1, f2, np);
+end
+
+if num > 1
+ mm_db = mean(m_db);
+ mgd_s = mean(gd_s);
+else
+ mm_db = m_db;
+ mgd_s = gd_s;
+end
+end
+
+function [ms_db, noct] = logsmooth(f, m_db, c)
+
+%% Create a 1/N octave smoothing filter
+ind1 = find(f < 1000);
+ind2 = find(f < 2000);
+noct = ind2(end)-ind1(end);
+n = 2*round(c*noct/2);
+b_smooth = ones(1,n)*1/n;
+
+%% Smooth the response
+tmp = filter(b_smooth, 1, m_db);
+ms_db = [tmp(n/2+1:end) linspace(tmp(end), m_db(end), n/2)];
+ms_db(1:n) = ones(1,n)*ms_db(n);
+end
+
+function [m_db, fmin_fir, fmax_fir] = get_fir_target(fhz, err2db, fmin_fir, ...
+ fmax_fir, amin_fir, amax_fir, noct, auto)
+
+
+%% Find maximum in 1-6 kHz band
+idx = find(fhz > 1e3, 1, 'first') - 1;
+m_db = err2db - err2db(idx);
+if auto
+ cf = [1e3 6e3];
+ ind1 = find(fhz < cf(2));
+ ind2 = find(fhz(ind1) > cf(1));
+ ipeak = find(m_db(ind2) == max(m_db(ind2))) + ind2(1);
+ ind1 = find(fhz < cf(1));
+ ind2 = find(m_db(ind1) > m_db(ipeak));
+ if length(ind2) > 0
+ fmin_fir = fhz(ind2(end));
+ end
+ ind1 = find(fhz > cf(2));
+ ind2 = find(m_db(ind1) > m_db(ipeak)) + ind1(1);
+ if length(ind2) > 0
+ fmax_fir = fhz(ind2(1));
+ end
+end
+
+%% Find FIR target response
+ind1 = find(fhz < fmin_fir);
+ind2 = find(fhz > fmax_fir);
+p1 = ind1(end)+1;
+if length(ind2) > 0
+ p2 = ind2(1)-1;
+else
+ p2 = length(fhz);
+end
+m_db(ind1) = m_db(p1);
+m_db(ind2) = m_db(p2);
+ind = find(m_db > amax_fir);
+m_db(ind) = amax_fir;
+ind = find(m_db < amin_fir);
+m_db(ind) = amin_fir;
+
+%% Smooth high frequency corner with spline
+nn = round(noct/8);
+x = [p2-nn p2-nn+1 p2+nn-1 p2+nn];
+if max(x) < length(m_db)
+ y = m_db(x);
+ xx = p2-nn:p2+nn;
+ yy = spline(x, y, xx);
+ m_db(p2-nn:p2+nn) = yy;
+end
+
+%% Smooth low frequency corner with spline
+nn = round(noct/8);
+x = [p1-nn p1-nn+1 p1+nn-1 p1+nn];
+if min(x) > 0
+ y = m_db(x);
+ xx = p1-nn:p1+nn;
+ yy = spline(x, y, xx);
+ m_db(p1-nn:p1+nn) = yy;
+end
+
+end
+
+function b = compute_linph_fir(f_hz, m_db, taps, fs, beta)
+if nargin < 5
+ beta = 4;
+end
+if mod(taps,2) == 0
+ fprintf('Warning: Even FIR length requested.\n');
+end
+n_fft = 2*2^ceil(log(taps)/log(2));
+n_half = n_fft/2+1;
+f_fft = linspace(0, fs/2, n_half);
+m_lin = 10.^(m_db/20);
+if f_hz(1) > 0
+ f_hz = [0 f_hz];
+ m_lin = [m_lin(1) m_lin];
+end
+a_half = interp1(f_hz, m_lin, f_fft, 'linear');
+a = [a_half conj(a_half(end-1:-1:2))];
+h = real(fftshift(ifft(a)));
+b0 = h(n_half-floor((taps-1)/2):n_half+floor((taps-1)/2));
+win = kaiser(length(b0), beta)';
+b = b0 .* win;
+if length(b) < taps
+ % Append to even length
+ b = [b 0];
+end
+end
+
+function b_fir = compute_minph_fir(f, m_db, fir_length, fs, beta)
+
+%% Design double length H^2 FIR
+n = 2*fir_length+1;
+m_lin2 = (10.^(m_db/20)).^2;
+m_db2 = 20*log10(m_lin2);
+blin = compute_linph_fir(f, m_db2, n, fs, beta);
+
+%% Find zeros inside unit circle
+myeps = 1e-3;
+hdzeros = roots(blin);
+ind1 = find( abs(hdzeros) < (1-myeps) );
+minzeros = hdzeros(ind1);
+
+%% Find double zeros at unit circle
+ind2 = find( abs(hdzeros) > (1-myeps) );
+outzeros = hdzeros(ind2);
+ind3 = find( abs(outzeros) < (1+myeps) );
+circlezeros = outzeros(ind3);
+
+%% Get half of the unit circle zeros
+if isempty(circlezeros)
+ %% We are fine ...
+else
+ %% Eliminate double zeros
+ cangle = angle(circlezeros);
+ [sorted_cangle, ind] = sort(cangle);
+ sorted_czeros = circlezeros(ind);
+ pos = find(angle(sorted_czeros) > 0);
+ neg = find(angle(sorted_czeros) < 0);
+ pos_czeros = sorted_czeros(pos);
+ neg_czeros = sorted_czeros(neg(end:-1:1));
+ h1 = [];
+ for i = 1:2:length(pos_czeros)-1
+ x=mean(angle(pos_czeros(i:i+1)));
+ h1 = [h1' complex(cos(x),sin(x))]';
+ end
+ h2 = [];
+ for i = 1:2:length(neg_czeros)-1;
+ x=mean(angle(neg_czeros(i:i+1)));
+ h2 = [h2' complex(cos(x),sin(x))]';
+ end
+ halfcirclezeros = [h1' h2']';
+ if length(halfcirclezeros)*2 < length(circlezeros)-0.1
+ %% Replace the last zero pair
+ halfcirclezeros = [halfcirclezeros' complex(-1, 0)]';
+ end
+ minzeros = [ minzeros' halfcirclezeros' ]';
+end
+
+%% Convert to transfer function
+bmin = mypoly(minzeros);
+
+%% Scale peak in passhz to max m_db
+hmin = freqz(bmin, 1, 512, fs);
+b_fir = 10^(max(m_db)/20)*bmin/max(abs(hmin));
+
+end
+
+function tf = mypoly( upolyroots )
+
+% Sort roots to increasing angle to ensure more consistent behavior
+aa = abs(angle(upolyroots));
+[sa, ind] = sort(aa);
+polyroots = upolyroots(ind);
+
+n = length(polyroots);
+n1 = 16; % do not change, hardwired to 16 code below
+
+if n < (2*n1+1)
+ % No need to split
+ tf = poly(polyroots);
+else
+ % Split roots evenly to 16 poly computations
+ % The fist polys will rpb+1 roots and the rest
+ % rpb roots to compute
+ rpb = floor(n/n1);
+ rem = mod(n,n1);
+ i1 = zeros(1,n1);
+ i2 = zeros(1,n1);
+ i1(1) = 1;
+ for i = 1:n1-1;
+ if rem > 0
+ i2(i) = i1(i)+rpb;
+ rem = rem-1;
+ else
+ i2(i) = i1(i)+rpb-1;
+ end
+ i1(i+1) = i2(i)+1;
+ end
+ i2(n1) = n;
+ tf101 = poly(polyroots(i1(1):i2(1)));
+ tf102 = poly(polyroots(i1(2):i2(2)));
+ tf103 = poly(polyroots(i1(3):i2(3)));
+ tf104 = poly(polyroots(i1(4):i2(4)));
+ tf105 = poly(polyroots(i1(5):i2(5)));
+ tf106 = poly(polyroots(i1(6):i2(6)));
+ tf107 = poly(polyroots(i1(7):i2(7)));
+ tf108 = poly(polyroots(i1(8):i2(8)));
+ tf109 = poly(polyroots(i1(9):i2(9)));
+ tf110 = poly(polyroots(i1(10):i2(10)));
+ tf111 = poly(polyroots(i1(11):i2(11)));
+ tf112 = poly(polyroots(i1(12):i2(12)));
+ tf113 = poly(polyroots(i1(13):i2(13)));
+ tf114 = poly(polyroots(i1(14):i2(14)));
+ tf115 = poly(polyroots(i1(15):i2(15)));
+ tf116 = poly(polyroots(i1(16):i2(16)));
+ % Combine coefficients with convolution
+ tf21 = conv(tf101, tf116);
+ tf22 = conv(tf102, tf115);
+ tf23 = conv(tf103, tf114);
+ tf24 = conv(tf104, tf113);
+ tf25 = conv(tf105, tf112);
+ tf26 = conv(tf106, tf111);
+ tf27 = conv(tf107, tf110);
+ tf28 = conv(tf108, tf109);
+ tf31 = conv(tf21, tf28);
+ tf32 = conv(tf22, tf27);
+ tf33 = conv(tf23, tf26);
+ tf34 = conv(tf24, tf25);
+ tf41 = conv(tf31, tf34);
+ tf42 = conv(tf32, tf33);
+ tf = conv(tf41, tf42);
+
+ % Ensure the tf coefficents are real if rounding issues
+ tf = real(tf);
+end
+
+end
diff --git a/tune/eq/eq_compute_response.m b/tune/eq/eq_compute_response.m
new file mode 100644
index 0000000..e8a4704
--- /dev/null
+++ b/tune/eq/eq_compute_response.m
@@ -0,0 +1,72 @@
+function [m, ph, gd] = eq_compute_response(z, p, k, f, fs)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+switch nargin
+ case 3
+ b = z; % 1st arg
+ f = p; % 2nd arg
+ fs = k; % 3rd arg
+ h = freqz(b, 1, f, fs);
+ m = 20*log10(abs(h));
+ ph = 180/pi*angle(h);
+
+ if length(b) == 1
+ gd = zeros(1, length(f));
+ else
+ if exist('OCTAVE_VERSION', 'builtin')
+ % grpdelay() has some issue so better to not show a plot
+ gd = NaN * zeros(1, length(f));
+ else
+ gd = 1/fs*grpdelay(b, 1, f, fs);
+ end
+ end
+ case 5
+ [b, a] = zp2tf(z, p, k);
+ h = freqz(b, a, f, fs);
+ m = 20*log10(abs(h));
+ ph = 180/pi*angle(h);
+
+ if length(z) == 0 && length(p) == 0
+ gd = zeros(1, length(f));
+ else
+ if exist('OCTAVE_VERSION', 'builtin')
+ % grpdelay() has some issue so better to not show a plot
+ gd = NaN * zeros(1, length(f));
+ else
+ gd = 1/fs*grpdelay(b, a, f, fs);
+ end
+ end
+ otherwise
+ error('Incorrect input parameters');
+end
+
+end
diff --git a/tune/eq/eq_compute_tot_response.m b/tune/eq/eq_compute_tot_response.m
new file mode 100644
index 0000000..250c364
--- /dev/null
+++ b/tune/eq/eq_compute_tot_response.m
@@ -0,0 +1,50 @@
+function eq = eq_compute_tot_response(eq)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+% FIR response and combined IIR+FIR EQ
+[eq.iir_eq_db, eq.iir_eq_ph, eq.iir_eq_gd] = eq_compute_response(eq.p_z, eq.p_p, eq.p_k, eq.f, eq.fs);
+[eq.fir_eq_db, eq.fir_eq_ph, eq.fir_eq_gd] = eq_compute_response(eq.b_fir, eq.f, eq.fs);
+eq.tot_eq_db = eq.iir_eq_db + eq.fir_eq_db;
+eq.tot_eq_gd = eq.iir_eq_gd + eq.fir_eq_gd;
+
+% Simulated equalized result
+eq.m_eqd = eq.m_db + eq.tot_eq_db; % Simulated response
+eq.m_eqd_s = eq.m_db_s + eq.tot_eq_db; % Smoothed simulated response
+eq.gd_eqd = eq.gd_s' + eq.tot_eq_gd;
+
+% Align
+[eq.m_eqd_s, adjust, p] = eq_align(eq.f, eq.m_eqd_s, eq.f_align, eq.db_align);
+eq.m_eqd = eq.m_eqd + adjust;
+eq.m_eq_loss = eq.tot_eq_db(p);
+eq.m_eqd_abs = eq.m_db_abs+eq.m_eq_loss;
+
+end
diff --git a/tune/eq/eq_defaults.m b/tune/eq/eq_defaults.m
new file mode 100644
index 0000000..880e4e3
--- /dev/null
+++ b/tune/eq/eq_defaults.m
@@ -0,0 +1,113 @@
+function p = eq_defaults
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+% Misc
+p.plot_figs = 0;
+p.fn = 'configuration.txt';
+p.fs = 48e3;
+p.f_align = 997;
+p.db_align = 0;
+p.logsmooth_plot = 1/3; % Smooth over 1/3 octaves
+p.logsmooth_eq = 1/3; % Smooth over 1/3 octaves
+p.np_fine = 5000; % 5000 point design grid
+
+% Parametric EQ IDs
+p.PEQ_HP1 = 1; p.PEQ_HP2 = 2; p.PEQ_LP1 = 3; p.PEQ_LP2 = 4;
+p.PEQ_LS1 = 5; p.PEQ_LS2 = 6; p.PEQ_HS1 = 7; p.PEQ_HS2 = 8;
+p.PEQ_PN2 = 9; p.PEQ_LP4 = 10; p.PEQ_HP4 = 11;
+
+% FIR constraints
+p.fmin_fir = 200; %
+p.fmax_fir = 15e3; %
+p.amax_fir = 20;
+p.amin_fir = -20;
+p.fir_beta = 8;
+p.fir_length = 63;
+p.fir_minph = 0; % 0 = linear phase, 1 = minimum phase
+% Adjust fmin_fir, fmax_fir automatically for least gain loss in FIR
+p.fir_autoband = 1;
+p.enable_fir = 0;
+
+% IIR conf
+p.iir_biquads_max = 8;
+p.enable_iir = 0;
+
+% Initialize other fields those are computed later to allow use of struct
+% arrays
+p.raw_f = [10 100e3];
+p.raw_m_db = [0 0];
+p.raw_gd_s = [];
+p.f = [];
+p.m_db = [];
+p.gd_s = [];
+p.num_responses = 0;
+p.m_db_s = [];
+p.gd_s_s = [];
+p.logsmooth_noct = 0;
+p.t_z = [];
+p.t_p = [];
+p.t_k = [];
+p.t_db = [];
+p.m_db_abs = 0;
+p.m_db_offs = 0;
+p.raw_m_noalign_db = [];
+p.err_db = [];
+p.p_z = [];
+p.p_p = [];
+p.p_k = [];
+p.iir_eq_db = [];
+p.iir_eq_ph = [];
+p.iir_eq_gd = [];
+p.err2_db = [];
+p.t_fir_db = [];
+p.b_fir = [];
+p.fir_eq_db = [];
+p.fir_eq_ph = [];
+p.fir_eq_gd = [];
+p.tot_eq_db = [];
+p.tot_eq_gd = [];
+p.m_eqd = [];
+p.gd_eqd = [];
+p.m_eq_loss = 0;
+p.m_eqd_abs = 0;
+p.sim_m_db = [];
+p.parametric_target_response = [];
+p.target_f = [10 100e3];
+p.target_m_db = [0 0];
+p.fir_compensate_iir = 1;
+p.p_fmin = 10;
+p.p_fmax = 30e3;
+p.name = '';
+p.norm_type = 'loudness'; % loudness/peak/1k
+p.norm_offs_db = 0;
+
+end
diff --git a/tune/eq/eq_define_parametric_eq.m b/tune/eq/eq_define_parametric_eq.m
new file mode 100644
index 0000000..2beecf2
--- /dev/null
+++ b/tune/eq/eq_define_parametric_eq.m
@@ -0,0 +1,143 @@
+function [z, p, k] = eq_define_parametric_eq(peq, fs)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+% Parametric types
+PEQ_HP1 = 1; PEQ_HP2 = 2; PEQ_LP1 = 3; PEQ_LP2 = 4;
+PEQ_LS1 = 5; PEQ_LS2 = 6; PEQ_HS1 = 7; PEQ_HS2 = 8;
+PEQ_PN2 = 9; PEQ_LP4 = 10; PEQ_HP4 = 11;
+
+sp = size(peq);
+z = [];
+p = [];
+k = 1;
+for i=1:sp(1)
+ type = peq(i,1);
+ f = peq(i,2);
+ g = peq(i,3);
+ Q = peq(i,4);
+ if f < fs/2
+ a0 = [];
+ b0 = [];
+ z0 = [];
+ p0 = [];
+ k0 = [];
+ switch peq(i,1)
+ case PEQ_HP1, [z0, p0, k0] = butter(1, 2*f/fs, 'high');
+ case PEQ_HP2, [z0, p0, k0] = butter(2, 2*f/fs, 'high');
+ case PEQ_HP4, [z0, p0, k0] = butter(4, 2*f/fs, 'high');
+ case PEQ_LP1, [z0, p0, k0] = butter(1, 2*f/fs);
+ case PEQ_LP2, [z0, p0, k0] = butter(2, 2*f/fs);
+ case PEQ_LP4, [z0, p0, k0] = butter(4, 2*f/fs);
+ case PEQ_LS1, [b0, a0] = low_shelf_1st(f, g, fs);
+ case PEQ_LS2, [b0, a0] = low_shelf_2nd(f, g, fs);
+ case PEQ_HS1, [b0, a0] = high_shelf_1st(f, g, fs);
+ case PEQ_HS2, [b0, a0] = high_shelf_2nd(f, g, fs);
+ case PEQ_PN2, [b0, a0] = peak_2nd(f, g, Q, fs);
+ otherwise
+ error('Unknown parametric EQ type');
+ end
+ if length(a0) > 0
+ [z0, p0, k0] = tf2zp(b0, a0);
+ end
+ if length(k0) > 0
+ z = [z ; z0(:)];
+ p = [p ; p0(:)];
+ k = k * k0;
+ end
+ end
+end
+end
+
+function [b, a] = low_shelf_1st(fhz, gdb, fs)
+zw = 2*pi*fhz;
+w = wmap(zw, fs);
+glin = 10^(gdb/20);
+bs = [1 glin*w];
+as = [1 w];
+[b, a] = my_bilinear(bs, as, fs);
+end
+
+function [b, a] = low_shelf_2nd(fhz, gdb, fs)
+zw = 2*pi*fhz;
+w = wmap(zw, fs);
+glin = 10^(gdb/20);
+bs = [1 w*sqrt(2*glin) glin*w^2];
+as = [1 w*sqrt(2) w^2];
+[b, a] = my_bilinear(bs, as, fs);
+end
+
+function [b, a] = high_shelf_1st(fhz, gdb, fs)
+zw = 2*pi*fhz;
+w = wmap(zw, fs);
+glin = 10^(gdb/20);
+bs = [glin w];
+as = [1 w];
+[b, a] = my_bilinear(bs, as, fs);
+end
+
+function [b, a] = high_shelf_2nd(fhz, gdb, fs)
+zw = 2*pi*fhz;
+w = wmap(zw, fs);
+glin = 10^(gdb/20);
+bs = [glin w*sqrt(2*glin) w^2];
+as = [1 w*sqrt(2) w^2];
+[b, a] = my_bilinear(bs, as, fs);
+end
+
+
+function [b, a] = peak_2nd(fhz, gdb, Q, fs)
+ % Reference http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+ A = 10^(gdb/40); % Square root of linear gain
+ wc = 2*pi*fhz/fs;
+ alpha = sin(wc)/(2*Q);
+ b0 = 1 + alpha * A;
+ b1 = -2 * cos(wc);
+ b2 = 1 - alpha * A;
+ a0 = 1 + alpha / A;
+ a1 = -2 * cos(wc);
+ a2 = 1 - alpha / A;
+ b = [b0 / a0 b1 / a0 b2 / a0];
+ a = [1 a1 / a0 a2 / a0];
+end
+
+function [b, a] = my_bilinear(sb, sa, fs)
+if exist('OCTAVE_VERSION', 'builtin')
+ [b, a] = bilinear(sb, sa, 1/fs);
+else
+ [b, a] = bilinear(sb, sa, fs);
+end
+end
+
+function sw = wmap(w, fs)
+t = 1/fs;
+sw = 2/t*tan(w*t/2);
+end
diff --git a/tune/eq/eq_fir_blob_merge.m b/tune/eq/eq_fir_blob_merge.m
new file mode 100644
index 0000000..6876453
--- /dev/null
+++ b/tune/eq/eq_fir_blob_merge.m
@@ -0,0 +1,50 @@
+function bs = eq_fir_blob_merge(platform_max_channels, ...
+ number_of_responses_defined, assign_response, all_coefficients);
+
+%% Merge equalizer definition into a struct used by successive blob making
+% functions.
+%
+% bs = eq_fir_blob_merge(platform_max_channels, number_of_responses_defined, ...
+% assign_response, all_coefficients);
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if length(assign_response) ~= platform_max_channels
+ error("Incorrect length in EQ assign vector!");
+end
+
+bs.platform_max_channels = platform_max_channels;
+bs.number_of_responses_defined = number_of_responses_defined;
+bs.assign_response = assign_response;
+bs.all_coefficients = all_coefficients;
+
+end
diff --git a/tune/eq/eq_fir_blob_pack.m b/tune/eq/eq_fir_blob_pack.m
new file mode 100644
index 0000000..f8e647f
--- /dev/null
+++ b/tune/eq/eq_fir_blob_pack.m
@@ -0,0 +1,139 @@
+function blob8 = eq_fir_blob_pack(bs, endian)
+
+%% Pack equalizer struct to bytes
+%
+% blob8 = eq_fir_blob_pack(bs, endian)
+% bs - blob struct
+% endian - optional, use 'little' or 'big'. Defaults to little.
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 2
+ endian = 'little';
+end
+
+%% Endiannes of blob
+switch lower(endian)
+ case 'little'
+ sh16 = [0 -8];
+ sh32 = [0 -8 -16 -24];
+ case 'big'
+ sh16 = [-8 0];
+ sh32 = [-24 -16 -8 0];
+ otherwise
+ error('Unknown endiannes');
+end
+
+%% Channels count must be even
+if mod(bs.platform_max_channels, 2) > 0
+ error("Channels # must be even");
+end
+
+%% Channels cound and assign vector length must be the same
+if bs.platform_max_channels ~= length( bs.assign_response)
+ bs
+ error("Channels # and response assign length must match");
+end
+
+%% Coefficients vector length must be multiple of 4
+len = length(bs.all_coefficients);
+len_no_header = len - 2 * bs.number_of_responses_defined;
+if mod(len_no_header, 4) > 0
+ bs
+ error("Coefficient data vector length must be multiple of 4");
+end
+
+%% Pack as 16 bits
+nh16 = 4+bs.platform_max_channels;
+h16 = zeros(1, nh16, 'int16');
+h16(3) = bs.platform_max_channels;
+h16(4) = bs.number_of_responses_defined;
+for i=1:bs.platform_max_channels
+ h16(4+i) = bs.assign_response(i);
+end
+
+%% Merge header and coefficients, make even number of int16 to make it
+% multiple of int32
+nc16 = length(bs.all_coefficients);
+nb16 = ceil((nh16+nc16)/2)*2;
+blob16 = zeros(1,nb16, 'int16');
+blob16(1:nh16) = h16;
+blob16(nh16+1:nh16+nc16) = int16(bs.all_coefficients);
+
+%% Print as 16 bit hex
+nl = ceil(nb16/16);
+for i = 1:nl
+ m = min(16, nb16-(i-1)*16);
+ for j = 1:m
+ k = (i-1)*16 + j;
+ v = int32(blob16(k));
+ if v < 0
+ v = 65536+v;
+ end
+ fprintf(1, "%04x ", v);
+ end
+ fprintf(1, "\n");
+end
+fprintf(1, "\n");
+
+
+%% Pack as 8 bits
+nb8 = length(blob16)*2;
+blob8 = zeros(1, nb8, 'uint8');
+j = 1;
+for i = 1:length(blob16)
+ blob8(j:j+1) = w16b(blob16(i), sh16);
+ j = j+2;
+end
+
+%% Add size into first four bytes
+blob8(1:4) = w32b(nb8, sh32);
+
+%% Done
+fprintf('Blob size is %d bytes.\n', nb8);
+
+end
+
+
+function bytes = w16b(word, sh)
+bytes = uint8(zeros(1,2));
+bytes(1) = bitand(bitshift(word, sh(1)), 255);
+bytes(2) = bitand(bitshift(word, sh(2)), 255);
+end
+
+function bytes = w32b(word, sh)
+bytes = uint8(zeros(1,4));
+bytes(1) = bitand(bitshift(word, sh(1)), 255);
+bytes(2) = bitand(bitshift(word, sh(2)), 255);
+bytes(3) = bitand(bitshift(word, sh(3)), 255);
+bytes(4) = bitand(bitshift(word, sh(4)), 255);
+end
diff --git a/tune/eq/eq_fir_blob_quant.m b/tune/eq/eq_fir_blob_quant.m
new file mode 100644
index 0000000..6d06003
--- /dev/null
+++ b/tune/eq/eq_fir_blob_quant.m
@@ -0,0 +1,105 @@
+function fbr = eq_fir_blob_quant(b, bits)
+
+%% Quantize FIR coefficients and return vector with length,
+% out shift, and coefficients to be used in the setup blob.
+%
+% fbr = eq_fir_blob_resp(b, bits)
+% b - FIR coefficients
+% bits - optional number of bits, defaults to 16
+%
+% fbr - vector with length, in shift, out shift, and quantized coefficients
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 2
+ bits = 16;
+end
+
+%% Quantize
+[bq, shift] = eq_fir_quantize(b, bits);
+
+%% Check trailing zeros
+nf = length(bq);
+nz = nf;
+while bq(nz) == 0
+ nz = nz - 1;
+end
+if nz < nf
+ nb = nz + 1;
+ fprintf(1,'Note: Filter length was reduced to %d -> %d due to trailing zeros.\n', ...
+ nf, nb);
+ bq = bq(1:nb);
+else
+ nb = nf;
+end
+
+%% Make length multiple of four (optimized FIR core)
+mod4 = mod(nb, 4);
+if mod4 > 0
+ pad = zeros(1,4-mod4);
+ bqp = [bq pad];
+ nnew = length(bqp);
+ fprintf(1,'Note: Filter length was %d, padded length into %d.\n', nb, nnew);
+else
+ nnew = nb;
+ bqp = bq;
+end
+
+fbr = [nnew shift bqp];
+
+end
+
+function [bq, shift] = eq_fir_quantize(b, bits)
+
+% [bq, shift] = eq_fir_quantize(b, bits)
+%
+% Inputs
+% b - FIR coefficients
+% bits - number bits for 2s complement coefficient
+%
+% Outputs
+% bq - quantized coefficients
+% shift - shift right parameter to apply after FIR computation to
+% compensate for coefficients scaling
+%
+
+scale = 2^(bits-1);
+
+%% Output shift for coefficients
+m = max(abs(b));
+shift = -ceil(log(m+1/scale)/log(2));
+bsr = b*2^shift;
+
+%% Quantize to Q1.bits-1 format, e.g. Q1.15 for 16 bits
+bq = eq_coef_quant(bsr, bits, bits-1);
+
+end
diff --git a/tune/eq/eq_iir_blob_merge.m b/tune/eq/eq_iir_blob_merge.m
new file mode 100644
index 0000000..c05fe67
--- /dev/null
+++ b/tune/eq/eq_iir_blob_merge.m
@@ -0,0 +1,52 @@
+function bs = eq_iir_blob_merge(platform_max_channels, ...
+ number_of_responses_defined, ...
+ assign_response, ...
+ all_coefficients);
+
+%% Merge equalizer definition into a struct used by successive blob making
+% functions.
+%
+% bs = eq_iir_blob_merge(platform_max_channels, number_of_responses_defined, ...
+% assign_response, all_coefficients);
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if length(assign_response) ~= platform_max_channels
+ error("Assign response does not match channels count!");
+end
+
+bs.platform_max_channels = platform_max_channels;
+bs.number_of_responses_defined = number_of_responses_defined;
+bs.assign_response = assign_response;
+bs.all_coefficients = all_coefficients;
+
+end
diff --git a/tune/eq/eq_iir_blob_pack.m b/tune/eq/eq_iir_blob_pack.m
new file mode 100644
index 0000000..8a55f38
--- /dev/null
+++ b/tune/eq/eq_iir_blob_pack.m
@@ -0,0 +1,84 @@
+function blob8 = eq_iir_blob_pack(bs, endian)
+
+%% Pack equalizer struct to bytes
+%
+% blob8 = eq_iir_blob_pack(bs, endian)
+% bs - blob struct
+% endian - optional, use 'little' or 'big'. Defaults to little.
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 2
+ endian = 'little';
+end
+
+%% Shift values for little/big endian
+switch lower(endian)
+ case 'little'
+ sh = [0 -8 -16 -24];
+ case 'big'
+ sh = [-24 -16 -8 0];
+ otherwise
+ error('Unknown endiannes');
+end
+
+%% Pack as 8 bits, header
+nbytes_head = (3+bs.platform_max_channels)*4;
+nbytes_coef = length(bs.all_coefficients)*4;
+nbytes = nbytes_head + nbytes_coef;
+blob8 = uint8(zeros(1,nbytes));
+
+j = 1;
+blob8(j:j+3) = w2b(nbytes, sh); j=j+4;
+blob8(j:j+3) = w2b(bs.platform_max_channels, sh); j=j+4;
+blob8(j:j+3) = w2b(bs.number_of_responses_defined, sh); j=j+4;
+
+for i=1:bs.platform_max_channels
+ blob8(j:j+3) = w2b(bs.assign_response(i), sh); j=j+4;
+end
+
+%% Pack coefficients
+for i=1:length(bs.all_coefficients)
+ blob8(j:j+3) = w2b(bs.all_coefficients(i), sh); j=j+4;
+end
+fprintf('Blob size is %d bytes.\n', nbytes);
+
+
+end
+
+function bytes = w2b(word, sh)
+bytes = uint8(zeros(1,4));
+bytes(1) = bitand(bitshift(word, sh(1)), 255);
+bytes(2) = bitand(bitshift(word, sh(2)), 255);
+bytes(3) = bitand(bitshift(word, sh(3)), 255);
+bytes(4) = bitand(bitshift(word, sh(4)), 255);
+end
diff --git a/tune/eq/eq_iir_blob_quant.m b/tune/eq/eq_iir_blob_quant.m
new file mode 100644
index 0000000..0c19fb3
--- /dev/null
+++ b/tune/eq/eq_iir_blob_quant.m
@@ -0,0 +1,144 @@
+function iir_resp = eq_iir_blob_quant(eq_z, eq_p, eq_k)
+
+%% Convert IIR coefficients to 2nd order sections and quantize
+%
+% iir_resp = eq_iir_blob_quant(z, p, k)
+%
+% z - zeros
+% p - poles
+% k - gain
+%
+% iir_resp - vector to setup an IIR equalizer with number of sections, shifts,
+% and quantized coefficients
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Settings
+bits_iir = 32; % Q2.30
+qf_iir = 30;
+bits_gain = 16; % Q2.14
+qf_gain = 14;
+scale_max = -6; % dB, scale biquads peak gain to this
+plot_pz = 0;
+plot_fr = 0;
+
+%% Convert IIR to 2nd order sections
+% This a simple implementation of zp2sos() function. It is not used here due
+% to utilization of rather strong scaling and resulting low SNR with the
+% available word length in EQ in SOF. This poles and zeros allocation to
+% biquads is base only in ascending sort of angular frequency.
+sz = length(eq_z);
+sp = length(eq_p);
+sk = length(eq_k);
+nb = max(sz, sp)/2;
+az = angle(eq_z);
+ap = angle(eq_p);
+[~, iz] = sort(abs(az));
+[~, ip] = sort(abs(ap));
+eq_z = eq_z(iz);
+eq_p = eq_p(ip);
+sos = zeros(nb, 6);
+for i = 1:nb
+ j = 2*(i-1)+1;
+ if i == 1
+ [b, a] = zp2tf(eq_z(j:j+1), eq_p(j:j+1), eq_k);
+ else
+ [b, a] = zp2tf(eq_z(j:j+1), eq_p(j:j+1), 1);
+ end
+ sos(i,1:3) = b;
+ sos(i,4:6) = a;
+end
+gain = 1;
+
+%% Convert 2nd order sections to SOF parameters format and scale the biquads
+% with criteria below (Gain max -6 dB at any frequency). Then calculate
+% scaling shifts and finally gain multiplier for output.
+sz = size(sos);
+nbr_sections = sz(1);
+n_section_header = 2;
+n_section = 7;
+iir_resp = int32(zeros(1,n_section_header+nbr_sections*n_section));
+iir_resp(1) = nbr_sections;
+iir_resp(2) = nbr_sections; % Note: All sections in series
+
+scale_max_lin = 10^(scale_max/20);
+for n=1:nbr_sections
+ b = sos(n,1:3);
+ a = sos(n,4:6);
+ if plot_pz
+ figure
+ zplane(b,a);
+ tstr = sprintf('SOS %d poles and zeros', n);
+ title(tstr);
+ end
+
+ np = 1024;
+ [h, w] = freqz(b, a, np);
+ hm = max(abs(h));
+ scale = scale_max_lin/hm;
+ gain_remain = 1/scale;
+ gain = gain*gain_remain;
+ b = b * scale;
+ ma = max(abs(a));
+ mb = max(abs(b));
+ if plot_fr
+ figure
+ [h, w] = freqz(b, a, np);
+ plot(w, 20*log10(abs(h))); grid on;
+ xlabel('Frequency (w)');
+ ylabel('Magnitude (dB)');
+ tstr = sprintf('SOS %d frequency response', n);
+ title(tstr);
+ end
+
+ %% Apply remaining gain at last section output
+ if n == nbr_sections
+ section_shift = -fix(log(gain)/log(2));
+ section_gain= gain/2^(-section_shift);
+ else
+ section_shift = 0;
+ section_gain = 1;
+ end
+
+ %% Note: Invert sign of a!
+ %% Note: a(1) is omitted, it's always 1
+ m = n_section_header+(n-1)*n_section+1;
+ iir_resp(m:m+1) = eq_coef_quant(-a(3:-1:2), bits_iir, qf_iir);
+ iir_resp(m+2:m+4) = eq_coef_quant( b(3:-1:1), bits_iir, qf_iir);
+ iir_resp(m+5) = section_shift;
+ iir_resp(m+6) = eq_coef_quant( section_gain, bits_gain, qf_gain);
+
+ %fprintf('sec=%d, shift=%d, gain=%f\n', n, section_shift, section_gain);
+
+end
+
+end
diff --git a/tune/eq/eq_norm.m b/tune/eq/eq_norm.m
new file mode 100644
index 0000000..47b40d9
--- /dev/null
+++ b/tune/eq/eq_norm.m
@@ -0,0 +1,114 @@
+function eq = eq_norm(eq)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Normalize loudness of EQ by computing weighted average of linear
+% response. Find scale need to make the average one.
+w_lin = level_norm_fweight(eq.f);
+m_lin_fir = 10.^(eq.fir_eq_db/20);
+m_lin_iir = 10.^(eq.iir_eq_db/20);
+i1k = find(eq.f > 1e3, 1, 'first') - 1;
+m_max_fir = max(eq.fir_eq_db);
+m_max_iir = max(eq.iir_eq_db);
+sens_fir = sum(m_lin_fir.*w_lin)/sum(w_lin);
+sens_iir = sum(m_lin_iir.*w_lin)/sum(w_lin);
+g_offs = 10^(eq.norm_offs_db/20);
+
+%% Determine scaling gain
+switch lower(eq.norm_type)
+ case 'loudness'
+ g_fir = 1/sens_fir;
+ g_iir = 1/sens_iir;
+ case '1k'
+ g_fir = 1/m_lin_fir(i1k);
+ g_iir = 1/m_lin_iir(i1k);
+
+ case 'peak'
+ g_fir = 10^(-m_max_fir/20);
+ g_iir = 10^(-m_max_iir/20);
+ otherwise
+ error('Requested normalization is not supported');
+end
+
+%% Adjust FIR and IIR gains if enabled
+if eq.enable_fir && eq.enable_iir
+ eq.b_fir = eq.b_fir * g_fir * g_offs;
+ eq.p_k = eq.p_k * g_iir * g_offs;
+end
+if eq.enable_fir && eq.enable_iir == 0
+ eq.b_fir = eq.b_fir * g_fir * g_offs;
+end
+if eq.enable_fir == 0 && eq.enable_iir
+ eq.p_k = eq.p_k * g_iir * g_offs;
+end
+
+%% Re-compute response after adjusting gain
+eq = eq_compute_tot_response(eq);
+
+end
+
+function m_lin = level_norm_fweight(f)
+
+%% w_lin = level_norm_fweight(f)
+%
+% Provides frequency weight that is useful in normalization of
+% loudness of effect like equalizers. The weight consists of pink noise
+% like spectral shape that attenuates higher frequencies 3 dB per
+% octave. The low frequencies are shaped by 2nd order high-pass
+% response at 20 Hz and higher frequencies by 3rd order low-pass at 20
+% kHz.
+%
+% Note: This weight may have similarity with a standard defined test signal
+% characteristic for evaluating music player output levels but this is not
+% an implementation of it. This weight may help in avoiding a designed EQ to
+% exceed safe playback levels in othervise compliant device.
+%
+% Input f - frequencies vector in Hz
+%
+% Output w_lin - weight curve, aligned to peak of 1.0 in the requested f
+%
+
+[z_hp, p_hp] = butter(2, 22.4,'high','s');
+[z_lp, p_lp] = butter(3, 22.4e3,'s');
+z_bp = conv(z_hp, z_lp);
+p_bp = conv(p_hp, p_lp);
+h = freqs(z_bp, p_bp, f);
+m0 = 20*log10(abs(h));
+noct = log(max(f)/min(f))/log(2);
+att = 3*noct;
+nf = length(f);
+w = zeros(1,nf);
+w = w - linspace(0,att,nf);
+m = m0 + w;
+m = m-max(m);
+m_lin = 10.^(m/20);
+
+end
diff --git a/tune/eq/eq_plot.m b/tune/eq/eq_plot.m
new file mode 100644
index 0000000..95968c4
--- /dev/null
+++ b/tune/eq/eq_plot.m
@@ -0,0 +1,178 @@
+function eq_plot(eq, fn)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 2
+ fn = 1;
+end
+
+%% Raw measured response
+if length(eq.raw_m_db) > 2
+ % Raw without EQ
+ fh=figure(fn); fn = fn+1;
+ f1 = min(eq.raw_f);
+ f2 = max(eq.raw_f);
+ i1 = find(eq.f > f1, 1, 'first') - 1;
+ i2 = find(eq.f > f2, 1, 'first') - 1;
+ idx = i1:i2;
+ semilogx(eq.f(idx), eq.m_db(idx), eq.f(idx), eq.m_db_s(idx));
+ grid on;
+ ax=axis; axis([eq.p_fmin eq.p_fmax min(max(ax(3:4), -40), 20)]);
+ legend('Raw','Smoothed');
+ xlabel('Frequency (Hz)');
+ ylabel('Magnitude (dB)');
+ tstr = sprintf('Imported frequency response: %s', eq.name);
+ title(tstr);
+
+ % Simulated with EQ
+ fh=figure(fn); fn = fn+1;
+ semilogx(eq.f(idx), eq.m_eqd(idx), eq.f(idx), eq.m_eqd_s(idx));
+ grid on;
+ ax=axis; axis([eq.p_fmin eq.p_fmax min(max(ax(3:4), -40), 20)]);
+ legend('Raw','Smoothed');
+ xlabel('Frequency (Hz)');
+ ylabel('Magnitude (dB)');
+ tstr = sprintf('Simulated frequency response: %s', eq.name);
+ title(tstr);
+end
+
+%% Filter responses
+fh=figure(fn); fn = fn+1;
+i1k = find(eq.f > 1e3, 1, 'first') - 1;
+offs_tot = -eq.tot_eq_db(i1k);
+offs_fir = -eq.fir_eq_db(i1k);
+offs_iir = -eq.iir_eq_db(i1k);
+if eq.enable_fir && eq.enable_iir
+ semilogx(eq.f, eq.err_db_s, eq.f, eq.tot_eq_db + offs_tot, ...
+ eq.f, eq.iir_eq_db + offs_iir, '--',...
+ eq.f, eq.fir_eq_db + offs_fir, '--');
+ legend('Target', 'Combined', 'IIR', 'FIR', 'Location', 'NorthWest');
+end
+if eq.enable_fir && eq.enable_iir == 0
+ semilogx(eq.f, eq.err_db_s, eq.f, eq.fir_eq_db + offs_fir);
+ legend('Target', 'FIR', 'Location', 'NorthWest');
+end
+if eq.enable_fir == 0 && eq.enable_iir
+ semilogx(eq.f, eq.err_db_s, eq.f, eq.iir_eq_db + offs_iir);
+ legend('Target', 'IIR', 'Location', 'NorthWest');
+end
+grid on;
+ax=axis; axis([eq.p_fmin eq.p_fmax min(max(ax(3:4), -40), 40)]);
+xlabel('Frequency (Hz)');
+ylabel('Magnitude (dB)');
+tstr = sprintf('Filter target vs. achieved response: %s', eq.name);
+title(tstr);
+
+%% FIR filter
+if length(eq.b_fir) > 1
+ % Response
+ fh=figure(fn); fn = fn+1;
+ semilogx(eq.f, eq.fir_eq_db);
+ grid on;
+ xlabel('Frequency (Hz)');
+ ylabel('Magnitude (dB)');
+ ax = axis; axis([eq.p_fmin eq.p_fmax max(ax(3:4), -40)]);
+ tstr = sprintf('FIR filter normalized response: %s', eq.name);
+ title(tstr);
+
+ % Impulse response / coefficients
+ fh=figure(fn); fn = fn+1;
+ stem(eq.b_fir);
+ grid on;
+ xlabel('Coefficient #');
+ ylabel('Coefficient value');
+ tstr = sprintf('FIR filter impulse response: %s', eq.name);
+ title(tstr);
+
+end
+
+%% IIR filter
+if length(eq.p_z) > 1 || length(eq.p_p) > 1
+ % Response
+ fh=figure(fn); fn = fn+1;
+ semilogx(eq.f, eq.iir_eq_db);
+ grid on;
+ xlabel('Frequency (Hz)');
+ ylabel('Magnitude (dB)');
+ ax = axis; axis([eq.p_fmin eq.p_fmax max(ax(3:4), -40)]);
+ tstr = sprintf('IIR filter normalized response: %s', eq.name);
+ title(tstr);
+
+ % Polar
+ fh=figure(fn); fn = fn+1;
+ zplane(eq.p_z, eq.p_p);
+ grid on;
+ tstr = sprintf('IIR zeros and poles: %s', eq.name);
+ title(tstr);
+
+ % Impulse
+ ti = 50e-3;
+ x = zeros(1, ti * round(eq.fs));
+ x(1) = 1;
+ sos = zp2sos(eq.p_z, eq.p_p, eq.p_k);
+ y = sosfilt(sos, x);
+ fh=figure(fn); fn = fn+1;
+ t = (0:(length(x)-1)) / eq.fs;
+ plot(t, y);
+ grid on;
+ xlabel('Time (s)');
+ ylabel('Sample value');
+ tstr = sprintf('IIR filter impulse response: %s', eq.name);
+ title(tstr);
+end
+
+%% Group delay
+if ~exist('OCTAVE_VERSION', 'builtin')
+ % Skip plot if running in Octave due to incorrect result
+ fh=figure(fn); fn = fn+1;
+ if eq.enable_fir && eq.enable_iir
+ semilogx(eq.f, eq.tot_eq_gd * 1e3, ...
+ eq.f, eq.fir_eq_gd * 1e3, '--', ...
+ eq.f, eq.iir_eq_gd * 1e3, '--');
+ legend('Combined','FIR','IIR');
+ end
+ if eq.enable_fir && eq.enable_iir == 0
+ semilogx(eq.f, eq.fir_eq_gd * 1e3);
+ legend('FIR');
+ end
+ if eq.enable_fir == 0 && eq.enable_iir
+ semilogx(eq.f, eq.iir_eq_gd * 1e3);
+ legend('IIR');
+ end
+ grid on;
+ xlabel('Frequency (Hz)');
+ ylabel('Group delay (ms)');
+ ax = axis; axis([eq.p_fmin eq.p_fmax ax(3:4)]);
+ tstr = sprintf('Filter group delay: %s', eq.name);
+ title(tstr);
+end
+
+end
diff --git a/tune/eq/eq_tplg_write.m b/tune/eq/eq_tplg_write.m
new file mode 100644
index 0000000..cda5e01
--- /dev/null
+++ b/tune/eq/eq_tplg_write.m
@@ -0,0 +1,63 @@
+function eq_tplg_write(fn, blob8, eqtype)
+
+%%
+% Copyright (c) 2018, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Pad blob length to multiple of four bytes
+n_orig = length(blob8);
+n_new = ceil(n_orig/4)*4;
+blob8_new = zeros(1, n_new);
+blob8_new(1:n_orig) = blob8;
+
+%% Write blob
+fh = fopen(fn, 'w');
+nl = 8;
+fprintf(fh, '`SectionData."''N_EQ_%s($1)`_data_bytes" {''\n', ...
+ upper(eqtype));
+fprintf(fh, '` bytes "');
+for i = 1:nl:n_new
+ if i > 1
+ fprintf(fh, '` ');
+ end
+ for j = 0:nl-1
+ n = i + j;
+ if n < n_new
+ fprintf(fh, '0x%02x,', blob8_new(n));
+ end
+ if n == n_new
+ fprintf(fh, '0x%02x"', blob8_new(n));
+ end
+ end
+ fprintf(fh, '''\n');
+end
+fprintf(fh, '`}''\n');
+fclose(fh);
+
+end
diff --git a/tune/eq/example_fir_eq.m b/tune/eq/example_fir_eq.m
new file mode 100644
index 0000000..2186ea6
--- /dev/null
+++ b/tune/eq/example_fir_eq.m
@@ -0,0 +1,115 @@
+%% Design demo EQs and bundle them to parameter block
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function example_fir_eq()
+
+ascii_blob_fn = 'example_fir_eq.txt';
+binary_blob_fn = 'example_fir_eq.blob';
+tplg_blob_fn = 'example_fir_eq.m4';
+endian = 'little';
+fs = 48e3;
+
+%% Design FIR loudness equalizer
+eq_loud = loudness_fir_eq(fs);
+
+%% Define a passthru EQ with one tap
+b_pass = 1;
+
+%% Quantize filter coefficients for both equalizers
+bq_pass = eq_fir_blob_quant(b_pass);
+bq_loud = eq_fir_blob_quant(eq_loud.b_fir);
+
+%% Build blob
+platform_max_channels = 4; % Setup max 4 channels EQ
+assign_response = [1 1 1 1]; % Switch to response #1
+num_responses = 2; % Two responses pass, loud
+bm = eq_fir_blob_merge(platform_max_channels, ...
+ num_responses, ...
+ assign_response, ...
+ [ bq_pass bq_loud ]);
+
+%% Pack and write file
+bp = eq_fir_blob_pack(bm, endian);
+eq_alsactl_write(ascii_blob_fn, bp);
+eq_blob_write(binary_blob_fn, bp);
+eq_tplg_write(tplg_blob_fn, bp, 'FIR');
+
+end
+
+function eq = loudness_fir_eq(fs)
+
+%% Derived from Fletcher-Munson curves for 80 and 60 phon
+f = [ 20,21,22,24,25,27,28,30,32,34,36,38,40,43,45,48,51,54,57,60,64, ...
+ 68,72,76,81,85,90,96,102,108,114,121,128,136,144,153,162,171, ...
+ 182,192,204,216,229,243,257,273,289,306,324,344,364,386,409, ...
+ 434,460,487,516,547,580,614,651,690,731,775,821,870,922,977, ...
+ 1036,1098,1163,1233,1307,1385,1467,1555,1648,1747,1851,1962, ...
+ 2079,2203,2335,2474,2622,2779,2945,3121,3308,3505,3715,3937, ...
+ 4172,4421,4686,4966,5263,5577,5910,6264,6638,7035,7455,7901, ...
+ 8373,8873,9404,9966,10561,11193,11861,12570,13322,14118,14962, ...
+ 15856,16803,17808,18872,20000];
+
+m = [ 0.00,-0.13,-0.27,-0.39,-0.52,-0.64,-0.77,-0.89,-1.02,-1.16, ...
+ -1.31,-1.46,-1.61,-1.76,-1.91,-2.07,-2.24,-2.43,-2.64,-2.85, ...
+ -3.04,-3.21,-3.35,-3.48,-3.62,-3.78,-3.96,-4.16,-4.35,-4.54, ...
+ -4.72,-4.90,-5.08,-5.26,-5.45,-5.64,-5.83,-6.02,-6.19,-6.37, ...
+ -6.57,-6.77,-6.98,-7.19,-7.40,-7.58,-7.76,-7.92,-8.08,-8.25, ...
+ -8.43,-8.60,-8.76,-8.92,-9.08,-9.23,-9.38,-9.54,-9.69,-9.84, ...
+ -9.97,-10.09,-10.18,-10.26,-10.33,-10.38,-10.43,-10.48,-10.54, ...
+ -10.61,-10.70,-10.78,-10.85,-10.91,-10.95,-10.98,-11.02, ...
+ -11.05,-11.07,-11.10,-11.11,-11.11,-11.10,-11.10,-11.11, ...
+ -11.14,-11.17,-11.20,-11.21,-11.22,-11.21,-11.20,-11.20, ...
+ -11.21,-11.21,-11.20,-11.17,-11.11,-11.02,-10.91,-10.78, ...
+ -10.63,-10.46,-10.25,-10.00,-9.72,-9.39,-9.02,-8.62,-8.19, ...
+ -7.73,-7.25,-6.75,-6.25,-5.75,-5.28,-4.87,-4.54,-4.33,-4.30];
+
+%% Design EQ
+eq = eq_defaults();
+eq.fs = fs;
+eq.target_f = f; % Set EQ frequency response target: frequency vector
+eq.target_m_db = m; % Set EQ frequency response target: magnitude
+eq.norm_type = 'loudness'; % Can be loudness/peak/1k to select normalize criteria
+eq.norm_offs_db = 0; % E.g. -1 would leave 1 dB headroom if used with peak
+
+eq.enable_fir = 1; % By default both FIR and IIR disabled, enable one
+eq.fir_beta = 3.5; % Use with care, low value can corrupt
+eq.fir_length = 136; % Gives just < 316 bytes
+eq.fir_autoband = 0; % Select manually frequency limits
+eq.fmin_fir = 100; % Equalization starts from 100 Hz
+eq.fmax_fir = 20e3; % Equalization ends at 20 kHz
+eq.fir_minph = 1; % If no linear phase required, check result carefully if 1
+eq = eq_compute(eq);
+
+%% Plot
+eq_plot(eq);
+
+end
diff --git a/tune/eq/example_iir_eq.m b/tune/eq/example_iir_eq.m
new file mode 100644
index 0000000..0345bcf
--- /dev/null
+++ b/tune/eq/example_iir_eq.m
@@ -0,0 +1,128 @@
+%% Design effect EQs and bundle them to parameter block
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function example_iir_eq()
+
+blob_fn = 'example_iir_eq.blob';
+alsa_fn = 'example_iir_eq.txt';
+tplg_fn = 'example_iir_eq.m4';
+endian = 'little';
+fs = 48e3;
+
+%% Design IIR loudness equalizer
+eq_loud = loudness_iir_eq(fs);
+
+%% Define a passthru IIR EQ equalizer
+[z_pass, p_pass, k_pass] = tf2zp([1 0 0],[1 0 0]);
+
+%% Quantize and pack filter coefficients plus shifts etc.
+bq_pass = eq_iir_blob_quant(z_pass, p_pass, k_pass);
+bq_loud = eq_iir_blob_quant(eq_loud.p_z, eq_loud.p_p, eq_loud.p_k);
+
+%% Build blob
+platform_max_channels = 4; % Setup max 4 channels EQ
+assign_response = [1 1 1 1]; % Switch to response #1
+num_responses = 2; % Two responses: pass, loud
+bm = eq_iir_blob_merge(platform_max_channels, ...
+ num_responses, ...
+ assign_response, ...
+ [bq_pass bq_loud]);
+
+%% Pack and write file
+bp = eq_iir_blob_pack(bm);
+eq_blob_write(blob_fn, bp);
+eq_alsactl_write(alsa_fn, bp);
+eq_tplg_write(tplg_fn, bp, 'IIR');
+
+end
+
+%%
+
+function eq = loudness_iir_eq(fs)
+
+%% Derived from Fletcher-Munson curves for 80 and 60 phon
+f = [ 20,21,22,24,25,27,28,30,32,34,36,38,40,43,45,48,51,54,57,60,64, ...
+ 68,72,76,81,85,90,96,102,108,114,121,128,136,144,153,162,171, ...
+ 182,192,204,216,229,243,257,273,289,306,324,344,364,386,409, ...
+ 434,460,487,516,547,580,614,651,690,731,775,821,870,922,977, ...
+ 1036,1098,1163,1233,1307,1385,1467,1555,1648,1747,1851,1962, ...
+ 2079,2203,2335,2474,2622,2779,2945,3121,3308,3505,3715,3937, ...
+ 4172,4421,4686,4966,5263,5577,5910,6264,6638,7035,7455,7901, ...
+ 8373,8873,9404,9966,10561,11193,11861,12570,13322,14118,14962, ...
+ 15856,16803,17808,18872,20000];
+
+m = [ 0.00,-0.13,-0.27,-0.39,-0.52,-0.64,-0.77,-0.89,-1.02,-1.16, ...
+ -1.31,-1.46,-1.61,-1.76,-1.91,-2.07,-2.24,-2.43,-2.64,-2.85, ...
+ -3.04,-3.21,-3.35,-3.48,-3.62,-3.78,-3.96,-4.16,-4.35,-4.54, ...
+ -4.72,-4.90,-5.08,-5.26,-5.45,-5.64,-5.83,-6.02,-6.19,-6.37, ...
+ -6.57,-6.77,-6.98,-7.19,-7.40,-7.58,-7.76,-7.92,-8.08,-8.25, ...
+ -8.43,-8.60,-8.76,-8.92,-9.08,-9.23,-9.38,-9.54,-9.69,-9.84, ...
+ -9.97,-10.09,-10.18,-10.26,-10.33,-10.38,-10.43,-10.48,-10.54, ...
+ -10.61,-10.70,-10.78,-10.85,-10.91,-10.95,-10.98,-11.02, ...
+ -11.05,-11.07,-11.10,-11.11,-11.11,-11.10,-11.10,-11.11, ...
+ -11.14,-11.17,-11.20,-11.21,-11.22,-11.21,-11.20,-11.20, ...
+ -11.21,-11.21,-11.20,-11.17,-11.11,-11.02,-10.91,-10.78, ...
+ -10.63,-10.46,-10.25,-10.00,-9.72,-9.39,-9.02,-8.62,-8.19, ...
+ -7.73,-7.25,-6.75,-6.25,-5.75,-5.28,-4.87,-4.54,-4.33,-4.30];
+
+%% Get defaults for equalizer design
+eq = eq_defaults();
+eq.fs = fs;
+eq.target_f = f;
+eq.target_m_db = m;
+eq.enable_iir = 1;
+eq.norm_type = 'loudness';
+eq.norm_offs_db = 0;
+
+%% Manually setup low-shelf and high shelf parametric equalizers
+%
+% Parametric EQs are PEQ_HP1, PEQ_HP2, PEQ_LP1, PEQ_LP2, PEQ_LS1,
+% PEQ_LS2, PEQ_HS1, PEQ_HS2 = 8, PEQ_PN2, PEQ_LP4, and PEQ_HP4.
+%
+% Parametric EQs take as second argument the cutoff frequency in Hz
+% and as second argument a dB value (or NaN when not applicable) . The
+% Third argument is a Q-value (or NaN when not applicable).
+eq.peq = [ ...
+ eq.PEQ_LS1 40 +2 NaN ; ...
+ eq.PEQ_LS1 80 +3 NaN ; ...
+ eq.PEQ_LS1 200 +3 NaN ; ...
+ eq.PEQ_LS1 400 +3 NaN ; ...
+ eq.PEQ_HS2 13000 +7 NaN ; ...
+ ];
+
+%% Design EQ
+eq = eq_compute(eq);
+
+%% Plot
+eq_plot(eq);
+
+end
diff --git a/tune/eq/example_spk_eq.m b/tune/eq/example_spk_eq.m
new file mode 100644
index 0000000..d829e02
--- /dev/null
+++ b/tune/eq/example_spk_eq.m
@@ -0,0 +1,155 @@
+function example_spk_eq()
+
+%% Design an example speaker equalizer with the provided sample data
+% This equalizer by default uses a FIR and IIR components those should be
+% both in the speaker pipeline.
+%
+% Note that IIR should be first since the included band-pass response provides
+% signal headroom.
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Get defaults for equalizer design
+eq = eq_defaults();
+
+%% Settings for this EQ
+eq.fs = 48e3; % Default sample rate in SOF
+eq.enable_fir = 1; % Try enabling and disabling FIR part
+eq.enable_iir = 1; % Try enabling and disabling IIR part
+eq.norm_type = 'peak'; % Scale filters to have peak at 0 dB
+eq.norm_offs_db = 0; % Can be used to control gain
+eq.p_fmin = 100; % With this data start plots from 100 Hz
+eq.p_fmax = 20e3; % and end to 20 kHz.
+
+%% Get acousticial frequency response measurement data. This is
+% a quite typical response for a miniature speaker. Alternatively
+% the response could be read from spreadsheet column format that is
+% commonly supported by audio measurement equipment. Then extract
+% the frequency and magnitude columns. E.g.
+%
+% data = xlsread('spkr.xlsx', 1, 'A5:B78');
+% eq.raw_f = data(:,1);
+% eq.raw_m_db = data(:,2);
+
+eq.raw_f = [ ...
+ 298.533, 316.232, 334.971, 354.813, 375.838, 398.106, ...
+ 421.699, 446.685, 473.153, 501.186, 530.887, 562.342, ...
+ 595.663, 630.958, 668.345, 707.946, 749.895, 794.329, ...
+ 841.397, 891.252, 944.062, 1000, 1059.26, 1122.02, ...
+ 1188.5, 1258.93, 1333.52, 1412.54, 1496.24, 1584.9, ...
+ 1678.81, 1778.28, 1883.65, 1995.27, 2113.49, 2238.72, ...
+ 2371.38, 2511.89, 2660.73, 2818.39, 2985.39, 3162.28, ...
+ 3349.66, 3548.14, 3758.38, 3981.08, 4216.97, 4466.84, ...
+ 4731.52, 5011.88, 5308.85, 5623.42, 5956.63, 6309.58, ...
+ 6683.45, 7079.47, 7498.95, 7943.3, 8413.97, 8912.52, ...
+ 9440.62, 10000, 10592.6, 11220.2, 11885, 12589.3, ...
+ 13335.2, 14125.4, 14962.4, 15849, 16788.1, 17782.8, ...
+ 18836.5, 19952.7 ...
+];
+
+eq.raw_m_db = [ ...
+ 58.1704, 60.074, 60.4541, 61.3079, 62.8198, 64.3749, ...
+ 65.1556, 66.512, 67.5916, 68.6344, 69.9276, 70.7658, ...
+ 71.1125, 72.0627, 73.5348, 75.4887, 77.3088, 79.1541, ...
+ 80.9627, 82.0607, 81.943, 81.2228, 81.9497, 83.1848, ...
+ 84.3375, 85.4993, 86.4642, 87.1179, 87.4424, 87.53, ...
+ 85.7425, 85.0095, 82.9405, 82.9242, 82.7327, 83.6423, ...
+ 83.2839, 82.4201, 84.1403, 84.6485, 83.9274, 83.3366, ...
+ 83.3005, 84.2598, 85.1544, 86.015, 86.6519, 87.2118, ...
+ 87.5498, 88.1742, 88.5215, 88.3801, 89.8762, 91.4418, ...
+ 93.1845, 94.3355, 95.0918, 95.0258, 94.0337, 91.1068, ...
+ 88.7303, 87.4853, 86.2916, 83.037, 79.8056, 78.2022, ...
+ 76.0341, 74.5674, 69.2288, 56.1308, 68.697, 69.687, ...
+ 68.0005, 64.698 ...
+];
+
+%% With parametric IIR EQ try to place peaking EQ at
+% resonant frequencies 1.4 kHz and 7.5 kHz. The gain
+% and Q values were experimented manually. Additionally
+% The lowest and highest frequeciens below and above speaker
+% capability are attenuated with high-pass and low-pass
+% filtering.
+if eq.enable_iir;
+ eq.peq = [ ...
+ eq.PEQ_HP2 100 NaN NaN; ...
+ eq.PEQ_PN2 1480 -7 2.0; ...
+ eq.PEQ_PN2 7600 -11 1.3; ...
+ eq.PEQ_LP2 14500 NaN NaN; ...
+ ];
+end
+
+%% With FIR EQ try to flatten frequency response within
+% 1 - 13 kHz frequency band.
+if eq.enable_fir
+ eq.fir_minph = 1;
+ eq.fir_beta = 4;
+ eq.fir_length = 63;
+ eq.fir_autoband = 0;
+ eq.fmin_fir = 900;
+ eq.fmax_fir = 10700;
+end
+
+%% Design EQ
+eq = eq_compute(eq);
+
+%% Plot
+eq_plot(eq, 1);
+
+%% Export FIR part
+platform_max_channels = 2; % Identical two speakers
+assign_response = [0 0]; % Switch to response #0
+num_responses = 1; % Single response
+if eq.enable_fir
+ bq_fir = eq_fir_blob_quant(eq.b_fir);
+ bm_fir = eq_fir_blob_merge(platform_max_channels, ...
+ num_responses, ...
+ assign_response, ...
+ [ bq_fir ]);
+ bp_fir = eq_fir_blob_pack(bm_fir);
+ eq_alsactl_write('example_spk_eq_fir.txt', bp_fir);
+ eq_blob_write('example_spk_eq_fir.blob', bp_fir);
+ eq_tplg_write('example_spk_eq_fir.m4', bp_fir, 'FIR');
+end
+
+%% Export IIR part
+if eq.enable_iir
+ bq_iir = eq_iir_blob_quant(eq.p_z, eq.p_p, eq.p_k);
+ bm_iir = eq_iir_blob_merge(platform_max_channels, ...
+ num_responses, ...
+ assign_response, ...
+ [ bq_iir ]);
+ bp_iir = eq_iir_blob_pack(bm_iir);
+ eq_alsactl_write('example_spk_eq_iir.txt', bp_iir);
+ eq_blob_write('example_spk_eq_iir.blob', bp_iir);
+ eq_tplg_write('example_spk_eq_iir.m4', bp_iir, 'IIR');
+end
+
+end
diff --git a/tune/src/README b/tune/src/README
new file mode 100644
index 0000000..e135f9a
--- /dev/null
+++ b/tune/src/README
@@ -0,0 +1,36 @@
+Sample rate converter (SRC) Setup Tools
+=======================================
+
+This is a tool to set up SRC conversions sample rates list, define
+quality related parameters, and test the C implementation for a number
+of objective audio quality parameters.
+
+The tools need GNU Octave version 4.0.0 or later with octave-signal
+package.
+
+src_std_int32.m
+---------------
+
+This script creates the default coefficient set and contains nothing
+else but call for src_generate.
+
+src_tiny_int16.m
+----------------
+
+This script creates the tiny coefficient set. The script contains an
+example how to customize the input/output rates matrix and in a simple
+way the scale conversions quality. More controlled quality adjust can
+be done by editing file src_param.m directly. Note that int16
+presentation for SRC coefficients will degrade even the default
+quality.
+
+src_generate.m
+--------------
+
+Creates the header files to include to C into directory "include". A
+report of create modes is written to directory "reports". The
+coefficients need to be copied to directory
+sof.git/src/include/sof/audio/coefficients/src.
+
+The default quality of SRC is defined in module src_param.m. The
+quality impacts the complexity and coefficents tables size of SRC.
diff --git a/tune/src/src_export_coef.m b/tune/src/src_export_coef.m
new file mode 100644
index 0000000..f6fdbb4
--- /dev/null
+++ b/tune/src/src_export_coef.m
@@ -0,0 +1,212 @@
+function success=src_export_coef(src, ctype, vtype, hdir, profile)
+
+% src_export_coef - Export FIR coefficients
+%
+% success=src_export_coef(src, ctype, hdir, profile)
+%
+% src - src definition struct
+% ctype - 'float','int32', or 'int24'
+% vtype - 'float','int32_t'
+% hdir - directory for header files
+% profile - string to append to filename
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 5
+ profile = '';
+end
+
+if src.L == src.M
+ success = 0;
+else
+ pbi = round(src.c_pb*1e4);
+ sbi = round(src.c_sb*1e4);
+ if isempty(profile)
+ hfn = sprintf('%s/src_%s_%d_%d_%d_%d.h', ...
+ hdir, ctype, src.L, src.M, pbi, sbi);
+ else
+ hfn = sprintf('%s/src_%s_%s_%d_%d_%d_%d.h', ...
+ hdir, profile, ctype, src.L, src.M, pbi, sbi);
+ end
+ vfn = sprintf('src_%s_%d_%d_%d_%d_fir', ctype, src.L, src.M, pbi, sbi);
+ sfn = sprintf('src_%s_%d_%d_%d_%d', ctype, src.L, src.M, pbi, sbi);
+
+ fprintf('Exporting %s ...\n', hfn);
+ fh = fopen(hfn, 'w');
+
+ switch ctype
+ case 'float'
+ fprintf(fh, 'const %s %s[%d] = {\n', ...
+ vtype, vfn, src.filter_length);
+ fprintf(fh,'\t%16.9e', src.coefs(1));
+ for n=2:src.filter_length
+ fprintf(fh, ',\n');
+ fprintf(fh,'\t%16.9e', src.coefs(n));
+ end
+ fprintf(fh,'\n\n};');
+ case 'int32'
+ print_int_coef(src, fh, vtype, vfn, 32);
+ case 'int24'
+ print_int_coef(src, fh, vtype, vfn, 24);
+ case 'int16'
+ print_int_coef(src, fh, vtype, vfn, 16);
+ otherwise
+ error('Unknown type %s !!!', ctype);
+ end
+
+ fprintf(fh, '\n');
+ switch ctype
+ case 'float'
+ fprintf(fh, 'struct src_stage %s = {\n', sfn);
+ fprintf(fh, '\t%d, %d, %d, %d, %d, %d, %d, %d, %f,\n\t%s};\n', ...
+ src.idm, src.odm, src.num_of_subfilters, ...
+ src.subfilter_length, src.filter_length, ...
+ src.blk_in, src.blk_out, src.halfband, ...
+ src.gain, vfn);
+ case { 'int16' 'int24' 'int32' }
+ fprintf(fh, 'struct src_stage %s = {\n', sfn);
+ fprintf(fh, '\t%d, %d, %d, %d, %d, %d, %d, %d, %d,\n\t%s};\n', ...
+ src.idm, src.odm, src.num_of_subfilters, ...
+ src.subfilter_length, src.filter_length, ...
+ src.blk_in, src.blk_out, src.halfband, ...
+ src.shift, vfn);
+ otherwise
+ error('Unknown type %s !!!', ctype);
+ end
+ %fprintf(fh, '\n');
+ fclose(fh);
+ success = 1;
+end
+
+end
+
+function print_int_coef(src, fh, vtype, vfn, nbits)
+ fprintf(fh, 'const %s %s[%d] = {\n', ...
+ vtype, vfn, src.filter_length);
+
+ cint = coef_quant(src, nbits);
+ fprintf(fh,'\t%d', cint(1));
+ for n=2:src.filter_length
+ fprintf(fh, ',\n');
+ fprintf(fh,'\t%d', cint(n));
+ end
+ fprintf(fh,'\n\n};');
+end
+
+function cint = coef_quant(src, nbits)
+
+ sref = 2^(nbits-1);
+ pmax = sref-1;
+ nmin = -sref;
+
+ if nbits > 16
+ %% Round() is OK
+ cint0 = round(sref*src.coefs);
+ else
+ %% Prepare to optimize coefficient quantization
+ fs = max(src.fs1, src.fs2);
+ f = linspace(0, fs/2, 1000);
+
+ %% Test sensitivity for stopband and find the most sensitive
+ % coefficients
+ sbf = linspace(src.f_sb,fs/2, 500);
+ n = src.filter_length;
+ psens = zeros(1,n);
+ bq0 = round(sref*src.coefs);
+ h = freqz(bq0/sref/src.L, 1, sbf, fs);
+ sb1 = 20*log10(sqrt(sum(h.*conj(h))));
+ for i=1:n
+ bq = src.coefs;
+ bq(i) = round(sref*bq(i))/sref;
+ %tbq = bq; %tbq(i) = bq(i)+1;
+ h = freqz(bq, 1, sbf, fs);
+ psens(i) = sum(h.*conj(h));
+ end
+ [spsens, pidx] = sort(psens, 'descend');
+
+ %% Test quantization in the found order
+ % The impact to passband is minimal so it's not tested
+ bi = round(sref*src.coefs);
+ bi0 = bi;
+ dl = -1:1;
+ nd = length(dl);
+ msb = zeros(1,nd);
+ for i=pidx
+ bit = bi;
+ for j=1:nd
+ bit(i) = bi(i) + dl(j);
+ h = freqz(bit, 1, sbf, fs);
+ msb(j) = sum(h.*conj(h));
+ end
+ idx = find(msb == min(msb), 1, 'first');
+ bi(i) = bi(i) + dl(idx);
+ end
+ h = freqz(bi/sref/src.L, 1, sbf, fs);
+ sb2 = 20*log10(sqrt(sum(h.*conj(h))));
+
+ %% Plot to compare
+ if 0
+ f = linspace(0, fs/2, 1000);
+ h1 = freqz(src.coefs/src.L, 1, f, fs);
+ h2 = freqz(bq0/sref/src.L, 1, f, fs);
+ h3 = freqz(bi/sref/src.L, 1, f, fs);
+ figure;
+ plot(f, 20*log10(abs(h1)), f, 20*log10(abs(h2)), f, 20*log10(abs(h3)));
+ grid on;
+ fprintf('Original = %4.1f dB, optimized = %4.1f dB, delta = %4.1f dB\n', ...
+ sb1, sb2, sb1-sb2);
+ end
+ cint0 = bi;
+ end
+
+
+ %% Re-order coefficients for filter implementation
+ cint = zeros(src.filter_length,1);
+ for n = 1:src.num_of_subfilters
+ i11 = (n-1)*src.subfilter_length+1;
+ i12 = i11+src.subfilter_length-1;
+ cint(i11:i12) = cint0(n:src.num_of_subfilters:end);
+ end
+
+ %% Done check for no overflow
+ max_fix = max(cint);
+ min_fix = min(cint);
+ if (max_fix > pmax)
+ printf('Fixed point coefficient %d exceeded %d\n.', max_fix, pmax);
+ error('Something went wrong!');
+ end
+ if (min_fix < nmin)
+ printf('Fixed point coefficient %d exceeded %d\n.', min_fix, nmax);
+ error('Something went wrong!');
+ end
+
+
+end
diff --git a/tune/src/src_export_defines.m b/tune/src/src_export_defines.m
new file mode 100644
index 0000000..63fb4c2
--- /dev/null
+++ b/tune/src/src_export_defines.m
@@ -0,0 +1,66 @@
+function src_export_defines(defs, ctype, hdir, profile)
+
+% src_export_defines - Exports the constants to header files
+%
+% src_export_defines(defs, ctype, hdir)
+%
+% defs - defs struct
+% ctype - e.g. 'int24' appended to file name
+% hdir - directory for header file
+% profile - string to append to file name
+%
+
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 4
+ profile = '';
+end
+
+if isempty(profile)
+ hfn = sprintf('src_%s_define.h', ctype);
+else
+ hfn = sprintf('src_%s_%s_define.h', profile, ctype);
+end
+fh = fopen(fullfile(hdir,hfn), 'w');
+fprintf(fh, '/* SRC constants */\n');
+fprintf(fh, '#define MAX_FIR_DELAY_SIZE %d\n', defs.fir_delay_size);
+fprintf(fh, '#define MAX_OUT_DELAY_SIZE %d\n', defs.out_delay_size);
+fprintf(fh, '#define MAX_BLK_IN %d\n', defs.blk_in);
+fprintf(fh, '#define MAX_BLK_OUT %d\n', defs.blk_out);
+fprintf(fh, '#define NUM_IN_FS %d\n', defs.num_in_fs);
+fprintf(fh, '#define NUM_OUT_FS %d\n', defs.num_out_fs);
+fprintf(fh, '#define STAGE1_TIMES_MAX %d\n', defs.stage1_times_max);
+fprintf(fh, '#define STAGE2_TIMES_MAX %d\n', defs.stage2_times_max);
+fprintf(fh, '#define STAGE_BUF_SIZE %d\n', defs.stage_buf_size);
+fprintf(fh, '#define NUM_ALL_COEFFICIENTS %d\n', defs.sum_filter_lengths);
+fclose(fh);
+
+end
diff --git a/tune/src/src_export_table_2s.m b/tune/src/src_export_table_2s.m
new file mode 100644
index 0000000..7772b93
--- /dev/null
+++ b/tune/src/src_export_table_2s.m
@@ -0,0 +1,190 @@
+function sfl = src_export_table_2s(fs_in, fs_out, l_2s, m_2s, ...
+ pb_2s, sb_2s, taps_2s, ctype, vtype, ppath, hdir, profile)
+
+% src_export_table_2s - Export src setup table
+%
+% src_export_table_2s(fs_in, fs_out, l, m, pb, sb, ctype, vtype, hdir, profile)
+%
+% The parameters are used to differentiate files for possibly many same
+% conversion factor filters with possibly different characteristic.
+%
+% fs_in - input sample rates
+% fs_out - output sample rates
+% l - interpolation factors
+% m - decimation factors
+% pb - passband widths
+% sb - stopband start frequencies
+% ctype - coefficient quantization
+% vtype - C variable type
+% ppath - print directory prefix to header file name include
+% hdir - directory for header files
+% profile - string to append to file name
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 12
+ profile = '';
+end
+
+if isempty(profile)
+ hfn = sprintf('src_%s_table.h', ctype);
+else
+ hfn = sprintf('src_%s_%s_table.h', profile, ctype);
+end
+fh = fopen(fullfile(hdir,hfn), 'w');
+
+fprintf(fh, '/* SRC conversions */\n');
+sfl = 0;
+n_in = length(fs_in);
+n_out = length(fs_out);
+i=1;
+all_modes = zeros(2*n_in*n_out, 7);
+for n=1:2
+ for b=1:n_out
+ for a=1:n_in
+ all_modes(i,:) = [ l_2s(n,a,b) m_2s(n,a,b) ...
+ pb_2s(n,a,b) sb_2s(n,a,b) n a b ];
+ i=i+1;
+ end
+ end
+end
+
+all_modes_sub = all_modes(:,1:4);
+[unique_modes, ia] = unique(all_modes_sub,'rows');
+sm = size(unique_modes);
+
+if isempty(profile)
+ prof_ctype = ctype;
+else
+ prof_ctype = sprintf('%s_%s', profile, ctype);
+end
+for i=1:sm(1)
+ um_tmp = unique_modes(i,:);
+ if isequal(um_tmp(1:2),[1 1]) || isequal(um_tmp(1:2),[0 0])
+ else
+ fprintf(fh, '#include <%ssrc_%s_%d_%d_%d_%d.h>\n', ...
+ ppath, prof_ctype, um_tmp(1:4));
+
+ n = all_modes(ia(i), 5);
+ a = all_modes(ia(i), 6);
+ b = all_modes(ia(i), 7);
+ sfl = sfl +taps_2s(n, a, b); % Count sum of filter lengths
+ end
+end
+fprintf(fh,'\n');
+
+fprintf(fh, '/* SRC table */\n');
+switch ctype
+ case 'float'
+ fprintf(fh, '%s fir_one = 1.0;\n', vtype);
+ fprintf(fh, 'struct src_stage src_double_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, 1.0, &fir_one };\n');
+ fprintf(fh, 'struct src_stage src_double_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0.0, &fir_one };\n');
+ case 'int16'
+ scale16 = 2^15;
+ fprintf(fh, '%s fir_one = %d;\n', vtype, round(scale16*0.5));
+ fprintf(fh, 'struct src_stage src_int16_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n');
+ fprintf(fh, 'struct src_stage src_int16_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n');
+ case 'int24'
+ scale24 = 2^23;
+ fprintf(fh, '%s fir_one = %d;\n', vtype, round(scale24*0.5));
+ fprintf(fh, 'struct src_stage src_int24_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n');
+ fprintf(fh, 'struct src_stage src_int24_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n');
+ case 'int32'
+ scale32 = 2^31;
+ fprintf(fh, '%s fir_one = %d;\n', vtype, round(scale32*0.5));
+ fprintf(fh, 'struct src_stage src_int32_1_1_0_0 = { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n');
+ fprintf(fh, 'struct src_stage src_int32_0_0_0_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, &fir_one };\n');
+ otherwise
+ error('Unknown coefficient type!');
+end
+
+fprintf(fh, 'int src_in_fs[%d] = {', n_in);
+j = 1;
+for i=1:n_in
+ fprintf(fh, ' %d', fs_in(i));
+ if i < n_in
+ fprintf(fh, ',');
+ end
+ j = j + 1;
+ if (j > 8)
+ fprintf(fh, '\n\t');
+ j = 1;
+ end
+end
+fprintf(fh, '};\n');
+
+fprintf(fh, 'int src_out_fs[%d] = {', n_out);
+j = 1;
+for i=1:n_out
+ fprintf(fh, ' %d', fs_out(i));
+ if i < n_out
+ fprintf(fh, ',');
+ end
+ j = j + 1;
+ if (j > 8)
+ fprintf(fh, '\n\t');
+ j = 1;
+ end
+end
+fprintf(fh, '};\n');
+
+for n = 1:2
+ fprintf(fh, 'struct src_stage *src_table%d[%d][%d] = {\n', ...
+ n, n_out, n_in);
+ i = 1;
+ for b = 1:n_out
+ fprintf(fh, '\t{');
+ for a = 1:n_in
+ fprintf(fh, ' &src_%s_%d_%d_%d_%d', ...
+ ctype, l_2s(n,a,b), m_2s(n,a,b), ...
+ pb_2s(n,a,b), sb_2s(n,a,b));
+ if a < n_in
+ fprintf(fh, ',');
+ end
+ i = i + 1;
+ if i > 2
+ fprintf(fh, '\n\t');
+ i = 1;
+ end
+ end
+ fprintf(fh, '}');
+ if b < n_out
+ fprintf(fh, ',\n');
+ else
+ fprintf(fh, '\n');
+ end
+ end
+ fprintf(fh, '};\n');
+end
+
+fclose(fh);
+
+end
diff --git a/tune/src/src_factor1_lm.m b/tune/src/src_factor1_lm.m
new file mode 100644
index 0000000..54e9173
--- /dev/null
+++ b/tune/src/src_factor1_lm.m
@@ -0,0 +1,44 @@
+function [l, m] = src_factor1_lm(fs1, fs2)
+
+% factor1_lm - factorize input and output sample rates ratio to fraction l/m
+%
+% [l, m] = factor1_lm(fs1, fs2)
+%
+% fs1 - input sample rate
+% fs2 - output sample rate
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+k = gcd(fs1, fs2);
+l = fs2/k;
+m = fs1/k;
+
+end
diff --git a/tune/src/src_factor2_lm.m b/tune/src/src_factor2_lm.m
new file mode 100644
index 0000000..6ac8602
--- /dev/null
+++ b/tune/src/src_factor2_lm.m
@@ -0,0 +1,155 @@
+function [l1, m1, l2, m2] = src_factor2_lm(fs1, fs2)
+
+% factor2_lm - factorize input and output sample rates ratio to fraction l1/m2*l2/m2
+%
+% [l1, m1, l2, m2] = factor2_lm(fs1, fs2)
+%
+% fs1 - input sample rate
+% fs2 - output sample rate
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+
+%% The same sample rate?
+if abs(fs1-fs2) < eps
+ l1 = 1; m1 = 1; l2 = 1; m2 = 1;
+ return
+end
+
+%% Find fraction, and factorize
+k = gcd(fs1, fs2);
+l = fs2/k;
+m = fs1/k;
+[l01, l02] = factor2(l);
+[m01, m02] = factor2(m);
+
+%% Hand fixing for some ratios, guide to reuse some common filters
+if (l==147) && (m==640)
+ l01 = 7; m01 = 8; l02 = l/l01; m02 = m/m01; % 192 to 44.1
+end
+if (l==147) && (m==320)
+ l01 = 7; m01 = 8; l02 = l/l01; m02 = m/m01; % 96 to 44.1
+end
+if (l==147) && (m==160)
+ l01 = 7; m01 = 8; l02 = l/l01; m02 = m/m01; % 48 to 44.1
+end
+if (l==160) && (m==147)
+ l01 = 8; m01 = 7; l02 = l/l01; m02 = m/m01; % 44.1 to 48
+end
+if (l==320) && (m==147)
+ l01 = 8; m01 = 7; l02 = l/l01; m02 = m/m01; % 44.1 to 96
+end
+if (l==4) && (m==3)
+ l01 = 4; m01 = 3; l02 = l/l01; m02 = m/m01; % 24 to 32, no 2 stage
+end
+if (l==3) && (m==4)
+ l01 = 3; m01 = 4; l02 = l/l01; m02 = m/m01; % 24 to 32, no 2 stage
+end
+
+
+r11 = l01/m01;
+r22 = l02/m02;
+r12 = l01/m02;
+r21 = l02/m01;
+fs3 = [r11 r12 r21 r22].*fs1;
+
+
+if fs1 > fs2 % Decrease sample rate, dont go below output rate
+ idx = find(fs3 >= fs2);
+ if length(idx) < 1
+ error('Cant factorise interpolations');
+ end
+ fs3_possible = fs3(idx);
+ delta = fs3_possible-fs2; % Fs3 that is nearest to fs2
+ idx = find(delta == min(delta), 1, 'first');
+ fs3_min = fs3_possible(idx);
+ idx = find(fs3 == fs3_min, 1, 'first');
+ switch idx
+ case 1, l1 = l01; m1 = m01; l2 = l02; m2 = m02;
+ case 2, l1 = l01; m1 = m02; l2 = l02; m2 = m01;
+ case 3, l1 = l02; m1 = m01; l2 = l01; m2 = m02;
+ case 4, l1 = l02; m1 = m02; l2 = l01; m2 = m01;
+ end
+else % Increase sample rate, don't go below input rate
+ idx = find(fs3 >= fs1);
+ if length(idx) < 1
+ error('Cant factorise interpolations');
+ end
+ fs3_possible = fs3(idx);
+ delta = fs3_possible-fs1; % Fs2 that is nearest to fs1
+ idx = find(delta == min(delta), 1, 'first');
+ fs3_min = fs3_possible(idx);
+ idx = find(fs3 == fs3_min, 1, 'first');
+ switch idx
+ case 1, l1 = l01; m1 = m01; l2 = l02; m2 = m02;
+ case 2, l1 = l01; m1 = m02; l2 = l02; m2 = m01;
+ case 3, l1 = l02; m1 = m01; l2 = l01; m2 = m02;
+ case 4, l1 = l02; m1 = m02; l2 = l01; m2 = m01;
+ end
+end
+
+%% If 1st stage is 1:1
+if (l1 == 1) && (m1 == 1)
+ l1 = l2;
+ m1 = m2;
+ l2 = 1;
+ m2 = 1;
+end
+
+f1=l/m;
+f2=l1/m1*l2/m2;
+if abs(f1 - f2) > 1e-6
+ error('Bug in factorization code!');
+end
+
+end
+
+
+function [a, b]=factor2(c)
+x = round(sqrt(c));
+t1 = x:2*x;
+d1 = c./t1;
+idx1 = find(d1 == floor(d1), 1, 'first');
+a1 = t1(idx1);
+t2 = x:-1:floor(x/2);
+d2 = c./t2;
+idx2 = find(d2 == floor(d2), 1, 'first');
+a2 = t2(idx2);
+if (a1-x) < (x-a2)
+ a = a1;
+else
+ a = a2;
+end
+b = c/a;
+end
+
+
+
diff --git a/tune/src/src_find_l0m0.m b/tune/src/src_find_l0m0.m
new file mode 100644
index 0000000..2a360a3
--- /dev/null
+++ b/tune/src/src_find_l0m0.m
@@ -0,0 +1,71 @@
+function [l0, m0] = src_find_l0m0(L, M)
+
+% find_l0m0 - find l0, m0 to meet -l0*L + m0*M == 1
+%
+% [l0, m0] = find_l0m0(L, M)
+%
+% L - interpolatation factor
+% M - decimation factor
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if M == 1
+ l0 = 0;
+ m0 = 1;
+ return
+end
+
+if L == 1
+ l0 = 1;
+ m0 = 0;
+ return
+end
+
+l0 = [];
+m0 = [];
+for lt=1:4*L
+ mt = (1+lt*L)/M; % Check if -lt*L + mt*M == 1
+ if floor(mt) == mt
+ l0 = [l0 lt];
+ m0 = [m0 mt];
+ end
+end
+
+s = l0+m0;
+idx = find(s == min(s), 1, 'first');
+l0 = l0(idx);
+m0 = m0(idx);
+
+if -l0*L + m0*M ~= 1
+ error('Something went wrong!');
+end
+
+end
diff --git a/tune/src/src_generate.m b/tune/src/src_generate.m
new file mode 100644
index 0000000..b01b29d
--- /dev/null
+++ b/tune/src/src_generate.m
@@ -0,0 +1,311 @@
+function src_generate(fs_in, fs_out, ctype, fs_inout, profile, qc)
+
+% src_generate - export src conversions for given fs_in and fs_out
+%
+% src_generate(fs_in, fs_out <, ctype, fs_inout>>)
+%
+% fs_in - vector of input sample rates (M)
+% fs_out - vector of output sample rates (N)
+% ctype - coefficient type, use 'int16','int24', 'int32', or 'float'
+% fs_inout - matrix of supported conversions (MxN),
+% 0 = no support, 1 = supported
+% %
+% if ctype is omitted then ctype defaults to 'int16'.
+%
+% If fs_inout matrix is omitted this script will compute coefficients
+% for all fs_in <-> fs_out combinations.
+%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if (nargin == 1) || (nargin > 6)
+ error('Incorrect arguments for function!');
+end
+if nargin == 0
+ %% Default input and output rates
+ fs_in = [8e3 11025 12e3 16e3 18900 22050 24e3 32e3 44100 48e3 ...
+ 64e3 88.2e3 96e3 176400 192e3];
+
+ fs_out = [8e3 11025 12e3 16e3 18900 22050 24e3 32e3 44100 48e3];
+
+ fs_inout = [ 0 0 0 1 0 0 1 1 0 1 ; ...
+ 0 0 0 0 0 0 0 0 0 1 ; ...
+ 0 0 0 0 0 0 0 0 0 1 ; ...
+ 1 0 0 0 0 0 1 1 0 1 ; ...
+ 0 0 0 0 0 0 0 0 0 1 ; ...
+ 0 0 0 0 0 0 0 0 0 1 ; ...
+ 1 0 0 1 0 0 0 1 0 1 ; ...
+ 1 0 0 1 0 0 1 0 0 1 ; ...
+ 0 0 0 0 0 0 0 0 0 1 ; ...
+ 1 1 1 1 0 1 1 1 1 0 ; ...
+ 0 0 0 0 0 0 0 0 0 1 ; ...
+ 0 0 0 0 0 0 0 0 0 1 ; ...
+ 0 0 0 0 0 0 0 0 0 1 ; ...
+ 0 0 0 0 0 0 0 0 0 1 ; ...
+ 0 0 0 0 0 0 0 0 0 1 ];
+
+ ctype = 'int32';
+ profile = 'std';
+ qc = 1.0;
+else
+ if nargin < 3
+ ctype = 'int16';
+ end
+ if nargin < 4
+ fs_inout = ones(length(fs_in), length(fs_out));
+ end
+ if nargin < 5
+ profile = '';
+ end
+ if nargin < 6
+ qc = 1.0;
+ end
+end
+
+sio = size(fs_inout);
+if (length(fs_in) ~= sio(1)) || (length(fs_out) ~= sio(2))
+ error('Sample rates in/out matrix size mismatch!');
+end
+
+%% Exported coefficients type int16, int24, int32, float
+
+switch ctype
+ case 'int16'
+ coef_label = 'int16';
+ coef_ctype = 'int16_t';
+ coef_bits = 16;
+ coef_bytes = 2;
+ case 'int24'
+ coef_label = 'int24';
+ coef_ctype = 'int32_t';
+ coef_bits = 24;
+ coef_bytes = 4;
+ case 'int32'
+ coef_label = 'int32';
+ coef_ctype = 'int32_t';
+ coef_bits = 32;
+ coef_bytes = 4;
+ case 'float'
+ coef_label = 'float'; coef_ctype = 'float';
+ coef_bits = 24;
+ coef_bytes = 4;
+ otherwise
+ error('Request for incorrect coefficient type');
+end
+data_bytes = 4;
+
+hdir = mkdir_check('include');
+rdir = mkdir_check('reports');
+
+%% Find fractional conversion factors
+nfsi = length(fs_in);
+nfso = length(fs_out);
+l_2s = zeros(2, nfsi, nfso);
+m_2s = zeros(2, nfsi, nfso);
+mops_2s = zeros(2, nfsi, nfso);
+pb_2s = zeros(2,nfsi, nfso);
+sb_2s = zeros(2,nfsi, nfso);
+taps_2s = zeros(2,nfsi, nfso);
+defs.fir_delay_size = 0;
+defs.out_delay_size = 0;
+defs.blk_in = 0;
+defs.blk_out = 0;
+defs.num_in_fs = nfsi;
+defs.num_out_fs = nfso;
+defs.stage1_times_max = 0;
+defs.stage2_times_max = 0;
+defs.stage_buf_size = 0;
+h = 1;
+for b = 1:nfso
+ for a = 1:nfsi
+ fs1 = fs_in(a);
+ fs2 = fs_out(b);
+ [l1, m1, l2, m2] = src_factor2_lm(fs1, fs2);
+ fs3 = fs1*l1/m1;
+ cnv1 = src_param(fs1, fs3, coef_bits, qc);
+ cnv2 = src_param(fs3, fs2, coef_bits, qc);
+ if (fs2 < fs1)
+ % When decimating 1st stage passband can be limited
+ % for wider transition band
+ f_pb = fs2*cnv2.c_pb;
+ cnv1.c_pb = f_pb/min(fs1,fs3);
+ end
+ if (fs2 > fs1)
+ % When interpolating 2nd stage passband can be limited
+ % for wider transition band
+ f_pb = fs1*cnv1.c_pb;
+ cnv2.c_pb = f_pb/min(fs2,fs3);
+ end
+ if fs_inout(a,b) > 0 || (a == b)
+ if cnv2.fs1-cnv2.fs2 > eps
+ % Allow half ripple for dual stage SRC parts
+ cnv1.rp = cnv1.rp/2;
+ cnv2.rp = cnv2.rp/2;
+ end
+ src1 = src_get(cnv1);
+ src2 = src_get(cnv2);
+ k = gcd(src1.blk_out, src2.blk_in);
+ stage1_times = src2.blk_in/k;
+ stage2_times = stage1_times*src1.blk_out/src2.blk_in;
+ defs.stage1_times_max = max(defs.stage1_times_max, stage1_times);
+ defs.stage2_times_max = max(defs.stage2_times_max, stage2_times);
+ l_2s(:,a,b) = [src1.L src2.L];
+ m_2s(:,a,b) = [src1.M src2.M];
+ mops_2s(:,a,b) = [src1.MOPS src2.MOPS];
+ pb_2s(:,a,b) = [round(1e4*src1.c_pb) round(1e4*src2.c_pb)];
+ sb_2s(:,a,b) = [round(1e4*src1.c_sb) round(1e4*src2.c_sb)];
+ taps_2s(:,a,b) = [src1.filter_length src2.filter_length];
+ defs.fir_delay_size = max(defs.fir_delay_size, src1.fir_delay_size);
+ defs.out_delay_size = max(defs.out_delay_size, src1.out_delay_size);
+ defs.blk_in = max(defs.blk_in, src1.blk_in);
+ defs.blk_out = max(defs.blk_out, src1.blk_out);
+ defs.fir_delay_size = max(defs.fir_delay_size, src2.fir_delay_size);
+ defs.out_delay_size = max(defs.out_delay_size, src2.out_delay_size);
+ defs.blk_in = max(defs.blk_in, src2.blk_in);
+ defs.blk_out = max(defs.blk_out, src2.blk_out);
+ defs.stage_buf_size = max(defs.stage_buf_size, src1.blk_out*stage1_times);
+ src_export_coef(src1, coef_label, coef_ctype, hdir, profile);
+ src_export_coef(src2, coef_label, coef_ctype, hdir, profile);
+ end
+ end
+end
+
+%% Export modes table
+defs.sum_filter_lengths = src_export_table_2s(fs_in, fs_out, l_2s, m_2s, ...
+ pb_2s, sb_2s, taps_2s, coef_label, coef_ctype, ...
+ 'sof/audio/coefficients/src/', hdir, profile);
+src_export_defines(defs, coef_label, hdir, profile);
+
+%% Print 2 stage conversion factors
+fn = sprintf('%s/src_2stage.txt', rdir);
+fh = fopen(fn,'w');
+fprintf(fh,'\n');
+fprintf(fh,'Dual stage fractional SRC: Ratios\n');
+fprintf(fh,'%8s, ', 'in \ out');
+for b = 1:nfso
+ fprintf(fh,'%12.1f, ', fs_out(b)/1e3);
+end
+fprintf(fh,'\n');
+for a = 1:nfsi
+ fprintf(fh,'%8.1f, ', fs_in(a)/1e3);
+ for b = 1:nfso
+ cstr = print_ratios(l_2s, m_2s, a, b);
+ fprintf(fh,'%12s, ', cstr);
+ end
+ fprintf(fh,'\n');
+end
+fprintf(fh,'\n');
+
+%% Print 2 stage MOPS
+fprintf(fh,'Dual stage fractional SRC: MOPS\n');
+fprintf(fh,'%8s, ', 'in \ out');
+for b = 1:nfso
+ fprintf(fh,'%8.1f, ', fs_out(b)/1e3);
+end
+fprintf(fh,'\n');
+for a = 1:nfsi
+ fprintf(fh,'%8.1f, ', fs_in(a)/1e3);
+ for b = 1:nfso
+ mops = sum(mops_2s(:,a,b));
+ if sum(l_2s(:,a,b)) < eps
+ mops_str = 'x';
+ else
+ mops_str = sprintf('%.2f', mops);
+ end
+ fprintf(fh,'%8s, ', mops_str);
+ end
+ fprintf(fh,'\n');
+end
+fprintf(fh,'\n');
+
+%% Print 2 stage MOPS per stage
+fprintf(fh,'Dual stage fractional SRC: MOPS per stage\n');
+fprintf(fh,'%10s, ', 'in \ out');
+for b = 1:nfso
+ fprintf(fh,'%10.1f, ', fs_out(b)/1e3);
+end
+fprintf(fh,'\n');
+for a = 1:nfsi
+ fprintf(fh,'%10.1f, ', fs_in(a)/1e3);
+ for b = 1:nfso
+ mops = mops_2s(:,a,b);
+ if sum(l_2s(:,a,b)) < eps
+ mops_str = 'x';
+ else
+ mops_str = sprintf('%.2f+%.2f', mops(1), mops(2));
+ end
+ fprintf(fh,'%10s, ', mops_str);
+ end
+ fprintf(fh,'\n');
+end
+fprintf(fh,'\n');
+
+fprintf(fh,'Coefficient RAM %.1f kB\n', ...
+ defs.sum_filter_lengths*coef_bytes/1024);
+fprintf(fh,'Max. data RAM %.1f kB\n', ...
+ (defs.fir_delay_size + defs.out_delay_size+defs.stage_buf_size) ...
+ * data_bytes/1024);
+
+fprintf(fh,'\n');
+fclose(fh);
+type(fn);
+
+end
+
+function d = mkdir_check(d)
+if exist(d) ~= 7
+ mkdir(d);
+end
+end
+
+function cstr = print_ratios(l_2s, m_2s, a, b)
+l1 = l_2s(1,a,b);
+m1 = m_2s(1,a,b);
+l2 = l_2s(2,a,b);
+m2 = m_2s(2,a,b);
+if l1+m2+l2+m2 == 0
+ cstr = 'x';
+else
+ if m2 == 1
+ if l2 == 1
+ cstr2 = '';
+ else
+ cstr2 = sprintf('*%d', l2);
+ end
+ else
+ cstr2 = sprintf('*%d/%d', l2, m2);
+ end
+ if m1 == 1
+ cstr1 = sprintf('%d', l1);
+ else
+ cstr1 = sprintf('%d/%d', l1, m1);
+ end
+ cstr = sprintf('%s%s', cstr1, cstr2);
+end
+end
diff --git a/tune/src/src_get.m b/tune/src/src_get.m
new file mode 100644
index 0000000..4520af9
--- /dev/null
+++ b/tune/src/src_get.m
@@ -0,0 +1,254 @@
+function src = src_get(cnv)
+
+% src_get - calculate coefficients for a src
+%
+% src = src_get(cnv);
+%
+% cnv - src parameters
+% src - src result
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+use_firpm = 0;
+use_remez = 0;
+use_kaiser = 0;
+switch lower(cnv.design)
+ case 'firpm'
+ if exist('OCTAVE_VERSION', 'builtin')
+ use_remez = 1;
+ else
+ use_firpm = 1;
+ end
+ case 'kaiser'
+ use_kaiser = 1;
+ otherwise
+ error('Unknown FIR design request!');
+end
+
+if abs(cnv.fs1-cnv.fs2) < 1
+ %% Return minimum needed for scripts to work
+ src.L=1;
+ src.M=1;
+ src.odm=1;
+ src.idm=1;
+ src.MOPS=0;
+ src.c_pb = 0;
+ src.c_sb = 0;
+ src.fir_delay_size = 0;
+ src.out_delay_size = 0;
+ src.blk_in = 1;
+ src.blk_out = 1;
+ src.gain = 1;
+ src.filter_length = 0;
+ return
+end
+
+%% fractional SRC parameters
+[L, M] = src_factor1_lm(cnv.fs1, cnv.fs2);
+src.L = L;
+src.M = M;
+src.num_of_subfilters = L;
+[src.idm src.odm] = src_find_l0m0(src.L, src.M);
+min_fs = min(cnv.fs1,cnv.fs2);
+src.f_pb = min_fs*cnv.c_pb;
+src.f_sb = min_fs*cnv.c_sb;
+src.c_pb = cnv.c_pb;
+src.c_sb = cnv.c_sb;
+src.fs1 = cnv.fs1;
+src.fs2 = cnv.fs2;
+src.rp = cnv.rp;
+src.rs = cnv.rs;
+
+%% FIR PM design
+fs3 = src.L*cnv.fs1;
+f = [src.f_pb src.f_sb];
+a = [1 0];
+
+% Kaiser fir is not equiripple, can allow more ripple in the passband
+% lower freq.
+dev = [(10^(cnv.rp/20)-1)/(10^(cnv.rp/20)+1) 10^(-cnv.rs/20)];
+[kn0, kw, kbeta, kftype] = kaiserord(f, a, dev, fs3);
+if use_firpm
+ %dev = [(10^(cnv.rp/20)-1)/(10^(cnv.rp/20)+1) 10^(-cnv.rs/20)];
+ [n0,fo,ao,w] = firpmord(f,a,dev,fs3);
+ n0 = round(n0*0.95); % Decrease order to 95%
+end
+if use_remez
+ n0 = round(kn0*0.60); % Decrease order to 70%
+ fo = [0 2*f/fs3 1];
+ ao = [1 1 0 0];
+ w = [1 dev(1)/dev(2)];
+end
+if use_kaiser
+ n0 = round(kn0*0.70); % Decrease order to 70%
+end
+
+% Constrain filter length to be a suitable multiple. Multiple of
+% interpolation factor ensures that all subfilters are equal length.
+% Make each sub-filter order multiple of N helps in making efficient
+% implementation.
+nfir_increment = src.num_of_subfilters * cnv.filter_length_mult;
+
+nsf0 = (n0+1)/nfir_increment;
+if nsf0 > floor(nsf0)
+ n = (floor(nsf0)+1)*nfir_increment-1;
+else
+ n = n0;
+end
+
+src.subfilter_length = (n+1)/src.num_of_subfilters;
+src.filter_length = n+1;
+nfir = n;
+f_sb = linspace(src.f_sb, fs3/2, 500);
+stopband_ok = 0;
+need_to_stop = 0;
+delta = 100;
+n_worse = 0;
+n_worse_max = 20;
+n = 1;
+n_max = 100;
+dn = ones(1, n_max)*1000;
+fn = zeros(1, n_max);
+while (stopband_ok) == 0 && (n < n_max)
+ if use_firpm || use_remez
+ if nfir > 1800
+ b = fir1(nfir, kw, kftype, kaiser(nfir+1, kbeta));
+ else
+ if use_firpm
+ b = firpm(nfir,fo,ao,w);
+ else
+ b = remez(nfir,fo,ao,w);
+ end
+ end
+ else
+ b = fir1(nfir, kw, kftype, kaiser(nfir+1, kbeta));
+ end
+ m_b = max(abs(b));
+ %sref = 2^(cnv.coef_bits-1);
+ %bq = round(b*sref/m_b)*m_b/sref;
+ bq = b;
+ h_sb = freqz(bq, 1, f_sb, fs3);
+ m_sb = 20*log10(abs(h_sb));
+ delta_prev = delta;
+ delta = cnv.rs+max(m_sb);
+ fprintf('Step=%3d, Delta=%f dB, N=%d\n', n, delta, nfir);
+ dn(n) = delta;
+ fn(n) = nfir;
+ if delta < 0
+ stopband_ok = 1;
+ else
+ if delta_prev < delta
+ n_worse = n_worse+1;
+ if n_worse > n_worse_max
+ need_to_stop = 1; % No improvement, reverse
+ idx = find(dn == min(dn), 1, 'first');
+ nfir = fn(idx);
+ else
+ nfir = nfir + nfir_increment;
+ end
+ else
+ if need_to_stop == 0
+ nfir = nfir + nfir_increment;
+ else
+ stopband_ok = 1; % Exit after reverse
+ fprintf('Warning: Filter stop band could not be ');
+ fprintf('reached.\n', cnv.coef_bits);
+ end
+ end
+ end
+ n = n + 1;
+end
+
+f_p = linspace(0, fs3/2, 2000);
+m_db = 20*log10(abs(freqz(bq, 1, f_p, fs3)));
+i_pb = find(f_p < src.f_pb);
+g_pb = max(m_db(i_pb));
+g_att_lin = 10^(-g_pb/20);
+
+if 1
+ p_ymin = floor((-cnv.rs-50)/10)*10;
+ p_ymax = 10;
+ figure;
+ clf;
+ plot(f_p, m_db);
+ grid on;
+ xlabel('Frequency (Hz)');
+ ylabel('Magnitude (dB)');
+ axis([0 fs3/2 p_ymin p_ymax]);
+ hold on
+ plot([src.f_sb src.f_sb],[p_ymin p_ymax], 'r--');
+ plot([0 fs3],[-cnv.rs -cnv.rs], 'r--');
+ hold off
+ axes('Position', [ 0.58 0.7 0.3 0.2]);
+ box on;
+ plot(f_p(i_pb), m_db(i_pb));
+ axis([0 src.f_pb -cnv.rp-0.01 cnv.rp+0.01]);
+ hold on
+ plot([0 src.f_pb], +0.5*cnv.rp*ones(1,2), 'r--');
+ plot([0 src.f_pb], -0.5*cnv.rp*ones(1,2), 'r--');
+ hold off
+ grid on;
+ box off;
+end
+
+src.subfilter_length = ceil((nfir+1)/src.num_of_subfilters);
+src.filter_length = src.subfilter_length*src.num_of_subfilters;
+src.b = zeros(src.filter_length,1);
+src.gain = 1;
+src.b(1:nfir+1) = b*src.L*g_att_lin;
+m = max(abs(src.b));
+gmax = (32767/32768)/m;
+maxshift = floor(log(gmax)/log(2));
+src.b = src.b * 2^maxshift;
+src.gain = 1/2^maxshift;
+src.shift = maxshift;
+
+%% Reorder coefficients
+if 1
+ src.coefs = src.b;
+else
+ src.coefs = zeros(src.filter_length,1);
+ for n = 1:src.num_of_subfilters
+ i11 = (n-1)*src.subfilter_length+1;
+ i12 = i11+src.subfilter_length-1;
+ src.coefs(i11:i12) = src.b(n:src.num_of_subfilters:end);
+ end
+end
+
+src.halfband = 0;
+src.blk_in = M;
+src.blk_out = L;
+src.MOPS = cnv.fs1/M*src.filter_length/1e6;
+src.fir_delay_size = src.subfilter_length + ...
+ (src.num_of_subfilters-1)*src.idm + src.blk_in;
+src.out_delay_size = (src.num_of_subfilters-1)*src.odm + 1;
+
+end
diff --git a/tune/src/src_param.m b/tune/src/src_param.m
new file mode 100644
index 0000000..49e935c
--- /dev/null
+++ b/tune/src/src_param.m
@@ -0,0 +1,87 @@
+function cnv = src_param(fs1, fs2, coef_bits, q)
+
+% src_param - get converter parameters
+%
+% cnv = src_param(fs1, fs2, coef_bits, q)
+%
+% fs1 - input rate
+% fs2 - output rate
+% coef_bits - word length identifier
+% q - quality scale filter bandwidth and stopband attenuation,
+% 1 is default
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+% Note: firpm design with rs 93 dB, or kaiser with 69 dB rs is fair quality.
+% Both give about -80 dB THD+N with 24 bit coefficients. With 16 bit
+% coefficients THD+N is limited to about -76 dB.
+
+if nargin < 4
+ q = 1.0;
+end
+
+%% Copy input parameters
+cnv.fs1 = fs1;
+cnv.fs2 = fs2;
+cnv.coef_bits = coef_bits;
+
+%% FIR design
+cnv.design = 'kaiser'; % Use firpm or kaiser
+
+%% Default SRC quality
+cnv.c_pb = q * 22/48; % Gives 22 kHz BW @ 48 kHz
+cnv.c_sb = 0.5; % Start stopband at Fs/2
+cnv.rs = 70; % Stopband attenuation in dB
+cnv.rp = 0.1; % Passband ripple in dB
+cnv.rp_tot = 0.1; % Max +/- passband ripple allowed, used in test script only
+
+%% Constrain sub-filter lengths. Make subfilters lengths multiple of four
+% is a good assumption for processors.
+cnv.filter_length_mult = 4;
+
+%% Exceptions for quality
+if min(fs1, fs2) > 80e3
+ cnv.c_pb = 30e3/min(fs1, fs2); % 30 kHz BW for > 80 kHz
+end
+
+%% Sanity checks
+if cnv.c_pb > 0.49
+ error('Too wide passband');
+end
+if cnv.c_pb < 0.15
+ error('Too narrow passband');
+end
+if cnv.rs > 160
+ error('Too large stopband attenuation');
+end
+if cnv.rs < 40
+ error('Too low stopband attenuation');
+end
diff --git a/tune/src/src_std_int32.m b/tune/src/src_std_int32.m
new file mode 100644
index 0000000..125ae96
--- /dev/null
+++ b/tune/src/src_std_int32.m
@@ -0,0 +1,30 @@
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+src_generate();
diff --git a/tune/src/src_tiny_int16.m b/tune/src/src_tiny_int16.m
new file mode 100644
index 0000000..be310fb
--- /dev/null
+++ b/tune/src/src_tiny_int16.m
@@ -0,0 +1,41 @@
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+% * Redistributions of source code must retain the above copyright
+% notice, this list of conditions and the following disclaimer.
+% * Redistributions in binary form must reproduce the above copyright
+% notice, this list of conditions and the following disclaimer in the
+% documentation and/or other materials provided with the distribution.
+% * Neither the name of the Intel Corporation nor the
+% names of its contributors may be used to endorse or promote products
+% derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+fs1 = [8e3 16e3 24e3 32e3 44.1e3 48e3];
+fs2 = [8e3 16e3 24e3 32e3 44.1e3 48e3];
+fsm = [0 0 0 0 0 1; ...
+ 0 0 0 0 0 1; ...
+ 0 0 0 0 0 1; ...
+ 0 0 0 0 0 1; ...
+ 0 0 0 0 0 1; ...
+ 1 1 1 1 1 0; ...
+ ];
+fmt = 'int16'; profile = 'tiny'; q = 0.75;
+
+src_generate(fs1, fs2, fmt, fsm, profile, q);