2#include "ase/processor.hh"
12using LiquidSFZ::Synth;
16 enum { STATE_IDLE, STATE_LOAD };
25 uint want_sample_rate_ = 0;
26 uint have_sample_rate_ = 0;
34 if (state_.load() == STATE_LOAD)
36 if (want_sfz_ != have_sfz_)
38 printerr (
"LiquidSFZ: loading %s...", want_sfz_.
c_str());
39 bool result = synth_.load (want_sfz_);
40 printerr (
"%s\n", result ?
"OK" :
"FAIL");
43 have_sfz_ = want_sfz_;
45 if (want_sample_rate_ != have_sample_rate_)
47 synth_.set_sample_rate (want_sample_rate_);
48 have_sample_rate_ = want_sample_rate_;
50 state_.store (STATE_IDLE);
53 printerr (
"LiquidSFZ: run() done\n");
56 LiquidSFZLoader (Synth &synth) :
59 thread_ =
std::thread (&LiquidSFZLoader::run,
this);
61 printerr (
"LiquidSFZLoader()\n");
68 printerr (
"~LiquidSFZLoader()\n");
74 if (state_.load() == STATE_IDLE)
76 if (want_sfz_ == have_sfz_ && (want_sample_rate_ == have_sample_rate_ || want_sfz_ ==
""))
79 state_.store (STATE_LOAD);
91 set_sample_rate (
uint sample_rate)
93 want_sample_rate_ = sample_rate;
99class LiquidSFZ :
public AudioProcessor {
102 bool synth_need_reset_ =
false;
103 LiquidSFZLoader loader_;
109 static constexpr const int PID_CC_OFFSET = 1000;
114 install_params (build_parameter_map());
116 loader_.set_sample_rate (sample_rate());
117 prepare_event_input();
118 stereo_out_ = add_output_bus (
"Stereo Out", SpeakerArrangement::STEREO);
119 assert_return (bus_info (stereo_out_).ident ==
"stereo_out");
125 build_parameter_map()
128 pmap[INSTRUMENT] =
Param {
"instrument",
_(
"Instrument"),
_(
"Inst"),
"",
"", {},
"", {
129 String (
"blurb=") +
_(
"Instrument File Name"),
132 auto ccs = synth_.list_ccs();
133 for (
const auto& cc_info : ccs)
135 uint32_t pid = cc_info.cc() + PID_CC_OFFSET;
136 pmap[pid] =
Param {
string_format (
"cc_%d", cc_info.cc()), cc_info.label(), cc_info.label(),
137 cc_info.default_value() / 127. * 100,
"%", { 0, 100 } };
142 reset (
uint64 target_stamp)
override
144 synth_need_reset_ =
true;
148 adjust_param (uint32_t tag)
override
153 loader_.load (text_param_from_quark (INSTRUMENT,
irintf (get_param (tag))));
158 generate_cc_event (
const MidiEvent& event)
160 const int cc =
event.param - PID_CC_OFFSET;
161 const int cc_value =
std::clamp (
irintf (event.pvalue * 0.01 * 127), 0, 127);
171 synth_.add_event_cc (event.
frame, 0, cc, cc_value);
174 render (
uint n_frames)
override
180 if (synth_need_reset_)
182 synth_.system_reset();
183 synth_need_reset_ =
false;
186 MidiEventInput evinput = midi_event_input();
187 for (
const auto &ev : evinput)
189 switch (ev.message())
191 case MidiMessage::NOTE_OFF:
192 synth_.add_event_note_off (ev.frame, ev.channel, ev.key);
194 case MidiMessage::NOTE_ON:
195 synth_.add_event_note_on (ev.frame, ev.channel, ev.key,
std::clamp (
irintf (ev.velocity * 127), 0, 127));
197 case MidiMessage::ALL_NOTES_OFF:
198 case MidiMessage::ALL_SOUND_OFF:
199 synth_.all_sound_off();
201 case MidiMessage::PARAM_VALUE:
203 adjust_param (ev.param);
204 if (ev.param >= PID_CC_OFFSET)
205 generate_cc_event (ev);
212 oblock (stereo_out_, 0),
213 oblock (stereo_out_, 1)
215 synth_.process (output, n_frames);
219 float *left_out = oblock (stereo_out_, 0);
220 float *right_out = oblock (stereo_out_, 1);
227 LiquidSFZ (
const ProcessorSetup &psetup) :
228 AudioProcessor (psetup),
232 static_info (AudioProcessorInfo &info)
235 info.label =
"LiquidSFZ";
236 info.category =
"Synth";
237 info.creator_name =
"Stefan Westerfeld";
238 info.website_url =
"https://anklang.testbit.eu";
242static auto liquidsfz = register_audio_processor<LiquidSFZ> (
"Ase::Devices::LiquidSFZ");
int wait() noexcept
Wait indefinitely for ScopedSemaphore.
int post() noexcept
Unlock ScopedSemaphore.
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
#define _(...)
Retrieve the translation of a C or C++ string.
int run(const StringS &test_names)
Run named tests.
The Anklang C++ API namespace.
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
void floatfill(float *dst, float f, size_t n)
Fill n values of dst with f.
SpeakerArrangement
Flags to indicate channel arrangements of a bus.
std::string String
Convenience alias for std::string.
int irintf(float f)
Round float to int, using round-to-nearest Fast version of f < 0 ? int (f - 0.5) : int (f + 0....
uint32_t uint
Provide 'uint' as convenience type.
MidiEvent data structure.
uint frame
Offset into current block, delayed if negative.
Structured initializer for Parameter.
Parameter list construction helper.