diff --git a/Makefile b/Makefile
index a6934fe8b9df79ef4c6dda217660c9280ecc9ebc..149798d4ba1f9dc1034f029667b9336c452689d6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,13 @@
 all: kissinference kissinference_test
 
 kissinference:
-	dotnet msbuild kissinference.csproj -t:Build
+	dotnet msbuild kissinferencesharp.csproj -t:Build
 
 kissinference_test: kissinference
 	dotnet msbuild kissinference_test.csproj -t:Build
 
 clean:
-	dotnet msbuild kissinference.csproj -t:Clean
+	dotnet msbuild kissinferencesharp.csproj -t:Clean
 	dotnet msbuild kissinference_test.csproj -t:Clean
 	rm -r doc/html doc/latex || true
 
@@ -16,7 +16,7 @@ doc:
 	doxygen doc/libkissinference.doxygen
 
 restore:
-	dotnet restore kissinference.sln
+	dotnet restore kissinferencesharp.sln
 	dotnet restore kissinference_test.csproj
 
 run:
diff --git a/doc/libkissinference.doxygen b/doc/libkissinference.doxygen
index faf9a6de8b21dc89d75d0c05d161220fdbbe2ba6..0049a94fd362e4f19fa9a17130aac3f91d27cd37 100644
--- a/doc/libkissinference.doxygen
+++ b/doc/libkissinference.doxygen
@@ -1,4 +1,4 @@
-# Doxyfile 1.9.3
+# Doxyfile 1.10.0
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project.
@@ -12,6 +12,16 @@
 # For lists, items can also be appended using:
 # TAG += value [value, ...]
 # Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+#
+# Use doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# Use doxygen to compare the used configuration file with the template
+# configuration file without replacing the environment variables or CMake type
+# replacement variables:
+# doxygen -x_noenv [configFile]
 
 #---------------------------------------------------------------------------
 # Project related configuration options
@@ -53,6 +63,12 @@ PROJECT_BRIEF          =
 
 PROJECT_LOGO           =
 
+# With the PROJECT_ICON tag one can specify an icon that is included in the tabs
+# when the HTML document is shown. Doxygen will copy the logo to the output
+# directory.
+
+PROJECT_ICON           =
+
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
 # into which the generated documentation will be written. If a relative path is
 # entered, it will be relative to the location where doxygen was started. If
@@ -60,16 +76,28 @@ PROJECT_LOGO           =
 
 OUTPUT_DIRECTORY       = doc
 
-# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
 # option can be useful when feeding doxygen a huge amount of source files, where
 # putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
 # The default value is: NO.
 
 CREATE_SUBDIRS         = NO
 
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# number of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+
+CREATE_SUBDIRS_LEVEL   = 8
+
 # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
 # characters to appear in the names of generated files. If set to NO, non-ASCII
 # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
@@ -81,14 +109,14 @@ ALLOW_UNICODE_NAMES    = NO
 # The OUTPUT_LANGUAGE tag is used to specify the language in which all
 # documentation generated by doxygen is written. Doxygen will use this
 # information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
 # The default value is: English.
 
 OUTPUT_LANGUAGE        = English
@@ -331,6 +359,17 @@ MARKDOWN_SUPPORT       = YES
 
 TOC_INCLUDE_HEADINGS   = 5
 
+# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
+# generate identifiers for the Markdown headings. Note: Every identifier is
+# unique.
+# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
+# sequence number starting at 0 and GITHUB use the lower case version of title
+# with any whitespace replaced by '-' and punctuation characters removed.
+# The default value is: DOXYGEN.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+MARKDOWN_ID_STYLE      = DOXYGEN
+
 # When enabled doxygen tries to link words that correspond to documented
 # classes, or namespaces to their corresponding documentation. Such a link can
 # be prevented in individual cases by putting a % sign in front of the word or
@@ -442,7 +481,7 @@ TYPEDEF_HIDES_STRUCT   = YES
 
 LOOKUP_CACHE_SIZE      = 0
 
-# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
+# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
 # during processing. When set to 0 doxygen will based this on the number of
 # cores available in the system. You can set it explicitly to a value larger
 # than 0 to get more control over the balance between CPU load and processing
@@ -455,6 +494,14 @@ LOOKUP_CACHE_SIZE      = 0
 
 NUM_PROC_THREADS       = 1
 
+# If the TIMESTAMP tag is set different from NO then each generated page will
+# contain the date or date and time when the page was generated. Setting this to
+# NO can help when comparing the output of multiple runs.
+# Possible values are: YES, NO, DATETIME and DATE.
+# The default value is: NO.
+
+TIMESTAMP              = NO
+
 #---------------------------------------------------------------------------
 # Build related configuration options
 #---------------------------------------------------------------------------
@@ -536,7 +583,8 @@ HIDE_UNDOC_MEMBERS     = NO
 # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
 # undocumented classes that are normally visible in the class hierarchy. If set
 # to NO, these classes will be included in the various overviews. This option
-# has no effect if EXTRACT_ALL is enabled.
+# will also hide undocumented C++ concepts if enabled. This option has no effect
+# if EXTRACT_ALL is enabled.
 # The default value is: NO.
 
 HIDE_UNDOC_CLASSES     = NO
@@ -567,14 +615,15 @@ INTERNAL_DOCS          = NO
 # filesystem is case sensitive (i.e. it supports files in the same directory
 # whose names only differ in casing), the option must be set to YES to properly
 # deal with such files in case they appear in the input. For filesystems that
-# are not case sensitive the option should be be set to NO to properly deal with
+# are not case sensitive the option should be set to NO to properly deal with
 # output files written for symbols that only differ in casing, such as for two
 # classes, one named CLASS and the other named Class, and to also support
 # references to files without having to specify the exact matching casing. On
 # Windows (including Cygwin) and MacOS, users should typically set this option
 # to NO, whereas on Linux or other Unix flavors it should typically be set to
 # YES.
-# The default value is: system dependent.
+# Possible values are: SYSTEM, NO and YES.
+# The default value is: SYSTEM.
 
 CASE_SENSE_NAMES       = YES
 
@@ -826,11 +875,26 @@ WARN_IF_INCOMPLETE_DOC = YES
 
 WARN_NO_PARAMDOC       = YES
 
+# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
+# undocumented enumeration values. If set to NO, doxygen will accept
+# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: NO.
+
+WARN_IF_UNDOC_ENUM_VAL = NO
+
 # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
 # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
 # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
 # at the end of the doxygen process doxygen will return with a non-zero status.
-# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
+# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
+# write the warning messages in between other messages but write them at the end
+# of a run, in case a WARN_LOGFILE is defined the warning messages will be
+# besides being in the defined file also be shown at the end of a run, unless
+# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
+# the behavior will remain as with the setting FAIL_ON_WARNINGS.
+# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
 # The default value is: NO.
 
 WARN_AS_ERROR          = NO
@@ -841,10 +905,21 @@ WARN_AS_ERROR          = NO
 # and the warning text. Optionally the format may contain $version, which will
 # be replaced by the version of the file (if it could be obtained via
 # FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
 # The default value is: $file:$line: $text.
 
 WARN_FORMAT            = "$file:$line: $text"
 
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+
+WARN_LINE_FORMAT       = "at line $line of file $file"
+
 # The WARN_LOGFILE tag can be used to specify a file to which warning and error
 # messages should be written. If left blank the output is written to standard
 # error (stderr). In case the file specified cannot be opened for writing the
@@ -864,17 +939,34 @@ WARN_LOGFILE           =
 # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = kissinference.cs doc/mainpage.txt
+INPUT                  = src/network.cs \
+                         src/spectra.cs \
+                         src/capi.cs \
+                         src/utils.cs \
+                         src/versionfixed.cs \
+                         src/inferenceexception.cs \
+                         doc/mainpage.txt
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
 # libiconv (or the iconv built into libc) for the transcoding. See the libiconv
 # documentation (see:
 # https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# See also: INPUT_FILE_ENCODING
 # The default value is: UTF-8.
 
 INPUT_ENCODING         = UTF-8
 
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
+# character encoding on a per file pattern basis. Doxygen will compare the file
+# name with each pattern and apply the encoding instead of the default
+# INPUT_ENCODING) if there is a match. The character encodings are a list of the
+# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
+# "INPUT_ENCODING" for further information on supported encodings.
+
+INPUT_FILE_ENCODING    =
+
 # If the value of the INPUT tag contains directories, you can use the
 # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
 # *.h) to filter out the source-files in the directories.
@@ -886,12 +978,12 @@ INPUT_ENCODING         = UTF-8
 # Note the list of default checked file patterns might differ from the list of
 # default file extension mappings.
 #
-# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
-# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
-# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
-# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
-# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
-# *.vhdl, *.ucf, *.qsf and *.ice.
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
+# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl,
+# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d,
+# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to
+# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
 
 FILE_PATTERNS          =
 
@@ -931,9 +1023,6 @@ EXCLUDE_PATTERNS       =
 # output. The symbol name can be a fully qualified name, a word, or if the
 # wildcard * is used, a substring. Examples: ANamespace, AClass,
 # ANamespace::AClass, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
 
 EXCLUDE_SYMBOLS        =
 
