Reimplement modulation matrix (and tables in general) using configure variables. Slow and most likely incomplete, but a good start.
This commit is contained in:
committed by
Tobias Doerffel
parent
8053f5adcf
commit
43e2886e79
@@ -222,27 +222,15 @@ struct table_column_info
|
||||
};
|
||||
|
||||
/// 'has string parameters containing tabular data' interface
|
||||
struct table_edit_iface
|
||||
struct table_metadata_iface
|
||||
{
|
||||
/// retrieve the table layout for specific parameter
|
||||
virtual const table_column_info *get_table_columns() const = 0;
|
||||
|
||||
/// return the current number of rows
|
||||
/// return the fixed number of rows, or 0 if the number of rows is variable
|
||||
virtual uint32_t get_table_rows() const = 0;
|
||||
|
||||
/// retrieve data item from the plugin
|
||||
virtual std::string get_cell(int row, int column) const;
|
||||
|
||||
/// set data item to the plugin
|
||||
virtual void set_cell(int row, int column, const std::string &src, std::string &error) { error.clear(); }
|
||||
|
||||
/// return a line graph interface for a specific parameter/column (unused for now)
|
||||
virtual const line_graph_iface *get_graph_iface(int column) const { return NULL; }
|
||||
|
||||
/// return an editor name for a specific grid cell (unused for now - I don't even know how editors be implemented)
|
||||
virtual const char *get_cell_editor(int column) const { return NULL; }
|
||||
|
||||
virtual ~table_edit_iface() {}
|
||||
virtual ~table_metadata_iface() {}
|
||||
};
|
||||
|
||||
/// 'may receive configure variables' interface
|
||||
@@ -331,6 +319,8 @@ struct plugin_metadata_iface
|
||||
virtual bool requires_configure() const = 0;
|
||||
/// obtain array of names of configure variables (or NULL is none needed)
|
||||
virtual const char *const *get_configure_vars() const { return NULL; }
|
||||
/// @return table_metadata_iface if any
|
||||
virtual const table_metadata_iface *get_table_metadata_iface(const char *key) const { return NULL; }
|
||||
|
||||
/// Do-nothing destructor to silence compiler warning
|
||||
virtual ~plugin_metadata_iface() {}
|
||||
@@ -365,8 +355,6 @@ struct plugin_ctl_iface
|
||||
virtual const plugin_metadata_iface *get_metadata_iface() const = 0;
|
||||
/// @return line_graph_iface if any
|
||||
virtual const line_graph_iface *get_line_graph_iface() const = 0;
|
||||
/// @return table_edit_iface if any
|
||||
virtual table_edit_iface *get_table_edit_iface(const char *key) = 0;
|
||||
/// Do-nothing destructor to silence compiler warning
|
||||
virtual ~plugin_ctl_iface() {}
|
||||
};
|
||||
@@ -447,8 +435,6 @@ struct audio_module_iface
|
||||
virtual uint32_t message_run(const void *valid_ports, void *output_ports) = 0;
|
||||
/// @return line_graph_iface if any
|
||||
virtual const line_graph_iface *get_line_graph_iface() const = 0;
|
||||
/// @return table_edit_iface if any for given parameter
|
||||
virtual table_edit_iface *get_table_edit_iface(const char *key) = 0;
|
||||
virtual ~audio_module_iface() {}
|
||||
};
|
||||
|
||||
@@ -548,8 +534,6 @@ public:
|
||||
}
|
||||
/// @return line_graph_iface if any
|
||||
virtual const line_graph_iface *get_line_graph_iface() const { return dynamic_cast<const line_graph_iface *>(this); }
|
||||
virtual table_edit_iface *get_table_edit_iface(const char *key) { const char *key_us = get_table_edit_iface_key(); return (key_us && !strcmp(key, key_us)) ? dynamic_cast<table_edit_iface *>(this) : NULL; }
|
||||
virtual const char *get_table_edit_iface_key() const { return NULL; }
|
||||
};
|
||||
|
||||
#if USE_EXEC_GUI || USE_DSSI
|
||||
@@ -678,8 +662,46 @@ struct preset_access_iface
|
||||
virtual ~preset_access_iface() {}
|
||||
};
|
||||
|
||||
/// Implementation of table_metadata_iface providing metadata for mod matrices
|
||||
class mod_matrix_metadata: public table_metadata_iface
|
||||
{
|
||||
public:
|
||||
/// Mapping modes
|
||||
enum mapping_mode {
|
||||
map_positive, ///< 0..100%
|
||||
map_bipolar, ///< -100%..100%
|
||||
map_negative, ///< -100%..0%
|
||||
map_squared, ///< x^2
|
||||
map_squared_bipolar, ///< x^2 scaled to -100%..100%
|
||||
map_antisquared, ///< 1-(1-x)^2 scaled to 0..100%
|
||||
map_antisquared_bipolar, ///< 1-(1-x)^2 scaled to -100..100%
|
||||
map_parabola, ///< inverted parabola (peaks at 0.5, then decreases to 0)
|
||||
map_type_count
|
||||
};
|
||||
const char **mod_src_names, **mod_dest_names;
|
||||
|
||||
mod_matrix_metadata(unsigned int _rows, const char **_src_names, const char **_dest_names);
|
||||
virtual const table_column_info *get_table_columns() const;
|
||||
virtual uint32_t get_table_rows() const;
|
||||
|
||||
protected:
|
||||
/// Column descriptions for table widget
|
||||
table_column_info table_columns[6];
|
||||
|
||||
unsigned int matrix_rows;
|
||||
};
|
||||
|
||||
/// Check if a given key is either prefix + rows or prefix + i2s(row) + "," + i2s(column)
|
||||
/// @arg key key to parse
|
||||
/// @arg prefix table prefix (e.g. "modmatrix:")
|
||||
/// @arg is_rows[out] set to true if key == prefix + "rows"
|
||||
/// @arg row[out] if key is of a form: prefix + row + "," + i2s(column), returns row, otherwise returns -1
|
||||
/// @arg column[out] if key is of a form: prefix + row + "," + i2s(column), returns row, otherwise returns -1
|
||||
/// @retval true if this is one of the recognized string forms
|
||||
extern bool parse_table_key(const char *key, const char *prefix, bool &is_rows, int &row, int &column);
|
||||
|
||||
#if USE_EXEC_GUI
|
||||
class table_via_configure: public table_edit_iface
|
||||
class table_via_configure
|
||||
{
|
||||
protected:
|
||||
typedef std::pair<int, int> coord;
|
||||
@@ -689,13 +711,6 @@ protected:
|
||||
public:
|
||||
table_via_configure();
|
||||
void configure(const char *key, const char *value);
|
||||
|
||||
virtual const table_column_info *get_table_columns() const;
|
||||
virtual uint32_t get_table_rows() const;
|
||||
virtual std::string get_cell(int row, int column) const;
|
||||
virtual void set_cell(int row, int column, const std::string &src, std::string &error);
|
||||
virtual const line_graph_iface *get_graph_iface(int column) const;
|
||||
virtual const char *get_cell_editor(int column) const;
|
||||
virtual ~table_via_configure();
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -48,7 +48,6 @@ struct ladspa_instance: public plugin_ctl_iface
|
||||
|
||||
ladspa_instance(audio_module_iface *_module, ladspa_plugin_metadata_set *_ladspa, int sample_rate);
|
||||
virtual const line_graph_iface *get_line_graph_iface() const { return module->get_line_graph_iface(); }
|
||||
virtual table_edit_iface *get_table_edit_iface(const char *key) { return module->get_table_edit_iface(key); }
|
||||
virtual float get_param_value(int param_no);
|
||||
virtual void set_param_value(int param_no, float value);
|
||||
virtual bool activate_preset(int bank, int program);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <lv2.h>
|
||||
#include <calf/giface.h>
|
||||
#include <calf/lv2_event.h>
|
||||
#include <calf/lv2_persist.h>
|
||||
#include <calf/lv2_persist2.h>
|
||||
#include <calf/lv2_progress.h>
|
||||
#include <calf/lv2_uri_map.h>
|
||||
#include <string.h>
|
||||
@@ -91,11 +91,15 @@ struct lv2_instance: public plugin_ctl_iface, public progress_report_iface
|
||||
const char *const *vars = module->get_metadata_iface()->get_configure_vars();
|
||||
if (!vars)
|
||||
return;
|
||||
assert(uri_map);
|
||||
uint32_t string_type = uri_map->uri_to_id(uri_map, NULL, "http://lv2plug.in/ns/ext/atom#String");
|
||||
assert(string_type);
|
||||
for (unsigned int i = 0; vars[i]; i++)
|
||||
{
|
||||
size_t len = 0;
|
||||
const void *ptr = (*retrieve)(callback_data, vars[i], &len);
|
||||
if (ptr)
|
||||
uint32_t type = 0;
|
||||
const void *ptr = (*retrieve)(callback_data, vars[i], &len, &type);
|
||||
if (ptr && type == string_type)
|
||||
{
|
||||
printf("Calling configure on %s\n", vars[i]);
|
||||
configure(vars[i], std::string((const char *)ptr, len).c_str());
|
||||
@@ -160,7 +164,6 @@ struct lv2_instance: public plugin_ctl_iface, public progress_report_iface
|
||||
}
|
||||
virtual const plugin_metadata_iface *get_metadata_iface() const { return metadata; }
|
||||
virtual const line_graph_iface *get_line_graph_iface() const { return module->get_line_graph_iface(); }
|
||||
virtual table_edit_iface *get_table_edit_iface(const char *key) { return module->get_table_edit_iface(key); }
|
||||
virtual int send_status_updates(send_updates_iface *sui, int last_serial) { return module->send_status_updates(sui, last_serial); }
|
||||
};
|
||||
|
||||
@@ -297,15 +300,20 @@ struct lv2_wrapper
|
||||
{
|
||||
LV2_Persist_Store_Function store;
|
||||
void *callback_data;
|
||||
uint32_t string_data_type;
|
||||
|
||||
virtual void send_configure(const char *key, const char *value)
|
||||
{
|
||||
(*store)(callback_data, key, value, strlen(value));
|
||||
(*store)(callback_data, key, value, strlen(value) + 1, string_data_type);
|
||||
}
|
||||
};
|
||||
// A host that supports a Persist extension should support an URI map extension as well.
|
||||
assert(inst->uri_map);
|
||||
store_state s;
|
||||
s.store = store;
|
||||
s.callback_data = callback_data;
|
||||
s.string_data_type = inst->uri_map->uri_to_id(inst->uri_map, NULL, "http://lv2plug.in/ns/ext/atom#String");
|
||||
|
||||
inst->send_configures(&s);
|
||||
}
|
||||
static void cb_persist_restore(LV2_Handle Instance, LV2_Persist_Retrieve_Function retrieve, void *callback_data)
|
||||
|
||||
@@ -118,6 +118,7 @@ struct monosynth_metadata: public plugin_metadata<monosynth_metadata>
|
||||
param_count };
|
||||
enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true };
|
||||
enum { step_size = 64, step_shift = 6 };
|
||||
enum { mod_matrix_slots = 10 };
|
||||
enum {
|
||||
modsrc_none,
|
||||
modsrc_velocity,
|
||||
@@ -143,6 +144,12 @@ struct monosynth_metadata: public plugin_metadata<monosynth_metadata>
|
||||
moddest_count,
|
||||
};
|
||||
PLUGIN_NAME_ID_LABEL("monosynth", "monosynth", "Monosynth")
|
||||
|
||||
mod_matrix_metadata mm_metadata;
|
||||
|
||||
monosynth_metadata();
|
||||
/// Lookup of table edit interface
|
||||
virtual const table_metadata_iface *get_table_metadata_iface(const char *key) const { if (!strcmp(key, "mod_matrix")) return &mm_metadata; else return NULL; }
|
||||
};
|
||||
|
||||
/// Thor's compressor - metadata
|
||||
@@ -482,8 +489,14 @@ struct wavetable_metadata: public plugin_metadata<wavetable_metadata>
|
||||
par_pwhlrange,
|
||||
param_count };
|
||||
enum { in_count = 0, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = true, require_midi = true, rt_capable = true };
|
||||
enum { mod_matrix_slots = 10 };
|
||||
enum { step_size = 64 };
|
||||
PLUGIN_NAME_ID_LABEL("wavetable", "wavetable", "Wavetable")
|
||||
mod_matrix_metadata mm_metadata;
|
||||
|
||||
wavetable_metadata();
|
||||
/// Lookup of table edit interface
|
||||
virtual const table_metadata_iface *get_table_metadata_iface(const char *key) const { if (!strcmp(key, "mod_matrix")) return &mm_metadata; else return NULL; }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -25,26 +25,13 @@
|
||||
|
||||
namespace dsp {
|
||||
|
||||
/// Mapping modes
|
||||
enum mapping_mode {
|
||||
map_positive, ///< 0..100%
|
||||
map_bipolar, ///< -100%..100%
|
||||
map_negative, ///< -100%..0%
|
||||
map_squared, ///< x^2
|
||||
map_squared_bipolar, ///< x^2 scaled to -100%..100%
|
||||
map_antisquared, ///< 1-(1-x)^2 scaled to 0..100%
|
||||
map_antisquared_bipolar, ///< 1-(1-x)^2 scaled to -100..100%
|
||||
map_parabola, ///< inverted parabola (peaks at 0.5, then decreases to 0)
|
||||
map_type_count
|
||||
};
|
||||
|
||||
/// Single entry in modulation matrix
|
||||
struct modulation_entry
|
||||
{
|
||||
/// Mapped source
|
||||
int src1;
|
||||
/// Source mapping mode
|
||||
mapping_mode mapping;
|
||||
calf_plugins::mod_matrix_metadata::mapping_mode mapping;
|
||||
/// Unmapped modulating source
|
||||
int src2;
|
||||
/// Modulation amount
|
||||
@@ -60,7 +47,7 @@ struct modulation_entry
|
||||
void reset() {
|
||||
src1 = 0;
|
||||
src2 = 0;
|
||||
mapping = map_positive;
|
||||
mapping = calf_plugins::mod_matrix_metadata::map_positive;
|
||||
amount = 0.f;
|
||||
dest = 0;
|
||||
}
|
||||
@@ -70,24 +57,17 @@ struct modulation_entry
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
class mod_matrix: public table_edit_iface
|
||||
class mod_matrix_impl
|
||||
{
|
||||
protected:
|
||||
/// Polynomials for different scaling modes (1, x, x^2)
|
||||
static const float scaling_coeffs[dsp::map_type_count][3];
|
||||
/// Column descriptions for table widget
|
||||
table_column_info table_columns[6];
|
||||
|
||||
dsp::modulation_entry *matrix;
|
||||
mod_matrix_metadata *metadata;
|
||||
unsigned int matrix_rows;
|
||||
const char **mod_src_names, **mod_dest_names;
|
||||
/// Polynomials for different scaling modes (1, x, x^2)
|
||||
static const float scaling_coeffs[calf_plugins::mod_matrix_metadata::map_type_count][3];
|
||||
|
||||
mod_matrix(dsp::modulation_entry *_matrix, unsigned int _rows, const char **_src_names, const char **_dest_names);
|
||||
public:
|
||||
virtual const table_column_info *get_table_columns() const;
|
||||
virtual uint32_t get_table_rows() const;
|
||||
virtual std::string get_cell(int row, int column) const;
|
||||
virtual void set_cell(int row, int column, const std::string &src, std::string &error);
|
||||
mod_matrix_impl(dsp::modulation_entry *_matrix, calf_plugins::mod_matrix_metadata *_metadata);
|
||||
|
||||
/// Process modulation matrix, calculate outputs from inputs
|
||||
inline void calculate_modmatrix(float *moddest, int moddest_count, float *modsrc)
|
||||
@@ -105,8 +85,14 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
void send_configures(send_configure_iface *);
|
||||
char *configure(const char *key, const char *value);
|
||||
|
||||
private:
|
||||
std::string get_cell(int row, int column) const;
|
||||
void set_cell(int row, int column, const std::string &src, std::string &error);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -37,10 +37,9 @@ namespace calf_plugins {
|
||||
|
||||
/// Monosynth-in-making. Parameters may change at any point, so don't make songs with it!
|
||||
/// It lacks inertia for parameters, even for those that really need it.
|
||||
class monosynth_audio_module: public audio_module<monosynth_metadata>, public line_graph_iface, public mod_matrix
|
||||
class monosynth_audio_module: public audio_module<monosynth_metadata>, public line_graph_iface, public mod_matrix_impl
|
||||
{
|
||||
public:
|
||||
enum { mod_matrix_slots = 10 };
|
||||
uint32_t srate, crate;
|
||||
static dsp::waveform_family<MONOSYNTH_WAVE_BITS> *waves;
|
||||
dsp::waveform_oscillator<MONOSYNTH_WAVE_BITS> osc1, osc2;
|
||||
@@ -178,8 +177,9 @@ public:
|
||||
void apply_fadeout();
|
||||
/// Main processing function
|
||||
uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask);
|
||||
/// Lookup of table edit interface
|
||||
virtual table_edit_iface *get_table_edit_iface(const char *key) { if (!strcmp(key, "mod_matrix")) return static_cast<mod_matrix *>(this); else return NULL; }
|
||||
/// Send all configure variables set within a plugin to given destination (which may be limited to only those that plugin understands)
|
||||
virtual void send_configures(send_configure_iface *sci) { return mod_matrix_impl::send_configures(sci); }
|
||||
virtual char *configure(const char *key, const char *value) { return mod_matrix_impl::configure(key, value); }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
164
plugins/ladspa_effect/calf/src/calf/wavetable.h
Normal file
164
plugins/ladspa_effect/calf/src/calf/wavetable.h
Normal file
@@ -0,0 +1,164 @@
|
||||
#ifndef __CALF_WAVETABLE_H
|
||||
#define __CALF_WAVETABLE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include "biquad.h"
|
||||
#include "onepole.h"
|
||||
#include "audio_fx.h"
|
||||
#include "inertia.h"
|
||||
#include "osc.h"
|
||||
#include "synth.h"
|
||||
#include "envelope.h"
|
||||
#include "modmatrix.h"
|
||||
|
||||
namespace calf_plugins {
|
||||
|
||||
#define WAVETABLE_WAVE_BITS 8
|
||||
|
||||
class wavetable_audio_module;
|
||||
|
||||
struct wavetable_oscillator: public dsp::simple_oscillator
|
||||
{
|
||||
enum { SIZE = 1 << 8, MASK = SIZE - 1, SCALE = 1 << (32 - 8) };
|
||||
int16_t (*tables)[256];
|
||||
inline float get(uint16_t slice)
|
||||
{
|
||||
float fracslice = (slice & 255) * (1.0 / 256.0);
|
||||
slice = slice >> 8;
|
||||
int16_t *waveform = tables[slice];
|
||||
int16_t *waveform2 = tables[slice + 1];
|
||||
float value1 = 0.f, value2 = 0.f;
|
||||
uint32_t cphase = phase, cphasedelta = phasedelta >> 3;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
uint32_t wpos = cphase >> (32 - 8);
|
||||
uint32_t wpos2 = (wpos + 1) & MASK;
|
||||
float frac = (cphase & (SCALE - 1)) * (1.0f / SCALE);
|
||||
value1 += dsp::lerp((float)waveform[wpos], (float)waveform[wpos2], frac);
|
||||
value2 += dsp::lerp((float)waveform2[wpos], (float)waveform2[wpos2], frac);
|
||||
cphase += cphasedelta;
|
||||
}
|
||||
phase += phasedelta;
|
||||
return dsp::lerp(value1, value2, fracslice) * (1.0 / 8.0) * (1.0 / 32768.0);;
|
||||
}
|
||||
};
|
||||
|
||||
class wavetable_voice: public dsp::voice
|
||||
{
|
||||
public:
|
||||
enum { Channels = 2, BlockSize = 64, EnvCount = 3, OscCount = 2 };
|
||||
float output_buffer[BlockSize][Channels];
|
||||
protected:
|
||||
int note;
|
||||
wavetable_audio_module *parent;
|
||||
float **params;
|
||||
dsp::decay amp;
|
||||
wavetable_oscillator oscs[OscCount];
|
||||
dsp::adsr envs[EnvCount];
|
||||
/// Current MIDI velocity
|
||||
float velocity;
|
||||
/// Current calculated mod matrix outputs
|
||||
float moddest[wavetable_metadata::moddest_count];
|
||||
/// Last oscillator shift (wavetable index) of each oscillator
|
||||
float last_oscshift[OscCount];
|
||||
/// Last oscillator amplitude of each oscillator
|
||||
float last_oscamp[OscCount];
|
||||
/// Current osc amplitude
|
||||
float cur_oscamp[OscCount];
|
||||
public:
|
||||
wavetable_voice();
|
||||
void set_params_ptr(wavetable_audio_module *_parent, int _srate);
|
||||
void reset();
|
||||
void note_on(int note, int vel);
|
||||
void note_off(int /* vel */);
|
||||
void channel_pressure(int value);
|
||||
void steal();
|
||||
void render_block();
|
||||
virtual int get_current_note() {
|
||||
return note;
|
||||
}
|
||||
virtual bool get_active() {
|
||||
// printf("note %d getactive %d use_percussion %d pamp active %d\n", note, amp.get_active(), use_percussion(), pamp.get_active());
|
||||
return (note != -1) && (amp.get_active()) && !envs[0].stopped();
|
||||
}
|
||||
inline void calc_derived_dests() {
|
||||
float cv = dsp::clip<float>(0.5f + moddest[wavetable_metadata::moddest_oscmix], 0.f, 1.f);
|
||||
cur_oscamp[0] = (cv) * *params[wavetable_metadata::par_o1level];
|
||||
cur_oscamp[1] = (1 - cv) * *params[wavetable_metadata::par_o2level];
|
||||
}
|
||||
};
|
||||
|
||||
class wavetable_audio_module: public audio_module<wavetable_metadata>, public dsp::basic_synth, public mod_matrix_impl
|
||||
{
|
||||
public:
|
||||
using dsp::basic_synth::note_on;
|
||||
using dsp::basic_synth::note_off;
|
||||
using dsp::basic_synth::control_change;
|
||||
using dsp::basic_synth::pitch_bend;
|
||||
|
||||
protected:
|
||||
uint32_t crate;
|
||||
bool panic_flag;
|
||||
|
||||
public:
|
||||
int16_t tables[wt_count][129][256]; // one dummy level for interpolation
|
||||
/// Rows of the modulation matrix
|
||||
dsp::modulation_entry mod_matrix_data[mod_matrix_slots];
|
||||
/// Smoothed cutoff value
|
||||
dsp::inertia<dsp::exponential_ramp> inertia_cutoff;
|
||||
/// Smoothed pitch bend value
|
||||
dsp::inertia<dsp::exponential_ramp> inertia_pitchbend;
|
||||
/// Smoothed channel pressure value
|
||||
dsp::inertia<dsp::linear_ramp> inertia_pressure;
|
||||
/// Unsmoothed mod wheel value
|
||||
float modwheel_value;
|
||||
|
||||
public:
|
||||
wavetable_audio_module();
|
||||
|
||||
dsp::voice *alloc_voice() {
|
||||
dsp::block_voice<wavetable_voice> *v = new dsp::block_voice<wavetable_voice>();
|
||||
v->set_params_ptr(this, sample_rate);
|
||||
return v;
|
||||
}
|
||||
|
||||
/// process function copied from Organ (will probably need some adjustments as well as implementing the panic flag elsewhere
|
||||
uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
|
||||
float *o[2] = { outs[0] + offset, outs[1] + offset };
|
||||
if (panic_flag)
|
||||
{
|
||||
control_change(120, 0); // stop all sounds
|
||||
control_change(121, 0); // reset all controllers
|
||||
panic_flag = false;
|
||||
}
|
||||
float buf[4096][2];
|
||||
dsp::zero(&buf[0][0], 2 * nsamples);
|
||||
basic_synth::render_to(buf, nsamples);
|
||||
float gain = 1.0f;
|
||||
for (uint32_t i=0; i<nsamples; i++) {
|
||||
o[0][i] = gain*buf[i][0];
|
||||
o[1][i] = gain*buf[i][1];
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
void set_sample_rate(uint32_t sr) {
|
||||
setup(sr);
|
||||
crate = sample_rate / wavetable_voice::BlockSize;
|
||||
inertia_cutoff.ramp.set_length(crate / 30); // 1/30s
|
||||
inertia_pitchbend.ramp.set_length(crate / 30); // 1/30s
|
||||
inertia_pressure.ramp.set_length(crate / 30); // 1/30s - XXXKF monosynth needs that too
|
||||
}
|
||||
/// Handle MIDI Channel Pressure
|
||||
void channel_pressure(int value);
|
||||
/// Handle pitch bend message.
|
||||
inline void pitch_bend(int value)
|
||||
{
|
||||
inertia_pitchbend.set_inertia(pow(2.0, (value * *params[par_pwhlrange]) / (1200.0 * 8192.0)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -214,7 +214,7 @@ const char *calf_plugins::load_gui_xml(const std::string &plugin_id)
|
||||
}
|
||||
}
|
||||
|
||||
bool calf_plugins::get_freq_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context, bool use_frequencies)
|
||||
bool calf_plugins::get_freq_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context, bool use_frequencies, float res, float ofs)
|
||||
{
|
||||
if (subindex < 0 )
|
||||
return false;
|
||||
@@ -247,7 +247,7 @@ bool calf_plugins::get_freq_gridline(int subindex, float &pos, bool &vertical, s
|
||||
if (subindex >= 32)
|
||||
return false;
|
||||
float gain = 16.0 / (1 << subindex);
|
||||
pos = dB_grid(gain);
|
||||
pos = dB_grid(gain, res, ofs);
|
||||
if (pos < -1)
|
||||
return false;
|
||||
if (subindex != 4)
|
||||
@@ -319,11 +319,67 @@ const plugin_metadata_iface *calf_plugins::plugin_registry::get_by_id(const char
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string table_edit_iface::get_cell(int row, int column) const
|
||||
bool calf_plugins::parse_table_key(const char *key, const char *prefix, bool &is_rows, int &row, int &column)
|
||||
{
|
||||
return calf_utils::i2s(row)+":"+calf_utils::i2s(column);
|
||||
is_rows = false;
|
||||
row = -1;
|
||||
column = -1;
|
||||
if (0 != strncmp(key, prefix, strlen(prefix)))
|
||||
return false;
|
||||
|
||||
key += strlen(prefix);
|
||||
|
||||
if (!strcmp(key, "rows"))
|
||||
{
|
||||
is_rows = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *comma = strchr(key, ',');
|
||||
if (comma)
|
||||
{
|
||||
row = atoi(string(key, comma - key).c_str());
|
||||
column = atoi(comma + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
printf("Unknown key %s under prefix %s", key, prefix);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const char *mod_mapping_names[] = { "0..1", "-1..1", "-1..0", "x^2", "2x^2-1", "ASqr", "ASqrBip", "Para", NULL };
|
||||
|
||||
mod_matrix_metadata::mod_matrix_metadata(unsigned int _rows, const char **_src_names, const char **_dest_names)
|
||||
: mod_src_names(_src_names)
|
||||
, mod_dest_names(_dest_names)
|
||||
, matrix_rows(_rows)
|
||||
{
|
||||
table_column_info tci[6] = {
|
||||
{ "Source", TCT_ENUM, 0, 0, 0, mod_src_names },
|
||||
{ "Mapping", TCT_ENUM, 0, 0, 0, mod_mapping_names },
|
||||
{ "Modulator", TCT_ENUM, 0, 0, 0, mod_src_names },
|
||||
{ "Amount", TCT_FLOAT, 0, 1, 1, NULL},
|
||||
{ "Destination", TCT_ENUM, 0, 0, 0, mod_dest_names },
|
||||
{ NULL }
|
||||
};
|
||||
assert(sizeof(table_columns) == sizeof(tci));
|
||||
memcpy(table_columns, tci, sizeof(table_columns));
|
||||
}
|
||||
|
||||
const table_column_info *mod_matrix_metadata::get_table_columns() const
|
||||
{
|
||||
return table_columns;
|
||||
}
|
||||
|
||||
uint32_t mod_matrix_metadata::get_table_rows() const
|
||||
{
|
||||
return matrix_rows;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -435,45 +491,6 @@ table_via_configure::table_via_configure()
|
||||
rows = 0;
|
||||
}
|
||||
|
||||
const table_column_info *table_via_configure::get_table_columns() const
|
||||
{
|
||||
return &columns[0];
|
||||
}
|
||||
|
||||
uint32_t table_via_configure::get_table_rows() const
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
|
||||
string table_via_configure::get_cell(int row, int column) const
|
||||
{
|
||||
if (row >= rows)
|
||||
return string();
|
||||
coord c = make_pair(row, column);
|
||||
std::map<coord, std::string>::const_iterator i = values.find(c);
|
||||
if (i == values.end())
|
||||
return std::string();
|
||||
else
|
||||
return i->second;
|
||||
}
|
||||
|
||||
void table_via_configure::set_cell(int row, int column, const std::string &src, std::string &error)
|
||||
{
|
||||
coord c = make_pair(row, column);
|
||||
values[c] = src;
|
||||
error = "";
|
||||
}
|
||||
|
||||
const line_graph_iface *table_via_configure::get_graph_iface(int column) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *table_via_configure::get_cell_editor(int column) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
table_via_configure::~table_via_configure()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -777,6 +777,37 @@ CALF_PORT_PROPS(monosynth) = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const char *monosynth_mod_src_names[] = {
|
||||
"None",
|
||||
"Velocity",
|
||||
"Pressure",
|
||||
"ModWheel",
|
||||
"Envelope 1",
|
||||
"Envelope 2",
|
||||
"LFO 1",
|
||||
"LFO 2",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *monosynth_mod_dest_names[] = {
|
||||
"None",
|
||||
"Attenuation",
|
||||
"Osc Mix Ratio (%)",
|
||||
"Cutoff [ct]",
|
||||
"Resonance",
|
||||
"O1: Detune [ct]",
|
||||
"O2: Detune [ct]",
|
||||
"O1: PW (%)",
|
||||
"O2: PW (%)",
|
||||
"O1: Stretch",
|
||||
NULL
|
||||
};
|
||||
|
||||
monosynth_metadata::monosynth_metadata()
|
||||
: mm_metadata(mod_matrix_slots, monosynth_mod_src_names, monosynth_mod_dest_names)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CALF_PLUGIN_INFO(organ) = { 0x8481, "Organ", "Calf Organ", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "SynthesizerPlugin" };
|
||||
@@ -1037,7 +1068,29 @@ const char *wavetable_names[] = {
|
||||
"Multi 2",
|
||||
};
|
||||
|
||||
const char *wavetable_init_soundfont = "";
|
||||
static const char *wavetable_mod_src_names[] = {
|
||||
"None",
|
||||
"Velocity",
|
||||
"Pressure",
|
||||
"ModWheel",
|
||||
"Env 1",
|
||||
"Env 2",
|
||||
"Env 3",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *wavetable_mod_dest_names[] = {
|
||||
"None",
|
||||
"Attenuation",
|
||||
"Osc Mix Ratio (%)",
|
||||
"Cutoff [ct]",
|
||||
"Resonance",
|
||||
"O1: Shift (%)",
|
||||
"O2: Shift (%)",
|
||||
"O1: Detune [ct]",
|
||||
"O2: Detune [ct]",
|
||||
NULL
|
||||
};
|
||||
|
||||
CALF_PORT_NAMES(wavetable) = {
|
||||
"Out L", "Out R",
|
||||
@@ -1083,6 +1136,11 @@ CALF_PORT_PROPS(wavetable) = {
|
||||
{}
|
||||
};
|
||||
|
||||
wavetable_metadata::wavetable_metadata()
|
||||
: mm_metadata(mod_matrix_slots, wavetable_mod_src_names, wavetable_mod_dest_names)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
calf_plugins::plugin_registry::plugin_registry()
|
||||
|
||||
@@ -26,10 +26,18 @@
|
||||
using namespace std;
|
||||
using namespace dsp;
|
||||
using namespace calf_plugins;
|
||||
using namespace calf_utils;
|
||||
|
||||
const char *mod_mapping_names[] = { "0..1", "-1..1", "-1..0", "x^2", "2x^2-1", "ASqr", "ASqrBip", "Para", NULL };
|
||||
mod_matrix_impl::mod_matrix_impl(dsp::modulation_entry *_matrix, mod_matrix_metadata *_metadata)
|
||||
: matrix(_matrix)
|
||||
, metadata(_metadata)
|
||||
{
|
||||
matrix_rows = metadata->get_table_rows();
|
||||
for (unsigned int i = 0; i < matrix_rows; i++)
|
||||
matrix[i].reset();
|
||||
}
|
||||
|
||||
const float mod_matrix::scaling_coeffs[dsp::map_type_count][3] = {
|
||||
const float mod_matrix_impl::scaling_coeffs[mod_matrix_metadata::map_type_count][3] = {
|
||||
{ 0, 1, 0 },
|
||||
{ -1, 2, 0 },
|
||||
{ -1, 1, 0 },
|
||||
@@ -40,66 +48,33 @@ const float mod_matrix::scaling_coeffs[dsp::map_type_count][3] = {
|
||||
{ 0, 4, -4 },
|
||||
};
|
||||
|
||||
mod_matrix::mod_matrix(modulation_entry *_matrix, unsigned int _rows, const char **_src_names, const char **_dest_names)
|
||||
: matrix(_matrix)
|
||||
, matrix_rows(_rows)
|
||||
, mod_src_names(_src_names)
|
||||
, mod_dest_names(_dest_names)
|
||||
{
|
||||
table_column_info tci[6] = {
|
||||
{ "Source", TCT_ENUM, 0, 0, 0, mod_src_names },
|
||||
{ "Mapping", TCT_ENUM, 0, 0, 0, mod_mapping_names },
|
||||
{ "Modulator", TCT_ENUM, 0, 0, 0, mod_src_names },
|
||||
{ "Amount", TCT_FLOAT, 0, 1, 1, NULL},
|
||||
{ "Destination", TCT_ENUM, 0, 0, 0, mod_dest_names },
|
||||
{ NULL }
|
||||
};
|
||||
assert(sizeof(table_columns) == sizeof(tci));
|
||||
memcpy(table_columns, tci, sizeof(table_columns));
|
||||
for (unsigned int i = 0; i < matrix_rows; i++)
|
||||
matrix[i].reset();
|
||||
}
|
||||
|
||||
const table_column_info *mod_matrix::get_table_columns() const
|
||||
{
|
||||
return table_columns;
|
||||
}
|
||||
|
||||
uint32_t mod_matrix::get_table_rows() const
|
||||
{
|
||||
return matrix_rows;
|
||||
}
|
||||
|
||||
std::string mod_matrix::get_cell(int row, int column) const
|
||||
std::string mod_matrix_impl::get_cell(int row, int column) const
|
||||
{
|
||||
assert(row >= 0 && row < (int)matrix_rows);
|
||||
modulation_entry &slot = matrix[row];
|
||||
const char **arr = metadata->get_table_columns()[column].values;
|
||||
switch(column) {
|
||||
case 0: // source 1
|
||||
return mod_src_names[slot.src1];
|
||||
return arr[slot.src1];
|
||||
case 1: // mapping mode
|
||||
return mod_mapping_names[slot.mapping];
|
||||
return arr[slot.mapping];
|
||||
case 2: // source 2
|
||||
return mod_src_names[slot.src2];
|
||||
return arr[slot.src2];
|
||||
case 3: // amount
|
||||
return calf_utils::f2s(slot.amount);
|
||||
case 4: // destination
|
||||
return mod_dest_names[slot.dest];
|
||||
return arr[slot.dest];
|
||||
default:
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void mod_matrix::set_cell(int row, int column, const std::string &src, std::string &error)
|
||||
void mod_matrix_impl::set_cell(int row, int column, const std::string &src, std::string &error)
|
||||
{
|
||||
assert(row >= 0 && row < (int)matrix_rows);
|
||||
modulation_entry &slot = matrix[row];
|
||||
const char **arr = mod_src_names;
|
||||
if (column == 1)
|
||||
arr = mod_mapping_names;
|
||||
if (column == 4)
|
||||
arr = mod_dest_names;
|
||||
const char **arr = metadata->get_table_columns()[column].values;
|
||||
switch(column) {
|
||||
case 0:
|
||||
case 1:
|
||||
@@ -113,7 +88,7 @@ void mod_matrix::set_cell(int row, int column, const std::string &src, std::stri
|
||||
if (column == 0)
|
||||
slot.src1 = i;
|
||||
else if (column == 1)
|
||||
slot.mapping = (mapping_mode)i;
|
||||
slot.mapping = (mod_matrix_metadata::mapping_mode)i;
|
||||
else if (column == 2)
|
||||
slot.src2 = i;
|
||||
else if (column == 4)
|
||||
@@ -135,3 +110,33 @@ void mod_matrix::set_cell(int row, int column, const std::string &src, std::stri
|
||||
}
|
||||
}
|
||||
|
||||
void mod_matrix_impl::send_configures(send_configure_iface *sci)
|
||||
{
|
||||
for (int i = 0; i < (int)matrix_rows; i++)
|
||||
{
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
string key = "mod_matrix:" + i2s(i) + "," + i2s(j);
|
||||
sci->send_configure(key.c_str(), get_cell(i, j).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *mod_matrix_impl::configure(const char *key, const char *value)
|
||||
{
|
||||
bool is_rows;
|
||||
int row, column;
|
||||
if (!parse_table_key(key, "mod_matrix:", is_rows, row, column))
|
||||
return NULL;
|
||||
if (is_rows)
|
||||
return strdup("Unexpected key");
|
||||
|
||||
if (row != -1 && column != -1)
|
||||
{
|
||||
string error;
|
||||
set_cell(row, column, value, error);
|
||||
if (!error.empty())
|
||||
return strdup(error.c_str());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -27,34 +27,8 @@ using namespace std;
|
||||
|
||||
float silence[4097];
|
||||
|
||||
static const char *monosynth_mod_src_names[] = {
|
||||
"None",
|
||||
"Velocity",
|
||||
"Pressure",
|
||||
"ModWheel",
|
||||
"Envelope 1",
|
||||
"Envelope 2",
|
||||
"LFO 1",
|
||||
"LFO 2",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *monosynth_mod_dest_names[] = {
|
||||
"None",
|
||||
"Attenuation",
|
||||
"Osc Mix Ratio (%)",
|
||||
"Cutoff [ct]",
|
||||
"Resonance",
|
||||
"O1: Detune [ct]",
|
||||
"O2: Detune [ct]",
|
||||
"O1: PW (%)",
|
||||
"O2: PW (%)",
|
||||
"O1: Stretch",
|
||||
NULL
|
||||
};
|
||||
|
||||
monosynth_audio_module::monosynth_audio_module()
|
||||
: mod_matrix(mod_matrix_data, mod_matrix_slots, monosynth_mod_src_names, monosynth_mod_dest_names)
|
||||
: mod_matrix_impl(mod_matrix_data, &mm_metadata)
|
||||
, inertia_cutoff(1)
|
||||
, inertia_pitchbend(1)
|
||||
, inertia_pressure(64)
|
||||
|
||||
552
plugins/ladspa_effect/calf/src/wavetable.cpp
Normal file
552
plugins/ladspa_effect/calf/src/wavetable.cpp
Normal file
@@ -0,0 +1,552 @@
|
||||
/* Calf DSP Library
|
||||
* Example audio modules - wavetable synthesizer
|
||||
*
|
||||
* Copyright (C) 2009 Krzysztof Foltman
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if ENABLE_EXPERIMENTAL
|
||||
|
||||
#include <calf/giface.h>
|
||||
#include <calf/modules_synths.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace dsp;
|
||||
using namespace calf_plugins;
|
||||
|
||||
wavetable_voice::wavetable_voice()
|
||||
{
|
||||
sample_rate = -1;
|
||||
}
|
||||
|
||||
void wavetable_voice::set_params_ptr(wavetable_audio_module *_parent, int _srate)
|
||||
{
|
||||
parent = _parent;
|
||||
params = parent->params;
|
||||
sample_rate = _srate;
|
||||
}
|
||||
|
||||
void wavetable_voice::reset()
|
||||
{
|
||||
note = -1;
|
||||
}
|
||||
|
||||
void wavetable_voice::note_on(int note, int vel)
|
||||
{
|
||||
typedef wavetable_metadata md;
|
||||
this->note = note;
|
||||
velocity = vel / 127.0;
|
||||
amp.set(1.0);
|
||||
for (int i = 0; i < OscCount; i++) {
|
||||
oscs[i].reset();
|
||||
oscs[i].set_freq(note_to_hz(note, 0), sample_rate);
|
||||
last_oscshift[i] = 0;
|
||||
}
|
||||
int cr = sample_rate / BlockSize;
|
||||
for (int i = 0; i < EnvCount; i++) {
|
||||
envs[i].set(0.01, 0.1, 0.5, 1, cr);
|
||||
envs[i].note_on();
|
||||
}
|
||||
float modsrc[wavetable_metadata::modsrc_count] = { 1, velocity, parent->inertia_pressure.get_last(), parent->modwheel_value, envs[0].value, envs[1].value, envs[2].value};
|
||||
parent->calculate_modmatrix(moddest, md::moddest_count, modsrc);
|
||||
calc_derived_dests();
|
||||
|
||||
float oscshift[2] = { moddest[md::moddest_o1shift], moddest[md::moddest_o2shift] };
|
||||
memcpy(last_oscshift, oscshift, sizeof(oscshift));
|
||||
memcpy(last_oscamp, cur_oscamp, sizeof(cur_oscamp));
|
||||
}
|
||||
|
||||
void wavetable_voice::note_off(int vel)
|
||||
{
|
||||
for (int i = 0; i < EnvCount; i++)
|
||||
envs[i].note_off();
|
||||
}
|
||||
|
||||
void wavetable_voice::steal()
|
||||
{
|
||||
}
|
||||
|
||||
void wavetable_voice::render_block()
|
||||
{
|
||||
typedef wavetable_metadata md;
|
||||
|
||||
const float step = 1.f / BlockSize;
|
||||
|
||||
float s = 0.001;
|
||||
float scl[EnvCount];
|
||||
int espc = md::par_eg2attack - md::par_eg1attack;
|
||||
for (int j = 0; j < EnvCount; j++) {
|
||||
int o = j*espc;
|
||||
envs[j].set(*params[md::par_eg1attack + o] * s, *params[md::par_eg1decay + o] * s, *params[md::par_eg1sustain + o], *params[md::par_eg1release + o] * s, sample_rate / BlockSize, *params[md::par_eg1fade + o] * s);
|
||||
scl[j] = dsp::lerp(1.f, velocity, *params[md::par_eg1velscl + o]);;
|
||||
}
|
||||
|
||||
for (int i = 0; i < EnvCount; i++)
|
||||
envs[i].advance();
|
||||
|
||||
float modsrc[wavetable_metadata::modsrc_count] = { 1, velocity, parent->inertia_pressure.get_last(), parent->modwheel_value, envs[0].value, envs[1].value, envs[2].value};
|
||||
parent->calculate_modmatrix(moddest, md::moddest_count, modsrc);
|
||||
calc_derived_dests();
|
||||
|
||||
int ospc = md::par_o2level - md::par_o1level;
|
||||
for (int j = 0; j < OscCount; j++) {
|
||||
oscs[j].tables = parent->tables[(int)*params[md::par_o1wave + j * ospc]];
|
||||
oscs[j].set_freq(note_to_hz(note, *params[md::par_o1transpose + j * ospc] * 100+ *params[md::par_o1detune + j * ospc] + moddest[md::moddest_o1detune]), sample_rate);
|
||||
}
|
||||
|
||||
float oscshift[2] = { moddest[md::moddest_o1shift], moddest[md::moddest_o2shift] };
|
||||
float osstep[2] = { (oscshift[0] - last_oscshift[0]) * step, (oscshift[1] - last_oscshift[1]) * step };
|
||||
float oastep[2] = { (cur_oscamp[0] - last_oscamp[0]) * step, (cur_oscamp[1] - last_oscamp[1]) * step };
|
||||
for (int i = 0; i < BlockSize; i++) {
|
||||
float value = 0.f;
|
||||
|
||||
for (int j = 0; j < OscCount; j++) {
|
||||
float o = last_oscshift[j] * 0.01;
|
||||
value += last_oscamp[j] * oscs[j].get(dsp::clip(fastf2i_drm((o + *params[md::par_o1offset + j * ospc]) * 127.0 * 256), 0, 127 * 256));
|
||||
last_oscshift[j] += osstep[j];
|
||||
last_oscamp[j] += oastep[j];
|
||||
}
|
||||
|
||||
output_buffer[i][0] = output_buffer[i][1] = value;
|
||||
}
|
||||
if (envs[0].stopped())
|
||||
released = true;
|
||||
memcpy(last_oscshift, oscshift, sizeof(oscshift));
|
||||
memcpy(last_oscamp, cur_oscamp, sizeof(cur_oscamp));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline float sincl(float x, float clip)
|
||||
{
|
||||
if (fabs(x) > clip)
|
||||
return 0;
|
||||
return sin(M_PI * x);
|
||||
}
|
||||
|
||||
static inline float blip(float x, float center, float range)
|
||||
{
|
||||
if (x < center - range || x > center + range)
|
||||
return 0;
|
||||
return 1 - fabs(x - center)/range;
|
||||
}
|
||||
|
||||
static void interpolate_wt(int16_t table[129][256], int step)
|
||||
{
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
if (!(i % step))
|
||||
continue;
|
||||
int prev = i - i % step;
|
||||
int next = prev + step;
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
table[i][j] = table[prev][j] + (i - prev) * (table[next][j] - table[prev][j]) / step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wavetable_audio_module::wavetable_audio_module()
|
||||
: mod_matrix_impl(mod_matrix_data, &mm_metadata)
|
||||
, inertia_cutoff(1)
|
||||
, inertia_pitchbend(1)
|
||||
, inertia_pressure(64)
|
||||
{
|
||||
panic_flag = false;
|
||||
modwheel_value = 0.;
|
||||
for (int i = 0; i < 129; i += 8)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
int harm = 1 + 2 * (i / 8);
|
||||
float ii = i / 128.0;
|
||||
float rezo1 = sin(harm * ph) * sin(ph);
|
||||
float rezo2 = sin((harm+1) * ph) * sin(ph * 2);
|
||||
float rezo3 = sin((harm+3) * ph) * sin(ph * 4);
|
||||
float rezo = (rezo1 + rezo2 + rezo3) / 3;
|
||||
float v = (sin (ph) + ii * ii * rezo) / 2;
|
||||
tables[0][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
interpolate_wt(tables[0], 8);
|
||||
for (int i = 0; i < 129; i += 4)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
int harm = 1 + (i / 4);
|
||||
float ii = i / 128.0;
|
||||
float h = sin(harm * ph);
|
||||
float rezo1 = h * sin(ph);
|
||||
float rezo2 = h * sin(ph * 2)/2;
|
||||
float rezo3 = h * sin(ph * 3)/3;
|
||||
float rezo4 = h * sin(ph * 4)/4;
|
||||
float rezo5 = h * sin(ph * 5)/5;
|
||||
float rezo = (rezo1 + rezo2 + rezo3 + rezo4 + rezo5) / 3;
|
||||
float v = sin (ph + ii * rezo);
|
||||
tables[1][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
interpolate_wt(tables[1], 4);
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = (i & ~3) / 128.0;
|
||||
float ii2 = ((i & ~3) + 4) / 128.0;
|
||||
float peak = (32 * ii);
|
||||
float rezo1 = sin(floor(peak) * ph);
|
||||
float rezo2 = sin(floor(peak + 1) * ph);
|
||||
float widener = (0.5 + 0.3 * sin(ph) + 0.2 * sin (3 * ph));
|
||||
float v1 = 0.5 * sin (ph) + 0.5 * ii * ii * rezo1 * widener;
|
||||
float v2 = 0.5 * sin (ph) + 0.5 * ii2 * ii2 * rezo2 * widener;
|
||||
tables[wavetable_metadata::wt_rezo][i][j] = 32767 * lerp(v1, v2, (i & 3) / 4.0);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph) + ii * sin(ph + 2 * ii * sin(ph)) + ii * ii * sin(ph + 6 * ii * ii * sin(6 * ph)) + ii * ii * ii * ii * sin(ph + 11 * ii * ii * ii * ii * sin(11 * ph))) / 4;
|
||||
tables[wavetable_metadata::wt_metal][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph) + ii * sin(ph - 3 * ii * sin(ph)) + ii * ii * sin(5 * ph - 5 * ii * ii * ii * ii * sin(11 * ph))) / 3;
|
||||
tables[wavetable_metadata::wt_bell][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
//float v = (sin(ph) + ii * sin(ph + 2 * ii * sin(ph)) + ii * ii * sin(ph + 3 * ii * ii * sin(3 * ph)) + ii * ii * ii * sin(ph + 5 * ii * ii * ii * sin(5 * ph))) / 4;
|
||||
float v = (sin(ph) + sin(ph - 3 * sin(ii * 5 - 2) * sin(ph)) + sin(ii * 4 - 1.3) * sin(5 * ph + 3 * ii * ii * sin(6 * ph))) / 3;
|
||||
tables[wavetable_metadata::wt_blah][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
tables[wavetable_metadata::wt_pluck][128][i] = (i < 128) ? 32000 * fabs(sin(i / 32.0 * M_PI) * sin(i / 13.0 * M_PI) * sin(i / 19.0 * M_PI)) : 0;
|
||||
}
|
||||
for (int i = 127; i >= 0; i--)
|
||||
{
|
||||
int16_t *parent = tables[wavetable_metadata::wt_pluck][i + 1];
|
||||
float damp = 0.05;
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
tables[wavetable_metadata::wt_pluck][i][j] = (1 - 2*damp) * parent[j] + damp * parent[(j+1)&255] + damp * parent[(j+2)&255];// + 0.1 * parent[(j-1)&255]+ 0.1 * parent[(j-2)&255];
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j / 128.0 - 1.0;
|
||||
float ii = i / 128.0;
|
||||
float v = sincl(ph * (1 + 15 * ii), 1);
|
||||
tables[wavetable_metadata::wt_stretch][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j / 128.0 - 1.0;
|
||||
float ii = i / 128.0;
|
||||
float v = sincl(ph * (1 + 15 * ii), 4) * sincl(j / 256.0, 1);
|
||||
tables[wavetable_metadata::wt_stretch2][i][j] = 32000 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j / 128.0 - 1.0;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph * (1 + 15 * ii), 4);
|
||||
float v = pow(w, 9) * sincl(j / 256.0, 1);
|
||||
tables[wavetable_metadata::wt_hardsync][i][j] = 32000 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j / 128.0 - 1.0;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph * (1 + 31 * ii), 3);
|
||||
float v = pow(w, 5) * sincl(j / 256.0, 1);
|
||||
tables[wavetable_metadata::wt_hardsync2][i][j] = 32000 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j / 128.0 - 1.0;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph * ph * (1 + 15 * ii), 2);
|
||||
float v = pow(w, 4) * sincl(j / 256.0, 1);
|
||||
tables[wavetable_metadata::wt_softsync][i][j] = 32000 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph) + ii * sin(ph - 3 * ii * sin(ph)) + ii * ii * ii * sin(7 * ph - 2 * ii * ii * ii * ii * sin(13 * ph))) / 3;
|
||||
tables[wavetable_metadata::wt_bell2][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph) + ii * sin(ph - 3 * ii * sin(ph)) + ii * ii * ii * sin(9 * ph - ii * ii * sin(11 * ph))) / 3;
|
||||
tables[wavetable_metadata::wt_bell3][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph + ii * sin(ph - 3 * ii * sin(ph) + ii * ii * ii * sin(5 * ph - ii * ii * sin(7 * ph)))));
|
||||
tables[wavetable_metadata::wt_tine][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float v = (sin(ph + ii * sin(ph - 2 * ii * sin(ph) + ii * ii * ii * sin(3 * ph - ii * ii * sin(4 * ph)))));
|
||||
tables[wavetable_metadata::wt_tine2][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ph2 = j / 128.0 - 1;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph2 * (1 + 7 * ii * ii), 4) * pow(sincl(j / 256.0, 1), 2);
|
||||
float v = sin(ph + ii * sin(ph - 2 * ii * w));
|
||||
tables[wavetable_metadata::wt_clav][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ph2 = j / 128.0 - 1;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph2 * (1 + 7 * ii * ii), 6) * sincl(j / 256.0, 1);
|
||||
float v = sin(ph + ii * sin(3 * ph - 2 * ii * w));
|
||||
tables[wavetable_metadata::wt_clav2][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
/*
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ph2 = j / 128.0 - 1;
|
||||
float ii = i / 128.0;
|
||||
float w = sincl(ph2 * (1 + 7 * ii * ii), 6) * pow(sincl(j / 256.0, 1), 1);
|
||||
float v = sin(ph + ii * ii * ii * sin(3 * ph - ii * ii * ii * w));
|
||||
tables[wavetable_metadata::wt_gtr][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
*/
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = ii;
|
||||
float w = pow(sincl(j / 256.0, 1), 1);
|
||||
float v = sin(ph + ii2 * ii2 * ii2 * sin(3 * ph - ii2 * ii2 * ii2 * w * sin(ph + sin(3 * ph) + ii * sin(11 * ph) + ii * ii * sin(25 * ph))));
|
||||
tables[wavetable_metadata::wt_gtr][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = dsp::clip(ii - 0.5, 0.0, 1.0);
|
||||
float w = pow(sincl(j / 256.0, 1), 1);
|
||||
float v = sin(ph + ii * ii * ii * sin(3 * ph - ii * ii * ii * w * sin(ph + sin(3 * ph + ii2 * sin(13 * ph)))));
|
||||
tables[wavetable_metadata::wt_gtr2][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = dsp::clip(2 * (ii - 0.5), 0.0, 1.0);
|
||||
//float w = sincl(ph2 * (1 + 15 * ii2 * ii2), 4) * pow(sincl(j / 256.0, 1), 1);
|
||||
float w = pow(sincl(j / 256.0, 1), 1);
|
||||
float v = sin(ph + ii * sin(3 * ph - ii * w * sin(ph + sin(3 * ph + 0.5 * ii2 * sin(13 * ph + 0.5 * sin(4 * ph))))));
|
||||
tables[wavetable_metadata::wt_gtr3][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = dsp::clip(2 * (ii - 0.5), 0.0, 1.0);
|
||||
//float w = sincl(ph2 * (1 + 15 * ii2 * ii2), 4) * pow(sincl(j / 256.0, 1), 1);
|
||||
float w = pow(sincl(j / 256.0, 1), 1);
|
||||
float v = sin(ph + ii * sin(3 * ph - ii * w * sin(2 * ph + sin(5 * ph + 0.5 * ii2 * sin(13 * ph + 0.5 * sin(4 * ph))))));
|
||||
tables[wavetable_metadata::wt_gtr4][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = dsp::clip((ii - 0.25)/0.75, 0.0, 1.0);
|
||||
//float w = sincl(ph2 * (1 + 15 * ii2 * ii2), 4) * pow(sincl(j / 256.0, 1), 1);
|
||||
float w = pow(sincl(j / 256.0, 1), 3);
|
||||
float v = sin(ph + (ii + 0.05) * sin(3 * ph - 2 * ii * w * sin(5 * ph + sin(7 * ph + 0.5 * ii2 * sin(13 * ph + 0.5 * sin(11 * ph))))));
|
||||
tables[wavetable_metadata::wt_gtr5][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float w = pow(sincl(2 * (j / 256.0), 2), 3);
|
||||
float v = sin(ph + (ii + 0.05) * sin(7 * ph - 2 * ii * w * sin(11 * ph)));
|
||||
tables[wavetable_metadata::wt_reed][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float ii2 = dsp::clip((ii - 0.25)/0.75, 0.0, 1.0);
|
||||
float ii3 = dsp::clip((ii - 0.5)/0.5, 0.0, 1.0);
|
||||
float v = sin(ph + (ii + 0.05) * sin(ii * sin(2 * ph) - 2 * ii2 * sin(2 * ph + ii2 * sin(3 * ph)) + 3 * ii3 * sin(3 * ph)));
|
||||
tables[wavetable_metadata::wt_reed2][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float mod = 0;
|
||||
for (int k = 0; k < 13; k++)
|
||||
{
|
||||
mod += blip(i, k * 10, 30) * sin (ph * (5 + 3 * k) + ii * cos(ph * (2 + 2 * k)));
|
||||
}
|
||||
float v = sin(ph + ii * mod);
|
||||
tables[wavetable_metadata::wt_silver][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float mod = 0;
|
||||
for (int k = 0; k < 16; k++)
|
||||
{
|
||||
mod += 2 * blip(i, k * 8, k * 4 + 10) * cos (ph * (k + 1));
|
||||
}
|
||||
float v = sin(ph + ii * mod);
|
||||
tables[wavetable_metadata::wt_brass][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float ii = i / 128.0;
|
||||
float mod = 0;
|
||||
for (int k = 0; k < 16; k++)
|
||||
{
|
||||
mod += 2 * blip(i, k * 8, 16) * cos (ph * (2 * k + 1));
|
||||
}
|
||||
float v = (sin(ph + ii * mod) + ii * sin(2 * ph + ii * mod)) / 2;
|
||||
tables[wavetable_metadata::wt_multi][i][j] = 32767 * v;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 129; i ++)
|
||||
{
|
||||
float h = 1 + i / 16.0;
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
float ph = j * 2 * M_PI / 256;
|
||||
float v = sin(ph), tv = 1;
|
||||
for (int k = 1; k < 24; k++) {
|
||||
float amp = blip(i, k * 6, 20) / k;
|
||||
v += amp * sin((k + 1) * ph + h * sin(ph));
|
||||
tv += amp;
|
||||
}
|
||||
tables[wavetable_metadata::wt_multi2][i][j] = 32767 * v / tv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wavetable_audio_module::channel_pressure(int value)
|
||||
{
|
||||
inertia_pressure.set_inertia(value * (1.0 / 127.0));
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user