External for puredata
This commit is contained in:
parent
db869ed402
commit
4ef3824209
7 changed files with 395 additions and 0 deletions
|
|
@ -28,6 +28,7 @@ option_ex (SFIZZ_LV2_UI "Enable LV2 plug-in user interface" ON)
|
||||||
option_ex (SFIZZ_VST "Enable VST plug-in build" ON)
|
option_ex (SFIZZ_VST "Enable VST plug-in build" ON)
|
||||||
option_ex (SFIZZ_AU "Enable AU plug-in build" APPLE)
|
option_ex (SFIZZ_AU "Enable AU plug-in build" APPLE)
|
||||||
option_ex (SFIZZ_VST2 "Enable VST2 plug-in build (unsupported)" OFF)
|
option_ex (SFIZZ_VST2 "Enable VST2 plug-in build (unsupported)" OFF)
|
||||||
|
option_ex (SFIZZ_PUREDATA "Enable Puredata plug-in build" OFF)
|
||||||
option_ex (SFIZZ_BENCHMARKS "Enable benchmarks build" OFF)
|
option_ex (SFIZZ_BENCHMARKS "Enable benchmarks build" OFF)
|
||||||
option_ex (SFIZZ_TESTS "Enable tests build" OFF)
|
option_ex (SFIZZ_TESTS "Enable tests build" OFF)
|
||||||
option_ex (SFIZZ_DEMOS "Enable feature demos build" OFF)
|
option_ex (SFIZZ_DEMOS "Enable feature demos build" OFF)
|
||||||
|
|
|
||||||
15
cmake/PuredataConfig.cmake
Normal file
15
cmake/PuredataConfig.cmake
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
find_path(PUREDATA_INCLUDE_DIR "m_pd.h" PATH_SUFFIXES "pd")
|
||||||
|
|
||||||
|
if(NOT PUREDATA_INCLUDE_DIR)
|
||||||
|
message(FATAL_ERROR "Cannot find Puredata headers")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "Puredata headers: ${PUREDATA_INCLUDE_DIR}")
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(PUREDATA_SUFFIX ".dll")
|
||||||
|
elseif(APPLE)
|
||||||
|
set(PUREDATA_SUFFIX ".pd_darwin")
|
||||||
|
else()
|
||||||
|
set(PUREDATA_SUFFIX ".pd_linux")
|
||||||
|
endif()
|
||||||
|
|
@ -58,3 +58,7 @@ endif()
|
||||||
if(SFIZZ_VST OR SFIZZ_AU OR SFIZZ_VST2)
|
if(SFIZZ_VST OR SFIZZ_AU OR SFIZZ_VST2)
|
||||||
add_subdirectory(vst)
|
add_subdirectory(vst)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(SFIZZ_PUREDATA)
|
||||||
|
add_subdirectory(puredata)
|
||||||
|
endif()
|
||||||
|
|
|
||||||
38
plugins/puredata/CMakeLists.txt
Normal file
38
plugins/puredata/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
# Puredata plugin specific settings
|
||||||
|
include(PuredataConfig)
|
||||||
|
|
||||||
|
set(PUREDATA_BINARY_DIR "${PROJECT_BINARY_DIR}/pd/sfizz")
|
||||||
|
|
||||||
|
set(PUREDATA_RESOURCES
|
||||||
|
"sfizz~-help.pd"
|
||||||
|
"example.sfz")
|
||||||
|
|
||||||
|
function(copy_puredata_resources TARGET SOURCE_DIR DESTINATION_DIR)
|
||||||
|
set(_deps)
|
||||||
|
foreach(res ${PUREDATA_RESOURCES})
|
||||||
|
get_filename_component(_dir "${res}" DIRECTORY)
|
||||||
|
file(MAKE_DIRECTORY "${DESTINATION_DIR}/${_dir}")
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${DESTINATION_DIR}/${res}"
|
||||||
|
COMMAND "${CMAKE_COMMAND}" "-E" "copy"
|
||||||
|
"${SOURCE_DIR}/${res}" "${DESTINATION_DIR}/${res}"
|
||||||
|
DEPENDS "${SOURCE_DIR}/${res}")
|
||||||
|
list(APPEND _deps "${DESTINATION_DIR}/${res}")
|
||||||
|
endforeach()
|
||||||
|
add_custom_target("${TARGET}_puredata_resources" DEPENDS ${_deps})
|
||||||
|
add_dependencies("${TARGET}" "${TARGET}_puredata_resources")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
add_library(sfizz_puredata MODULE sfizz_puredata.c)
|
||||||
|
target_include_directories(sfizz_puredata PRIVATE "${PUREDATA_INCLUDE_DIR}")
|
||||||
|
target_link_libraries(sfizz_puredata PRIVATE sfizz::sfizz sfizz::spin_mutex)
|
||||||
|
|
||||||
|
set_target_properties(sfizz_puredata PROPERTIES
|
||||||
|
PREFIX ""
|
||||||
|
SUFFIX "${PUREDATA_SUFFIX}"
|
||||||
|
OUTPUT_NAME "sfizz"
|
||||||
|
LIBRARY_OUTPUT_DIRECTORY "${PUREDATA_BINARY_DIR}/$<0:>")
|
||||||
|
|
||||||
|
copy_puredata_resources(sfizz_puredata
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
"${PUREDATA_BINARY_DIR}")
|
||||||
22
plugins/puredata/example.sfz
Normal file
22
plugins/puredata/example.sfz
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<group>
|
||||||
|
ampeg_attack=0.25
|
||||||
|
ampeg_decay=5
|
||||||
|
ampeg_sustain=50
|
||||||
|
ampeg_release=2
|
||||||
|
fil_type=lpf_4p
|
||||||
|
resonance=3
|
||||||
|
cutoff=2000
|
||||||
|
oscillator_phase=-1
|
||||||
|
cutoff_oncc300=3600
|
||||||
|
cutoff_curvecc300=1
|
||||||
|
|
||||||
|
<region>
|
||||||
|
sample=*saw
|
||||||
|
oscillator_multi=3
|
||||||
|
oscillator_detune=10
|
||||||
|
lfo1_freq=5
|
||||||
|
lfo1_pitch=30
|
||||||
|
|
||||||
|
<region>
|
||||||
|
sample=*triangle
|
||||||
|
transpose=-12
|
||||||
269
plugins/puredata/sfizz_puredata.c
Normal file
269
plugins/puredata/sfizz_puredata.c
Normal file
|
|
@ -0,0 +1,269 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
#include <m_pd.h>
|
||||||
|
#include <sfizz.h>
|
||||||
|
#include <spin_mutex.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
static t_class* cls_sfizz_tilde;
|
||||||
|
|
||||||
|
typedef struct _sfizz_tilde {
|
||||||
|
t_object obj;
|
||||||
|
t_outlet* outputs[2];
|
||||||
|
sfizz_synth_t* synth;
|
||||||
|
spin_mutex_t* mutex;
|
||||||
|
int midi[3];
|
||||||
|
int midinum;
|
||||||
|
t_symbol* dir;
|
||||||
|
char* filepath;
|
||||||
|
} t_sfizz_tilde;
|
||||||
|
|
||||||
|
static void sfizz_tilde_set_file(t_sfizz_tilde* self, const char* file)
|
||||||
|
{
|
||||||
|
const char* dir = self->dir->s_name;
|
||||||
|
char* filepath;
|
||||||
|
if (file[0] != '\0') {
|
||||||
|
filepath = malloc(strlen(dir) + 1 + strlen(file) + 1);
|
||||||
|
sprintf(filepath, "%s/%s", dir, file);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
filepath = malloc(1);
|
||||||
|
*filepath = '\0';
|
||||||
|
}
|
||||||
|
free(self->filepath);
|
||||||
|
self->filepath = filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sfizz_tilde_do_load(t_sfizz_tilde* self)
|
||||||
|
{
|
||||||
|
bool loaded;
|
||||||
|
spin_mutex_lock(self->mutex);
|
||||||
|
if (self->filepath[0] != '\0')
|
||||||
|
loaded = sfizz_load_file(self->synth, self->filepath);
|
||||||
|
else
|
||||||
|
loaded = sfizz_load_string(self->synth, "default.sfz", "<region>sample=*sine");
|
||||||
|
spin_mutex_unlock(self->mutex);
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* sfizz_tilde_new(t_symbol* sym, int argc, t_atom argv[])
|
||||||
|
{
|
||||||
|
(void)sym;
|
||||||
|
t_sfizz_tilde* self = (t_sfizz_tilde*)pd_new(cls_sfizz_tilde);
|
||||||
|
|
||||||
|
const char* file;
|
||||||
|
if (argc == 0)
|
||||||
|
file = "";
|
||||||
|
else if (argc == 1 && argv[0].a_type == A_SYMBOL)
|
||||||
|
file = argv[0].a_w.w_symbol->s_name;
|
||||||
|
else {
|
||||||
|
pd_free((t_pd*)self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->dir = canvas_getcurrentdir();
|
||||||
|
|
||||||
|
self->outputs[0] = outlet_new(&self->obj, &s_signal);
|
||||||
|
self->outputs[1] = outlet_new(&self->obj, &s_signal);
|
||||||
|
|
||||||
|
sfizz_synth_t* synth = sfizz_create_synth();
|
||||||
|
self->synth = synth;
|
||||||
|
|
||||||
|
self->mutex = spin_mutex_create();
|
||||||
|
|
||||||
|
sfizz_set_sample_rate(synth, sys_getsr());
|
||||||
|
sfizz_set_samples_per_block(synth, sys_getblksize());
|
||||||
|
|
||||||
|
sfizz_tilde_set_file(self, file);
|
||||||
|
if (!sfizz_tilde_do_load(self)) {
|
||||||
|
pd_free((t_pd*)self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sfizz_tilde_free(t_sfizz_tilde* self)
|
||||||
|
{
|
||||||
|
if (self->filepath)
|
||||||
|
free(self->filepath);
|
||||||
|
if (self->synth)
|
||||||
|
sfizz_free(self->synth);
|
||||||
|
if (self->mutex)
|
||||||
|
spin_mutex_destroy(self->mutex);
|
||||||
|
if (self->outputs[0])
|
||||||
|
outlet_free(self->outputs[0]);
|
||||||
|
if (self->outputs[1])
|
||||||
|
outlet_free(self->outputs[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_int* sfizz_tilde_perform(t_int* w)
|
||||||
|
{
|
||||||
|
t_sfizz_tilde* self;
|
||||||
|
t_sample* outputs[2];
|
||||||
|
t_int nframes;
|
||||||
|
|
||||||
|
w++;
|
||||||
|
self = (t_sfizz_tilde*)*w++;
|
||||||
|
outputs[0] = (t_sample*)*w++;
|
||||||
|
outputs[1] = (t_sample*)*w++;
|
||||||
|
nframes = (t_int)*w++;
|
||||||
|
|
||||||
|
if (spin_mutex_trylock(self->mutex)) {
|
||||||
|
sfizz_render_block(self->synth, outputs, 2, nframes);
|
||||||
|
spin_mutex_unlock(self->mutex);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memset(outputs[0], 0, nframes * sizeof(t_sample));
|
||||||
|
memset(outputs[1], 0, nframes * sizeof(t_sample));
|
||||||
|
}
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sfizz_tilde_dsp(t_sfizz_tilde* self, t_signal** sp)
|
||||||
|
{
|
||||||
|
dsp_add(
|
||||||
|
&sfizz_tilde_perform, 4, (t_int)self,
|
||||||
|
(t_int)sp[0]->s_vec, (t_int)sp[1]->s_vec, (t_int)sp[0]->s_n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sfizz_tilde_midiin(t_sfizz_tilde* self, t_float f)
|
||||||
|
{
|
||||||
|
int byte = (int)f;
|
||||||
|
bool isstatus = (byte & 0x80) != 0;
|
||||||
|
|
||||||
|
int* midi = self->midi;
|
||||||
|
int midinum = self->midinum;
|
||||||
|
|
||||||
|
//
|
||||||
|
if (isstatus) {
|
||||||
|
midi[0] = byte;
|
||||||
|
midinum = 1;
|
||||||
|
}
|
||||||
|
else if (midinum != -1 && midinum < 3)
|
||||||
|
midi[midinum++] = byte;
|
||||||
|
else
|
||||||
|
midinum = -1;
|
||||||
|
|
||||||
|
//
|
||||||
|
switch (midinum) {
|
||||||
|
case 2:
|
||||||
|
switch (midi[0] & 0xf0) {
|
||||||
|
case 0xd0: // channel aftertouch
|
||||||
|
if (spin_mutex_trylock(self->mutex)) {
|
||||||
|
sfizz_send_channel_aftertouch(self->synth, 0, midi[1]);
|
||||||
|
spin_mutex_unlock(self->mutex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
switch (midi[0] & 0xf0) {
|
||||||
|
case 0x90: // note on
|
||||||
|
if (midi[2] == 0)
|
||||||
|
goto noteoff;
|
||||||
|
if (spin_mutex_trylock(self->mutex)) {
|
||||||
|
sfizz_send_note_on(self->synth, 0, midi[1], midi[2]);
|
||||||
|
spin_mutex_unlock(self->mutex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x80: // note off
|
||||||
|
noteoff:
|
||||||
|
if (spin_mutex_trylock(self->mutex)) {
|
||||||
|
sfizz_send_note_off(self->synth, 0, midi[1], midi[2]);
|
||||||
|
spin_mutex_unlock(self->mutex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xb0: // controller
|
||||||
|
if (spin_mutex_trylock(self->mutex)) {
|
||||||
|
sfizz_send_cc(self->synth, 0, midi[1], midi[2]);
|
||||||
|
spin_mutex_unlock(self->mutex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xa0: // key aftertouch
|
||||||
|
if (spin_mutex_trylock(self->mutex)) {
|
||||||
|
sfizz_send_poly_aftertouch(self->synth, 0, midi[1], midi[2]);
|
||||||
|
spin_mutex_unlock(self->mutex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xe0: // pitch bend
|
||||||
|
if (spin_mutex_trylock(self->mutex)) {
|
||||||
|
sfizz_send_pitch_wheel(self->synth, 0, (midi[1] + (midi[2] << 7)) - 8192);
|
||||||
|
spin_mutex_unlock(self->mutex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->midinum = midinum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sfizz_tilde_load(t_sfizz_tilde* self, t_symbol* sym)
|
||||||
|
{
|
||||||
|
sfizz_tilde_set_file(self, sym->s_name);
|
||||||
|
sfizz_tilde_do_load(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sfizz_tilde_reload(t_sfizz_tilde* self, t_float value)
|
||||||
|
{
|
||||||
|
(void)value;
|
||||||
|
sfizz_tilde_do_load(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sfizz_tilde_hdcc(t_sfizz_tilde* self, t_float cc, t_float value)
|
||||||
|
{
|
||||||
|
if (spin_mutex_trylock(self->mutex)) {
|
||||||
|
sfizz_automate_hdcc(self->synth, 0, (int)cc, value);
|
||||||
|
spin_mutex_unlock(self->mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sfizz_tilde_voices(t_sfizz_tilde* self, t_float value)
|
||||||
|
{
|
||||||
|
if (spin_mutex_trylock(self->mutex)) {
|
||||||
|
int numvoices = (int)value;
|
||||||
|
if (numvoices < 1)
|
||||||
|
numvoices = 1;
|
||||||
|
sfizz_set_num_voices(self->synth, numvoices);
|
||||||
|
spin_mutex_unlock(self->mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
__declspec(dllexport)
|
||||||
|
#else
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
#endif
|
||||||
|
void sfizz_setup()
|
||||||
|
{
|
||||||
|
post("sfizz external for Puredata");
|
||||||
|
|
||||||
|
cls_sfizz_tilde = class_new(
|
||||||
|
gensym("sfizz~"),
|
||||||
|
(t_newmethod)&sfizz_tilde_new,
|
||||||
|
(t_method)&sfizz_tilde_free,
|
||||||
|
sizeof(t_sfizz_tilde),
|
||||||
|
CLASS_DEFAULT, A_GIMME, A_NULL);
|
||||||
|
class_addmethod(
|
||||||
|
cls_sfizz_tilde, (t_method)&sfizz_tilde_dsp, gensym("dsp"), A_CANT, A_NULL);
|
||||||
|
class_addmethod(
|
||||||
|
cls_sfizz_tilde, (t_method)&sfizz_tilde_midiin, &s_float, A_FLOAT, A_NULL);
|
||||||
|
class_addmethod(
|
||||||
|
cls_sfizz_tilde, (t_method)&sfizz_tilde_load, gensym("load"), A_DEFSYM, A_NULL);
|
||||||
|
class_addmethod(
|
||||||
|
cls_sfizz_tilde, (t_method)&sfizz_tilde_reload, gensym("reload"), A_DEFFLOAT, A_NULL);
|
||||||
|
class_addmethod(
|
||||||
|
cls_sfizz_tilde, (t_method)&sfizz_tilde_hdcc, gensym("hdcc"), A_FLOAT, A_FLOAT, A_NULL);
|
||||||
|
class_addmethod(
|
||||||
|
cls_sfizz_tilde, (t_method)&sfizz_tilde_voices, gensym("voices"), A_FLOAT, A_NULL);
|
||||||
|
}
|
||||||
46
plugins/puredata/sfizz~-help.pd
Normal file
46
plugins/puredata/sfizz~-help.pd
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#N canvas 932 395 659 405 12;
|
||||||
|
#X declare -lib sfizz;
|
||||||
|
#X obj 4 3 cnv 15 650 80 empty empty sfizz 20 30 0 40 -261682 -66577
|
||||||
|
0;
|
||||||
|
#X text 45 54 A synthesizer for instruments in SFZ format;
|
||||||
|
#X obj 241 165 r sfizz-ctl;
|
||||||
|
#X text 33 167 create a SFZ instrument;
|
||||||
|
#X obj 29 324 midiin;
|
||||||
|
#X obj 29 349 s sfizz-ctl;
|
||||||
|
#X text 26 301 connect MIDI-in;
|
||||||
|
#X obj 162 223 dac~;
|
||||||
|
#X msg 180 346 voices \$1;
|
||||||
|
#X obj 180 371 s sfizz-ctl;
|
||||||
|
#X text 178 302 modify the polyphony;
|
||||||
|
#X obj 183 326 hsl 128 15 1 256 0 1 empty empty empty -2 -8 0 10 -262144
|
||||||
|
-1 -1 3138 1;
|
||||||
|
#X floatatom 273 346 5 0 0 0 - - -;
|
||||||
|
#X obj 378 372 s sfizz-ctl;
|
||||||
|
#X obj 381 327 hsl 128 15 0 1 0 1 empty empty empty -2 -8 0 10 -262144
|
||||||
|
-1 -1 6350 1;
|
||||||
|
#X floatatom 471 347 5 0 0 0 - - -;
|
||||||
|
#X text 377 303 modulate a parameter;
|
||||||
|
#X msg 378 347 hdcc 300 \$1;
|
||||||
|
#X obj 27 115 declare -lib sfizz;
|
||||||
|
#X obj 163 192 sfizz~ example.sfz;
|
||||||
|
#X text 18 93 load the sfizz library;
|
||||||
|
#X msg 221 115 \; pd dsp 1;
|
||||||
|
#X text 218 94 click to turn on DSP;
|
||||||
|
#X text 153 247 output stereo audio;
|
||||||
|
#X msg 366 223 reload;
|
||||||
|
#X obj 366 248 s sfizz-ctl;
|
||||||
|
#X obj 466 248 s sfizz-ctl;
|
||||||
|
#X msg 466 223 load example.sfz;
|
||||||
|
#X text 364 200 reload the instrument or load another;
|
||||||
|
#X connect 2 0 19 0;
|
||||||
|
#X connect 4 0 5 0;
|
||||||
|
#X connect 8 0 9 0;
|
||||||
|
#X connect 11 0 8 0;
|
||||||
|
#X connect 11 0 12 0;
|
||||||
|
#X connect 14 0 17 0;
|
||||||
|
#X connect 14 0 15 0;
|
||||||
|
#X connect 17 0 13 0;
|
||||||
|
#X connect 19 0 7 0;
|
||||||
|
#X connect 19 1 7 1;
|
||||||
|
#X connect 24 0 25 0;
|
||||||
|
#X connect 27 0 26 0;
|
||||||
Loading…
Add table
Reference in a new issue