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_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)
|
||||
|
|
|
|||
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)
|
||||
add_subdirectory(vst)
|
||||
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