Merge pull request #78 from jpcima/midnam
Add the MIDNAM API, and the LV2 extension
This commit is contained in:
commit
3bfa573dc2
16 changed files with 15057 additions and 4 deletions
|
|
@ -48,6 +48,9 @@ else()
|
|||
target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_LIBRARIES})
|
||||
endif()
|
||||
|
||||
add_library(sfizz-pugixml STATIC "src/external/pugixml/src/pugixml.cpp")
|
||||
target_include_directories(sfizz-pugixml PUBLIC "src/external/pugixml/src")
|
||||
|
||||
# If we build with Clang use libc++
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT ANDROID)
|
||||
set(USE_LIBCPP ON CACHE BOOL "Use libc++ with clang")
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ set (LV2PLUGIN_TTL_SRC_FILES
|
|||
)
|
||||
add_library (${LV2PLUGIN_PRJ_NAME} SHARED ${PROJECT_NAME}.c ${LV2PLUGIN_TTL_SRC_FILES})
|
||||
target_link_libraries (${LV2PLUGIN_PRJ_NAME} ${PROJECT_NAME}::${PROJECT_NAME})
|
||||
target_include_directories(${LV2PLUGIN_PRJ_NAME} PRIVATE .)
|
||||
target_include_directories(${LV2PLUGIN_PRJ_NAME} PRIVATE . external/ardour)
|
||||
sfizz_enable_lto_if_needed (${LV2PLUGIN_PRJ_NAME})
|
||||
|
||||
# Remove the "lib" prefix, rename the target name and build it in the .lv build dir
|
||||
|
|
|
|||
64
lv2/atomic_compat.h
Normal file
64
lv2/atomic_compat.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
SPDX-License-Identifier: ISC
|
||||
|
||||
Sfizz LV2 plugin
|
||||
|
||||
Copyright 2019-2020, Paul Ferrand <paul@ferrand.cc>
|
||||
|
||||
This file was based on skeleton and example code from the LV2 plugin
|
||||
distribution available at http://lv2plug.in/
|
||||
|
||||
The LV2 sample plugins have the following copyright and notice, which are
|
||||
extended to the current work:
|
||||
Copyright 2011-2016 David Robillard <d@drobilla.net>
|
||||
Copyright 2011 Gabriel M. Beddingfield <gabriel@teuton.org>
|
||||
Copyright 2011 James Morris <jwm.art.net@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
Compiling this plugin statically against libsndfile implies distributing it
|
||||
under the terms of the LGPL v3 license. See the LICENSE.md file for more
|
||||
information. If you did not receive a LICENSE.md file, inform the current
|
||||
maintainer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
typedef volatile int atomic_int;
|
||||
|
||||
inline int atomic_exchange(atomic_int *d, int x)
|
||||
{
|
||||
return _InterlockedExchange((volatile long *)d, (long)x);
|
||||
}
|
||||
|
||||
inline void atomic_store(atomic_int *d, int x)
|
||||
{
|
||||
_InterlockedExchange((volatile long *)d, (long)x);
|
||||
}
|
||||
|
||||
inline int atomic_load(const atomic_int *d)
|
||||
{
|
||||
return _InterlockedOr((volatile long *)d, 0);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#endif
|
||||
282
lv2/external/ardour/ardour/lv2_extensions.h
vendored
Normal file
282
lv2/external/ardour/ardour/lv2_extensions.h
vendored
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
Copyright 2016 Robin Gareus <robin@gareus.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _ardour_lv2_extensions_h_
|
||||
#define _ardour_lv2_extensions_h_
|
||||
|
||||
#include "lv2/core/lv2.h"
|
||||
|
||||
/**
|
||||
@defgroup lv2inlinedisplay Inline-Display
|
||||
|
||||
Support for displaying a miniaturized generic view
|
||||
directly in the host's Mixer Window.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#define LV2_INLINEDISPLAY_URI "http://harrisonconsoles.com/lv2/inlinedisplay"
|
||||
#define LV2_INLINEDISPLAY_PREFIX LV2_INLINEDISPLAY_URI "#"
|
||||
#define LV2_INLINEDISPLAY__interface LV2_INLINEDISPLAY_PREFIX "interface"
|
||||
#define LV2_INLINEDISPLAY__queue_draw LV2_INLINEDISPLAY_PREFIX "queue_draw"
|
||||
#define LV2_INLINEDISPLAY__in_gui LV2_INLINEDISPLAY_PREFIX "in_gui"
|
||||
|
||||
/** Opaque handle for LV2_Inline_Display::queue_draw() */
|
||||
typedef void* LV2_Inline_Display_Handle;
|
||||
|
||||
/** raw image pixmap format is ARGB32,
|
||||
* the data pointer is owned by the plugin and must be valid
|
||||
* from the first call to render until cleanup.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char *data;
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
} LV2_Inline_Display_Image_Surface;
|
||||
|
||||
/** a LV2 Feature provided by the Host to the plugin */
|
||||
typedef struct {
|
||||
/** Opaque host data */
|
||||
LV2_Inline_Display_Handle handle;
|
||||
/** Request from run() that the host should call render() at a later time
|
||||
* to update the inline display */
|
||||
void (*queue_draw)(LV2_Inline_Display_Handle handle);
|
||||
} LV2_Inline_Display;
|
||||
|
||||
/**
|
||||
* Plugin Inline-Display Interface.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* The render method. This is called by the host in a non-realtime context,
|
||||
* usually the main GUI thread.
|
||||
* The data pointer is owned by the plugin and must be valid
|
||||
* from the first call to render until cleanup.
|
||||
*
|
||||
* @param instance The LV2 instance
|
||||
* @param w the max available width
|
||||
* @param h the max available height
|
||||
* @return pointer to a LV2_Inline_Display_Image_Surface or NULL
|
||||
*/
|
||||
LV2_Inline_Display_Image_Surface* (*render)(LV2_Handle instance, uint32_t w, uint32_t h);
|
||||
} LV2_Inline_Display_Interface;
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup lv2automate Self-Automation
|
||||
|
||||
Support for plugins to write automation data via Atom Events
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#define LV2_AUTOMATE_URI "http://ardour.org/lv2/automate"
|
||||
#define LV2_AUTOMATE_URI_PREFIX LV2_AUTOMATE_URI "#"
|
||||
/** an lv2:optionalFeature */
|
||||
#define LV2_AUTOMATE_URI__can_write LV2_AUTOMATE_URI_PREFIX "canWriteAutomatation"
|
||||
/** atom:supports */
|
||||
#define LV2_AUTOMATE_URI__control LV2_AUTOMATE_URI_PREFIX "automationControl"
|
||||
/** lv2:portProperty */
|
||||
#define LV2_AUTOMATE_URI__controlled LV2_AUTOMATE_URI_PREFIX "automationControlled"
|
||||
#define LV2_AUTOMATE_URI__controller LV2_AUTOMATE_URI_PREFIX "automationController"
|
||||
|
||||
/** atom messages */
|
||||
#define LV2_AUTOMATE_URI__event LV2_AUTOMATE_URI_PREFIX "event"
|
||||
#define LV2_AUTOMATE_URI__setup LV2_AUTOMATE_URI_PREFIX "setup"
|
||||
#define LV2_AUTOMATE_URI__finalize LV2_AUTOMATE_URI_PREFIX "finalize"
|
||||
#define LV2_AUTOMATE_URI__start LV2_AUTOMATE_URI_PREFIX "start"
|
||||
#define LV2_AUTOMATE_URI__end LV2_AUTOMATE_URI_PREFIX "end"
|
||||
#define LV2_AUTOMATE_URI__parameter LV2_AUTOMATE_URI_PREFIX "parameter"
|
||||
#define LV2_AUTOMATE_URI__value LV2_AUTOMATE_URI_PREFIX "value"
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup lv2license License-Report
|
||||
|
||||
Allow for commercial LV2 to report their
|
||||
licensing status.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#define LV2_PLUGINLICENSE_URI "http://harrisonconsoles.com/lv2/license"
|
||||
#define LV2_PLUGINLICENSE_PREFIX LV2_PLUGINLICENSE_URI "#"
|
||||
#define LV2_PLUGINLICENSE__interface LV2_PLUGINLICENSE_PREFIX "interface"
|
||||
#define LV2_PLUGINLICENSE__interface2 LV2_PLUGINLICENSE_PREFIX "interface2"
|
||||
|
||||
|
||||
typedef struct _LV2_License_Interface {
|
||||
/* @return -1 if no license is needed; 0 if unlicensed, 1 if licensed */
|
||||
int (*is_licensed)(LV2_Handle instance);
|
||||
/* @return a string copy of the licensee name if licensed, or NULL, the caller needs to free this */
|
||||
char* (*licensee)(LV2_Handle instance);
|
||||
/* @return a URI identifying the plugin-bundle or plugin for which a given license is valid */
|
||||
const char* (*product_uri)(LV2_Handle instance);
|
||||
/* @return human readable product name for the URI */
|
||||
const char* (*product_name)(LV2_Handle instance);
|
||||
/* @return link to website or webstore */
|
||||
const char* (*store_url)(LV2_Handle instance);
|
||||
/* interface2 ext: preferred location to install the license file, the caller needs to free this */
|
||||
char* (*preferred_license_file_path)(LV2_Handle instance);
|
||||
/* interface2 ext: currently used license file (if any, may be NULL), the caller needs to free this */
|
||||
char* (*current_license_file_path)(LV2_Handle instance);
|
||||
/* interface2 ext: free() allocated strings (licensee, license_file_paths) */
|
||||
void (*free)(char*);
|
||||
} LV2_License_Interface;
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup lv2bypass Plugin-provided bypass
|
||||
|
||||
A port with the designation "processing#enable" must
|
||||
control a plugin's internal bypass mode.
|
||||
|
||||
If the port value is larger than zero the plugin processes
|
||||
normally.
|
||||
|
||||
If the port value is zero, the plugin is expected to bypass
|
||||
all signals unmodified.
|
||||
|
||||
The plugin is responsible for providing a click-free transition
|
||||
between the states.
|
||||
|
||||
(values less than zero are reserved for future use:
|
||||
e.g click-free insert/removal of latent plugins.
|
||||
Generally values <= 0 are to be treated as bypassed.)
|
||||
|
||||
lv2:designation <http://ardour.org/lv2/processing#enable> ;
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#define LV2_PROCESSING_URI "http://ardour.org/lv2/processing"
|
||||
#define LV2_PROCESSING_URI_PREFIX LV2_PROCESSING_URI "#"
|
||||
#define LV2_PROCESSING_URI__enable LV2_PROCESSING_URI_PREFIX "enable"
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
@defgroup lv2routing plugin port/routing control
|
||||
|
||||
This is a "feature" to simplify per port meta-data of
|
||||
http://lv2plug.in/ns/ext/port-groups/port-groups.html#source
|
||||
|
||||
Plugins using this feature provide a strong hint that the host
|
||||
should always connect all audio output-ports.
|
||||
|
||||
This allows mono->stereo plugins to override strict_io rules.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#define LV2_ROUTING_URI "http://harrisonconsoles.com/lv2/routing"
|
||||
#define LV2_ROUTING_PREFIX LV2_ROUTING_URI "#"
|
||||
#define LV2_ROUTING__connectAllOutputs LV2_ROUTING_PREFIX "connectAllOutputs"
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup lv2midnam MIDI Naming
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
|
||||
#define LV2_MIDNAM_URI "http://ardour.org/lv2/midnam"
|
||||
#define LV2_MIDNAM_PREFIX LV2_MIDNAM_URI "#"
|
||||
#define LV2_MIDNAM__interface LV2_MIDNAM_PREFIX "interface"
|
||||
#define LV2_MIDNAM__update LV2_MIDNAM_PREFIX "update"
|
||||
|
||||
typedef void* LV2_Midnam_Handle;
|
||||
|
||||
/** a LV2 Feature provided by the Host to the plugin */
|
||||
typedef struct {
|
||||
/** Opaque host data */
|
||||
LV2_Midnam_Handle handle;
|
||||
/** Request from run() that the host should re-read the midnam */
|
||||
void (*update)(LV2_Midnam_Handle handle);
|
||||
} LV2_Midnam;
|
||||
|
||||
typedef struct {
|
||||
/** Query midnam document. The plugin
|
||||
* is expected to return a null-terminated XML
|
||||
* text which is a valid midnam desciption
|
||||
* (or NULL in case of error).
|
||||
*
|
||||
* The midnam \<Model\> must be unique and
|
||||
* specific for the given plugin-instance.
|
||||
*/
|
||||
char* (*midnam)(LV2_Handle instance);
|
||||
|
||||
/** The unique model id used ith the midnam,
|
||||
* (or NULL).
|
||||
*/
|
||||
char* (*model)(LV2_Handle instance);
|
||||
|
||||
/** free allocated strings. The host
|
||||
* calls this for every value returned by
|
||||
* \ref midnam and \ref model.
|
||||
*/
|
||||
void (*free)(char*);
|
||||
} LV2_Midnam_Interface;
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup lv2bankpatch MIDI Bank/Patch Notifications
|
||||
|
||||
LV2 extension to allow a synth to inform a host about the
|
||||
currentl used MIDI bank/program.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
|
||||
#define LV2_BANKPATCH_URI "http://ardour.org/lv2/bankpatch"
|
||||
#define LV2_BANKPATCH_PREFIX LV2_BANKPATCH_URI "#"
|
||||
#define LV2_BANKPATCH__notify LV2_BANKPATCH_PREFIX "notify"
|
||||
|
||||
typedef void* LV2_BankPatch_Handle;
|
||||
|
||||
/** a LV2 Feature provided by the Host to the plugin */
|
||||
typedef struct {
|
||||
/** Opaque host data */
|
||||
LV2_BankPatch_Handle handle;
|
||||
/** Info from plugin's run(), notify host that bank/program changed */
|
||||
void (*notify)(LV2_BankPatch_Handle handle, uint8_t channel, uint32_t bank, uint8_t pgm);
|
||||
} LV2_BankPatch;
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
#endif
|
||||
50
lv2/sfizz.c
50
lv2/sfizz.c
|
|
@ -47,12 +47,16 @@
|
|||
#include <lv2/log/logger.h>
|
||||
#include <lv2/log/log.h>
|
||||
|
||||
#include <ardour/lv2_extensions.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <sfizz.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "atomic_compat.h"
|
||||
|
||||
#define DEFAULT_SFZ_FILE "/home/paul/Documents/AVL_Percussions/AVL_Drumkits_Percussion-1.0-Alt.sfz"
|
||||
#define SFIZZ_URI "http://sfztools.github.io/sfizz"
|
||||
#define SFIZZ_PREFIX SFIZZ_URI "#"
|
||||
|
|
@ -90,6 +94,7 @@ typedef struct
|
|||
LV2_URID_Unmap *unmap;
|
||||
LV2_Worker_Schedule *worker;
|
||||
LV2_Log_Log *log;
|
||||
LV2_Midnam *midnam;
|
||||
|
||||
// Ports
|
||||
const LV2_Atom_Sequence *control_port;
|
||||
|
|
@ -145,6 +150,7 @@ typedef struct
|
|||
int max_block_size;
|
||||
int sample_counter;
|
||||
float sample_rate;
|
||||
atomic_int must_update_midnam;
|
||||
} sfizz_plugin_t;
|
||||
|
||||
enum
|
||||
|
|
@ -310,6 +316,9 @@ instantiate(const LV2_Descriptor *descriptor,
|
|||
|
||||
if (!strcmp((**f).URI, LV2_LOG__log))
|
||||
self->log = (**f).data;
|
||||
|
||||
if (!strcmp((**f).URI, LV2_MIDNAM__update))
|
||||
self->midnam = (**f).data;
|
||||
}
|
||||
|
||||
// Setup the loggers
|
||||
|
|
@ -684,6 +693,11 @@ run(LV2_Handle instance, uint32_t sample_count)
|
|||
|
||||
// Render the block
|
||||
sfizz_render_block(self->synth, self->output_buffers, 2, (int)sample_count);
|
||||
|
||||
if (self->midnam && atomic_exchange(&self->must_update_midnam, 0))
|
||||
{
|
||||
self->midnam->update(self->midnam->handle);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
|
|
@ -770,6 +784,8 @@ sfizz_lv2_update_file_info(sfizz_plugin_t* self, const char* file_path)
|
|||
lv2_log_note(&self->logger, "[sfizz] Number of masters: %d\n", sfizz_get_num_masters(self->synth));
|
||||
lv2_log_note(&self->logger, "[sfizz] Number of groups: %d\n", sfizz_get_num_groups(self->synth));
|
||||
lv2_log_note(&self->logger, "[sfizz] Number of regions: %d\n", sfizz_get_num_regions(self->synth));
|
||||
|
||||
atomic_store(&self->must_update_midnam, 1);
|
||||
}
|
||||
|
||||
static LV2_State_Status
|
||||
|
|
@ -1066,12 +1082,44 @@ work_response(LV2_Handle instance,
|
|||
return LV2_WORKER_SUCCESS;
|
||||
}
|
||||
|
||||
static char *
|
||||
midnam_model(LV2_Handle instance)
|
||||
{
|
||||
char *model = malloc(64);
|
||||
if (!model)
|
||||
return NULL;
|
||||
|
||||
sprintf(model, "Sfizz LV2:%p", instance);
|
||||
return model;
|
||||
}
|
||||
|
||||
static char *
|
||||
midnam_export(LV2_Handle instance)
|
||||
{
|
||||
sfizz_plugin_t *self = (sfizz_plugin_t *)instance;
|
||||
|
||||
char *model = midnam_model(instance);
|
||||
if (!model)
|
||||
return NULL;
|
||||
|
||||
char *xml = sfizz_export_midnam(self->synth, model);
|
||||
free(model);
|
||||
return xml;
|
||||
}
|
||||
|
||||
static void
|
||||
midnam_free(char *string)
|
||||
{
|
||||
free(string);
|
||||
}
|
||||
|
||||
static const void *
|
||||
extension_data(const char *uri)
|
||||
{
|
||||
static const LV2_Options_Interface options = {lv2_get_options, lv2_set_options};
|
||||
static const LV2_State_Interface state = {save, restore};
|
||||
static const LV2_Worker_Interface worker = {work, work_response, NULL};
|
||||
static const LV2_Midnam_Interface midnam = {midnam_export, midnam_model, midnam_free};
|
||||
|
||||
// Advertise the extensions we support
|
||||
if (!strcmp(uri, LV2_OPTIONS__interface))
|
||||
|
|
@ -1080,6 +1128,8 @@ extension_data(const char *uri)
|
|||
return &state;
|
||||
else if (!strcmp(uri, LV2_WORKER__interface))
|
||||
return &worker;
|
||||
else if (!strcmp(uri, LV2_MIDNAM__interface))
|
||||
return &midnam;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
|
||||
@prefix opts: <http://lv2plug.in/ns/ext/options#> .
|
||||
@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
|
||||
@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
|
||||
@prefix pg: <http://lv2plug.in/ns/ext/port-groups#> .
|
||||
@prefix pprop: <http://lv2plug.in/ns/ext/port-props#> .
|
||||
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||
|
|
@ -14,6 +14,10 @@
|
|||
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
|
||||
@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
|
||||
@prefix work: <http://lv2plug.in/ns/ext/worker#> .
|
||||
@prefix midnam: <http://ardour.org/lv2/midnam#> .
|
||||
|
||||
midnam:interface a lv2:ExtensionData .
|
||||
midnam:update a lv2:Feature .
|
||||
|
||||
<#config>
|
||||
a pg:Group ;
|
||||
|
|
@ -65,6 +69,9 @@
|
|||
lv2:optionalFeature lv2:hardRTCapable, opts:options ;
|
||||
lv2:extensionData opts:interface, state:interface, work:interface ;
|
||||
|
||||
lv2:optionalFeature midnam:update ;
|
||||
lv2:extensionData midnam:interface ;
|
||||
|
||||
patch:writable <@LV2PLUGIN_URI@:sfzfile> ;
|
||||
|
||||
lv2:port [
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ target_sources(sfizz_static PRIVATE ${SFIZZ_SOURCES} sfizz/sfizz_wrapper.cpp)
|
|||
target_include_directories (sfizz_static PUBLIC .)
|
||||
target_include_directories (sfizz_static PUBLIC external)
|
||||
target_link_libraries (sfizz_static PUBLIC absl::strings absl::span)
|
||||
target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile)
|
||||
target_link_libraries (sfizz_static PRIVATE sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile sfizz-pugixml)
|
||||
|
||||
add_library (sfizz::parser ALIAS sfizz_parser)
|
||||
add_library (sfizz::sfizz ALIAS sfizz_static)
|
||||
|
|
@ -47,7 +47,7 @@ if (SFIZZ_SHARED)
|
|||
target_sources(sfizz_shared PRIVATE ${SFIZZ_SOURCES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp)
|
||||
target_include_directories (sfizz_shared PRIVATE .)
|
||||
target_include_directories (sfizz_static PRIVATE external)
|
||||
target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile)
|
||||
target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads sfizz-sndfile sfizz-pugixml)
|
||||
target_compile_definitions(sfizz_shared PRIVATE SFIZZ_EXPORT_SYMBOLS)
|
||||
set_target_properties (sfizz_shared PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp")
|
||||
set_property (TARGET sfizz_shared PROPERTY SOVERSION ${PROJECT_VERSION_MAJOR})
|
||||
|
|
|
|||
24
src/external/pugixml/LICENSE.md
vendored
Normal file
24
src/external/pugixml/LICENSE.md
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2006-2019 Arseny Kapoulkine
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
74
src/external/pugixml/src/pugiconfig.hpp
vendored
Normal file
74
src/external/pugixml/src/pugiconfig.hpp
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* pugixml parser - version 1.10
|
||||
* --------------------------------------------------------
|
||||
* Copyright (C) 2006-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||
* Report bugs and download new versions at https://pugixml.org/
|
||||
*
|
||||
* This library is distributed under the MIT License. See notice at the end
|
||||
* of this file.
|
||||
*
|
||||
* This work is based on the pugxml parser, which is:
|
||||
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
*/
|
||||
|
||||
#ifndef HEADER_PUGICONFIG_HPP
|
||||
#define HEADER_PUGICONFIG_HPP
|
||||
|
||||
// Uncomment this to enable wchar_t mode
|
||||
// #define PUGIXML_WCHAR_MODE
|
||||
|
||||
// Uncomment this to enable compact mode
|
||||
// #define PUGIXML_COMPACT
|
||||
|
||||
// Uncomment this to disable XPath
|
||||
// #define PUGIXML_NO_XPATH
|
||||
|
||||
// Uncomment this to disable STL
|
||||
// #define PUGIXML_NO_STL
|
||||
|
||||
// Uncomment this to disable exceptions
|
||||
// #define PUGIXML_NO_EXCEPTIONS
|
||||
|
||||
// Set this to control attributes for public classes/functions, i.e.:
|
||||
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||
|
||||
// Tune these constants to adjust memory-related behavior
|
||||
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||
|
||||
// Uncomment this to switch to header-only version
|
||||
// #define PUGIXML_HEADER_ONLY
|
||||
|
||||
// Uncomment this to enable long long support
|
||||
// #define PUGIXML_HAS_LONG_LONG
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copyright (c) 2006-2019 Arseny Kapoulkine
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
12948
src/external/pugixml/src/pugixml.cpp
vendored
Normal file
12948
src/external/pugixml/src/pugixml.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
1490
src/external/pugixml/src/pugixml.hpp
vendored
Normal file
1490
src/external/pugixml/src/pugixml.hpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
10
src/sfizz.h
10
src/sfizz.h
|
|
@ -94,6 +94,16 @@ SFIZZ_EXPORTED_API int sfizz_get_num_masters(sfizz_synth_t* synth);
|
|||
* @return int the number of curves
|
||||
*/
|
||||
SFIZZ_EXPORTED_API int sfizz_get_num_curves(sfizz_synth_t* synth);
|
||||
/**
|
||||
* @brief Export a MIDI Name document describing the the currently loaded
|
||||
* SFZ file.
|
||||
*
|
||||
* @param synth The synth
|
||||
* @param model the model name used if a non-empty string, otherwise generated
|
||||
*
|
||||
* @return char* a newly allocated XML string, which must be freed after use
|
||||
*/
|
||||
SFIZZ_EXPORTED_API char* sfizz_export_midnam(sfizz_synth_t* synth, const char* model);
|
||||
/**
|
||||
* @brief Returns the number of preloaded samples for the current SFZ file.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#endif
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#endif
|
||||
#include "absl/strings/string_view.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
|
|
@ -62,6 +63,11 @@ namespace config {
|
|||
modulated filter. The lower, the more CPU resources are consumed.
|
||||
*/
|
||||
constexpr int filterControlInterval { 16 };
|
||||
/**
|
||||
Default metadata for MIDIName documents
|
||||
*/
|
||||
const absl::string_view midnamManufacturer { "The Sfizz authors" };
|
||||
const absl::string_view midnamModel { "Sfizz" };
|
||||
} // namespace config
|
||||
|
||||
// Enable or disable SIMD accelerators by default
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "MidiState.h"
|
||||
#include "ScopedFTZ.h"
|
||||
#include "StringViewHelpers.h"
|
||||
#include "pugixml.hpp"
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include <algorithm>
|
||||
|
|
@ -577,6 +578,91 @@ int sfz::Synth::getNumCurves() const noexcept
|
|||
return numCurves;
|
||||
}
|
||||
|
||||
std::string sfz::Synth::exportMidnam(absl::string_view model) const
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
absl::string_view manufacturer = config::midnamManufacturer;
|
||||
|
||||
if (model.empty())
|
||||
model = config::midnamModel;
|
||||
|
||||
doc.append_child(pugi::node_doctype).set_value(
|
||||
"MIDINameDocument PUBLIC"
|
||||
" \"-//MIDI Manufacturers Association//DTD MIDINameDocument 1.0//EN\""
|
||||
" \"http://www.midi.org/dtds/MIDINameDocument10.dtd\"");
|
||||
|
||||
pugi::xml_node root = doc.append_child("MIDINameDocument");
|
||||
|
||||
root.append_child(pugi::node_comment)
|
||||
.set_value("Generated by Sfizz for the current instrument");
|
||||
|
||||
root.append_child("Author");
|
||||
|
||||
pugi::xml_node device = root.append_child("MasterDeviceNames");
|
||||
device.append_child("Manufacturer")
|
||||
.append_child(pugi::node_pcdata).set_value(std::string(manufacturer).c_str());
|
||||
device.append_child("Model")
|
||||
.append_child(pugi::node_pcdata).set_value(std::string(model).c_str());
|
||||
|
||||
{
|
||||
pugi::xml_node devmode = device.append_child("CustomDeviceMode");
|
||||
devmode.append_attribute("Name").set_value("Default");
|
||||
|
||||
pugi::xml_node nsas = devmode.append_child("ChannelNameSetAssignments");
|
||||
for (unsigned c = 0; c < 16; ++c) {
|
||||
pugi::xml_node nsa = nsas.append_child("ChannelNameSetAssign");
|
||||
nsa.append_attribute("Channel").set_value(std::to_string(c + 1).c_str());
|
||||
nsa.append_attribute("NameSet").set_value("Play");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
pugi::xml_node chns = device.append_child("ChannelNameSet");
|
||||
chns.append_attribute("Name").set_value("Play");
|
||||
|
||||
pugi::xml_node acs = chns.append_child("AvailableForChannels");
|
||||
for (unsigned c = 0; c < 16; ++c) {
|
||||
pugi::xml_node ac = acs.append_child("AvailableChannel");
|
||||
ac.append_attribute("Channel").set_value(std::to_string(c + 1).c_str());
|
||||
ac.append_attribute("Available").set_value("true");
|
||||
}
|
||||
|
||||
chns.append_child("UsesControlNameList")
|
||||
.append_attribute("Name").set_value("Controls");
|
||||
}
|
||||
|
||||
{
|
||||
pugi::xml_node cns = device.append_child("ControlNameList");
|
||||
cns.append_attribute("Name").set_value("Controls");
|
||||
for (const CCNamePair& pair : ccNames) {
|
||||
pugi::xml_node cn = cns.append_child("Control");
|
||||
cn.append_attribute("Type").set_value("7bit");
|
||||
cn.append_attribute("Number").set_value(std::to_string(pair.first).c_str());
|
||||
cn.append_attribute("Name").set_value(pair.second.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
struct string_writer : pugi::xml_writer {
|
||||
std::string result;
|
||||
|
||||
string_writer()
|
||||
{
|
||||
result.reserve(8192);
|
||||
}
|
||||
|
||||
void write(const void* data, size_t size) override
|
||||
{
|
||||
result.append(static_cast<const char*>(data), size);
|
||||
}
|
||||
};
|
||||
|
||||
///
|
||||
string_writer writer;
|
||||
doc.save(writer);
|
||||
return std::move(writer.result);
|
||||
}
|
||||
|
||||
const sfz::Region* sfz::Synth::getRegionView(int idx) const noexcept
|
||||
{
|
||||
return (size_t)idx < regions.size() ? regions[idx].get() : nullptr;
|
||||
|
|
|
|||
|
|
@ -111,6 +111,10 @@ public:
|
|||
* @return int
|
||||
*/
|
||||
int getNumCurves() const noexcept;
|
||||
/**
|
||||
* @brief Export a MIDI Name document describing the loaded instrument
|
||||
*/
|
||||
std::string exportMidnam(absl::string_view model = {}) const;
|
||||
/**
|
||||
* @brief Get a raw view into a specific region. This is mostly used
|
||||
* for testing.
|
||||
|
|
|
|||
|
|
@ -49,6 +49,11 @@ int sfizz_get_num_curves(sfizz_synth_t* synth)
|
|||
auto self = reinterpret_cast<sfz::Synth*>(synth);
|
||||
return self->getNumCurves();
|
||||
}
|
||||
char* sfizz_export_midnam(sfizz_synth_t* synth, const char* model)
|
||||
{
|
||||
auto self = reinterpret_cast<sfz::Synth*>(synth);
|
||||
return strdup(self->exportMidnam(model ? model : "").c_str());
|
||||
}
|
||||
size_t sfizz_get_num_preloaded_samples(sfizz_synth_t* synth)
|
||||
{
|
||||
auto self = reinterpret_cast<sfz::Synth*>(synth);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue