External for puredata

This commit is contained in:
Jean Pierre Cimalando 2021-04-29 19:28:29 +02:00
parent db869ed402
commit 4ef3824209
7 changed files with 395 additions and 0 deletions

View file

@ -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_AU "Enable AU plug-in build" APPLE)
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_TESTS "Enable tests build" OFF)
option_ex (SFIZZ_DEMOS "Enable feature demos build" OFF)

View 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()

View file

@ -58,3 +58,7 @@ endif()
if(SFIZZ_VST OR SFIZZ_AU OR SFIZZ_VST2)
add_subdirectory(vst)
endif()
if(SFIZZ_PUREDATA)
add_subdirectory(puredata)
endif()

View 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}")

View 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

View 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);
}

View 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;