[SCM] libambix/master: New upstream version 0.1

umlaeute at users.alioth.debian.org umlaeute at users.alioth.debian.org
Wed Oct 5 21:12:10 UTC 2016


The following commit has been merged in the master branch:
commit ecb0a034b940c6d3b4103cd0cf5cb6fa5c069a0d
Author: IOhannes m zmölnig <zmoelnig at umlautQ.umlaeute.mur.at>
Date:   Wed Oct 5 22:56:14 2016 +0200

    New upstream version 0.1

diff --git a/.deploy-documentation.sh b/.deploy-documentation.sh
new file mode 100755
index 0000000..31d17fc
--- /dev/null
+++ b/.deploy-documentation.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+WD=$(pwd)
+INPUTDIR="${WD}/doc/apiref"
+INPUT2DIR="${WD}/coverage"
+OUTPUTDIR="${WD}/gh-pages"
+REMOTE=https://github.com/iem-projects/ambix
+
+error() {
+ echo "$@" 1>&2
+}
+
+if [ -e "${INPUTDIR}/index.html" ]; then
+ :
+else
+ error "missing {INPUTDIR}/index.html"
+ exit 0
+fi
+if [ "x${REMOTE}" = "x" ]; then
+ error "no remote"
+ exit 0
+fi
+COMMIT=$(git describe --always)
+
+commit_msg() {
+echo "Deploy code docs to GitHub Pages"
+echo ""
+if [ "x${COMMIT}" != x ]; then
+ echo "Commit: ${COMMIT}"
+fi
+if [ "x${TRAVIS_BUILD_NUMBER}" != "x" ]; then
+  echo "Travis build: ${TRAVIS_BUILD_NUMBER}"
+fi
+if [ "x${TRAVIS_COMMIT}" != "x" ]; then
+  echo "Travis commit: ${TRAVIS_COMMIT}"
+fi
+}
+
+git clone -b gh-pages "${REMOTE}" "${OUTPUTDIR}"
+cd "${OUTPUTDIR}" || exit 1
+
+##### Configure git.
+# Set the push default to simple i.e. push only the current branch.
+git config push.default simple
+# Pretend to be an user called Travis CI.
+git config user.name "Travis CI"
+git config user.email "travis at travis-ci.org"
+
+## clean gh-pages
+rm -rf "${INPUTDIR##*/}"
+
+## copy the doxygen documentation
+cp -rav "${INPUTDIR}" "${INPUTDIR##*/}"
+
+## add and commit to git
+git add --all "${INPUTDIR##*/}"
+
+## add coverage info (if it is there)
+if [ -d "${INPUT2DIR}" ]; then
+  error "adding coverage info ${INPUT2DIR##*/}"
+  rm -rf "${INPUT2DIR##*/}"
+  cp -rav "${INPUT2DIR}" "${INPUT2DIR##*/}"
+  git add --all "${INPUT2DIR##*/}"
+fi
+
+error "committing to git"
+commit_msg | git commit -F - .
+
+
+# and push
+error "pushing to git"
+if [ "x${GH_REPO_TOKEN}" != "x" ]; then
+  GH_REPO_REF=${REMOTE#*@}
+  GH_REPO_REF=${GH_REPO_REF#*//}
+  git push --force "https://${GH_REPO_TOKEN}@${GH_REPO_REF}" > /dev/null
+else
+  git push --force > /dev/null
+fi
+
+rm -rf "${OUTPUTDIR}"
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 189502d..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,43 +0,0 @@
-# backup copies
-*~
-# build products
-*\.la
-*\.lo
-*\.o
-*\.so
-*\.dll
-*\.pd_*
-\.deps/
-\.libs/
-# autotools byproducts
-Makefile
-Makefile\.in
-aclocal\.m4
-autom4te\.cache/
-configure
-config\.guess
-config\.log
-config\.status
-config\.sub
-missing
-install-sh
-stamp-h1
-libtool
-depcomp
-ltmain\.sh
-config\.h
-config\.h\.in
-m4/libtool\.m4
-m4/ltoptions\.m4
-m4/ltsugar\.m4
-m4/ltversion\.m4
-m4/lt~obsolete\.m4
-## w32 build projects
-build/w32-vs*/*
-*.vcproj.*.*.user
-!*.dsw
-!*.dsp
-!*.sln
-!*.vcproj
-!*.vsprops
-!Makefile.am
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..db98016
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,59 @@
+language: c
+sudo: required
+dist: trusty
+
+env:
+  global:
+        - secure: "nAc3WvwtJBm+hLIYxp4srwgM7qDWRovkEpsza+UITEE8TUqeZND2543xMZlWz1w5qn8V/F/1yX1oYl7Ot0ymmu9Uh41b1NBr3cvo2U8RLDSM9SBoqtyS1pSCnJ2qiSk+hg5GxObWug/ph3TkEgZaDmYCDAgHiv1I9WXVRxeR144="
+        - COVERITY_SCAN_BRANCH_PATTERN="(master|coverity-.*)"
+        - COVERITY_SCAN_NOTIFICATION_EMAIL="dev at umlaeute.mur.at"
+        - COVERITY_SCAN_BUILD_COMMAND="make"
+        - LIBSNDFILE_URL="http://www.mega-nerd.com/libsndfile/files/libsndfile-1.0.26.tar.gz"
+
+addons:
+  apt:
+    packages:
+      - libvorbis-dev
+      - libflac-dev
+      - libasound2-dev
+      - doxygen
+      - lcov
+      - ca-certificates
+
+matrix:
+  include:
+    - compiler: clang
+      env:
+        - COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG"
+    - compiler: gcc
+      env:
+        - DO_COVERAGE="yes"
+
+install:
+  ## build libsndfile
+  - mkdir -p libsndfile/build && curl "$LIBSNDFILE_URL" | tar --strip-components=1 -C libsndfile -xvzf -
+  - cd libsndfile/build && ../configure --disable-silent-rules && make && sudo make install
+  ## remove libtool libs
+  - find /usr/local/lib -type f -name "*.la" -exec sudo rm -f {} \+
+before_script:
+  - cd "$TRAVIS_BUILD_DIR"
+  - ./autogen.sh
+  - ./configure --disable-silent-rules
+  # OMG, Coverity scan uses a certificate not supported by travis-ci
+  - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-certificates.crt
+  # implement Coverity Scan with before_script instead of addons.coverity_scan
+  # to work around too-early quota check by the coverity_scan addon
+  - if [[ -n $COVERITY_SCAN_PROJECT_NAME ]] ; then curl -s 'https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh' | bash || true ; fi
+
+script:
+- make
+- LD_LIBRARY_PATH=/usr/local/lib make distcheck
+
+after_success:
+  - if [[ "x${DO_COVERAGE}" = "xyes" ]] ; then LD_LIBRARY_PATH=/usr/local/lib ./coverage.sh; fi
+  - if [[ "yes.${TRAVIS_BRANCH}.${TRAVIS_PULLREQUEST}" = "yes.master." ]]; then ./.deploy-documentation.sh ; fi
+  - bash <(curl -s https://codecov.io/bash)
+
+after_failure:
+  # spit out any test-suite results...
+  - find . -name test-suite.log -exec grep . {} \+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..3573ba6
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,104 @@
+Contributing to libambix development
+====================================
+
+Contribution should be done via
+- Merge Requests / Pull Requests
+OR
+- via git patchsets (`git format-patch`)
+
+# GIT
+
+## Canonical Repositories
+
+MAIN repository
+- https://git.iem.at/ambisonics/libambix
+
+secondary repository
+- https://github.com/iem-projects/ambix
+
+Please *do not use* these legacy repositories:
+- ~~https://github.com/umlaeute/ambix~~
+- ~~https://git.code.sf.net/p/iem/ambix~~ (SourceForge)
+
+## Commits
+
+- make small, atomic commits
+- commit often
+- be sure that the description matches the actual changeset
+- do not mix unrelated changes into a single commit (*"fixed bug BAR, added
+  feature FOO"* is **bad**)
+- never mix changes to different components
+  (e.g. changes to `libambix/` should go in different commits as changes to `utils/`
+  and changes to `samples/pd/`)
+  - even if this temporarily breaks compilation! (e.g. if you are changing the
+    API of the libambix library, you have to update any code that uses this API;
+    in this case, first commit the changes to libambix, and then commit the
+    required changes in the utilities. the latter should be a single commit that
+    only adapts the code to the new API)
+	- make small, atomic commits
+
+# Coding Style
+
+- libambix is written in `ANSI-C` (aka `C89`)
+
+- function names use underscores to separate names (e.g. `ambix_open`)
+- *public* functions
+  - each *public* function **MUST** be declared in `libambix/ambix/ambi.h`
+  - each *public* function **MUST** be declared with the `AMBIX_API` decorator
+  - each *public* function **MUST** start with the `ambix_` prefix (to avoid nameclashes with other libraries)
+- *non-public* functions
+  - *non-public* functions that are only used within a single source file **MUST** be declared `static`
+  - *non-public* functions that are used within the entire libambix library **MUST** be prefixed with `_ambix`
+  - *non-public* functions that are used within the entire libambix library **SHOULD** be declared in `libambix/src/private.h` file
+
+- type names use underscores to separate names (e.g. `ambix_matrix_t`)
+- type names have a `_t` suffix (and an `ambix_` prefix if they are non-trivial)
+- *public* types
+  - complex types (aka `struct`s) should always be opaque (the actual `struct` is kept as an implementation detail)
+  - if needed, use (public) accessor functions (`get`/`set`) for the elements of a complex type
+
+-
+
+## Code Formatting
+
+TODO (follow mine :-))
+- no whitespace at the end-of-line
+- no empty line at the end-of-file
+
+
+# Code Testing
+
+## Unit Tests
+
+See `libambix/tests/` for example tests.
+
+All public functionality (and as far as possible all private functionality)
+should be tested via unit tests.
+The testing "framework" in use is provided by autotools.
+
+When testing private interfaces (non-public functions), the unit tests
+need to be compiled in debug-mode (using the `--enable-debug` configure option)
+and the tests should be protected by an `if DEBUG / endif` clause
+`libambix/tests/Makefile.am`.
+
+## Checking for memory leaks
+The unit tests can be instrumented to be run through valgrind:
+
+    cd libambix/tests
+    make check-valgrind
+
+The above will run the tests through the standard `memcheck` tool.
+If you want to use another valgrind tool, You can specify that as well:
+
+    cd libambix/tests
+    make check-valgrind-tool VALGRIND_TOOL=memcheck
+
+## Continuous Integration
+The library is automatically built and tested via
+[Travis-CI](https://travis-ci.org/iem-projects/ambix) whenever new code is
+committed.
+
+If you do not have write access to the main repository of libambix, you can
+Trigger a CI build for your contribution simply by creating a *Pull Request*
+against the [iem-projects/ambix](https://github.com/iem-projects/ambix)
+repository on GitHub.
diff --git a/README b/README
deleted file mode 100644
index 7656a44..0000000
--- a/README
+++ /dev/null
@@ -1,95 +0,0 @@
-This is ambix 0.0.1
-
-libambix is a library of C routines for reading and writing
-files following the "ambix" (AMBIsonics eXchange) conventions.
-
-
-Directory layout
-----------------
-libambix/
-	all components of the libambix library
-libambix/src
-	the source code for library itself.
-libambix/ambix
-	public header files for the library
-libambix/tests
-	programs which link against libambix and test its functionality.
-utils/
-	utility programs using libambix
-
-
-NOTES
------
-libambix is a reads and writes soundfiles following the "ambix" specificiation.
-such files are:
-- CAF (Core Audio Format) files 
-- with a special UUID-chunk
-
-Audio data as output by libambix will follow the following specification:
-- sample format is either PCM16, PCM24 or float32 (the latter being best tested)
-- audio data is interleaved
-- ambisonics channels are
-	- normalization		: SN3D
-	- channel ordering	: ACN
-
-It is planned to provide conversion matrices to present the audio data in other
-(common) formats namely
-- Furse-Malham set
-- other normalizations (N3D)
-- other ordering (SID)
-
-
-
-DEPENDENCIES
-------------
-Currently libambix uses libsndfile to read the actual file.
-Due to some advanced functionality, you need at least libsndfile-1.0.26.
-At the time of writing, libsndfile-1.0.26 has not yet been released. so 
-you need the current development version of libsndfile
-	https://github.com/erikd/libsndfile
-
-
-LINUX
------
-Whereever possible, you should use the packages supplied by your Linux
-distribution.
-
-If you really do need to compile from source it should be as easy as:
-
-	$ ./configure
-	$ make
-	$ make install
-
-if you want to compile the development version of libambix, you might need
-to run
-	$ ./autogen.sh
-_before_ any of the above.
-
-UNIX
-----
-Compile as for Linux.
-
-
-Win32/Win64
------------
-The default Windows compilers (Microsoft's Visual Studio) are nowhere near
-compliant with the 1999 ISO C Standard and hence not able to compile libambix.
-
-Please use the libambix binaries available on the ambix web site.
-
-
-MacOSX
-------
-Building on MacOSX should be the same as building it on any other Unix.
-
-
-CONTACTS
---------
-
-libambix was written by IOhannes m zmölnig at the Institute of Electronic Music
-and Acoustics (IEM), andthe University of Music and Performing Arts (KUG), Graz,
-Austria
-The libambix home page is at :
-
-	http://ambisonics.iem.at/xchange/format
-
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..bdd5d0b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,107 @@
+libambix - The AMBIsonics eXchange library
+==========================================
+
+This is libambix `0.0.1`
+
+libambix is a library of C routines for reading and writing
+files following the "ambix" (AMBIsonics eXchange) conventions.
+
+# Status
+
+| *Check*                | *Health*                                                            |
+| :--------------------- | :------------------------------------------------------------------ |
+| Continuous Integration | ![Travis-CI](https://api.travis-ci.org/umlaeute/pd-iemnet.svg)      |
+| Static Code Analysis   | ![Coverity Scan](https://scan.coverity.com/projects/1736/badge.svg) |
+| Test Coverage          | [![codecov](https://codecov.io/gh/iem-projects/ambix/branch/master/graph/badge.svg)](https://codecov.io/gh/iem-projects/ambix) |
+
+
+# INTRODUCTION
+libambix is a library that reads and writes soundfiles following the "ambix"
+specificiation.
+Such files are:
+- `CAF` (Core Audio Format) files
+- *with* a special `UUID-chunk`
+
+Audio data as output (and accepted as input) by libambix will follow the following specification:
+- sample format is either `PCM16`, `PCM24`, `float32` (this one being best
+  tested) and `float64`
+- audio data is *interleaved*
+- ambisonics channels are
+	- normalization		: `SN3D`
+	- channel ordering	: `ACN`
+
+It is planned to provide conversion matrices to present the audio data in other
+(common) formats namely
+- Furse-Malham set (*FuMa*)
+- other normalizations (*N3D*)
+- other ordering (*SID*)
+
+# Download
+
+Get the source code (and releases) from
+  https://git.iem.at/ambisonics/libambix
+
+The source code is also mirrored to
+ [GitHub](https://github.com/iem-projects/ambix/)
+and (less often) to
+ [SourceForge](https://sourceforge.net/p/iem/ambix/)
+
+# API Documentation
+
+An up-to-date API Documentation can be found at
+  http://iem-projects.github.io/ambix/apiref/
+
+# Directory layout
+- `libambix/` - all components of the libambix library
+- `libambix/src` - the source code for library itself.
+- `libambix/ambix` - public header files for the library
+- `libambix/tests` - programs which link against libambix and test its functionality.
+- `utils/` - utility programs using libambix
+
+# BUILDING from source
+
+## DEPENDENCIES
+Currently libambix uses libsndfile to read the actual file.
+Due to some advanced functionality, you need at least libsndfile-1.0.26.
+The current version of libsndfile can be obtained from
+  https://github.com/erikd/libsndfile
+
+
+## LINUX
+Wherever possible, you should use the packages supplied by your Linux
+distribution.
+
+If you really do need to compile from source it should be as easy as:
+
+    $ ./configure
+    $ make
+    $ make install
+
+if you want to compile the development version of libambix, you might need
+to run the following *before* any of the above:
+
+    $ ./autogen.sh
+
+## UNIX
+Compile as for Linux.
+
+
+## Win32/Win64
+The default Windows compilers (Microsoft's Visual Studio) are nowhere near
+compliant with the 1999 ISO C Standard and hence not able to compile libambix.
+
+Please use the libambix binaries available on the ambix web site.
+
+
+## MacOSX
+Building on MacOSX should be the same as building it on any other Unix.
+
+
+# CONTACT
+
+libambix was written by IOhannes m zmölnig at the Institute of Electronic Music
+and Acoustics (IEM), and the University of Music and Performing Arts (KUG), Graz,
+Austria
+The libambix home page is at :
+
+	http://git.iem.at/ambisonics/libambix
diff --git a/configure.ac b/configure.ac
index d296de4..685f4bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
-AC_INIT([ambix],[0.0.1],[zmoelnig at iem.at],
+AC_INIT([ambix],[0.1],[zmoelnig at iem.at],
                 [libambix],[http://ambisonics.iem.at/xchange/format])
-AM_INIT_AUTOMAKE
+AM_INIT_AUTOMAKE([foreign])
 
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 
@@ -11,7 +11,7 @@ AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_HEADERS([config.h])
 
 AC_CONFIG_FILES([Makefile])
-AC_CONFIG_FILES([libambix/Makefile libambix/src/Makefile libambix/tests/Makefile])
+AC_CONFIG_FILES([libambix/Makefile libambix/src/Makefile libambix/tests/Makefile libambix/tests/data/Makefile])
 AC_CONFIG_FILES([libambix/libambix.pc])
 AC_CONFIG_FILES([utils/Makefile utils/jcommon/Makefile])
 AC_CONFIG_FILES([doc/Makefile])
@@ -65,6 +65,18 @@ AC_HEADER_STDC
 AM_CONDITIONAL(DISABLED, [test "xno" = "xyes"])
 AM_CONDITIONAL(ENABLED, [test "xyes" = "xyes"])
 
+
+AC_ARG_ENABLE(debug,
+AS_HELP_STRING([--enable-debug],
+               [enable debugging build, default: no]),
+	       AS_CASE(["$enableval"],
+			yes, debug=true,
+			no,  debug=false,
+			AC_MSG_ERROR([bad value ${enableval} for --enable-debug])),
+               [debug=false])
+AM_CONDITIONAL(DEBUG, test x"$debug" = x"true")
+
+
 ## check for math
 AC_CHECK_LIB([m],[sqrt])
 
@@ -160,5 +172,8 @@ AC_CHECK_FUNCS([strndup])
 
 AX_PTHREAD
 
+# run unitttests in valgrind
+AC_SUBST(VALGRIND_CHECK_RULES)
+m4_ifdef([AX_VALGRIND_CHECK], [AX_VALGRIND_CHECK])
 
 AC_OUTPUT
diff --git a/coverage.sh b/coverage.sh
index b50b51b..67c1e3a 100755
--- a/coverage.sh
+++ b/coverage.sh
@@ -7,7 +7,8 @@ MAKE=make
 ${MAKE} clean
 
 # Reconfigure with gcov support
-CXXFLAGS="-g -O0 --coverage" CFLAGS="-g -O0 --coverage" ./configure || exit 1
+CFLAGS="-g -O0 --coverage" CXXFLAGS="-g -O0 --coverage" LDFLAGS="--coverage" \
+	./configure --enable-debug --disable-silent-rules || exit 1
 
 # Generate gcov output
 ${MAKE} || exit 1
diff --git a/doc/Makefile.am b/doc/Makefile.am
index b879dcf..ded5b11 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -6,10 +6,12 @@ if HAVE_DOXYGEN
 html_DATA+=apiref/*
 endif
 
+DOXYFILE=$(srcdir)/libambix.doxy
+
 apiref/*: all-local
 
 all-local:
-	$(DOXYGEN) $(srcdir)/libambix.doxy
+	$(DOXYGEN) $(DOXYFILE)
 
 clean-local:
 	-rm -rf apiref
diff --git a/doc/libambix.doxy b/doc/libambix.doxy
index 0cb6968..338a4a8 100644
--- a/doc/libambix.doxy
+++ b/doc/libambix.doxy
@@ -38,7 +38,7 @@ PROJECT_NUMBER         =
 # for a project that appears at the top of each page and should give viewer
 # a quick idea about the purpose of the project. Keep the description short.
 
-PROJECT_BRIEF          =
+PROJECT_BRIEF          = "the AMBIsonics eXchange library"
 
 # With the PROJECT_LOGO tag one can specify an logo or icon that is
 # included in the documentation. The maximum height of the logo should not
@@ -926,7 +926,7 @@ HTML_COLORSTYLE_GAMMA  = 80
 # page will contain the date and time when the page was generated. Setting
 # this to NO can help when comparing the output of multiple runs.
 
-HTML_TIMESTAMP         = YES
+HTML_TIMESTAMP         = NO
 
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
@@ -1160,7 +1160,7 @@ USE_MATHJAX            = YES
 # MathJax, but it is strongly recommended to install a local copy of MathJax
 # before deployment.
 
-MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
+MATHJAX_RELPATH        = https://cdn.mathjax.org/mathjax/latest
 
 # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
 # names that should be enabled during MathJax rendering.
diff --git a/doc/libambix.incl b/doc/libambix.incl
index 6d3bd3a..3ae7646 100644
--- a/doc/libambix.incl
+++ b/doc/libambix.incl
@@ -103,6 +103,7 @@
      free(ambidata);
      free(extradata);
    }
+   free(info);
  * @endcode
  *
  *
@@ -119,7 +120,9 @@
    ambix_t*ambix = NULL;
    ambix_info_t*info  = calloc(1, sizeof(ambix_info_t));
 
-   // setting the fileformat to AMBIX_EXTENDED forces the ambi data to be delivered as stored in the file
+   /* setting the fileformat to AMBIX_EXTENDED forces the ambi data
+    * be delivered as stored in the file
+    */
    ambix->fileformat = AMBIX_EXTENDED;
 
    ambix = ambix_open("ambixfile.caf", AMBIX_READ, info);
@@ -152,17 +155,18 @@
      free(ambidata);
      free(extradata);
    }
+   free(info);
  * @endcode
  *
  *
  * @subsection readunknown_usage Reading any ambix files
  *
- * If you don't specify the format prior to opening, you can query the format of the file
+ * If you do not specify the format prior to opening, you can query the format of the file
  * from the ambix_info_t struct.
  *
  * @code
    ambix_t*ambix = NULL;
-   ambix_info_t*info  = calloc(1, sizeof(ambix_info_t)); // initialize the format field (among others) to 0
+   ambix_info_t*info  = calloc(1, sizeof(ambix_info_t)); /* initialize the format field (among others) to 0 */
 
    ambix = ambix_open("ambixfile.caf", AMBIX_READ, info);
 
@@ -181,11 +185,9 @@
        printf("this file is of unknown format...\n");
      }
 
-     // using the adaptormatrix
-     // ...
-
      ambix_close(ambix);
    }
+   free(info);
  * @endcode
  *
  *
@@ -203,8 +205,9 @@
  * ambix_info_t struct to @ref AMBIX_BASIC prior to opening the file.
  *
  * You will need to provide a full set of ambisonics channels when writing data
- * to the file, and must not set an adaptor matrix. A full set of ambisonics
- * must always satisfy the formula @f$channels=(order_{ambi}+1)^2 at f$.
+ * to the file, and must not set an adaptor matrix (see also @ref writebasic2extended_usage).
+ * A full set of ambisonics must always satisfy the formula
+ * @f$channels=(order_{ambi}+1)^2 at f$.
  *
  * You cannot write extra audio channels into a "BASIC" ambix file.
  *
@@ -212,11 +215,11 @@
    ambix_t*ambix = NULL;
    ambix_info_t*info  = calloc(1, sizeof(ambix_info_t));
 
-   // need to specify samplerate and sampleformat
+   /* need to specify samplerate and sampleformat */
    ambix->samplerate = 44100;
-   ambix->sampleformat = AMBIX_SAMPLEFORMAT_PCM16;
+   ambix->sampleformat = AMBIX_SAMPLEFORMAT_PCM24;
    ambix->fileformat = AMBIX_BASIC;
-   ambix->ambichannels = 16; // 16 channels means 3rd order ambisonics, according to L=(2N+1)^2
+   ambix->ambichannels = 16; /* 16 channels means 3rd order ambisonics, according to L=(2N+1)^2 */
 
    ambix = ambix_open("ambixfile.caf", AMBIX_WRITE, info);
    if(ambix) {
@@ -237,6 +240,7 @@
      ambix_close(ambix);
      free(ambidata);
    }
+   free(info);
  * @endcode
  *
  * @subsection writeextended_usage Writing EXTENDED ambix files
@@ -253,12 +257,12 @@
    ambix_t*ambix = NULL;
    ambix_info_t*info  = calloc(1, sizeof(ambix_info_t));
 
-   // need to specify samplerate and sampleformat
+   /* need to specify samplerate and sampleformat */
    ambix->samplerate = 44100;
-   ambix->sampleformat = AMBIX_SAMPLEFORMAT_PCM16;
+   ambix->sampleformat = AMBIX_SAMPLEFORMAT_PCM24;
    ambix->fileformat = AMBIX_EXTENDED;
-   ambix->ambichannels = 8;  // a reduced ambisonics set
-   ambix->extrachannels = 1; // an extrachannel, e.g. click-track
+   ambix->ambichannels = 8;  /* a reduced ambisonics set */
+   ambix->extrachannels = 1; /* an extrachannel, e.g. click-track */
 
    ambix = ambix_open("ambixfile.caf", AMBIX_WRITE, info);
    if(ambix) {
@@ -267,9 +271,9 @@
      uint64_t block;
 
      float32_t*ambidata  = calloc(info->ambichannels  * blocksize, sizeof(float32_t));
-     float32_t*extradata  = calloc(info->extrachannels  * blocksize, sizeof(float32_t));
+     float32_t*extradata = calloc(info->extrachannels  * blocksize, sizeof(float32_t));
 
-     // create an adaptormatrix:
+     /* create an adaptormatrix: */
      ambix_matrix_t adaptormatrix = {0, 0, NULL};
      ambix_matrix_init(16, 8, &adaptormatrix);
      // fill the adaptormatrix, that expands our 8 channels to a full 3D 3rd-order set (16 channels)
@@ -291,8 +295,78 @@
      free(ambidata);
      free(extradata);
    }
+   free(info);
  * @endcode
  *
+ * @subsection writebasic2extended_usage Writing EXTENDED ambix files using the BASIC interface
+ *
+ * Finally, you can create "EXTENDED" ambix files from a full set of ambisonics channels and an
+ * adaptor matrix.
+ * This can be useful if you have a setup that works with full ambisonics sets (e.g. a DAW project)
+ * and you want to create a size-optimized ambix file that only stores a reduced set.
+ *
+ * This can be achieved by setting the 'fileformat' member of the ambix_info_t struct to
+ * @ref AMBIX_BASIC (because you will provide the full ambisonics set as if the file were opened in
+ * "BASIC" mode) and the 'ambichannels' member to the (reduced) number of ambisonics channel as will
+ * be written to the disk, and then setting an adaptor matrix ambix_set_adaptormatrix(), that will
+ * convert the reduced set back to the full set.
+ * libambix will internally reduce the full ambisonics set (as passed to @ref ambix_writef) using
+ * the (pseudo) inverse of the adaptor-matrix.
+ *
+ * @note You must ensure yourself that the adaptor matrix is inversible.
+ *
+ * The adaptor matrix gets written to disk prior to writing any samples to the file
+ * (or closing the ambix file). It is an error to call ambix_set_adaptormatrix()
+ * after starting to write samples.
+ *
+ * @note If you pass an adaptor matrix that expands a reduced set to full ambisonics
+ * (e.g. converting from 1st order horizontal-only ambisonics set to a 2nd order fully periphonic set)
+ * the reconstructed ambisonics channels (when reading the ambix file later),
+ * might be different from the ambisonics channels you passed in when writing the file
+ * (e.g. channels that contain 3rd-order and/or Z-axis components will be muted).
+ *
+ * @code
+   ambix_t*ambix = NULL;
+   ambix_info_t*info  = calloc(1, sizeof(ambix_info_t));
+
+   /* need to specify samplerate and sampleformat */
+   info->samplerate   = 44100;
+   info->sampleformat = AMBIX_SAMPLEFORMAT_PCM24;
+   info->fileformat   = AMBIX_BASIC;
+   info->ambichannels = 7; /* 3rd-order horizontal-only(!) */
+
+   ambix = ambix_open("ambixfile.caf", AMBIX_WRITE, info);
+   if(ambix) {
+     uint64_t fullambichannels = 16;
+     uint64_t frames = info->frames;
+     uint64_t blocksize = 1024;
+     uint64_t block;
+
+     float32_t*ambidata  = calloc(fullambichannels  * blocksize, sizeof(float32_t));
+
+     /* on disk, the data is stored as 3rd-order horizontal-only Furse-Malham
+      * set (7 channels); we need to provide an adaptor matrix that converts
+      * from the 7 FuMa-channels to the 16 AMBIX channels
+      */
+     ambix_matrix_t*mtx = NULL;
+     mtx = ambix_matrix_init(fullambichannels, info->ambichannels, mtx);
+     mtx = ambix_matrix_fill(mtx, ABIX_MATRIX_FUMA); /* fuma->ambix matrix [16x7] */
+     ambix_set_adaptormatrix(ambix, mtx);
+     ambix_matrix_destroy(mtx);
+
+     while(haveData) {
+       // acquire blocksize samples of a full set of 3rd order ambisonics data (16 channels)
+       //  into ambidata (interleaved)
+       // ...
+
+       block = ambix_write_float32(ambix, ambidata, NULL, blocksize);
+     }
+
+     ambix_close(ambix);
+     free(ambidata);
+   }
+   free(info);
+ * @endcode
  *
  */
 
@@ -315,7 +389,7 @@
  *
  * @section format_bugfix Bug-fixes for the format-specification
  *
- * The original @link http://ambisonics.iem.at/xchange/format/2011_NachbarZotterSontacchiDeleflie_ambix.pdf format proposal at endlink
+ * The original <a href="http://ambisonics.iem.at/xchange/fileformat/2011_nachbarzottersontacchideleflie_ambix.pdf">format proposal</a>
  * had a number of flaws and bugs that have been discovered during the implenentation of @em libambix.
  * Consequently, these flaws and bugs have been fixed.
  *
@@ -376,3 +450,95 @@
  * @f$ACN = l * ( l + 1 ) + m at f$
  *
  */
+
+/**
+ * @cond
+ * @page utilities ambix commandline utilities
+ *
+ * libambix comes with a number of commandline utilities
+ *
+ * @section informational informational
+ * @subsection ambix-info ambix-info
+ * @subsection ambix-dump ambix-dump
+ * @section ambix-refile file creation
+ * @subsection ambix-interleave ambix-interleave
+ * @subsection ambix-deinterleave ambix-deinterleave
+ * @section recording and playback
+ * @subsection ambix-jplay ambix-jplay
+ * @subsection ambix-jrecord ambix-jrecord
+ * @section tests
+ * @subsection ambix-test ambix-test
+ * @subsection ambix-matrix ambix-matrix
+ * @endcond
+ */
+
+
+/**
+ * @page FAQ Frequently Asked Questions
+ *
+ * @section Terms
+ *
+ * @subsection term-ambix What does libambix stand for?
+ * @c libambix is a <b>lib</b>rary for reading and writing <b>ambi</b>sonics e<b>x</b>change files.
+ *
+ * @subsection basic-vs-extended What is the difference between BASIC and EXTENDED ambix files?
+ * @c BASIC ambix files contain exactly a full set of periphonic ambisonics channels,
+ * using ACN channel ordering and SN3D normalisation.
+ *
+ * @c EXTENDED ambix files contain an additional adaptor matrix at the beginning of the file,
+ * which can be used to turn the actually stored audio channels into a full set of
+ * periphonic ambisonics channels (periphonic, ACN, SN3D).
+ * These files can be used to store a reduced number of channels
+ * (e.g. when your soundfield is horizontal only,
+ * there is no need to store the channels with height-information, as they will be muted anyhow),
+ * while providing a simple and standardized way to play them back on a full ambisonics decoder.
+ *
+ * See @ref format for more information.
+ *
+ * @section HOW-TOs
+ *
+ * @subsection howto-channels2basic How can I create an ambix file from a set of mono soundfiles?
+ * If you have an ambisonics recording as multiple mono soundfiles following the ambix standard
+ * (channel ordering: ACN, normalisation: SN3D), you can merge them into an ambix files
+ * using the `ambix-interleave` command.
+ * @code
+ ambix-interleave -o ambixfile.caf recording-ambi0.wav recording-ambi1.wav recording-ambi2.wav recording-ambi3.wav
+ * @endcode
+ *
+ * @subsection howto-multichannel2basic How can I create an ambix file from a multichannel soundfile?
+ * If you have an ambisonics recording already as a multichannel soundfile, with the channels
+ * following the ambix standard (channel ordering: ACN, normalisation: SN3D),
+ * you can create an ambix file from that using the `ambix-interleave` command.
+ * @code
+ ambix-interleave -o ambixfile.caf recording.wav
+ * @endcode
+ *
+ * @subsection howto-amb2extended How can I convert my .amb files to ambix?
+ * You can use the `ambix-interleave` file to create EXTENDED ambix files from your
+ * old .amb recordings.
+ * If `ambix-interleave` detects that the input is an .amb file, it will
+ * add an adaptor matrix that converts from .amb's Furse-Malham channels to ambix channels,
+ * and will otherwise leave the audio data intact.
+ * @code
+ ambix-interleave -o ambixfile.caf recording.amb
+ * @endcode
+ *
+ * @subsection howto-amb2basic How can I convert my .amb files to ambix?
+ * To create BASIC ambix files (without an adaptor matrix), you can use
+ * `ambix-deinterleave` to convert the .amb file to SN3D/ACN channels, and then
+ * use `ambix-interleave` to merge those files into a single ambix file:
+ * @code
+ ambix-deinterleave recording.amb
+ ambix-interleave -o ambixfile.caf recording-ambi*
+ * @endcode
+ *
+ * @subsection howto-extended2basic How can I convert an EXTENDED ambix file to BASIC?
+ * The easiest way to convert an EXTENDED ambix file to a BASIC file is to first
+ * extract the channels into separate files using `ambix-deinterleave`,
+ * and then merge them back using `ambix-interleave`:
+ * @code
+ ambix-deinterleave ambixextended.caf
+ ambix-interleave -o ambixbasic.caf ambixextended-ambi*
+ * @endcode
+ *
+ */
diff --git a/libambix/ambix/ambix.h b/libambix/ambix/ambix.h
index dd5bf88..966895b 100644
--- a/libambix/ambix/ambix.h
+++ b/libambix/ambix/ambix.h
@@ -21,8 +21,8 @@
 */
 
 /**
- * @file	ambix/ambix.h
- * @brief	AMBIsonics eXchange Library Interface
+ * @file        ambix/ambix.h
+ * @brief       AMBIsonics eXchange Library Interface
  * @details This file is part of libambix
  * @author IOhannes m zmölnig <zmoelnig at iem.at>
  * @date 2012
@@ -39,6 +39,9 @@ extern "C" {
 
 /** 32bit floating point number */
 typedef float float32_t;
+    
+/** 64bit floating point number */
+typedef double float64_t;
 
 #ifdef _MSC_VER
 /** 16bit signed integer */
@@ -57,7 +60,7 @@ typedef unsigned long uint64_t;
 # include <stdint.h>
 #endif
 
-/** a 32bit number (either float or int), useful for endianess operations */
+/** a 32bit number (either float or int), useful for endianness operations */
 typedef union {
   /** 32bit floating point */
   float32_t f;
@@ -128,6 +131,8 @@ typedef enum {
   AMBIX_SAMPLEFORMAT_PCM32,
   /** 32 bit floating point */
   AMBIX_SAMPLEFORMAT_FLOAT32,
+  /** 64 bit floating point */
+  AMBIX_SAMPLEFORMAT_FLOAT64,
 } ambix_sampleformat_t;
 
 /** ambix matrix types */
@@ -143,7 +148,7 @@ typedef enum {
 
   /** matrices with the 0x8000 bit set convert between ambix and other ambisonics formats:
    * if the 0x4000 bit is set to 0, the matrix converts to ambix,
-   * if the 0x4000 but is set to 1, the matrix converts from ambix.
+   * if the 0x4000 bit is set to 1, the matrix converts from ambix.
    * @remark some of the following matrixes might not be implemented yet
    * @remark AMBIX_MATRIX_AMBIX converts from ambix to ambix (and is quite useless by itself)
    */
@@ -160,7 +165,7 @@ typedef enum {
 
   /** conversion matrix SN3D -> N3D */
   AMBIX_MATRIX_TO_N3D  = AMBIX_MATRIX_TO_AMBIX | AMBIX_MATRIX_N3D,
-  /** conversion matrix SID -> ACN */
+  /** conversion matrix ACN -> SID */
   AMBIX_MATRIX_TO_SID  = AMBIX_MATRIX_TO_AMBIX | AMBIX_MATRIX_SID,
   /** conversion matrix ambix -> Furse-Malham */
   AMBIX_MATRIX_TO_FUMA = AMBIX_MATRIX_TO_AMBIX | AMBIX_MATRIX_FUMA,
@@ -187,7 +192,20 @@ typedef struct ambix_info_t {
   double samplerate;
   /** sample type of the ambix file */
   ambix_sampleformat_t sampleformat;
-  /** layout type of the ambix file */
+
+  /** layout type of the ambix file
+   *
+   * When opening a file, this format specifies the format from the
+   * user-perspective. This is not necessarily the same as the actual
+   * format of the file on disk.
+   * E.g. when setting this to @ref AMBIX_BASIC to read an @ref AMBIX_EXTENDED
+   * file, the library will automatically convert the reduced channel set
+   * to the full set (using the embedded adaptor matrix).
+   * Similarly, when setting this to @ref AMBIX_BASIC for writing a file,
+   * and then setting an adaptor matrix (using @ref ambix_set_adaptormatrix())
+   * the actual file will be @ref AMBIX_EXTENDED, but the user has to provide
+   * the full set (and the library will store the reduced set).
+   */
   ambix_fileformat_t fileformat;
 
   /** number of non-ambisonics channels in the file
@@ -197,17 +215,43 @@ typedef struct ambix_info_t {
 
   /** number of (raw) ambisonics channels present in the file.
    *
-   * If the file contains a full set of ambisonics channels (always true if
-   * ambixformat==AMBIX_BASIC), then \f$ambichannel=(order_{ambi}+1)^2\f$; if
-   * the file contains an adaptor matrix, it has to be used to reconstruct the
-   * full set by multiplying the adaptor matrix with the channels present.
+   * If the file contains a full set of ambisonics channels (format==@ref AMBIX_BASIC),
+   * then \f$ambichannel=(order_{ambi}+1)^2\f$; if the file contains an adaptor
+   * matrix, it has to be used to reconstruct the full set by multiplying the
+   * adaptor matrix with the channels present.
+   *
+   * @remark when opening for WRITING an @ref AMBIX_EXTENDED file as
+   * @ref AMBIX_BASIC (by specifying an adaptor matrix via @ref ambix_set_adaptormatrix()),
+   * this value must contain the reduced numer of channels (as stored on disk).
    */
   uint32_t ambichannels;
 } ambix_info_t;
 
+/** struct for holding a marker */
+typedef struct ambix_marker_t {
+  /** position in samples */
+  float64_t position;
+  /** name: NULL terminated string with maximum length of 255 */
+  char name[256];
+} ambix_marker_t;
+
+/** struct for holding a region */
+typedef struct ambix_region_t {
+  /** start position in samples */
+  float64_t start_position;
+  /** end position in samples */
+  float64_t end_position;
+  /** name: NULL terminated string with maximum length of 255 */
+  char name[256];
+} ambix_region_t;
+
 /*
  * @section api_main Main Interface
  */
+/** @defgroup ambix ambix
+ *
+ * @brief handling AmbiX files
+ */
 
 /** @brief Open an ambix file
  *
@@ -234,6 +278,8 @@ typedef struct ambix_info_t {
  * @ref AMBIX_BASIC, then ambixinfo.ambichannels must be @f$(order_{ambi}+1)^2 at f$
  *
  * @return A handle to the opened file (or NULL on failure)
+ *
+ * @ingroup ambix
  */
 AMBIX_API
 ambix_t *ambix_open (const char *path, const ambix_filemode_t mode, ambix_info_t *ambixinfo) ;
@@ -246,6 +292,8 @@ ambix_t *ambix_open (const char *path, const ambix_filemode_t mode, ambix_info_t
  * @param ambix The handle to an ambix file
  *
  * @return an error code indicating success
+ *
+ * @ingroup ambix
  */
 AMBIX_API
 ambix_err_t ambix_close (ambix_t *ambix) ;
@@ -264,20 +312,12 @@ ambix_err_t ambix_close (ambix_t *ambix) ;
  *
  * @return the offset in (multichannel) frames from the start of the audio data
  * or -1 if an error occurred.
+ *
+ * @ingroup ambix
  */
 AMBIX_API
 int64_t ambix_seek (ambix_t *ambix, int64_t frames, int whence) ;
 
-/** @brief Read samples (as 16bit signed integer values) from the ambix file
- * @ingroup ambix_readf
- */
-AMBIX_API
-int64_t ambix_readf_int16 (ambix_t *ambix, int16_t *ambidata, int16_t *otherdata, int64_t frames) ;
-/** @brief Read samples (as 32bit signed integer values) from the ambix file
- * @ingroup ambix_readf
- */
-AMBIX_API
-int64_t ambix_readf_int32 (ambix_t *ambix, int32_t *ambidata, int32_t *otherdata, int64_t frames) ;
 /** @brief Read samples from the ambix file
  * @defgroup ambix_readf ambix_readf()
  *
@@ -301,25 +341,34 @@ int64_t ambix_readf_int32 (ambix_t *ambix, int32_t *ambidata, int32_t *otherdata
  * @param frames number of sample frames you want to read
  *
  * @return the number of sample frames successfully read
+ *
+ * @ingroup ambix
  */
-/** @brief Read samples (as single prevision floating point values) from the
- * ambix file
+/** @brief Read samples (as 16bit signed integer values) from the ambix file
  * @ingroup ambix_readf
  */
 AMBIX_API
-int64_t ambix_readf_float32 (ambix_t *ambix, float32_t *ambidata, float32_t *otherdata, int64_t frames) ;
-
-/** @brief Write (16bit signed integer) samples to the ambix file
- * @ingroup ambix_writef
+int64_t ambix_readf_int16 (ambix_t *ambix, int16_t *ambidata, int16_t *otherdata, int64_t frames) ;
+/** @brief Read samples (as 32bit signed integer values) from the ambix file
+ * @ingroup ambix_readf
  */
 AMBIX_API
-int64_t ambix_writef_int16 (ambix_t *ambix, const int16_t *ambidata, const int16_t *otherdata, int64_t frames) ;
-/** @brief Write (32bit signed integer) samples to the ambix file
- * @ingroup ambix_writef
+int64_t ambix_readf_int32 (ambix_t *ambix, int32_t *ambidata, int32_t *otherdata, int64_t frames) ;
+/** @brief Read samples (as single precision floating point values) from the
+ * ambix file
+ * @ingroup ambix_readf
  */
 AMBIX_API
-int64_t ambix_writef_int32 (ambix_t *ambix, const int32_t *ambidata, const int32_t *otherdata, int64_t frames) ;
-/** @brief Write samples to the ambix file
+int64_t ambix_readf_float32 (ambix_t *ambix, float32_t *ambidata, float32_t *otherdata, int64_t frames) ;
+
+/** @brief Read samples (as double precision floating point values) from the
+* ambix file
+* @ingroup ambix_readf
+*/
+AMBIX_API
+int64_t ambix_readf_float64 (ambix_t *ambix, float64_t *ambidata, float64_t *otherdata, int64_t frames) ;
+
+/** @brief Write samples to the ambix file.
  * @defgroup ambix_writef ambix_writef()
  *
  * Writes samples (as single precision floating point values) to an ambix file,
@@ -343,13 +392,29 @@ int64_t ambix_writef_int32 (ambix_t *ambix, const int32_t *ambidata, const int32
  * @param frames number of sample frames you want to write
  *
  * @return the number of sample frames successfully written
+ *
+ * @ingroup ambix
+ */
+/** @brief Write (16bit signed integer) samples to the ambix file
+ * @ingroup ambix_writef
  */
+AMBIX_API
+int64_t ambix_writef_int16 (ambix_t *ambix, const int16_t *ambidata, const int16_t *otherdata, int64_t frames) ;
+/** @brief Write (32bit signed integer) samples to the ambix file
+ * @ingroup ambix_writef
+ */
+AMBIX_API
+int64_t ambix_writef_int32 (ambix_t *ambix, const int32_t *ambidata, const int32_t *otherdata, int64_t frames) ;
 /** @brief Write (32bit floating point) samples to the ambix file
  * @ingroup ambix_writef
  */
 AMBIX_API
 int64_t ambix_writef_float32 (ambix_t *ambix, const float32_t *ambidata, const float32_t *otherdata, int64_t frames) ;
-
+/** @brief Write (64bit floating point) samples to the ambix file
+ * @ingroup ambix_writef
+ */
+AMBIX_API
+int64_t ambix_writef_float64 (ambix_t *ambix, const float64_t *ambidata, const float64_t *otherdata, int64_t frames) ;
 /**
  * typedef from libsndfile
  * @private
@@ -359,16 +424,110 @@ struct SNDFILE_tag;
 /** @brief Get the libsndfile handle associated with the ambix handle
  *
  * If possible, require an SNDFILE handle if possible; if the ambix handle is
- * not asociated with SNDFILE (e.g. because libambix is compiled without
+ * not associated with SNDFILE (e.g. because libambix is compiled without
  * libsndfile support), NULL is returned.
  *
  * @param ambix The handle to an ambix file
  *
  * @return A libsndfile handle or NULL
+ *
+ * @ingroup ambix
  */
 AMBIX_API
 struct SNDFILE_tag *ambix_get_sndfile (ambix_t *ambix) ;
-
+/** @brief Get the number of stored markers within the ambix file.
+ *
+ * @return number of markers.
+ *
+ * @ingroup ambix
+ */
+AMBIX_API
+uint32_t ambix_get_num_markers(ambix_t *ambix) ;
+/** @brief Get the number of stored regions within the ambix file.
+ *
+ * @param ambix The handle to an ambix file
+ *
+ * @return Number of regions.
+ *
+ * @ingroup ambix
+ */
+AMBIX_API
+uint32_t ambix_get_num_regions(ambix_t *ambix) ;
+/** @brief Get one marker.
+ *
+ * @param ambix The handle to an ambix file
+ *
+ * @param id The id of the marker to retrieve.
+ *
+ * @return The marker requested or NULL in case the marker does not exist.
+ *
+ * @ingroup ambix
+ */
+AMBIX_API
+ambix_marker_t *ambix_get_marker(ambix_t *ambix, uint32_t id) ;
+/** @brief Get one region.
+ *
+ * @param ambix The handle to an ambix file
+ *
+ * @param id The id of the region to retrieve.
+ *
+ * @return The region requested or NULL in case the region does not exist.
+ *
+ * @ingroup ambix
+ */
+AMBIX_API
+ambix_region_t *ambix_get_region(ambix_t *ambix, uint32_t id) ;
+/** @brief Add a new marker to the ambix file.
+ *
+ * @remark Markers have to be set before sample data is written!
+ *
+ * @param ambix The handle to an ambix file
+ *
+ * @param marker A valid marker that should be added to the ambix file.
+ *
+ * @return an errorcode indicating success.
+ *
+ * @ingroup ambix
+ */
+AMBIX_API
+ambix_err_t ambix_add_marker(ambix_t *ambix, ambix_marker_t *marker) ;  // returns id
+/** @brief Add a new region to the ambix file.
+ *
+ * @remark Regions have to be set before sample data is written!
+ *
+ * @param ambix The handle to an ambix file
+ *
+ * @param region A valid region that should be added to the ambix file.
+ *
+ * @return an errorcode indicating success.
+ *
+ * @ingroup ambix
+ */
+AMBIX_API
+ambix_err_t ambix_add_region(ambix_t *ambix, ambix_region_t *region) ; // returns id
+/** @brief Deletes all markers in the ambix file.
+ *
+ * @param ambix The handle to an ambix file
+ *
+ * @return an errorcode indicating success.
+ *
+ * @ingroup ambix
+ */
+AMBIX_API
+ambix_err_t ambix_delete_markers(ambix_t *ambix) ;
+/** @brief Deletes all regions in the ambix file.
+ *
+ * @param ambix The handle to an ambix file
+ *
+ * @return an errorcode indicating success.
+ *
+ * @ingroup ambix
+ */
+AMBIX_API
+ambix_err_t ambix_delete_regions(ambix_t *ambix) ;
+/** @brief Various utilities to handle matrices
+ * @defgroup ambix_matrix ambix_matrix
+ */
 /** @brief Get the adaptor matrix
  *
  * The ambix extended fileformat comes with a adaptor matrix, that can be used
@@ -389,6 +548,8 @@ struct SNDFILE_tag *ambix_get_sndfile (ambix_t *ambix) ;
  * @return the adaptor matrix to restore the full ambisonics set from the
  * reduced set, or NULL if there is no such matrix; the memory is owned by the
  * library and must neither be freed nor used after calling ambix_close().
+ *
+ * @ingroup ambix
  */
 AMBIX_API
 const ambix_matrix_t *ambix_get_adaptormatrix (ambix_t *ambix) ;
@@ -399,7 +560,7 @@ const ambix_matrix_t *ambix_get_adaptormatrix (ambix_t *ambix) ;
  * of operation this can have different meanings! When READing an ambix '@ref
  * AMBIX_BASIC' file, this tells the library to do an (additional)
  * matrix-multiplication When reconstructing the full ambisonics set; you can
- * use use this to get the ambisonics channels in a format other than SN3D/ACN
+ * use this to get the ambisonics channels in a format other than SN3D/ACN
  * (e.g. using an ambix to Furse-Malham adaptor matrix) or getting the
  * loudspeaker feeds directly (by supplying a decoder matrix); in this case, the
  * matrix MUST have ambix->ambichannels columns. When WRITEing an ambix '@ref
@@ -416,6 +577,8 @@ const ambix_matrix_t *ambix_get_adaptormatrix (ambix_t *ambix) ;
  * @remark using this on ambix handles other than @ref AMBIX_READ/@ref
  * AMBIX_BASIC or @ref AMBIX_WRITE/@ref AMBIX_EXTENDED
  * is an error.
+ *
+ * @ingroup ambix
  */
 AMBIX_API
 ambix_err_t ambix_set_adaptormatrix (ambix_t *ambix, const ambix_matrix_t *matrix) ;
@@ -430,6 +593,8 @@ ambix_err_t ambix_set_adaptormatrix (ambix_t *ambix, const ambix_matrix_t *matri
  * It's equivalent to calling ambix_matrix_init(0, 0, NULL) ;
  *
  * @return a new matrix object or NULL
+ *
+ * @ingroup ambix_matrix
  */
 AMBIX_API
 ambix_matrix_t *ambix_matrix_create (void) ;
@@ -440,6 +605,8 @@ ambix_matrix_t *ambix_matrix_create (void) ;
  * It's a shortcut for ambix_matrix_deinit(mtx), free(mtx)
  *
  * @param mtx matrix object to destroy
+ *
+ * @ingroup ambix_matrix
  */
 AMBIX_API
 void ambix_matrix_destroy (ambix_matrix_t *mtx) ;
@@ -457,6 +624,8 @@ void ambix_matrix_destroy (ambix_matrix_t *mtx) ;
  *
  * @return pointer to a newly initialized (and/or allocated) matrix, or NULL on
  * error.
+ *
+ * @ingroup ambix_matrix
  */
 AMBIX_API
 ambix_matrix_t *ambix_matrix_init (uint32_t rows, uint32_t cols, ambix_matrix_t *mtx) ;
@@ -466,6 +635,8 @@ ambix_matrix_t *ambix_matrix_init (uint32_t rows, uint32_t cols, ambix_matrix_t
  * Frees associated resources and sets rows/columns to 0
  *
  * @param mtx matrix object to deinitialize
+ *
+ * @ingroup ambix_matrix
  */
 AMBIX_API
 void ambix_matrix_deinit (ambix_matrix_t *mtx) ;
@@ -486,6 +657,8 @@ void ambix_matrix_deinit (ambix_matrix_t *mtx) ;
  *
  * @return pointer to the matrix object, or NULL if the type was not valid (for the
  * input matrix)
+ *
+ * @ingroup ambix_matrix
  */
 AMBIX_API
 ambix_matrix_t *ambix_matrix_fill (ambix_matrix_t *matrix, ambix_matrixtype_t type) ;
@@ -501,6 +674,8 @@ ambix_matrix_t *ambix_matrix_fill (ambix_matrix_t *matrix, ambix_matrixtype_t ty
  * A[rows-1, cols-1])
  *
  * @return an error code indicating success
+ *
+ * @ingroup ambix_matrix
  */
 AMBIX_API
 ambix_err_t ambix_matrix_fill_data (ambix_matrix_t *mtx, const float32_t *data) ;
@@ -514,9 +689,12 @@ ambix_err_t ambix_matrix_fill_data (ambix_matrix_t *mtx, const float32_t *data)
  * @param dest the destination matrix (if NULL a new matrix will be created)
  *
  * @return pointer to the destination matrix
+ *
+ * @ingroup ambix_matrix
  */
 AMBIX_API
 ambix_matrix_t *ambix_matrix_copy (const ambix_matrix_t *src, ambix_matrix_t *dest) ;
+/** @cond DEPRECATED */
 /** @brief Multiply two matrices
  *
  * Multiply matrices dest=A*B, possibly resizing or creating the destination
@@ -533,12 +711,31 @@ ambix_matrix_t *ambix_matrix_copy (const ambix_matrix_t *src, ambix_matrix_t *de
  *
  * @remark If this returns a newly allocated matrix object (result!=return
  * value), the host has to take care of calling ambix_matrix_destroy().
+ *
+ * @ingroup ambix_matrix
  */
-AMBIX_API
+AMBIX_API AMBIX_DEPRECATED
 ambix_matrix_t *ambix_matrix_multiply (const ambix_matrix_t *A, const ambix_matrix_t *B, ambix_matrix_t *result) ;
-
+/** @brief Get the Moore-Penrose pseudoinverse of a matrix.
+ *
+ * Get the Moore-Penrose pseudoinverse of the matrix input and write the result
+ * to pinv
+ *
+ * @param matrix input matrix
+ *
+ * @param pinv pointer to the matrix object that will hold the result or NULL
+ *
+ * @return pointer to the result matrix, or NULL in case the matrix
+ * inversion did not succeed.
+ *
+ * @ingroup ambix_matrix
+ */
+AMBIX_API AMBIX_DEPRECATED
+ambix_matrix_t* ambix_matrix_pinv(const ambix_matrix_t*matrix, ambix_matrix_t*pinv) ;
+/** @endcond */
 /** @brief Multiply a matrix with data
  * @defgroup ambix_matrix_multiply_data ambix_matrix_multiply_data()
+ * @ingroup ambix_matrix
  *
  * Multiply a [rows*cols] matrix with an array of [cols*frames] source data to
  * get [rows*frames] dest data.
@@ -558,12 +755,19 @@ ambix_matrix_t *ambix_matrix_multiply (const ambix_matrix_t *A, const ambix_matr
  * @remark Both source and dest data are arranged column-wise (as is the default
  * for interleaved audio-data).
  */
+
 /** @brief Multiply a matrix with (32bit floating point) data
  *
  * @ingroup ambix_matrix_multiply_data
  */
 AMBIX_API
 ambix_err_t ambix_matrix_multiply_float32(float32_t *dest, const ambix_matrix_t *mtx, const float32_t *source, int64_t frames) ;
+/** @brief Multiply a matrix with (64bit float) data
+ *
+ * @ingroup ambix_matrix_multiply_data
+ */
+AMBIX_API
+ambix_err_t ambix_matrix_multiply_float64(float64_t *dest, const ambix_matrix_t *mtx, const float64_t *source, int64_t frames) ;
 /** @brief Multiply a matrix with (32bit signed integer) data
  *
  * @ingroup ambix_matrix_multiply_data
@@ -577,15 +781,20 @@ ambix_err_t ambix_matrix_multiply_int32(int32_t *dest, const ambix_matrix_t *mtx
 AMBIX_API
 ambix_err_t ambix_matrix_multiply_int16(int16_t *dest, const ambix_matrix_t *mtx, const int16_t *source, int64_t frames) ;
 
-/*
+/**
  * @section api_utils utility functions
  */
-
+/** @defgroup ambix_utilities ambix_utilities
+ *
+ * @brief utility functions
+ */
 /** @brief Calculate the number of channels for a full 3d ambisonics set of a
  * given order.
  *
  * @param order the order of the full set
  * @return the number of channels of the full set
+ *
+ * @ingroup ambix_utilities
  */
 AMBIX_API
 uint32_t ambix_order2channels(uint32_t order) ;
@@ -596,6 +805,8 @@ uint32_t ambix_order2channels(uint32_t order) ;
  * @param channels the number of channels of the full set
  * @return the order of the full set, or -1 if the channels don't form a full
  * set.
+ *
+ * @ingroup ambix_utilities
  */
 AMBIX_API
 int32_t ambix_channels2order(uint32_t channels) ;
@@ -605,6 +816,8 @@ int32_t ambix_channels2order(uint32_t channels) ;
  * @param channels the number of channels supposed to form a full set.
  *
  * @return TRUE if the channels can form full set, FALSE otherwise.
+ *
+ * @ingroup ambix_utilities
  */
 AMBIX_API
 int ambix_is_fullset(uint32_t channels) ;
diff --git a/libambix/ambix/exportdefs.h b/libambix/ambix/exportdefs.h
index 5c23515..7a66197 100644
--- a/libambix/ambix/exportdefs.h
+++ b/libambix/ambix/exportdefs.h
@@ -1,4 +1,4 @@
-/* ambix/exportdefs.h -  defines for dll import/export	-*- c -*-
+/* ambix/exportdefs.h -  defines for dll import/export  -*- c -*-
 
    Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>
          Institute of Electronic Music and Acoustics (IEM),
@@ -22,8 +22,8 @@
 */
 
 /**
- * @file	ambix/exportdefs.h
- * @brief	export definitions for various compilers
+ * @file        ambix/exportdefs.h
+ * @brief       export definitions for various compilers
  * @details This file is part of libambix
  * @author IOhannes m zmölnig <zmoelnig at iem.at>
  * @date 2012
diff --git a/libambix/src/Makefile.am b/libambix/src/Makefile.am
index cf821c0..e9a2ede 100644
--- a/libambix/src/Makefile.am
+++ b/libambix/src/Makefile.am
@@ -36,10 +36,18 @@ lib_LTLIBRARIES = libambix.la
 # 3. Programs may need to be changed, recompiled, relinked in order to use the
 #    new version. Bump current, set revision and age to 0.
 
-libambix_la_LDFLAGS = -version-info 0:0:0 -no-undefined
-libambix_la_CFLAGS  = -DAMBIX_INTERNAL
-libambix_la_CFLAGS += -fvisibility=hidden
-libambix_la_LIBADD  = $(LIBM)
+libambix_la_CPPFLAGS  = $(AM_CPPFLAGS)
+libambix_la_CFLAGS    = $(AM_CFLAGS)
+libambix_la_LDFLAGS   = $(AM_LDFLAGS)
+
+libambix_la_CPPFLAGS += -DAMBIX_INTERNAL
+if DEBUG
+libambix_la_CPPFLAGS += -DDEBUG=1
+else
+libambix_la_CFLAGS   += -fvisibility=hidden
+endif
+libambix_la_LDFLAGS  += -version-info 0:0:0 -no-undefined
+libambix_la_LIBADD    = $(LIBM)
 
 libambix_la_OBJCFLAGS = $(libambix_la_CFLAGS)
 
@@ -47,9 +55,10 @@ libambix_la_SOURCES = libambix.c \
 	adaptor.c \
 	adaptor_acn.c \
 	adaptor_fuma.c \
-	matrix.c \
+	matrix.c matrix_invert.c \
 	utils.c \
 	uuid_chunk.c \
+  marker_region_chunk.c \
 	private.h
 
 if HAVE_SNDFILE
diff --git a/libambix/src/adaptor.c b/libambix/src/adaptor.c
index 47b1f79..dcc3842 100644
--- a/libambix/src/adaptor.c
+++ b/libambix/src/adaptor.c
@@ -1,6 +1,6 @@
 /* adaptor.c -  extracting ambisonics data from data using adaptor matrices              -*- c -*-
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -27,11 +27,14 @@
 # include <stdlib.h>
 #endif /* HAVE_STDLIB_H */
 
+static inline uint64_t max_u64(uint64_t a, uint64_t b) {
+  return((a>b)?a:b);
+}
 ambix_err_t _ambix_adaptorbuffer_resize(ambix_t*ambix, uint64_t frames, uint16_t itemsize) {
-  uint32_t channels=ambix->info.ambichannels + ambix->info.extrachannels;
-
+  uint32_t ambichannels=max_u64(ambix->info.ambichannels,ambix->realinfo.ambichannels);
+  uint32_t extrachannels=max_u64(ambix->info.extrachannels,ambix->realinfo.extrachannels);
+  uint32_t channels=ambichannels + extrachannels;
   uint64_t size=channels*frames*itemsize;
-
   if(frames<1 || channels<1)
     return AMBIX_ERR_SUCCESS;
   if(size<1)
@@ -62,7 +65,7 @@ ambix_err_t _ambix_adaptorbuffer_destroy(ambix_t*ambix) {
 }
 
 
-#define _AMBIX_SPLITADAPTOR(type) \
+#define _AMBIX_SPLITADAPTOR(type)                                       \
   ambix_err_t _ambix_splitAdaptor_##type(const type##_t*source, uint32_t sourcechannels, \
                                          uint32_t ambichannels, type##_t*dest_ambi, type##_t*dest_other, \
                                          int64_t frames) {              \
@@ -78,6 +81,7 @@ ambix_err_t _ambix_adaptorbuffer_destroy(ambix_t*ambix) {
   }
 
 _AMBIX_SPLITADAPTOR(float32);
+_AMBIX_SPLITADAPTOR(float64);
 _AMBIX_SPLITADAPTOR(int32);
 _AMBIX_SPLITADAPTOR(int16);
 
@@ -100,7 +104,7 @@ _AMBIX_SPLITADAPTOR(int16);
         for(inchan=0; inchan<rawambichannels; inchan++) {               \
           sum+=mtx[outchan][inchan] * src[inchan];                      \
         }                                                               \
-		*dest_ambi++=(type##_t)sum;  /* FIXXXME: integer saturation */   \
+        *dest_ambi++=(type##_t)sum;  /* FIXXXME: integer saturation */  \
       }                                                                 \
       for(inchan=rawambichannels; inchan<sourcechannels; inchan++)      \
         *dest_other++=src[inchan];                                      \
@@ -109,6 +113,7 @@ _AMBIX_SPLITADAPTOR(int16);
   }
 
 _AMBIX_SPLITADAPTOR_MATRIX(float32);
+_AMBIX_SPLITADAPTOR_MATRIX(float64);
 /* both _int16 and _int32 are highly unoptimized!
  * LATER: add some fixed point magic to speed things up
  */
@@ -131,7 +136,40 @@ _AMBIX_SPLITADAPTOR_MATRIX(int16);
   }
 
 _AMBIX_MERGEADAPTOR(float32);
-
+_AMBIX_MERGEADAPTOR(float64);
 _AMBIX_MERGEADAPTOR(int32);
-
 _AMBIX_MERGEADAPTOR(int16);
+
+
+//#define _AMBIX_MERGEADAPTOR_MATRIX(type)      \
+
+#define _AMBIX_MERGEADAPTOR_MATRIX(type)                                \
+  ambix_err_t _ambix_mergeAdaptormatrix_##type(const type##_t*ambi_data, const ambix_matrix_t*matrix, \
+                                               const type##_t*otherdata, uint32_t source2channels, \
+                                               type##_t*destination, int64_t frames) { \
+    float32_t**mtx=matrix->data;                                        \
+    const uint32_t fullambichannels=matrix->cols;                       \
+    const uint32_t ambixchannels=matrix->rows;                          \
+    int64_t f;                                                          \
+    for(f=0; f<frames; f++) {                                           \
+      /* encode ambisonics->ambix and store in destination */           \
+      uint32_t outchan, inchan;                                         \
+      const type##_t*src = ambi_data+fullambichannels*f;                \
+      for(outchan=0; outchan<ambixchannels; outchan++) {                \
+        float32_t sum=0.;                                               \
+        for(inchan=0; inchan<fullambichannels; inchan++) {              \
+          sum+=mtx[outchan][inchan] * src[inchan];                      \
+        }                                                               \
+        *destination++=(type##_t)sum;                                   \
+      }                                                                 \
+      /* store the otherchannels */                                     \
+      for(inchan=0; inchan<source2channels; inchan++)                   \
+        *destination++=*otherdata++;                                    \
+    }                                                                   \
+    return AMBIX_ERR_SUCCESS;                                           \
+  }
+
+_AMBIX_MERGEADAPTOR_MATRIX(float32);
+_AMBIX_MERGEADAPTOR_MATRIX(float64);
+_AMBIX_MERGEADAPTOR_MATRIX(int32);
+_AMBIX_MERGEADAPTOR_MATRIX(int16);
diff --git a/libambix/src/adaptor_fuma.c b/libambix/src/adaptor_fuma.c
index efb0fc7..7ed25a5 100644
--- a/libambix/src/adaptor_fuma.c
+++ b/libambix/src/adaptor_fuma.c
@@ -1,6 +1,6 @@
 /* adaptor_fuma.c -  adaptors to/from FUrse-MAlham sets              -*- c -*-
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -24,15 +24,15 @@
   http://members.tripod.com/martin_leese/Ambisonic/B-Format_file_format.html
 
 #chan|fuma|   type     | xy | z | channels         | done
-  3 	h 	  horizontal 	  1 	0 	WXY                 X
-  4 	f 	  full-sphere 	1 	1 	WXYZ                X
-  5 	hh 	  horizontal   	2 	0 	WXYUV
-  6 	fh 	  mixed-order 	2 	1 	WXYZUV
-  9 	ff 	  full-sphere 	2 	2 	WXYZRSTUV           X
-  7 	hhh 	horizontal 	  3 	0 	WXYUVPQ
-  8 	fhh 	mixed-order 	3 	1 	WXYZUVPQ
-  11 	ffh 	mixed-order 	3 	2 	WXYZRSTUVPQ
-  16 	fff 	full-sphere 	3 	3 	WXYZRSTUVKLMNOPQ    X
+  3     h         horizontal      1     0       WXY                 X
+  4     f         full-sphere   1       1       WXYZ                X
+  5     hh        horizontal    2       0       WXYUV
+  6     fh        mixed-order   2       1       WXYZUV
+  9     ff        full-sphere   2       2       WXYZRSTUV           X
+  7     hhh     horizontal        3     0       WXYUVPQ
+  8     fhh     mixed-order     3       1       WXYZUVPQ
+  11    ffh     mixed-order     3       2       WXYZRSTUVPQ
+  16    fff     full-sphere     3       3       WXYZRSTUVKLMNOPQ    X
 */
 
 #include "private.h"
@@ -68,7 +68,7 @@ fuma2ambix_weightorder(void) {
   weight_m=_matrix_diag  (weight_m, weights, sizeof(weights)/sizeof(*weights));
   order_m =_matrix_router(order_m , order, sizeof(order)/sizeof(*order), 1);
 
-  result_m=ambix_matrix_multiply(weight_m, order_m, result_m);
+  result_m=_ambix_matrix_multiply(weight_m, order_m, result_m);
 
   ambix_matrix_destroy(weight_m);weight_m=NULL;
   ambix_matrix_destroy(order_m); order_m=NULL;
@@ -104,7 +104,7 @@ ambix2fuma_weightorder(void) {
   weight_m=_matrix_diag  (weight_m, weights, sizeof(weights)/sizeof(*weights));
   order_m =_matrix_router(order_m , order, sizeof(order)/sizeof(*order), 0);
 
-  result_m=ambix_matrix_multiply(order_m, weight_m, result_m);
+  result_m=_ambix_matrix_multiply(order_m, weight_m, result_m);
 
   ambix_matrix_destroy(weight_m);weight_m=NULL;
   ambix_matrix_destroy(order_m); order_m=NULL;
@@ -120,8 +120,8 @@ _matrix_multiply3(ambix_matrix_t*mtx1,
                   ambix_matrix_t*result) {
   ambix_matrix_t*tmp=NULL;
 
-  tmp=ambix_matrix_multiply(mtx1, mtx2, tmp);
-  result=ambix_matrix_multiply(tmp, mtx3, result);
+  tmp=_ambix_matrix_multiply(mtx1, mtx2, tmp);
+  result=_ambix_matrix_multiply(tmp, mtx3, result);
 
   ambix_matrix_destroy(tmp);
   return result;
diff --git a/libambix/src/coreaudio.m b/libambix/src/coreaudio.m
index 0da629b..8f6dab4 100644
--- a/libambix/src/coreaudio.m
+++ b/libambix/src/coreaudio.m
@@ -496,6 +496,9 @@ int64_t _ambix_readf_int32   (ambix_t*ambix, int32_t*data, int64_t frames) {
 int64_t _ambix_readf_float32   (ambix_t*ambix, float32_t*data, int64_t frames) {
   return coreaudio_readf(ambix, data, frames, AMBIX_SAMPLEFORMAT_FLOAT32, 4);
 }
+int64_t _ambix_readf_float64   (ambix_t*ambix, float64_t*data, int64_t frames) {
+  return coreaudio_readf(ambix, data, frames, AMBIX_SAMPLEFORMAT_FLOAT64, 8);
+}
 
 int64_t coreaudio_writef(ambix_t*ambix, const void*data, int64_t frames, ambix_sampleformat_t sampleformat, UInt32 bytespersample) {
  //printf("info:\n");_ambix_print_info(&ambix->info);
@@ -527,6 +530,9 @@ int64_t _ambix_writef_float32   (ambix_t*ambix, const float32_t*data, int64_t fr
 //printf("_ambix_writef_float32(%p, %p, %lu)\n", ambix, data);
   return coreaudio_writef(ambix, data, frames, AMBIX_SAMPLEFORMAT_FLOAT32, 4);
 }
+int64_t _ambix_writef_float64   (ambix_t*ambix, const float64_t*data, int64_t frames) {
+  return coreaudio_writef(ambix, data, frames, AMBIX_SAMPLEFORMAT_FLOAT64, 8);
+}
 ambix_err_t _ambix_write_uuidchunk_at(ambix_t*ax, UInt32 index, const void*data, int64_t datasize) {
   OSStatus  err = AudioFileSetUserData (
                                         PRIVATE(ax)->file,
diff --git a/libambix/src/libambix.c b/libambix/src/libambix.c
index b27d908..ea0b967 100644
--- a/libambix/src/libambix.c
+++ b/libambix/src/libambix.c
@@ -1,6 +1,6 @@
 /* libambix.c -  AMBIsonics eXchange Library              -*- c -*-
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -30,9 +30,8 @@
 # include <string.h>
 #endif /* HAVE_STRING_H */
 
-
 /* forward declarations */
-ambix_err_t	_ambix_write_header	(ambix_t*ambix);
+ambix_err_t     _ambix_write_header     (ambix_t*ambix);
 
 
 static ambix_err_t _check_write_ambixinfo(ambix_info_t*info) {
@@ -56,11 +55,11 @@ static ambix_err_t _check_write_ambixinfo(ambix_info_t*info) {
 }
 
 static void _ambix_info_set(ambix_t*ambix
-                       , ambix_fileformat_t format
-                       , int32_t otherchannels
-                       , int32_t ambichannels
-                       , int32_t fullambichannels
-                       ) {
+                            , ambix_fileformat_t format
+                            , int32_t otherchannels
+                            , int32_t ambichannels
+                            , int32_t fullambichannels
+                            ) {
   switch(format) {
   case AMBIX_NONE:
     ambichannels=fullambichannels=0;
@@ -77,10 +76,11 @@ static void _ambix_info_set(ambix_t*ambix
   ambix->ambisonics_order=(fullambichannels>0)?ambix_channels2order(fullambichannels):0;
 }
 
-ambix_t* 	ambix_open	(const char *path, const ambix_filemode_t mode, ambix_info_t*ambixinfo) {
+ambix_t*        ambix_open      (const char *path, const ambix_filemode_t mode, ambix_info_t*ambixinfo) {
   ambix_t*ambix=NULL;
   ambix_err_t err = AMBIX_ERR_UNKNOWN;
   int32_t ambichannels=0, otherchannels=0;
+  int basic2extended = 0; /* writing extended file as basic */
 
   if((AMBIX_WRITE & mode) && (AMBIX_READ & mode)) {
     /* RDRW not yet implemented */
@@ -89,21 +89,34 @@ ambix_t* 	ambix_open	(const char *path, const ambix_filemode_t mode, ambix_info_
 
   if(AMBIX_WRITE & mode) {
     err=_check_write_ambixinfo(ambixinfo);
-    if(err!=AMBIX_ERR_SUCCESS)
-      return NULL;
+    if(err!=AMBIX_ERR_SUCCESS) {
+      if (AMBIX_BASIC == ambixinfo->fileformat) {
+        /* the user might actually try to write an EXTENDED file as BASIC:
+         * - ambichannels do not form a full set
+         * - otherchannels>0
+         * LATER add better checks whether this is really the case
+         */
+        ambixinfo->fileformat = AMBIX_EXTENDED;
+        err=_check_write_ambixinfo(ambixinfo);
+        if(err!=AMBIX_ERR_SUCCESS)
+          return NULL;
+        basic2extended = 1;
+      } else
+        return NULL;
+    }
     ambichannels=ambixinfo->ambichannels;
     otherchannels=ambixinfo->extrachannels;
   }
 
   ambix=(ambix_t*)calloc(1, sizeof(ambix_t));
   if(AMBIX_ERR_SUCCESS == _ambix_open(ambix, path, mode, ambixinfo)) {
-    const ambix_fileformat_t wantformat=ambixinfo->fileformat;
+    const ambix_fileformat_t wantformat=basic2extended?AMBIX_BASIC:ambixinfo->fileformat;
     ambix_fileformat_t haveformat;
     uint32_t channels = ambix->channels;
     /* successfully opened, initialize common stuff... */
     if(ambix->is_AMBIX) {
       if(AMBIX_WRITE & mode) {
-        switch(wantformat) {
+        switch(ambixinfo->fileformat) {
         case(AMBIX_NONE):
           _ambix_info_set(ambix, AMBIX_NONE, channels, 0, 0);
           break;
@@ -112,7 +125,7 @@ ambix_t* 	ambix_open	(const char *path, const ambix_filemode_t mode, ambix_info_
           break;
         case(AMBIX_EXTENDED):
           /* the number of full channels is not clear yet!
-           * the user has to call setAdaptorMatrix() first */
+           * the user MUST call set_adaptormatrix() first */
           _ambix_info_set(ambix, AMBIX_EXTENDED, otherchannels, ambichannels, 0);
           break;
         }
@@ -144,6 +157,8 @@ ambix_t* 	ambix_open	(const char *path, const ambix_filemode_t mode, ambix_info_
           }
         }
       }
+      /* retrieve markers/regions/strings*/
+      _ambix_read_markersregions(ambix);
     } else {
       /* it's not a CAF file.... */
       _ambix_info_set(ambix, AMBIX_NONE, channels, 0, 0);
@@ -154,6 +169,14 @@ ambix_t* 	ambix_open	(const char *path, const ambix_filemode_t mode, ambix_info_
     ambix->filemode=mode;
     memcpy(&ambix->info, &ambix->realinfo, sizeof(ambix->info));
 
+    if(basic2extended) {
+      /* write EXTENDED files as BASIC */
+#if 0
+      ambix_matrix_init(ambix->info.ambichannels, ambix->realinfo.ambichannels, &ambix->matrix);
+      ambix_matrix_fill(&ambix->matrix, AMBIX_MATRIX_IDENTITY);
+      _ambix_matrix_pinv(&ambix->matrix, &ambix->matrix2);
+#endif
+    }
     if(0) {
     } else if(AMBIX_BASIC==wantformat && AMBIX_EXTENDED==haveformat) {
       ambix->info.fileformat=AMBIX_BASIC;
@@ -176,7 +199,7 @@ ambix_t* 	ambix_open	(const char *path, const ambix_filemode_t mode, ambix_info_
   return NULL;
 }
 
-ambix_err_t	ambix_close	(ambix_t*ambix) {
+ambix_err_t     ambix_close     (ambix_t*ambix) {
   ambix_err_t res=AMBIX_ERR_SUCCESS;
   if(NULL==ambix) {
     return AMBIX_ERR_INVALID_HANDLE;
@@ -192,6 +215,9 @@ ambix_err_t	ambix_close	(ambix_t*ambix) {
   ambix_matrix_deinit(&ambix->matrix);
   ambix_matrix_deinit(&ambix->matrix2);
 
+  ambix_delete_markers(ambix);
+  ambix_delete_regions(ambix);
+
   free(ambix);
   ambix=NULL;
   return res;
@@ -201,26 +227,111 @@ int64_t ambix_seek (ambix_t* ambix, int64_t frames, int whence) {
   return _ambix_seek(ambix, frames, whence);
 }
 
-struct SNDFILE_tag*ambix_get_sndfile	(ambix_t*ambix) {
+struct SNDFILE_tag*ambix_get_sndfile    (ambix_t*ambix) {
 #ifdef HAVE_SNDFILE_H
   return _ambix_get_sndfile(ambix);
 #endif
   return NULL;
 }
 
+uint32_t ambix_get_num_markers (ambix_t*ambix) {
+  return ambix->num_markers;
+}
+uint32_t ambix_get_num_regions(ambix_t *ambix) {
+  return ambix->num_regions;
+}
+ambix_marker_t *ambix_get_marker(ambix_t *ambix, uint32_t id) {
+  if (id < ambix->num_markers)
+    return &ambix->markers[id];
+  else
+    return NULL;
+}
+ambix_region_t *ambix_get_region(ambix_t *ambix, uint32_t id) {
+  if (id < ambix->num_regions)
+    return &ambix->regions[id];
+  else
+    return NULL;
+}
+ambix_err_t ambix_add_marker(ambix_t *ambix, ambix_marker_t *marker) {
+  if(ambix->startedWriting)
+    return AMBIX_ERR_UNKNOWN;
+
+  if (!marker)
+    return AMBIX_ERR_UNKNOWN;
+
+  if (ambix->num_markers > 0)
+    if (ambix->markers)
+      ambix->markers = (ambix_marker_t*)realloc(ambix->markers, (ambix->num_markers+1)*sizeof(ambix_marker_t));
+    else
+      return AMBIX_ERR_UNKNOWN;
+  else
+    ambix->markers = (ambix_marker_t*)calloc(1, sizeof(ambix_marker_t));
+
+  memcpy(&ambix->markers[ambix->num_markers], marker, sizeof(ambix_marker_t));
+  ambix->num_markers += 1;
+
+  ambix->pendingHeaders = 1;
+  return AMBIX_ERR_SUCCESS;
+}
+ambix_err_t ambix_add_region(ambix_t *ambix, ambix_region_t *region) {
+  if(ambix->startedWriting)
+    return AMBIX_ERR_UNKNOWN;
+
+  if (!region)
+    return AMBIX_ERR_UNKNOWN;
+
+  if (ambix->num_regions > 0)
+    if (ambix->regions)
+      ambix->regions = (ambix_region_t*)realloc(ambix->regions, (ambix->num_regions+1)*sizeof(ambix_region_t));
+    else
+      return AMBIX_ERR_UNKNOWN;
+  else
+    ambix->regions = (ambix_region_t*)calloc(1, sizeof(ambix_region_t));
+
+  memcpy(&ambix->regions[ambix->num_regions], region, sizeof(ambix_region_t));
+  ambix->num_regions += 1;
+
+  ambix->pendingHeaders = 1;
+  return AMBIX_ERR_SUCCESS;
+}
+ambix_err_t ambix_delete_markers(ambix_t *ambix) {
+  if (ambix->num_markers > 0) {
+    if (ambix->markers)
+      free (ambix->markers);
+    else
+      return AMBIX_ERR_UNKNOWN;
+
+    ambix->num_markers = 0;
+    return AMBIX_ERR_SUCCESS;
+  }
+
+  return AMBIX_ERR_UNKNOWN;
+}
+ambix_err_t ambix_delete_regions(ambix_t *ambix) {
+  if (ambix->num_regions > 0) {
+    if (ambix->regions)
+      free (ambix->regions);
+    else
+      return AMBIX_ERR_UNKNOWN;
+
+    ambix->num_regions = 0;
+    return AMBIX_ERR_SUCCESS;
+  }
+  return AMBIX_ERR_UNKNOWN;
+}
 
-const ambix_matrix_t*ambix_get_adaptormatrix	(ambix_t*ambix) {
+const ambix_matrix_t*ambix_get_adaptormatrix    (ambix_t*ambix) {
   if(AMBIX_EXTENDED==ambix->info.fileformat)
     return &(ambix->matrix);
   return NULL;
 }
-ambix_err_t ambix_set_adaptormatrix	(ambix_t*ambix, const ambix_matrix_t*matrix) {
+ambix_err_t ambix_set_adaptormatrix     (ambix_t*ambix, const ambix_matrix_t*matrix) {
   if(0) {
   } else if((ambix->filemode & AMBIX_READ ) && (AMBIX_BASIC   == ambix->info.fileformat)) {
     ambix_matrix_t*mtx=NULL;
     /* multiply the matrix with the previous adaptor matrix */
     if(AMBIX_EXTENDED == ambix->realinfo.fileformat) {
-      mtx=ambix_matrix_multiply(matrix, &ambix->matrix, &ambix->matrix2);
+      mtx=_ambix_matrix_multiply(matrix, &ambix->matrix, &ambix->matrix2);
       if(mtx != &ambix->matrix2)
         return AMBIX_ERR_UNKNOWN;
       ambix->use_matrix=2;
@@ -236,17 +347,48 @@ ambix_err_t ambix_set_adaptormatrix	(ambix_t*ambix, const ambix_matrix_t*matrix)
         return AMBIX_ERR_UNKNOWN;
       }
     }
-  } else if((ambix->filemode & AMBIX_WRITE) && (AMBIX_EXTENDED == ambix->info.fileformat)) {
+  } else if(ambix->filemode & AMBIX_WRITE) {
+    int basic2extended = AMBIX_BASIC == ambix->info.fileformat;
+    if ((AMBIX_EXTENDED != ambix->info.fileformat) && (AMBIX_BASIC != ambix->info.fileformat))
+      return AMBIX_ERR_UNKNOWN;
     /* too late, writing started already */
     if(ambix->startedWriting)
       return AMBIX_ERR_UNKNOWN;
-
     /* check whether the matrix will expand to a full set */
     if(!ambix_is_fullset(matrix->rows))
       return AMBIX_ERR_INVALID_DIMENSION;
 
+    if(basic2extended) {
+      ambix_matrix_t*pinv=NULL;
+      /* user requested AMBIX_BASIC, but now sets a matrix...
+       * so we write an ambix-extended format, and create the ambix-channels by
+       * multiplying the full-set with pinv(matrix)
+       */
+
+      /* check whether the reduced set has the same number of channels as we created our file for */
+      if(ambix->realinfo.ambichannels != matrix->cols)
+        return AMBIX_ERR_INVALID_DIMENSION;
+
+      /* check whether the matrix is actually invertible */
+      pinv=_ambix_matrix_pinv(matrix, pinv);
+      if(!pinv)
+        return AMBIX_ERR_INVALID_MATRIX;
+
+      if(!ambix_matrix_copy(pinv, &ambix->matrix2))
+        return AMBIX_ERR_UNKNOWN;
+
+      ambix_matrix_destroy(pinv);
+    }
+
     if(!ambix_matrix_copy(matrix, &ambix->matrix))
       return AMBIX_ERR_UNKNOWN;
+
+    if(basic2extended) {
+      ambix->realinfo.fileformat=AMBIX_EXTENDED;
+      ambix->info.ambichannels=matrix->rows;
+      ambix->use_matrix=2;
+    }
+
     /* ready to write it to file */
     ambix->pendingHeaders=1;
     return AMBIX_ERR_SUCCESS;
@@ -255,10 +397,11 @@ ambix_err_t ambix_set_adaptormatrix	(ambix_t*ambix, const ambix_matrix_t*matrix)
   return AMBIX_ERR_UNKNOWN;
 }
 
-ambix_err_t	_ambix_write_header	(ambix_t*ambix) {
+ambix_err_t     _ambix_write_header     (ambix_t*ambix) {
   void*data=NULL;
   if(ambix->filemode & AMBIX_WRITE) {
-    if((AMBIX_EXTENDED == ambix->info.fileformat)) {
+    if((AMBIX_EXTENDED == ambix->realinfo.fileformat)) {
+      _ambix_write_markersregions(ambix); // this need to be done in a more elegant way...!
       ambix_err_t res;
       /* generate UUID-chunk */
       uint64_t datalen=_ambix_matrix_to_uuid1(&ambix->matrix, NULL, ambix->byteswap);
@@ -280,8 +423,13 @@ ambix_err_t	_ambix_write_header	(ambix_t*ambix) {
         ambix->pendingHeaders=0;
 
       return res;
+    } else {
+      ambix_err_t res;
+      res = _ambix_write_markersregions(ambix); // this need to be done in a more elegant way...!
+      if(AMBIX_ERR_SUCCESS==res)
+         ambix->pendingHeaders=0;
+      return res;
     }
-    return AMBIX_ERR_INVALID_FORMAT;
   } else
     return AMBIX_ERR_INVALID_FILE;
 
@@ -297,6 +445,7 @@ static ambix_err_t _ambix_check_write(ambix_t*ambix, const void*ambidata, const
   if((ambix->realinfo.fileformat==AMBIX_EXTENDED) && !ambix_is_fullset(ambix->matrix.rows))
     return AMBIX_ERR_INVALID_DIMENSION;
 
+  /* write out any headers if we haven't done so yet */
   if(ambix->pendingHeaders) {
     ambix_err_t res=_ambix_write_header(ambix);
     if(AMBIX_ERR_SUCCESS!=res)
@@ -308,21 +457,21 @@ static ambix_err_t _ambix_check_write(ambix_t*ambix, const void*ambidata, const
 }
 
 static ambix_err_t _ambix_check_read(ambix_t*ambix, const void*ambidata, const void*otherdata, int64_t frames) {
-  /* TODO: add some checks whether writing is feasible
+  /* TODO: add some checks whether reading is feasible
    * e.g. format=extended but no (or wrong) matrix present */
   ambix->startedReading=1;
   return AMBIX_ERR_SUCCESS;
 }
 
 
-#define AMBIX_READF(type) \
+#define AMBIX_READF(type)                                               \
   int64_t ambix_readf_##type (ambix_t*ambix, type##_t*ambidata, type##_t*otherdata, int64_t frames) { \
     int64_t realframes;                                                 \
     type##_t*adaptorbuffer;                                             \
     ambix_err_t err= _ambix_check_read(ambix, (const void*)ambidata, (const void*)otherdata, frames); \
-    if(AMBIX_ERR_SUCCESS != err) {if (err>0)return -err; return err;}   \
+    if(AMBIX_ERR_SUCCESS != err) { return (err>0)?-err:err;}            \
     err=_ambix_adaptorbuffer_resize(ambix, frames, sizeof(type##_t));   \
-    if(AMBIX_ERR_SUCCESS != err) {if (err>0)return -err; return err;}   \
+    if(AMBIX_ERR_SUCCESS != err) { return (err>0)?-err:err;}            \
     adaptorbuffer=(type##_t*)ambix->adaptorbuffer;                      \
     realframes=_ambix_readf_##type(ambix, adaptorbuffer, frames);       \
     switch(ambix->use_matrix) {                                         \
@@ -338,27 +487,33 @@ static ambix_err_t _ambix_check_read(ambix_t*ambix, const void*ambidata, const v
     return realframes;                                                  \
   }
 
-#define AMBIX_WRITEF(type) \
+#define AMBIX_WRITEF(type)                                              \
   int64_t ambix_writef_##type (ambix_t*ambix, const type##_t *ambidata, const type##_t*otherdata, int64_t frames) { \
     type##_t*adaptorbuffer;                                             \
     ambix_err_t err= _ambix_check_write(ambix, (const void*)ambidata, (const void*)otherdata, frames); \
-    if(AMBIX_ERR_SUCCESS != err) {if (err>0)return -err; return err;}   \
+    if(AMBIX_ERR_SUCCESS != err) { return (err>0)?-err:err;}            \
     err=_ambix_adaptorbuffer_resize(ambix, frames, sizeof(type##_t));   \
-    if(AMBIX_ERR_SUCCESS != err) {if (err>0)return -err; return err;}   \
+    if(AMBIX_ERR_SUCCESS != err) { return (err>0)?-err:err;}            \
     adaptorbuffer=(type##_t*)ambix->adaptorbuffer;                      \
-    _ambix_mergeAdaptor_##type(ambidata, ambix->info.ambichannels, otherdata, ambix->info.extrachannels, adaptorbuffer, frames); \
+    switch(ambix->use_matrix) {                                         \
+    case 1:                                                             \
+      _ambix_mergeAdaptormatrix_##type(ambidata, &ambix->matrix , otherdata, ambix->info.extrachannels, adaptorbuffer, frames); \
+      break;                                                            \
+    case 2:                                                             \
+      _ambix_mergeAdaptormatrix_##type(ambidata, &ambix->matrix2, otherdata, ambix->info.extrachannels, adaptorbuffer, frames); \
+      break;                                                            \
+    default:                                                            \
+      _ambix_mergeAdaptor_##type(ambidata, ambix->info.ambichannels, otherdata, ambix->info.extrachannels, adaptorbuffer, frames); \
+    };                                                                  \
     return _ambix_writef_##type(ambix, adaptorbuffer, frames);          \
   }
 
-
 AMBIX_READF(int16);
-
 AMBIX_READF(int32);
-
 AMBIX_READF(float32);
+AMBIX_READF(float64);
 
 AMBIX_WRITEF(int16);
-
 AMBIX_WRITEF(int32);
-
 AMBIX_WRITEF(float32);
+AMBIX_WRITEF(float64);
diff --git a/libambix/src/marker_region_chunk.c b/libambix/src/marker_region_chunk.c
new file mode 100644
index 0000000..db6fb21
--- /dev/null
+++ b/libambix/src/marker_region_chunk.c
@@ -0,0 +1,510 @@
+/* marker_region_chunk.c -  read/write marker and region chunk              -*- c -*-
+
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
+         Institute of Electronic Music and Acoustics (IEM),
+         University of Music and Dramatic Arts, Graz
+
+   Copyright © 2016 Matthias Kronlachner <mail at matthiaskronlachner.com>
+
+   This file is part of libambix
+
+   libambix is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   libambix is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "private.h"
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+
+/* dense pack all structs */
+/* in a CAF file there are no pad fields to ensure correct byte alignment */
+#pragma pack(push, 1)
+
+/* ------------------------------------------------ */
+/* MARKER CHUNK */
+
+/* this is for the mSMPTETime of CAFMarker */
+typedef struct {
+    unsigned char   mHours;
+    unsigned char   mMinutes;
+    unsigned char   mSeconds;
+    unsigned char   mFrames;
+    uint32_t        mSubFrameSampleOffset;
+} CAF_SMPTE_Time;
+
+/* this is for the mSMPTE_TimeType of CAFMarkerChunk */
+typedef enum {
+    kCAF_SMPTE_TimeTypeNone     = 0,
+    kCAF_SMPTE_TimeType24       = 1,
+    kCAF_SMPTE_TimeType25       = 2,
+    kCAF_SMPTE_TimeType30Drop   = 3,
+    kCAF_SMPTE_TimeType30       = 4,
+    kCAF_SMPTE_TimeType2997     = 5,
+    kCAF_SMPTE_TimeType2997Drop = 6,
+    kCAF_SMPTE_TimeType60       = 7,
+    kCAF_SMPTE_TimeType5994     = 8
+} kCAF_SMPTE_TimeType; // uint32_t
+
+/* this is for the mType field of CAFMarker */
+typedef enum {
+    kCAFMarkerType_Generic              = 0,
+    kCAFMarkerType_ProgramStart         = 'pbeg',
+    kCAFMarkerType_ProgramEnd           = 'pend',
+    kCAFMarkerType_TrackStart           = 'tbeg',
+    kCAFMarkerType_TrackEnd             = 'tend',
+    kCAFMarkerType_Index                = 'indx',
+    kCAFMarkerType_RegionStart          = 'rbeg',
+    kCAFMarkerType_RegionEnd            = 'rend',
+    kCAFMarkerType_RegionSyncPoint      = 'rsyc',
+    kCAFMarkerType_SelectionStart       = 'sbeg',
+    kCAFMarkerType_SelectionEnd         = 'send',
+    kCAFMarkerType_EditSourceBegin      = 'cbeg',
+    kCAFMarkerType_EditSourceEnd        = 'cend',
+    kCAFMarkerType_EditDestinationBegin = 'dbeg',
+    kCAFMarkerType_EditDestinationEnd   = 'dend',
+    kCAFMarkerType_SustainLoopStart     = 'slbg',
+    kCAFMarkerType_SustainLoopEnd       = 'slen',
+    kCAFMarkerType_ReleaseLoopStart     = 'rlbg',
+    kCAFMarkerType_ReleaseLoopEnd       = 'rlen'
+} kCAFMarkerType; // uint32_t
+
+/* individual marker struct */
+typedef struct {
+    uint32_t        mType;
+    float64_t       mFramePosition;
+    uint32_t        mMarkerID;        // reference to a mStringsIDs for naming
+    CAF_SMPTE_Time  mSMPTETime;
+    uint32_t        mChannel;
+} CAFMarker;
+
+
+/* chunk holding all markers */
+typedef struct {
+    uint32_t     mSMPTE_TimeType;
+    uint32_t     mNumberMarkers;
+    CAFMarker*  mMarkers;
+} CAFMarkerChunk;
+
+/* ------------------------------------------------ */
+/* REGIONS CHUNK */
+
+/* used for mFlags in CAFRegion */
+typedef enum {
+    kCAFRegionFlag_LoopEnable    = 1,
+    kCAFRegionFlag_PlayForward   = 2,
+    kCAFRegionFlag_PlayBackward  = 4
+} kCAFRegionFlag; // uint32_t
+
+typedef struct {
+    uint32_t    mRegionID;
+    uint32_t    mFlags;
+    uint32_t    mNumberMarkers;
+    CAFMarker* mMarkers;
+} CAFRegion;
+#define SIZEOF_CAFRegion 12
+
+typedef struct {
+    uint32_t     mSMPTE_TimeType;
+    uint32_t     mNumberRegions;
+    CAFRegion*   mRegions;
+} CAFRegionChunk;
+#define SIZEOF_CAFRegionChunk 8
+
+/* ------------------------------------------------ */
+/* STRINGS CHUNK - used as labels for Markers and Regions*/
+
+typedef struct {
+    uint32_t  mStringID;
+    int64_t   mStringStartByteOffset;
+} CAFStringID;
+
+typedef struct {
+    uint32_t       mNumEntries; // The number of strings in the mStrings field.
+    CAFStringID*   mStringsIDs; // the marker refers to this id with mMarkerID
+    unsigned char* mStrings;    // An array of null-terminated UTF8-encoded text strings.
+} CAFStrings;
+#define SIZEOF_CAFStrings 4
+
+#pragma pack(pop)
+
+union int_chars {
+  uint32_t a;
+  char b[4];
+};
+
+typedef struct {
+  uint32_t      num_strings;
+  uint32_t      *string_ids;
+  unsigned char **strings;
+} strings_buffer;
+
+void swap_marker_chunk(CAFMarkerChunk* marker_chunk) {
+  _ambix_swap4array(&marker_chunk->mSMPTE_TimeType, 1);
+  _ambix_swap4array(&marker_chunk->mNumberMarkers, 1);
+}
+void swap_marker(CAFMarker* marker) {
+  _ambix_swap4array(&marker->mType, 1);
+  _ambix_swap8array((uint64_t *)&marker->mFramePosition, 1);
+  _ambix_swap4array(&marker->mMarkerID, 1);
+  _ambix_swap4array(&marker->mChannel, 1);
+}
+void swap_region(CAFRegion* region) {
+  _ambix_swap4array(&region->mRegionID, 1);
+  _ambix_swap4array(&region->mFlags, 1);
+  _ambix_swap4array(&region->mNumberMarkers, 1);
+}
+void swap_region_chunk(CAFRegionChunk* region_chunk) {
+  _ambix_swap4array(&region_chunk->mSMPTE_TimeType, 1);
+  _ambix_swap4array(&region_chunk->mNumberRegions, 1);
+}
+void swap_stringid(CAFStringID* caf_stringid) {
+  _ambix_swap4array(&caf_stringid->mStringID, 1);
+  _ambix_swap8array((uint64_t *)&caf_stringid->mStringStartByteOffset, 1);
+}
+unsigned char* get_string_from_buffer(strings_buffer* buffer, uint32_t id) {
+  if (buffer) {
+    uint32_t i;
+    for (i=0; i<buffer->num_strings;i++) {
+      if (buffer->string_ids[i] == id)
+        return buffer->strings[i];
+    }
+    return NULL;
+  } else
+    return NULL;
+}
+
+ambix_err_t _ambix_read_markersregions(ambix_t*ambix) {
+  int byteswap = ambix->byteswap;
+  uint32_t chunk_it = 0;
+  uint32_t i;
+
+  int64_t strings_datasize = 1;
+  union int_chars strg_id;
+  strings_buffer mystrings;
+  memset(&mystrings, 0, sizeof(strings_buffer));
+
+  strg_id.b[0] = 's'; strg_id.b[1] = 't'; strg_id.b[2] = 'r'; strg_id.b[3] = 'g';
+
+  /* first parse strings and save into a struct for later usage */
+  while (strings_datasize) {
+    void*strings_data = _ambix_read_chunk(ambix, strg_id.a, chunk_it++, &strings_datasize);
+    if (strings_datasize > SIZEOF_CAFStrings) {
+      uint32_t temp_num_strings = 0;
+      int64_t mstrings_datasize = 0;
+      char *strings_ptr = NULL;
+      CAFStringID* caf_stringid = NULL;
+      CAFStrings* strings_chunk = (CAFStrings*)strings_data;
+      if (byteswap)
+        _ambix_swap4array(&strings_chunk->mNumEntries, 1);
+      if (strings_datasize < (SIZEOF_CAFStrings + strings_chunk->mNumEntries*sizeof(CAFStringID))) {
+        if (strings_data)
+          free(strings_data);
+        break;
+      }
+      temp_num_strings = strings_chunk->mNumEntries;
+      mstrings_datasize = strings_datasize - (SIZEOF_CAFStrings + temp_num_strings*sizeof(CAFStringID));
+      // allocate memory for mystrings
+      if (!mystrings.string_ids) {
+        mystrings.string_ids = malloc((mystrings.num_strings+temp_num_strings)*sizeof(uint32_t));
+        mystrings.strings = malloc((mystrings.num_strings+temp_num_strings)*sizeof(unsigned char*));
+      } else {
+        mystrings.string_ids = realloc(mystrings.string_ids, (mystrings.num_strings+temp_num_strings)*sizeof(uint32_t));
+        mystrings.strings = realloc(mystrings.strings, (mystrings.num_strings+temp_num_strings)*sizeof(unsigned char*));
+      }
+      strings_ptr = strings_data;
+      strings_ptr += (4+temp_num_strings*sizeof(CAFStringID)); // start of mStrings
+      caf_stringid = (CAFStringID*)(&strings_data[4]);
+      for (i=0; i<temp_num_strings; i++) {
+        unsigned char* mString = NULL;
+        uint32_t mString_len = 0;
+        if (byteswap)
+          swap_stringid(&caf_stringid[i]);
+        if (caf_stringid[i].mStringStartByteOffset >= mstrings_datasize)
+          break; // invalid offset!
+        mString = (unsigned char*) (strings_ptr+caf_stringid[i].mStringStartByteOffset);
+        mystrings.string_ids[mystrings.num_strings] = caf_stringid[i].mStringID;
+        mString_len = strlen((const char *)mString);
+        mystrings.strings[mystrings.num_strings] = calloc((mString_len+1), sizeof(unsigned char));
+        memcpy(mystrings.strings[mystrings.num_strings], mString, mString_len*sizeof(unsigned char));
+        mystrings.num_strings++;
+      }
+    }
+    if (strings_data)
+      free(strings_data);
+  }
+
+  /* parse markers */
+  do {
+    int64_t marker_datasize = 1;
+    union int_chars mark_id;
+    chunk_it = 0;
+    mark_id.b[0] = 'm'; mark_id.b[1] = 'a'; mark_id.b[2] = 'r'; mark_id.b[3] = 'k';
+    while (marker_datasize) {
+      void*marker_data = _ambix_read_chunk(ambix, mark_id.a, chunk_it++, &marker_datasize);
+      if (marker_datasize > 2*sizeof(uint32_t)) {
+        CAFMarkerChunk* marker_chunk = (CAFMarkerChunk*)marker_data;
+        unsigned char* bytePtr = NULL;
+        if (byteswap)
+          swap_marker_chunk(marker_chunk);
+        if (marker_datasize < (marker_chunk->mNumberMarkers*(sizeof(CAFMarker)) + 2*sizeof(uint32_t))) {
+          if (marker_data)
+            free(marker_data);
+          break;
+        }
+        bytePtr = (unsigned char*)marker_data;
+        bytePtr += 2*sizeof(uint32_t);
+        for (i=0; i<marker_chunk->mNumberMarkers; i++) {
+          ambix_marker_t new_ambix_marker;
+          CAFMarker *caf_marker = (CAFMarker*)bytePtr;
+          unsigned char* string = NULL;
+          if (byteswap)
+            swap_marker(caf_marker);
+          memset(&new_ambix_marker, 0, sizeof(ambix_marker_t));
+          new_ambix_marker.position = caf_marker->mFramePosition;
+          string = get_string_from_buffer(&mystrings, caf_marker->mMarkerID);
+          if (string) {
+            strncpy(new_ambix_marker.name, (const char *)string, 255);
+          }
+          ambix_add_marker(ambix, &new_ambix_marker);
+          bytePtr += sizeof(CAFMarker);
+        }
+      }
+      if (marker_data)
+        free(marker_data);
+    }
+  } while(0);
+
+  /* parse regions */
+  do {
+    void* region_data = NULL;
+    int64_t region_datasize = 1;
+    union int_chars regn_id;
+    regn_id.b[0] = 'r'; regn_id.b[1] = 'e'; regn_id.b[2] = 'g'; regn_id.b[3] = 'n';
+
+    chunk_it = 0;
+
+    while (region_datasize) {
+      region_data = _ambix_read_chunk(ambix, regn_id.a, chunk_it++, &region_datasize);
+      if (region_datasize > 2*sizeof(uint32_t)) {
+        int64_t data_read = 0;
+        unsigned char* bytePtr = NULL;
+        CAFRegionChunk* region_chunk = (CAFRegionChunk*)region_data;
+        if (byteswap)
+          swap_region_chunk(region_chunk);
+        if (region_datasize < (region_chunk->mNumberRegions*(SIZEOF_CAFRegion+sizeof(CAFMarker)) + SIZEOF_CAFRegionChunk)) {
+          if (region_data)
+            free(region_data);
+          break;
+        }
+        bytePtr = (unsigned char*)region_data;
+        data_read += 2*sizeof(uint32_t); // SIZEOF_CAFRegionChunk
+        for (i=0; i<region_chunk->mNumberRegions; i++) {
+          uint32_t j;
+          ambix_region_t new_ambix_region;
+          CAFRegion *caf_region = NULL;
+          if (region_datasize < data_read + SIZEOF_CAFRegion)
+            break;
+          caf_region = (CAFRegion*)&bytePtr[data_read];
+          if (byteswap)
+            swap_region(caf_region);
+          memset(&new_ambix_region, 0, sizeof(ambix_region_t));
+          /* iterate over all markers and find startMarker and endMarker */
+          data_read += SIZEOF_CAFRegion;
+          for (j=0; j<caf_region->mNumberMarkers; j++) {
+            CAFMarker *caf_marker = NULL;
+            if (region_datasize < data_read + sizeof(CAFMarker))
+              break;
+            caf_marker = (CAFMarker*)&bytePtr[data_read];
+            if (byteswap)
+              swap_marker(caf_marker);
+            if (caf_marker->mType == kCAFMarkerType_RegionStart) {
+              unsigned char* string = NULL;
+              new_ambix_region.start_position = caf_marker->mFramePosition;
+              string = get_string_from_buffer(&mystrings, caf_marker->mMarkerID);
+              if (string)
+                strncpy(new_ambix_region.name, (const char *)string, 255);
+            }
+            else if (caf_marker->mType == kCAFMarkerType_RegionEnd)
+              new_ambix_region.end_position = caf_marker->mFramePosition;
+            data_read += sizeof(CAFMarker);
+          }
+          ambix_add_region(ambix, &new_ambix_region);
+        }
+      }
+      if (region_data)
+        free(region_data);
+    }
+  } while(0);
+
+  /* free allocated strings data */
+  if (mystrings.string_ids)
+    free(mystrings.string_ids);
+  for (i=0; i<mystrings.num_strings; i++) {
+    if (mystrings.strings[i])
+      free(mystrings.strings[i]);
+  }
+  if (mystrings.strings)
+    free(mystrings.strings);
+  memset(&mystrings, 0, sizeof(strings_buffer));
+
+  return AMBIX_ERR_UNKNOWN;
+}
+
+void add_string_to_data(int id, unsigned char *byte_ptr_stringid, char *name, int64_t *byteoffset_strings, unsigned char *byte_ptr_strings, uint32_t *datasize_strings, int byteswap) {
+  /* handle the string */
+  CAFStringID* string_id = (CAFStringID*)byte_ptr_stringid;
+  uint32_t name_len = strlen((const char *)name);
+  string_id->mStringID = id;
+  string_id->mStringStartByteOffset = *byteoffset_strings;
+  memcpy(byte_ptr_strings, name, name_len*sizeof(char));
+  byte_ptr_strings[name_len] = 0; // set the last char to NUL
+  *byteoffset_strings += (name_len+1);
+  *datasize_strings += (name_len+1);
+  if (byteswap)
+    swap_stringid(string_id);
+}
+
+ambix_err_t _ambix_write_markersregions(ambix_t*ambix) {
+  uint32_t i;
+  int byteswap = ambix->byteswap;
+
+  void *strings_data = NULL;
+  uint32_t num_strings = ambix->num_markers+ambix->num_regions;
+  uint32_t datasize_strings = 0;
+  unsigned char* byte_ptr_strings = NULL;
+  unsigned char* byte_ptr_stringid = NULL;
+  int64_t byteoffset_strings = 0;
+
+  void *marker_data = NULL;
+  uint32_t datasize_markers = 0;
+
+  /* reserve space for strings */
+  if (num_strings > 0) {
+    CAFStrings *strings_chunk = NULL;
+    datasize_strings = sizeof(uint32_t)+num_strings*sizeof(CAFStringID);
+    strings_data = calloc(1, datasize_strings+256); // reserve a fixed space of 256 bytes for each string
+    byte_ptr_strings = (unsigned char*)strings_data;
+    byte_ptr_strings += (sizeof(uint32_t)+num_strings*(sizeof(CAFStringID)));
+    byte_ptr_stringid = (unsigned char*)strings_data;
+    byte_ptr_stringid += sizeof(uint32_t);
+    strings_chunk = (CAFStrings*)strings_data;
+    strings_chunk->mNumEntries = num_strings;
+    if (byteswap)
+      _ambix_swap4array(&strings_chunk->mNumEntries, 1);
+  }
+  /* markers */
+  if (ambix->num_markers > 0) {
+    CAFMarkerChunk* marker_chunk = NULL;
+    unsigned char* bytePtr = NULL;
+    datasize_markers = 2*sizeof(uint32_t) + ambix->num_markers*sizeof(CAFMarker);
+    marker_data = calloc(1, datasize_markers);
+    bytePtr = (unsigned char*)marker_data;
+
+    marker_chunk = (CAFMarkerChunk*)marker_data;
+    marker_chunk->mSMPTE_TimeType = kCAF_SMPTE_TimeTypeNone;
+    marker_chunk->mNumberMarkers = ambix->num_markers;
+    if (byteswap)
+      swap_marker_chunk(marker_chunk);
+
+    // offset the data pointer by 2*uint32_t to point to start of markers
+    bytePtr += 2*sizeof(uint32_t);
+    for (i=0; i<ambix->num_markers;i++) {
+      CAFMarker* new_marker = (CAFMarker*) bytePtr;
+      new_marker->mType = kCAFMarkerType_Generic;
+      new_marker->mFramePosition = ambix->markers[i].position;
+      new_marker->mMarkerID = i+1; // string ID -> 1...num_markers
+      new_marker->mChannel = 0; // 0 means for all channels
+      if (byteswap) {
+        swap_marker(new_marker);
+      }
+      bytePtr += sizeof(CAFMarker);
+
+      add_string_to_data(i+1, byte_ptr_stringid, ambix->markers[i].name, &byteoffset_strings, byte_ptr_strings, &datasize_strings, byteswap);
+      byte_ptr_strings += (strlen((const char*)ambix->markers[i].name)+1);
+      byte_ptr_stringid += sizeof(CAFStringID);
+    }
+  }
+
+  /* regions */
+  // a region consists of 2 markers (start,end) and region chunk
+  uint32_t datasize_regions = 2*sizeof(uint32_t) + ambix->num_regions*(SIZEOF_CAFRegion + 2*sizeof(CAFMarker));
+  void *region_data               = calloc(1, datasize_regions);
+  CAFRegionChunk* region_chunk    = (CAFRegionChunk*)region_data;
+  unsigned char* byte_ptr_regions = (unsigned char*)region_data;
+  region_chunk->mSMPTE_TimeType = kCAF_SMPTE_TimeTypeNone;
+  region_chunk->mNumberRegions = ambix->num_regions;
+  if (byteswap)
+    swap_region_chunk(region_chunk);
+  // offset the data pointer by 2*uint32_t to point to start of mRegions
+  byte_ptr_regions += 2*sizeof(uint32_t);
+  for (i=0; i<ambix->num_regions;i++) {
+    CAFRegion *new_region   = NULL;
+    CAFMarker *start_marker = NULL, *end_marker = NULL;
+
+    /* region */
+    new_region = (CAFRegion*) byte_ptr_regions;
+    new_region->mRegionID = i+1; // does not have a connection with a string
+    new_region->mFlags = 0;
+    new_region->mNumberMarkers = 2; // start, end marker
+
+    /* start region marker */
+    byte_ptr_regions += SIZEOF_CAFRegion; // offset pointer to start marker
+    start_marker = (CAFMarker*)byte_ptr_regions;// &((new_region->mMarkers)[0]);
+    start_marker->mType = kCAFMarkerType_RegionStart;
+    start_marker->mFramePosition = ambix->regions[i].start_position;
+    start_marker->mMarkerID = ambix->num_markers+i+1; // string ID -> num_markers+1...num_markers+num_regions
+    start_marker->mChannel = 0; // 0 means for all channels
+
+    /* end region marker */
+    byte_ptr_regions += sizeof(CAFMarker); // offset pointer to end marker
+    end_marker = (CAFMarker*)byte_ptr_regions; // &new_region->mMarkers[1];
+    end_marker->mType = kCAFMarkerType_RegionEnd;
+    end_marker->mFramePosition = ambix->regions[i].end_position;
+    end_marker->mMarkerID = ambix->num_markers+i+1; // string ID -> num_markers+1...num_markers+num_regions
+    end_marker->mChannel = 0; // 0 means for all channels
+    if (byteswap) {
+      swap_region(new_region);
+      swap_marker(start_marker);
+      swap_marker(end_marker);
+    }
+    byte_ptr_regions += sizeof(CAFMarker);
+
+    add_string_to_data(ambix->num_markers+i+1, byte_ptr_stringid, ambix->regions[i].name, &byteoffset_strings, byte_ptr_strings, &datasize_strings, byteswap);
+    byte_ptr_strings += (strlen((const char*)ambix->regions[i].name)+1);
+    byte_ptr_stringid += sizeof(CAFStringID);
+  }
+
+  /* add the chunk data */
+  do {
+    union int_chars mark_id, regn_id, strg_id;
+
+    mark_id.b[0] = 'm'; mark_id.b[1] = 'a'; mark_id.b[2] = 'r'; mark_id.b[3] = 'k';
+    _ambix_write_chunk(ambix, mark_id.a, marker_data, datasize_markers);
+    free(marker_data);
+
+    regn_id.b[0] = 'r'; regn_id.b[1] = 'e'; regn_id.b[2] = 'g'; regn_id.b[3] = 'n';
+    _ambix_write_chunk(ambix, regn_id.a, region_data, datasize_regions);
+    free(region_data);
+
+    strg_id.b[0] = 's'; strg_id.b[1] = 't'; strg_id.b[2] = 'r'; strg_id.b[3] = 'g';
+    _ambix_write_chunk(ambix, strg_id.a, strings_data, datasize_strings);
+    free(strings_data);
+  } while(0);
+  return AMBIX_ERR_SUCCESS;
+}
diff --git a/libambix/src/matrix.c b/libambix/src/matrix.c
index 0edb457..d042dee 100644
--- a/libambix/src/matrix.c
+++ b/libambix/src/matrix.c
@@ -1,6 +1,6 @@
 /* matrix.c -  Matrix handling              -*- c -*-
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -80,7 +80,7 @@ ambix_matrix_init(uint32_t rows, uint32_t cols, ambix_matrix_t*orgmtx) {
 }
 
 ambix_matrix_t*
-ambix_matrix_transpose(const ambix_matrix_t*matrix, ambix_matrix_t*xirtam) {
+_ambix_matrix_transpose(const ambix_matrix_t*matrix, ambix_matrix_t*xirtam) {
   uint32_t rows, cols, r, c;
   float32_t**mtx, **xtm;
   if(!xirtam)
@@ -132,6 +132,7 @@ _ambix_matrix_fill_data_byteswapped(ambix_matrix_t*mtx, const number32_t*data) {
   return AMBIX_ERR_SUCCESS;
 }
 
+#if 0
 ambix_err_t
 ambix_matrix_fill_data_transposed(ambix_matrix_t*mtx, const float32_t*data, int byteswap) {
   ambix_err_t err=AMBIX_ERR_SUCCESS;
@@ -146,7 +147,7 @@ ambix_matrix_fill_data_transposed(ambix_matrix_t*mtx, const float32_t*data, int
     err=ambix_matrix_fill_data(xtm, data);
 
   if(AMBIX_ERR_SUCCESS==err) {
-    ambix_matrix_t*resu=ambix_matrix_transpose(mtx, xtm);
+    ambix_matrix_t*resu=_ambix_matrix_transpose(mtx, xtm);
     if(!resu)
       err=AMBIX_ERR_UNKNOWN;
   }
@@ -154,6 +155,7 @@ ambix_matrix_fill_data_transposed(ambix_matrix_t*mtx, const float32_t*data, int
   ambix_matrix_destroy(xtm);
   return err;
 }
+#endif
 
 
 
@@ -183,7 +185,7 @@ ambix_matrix_copy(const ambix_matrix_t*src, ambix_matrix_t*dest) {
 
 
 ambix_matrix_t*
-ambix_matrix_multiply(const ambix_matrix_t*left, const ambix_matrix_t*right, ambix_matrix_t*dest) {
+_ambix_matrix_multiply(const ambix_matrix_t*left, const ambix_matrix_t*right, ambix_matrix_t*dest) {
   uint32_t r, c, rows, cols, common;
   float32_t**ldat,**rdat,**ddat;
   float32_t lv, rv;
@@ -325,7 +327,7 @@ ambix_matrix_fill(ambix_matrix_t*matrix, ambix_matrixtype_t typ) {
         counter++;
       }
     }
-   matrix=_matrix_diag(matrix, weights, rows);
+    matrix=_matrix_diag(matrix, weights, rows);
     free(weights);
   }
     break;
@@ -335,36 +337,89 @@ ambix_matrix_fill(ambix_matrix_t*matrix, ambix_matrixtype_t typ) {
   return matrix;
 }
 
-ambix_err_t ambix_matrix_multiply_float32(float32_t*dest, const ambix_matrix_t*matrix, const float32_t*source, int64_t frames) {
-  float32_t**mtx=matrix->data;
-  const uint32_t outchannels=matrix->rows;
-  const uint32_t inchannels=matrix->cols;
-  int64_t frame;
-  float32_t*dst=dest;
-  const float32_t*src=source;
-  for(frame=0; frame<frames; frame++) {
-    uint32_t outchan;
-    for(outchan=0; outchan<outchannels; outchan++) {
-      double sum=0.;
-      uint32_t inchan;
-      //      printf("..output:%d @ %d\n", (int)outchan, (int)frame);
-      for(inchan=0; inchan<inchannels; inchan++) {
-        double scale=mtx[outchan][inchan];
-        double in=src[frame*inchannels+inchan];
-        //        printf("....%f[%d|%d]*%f\n", (float)scale, (int)outchan, (int)inchan, (float)in);
-        sum+=scale*in;
+ambix_matrix_t*
+_ambix_matrix_pinv(const ambix_matrix_t*A, ambix_matrix_t*P) {
+  const float32_t eps=1e-7;
+  ambix_matrix_t *result = NULL;
+
+  /* try cholesky inversion */
+  result=_ambix_matrix_pinvert_cholesky(A, P, eps);
+  if(result)
+    return result;
+
+  /* if that fails (should never happen), fall back to gauss-jordan */
+  if (A->rows==A->cols) {
+    ambix_matrix_t*Ax = ambix_matrix_copy(A, NULL);
+    result = _ambix_matrix_invert_gaussjordan(Ax, P, eps); // do normal inverse if square matrix
+    if(Ax)   ambix_matrix_destroy(Ax);
+  } else {
+    /* we'll have to do the pseudo-inverse:
+     * P=A'*inv(A*A') if row<col
+     * P=inv(A'*A)*A' if col<row
+     */
+    ambix_matrix_t *At = NULL;
+    ambix_matrix_t *temp = NULL;
+    ambix_matrix_t *temp2 = NULL;
+    do {
+      At = _ambix_matrix_transpose(A, At);
+
+      if (A->rows > A->cols) {
+        temp = _ambix_matrix_multiply(At, A, NULL);
+        if (!temp)break;
+        temp2 = _ambix_matrix_invert_gaussjordan(temp, temp2, eps);
+        if (!temp2)break;
+
+        result = _ambix_matrix_multiply(temp2, At, P);
+      } else {
+        temp = _ambix_matrix_multiply(A, At, NULL);
+        if (!temp)break;
+        temp2 = _ambix_matrix_invert_gaussjordan(temp, temp2, eps);
+        if (!temp2)break;
+
+        result = _ambix_matrix_multiply(At, temp2, P);
       }
-      dst[frame*outchannels+outchan]=(float32_t)sum;
-    }
+    } while (0);
+    if(At)   ambix_matrix_destroy(At);
+    if(temp) ambix_matrix_destroy(temp);
+    if(temp2)ambix_matrix_destroy(temp2);
   }
-  return AMBIX_ERR_SUCCESS;
+
+  return result;
 }
-#define MTXMULTIPLY_DATA_INT(typ)                                       \
+
+#define MTXMULTIPLY_DATA_FLOAT(typ)                                     \
   ambix_err_t ambix_matrix_multiply_##typ(typ##_t*dest, const ambix_matrix_t*matrix, const typ##_t*source, int64_t frames) { \
     float32_t**mtx=matrix->data;                                        \
     const uint32_t outchannels=matrix->rows;                            \
     const uint32_t inchannels=matrix->cols;                             \
     int64_t frame;                                                      \
+    typ##_t*dst=dest;                                                   \
+    const typ##_t*src=source;                                           \
+    for(frame=0; frame<frames; frame++) {                               \
+      uint32_t outchan;                                                 \
+      for(outchan=0; outchan<outchannels; outchan++) {                  \
+        double sum=0.;                                                  \
+        uint32_t inchan;                                                \
+        for(inchan=0; inchan<inchannels; inchan++) {                    \
+          double scale=mtx[outchan][inchan];                            \
+          double in=src[frame*inchannels+inchan];                       \
+          sum+=scale*in;                                                \
+        }                                                               \
+        dst[frame*outchannels+outchan]=(typ##_t)sum;                    \
+      }                                                                 \
+    }                                                                   \
+    return AMBIX_ERR_SUCCESS;                                           \
+  }                                                                     \
+
+MTXMULTIPLY_DATA_FLOAT(float32);
+MTXMULTIPLY_DATA_FLOAT(float64);
+
+#define MTXMULTIPLY_DATA_INT(typ)                                       \
+  ambix_err_t ambix_matrix_multiply_##typ(typ##_t*dest, const ambix_matrix_t*matrix, const typ##_t*source, int64_t frames) { \
+    float32_t**mtx=matrix->data; \
+    const uint32_t outchannels=matrix->rows;                            \
+    const uint32_t inchannels=matrix->cols;                             \
+    int64_t frame;                                                      \
     for(frame=0; frame<frames; frame++) {                               \
       uint32_t outchan;                                                 \
       typ##_t*dst=dest+frame;                                           \
@@ -377,7 +432,7 @@ ambix_err_t ambix_matrix_multiply_float32(float32_t*dest, const ambix_matrix_t*m
           double in=src[inchan*frames];                                 \
           sum+=scale * in;                                              \
         }                                                               \
-		dst[frames*outchan]=(typ##_t)(sum);  /* FIXXXME: saturation */  \
+        dst[frames*outchan]=(typ##_t)(sum);  /* FIXXXME: saturation */  \
       }                                                                 \
     }                                                                   \
     return AMBIX_ERR_SUCCESS;                                           \
@@ -450,3 +505,13 @@ ambix_matrix_t*_matrix_permutate(ambix_matrix_t*matrix, const float32_t*route, i
   }
   return matrix;
 }
+
+
+ambix_matrix_t*
+ambix_matrix_pinv(const ambix_matrix_t*A, ambix_matrix_t*P) {
+  return _ambix_matrix_pinv(A, P);
+}
+ambix_matrix_t*
+ambix_matrix_multiply(const ambix_matrix_t*left, const ambix_matrix_t*right, ambix_matrix_t*dest) {
+  return _ambix_matrix_multiply(left, right, dest);
+}
diff --git a/libambix/src/matrix_invert.c b/libambix/src/matrix_invert.c
new file mode 100644
index 0000000..8012693
--- /dev/null
+++ b/libambix/src/matrix_invert.c
@@ -0,0 +1,258 @@
+/* matrix_invert.c -  utilities for matrix inversion              -*- c -*-
+
+   Copyright © 2016 IOhannes m zmölnig <zmoelnig at iem.at>.
+         Institute of Electronic Music and Acoustics (IEM),
+         University of Music and Dramatic Arts, Graz
+
+   This file is part of libambix
+
+   libambix is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   libambix is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "private.h"
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+
+#include <math.h>
+
+/**
+ * simple matrix inversion of square matrices, using Gauss-Jordan
+ */
+/* this modifies the input matrix! */
+ambix_matrix_t*
+_ambix_matrix_invert_gaussjordan(ambix_matrix_t*input, ambix_matrix_t*inverse, float32_t eps)
+{
+  ambix_matrix_t*inverse_org = inverse;
+  int i, k;
+  float32_t *a1, *b1, *a2, *b2;
+
+  int errors=0; /* error counter */
+
+  if(input==0)
+    { // no input matrix
+      return NULL;
+    }
+
+  if (input->cols != input->rows)
+    {// matrix is not squared
+      return NULL;
+    }
+
+  int col=input->cols, row=input->rows;
+
+  /* 1a reserve space for the inverted matrix */
+  if(!inverse)
+    {
+      inverse=ambix_matrix_init(row, col, NULL);
+    }
+
+  float32_t **original=input->data;
+  float32_t **inverted=inverse->data;
+
+
+  /* 1b make an eye-shaped float-buf for B */
+  ambix_matrix_fill(inverse, AMBIX_MATRIX_IDENTITY);
+
+  /* 2. do the Gauss-Jordan */
+  //printf("GaussJordan\n");
+  for (k=0; k<row; k++) {
+    /* adjust current row */
+    float32_t diagel = original[k][k];
+    float32_t i_diagel = 0;
+    if(diagel>-eps && diagel<eps)
+      errors++;
+    else
+      i_diagel = 1./diagel;
+
+    /* normalize current row (set the diagonal-element to 1 */
+    for (i=0; i < row; i++)
+      {
+        original[k][i] *= i_diagel;
+        inverted[k][i] *= i_diagel;
+      }
+
+    /* eliminate the k-th element in each row by adding the weighted normalized row */
+    for (i=0; i < row; i++)
+      {
+        if (i-k)
+          {
+            float32_t f =-original[i][k];
+            int j;
+            for (j=row-1; j >= 0; j--) {
+              original[i][j] += f * original[k][j];
+              inverted[i][j] += f * inverted[k][j];
+            }
+          }
+      }
+  }
+
+  if (errors > 0) {
+    if(inverse != inverse_org)
+      /* if the 'inverse' was locally allocated, free it */
+      ambix_matrix_destroy(inverse);
+    inverse=NULL;
+  }
+
+  return inverse;
+}
+
+/**
+ * matrix inversion using the Cholesky algorithm
+ *
+ * the functions _am_cholesky2_decomp and _am_cholesky_2_inverse
+ * have been extracted from the "Survival" package for R.
+ *   https://cran.r-project.org/web/packages/survival/index.html
+ *
+ * They are distributed under the Lesser Gnu General Public License 2 (or greater)
+ * and are
+ * © 2009 Thomas Lumley
+ * © 2009-2016 Terry M Therneau
+ */
+/** cholesky2 decomposition
+ * \author © -2009 Thomas Lumley
+ * \author © 2009-2016 Terry M Therneau <therneau.terry at mayo.edu>
+ * \copyright LGPL >= 2
+ * \note origin survival 2.39-3 https://cran.r-project.org/web/packages/survival/index.html
+ */
+static int _am_cholesky2_decomp(ambix_matrix_t*mtx, float32_t toler)
+{
+  const uint32_t columns = mtx->cols;
+  float32_t**matrix= mtx->data;
+  float32_t temp;
+  int i, j, k;
+  float32_t eps, pivot;
+  int rank;
+  int nonneg;
+
+  nonneg = 1;
+  eps = 0;
+  for (i = 0; i < columns; i++) {
+    if (matrix[i][i] > eps)
+      eps = matrix[i][i];
+    for (j = (i + 1); j < columns; j++)
+      matrix[j][i] = matrix[i][j];
+  }
+  eps *= toler;
+
+  rank = 0;
+  for (i = 0; i < columns; i++) {
+    pivot = matrix[i][i];
+    if (pivot < eps) {
+      matrix[i][i] = 0;
+      if (pivot < -8 * eps)
+        nonneg = -1;
+    } else {
+      rank++;
+      for (j = (i + 1); j < columns; j++) {
+        temp = matrix[j][i] / pivot;
+        matrix[j][i] = temp;
+        matrix[j][j] -= temp * temp * pivot;
+        for (k = (j + 1); k < columns; k++)
+          matrix[k][j] -= temp * matrix[k][i];
+      }
+    }
+  }
+  return (rank * nonneg);
+}
+/* inplace inverse */
+/** inplace inversion of a cholesky2 decomposed matrix
+ * \author © -2009 Thomas Lumley
+ * \author © 2009-2016 Terry M Therneau <therneau.terry at mayo.edu>
+ * \copyright LGPL >= 2
+ * \note origin survival 2.39-3 https://cran.r-project.org/web/packages/survival/index.html
+ */
+static void _am_cholesky2_inverse(ambix_matrix_t*mtx)
+{
+  const int columns = mtx->cols;;
+  float32_t**matrix = mtx->data;
+  register float32_t temp;
+  register int i, j, k;
+
+  /*
+  ** invert the cholesky in the lower triangle
+  **   take full advantage of the cholesky's diagonal of 1's
+  */
+  for (i = 0; i < columns; i++) {
+    if (matrix[i][i] > 0) {
+      matrix[i][i] = 1 / matrix[i][i]; /*this line inverts D */
+      for (j = (i + 1); j < columns; j++) {
+        matrix[j][i] = -matrix[j][i];
+        for (k = 0; k < i; k++) /* sweep operator */
+          matrix[j][k] += matrix[j][i] * matrix[i][k];
+      }
+    }
+  }
+
+  /*
+  ** lower triangle now contains inverse of cholesky
+  ** calculate F'DF (inverse of cholesky decomp process) to get inverse
+  **   of original matrix
+  */
+  for (i = 0; i < columns; i++) {
+    if (matrix[i][i] == 0) { /* singular row */
+      for (j = 0; j < i; j++)
+        matrix[j][i] = 0;
+      for (j = i; j < columns; j++)
+        matrix[i][j] = 0;
+    } else {
+      for (j = (i + 1); j < columns; j++) {
+        temp = matrix[j][i] * matrix[j][j];
+        if (j != i)
+          matrix[i][j] = temp;
+        for (k = i; k < j; k++)
+          matrix[i][k] += temp * matrix[j][k];
+      }
+    }
+  }
+
+  // ugly fix to return only inverse
+  for (i = 1; i < columns; i++)
+    for (j = 0; j < i; j++)
+      matrix[i][j] = matrix[j][i];
+}
+
+/*
+ * calculate the inverse of any (rectangular) real-valued matrix using cholesky decomposition
+ */
+ambix_matrix_t*
+_ambix_matrix_pinvert_cholesky(const ambix_matrix_t*input, ambix_matrix_t*inverse, float32_t tolerance) {
+  /* (rows>cols)?(inv(x'*x)*x'):(x'*inv(x*x')) */
+  float32_t toler = tolerance;
+  ambix_matrix_t*trans = _ambix_matrix_transpose(input, 0);
+  ambix_matrix_t*chinv=0;
+  ambix_matrix_t*result=0;
+  do {
+    if(!trans)break;
+    if(input->rows > input->cols) {
+      chinv=_ambix_matrix_multiply(trans, input, chinv);
+      if(!chinv)break;
+      _am_cholesky2_decomp(chinv, toler);
+      _am_cholesky2_inverse(chinv);
+      result=_ambix_matrix_multiply(chinv, trans, inverse);
+    } else {
+      chinv=_ambix_matrix_multiply(input, trans, chinv);
+      if(!chinv)break;
+      _am_cholesky2_decomp(chinv, toler);
+      _am_cholesky2_inverse(chinv);
+      result=_ambix_matrix_multiply(trans, chinv, inverse);
+    }
+  } while(0);
+  if(trans)ambix_matrix_destroy(trans);
+  if(chinv)ambix_matrix_destroy(chinv);
+
+  return result;
+}
diff --git a/libambix/src/null.c b/libambix/src/null.c
index 19eebde..5a4d455 100644
--- a/libambix/src/null.c
+++ b/libambix/src/null.c
@@ -22,15 +22,15 @@
 
 #include "private.h"
 
-ambix_err_t _ambix_open	(ambix_t*ambix, const char *path, const ambix_filemode_t mode, const ambix_info_t*ambixinfo) {
+ambix_err_t _ambix_open (ambix_t*ambix, const char *path, const ambix_filemode_t mode, const ambix_info_t*ambixinfo) {
   return AMBIX_ERR_INVALID_FILE;
 }
 
-ambix_err_t	_ambix_close	(ambix_t*ambix) {
+ambix_err_t     _ambix_close    (ambix_t*ambix) {
   return AMBIX_ERR_INVALID_FILE;
 }
 
-struct SNDFILE_tag*_ambix_get_sndfile	(ambix_t*ambix) {
+struct SNDFILE_tag*_ambix_get_sndfile   (ambix_t*ambix) {
   return 0;
 }
 
@@ -43,6 +43,9 @@ int64_t _ambix_readf_int32   (ambix_t*ambix, int32_t*data, int64_t frames) {
 int64_t _ambix_readf_float32   (ambix_t*ambix, float32_t*data, int64_t frames) {
   return -1;
 }
+int64_t _ambix_readf_float64   (ambix_t*ambix, float64_t*data, int64_t frames) {
+  return -1;
+}
 
 int64_t _ambix_writef_int16   (ambix_t*ambix, const int16_t*data, int64_t frames) {
   return -1;
@@ -53,6 +56,9 @@ int64_t _ambix_writef_int32   (ambix_t*ambix, const int32_t*data, int64_t frames
 int64_t _ambix_writef_float32   (ambix_t*ambix, const float32_t*data, int64_t frames) {
   return -1;
 }
+int64_t _ambix_writef_float64   (ambix_t*ambix, const float64_t*data, int64_t frames) {
+  return -1;
+}
 ambix_err_t _ambix_write_uuidchunk(ambix_t*ax, const void*data, int64_t datasize) {
   return  AMBIX_ERR_UNKNOWN;
 }
diff --git a/libambix/src/private.h b/libambix/src/private.h
index a340c18..404aeb5 100644
--- a/libambix/src/private.h
+++ b/libambix/src/private.h
@@ -89,6 +89,15 @@ struct ambix_t_struct {
   /** ambisonics order of the full set */
   uint32_t ambisonics_order;
 
+  /** the number of stored markers */
+  uint32_t num_markers;
+  /** storage for markers */
+  ambix_marker_t *markers;
+  /** the number of stored regions */
+  uint32_t num_regions;
+  /** storage for regions */
+  ambix_region_t *regions;
+
   /** whether we already started reading samples */
   int startedReading;
   /** whether we already started writing samples */
@@ -143,6 +152,10 @@ struct SNDFILE_tag*_ambix_get_sndfile	(ambix_t*ambix);
  * @return number of sample frames successfully read
  */
 int64_t _ambix_readf_float32   (ambix_t*ambix, float32_t*data, int64_t frames);
+/** @see _ambix_readf_float64
+ * @remark this operates on 64bit float data (double)
+ */
+int64_t _ambix_readf_float64   (ambix_t*ambix, float64_t*data, int64_t frames);
 /** @see _ambix_readf_float32
  * @remark this operates on 32bit integer data
  */
@@ -160,6 +173,10 @@ int64_t _ambix_readf_int16   (ambix_t*ambix, int16_t*data, int64_t frames);
  */
 int64_t _ambix_writef_float32   (ambix_t*ambix, const float32_t*data, int64_t frames);
 /** @see _ambix_writef_float32
+ * @remark this operates on 64bit float data
+ */
+int64_t _ambix_writef_float64   (ambix_t*ambix, const float64_t*data, int64_t frames);
+/** @see _ambix_writef_float32
  * @remark this operates on 32bit integer data
  */
 int64_t _ambix_writef_int32   (ambix_t*ambix, const int32_t*data, int64_t frames);
@@ -209,6 +226,37 @@ uint64_t _ambix_matrix_to_uuid1(const ambix_matrix_t*matrix, void*data, int byte
  */
 ambix_err_t _ambix_write_uuidchunk(ambix_t*ax, const void*data, int64_t datasize);
 
+/** @brief read marker, region and corresponding strings chunk from file
+ * @param ambix valid ambix handle
+ * @return error code indicating success
+ */
+ambix_err_t _ambix_read_markersregions(ambix_t*ax);
+/** @brief write marker, region and corresponding strings chunk to file
+ * @param ambix valid ambix handle
+ * @return error code indicating success
+ */
+ambix_err_t _ambix_write_markersregions(ambix_t*ax);
+/** @brief write general chunk to file
+ * @param ambix valid ambix handle
+ * @param id four-character code identifying the chunk
+ * @param data pointer to memory holding the chunk
+ * @param datasize size of data
+ * @return error code indicating success
+ */
+ambix_err_t _ambix_write_chunk(ambix_t*ax, uint32_t id, const void*data, int64_t datasize);
+/** @brief read general chunk to file
+ * @param ambix valid ambix handle
+ * @param id four-character code identifying the chunk
+ * @param chunk_it try to get the chunk_it-th chunk with the specified id
+ * @param datasize returns size of data
+ * @return data pointer to memory holding the chunk
+ *
+ * @remark several chunks with the same id may exist in the file
+ * use chunk_it from 0...n for retrieving all existing chunks
+ *
+ * @remark in case of success the caller has to free the returned data! 
+ */
+void* _ambix_read_chunk(ambix_t*ax, uint32_t id, uint32_t chunk_it, int64_t *datasize);
 
 /** @brief Fill a matrix with byteswapped values
  *
@@ -221,6 +269,77 @@ ambix_err_t _ambix_write_uuidchunk(ambix_t*ax, const void*data, int64_t datasize
 ambix_err_t
 _ambix_matrix_fill_data_byteswapped(ambix_matrix_t*mtx, const number32_t*data);
 
+/** @brief Transpose a matrix
+ *
+ * swap rows/columns: a[i][j] -> a[j][i]
+ *
+ * @param matrix the matrix to transpose
+ * @param xirtam the result matrix (if NULL one will be allocated for you)
+ * @return a pointer to the result matrix (or NULL on failure)
+ */
+ambix_matrix_t*
+_ambix_matrix_transpose(const ambix_matrix_t*matrix, ambix_matrix_t*xirtam);
+/** @brief Multiply two matrices
+ *
+ * Multiply matrices dest=A*B, possibly resizing or creating the destination
+ * matrix.
+ *
+ * @param A left-hand operator
+ *
+ * @param B right-hand operator
+ *
+ * @param result pointer to the matrix object that will hold the result or NULL
+ *
+ * @return pointer to the result matrix, or NULL in case the matrix
+ * multiplication did not succeed.
+ *
+ * @remark If this returns a newly allocated matrix object (result!=return
+ * value), the host has to take care of calling ambix_matrix_destroy().
+ */
+ambix_matrix_t*
+_ambix_matrix_multiply (const ambix_matrix_t *A, const ambix_matrix_t *B, ambix_matrix_t *result) ;
+/** @brief Get the Moore-Penrose pseudoinverse of a matrix.
+ *
+ * Get the Moore-Penrose pseudoinverse of the matrix input and write the result
+ * to pinv
+ *
+ * @param matrix input matrix
+ *
+ * @param pinv pointer to the matrix object that will hold the result or NULL
+ *
+ * @return pointer to the result matrix, or NULL in case the matrix
+ * inversion did not succeed.
+ */
+ambix_matrix_t*
+_ambix_matrix_pinv(const ambix_matrix_t*matrix, ambix_matrix_t*pinv) ;
+
+/** @brief Invert a matrix using Gauss-Jordan
+ *
+ * Invert a square matrix using the Gauss-Jordan algorithm
+ *
+ * @param matrix the matrix to invert
+ * @param result the result matrix (if NULL one will be allocated for you)
+ * @param eps threshold to detect singularities
+ * @return a pointer to the result matrix (or NULL on failure)
+ *
+ * @note the input matrix will be modified!
+ */
+ambix_matrix_t*
+_ambix_matrix_invert_gaussjordan(ambix_matrix_t*matrix, ambix_matrix_t*result, float32_t eps);
+
+/** @brief Invert a matrix using Cholesky
+ *
+ * Invert a matrix using the Cholesky decomposition.
+ * If the matrix is non-square, this computes the pseuo-inverse.
+ *
+ * @param matrix the matrix to invert
+ * @param result the result matrix (if NULL one will be allocated for you)
+ * @param tolerance threshold for pivoting (scaled by the largest matrix values)
+ * @return a pointer to the result matrix (or NULL on failure)
+ *
+ */
+ambix_matrix_t*
+_ambix_matrix_pinvert_cholesky(const ambix_matrix_t*matrix, ambix_matrix_t*result, float32_t tolerance);
 
 /** @brief byte-swap 32bit data
  * @param n a 32bit chunk in the wrong byte order
@@ -231,11 +350,31 @@ static inline uint32_t swap4(uint32_t n)
   return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
           ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
 }
+/** @brief byte-swap 64bit data
+ * @param n a 64bit chunk in the wrong byte order
+ * @return byte-swapped data
+ */
+static inline uint64_t swap8(uint64_t n)
+{
+  return ((((n) & 0xff00000000000000ull) >> 56) |
+          (((n) & 0x00ff000000000000ull) >> 40) |
+          (((n) & 0x0000ff0000000000ull) >> 24) |
+          (((n) & 0x000000ff00000000ull) >> 8 ) |
+          (((n) & 0x00000000ff000000ull) << 8 ) |
+          (((n) & 0x0000000000ff0000ull) << 24) |
+          (((n) & 0x000000000000ff00ull) << 40) |
+          (((n) & 0x00000000000000ffull) << 56));
+}
 /** @brief byte-swap arrays of 32bit data
  * @param data a pointer to an array of 32bit data to be byteswapped
  * @param datasize the size of the array
  */
 void _ambix_swap4array(uint32_t*data, uint64_t datasize);
+/** @brief byte-swap arrays of 64bit data
+ * @param data a pointer to an array of 64bit data to be byteswapped
+ * @param datasize the size of the array
+ */
+void _ambix_swap8array(uint64_t*data, uint64_t datasize);
 
 /** @brief resize adaptor buffer to given size
  *
@@ -269,6 +408,10 @@ ambix_err_t _ambix_adaptorbuffer_destroy(ambix_t*ambix);
  * @return error code indicating success
  */
 ambix_err_t _ambix_splitAdaptor_float32(const float32_t*source, uint32_t sourcechannels, uint32_t ambichannels, float32_t*dest_ambi, float32_t*dest_other, int64_t frames);
+/** @brief extract ambisonics and non-ambisonics channels from interleaved (64bit float) data
+ * @see _ambix_splitAdaptor_float64
+ */
+ambix_err_t _ambix_splitAdaptor_float64(const float64_t*source, uint32_t sourcechannels, uint32_t ambichannels, float64_t*dest_ambi, float64_t*dest_other, int64_t frames);
 /** @brief extract ambisonics and non-ambisonics channels from interleaved (32bit signed integer) data
  * @see _ambix_splitAdapator_float32
  */
@@ -293,6 +436,8 @@ ambix_err_t _ambix_splitAdaptor_int16(const int16_t*source, uint32_t sourcechann
  */
 ambix_err_t _ambix_splitAdaptormatrix_float32(const float32_t*source, uint32_t sourcechannels, const ambix_matrix_t*matrix, float32_t*dest_ambi, float32_t*dest_other, int64_t frames);
 /* @see _ambix_splitAdaptormatrix_float32 */
+ambix_err_t _ambix_splitAdaptormatrix_float64(const float64_t*source, uint32_t sourcechannels, const ambix_matrix_t*matrix, float64_t*dest_ambi, float64_t*dest_other, int64_t frames);
+/* @see _ambix_splitAdaptormatrix_float32 */
 ambix_err_t _ambix_splitAdaptormatrix_int32(const int32_t*source, uint32_t sourcechannels, const ambix_matrix_t*matrix, int32_t*dest_ambi, int32_t*dest_other, int64_t frames);
 /* @see _ambix_splitAdaptormatrix_float32 */
 ambix_err_t _ambix_splitAdaptormatrix_int16(const int16_t*source, uint32_t sourcechannels, const ambix_matrix_t*matrix, int16_t*dest_ambi, int16_t*dest_other, int64_t frames);
@@ -311,6 +456,10 @@ ambix_err_t _ambix_splitAdaptormatrix_int16(const int16_t*source, uint32_t sourc
  * @return error code indicating success
  */
 ambix_err_t _ambix_mergeAdaptor_float32(const float32_t*source1, uint32_t source1channels, const float32_t*source2, uint32_t source2channels, float32_t*destination, int64_t frames);
+/** @brief merge two separate interleaved (64bit float) audio data blocks into one
+ * @see _ambix_mergeAdapator_float32
+ */
+ambix_err_t _ambix_mergeAdaptor_float64(const float64_t*source1, uint32_t source1channels, const float64_t*source2, uint32_t source2channels, float64_t*destination, int64_t frames);
 /** @brief merge two separate interleaved (32bit signed integer) audio data blocks into one
  * @see _ambix_mergeAdapator_float32
  */
@@ -321,6 +470,29 @@ ambix_err_t _ambix_mergeAdaptor_int32(const int32_t*source1, uint32_t source1cha
 ambix_err_t _ambix_mergeAdaptor_int16(const int16_t*source1, uint32_t source1channels, const int16_t*source2, uint32_t source2channels, int16_t*destination, int64_t frames);
 
 
+/** @brief merge interleaved ambisonics and interleaved non-ambisonics channels into a single interleaved audio data block using matrix operations
+ *
+ * multiply matrix.rows ambisonics channels with the matrix to get a (reduced) set of
+ * matrix.cols ambix-extended channels.
+ * append ambix-extended and non-ambisonics channels into one big interleaved chunk
+ *
+ * @param source1 the first interleaved samplebuffer (full ambisonics set) to read from
+ * @param matrix the encoder-matrix
+ * @param source2 the second interleaved samplebuffer to read from
+ * @param source2channels the number of channels in source2
+ * @param destination the samplebuffer to merge the data info; must be big enough to hold frames*(matrix.cols+source2channels) samples
+ * @param frames number of frames to extract
+ * @return error code indicating success
+ */
+ambix_err_t _ambix_mergeAdaptormatrix_float32(const float32_t*source1, const ambix_matrix_t*matrix, const float32_t*source2, uint32_t source2channels, float32_t*destination, int64_t frames);
+/* @see _ambix_mergeAdaptormatrix_float32 */
+ambix_err_t _ambix_mergeAdaptormatrix_float64(const float64_t*source1, const ambix_matrix_t*matrix, const float64_t*source2, uint32_t source2channels, float64_t*destination, int64_t frames);
+/* @see _ambix_mergeAdaptormatrix_float32 */
+ambix_err_t _ambix_mergeAdaptormatrix_int32(const int32_t*source1, const ambix_matrix_t*matrix, const int32_t*source2, uint32_t source2channels, int32_t*destination, int64_t frames);
+/* @see _ambix_mergeAdaptormatrix_float32 */
+ambix_err_t _ambix_mergeAdaptormatrix_int16(const int16_t*source1, const ambix_matrix_t*matrix, const int16_t*source2, uint32_t source2channels, int16_t*destination, int64_t frames);
+
+
 /** @brief debugging printout for ambix_info_t
  * @param info an ambixinfo struct
  */
@@ -351,7 +523,7 @@ ambix_matrix_t*_matrix_router(ambix_matrix_t*orgmatrix, const float32_t*route, u
  * @param permutate permutation vector (if(permutate[1]==4)then{row#1 of output matrix will be [0 0 0 0 1 0 ...]}; 
  *        the permutate vector must have matrix->rows elements (matrix->cols if swap is TRUE);
  *        negative permutation indices will skip the given row (if(permutate[3]=-1)then{row#3 will be [0 0 0 ...]};
- *        permutation indicies exceeding the valid range will restult in an error
+ *        permutation indices exceeding the valid range will restult in an error
  * @param transpose whether the result should be transposed (swapped rows and columns)
  * @return pointer to the resulting permutation matrix, or NULL in case something went wrong
  */
diff --git a/libambix/src/sndfile.c b/libambix/src/sndfile.c
index c0984ab..4448fc4 100644
--- a/libambix/src/sndfile.c
+++ b/libambix/src/sndfile.c
@@ -1,6 +1,6 @@
 /* sndfile.c -  libsndfile support              -*- c -*-
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -43,6 +43,9 @@
 # define snprintf _snprintf
 #endif /* _MSC_VER */
 
+//#define DEBUG_SFINFO
+
+
 typedef struct ambixsndfile_private_t {
   /** handle to the libsndfile object */
   SNDFILE*sf_file;
@@ -51,6 +54,9 @@ typedef struct ambixsndfile_private_t {
 #if defined HAVE_SF_CHUNK_INFO
   /** for writing uuid chunks */
   SF_CHUNK_INFO sf_chunk;
+  /** for writing other kind of chunks */
+  SF_CHUNK_INFO *sf_otherchunks;
+  uint32_t sf_numchunks;
 #elif defined HAVE_SF_UUID_INFO
 #endif
 }ambixsndfile_private_t;
@@ -64,6 +70,7 @@ sndfile2ambix_sampleformat(int sformat) {
   case(SF_FORMAT_PCM_24): return AMBIX_SAMPLEFORMAT_PCM24  ;
   case(SF_FORMAT_PCM_32): return AMBIX_SAMPLEFORMAT_PCM32  ;
   case(SF_FORMAT_FLOAT ): return AMBIX_SAMPLEFORMAT_FLOAT32;
+  case(SF_FORMAT_DOUBLE): return AMBIX_SAMPLEFORMAT_FLOAT64;
   }
   return AMBIX_SAMPLEFORMAT_NONE;
 }
@@ -75,10 +82,12 @@ ambix2sndfile_sampleformat(ambix_sampleformat_t asformat) {
   case(AMBIX_SAMPLEFORMAT_PCM24):   return SF_FORMAT_PCM_24;
   case(AMBIX_SAMPLEFORMAT_PCM32):   return SF_FORMAT_PCM_32;
   case(AMBIX_SAMPLEFORMAT_FLOAT32): return SF_FORMAT_FLOAT;
+  case(AMBIX_SAMPLEFORMAT_FLOAT64): return SF_FORMAT_DOUBLE;
   default:break;
   }
   return SF_FORMAT_PCM_24;
 }
+#ifdef DEBUG_SFINFO
 static void print_sfinfo(SF_INFO*info) {
   printf("SF_INFO %p\n", info);
   printf("  frames\t: %d\n", (int)(info->frames));
@@ -88,6 +97,7 @@ static void print_sfinfo(SF_INFO*info) {
   printf("  sections\t: %d\n", info->sections);
   printf("  seekable\t: %d\n", info->seekable);
 }
+#endif
 
 static void
 ambix2sndfile_info(const ambix_info_t*axinfo, SF_INFO *sfinfo) {
@@ -109,16 +119,16 @@ sndfile2ambix_info(const SF_INFO*sfinfo, ambix_info_t*axinfo) {
 static int
 read_uuidchunk(ambix_t*ax) {
 #if defined HAVE_SF_GET_CHUNK_ITERATOR && defined (HAVE_SF_CHUNK_INFO)
-	int				err ;
-	SF_CHUNK_INFO	chunk_info ;
+  int                           err ;
+  SF_CHUNK_INFO chunk_info ;
   SNDFILE*file=PRIVATE(ax)->sf_file;
   SF_CHUNK_ITERATOR *iterator;
   uint32_t chunkver=0;
 
   const char*id="uuid";
-	memset (&chunk_info, 0, sizeof (chunk_info)) ;
-	snprintf (chunk_info.id, sizeof (chunk_info.id), "%s", id) ;
-	chunk_info.id_size = 4 ;
+  memset (&chunk_info, 0, sizeof (chunk_info)) ;
+  snprintf (chunk_info.id, sizeof (chunk_info.id), "%s", id) ;
+  chunk_info.id_size = 4 ;
 
   for(iterator = sf_get_chunk_iterator (file, &chunk_info); NULL!=iterator; iterator=sf_next_chunk_iterator (iterator)) {
     if(chunk_info.data)
@@ -146,8 +156,7 @@ read_uuidchunk(ambix_t*ax) {
     chunkver=_ambix_checkUUID((const char*)chunk_info.data);
     if(1==chunkver) {
       if(_ambix_uuid1_to_matrix(((const char*)chunk_info.data+16), chunk_info.datalen-16, &ax->matrix, ax->byteswap)) {
-        if(chunk_info.data)
-          free(chunk_info.data) ;
+        free(chunk_info.data);
         return AMBIX_ERR_SUCCESS;
       }
     } else
@@ -159,17 +168,17 @@ read_uuidchunk(ambix_t*ax) {
   return AMBIX_ERR_UNKNOWN;
 
 #elif defined HAVE_SF_UUID_INFO
-		SF_UUID_INFO uuid;
-    SNDFILE*file=PRIVATE(ax)->sf_file;
-
-		memset(&uuid, 0, sizeof(uuid));
-		strncpy(uuid.id, _ambix_getUUID(1), 16);
-		if ( !sf_command(file, SFC_GET_UUID, &uuid, sizeof(uuid)) )	{
-			// extended
-      if(_ambix_uuid1_to_matrix(uuid.data, uuid.data_size, &ax->matrix, ax->byteswap)) {
-        return AMBIX_ERR_SUCCESS;
-      }
-		}
+  SF_UUID_INFO uuid;
+  SNDFILE*file=PRIVATE(ax)->sf_file;
+
+  memset(&uuid, 0, sizeof(uuid));
+  strncpy(uuid.id, _ambix_getUUID(1), 16);
+  if ( !sf_command(file, SFC_GET_UUID, &uuid, sizeof(uuid)) )   {
+    // extended
+    if(_ambix_uuid1_to_matrix(uuid.data, uuid.data_size, &ax->matrix, ax->byteswap)) {
+      return AMBIX_ERR_SUCCESS;
+    }
+  }
 #endif
   return AMBIX_ERR_UNKNOWN;
 }
@@ -177,7 +186,7 @@ read_uuidchunk(ambix_t*ax) {
 
 
 
-ambix_err_t _ambix_open	(ambix_t*ambix, const char *path, const ambix_filemode_t mode, const ambix_info_t*ambixinfo) {
+ambix_err_t _ambix_open (ambix_t*ambix, const char *path, const ambix_filemode_t mode, const ambix_info_t*ambixinfo) {
   int sfmode=0;
   int caf=0;
   int is_ambix=0;
@@ -186,11 +195,11 @@ ambix_err_t _ambix_open	(ambix_t*ambix, const char *path, const ambix_filemode_t
   ambix2sndfile_info(ambixinfo, &PRIVATE(ambix)->sf_info);
 
   if((mode & AMBIX_READ) && (mode & AMBIX_WRITE))
-    sfmode=	SFM_RDWR;
+    sfmode=     SFM_RDWR;
   else if (mode & AMBIX_WRITE)
-    sfmode=	SFM_WRITE;
+    sfmode=     SFM_WRITE;
   else if (mode & AMBIX_READ)
-    sfmode=	SFM_READ;
+    sfmode=     SFM_READ;
 
   PRIVATE(ambix)->sf_file=sf_open(path, sfmode, &PRIVATE(ambix)->sf_info) ;
   if(!PRIVATE(ambix)->sf_file)
@@ -278,14 +287,15 @@ ambix_err_t _ambix_open	(ambix_t*ambix, const char *path, const ambix_filemode_t
   }
 
   ambix->is_AMBIX=is_ambix;
-  if(0) {
+#ifdef DEBUG_SFINFO
     print_sfinfo( &PRIVATE(ambix)->sf_info);
-  }
+#endif
 
   return AMBIX_ERR_SUCCESS;
 }
 
-ambix_err_t	_ambix_close	(ambix_t*ambix) {
+ambix_err_t     _ambix_close    (ambix_t*ambix) {
+  int i;
   if(PRIVATE(ambix)->sf_file)
     sf_close(PRIVATE(ambix)->sf_file);
   PRIVATE(ambix)->sf_file=NULL;
@@ -293,6 +303,11 @@ ambix_err_t	_ambix_close	(ambix_t*ambix) {
 #if defined HAVE_SF_SET_CHUNK && defined (HAVE_SF_CHUNK_INFO)
   if((PRIVATE(ambix)->sf_chunk).data)
     free((PRIVATE(ambix)->sf_chunk).data);
+  for (i=0;i<PRIVATE(ambix)->sf_numchunks;i++) {
+    if (PRIVATE(ambix)->sf_otherchunks[i].data)
+      free(PRIVATE(ambix)->sf_otherchunks[i].data);
+  }
+  free(PRIVATE(ambix)->sf_otherchunks);
 #endif
 
   free(PRIVATE(ambix));
@@ -317,7 +332,7 @@ int64_t _ambix_seek (ambix_t* ambix, int64_t frames, int bias) {
   return -1;
 }
 
-SNDFILE*_ambix_get_sndfile	(ambix_t*ambix) {
+SNDFILE*_ambix_get_sndfile      (ambix_t*ambix) {
   return PRIVATE(ambix)->sf_file;
 }
 int64_t _ambix_readf_int16   (ambix_t*ambix, int16_t*data, int64_t frames) {
@@ -329,6 +344,9 @@ int64_t _ambix_readf_int32   (ambix_t*ambix, int32_t*data, int64_t frames) {
 int64_t _ambix_readf_float32   (ambix_t*ambix, float32_t*data, int64_t frames) {
   return (int64_t)sf_readf_float(PRIVATE(ambix)->sf_file, (float*)data, frames) ;
 }
+int64_t _ambix_readf_float64   (ambix_t*ambix, float64_t*data, int64_t frames) {
+  return (int64_t)sf_readf_double(PRIVATE(ambix)->sf_file, (double*)data, frames) ;
+}
 
 int64_t _ambix_writef_int16   (ambix_t*ambix, const int16_t*data, int64_t frames) {
   return (int64_t)sf_writef_short(PRIVATE(ambix)->sf_file, (short*)data, frames) ;
@@ -339,36 +357,121 @@ int64_t _ambix_writef_int32   (ambix_t*ambix, const int32_t*data, int64_t frames
 int64_t _ambix_writef_float32   (ambix_t*ambix, const float32_t*data, int64_t frames) {
   return (int64_t)sf_writef_float(PRIVATE(ambix)->sf_file, (float*)data, frames) ;
 }
+int64_t _ambix_writef_float64   (ambix_t*ambix, const float64_t*data, int64_t frames) {
+  return (int64_t)sf_writef_double(PRIVATE(ambix)->sf_file, (double*)data, frames) ;
+}
 ambix_err_t _ambix_write_uuidchunk(ambix_t*ax, const void*data, int64_t datasize) {
 #if defined HAVE_SF_SET_CHUNK && defined (HAVE_SF_CHUNK_INFO)
-	int				err ;
+  int                           err ;
   SF_CHUNK_INFO*chunk=&PRIVATE(ax)->sf_chunk;
   int64_t datasize4 = datasize>>2;
 
   if(datasize4*4 < datasize)
     datasize4++;
-	memset (chunk, 0, sizeof (*chunk)) ;
-	snprintf (chunk->id, sizeof (chunk->id), "uuid") ;
-	chunk->id_size = 4 ;
+  memset (chunk, 0, sizeof (*chunk)) ;
+  snprintf (chunk->id, sizeof (chunk->id), "uuid") ;
+  chunk->id_size = 4 ;
   if(chunk->data)
     free(chunk->data);
 
-	chunk->data = calloc(datasize4, 4);
+  chunk->data = calloc(datasize4, 4);
 
   memcpy(chunk->data, data, datasize);
-	chunk->datalen = datasize ;
-	err = sf_set_chunk (PRIVATE(ax)->sf_file, chunk) ;
+  chunk->datalen = datasize ;
+  err = sf_set_chunk (PRIVATE(ax)->sf_file, chunk) ;
   if(SF_ERR_NO_ERROR != err)
     return AMBIX_ERR_UNKNOWN;
   return AMBIX_ERR_SUCCESS;
 #elif defined HAVE_SF_UUID_INFO
-		SF_UUID_INFO uuid;
-    memcpy(uuid.id, data, 16);
-		uuid.data=(void*)(data+16);
-		uuid.data_size=datasize-16;
-		if(!sf_command(PRIVATE(ax)->sf_file, SFC_SET_UUID, &uuid, sizeof(uuid))) {
-      return  AMBIX_ERR_SUCCESS;
-    }
+  SF_UUID_INFO uuid;
+  memcpy(uuid.id, data, 16);
+  uuid.data=(void*)(data+16);
+  uuid.data_size=datasize-16;
+  if(!sf_command(PRIVATE(ax)->sf_file, SFC_SET_UUID, &uuid, sizeof(uuid))) {
+    return  AMBIX_ERR_SUCCESS;
+  }
+#endif
+  return  AMBIX_ERR_UNKNOWN;
+}
+ambix_err_t _ambix_write_chunk(ambix_t*ax, uint32_t id, const void*data, int64_t datasize) {
+#if defined (HAVE_SF_SET_CHUNK)
+  int err ;
+  int64_t datasize4 = datasize>>2;
+
+  SF_CHUNK_INFO *chunks = NULL;
+  SF_CHUNK_INFO *chunk  = NULL;
+  unsigned int numchunks=(PRIVATE(ax)->sf_numchunks);
+
+  if(datasize4*4 < datasize)
+    datasize4++;
+
+  /* (re-)allocate memory for the new chunk - data has to be kept until file closes! */
+  if (0 == numchunks) {
+    chunks = (SF_CHUNK_INFO*)calloc(1, sizeof(*chunks));
+  } else {
+    chunks = (SF_CHUNK_INFO*)realloc(PRIVATE(ax)->sf_otherchunks, (numchunks+1)*sizeof(*chunks));
+  }
+  if (NULL == chunks)
+    return AMBIX_ERR_UNKNOWN;
+  chunk = chunks + numchunks;
+  memset (chunk, 0, sizeof (*chunk)) ;
+
+  //snprintf (chunk->id, 4, id) ;
+  memcpy(chunk->id, &id, 4);
+  chunk->id_size = 4 ;
+  if(chunk->data)
+    free(chunk->data);
+
+  chunk->data = calloc(datasize4, 4);
+
+  memcpy(chunk->data, data, datasize);
+  chunk->datalen = datasize ;
+  err = sf_set_chunk (PRIVATE(ax)->sf_file, chunk);
+
+  PRIVATE(ax)->sf_numchunks += 1;
+  PRIVATE(ax)->sf_otherchunks = chunks;
+
+  if(SF_ERR_NO_ERROR != err)
+    return AMBIX_ERR_UNKNOWN;
+  return AMBIX_ERR_SUCCESS;
 #endif
   return  AMBIX_ERR_UNKNOWN;
 }
+void* _ambix_read_chunk(ambix_t*ax, uint32_t id, uint32_t chunk_it, int64_t *datasize) {
+#if defined HAVE_SF_GET_CHUNK_ITERATOR
+  int err;
+  SF_CHUNK_INFO	chunk_info;
+  SF_CHUNK_ITERATOR * iterator;
+  int i;
+  memset (&chunk_info, 0, sizeof (chunk_info));
+  memcpy(chunk_info.id, &id, 4);
+  chunk_info.id_size = 4;
+  iterator = sf_get_chunk_iterator (PRIVATE(ax)->sf_file, &chunk_info);
+  if (!iterator) {
+    *datasize = 0;
+    return NULL;
+  }
+  // jump to wanted iterator
+  for (i=0; i<chunk_it; i++) {
+    iterator = sf_next_chunk_iterator (iterator) ;
+    if (!iterator) {
+      *datasize = 0;
+      return NULL;
+    }
+  }
+  memset (&chunk_info, 0, sizeof (chunk_info));
+  err = sf_get_chunk_size (iterator, &chunk_info);
+  if (!chunk_info.datalen) {
+    *datasize = 0;
+    return NULL;
+  }
+  chunk_info.data = malloc (chunk_info.datalen); // has to be freed later by the caller!
+  err = sf_get_chunk_data (iterator, &chunk_info);
+
+  // free (chunk_info.data);
+  *datasize = chunk_info.datalen;
+  return chunk_info.data;
+#endif
+  *datasize = 0;
+  return NULL;
+}
diff --git a/libambix/src/utils.c b/libambix/src/utils.c
index 891306a..c7a5fad 100644
--- a/libambix/src/utils.c
+++ b/libambix/src/utils.c
@@ -73,6 +73,25 @@ void _ambix_print_matrix(const ambix_matrix_t*mtx) {
 
 }
 
+void _ambix_print_markers(const ambix_t*ambix)
+{
+  if (ambix->markers) {
+    int i;
+    for (i=0; i < ambix->num_markers; i++) {
+      printf("    marker %d: name: %s position: %f \n", i, ambix->markers[i].name, ambix->markers[i].position);
+    }
+  }
+}
+void _ambix_print_regions(const ambix_t*ambix)
+{
+  if (ambix->regions) {
+    int i;
+    for (i=0; i < ambix->num_regions; i++) {
+      printf("    region %d: name: %s start_position: %f end_position: %f \n", i, ambix->regions[i].name, ambix->regions[i].start_position, ambix->regions[i].end_position);
+    }
+  }
+}
+
 void _ambix_print_ambix(const ambix_t*ambix) {
   printf("AMBIX %p\n", ambix);
   if(!ambix)return;
@@ -95,6 +114,10 @@ void _ambix_print_ambix(const ambix_t*ambix) {
   printf("  adaptorbuffer\t: %p\n", ambix->adaptorbuffer);
   printf("  adaptorbuffersize\t: %d\n", (int)(ambix->adaptorbuffersize));
   printf("  ambisonics_order\t: %d\n", ambix->ambisonics_order);
+  printf("  num_markers\t: %d\n", ambix->num_markers);
+  _ambix_print_markers(ambix);
+  printf("  num_regions\t: %d\n", ambix->num_regions);
+  _ambix_print_regions(ambix);
   printf("  startedReading\t: %d\n", ambix->startedReading);
   printf("  startedWriting\t: %d\n", ambix->startedWriting);
 }
@@ -107,3 +130,10 @@ void _ambix_swap4array(uint32_t*data, uint64_t datasize) {
     *data++=swap4(v);
   }
 }
+void _ambix_swap8array(uint64_t*data, uint64_t datasize) {
+  uint64_t i;
+  for(i=0; i<datasize; i++) {
+    uint64_t v=*data;
+    *data++=swap8(v);
+  }
+}
diff --git a/libambix/src/uuid_chunk.c b/libambix/src/uuid_chunk.c
index d85d76f..8fef5f2 100644
--- a/libambix/src/uuid_chunk.c
+++ b/libambix/src/uuid_chunk.c
@@ -1,6 +1,6 @@
 /* uuid_chunk.c -  parse an UUID-chunk to extract relevant data              -*- c -*-
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -48,30 +48,33 @@
  */
 
 #include <stdio.h>
-static void _ambix_printUUID4(const char data[2]) {
- printf("%02x%02x", (signed char)data[0], (signed char)data[1]);
 
+#if 0
+static void _ambix_printUUID4(const char data[2]) {
+  unsigned char data0=data[0];
+  unsigned char data1=data[1];
+  printf("%02x%02x", data0, data1);
 }
 static void _ambix_printUUID(const char data[16]) {
- /* 8-4-4-4-12 */
- _ambix_printUUID4(data);data+=2;
- _ambix_printUUID4(data);data+=2;
+  /* 8-4-4-4-12 */
+  _ambix_printUUID4(data);data+=2;
+  _ambix_printUUID4(data);data+=2;
   printf("-");
- _ambix_printUUID4(data);data+=2;
+  _ambix_printUUID4(data);data+=2;
   printf("-");
- _ambix_printUUID4(data);data+=2;
+  _ambix_printUUID4(data);data+=2;
   printf("-");
- _ambix_printUUID4(data);data+=2;
+  _ambix_printUUID4(data);data+=2;
   printf("-");
- _ambix_printUUID4(data);data+=2;
- _ambix_printUUID4(data);data+=2;
- _ambix_printUUID4(data);data+=2;
+  _ambix_printUUID4(data);data+=2;
+  _ambix_printUUID4(data);data+=2;
+  _ambix_printUUID4(data);data+=2;
 }
-
- /*
-  * uarg, this is not a UUID!
-  * (well it is...UUID::Tiny thinks it's a v2 (DCE security) UUID
-  */
+#endif
+/*
+ * uarg, this is not a UUID!
+ * (well it is...UUID::Tiny thinks it's a v2 (DCE security) UUID
+ */
 static const char _ambix_uuid_v1_[]="IEM.AT/AMBIX/XML";
 /*
  * that's a better UUID, based on a SHA1-hash of "http://ambisonics.iem.at/xchange/format/1.0"
@@ -138,7 +141,7 @@ _ambix_uuid1_to_matrix(const void*vdata, uint64_t datasize, ambix_matrix_t*orgmt
   }
 
   if(!ambix_matrix_init(rows, cols, mtx))
-      goto cleanup;
+    goto cleanup;
 
   if(swap) {
     if(_ambix_matrix_fill_data_byteswapped(mtx, (number32_t*)(cdata+index)) != AMBIX_ERR_SUCCESS)
diff --git a/libambix/tests/Makefile.am b/libambix/tests/Makefile.am
index 589fd2c..2712dc4 100644
--- a/libambix/tests/Makefile.am
+++ b/libambix/tests/Makefile.am
@@ -1,81 +1,225 @@
-AUTOMAKE_OPTIONS = foreign serial-tests
+#AUTOMAKE_OPTIONS = foreign serial-tests
+AUTOMAKE_OPTIONS = foreign
+SUBDIRS=data
 
 #TESTS_ENVIRONMENT = RUNTESTS_NOLOG=yes TESTDIR=$(srcdir)
-AM_TESTS_ENVIRONMENT = TESTDIR=$(srcdir) ./runtest.sh
+#AM_TESTS_ENVIRONMENT = TESTDIR=$(srcdir) ./runtest.sh
+
+ at VALGRIND_CHECK_RULES@
 
 AM_CPPFLAGS = -I$(top_srcdir)/libambix
+if DEBUG
+AM_CPPFLAGS += -I$(top_srcdir)/libambix/src -DAMBIX_INTERNAL
+endif
 LDADD = $(top_builddir)/libambix/src/libambix.la
 
+check_PROGRAMS =
 TESTS = \
 	pass skip fail
 
 XFAIL_TESTS = fail
 
-check_PROGRAMS= \
-	pass skip fail
-
-SOURCES=common.c common.h
-noinst_HEADERS = common.h 
+SOURCES=common.c common.h data.h common_basic2extended.h
+noinst_HEADERS = common.h data.h common_basic2extended.h
 
 pass_SOURCES=pass.c
 skip_SOURCES=skip.c
 fail_SOURCES=fail.c
 
+TESTS += pass_if0 pass_if1 skip_if0 skip_if1 fail_if0 fail_if1
+XFAIL_TESTS += fail_if1
+pass_if0_SOURCES=pass_if0.c
+pass_if1_SOURCES=pass_if1.c
+skip_if0_SOURCES=skip_if0.c
+skip_if1_SOURCES=skip_if1.c
+fail_if0_SOURCES=fail_if0.c
+fail_if1_SOURCES=fail_if1.c
+
+
+TESTS += datatest
+datatest_SOURCES = datatest.c common.c
+
 TESTS += matrix
-check_PROGRAMS += matrix
-matrix_SOURCES = matrix.c common.c
+matrix_SOURCES = matrixtests.c common.c
 
 TESTS += matrices
-check_PROGRAMS += matrices
 matrices_SOURCES = matrices.c common.c
 
+TESTS += const_matrix
+const_matrix_SOURCES = const_matrix.c common.c
+
+if DEBUG
+TESTS += debug_utils
+debug_utils_SOURCES = debug_utils.c common.c
+endif
+
+TESTS          += markers_regions
+markers_regions_SOURCES = markers_regions.c common.c
+
 TESTS          += none_float32
-check_PROGRAMS += none_float32
-none_float32_SOURCES = none_float32.c ambix_none.c common.c
-
-TESTS          += simple_float32 simple_pcm32 simple_pcm16
-check_PROGRAMS += simple_float32 simple_pcm32 simple_pcm16
-simple_float32_SOURCES = simple_float32.c ambix_simple.c common.c
-simple_pcm32_SOURCES = simple_pcm32.c ambix_simple.c common.c
-simple_pcm16_SOURCES = simple_pcm16.c ambix_simple.c common.c
-
-TESTS          += extended_float32_0 extended_pcm32_0 extended_pcm16_0
-check_PROGRAMS += extended_float32_0 extended_pcm32_0 extended_pcm16_0
-extended_float32_0_SOURCES = extended_float32_0.c ambix_extended.c common.c
-extended_pcm32_0_SOURCES   = extended_pcm32_0.c ambix_extended.c common.c
-extended_pcm16_0_SOURCES   = extended_pcm16_0.c ambix_extended.c common.c
-
-TESTS          += extended_float32_1024 extended_pcm32_1024 extended_pcm16_1024
-check_PROGRAMS += extended_float32_1024 extended_pcm32_1024 extended_pcm16_1024
-extended_float32_1024_SOURCES = extended_float32_1024.c ambix_extended.c common.c
-extended_pcm32_1024_SOURCES   = extended_pcm32_1024.c ambix_extended.c common.c
-extended_pcm16_1024_SOURCES   = extended_pcm16_1024.c ambix_extended.c common.c
+none_float32_SOURCES = none_float32.c common_none.c common.c
+TESTS          += none_float64
+none_float64_SOURCES = none_float64.c common_none.c common.c
+
+TESTS          += basic_float32 basic_float64 basic_pcm32 basic_pcm16
+basic_float32_SOURCES = basic_float32.c common_basic.c common.c
+basic_float64_SOURCES = basic_float64.c common_basic.c common.c
+basic_pcm32_SOURCES = basic_pcm32.c common_basic.c common.c
+basic_pcm16_SOURCES = basic_pcm16.c common_basic.c common.c
+
+TESTS          += extended_float32_0 extended_float64_0 extended_pcm32_0 extended_pcm16_0
+extended_float32_0_SOURCES = extended_float32_0.c common_extended.c common.c
+extended_float64_0_SOURCES = extended_float64_0.c common_extended.c common.c
+extended_pcm32_0_SOURCES   = extended_pcm32_0.c common_extended.c common.c
+extended_pcm16_0_SOURCES   = extended_pcm16_0.c common_extended.c common.c
+
+TESTS          += extended_float32_1024 extended_float64_1024 extended_pcm32_1024 extended_pcm16_1024
+extended_float32_1024_SOURCES = extended_float32_1024.c common_extended.c common.c
+extended_float64_1024_SOURCES = extended_float64_1024.c common_extended.c common.c
+extended_pcm32_1024_SOURCES   = extended_pcm32_1024.c common_extended.c common.c
+extended_pcm16_1024_SOURCES   = extended_pcm16_1024.c common_extended.c common.c
 
 TESTS += ambix_open
-check_PROGRAMS += ambix_open
 ambix_open_SOURCES = ambix_open.c
 
-
 TESTS += ambix_close
-check_PROGRAMS += ambix_close
 ambix_close_SOURCES = ambix_close.c
 
+TESTS += ambix_get_sndfile
+ambix_get_sndfile_SOURCES = ambix_get_sndfile.c
+
 TESTS += ambix_seek
-check_PROGRAMS += ambix_seek
 ambix_seek_SOURCES = ambix_seek.c
 
 TESTS += ambix_seek_read
-check_PROGRAMS += ambix_seek_read
 ambix_seek_read_SOURCES = ambix_seek_read.c
 
 TESTS += ambix_readf_int16
-check_PROGRAMS += ambix_readf_int16
 ambix_readf_int16_SOURCES = ambix_readf_int16.c
 
 TESTS += ambix_writef_int16
-check_PROGRAMS += ambix_writef_int16
 ambix_writef_int16_SOURCES = ambix_writef_int16.c
 
+common_b2x=common_basic2extended.c common.c
+## float32
+TESTS          += \
+	basic2extended_identity4x4_float32 \
+	basic2extended_N3D4x4_float32 \
+	basic2extended_SID4x4_float32 \
+	basic2extended_FUMA4x4_float32 \
+	basic2extended_rand4x9_float32 \
+	basic2extended_rand4x7_float32 \
+	basic2extended_identity4x4_3extra_float32 \
+	basic2extended_N3D4x4_3extra_float32 \
+	basic2extended_SID4x4_3extra_float32 \
+	basic2extended_FUMA4x4_3extra_float32 \
+	basic2extended_rand4x9_3extra_float32 \
+	basic2extended_rand4x7_3extra_float32
+basic2extended_identity4x4_float32_SOURCES = basic2extended_identity4x4_float32.c $(common_b2x)
+basic2extended_N3D4x4_float32_SOURCES = basic2extended_N3D4x4_float32.c $(common_b2x)
+basic2extended_SID4x4_float32_SOURCES = basic2extended_SID4x4_float32.c $(common_b2x)
+basic2extended_FUMA4x4_float32_SOURCES = basic2extended_FUMA4x4_float32.c $(common_b2x)
+basic2extended_rand4x9_float32_SOURCES = basic2extended_rand4x9_float32.c $(common_b2x)
+basic2extended_rand4x7_float32_SOURCES = basic2extended_rand4x7_float32.c $(common_b2x)
+basic2extended_identity4x4_3extra_float32_SOURCES = basic2extended_identity4x4_3extra_float32.c $(common_b2x)
+basic2extended_N3D4x4_3extra_float32_SOURCES = basic2extended_N3D4x4_3extra_float32.c $(common_b2x)
+basic2extended_SID4x4_3extra_float32_SOURCES = basic2extended_SID4x4_3extra_float32.c $(common_b2x)
+basic2extended_FUMA4x4_3extra_float32_SOURCES = basic2extended_FUMA4x4_3extra_float32.c $(common_b2x)
+basic2extended_rand4x9_3extra_float32_SOURCES = basic2extended_rand4x9_3extra_float32.c $(common_b2x)
+basic2extended_rand4x7_3extra_float32_SOURCES = basic2extended_rand4x7_3extra_float32.c $(common_b2x)
+
+TESTS          += \
+	basic2extended_identity4x4_float32__f64 \
+	basic2extended_identity4x4_float32__i16 \
+	basic2extended_identity4x4_float32__i32
+basic2extended_identity4x4_float32__f64_SOURCES = basic2extended_identity4x4_float32__f64.c $(common_b2x)
+basic2extended_identity4x4_float32__i16_SOURCES = basic2extended_identity4x4_float32__i16.c $(common_b2x)
+basic2extended_identity4x4_float32__i32_SOURCES = basic2extended_identity4x4_float32__i32.c $(common_b2x)
+
+## float64
+TESTS          += \
+	basic2extended_identity4x4_float64 \
+	basic2extended_N3D4x4_float64 \
+	basic2extended_SID4x4_float64 \
+	basic2extended_FUMA4x4_float64 \
+	basic2extended_rand4x9_float64 \
+	basic2extended_rand4x7_float64 \
+	basic2extended_identity4x4_3extra_float64 \
+	basic2extended_N3D4x4_3extra_float64 \
+	basic2extended_SID4x4_3extra_float64 \
+	basic2extended_FUMA4x4_3extra_float64 \
+	basic2extended_rand4x9_3extra_float64 \
+	basic2extended_rand4x7_3extra_float64
+basic2extended_identity4x4_float64_SOURCES = basic2extended_identity4x4_float64.c $(common_b2x)
+basic2extended_N3D4x4_float64_SOURCES = basic2extended_N3D4x4_float64.c $(common_b2x)
+basic2extended_SID4x4_float64_SOURCES = basic2extended_SID4x4_float64.c $(common_b2x)
+basic2extended_FUMA4x4_float64_SOURCES = basic2extended_FUMA4x4_float64.c $(common_b2x)
+basic2extended_rand4x9_float64_SOURCES = basic2extended_rand4x9_float64.c $(common_b2x)
+basic2extended_rand4x7_float64_SOURCES = basic2extended_rand4x7_float64.c $(common_b2x)
+basic2extended_identity4x4_3extra_float64_SOURCES = basic2extended_identity4x4_3extra_float64.c $(common_b2x)
+basic2extended_N3D4x4_3extra_float64_SOURCES = basic2extended_N3D4x4_3extra_float64.c $(common_b2x)
+basic2extended_SID4x4_3extra_float64_SOURCES = basic2extended_SID4x4_3extra_float64.c $(common_b2x)
+basic2extended_FUMA4x4_3extra_float64_SOURCES = basic2extended_FUMA4x4_3extra_float64.c $(common_b2x)
+basic2extended_rand4x9_3extra_float64_SOURCES = basic2extended_rand4x9_3extra_float64.c $(common_b2x)
+basic2extended_rand4x7_3extra_float64_SOURCES = basic2extended_rand4x7_3extra_float64.c $(common_b2x)
+
+## pcm32
+TESTS          += \
+	basic2extended_identity4x4_pcm32 \
+	basic2extended_N3D4x4_pcm32 \
+	basic2extended_SID4x4_pcm32 \
+	basic2extended_FUMA4x4_pcm32 \
+	basic2extended_rand4x9_pcm32 \
+	basic2extended_rand4x7_pcm32 \
+	basic2extended_identity4x4_3extra_pcm32 \
+	basic2extended_N3D4x4_3extra_pcm32 \
+	basic2extended_SID4x4_3extra_pcm32 \
+	basic2extended_FUMA4x4_3extra_pcm32 \
+	basic2extended_rand4x9_3extra_pcm32 \
+	basic2extended_rand4x7_3extra_pcm32
+basic2extended_identity4x4_pcm32_SOURCES = basic2extended_identity4x4_pcm32.c $(common_b2x)
+basic2extended_N3D4x4_pcm32_SOURCES = basic2extended_N3D4x4_pcm32.c $(common_b2x)
+basic2extended_SID4x4_pcm32_SOURCES = basic2extended_SID4x4_pcm32.c $(common_b2x)
+basic2extended_FUMA4x4_pcm32_SOURCES = basic2extended_FUMA4x4_pcm32.c $(common_b2x)
+basic2extended_rand4x9_pcm32_SOURCES = basic2extended_rand4x9_pcm32.c $(common_b2x)
+basic2extended_rand4x7_pcm32_SOURCES = basic2extended_rand4x7_pcm32.c $(common_b2x)
+basic2extended_identity4x4_3extra_pcm32_SOURCES = basic2extended_identity4x4_3extra_pcm32.c $(common_b2x)
+basic2extended_N3D4x4_3extra_pcm32_SOURCES = basic2extended_N3D4x4_3extra_pcm32.c $(common_b2x)
+basic2extended_SID4x4_3extra_pcm32_SOURCES = basic2extended_SID4x4_3extra_pcm32.c $(common_b2x)
+basic2extended_FUMA4x4_3extra_pcm32_SOURCES = basic2extended_FUMA4x4_3extra_pcm32.c $(common_b2x)
+basic2extended_rand4x9_3extra_pcm32_SOURCES = basic2extended_rand4x9_3extra_pcm32.c $(common_b2x)
+basic2extended_rand4x7_3extra_pcm32_SOURCES = basic2extended_rand4x7_3extra_pcm32.c $(common_b2x)
+
+## pcm16
+TESTS          += \
+	basic2extended_identity4x4_pcm16 \
+	basic2extended_N3D4x4_pcm16 \
+	basic2extended_SID4x4_pcm16 \
+	basic2extended_FUMA4x4_pcm16 \
+	basic2extended_rand4x9_pcm16 \
+	basic2extended_rand4x7_pcm16 \
+	basic2extended_identity4x4_3extra_pcm16 \
+	basic2extended_N3D4x4_3extra_pcm16 \
+	basic2extended_SID4x4_3extra_pcm16 \
+	basic2extended_FUMA4x4_3extra_pcm16 \
+	basic2extended_rand4x9_3extra_pcm16 \
+	basic2extended_rand4x7_3extra_pcm16
+basic2extended_identity4x4_pcm16_SOURCES = basic2extended_identity4x4_pcm16.c $(common_b2x)
+basic2extended_N3D4x4_pcm16_SOURCES = basic2extended_N3D4x4_pcm16.c $(common_b2x)
+basic2extended_SID4x4_pcm16_SOURCES = basic2extended_SID4x4_pcm16.c $(common_b2x)
+basic2extended_FUMA4x4_pcm16_SOURCES = basic2extended_FUMA4x4_pcm16.c $(common_b2x)
+basic2extended_rand4x9_pcm16_SOURCES = basic2extended_rand4x9_pcm16.c $(common_b2x)
+basic2extended_rand4x7_pcm16_SOURCES = basic2extended_rand4x7_pcm16.c $(common_b2x)
+basic2extended_identity4x4_3extra_pcm16_SOURCES = basic2extended_identity4x4_3extra_pcm16.c $(common_b2x)
+basic2extended_N3D4x4_3extra_pcm16_SOURCES = basic2extended_N3D4x4_3extra_pcm16.c $(common_b2x)
+basic2extended_SID4x4_3extra_pcm16_SOURCES = basic2extended_SID4x4_3extra_pcm16.c $(common_b2x)
+basic2extended_FUMA4x4_3extra_pcm16_SOURCES = basic2extended_FUMA4x4_3extra_pcm16.c $(common_b2x)
+basic2extended_rand4x9_3extra_pcm16_SOURCES = basic2extended_rand4x9_3extra_pcm16.c $(common_b2x)
+basic2extended_rand4x7_3extra_pcm16_SOURCES = basic2extended_rand4x7_3extra_pcm16.c $(common_b2x)
+
+
+# ##################################################
+check_PROGRAMS += $(TESTS)
 
 .PHONY: buildtests
 buildtests: $(check_PROGRAMS)
diff --git a/libambix/tests/ambix_get_sndfile.c b/libambix/tests/ambix_get_sndfile.c
new file mode 100644
index 0000000..8872f97
--- /dev/null
+++ b/libambix/tests/ambix_get_sndfile.c
@@ -0,0 +1,26 @@
+#include "common.h"
+#include "data.h"
+
+int main()
+{
+  ambix_t*ambix = NULL;
+  struct SNDFILE_tag *sndfile = NULL;
+  ambix_info_t *info= calloc(1, sizeof(ambix_info_t));
+
+  ambix=ambix_open(AMBIXTEST_FILE1, AMBIX_READ, info);
+
+  fail_if(NULL==ambix, __LINE__, "File was not open");
+  sndfile = ambix_get_sndfile (ambix);
+
+#ifdef HAVE_SNDFILE
+#warning LATER: skip, once we have multiple (working) backends
+  /* there is no need to use libsndfile even if libsndfile is present */
+  fail_if(NULL==sndfile, __LINE__, "no sndfile handle despite using libsndfile");
+#else
+  fail_if(NULL!=sndfile, __LINE__, "got sndfile handle without libsndfile!");
+#endif
+
+  ambix_close (ambix);
+  free(info);
+  return 0;
+}
diff --git a/libambix/tests/ambix_readf_int16.c b/libambix/tests/ambix_readf_int16.c
index 4e5c5eb..520768f 100644
--- a/libambix/tests/ambix_readf_int16.c
+++ b/libambix/tests/ambix_readf_int16.c
@@ -2,6 +2,6 @@
 
 int main ()
 {
-  pass();
-  return 0;
+  /* FIXXME: no test yet */
+  return skip();
 }
diff --git a/libambix/tests/ambix_seek_read.c b/libambix/tests/ambix_seek_read.c
index 9c6dc1b..3e23a50 100644
--- a/libambix/tests/ambix_seek_read.c
+++ b/libambix/tests/ambix_seek_read.c
@@ -16,8 +16,6 @@ int main()
   //ambix_readf_int32 (ambix_t *ambix, int32_t *ambidata, int32_t *otherdata, int64_t frames)
   //Read samples (as 32bit signed integer values) from the ambix file. 
   
-  pass();
-  
   
   //UNCOMMENT WHEN FIXED
   /*cmp= ambix_readf_int32(ambix, *ambidata, otherdata, 100);
@@ -32,7 +30,8 @@ int main()
   fail_if (result!=100, __LINE__, "File failed to seek correct data");*/
   
   ambix_close(ambix);
-  
   free(info);
-  return 0;
+
+  /* FIXXXME: this test is not working yet */
+  return skip();
 }
diff --git a/libambix/tests/ambix_writef_int16.c b/libambix/tests/ambix_writef_int16.c
index af9edbc..00f2f53 100644
--- a/libambix/tests/ambix_writef_int16.c
+++ b/libambix/tests/ambix_writef_int16.c
@@ -26,5 +26,7 @@ int main ()
   
   ambix_close(ambix);
   free(info);
-  return 0;
+
+  /* FIXXME: no test yet */
+  return skip();
 }
diff --git a/libambix/tests/basic2extended_FUMA4x4_3extra_float32.c b/libambix/tests/basic2extended_FUMA4x4_3extra_float32.c
new file mode 100644
index 0000000..83707dd
--- /dev/null
+++ b/libambix/tests/basic2extended_FUMA4x4_3extra_float32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("FuMa[f]" , 4, 4, AMBIX_MATRIX_FUMA    , 3, 1024, 6e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_FUMA4x4_3extra_float64.c b/libambix/tests/basic2extended_FUMA4x4_3extra_float64.c
new file mode 100644
index 0000000..74eb42f
--- /dev/null
+++ b/libambix/tests/basic2extended_FUMA4x4_3extra_float64.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("FuMa[f]" , 4, 4, AMBIX_MATRIX_FUMA    , 3, 1024, 6e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_FUMA4x4_3extra_pcm16.c b/libambix/tests/basic2extended_FUMA4x4_3extra_pcm16.c
new file mode 100644
index 0000000..e502fd8
--- /dev/null
+++ b/libambix/tests/basic2extended_FUMA4x4_3extra_pcm16.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("FuMa[f]" , 4, 4, AMBIX_MATRIX_FUMA    , 3, 1024, 4e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_FUMA4x4_3extra_pcm32.c b/libambix/tests/basic2extended_FUMA4x4_3extra_pcm32.c
new file mode 100644
index 0000000..6e9dad8
--- /dev/null
+++ b/libambix/tests/basic2extended_FUMA4x4_3extra_pcm32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("FuMa[f]" , 4, 4, AMBIX_MATRIX_FUMA    , 3, 1024, 6e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_FUMA4x4_float32.c b/libambix/tests/basic2extended_FUMA4x4_float32.c
new file mode 100644
index 0000000..52a8bf6
--- /dev/null
+++ b/libambix/tests/basic2extended_FUMA4x4_float32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("FuMa[f]" , 4, 4, AMBIX_MATRIX_FUMA    , 0, 1024, 6e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_FUMA4x4_float64.c b/libambix/tests/basic2extended_FUMA4x4_float64.c
new file mode 100644
index 0000000..ca9240b
--- /dev/null
+++ b/libambix/tests/basic2extended_FUMA4x4_float64.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("FuMa[f]" , 4, 4, AMBIX_MATRIX_FUMA    , 0, 1024, 6e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_FUMA4x4_pcm16.c b/libambix/tests/basic2extended_FUMA4x4_pcm16.c
new file mode 100644
index 0000000..aa91c1b
--- /dev/null
+++ b/libambix/tests/basic2extended_FUMA4x4_pcm16.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("FuMa[f]" , 5, 4, AMBIX_MATRIX_FUMA    , 0, 1024, 4e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_FUMA4x4_pcm32.c b/libambix/tests/basic2extended_FUMA4x4_pcm32.c
new file mode 100644
index 0000000..68cc048
--- /dev/null
+++ b/libambix/tests/basic2extended_FUMA4x4_pcm32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("FuMa[f]" , 4, 4, AMBIX_MATRIX_FUMA    , 0, 1024, 6e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_N3D4x4_3extra_float32.c b/libambix/tests/basic2extended_N3D4x4_3extra_float32.c
new file mode 100644
index 0000000..58955d6
--- /dev/null
+++ b/libambix/tests/basic2extended_N3D4x4_3extra_float32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("N3D"     , 4, 4, AMBIX_MATRIX_N3D     , 3, 1024, 3e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_N3D4x4_3extra_float64.c b/libambix/tests/basic2extended_N3D4x4_3extra_float64.c
new file mode 100644
index 0000000..d9bc5df
--- /dev/null
+++ b/libambix/tests/basic2extended_N3D4x4_3extra_float64.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("N3D"     , 4, 4, AMBIX_MATRIX_N3D     , 3, 1024, 3e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_N3D4x4_3extra_pcm16.c b/libambix/tests/basic2extended_N3D4x4_3extra_pcm16.c
new file mode 100644
index 0000000..40069ef
--- /dev/null
+++ b/libambix/tests/basic2extended_N3D4x4_3extra_pcm16.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("N3D"     , 4, 4, AMBIX_MATRIX_N3D     , 3, 1024, 4e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_N3D4x4_3extra_pcm32.c b/libambix/tests/basic2extended_N3D4x4_3extra_pcm32.c
new file mode 100644
index 0000000..1021c3b
--- /dev/null
+++ b/libambix/tests/basic2extended_N3D4x4_3extra_pcm32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("N3D"     , 4, 4, AMBIX_MATRIX_N3D     , 3, 1024, 3e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_N3D4x4_float32.c b/libambix/tests/basic2extended_N3D4x4_float32.c
new file mode 100644
index 0000000..c7c46c6
--- /dev/null
+++ b/libambix/tests/basic2extended_N3D4x4_float32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("N3D"     , 4, 4, AMBIX_MATRIX_N3D     , 0, 1024, 3e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_N3D4x4_float64.c b/libambix/tests/basic2extended_N3D4x4_float64.c
new file mode 100644
index 0000000..4c5e20e
--- /dev/null
+++ b/libambix/tests/basic2extended_N3D4x4_float64.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("N3D"     , 4, 4, AMBIX_MATRIX_N3D     , 0, 1024, 3e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_N3D4x4_pcm16.c b/libambix/tests/basic2extended_N3D4x4_pcm16.c
new file mode 100644
index 0000000..f9e8181
--- /dev/null
+++ b/libambix/tests/basic2extended_N3D4x4_pcm16.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("N3D"     , 4, 4, AMBIX_MATRIX_N3D     , 0, 1024, 4e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_N3D4x4_pcm32.c b/libambix/tests/basic2extended_N3D4x4_pcm32.c
new file mode 100644
index 0000000..0e0ad53
--- /dev/null
+++ b/libambix/tests/basic2extended_N3D4x4_pcm32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("N3D"     , 4, 4, AMBIX_MATRIX_N3D     , 0, 1024, 3e-8);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_SID4x4_3extra_float32.c b/libambix/tests/basic2extended_SID4x4_3extra_float32.c
new file mode 100644
index 0000000..86b2892
--- /dev/null
+++ b/libambix/tests/basic2extended_SID4x4_3extra_float32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("SID"     , 4, 4, AMBIX_MATRIX_SID     , 3, 1024, 0);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_SID4x4_3extra_float64.c b/libambix/tests/basic2extended_SID4x4_3extra_float64.c
new file mode 100644
index 0000000..fe136f0
--- /dev/null
+++ b/libambix/tests/basic2extended_SID4x4_3extra_float64.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("SID"     , 4, 4, AMBIX_MATRIX_SID     , 3, 1024, 0);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_SID4x4_3extra_pcm16.c b/libambix/tests/basic2extended_SID4x4_3extra_pcm16.c
new file mode 100644
index 0000000..dcfd5b6
--- /dev/null
+++ b/libambix/tests/basic2extended_SID4x4_3extra_pcm16.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("SID"     , 4, 4, AMBIX_MATRIX_SID     , 3, 1024, 4e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_SID4x4_3extra_pcm32.c b/libambix/tests/basic2extended_SID4x4_3extra_pcm32.c
new file mode 100644
index 0000000..13b5c6c
--- /dev/null
+++ b/libambix/tests/basic2extended_SID4x4_3extra_pcm32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("SID"     , 4, 4, AMBIX_MATRIX_SID     , 3, 1024, 1e-9);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_SID4x4_float32.c b/libambix/tests/basic2extended_SID4x4_float32.c
new file mode 100644
index 0000000..626d9f5
--- /dev/null
+++ b/libambix/tests/basic2extended_SID4x4_float32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("SID"     , 4, 4, AMBIX_MATRIX_SID     , 0, 1024, 0);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_SID4x4_float64.c b/libambix/tests/basic2extended_SID4x4_float64.c
new file mode 100644
index 0000000..c744976
--- /dev/null
+++ b/libambix/tests/basic2extended_SID4x4_float64.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("SID"     , 4, 4, AMBIX_MATRIX_SID     , 0, 1024, 0);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_SID4x4_pcm16.c b/libambix/tests/basic2extended_SID4x4_pcm16.c
new file mode 100644
index 0000000..6d087a8
--- /dev/null
+++ b/libambix/tests/basic2extended_SID4x4_pcm16.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("SID"     , 4, 4, AMBIX_MATRIX_SID     , 0, 1024, 4e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_SID4x4_pcm32.c b/libambix/tests/basic2extended_SID4x4_pcm32.c
new file mode 100644
index 0000000..292ceb9
--- /dev/null
+++ b/libambix/tests/basic2extended_SID4x4_pcm32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("SID"     , 4, 4, AMBIX_MATRIX_SID     , 0, 1024, 1e-9);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_identity4x4_3extra_float32.c b/libambix/tests/basic2extended_identity4x4_3extra_float32.c
new file mode 100644
index 0000000..362602b
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_3extra_float32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("IDENTITY", 4, 4, AMBIX_MATRIX_IDENTITY, 3, 1024, 0);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_identity4x4_3extra_float64.c b/libambix/tests/basic2extended_identity4x4_3extra_float64.c
new file mode 100644
index 0000000..42776a3
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_3extra_float64.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("IDENTITY", 4, 4, AMBIX_MATRIX_IDENTITY, 3, 1024, 0);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_identity4x4_3extra_pcm16.c b/libambix/tests/basic2extended_identity4x4_3extra_pcm16.c
new file mode 100644
index 0000000..086ecb6
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_3extra_pcm16.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("IDENTITY", 4, 4, AMBIX_MATRIX_IDENTITY, 3, 1024, 4e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_identity4x4_3extra_pcm32.c b/libambix/tests/basic2extended_identity4x4_3extra_pcm32.c
new file mode 100644
index 0000000..9f1a322
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_3extra_pcm32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("IDENTITY", 4, 4, AMBIX_MATRIX_IDENTITY, 3, 1024, 1e-9);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_identity4x4_float32.c b/libambix/tests/basic2extended_identity4x4_float32.c
new file mode 100644
index 0000000..28356c2
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_float32.c
@@ -0,0 +1,27 @@
+#include "common_basic2extended.h"
+
+#ifndef FMT
+# define FMT FLOAT32
+#endif
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps, ambixtest_presentationformat_t fmt) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, fmt, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("IDENTITY1024:" STRINGIFY(FMT), 4, 4, AMBIX_MATRIX_IDENTITY, 0, 1024, 0, FMT);
+  err+=test_defaultmatrix("IDENTITY0000:" STRINGIFY(FMT), 4, 4, AMBIX_MATRIX_IDENTITY, 0,    0, 0, FMT);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_identity4x4_float32__f64.c b/libambix/tests/basic2extended_identity4x4_float32__f64.c
new file mode 100644
index 0000000..3cc43b2
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_float32__f64.c
@@ -0,0 +1,2 @@
+#define FMT FLOAT64
+#include "basic2extended_identity4x4_float32.c"
diff --git a/libambix/tests/basic2extended_identity4x4_float32__i16.c b/libambix/tests/basic2extended_identity4x4_float32__i16.c
new file mode 100644
index 0000000..bb52167
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_float32__i16.c
@@ -0,0 +1,2 @@
+#define FMT INT16
+#include "basic2extended_identity4x4_float32.c"
diff --git a/libambix/tests/basic2extended_identity4x4_float32__i32.c b/libambix/tests/basic2extended_identity4x4_float32__i32.c
new file mode 100644
index 0000000..8353436
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_float32__i32.c
@@ -0,0 +1,2 @@
+#define FMT INT32
+#include "basic2extended_identity4x4_float32.c"
diff --git a/libambix/tests/basic2extended_identity4x4_float64.c b/libambix/tests/basic2extended_identity4x4_float64.c
new file mode 100644
index 0000000..f4a350c
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_float64.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("IDENTITY", 4, 4, AMBIX_MATRIX_IDENTITY, 0, 1024, 0);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_identity4x4_pcm16.c b/libambix/tests/basic2extended_identity4x4_pcm16.c
new file mode 100644
index 0000000..f6ae9b0
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_pcm16.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("IDENTITY", 4, 4, AMBIX_MATRIX_IDENTITY, 0, 1024, 4e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_identity4x4_pcm32.c b/libambix/tests/basic2extended_identity4x4_pcm32.c
new file mode 100644
index 0000000..9422c7d
--- /dev/null
+++ b/libambix/tests/basic2extended_identity4x4_pcm32.c
@@ -0,0 +1,22 @@
+#include "common_basic2extended.h"
+
+int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp,
+		       uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill(mtx, mtyp);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_defaultmatrix("IDENTITY", 4, 4, AMBIX_MATRIX_IDENTITY, 0, 1024, 1e-9);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x7_3extra_float32.c b/libambix/tests/basic2extended_rand4x7_3extra_float32.c
new file mode 100644
index 0000000..63089f6
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x7_3extra_float32.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_7[]={
+0.588219, 0.758465, 0.240167, 0.827193, 0.899134, 0.121186, 0.974490,
+0.079994, 0.828276, 0.223099, 0.525774, 0.895537, 0.884317, 0.434495,
+0.426266, 0.302895, 0.341656, 0.325299, 0.474342, 0.677271, 0.185883,
+0.183465, 0.654321, 0.243639, 0.779875, 0.250082, 0.939078, 0.449736,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x7]", 4, 7, data_4_7          , 3, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x7_3extra_float64.c b/libambix/tests/basic2extended_rand4x7_3extra_float64.c
new file mode 100644
index 0000000..6c49891
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x7_3extra_float64.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_7[]={
+0.588219, 0.758465, 0.240167, 0.827193, 0.899134, 0.121186, 0.974490,
+0.079994, 0.828276, 0.223099, 0.525774, 0.895537, 0.884317, 0.434495,
+0.426266, 0.302895, 0.341656, 0.325299, 0.474342, 0.677271, 0.185883,
+0.183465, 0.654321, 0.243639, 0.779875, 0.250082, 0.939078, 0.449736,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x7]", 4, 7, data_4_7          , 3, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x7_3extra_pcm16.c b/libambix/tests/basic2extended_rand4x7_3extra_pcm16.c
new file mode 100644
index 0000000..4500166
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x7_3extra_pcm16.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_7[]={
+0.588219, 0.758465, 0.240167, 0.827193, 0.899134, 0.121186, 0.974490,
+0.079994, 0.828276, 0.223099, 0.525774, 0.895537, 0.884317, 0.434495,
+0.426266, 0.302895, 0.341656, 0.325299, 0.474342, 0.677271, 0.185883,
+0.183465, 0.654321, 0.243639, 0.779875, 0.250082, 0.939078, 0.449736,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[5x7]", 4, 7, data_4_7          , 3, 1024, 7e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x7_3extra_pcm32.c b/libambix/tests/basic2extended_rand4x7_3extra_pcm32.c
new file mode 100644
index 0000000..6755ba6
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x7_3extra_pcm32.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_7[]={
+0.588219, 0.758465, 0.240167, 0.827193, 0.899134, 0.121186, 0.974490,
+0.079994, 0.828276, 0.223099, 0.525774, 0.895537, 0.884317, 0.434495,
+0.426266, 0.302895, 0.341656, 0.325299, 0.474342, 0.677271, 0.185883,
+0.183465, 0.654321, 0.243639, 0.779875, 0.250082, 0.939078, 0.449736,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x7]", 4, 7, data_4_7          , 3, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x7_float32.c b/libambix/tests/basic2extended_rand4x7_float32.c
new file mode 100644
index 0000000..7488f53
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x7_float32.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_7[]={
+0.588219, 0.758465, 0.240167, 0.827193, 0.899134, 0.121186, 0.974490,
+0.079994, 0.828276, 0.223099, 0.525774, 0.895537, 0.884317, 0.434495,
+0.426266, 0.302895, 0.341656, 0.325299, 0.474342, 0.677271, 0.185883,
+0.183465, 0.654321, 0.243639, 0.779875, 0.250082, 0.939078, 0.449736,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x7]", 4, 7, data_4_7          , 0, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x7_float64.c b/libambix/tests/basic2extended_rand4x7_float64.c
new file mode 100644
index 0000000..74a4006
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x7_float64.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_7[]={
+0.588219, 0.758465, 0.240167, 0.827193, 0.899134, 0.121186, 0.974490,
+0.079994, 0.828276, 0.223099, 0.525774, 0.895537, 0.884317, 0.434495,
+0.426266, 0.302895, 0.341656, 0.325299, 0.474342, 0.677271, 0.185883,
+0.183465, 0.654321, 0.243639, 0.779875, 0.250082, 0.939078, 0.449736,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x7]", 4, 7, data_4_7          , 0, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x7_pcm16.c b/libambix/tests/basic2extended_rand4x7_pcm16.c
new file mode 100644
index 0000000..2444488
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x7_pcm16.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_7[]={
+0.588219, 0.758465, 0.240167, 0.827193, 0.899134, 0.121186, 0.974490,
+0.079994, 0.828276, 0.223099, 0.525774, 0.895537, 0.884317, 0.434495,
+0.426266, 0.302895, 0.341656, 0.325299, 0.474342, 0.677271, 0.185883,
+0.183465, 0.654321, 0.243639, 0.779875, 0.250082, 0.939078, 0.449736,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x7]", 4, 7, data_4_7          , 0, 1024, 7e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x7_pcm32.c b/libambix/tests/basic2extended_rand4x7_pcm32.c
new file mode 100644
index 0000000..cfa1298
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x7_pcm32.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_7[]={
+0.588219, 0.758465, 0.240167, 0.827193, 0.899134, 0.121186, 0.974490,
+0.079994, 0.828276, 0.223099, 0.525774, 0.895537, 0.884317, 0.434495,
+0.426266, 0.302895, 0.341656, 0.325299, 0.474342, 0.677271, 0.185883,
+0.183465, 0.654321, 0.243639, 0.779875, 0.250082, 0.939078, 0.449736,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x7]", 4, 7, data_4_7          , 0, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x9_3extra_float32.c b/libambix/tests/basic2extended_rand4x9_3extra_float32.c
new file mode 100644
index 0000000..4e8c330
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x9_3extra_float32.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_9[]={
+  0.519497, 0.101224, 0.775246, 0.219242, 0.795973, 0.649863, 0.190978, 0.837028, 0.763130,
+  0.165074, 0.276581, 0.220167, 0.383229, 0.937749, 0.381838, 0.025107, 0.846256, 0.773257,
+  0.546205, 0.501742, 0.476078, 0.539815, 0.671716, 0.069030, 0.748010, 0.369414, 0.667491,
+  0.192167, 0.936164, 0.792496, 0.447073, 0.689901, 0.618242, 0.769460, 0.815128, 0.466140,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x9]", 4, 9, data_4_9          , 3, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x9_3extra_float64.c b/libambix/tests/basic2extended_rand4x9_3extra_float64.c
new file mode 100644
index 0000000..aee794a
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x9_3extra_float64.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_9[]={
+  0.519497, 0.101224, 0.775246, 0.219242, 0.795973, 0.649863, 0.190978, 0.837028, 0.763130,
+  0.165074, 0.276581, 0.220167, 0.383229, 0.937749, 0.381838, 0.025107, 0.846256, 0.773257,
+  0.546205, 0.501742, 0.476078, 0.539815, 0.671716, 0.069030, 0.748010, 0.369414, 0.667491,
+  0.192167, 0.936164, 0.792496, 0.447073, 0.689901, 0.618242, 0.769460, 0.815128, 0.466140,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x9]", 4, 9, data_4_9          , 3, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x9_3extra_pcm16.c b/libambix/tests/basic2extended_rand4x9_3extra_pcm16.c
new file mode 100644
index 0000000..22b2d5c
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x9_3extra_pcm16.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_9[]={
+  0.519497, 0.101224, 0.775246, 0.219242, 0.795973, 0.649863, 0.190978, 0.837028, 0.763130,
+  0.165074, 0.276581, 0.220167, 0.383229, 0.937749, 0.381838, 0.025107, 0.846256, 0.773257,
+  0.546205, 0.501742, 0.476078, 0.539815, 0.671716, 0.069030, 0.748010, 0.369414, 0.667491,
+  0.192167, 0.936164, 0.792496, 0.447073, 0.689901, 0.618242, 0.769460, 0.815128, 0.466140,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x9]", 4, 9, data_4_9          , 3, 1024, 9e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x9_3extra_pcm32.c b/libambix/tests/basic2extended_rand4x9_3extra_pcm32.c
new file mode 100644
index 0000000..ae733c6
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x9_3extra_pcm32.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_9[]={
+  0.519497, 0.101224, 0.775246, 0.219242, 0.795973, 0.649863, 0.190978, 0.837028, 0.763130,
+  0.165074, 0.276581, 0.220167, 0.383229, 0.937749, 0.381838, 0.025107, 0.846256, 0.773257,
+  0.546205, 0.501742, 0.476078, 0.539815, 0.671716, 0.069030, 0.748010, 0.369414, 0.667491,
+  0.192167, 0.936164, 0.792496, 0.447073, 0.689901, 0.618242, 0.769460, 0.815128, 0.466140,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x9]", 4, 9, data_4_9          , 3, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x9_float32.c b/libambix/tests/basic2extended_rand4x9_float32.c
new file mode 100644
index 0000000..fe62715
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x9_float32.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_9[]={
+  0.519497, 0.101224, 0.775246, 0.219242, 0.795973, 0.649863, 0.190978, 0.837028, 0.763130,
+  0.165074, 0.276581, 0.220167, 0.383229, 0.937749, 0.381838, 0.025107, 0.846256, 0.773257,
+  0.546205, 0.501742, 0.476078, 0.539815, 0.671716, 0.069030, 0.748010, 0.369414, 0.667491,
+  0.192167, 0.936164, 0.792496, 0.447073, 0.689901, 0.618242, 0.769460, 0.815128, 0.466140,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x9]", 4, 9, data_4_9          , 0, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x9_float64.c b/libambix/tests/basic2extended_rand4x9_float64.c
new file mode 100644
index 0000000..1bec76e
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x9_float64.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_9[]={
+  0.519497, 0.101224, 0.775246, 0.219242, 0.795973, 0.649863, 0.190978, 0.837028, 0.763130,
+  0.165074, 0.276581, 0.220167, 0.383229, 0.937749, 0.381838, 0.025107, 0.846256, 0.773257,
+  0.546205, 0.501742, 0.476078, 0.539815, 0.671716, 0.069030, 0.748010, 0.369414, 0.667491,
+  0.192167, 0.936164, 0.792496, 0.447073, 0.689901, 0.618242, 0.769460, 0.815128, 0.466140,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_FLOAT64,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x9]", 4, 9, data_4_9          , 0, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x9_pcm16.c b/libambix/tests/basic2extended_rand4x9_pcm16.c
new file mode 100644
index 0000000..91fcfa4
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x9_pcm16.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_9[]={
+  0.519497, 0.101224, 0.775246, 0.219242, 0.795973, 0.649863, 0.190978, 0.837028, 0.763130,
+  0.165074, 0.276581, 0.220167, 0.383229, 0.937749, 0.381838, 0.025107, 0.846256, 0.773257,
+  0.546205, 0.501742, 0.476078, 0.539815, 0.671716, 0.069030, 0.748010, 0.369414, 0.667491,
+  0.192167, 0.936164, 0.792496, 0.447073, 0.689901, 0.618242, 0.769460, 0.815128, 0.466140,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x9]", 4, 9, data_4_9          , 0, 1024, 9e-5);
+  return pass();
+}
diff --git a/libambix/tests/basic2extended_rand4x9_pcm32.c b/libambix/tests/basic2extended_rand4x9_pcm32.c
new file mode 100644
index 0000000..7287b50
--- /dev/null
+++ b/libambix/tests/basic2extended_rand4x9_pcm32.c
@@ -0,0 +1,29 @@
+#include "common_basic2extended.h"
+
+float32_t data_4_9[]={
+  0.519497, 0.101224, 0.775246, 0.219242, 0.795973, 0.649863, 0.190978, 0.837028, 0.763130,
+  0.165074, 0.276581, 0.220167, 0.383229, 0.937749, 0.381838, 0.025107, 0.846256, 0.773257,
+  0.546205, 0.501742, 0.476078, 0.539815, 0.671716, 0.069030, 0.748010, 0.369414, 0.667491,
+  0.192167, 0.936164, 0.792496, 0.447073, 0.689901, 0.618242, 0.769460, 0.815128, 0.466140,
+};
+
+int test_datamatrix(const char*name, uint32_t rows, uint32_t cols, float32_t*data,
+		    uint32_t xtrachannels, uint32_t chunksize, float32_t eps) {
+  int result=0;
+  ambix_matrix_t*mtx=0;
+  STARTTEST("%s\n", name);
+  mtx=ambix_matrix_init(rows,cols,mtx);
+  if(!mtx)return 1;
+  ambix_matrix_fill_data(mtx, data);
+  result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM32,
+			  mtx,xtrachannels,
+			  chunksize, FLOAT32, eps);
+  ambix_matrix_destroy(mtx);
+  return result;
+}
+
+int main(int argc, char**argv) {
+  int err=0;
+  err+=test_datamatrix   ("'rand'[4x9]", 4, 9, data_4_9          , 0, 1024, 5e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic_float32.c b/libambix/tests/basic_float32.c
new file mode 100644
index 0000000..d469403
--- /dev/null
+++ b/libambix/tests/basic_float32.c
@@ -0,0 +1,7 @@
+#include "common.h"
+void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t eps);
+
+int main(int argc, char**argv) {
+  check_create_simple(FILENAME_FILE,  AMBIX_SAMPLEFORMAT_FLOAT32, 1e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic_float64.c b/libambix/tests/basic_float64.c
new file mode 100644
index 0000000..233aea3
--- /dev/null
+++ b/libambix/tests/basic_float64.c
@@ -0,0 +1,7 @@
+#include "common.h"
+void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t eps);
+
+int main(int argc, char**argv) {
+  check_create_simple(FILENAME_FILE,  AMBIX_SAMPLEFORMAT_FLOAT64, 1e-7);
+  return pass();
+}
diff --git a/libambix/tests/basic_pcm16.c b/libambix/tests/basic_pcm16.c
new file mode 100644
index 0000000..79804bf
--- /dev/null
+++ b/libambix/tests/basic_pcm16.c
@@ -0,0 +1,7 @@
+#include "common.h"
+void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t eps);
+
+int main(int argc, char**argv) {
+  check_create_simple(FILENAME_FILE,  AMBIX_SAMPLEFORMAT_PCM16, 1./20000.);
+  return pass();
+}
diff --git a/libambix/tests/basic_pcm32.c b/libambix/tests/basic_pcm32.c
new file mode 100644
index 0000000..3bbddc9
--- /dev/null
+++ b/libambix/tests/basic_pcm32.c
@@ -0,0 +1,7 @@
+#include "common.h"
+void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t eps);
+
+int main(int argc, char**argv) {
+  check_create_simple(FILENAME_FILE,  AMBIX_SAMPLEFORMAT_PCM32, 1e-5);
+  return pass();
+}
diff --git a/libambix/tests/common.c b/libambix/tests/common.c
index 0ac5d44..91713c4 100644
--- a/libambix/tests/common.c
+++ b/libambix/tests/common.c
@@ -1,6 +1,6 @@
 /* common test functionality
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -23,9 +23,36 @@
 
 #include "common.h"
 #include <math.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+
+static char* snprintdata(char*out, size_t size, ambixtest_presentationformat_t fmt, const void*data, uint64_t index) {
+  switch(fmt) {
+  case INT16  :
+    snprintf(out, size, "%d", ((int16_t*)data)[index]);
+    break;
+  case INT32  :
+    snprintf(out, size, "%d", ((int32_t*)data)[index]);
+    break;
+  case FLOAT32:
+    snprintf(out, size, "%g", ((float32_t*)data)[index]);
+    break;
+  case FLOAT64:
+    snprintf(out, size, "%g", ((float64_t*)data)[index]);
+    break;
+  default     :
+    snprintf(out, size, "???");
+    break;
+  }
+  out[size-1]=0;
+  return out;
+}
 
 void matrix_print(const ambix_matrix_t*mtx) {
-  printf("matrix [%dx%d]\n", mtx->rows, mtx->cols);
+  printf("matrix[%p] ", mtx);
+  printf(" [%dx%d]@%p\n", mtx->rows, mtx->cols, mtx->data);
   if(mtx->data) {
     uint32_t c, r;
     for(r=0; r<mtx->rows; r++) {
@@ -55,59 +82,85 @@ float32_t matrix_diff(uint32_t line, const ambix_matrix_t*A, const ambix_matrix_
     for(c=0; c<B->cols; c++) {
       float32_t v=a[r][c]-b[r][c];
       float32_t vabs=(v<0)?-v:v;
-      fail_if(isnan(v), line, "[%d|%d] is NaN: %f <-> %f", r, c, a[r][c], b[r][c]);
+      if(isnan(v))return v;
       if(vabs>maxdiff)
         maxdiff=vabs;
       sum+=vabs;
       if(vabs>eps) {
         overcount++;
         if(overcount<MAX_OVER)
-          printf("%f - %f=%f @ [%02d|%02d]\n", a[r][c], b[r][c], v, r, c);
+          printf("%+f - %+f = %+g @ [%02d|%02d]\n", a[r][c], b[r][c], v, r, c);
       }
     }
 
   if(overcount>MAX_OVER)
-    printf("accumulated error %f over %d/%d frames\n", sum, (int)overcount, (int)(A->cols*B->rows));
+    printf("[%d] accumulated error %f over %d/%d frames (eps=%g)\n", line, sum, (int)overcount, (int)(A->cols*B->rows), eps);
   return maxdiff;
 }
 
 
-float32_t data_diff(uint32_t line, const float32_t*A, const float32_t*B, uint64_t frames, float32_t eps) {
+float32_t data_diff(uint32_t line,
+                    ambixtest_presentationformat_t fmt,
+                    const void*A, const void*B, uint64_t frames,
+                    float32_t eps) {
   uint64_t i;
   float32_t sum=0.;
   float32_t maxdiff=-1.f;
   uint64_t overcount=0;
+  char aout[16];
+  char bout[16];
 
   fail_if((NULL==A), line, "left-hand data of datadiff is NULL");
   fail_if((NULL==B), line, "right-hand data of datadiff is NULL");
 
   for(i=0; i<frames; i++) {
-    float32_t v=A[i]-B[i];
-    float32_t vabs=(v<0)?-v:v;
-    fail_if(isnan(v), line, "[%d] is NaN: %f <-> %f", i, A[i], B[i]);
+    float64_t v=0;
+    float64_t vabs=0;
+    switch(fmt) {
+    case INT16  :
+      v=((int16_t*)A)[i]-((int16_t*)B)[i];
+      break;
+    case INT32  :
+      v=((int32_t*)A)[i]-((int32_t*)B)[i];
+      break;
+    case FLOAT32:
+      v=((float32_t*)A)[i]-((float32_t*)B)[i];
+      break;
+    case FLOAT64:
+      v=((float64_t*)A)[i]-((float64_t*)B)[i];
+      break;
+    default: break;
+    }
+    fail_if(isnan(v), line, "[%d] is NaN: %s <-> %s", i,
+            snprintdata(aout, 16, fmt, A, i),
+            snprintdata(bout, 16, fmt, B, i));
+    vabs=(v<0)?-v:v;
     if(vabs>maxdiff)
       maxdiff=vabs;
     sum+=vabs;
     if(vabs>eps) {
       overcount++;
       if(overcount<MAX_OVER)
-        printf("%f - %f=%f @ %d\n", A[i], B[i], v, (int)i);
+        printf("%s - %s=%g @ %d\n",
+               snprintdata(aout, 16, fmt, A, i),
+               snprintdata(bout, 16, fmt, B, i),
+               v, (int)i);
     }
 
   }
 
   if(overcount>MAX_OVER)
-    printf("accumulated error %f over %d/%d frames\n", sum, (int)overcount, (int)frames);
+    printf("[%d] accumulated error %f over %d/%d frames (eps=%g)\n", line, sum, (int)overcount, (int)frames, eps);
 
   return maxdiff;
 }
 
 
-void data_print(const float32_t*data, uint64_t frames) {
+void data_print(ambixtest_presentationformat_t fmt, const void*data, uint64_t frames) {
   uint64_t i;
+  char out[16];
   for(i=0; i<frames; i++) {
-    float f=*data++;
-    printf("%05d: %f\n", (int)i, f);
+    printf("%05d: %s\n", (int)i, snprintdata(out, 16, fmt, data, i));
   }
 }
 
@@ -123,37 +176,142 @@ void data_transpose(float32_t*outdata, const float32_t*indata, uint32_t inrows,
   }
 }
 
+static void setdata(ambixtest_presentationformat_t fmt, void*data, uint64_t index, float64_t value) {
+  switch(fmt) {
+  case INT16  :
+    ((int16_t*)data)[index]=(int16_t)(value*32768.);
+    break;
+  case INT32  :
+    ((int32_t*)data)[index]=(int32_t)(value*2147483648.);
+    break;
+  case FLOAT32:
+    ((float32_t*)data)[index]=(float32_t)value;
+    break;
+  case FLOAT64:
+    ((float64_t*)data)[index]=(float64_t)value;
+    break;
+  default     : break;
+  }
+}
+
+size_t data_size(ambixtest_presentationformat_t fmt) {
+  switch(fmt) {
+  case INT16  : return 2;
+  case INT32  : return 4;
+  case FLOAT32: return 4;
+  case FLOAT64: return 8;
+  default     : break;
+  }
+  return 0;
+}
+
+void*data_calloc(ambixtest_presentationformat_t fmt, size_t nmembers) {
+  size_t nmemb=nmembers*data_size(fmt)/sizeof(float64_t)+1;
+  size_t size = sizeof(float64_t);
+  void*data=calloc(nmemb, size);
+  //printf("%dx%d[%d] allocated %d of %d bytes to %p\n", (int)frames, channels, fmt, (int)nmemb, (int)size, data);
+  return data;
+}
 
-float32_t*data_sine(uint64_t frames, uint32_t channels, float32_t freq) {
-  float32_t periods=44100./freq;
-  float32_t*data=(float32_t*)calloc(frames*channels, sizeof(float32_t));
-  float32_t*datap=data;
+void*data_sine(ambixtest_presentationformat_t fmt, uint64_t frames, uint32_t channels, float32_t freq) {
+  float32_t periods=freq/44100.;
+  void*data=data_calloc(fmt, frames*channels);
   int64_t frame;
   for(frame=0; frame<frames; frame++) {
-    //    float f=(float32_t)frame*periods/(float32_t)frames;
-    float f=(float32_t)frame*periods;
-    float32_t value=0.5*sinf(f);
     int32_t chan;
+    float64_t f=(float64_t)frame*periods;
+    float64_t value=0.5*sinf(f);
     for(chan=0; chan<channels; chan++)
-      *datap++=value;
+      setdata(fmt, data, f*channels+chan, value);
   }
   return data;
 }
 
-float32_t*data_ramp(uint64_t frames, uint32_t channels) {
-  float32_t*data=(float32_t*)calloc(frames*channels, sizeof(float32_t));
-  float32_t*datap=data;
+void*data_ramp(ambixtest_presentationformat_t fmt, uint64_t frames, uint32_t channels) {
+  void*data=data_calloc(fmt, frames*channels);
   double increment=1./(double)frames;
   double value=0.;
   int64_t frame;
   for(frame=0; frame<frames; frame++) {
-    value+=increment;
     int32_t chan;
+    float32_t v32=value-0.5;
+    value+=increment;
     for(chan=0; chan<channels; chan++)
-      *datap++=(value-0.5);
+      setdata(fmt, data, frame*channels+chan, v32);
   }
   return data;
 }
 
 
+int64_t ambixtest_readf (ambix_t *ambix, ambixtest_presentationformat_t fmt,
+                         void*ambidata , uint64_t ambioffset,
+                         void*otherdata, uint64_t otheroffset,
+                         int64_t frames) {
+   switch(fmt) {
+   case INT16  :
+     return ambix_readf_int16(ambix, ((int16_t*)ambidata)+ambioffset, ((int16_t*)otherdata)+otheroffset, frames);
+   case INT32  :
+     return ambix_readf_int32(ambix, ((int32_t*)ambidata)+ambioffset, ((int32_t*)otherdata)+otheroffset, frames);
+   case FLOAT32:
+     return ambix_readf_float32(ambix, ((float32_t*)ambidata)+ambioffset, ((float32_t*)otherdata)+otheroffset, frames);
+   case FLOAT64:
+     return ambix_readf_float64(ambix, ((float64_t*)ambidata)+ambioffset, ((float64_t*)otherdata)+otheroffset, frames);
+   default     : break;
+   }
+   return -1;
+}
+
+int64_t ambixtest_writef (ambix_t *ambix, ambixtest_presentationformat_t fmt,
+                          const void*ambidata , const uint64_t ambioffset,
+                          const void*otherdata, const uint64_t otheroffset,
+                          int64_t frames) {
+   switch(fmt) {
+   case INT16  :
+     return ambix_writef_int16(ambix,
+                               ((const int16_t*)ambidata)+ambioffset, ((const int16_t*)otherdata)+otheroffset,
+                               frames);
+   case INT32  :
+     return ambix_writef_int32(ambix,
+                               ((const int32_t*)ambidata)+ambioffset, ((const int32_t*)otherdata)+otheroffset,
+                               frames);
+   case FLOAT32:
+     return ambix_writef_float32(ambix,
+                                 ((const float32_t*)ambidata)+ambioffset, ((const float32_t*)otherdata)+otheroffset,
+                                 frames);
+   case FLOAT64:
+     return ambix_writef_float64(ambix,
+                                 ((const float64_t*)ambidata)+ambioffset, ((const float64_t*)otherdata)+otheroffset,
+                                 frames);
+   default     : break;
+   }
+   return -1;
+}
 
+
+int ambixtest_rmfile(const char*path) {
+  /* only remove if AMBIXTEST_KEEPFILES is not set */
+  if(NULL==getenv("AMBIXTEST_KEEPFILES"))return unlink(path);
+  return 0;
+}
+int ambixtest_uniquenumber() {
+#ifdef HAVE_UNISTD_H
+  return getpid();
+#endif
+  return 0;
+}
+const char*getbasename(const char*fullpath) {
+  char*pos=NULL;
+  if(!fullpath)return "";
+  pos=strrchr(fullpath, '/');
+  if(pos)return pos+1;
+  return fullpath;
+}
+char*ambixtest_getfname(char*inbuf, size_t length, const char*path_, const char*basename_, const char*ext_) {
+  static unsigned int count=0;
+  const char*ext=(ext_)?ext_:".caf";
+  const char*path=(path_)?path_:"";
+  const char*basename=getbasename(basename_);
+  snprintf(inbuf, length, "%s%s-%d.%d%s", path, basename, ambixtest_uniquenumber(), count, ext);
+  count++;
+  return inbuf;
+}
diff --git a/libambix/tests/common.h b/libambix/tests/common.h
index 46bb1c6..7dc685f 100644
--- a/libambix/tests/common.h
+++ b/libambix/tests/common.h
@@ -26,16 +26,21 @@
 
 #include <ambix/ambix.h>
 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #include <stdlib.h>
-static inline void pass(void) {exit(0); }
-static inline void fail(void) {exit(1); }
-static inline void skip(void) {exit(77); }
+static inline int my_exit(int i) {exit(i); return i;}
+static inline int pass(void) {return my_exit(0); }
+static inline int fail(void) {return my_exit(1); }
+static inline int skip(void) {return my_exit(77); }
 
 #include <stdio.h>
 #include <stdarg.h>
 #define MARK() printf("%s:%d[%s]\n", __FILE__, __LINE__, __FUNCTION__)
 
-static inline void pass_if (int test, int line, const char *format, ...)
+static inline int pass_if (int test, int line, const char *format, ...)
 {
   if (test) {
     va_list argptr ;
@@ -44,10 +49,11 @@ static inline void pass_if (int test, int line, const char *format, ...)
     vprintf (format, argptr) ;
     va_end (argptr) ;
     printf("\n");
-    pass();
+    return pass();
   } ;
+  return test;
 } /* pass_if */
-static inline void skip_if (int test, int line, const char *format, ...)
+static inline int skip_if (int test, int line, const char *format, ...)
 {
   if (test) {
     va_list argptr ;
@@ -56,10 +62,11 @@ static inline void skip_if (int test, int line, const char *format, ...)
     vprintf (format, argptr) ;
     va_end (argptr) ;
     printf("\n");
-    skip();
+    return skip();
   } ;
+  return test;
 } /* skip_if */
-static inline void fail_if (int test, int line, const char *format, ...)
+static inline int fail_if (int test, int line, const char *format, ...)
 {
   if (test) {
     va_list argptr ;
@@ -68,22 +75,62 @@ static inline void fail_if (int test, int line, const char *format, ...)
     vprintf (format, argptr) ;
     va_end (argptr) ;
     printf("\n");
-    fail();
+    return fail();
   } ;
+  return test;
 } /* fail_if */
+static inline int print_if (int test, int line, const char *format, ...)
+{
+  if (test) {
+    va_list argptr ;
+    printf("@%d: ", line);
+    va_start (argptr, format) ;
+    vprintf (format, argptr) ;
+    va_end (argptr) ;
+    printf("\n");
+  }
+  return test;
+} /* print_if */
+
+typedef enum {
+ INT16,
+ INT32,
+ FLOAT32,
+ FLOAT64
+} ambixtest_presentationformat_t;
+
 
 void matrix_print(const ambix_matrix_t*mtx);
 float32_t matrix_diff(uint32_t line, const ambix_matrix_t*A, const ambix_matrix_t*B, float32_t eps);
 
-void data_print(const float32_t*data, uint64_t frames);
-float32_t data_diff(uint32_t line, const float32_t*A, const float32_t*B, uint64_t frames, float32_t eps);
+void data_print(ambixtest_presentationformat_t fmt, const void*data, uint64_t frames);
+float32_t data_diff(uint32_t line, ambixtest_presentationformat_t fmt, const void*A, const void*B, uint64_t frames, float32_t eps);
 
+size_t data_size(ambixtest_presentationformat_t fmt);
+void*data_calloc(ambixtest_presentationformat_t fmt, size_t nmembers);
 void data_transpose(float32_t*outdata, const float32_t*indata, uint32_t inrows, uint32_t incols);
-float32_t*data_sine(uint64_t frames, uint32_t channels, float32_t periods);
-float32_t*data_ramp(uint64_t frames, uint32_t channels);
+void*data_sine(ambixtest_presentationformat_t fmt, uint64_t frames, uint32_t channels, float32_t periods);
+void*data_ramp(ambixtest_presentationformat_t fmt, uint64_t frames, uint32_t channels);
+
+int64_t ambixtest_readf (ambix_t *ambix, ambixtest_presentationformat_t fmt,
+                         void*ambidata , uint64_t ambioffset,
+                         void*otherdata, uint64_t otheroffset,
+                         int64_t frames);
+int64_t ambixtest_writef (ambix_t *ambix, ambixtest_presentationformat_t fmt,
+                          const void*ambidata , const uint64_t ambioffset,
+                          const void*otherdata, const uint64_t otheroffset,
+                          int64_t frames);
+int ambixtest_rmfile(const char*path);
+int ambixtest_uniquenumber(void);
+/* write uniquish filename into 'inbuf' and return a pointer to it
+ * if ext is NULL, it defaults to '.caf'*/
+char*ambixtest_getfname(char*inbuf, size_t length, const char*path, const char*basename, const char*ext);
+#define FILENAME_MAIN ambixtest_getfname(alloca(1024), 1024, 0, argv[0], 0)
+#define FILENAME_FILE ambixtest_getfname(alloca(1024), 1024, 0, __FILE__, 0)
 
 #define STRINGIFY(x) #x
-#define STARTTEST(x)   printf("============ %s[%04d]:\t%s '%s'\n", __FILE__, __LINE__, __FUNCTION__, x)
+#define STARTTEST   printf("<<< running TEST %s[%04d]:%s\t", __FILE__, __LINE__, __FUNCTION__),printf
+#define STOPTEST    printf(">>> test SUCCESS %s[%04d]:%s\t", __FILE__, __LINE__, __FUNCTION__),printf
 
 
 #endif /* TESTS_COMMON_H */
diff --git a/libambix/tests/ambix_simple.c b/libambix/tests/common_basic.c
similarity index 90%
rename from libambix/tests/ambix_simple.c
rename to libambix/tests/common_basic.c
index 9ed13b4..3d62af9 100644
--- a/libambix/tests/ambix_simple.c
+++ b/libambix/tests/common_basic.c
@@ -1,6 +1,6 @@
 /* simple - test ambix simple
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -31,7 +31,7 @@ void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t
   float32_t*orgdata,*data,*resultdata;
   uint32_t frames=441000;
   uint32_t channels=4;
-  float32_t periods=20000;
+  float32_t periods=4724;
   int64_t err64;
   float32_t diff=0.;
   uint32_t gotframes;
@@ -55,8 +55,8 @@ void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t
   ambix=ambix_open(path, AMBIX_WRITE, &rinfo);
   fail_if((NULL==ambix), __LINE__, "couldn't create ambix file '%s' for writing", path);
 
-  orgdata=data_sine(frames, channels, periods);
-  //data_print(orgdata, 100);
+  orgdata=data_sine(FLOAT32, frames, channels, periods);
+  //data_print(FLOAT32, orgdata, 100);
 
   memcpy(data, orgdata, frames*channels*sizeof(float32_t));
 
@@ -65,7 +65,7 @@ void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t
   err64=ambix_writef_float32(ambix, data, NULL, frames);
   fail_if((err64!=frames), __LINE__, "wrote only %d frames of %d", (int)err64, (int)frames);
 
-  diff=data_diff(__LINE__, orgdata, data, frames*channels, eps);
+  diff=data_diff(__LINE__, FLOAT32, orgdata, data, frames*channels, eps);
   fail_if((diff>eps), __LINE__, "data diff %f > %f", diff, eps);
 
   fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix);
@@ -87,7 +87,7 @@ void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t
     gotframes+=err64;
   } while(err64>0 && gotframes<frames);
 
-  diff=data_diff(__LINE__, orgdata, resultdata, frames*channels, eps);
+  diff=data_diff(__LINE__, FLOAT32, orgdata, resultdata, frames*channels, eps);
   fail_if((diff>eps), __LINE__, "data diff %f > %f", diff, eps);
 
   fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix);
@@ -97,7 +97,5 @@ void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t
   free(resultdata);
   free(orgdata);
 
-  unlink(path);
+  ambixtest_rmfile(path);
 }
-
-
diff --git a/libambix/tests/common_basic2extended.c b/libambix/tests/common_basic2extended.c
new file mode 100644
index 0000000..d7adb72
--- /dev/null
+++ b/libambix/tests/common_basic2extended.c
@@ -0,0 +1,199 @@
+/* common_simple2exetended - common function for writing extended files as simple files
+
+   Copyright © 2016 IOhannes m zmölnig <zmoelnig at iem.at>.
+         Institute of Electronic Music and Acoustics (IEM),
+         University of Music and Dramatic Arts, Graz
+
+   This file is part of libambix
+
+   libambix is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   libambix is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "common.h"
+#include <string.h>
+
+uint32_t max_u32(uint32_t a, uint32_t b) { return (a>b)?a:b;}
+
+int check_create_b2e(const char*path, ambix_sampleformat_t format,
+		      ambix_matrix_t*matrix, uint32_t extrachannels,
+		      uint32_t chunksize, ambixtest_presentationformat_t fmt,float32_t eps) {
+  uint32_t fullambichannels = matrix?matrix->rows:0;
+  uint32_t ambixchannels = matrix?matrix->cols:0;
+  ambix_info_t info, rinfo, winfo;
+  ambix_t*ambix=NULL;
+  void*orgambidata,*ambidata,*resultambidata;
+  void*orgotherdata,*otherdata,*resultotherdata;
+  uint32_t framesize=441000;
+  float32_t periods=8192;
+  const ambix_matrix_t*mtx2=NULL;
+  int64_t err64, gotframes;
+  float32_t diff=0.;
+  ambix_err_t err=0;
+  STARTTEST("ambi=[%dx%d],extra=%d, format=%d datafmt=%d\n",
+	    matrix?matrix->rows:-1, matrix?matrix->cols:-1, extrachannels, format, fmt);
+  resultambidata=data_calloc(fmt, max_u32(fullambichannels, ambixchannels)*framesize);
+  ambidata=data_calloc(fmt, fullambichannels*framesize);
+
+  resultotherdata=data_calloc(fmt, extrachannels*framesize);
+  otherdata=data_calloc(fmt, extrachannels*framesize);
+
+  memset(&info, 0, sizeof(info));
+  info.fileformat=AMBIX_EXTENDED;
+  info.ambichannels=ambixchannels;
+  info.extrachannels=extrachannels;
+  info.samplerate=44100;
+  info.sampleformat=format;
+
+  memcpy(&winfo, &info, sizeof(info));
+  /* we want to write an EXTENDED file using the BASIC api (full set) */
+  winfo.fileformat=AMBIX_BASIC;
+
+  ambix=ambix_open(path, AMBIX_WRITE, &winfo);
+  if(fail_if((NULL==ambix), __LINE__, "couldn't create ambix file '%s' for writing", path))return 1;
+
+  orgambidata =data_sine(fmt, framesize, fullambichannels, periods);
+  orgotherdata=data_ramp(fmt, framesize, extrachannels);
+  if(fail_if((NULL==orgambidata), __LINE__, "couldn't create ambidata %dx%d sine @ %f", (int)framesize, (int)fullambichannels, (float)periods))return 1;
+  if(fail_if((NULL==orgotherdata), __LINE__, "couldn't create otherdata %dx%d sine @ %f", (int)framesize, (int)extrachannels, (float)periods))return 1;
+
+  memcpy(ambidata, orgambidata, framesize*fullambichannels*data_size(fmt));
+  memcpy(otherdata, orgotherdata, framesize*extrachannels*data_size(fmt));
+
+  err=ambix_set_adaptormatrix(ambix, matrix);
+#if 0
+  if(1 || AMBIX_ERR_SUCCESS!=err) {
+    ambix_matrix_t*pinv=0;
+    //printf("adaptor matrix:\n"); matrix_print(matrix);
+    pinv=ambix_matrix_pinv(matrix, pinv);
+    if(pinv) {
+      //printf("pseudo-inverse:\n"); matrix_print(pinv);
+    } else {
+      //printf("no pseudo-inverse!\n");
+      ;
+    }
+    if(pinv)ambix_matrix_destroy(pinv);
+  }
+#endif
+  if(fail_if((AMBIX_ERR_SUCCESS!=err), __LINE__, "failed setting adaptor matrix [%d]", err))return 1;
+
+  if(chunksize>0) {
+    uint32_t subframe=chunksize;
+    uint32_t chunks = framesize/chunksize;
+    uint32_t framesleft=framesize;
+    uint32_t frame;
+    for(frame=0; frame<chunks; frame++) {
+      err64=ambixtest_writef(ambix, fmt,
+                             ambidata, fullambichannels*frame*chunksize, otherdata, extrachannels*frame*chunksize,
+                             chunksize);
+      if(fail_if((err64!=chunksize), __LINE__, "wrote only %d chunksize of %d", (int)err64, (int)chunksize))return 1;
+      framesleft-=chunksize;
+    }
+    subframe=framesleft;
+    err64=ambixtest_writef(ambix, fmt,
+                           ambidata, fullambichannels*frame*chunksize,
+                           otherdata,extrachannels*frame*chunksize,
+                           subframe);
+    if(fail_if((err64!=subframe), __LINE__, "wrote only %d subframe of %d", (int)err64, (int)subframe))return 1;
+
+  } else {
+    err64=ambixtest_writef(ambix, fmt, ambidata, 0, otherdata, 0, framesize);
+    if(fail_if((err64!=framesize), __LINE__, "wrote only %d frames of %d", (int)err64, (int)framesize))return 1;
+  }
+
+  diff=data_diff(__LINE__, fmt, orgambidata, ambidata, framesize*fullambichannels, eps);
+  if(fail_if((diff>eps), __LINE__, "ambidata diff %f > %f", diff, eps))return 1;
+  diff=data_diff(__LINE__, fmt, orgotherdata, otherdata, framesize*extrachannels, eps);
+  if(fail_if((diff>eps), __LINE__, "otherdata diff %f > %f", diff, eps))return 1;
+
+  if(fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix))return 1;
+  ambix=NULL;
+
+  /* read data back via BASIC */
+  STARTTEST("readback BASIC\n");
+  memset(&rinfo, 0, sizeof(rinfo));
+  rinfo.fileformat = AMBIX_BASIC;
+  ambix=ambix_open(path, AMBIX_READ, &rinfo);
+  if(fail_if((NULL==ambix), __LINE__, "couldn't open ambix file '%s' for reading", path))return 1;
+
+  if(fail_if((AMBIX_BASIC!=rinfo.fileformat), __LINE__, "fileformat mismatch %d!=%d", (int)AMBIX_BASIC, (int)rinfo.fileformat))return 1;
+  if(fail_if((info.samplerate!=rinfo.samplerate), __LINE__, "samplerate mismatch %g!=%g", (float)info.samplerate, (float)rinfo.samplerate))return 1;
+  if(fail_if((info.sampleformat!=rinfo.sampleformat), __LINE__, "sampleformat mismatch %d!=%d", (int)info.sampleformat, (int)rinfo.sampleformat))return 1;
+  if(fail_if((fullambichannels!=rinfo.ambichannels), __LINE__, "ambichannels mismatch %d!=%d", (int)fullambichannels, (int)rinfo.ambichannels))return 1;
+  if(fail_if((info.extrachannels!=rinfo.extrachannels), __LINE__, "extrachannels mismatch %d!=%d", (int)info.extrachannels, (int)rinfo.extrachannels))return 1;
+
+  gotframes=0;
+  do {
+    err64=ambixtest_readf(ambix, fmt,
+                          resultambidata,(gotframes*fullambichannels ),
+                          resultotherdata,(gotframes*extrachannels),
+                          (framesize-gotframes));
+    if(fail_if((err64<0), __LINE__, "reading frames failed after %d/%d frames", (int)gotframes, (int)framesize))return 1;
+    gotframes+=err64;
+  } while(err64>0 && gotframes<framesize);
+
+  diff=data_diff(__LINE__, fmt, orgambidata, resultambidata, framesize*fullambichannels, eps);
+  if(fail_if((diff>eps), __LINE__, "ambidata diff %f > %f", diff, eps))return 1;
+
+  diff=data_diff(__LINE__, fmt, orgotherdata, resultotherdata, framesize*extrachannels, eps);
+  if(fail_if((diff>eps), __LINE__, "otherdata diff %f > %f", diff, eps))return 1;
+
+  if(fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix))return 1;
+  ambix=NULL;
+
+  /* read data back via EXTENDED */
+  STARTTEST("readback EXTENDED\n");
+  memset(&rinfo, 0, sizeof(rinfo));
+  rinfo.fileformat = AMBIX_EXTENDED;
+
+  ambix=ambix_open(path, AMBIX_READ, &rinfo);
+  if(fail_if((NULL==ambix), __LINE__, "couldn't open ambix file '%s' for reading", path))return 1;
+
+  if(fail_if((AMBIX_EXTENDED!=rinfo.fileformat), __LINE__, "fileformat mismatch %d!=%d", (int)info.fileformat, (int)rinfo.fileformat))return 1;
+  if(fail_if((info.samplerate!=rinfo.samplerate), __LINE__, "samplerate mismatch %g!=%g", (float)info.samplerate, (float)rinfo.samplerate))return 1;
+  if(fail_if((info.sampleformat!=rinfo.sampleformat), __LINE__, "sampleformat mismatch %d!=%d", (int)info.sampleformat, (int)rinfo.sampleformat))return 1;
+  if(fail_if((info.ambichannels!=rinfo.ambichannels), __LINE__, "ambichannels mismatch %d!=%d", (int)info.ambichannels, (int)rinfo.ambichannels))return 1;
+  if(fail_if((info.extrachannels!=rinfo.extrachannels), __LINE__, "extrachannels mismatch %d!=%d", (int)info.extrachannels, (int)rinfo.extrachannels))return 1;
+
+  mtx2=ambix_get_adaptormatrix(ambix);
+  if(fail_if((NULL==mtx2), __LINE__, "failed reading adaptor matrix"))return 1;
+
+  diff=matrix_diff(__LINE__, matrix, mtx2, eps);
+  if(fail_if((diff>eps), __LINE__, "adaptormatrix diff %f > %f", diff, eps))return 1;
+
+  gotframes=0;
+  do {
+    err64=ambixtest_readf(ambix, fmt,
+                          resultambidata,(gotframes*ambixchannels ),
+                          resultotherdata,(gotframes*extrachannels),
+                          (framesize-gotframes));
+    if(fail_if((err64<0), __LINE__, "reading frames failed after %d/%d frames", (int)gotframes, (int)framesize))return 1;
+    gotframes+=err64;
+  } while(err64>0 && gotframes<framesize);
+  diff=data_diff(__LINE__, fmt, orgotherdata, resultotherdata, framesize*extrachannels, eps);
+  if(fail_if((diff>eps), __LINE__, "otherdata diff %f > %f", diff, eps))return 1;
+
+  if(fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix))return 1;
+  ambix=NULL;
+
+  free(resultambidata);
+  free(ambidata);
+  free(resultotherdata);
+  free(otherdata);
+
+  free(orgambidata);
+  free(orgotherdata);
+
+  ambixtest_rmfile(path);
+  return 0;
+}
diff --git a/libambix/tests/none_float32.c b/libambix/tests/common_basic2extended.h
similarity index 64%
copy from libambix/tests/none_float32.c
copy to libambix/tests/common_basic2extended.h
index 176a0e8..2c72208 100644
--- a/libambix/tests/none_float32.c
+++ b/libambix/tests/common_basic2extended.h
@@ -1,4 +1,4 @@
-/* none_float32 - test ambix none (FLOAT32)
+/* tests/common_basic2extended.h -  AMBIsonics eXchange Library test utilities              -*- c -*-
 
    Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
@@ -21,16 +21,17 @@
 
 */
 
+#ifndef TESTS_COMMON_BASIC2EXTENDED_H
+#define TESTS_COMMON_BASIC2EXTENDED_H
+
 #include "common.h"
-#include <unistd.h>
-#include <string.h>
+
+/* specific helper-functions */
+int check_create_b2e(const char*path, ambix_sampleformat_t format,
+                     ambix_matrix_t*matrix, uint32_t extrachannels,
+                     uint32_t chunksize, ambixtest_presentationformat_t fmt,float32_t eps);
 
 
-void check_create_none(const char*path, ambix_sampleformat_t format);
 
-int main(int argc, char**argv) {
-  check_create_none("test-simple.caf",  AMBIX_SAMPLEFORMAT_FLOAT32);
+#endif /* TESTS_COMMON_BASIC2EXTENDED_H */
 
-  pass();
-  return 0;
-}
diff --git a/libambix/tests/ambix_extended.c b/libambix/tests/common_extended.c
similarity index 90%
rename from libambix/tests/ambix_extended.c
rename to libambix/tests/common_extended.c
index 7d4b46f..fc5adca 100644
--- a/libambix/tests/ambix_extended.c
+++ b/libambix/tests/common_extended.c
@@ -1,6 +1,6 @@
 /* extended - test ambix extended
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -38,7 +38,7 @@ void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_
   const ambix_matrix_t*eye2=NULL;
   int64_t err64, gotframes;
   float32_t diff=0.;
-  STARTTEST("");
+  STARTTEST("\n");
 
   printf("test using '%s' [%d] with chunks of %d and eps=%f\n", path, (int)format, (int)chunksize, eps);
 
@@ -65,9 +65,9 @@ void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_
   ambix=ambix_open(path, AMBIX_WRITE, &rinfo);
   fail_if((NULL==ambix), __LINE__, "couldn't create ambix file '%s' for writing", path);
 
-  orgambidata=data_sine(framesize, ambichannels, periods);
-  orgotherdata=data_ramp(framesize, extrachannels);
-  //data_print(orgdata, 100);
+  orgambidata=data_sine (FLOAT32, framesize, ambichannels, periods);
+  orgotherdata=data_ramp(FLOAT32, framesize, extrachannels);
+  //data_print(FLOAT32, orgdata, 100);
   fail_if((NULL==orgambidata), __LINE__, "couldn't create ambidata %dx%d sine @ %f", (int)framesize, (int)ambichannels, (float)periods);
   fail_if((NULL==orgotherdata), __LINE__, "couldn't create otherdata %dx%d sine @ %f", (int)framesize, (int)extrachannels, (float)periods);
 
@@ -98,9 +98,9 @@ void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_
     fail_if((err64!=framesize), __LINE__, "wrote only %d frames of %d", (int)err64, (int)framesize);
   }
 
-  diff=data_diff(__LINE__, orgambidata, ambidata, framesize*ambichannels, eps);
+  diff=data_diff(__LINE__, FLOAT32, orgambidata, ambidata, framesize*ambichannels, eps);
   fail_if((diff>eps), __LINE__, "ambidata diff %f > %f", diff, eps);
-  diff=data_diff(__LINE__, orgotherdata, otherdata, framesize*extrachannels, eps);
+  diff=data_diff(__LINE__, FLOAT32, orgotherdata, otherdata, framesize*extrachannels, eps);
   fail_if((diff>eps), __LINE__, "otherdata diff %f > %f", diff, eps);
 
   fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix);
@@ -136,10 +136,10 @@ void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_
     gotframes+=err64;
   } while(err64>0 && gotframes<framesize);
 
-  diff=data_diff(__LINE__, orgambidata, resultambidata, framesize*ambichannels, eps);
+  diff=data_diff(__LINE__, FLOAT32, orgambidata, resultambidata, framesize*ambichannels, eps);
   fail_if((diff>eps), __LINE__, "ambidata diff %f > %f", diff, eps);
 
-  diff=data_diff(__LINE__, orgotherdata, resultotherdata, framesize*extrachannels, eps);
+  diff=data_diff(__LINE__, FLOAT32, orgotherdata, resultotherdata, framesize*extrachannels, eps);
   fail_if((diff>eps), __LINE__, "otherdata diff %f > %f", diff, eps);
 
   fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix);
@@ -155,5 +155,5 @@ void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_
 
   ambix_matrix_deinit(&eye);
 
-  unlink(path);
+  ambixtest_rmfile(path);
 }
diff --git a/libambix/tests/ambix_none.c b/libambix/tests/common_none.c
similarity index 91%
rename from libambix/tests/ambix_none.c
rename to libambix/tests/common_none.c
index 13452d2..69380f2 100644
--- a/libambix/tests/ambix_none.c
+++ b/libambix/tests/common_none.c
@@ -1,6 +1,6 @@
 /* none - test ambix none
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -53,8 +53,8 @@ void check_create_none(const char*path, ambix_sampleformat_t format) {
   ambix=ambix_open(path, AMBIX_WRITE, &rinfo);
   fail_if((NULL==ambix), __LINE__, "couldn't create ambix file '%s' for writing", path);
 
-  orgdata=data_sine(frames, channels, periods);
-  //data_print(orgdata, 100);
+  orgdata=data_sine(FLOAT32, frames, channels, periods);
+  //data_print(FLOAT32, orgdata, 100);
 
   memcpy(data, orgdata, frames*channels*sizeof(float32_t));
 
@@ -63,7 +63,7 @@ void check_create_none(const char*path, ambix_sampleformat_t format) {
   err64=ambix_writef_float32(ambix, NULL, data, frames);
   fail_if((err64!=frames), __LINE__, "wrote only %d frames of %d", (int)err64, (int)frames);
 
-  diff=data_diff(__LINE__, orgdata, data, frames*channels, eps);
+  diff=data_diff(__LINE__, FLOAT32, orgdata, data, frames*channels, eps);
   fail_if((diff>eps), __LINE__, "data diff %f > %f", diff, eps);
 
   fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix);
@@ -85,7 +85,7 @@ void check_create_none(const char*path, ambix_sampleformat_t format) {
     gotframes+=err64;
   } while(err64>0 && gotframes<frames);
 
-  diff=data_diff(__LINE__, orgdata, resultdata, frames*channels, eps);
+  diff=data_diff(__LINE__, FLOAT32, orgdata, resultdata, frames*channels, eps);
   fail_if((diff>eps), __LINE__, "data diff %f > %f", diff, eps);
 
   fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix);
@@ -96,7 +96,5 @@ void check_create_none(const char*path, ambix_sampleformat_t format) {
   free(data);
   free(orgdata);
 
-  unlink(path);
+  ambixtest_rmfile(path);
 }
-
-
diff --git a/libambix/tests/const_matrix.c b/libambix/tests/const_matrix.c
new file mode 100644
index 0000000..6cb1678
--- /dev/null
+++ b/libambix/tests/const_matrix.c
@@ -0,0 +1,273 @@
+/* const_matrix - test constness in matrix operations
+
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
+         Institute of Electronic Music and Acoustics (IEM),
+         University of Music and Dramatic Arts, Graz
+
+   This file is part of libambix
+
+   libambix is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   libambix is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+#include <string.h>
+
+static float32_t data_3_2[]= {
+   0.22, 0.46,
+   0.36, 0.53,
+   0.77, 0.85,
+};
+static float32_t data_3_4[]= {
+ 0.320059925923633, -0.616572833442599, -0.758203952544301,  1.397070173352668,
+-0.475395139478048, -2.112396458091558,  1.443108803981482, -0.198593134445739,
+ 0.349719602203337,  2.683861685335670, -0.150602340058839, -0.196372558639406,
+};
+static float32_t data_4_4[]= {
+  0.7131185686247925, 0.1054799265939327, 0.1882023608287114, 0.1496964665104298,
+  0.9035382689904633, 0.0958506183093942, 0.1490156537909140, 0.6730762573692578,
+  0.7110257215280688, 0.4278857180785819, 0.5050723092090162, 0.2342525090113509,
+  0.1917073427152419, 0.3837280931544647, 0.0397484032568303, 0.5895499716980565,
+};
+static float32_t data_4_3[]= {
+   0.19, 0.06, 0.14,
+   0.05, 0.08, 0.44,
+   0.25, 0.90, 0.77,
+   0.83, 0.51, 0.58,
+};
+static float32_t data_4_2[]= {
+   0.1712, 0.2382,
+   0.3786, 0.4394,
+   0.9719, 1.2465,
+   0.8128, 1.1451,
+};
+
+
+static void test__amfd(unsigned int rows, unsigned int cols,
+                       const float32_t*orgdata, unsigned long frames,
+                       uint32_t line, float32_t eps) {
+  ambix_matrix_t*mtx=ambix_matrix_init(rows, cols, NULL);
+  float32_t*data=calloc(frames, sizeof(*orgdata));
+  float32_t errf=0;
+  STARTTEST("[%dx%d]\n", rows, cols);
+  /* make a copy of the org data, and verify it */
+  memcpy(data, orgdata, frames*sizeof(*orgdata));
+  errf = data_diff(line, FLOAT32, orgdata, data, frames, eps);
+  fail_if(!(errf<eps), line, "orgdata differs from memcpy by %g (>%g)", errf, eps);
+
+  /* fill in the data */
+  ambix_matrix_fill_data(mtx, data);
+
+  /* check if data has been modified */
+  errf = data_diff(line, FLOAT32, orgdata, data, frames, eps);
+  fail_if(!(errf<eps), line, "orgdata differs from filled data by %g (>%g)", errf, eps);
+
+  free(data);
+  ambix_matrix_destroy(mtx);
+}
+static void test_ambix_matrix_fill_data (float32_t eps) {
+  /*
+    ambix_err_t ambix_matrix_fill_data (ambix_matrix_t *mtx, const float32_t *data) ;
+   */
+  test__amfd(3, 2, data_3_2, sizeof(data_3_2)/sizeof(*data_3_2), __LINE__, eps);
+  test__amfd(3, 4, data_3_4, sizeof(data_3_4)/sizeof(*data_3_4), __LINE__, eps);
+  test__amfd(4, 2, data_4_2, sizeof(data_4_2)/sizeof(*data_4_2), __LINE__, eps);
+  test__amfd(4, 3, data_4_3, sizeof(data_4_3)/sizeof(*data_4_3), __LINE__, eps);
+  test__amfd(4, 4, data_4_4, sizeof(data_4_4)/sizeof(*data_4_4), __LINE__, eps);
+  STOPTEST("ALL\n");
+}
+
+static void test__amc(unsigned int rows, unsigned int cols,
+                       const float32_t*orgdata, unsigned long frames,
+                       uint32_t line, float32_t eps) {
+  ambix_matrix_t org_mtx;
+  float32_t**org_vectors=calloc(rows, sizeof(*org_vectors));
+  float32_t**org_data=calloc(rows, sizeof(*org_data));
+  ambix_matrix_t*mtx=ambix_matrix_init(rows, cols, NULL);
+  ambix_matrix_t*result=0;
+  ambix_matrix_fill_data(mtx, orgdata);
+  uint32_t r;
+
+  STARTTEST("[%dx%d]\n", rows, cols);
+  /* backup the matrix */
+  memcpy(&org_mtx, mtx, sizeof(org_mtx));
+  memcpy(org_vectors, mtx->data, rows*sizeof(*org_data));
+
+  for(r=0; r<rows; r++) {
+    org_data[r]=calloc(cols, sizeof(*org_data[r]));
+    memcpy(org_data[r], mtx->data[r], cols*sizeof(*org_data[r]));
+  }
+
+  /* call something */
+  result=ambix_matrix_copy(mtx, result);
+
+  /* check whether the mtx has been untouched */
+  fail_if(!(org_mtx.rows==mtx->rows && org_mtx.cols==mtx->cols), line,
+          "original matrix [%dx%d] does not match copied-from matrix [%dx%d]",
+          org_mtx.rows, org_mtx.cols, mtx->rows, mtx->cols);
+  fail_if(!(org_mtx.data==mtx->data), line,
+          "original matrix data [%p] does not match copied-from matrix data [%p]",
+          org_mtx.data, mtx->data);
+  for(r=0; r<org_mtx.rows; r++) {
+    float32_t*org_row=org_mtx.data[r];
+    float32_t*row    =mtx->data[r];
+    float32_t errf=0;
+    fail_if(!(org_row == row), line,
+            "original matrix row[%d: %p] does not match copied-from matrix row[%d: %p]",
+            r, org_row, r, row);
+    /* compare the actual row-vector */
+    errf=data_diff(line, FLOAT32, org_data[r], mtx->data[r], cols, eps);
+    fail_if(!(errf<eps), line, "orgdata differs from copied-from data by %g (>%g)", errf, eps);
+  }
+
+  /* cleanup */
+  ambix_matrix_destroy(mtx);
+  ambix_matrix_destroy(result);
+  free(org_vectors);
+  for(r=0; r<rows; r++) {
+    free(org_data[r]);
+  }
+  free(org_data);
+}
+static void test_ambix_matrix_copy (float32_t eps) {
+  /*
+    ambix_matrix_t *ambix_matrix_copy (const ambix_matrix_t *src, ambix_matrix_t *dest) ;
+   */
+  test__amc(3, 2, data_3_2, sizeof(data_3_2)/sizeof(*data_3_2), __LINE__, eps);
+  test__amc(3, 4, data_3_4, sizeof(data_3_4)/sizeof(*data_3_4), __LINE__, eps);
+  test__amc(4, 2, data_4_2, sizeof(data_4_2)/sizeof(*data_4_2), __LINE__, eps);
+  test__amc(4, 3, data_4_3, sizeof(data_4_3)/sizeof(*data_4_3), __LINE__, eps);
+  test__amc(4, 4, data_4_4, sizeof(data_4_4)/sizeof(*data_4_4), __LINE__, eps);
+  STOPTEST("ALL\n");
+}
+static void test__amm (unsigned int rows1, unsigned int cols1, const float32_t*data1,
+                       unsigned int rows2, unsigned int cols2, const float32_t*data2,
+                        uint32_t line, float32_t eps) {
+  ambix_matrix_t*A=0, *B=0, *result=0;
+  ambix_matrix_t*A0=0, *B0=0;
+  float32_t errf=0;
+  STARTTEST("[%dx%d]*[%dx%d]\n", rows1, cols1, rows2, cols2);
+
+  A=ambix_matrix_init(rows1, cols1, A); ambix_matrix_fill_data(A, data1);
+  B=ambix_matrix_init(rows2, cols2, B); ambix_matrix_fill_data(B, data2);
+  A0=ambix_matrix_copy(A, A0); B0=ambix_matrix_copy(B, B0);
+  result=ambix_matrix_multiply(A, B, result);
+
+  errf=matrix_diff(line, A, A0, eps);
+  fail_if(!(errf<eps), line, "left-hand multiplication matrix has changed by %f (>%f)", errf, eps);
+  errf=matrix_diff(line, B, B0, eps);
+  fail_if(!(errf<eps), line, "right-hand multiplication matrix has changed by %f (>%f)", errf, eps);
+
+  if(A     )ambix_matrix_destroy(A);
+  if(A0    )ambix_matrix_destroy(A0);
+  if(B     )ambix_matrix_destroy(B);
+  if(B0    )ambix_matrix_destroy(B0);
+  if(result)ambix_matrix_destroy(result);
+}
+
+static void test_ambix_matrix_multiply (float32_t eps) {
+  /*
+    ambix_matrix_t *ambix_matrix_multiply (const ambix_matrix_t *A, const ambix_matrix_t *B, ambix_matrix_t *result) ;
+   */
+  test__amm(3,4,data_3_4, 4,4,data_4_4, __LINE__, eps);
+  test__amm(3,4,data_3_4, 4,3,data_4_3, __LINE__, eps);
+  test__amm(3,4,data_3_4, 4,2,data_4_2, __LINE__, eps);
+  test__amm(3,4,data_3_4, 3,2,data_3_4, __LINE__, eps);
+
+  STOPTEST("ALL\n");
+}
+static void test__amp(unsigned int rows, unsigned int cols,
+                      const float32_t*data,
+                      uint32_t line, float32_t eps) {
+  ambix_matrix_t*A=0, *A0=0, *result=0;
+  float32_t errf=0;
+  STARTTEST("[%dx%d]\n", rows, cols);
+
+  A=ambix_matrix_init(rows, cols, A); ambix_matrix_fill_data(A, data);
+  A0=ambix_matrix_copy(A, A0);
+
+  result=ambix_matrix_pinv(A, result);
+
+  errf=matrix_diff(line, A, A0, eps);
+  fail_if(!(errf<eps), line, "pseudo-inverted matrix has changed by %f (>%f)", errf, eps);
+
+  if(A     )ambix_matrix_destroy(A);
+  if(A0    )ambix_matrix_destroy(A0);
+  if(result)ambix_matrix_destroy(result);
+}
+static void test_ambix_matrix_pinv(float32_t eps) {
+  /*
+    ambix_matrix_t* ambix_matrix_pinv(const ambix_matrix_t*matrix, ambix_matrix_t*pinv) ;
+   */
+  test__amp(3, 2, data_3_2, __LINE__, eps);
+  test__amp(3, 4, data_3_4, __LINE__, eps);
+  test__amp(4, 2, data_4_2, __LINE__, eps);
+  test__amp(4, 3, data_4_3, __LINE__, eps);
+  test__amp(4, 4, data_4_4, __LINE__, eps);
+}
+static void test_ambix_matrix_multiply_float32(float32_t eps) {
+  /*
+    ambix_err_t ambix_matrix_multiply_float32(float32_t *dest, const ambix_matrix_t *mtx, const float32_t *source, int64_t frames) ;
+   */
+  STARTTEST("\n");
+  STOPTEST("\n");
+}
+static void test_ambix_matrix_multiply_float64(float32_t eps) {
+  /*
+    ambix_err_t ambix_matrix_multiply_float64(float64_t *dest, const ambix_matrix_t *mtx, const float64_t *source, int64_t frames) ;
+   */
+  STARTTEST("\n");
+  STOPTEST("\n");
+}
+static void test_ambix_matrix_multiply_int32(float32_t eps) {
+  /*
+    ambix_err_t ambix_matrix_multiply_int32(int32_t *dest, const ambix_matrix_t *mtx, const int32_t *source, int64_t frames) ;
+   */
+  STARTTEST("\n");
+  STOPTEST("\n");
+}
+static void test_ambix_matrix_multiply_int16(float32_t eps) {
+  /*
+    ambix_err_t ambix_matrix_multiply_int16(int16_t *dest, const ambix_matrix_t *mtx, const int16_t *source, int64_t frames) ;
+   */
+  STARTTEST("\n");
+  STOPTEST("\n");
+}
+
+
+
+int main(int argc, char**argv) {
+  test_ambix_matrix_fill_data(1e-7);
+  test_ambix_matrix_copy(1e-7);
+  test_ambix_matrix_multiply(1e-7);
+  test_ambix_matrix_pinv(1e-7);
+
+#warning  test_ambix_matrix_multiply_float32(1e-7);
+#warning  test_ambix_matrix_multiply_float64(1e-7);
+#warning  test_ambix_matrix_multiply_int32(1e-7);
+#warning  test_ambix_matrix_multiply_int16(1e-7);
+
+  return pass();
+}
+
+#if 0
+/* FIXXME other constness tests */
+ambix_t *ambix_open (const char *path, const ambix_filemode_t mode, ambix_info_t *ambixinfo) ;
+int64_t ambix_writef_int16 (ambix_t *ambix, const int16_t *ambidata, const int16_t *otherdata, int64_t frames) ;
+int64_t ambix_writef_int32 (ambix_t *ambix, const int32_t *ambidata, const int32_t *otherdata, int64_t frames) ;
+int64_t ambix_writef_float32 (ambix_t *ambix, const float32_t *ambidata, const float32_t *otherdata, int64_t frames) ;
+int64_t ambix_writef_float64 (ambix_t *ambix, const float64_t *ambidata, const float64_t *otherdata, int64_t frames) ;
+ambix_err_t ambix_set_adaptormatrix (ambix_t *ambix, const ambix_matrix_t *matrix) ;
+/* need to test for LATER side-effects: e.g. ambix_set_adaptormatrix() might not do anything NOW, but sometimes later... */
+#endif
diff --git a/libambix/tests/data/Makefile.am b/libambix/tests/data/Makefile.am
new file mode 100644
index 0000000..9412cef
--- /dev/null
+++ b/libambix/tests/data/Makefile.am
@@ -0,0 +1,10 @@
+AUTOMAKE_OPTIONS = foreign
+
+EXTRA_DIST = file1.caf.org
+noinst_DATA=$(EXTRA_DIST:%.org=%)
+
+% :: %.org
+	cp $< $@
+
+clean-local:
+	rm -rf $(noinst_DATA)
diff --git a/libambix/tests/data/file1.caf b/libambix/tests/data/file1.caf.org
similarity index 100%
copy from libambix/tests/data/file1.caf
copy to libambix/tests/data/file1.caf.org
diff --git a/libambix/tests/data/foo.pd b/libambix/tests/data/foo.pd
new file mode 100644
index 0000000..8034140
--- /dev/null
+++ b/libambix/tests/data/foo.pd
@@ -0,0 +1,46 @@
+#N canvas 4 49 450 543 10;
+#X obj 183 105 soundfiler;
+#N canvas 8 49 450 300 tables 0;
+#X obj 100 100 table a0;
+#X obj 100 120 table a1;
+#X obj 100 140 table a2;
+#X obj 100 160 table a3;
+#X obj 100 180 table a4;
+#X obj 100 200 table a5;
+#X obj 100 220 table a6;
+#X obj 100 240 table a7;
+#X obj 100 260 table a8;
+#X restore 315 171 pd tables;
+#X msg 153 203 9;
+#X obj 153 247 until;
+#X obj 153 269 i;
+#X obj 153 291 + 1;
+#X msg 209 254 -1;
+#X obj 153 357 + 100;
+#X obj 153 379 pack;
+#X obj 153 423 s pd-tables;
+#X msg 220 367 clear;
+#X obj 152 225 t f b b;
+#X msg 153 401 obj 100 \$1 table a\$2;
+#X obj 153 313 t f f f;
+#X obj 153 335 * 20;
+#X msg 186 64 read -resize foo.wav a0 a1 a2 a3 a4 a5 a6 a7 a8;
+#X floatatom 183 127 5 0 0 0 - - -;
+#X connect 0 0 16 0;
+#X connect 2 0 11 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 13 0;
+#X connect 6 0 4 1;
+#X connect 7 0 8 0;
+#X connect 8 0 12 0;
+#X connect 10 0 9 0;
+#X connect 11 0 3 0;
+#X connect 11 1 6 0;
+#X connect 11 2 10 0;
+#X connect 12 0 9 0;
+#X connect 13 0 14 0;
+#X connect 13 1 8 1;
+#X connect 13 2 4 1;
+#X connect 14 0 7 0;
+#X connect 15 0 0 0;
diff --git a/libambix/tests/data/file1.caf b/libambix/tests/data/foo.wav
similarity index 99%
rename from libambix/tests/data/file1.caf
rename to libambix/tests/data/foo.wav
index 2afd73e..8788b1f 100644
Binary files a/libambix/tests/data/file1.caf and b/libambix/tests/data/foo.wav differ
diff --git a/libambix/tests/datatest.c b/libambix/tests/datatest.c
new file mode 100644
index 0000000..2e21c8a
--- /dev/null
+++ b/libambix/tests/datatest.c
@@ -0,0 +1,114 @@
+/* data - test generic data functionality
+
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
+         Institute of Electronic Music and Acoustics (IEM),
+         University of Music and Dramatic Arts, Graz
+
+   This file is part of libambix
+
+   libambix is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   libambix is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+#include <string.h>
+#include <stdlib.h>
+
+static float32_t left[]= {
+   0.19, 0.06, 0.14,
+   0.05, 0.08, 0.44,
+   0.25, 0.90, 0.77,
+   0.83, 0.51, 0.58,
+};
+
+void do_diff(float32_t eps) {
+  float32_t errf;
+  unsigned int i;
+  unsigned int size=sizeof(left)/sizeof(*left);
+  float32_t*right=malloc(sizeof(left));
+  float32_t maxeps=eps;
+
+  STARTTEST("\n");
+  data_print(FLOAT32, left, size);
+
+  /* comparisons:
+       - left/right data is NULL
+     - non-failing tests:
+       - all values diff==0
+       - all values diff<eps
+       - few values diff<eps
+       - many values diff<eps
+  */
+  /* compare equal data */
+  STARTTEST("ident\n");
+  errf=data_diff(__LINE__, FLOAT32, left, left, size, eps);
+  fail_if(errf>0.f, __LINE__, "diffing mtx with itself returned %g (>%g)", errf, 0.f);
+
+  /* compare equal data */
+  STARTTEST("equal\n");
+  for(i=0; i<size; i++) {
+    right[i]=left[i];
+  }
+  errf=data_diff(__LINE__, FLOAT32, left, right, size, eps);
+  fail_if(errf>0.f, __LINE__, "diffing mtx with copy returned %g (>%g)", errf, 0.f);
+
+  /* compare data where all values differ, but <eps */
+  STARTTEST("all<eps\n");
+  for(i=0; i<size; i++) {
+    right[i]=left[i]+eps*0.5;
+  }
+  errf=data_diff(__LINE__, FLOAT32, left, right, size, eps);
+  fail_if(errf>eps, __LINE__, "diffing mtx with mtx+eps/2 returned %g (>%g)", errf, size, eps);
+  for(i=0; i<size; i++) {
+    right[i]=left[i]-eps*0.5;
+  }
+  errf=data_diff(__LINE__, FLOAT32, left, right, size, eps);
+  fail_if(errf>eps, __LINE__, "diffing mtx with mtx-eps/2 returned %g (>%g)", errf, size, eps);
+
+  /* compare data where many values differ with <eps; but one with >eps */
+  STARTTEST("most<eps;one>eps\n");
+  for(i=0; i<size; i++) {
+    right[i]=left[i];
+  }
+  for(i=0; i<(size/2); i++) {
+    right[i]=left[i]+eps*0.5;
+  }
+  right[0]=left[0]+eps*1.5;
+  errf=data_diff(__LINE__, FLOAT32, left, right, size, eps);
+  fail_if(errf>(eps*2.0), __LINE__, "diffing mtx with one value>eps returned %g (>%g)", errf, size, eps);
+  fail_if(errf<(eps*1.0), __LINE__, "diffing mtx with one value>eps returned %g (>%g)", errf, size, eps);
+
+  /* compare data where most values differ with >eps */
+  STARTTEST("most>eps\n");
+  for(i=0; i<size; i++) {
+    right[i]=left[i];
+  }
+  maxeps=eps*1.5;
+  for(i=0; i<(size-1); i++) {
+    right[i]=left[i]-maxeps;
+  }
+  errf=data_diff(__LINE__, FLOAT32, left, right, size, eps);
+  fail_if(errf<eps*1.0, __LINE__, "diffing mtx with one value>eps returned %g (<%g)", errf, eps*1.0);
+  fail_if(errf>eps*2.0, __LINE__, "diffing mtx with one value>eps returned %g (<%g)", errf, eps*2.0);
+
+  free(right);
+  STOPTEST("\n");
+}
+
+int main(int argc, char**argv) {
+  do_diff(1e-1);
+  do_diff(1e-7);
+
+  return pass();
+}
diff --git a/libambix/tests/debug_utils.c b/libambix/tests/debug_utils.c
new file mode 100644
index 0000000..048665a
--- /dev/null
+++ b/libambix/tests/debug_utils.c
@@ -0,0 +1,32 @@
+#include "common.h"
+#include "data.h"
+
+/* libambix's private header */
+#include "private.h"
+
+int main(int argc, char**argv) {
+  ambix_info_t*info=NULL;
+  ambix_matrix_t*mtx=NULL;
+  ambix_t*ambix=NULL;
+  _ambix_print_info(info);
+  _ambix_print_matrix(mtx);
+  _ambix_print_ambix(ambix);
+
+  info= calloc(1, sizeof(ambix_info_t));
+  ambix=ambix_open(AMBIXTEST_FILE1, AMBIX_READ, info);
+  fail_if(NULL==ambix, __LINE__, "File was not open");
+
+  _ambix_print_info(info);
+  _ambix_print_ambix(ambix);
+
+  ambix_close(ambix);
+  free(info);
+
+  mtx=ambix_matrix_init(4, 5, mtx);
+  _ambix_print_matrix(mtx);
+  mtx=ambix_matrix_fill(mtx, AMBIX_MATRIX_ONE);
+  _ambix_print_matrix(mtx);
+  ambix_matrix_destroy(mtx);
+
+  return pass();
+}
diff --git a/libambix/tests/extended_float32_0.c b/libambix/tests/extended_float32_0.c
index 187a716..7930001 100644
--- a/libambix/tests/extended_float32_0.c
+++ b/libambix/tests/extended_float32_0.c
@@ -1,25 +1,3 @@
-/* extended_float32_0 - test ambix extended (FLOAT32, blocksize 0)
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
 #include "common.h"
 #include <unistd.h>
 #include <string.h>
@@ -28,8 +6,7 @@
 void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_t chunksize, float32_t eps);
 
 int main(int argc, char**argv) {
-  check_create_extended("test2-float32.caf",AMBIX_SAMPLEFORMAT_FLOAT32, 0, 1e-7);
+  check_create_extended(FILENAME_FILE,AMBIX_SAMPLEFORMAT_FLOAT32, 0, 1e-7);
 
-  pass();
-  return 0;
+  return pass();
 }
diff --git a/libambix/tests/extended_float32_1024.c b/libambix/tests/extended_float32_1024.c
index ad0b316..5f899f2 100644
--- a/libambix/tests/extended_float32_1024.c
+++ b/libambix/tests/extended_float32_1024.c
@@ -1,25 +1,3 @@
-/* extended_float32_1024 - test ambix extended (FLOAT32, blocksize 1024)
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
 #include "common.h"
 #include <unistd.h>
 #include <string.h>
@@ -28,8 +6,7 @@
 void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_t chunksize, float32_t eps);
 
 int main(int argc, char**argv) {
-  check_create_extended("test2-float32.caf",AMBIX_SAMPLEFORMAT_FLOAT32, 1024, 1e-7);
+  check_create_extended(FILENAME_FILE,AMBIX_SAMPLEFORMAT_FLOAT32, 1024, 1e-7);
 
-  pass();
-  return 0;
+  return pass();
 }
diff --git a/libambix/tests/extended_float64_0.c b/libambix/tests/extended_float64_0.c
new file mode 100644
index 0000000..0b1600f
--- /dev/null
+++ b/libambix/tests/extended_float64_0.c
@@ -0,0 +1,12 @@
+#include "common.h"
+#include <unistd.h>
+#include <string.h>
+
+
+void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_t chunksize, float32_t eps);
+
+int main(int argc, char**argv) {
+  check_create_extended(FILENAME_FILE,AMBIX_SAMPLEFORMAT_FLOAT64, 0, 1e-7);
+
+  return pass();
+}
diff --git a/libambix/tests/extended_float64_1024.c b/libambix/tests/extended_float64_1024.c
new file mode 100644
index 0000000..07bb011
--- /dev/null
+++ b/libambix/tests/extended_float64_1024.c
@@ -0,0 +1,12 @@
+#include "common.h"
+#include <unistd.h>
+#include <string.h>
+
+
+void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_t chunksize, float32_t eps);
+
+int main(int argc, char**argv) {
+  check_create_extended(FILENAME_FILE,AMBIX_SAMPLEFORMAT_FLOAT64, 1024, 1e-7);
+
+  return pass();
+}
diff --git a/libambix/tests/extended_pcm16_0.c b/libambix/tests/extended_pcm16_0.c
index 579b390..b49d65b 100644
--- a/libambix/tests/extended_pcm16_0.c
+++ b/libambix/tests/extended_pcm16_0.c
@@ -1,25 +1,3 @@
-/* extended_pcm16_0 - test ambix extended (PCM16, blocksize 0)
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
 #include "common.h"
 #include <unistd.h>
 #include <string.h>
@@ -28,8 +6,7 @@
 void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_t chunksize, float32_t eps);
 
 int main(int argc, char**argv) {
-  check_create_extended("test2-pcm16.caf",  AMBIX_SAMPLEFORMAT_PCM16, 1024, 1./20000.);
+  check_create_extended(FILENAME_FILE,  AMBIX_SAMPLEFORMAT_PCM16, 1024, 1./20000.);
 
-  pass();
-  return 0;
+  return pass();
 }
diff --git a/libambix/tests/extended_pcm16_1024.c b/libambix/tests/extended_pcm16_1024.c
index 54cc9aa..b49d65b 100644
--- a/libambix/tests/extended_pcm16_1024.c
+++ b/libambix/tests/extended_pcm16_1024.c
@@ -1,25 +1,3 @@
-/* extended_pcm16_1024 - test ambix extended (PCM16, blocksize 1024)
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
 #include "common.h"
 #include <unistd.h>
 #include <string.h>
@@ -28,8 +6,7 @@
 void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_t chunksize, float32_t eps);
 
 int main(int argc, char**argv) {
-  check_create_extended("test2-pcm16.caf",  AMBIX_SAMPLEFORMAT_PCM16, 1024, 1./20000.);
+  check_create_extended(FILENAME_FILE,  AMBIX_SAMPLEFORMAT_PCM16, 1024, 1./20000.);
 
-  pass();
-  return 0;
+  return pass();
 }
diff --git a/libambix/tests/extended_pcm32_0.c b/libambix/tests/extended_pcm32_0.c
index 39dcfb7..1c93bdb 100644
--- a/libambix/tests/extended_pcm32_0.c
+++ b/libambix/tests/extended_pcm32_0.c
@@ -1,25 +1,3 @@
-/* extended_pcm32_0 - test ambix extended (PCM32, blocksize 0)
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
 #include "common.h"
 #include <unistd.h>
 #include <string.h>
@@ -28,8 +6,7 @@
 void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_t chunksize, float32_t eps);
 
 int main(int argc, char**argv) {
-  check_create_extended("test2-pcm32.caf",  AMBIX_SAMPLEFORMAT_PCM32, 0, 1e-5);
+  check_create_extended(FILENAME_FILE,  AMBIX_SAMPLEFORMAT_PCM32, 0, 1e-5);
 
-  pass();
-  return 0;
+  return pass();
 }
diff --git a/libambix/tests/extended_pcm32_1024.c b/libambix/tests/extended_pcm32_1024.c
index f10e360..ec25d50 100644
--- a/libambix/tests/extended_pcm32_1024.c
+++ b/libambix/tests/extended_pcm32_1024.c
@@ -1,25 +1,3 @@
-/* extended_pcm32_1024 - test ambix extended (PCM32, blocksize 1024)
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
 #include "common.h"
 #include <unistd.h>
 #include <string.h>
@@ -28,8 +6,7 @@
 void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_t chunksize, float32_t eps);
 
 int main(int argc, char**argv) {
-  check_create_extended("test2-pcm32.caf",  AMBIX_SAMPLEFORMAT_PCM32, 1024, 1e-5);
+  check_create_extended(FILENAME_FILE,  AMBIX_SAMPLEFORMAT_PCM32, 1024, 1e-5);
 
-  pass();
-  return 0;
+  return pass();
 }
diff --git a/libambix/tests/fail.c b/libambix/tests/fail.c
index 963418b..e68ad06 100644
--- a/libambix/tests/fail.c
+++ b/libambix/tests/fail.c
@@ -1,30 +1,5 @@
-/* fail - simple test that always fails
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-
-*/
-
 #include "common.h"
 
 int main(int argc, char**argv) {
-
-  fail();
-  return 0;
+  return fail();
 }
diff --git a/libambix/tests/fail_if0.c b/libambix/tests/fail_if0.c
new file mode 100644
index 0000000..ee8feb0
--- /dev/null
+++ b/libambix/tests/fail_if0.c
@@ -0,0 +1,5 @@
+#include "common.h"
+
+int main(int argc, char**argv) {
+  return fail_if(0, __LINE__, "should %s fail", "NOT");
+}
diff --git a/libambix/tests/fail_if1.c b/libambix/tests/fail_if1.c
new file mode 100644
index 0000000..25957a3
--- /dev/null
+++ b/libambix/tests/fail_if1.c
@@ -0,0 +1,5 @@
+#include "common.h"
+
+int main(int argc, char**argv) {
+  return fail_if(1, __LINE__, "should %s fail", "indeed");
+}
diff --git a/libambix/tests/markers_regions.c b/libambix/tests/markers_regions.c
new file mode 100644
index 0000000..f81bfaf
--- /dev/null
+++ b/libambix/tests/markers_regions.c
@@ -0,0 +1,117 @@
+#include "common.h"
+#include "data.h"
+
+#include <string.h>
+
+int main(int argc, char**argv) {
+  const char*markerfile=FILENAME_FILE;
+  ambix_t*ambix=NULL;
+  ambix_info_t info;
+  memset(&info, 0, sizeof(info));
+  uint32_t frames=441000;
+  uint32_t channels=4;
+  int64_t err64;
+  float32_t*data;
+  
+  info.fileformat=AMBIX_BASIC;
+  info.ambichannels=channels;
+  info.extrachannels=0;
+  info.samplerate=44100;
+  info.sampleformat=AMBIX_SAMPLEFORMAT_FLOAT32;
+  
+  data=(float32_t*)calloc(channels*frames, sizeof(float32_t));
+  
+  ambix=ambix_open(markerfile, AMBIX_WRITE, &info);
+  fail_if(NULL==ambix, __LINE__, "File was not open");
+
+  /* add some markers */
+  ambix_marker_t marker_1;
+  memset(&marker_1, 0, sizeof(ambix_marker_t));
+  marker_1.position = 1.0;
+  strncpy(marker_1.name, "this is marker #1", 255);
+
+  ambix_marker_t marker_2;
+  memset(&marker_2, 0, sizeof(ambix_marker_t));
+  marker_2.position = 2.0;
+  strncpy(marker_2.name, "this is marker #2", 255);
+
+
+  ambix_marker_t marker_3;
+  memset(&marker_3, 0, sizeof(ambix_marker_t));
+  marker_3.position = 3.0;
+
+  fail_if(0!=ambix_add_marker(ambix, &marker_1), __LINE__, "Could not add marker");
+  fail_if(0!=ambix_add_marker(ambix, &marker_2), __LINE__, "Could not add marker");
+  fail_if(0!=ambix_add_marker(ambix, &marker_3), __LINE__, "Could not add marker");
+
+  /* add some regions */
+  ambix_region_t region_1;
+  memset(&region_1, 0, sizeof(ambix_region_t));
+  region_1.start_position = 1.0;
+  region_1.end_position = 2.0;
+  strncpy(region_1.name, "this is region #1", 255);
+
+  ambix_region_t region_2;
+  memset(&region_2, 0, sizeof(ambix_region_t));
+  region_2.start_position = 3.0;
+  region_2.end_position = 4.0;
+  strncpy(region_2.name, "this is region #2", 255);
+
+  ambix_region_t region_3;
+  memset(&region_3, 0, sizeof(ambix_region_t));
+  region_3.start_position = 3.0;
+  region_3.end_position = 4.0;
+
+  fail_if(0!=ambix_add_region(ambix, &region_1), __LINE__, "Could not add region");
+  fail_if(0!=ambix_add_region(ambix, &region_2), __LINE__, "Could not add region");
+  fail_if(0!=ambix_add_region(ambix, &region_3), __LINE__, "Could not add region");
+
+  /* write testsamples */
+  err64=ambix_writef_float32(ambix, data, NULL, frames);
+
+  ambix_close(ambix);
+
+
+  /* open the file again and see wheter the markers and regions have been saved and can be read */
+  memset(&info, 0, sizeof(info));
+  ambix=ambix_open(markerfile, AMBIX_READ, &info);
+
+  fail_if(0 == ambix_get_num_markers(ambix), __LINE__, "No markers in file");
+  fail_if(0 == ambix_get_num_regions(ambix), __LINE__, "No regions in file");
+
+  ambix_marker_t *marker_1_retr;
+  ambix_marker_t *marker_2_retr;
+  ambix_marker_t *marker_3_retr;
+
+  ambix_region_t *region_1_retr;
+  ambix_region_t *region_2_retr;
+  ambix_region_t *region_3_retr;
+
+  marker_1_retr=ambix_get_marker(ambix, 0);
+  marker_2_retr=ambix_get_marker(ambix, 1);
+  marker_3_retr=ambix_get_marker(ambix, 2);
+
+  region_1_retr=ambix_get_region(ambix, 0);
+  region_2_retr=ambix_get_region(ambix, 1);
+  region_3_retr=ambix_get_region(ambix, 2);
+
+  fail_if(marker_1_retr==NULL, __LINE__, "Could not retrieve marker 1");
+  fail_if(marker_2_retr==NULL, __LINE__, "Could not retrieve marker 2");
+  fail_if(marker_3_retr==NULL, __LINE__, "Could not retrieve marker 3");
+  fail_if(region_1_retr==NULL, __LINE__, "Could not retrieve region 1");
+  fail_if(region_2_retr==NULL, __LINE__, "Could not retrieve region 2");
+  fail_if(region_3_retr==NULL, __LINE__, "Could not retrieve region 3");
+
+  fail_if(memcmp(&marker_1, marker_1_retr, sizeof(ambix_marker_t)), __LINE__, "Marker 1 does not match");
+  fail_if(memcmp(&marker_2, marker_2_retr, sizeof(ambix_marker_t)), __LINE__, "Marker 2 does not match");
+  fail_if(memcmp(&marker_3, marker_3_retr, sizeof(ambix_marker_t)), __LINE__, "Marker 3 does not match");
+  fail_if(memcmp(&region_1, region_1_retr, sizeof(ambix_region_t)), __LINE__, "Region 1 does not match");
+  fail_if(memcmp(&region_2, region_2_retr, sizeof(ambix_region_t)), __LINE__, "Region 2 does not match");
+  fail_if(memcmp(&region_3, region_3_retr, sizeof(ambix_region_t)), __LINE__, "Region 3 does not match");
+
+  if(data)
+    free(data);
+  ambix_close(ambix);
+  ambixtest_rmfile(markerfile);
+  return pass();
+}
diff --git a/libambix/tests/matrices.c b/libambix/tests/matrices.c
index 98bf649..531e929 100644
--- a/libambix/tests/matrices.c
+++ b/libambix/tests/matrices.c
@@ -1,6 +1,6 @@
 /* matrices - test preset matrices
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -79,7 +79,7 @@ void check_inversion(const char*name, ambix_matrixtype_t typ, uint32_t rows, uin
   float32_t errf;
   float32_t eps=1e-6;
 
-  STARTTEST(name);
+  STARTTEST("%s\n", name);
 
   result=inverse_matrices(typ, rows, cols);
   eye=ambix_matrix_init(result->rows, result->cols, eye);
@@ -106,7 +106,7 @@ void check_matrix(const char*name, ambix_matrixtype_t typ, uint32_t rows, uint32
   float32_t errf=0.f;
   float32_t eps=1e-20;
 
-  STARTTEST(name);
+  STARTTEST("%s\n", name);
 
   mtx=ambix_matrix_init(rows, cols, mtx);
   skip_if(NULL==mtx, __LINE__, "couldn't create mtx-matrix");
@@ -133,6 +133,21 @@ void check_matrix(const char*name, ambix_matrixtype_t typ, uint32_t rows, uint32
   ambix_matrix_destroy(mtx);
   ambix_matrix_destroy(zeros);
 }
+void check_nomatrix(const char*name, ambix_matrixtype_t typ, uint32_t rows, uint32_t cols) {
+  ambix_matrix_t*mtx=NULL;
+  ambix_matrix_t*result=NULL;
+  float32_t errf=0.f;
+  float32_t eps=1e-20;
+
+  STARTTEST("%s\n", name);
+
+  mtx=ambix_matrix_init(rows, cols, mtx);
+  skip_if(NULL==mtx, __LINE__, "couldn't create mtx-matrix");
+  result=ambix_matrix_fill(mtx, typ);
+  fail_if(NULL!=result, __LINE__, "filled illegal result-matrix");
+  ambix_matrix_destroy(mtx);
+}
+
 
 int main(int argc, char**argv) {
   uint32_t r, c, o;
@@ -159,8 +174,29 @@ int main(int argc, char**argv) {
   check_matrix("FuMa[16, 8]", AMBIX_MATRIX_FUMA, 16,  8);
   check_matrix("FuMa[16,11]", AMBIX_MATRIX_FUMA, 16, 11);
   check_matrix("FuMa[16,16]", AMBIX_MATRIX_FUMA, 16, 16);
-
-
+  check_nomatrix("FuMa[ 4, 2]", AMBIX_MATRIX_FUMA,  4,  2);
+  check_nomatrix("FuMa[16,10]", AMBIX_MATRIX_FUMA, 16, 10);
+  check_nomatrix("FuMa[16,12]", AMBIX_MATRIX_FUMA, 16, 12);
+  check_nomatrix("FuMa[16,13]", AMBIX_MATRIX_FUMA, 16, 13);
+  check_nomatrix("FuMa[16,14]", AMBIX_MATRIX_FUMA, 16, 14);
+  check_nomatrix("FuMa[16,15]", AMBIX_MATRIX_FUMA, 16, 15);
+  check_nomatrix("FuMa[25,25]", AMBIX_MATRIX_FUMA, 25, 25);
+
+  check_nomatrix("MaFu[ 4, 2]", AMBIX_MATRIX_TO_FUMA,  2,  4);
+  check_nomatrix("MaFu[16,10]", AMBIX_MATRIX_TO_FUMA, 10, 16);
+  check_nomatrix("MaFu[16,12]", AMBIX_MATRIX_TO_FUMA, 12, 16);
+  check_nomatrix("MaFu[16,13]", AMBIX_MATRIX_TO_FUMA, 13, 16);
+  check_nomatrix("MaFu[16,14]", AMBIX_MATRIX_TO_FUMA, 14, 16);
+  check_nomatrix("MaFu[16,15]", AMBIX_MATRIX_TO_FUMA, 15, 16);
+  check_nomatrix("MaFu[25,25]", AMBIX_MATRIX_TO_FUMA, 25, 25);
+
+  check_nomatrix("sid2acn [ 7, 7]", AMBIX_MATRIX_SID,  7,  7);
+  check_nomatrix("acn2sid [ 7, 7]", AMBIX_MATRIX_TO_SID,  7,  7);
+  check_nomatrix("n3d->sn3d [ 7, 7]", AMBIX_MATRIX_N3D,  7,  7);
+  check_nomatrix("sn3d->n3d [ 7, 7]", AMBIX_MATRIX_TO_N3D,  7,  7);
+  check_nomatrix("nada[ 4, 4]", AMBIX_MATRIX_INVALID,  4,  4);
+
+  STOPTEST("matrices\n");
 
   check_inversion("FuMa[ 1, 1]", AMBIX_MATRIX_FUMA,  1,  1);
   check_inversion("FuMa[ 4, 3]", AMBIX_MATRIX_FUMA,  4,  3);
@@ -172,6 +208,7 @@ int main(int argc, char**argv) {
   check_inversion("FuMa[16, 8]", AMBIX_MATRIX_FUMA, 16,  8);
   check_inversion("FuMa[16,11]", AMBIX_MATRIX_FUMA, 16, 11);
   check_inversion("FuMa[16,16]", AMBIX_MATRIX_FUMA, 16, 16);
+  STOPTEST("matrix inversion\n");
 
   for(o=1; o<6; o++) {
     uint32_t chan=ambix_order2channels(o);
@@ -191,8 +228,7 @@ int main(int argc, char**argv) {
     snprintf(name, 63, "sid[%d, %d]", chan, chan);
     check_inversion(name, AMBIX_MATRIX_SID,  1,  1);
   }
+  STOPTEST("\n");
 
-
-  pass();
-  return 0;
+  return pass();
 }
diff --git a/libambix/tests/matrix.c b/libambix/tests/matrix.c
deleted file mode 100644
index 49164de..0000000
--- a/libambix/tests/matrix.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/* matrix - test matrix functionality
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "common.h"
-#include <string.h>
-
-static float32_t leftdata_4_3[]= {
-   0.19, 0.06, 0.14,
-   0.05, 0.08, 0.44,
-   0.25, 0.9, 0.77,
-   0.83, 0.51, 0.58,
-};
-
-
-static float32_t rightdata_3_2[]= {
-   0.22, 0.46,
-   0.36, 0.53,
-   0.77, 0.85,
-};
-
-static float32_t resultdata_4_2[]= {
-   0.1712, 0.2382,
-   0.3786, 0.4394,
-   0.9719, 1.2465,
-   0.8128, 1.1451,
-};
-
-void mtxmul_tests(float32_t eps) {
-  float32_t errf;
-  ambix_matrix_t *left, *right, *result, *testresult;
-  STARTTEST("");
-
- /* fill in some test data */
-  left=ambix_matrix_init(4, 3, NULL);
-  ambix_matrix_fill_data(left, leftdata_4_3);
-  right=ambix_matrix_init(3, 2, NULL);
-  ambix_matrix_fill_data(right, rightdata_3_2);
-  testresult=ambix_matrix_init(4, 2, NULL);
-  ambix_matrix_fill_data(testresult, resultdata_4_2);
-
-  errf=matrix_diff(__LINE__, left, left, eps);
-  fail_if(!(errf<eps), __LINE__, "diffing matrix with itself returned %f (>%f)", errf, eps);
-
-  /* do some matrix multiplication */
-  result=ambix_matrix_multiply(left, right, NULL);
-  fail_if((NULL==result), __LINE__, "multiply into NULL did not create matrix");
-
-  fail_if((result!=ambix_matrix_multiply(left, right, result)), __LINE__, "multiply into existing matrix returned new matrix");
-
-#if 0
-  matrix_print(left);
-  matrix_print(right);
-  matrix_print(result);
-  printf("------------\n");
-#endif
-  errf=matrix_diff(__LINE__, testresult, result, eps);
-  fail_if((errf>eps), __LINE__, "diffing two results of same multiplication returned %f (>%f)", errf, eps);
-
-  ambix_matrix_destroy(left);
-  ambix_matrix_destroy(right);
-  ambix_matrix_destroy(result);
-  ambix_matrix_destroy(testresult);
-}
-void mtxmul_eye_tests(float32_t eps) {
-  float32_t errf;
-  ambix_matrix_t *left, *result, *eye;
-  STARTTEST("");
-  eye=ambix_matrix_init(4, 4, NULL);
-  fail_if((eye!=ambix_matrix_fill(eye, AMBIX_MATRIX_IDENTITY)), __LINE__, "filling unity matrix %p did not return original matrix %p", eye);
-
-  left=ambix_matrix_init(4, 2, NULL);
-  fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_fill_data(left, resultdata_4_2), __LINE__,
-          "filling left data failed");
-
-  result=ambix_matrix_init(4, 2, NULL);
-  fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_fill_data(result, resultdata_4_2), __LINE__,
-          "filling result data failed");
-
-  fail_if((result!=ambix_matrix_multiply(eye, left, result)), __LINE__, "multiplication into matrix did not return original matrix");
-#if 0
-  matrix_print(eye);
-  matrix_print(result);
-  matrix_print(left);
-#endif
-  errf=matrix_diff(__LINE__, left, result, eps);
-  fail_if((errf>eps), __LINE__, "diffing matrix M with E*M returned %f (>%f)", errf, eps);
-
-  ambix_matrix_destroy(left);
-  ambix_matrix_destroy(result);
-  ambix_matrix_destroy(eye);
-}
-void datamul_tests(float32_t eps) {
-  float32_t errf;
-  float32_t*resultdata  = (float32_t*)calloc(2*4, sizeof(float32_t));
-  float32_t*resultdataT = (float32_t*)calloc(4*2, sizeof(float32_t));
-  float32_t*inputdata   = (float32_t*)calloc(2*3, sizeof(float32_t));
-
-  fail_if((NULL==resultdata), __LINE__, "couldn't callocate resultdata");
-  fail_if((NULL==resultdataT), __LINE__, "couldn't callocate resultdataT");
-  fail_if((NULL==inputdata), __LINE__, "couldn't callocate inputdata");
-
-  ambix_matrix_t*mtx=NULL;
-  STARTTEST("");
-
-  mtx=ambix_matrix_init(4, 3, NULL);
-  ambix_matrix_fill_data(mtx, leftdata_4_3);
-
-  data_transpose(inputdata, rightdata_3_2, 3, 2);
-
-  fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_multiply_float32(resultdata, mtx, inputdata, 2), __LINE__,
-          "data multiplication failed");
-
-  data_transpose(resultdataT, resultdata, 2, 4);
-
-  errf=data_diff(__LINE__, resultdataT, resultdata_4_2, 4*2, eps);
-  if(errf>eps) {
-    printf("matrix:\n");
-    matrix_print(mtx);
-    printf("input:\n");
-    data_print(inputdata, 3*2);
-
-    printf("expected:\n");
-    data_print(resultdata_4_2, 4*2);
-    printf("calculated:\n");
-    data_print(resultdataT   , 4*2);
-
-  }
-  fail_if(!(errf<eps), __LINE__, "diffing data multiplication returned %f (>%f)", errf, eps);
-
-#if 0
-  printf("matrix:\n");matrix_print(mtx);
-  printf("input :\n");  data_print(rightdata_3_2, 3*2);
-  printf("output:\n");  data_print(resultdata, 4*2);
-
-  printf("target:\n");  data_print(resultdata_4_2, 4*2);
-#endif
-
-
-  if(mtx)ambix_matrix_destroy(mtx);
-  free(resultdata);
-  free(resultdataT);
-  free(inputdata);
-}
-
-void datamul_eye_tests(float32_t eps) {
-  float32_t errf;
-  uint64_t frames=4096;
-  uint32_t channels=16;
-  float32_t*inputdata;
-  float32_t*outputdata;
-  float32_t freq=500;
-  ambix_matrix_t eye = {0, 0, NULL};
-  STARTTEST("");
-
-
-  inputdata =data_sine(frames, channels, freq);
-  outputdata=(float32_t*)malloc(sizeof(float32_t)*frames*channels);
-  fail_if((NULL==outputdata), __LINE__, "couldn't mallocate outputdata");
-
-  ambix_matrix_init(channels, channels, &eye);
-  ambix_matrix_fill(&eye, AMBIX_MATRIX_IDENTITY);
-
-  fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_multiply_float32(outputdata, &eye, inputdata, frames),
-          __LINE__, "data multilplication failed");
-
-  errf=data_diff(__LINE__, inputdata, outputdata, frames*channels, eps);
-  fail_if(!(errf<eps), __LINE__, "diffing data multiplication returned %f (>%f)", errf, eps);
-
-#if 0
-  printf("matrix:\n");  matrix_print(&eye);
-  printf("input :\n");  data_print(inputdata, frames*channels);
-  printf("output:\n");  data_print(outputdata,frames*channels);
-#endif
-
-  free(inputdata);
-  free(outputdata);
-  ambix_matrix_deinit(&eye);
-}
-
-void datamul_4_2_tests(uint32_t chunksize, float32_t eps) {
-  uint32_t r, c, rows, cols;
-  float32_t errf;
-  uint64_t frames=8;
-  uint32_t rawchannels=2;
-  uint32_t cokchannels=4;
-
-  float32_t*inputdata;
-  float32_t*outputdata;
-  float32_t*targetdata;
-
-  float32_t freq=500;
-
-  ambix_matrix_t eye = {0, 0, NULL};
-  STARTTEST("");
-
-
-
-  inputdata =data_sine(frames, rawchannels, freq);
-  targetdata=data_sine(frames, cokchannels, freq);
-
-  outputdata=(float32_t*)malloc(sizeof(float32_t)*frames*cokchannels);
-  fail_if((NULL==outputdata), __LINE__, "couldn't allocate outputdata");
-
-  ambix_matrix_init(cokchannels, rawchannels, &eye);
-  rows=eye.rows;
-  cols=eye.cols;
-
-  for(r=0; r<rows; r++) {
-    for(c=0; c<cols; c++) {
-      eye.data[r][c]=(1+r+c)%2;
-    }
-  }
-
-#if 0
-  matrix_print(&eye);
-  printf("input\n");
-  data_print(inputdata, rawchannels*frames);
-#endif
-
-  fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_multiply_float32(outputdata, &eye, inputdata, frames),
-          __LINE__, "data multilplication failed");
-
-#if 0
-  printf("output\n");
-  data_print(outputdata, cokchannels*frames);
-
-  printf("target\n");
-  data_print(targetdata, cokchannels*frames);
-#endif
-
-
-
-  errf=data_diff(__LINE__, targetdata, outputdata, frames*cokchannels, eps);
-  fail_if(!(errf<eps), __LINE__, "diffing data multiplication returned %f (>%f)", errf, eps);
-
-#if 0
-  printf("matrix:\n");  matrix_print(&eye);
-  printf("input :\n");  data_print(inputdata, frames*channels);
-  printf("output:\n");  data_print(outputdata,frames*channels);
-#endif
-
-  ambix_matrix_deinit(&eye);
-
-  free(inputdata);
-  free(outputdata);
-  free(targetdata);
-}
-
-
-
-
-
-
-
-void create_tests(float32_t eps) {
-  int rows=4;
-  int cols=3;
-  int cols2=2;
-  ambix_matrix_t matrix, *left, *right;
-  STARTTEST("");
-
-  memset(&matrix, 0, sizeof(matrix));
-
-  left=ambix_matrix_create();
-  fail_if((left==NULL), __LINE__, "failed to create left matrix");
-  fail_if((left->rows || left->cols), __LINE__, "created empty matrix has non-zero size");
-  fail_if((left!=ambix_matrix_init(rows, cols, left)), __LINE__, "initializing existing matrix* returned new matrix");
-  fail_if((left->rows!=rows || left->cols!=cols), __LINE__, "created matrix [%dx%d] does not match [%dx%d]", left->rows, left->cols, cols, cols2);
-
-  right=ambix_matrix_init(cols, cols2, NULL);
-  fail_if((right==NULL), __LINE__, "failed to create right matrix");
-  fail_if((right->rows!=cols || right->cols!=cols2), __LINE__, "created matrix [%dx%d] does not match [%dx%d]", right->rows, right->cols, cols, cols2);
-
-  fail_if((&matrix!=ambix_matrix_init(rows, cols2, &matrix)), __LINE__, "initializing existing matrix returned new matrix");
-  fail_if((matrix.rows!=rows || matrix.cols!=cols2), __LINE__, "initialized matrix [%dx%d] does not match [%dx%d]", matrix.rows, matrix.cols, rows, cols2);
-
-
-  ambix_matrix_deinit(&matrix);
-  fail_if((matrix.rows || matrix.cols), __LINE__, "deinitialized matrix is non-zero");
-
-  ambix_matrix_deinit(left);
-  fail_if((left->rows || left->cols), __LINE__, "deinitialized matrix is non-zero");
-
-  ambix_matrix_destroy(left);
-  ambix_matrix_destroy(right);
-}
-
-
-
-int main(int argc, char**argv) {
-#if 1
-  create_tests(1e-7);
-  mtxmul_tests(1e-7);
-  mtxmul_eye_tests(1e-7);
-  datamul_tests(1e-7);
-  datamul_eye_tests(1e-7);
-#endif
-  datamul_4_2_tests(1024, 1e-7);
-
-  pass();
-  return 0;
-}
diff --git a/libambix/tests/matrixtests.c b/libambix/tests/matrixtests.c
new file mode 100644
index 0000000..c013623
--- /dev/null
+++ b/libambix/tests/matrixtests.c
@@ -0,0 +1,600 @@
+/* matrix - test matrix functionality
+
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
+         Institute of Electronic Music and Acoustics (IEM),
+         University of Music and Dramatic Arts, Graz
+
+   This file is part of libambix
+
+   libambix is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   libambix is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "common.h"
+#include <string.h>
+#include <stdlib.h>
+
+static float32_t leftdata_4_3[]= {
+   0.19, 0.06, 0.14,
+   0.05, 0.08, 0.44,
+   0.25, 0.90, 0.77,
+   0.83, 0.51, 0.58,
+};
+static float32_t leftdata_4_4[]= {
+  0.7131185686247925, 0.1054799265939327, 0.1882023608287114, 0.1496964665104298,
+  0.9035382689904633, 0.0958506183093942, 0.1490156537909140, 0.6730762573692578,
+  0.7110257215280688, 0.4278857180785819, 0.5050723092090162, 0.2342525090113509,
+  0.1917073427152419, 0.3837280931544647, 0.0397484032568303, 0.5895499716980565,
+};
+static float32_t rightdata_3_2[]= {
+   0.22, 0.46,
+   0.36, 0.53,
+   0.77, 0.85,
+};
+static float32_t resultdata_4_2[]= {
+  /* leftdata[4,3] * rightdata[3,2] */
+   0.1712, 0.2382,
+   0.3786, 0.4394,
+   0.9719, 1.2465,
+   0.8128, 1.1451,
+};
+static float32_t resultpinv_4_3[] = {
+  /* (leftdata[4,3])^-1 */
+ 0.320059925923633, -0.616572833442599, -0.758203952544301,  1.397070173352668,
+-0.475395139478048, -2.112396458091558,  1.443108803981482, -0.198593134445739,
+ 0.349719602203337,  2.683861685335670, -0.150602340058839, -0.196372558639406,
+};
+static float32_t resultpinv_4_4[] = {
+  /* (leftdata[4,4])^-1 */
+  3.260687761423661,-0.750604578051301,-1.027983295100203, 0.437466478433052,
+  4.478583197847279,-3.527343133136301,-0.883177052786819, 3.240826676373624,
+ -6.751824651655014, 2.959470009112655, 3.874801812795508,-3.203980734335171,
+ -3.520111656963465, 2.340434097800232, 0.647874863173282,-0.339426118611342,
+};
+static void mtxinverse_test(const ambix_matrix_t *mtx, const ambix_matrix_t *result, float32_t eps) {
+  ambix_matrix_t *pinv = 0;
+  ambix_matrix_t *mul=0;
+  ambix_matrix_t *eye=0;
+  float32_t errf;
+  int min_rowcol=(mtx->cols<mtx->rows)?mtx->cols:mtx->rows;
+
+  fail_if((NULL==mtx), __LINE__, "cannot invert NULL-matrix");
+  eye=ambix_matrix_init(min_rowcol, min_rowcol, eye);
+  eye=ambix_matrix_fill(eye, AMBIX_MATRIX_IDENTITY);
+  fail_if((NULL==eye), __LINE__, "cannot create eye-matrix for pinv-verification");
+
+  pinv=ambix_matrix_pinv(mtx, pinv);
+  if(NULL==pinv)matrix_print(mtx);
+  fail_if((NULL==pinv), __LINE__, "could not invert matrix");
+
+  if(mtx->cols < mtx->rows)
+    mul=ambix_matrix_multiply(pinv, mtx, 0);
+  else
+    mul=ambix_matrix_multiply(mtx, pinv, 0);
+
+#if 0
+  matrix_print(mtx);
+  matrix_print(pinv);
+  matrix_print(mul);
+  if(result)matrix_print(result);
+  printf("------------\n");
+#endif
+
+  if(result) {
+    errf=matrix_diff(__LINE__, pinv, result, eps);
+    fail_if((errf>eps), __LINE__, "diffing (pseudo)inverse returned %g (>%g)", errf, eps);
+
+    errf=matrix_diff(__LINE__, mul, eye, eps);
+    fail_if((errf>eps), __LINE__, "diffing mtx*pinv(mtx) returned %g (>%g)", errf, eps);
+  } else {
+    errf=matrix_diff(__LINE__, mul, eye, eps);
+    fail_if((!(isnan(errf) || isinf(errf) || (errf>eps))), __LINE__, "diffing invalid mtx*pinv(mtx) returned %g (!>%g)", errf, eps);
+  }
+
+  ambix_matrix_destroy(pinv);
+  ambix_matrix_destroy(mul);
+  ambix_matrix_destroy(eye);
+}
+void mtxinverse_tests(float32_t eps) {
+  float32_t errf;
+  ambix_matrix_t *mtx=0, *testresult=0;
+  float32_t*transposedata = (float32_t*)calloc(3*4, sizeof(float32_t));
+
+  STARTTEST("\n");
+
+  /* fill in some test data 4x4 */
+  STARTTEST("[4x4]\n");
+  mtx=ambix_matrix_init(4, 4, mtx);
+  ambix_matrix_fill_data(mtx, leftdata_4_4);
+  testresult=ambix_matrix_init(4, 4, testresult);
+  ambix_matrix_fill_data(testresult, resultpinv_4_4);
+  mtxinverse_test(mtx, testresult, eps);
+
+  /* fill in some test data 4x3 */
+  STARTTEST("[4x3]\n");
+  mtx=ambix_matrix_init(4, 3, mtx);
+  ambix_matrix_fill_data(mtx, leftdata_4_3);
+  testresult=ambix_matrix_init(3, 4, testresult);
+  ambix_matrix_fill_data(testresult, resultpinv_4_3);
+  mtxinverse_test(mtx, testresult, eps);
+
+  /* fill in some test data 3x4 */
+  STARTTEST("[3x4]\n");
+  data_transpose(transposedata, leftdata_4_3, 4, 3);
+  mtx=ambix_matrix_init(3, 4, mtx);
+  ambix_matrix_fill_data(mtx, transposedata);
+
+  data_transpose(transposedata, resultpinv_4_3, 3, 4);
+  testresult=ambix_matrix_init(4, 3, testresult);
+  ambix_matrix_fill_data(testresult, transposedata);
+  mtxinverse_test(mtx, testresult, eps);
+
+  /* fill in some test data 4x4 */
+  STARTTEST("[identity:4x4]\n");
+  mtx=ambix_matrix_init(4, 4, mtx);
+  ambix_matrix_fill(mtx, AMBIX_MATRIX_IDENTITY);
+  testresult=ambix_matrix_init(4, 4, testresult);
+  ambix_matrix_fill(testresult, AMBIX_MATRIX_IDENTITY);
+  mtxinverse_test(mtx, testresult, eps);
+
+  STARTTEST("[one:4x4]\n");
+  mtx=ambix_matrix_init(4, 4, mtx);
+  ambix_matrix_fill(mtx, AMBIX_MATRIX_ONE);
+  mtxinverse_test(mtx, NULL, eps);
+  STARTTEST("[zero:4x4]\n");
+  mtx=ambix_matrix_init(4, 4, mtx);
+  ambix_matrix_fill(mtx, AMBIX_MATRIX_ZERO);
+  mtxinverse_test(mtx, NULL, eps);
+
+  STARTTEST("[SID:4x4]\n");
+  mtx=ambix_matrix_init(4, 4, mtx);
+  ambix_matrix_fill(mtx, AMBIX_MATRIX_SID);
+  testresult=ambix_matrix_init(4, 4, testresult);
+  ambix_matrix_fill(testresult, AMBIX_MATRIX_TO_SID);
+  mtxinverse_test(mtx, testresult, eps);
+
+  STARTTEST("[N3D:4x4]\n");
+  mtx=ambix_matrix_init(4, 4, mtx);
+  ambix_matrix_fill(mtx, AMBIX_MATRIX_N3D);
+  testresult=ambix_matrix_init(4, 4, testresult);
+  ambix_matrix_fill(testresult, AMBIX_MATRIX_TO_N3D);
+  mtxinverse_test(mtx, testresult, eps);
+
+  STARTTEST("[FUMA:4x4]\n");
+  mtx=ambix_matrix_init(4, 4, mtx);
+  ambix_matrix_fill(mtx, AMBIX_MATRIX_FUMA);
+  testresult=ambix_matrix_init(4, 4, testresult);
+  ambix_matrix_fill(testresult, AMBIX_MATRIX_TO_FUMA);
+  mtxinverse_test(mtx, testresult, eps);
+
+
+  ambix_matrix_destroy(mtx);
+  ambix_matrix_destroy(testresult);
+  free(transposedata);
+  STOPTEST("\n");
+}
+void mtxmul_tests(float32_t eps) {
+  float32_t errf;
+  ambix_matrix_t *left=NULL, *right=NULL, *result, *testresult;
+  STARTTEST("\n");
+
+ /* fill in some test data */
+  left=ambix_matrix_init(4, 3, NULL);
+  ambix_matrix_fill_data(left, leftdata_4_3);
+  right=ambix_matrix_init(3, 2, NULL);
+  ambix_matrix_fill_data(right, rightdata_3_2);
+  testresult=ambix_matrix_init(4, 2, NULL);
+  ambix_matrix_fill_data(testresult, resultdata_4_2);
+
+  errf=matrix_diff(__LINE__, left, left, eps);
+  fail_if(!(errf<eps), __LINE__, "diffing matrix with itself returned %f (>%f)", errf, eps);
+
+  /* NULL multiplications */
+  result=ambix_matrix_multiply(NULL, NULL, NULL);
+  fail_if(NULL!=result, __LINE__, "multiplying NULL*NULL returned success");
+  result=ambix_matrix_multiply(left, NULL, result);
+  fail_if(NULL!=result, __LINE__, "multiplying left*NULL returned success");
+  result=ambix_matrix_multiply(NULL, left, result);
+  fail_if(NULL!=result, __LINE__, "multiplying NULL*left returned success");
+
+  /* do some matrix multiplication */
+  result=ambix_matrix_multiply(left, right, NULL);
+  fail_if((NULL==result), __LINE__, "multiply into NULL did not create matrix");
+
+  fail_if((result!=ambix_matrix_multiply(left, right, result)), __LINE__, "multiply into existing matrix returned new matrix");
+
+#if 0
+  matrix_print(left);
+  matrix_print(right);
+  matrix_print(result);
+  printf("------------\n");
+#endif
+  errf=matrix_diff(__LINE__, testresult, result, eps);
+  fail_if((errf>eps), __LINE__, "diffing two results of same multiplication returned %f (>%f)", errf, eps);
+
+  ambix_matrix_destroy(left);
+  ambix_matrix_destroy(right);
+  ambix_matrix_destroy(result);
+  ambix_matrix_destroy(testresult);
+  STOPTEST("\n");
+}
+void mtxmul_eye_tests(float32_t eps) {
+  float32_t errf;
+  ambix_matrix_t *left, *result, *eye;
+  STARTTEST("\n");
+  eye=ambix_matrix_init(4, 4, NULL);
+  fail_if((eye!=ambix_matrix_fill(eye, AMBIX_MATRIX_IDENTITY)), __LINE__, "filling unity matrix %p did not return original matrix %p", eye);
+
+  left=ambix_matrix_init(4, 2, NULL);
+  fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_fill_data(left, resultdata_4_2), __LINE__,
+          "filling left data failed");
+
+  result=ambix_matrix_init(4, 2, NULL);
+  fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_fill_data(result, resultdata_4_2), __LINE__,
+          "filling result data failed");
+
+  fail_if((result!=ambix_matrix_multiply(eye, left, result)), __LINE__, "multiplication into matrix did not return original matrix");
+#if 0
+  matrix_print(eye);
+  matrix_print(result);
+  matrix_print(left);
+#endif
+  errf=matrix_diff(__LINE__, left, result, eps);
+  fail_if((errf>eps), __LINE__, "diffing matrix M with E*M returned %f (>%f)", errf, eps);
+
+  ambix_matrix_destroy(left);
+  ambix_matrix_destroy(result);
+  ambix_matrix_destroy(eye);
+  STOPTEST("\n");
+}
+void datamul_tests(float32_t eps) {
+  float32_t errf;
+  float32_t*resultdata  = (float32_t*)calloc(2*4, sizeof(float32_t));
+  float32_t*resultdataT = (float32_t*)calloc(4*2, sizeof(float32_t));
+  float32_t*inputdata   = (float32_t*)calloc(2*3, sizeof(float32_t));
+
+  fail_if((NULL==resultdata), __LINE__, "couldn't callocate resultdata");
+  fail_if((NULL==resultdataT), __LINE__, "couldn't callocate resultdataT");
+  fail_if((NULL==inputdata), __LINE__, "couldn't callocate inputdata");
+
+  ambix_matrix_t*mtx=NULL;
+  STARTTEST("\n");
+
+  mtx=ambix_matrix_init(4, 3, NULL);
+  ambix_matrix_fill_data(mtx, leftdata_4_3);
+
+  data_transpose(inputdata, rightdata_3_2, 3, 2);
+
+  fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_multiply_float32(resultdata, mtx, inputdata, 2), __LINE__,
+          "data multiplication failed");
+
+  data_transpose(resultdataT, resultdata, 2, 4);
+
+  errf=data_diff(__LINE__, FLOAT32, resultdataT, resultdata_4_2, 4*2, eps);
+  if(errf>eps) {
+    printf("matrix:\n");
+    matrix_print(mtx);
+    printf("input:\n");
+    data_print(FLOAT32, inputdata, 3*2);
+
+    printf("expected:\n");
+    data_print(FLOAT32, resultdata_4_2, 4*2);
+    printf("calculated:\n");
+    data_print(FLOAT32, resultdataT   , 4*2);
+
+  }
+  fail_if(!(errf<eps), __LINE__, "diffing data multiplication returned %f (>%f)", errf, eps);
+
+#if 0
+  printf("matrix:\n");matrix_print(mtx);
+  printf("input :\n");  data_print(FLOAT32, rightdata_3_2, 3*2);
+  printf("output:\n");  data_print(FLOAT32, resultdata, 4*2);
+
+  printf("target:\n");  data_print(FLOAT32, resultdata_4_2, 4*2);
+#endif
+
+
+  if(mtx)ambix_matrix_destroy(mtx);
+  free(resultdata);
+  free(resultdataT);
+  free(inputdata);
+  STOPTEST("\n");
+}
+
+void datamul_eye_tests(float32_t eps) {
+  float32_t errf;
+  uint64_t frames=4096;
+  uint32_t channels=16;
+  float32_t*inputdata;
+  float32_t*outputdata;
+  float32_t freq=500;
+  ambix_matrix_t eye = {0, 0, NULL};
+  STARTTEST("\n");
+
+  inputdata =data_sine(FLOAT32, frames, channels, freq);
+  outputdata=(float32_t*)malloc(sizeof(float32_t)*frames*channels);
+  fail_if((NULL==outputdata), __LINE__, "couldn't mallocate outputdata");
+
+  ambix_matrix_init(channels, channels, &eye);
+  ambix_matrix_fill(&eye, AMBIX_MATRIX_IDENTITY);
+
+  fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_multiply_float32(outputdata, &eye, inputdata, frames),
+          __LINE__, "data multilplication failed");
+
+  errf=data_diff(__LINE__, FLOAT32, inputdata, outputdata, frames*channels, eps);
+  fail_if(!(errf<eps), __LINE__, "diffing data multiplication returned %f (>%f)", errf, eps);
+
+#if 0
+  printf("matrix:\n");  matrix_print(&eye);
+  printf("input :\n");  data_print(FLOAT32, inputdata, frames*channels);
+  printf("output:\n");  data_print(FLOAT32, outputdata,frames*channels);
+#endif
+
+  free(inputdata);
+  free(outputdata);
+  ambix_matrix_deinit(&eye);
+  STOPTEST("\n");
+}
+
+void datamul_4_2_tests(uint32_t chunksize, float32_t eps) {
+  uint32_t r, c, rows, cols;
+  float32_t errf;
+  uint64_t frames=8;
+  uint32_t rawchannels=2;
+  uint32_t cokchannels=4;
+
+  float32_t*inputdata;
+  float32_t*outputdata;
+  float32_t*targetdata;
+
+  float32_t freq=500;
+
+  ambix_matrix_t eye = {0, 0, NULL};
+  STARTTEST("\n");
+
+  inputdata =data_sine(FLOAT32, frames, rawchannels, freq);
+  targetdata=data_sine(FLOAT32, frames, cokchannels, freq);
+
+  outputdata=(float32_t*)malloc(sizeof(float32_t)*frames*cokchannels);
+  fail_if((NULL==outputdata), __LINE__, "couldn't allocate outputdata");
+
+  ambix_matrix_init(cokchannels, rawchannels, &eye);
+  rows=eye.rows;
+  cols=eye.cols;
+
+  for(r=0; r<rows; r++) {
+    for(c=0; c<cols; c++) {
+      eye.data[r][c]=(1+r+c)%2;
+    }
+  }
+
+#if 0
+  matrix_print(&eye);
+  printf("input\n");
+  data_print(FLOAT32, inputdata, rawchannels*frames);
+#endif
+
+  fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_multiply_float32(outputdata, &eye, inputdata, frames),
+          __LINE__, "data multilplication failed");
+
+#if 0
+  printf("output\n");
+  data_print(FLOAT32, outputdata, cokchannels*frames);
+
+  printf("target\n");
+  data_print(FLOAT32, targetdata, cokchannels*frames);
+#endif
+
+
+
+  errf=data_diff(__LINE__, FLOAT32, targetdata, outputdata, frames*cokchannels, eps);
+  fail_if(!(errf<eps), __LINE__, "diffing data multiplication returned %f (>%f)", errf, eps);
+
+#if 0
+  printf("matrix:\n");  matrix_print(&eye);
+  printf("input :\n");  data_print(FLOAT32, inputdata, frames*channels);
+  printf("output:\n");  data_print(FLOAT32, outputdata,frames*channels);
+#endif
+
+  ambix_matrix_deinit(&eye);
+
+  free(inputdata);
+  free(outputdata);
+  free(targetdata);
+  STOPTEST("\n");
+}
+
+void mtx_copy(float32_t eps) {
+  float32_t errf;
+  ambix_matrix_t *left=NULL, *right=NULL;
+  unsigned int i;
+  float32_t maxeps=eps;
+
+  STARTTEST("\n");
+
+  right=ambix_matrix_copy(left, NULL);
+  fail_if((NULL!=right), __LINE__, "copying from NULL matrix erroneously succeeded");
+
+  left=ambix_matrix_create();
+  fail_if((left !=ambix_matrix_init(4, 3, left )), __LINE__, "initializing left matrix failed");
+  ambix_matrix_fill_data(left, leftdata_4_3);
+
+  right=ambix_matrix_copy(left, NULL);
+  fail_if((NULL==right), __LINE__, "copying to NULL matrix failed");
+  errf=matrix_diff(__LINE__, left, right, eps);
+  fail_if(errf>0.f, __LINE__, "diffing mtx with copy0 returned %g (>%g)", errf, 0.f);
+
+  right=ambix_matrix_copy(left, right);
+  fail_if((NULL==right), __LINE__, "copying to right matrix failed");
+  errf=matrix_diff(__LINE__, left, right, eps);
+  fail_if(errf>0.f, __LINE__, "diffing mtx with copy returned %g (>%g)", errf, 0.f);
+
+  ambix_matrix_destroy(left);
+  ambix_matrix_destroy(right);
+  STOPTEST("\n");
+
+}
+
+void mtx_diff(float32_t eps) {
+  float32_t errf;
+  ambix_matrix_t *left=NULL, *right=NULL;
+  unsigned int i;
+  const unsigned int rows=4;
+  const unsigned int cols=3;
+  float32_t*leftdata=leftdata_4_3;
+  float32_t*rightdata=malloc(sizeof(leftdata_4_3));
+  float32_t maxeps=eps;
+
+  STARTTEST("\n");
+
+  left=ambix_matrix_create();
+  right=ambix_matrix_create();
+
+  /* comparisons:
+     - failing tests:
+       - different dimensions
+       - left/right matrix is NULL
+     - non-failing tests:
+       - all values diff==0
+       - all values diff<eps
+       - few values diff<eps
+       - many values diff<eps
+  */
+  fail_if((left !=ambix_matrix_init(3, 4, left )), __LINE__, "initializing left matrix failed");
+  fail_if((right!=ambix_matrix_init(3, 4, right)), __LINE__, "initializing right matrix failed");
+
+  /* compare equal matrices */
+  STARTTEST("ident\n");
+  ambix_matrix_fill_data(left, leftdata);
+  errf=matrix_diff(__LINE__, left, left, eps);
+  fail_if(errf>0.f, __LINE__, "diffing mtx with itself returned %g (>%g)", errf, 0.f);
+
+  /* compare equal matrices */
+  STARTTEST("equal\n");
+  for(i=0; i<rows*cols; i++) {
+    rightdata[i]=leftdata[i];
+  }
+  ambix_matrix_fill_data(left , leftdata);
+  ambix_matrix_fill_data(right, rightdata);
+  errf=matrix_diff(__LINE__, left, right, eps);
+  fail_if(errf>0.f, __LINE__, "diffing mtx with copy returned %g (>%g)", errf, 0.f);
+
+  /* compare matrices where all values differ, but <eps */
+  STARTTEST("all<eps\n");
+  for(i=0; i<rows*cols; i++) {
+    rightdata[i]=leftdata[i]+eps*0.5;
+  }
+  ambix_matrix_fill_data(left , leftdata);
+  ambix_matrix_fill_data(right, rightdata);
+  errf=matrix_diff(__LINE__, left, right, eps);
+  fail_if(errf>eps, __LINE__, "diffing mtx with mtx+eps/2 returned %g (>%g)", errf, eps);
+  for(i=0; i<rows*cols; i++) {
+    rightdata[i]=leftdata[i]-eps*0.5;
+  }
+  ambix_matrix_fill_data(left , leftdata);
+  ambix_matrix_fill_data(right, rightdata);
+  errf=matrix_diff(__LINE__, left, right, eps);
+  fail_if(errf>eps, __LINE__, "diffing mtx with mtx-eps/2 returned %g (>%g)", errf, eps);
+
+  /* compare matrices where many values differ with <eps; but one with >eps */
+  STARTTEST("most<eps;one>eps\n");
+  for(i=0; i<rows*cols; i++) {
+    rightdata[i]=leftdata[i];
+  }
+  for(i=0; i<rows; i++) {
+    rightdata[i]=leftdata[i]+eps*0.5;
+  }
+  rightdata[0]=leftdata[0]+eps*1.5;
+  ambix_matrix_fill_data(left , leftdata);
+  ambix_matrix_fill_data(right, rightdata);
+  errf=matrix_diff(__LINE__, left, right, eps);
+  fail_if(errf>(eps*2.0), __LINE__, "diffing mtx with one value>eps returned %g (>%g)", errf, eps);
+  fail_if(errf<(eps*1.0), __LINE__, "diffing mtx with one value>eps returned %g (>%g)", errf, eps);
+
+  /* compare matrices where most values differ with >eps */
+  STARTTEST("most>eps\n");
+  for(i=0; i<rows*cols; i++) {
+    rightdata[i]=leftdata[i];
+  }
+  maxeps=eps*1.5;
+  for(i=0; i<(rows*cols)-1; i++) {
+    rightdata[i]=leftdata[i]-maxeps;
+  }
+  ambix_matrix_fill_data(left , leftdata);
+  ambix_matrix_fill_data(right, rightdata);
+  errf=matrix_diff(__LINE__, left, right, eps);
+  fail_if(errf<eps*1.0, __LINE__, "diffing mtx with one value>eps returned %g (<%g)", errf, eps*1.0);
+  fail_if(errf>eps*2.0, __LINE__, "diffing mtx with one value>eps returned %g (<%g)", errf, eps*2.0);
+
+  ambix_matrix_destroy(left);
+  ambix_matrix_destroy(right);
+  free(rightdata);
+  STOPTEST("\n");
+}
+
+void create_tests(float32_t eps) {
+  int rows=4;
+  int cols=3;
+  int cols2=2;
+  ambix_matrix_t matrix, *left, *right;
+  STARTTEST("\n");
+
+  memset(&matrix, 0, sizeof(matrix));
+  matrix_print(&matrix);
+
+  left=ambix_matrix_create();
+  fail_if((left==NULL), __LINE__, "failed to create left matrix");
+  fail_if((left->rows || left->cols), __LINE__, "created empty matrix has non-zero size");
+  fail_if((left!=ambix_matrix_init(rows, cols, left)), __LINE__, "initializing existing matrix* returned new matrix");
+  fail_if((left->rows!=rows || left->cols!=cols), __LINE__, "created matrix [%dx%d] does not match [%dx%d]", left->rows, left->cols, cols, cols2);
+  matrix_print(left);
+
+  right=ambix_matrix_init(cols, cols2, NULL);
+  fail_if((right==NULL), __LINE__, "failed to create right matrix");
+  fail_if((right->rows!=cols || right->cols!=cols2), __LINE__, "created matrix [%dx%d] does not match [%dx%d]", right->rows, right->cols, cols, cols2);
+  matrix_print(right);
+
+  fail_if((&matrix!=ambix_matrix_init(rows, cols2, &matrix)), __LINE__, "initializing existing matrix returned new matrix");
+  fail_if((matrix.rows!=rows || matrix.cols!=cols2), __LINE__, "initialized matrix [%dx%d] does not match [%dx%d]", matrix.rows, matrix.cols, rows, cols2);
+
+
+  ambix_matrix_deinit(&matrix);
+  fail_if((matrix.rows || matrix.cols), __LINE__, "deinitialized matrix is non-zero");
+
+  ambix_matrix_deinit(left);
+  fail_if((left->rows || left->cols), __LINE__, "deinitialized matrix is non-zero");
+
+  ambix_matrix_destroy(left);
+  ambix_matrix_destroy(right);
+  STOPTEST("\n");
+}
+
+
+
+int main(int argc, char**argv) {
+#if 1
+  create_tests(1e-7);
+  mtx_copy(1e-7);
+  mtx_diff(1e-1);
+  mtx_diff(1e-7);
+  mtxmul_tests(1e-7);
+  mtxmul_eye_tests(1e-7);
+  datamul_tests(1e-7);
+  datamul_eye_tests(1e-7);
+#endif
+  datamul_4_2_tests(1024, 1e-7);
+  mtxinverse_tests(1e-5);
+
+  return pass();
+}
diff --git a/libambix/tests/none_float32.c b/libambix/tests/none_float32.c
index 176a0e8..c4111a6 100644
--- a/libambix/tests/none_float32.c
+++ b/libambix/tests/none_float32.c
@@ -29,8 +29,7 @@
 void check_create_none(const char*path, ambix_sampleformat_t format);
 
 int main(int argc, char**argv) {
-  check_create_none("test-simple.caf",  AMBIX_SAMPLEFORMAT_FLOAT32);
+  check_create_none(FILENAME_FILE,  AMBIX_SAMPLEFORMAT_FLOAT32);
 
-  pass();
-  return 0;
+  return pass();
 }
diff --git a/libambix/tests/none_float32.c b/libambix/tests/none_float64.c
similarity index 83%
copy from libambix/tests/none_float32.c
copy to libambix/tests/none_float64.c
index 176a0e8..b3cfec3 100644
--- a/libambix/tests/none_float32.c
+++ b/libambix/tests/none_float64.c
@@ -1,6 +1,6 @@
-/* none_float32 - test ambix none (FLOAT32)
+/* none_float32 - test ambix none (FLOAT64)
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -29,8 +29,7 @@
 void check_create_none(const char*path, ambix_sampleformat_t format);
 
 int main(int argc, char**argv) {
-  check_create_none("test-simple.caf",  AMBIX_SAMPLEFORMAT_FLOAT32);
+  check_create_none(FILENAME_FILE,  AMBIX_SAMPLEFORMAT_FLOAT64);
 
-  pass();
-  return 0;
+  return pass();
 }
diff --git a/libambix/tests/pass.c b/libambix/tests/pass.c
index 5505cd7..0d400e9 100644
--- a/libambix/tests/pass.c
+++ b/libambix/tests/pass.c
@@ -25,6 +25,5 @@
 
 int main(int argc, char**argv) {
 
-  pass();
-  return 0;
+  return pass();
 }
diff --git a/libambix/tests/pass_if0.c b/libambix/tests/pass_if0.c
new file mode 100644
index 0000000..9dd5498
--- /dev/null
+++ b/libambix/tests/pass_if0.c
@@ -0,0 +1,5 @@
+#include "common.h"
+
+int main(int argc, char**argv) {
+  return pass_if(0, __LINE__, "should %s pass", "NOT");
+}
diff --git a/libambix/tests/pass_if1.c b/libambix/tests/pass_if1.c
new file mode 100644
index 0000000..764222c
--- /dev/null
+++ b/libambix/tests/pass_if1.c
@@ -0,0 +1,5 @@
+#include "common.h"
+
+int main(int argc, char**argv) {
+  return pass_if(1, __LINE__, "should %s pass", "indeed");
+}
diff --git a/libambix/tests/runtest.sh b/libambix/tests/runtest.sh
index 36ffce5..fb6600a 100755
--- a/libambix/tests/runtest.sh
+++ b/libambix/tests/runtest.sh
@@ -32,7 +32,6 @@ case "$1" in
     echo ${HELGRIND}
  ;;
  *)
-    
  ;;
 esac
 }
diff --git a/libambix/tests/simple_float32.c b/libambix/tests/simple_float32.c
deleted file mode 100644
index 9bd0834..0000000
--- a/libambix/tests/simple_float32.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* simple_float32 - test ambix simple (FLOAT32)
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "common.h"
-void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t eps);
-
-int main(int argc, char**argv) {
-  check_create_simple("test-float32.caf",  AMBIX_SAMPLEFORMAT_FLOAT32, 1e-7);
-  pass();
-  return 0;
-}
diff --git a/libambix/tests/simple_pcm16.c b/libambix/tests/simple_pcm16.c
deleted file mode 100644
index cd4812d..0000000
--- a/libambix/tests/simple_pcm16.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* simple_pcm16 - test ambix simple (PCM32)
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "common.h"
-void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t eps);
-
-int main(int argc, char**argv) {
-  check_create_simple("test-pcm16.caf",  AMBIX_SAMPLEFORMAT_PCM16, 1./20000.);
-  pass();
-  return 0;
-}
diff --git a/libambix/tests/simple_pcm32.c b/libambix/tests/simple_pcm32.c
deleted file mode 100644
index 4a4f10d..0000000
--- a/libambix/tests/simple_pcm32.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* simple_pcm32 - test ambix simple (PCM32)
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "common.h"
-void check_create_simple(const char*path, ambix_sampleformat_t format, float32_t eps);
-
-int main(int argc, char**argv) {
-  check_create_simple("test-pcm32.caf",  AMBIX_SAMPLEFORMAT_PCM32, 1e-5);
-  pass();
-  return 0;
-}
diff --git a/libambix/tests/skip.c b/libambix/tests/skip.c
index bd9b242..b106115 100644
--- a/libambix/tests/skip.c
+++ b/libambix/tests/skip.c
@@ -1,30 +1,5 @@
-/* skip - simple test that always softfails
-
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
-         Institute of Electronic Music and Acoustics (IEM),
-         University of Music and Dramatic Arts, Graz
-
-   This file is part of libambix
-
-   libambix is free software; you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-
-   libambix is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
-
-*/
-
 #include "common.h"
 
 int main(int argc, char**argv) {
-
-  skip();
-  return 0;
+  return skip();
 }
diff --git a/libambix/tests/skip_if0.c b/libambix/tests/skip_if0.c
new file mode 100644
index 0000000..572df55
--- /dev/null
+++ b/libambix/tests/skip_if0.c
@@ -0,0 +1,5 @@
+#include "common.h"
+
+int main(int argc, char**argv) {
+  return skip_if(0, __LINE__, "should %s skip", "NOT");
+}
diff --git a/libambix/tests/skip_if1.c b/libambix/tests/skip_if1.c
new file mode 100644
index 0000000..cefc329
--- /dev/null
+++ b/libambix/tests/skip_if1.c
@@ -0,0 +1,5 @@
+#include "common.h"
+
+int main(int argc, char**argv) {
+  return skip_if(1, __LINE__, "should %s skip", "indeed");
+}
diff --git a/samples/pd/ambix_readX~-help.pd b/samples/pd/ambix_readX~-help.pd
index 7eafb76..ccd7d9f 100644
--- a/samples/pd/ambix_readX~-help.pd
+++ b/samples/pd/ambix_readX~-help.pd
@@ -1,18 +1,18 @@
-#N canvas 200 134 758 600 10;
+#N canvas 775 240 758 600 10;
 #X declare -lib iemmatrix;
 #X obj 405 363 route bang;
 #X obj 405 383 print EOF;
 #X obj 535 387 print info;
-#X msg 111 216 1;
+#X msg 95 185 1;
 #X obj 495 429 /;
-#X floatatom 495 449 5 0 0 1 seconds - -;
+#X floatatom 495 449 5 0 0 1 seconds - -, f 5;
 #X obj 495 387 t a a;
 #X obj 495 409 route frames samplerate;
 #X obj 264 388 env~;
-#X floatatom 264 408 5 0 0 3 xtra0 - -;
+#X floatatom 264 408 5 0 0 3 xtra0 - -, f 5;
 #X obj 299 388 env~;
-#X floatatom 299 408 5 0 0 3 xtra1 - -;
-#X msg 111 245 0;
+#X floatatom 299 408 5 0 0 3 xtra1 - -, f 5;
+#X msg 95 214 0;
 #X msg 646 30 \; pd dsp 1;
 #X msg 74 161 open \$1;
 #X msg 74 49 bang;
@@ -48,16 +48,62 @@ you will get through the 1st outlet (e.g. using iemmatrix' [mtx_*~]
 ;
 #X obj 145 527 ambix_read~;
 #X obj 77 372 env~;
-#X floatatom 77 392 5 0 0 3 ACN0 - -;
+#X floatatom 77 392 5 0 0 3 ACN0 - -, f 5;
 #X obj 112 406 env~;
-#X floatatom 112 426 5 0 0 3 ACN1 - -;
+#X floatatom 112 426 5 0 0 3 ACN1 - -, f 5;
 #X obj 152 406 env~;
-#X floatatom 152 426 5 0 0 3 ACN2 - -;
+#X floatatom 152 426 5 0 0 3 ACN2 - -, f 5;
 #X obj 192 406 env~;
-#X floatatom 192 426 5 0 0 3 ACN3 - -;
+#X floatatom 192 426 5 0 0 3 ACN3 - -, f 5;
 #X obj 77 350 mtx_*~ 4 4;
 #X obj 496 552 declare -lib iemmatrix;
 #X obj 232 527 ambix_info;
+#X obj 289 350 s info-\$0;
+#N canvas 923 305 706 352 marker/regions 0;
+#X msg 42 121 get_all_markers;
+#X obj 35 300 outlet;
+#X msg 88 206 get_all_regions;
+#X msg 75 171 get_region \$1;
+#X msg 31 93 get_marker \$1;
+#X floatatom 31 72 5 0 0 0 - - -, f 5;
+#X floatatom 75 151 5 0 0 0 - - -, f 5;
+#X obj 372 90 r info-\$0;
+#X msg 344 267 seek \$1;
+#X obj 372 112 route marker region;
+#X obj 372 139 route 0 1 2;
+#X floatatom 344 236 10 0 0 0 - - -, f 10;
+#X obj 455 139 route 0 1 2;
+#X text 145 119 retrieve all markers;
+#X text 26 9 MARKER/REGION Info is sent to the rightmost outlet;
+#X text 78 70 get a marker with specific id;
+#X text 118 150 get a region with specific id;
+#X text 186 206 retrieve all regions;
+#X text 460 84 parse marker/region info;
+#X text 394 303 and BEFORE starting playback;
+#X text 394 286 this only works AFTER opening a file;
+#X msg 372 170 set \$1;
+#X obj 339 176 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
+-1 -1;
+#X text 399 267 set playhead to a certain position in [samples];
+#X text 27 29 retrieving markers/regions only works AFTER opening a
+file;
+#X connect 0 0 1 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 0;
+#X connect 6 0 3 0;
+#X connect 7 0 9 0;
+#X connect 8 0 1 0;
+#X connect 9 0 10 0;
+#X connect 9 1 12 0;
+#X connect 10 0 21 0;
+#X connect 10 1 21 0;
+#X connect 10 2 21 0;
+#X connect 11 0 8 0;
+#X connect 21 0 11 0;
+#X connect 22 0 11 0;
+#X restore 105 242 pd marker/regions;
 #X connect 0 0 1 0;
 #X connect 0 1 6 0;
 #X connect 3 0 30 0;
@@ -83,6 +129,7 @@ you will get through the 1st outlet (e.g. using iemmatrix' [mtx_*~]
 #X connect 30 5 8 0;
 #X connect 30 6 10 0;
 #X connect 30 7 0 0;
+#X connect 30 7 46 0;
 #X connect 32 0 31 0;
 #X connect 32 1 43 0;
 #X connect 35 0 36 0;
@@ -93,3 +140,4 @@ you will get through the 1st outlet (e.g. using iemmatrix' [mtx_*~]
 #X connect 43 1 37 0;
 #X connect 43 2 39 0;
 #X connect 43 3 41 0;
+#X connect 47 0 30 0;
diff --git a/samples/pd/ambix_read~-help.pd b/samples/pd/ambix_read~-help.pd
index f8db0f4..a4ba798 100644
--- a/samples/pd/ambix_read~-help.pd
+++ b/samples/pd/ambix_read~-help.pd
@@ -1,28 +1,28 @@
-#N canvas 518 132 758 533 10;
+#N canvas 307 182 758 533 10;
 #X obj 405 333 route bang;
 #X obj 405 353 print EOF;
 #X obj 535 357 print info;
-#X msg 111 186 1;
+#X msg 94 153 1;
 #X obj 74 298 env~;
-#X floatatom 74 318 5 0 0 3 ACN0 - -;
+#X floatatom 74 318 5 0 0 3 ACN0 - -, f 5;
 #X obj 495 399 /;
-#X floatatom 495 419 5 0 0 1 seconds - -;
+#X floatatom 495 419 5 0 0 1 seconds - -, f 5;
 #X obj 495 357 t a a;
 #X obj 495 379 route frames samplerate;
 #X obj 109 330 env~;
-#X floatatom 109 350 5 0 0 3 ACN1 - -;
+#X floatatom 109 350 5 0 0 3 ACN1 - -, f 5;
 #X obj 149 330 env~;
-#X floatatom 149 350 5 0 0 3 ACN2 - -;
+#X floatatom 149 350 5 0 0 3 ACN2 - -, f 5;
 #X obj 189 330 env~;
-#X floatatom 189 350 5 0 0 3 ACN3 - -;
+#X floatatom 189 350 5 0 0 3 ACN3 - -, f 5;
 #X obj 74 238 ambix_read~ 4 2;
 #X obj 264 358 env~;
-#X floatatom 264 378 5 0 0 3 xtra0 - -;
+#X floatatom 264 378 5 0 0 3 xtra0 - -, f 5;
 #X obj 299 358 env~;
-#X floatatom 299 378 5 0 0 3 xtra1 - -;
-#X msg 111 215 0;
+#X floatatom 299 378 5 0 0 3 xtra1 - -, f 5;
+#X msg 99 175 0;
 #X msg 646 30 \; pd dsp 1;
-#X msg 74 161 open \$1;
+#X msg 74 122 open \$1;
 #X msg 74 49 bang;
 #X obj 74 69 openpanel;
 #X obj 145 499 readsf~;
@@ -52,6 +52,52 @@ need to transform the output data.;
 #X text 215 243 arguments: <#ambioutlet~s:4> <#extraoutlet~s:0> <buffersize>
 ;
 #X obj 242 477 ambix_info;
+#N canvas 923 305 706 352 marker/regions 1;
+#X msg 42 121 get_all_markers;
+#X obj 35 300 outlet;
+#X msg 88 206 get_all_regions;
+#X msg 75 171 get_region \$1;
+#X msg 31 93 get_marker \$1;
+#X floatatom 31 72 5 0 0 0 - - -, f 5;
+#X floatatom 75 151 5 0 0 0 - - -, f 5;
+#X obj 372 90 r info-\$0;
+#X msg 344 267 seek \$1;
+#X obj 372 112 route marker region;
+#X obj 372 139 route 0 1 2;
+#X floatatom 344 236 10 0 0 0 - - -, f 10;
+#X obj 455 139 route 0 1 2;
+#X text 145 119 retrieve all markers;
+#X text 26 9 MARKER/REGION Info is sent to the rightmost outlet;
+#X text 78 70 get a marker with specific id;
+#X text 118 150 get a region with specific id;
+#X text 186 206 retrieve all regions;
+#X text 460 84 parse marker/region info;
+#X text 394 303 and BEFORE starting playback;
+#X text 394 286 this only works AFTER opening a file;
+#X msg 372 170 set \$1;
+#X obj 339 176 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
+-1 -1;
+#X text 399 267 set playhead to a certain position in [samples];
+#X text 27 29 retrieving markers/regions only works AFTER opening a
+file;
+#X connect 0 0 1 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 0;
+#X connect 6 0 3 0;
+#X connect 7 0 9 0;
+#X connect 8 0 1 0;
+#X connect 9 0 10 0;
+#X connect 9 1 12 0;
+#X connect 10 0 21 0;
+#X connect 10 1 21 0;
+#X connect 10 2 21 0;
+#X connect 11 0 8 0;
+#X connect 21 0 11 0;
+#X connect 22 0 11 0;
+#X restore 101 207 pd marker/regions;
+#X obj 300 323 s info-\$0;
 #X connect 0 0 1 0;
 #X connect 0 1 8 0;
 #X connect 3 0 16 0;
@@ -72,6 +118,7 @@ need to transform the output data.;
 #X connect 16 4 17 0;
 #X connect 16 5 19 0;
 #X connect 16 6 0 0;
+#X connect 16 6 44 0;
 #X connect 17 0 18 0;
 #X connect 19 0 20 0;
 #X connect 21 0 16 0;
@@ -80,3 +127,4 @@ need to transform the output data.;
 #X connect 25 0 23 0;
 #X connect 32 0 34 0;
 #X connect 33 0 32 0;
+#X connect 43 0 16 0;
diff --git a/samples/pd/ambix_read~.c b/samples/pd/ambix_read~.c
index a1b04c8..fe72a25 100644
--- a/samples/pd/ambix_read~.c
+++ b/samples/pd/ambix_read~.c
@@ -1,7 +1,8 @@
 /* ambix_read~ -  read AMBIsonics eXchange files in Pd        -*- c -*-
 
- Copyright © 1997-1999 Miller Puckette <msp at ucsd.edu>.
- Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+ Copyright © 1997-1999, Miller Puckette <msp at ucsd.edu>.
+ Copyright © 2012-2014, IOhannes m zmölnig <zmoelnig at iem.at>.
+ Copyright © 2016, Matthias Kronlachner
  Institute of Electronic Music and Acoustics (IEM),
  University of Music and Dramatic Arts, Graz
 
@@ -200,6 +201,7 @@ typedef struct _ambix_read {
 
   ambix_matrix_t x_matrix;
   ambix_info_t   x_ambix;
+  ambix_t        *x_ambix_t;
 
   int x_fifosize;         /* buffer size appropriately rounded down */
   int x_fifohead;         /* index of next byte to get from file */
@@ -219,7 +221,7 @@ typedef struct _ambix_read {
 
 static void *ambix_read_child_main(void *zz) {
   t_ambix_read *x = (t_ambix_read*)zz;
-  ambix_t*ambix=NULL;
+  x->x_ambix_t=NULL;
   const uint32_t want_ambichannels    = x->x_ambichannels;
   const uint32_t want_xtrachannels    = x->x_xtrachannels;
   const ambix_fileformat_t want_fileformat = x->x_fileformat;
@@ -259,15 +261,15 @@ static void *ambix_read_child_main(void *zz) {
 
       memset(&ainfo, 0, sizeof(ainfo));
       ainfo.fileformat=want_fileformat;
-      if (ambix)
-        ambix_close(ambix);
-      ambix=ambix_open(filename, AMBIX_READ, &ainfo);
+      if (x->x_ambix_t)
+        ambix_close(x->x_ambix_t);
+      x->x_ambix_t=ambix_open(filename, AMBIX_READ, &ainfo);
       free(filename);
 
-      if(ambix) {
-        matrix=ambix_get_adaptormatrix(ambix);
+      if(x->x_ambix_t) {
+        matrix=ambix_get_adaptormatrix(x->x_ambix_t);
         if(onsetframes) {
-          ambix_seek(ambix, onsetframes, SEEK_SET);
+          ambix_seek(x->x_ambix_t, onsetframes, SEEK_SET);
         }
       }
 
@@ -279,7 +281,7 @@ static void *ambix_read_child_main(void *zz) {
 
       pthread_mutex_lock(&x->x_mutex);
 
-      if (NULL==ambix) {
+      if (NULL==x->x_ambix_t) {
         x->x_fileerror = errno;
         x->x_eof = 1;
         goto lost;
@@ -358,7 +360,7 @@ static void *ambix_read_child_main(void *zz) {
           ambibuf = (float32_t*)calloc(localfifosize*ambichannels, sizeof(float32_t));
           xtrabuf = (float32_t*)calloc(localfifosize*xtrachannels, sizeof(float32_t));
         }
-        sysrtn = ambix_readf_float32(ambix, ambibuf, xtrabuf, wantframes);
+        sysrtn = ambix_readf_float32(x->x_ambix_t, ambibuf, xtrabuf, wantframes);
         if(sysrtn>0) {
           merge_samples(ambibuf, ambichannels, want_ambichannels,
                         xtrabuf, xtrachannels, want_xtrachannels,
@@ -389,30 +391,30 @@ static void *ambix_read_child_main(void *zz) {
         x->x_requestcode = REQUEST_NOTHING;
       /* fell out of read loop: close file if necessary,
          set EOF and signal once more */
-      if(ambix) {
+      if(x->x_ambix_t) {
         pthread_mutex_unlock(&x->x_mutex);
-        ambix_close(ambix);
-        ambix=NULL;
+        ambix_close(x->x_ambix_t);
+        x->x_ambix_t=NULL;
         pthread_mutex_lock(&x->x_mutex);
       }
 
       pthread_cond_signal(&x->x_answercondition);
 
     } else if (x->x_requestcode == REQUEST_CLOSE) {
-      if(ambix) {
+      if(x->x_ambix_t) {
         pthread_mutex_unlock(&x->x_mutex);
-        ambix_close(ambix);
-        ambix=NULL;
+        ambix_close(x->x_ambix_t);
+        x->x_ambix_t=NULL;
         pthread_mutex_lock(&x->x_mutex);
       }
       if (x->x_requestcode == REQUEST_CLOSE)
         x->x_requestcode = REQUEST_NOTHING;
       pthread_cond_signal(&x->x_answercondition);
     } else if (x->x_requestcode == REQUEST_QUIT) {
-      if(ambix) {
+      if(x->x_ambix_t) {
         pthread_mutex_unlock(&x->x_mutex);
-        ambix_close(ambix);
-        ambix=NULL;
+        ambix_close(x->x_ambix_t);
+        x->x_ambix_t=NULL;
         pthread_mutex_lock(&x->x_mutex);
       }
       x->x_requestcode = REQUEST_NOTHING;
@@ -554,6 +556,14 @@ static void ambix_read_tick(t_ambix_read *x) {
     /* number of sample frames in file */
     SETFLOAT(atoms+0, (t_float)(x->x_ambix.frames));
     outlet_anything(x->x_infoout, gensym("frames"), 1, atoms);
+
+    /* number of markers in the file */
+    SETFLOAT(atoms+0, (t_float)(ambix_get_num_markers(x->x_ambix_t)));
+    outlet_anything(x->x_infoout, gensym("num_markers"), 1, atoms);
+
+    /* number of regions in the file */
+    SETFLOAT(atoms+0, (t_float)(ambix_get_num_regions(x->x_ambix_t)));
+    outlet_anything(x->x_infoout, gensym("num_regions"), 1, atoms);
   }
 
 
@@ -614,8 +624,8 @@ static t_int *ambix_read_perform(t_int *w) {
 
     /* check for EOF (and buffer is about to drain) */
     if (x->x_eof &&
-        x->x_fifohead > x->x_fifotail &&
-        x->x_fifohead <=  x->x_fifotail + wantframes-1
+        x->x_fifohead >= x->x_fifotail &&
+        x->x_fifohead <  x->x_fifotail + wantframes-1
         ) {
       int xfersize;
       if (x->x_fileerror) {
@@ -785,6 +795,80 @@ static void ambix_read_free(t_ambix_read *x) {
   ambix_matrix_deinit(&x->x_matrix);
 }
 
+static void ambix_read_marker(t_ambix_read*x, t_float marker_id) {
+  if (!x->x_ambix_t)
+    return;
+  if ( ((int)marker_id >= 0) && ((int)marker_id < ambix_get_num_markers(x->x_ambix_t)) ) {
+    ambix_marker_t *marker;
+    marker = ambix_get_marker(x->x_ambix_t, (int)marker_id);
+    if (marker) {
+      t_atom atoms[3]; // id pos name
+      SETFLOAT(atoms+0, (t_float)(int)marker_id);
+      SETFLOAT(atoms+1, (t_float)marker->position);
+      SETSYMBOL(atoms+2, gensym(marker->name));
+      outlet_anything(x->x_infoout, gensym("marker"), 3, atoms);
+    }
+  } else {
+    pd_error(x, "ambix_read~: no marker with this id in file");
+  }
+}
+
+static void ambix_read_all_markers(t_ambix_read*x) {
+  int nummarkers, i;
+  if (!x->x_ambix_t)
+    return;
+  nummarkers = ambix_get_num_markers(x->x_ambix_t);
+  for (i=0; i<nummarkers; i++) {
+    ambix_read_marker(x, i);
+  }
+}
+
+static void ambix_read_region(t_ambix_read*x, t_float region_id) {
+  if (!x->x_ambix_t)
+    return;
+  if ( ((int)region_id >= 0) && ((int)region_id < ambix_get_num_regions(x->x_ambix_t)) ) {
+    ambix_region_t *region;
+    region = ambix_get_region(x->x_ambix_t, (int)region_id);
+    if (region) {
+      t_atom atoms[4]; // id start_pos end_pos name
+      SETFLOAT(atoms+0, (t_float)(int)region_id);
+      SETFLOAT(atoms+1, (t_float)region->start_position);
+      SETFLOAT(atoms+2, (t_float)region->end_position);
+      SETSYMBOL(atoms+3, gensym(region->name));
+      outlet_anything(x->x_infoout, gensym("region"), 4, atoms);
+    }
+  } else {
+    pd_error(x, "ambix_read~: no region with this id in file");
+  }
+}
+
+static void ambix_read_all_regions(t_ambix_read*x) {
+  int numregions, i;
+  if (!x->x_ambix_t)
+    return;
+  numregions = ambix_get_num_regions(x->x_ambix_t);
+  for (i=0; i<numregions; i++) {
+    ambix_read_region(x, i);
+  }
+}
+
+static void ambix_seek_pos(t_ambix_read*x, t_float position) {
+  if (!x->x_ambix_t) {
+    pd_error(x, "ambix_read~: seek not possible, requested with no prior 'open'");
+    return;
+  }
+  pthread_mutex_lock(&x->x_mutex);
+  if (x->x_state == STATE_STARTUP) {
+    int64_t ret = ambix_seek(x->x_ambix_t, (int64_t)position, SEEK_SET);
+    if (ret < 0)
+      pd_error(x, "ambix_read~: seek not possible");
+    pthread_mutex_unlock(&x->x_mutex);
+  } else {
+    pthread_mutex_unlock(&x->x_mutex);
+    pd_error(x, "ambix_read~: seek not possible, playback already started");
+  }
+}
+
 AMBIX_EXPORT
 void ambix_read_tilde_setup(void) {
   ambix_read_class = class_new(gensym("ambix_read~"), (t_newmethod)ambix_read_new,
@@ -797,6 +881,11 @@ void ambix_read_tilde_setup(void) {
   class_addmethod(ambix_read_class, (t_method)ambix_read_dsp, gensym("dsp"), A_NULL);
   class_addmethod(ambix_read_class, (t_method)ambix_read_open, gensym("open"), A_SYMBOL, A_DEFFLOAT, A_NULL);
   class_addmethod(ambix_read_class, (t_method)ambix_read_print, gensym("print"), A_NULL);
+  class_addmethod(ambix_read_class, (t_method)ambix_read_marker, gensym("get_marker"), A_DEFFLOAT, A_NULL);
+  class_addmethod(ambix_read_class, (t_method)ambix_read_all_markers, gensym("get_all_markers"), A_NULL);
+  class_addmethod(ambix_read_class, (t_method)ambix_read_region, gensym("get_region"), A_DEFFLOAT, A_NULL);
+  class_addmethod(ambix_read_class, (t_method)ambix_read_all_regions, gensym("get_all_regions"), A_NULL);
+  class_addmethod(ambix_read_class, (t_method)ambix_seek_pos, gensym("seek"), A_DEFFLOAT, A_NULL);
 
   if(0)
     MARK("[ambix_read~] setup done");
diff --git a/samples/pd/ambix_write~-help.pd b/samples/pd/ambix_write~-help.pd
index 78414bf..83fda33 100644
--- a/samples/pd/ambix_write~-help.pd
+++ b/samples/pd/ambix_write~-help.pd
@@ -1,6 +1,5 @@
-#N canvas 518 132 758 533 10;
+#N canvas 84 104 758 533 10;
 #X msg 646 30 \; pd dsp 1;
-#X msg 74 161 open \$1;
 #X msg 74 49 bang;
 #X obj 74 69 savepanel;
 #X text 356 432 <buffersize> is given in samples per channels (unlike
@@ -43,15 +42,16 @@ extra channels are requested) \, the ambisonics channels will always
 be periphonic (3D) semi-normalized (SN3D) and ordered after their ACN.
 ;
 #X obj 330 477 ambix_info;
-#X connect 1 0 22 0;
-#X connect 2 0 3 0;
-#X connect 3 0 1 0;
-#X connect 8 0 22 0;
-#X connect 9 0 22 0;
-#X connect 10 0 22 0;
-#X connect 16 0 22 2;
-#X connect 19 0 22 1;
-#X connect 20 0 22 3;
-#X connect 21 0 22 4;
-#X connect 27 0 22 0;
-#X connect 28 0 22 0;
+#X msg 74 161 open -bytes 3 \$1;
+#X connect 1 0 2 0;
+#X connect 2 0 33 0;
+#X connect 7 0 21 0;
+#X connect 8 0 21 0;
+#X connect 9 0 21 0;
+#X connect 15 0 21 2;
+#X connect 18 0 21 1;
+#X connect 19 0 21 3;
+#X connect 20 0 21 4;
+#X connect 26 0 21 0;
+#X connect 27 0 21 0;
+#X connect 33 0 21 0;
diff --git a/samples/pd/ambix_write~.c b/samples/pd/ambix_write~.c
index 72c64c1..0adbdbc 100644
--- a/samples/pd/ambix_write~.c
+++ b/samples/pd/ambix_write~.c
@@ -1,7 +1,8 @@
 /* ambix_write~ -  write AMBIsonics eXchange files in Pd        -*- c -*-
 
  Copyright © 1997-1999 Miller Puckette <msp at ucsd.edu>.
- Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+ Copyright © 2012-2014 IOhannes m zmölnig <zmoelnig at iem.at>.
+ Copyright © 2016, Matthias Kronlachner
  Institute of Electronic Music and Acoustics (IEM),
  University of Music and Dramatic Arts, Graz
 
@@ -190,6 +191,7 @@ typedef struct _ambix_write
   /* parameters to communicate with subthread */
   char *x_filename;       /* file to open (string is permanently allocated) */
   ambix_fileformat_t x_fileformat; /* extended or basic */
+  ambix_sampleformat_t x_sampleformat; /* 16, 24 or 32 bit */
   uint32_t x_ambichannels; /* number of ambisonics channels in soundfile */
   uint32_t x_extrachannels; /* number of extra channels in soundfile */
   ambix_matrix_t*x_matrix;
@@ -243,6 +245,8 @@ static void *ambix_write_child_main(void *zz) {
       int64_t onsetframes = x->x_onsetframes;
 
       ambix_fileformat_t fileformat = x->x_fileformat;
+	  
+	  ambix_sampleformat_t sampleformat = x->x_sampleformat;
 
       uint32_t ambichannels  = x->x_ambichannels;
       uint32_t xtrachannels  = x->x_extrachannels;
@@ -277,7 +281,7 @@ static void *ambix_write_child_main(void *zz) {
       ainfo.extrachannels=xtrachannels;
 
       ainfo.samplerate=samplerate;
-
+      ainfo.sampleformat=sampleformat;
       /* if there's already a file open, close it.  This
          should never happen since ambix_write_open() calls stop if
          needed and then waits until we're idle. */
@@ -470,8 +474,8 @@ static void *ambix_write_new(t_symbol*s, int argc, t_atom*argv) {
 
   x->x_f = 0;
 
-  x->x_ambichannels = 0;
-  x->x_extrachannels = nchannels;
+  x->x_ambichannels = achannels;
+  x->x_extrachannels = xchannels;
 
   x->x_matrix=NULL;
   x->x_canvas = canvas_getcurrent();
@@ -580,6 +584,7 @@ static void ambix_write_open(t_ambix_write *x, t_symbol *s, int argc, t_atom *ar
   x->x_filename = filesym->s_name;
   x->x_fileformat = fileformat;
   x->x_requestcode = REQUEST_OPEN;
+  x->x_sampleformat = sampleformat;
 
   x->x_fifotail = 0;
   x->x_fifohead = 0;
diff --git a/utils/ambix-deinterleave.c b/utils/ambix-deinterleave.c
index d1fde0d..b9b944c 100644
--- a/utils/ambix-deinterleave.c
+++ b/utils/ambix-deinterleave.c
@@ -1,6 +1,6 @@
 /* ambix_deinterleave -  create an ambix file              -*- c -*-
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2014 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
diff --git a/utils/ambix-dump.c b/utils/ambix-dump.c
index b20c06c..42227fb 100644
--- a/utils/ambix-dump.c
+++ b/utils/ambix-dump.c
@@ -1,6 +1,6 @@
 /* ambix_dump -  create an ambix file              -*- c -*-
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2014 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
diff --git a/utils/ambix-info.c b/utils/ambix-info.c
index 29e2d50..b9db912 100644
--- a/utils/ambix-info.c
+++ b/utils/ambix-info.c
@@ -33,6 +33,32 @@
 void print_usage(const char*name);
 void print_version(const char*name);
 
+void print_markers(ambix_t*ambix)
+{
+  uint32_t num_markers = ambix_get_num_markers(ambix);
+  if (num_markers) {
+    ambix_marker_t *marker = NULL;
+    uint32_t i;
+    for (i=0; i < num_markers; i++) {
+      marker = ambix_get_marker(ambix, i);
+      if (marker)
+        printf("  Marker %d: name: %s position: %f \n", i, marker->name, marker->position);
+    }
+  }
+}
+void print_regions(ambix_t*ambix)
+{
+  uint32_t num_regions = ambix_get_num_regions(ambix);
+  if (num_regions) {
+    ambix_region_t *region = NULL;
+    uint32_t i;
+    for (i=0; i < num_regions; i++) {
+      region = ambix_get_region(ambix, i);
+      printf("  Region %d: name: %s start_position: %f end_position: %f \n", i, region->name, region->start_position, region->end_position);
+    }
+  }
+}
+
 void printinfo(const char*path) {
   ambix_info_t info;
   ambix_t*ambix;
@@ -59,6 +85,7 @@ void printinfo(const char*path) {
   case(AMBIX_SAMPLEFORMAT_PCM24): printf("PCM24"); break;
   case(AMBIX_SAMPLEFORMAT_PCM32): printf("PCM32"); break;
   case(AMBIX_SAMPLEFORMAT_FLOAT32): printf("FLOAT32"); break;
+  case(AMBIX_SAMPLEFORMAT_FLOAT64): printf("FLOAT64"); break;
   default: printf("**unknown**");
   }
   printf(")\n");
@@ -94,6 +121,11 @@ void printinfo(const char*path) {
   }
   printf("\n");
 
+  printf("Number of Markers\t: %d\n", ambix_get_num_markers(ambix));
+  print_markers(ambix);
+  printf("Number of Regions\t: %d\n", ambix_get_num_regions(ambix));
+  print_regions(ambix);
+
   printf("Close file '%s': ", path);
   if(AMBIX_ERR_SUCCESS!=ambix_close(ambix))
     printf("failed\n");
diff --git a/utils/ambix-interleave.c b/utils/ambix-interleave.c
index 5714275..3007e32 100644
--- a/utils/ambix-interleave.c
+++ b/utils/ambix-interleave.c
@@ -1,6 +1,6 @@
 /* ambix_interleave -  create an ambix file              -*- c -*-
 
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2016 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 
@@ -46,6 +46,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <ctype.h>
 
 #ifdef _MSC_VER
 # define strdup _strdup
@@ -66,6 +67,8 @@ typedef struct ai_t {
   ambix_t*outhandle;
 
   ambix_matrix_t*matrix;
+  ambix_matrixtype_t matrix_norm; /* normalisation matrix */
+  ambix_matrixtype_t matrix_rout; /* routing matrix */
   uint32_t channels;
 
   uint32_t blocksize;
@@ -74,6 +77,7 @@ typedef struct ai_t {
 static void print_usage(const char*path);
 static void print_version(const char*path);
 static ai_t*ai_close(ai_t*ai);
+static int ai_exit = 0;
 
 static ai_t*ai_matrix(ai_t*ai, const char*path) {
   SF_INFO info;
@@ -88,7 +92,7 @@ static ai_t*ai_matrix(ai_t*ai, const char*path) {
   file=sf_open(path, SFM_READ, &info);
 
   if(!file) {
-    fprintf(stderr, "ambix_interleave: matrix open failed '%s'\n", path);
+    fprintf(stderr, "ambix_interleave: tried to open matrix file '%s': ...failed\n", path);
     return NULL;
   }
   rows=info.channels;
@@ -121,6 +125,47 @@ static ai_t*ai_matrix(ai_t*ai, const char*path) {
   return result;
 }
 
+static ai_t*ai_matrix_predefined(ai_t*ai, const char*format) {
+  /* just parse the format string, and set the output matrix type */
+#define MAX_MATRIX_NAME 10
+  size_t len=strnlen(format, MAX_MATRIX_NAME);
+  char*fmt=calloc(len+1, 1);
+  ai_t*result=ai;
+  size_t i;
+  /* make everything lower-case */
+  for(i=0; i<len; i++)
+    fmt[i]=tolower(format[i]);
+  fmt[len]=0;
+  /* FuMa */
+  if(!strncmp(fmt, "fuma", len)) {
+    ai->matrix_norm=AMBIX_MATRIX_FUMA;
+    ai->matrix_rout=AMBIX_MATRIX_FUMA;
+    goto cleanup;
+  }
+  /* N3D/SID */
+  if(!strncmp(fmt, "n3d|sid", len) || !strncmp(fmt, "sid|n3d", len)) {
+    ai->matrix_norm=AMBIX_MATRIX_N3D;
+    ai->matrix_rout=AMBIX_MATRIX_SID;
+    goto cleanup;
+  }
+  /* SID */
+  if(!strncmp(fmt, "sid", len) || !strncmp(fmt, "sn3d|sid", len) || !strncmp(fmt, "sid|sn3d", len)) {
+    ai->matrix_norm=AMBIX_MATRIX_IDENTITY;
+    ai->matrix_rout=AMBIX_MATRIX_SID;
+    goto cleanup;
+  }
+  /* N3D */
+  if(!strncmp(fmt, "n3d", len) || !strncmp(fmt, "sn3d|acn", len) || !strncmp(fmt, "acn|sn3d", len)) {
+    ai->matrix_norm=AMBIX_MATRIX_N3D;
+    ai->matrix_rout=AMBIX_MATRIX_IDENTITY;
+    goto cleanup;
+  }
+  result=0;
+ cleanup:
+  free(fmt);
+  return result;
+}
+
 static ai_t*ai_cmdline(const char*name, int argc, char**argv) {
   ai_t*ai=(ai_t*)calloc(1, sizeof(ai_t));
   uint32_t channels=0;
@@ -129,11 +174,13 @@ static ai_t*ai_cmdline(const char*name, int argc, char**argv) {
   while(argc) {
     if(!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help")) {
       print_usage(name);
-      exit(0);
+      ai_exit=0;
+      return ai_close(ai);
     }
     if(!strcmp(argv[0], "-V") || !strcmp(argv[0], "--version")) {
       print_version(name);
-      exit(0);
+      ai_exit=0;
+      return ai_close(ai);
     }
     if(!strcmp(argv[0], "-o") || !strcmp(argv[0], "--output")) {
       if(argc>1) {
@@ -143,6 +190,7 @@ static ai_t*ai_cmdline(const char*name, int argc, char**argv) {
         continue;
       }
       fprintf(stderr, "no output file specified\n");
+      ai_exit=64;
       return ai_close(ai);
     }
     if(!strcmp(argv[0], "-O") || !strcmp(argv[0], "--order")) {
@@ -154,6 +202,7 @@ static ai_t*ai_cmdline(const char*name, int argc, char**argv) {
         continue;
       }
       fprintf(stderr, "no ambisonics order specified\n");
+      ai_exit=64;
       return ai_close(ai);
     }
     if(!strcmp(argv[0], "-b") || !strcmp(argv[0], "--blocksize")) {
@@ -164,12 +213,14 @@ static ai_t*ai_cmdline(const char*name, int argc, char**argv) {
         continue;
       }
       fprintf(stderr, "no blocksize specified\n");
+      ai_exit=64;
       return ai_close(ai);
     }
     if(!strcmp(argv[0], "-X") || !strcmp(argv[0], "--matrix")) {
       if(argc>1) {
-        if(!ai_matrix(ai, argv[1])) {
+        if(!ai_matrix(ai, argv[1]) && !ai_matrix_predefined(ai, argv[1])) {
           fprintf(stderr, "Couldn't read matrix '%s'\n", argv[1]);
+	  ai_exit=66;
           return ai_close(ai);
         }
         argv+=2;
@@ -177,6 +228,7 @@ static ai_t*ai_cmdline(const char*name, int argc, char**argv) {
         continue;
       }
       fprintf(stderr, "no matrix file specified\n");
+      ai_exit=64;
       return ai_close(ai);
     }
     ai->infilenames=argv;
@@ -184,13 +236,22 @@ static ai_t*ai_cmdline(const char*name, int argc, char**argv) {
     break;
   }
 
+  if(ai->matrix && (ai->matrix_norm || ai->matrix_rout)) {
+    /* both a matrix-file and matrix-specs were given; bail out! */
+    print_usage(argv[0]);
+    ai_exit=64;
+    return ai_close(ai);
+  }
+
   if(!ai->infilenames) {
     fprintf(stderr, "no input files specified\n");
+    ai_exit=66;
     return ai_close(ai);
   }
 
   if(!ai->outfilename) {
     fprintf(stderr, "no output filename specified\n");
+    ai_exit=73;
     return ai_close(ai);
   }
 
@@ -205,10 +266,11 @@ static ai_t*ai_cmdline(const char*name, int argc, char**argv) {
   if((channels > 0) && ai->matrix) {
     if(channels != ai->matrix->rows) {
       fprintf(stderr, "ambix_interleave: order%02d needs %d channels, not %d\n", order, channels, ai->matrix->rows);
+      ai_exit=65;
       return ai_close(ai);
     }
   }
-
+  ai_exit=0;
   return ai;
 }
 
@@ -249,6 +311,12 @@ static ai_t*ai_close(ai_t*ai) {
   ai=NULL;
   return NULL;
 }
+static ambix_matrix_t*ai_calc_matrix(unsigned int rowcols, ambix_matrixtype_t typ) {
+  ambix_matrix_t*mtx=ambix_matrix_init(rowcols, rowcols, NULL);
+  ambix_matrix_t*mtx2=mtx?ambix_matrix_fill(mtx, typ):NULL;
+  if(mtx2!=mtx)ambix_matrix_destroy(mtx);  mtx=NULL;
+  return mtx2;
+}
 
 static ai_t*ai_open_input(ai_t*ai) {
   uint32_t i;
@@ -258,7 +326,6 @@ static ai_t*ai_open_input(ai_t*ai) {
     ai->inhandles=(SNDFILE**)calloc(ai->numIns, sizeof(SNDFILE*));
     ai->ininfo   =(SF_INFO*)calloc(ai->numIns, sizeof(SF_INFO));
   }
-
   for(i=0; i<ai->numIns; i++) {
     SNDFILE*inhandle=ai->inhandles[i];
     SF_INFO*info=&ai->ininfo[i];
@@ -271,7 +338,7 @@ static ai_t*ai_open_input(ai_t*ai) {
       ai->info.samplerate=info->samplerate;
     if(ai->info.sampleformat==AMBIX_SAMPLEFORMAT_NONE) {
       int format=info->format;
-      if((format & SF_FORMAT_FLOAT)  || (format & SF_FORMAT_DOUBLE))
+      if((format & SF_FORMAT_FLOAT))
         ai->info.sampleformat=AMBIX_SAMPLEFORMAT_FLOAT32;
       else if((format & SF_FORMAT_PCM_S8)  || (format & SF_FORMAT_PCM_16))
         ai->info.sampleformat=AMBIX_SAMPLEFORMAT_PCM16;
@@ -279,13 +346,54 @@ static ai_t*ai_open_input(ai_t*ai) {
         ai->info.sampleformat=AMBIX_SAMPLEFORMAT_PCM24;
       else if((format & SF_FORMAT_PCM_32))
         ai->info.sampleformat=AMBIX_SAMPLEFORMAT_PCM32;
+      else if((format & SF_FORMAT_DOUBLE))
+        ai->info.sampleformat=AMBIX_SAMPLEFORMAT_FLOAT64;
       else
         ai->info.sampleformat=AMBIX_SAMPLEFORMAT_PCM24;
     }
     channels+=info->channels;
     ai->inhandles[i]=inhandle;
+    /* check if the input is a single .AMB file, */
+    if(1 == ai->numIns
+       && inhandle
+       && (sf_command(inhandle, SFC_WAVEX_GET_AMBISONIC, NULL, 0) == SF_AMBISONIC_B_FORMAT)) {
+      /* it is, so we decode it as ambisonics */
+
+      if(ai->matrix || ai->matrix_rout || ai->matrix_norm) {
+	/* but not if the user already set an adaptor matrix */
+	fprintf(stderr, "Cannot set adaptor-matrix when interleaving from AMB file.\n");
+	ai_exit=65;
+	return ai_close(ai);
+      }
+      ai->matrix = ai_calc_matrix(info->channels, AMBIX_MATRIX_FUMA);
+    }
+  }
+  if (ai->matrix_rout || ai->matrix_norm) {
+    /* predefined matrix, but we need to calc the size based on the channels */
+
+    if(ai->matrix)ambix_matrix_destroy(ai->matrix);  ai->matrix=NULL;
+    if((ai->matrix_rout == ai->matrix_norm) && (ai->matrix_norm == AMBIX_MATRIX_FUMA)) {
+      ai->matrix=ai_calc_matrix(channels, AMBIX_MATRIX_FUMA);
+      if(!ai->matrix) {
+	fprintf(stderr, "Unable to set Furse-Malham matrix with %d channels\n", channels);
+	ai_exit=65;
+	return ai_close(ai);
+      }
+    } else {
+      ambix_matrix_t*route=ai_calc_matrix(channels, ai->matrix_rout);
+      ambix_matrix_t*norm =ai_calc_matrix(channels, ai->matrix_norm);
+      if(route && norm) {
+	ai->matrix = ambix_matrix_multiply(route, norm, NULL);
+      }
+      if(route)ambix_matrix_destroy(route); route=NULL;
+      if(norm )ambix_matrix_destroy(norm ); norm =NULL;
+      if(!ai->matrix) {
+	fprintf(stderr, "Unable to set normalisation/routing matrix with %d channels\n", channels);
+	ai_exit=65;
+	return ai_close(ai);
+      }
+    }
   }
-
    /* check whether input channels form a valid full set */
   if(ai->matrix) {
     if(channels<ai->matrix->cols) {
@@ -355,11 +463,20 @@ static ai_t*ai_open_output(ai_t*ai) {
   return ai;
 }
 
+/* deinterleave an *interleaved* source of <frames>*<channels> data in dest */
+static void deinterleaver(float*dest, const float*source, uint64_t frames, uint32_t channels) {
+  uint32_t channel;
+  for(channel=0; channel<channels; channel++) {
+    uint64_t frame;
+    for(frame=0; frame<frames; frame++) {
+      *dest++ = source[frame*channels+channel];
+    }
+  }
+}
 
+/* interleave a *non-interleaved* source of <frames>*<channels> data in dest */
 static void interleaver(float*dest, const float*source, uint64_t frames, uint32_t channels) {
   uint64_t frame;
-
-
   for(frame=0; frame<frames; frame++) {
     uint64_t channel;
     for(channel=0; channel<channels; channel++) {
@@ -372,7 +489,8 @@ static void interleaver(float*dest, const float*source, uint64_t frames, uint32_
 static ai_t*ai_copy_block(ai_t*ai,
                           float*ambidata,
                           float*extradata,
-                          float*interleavedata,
+                          float*deinterleavedata,
+                          float*sourcedata,
                           uint64_t frames) {
   uint32_t i;
   uint64_t channels=0;
@@ -381,20 +499,30 @@ static ai_t*ai_copy_block(ai_t*ai,
   for(i=0; i<ai->numIns; i++) {
     uint64_t offset=channels*frames;
     SNDFILE*in=ai->inhandles[i];
+    uint32_t inchannels=ai->ininfo[i].channels;
     if(in) {
+      uint64_t readframes=0;
       //printf("reading %d frames from[%d] at %p+%d\n", (int)frames, (int)i, interleavedata, (int)offset);
-      if(frames!=sf_readf_float(in, interleavedata+offset, frames)) {
+      if(sourcedata && inchannels>1) {
+	readframes=sf_readf_float(in, sourcedata, frames);
+	if(readframes)
+	  deinterleaver(deinterleavedata+offset, sourcedata, frames, inchannels);
+      } else {
+	readframes=sf_readf_float(in, deinterleavedata+offset, frames);
+      }
+
+      if(frames!=readframes) {
         return ai_close(ai);
       }
-      channels+=ai->ininfo[i].channels;
+      channels+=inchannels;
     }
   }
 
   if(ambidata)
-    interleaver(ambidata, interleavedata, frames, ai->info.ambichannels);
+    interleaver(ambidata, deinterleavedata, frames, ai->info.ambichannels);
 
   if(extradata)
-    interleaver(extradata, interleavedata+frames*ai->info.ambichannels, frames, ai->info.extrachannels);
+    interleaver(extradata, deinterleavedata+frames*ai->info.ambichannels, frames, ai->info.extrachannels);
 
   //printf("writing %d frames to  %p & %p\n", (int)frames,  ambidata, extradata);
 
@@ -408,7 +536,8 @@ static ai_t*ai_copy_block(ai_t*ai,
 static ai_t*ai_copy(ai_t*ai) {
   uint64_t blocksize=0, blocks=0;
   uint64_t frames=0, channels=0;
-  float32_t*ambidata=NULL,*extradata=NULL,*interleavebuffer=NULL;
+  float32_t*ambidata=NULL,*extradata=NULL,*interleavebuffer=NULL,*source=NULL;
+  uint64_t i, maxchannels=0;
   if(!ai)return ai;
   blocksize=ai->blocksize;
   if(blocksize<1)
@@ -416,27 +545,35 @@ static ai_t*ai_copy(ai_t*ai) {
   frames=ai->info.frames;
   channels=(ai->info.ambichannels+ai->info.extrachannels);
 
+  for(i=0; i<ai->numIns; i++) {
+    uint64_t c=ai->ininfo[i].channels;
+    if(c>maxchannels)maxchannels=c;
+  }
+
   if(ai->info.ambichannels>0)
-    ambidata =(float32_t*)malloc(sizeof(float32_t)*ai->info.ambichannels *blocksize);
+    ambidata =malloc(sizeof(*ambidata )*ai->info.ambichannels *blocksize);
   if(ai->info.extrachannels>0)
-    extradata=(float32_t*)malloc(sizeof(float32_t)*ai->info.extrachannels*blocksize);
+    extradata=malloc(sizeof(*extradata)*ai->info.extrachannels*blocksize);
+  if(maxchannels>1)
+    source   =malloc(sizeof(*source   )*maxchannels           *blocksize);
 
   interleavebuffer=(float32_t*)malloc(sizeof(float32_t)*channels*blocksize);
 
   while(frames>blocksize) {
     blocks++;
-    if(!ai_copy_block(ai, ambidata, extradata, interleavebuffer, blocksize)) {
-      return ai_close(ai);
-    }
+    ai=ai_copy_block(ai, ambidata, extradata, interleavebuffer, source, blocksize);
+    if(!ai) break;
     frames-=blocksize;
   }
-  if(!ai_copy_block(ai, ambidata, extradata, interleavebuffer, frames))
-    return ai_close(ai);
+  if(ai)
+    ai=ai_copy_block(ai, ambidata, extradata, interleavebuffer, source, frames);
 
 
   free(ambidata);
   free(extradata);
   free(interleavebuffer);
+  free(source);
+
   return ai;
 }
 
@@ -459,7 +596,7 @@ int main(int argc, char**argv) {
   ai_t*ai=ai_cmdline(argv[0], argc-1, argv+1);
   if(!ai) {
     print_usage(argv[0]);//"ambix_interleave");
-    return 1;
+    return ai_exit;
   }
 
   return ambix_interleave(ai);
@@ -474,7 +611,8 @@ void print_usage(const char*name) {
   printf("  -h, --help                       print this help\n");
   printf("  -o, --output                     output filename\n");
   printf("  -O, --order                      force ambisonics order (default: autodetect)\n");
-  printf("  -X, --matrix                     specify adaptor matrix file\n");
+  printf("  -X, --matrix                     specify adaptor matrix file or a predefined matrix\n");
+  printf("                                          ('FuMa', 'n3d|sid', 'n3d' or 'sid')\n");
   printf("  -b, --blocksize                  blocksize for copying (default: %d)\n", DEFAULT_BLOCKSIZE);
   printf("\n");
 
@@ -487,8 +625,9 @@ void print_usage(const char*name) {
          "\nIf you specify the 'order', then all extranous channels will be stored as 'extra' channels."
          "\n"
          "\nYou can also write extended ambix files, by specifying an adaptor matrix"
-         "\n(a soundfile where the channels are read as rows and the frames as columns),"
-         "\nin which case the columns of the matrix define the number of (reduced) ambisonics channels read from the input"
+         "\n(either a soundfile, where the channels are read as rows and the frames as columns,"
+	 "\nor by specifying one of the standard matrices), in which case the columns of the"
+	 "\nmatrix define the number of (reduced) ambisonics channels read from the input"
          "\nand the rows of the matrix must form a full 3d ambisonics set."
          "\nInput channels exceeding the number of matrix columns are stored as 'extra' channels."
          "\n"
diff --git a/utils/ambix-jplay.c b/utils/ambix-jplay.c
index 8aed9ad..41c0bae 100644
--- a/utils/ambix-jplay.c
+++ b/utils/ambix-jplay.c
@@ -1,7 +1,7 @@
 /* ambix-jplay.c -  play back an ambix file via jack            -*- c -*-
 
    Copyright © 2003-2010 Rohan Drape <rd at slavepianos.org>
-   Copyright © 2012 IOhannes m zmölnig <zmoelnig at iem.at>.
+   Copyright © 2012-2014 IOhannes m zmölnig <zmoelnig at iem.at>.
          Institute of Electronic Music and Acoustics (IEM),
          University of Music and Dramatic Arts, Graz
 

-- 
libambix packaging



More information about the pkg-multimedia-commits mailing list