@@ -978,6 +1067,11 @@ IMAGE_PATH             = doc/
 # code is scanned, but not when the output code is generated. If lines are added
 # or removed, the anchors will not be placed correctly.
 #
+# Note that doxygen will use the data processed and written to standard output
+# for further processing, therefore nothing else, like debug statements or used
+# commands (so in case of a Windows batch file always use @echo OFF), should be
+# written to standard output.
+#
 # Note that for custom extensions or not directly supported extensions you also
 # need to set EXTENSION_MAPPING for the extension otherwise the files are not
 # properly processed by doxygen.
@@ -1019,6 +1113,15 @@ FILTER_SOURCE_PATTERNS =
 
 USE_MDFILE_AS_MAINPAGE =
 
+# The Fortran standard specifies that for fixed formatted Fortran code all
+# characters from position 72 are to be considered as comment. A common
+# extension is to allow longer lines before the automatic comment starts. The
+# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
+# be processed before the automatic comment starts.
+# Minimum value: 7, maximum value: 10000, default value: 72.
+
+FORTRAN_COMMENT_AFTER  = 72
+
 #---------------------------------------------------------------------------
 # Configuration options related to source browsing
 #---------------------------------------------------------------------------
@@ -1033,7 +1136,8 @@ USE_MDFILE_AS_MAINPAGE =
 SOURCE_BROWSER         = NO
 
 # Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
+# multi-line macros, enums or list initialized variables directly into the
+# documentation.
 # The default value is: NO.
 
 INLINE_SOURCES         = NO
@@ -1105,6 +1209,46 @@ USE_HTAGS              = NO
 
 VERBATIM_HEADERS       = YES
 
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
+# tag is set to YES then doxygen will add the directory of each input to the
+# include path.
+# The default value is: YES.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_ADD_INC_PATHS    = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH    =
+
 #---------------------------------------------------------------------------
 # Configuration options related to the alphabetical class index
 #---------------------------------------------------------------------------
@@ -1116,10 +1260,11 @@ VERBATIM_HEADERS       = YES
 
 ALPHABETICAL_INDEX     = NO
 
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
+# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
+# that should be ignored while generating the index headers. The IGNORE_PREFIX
+# tag works for classes, function and member names. The entity will be placed in
+# the alphabetical list under the first letter of the entity name that remains
+# after removing the prefix.
 # This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
 
 IGNORE_PREFIX          =
@@ -1198,7 +1343,12 @@ HTML_STYLESHEET        =
 # Doxygen will copy the style sheet files to the output directory.
 # Note: The order of the extra style sheet files is of importance (e.g. the last
 # style sheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
+# list).
+# Note: Since the styling of scrollbars can currently not be overruled in
+# Webkit/Chromium, the styling will be left out of the default doxygen.css if
+# one or more extra stylesheets have been specified. So if scrollbar
+# customization is desired it has to be added explicitly. For an example see the
+# documentation.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_EXTRA_STYLESHEET  = doc/style.css
@@ -1213,6 +1363,19 @@ HTML_EXTRA_STYLESHEET  = doc/style.css
 
 HTML_EXTRA_FILES       =
 
+# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
+# should be rendered with a dark or light theme.
+# Possible values are: LIGHT always generate light mode output, DARK always
+# generate dark mode output, AUTO_LIGHT automatically set the mode according to
+# the user preference, use light mode if no preference is set (the default),
+# AUTO_DARK automatically set the mode according to the user preference, use
+# dark mode if no preference is set and TOGGLE allow to user to switch between
+# light and dark mode via a button.
+# The default value is: AUTO_LIGHT.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE        = AUTO_LIGHT
+
 # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
 # will adjust the colors in the style sheet and background images according to
 # this color. Hue is specified as an angle on a color-wheel, see
@@ -1243,15 +1406,6 @@ HTML_COLORSTYLE_SAT    = 100
 
 HTML_COLORSTYLE_GAMMA  = 80
 
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to YES can help to show when doxygen was last run and thus if the
-# documentation is up to date.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP         = NO
-
 # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
 # documentation will contain a main index with vertical navigation menus that
 # are dynamically created via JavaScript. If disabled, the navigation index will
@@ -1271,6 +1425,33 @@ HTML_DYNAMIC_MENUS     = YES
 
 HTML_DYNAMIC_SECTIONS  = NO
 
+# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
+# dynamically folded and expanded in the generated HTML source code.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_CODE_FOLDING      = YES
+
+# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in
+# the top right corner of code and text fragments that allows the user to copy
+# its content to the clipboard. Note this only works if supported by the browser
+# and the web page is served via a secure context (see:
+# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file:
+# protocol.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COPY_CLIPBOARD    = YES
+
+# Doxygen stores a couple of settings persistently in the browser (via e.g.
+# cookies). By default these settings apply to all HTML pages generated by
+# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store
+# the settings under a project specific key, such that the user preferences will
+# be stored separately.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_PROJECT_COOKIE    =
+
 # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
 # shown in the various tree structured indices initially; the user can expand
 # and collapse entries dynamically later on. Doxygen will expand the tree to
@@ -1401,6 +1582,16 @@ BINARY_TOC             = NO
 
 TOC_EXPAND             = NO
 
+# The SITEMAP_URL tag is used to specify the full URL of the place where the
+# generated documentation will be placed on the server by the user during the
+# deployment of the documentation. The generated sitemap is called sitemap.xml
+# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
+# is specified no sitemap is generated. For information about the sitemap
+# protocol see https://www.sitemaps.org
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SITEMAP_URL            =
+
 # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
 # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
 # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
@@ -1576,17 +1767,6 @@ HTML_FORMULA_FORMAT    = png
 
 FORMULA_FONTSIZE       = 10
 
-# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT    = YES
-
 # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
 # to create new LaTeX commands to be used in formulas as building blocks. See
 # the section "Including formulas" for details.
@@ -1900,9 +2080,16 @@ PDF_HYPERLINKS         = NO
 
 USE_PDFLATEX           = YES
 
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help.
+# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
+# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
+# mode nothing is printed on the terminal, errors are scrolled as if <return> is
+# hit at every error; missing files that TeX tries to input or request from
+# keyboard input (\read on a not open input stream) cause the job to abort,
+# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
+# but there is no possibility of user interaction just like in batch mode,
+# SCROLL In scroll mode, TeX will stop only for missing files to input or if
+# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
+# each error, asking for user intervention.
 # The default value is: NO.
 # This tag requires that the tag GENERATE_LATEX is set to YES.
 
@@ -1923,14 +2110,6 @@ LATEX_HIDE_INDICES     = NO
 
 LATEX_BIB_STYLE        = plain
 
-# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
-# 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.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_TIMESTAMP        = NO
-
 # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
 # path from which the emoji images will be read. If a relative path is entered,
 # it will be relative to the LATEX_OUTPUT directory. If left blank the
@@ -2096,13 +2275,39 @@ DOCBOOK_OUTPUT         = docbook
 #---------------------------------------------------------------------------
 
 # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
-# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
 # the structure of the code including all documentation. Note that this feature
 # is still experimental and incomplete at the moment.
 # The default value is: NO.
 
 GENERATE_AUTOGEN_DEF   = NO
 
+#---------------------------------------------------------------------------
+# Configuration options related to Sqlite3 output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3
+# database with symbols found by doxygen stored in tables.
+# The default value is: NO.
+
+GENERATE_SQLITE3       = NO
+
+# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
+# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
+# in front of it.
+# The default directory is: sqlite3.
+# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
+
+SQLITE3_OUTPUT         = sqlite3
+
+# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db
+# database file will be recreated with each doxygen run. If set to NO, doxygen
+# will warn if a database file is already found and not modify it.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
+
+SQLITE3_RECREATE_DB    = YES
+
 #---------------------------------------------------------------------------
 # Configuration options related to the Perl module output
 #---------------------------------------------------------------------------
@@ -2177,7 +2382,8 @@ SEARCH_INCLUDES        = YES
 
 # The INCLUDE_PATH tag can be used to specify one or more directories that
 # contain include files that are not input files but should be processed by the
-# preprocessor.
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
 # This tag requires that the tag SEARCH_INCLUDES is set to YES.
 
 INCLUDE_PATH           =
@@ -2244,15 +2450,15 @@ TAGFILES               =
 
 GENERATE_TAGFILE       =
 
-# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
-# the class index. If set to NO, only the inherited external classes will be
-# listed.
+# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
+# will be listed in the class and namespace index. If set to NO, only the
+# inherited external classes will be listed.
 # The default value is: NO.
 
 ALLEXTERNALS           = NO
 
 # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will be
+# in the topic index. If set to NO, only the current project's groups will be
 # listed.
 # The default value is: YES.
 
@@ -2266,16 +2472,9 @@ EXTERNAL_GROUPS        = YES
 EXTERNAL_PAGES         = YES
 
 #---------------------------------------------------------------------------
