diff options
43 files changed, 4559 insertions, 0 deletions
@@ -0,0 +1,4 @@ +Author: + +Dave Robillard <mailto:drobilla@connect.carleton.ca> + @@ -0,0 +1 @@ +/usr/share/automake-1.9/COPYING
\ No newline at end of file diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ChangeLog diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..aefe7ee --- /dev/null +++ b/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = include src slv2 examples doc + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libslv2.pc + @@ -0,0 +1,4 @@ +You should not be reading this. + +Tell no one! + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..a9a6c1b --- /dev/null +++ b/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +echo 'Generating necessary files...' +libtoolize --copy --force +aclocal +autoheader -Wall +automake --gnu --add-missing -Wall +autoconf + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..50973e5 --- /dev/null +++ b/configure.ac @@ -0,0 +1,100 @@ +AC_PREREQ(2.59) +AC_INIT([libslv2],[0.0.1],[drobilla@connect.carleton.ca]) +AC_CONFIG_SRCDIR([src/plugin.c]) +AC_CONFIG_SRCDIR([slv2/plugin.h]) +AC_CONFIG_SRCDIR([include/lv2.h]) +AC_CONFIG_SRCDIR([examples/plugins/Amp-swh.lv2/amp.c]) +AC_CONFIG_SRCDIR([examples/hosts/test_host.c]) +AC_CONFIG_HEADER([config.h]) +AM_INIT_AUTOMAKE + +# Checks for compiler +AC_PROG_CC + +# Check pedantic other stuff autoscan says we should :) +AC_C_CONST +AC_C_INLINE +AC_HEADER_STDBOOL +AC_TYPE_SIZE_T + +# Library building stuff +AC_PROG_LIBTOOL + +# Check for debugging flag +debug="no" +AC_ARG_ENABLE(debug, + [AS_HELP_STRING(--enable-debug, [Enable debugging (false)])], + [debug="$enableval"]) +if test "$debug" = "yes"; then + CFLAGS="-O0 -g -DDEBUG" + CXXFLAGS="$CFLAGS" +else + CFLAGS="$CFLAGS -DNDEBUG" + CXXFLAGS="$CXXFLAGS -DNDEBUG" +fi + +# Check for strict flag +strict="no" +AC_ARG_ENABLE(strict, + [AS_HELP_STRING(--enable-strict, [Enable strict compiler warnings and errors (false)])], + [strict="$enableval"]) +if test "$strict" = "yes"; then + CFLAGS="$CFLAGS -std=c99 -pedantic -Wall -Wconversion -Winit-self" + CXXFLAGS="$CXXFLAGS -ansi -pedantic -Wall -Wconversion -Winit-self -Woverloaded-virtual -Wsign-promo" +fi + +# Bolt on a few specific flags to CXXFLAGS that should always be used +#CXXFLAGS="$CXXFLAGS -pipe -Wall -fmessage-length=139 -fdiagnostics-show-location=every-line" +#CFLAGS="$CFLAGS -pipe -Wall -fmessage-length=139 -fdiagnostics-show-location=every-line" + +# Check plugin install directory +AC_MSG_CHECKING([where to install LV2 plugins]) +AC_ARG_WITH(lv2-dir, + AS_HELP_STRING([--with-lv2-dir=DIR], + [directory that LV2 plugins should be installed in ($libdir/lv2)]), + [lv2dir=$withval], [lv2dir=$libdir/lv2]) +AC_MSG_RESULT($lv2dir) +AC_SUBST(lv2dir) + +# Check for RASQAL +PKG_CHECK_MODULES(RASQAL, rasqal >= 0.20, build_rasqal="yes", build_rasqal="no") +AC_SUBST(JACK_CFLAGS) +AC_SUBST(JACK_LIBS) + +# Check for JACK +build_jack="yes" +AC_ARG_ENABLE(jack, + [AS_HELP_STRING(--with-jack, [Build JACK clients (true)])], + [ if test x$with_jack = xno ; then build_jack=no ; fi ]) +if test "$build_jack" = "yes"; then + PKG_CHECK_MODULES(JACK, jack >= 0.99.0, build_jack="yes", build_jack="no") +fi +if test "$build_jack" = "yes"; then + AC_DEFINE(HAVE_JACK, 1, [Has JACK]) + AC_SUBST(JACK_CFLAGS) + AC_SUBST(JACK_LIBS) +else + AC_MSG_WARN([JACK not found, JACK clients will not be built.]) +fi +AM_CONDITIONAL(WITH_JACK, [test "$build_jack" = "yes"]) + + +# Write output files +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([src/Makefile]) +AC_CONFIG_FILES([slv2/Makefile]) +AC_CONFIG_FILES([include/Makefile]) +AC_CONFIG_FILES([examples/Makefile]) +AC_CONFIG_FILES([examples/plugins/Makefile]) +AC_CONFIG_FILES([examples/hosts/Makefile]) +AC_CONFIG_FILES([libslv2.pc]) +AC_CONFIG_FILES([doc/Makefile]) +AC_CONFIG_FILES([doc/reference.doxygen]) +AC_OUTPUT + + +# Display summary message +AC_MSG_RESULT([]) +AC_MSG_RESULT([Building JACK client: $build_jack]) +AC_MSG_RESULT([]) + diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..78fc0af --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,2 @@ +doc: $(top_srcdir)/doc/reference.doxygen $(top_srcdir)/include/lv2.h $(top_srcdir)/slv2/*.h + doxygen $(top_srcdir)/doc/reference.doxygen diff --git a/doc/mainpage.dox b/doc/mainpage.dox new file mode 100644 index 0000000..545a92e --- /dev/null +++ b/doc/mainpage.dox @@ -0,0 +1,10 @@ +/** @mainpage + +@section Overview + +LibSLV2 is a host library to simply the use of LV2 plugins. + +It will have a lovely wordey description here once I get around to it. +For now click on the "Modules" tab above to get at the beef. + +*/ diff --git a/doc/reference.doxygen.in b/doc/reference.doxygen.in new file mode 100644 index 0000000..f4e83c6 --- /dev/null +++ b/doc/reference.doxygen.in @@ -0,0 +1,1163 @@ +# @configure_input@ + +# Doxyfile 1.3.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "LibSLV2" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @PACKAGE_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @top_srcdir@/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 option can be useful when feeding doxygen a huge amount of source +# files, where putting all generated files in the same directory would otherwise +# cause performance problems for the file system. + +CREATE_SUBDIRS = 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. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is used +# as the annotated text. Otherwise, the brief description is used as-is. If left +# blank, the following values are used ("$name" is automatically replaced with the +# name of the entity): "The $name class" "The $name widget" "The $name file" +# "is" "provides" "specifies" "contains" "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# 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 (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = YES + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = YES + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = NO + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# 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 stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @top_srcdir@/doc/mainpage.dox \ + @top_srcdir@/slv2/types.h \ + @top_srcdir@/slv2/pluginlist.h \ + @top_srcdir@/slv2/plugin.h \ + @top_srcdir@/slv2/port.h \ + @top_srcdir@/slv2/plugininstance.h #\ + #@top_srcdir@/slv2/query.h #\ + #@top_srcdir@/include + + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = @top_srcdir@/examples/hosts + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = *.c + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# 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 one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# 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. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +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. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +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 listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superseded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# 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. + +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, 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) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = NO + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are 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. + +COLLABORATION_GRAPH = NO + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# 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. + +INCLUDE_GRAPH = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = NO + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = NO + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes that +# lay further from the root node will be omitted. Note that setting this option to +# 1 or 2 may greatly reduce the computation time needed for large code bases. Also +# note that a graph may be further truncated if the graph's image dimensions are +# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). +# If 0 is used for the depth value (the default), the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = NO + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..94939c3 --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = plugins hosts + diff --git a/examples/hosts/.jack_host.c.swp b/examples/hosts/.jack_host.c.swp Binary files differnew file mode 100644 index 0000000..eb9bb86 --- /dev/null +++ b/examples/hosts/.jack_host.c.swp diff --git a/examples/hosts/Makefile.am b/examples/hosts/Makefile.am new file mode 100644 index 0000000..340c962 --- /dev/null +++ b/examples/hosts/Makefile.am @@ -0,0 +1,24 @@ +AM_CFLAGS = -std=c99 -I. -I$(top_srcdir)/include -I$(top_srcdir) `pkg-config --cflags rasqal` +AM_LDFLAGS = `pkg-config --libs rasqal` + +bin_PROGRAMS = test_host jack_host + +test_host_DEPENDENCIES = ../../src/libslv2.la +test_host_LDADD = ../../src/libslv2.la + +test_host_SOURCES = \ + test_host.c + + +if WITH_JACK + +jack_host_CFLAGS = @JACK_CFLAGS@ $(AM_CFLAGS) +#jack_host_LIBS = @JACK_LIBS@ + +jack_host_DEPENDENCIES = ../../src/libslv2.la +jack_host_LDADD = ../../src/libslv2.la @JACK_LIBS@ + +jack_host_SOURCES = \ + jack_host.c + +endif # WITH_JACK diff --git a/examples/hosts/jack_host.c b/examples/hosts/jack_host.c new file mode 100644 index 0000000..2247e03 --- /dev/null +++ b/examples/hosts/jack_host.c @@ -0,0 +1,218 @@ +/* LibSLV2 Jack Example Host + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <slv2/slv2.h> +#include <jack/jack.h> + + +/** This program's data */ +struct JackHost { + jack_client_t* jack_client; /**< Jack client */ + SLV2Plugin* plugin; /**< Plugin "class" (actually just a few strings) */ + SLV2Instance* instance; /**< Plugin "instance" (loaded shared lib) */ + unsigned long num_ports; /**< Size of the two following arrays: */ + jack_port_t** jack_ports; /**< For audio ports, otherwise NULL */ + float* controls; /**< For control ports, otherwise 0.0f */ +}; + + +void die(const char* msg); +void create_port(struct JackHost* host, unsigned long port_index); +int jack_process_cb(jack_nframes_t nframes, void* data); +void list_plugins(SLV2List list); + + +int +main(int argc, char** argv) +{ + struct JackHost host; + host.jack_client = NULL; + host.num_ports = 0; + host.jack_ports = NULL; + host.controls = NULL; + + /* Find all installed plugins */ + SLV2List plugins = slv2_list_new(); + slv2_list_load_all(plugins); + //slv2_list_load_bundle(plugins, "http://www.scs.carleton.ca/~drobilla/files/Amp-swh.lv2"); + + /* Find the plugin to run */ + const char* plugin_uri = (argc == 2) ? argv[1] : NULL; + + if (!plugin_uri) { + fprintf(stderr, "\nYou must specify a plugin URI to load.\n"); + fprintf(stderr, "\nKnown plugins:\n\n"); + list_plugins(plugins); + return EXIT_FAILURE; + } + + printf("URI:\t%s\n", plugin_uri); + host.plugin = slv2_list_get_plugin_by_uri(plugins, plugin_uri); + + if (!host.plugin) { + fprintf(stderr, "Failed to find plugin %s.\n", plugin_uri); + slv2_list_free(plugins); + return EXIT_FAILURE; + } + + /* Get the plugin's name */ + char* name = slv2_plugin_get_name(host.plugin); + printf("Name:\t%s\n", name); + + /* Connect to JACK (with plugin name as client name) */ + host.jack_client = jack_client_open(name, JackNullOption, NULL); + free(name); + if (!host.jack_client) + die("Failed to connect to JACK."); + else + printf("Connected to JACK.\n"); + + /* Instantiate the plugin */ + host.instance = slv2_plugin_instantiate( + host.plugin, jack_get_sample_rate(host.jack_client), NULL); + if (!host.instance) + die("Failed to instantiate plugin.\n"); + else + printf("Succesfully instantiated plugin.\n"); + + jack_set_process_callback(host.jack_client, &jack_process_cb, (void*)(&host)); + + /* Create ports */ + host.num_ports = slv2_plugin_get_num_ports(host.plugin); + host.jack_ports = calloc(host.num_ports, sizeof(jack_port_t*)); + host.controls = calloc(host.num_ports, sizeof(float*)); + + for (unsigned long i=0; i < host.num_ports; ++i) + create_port(&host, i); + + /* Activate plugin and JACK */ + slv2_instance_activate(host.instance); + jack_activate(host.jack_client); + + /* Run */ + printf("Press enter to quit: "); + getc(stdin); + printf("\n"); + + /* Deactivate plugin and JACK */ + slv2_instance_free(host.instance); + slv2_list_free(plugins); + + printf("Shutting down JACK.\n"); + for (unsigned long i=0; i < host.num_ports; ++i) { + if (host.jack_ports[i] != NULL) { + jack_port_unregister(host.jack_client, host.jack_ports[i]); + host.jack_ports[i] = NULL; + } + } + jack_client_close(host.jack_client); + + return 0; +} + + +/** Abort and exit on error */ +void +die(const char* msg) +{ + fprintf(stderr, "%s\n", msg); + exit(EXIT_FAILURE); +} + + +/** Creates a port and connects the plugin instance to it's data location. + * + * For audio ports, creates a jack port and connects plugin port to buffer. + * + * For control ports, sets controls array to default value and connects plugin + * port to that element. + */ +void +create_port(struct JackHost* host, + unsigned long port_index) +{ + /* Make sure this is a float port */ + enum SLV2DataType type = slv2_port_get_data_type(host->plugin, port_index); + if (type != SLV2_DATA_TYPE_FLOAT) + die("Unrecognized data type, aborting."); + + /* Get the port symbol (label) for console printing */ + char* symbol = slv2_port_get_symbol(host->plugin, port_index); + + /* Initialize the port array elements */ + host->jack_ports[port_index] = NULL; + host->controls[port_index] = 0.0f; + + /* Get the 'class' of the port (control input, audio output, etc) */ + enum SLV2PortClass class = slv2_port_get_class(host->plugin, port_index); + + /* Connect the port based on it's 'class' */ + switch (class) { + case SLV2_CONTROL_RATE_INPUT: + host->controls[port_index] = slv2_port_get_default_value(host->plugin, port_index); + slv2_instance_connect_port(host->instance, port_index, &host->controls[port_index]); + printf("Set %s to %f\n", symbol, host->controls[port_index]); + break; + case SLV2_CONTROL_RATE_OUTPUT: + slv2_instance_connect_port(host->instance, port_index, &host->controls[port_index]); + break; + case SLV2_AUDIO_RATE_INPUT: + host->jack_ports[port_index] = jack_port_register(host->jack_client, + symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + break; + case SLV2_AUDIO_RATE_OUTPUT: + host->jack_ports[port_index] = jack_port_register(host->jack_client, + symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + break; + default: + die("ERROR: Unknown port type, aborting messily!"); + } + + free(symbol); +} + + +/** Jack process callback. */ +int +jack_process_cb(jack_nframes_t nframes, void* data) +{ + struct JackHost* host = (struct JackHost*)data; + + /* Connect plugin ports directly to JACK buffers */ + for (unsigned long i=0; i < host->num_ports; ++i) + if (host->jack_ports[i] != NULL) + slv2_instance_connect_port(host->instance, i, + jack_port_get_buffer(host->jack_ports[i], nframes)); + + /* Run plugin for this cycle */ + slv2_instance_run(host->instance, nframes); + + return 0; +} + + +void +list_plugins(SLV2List list) +{ + for (int i=0; i < slv2_list_get_length(list); ++i) { + const SLV2Plugin* const p = slv2_list_get_plugin_by_index(list, i); + printf("%s\n", slv2_plugin_get_uri(p)); + } +} diff --git a/examples/hosts/test_host.c b/examples/hosts/test_host.c new file mode 100644 index 0000000..3ec8d86 --- /dev/null +++ b/examples/hosts/test_host.c @@ -0,0 +1,231 @@ +/* LibSLV2 Test Host + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _XOPEN_SOURCE 500 + +#include <rasqal.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#include <slv2/types.h> +#include <slv2/plugin.h> +#include <slv2/plugininstance.h> +#include <slv2/pluginlist.h> +#include <slv2/port.h> + + +void +create_control_input() +{ + printf("Control Input\n"); +} + + +void +create_control_output() +{ + printf("Control Output\n"); +} + + +void +create_audio_input() +{ + printf("Audio Input\n"); +} + + +void +create_audio_output() +{ + printf("Audio Output\n"); +} + + +void +create_port(SLV2Plugin* plugin, + SLV2Instance* instance, + unsigned long port_index) +{ + enum SLV2PortClass class = slv2_port_get_class(plugin, port_index); + + switch (class) { + case SLV2_CONTROL_RATE_INPUT: + create_control_input(port_index); + break; + case SLV2_CONTROL_RATE_OUTPUT: + create_control_output(port_index); + break; + case SLV2_AUDIO_RATE_INPUT: + + create_audio_input(port_index); + break; + case SLV2_AUDIO_RATE_OUTPUT: + create_audio_output(port_index); + break; + default: + printf("Unknown port type, ignored.\n"); + } + //printf("Port %ld class: %d\n", i, slv2_port_get_class(p, i)); +} + + +int +main() +{ + //const char* path = "foo"; + + const char* path = "/home/dave/code/libslv2/examples/plugins"; + + SLV2List plugins = slv2_list_new(); + slv2_list_load_path(plugins, path); + + const char* plugin_uri = "http://plugin.org.uk/swh-plugins/amp"; + printf("URI:\t%s\n", plugin_uri); + + const SLV2Plugin* p = slv2_list_get_plugin_by_uri(plugins, plugin_uri); + if (p) { + /* Get the plugin's name */ + unsigned char* name = slv2_plugin_get_name(p); + printf("Name:\t%s\n", name); + free(name); + + unsigned long num_ports = slv2_plugin_get_num_ports(p); + //printf("Number of ports: %ld\n", num_ports); + + for (unsigned long i=0; i < num_ports; ++i) { + enum SLV2PortClass class = slv2_port_get_class(p, i); + + switch (class) { + case SLV2_CONTROL_RATE_INPUT: + create_control_input(i); + break; + case SLV2_CONTROL_RATE_OUTPUT: + create_control_output(i); + break; + case SLV2_AUDIO_RATE_INPUT: + create_audio_input(i); + break; + case SLV2_AUDIO_RATE_OUTPUT: + create_audio_output(i); + break; + default: + printf("Unknown port type, ignored.\n"); + } + //printf("Port %ld class: %d\n", i, slv2_port_get_class(p, i)); + + + } + + SLV2Property prop; + for (unsigned long i=0; i < num_ports; ++i) { + const char* property = "a"; + prop = slv2_port_get_property(p, i, property); + if (prop) + printf("Port %ld %s = %s\n", i, property, prop->values[0]); + else + printf("No port %ld %s.\n", i, property); + free(prop); + } + printf("\n"); + + SLV2Instance* i = slv2_plugin_instantiate(p, 48000, NULL); + if (i) { + printf("Succesfully instantiated plugin.\n"); + + float gain = 2.0f; + float input = 0.25f; + float output = 0.0f; + slv2_instance_connect_port(i, 0, &gain); + slv2_instance_connect_port(i, 1, &input); + slv2_instance_connect_port(i, 2, &output); + + slv2_instance_activate(i); + slv2_instance_run(i, 1); + slv2_instance_deactivate(i); + + printf("Gain: %f, Input: %f => Output: %f\n", gain, input, output); + slv2_instance_free(i); + } + } + + slv2_list_free(plugins); + +#if 0 + /* Display all plugins found in path */ + if (plugins) + printf("Plugins found: %ld\n", slv2_list_get_size(plugins)); + else + printf("No plugins found in %s\n", path); + + for (unsigned long i=0; 1; ++i) { + const SLV2Plugin* p = + slv2_list_get_plugin_by_index(plugins, i); + + if (!p) + break; + else + printf("\t%s\n", slv2_plugin_get_uri(p)); + } +#endif + +#if 0 + const uchar* bundle_url = (const uchar*)"file:/home/dave/code/ladspa2/ladspa2_sdk/examples/plugins/Amp-swh.ladspa2/"; + LV2Bundle* b = slv2_bundle_load(bundle_url); + + if (b != NULL) { + printf("Loaded bundle %s\n", slv2_bundle_get_url(b)); + + for (unsigned long i=0; i < slv2_bundle_get_num_plugins(b); ++i) { + const SLV2Plugin* p = slv2_bundle_get_plugin_by_index(b, i); + //printf("Plugin: %s\n", p->plugin_uri); + //printf("Lib: %s\n", p->lib_url); + //printf("Data: %s\n", p->data_url); + + printf("\n"); + const uchar* property = (uchar*)"doap:name"; + printf("%s\t%s\n", slv2_plugin_get_uri(p), property); + struct SLV2Property* result = slv2_plugin_get_property(p, property); + + if (result) { + for (int i=0; i < result->num_values; ++i) + printf("\t%s\n", result->values[i]); + } else { + printf("No results.\n"); + } + printf("\n"); + + /* Instantiate plugin */ + SLV2PluginInstance* instance = slv2_plugin_instantiate( + p, 48000, NULL); + if (instance != NULL) { + printf("Successfully instantiated %s\n", slv2_plugin_get_uri(p)); + slv2_plugin_instance_free(instance); + } + + } + + } else { + printf("Failed to load bundle %s\n", bundle_url); + } +#endif + + return 0; +} + diff --git a/examples/plugins/Amp-swh.lv2/Makefile b/examples/plugins/Amp-swh.lv2/Makefile new file mode 100644 index 0000000..4fb858a --- /dev/null +++ b/examples/plugins/Amp-swh.lv2/Makefile @@ -0,0 +1,10 @@ +CFLAGS = -Wall -I../../../include + +all: amp.so + +amp.so: amp.o + $(LD) amp.o -o amp.so -shared + rm amp.o + +clean: + rm *.o amp.so diff --git a/examples/plugins/Amp-swh.lv2/amp.c b/examples/plugins/Amp-swh.lv2/amp.c new file mode 100644 index 0000000..a30c4bd --- /dev/null +++ b/examples/plugins/Amp-swh.lv2/amp.c @@ -0,0 +1,96 @@ +#include <stdlib.h> +#include <string.h> + +#include <math.h> + +#include "lv2.h" + +#ifdef WIN32 +#define SYMBOL_EXPORT __declspec(dllexport) +#else +#define SYMBOL_EXPORT +#endif + +#define AMP_URI "http://plugin.org.uk/swh-plugins/amp"; +#define AMP_GAIN 0 +#define AMP_INPUT 1 +#define AMP_OUTPUT 2 + +static LV2_Descriptor *ampDescriptor = NULL; + +typedef struct { + float *gain; + float *input; + float *output; +} Amp; + +static void cleanupAmp(LV2_Handle instance) { + free(instance); +} + +static void connectPortAmp(LV2_Handle instance, unsigned long port, + void *data) { + Amp *plugin = (Amp *)instance; + + switch (port) { + case AMP_GAIN: + plugin->gain = data; + break; + case AMP_INPUT: + plugin->input = data; + break; + case AMP_OUTPUT: + plugin->output = data; + break; + } +} + +static LV2_Handle instantiateAmp(const LV2_Descriptor *descriptor, + unsigned long s_rate, const char *path , const LV2_Host_Feature **features) { + Amp *plugin_data = (Amp *)malloc(sizeof(Amp)); + + return (LV2_Handle)plugin_data; +} + +#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f) + +static void runAmp(LV2_Handle instance, unsigned long sample_count) { + Amp *plugin_data = (Amp *)instance; + + const float gain = *(plugin_data->gain); + const float * const input = plugin_data->input; + float * const output = plugin_data->output; + + unsigned long pos; + float coef = DB_CO(gain); + + for (pos = 0; pos < sample_count; pos++) { + output[pos] = input[pos] * coef; + } +} + +static void init() { + ampDescriptor = + (LV2_Descriptor *)malloc(sizeof(LV2_Descriptor)); + + ampDescriptor->URI = AMP_URI; + ampDescriptor->activate = NULL; + ampDescriptor->cleanup = cleanupAmp; + ampDescriptor->connect_port = connectPortAmp; + ampDescriptor->deactivate = NULL; + ampDescriptor->instantiate = instantiateAmp; + ampDescriptor->run = runAmp; +} + +SYMBOL_EXPORT +const LV2_Descriptor *lv2_descriptor(unsigned long index) { + if (!ampDescriptor) init(); + + switch (index) { + case 0: + return ampDescriptor; + default: + return NULL; + } +} + diff --git a/examples/plugins/Amp-swh.lv2/amp.so b/examples/plugins/Amp-swh.lv2/amp.so Binary files differnew file mode 100755 index 0000000..281b709 --- /dev/null +++ b/examples/plugins/Amp-swh.lv2/amp.so diff --git a/examples/plugins/Amp-swh.lv2/amp.ttl b/examples/plugins/Amp-swh.lv2/amp.ttl new file mode 100644 index 0000000..d44c0b9 --- /dev/null +++ b/examples/plugins/Amp-swh.lv2/amp.ttl @@ -0,0 +1,68 @@ +@prefix lv2: <http://lv2plug.in/ontology#> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . +@prefix doap: <http://usefulinc.com/ns/doap#> . + +<http://plugin.org.uk/swh-plugins/amp> a lv2:Plugin ; + a lv2:AmplifierPlugin ; + doap:maintainer [ + foaf:name "Steve Harris"; + foaf:homepage <http://plugin.org.uk/> ; + foaf:mbox <mailto:steve@plugin.org.uk> ; + ] ; + doap:name "Simple amplifier" ; + doap:name "简单放大器"@ch ; + doap:name "Einfacher Verstärker"@de ; + doap:name "Simple amp"@en-gb ; + doap:name "Amplificador simple"@es ; + doap:name "Amplificateur de base"@fr ; + doap:name "Amplificatore semplice"@it ; + doap:name "簡単なアンプ"@jp ; + doap:name "Просто усилитель"@ru ; + doap:licence <http://usefulinc.com/doap/licenses/gpl> ; + lv2:property lv2:hardRtCapable ; + + lv2:port [ + a lv2:InputControlRatePort ; + lv2:datatype lv2:float ; + lv2:index 0 ; + lv2:symbol "gain" ; + lv2:name "gain" ; + lv2:name "收益"@ch ; + lv2:name "gewinn"@de ; + lv2:name "gain"@en-gb ; + lv2:name "aumento"@es ; + lv2:name "gain"@fr ; + lv2:name "guadagno"@it ; + lv2:name "利益"@jp ; + lv2:name "увеличение"@ru ; + lv2:default 0.0 ; + lv2:minimum -90.0 ; + lv2:maximum 24.0 ; + lv2:scalePoint [ + lv2:label "+5" ; + lv2:value 5.0 ; + ] , [ + lv2:label "0" ; + lv2:value 0.0 ; + ] , [ + lv2:label "-5" ; + lv2:value -5.0 ; + ] , [ + lv2:label "-10" ; + lv2:value -10.0 ; + ] + ] , [ + a lv2:InputAudioRatePort ; + lv2:datatype lv2:float ; + lv2:index 1 ; + lv2:symbol "in" ; + lv2:name "in" ; + ] , [ + a lv2:OutputAudioRatePort ; + lv2:datatype lv2:float ; + lv2:index 2 ; + lv2:symbol "out" ; + lv2:name "out" ; + ] +. + diff --git a/examples/plugins/Amp-swh.lv2/manifest.ttl b/examples/plugins/Amp-swh.lv2/manifest.ttl new file mode 100644 index 0000000..a26f506 --- /dev/null +++ b/examples/plugins/Amp-swh.lv2/manifest.ttl @@ -0,0 +1,9 @@ +# LV2 Plugin Manifest +# Lists where plugins' data files and shared objects reside. + +@prefix lv2: <http://lv2plug.in/ontology#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . + +<http://plugin.org.uk/swh-plugins/amp> lv2:binary <amp.so> ; + rdfs:seeAlso <amp.ttl> . + diff --git a/examples/plugins/Makefile.am b/examples/plugins/Makefile.am new file mode 100644 index 0000000..8044bc9 --- /dev/null +++ b/examples/plugins/Makefile.am @@ -0,0 +1,24 @@ +#AM_CFLAGS = -I$(top_srcdir)/include +#AM_LDFLAGS = -module -avoidversion -Wc,-nostartfiles +# +#plugindir = @umpdir@ +# +#plugin_LTLIBRARIES = \ +# test_plugin.la +# +## Stolen from swh-plugins, makes stupid libtool versions go away +#install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) +# mkdir -p @umpdir@ +# list='$(plugin_LTLIBRARIES)'; \ +# for file in $$list; do \ +# sofile=`basename $$file .la`.so; \ +# $(INSTALL_PROGRAM) .libs/$$sofile @umpdir@; \ +# done +# +#uninstall-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) +# list='$(plugin_LTLIBRARIES)'; \ +# for file in $$list; do \ +# sofile=`basename $$file .la`.so; \ +# rm -f @umpdir@/$$sofile; \ +# done +# diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..a8d9fe0 --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,3 @@ +lv2includedir = $(includedir) + +lv2include_HEADERS = lv2.h diff --git a/include/lv2.h b/include/lv2.h new file mode 100644 index 0000000..7c3cec7 --- /dev/null +++ b/include/lv2.h @@ -0,0 +1,305 @@ +/* LV2 - LADSPA (Linux Audio Developer's Simple Plugin API) Version 2.0 + * *** PROVISIONAL *** + * + * Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, Stefan + * Westerfeld + * Copyright (C) 2006 Steve Harris, Dave Robillard. + * + * This header 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. + * + * This header 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA. + */ + +#ifndef LV2_INCLUDED +#define LV2_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ************************************************************************* */ + +/* Overview: + * + * There are a large number of open source and free software synthesis + * packages in use or development at this time. This API ('LV2') + * attempts to give programmers the ability to write simple 'plugin' + * audio processors in C/C++ and link them dynamically ('plug') into + * a range of these packages ('hosts'). It should be possible for any + * host and any plugin to communicate completely through this interface. + * + * This API is deliberately as short and simple as possible. + * The information required to use a plugin is in a companion data + * (RDF) file. The shared library portion of the API (defined in this + * header) does not contain enough information to make use of the plugin + * possible - the data file is mandatory. + * + * Plugins are expected to distinguish between control rate and audio + * rate data. Plugins have 'ports' that are inputs or outputs for audio + * or control data and each plugin is 'run' for a 'block' corresponding + * to a short time interval measured in samples. Audio rate data is + * communicated using arrays with one element per sample processed, + * allowing a block of audio to be processed by the plugin in a single + * pass. Control rate data is communicated using single values. Control + * rate data has a single value at the start of a call to the 'run()' + * function, and may be considered to remain this value for its duration. + * Thus the 'control rate' is determined by the block size, controlled + * by the host. The plugin may assume that all its input and output + * ports have been connected to the relevant data location (see the + * 'connect_port()' function below) before it is asked to run. + * + * Plugins will reside in shared object files suitable for dynamic linking + * by dlopen() and family. The file will provide a number of 'plugin + * types' that can be used to instantiate actual plugins (sometimes known + * as 'plugin instances') that can be connected together to perform tasks. + * + * This API contains very limited error-handling. + */ + +/* ************************************************************************* */ + + +/** Plugin Handle. + * + * This plugin handle indicates a particular instance of the plugin + * concerned. It is valid to compare this to NULL (0 for C++) but + * otherwise the host MUST not attempt to interpret it. The plugin + * may use it to reference internal instance data. */ +typedef void * LV2_Handle; + + +/* ************************************************************************* */ + +/** Host feature. + * + * These are passed to a plugin's instantiate method to represent a special + * feature the host has which the plugin may depend on. This is to allow + * extensions to the LV2 specification without causing any breakage. The base + * LV2 specification does not define any host features; hosts are not required + * to use this facility. + */ +typedef struct _LV2_Host_Feature { + /** A globally unique, case-sensitive identifier for this feature. + * + * This MUST be defined in the specification of any LV2 extension which + * defines a host feature. + */ + const char * URI; + + /** Pointer to arbitrary data. + * + * This is to allow hosts to pass data to a plugin (simple values, data + * structures, function pointers, etc) as part of a 'feature'. The LV2 + * specification makes no restrictions on the contents of this data. + * The data here MUST be cleary defined by the LV2 extension which defines + * this feature. + * If no data is required, this may be set to NULL. + */ + void * data; +} LV2_Host_Feature; + + +/* ************************************************************************* */ + + +/** Descriptor for a Type of Plugin. + * + * This structure is used to describe a plugin type. It provides a number + * of functions to instantiate it, link it to buffers and run it. */ +typedef struct _LV2_Descriptor { + + /** A globally unique, case-sensitive identifier for this plugin type. + * + * All plugins with the same URI MUST be compatible in terms of 'port + * signature', meaning they have the same number of ports, same port + * shortnames, and roughly the same functionality. URIs should + * probably contain a version number (or similar) for this reason. + * + * Rationale: When serializing session/patch/etc files, hosts MUST + * refer to a loaded plugin by the plugin URI only. In the future + * loading a plugin with this URI MUST yield a plugin with the + * same ports (etc) which is 100% compatible. */ + const char * URI; + + /** Function pointer that instantiates a plugin. + * + * A handle is returned indicating the new plugin instance. The + * instantiation function accepts a sample rate as a parameter as well + * as the plugin descriptor from which this instantiate function was + * found. This function must return NULL if instantiation fails. + * + * BundlePath is a string of the path to the plugin's .lv2 bundle + * directory, it MUST not include the trailing /. + * + * HostFeatures is a NULL terminated array of the URIs of the LV2 + * features that the host supports. Plugins may refuse to instantiate + * if required features are not found here (however hosts SHOULD NOT use + * this as a discovery mechanism, instead reading the data file before + * attempting to instantiate the plugin). + * + * Note that instance initialisation should generally occur in + * activate() rather than here. If a host calls instantiate, it MUST + * call cleanup() at some point in the future. */ + LV2_Handle (*instantiate)(const struct _LV2_Descriptor * Descriptor, + unsigned long SampleRate, + const char * BundlePath, + const LV2_Host_Feature** HostFeatures); + + /** Function pointer that connects a port on a plugin instance to a memory + * location where the block of data for the port will be read/written. + * + * The data location is expected to be an array of void * (typically + * float *) for audio ports or a single void * value for control + * ports. Memory issues are managed by the host. The plugin must + * read/write the data at these locations every time run() is called + * and the data present at the time of this connection call MUST NOT + * be considered meaningful. + * + * connect_port() may be called more than once for a plugin instance + * to allow the host to change the buffers that the plugin is reading + * or writing. These calls may be made before or after activate() + * or deactivate() calls. + * + * connect_port() must be called at least once for each port before + * run() is called. The plugin must pay careful attention to the block + * size passed to the run function as the block allocated may only just + * be large enough to contain the block of data (typically samples), and + * is not guaranteed to be constant. + * + * Plugin writers should be aware that the host may elect to use the + * same buffer for more than one port and even use the same buffer for + * both input and output (see LV2_PROPERTY_INPLACE_BROKEN (FIXME)). + * However, overlapped buffers or use of a single buffer for both + * audio and control data may result in unexpected behaviour. */ + void (*connect_port)(LV2_Handle Instance, + unsigned long Port, + void * DataLocation); + + /** Function pointer that initialises a plugin instance and activates + * it for use. + * + * This is separated from instantiate() to aid real-time support and so + * that hosts can reinitialise a plugin instance by calling deactivate() + * and then activate(). In this case the plugin instance must reset all + * state information dependent on the history of the plugin instance + * except for any data locations provided by connect_port(). If there + * is nothing for activate() to do then the plugin writer may provide + * a NULL rather than an empty function. + * + * When present, hosts MUST call this function once before run() + * is called for the first time. This call SHOULD be made as close + * to the run() call as possible and indicates to real-time plugins + * that they are now live, however plugins MUST NOT rely on a prompt + * call to run() after activate(). activate() may not be called again + * unless deactivate() is called first (after which activate() may be + * called again, followed by deactivate, etc. etc.). If a host calls + * activate, it MUST call deactivate at some point in the future. + * + * Note that connect_port() may be called before or after a call to + * activate(). */ + void (*activate)(LV2_Handle Instance); + + /** Function pointer that runs a plugin instance for a block. + * + * Two parameters are required: the first is a handle to the particular + * instance to be run and the second indicates the block size (in + * samples) for which the plugin instance may run. + * + * Note that if an activate() function exists then it must be called + * before run(). If deactivate() is called for a plugin instance then + * the plugin instance may not be reused until activate() has been + * called again. + * + * If the plugin has the property LV2_PROPERTY_HARD_RT_CAPABLE then + * there are various things that the plugin MUST NOT do within the run() + * function (see above). */ + void (*run)(LV2_Handle Instance, + unsigned long SampleCount); + + /** This is the counterpart to activate() (see above). If there is + * nothing for deactivate() to do then the plugin writer may provide + * a NULL rather than an empty function. + * + * Hosts must deactivate all activated units after they have been run() + * for the last time. This call SHOULD be made as close to the last + * run() call as possible and indicates to real-time plugins that + * they are no longer live, however plugins MUST NOT rely on prompt + * deactivation. Note that connect_port() may be called before or + * after a call to deactivate(). + * + * Note that deactivation is not similar to pausing as the plugin + * instance will be reinitialised when activate() is called to reuse it. + * Hosts MUST NOT call deactivate() unless activate() was previously + * called. */ + void (*deactivate)(LV2_Handle Instance); + + /** This is the counterpart to instantiate() (see above). Once an instance + * of a plugin has been finished with it can be deleted using this + * function. The instance handle passed ceases to be valid after + * this call. + * + * If activate() was called for a plugin instance then a corresponding + * call to deactivate() MUST be made before cleanup() is called. + * Hosts MUST NOT call cleanup() unless instantiate() was previously + * called. */ + void (*cleanup)(LV2_Handle Instance); + +} LV2_Descriptor; + + +/* ****************************************************************** */ + + +/** Accessing a Plugin: + * + * The exact mechanism by which plugins are loaded is host-dependent, + * however all most hosts will need to know is the URI of the plugin they + * wish to load. The environment variable LV2_PATH, if present, should + * contain a colon-separated path indicating directories (containing + * plugin bundle subdirectories) that should be searched (in order) + * for plugins. It is expected that hosts will use a library to provide + * this functionality. + * + * A plugin programmer must include a function called "lv2_descriptor" + * with the following function prototype within the shared object + * file. This function will have C-style linkage (if you are using + * C++ this is taken care of by the 'extern "C"' clause at the top of + * the file). + * + * A host will find the plugin shared object file by one means or another, + * find the lv2_descriptor() function, call it, and proceed from there. + * + * Plugin types are accessed by index (not ID) using values from 0 + * upwards. Out of range indexes must result in this function returning + * NULL, so the plugin count can be determined by checking for the least + * index that results in NULL being returned. Index has no meaning, + * hosts MUST NOT depend on it remaining constant (ie when serialising) + * in any way. */ +const LV2_Descriptor * lv2_descriptor(unsigned long Index); + + +/** Datatype corresponding to the lv2_descriptor() function. */ +typedef const LV2_Descriptor * +(*LV2_Descriptor_Function)(unsigned long Index); + + +/* ******************************************************************** */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LV2_INCLUDED */ diff --git a/include/lv2.ttl b/include/lv2.ttl new file mode 100644 index 0000000..47b21ae --- /dev/null +++ b/include/lv2.ttl @@ -0,0 +1,326 @@ +# RDF Schema file for LV2 plugins +# *** PROVISIONAL *** +# +# This document describes the classes and properties that are defined by the +# core LV2 specification. + +@prefix : <http://lv2plug.in/ontology#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix dc: <http://purl.org/dc/elements/1.1/> . + +<> dc:creator "Steve Harris" ; + dc:date "2006-04-26" . + +# +# Classes +# + +:Plugin a rdfs:Class ; + rdfs:label "Plugin" ; + rdfs:comment """ +This is the class that represents an LV2 plugin. + +In order for it to be used by a host it must have at least one occurance of the +following properties: + rdf:type (with object :Plugin) + doap:name (one without language tag) + doap:licence + lv2:port + +This can be determined by the following SPARQL query: + +PREFIX : <http://lv2plug.in/ontology#> +PREFIX doap: <http://usefulinc.com/ns/doap#> +SELECT DISTINCT ?uri WHERE { + ?uri a :Plugin ; + doap:name ?name ; + doap:licence ?rights ; + :port ?port . + FILTER( LANG(?name) = "" ) +} +""" . + +:Port a rdfs:Class ; + rdfs:label "Port" ; + rdfs:comment """ +This is the class that represents an LV2 port + +In order for it to be used by a host it must have at least the following +properties: + rdf:type (where object is exactly one of :InputControlRatePort, + :OutputControlRatePort, :InputAudioRatePort or :OututAudioRatePort) + :datatype + :index + :symbol + :name +""" . + +:InputPort a rdfs:Class ; + rdfs:subClassOf :Port . + +:OutputPort a rdfs:Class ; + rdfs:subClassOf :Port . + +:ControlRatePort a rdfs:Class ; + rdfs:subClassOf :Port . + +:AudioRatePort a rdfs:Class ; + rdfs:subClassOf :Port . + +:InputControlRatePort a rdfs:Class ; + rdfs:label "Input control port" ; + rdfs:subClassOf :ControlRatePort ; + rdfs:subClassOf :InputPort ; + rdfs:comment """ +Ports of this type will be connected to a pointer to a single value of the type +defined by the :datatype property. + +Plugins will read values from this pointer during thier run method. +""" . + +:OutputControlRatePort a rdfs:Class ; + rdfs:label "Output control port" ; + rdfs:subClassOf :ControlRatePort ; + rdfs:subClassOf :OutputPort ; + rdfs:comment """ +Ports of this type will be connected to a pointer to a single value of the type +defined by the :datatype property. + +Plugins will write values to this pointer during thier run method. +""" . + +:InputAudioRatePort a rdfs:Class ; + rdfs:label "Input audio port" ; + rdfs:subClassOf :AudioRatePort ; + rdfs:subClassOf :InputPort ; + rdfs:comment """ +Ports of this type will be connected to a an array of values of length +SampleCount and of the type defined by the :datatype property. + +Plugins will read values from this array during their run method. +""" . + +:OutputAudioRatePort a rdfs:Class ; + rdfs:label "Output audio port" ; + rdfs:subClassOf :AudioRatePort ; + rdfs:subClassOf :OutputPort ; + rdfs:comment """ +Ports of this type will be connected to a an array of values of length +SampleCount and of the type defined by the :datatype property. + +Plugins will write values to this array during their run method. +""" . + +:ScalePoint a rdfs:Class ; + rdfs:label "Scale point" ; + rdfs:comment """ +Used to describe interesting values in a Port's range. + +It has two properties neccesary for use, :label and :value. +""" . + +:Property a rdfs:Class ; + rdfs:label "Property" ; + rdfs:comment """ +Used to inform the host of the capabilities of the Plugin. +""" . + +:Hint a rdfs:Class ; + rdfs:label "Hint" ; + rdfs:comment """ +Used to hint to the host various things which can make interacting with the +Port more natural. +""" . + +:HostFeature a rdfs:Class ; + rdfs:label "Host feature" ; + rdfs:comment """ +Used to describe a host feature which plugin may use or require. +""" . + + +# +# Properties +# + +:property a rdf:Property ; + rdfs:domain :Plugin ; + rdfs:range :Property ; + rdfs:label "property" ; + rdfs:comment "Relates Plugins to Properties." . + +:requiredHostFeature a rdf:Property ; + rdfs:domain :Plugin ; + rdfs:range :HostFeature ; + rdfs:label "Required host feature" ; + rdfs:comment """ +Signifies that plugin requires a certain host feature to function. +The plugin will fail to instantiate if a required host feature is not present; +hosts SHOULD always check this before attempting to instantiate a plugin. +""" . + +:hint a rdf:Property ; + rdfs:domain :Port ; + rdfs:range :Hint ; + rdfs:label "hint" ; + rdfs:comment "Relates Ports to Hints." . + +:datatype a rdf:Property ; + rdfs:domain :Port ; + rdfs:range :Datatype ; + rdfs:label "datatype" ; + rdfs:comment """ +Relates a Port to the datatype(s) is can accept. Currently the only specified +datatype is :float, which specfies IEEE-754 32bit floating point values. + +Hosts that do not support a specfied datatype MUST NOT instantiate the plugin. + +If multiple datatypes are specfied the plugin must have some way to distinguish +the values. +""" . + +# FIXME: rdfs:range = xsd:nonNegativeInteger? +:index a rdf:Property ; + rdfs:domain :Port ; + rdfs:label "index" ; + rdfs:comment """ +Specifies the index of the port, passed as an argument to the connect port +function. This number uniqely identifies the port within the plugin. +""" . + +# FIXME: rdfs:range = xsd:NCName? Closest thing xsd: has.. +:symbol a rdf:Property ; + rdfs:domain :Port ; + rdfs:label "symbol" ; + rdfs:comment """ +A short name used to identify the port in an easily machine and human readable way. + +The first character must be one of _, a-z or A-Z and subsequenct characters can +be from _, a-z, A-Z and 0-9. + +No language tag should be used on this property. +""" . + +:name a rdf:Property ; + rdfs:domain :Port ; + rdfs:label "name" ; + rdfs:comment """ +A display name for labeling the Port in a user interface. + +This property is required for Ports, but should not be used by the host for +port identification. The plugin author may change the values of this +property without changing the Plugin URI. +""" . + +:default a rdf:Property ; + rdfs:domain :ControlRatePort ; + rdfs:label "default" ; + rdfs:comment """ +The default value that the host SHOULD set this port to when there is not other +information available. Only meaningful for Ports with a :datatype of :float. +""" . + +:minimum a rdf:Property ; + rdfs:domain :Port ; + rdfs:label "minimum" ; + rdfs:comment """ +A hint to the host for the minimum useful value that the port will use. The +plugin is required to accept all values in the range of :float. +""" . + +:minimum a rdf:Property ; + rdfs:domain :Port ; + rdfs:label "maximum" ; + rdfs:comment """ +A hint to the host for the maximum useful value that the port will use. The +plugin is required to accept all values in the range of :float. +""" . + +:scalePoint a rdf:Property ; + rdfs:domain :Port ; + rdfs:range :ScalePoint ; + rdfs:label "scale point" ; + rdfs:comment "Relates a Port to its ScalePoints." . + + +# +# Instances +# + +:toggled a :Hint ; + rdfs:label "toggled" ; + rdfs:comment """ +Indicates that the data item should be considered a Boolean toggle. Data less +than or equal to zero should be considered `off' or `false,' and data above +zero should be considered `on' or `true.' +""" . + +:sampleRate a :Hint ; + rdfs:label "sample rate" ; + rdfs:comment """ +Indicates that any bounds specified should be interpreted as multiples of the +sample rate. For instance, a frequency range from 0Hz to the Nyquist frequency +(half the sample rate) could be requested by this hint in conjunction with +:minimum 0.0 and :maximum 0.5. Hosts that support bounds at all must support +this hint to retain meaning. +""" . + +:integer a :Hint ; + rdfs:label "integer" ; + rdfs:comment """ +Indicates that a user interface would probably wish to provide a stepped +control taking only integer values. +""" . + +:realtime a :Property ; + rdfs:label "realtime" ; + rdfs:comment """ +Indicates that the plugin has a real-time dependency (e.g. listens to a MIDI +device) and so its output must not be cached or subject to significant latency. +""" . + +:inplaceBroken a :Property ; + rdfs:label "in-place broken" ; + rdfs:comment """ +Indicates that the plugin may cease to work correctly if the host elects to use +the same data location for both input and output (see connect_port()). This +should be avoided as enabling this flag makes it impossible for hosts to use +the plugin to process audio `in-place.' +""" . + +:hardRtCapable a :Property ; + rdfs:label "hard realtime capable" ; + rdfs:comment """ +Indicates that the plugin is capable of running not only in a conventional host +but also in a `hard real-time' environment. To qualify for this the plugin must +satisfy all of the following: + + (1) The plugin must not use malloc(), free() or other heap memory + management within its run() or run_adding() functions. All new + memory used in run() must be managed via the stack. These + restrictions only apply to the run() function. + + (2) The plugin will not attempt to make use of any library + functions with the exceptions of functions in the ANSI standard C + and C maths libraries, which the host is expected to provide. + + (3) The plugin will not access files, devices, pipes, sockets, IPC + or any other mechanism that might result in process or thread + blocking. + + (4) The plugin will take an amount of time to execute a run() or + run_adding() call approximately of form (A+B*SampleCount) where A + and B depend on the machine and host in use. This amount of time + may not depend on input signals or plugin state. The host is left + the responsibility to perform timings to estimate upper bounds for + A and B. +""" . + +# FIXME: = xsd:float? +:float a :Datatype ; + rdfs:label "float" ; + rdfs:comment """ +Represents values conforming to the 32bit IEEE-754 floating point specification. +""" . + diff --git a/libslv2.pc.in b/libslv2.pc.in new file mode 100644 index 0000000..48b02d7 --- /dev/null +++ b/libslv2.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libslv2 +Version: @VERSION@ +Description: Convenience library for hosts to simplify LV2 plugin support +Libs: -L${libdir} -lslv2 +Cflags: -I${includedir} diff --git a/slv2/Makefile.am b/slv2/Makefile.am new file mode 100644 index 0000000..fafe21d --- /dev/null +++ b/slv2/Makefile.am @@ -0,0 +1,11 @@ +slv2includedir = $(includedir)/slv2 + +slv2include_HEADERS = \ + types.h \ + private_types.h \ + slv2.h \ + plugin.h \ + query.h \ + port.h \ + pluginlist.h \ + plugininstance.h diff --git a/slv2/plugin.h b/slv2/plugin.h new file mode 100644 index 0000000..6af04bc --- /dev/null +++ b/slv2/plugin.h @@ -0,0 +1,168 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __SLV2_PLUGIN_H__ +#define __SLV2_PLUGIN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> +#include <stdbool.h> +#include "types.h" + + +typedef const struct _Plugin SLV2Plugin; + + +/** \defgroup data Plugin data file access + * + * These functions work exclusively with the plugin's RDF data file. They do + * not load the plugin dynamic library (or access + * it in any way). + * + * @{ + */ + + +/** Check if this plugin is valid. + * + * This is used by plugin lists to avoid loading plugins that are not valid + * and will not work with libslv2 (eg plugins missing required fields, or + * having multiple values for mandatory single-valued fields, etc. + * + * Note that normal hosts do not need to worry about list - libslv2 does not + * load invalid plugins in to plugin lists. This is included for plugin + * testing utilities, etc. + * + * \return True if \a plugin is valid. + */ +bool +slv2_plugin_verify(const SLV2Plugin* plugin); + + +/** Duplicate a plugin. + * + * Use this if you want to keep an SLV2Plugin around but free the list it came + * from. + * + * \return a newly allocated SLV2Plugin identical to \a plugin (a deep copy). + */ +SLV2Plugin* +slv2_plugin_duplicate(const SLV2Plugin* plugin); + + +/** Get the URI of \a plugin. + * + * Any serialization that refers to plugins should refer to them by this. + * Hosts SHOULD NOT save any filesystem paths, plugin indexes, etc. in saved + * files; save only the URI. + * + * The URI is a globally unique identifier for one specific plugin. Two + * plugins with the same URI are compatible in port signature, and should + * be guaranteed to work in a compatible and consistent way. If a plugin + * is upgraded in an incompatible way (eg if it has different ports), it + * MUST have a different URI than it's predecessor. + * + * \return a shared string which must not be modified or free()'d. + */ +const unsigned char* +slv2_plugin_get_uri(const SLV2Plugin* plugin); + + +/** Get the URL of the RDF data file plugin information is located in. + * + * Only file: URL's are supported at this time. + * + * \return a complete URL eg. "file:///usr/foo/SomeBundle.lv2/someplug.ttl", + * which is shared and must not be modified or free()'d. + */ +const unsigned char* +slv2_plugin_get_data_url(const SLV2Plugin* plugin); + + +/** Get the local filesystem path of the RDF data file for \a plugin. + * + * \return a valid path on the local filesystem + * eg. "/usr/foo/SomeBundle.lv2/someplug.ttl" which is shared and must not + * be free()'d; or NULL if URL is not a local filesystem path. + */ +const unsigned char* +slv2_plugin_get_data_path(const SLV2Plugin* plugin); + + +/** Get the URL of the shared library for \a plugin. + * + * \return a shared string which must not be modified or free()'d. + */ +const unsigned char* +slv2_plugin_get_library_url(const SLV2Plugin* plugin); + + +/** Get the local filesystem path of the shared library for \a plugin. + * + * \return a valid path on the local filesystem + * eg. "/usr/foo/SomeBundle.lv2/someplug.so" which is shared and must not + * be free()'d; or NULL if URL is not a local filesystem path. + */ +const unsigned char* +slv2_plugin_get_library_path(const SLV2Plugin* plugin); + + +/** Get the name of \a plugin. + * + * This is guaranteed to return the untranslated name (the doap:name in the + * data file without a language tag). Returned value must be free()'d by + * the caller. + */ +unsigned char* +slv2_plugin_get_name(const SLV2Plugin* plugin); + + +/** Request some property of the plugin. + * + * May return NULL if the property was not found (ie is not defined in the + * data file). + * + * Return value must be free()'d by caller. + * + * Note that some properties may have multiple values. If the property is a + * string with multiple languages defined, the translation according to + * $LANG will be returned if it is set. Otherwise all values will be + * returned. + */ +SLV2Property +slv2_plugin_get_property(const SLV2Plugin* p, + const char* property); + + +/** Get the number of ports on this plugin. + */ +unsigned long +slv2_plugin_get_num_ports(const SLV2Plugin* p); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __SLV2_PLUGIN_H__ */ + diff --git a/slv2/plugininstance.h b/slv2/plugininstance.h new file mode 100644 index 0000000..5fd9393 --- /dev/null +++ b/slv2/plugininstance.h @@ -0,0 +1,205 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __SLV2_PLUGININSTANCE_H__ +#define __SLV2_PLUGININSTANCE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <assert.h> +#include <dlfcn.h> +#include <lv2.h> +#include <slv2/private_types.h> +#include <slv2/plugininstance.h> +#include <slv2/plugin.h> +#include <slv2/port.h> + + +typedef const struct _Instance SLV2Instance; + + +/** \defgroup lib Plugin library access + * + * An SLV2Instance is an instantiated SLV2Plugin (eg a loaded dynamic + * library). These functions interact with the binary library code only, + * they do not read any RDF data files whatsoever. + * + * @{ + */ + + +/** Instantiate a plugin. + * + * The returned object represents shared library objects loaded into memory, + * it must be cleaned up with slv2instance_free when no longer + * needed. + * + * \a plugin is not modified or directly referenced by the returned object + * (instances store only a copy of the plugin's URI). + * + * \return NULL if instantiation failed. + */ +SLV2Instance* +slv2_plugin_instantiate(const SLV2Plugin* plugin, + unsigned long sample_rate, + const LV2_Host_Feature** host_features); + + +/** Free a plugin instance. + * + * \a instance is invalid after this call. + */ +void +slv2_instance_free(SLV2Instance* instance); + + +#ifndef LIBSLV2_SOURCE + + +/** Get the URI of the plugin which \a instance is an instance of. + * + * Returned string is shared and must not be modified or deleted. + */ +inline const char* +slv2_instance_get_uri(SLV2Instance* instance) +{ + assert(instance); + assert(instance->descriptor); + + return instance->descriptor->URI; +} + + +/** Connect a port to a data location. + * + * This may be called regardless of whether the plugin is activated, + * activation and deactivation does not destroy port connections. + */ +inline void +slv2_instance_connect_port(SLV2Instance* instance, + unsigned long port_index, + void* data_location) +{ + assert(instance); + assert(instance->descriptor); + assert(instance->descriptor->connect_port); + + instance->descriptor->connect_port + (instance->lv2_handle, port_index, data_location); +} + + +/** Activate a plugin instance. + * + * This resets all state information in the plugin, except for port data + * locations (as set by slv2instance_connect_port). This MUST be called + * before calling slv2instance_run. + */ +inline void +slv2_instance_activate(SLV2Instance* instance) +{ + assert(instance); + assert(instance->descriptor); + + if (instance->descriptor->activate) + instance->descriptor->activate(instance->lv2_handle); +} + + +/** Run \a instance for \a sample_count frames. + * + * If the hint lv2:realtimeSafe is set for this plugin, this function is + * guaranteed not to block. + */ +inline void +slv2_instance_run(SLV2Instance* instance, + unsigned long sample_count) +{ + assert(instance); + assert(instance->descriptor); + assert(instance->lv2_handle), + assert(instance->descriptor->run); + + instance->descriptor->run(instance->lv2_handle, sample_count); +} + + +/** Deactivate a plugin instance. + * + * Note that to run the plugin after this you must activate it, which will + * reset all state information (except port connections). + */ +inline void +slv2_instance_deactivate(SLV2Instance* instance) +{ + assert(instance); + assert(instance->descriptor); + assert(instance->lv2_handle); + + if (instance->descriptor->deactivate) + instance->descriptor->deactivate(instance->lv2_handle); +} + + +/** Get the LV2_Descriptor of the plugin instance. + * + * Normally hosts should not need to access the LV2_Descriptor directly, + * use the slv2instance_* functions. + * + * The returned descriptor is shared and must not be deleted. + */ +inline const LV2_Descriptor* +slv2_instance_get_descriptor(SLV2Instance* instance) +{ + assert(instance); + assert(instance->descriptor); + + return instance->descriptor; +} + + +/** Get the LV2_Handle of the plugin instance. + * + * Normally hosts should not need to access the LV2_Handle directly, + * use the slv2instance_* functions. + * + * The returned handle is shared and must not be deleted. + */ +inline LV2_Handle +slv2_instance_get_handle(SLV2Instance* instance) +{ + assert(instance); + assert(instance->descriptor); + + return instance->lv2_handle; +} + +#endif /* LIBSLV2_SOURCE */ + + +/** @} */ + +#ifdef __cplusplus +} +#endif + + +#endif /* __SLV2_PLUGININSTANCE_H__ */ + diff --git a/slv2/pluginlist.h b/slv2/pluginlist.h new file mode 100644 index 0000000..d29a56d --- /dev/null +++ b/slv2/pluginlist.h @@ -0,0 +1,159 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __SLV2_PLUGINLIST_H__ +#define __SLV2_PLUGINLIST_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct _PluginList* SLV2List; + + +/** \defgroup lists Plugin lists + * + * These functions are for locating plugins installed on the system. + * + * Normal hosts which just want to easily load plugins by URI are strongly + * recommended to simply find all installed plugins with + * \ref slv2_list_load_all rather than find and load bundles manually. + * + * Functions are provided for hosts that wish to access bundles explicitly and + * individually for some reason, as well as make custom lists of plugins from + * a selection of bundles. This is mostly intended for hosts which are + * tied to a specific (bundled with the application) bundle. + * + * @{ + */ + + +/** Create a new, empty plugin list. + * + * Returned object must be freed with slv2_list_free. + */ +SLV2List +slv2_list_new(); + + +/** Free a plugin list. + * + * Note that all plugins in the list (eg those returned by the get_plugin + * functions) will be deleted as well. It is expected that hosts will + * keep the plugin list allocated until they are done with their plugins. + * If you want to keep a plugin around, but free the list it came from, you + * will have to copy it with slv2_plugin_duplicate(). + * + * \a list is invalid after this call (though it may be used again after a + * "list = slv2_list_new()") + */ +void +slv2_list_free(SLV2List list); + + +/** Add all plugins installed on the system to \a list. + * + * This is the recommended way for hosts to access plugins. It finds all + * plugins on the system using the recommended mechanism. At the time, this + * is by searching the path defined in the environment variable LADSPA2_PATH, + * though this is subject to change in the future. Future versions may, for + * example, allow users to specify a plugin whitelist of plugins they would + * like to be visible in apps (or conversely a blacklist of plugins they do + * not wish to use). + * + * Use of any of the other functions for locating plugins is highly + * discouraged without specific reason to do so. Use this one. + */ +void +slv2_list_load_all(SLV2List list); + + +/** Add all plugins found in \a search_path to \a list. + * + * If \a search_path is NULL, \a list will be unmodified. + * + * Use of this function is not recommended. Use \ref slv2_list_load_all. + * + * Returned value must be cleaned up by slv2list_free. + */ +void +slv2_list_load_path(SLV2List list, + const char* search_path); + + +/** Add all plugins found in the bundle at \a bundle_base_url to \a list. + * + * \arg bundle_base_url is a fully qualified path to the bundle directory, eg. + * "file:///usr/lib/lv2/someBundle" + * + * Use of this function is <b>strongly</b> discouraged, hosts should not attach + * any significance to bundle paths as there are no guarantees they will + * remain consistent whatsoever. This function should only be used by apps + * which ship with a special bundle (which it knows exists at some path). + * It is <b>not</b> to be used by normal hosts that want to load system + * installed plugins. Use \ref slv2_list_load_all. + */ +void +slv2_list_load_bundle(SLV2List list, + const unsigned char* bundle_base_url); + + +/** Get the number of plugins in the list. + */ +unsigned long +slv2_list_get_length(const SLV2List list); + + +/** Get a plugin from the list by URI. + * + * Return value is shared (stored in \a list) and must not be freed or + * modified by the caller in any way. + * + * \return NULL if plugin with \a url not found in \a list. + */ +const SLV2Plugin* +slv2_list_get_plugin_by_uri(const SLV2List list, + const unsigned char* uri); + + +/** Get a plugin from the list by index. + * + * \a index has no significance. Any \a index not less than + * slv2list_get_length(list) will return NULL. * All plugins in a list can + * thus be easily enumerated by repeated calls to this function starting + * with \a index 0. + * + * Return value is shared (stored in \a list) and must not be freed or + * modified by the caller in any way. + * + * \return NULL if \a index out of range. + */ +const SLV2Plugin* +slv2_list_get_plugin_by_index(const SLV2List list, + unsigned long index); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __SLV2_PLUGINLIST_H__ */ + diff --git a/slv2/port.h b/slv2/port.h new file mode 100644 index 0000000..749ea4e --- /dev/null +++ b/slv2/port.h @@ -0,0 +1,116 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __SLV2_PORT_H__ +#define __SLV2_PORT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" +#include "plugin.h" + +/** \addtogroup data + * @{ + */ + + +/** A port on a plugin. + * + * The information necessary to use the port is stored here, any extra + * information can be queried with slv2port_get_property. + */ +/*struct LV2Port { + unsigned long index; ///< Index in ports array + char* short_name; ///< Guaranteed unique identifier + char* type; ///< eg. lv2:InputControlPort + char* data_type; ///< eg. lv2:float +};*/ + + +/** Get a property of a port, by port index. + * + * Return value must be free()'d by caller. + */ +SLV2Property +slv2_port_get_property(SLV2Plugin* plugin, + unsigned long index, + const uchar* property); + + +/** Get the symbol of a port given the index. + * + * The 'symbol' is a short string, a valid C identifier. + * Returned string must be free()'d by caller. + * + * \return NULL when index is out of range + */ +uchar* +slv2_port_get_symbol(SLV2Plugin* plugin, + unsigned long index); + + +/** Get the class (direction and rate) of a port. + */ +enum SLV2PortClass +slv2_port_get_class(SLV2Plugin* plugin, + unsigned long index); + + +/** Get the data type of a port. + */ +enum SLV2DataType +slv2_port_get_data_type(SLV2Plugin* plugin, + unsigned long index); + + +/** Get the default value of a port. + * + * Only valid for ports with a data type of lv2:float. + */ +float +slv2_port_get_default_value(SLV2Plugin* plugin, + unsigned long index); + + +/** Get the minimum value of a port. + * + * Only valid for ports with a data type of lv2:float. + */ +float +slv2_port_get_minimum_value(SLV2Plugin* plugin, + unsigned long index); + + +/** Get the maximum value of a port. + * + * Only valid for ports with a data type of lv2:float. + */ +float +slv2_port_get_maximum_value(SLV2Plugin* plugin, + unsigned long index); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __SLV2_PORT_H__ */ diff --git a/slv2/private_types.h b/slv2/private_types.h new file mode 100644 index 0000000..849e5a2 --- /dev/null +++ b/slv2/private_types.h @@ -0,0 +1,65 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __SLV2_PRIVATE_TYPES_H__ +#define __SLV2_PRIVATE_TYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> +#include <lv2.h> + + +/** Record of an installed/available plugin. + * + * A simple reference to a plugin somewhere on the system. This just holds + * paths of relevant files, the actual data therein isn't loaded into memory. + */ +struct _Plugin { + unsigned char* plugin_uri; + unsigned char* bundle_url; // Bundle directory plugin was loaded from + unsigned char* data_url; // rdfs::seeAlso + unsigned char* lib_url; // lv2:binary +}; + + +/** Instance of a plugin (private type) */ +struct _Instance { + // FIXME: copy plugin here for convenience? + //struct LV2Plugin* plugin; + const LV2_Descriptor* descriptor; + void* lib_handle; + LV2_Handle lv2_handle; +}; + + +/** List of references to plugins available for loading (private type) */ +struct _PluginList { + size_t num_plugins; + struct _Plugin** plugins; +}; + + +#ifdef __cplusplus +} +#endif + +#endif /* __SLV2_PRIVATE_TYPES_H__ */ + diff --git a/slv2/query.h b/slv2/query.h new file mode 100644 index 0000000..f1708d7 --- /dev/null +++ b/slv2/query.h @@ -0,0 +1,102 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __SLV2_QUERY_H__ +#define __SLV2_QUERY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rasqal.h> +#include "plugin.h" +#include "types.h" + +/** \defgroup query SPARQL query helpers + * + * This part is in progress, incomplete, a random mishmash of crap that + * evolved along with my understanding of this rasqal library. Nothing + * to see here, move long now. Nothing to see here. + * + * Eventually this will contain functions that make it convenient for host + * authors to query plugins in ways libslv2 doesn't nicely wrap (eg. for + * extensions not (yet) supported by libslv2). + * + * @{ + */ + +/** Return a header for a SPARQL query on the given plugin. + * + * The returned header defines the namespace prefixes used in the standard + * (rdf: rdfs: doap: lv2:), plugin: as the plugin's URI, and data: as the + * URL of the plugin's RDF (Turtle) data file. + * + * Example query to get a plugin's doap:name using this header: + * + * <code> + * SELECT DISTINCT ?value FROM data: WHERE { + * plugin: doap:name ?value + * } + * </code> + * + * \return an unsigned (UTF-8) string which must be free()'d. + */ +unsigned char* +slv2_query_header(const SLV2Plugin* p); + + +/** Return a language filter for the given variable. + * + * If the environment variable $LANG is not set, returns NULL. + * + * \arg variable SPARQL variable, including "?" or "$" (eg "?value"). + * + * This needs to be put inside the WHERE block, after the triples. + * + * eg. FILTER( LANG(?value) = "en" || LANG(?value) = "" ) + */ +unsigned char* +slv2_query_lang_filter(const uchar* variable); + + +/** Run a SPARQL query on a plugin's data file. + * + * String arguments will be concatenated, allowing for variable substitution + * etc. (without having to define a token syntax and search the string for + * tokens, which would be slow). + * + * Header from slv2query_header will be prepended to passed query string. + * rasqal_init() must be called by the caller before calling this function. + */ +rasqal_query_results* +slv2_plugin_run_query(const SLV2Plugin* p, + const uchar* query_string, ...); + + +SLV2Property +slv2_query_get_results(rasqal_query_results* results); + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __SLV2_QUERY_H__ */ + diff --git a/slv2/slv2.h b/slv2/slv2.h new file mode 100644 index 0000000..6305f23 --- /dev/null +++ b/slv2/slv2.h @@ -0,0 +1,36 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __SLV2_H +#define __SLV2_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <slv2/types.h> +#include <slv2/plugin.h> +#include <slv2/plugininstance.h> +#include <slv2/pluginlist.h> +#include <slv2/port.h> + +#ifdef __cplusplus +} +#endif + +#endif /* __SLV2_H */ diff --git a/slv2/types.h b/slv2/types.h new file mode 100644 index 0000000..b6d71cc --- /dev/null +++ b/slv2/types.h @@ -0,0 +1,66 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __SLV2_TYPES_H__ +#define __SLV2_TYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> + + +typedef unsigned char uchar; + + +/* A property, resulting from a query. + * + * Note that properties may have many values. + */ +struct _Property { + size_t num_values; + unsigned char** values; +}; + +typedef struct _Property* SLV2Property; + + +/** Class (direction and rate) of a port */ +enum SLV2PortClass { + SLV2_UNKNOWN_PORT_CLASS, + SLV2_CONTROL_RATE_INPUT, /**< One input value per block */ + SLV2_CONTROL_RATE_OUTPUT, /**< One output value per block */ + SLV2_AUDIO_RATE_INPUT, /**< One input value per frame */ + SLV2_AUDIO_RATE_OUTPUT /**< One output value per frame */ +}; + + +/** Type contained in a port buffer. */ +enum SLV2DataType { + SLV2_DATA_TYPE_FLOAT, /**< IEEE-754 32-bit floating point number */ + SLV2_UNKNOWN_DATA_TYPE +}; + + +#ifdef __cplusplus +} +#endif + +#endif /* __SLV2_TYPES_H__ */ + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..5f6cea2 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,14 @@ +AM_CFLAGS = -std=c99 -I$(top_srcdir)/include -I$(top_srcdir) @RASQAL_CFLAGS@ -DLIBSLV2_SOURCE +AM_LDFLAGS = `pkg-config --libs rasqal` + +lib_LTLIBRARIES = libslv2.la +libslv2_la_LIBADD = @RASQAL_LIBS@ + +libslv2_la_SOURCES = \ + util.h \ + plugin.c \ + query.c \ + port.c \ + pluginlist.c \ + util.c \ + plugininstance.c diff --git a/src/plugin.c b/src/plugin.c new file mode 100644 index 0000000..27fb481 --- /dev/null +++ b/src/plugin.c @@ -0,0 +1,190 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <rasqal.h> +#include <slv2/private_types.h> +#include <slv2/plugin.h> +#include <slv2/types.h> +#include <slv2/query.h> +#include "util.h" + + +SLV2Plugin* +slv2_plugin_duplicate(const SLV2Plugin* p) +{ + assert(p); + struct _Plugin* result = malloc(sizeof(struct _Plugin)); + result->plugin_uri = p->plugin_uri; + result->bundle_url = p->bundle_url; + result->data_url = p->data_url; + result->lib_url = p->lib_url; + return result; +} + + +const unsigned char* +slv2_plugin_get_uri(const SLV2Plugin* p) +{ + assert(p); + return p->plugin_uri; +} + + +const unsigned char* +slv2_plugin_get_data_url(const SLV2Plugin* p) +{ + assert(p); + return p->data_url; +} + + +const unsigned char* +slv2_plugin_get_data_path(const SLV2Plugin* p) +{ + assert(p); + if (!strncmp((char*)p->data_url, "file://", 7)) + return (p->data_url) + 7; + else + return NULL; +} + + +const unsigned char* +slv2_plugin_get_library_url(const SLV2Plugin* p) +{ + assert(p); + return p->lib_url; +} + + +const unsigned char* +slv2_plugin_get_library_path(const SLV2Plugin* p) +{ + assert(p); + if (!strncmp((char*)p->lib_url, "file://", 7)) + return (p->lib_url) + 7; + else + return NULL; +} + + +bool +slv2_plugin_verify(const SLV2Plugin* plugin) +{ + // FIXME: finish this (properly) + /* + size_t num_values = 0; + + struct SLV2Property* prop = slv2_plugin_get_property(plugin, "doap:name"); + if (prop) { + num_values = prop->num_values; + free(prop); + } + if (num_values < 1) + return false; + + prop = slv2_plugin_get_property(plugin, "doap:license"); + num_values = prop->num_values; + free(prop); + if (num_values < 1) + return false; +*/ + return true; +} + + +unsigned char* +slv2_plugin_get_name(const SLV2Plugin* plugin) +{ +// FIXME: leak + unsigned char* result = NULL; + struct _Property* prop = slv2_plugin_get_property(plugin, "doap:name"); + + // FIXME: guaranteed to be the untagged one? + if (prop && prop->num_values >= 1) + result = prop->values[0]; + + return result; +} + + +SLV2Property +slv2_plugin_get_property(const SLV2Plugin* p, + const char* property) +{ + assert(p); + assert(property); + + /* + uchar* header = slv2_query_header(p); + uchar* lang_filter = slv2_query_lang_filter(U("?value")); + + uchar* query_string = ustrjoin( + header, + U("SELECT DISTINCT ?value FROM data: WHERE { \n"), + U("plugin: "), property, U(" ?value . \n"), + ((lang_filter != NULL) ? lang_filter : U("")), + "}", 0); + + free(header); + free(lang_filter);*/ + + rasqal_init(); + + rasqal_query_results* results = slv2_plugin_run_query(p, + U("SELECT DISTINCT ?value FROM data: WHERE { \n" + "plugin: "), property, U(" ?value . \n" + "} \n"), 0); + + struct _Property* result = slv2_query_get_results(results); + + //free(query_string); + rasqal_free_query_results(results); + rasqal_finish(); + + return result; +} + + +unsigned long +slv2_plugin_get_num_ports(const SLV2Plugin* p) +{ + unsigned long result = 0; + + rasqal_init(); + + + rasqal_query_results* results = slv2_plugin_run_query(p, + U("SELECT DISTINCT ?value FROM data: WHERE { \n" + "plugin: lv2:port ?value . \n" + "} \n"), 0); + + while (!rasqal_query_results_finished(results)) { + ++result; + rasqal_query_results_next(results); + } + + rasqal_free_query_results(results); + rasqal_finish(); + + return result; +} + diff --git a/src/plugininstance.c b/src/plugininstance.c new file mode 100644 index 0000000..40de08c --- /dev/null +++ b/src/plugininstance.c @@ -0,0 +1,100 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <dlfcn.h> +#include <slv2/private_types.h> +#include <slv2/types.h> +#include <slv2/plugin.h> +#include <slv2/plugininstance.h> +#include "util.h" + + +SLV2Instance* +slv2_plugin_instantiate(const SLV2Plugin* plugin, + unsigned long sample_rate, + const LV2_Host_Feature** host_features) +{ + struct _Instance* result = NULL; + + const unsigned char* const lib_path = slv2_plugin_get_library_path(plugin); + if (!lib_path) + return NULL; + + void* lib = dlopen((char*)lib_path, RTLD_NOW); + if (!lib) { + printf("Unable to open library %s\n", lib_path); + return NULL; + } + + LV2_Descriptor_Function df = dlsym(lib, "lv2_descriptor"); + + if (!df) { + printf("Could not find symbol 'lv2_descriptor', " + "%s is not a LV2 plugin.\n", lib_path); + dlclose(lib); + return NULL; + } else { + // Search for plugin by URI + + const char* const bundle_path = url2path(plugin->bundle_url); + + for (unsigned long i=0; 1; ++i) { + const LV2_Descriptor* ld = df(i); + + if (!ld) { + printf("Did not find plugin %s in %s\n", + plugin->plugin_uri, plugin->lib_url); + dlclose(lib); + break; // return NULL + } else if (!strcmp(ld->URI, (char*)plugin->plugin_uri)) { + //printf("Found %s at index %ld in:\n\t%s\n\n", plugin->plugin_uri, i, lib_path); + + assert(ld->instantiate); + + // Create SLV2Instance to return + result = malloc(sizeof(struct _Instance)); + /*result->plugin = malloc(sizeof(struct _Plugin)); + memcpy(result->plugin, plugin, sizeof(struct _Plugin));*/ + result->descriptor = ld; + result->lib_handle = lib; + result->lv2_handle = ld->instantiate(ld, sample_rate, (char*)bundle_path, host_features); + break; + } + } + } + + return result; +} + + +void +slv2_instance_free(SLV2Instance* instance) +{ + struct _Instance* i = (struct _Instance*)instance; + i->descriptor->cleanup(i->lv2_handle); + i->descriptor = NULL; + dlclose(i->lib_handle); + i->lib_handle = NULL; + free(i); +} + + diff --git a/src/pluginlist.c b/src/pluginlist.c new file mode 100644 index 0000000..61e4c4b --- /dev/null +++ b/src/pluginlist.c @@ -0,0 +1,243 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _XOPEN_SOURCE 500 +#include <rasqal.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <assert.h> +#include <dirent.h> +#include <slv2/private_types.h> +#include <slv2/types.h> +#include <slv2/plugin.h> +#include <slv2/pluginlist.h> +#include "util.h" + + +struct _PluginList* +slv2_list_new() +{ + struct _PluginList* result = malloc(sizeof(struct _PluginList)); + result->num_plugins = 0; + result->plugins = NULL; + return result; +} + + +void +slv2_list_free(SLV2List list) +{ + list->num_plugins = 0; + free(list->plugins); + free(list); +} + + +void +slv2_list_load_all(SLV2List list) +{ + assert(list != NULL); + + char* slv2_path = getenv("LV2_PATH"); + + if (!slv2_path) { + slv2_path = "~/.lv2:/usr/local/lib/lv2:usr/lib/lv2"; + + printf("$LV2_PATH is unset. Using default path %s\n", + slv2_path); + } + + slv2_list_load_path(list, slv2_path); +} + + +/* This is the parser for manifest.ttl */ +void +slv2_list_load_bundle(SLV2List list, + const unsigned char* bundle_base_uri) +{ + // FIXME: ew + unsigned char* manifest_uri = malloc( + (strlen((char*)bundle_base_uri) + strlen("manifest.ttl") + 2) * sizeof(unsigned char)); + memcpy(manifest_uri, bundle_base_uri, strlen((char*)bundle_base_uri)+1 * sizeof(unsigned char)); + if (bundle_base_uri[strlen((char*)bundle_base_uri)-1] == '/') + strcat((char*)manifest_uri, (char*)"manifest.ttl"); + else + strcat((char*)manifest_uri, (char*)"/manifest.ttl"); + + rasqal_init(); + rasqal_query_results *results; + raptor_uri *base_uri = raptor_new_uri(manifest_uri); + rasqal_query *rq = rasqal_new_query((const char*)"sparql", (const uchar*)base_uri); + + unsigned char* query_string = + U("PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n" + "PREFIX : <http://lv2plug.in/ontology#> \n\n" + + "SELECT DISTINCT $plugin_uri $data_url $lib_url FROM <> WHERE { \n" + "$plugin_uri :binary $lib_url ; \n" + " rdfs:seeAlso $data_url . \n" + "} \n"); + + //printf("%s\n\n", query_string); + + rasqal_query_prepare(rq, (const uchar*)query_string, base_uri); + results = rasqal_query_execute(rq); + + while (!rasqal_query_results_finished(results)) { + + // Create a new plugin + struct _Plugin* new_plugin = malloc(sizeof(struct _Plugin)); + new_plugin->bundle_url = ustrdup(bundle_base_uri); + + rasqal_literal* literal = NULL; + + literal = rasqal_query_results_get_binding_value_by_name(results, + U("plugin_uri")); + if (literal) + new_plugin->plugin_uri = ustrdup(rasqal_literal_as_string(literal)); + + literal = rasqal_query_results_get_binding_value_by_name(results, + U("data_url")); + if (literal) + new_plugin->data_url = ustrdup(rasqal_literal_as_string(literal)); + + literal = rasqal_query_results_get_binding_value_by_name(results, + U("lib_url")); + if (literal) + new_plugin->lib_url = ustrdup(rasqal_literal_as_string(literal)); + + /* Add the plugin if it's valid */ + if (new_plugin->lib_url && new_plugin->data_url && new_plugin->plugin_uri + && slv2_plugin_verify(new_plugin)) { + /* Yes, this is disgusting, but it doesn't seem there's a way to know + * how many matches there are before iterating over them */ + list->num_plugins++; + list->plugins = realloc(list->plugins, + list->num_plugins * sizeof(struct _Plugin*)); + list->plugins[list->num_plugins-1] = new_plugin; + } + + rasqal_query_results_next(results); + } + + rasqal_free_query_results(results); + rasqal_free_query(rq); + raptor_free_uri(base_uri); + rasqal_finish(); + + free(manifest_uri); +} + + +/* Add all the plugins found in dir to list. + * (Private helper function, not exposed in public API) + */ +void +add_plugins_from_dir(SLV2List list, const char* dir) +{ + DIR* pdir = opendir(dir); + if (!pdir) + return; + + struct dirent* pfile; + while ((pfile = readdir(pdir))) { + if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, "..")) + continue; + + char* bundle_path = (char*)ustrjoin(U(dir), U("/"), U(pfile->d_name), 0); + char* bundle_url = (char*)ustrjoin(U("file://"), U(dir), U("/"), U(pfile->d_name), 0); + DIR* bundle_dir = opendir(bundle_path); + + if (bundle_dir != NULL) { + closedir(bundle_dir); + + slv2_list_load_bundle(list, U(bundle_url)); + //printf("Loaded bundle %s\n", bundle_url); + } + + free(bundle_path); + } + + closedir(pdir); +} + + +void +slv2_list_load_path(SLV2List list, + const char* slv2_path) +{ + + char* path = (char*)ustrjoin(U(slv2_path), U(":"), 0); + + char* dir = path; // Pointer into path + + // Go through string replacing ':' with '\0', using the substring, + // then replacing it with 'X' and moving on. eg strtok on crack. + while (strchr(path, ':') != NULL) { + char* delim = strchr(path, ':'); + *delim = '\0'; + + add_plugins_from_dir(list, dir); + + *delim = 'X'; + dir = delim + 1; + } + + //char* slv2_path = strdup(slv2 + + free(path); +} + + +unsigned long +slv2_list_get_length(const SLV2List list) +{ + assert(list != NULL); + return list->num_plugins; +} + + +SLV2Plugin* +slv2_list_get_plugin_by_uri(const SLV2List list, const unsigned char* uri) +{ + if (list->num_plugins > 0) { + assert(list->plugins != NULL); + + for (unsigned long i=0; i < list->num_plugins; ++i) + if (!strcmp((char*)list->plugins[i]->plugin_uri, (char*)uri)) + return list->plugins[i]; + } + + return NULL; +} + + +SLV2Plugin* +slv2_list_get_plugin_by_index(const SLV2List list, unsigned long index) +{ + if (list->num_plugins == 0) + return NULL; + + assert(list->plugins != NULL); + + return (index < list->num_plugins) ? list->plugins[index] : NULL; +} + diff --git a/src/port.c b/src/port.c new file mode 100644 index 0000000..e25eb2f --- /dev/null +++ b/src/port.c @@ -0,0 +1,163 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _XOPEN_SOURCE 500 +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <slv2/port.h> +#include <slv2/types.h> +#include <slv2/query.h> +#include "util.h" + +enum SLV2PortClass +slv2_port_get_class(SLV2Plugin* p, + unsigned long index) +{ + struct _Property* class = slv2_port_get_property(p, index, U("rdf:type")); + assert(class); + assert(class->num_values == 1); + assert(class->values); + + if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#InputControlRatePort")) + return SLV2_CONTROL_RATE_INPUT; + else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#OutputControlRatePort")) + return SLV2_CONTROL_RATE_OUTPUT; + else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#InputAudioRatePort")) + return SLV2_AUDIO_RATE_INPUT; + else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#OutputAudioRatePort")) + return SLV2_AUDIO_RATE_OUTPUT; + else + return SLV2_UNKNOWN_PORT_CLASS; +} + + +enum SLV2DataType +slv2_port_get_data_type(SLV2Plugin* p, + unsigned long index) +{ + SLV2Property type = slv2_port_get_property(p, index, U("lv2:datatype")); + assert(type); + assert(type->num_values == 1); + assert(type->values); + + if (!strcmp((char*)type->values[0], "http://lv2plug.in/ontology#float")) + return SLV2_DATA_TYPE_FLOAT; + else + return SLV2_UNKNOWN_DATA_TYPE; +} + + +SLV2Property +slv2_port_get_property(SLV2Plugin* p, + unsigned long index, + const uchar* property) +{ + assert(p); + assert(property); + + char index_str[4]; + snprintf(index_str, 4, "%ld", index); + + rasqal_init(); + + rasqal_query_results* results = slv2_plugin_run_query(p, + U("SELECT DISTINCT ?value FROM data: WHERE { \n" + "plugin: lv2:port ?port \n" + "?port lv2:index "), index_str, U(" \n" + "?port "), property, U(" ?value . \n}\n"), 0); + + SLV2Property result = slv2_query_get_results(results); + + rasqal_free_query_results(results); + rasqal_finish(); + + return result; +} + + +uchar* +slv2_port_get_symbol(SLV2Plugin* p, unsigned long index) +{ + // FIXME: leaks + uchar* result = NULL; + + SLV2Property prop + = slv2_port_get_property(p, index, U("lv2:symbol")); + + if (prop && prop->num_values == 1) + result = (uchar*)strdup((char*)prop->values[0]); + free(prop); + + return result; +} + + +float +slv2_port_get_default_value(SLV2Plugin* p, + unsigned long index) +{ + // FIXME: do casting properly in the SPARQL query + + float result = 0.0f; + + SLV2Property prop + = slv2_port_get_property(p, index, U("lv2:default")); + + if (prop && prop->num_values == 1) + result = atof((char*)prop->values[0]); + + return result; +} + + +float +slv2_port_get_minimum_value(SLV2Plugin* p, + unsigned long index) +{ + // FIXME: do casting properly in the SPARQL query + + float result = 0.0f; + + SLV2Property prop + = slv2_port_get_property(p, index, U("lv2:minimum")); + + if (prop && prop->num_values == 1) + result = atof((char*)prop->values[0]); + + return result; +} + + +float +slv2_port_get_maximum_value(SLV2Plugin* p, + unsigned long index) +{ + // FIXME: do casting properly in the SPARQL query + + float result = 0.0f; + + SLV2Property prop + = slv2_port_get_property(p, index, U("lv2:maximum")); + + if (prop && prop->num_values == 1) + result = atof((char*)prop->values[0]); + + return result; +} + diff --git a/src/query.c b/src/query.c new file mode 100644 index 0000000..2030735 --- /dev/null +++ b/src/query.c @@ -0,0 +1,123 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <util.h> +#include <stdlib.h> +#include <assert.h> +#include <slv2/plugin.h> +#include <slv2/query.h> + + +unsigned char* +slv2_query_header(const SLV2Plugin* p) +{ + const unsigned char* plugin_uri = slv2_plugin_get_uri(p); + const unsigned char* data_file_url = slv2_plugin_get_data_url(p); + + unsigned char* query_string = ustrjoin(U( + "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n" + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n" + "PREFIX doap: <http://usefulinc.com/ns/doap#> \n" + "PREFIX lv2: <http://lv2plug.in/ontology#> \n" + "PREFIX plugin: <"), plugin_uri, U("> \n"), + U("PREFIX data: <"), data_file_url, U("> \n\n"), 0); + + return query_string; +} + + +unsigned char* +slv2_query_lang_filter(const uchar* variable) +{ + uchar* result = NULL; + uchar* const lang = (uchar*)getenv("LANG"); + if (lang) { + // FILTER( LANG(?value) = "en" || LANG(?value) = "" ) + result = ustrjoin( + //U("FILTER (lang(?value) = \""), lang, U("\")\n"), 0); + U("FILTER( lang(?value) = \""), lang, + U("\" || lang(?value) = \"\" )\n"), 0); + } + + return result; +} + + +rasqal_query_results* +slv2_plugin_run_query(const SLV2Plugin* p, + const uchar* first, ...) +{ + va_list args_list; + va_start(args_list, first); + va_list args_copy; + va_copy(args_copy, args_list); + + /* FIXME: Too much unecessary allocation */ + uchar* header = slv2_query_header(p); + uchar* args_str = vstrjoin(first, args_copy); + uchar* query_str = ustrjoin(header, args_str, 0); + + assert(p); + assert(query_str); + + rasqal_query *rq = rasqal_new_query("sparql", NULL); + + //printf("Query: \n%s\n\n", query_str); + + rasqal_query_prepare(rq, query_str, NULL); + rasqal_query_results* results = rasqal_query_execute(rq); + + rasqal_free_query(rq); + + free(query_str); + free(args_str); + free(header); + + return results; +} + + +SLV2Property +slv2_query_get_results(rasqal_query_results* results) +{ + struct _Property* result = NULL; + + if (rasqal_query_results_get_count(results) > 0) { + result = malloc(sizeof(struct _Property)); + result->num_values = 0; + result->values = NULL; + } + + while (!rasqal_query_results_finished(results)) { + + rasqal_literal* literal = + rasqal_query_results_get_binding_value_by_name(results, U("value")); + assert(literal != NULL); + + // Add value on to the array. Yes, this is disgusting. + result->num_values++; + // FIXME LEAK: + result->values = realloc(result->values, result->num_values * sizeof(char*)); + result->values[result->num_values-1] = ustrdup(rasqal_literal_as_string(literal)); + + rasqal_query_results_next(results); + } + + return result; +} + diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..55953b8 --- /dev/null +++ b/src/util.c @@ -0,0 +1,121 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _XOPEN_SOURCE 500 + +#include <util.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <stdarg.h> + + +void +ustrappend(uchar** dst, const uchar* suffix) +{ + assert(dst); + assert(*dst); + assert(suffix); + + const size_t new_length = strlen((char*)*dst) + strlen((char*)suffix) + 1; + *dst = realloc(*dst, (new_length * sizeof(char))); + assert(dst); + strcat((char*)*dst, (char*)suffix); +} + + +uchar* +ustrdup(const uchar* src) +{ + assert(src); + return (uchar*)strdup((char*)src); +} + + +uchar* +ustrjoin(const uchar* first, ...) +{ + // FIXME: this is horribly, awfully, disgracefully slow + + va_list args_list; + va_start(args_list, first); + + va_list args_copy; + va_copy(args_copy, args_list); + + uchar* result = vstrjoin(first, args_copy); + + //va_end(args_copy); + va_end(args_list); + + return result; + + /* + va_list args_list; + uchar* arg = NULL; + uchar* result = ustrdup(first); + + va_start(args_list, first); + + while ((arg = va_arg(args_list, uchar*)) != (uchar*)0) + ustrappend(&result, arg); + + va_end(args_list); + + return result;*/ +} + + +uchar* +vstrjoin(const uchar* first, va_list args_list) +{ + // FIXME: this is horribly, awfully, disgracefully slow + + uchar* arg = NULL; + uchar* result = ustrdup(first); + + while ((arg = va_arg(args_list, uchar*)) != NULL) + ustrappend(&result, arg); + + va_end(args_list); + + return result; +} + + + +/** Convert a URL to a local filesystem path (ie by chopping off the + * leading "file://". + * + * Returns NULL if URL is not a valid URL on the local filesystem. + * Result is simply a pointer in to \a url and must not be free()'d. + */ +const char* +url2path(const uchar* const url) +{ + /*assert(strlen((char*)url) > 8); + char* result = calloc(strlen((char*)url)-7+1, sizeof(char)); + strcpy(result, (char*)url+7); + return result;*/ + if (!strncmp((char*)url, "file://", 7)) + return (char*)url + 7; + else + return NULL; +} + + diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..dbb7801 --- /dev/null +++ b/src/util.h @@ -0,0 +1,53 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __UTIL_H +#define __UTIL_H + +#include <stdarg.h> +#include <slv2/types.h> + +/* Cast a char* to an unsigned char* (Used for string literals) */ +#define U(x) (unsigned char*)(x) + +/** Append \a suffix to \a *dst, reallocating \a dst as necessary. + * + * \a dst will (possibly) be freed, it must be dynamically allocated with malloc + * or NULL. + */ +void +ustrappend(uchar** dst, const uchar* suffix); + +uchar* +ustrdup(const uchar* src); + +/** Join all arguments into one string. + * + * Arguments are not modified, return value must be free()'d. + */ +uchar* +ustrjoin(const uchar* first, ...); + +uchar* +vstrjoin(const uchar* first, va_list args_list); + +const char* +url2path(const uchar* const url); + + +#endif |