-# Configuration options related to the dot tool
+# Configuration options related to diagram generator tools
 #---------------------------------------------------------------------------
 
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH               =
-
 # If set to YES the inheritance and collaboration graphs will hide inheritance
 # and usage relations if the target is undocumented or is not a class.
 # The default value is: YES.
@@ -2284,7 +2483,7 @@ HIDE_UNDOC_RELATIONS   = YES
 
 # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
 # available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
 # Bell Labs. The other options in this section have no effect if this option is
 # set to NO
 # The default value is: NO.
@@ -2301,37 +2500,55 @@ HAVE_DOT               = YES
 
 DOT_NUM_THREADS        = 0
 
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
+# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
+# subgraphs. When you want a differently looking font in the dot files that
+# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
+# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
+# Edge and Graph Attributes specification</a> You need to make sure dot is able
+# to find the font, which can be done by putting it in a standard location or by
+# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font. Default graphviz fontsize is 14.
+# The default value is: fontname=Helvetica,fontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_COMMON_ATTR        = "fontname=Helvetica,fontsize=10"
+
+# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
+# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
+# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
+# arrows shapes.</a>
+# The default value is: labelfontname=Helvetica,labelfontsize=10.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
-DOT_FONTNAME           =
+DOT_EDGE_ATTR          = "labelfontname=Helvetica,labelfontsize=10"
 
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
+# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
+# around nodes set 'shape=plain' or 'shape=plaintext' <a
+# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
+# The default value is: shape=box,height=0.2,width=0.4.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
-DOT_FONTSIZE           = 10
+DOT_NODE_ATTR          = "shape=box,height=0.2,width=0.4"
 
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
+# You can set the path where dot can find font specified with fontname in
+# DOT_COMMON_ATTR and others dot attributes.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_FONTPATH           =
 
-# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
-# graph for each documented class showing the direct and indirect inheritance
-# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
-# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
-# to TEXT the direct and indirect inheritance relations will be shown as texts /
-# links.
-# Possible values are: NO, YES, TEXT and GRAPH.
+# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
+# generate a graph for each documented class showing the direct and indirect
+# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
+# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
+# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
+# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
+# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
+# relations will be shown as texts / links. Explicit enabling an inheritance
+# graph or choosing a different representation for an inheritance graph of a
+# specific class, can be accomplished by means of the command \inheritancegraph.
+# Disabling an inheritance graph can be accomplished by means of the command
+# \hideinheritancegraph.
+# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
 # The default value is: YES.
 
 CLASS_GRAPH            = TEXT
@@ -2339,14 +2556,21 @@ CLASS_GRAPH            = TEXT
 # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
 # graph for each documented class showing the direct and indirect implementation
 # dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
+# class with other documented classes. Explicit enabling a collaboration graph,
+# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
+# command \collaborationgraph. Disabling a collaboration graph can be
+# accomplished by means of the command \hidecollaborationgraph.
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
 COLLABORATION_GRAPH    = YES
 
 # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
+# groups, showing the direct groups dependencies. Explicit enabling a group
+# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
+# of the command \groupgraph. Disabling a directory graph can be accomplished by
+# means of the command \hidegroupgraph. See also the chapter Grouping in the
+# manual.
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2388,8 +2612,8 @@ DOT_UML_DETAILS        = NO
 
 # The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
 # to display on a single line. If the actual line length exceeds this threshold
-# significantly it will wrapped across multiple lines. Some heuristics are apply
-# to avoid ugly line breaks.
+# significantly it will be wrapped across multiple lines. Some heuristics are
+# applied to avoid ugly line breaks.
 # Minimum value: 0, maximum value: 1000, default value: 17.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2406,7 +2630,9 @@ TEMPLATE_RELATIONS     = NO
 # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
 # YES then doxygen will generate a graph for each documented file showing the
 # direct and indirect include dependencies of the file with other documented
-# files.
+# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
+# can be accomplished by means of the command \includegraph. Disabling an
+# include graph can be accomplished by means of the command \hideincludegraph.
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2415,7 +2641,10 @@ INCLUDE_GRAPH          = NO
 # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
 # set to YES then doxygen will generate a graph for each documented file showing
 # the direct and indirect include dependencies of the file with other documented
-# files.
+# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
+# to NO, can be accomplished by means of the command \includedbygraph. Disabling
+# an included by graph can be accomplished by means of the command
+# \hideincludedbygraph.
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2455,7 +2684,10 @@ GRAPHICAL_HIERARCHY    = YES
 # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
 # dependencies a directory has on other directories in a graphical way. The
 # dependency relations are determined by the #include relations between the
-# files in the directories.
+# files in the directories. Explicit enabling a directory graph, when
+# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
+# \directorygraph. Disabling a directory graph can be accomplished by means of
+# the command \hidedirectorygraph.
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2471,7 +2703,7 @@ DIR_GRAPH_MAX_DEPTH    = 1
 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
 # generated by dot. For an explanation of the image formats see the section
 # output formats in the documentation of the dot tool (Graphviz (see:
-# http://www.graphviz.org/)).
+# https://www.graphviz.org/)).
 # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
 # to make the SVG files visible in IE 9+ (other browsers do not have this
 # requirement).
@@ -2508,11 +2740,12 @@ DOT_PATH               =
 
 DOTFILE_DIRS           =
 
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
 
-MSCFILE_DIRS           =
+DIA_PATH               =
 
 # The DIAFILE_DIRS tag can be used to specify one or more directories that
 # contain dia files that are included in the documentation (see the \diafile
@@ -2562,18 +2795,6 @@ DOT_GRAPH_MAX_NODES    = 50
 
 MAX_DOT_GRAPH_DEPTH    = 0
 
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT        = NO
-
 # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
 # files in one run (i.e. multiple -o and -T options on the command line). This
 # makes dot run faster, but since only newer versions of dot (>1.8.10) support
@@ -2601,3 +2822,19 @@ GENERATE_LEGEND        = NO
 # The default value is: YES.
 
 DOT_CLEANUP            = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
+# use a built-in version of mscgen tool to produce the charts. Alternatively,
+# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
+# specifying prog as the value, doxygen will call the tool as prog -T
+# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
+# output file formats "png", "eps", "svg", and "ismap".
+
+MSCGEN_TOOL            =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
diff --git a/doc/mainpage.txt b/doc/mainpage.txt
index 55abec9d8967c0abb56017ffe12a4a45d1fe99e4..80a66fa5a47e52d15e33833dc0be1d7a26d1dfde 100644
--- a/doc/mainpage.txt
+++ b/doc/mainpage.txt
@@ -1,12 +1,12 @@
 /*! \mainpage libkissinferencesharp manual
 
-_libkissinferencesharp_ is a c# libary containing bindings to the c libary libkissinference that allows client applicaitons to use KISS neural networks for varous tasks.
+_libkissinferencesharp_ is a C# libary containing bindings to the C libary libkissinference that allows client applicaitons to use KISS neural networks for varous tasks.
 
-A full description of the api can be found here: \ref API
+The best place to start, and probubly the only classes most users of this libary will need can be found here: \ref Kiss.Network and \ref Kiss.Spectra
 
 ## Building
 
-the main development platform of _libkissinferencesharp_ is explicitly cross-platform and has minimal dependancies. It is tested to work in Linux and Microsoft Windows 10.
+The main development platform of _libkissinferencesharp_ is explicitly cross-platform and has minimal dependancies. It is tested to work in Linux and Microsoft Windows 10.
 
 ### Requirements
 - [git](https://git-scm.com/) is required to get the source
diff --git a/kissinference.cs b/kissinference.cs
deleted file mode 100644
index 7cf6066abaadae024827a29fcf5a8317388c00f8..0000000000000000000000000000000000000000
--- a/kissinference.cs
+++ /dev/null
@@ -1,611 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using System.Collections.Generic;
-using System.Threading;
-
-namespace Kiss
-{
-
-/// <summary>
-/// Struct <c>VersionFixed</c> reprisents the version of kissinference
-/// </summary>
-[StructLayout (LayoutKind.Sequential)]
-public struct VersionFixed
-{
-	public int Major;
-	public int Minor;
-	public int Patch;
-
-	/// <summary>
-	/// This Method returns the version of the currently loaded kissinference instance.
-	/// </summary>
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "kiss_get_version", CallingConvention=CallingConvention.StdCall)]
-	public static extern VersionFixed GetVersion();
-}
-
-
-/// <summary>
-/// This Exception is thrown when an error occures during infference, usualy due to oom.
-/// </summary>
-public class InferenceException : Exception
-{
-	public InferenceException(){}
-	public InferenceException(string message): base(message){}
-	public InferenceException(string message, Exception inner): base(message, inner){}
-}
-
-
-/// <summary>
-/// This is the main class of kissinference, it allows you to load and use Kiss neural neturoks
-/// </summary>
-public class Network: System.IDisposable
-{
-	public delegate void ResultDlg(float[] result, Network network);
-
-	private struct Flight
-	{
-		public ResultDlg Callback;
-		public AutoResetEvent Signal;
-	}
-
-	private CNetwork net;
-	private bool disposed = false;
-	private Dictionary<IntPtr, Flight> inflight = new Dictionary<IntPtr, Flight>();
-	private IntPtr flightcounter = (IntPtr)0;
-
-	private void CResultCb(IntPtr result, ref CNetwork network, IntPtr data)
-	{
-		var managedResult = new float[(int)net.outputSize];
-		Marshal.Copy(result, managedResult, 0, (int)net.outputSize);
-		Capi.free(result);
-		var flight = inflight[data];
-		inflight.Remove(data);
-		flight.Callback(managedResult, this);
-		flight.Signal.Set();
-	}
-
-	/// <summary>
-	/// Constructs a new Network object by loading a network off disk
-	/// </summary>
-	/// <param name="path">
-	/// the path to the onnx network file to load
-	/// </param>
-	/// <param name="verbose">
-	/// if true is set here some extra debug information will be printed by the runtime
-	/// </param>
-	/// <exception cref="System.IO.FileLoadException">
-	/// Thrown when the network file could not be loaded
-	/// </exception>
-	public Network(string path, bool verbose = false)
-	{
-		byte ret = Capi.kiss_load_network_prealloc(ref net, path, CResultCb, Convert.ToByte(verbose));
-		Console.WriteLine("ret: {0:D}", ret);
-		if(ret == 0)
-			throw new System.IO.FileLoadException(getError());
-	}
-
-	/// <summary>
-	/// This method runs an inference pass on the given spectra asynchronously
-	/// </summary>
-	/// <param name="spectra">
-	/// the spectra to run inference on, must be of InputSize length
-	/// </param>
-	/// <param name="callback">
-	/// a delegate that will be called when inference completes, this callback will be called from a native thread in libkissiniferences thread pool
-	/// </param>
-	/// <exception cref="ArgumentException">
-	/// Thrown when the input is of an incorrect size for the network
-	/// </exception>
-	/// <exception cref="InferenceException">
-	/// Thrown when the inference engine encounteres an internal error
-	/// </exception>
-	/// <returns>
-	/// The AutoResetEvent returned can be waited on to ensure that the inference is finished and the callback has been executed.
-	/// </returns>
-	public AutoResetEvent Run(Spectra spectra, ResultDlg callback)
-	{
-		if(spectra.Real.Length*2 != (int)net.inputSize)
-			throw new ArgumentException("Spectra is the wrong size for network, use resample() first");
-		var flight = new Flight();
-		flight.Callback = callback;
-		flight.Signal = new AutoResetEvent(false);
-		inflight.Add(flightcounter, flight);
-		byte ret = Capi.kiss_async_run_inference_complex(ref net, spectra.Real, spectra.Imaginary, flightcounter);
-		if(ret == 0)
-			throw new InferenceException(getError());
-
-		flightcounter += 1;
-		return flight.Signal;
-	}
-
-	/// <summary>
-	/// This method runs an inference pass on the given spectra asynchronously
-	/// </summary>
-	/// <param name="data">
-	/// and array of floats containing the data inference on, must be of InputSize length
-	/// </param>
-	/// <param name="callback">
-	/// a delegate that will be called when inference completes, this callback will be called from a native thread in libkissiniferences thread pool
-	/// </param>
-	/// <exception cref="ArgumentException">
-	/// Thrown when the input is of an incorrect size for the network
-	/// </exception>
-	/// <exception cref="InferenceException">
-	/// Thrown when the inference engine encounteres an internal error
-	/// </exception>
-	/// <returns>
-	/// The AutoResetEvent returned can be waited on to ensure that the inference is finished and the callback has been executed.
-	/// </returns>
-	public AutoResetEvent Run(float[] data, ResultDlg callback)
-	{
-		if(data.Length != (int)net.inputSize)
-			throw new ArgumentException("Data is the wrong size for network");
-		var flight = new Flight();
-		flight.Callback = callback;
-		flight.Signal = new AutoResetEvent(false);
-		inflight.Add(flightcounter, flight);
-		byte ret = Capi.kiss_async_run_inference(ref net, data, flightcounter);
-		if(ret == 0)
-			throw new InferenceException(getError());
-		flightcounter += 1;
-		return flight.Signal;
-	}
-
-	/// <summary>
-	/// This method returns an error string for the last error to have occured in the libkissiniference.
-	/// Usually this method is not usefull as all errors reported by this interface are forwared via exceptions,
-	/// It is provided to ease implementations that also call the C api directly.
-	/// </summary>
-	/// <returns>
-	/// A string describeing the last reported error.
-	/// </returns>
-	private string getError()
-	{
-#if (NET6_0_OR_GREATER)
-		return Marshal.PtrToStringUTF8(Capi.kiss_get_strerror(ref net));
-#else
-		return Capi.UTF8StringFromPointer(Capi.kiss_get_strerror(ref net));
-#endif
-        }
-
-        public void Dispose()
-	{
-		Dispose(true);
-		GC.SuppressFinalize(this);
-	}
-
-	protected virtual void Dispose(bool disposing)
-	{
-		if(!disposed)
-		{
-			disposed = true;
-			Capi.kiss_free_network_prealloc(ref net);
-		}
-	}
-
-	~Network()
-	{
-		Dispose(false);
-	}
-
-	/// <summary>
-	/// This Property holds the number of input values the loaded network expects.
-	/// For networks with a convolutional input this may be -1 designateing "Any"
-	/// </summary>
-	public int InputSize
-	{
-		get{return (int)net.inputSize;}
-	}
-
-	/// <summary>
-	/// This Property holds the number of output values the loaded network expects.
-	/// </summary>
-	public int OutputSize
-	{
-		get{return (int)net.outputSize;}
-	}
-
-	/// <summary>
-	/// This Property holds a string describeing the purpose the network was trained on.
-	/// </summary>
-	public string Purpose
-	{
-		get{return Marshal.PtrToStringAnsi(net.purpose);}
-	}
-
-	/// <summary>
-	/// This Property holds a string describeing the type of input the network expects.
-	/// </summary>
-	public string InputLabel
-	{
-		get{return Marshal.PtrToStringAnsi(net.inputLabel);}
-	}
-
-	/// <summary>
-	/// This Property is true if the network expects a complex valued input
-	/// </summary>
-	public bool ComplexInput
-	{
-		get{return Convert.ToBoolean(net.complexInput);}
-	}
-
-	/// <summary>
-	/// This Property is an array of OutputSize with strings nameing what every output corrisponds to
-	/// </summary>
-	public string[] OutputLabels
-	{
-		get{return Capi.IntPtrToUtf8Array(net.outputLabels);}
-	}
-}
-
-/// <summary>
-/// This Class holds an impedance spectra and provides various transformations that are required to get the values into a form expected by kiss networks
-/// </summary>
-public class Spectra
-{
-	/// <summary>
-	/// The real part of the spectra
-	/// </summary>
-	public float[] Real;
-
-	/// <summary>
-	/// The imaginary part of the spectra
-	/// </summary>
-	public float[] Imaginary;
-
-	/// <summary>
-	/// The frequencys of the datapoints of the spectra
-	/// </summary>
-	public float[] Omega;
-
-	/// <summary>
-	/// This constructor constructs a spectra from a series of arrays
-	/// </summary>
-	/// <param name="Real">
-	/// The real part of the spectra
-	/// </param>
-	/// <param name="Imaginary">
-	/// The imaginary part of the spectra, its length must be the same as Real
-	/// </param>
-	/// <param name="Omega">
-	/// The frequency values in rad/s of eatch datapoint, its lenght must be the same as Real
-	/// </param>
-	public Spectra(float[] Real, float[] Imaginary, float[] Omega)
-	{
-		if(Real.Length != Imaginary.Length || Real.Length != Omega.Length)
-			throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size");
-		this.Real = Real;
-		this.Imaginary = Imaginary;
-		this.Omega = Omega;
-	}
-
-	/// <summary>
-	/// This constructor constructs a spectra from a series of arrays
-	/// </summary>
-	/// <param name="Real">
-	/// The real part of the spectra
-	/// </param>
-	/// <param name="Imaginary">
-	/// The imaginary part of the spectra, its length must be the same as Real
-	/// </param>
-	/// <param name="Omega">
-	/// The frequency values in rad/s of eatch datapoint, its lenght must be the same as Real
-	/// </param>
-	public Spectra(double[] Real, double[] Imaginary, double[] Omega)
-	{
-		if(Real.Length != Imaginary.Length || Real.Length != Omega.Length)
-			throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size");
-		this.Real = DoubleToFloat(Real);
-		this.Imaginary = DoubleToFloat(Imaginary);
-		this.Omega = DoubleToFloat(Omega);
-	}
-
-	/// <summary>
-	/// This method normalizes the data into the range [0, 1]
-	/// </summary>
-	public void Normalize()
-	{
-		Capi.kiss_normalize_spectra(Real, Imaginary, (UIntPtr)Real.Length);
-	}
-
-	/// <summary>
-	/// This method resamples the spectra to the size given in newSize.
-	/// Upsampling is achived via linear interpolation, downsampling is achived via the nearest-neighbor method.
-	/// </summary>
-	/// <param name="newSize">
-	/// The size to resample the spectra to
-	/// </param>
-	public void Resample(int newSize)
-	{
-		var ret_ptr_real = new IntPtr();
-		var ret_ptr_imag = new IntPtr();
-		Capi.kiss_resample_spectra(Real, Imaginary, (UIntPtr)Real.Length, ref ret_ptr_real, ref ret_ptr_imag, (UIntPtr)newSize);
-
-		Real = new float[newSize];
-		Imaginary = new float[newSize];
-		Marshal.Copy(ret_ptr_real, Real, 0, newSize);
-		Marshal.Copy(ret_ptr_imag, Imaginary, 0, newSize);
-
-		Capi.free(ret_ptr_real);
-		Capi.free(ret_ptr_imag);
-	}
-
-	/// <summary>
-	/// Approximate the element wise absolute gradient at the given point of the sepctra in the place given
-	/// </summary>
-	/// <param name="index">
-	/// The index at which to aproxmiate the gradiant
-	/// </param>
-	/// <return>
-	/// The element wise absolute of the gradiant as a tuple of floats
-	/// </return>
-	public Tuple<float, float> Absgrad(int index)
-	{
-		var resultArray = new float[2];
-		IntPtr ptr = Capi.kiss_absgrad(Real, Imaginary, Omega, (UIntPtr)Real.Length, (UIntPtr)index);
-		Marshal.Copy(ptr, resultArray, 0, 2);
-		Capi.free(ptr);
-		return new Tuple<float, float>(resultArray[0], resultArray[1]);
-	}
-
-	/// <summary>
-	/// Applies the same series of filteres used by kiss networks (applied by TorchKissAnn) during training.
-	///
-	/// In almost all cases this function should be called before a sepctra is given to a kiss network.
-	/// </summary>
-	/// <param name="outputSize">
-	/// the length the spectra should have after filtering
-	/// </param>
-	/// <return>
-	/// True if sucessfull, false otherwise
-	/// </return>
-	public bool Filter(int outputSize)
-	{
-		var ret_ptr_real = new IntPtr();
-		var ret_ptr_imag = new IntPtr();
-		byte ret = Capi.kiss_filter_spectra(Real, Imaginary, Omega, (UIntPtr)Real.Length, ref ret_ptr_real, ref ret_ptr_imag, (UIntPtr)outputSize);
-
-		if(ret == 1)
-		{
-			Real = new float[(int)outputSize];
-			Imaginary = new float[(int)outputSize];
-			Marshal.Copy(ret_ptr_real, Real, 0, (int)outputSize);
-			Marshal.Copy(ret_ptr_imag, Imaginary, 0, (int)outputSize);
-			Capi.free(ret_ptr_real);
-			Capi.free(ret_ptr_imag);
-		}
-
-		return Convert.ToBoolean(ret);
-	}
-
-	/// <summary>
-	/// Applies the same series of filteres used by kiss networks (applied by TorchKissAnn) during training.
-	///
-	/// In almost all cases this function should be called before a sepctra is given to a kiss network.
-	/// </summary>
-	/// <param name="outputSize">
-	/// the length the spectra should have after filtering
-	/// </param>
-	/// <return>
-	/// True if sucessfull, false otherwise
-	/// </return>
-	public bool Reduce(float threshFactor, bool useSecondDeriv)
-	{
-		var ret_ptr_real = new IntPtr();
-		var ret_ptr_imag = new IntPtr();
-		var lengthPtr = new UIntPtr();
-		byte ret = Capi.kiss_reduce_spectra(Real, Imaginary, Omega, (UIntPtr)Real.Length, threshFactor, Convert.ToByte(useSecondDeriv), ref ret_ptr_real, ref ret_ptr_imag, ref lengthPtr);
-
-		if(ret == 1)
-		{
-			Real = new float[(int)lengthPtr];
-			Imaginary = new float[(int)lengthPtr];
-			Marshal.Copy(ret_ptr_real, Real, 0, (int)lengthPtr);
-			Marshal.Copy(ret_ptr_imag, Imaginary, 0, (int)lengthPtr);
-			Capi.free(ret_ptr_real);
-			Capi.free(ret_ptr_imag);
-		}
-
-		return Convert.ToBoolean(ret);
-	}
-
-	/// <summary>
-	/// Converts an array of doubles to an array of floats.
-	/// </summary>
-	/// <param name="input">
-	/// The input array.
-	/// </param>
-	/// <return>
-	/// An array with the same values as the input truncated to floats.
-	/// </return>
-	private static float[] DoubleToFloat(double[] input)
-	{
-		var res = new float[input.Length];
-		for(int i = 0; i < input.Length; ++i)
-			res[i] = (float)input[i];
-		return res;
-	}
-
-}
-
-/// <summary>
-/// This class is a collection of static methods usefull for use with kissinference.
-/// </summary>
-public class Utils
-{
-	/// <summary>
-	/// Converts an array containing a linear or log range.
-	/// </summary>
-	/// <param name="start">
-	/// The startig value of the range.
-	/// </param>
-	/// <param name="end">
-	/// The ending value of the range.
-	/// </param>
-	/// <param name="size">
-	/// The number of elements in the range.
-	/// </param>
-	/// <param name="log">
-	/// If this is set to true the elements in the range are spaced in log10 fashion, otherwise linear spaceing is used.
-	/// </param>
-	/// <return>
-	/// An array containing the requested range
-	/// </return>
-	public static float[] CreateRange(float start, float end, int size, bool log)
-	{
-		IntPtr ptr = Capi.kiss_create_range(start, end, (UIntPtr)size, Convert.ToByte(log));
-		var ret = new float[size];
-		Marshal.Copy(ptr, ret, 0, size);
-		Capi.free(ptr);
-		return ret;
-	}
-
-	/// <summary>
-	/// Approximates the the derivative of an array at the given index.
-	/// </summary>
-	/// <param name="data">
-	/// The array, or y values, to approximate the derivative on
-	/// </param>
-	/// <param name="omegas">
-	/// The omega, or x values to approximate the derivative on
-	/// </param>
-	/// <param name="index">
-	/// The index at which to aproxmiate the gradiant at.
-	/// </param>
-	/// <return>
-	/// The aproxmiate derivative.
-	/// </return>
-	public static float Grad(float[] data, float[] omegas, int index)
-	{
-		if(data.Length != omegas.Length)
-			throw new ArgumentException("the data and omegas must be the same length");
-		return Capi.kiss_grad(data, omegas, (UIntPtr)data.Length, (UIntPtr)index);
-	}
-
-	/// <summary>
-	/// Calculates the median of the values given
-	/// </summary>
-	/// <param name="input">
-	/// The input array.
-	/// </param>
-	/// <return>
-	/// The median value
-	/// </return>
-	public static float Median(float[] data)
-	{
-		return Capi.kiss_median(data, (UIntPtr)data.Length);
-	}
-}
-
-/// <summary>
-/// This struct is a raw repisenstion of the C struct used in libkissiniference, ususally users of these bindings will not need to directly use this.
-/// </summary>
-[StructLayout (LayoutKind.Sequential)]
-public struct CNetwork
-{
-	private IntPtr _private;
-	public UIntPtr inputSize;
-	public UIntPtr outputSize;
-	public IntPtr purpose;
-	public IntPtr inputLabel;
-	public IntPtr outputLabels;
-	public byte complexInput;
-	public byte ready;
-	public byte softmax;
-	private IntPtr _resultCb;
-}
-
-internal class Capi
-{
-	public delegate void resultDlg(IntPtr result, ref CNetwork network, IntPtr data);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "kiss_free", CallingConvention=CallingConvention.StdCall)]
-	public static extern void free(IntPtr ptr);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern IntPtr kiss_create_range(float start, float end, UIntPtr length, byte log);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern void kiss_resample_spectra(float[] in_re, float[] in_im, UIntPtr input_length, ref IntPtr ret_ptr_real, ref IntPtr ret_ptr_imag, UIntPtr output_length);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern void kiss_normalize_spectra(float[] in_re, float[] in_im, UIntPtr input_length);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern IntPtr kiss_absgrad(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length, UIntPtr index);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern float kiss_grad(float[] data, float[] omegas, UIntPtr input_length, UIntPtr index);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern float kiss_median(float[] data, UIntPtr input_length);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern byte kiss_reduce_spectra(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length, float thresh_factor,
-	                                       byte use_second_deriv, ref IntPtr out_re, ref IntPtr out_im, ref UIntPtr output_length);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-
-	public static extern byte kiss_filter_spectra(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length,
-	                                              ref IntPtr out_re, ref IntPtr out_im, UIntPtr output_length);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern byte kiss_load_network_prealloc(ref CNetwork net, string path, resultDlg callback, byte verbose);
-
-	[DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern void puts(string path);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern void kiss_free_network_prealloc(ref CNetwork net);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern byte kiss_async_run_inference(ref CNetwork net, [Out] float[] inputs, IntPtr data);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern byte kiss_async_run_inference_complex(ref CNetwork net, [Out] float[] real, [Out] float[] imag, IntPtr data);
-
-	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
-	public static extern IntPtr kiss_get_strerror(ref CNetwork net);
-
-
-	public static unsafe string[] IntPtrToUtf8Array(IntPtr array)
-	{
-		IntPtr* ptr = (IntPtr*)array.ToPointer();
-		int size = 0;
-		while(ptr[size] != IntPtr.Zero)
-			++size;
-		string[] OutputStrArray = new string[size];
-		
-#if (NET6_0_OR_GREATER)
-		for(int i = 0; i < size; i++)
-			OutputStrArray[i] = Marshal.PtrToStringUTF8(ptr[i]);
-#else
-		for(int i = 0; i < size; i++)
-				OutputStrArray[i] = UTF8StringFromPointer(ptr[i]);
-#endif
-
-            return OutputStrArray;
-	}
-
-#if (NETSTANDARD2_0_OR_GREATER)
-	public static string UTF8StringFromPointer(IntPtr ptr)
-	{
-		var bytes = new List<byte>(128);
-		var idx = 0;
-		while (true)
-		{
-			var b = Marshal.ReadByte(ptr, idx);
-			if (b == 0)
-			{
-				break;
-			}
-			
-			bytes.Add(b);
-		}
-		
-		return System.Text.Encoding.UTF8.GetString(bytes.ToArray());
-	}
-#endif
-}
-
-}
diff --git a/kissinference.csproj b/kissinference.csproj
deleted file mode 100644
index cfe9bad193903c0c378a465e056ac2ff34413ee3..0000000000000000000000000000000000000000
--- a/kissinference.csproj
+++ /dev/null
@@ -1,13 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-<PropertyGroup>
-	<AssemblyName>kissinference</AssemblyName>
-	<OutputPath>bin\</OutputPath>
-	<OutputType>library</OutputType>
-	<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-	<TargetFrameworks>netstandard2.0;net6;net7;net8</TargetFrameworks>
-	<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
-</PropertyGroup>
-<ItemGroup>
-	<Compile Include="kissinference.cs" />
-</ItemGroup>
-</Project>
diff --git a/kissinference_test.csproj b/kissinference_test.csproj
index 0b18f8a538982e219a3eb894896ee896b7db5082..ec10ed5b93f78fe7dda3be6b70842efe15e46be9 100644
--- a/kissinference_test.csproj
+++ b/kissinference_test.csproj
@@ -9,9 +9,9 @@
 
 	</PropertyGroup>
 	<ItemGroup>
-		<Reference Include="kissinference">
-			<HintPath>bin\$(TargetFramework)\kissinference.dll</HintPath>
+		<Reference Include="kissinferencesharp">
+			<HintPath>bin\$(TargetFramework)\kissinferencesharp.dll</HintPath>
 		</Reference>
-		<Compile Include="program.cs" />
+		<Compile Include="src/test.cs" />
 	</ItemGroup>
 </Project>
diff --git a/kissinferencesharp.csproj b/kissinferencesharp.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..88cf2a4b5a175bd53325af71dbc8077b8ad7cf0d
--- /dev/null
+++ b/kissinferencesharp.csproj
@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+<PropertyGroup>
+	<AssemblyName>kissinferencesharp</AssemblyName>
+	<OutputPath>bin\</OutputPath>
+	<OutputType>library</OutputType>
+	<TargetFrameworks>netstandard2.0;net6;net7;net8</TargetFrameworks>
+	<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
+	<VersionPrefix>1.0.0</VersionPrefix>
+	<Title>KISS Inference</Title>
+	<Authors>Carl Philipp Klemm</Authors>
+	<Company>rhd instruments GmbH and Co. KG</Company>
+	<Description>A .NET interface for model inference from impedance spectra.</Description>
+</PropertyGroup>
+<ItemGroup>
+	<Compile Include="src/capi.cs" />
+	<Compile Include="src/network.cs"/>
+	<Compile Include="src/inferenceexception.cs" />
+	<Compile Include="src/utils.cs" />
+	<Compile Include="src/spectra.cs" />
+	<Compile Include="src/versionfixed.cs" />
+</ItemGroup>
+</Project>
diff --git a/kissinference.sln b/kissinferencesharp.sln
similarity index 92%
rename from kissinference.sln
rename to kissinferencesharp.sln
index cd5c5b3cf4ac3f46d1c510436e765947a61a4c7d..a48e6214a262c17550dd36331f9ccc98ea7015d3 100644
--- a/kissinference.sln
+++ b/kissinferencesharp.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio Version 17
 VisualStudioVersion = 17.9.34728.123
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "kissinference", "kissinference.csproj", "{B5C86025-19DE-4DCC-BE8A-63C85EEBC870}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "kissinferencesharp", "kissinferencesharp.csproj", "{B5C86025-19DE-4DCC-BE8A-63C85EEBC870}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/src/capi.cs b/src/capi.cs
new file mode 100644
index 0000000000000000000000000000000000000000..18871c07d7e68e2cc1da70d1832e61ac972a6ede
--- /dev/null
+++ b/src/capi.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+
+namespace Kiss
+{
+
+/// <summary>
+/// This struct is a raw repisenstion of the C struct used in libkissiniference. Ususally users of these bindings will not need to directly use this.
+/// </summary>
+[StructLayout (LayoutKind.Sequential)]
+public struct CNetwork
+{
+	private IntPtr _private;
+	public UIntPtr inputSize;
+	public UIntPtr outputSize;
+	public IntPtr purpose;
+	public IntPtr inputLabel;
+	public IntPtr outputLabels;
+	public byte complexInput;
+	public byte ready;
+	public byte softmax;
+	private IntPtr _resultCb;
+}
+
+internal class Capi
+{
+	public delegate void resultDlg(IntPtr result, ref CNetwork network, IntPtr data);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "kiss_free", CallingConvention=CallingConvention.StdCall)]
+	public static extern void free(IntPtr ptr);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern IntPtr kiss_create_range(float start, float end, UIntPtr length, byte log);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern void kiss_resample_spectra(float[] in_re, float[] in_im, UIntPtr input_length, ref IntPtr ret_ptr_real, ref IntPtr ret_ptr_imag, UIntPtr output_length);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern void kiss_normalize_spectra(float[] in_re, float[] in_im, UIntPtr input_length);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern IntPtr kiss_absgrad(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length, UIntPtr index);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern float kiss_grad(float[] data, float[] omegas, UIntPtr input_length, UIntPtr index);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern float kiss_median(float[] data, UIntPtr input_length);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern byte kiss_reduce_spectra(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length, float thresh_factor,
+												  byte use_second_deriv, ref IntPtr out_re, ref IntPtr out_im, ref UIntPtr output_length);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+
+	public static extern byte kiss_filter_spectra(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length,
+												  ref IntPtr out_re, ref IntPtr out_im, UIntPtr output_length);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern byte kiss_load_network_prealloc(ref CNetwork net, string path, resultDlg callback, byte verbose);
+
+	[DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern void puts(string path);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern void kiss_free_network_prealloc(ref CNetwork net);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern byte kiss_async_run_inference(ref CNetwork net, [Out] float[] inputs, IntPtr data);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern byte kiss_async_run_inference_complex(ref CNetwork net, [Out] float[] real, [Out] float[] imag, IntPtr data);
+
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern IntPtr kiss_get_strerror(ref CNetwork net);
+
+	public static string[] IntPtrToUtf8Array(IntPtr array)
+	{
+		var pointers = new List<IntPtr>();
+		var size = Marshal.SizeOf<IntPtr>();
+		var idx = 0;
+		while (true)
+		{
+			var ptr = Marshal.ReadIntPtr(array, idx * size);
+			if (ptr == IntPtr.Zero)
+				break;
+			pointers.Add(ptr);
+			idx++;
+		}
+
+		var res = new List<string>();
+		foreach (var p in pointers)
+			res.Add(UTF8StringFromPointer(p));
+
+		return res.ToArray();
+	}
+
+	public static string UTF8StringFromPointer(IntPtr ptr)
+	{
+		var bytes = new List<byte>(128);
+		var idx = 0;
+		while (true)
+		{
+			var b = Marshal.ReadByte(ptr, idx);
+			if (b == 0)
+				break;
+
+			bytes.Add(b);
+		}
+
+		return System.Text.Encoding.UTF8.GetString(bytes.ToArray());
+	}
+}
+
+}
diff --git a/src/inferenceexception.cs b/src/inferenceexception.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dc95710f6acce64d327de85b6486cafdd58a26ef
--- /dev/null
+++ b/src/inferenceexception.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Kiss
+{
+
+/// <summary>
+/// This exception is thrown when an error occures during inference, usually due to running out of memory.
+/// </summary>
+public class InferenceException : Exception
+{
+	public InferenceException(){}
+	public InferenceException(string message): base(message){}
+	public InferenceException(string message, Exception inner): base(message, inner){}
+}
+
+}
diff --git a/src/network.cs b/src/network.cs
new file mode 100644
index 0000000000000000000000000000000000000000..746f8b4846c171b064ed749aa1a32482eb584f1b
--- /dev/null
+++ b/src/network.cs
@@ -0,0 +1,212 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Kiss
+{
+
+/// <summary>
+/// This is the main class of kissinference, it allows you to load and use Kiss neural neturoks
+/// </summary>
+public class Network: System.IDisposable
+{
+	public delegate void ResultDlg(float[] result, Network network);
+
+	private struct Flight
+	{
+		public ResultDlg Callback;
+		public AutoResetEvent Signal;
+	}
+
+	private CNetwork net;
+	private bool disposed = false;
+	private Dictionary<IntPtr, Flight> inflight = new Dictionary<IntPtr, Flight>();
+	private IntPtr flightcounter = (IntPtr)0;
+
+	private void CResultCb(IntPtr result, ref CNetwork network, IntPtr data)
+	{
+		var managedResult = new float[(int)net.outputSize];
+		Marshal.Copy(result, managedResult, 0, (int)net.outputSize);
+		Capi.free(result);
+		var flight = inflight[data];
+		inflight.Remove(data);
+		flight.Callback(managedResult, this);
+		flight.Signal.Set();
+	}
+
+	/// <summary>
+	/// Constructs a new Network object by loading a network off disk
+	/// </summary>
+	/// <param name="path">
+	/// the path to the onnx network file to load
+	/// </param>
+	/// <param name="verbose">
+	/// if true is set here some extra debug information will be printed by the runtime
+	/// </param>
+	/// <exception cref="System.IO.FileLoadException">
+	/// Thrown when the network file could not be loaded
+	/// </exception>
+	public Network(string path, bool verbose = false)
+	{
+		byte ret = Capi.kiss_load_network_prealloc(ref net, path, CResultCb, Convert.ToByte(verbose));
+		Console.WriteLine("ret: {0:D}", ret);
+		if(ret == 0)
+			throw new System.IO.FileLoadException(getError());
+	}
+
+	/// <summary>
+	/// This method runs an inference pass on the given spectra asynchronously
+	/// </summary>
+	/// <param name="spectra">
+	/// the spectra to run inference on, must be of InputSize length
+	/// </param>
+	/// <param name="callback">
+	/// a delegate that will be called when inference completes, this callback will be called from a native thread in libkissiniferences thread pool
+	/// </param>
+	/// <exception cref="ArgumentException">
+	/// Thrown when the input is of an incorrect size for the network
+	/// </exception>
+	/// <exception cref="InferenceException">
+	/// Thrown when the inference engine encounteres an internal error
+	/// </exception>
+	/// <returns>
+	/// The AutoResetEvent returned can be waited on to ensure that the inference is finished and the callback has been executed.
+	/// </returns>
+	public AutoResetEvent Run(Spectra spectra, ResultDlg callback)
+	{
+		if(spectra.Real.Length*2 != (int)net.inputSize)
+			throw new ArgumentException("Spectra is the wrong size for network, use resample() first");
+		var flight = new Flight();
+		flight.Callback = callback;
+		flight.Signal = new AutoResetEvent(false);
+		inflight.Add(flightcounter, flight);
+		byte ret = Capi.kiss_async_run_inference_complex(ref net, spectra.Real, spectra.Imaginary, flightcounter);
+		if(ret == 0)
+			throw new InferenceException(getError());
+
+		flightcounter += 1;
+		return flight.Signal;
+	}
+
+	/// <summary>
+	/// This method runs an inference pass on the given spectra asynchronously
+	/// </summary>
+	/// <param name="data">
+	/// and array of floats containing the data inference on, must be of InputSize length
+	/// </param>
+	/// <param name="callback">
+	/// a delegate that will be called when inference completes, this callback will be called from a native thread in libkissiniferences thread pool
+	/// </param>
+	/// <exception cref="ArgumentException">
+	/// Thrown when the input is of an incorrect size for the network
+	/// </exception>
+	/// <exception cref="InferenceException">
+	/// Thrown when the inference engine encounteres an internal error
+	/// </exception>
+	/// <returns>
+	/// The AutoResetEvent returned can be waited on to ensure that the inference is finished and the callback has been executed.
+	/// </returns>
+	public AutoResetEvent Run(float[] data, ResultDlg callback)
+	{
+		if(data.Length != (int)net.inputSize)
+			throw new ArgumentException("Data is the wrong size for network");
+		var flight = new Flight();
+		flight.Callback = callback;
+		flight.Signal = new AutoResetEvent(false);
+		inflight.Add(flightcounter, flight);
+		byte ret = Capi.kiss_async_run_inference(ref net, data, flightcounter);
+		if(ret == 0)
+			throw new InferenceException(getError());
+		flightcounter += 1;
+		return flight.Signal;
+	}
+
+	/// <summary>
+	/// This method returns an error string for the last error to have occured in the libkissiniference.
+	/// Usually this method is not usefull as all errors reported by this interface are forwared via exceptions,
+	/// It is provided to ease implementations that also call the C api directly.
+	/// </summary>
+	/// <returns>
+	/// A string describeing the last reported error.
+	/// </returns>
+	private string getError()
+	{
+#if (NET6_0_OR_GREATER)
+		return Marshal.PtrToStringUTF8(Capi.kiss_get_strerror(ref net));
+#else
+		return Capi.UTF8StringFromPointer(Capi.kiss_get_strerror(ref net));
+#endif
+	}
+
+	public void Dispose()
+	{
+		Dispose(true);
+		GC.SuppressFinalize(this);
+	}
+
+	protected virtual void Dispose(bool disposing)
+	{
+		if(!disposed)
+		{
+			disposed = true;
+			Capi.kiss_free_network_prealloc(ref net);
+		}
+	}
+
+	~Network()
+	{
+		Dispose(false);
+	}
+
+	/// <summary>
+	/// This Property holds the number of input values the loaded network expects.
+	/// For networks with a convolutional input this may be -1 designateing "Any"
+	/// </summary>
+	public int InputSize
+	{
+		get{return (int)net.inputSize;}
+	}
+
+	/// <summary>
+	/// This Property holds the number of output values the loaded network expects.
+	/// </summary>
+	public int OutputSize
+	{
+		get{return (int)net.outputSize;}
+	}
+
+	/// <summary>
+	/// This Property holds a string describeing the purpose the network was trained on.
+	/// </summary>
+	public string Purpose
+	{
+		get{return Marshal.PtrToStringAnsi(net.purpose);}
+	}
+
+	/// <summary>
+	/// This Property holds a string describeing the type of input the network expects.
+	/// </summary>
+	public string InputLabel
+	{
+		get{return Marshal.PtrToStringAnsi(net.inputLabel);}
+	}
+
+	/// <summary>
+	/// This Property is true if the network expects a complex valued input
+	/// </summary>
+	public bool ComplexInput
+	{
+		get{return Convert.ToBoolean(net.complexInput);}
+	}
+
+	/// <summary>
+	/// This Property is an array of OutputSize with strings nameing what every output corrisponds to
+	/// </summary>
+	public string[] OutputLabels
+	{
+		get{return Capi.IntPtrToUtf8Array(net.outputLabels);}
+	}
+}
+
+}
diff --git a/src/spectra.cs b/src/spectra.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cde143beaecc9bc525ba2bd54629f2ac23a3155c
--- /dev/null
+++ b/src/spectra.cs
@@ -0,0 +1,197 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Kiss
+{
+
+/// <summary>
+/// This Class holds an impedance spectra and provides various transformations that are required to get the values into a form expected by kiss networks
+/// </summary>
+public class Spectra
+{
+	/// <summary>
+	/// The real part of the spectra
+	/// </summary>
+	public float[] Real;
+
+	/// <summary>
+	/// The imaginary part of the spectra
+	/// </summary>
+	public float[] Imaginary;
+
+	/// <summary>
+	/// The frequencys of the datapoints of the spectra
+	/// </summary>
+	public float[] Omega;
+
+	/// <summary>
+	/// This constructor constructs a spectra from a series of arrays
+	/// </summary>
+	/// <param name="Real">
+	/// The real part of the spectra
+	/// </param>
+	/// <param name="Imaginary">
+	/// The imaginary part of the spectra, its length must be the same as <paramref name="Real"/>
+	/// </param>
+	/// <param name="Omega">
+	/// The frequency values in rad/s of eatch datapoint, its lenght must be the same as <paramref name="Real"/>
+	/// </param>
+	public Spectra(float[] Real, float[] Imaginary, float[] Omega)
+	{
+		if(Real.Length != Imaginary.Length || Real.Length != Omega.Length)
+			throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size");
+		this.Real = Real;
+		this.Imaginary = Imaginary;
+		this.Omega = Omega;
+	}
+
+	/// <summary>
+	/// This constructor constructs a spectra from a series of arrays
+	/// </summary>
+	/// <param name="Real">
+	/// The real part of the spectra
+	/// </param>
+	/// <param name="Imaginary">
+	/// The imaginary part of the spectra, its length must be the same as <paramref name="Real"/>
+	/// </param>
+	/// <param name="Omega">
+	/// The frequency values in rad/s of eatch datapoint, its lenght must be the same as <paramref name="Real"/>
+	/// </param>
+	public Spectra(double[] Real, double[] Imaginary, double[] Omega)
+	{
+		if(Real.Length != Imaginary.Length || Real.Length != Omega.Length)
+			throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size");
+		this.Real = DoubleToFloat(Real);
+		this.Imaginary = DoubleToFloat(Imaginary);
+		this.Omega = DoubleToFloat(Omega);
+	}
+
+	/// <summary>
+	/// This method normalizes the data into the range [0, 1]
+	/// </summary>
+	public void Normalize()
+	{
+		Capi.kiss_normalize_spectra(Real, Imaginary, (UIntPtr)Real.Length);
+	}
+
+	/// <summary>
+	/// This method resamples the spectra to the size given in newSize.
+	/// Upsampling is achived via linear interpolation, downsampling is achived via the nearest-neighbor method.
+	/// </summary>
+	/// <param name="newSize">
+	/// The size to resample the spectra to
+	/// </param>
+	public void Resample(int newSize)
+	{
+		var ret_ptr_real = new IntPtr();
+		var ret_ptr_imag = new IntPtr();
+		Capi.kiss_resample_spectra(Real, Imaginary, (UIntPtr)Real.Length, ref ret_ptr_real, ref ret_ptr_imag, (UIntPtr)newSize);
+
+		Real = new float[newSize];
+		Imaginary = new float[newSize];
+		Marshal.Copy(ret_ptr_real, Real, 0, newSize);
+		Marshal.Copy(ret_ptr_imag, Imaginary, 0, newSize);
+
+		Capi.free(ret_ptr_real);
+		Capi.free(ret_ptr_imag);
+	}
+
+	/// <summary>
+	/// Approximate the element wise absolute gradient at the given point of the sepctra in the place given
+	/// </summary>
+	/// <param name="index">
+	/// The index at which to aproxmiate the gradiant
+	/// </param>
+	/// <returns>
+	/// The element wise absolute of the gradiant as a tuple of floats
+	/// </returns>
+	public Tuple<float, float> Absgrad(int index)
+	{
+		var resultArray = new float[2];
+		IntPtr ptr = Capi.kiss_absgrad(Real, Imaginary, Omega, (UIntPtr)Real.Length, (UIntPtr)index);
+		Marshal.Copy(ptr, resultArray, 0, 2);
+		Capi.free(ptr);
+		return new Tuple<float, float>(resultArray[0], resultArray[1]);
+	}
+
+	/// <summary>
+	/// Applies the same series of filteres used by kiss networks (applied by TorchKissAnn) during training.
+	///
+	/// In almost all cases this function should be called before a sepctra is given to a kiss network.
+	/// </summary>
+	/// <param name="outputSize">
+	/// the length the spectra should have after filtering
+	/// </param>
+	/// <returns>
+	/// True if sucessfull, false otherwise
+	/// </returns>
+	public bool Filter(int outputSize)
+	{
+		var ret_ptr_real = new IntPtr();
+		var ret_ptr_imag = new IntPtr();
+		byte ret = Capi.kiss_filter_spectra(Real, Imaginary, Omega, (UIntPtr)Real.Length, ref ret_ptr_real, ref ret_ptr_imag, (UIntPtr)outputSize);
+
+		if(ret == 1)
+		{
+			Real = new float[(int)outputSize];
+			Imaginary = new float[(int)outputSize];
+			Marshal.Copy(ret_ptr_real, Real, 0, (int)outputSize);
+			Marshal.Copy(ret_ptr_imag, Imaginary, 0, (int)outputSize);
+			Capi.free(ret_ptr_real);
+			Capi.free(ret_ptr_imag);
+		}
+
+		return Convert.ToBoolean(ret);
+	}
+
+	/// <summary>
+	/// Applies the same series of filteres used by kiss networks (applied by TorchKissAnn) during training.
+	///
+	/// In almost all cases this function should be called before a sepctra is given to a kiss network.
+	/// </summary>
+	/// <param name="outputSize">
+	/// the length the spectra should have after filtering
+	/// </param>
+	/// <returns>
+	/// True if sucessfull, false otherwise
+	/// </returns>
+	public bool Reduce(float threshFactor, bool useSecondDeriv)
+	{
+		var ret_ptr_real = new IntPtr();
+		var ret_ptr_imag = new IntPtr();
+		var lengthPtr = new UIntPtr();
+		byte ret = Capi.kiss_reduce_spectra(Real, Imaginary, Omega, (UIntPtr)Real.Length, threshFactor, Convert.ToByte(useSecondDeriv), ref ret_ptr_real, ref ret_ptr_imag, ref lengthPtr);
+
+		if(ret == 1)
+		{
+			Real = new float[(int)lengthPtr];
+			Imaginary = new float[(int)lengthPtr];
+			Marshal.Copy(ret_ptr_real, Real, 0, (int)lengthPtr);
+			Marshal.Copy(ret_ptr_imag, Imaginary, 0, (int)lengthPtr);
+			Capi.free(ret_ptr_real);
+			Capi.free(ret_ptr_imag);
+		}
+
+		return Convert.ToBoolean(ret);
+	}
+
+	/// <summary>
+	/// Converts an array of doubles to an array of floats.
+	/// </summary>
+	/// <param name="input">
+	/// The input array.
+	/// </param>
+	/// <returns>
+	/// An array with the same values as the input truncated to floats.
+	/// </returns>
+	private static float[] DoubleToFloat(double[] input)
+	{
+		var res = new float[input.Length];
+		for(int i = 0; i < input.Length; ++i)
+			res[i] = (float)input[i];
+		return res;
+	}
+
+}
+
+}
diff --git a/program.cs b/src/test.cs
similarity index 100%
rename from program.cs
rename to src/test.cs
diff --git a/src/utils.cs b/src/utils.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f37931346fbbdda8d7f66e915689c9bba1505615
--- /dev/null
+++ b/src/utils.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Kiss
+{
+
+/// <summary>
+/// This class is a collection of static methods usefull for use with kissinference.
+/// </summary>
+public class Utils
+{
+	/// <summary>
+	/// Converts an array containing a linear or log range.
+	/// </summary>
+	/// <param name="start">
+	/// The startig value of the range.
+	/// </param>
+	/// <param name="end">
+	/// The ending value of the range.
+	/// </param>
+	/// <param name="size">
+	/// The number of elements in the range.
+	/// </param>
+	/// <param name="log">
+	/// If this is set to true the elements in the range are spaced in log10 fashion, otherwise linear spaceing is used.
+	/// </param>
+	/// <returns>
+	/// An array containing the requested range
+	/// </returns>
+	public static float[] CreateRange(float start, float end, int size, bool log)
+	{
+		IntPtr ptr = Capi.kiss_create_range(start, end, (UIntPtr)size, Convert.ToByte(log));
+		var ret = new float[size];
+		Marshal.Copy(ptr, ret, 0, size);
+		Capi.free(ptr);
+		return ret;
+	}
+
+	/// <summary>
+	/// Approximates the the derivative of an array at the given index.
+	/// </summary>
+	/// <param name="data">
+	/// The array, or y values, to approximate the derivative on
+	/// </param>
+	/// <param name="omegas">
+	/// The omega, or x values to approximate the derivative on
+	/// </param>
+	/// <param name="index">
+	/// The index at which to aproxmiate the gradiant at.
+	/// </param>
+	/// <returns>
+	/// The aproxmiate derivative.
+	/// </returns>
+	public static float Grad(float[] data, float[] omegas, int index)
+	{
+		if(data.Length != omegas.Length)
+			throw new ArgumentException("the data and omegas must be the same length");
+		return Capi.kiss_grad(data, omegas, (UIntPtr)data.Length, (UIntPtr)index);
+	}
+
+	/// <summary>
+	/// Calculates the median of the values given
+	/// </summary>
+	/// <param name="input">
+	/// The input array.
+	/// </param>
+	/// <returns>
+	/// The median value
+	/// </returns>
+	public static float Median(float[] data)
+	{
+		return Capi.kiss_median(data, (UIntPtr)data.Length);
+	}
+}
+
+}
diff --git a/src/versionfixed.cs b/src/versionfixed.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f2c175dac9fb8f97ca046318be9e165026ae0c45
--- /dev/null
+++ b/src/versionfixed.cs
@@ -0,0 +1,23 @@
+using System.Runtime.InteropServices;
+
+namespace Kiss
+{
+
+/// <summary>
+/// Struct <c>VersionFixed</c> reprisents the version of kissinference
+/// </summary>
+[StructLayout (LayoutKind.Sequential)]
+public struct VersionFixed
+{
+	public int Major;
+	public int Minor;
+	public int Patch;
+
+	/// <summary>
+	/// This Method returns the version of the currently loaded kissinference instance.
+	/// </summary>
+	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "kiss_get_version", CallingConvention=CallingConvention.StdCall)]
+	public static extern VersionFixed GetVersion();
+}
+
+}