Browse Source

add manifest generator in guile, import zlfo, refactor

master
Alexandros Theodotou 2 years ago
parent
commit
6014d0ec61
Signed by: alex
GPG Key ID: 022EAE42313D70F3
  1. 22
      .builds/archlinux.yml
  2. 21
      .builds/debian.yml
  3. 25
      .builds/fedora.yml
  4. 23
      .builds/freebsd.yml
  5. 1
      ext/Soundpipe/modules/meson.build
  6. 2
      meson.build
  7. 5
      meson_options.txt
  8. 0
      plugins/chordz/common.h
  9. 0
      plugins/chordz/dsp.c
  10. 0
      plugins/compressorsp/common.h
  11. 0
      plugins/compressorsp/dsp.c
  12. 0
      plugins/compressorsp/ttl.h
  13. 372
      plugins/lfo/common.h
  14. 775
      plugins/lfo/dsp.c
  15. 514
      plugins/lfo/lfo_math.h
  16. 5
      plugins/lfo/presets.ttl.in
  17. 209
      plugins/lfo/resources/COPYING.breeze
  18. 45
      plugins/lfo/resources/README
  19. 63
      plugins/lfo/resources/curve.svg
  20. 63
      plugins/lfo/resources/curve_active.svg
  21. 14
      plugins/lfo/resources/custom.svg
  22. 75
      plugins/lfo/resources/down_arrow.svg
  23. 83
      plugins/lfo/resources/freeb.svg
  24. 83
      plugins/lfo/resources/freeb_black.svg
  25. 71
      plugins/lfo/resources/freeb_black_orig.svg
  26. 71
      plugins/lfo/resources/freeb_orig.svg
  27. 120
      plugins/lfo/resources/grid_snap.svg
  28. 120
      plugins/lfo/resources/grid_snap_click.svg
  29. 88
      plugins/lfo/resources/grid_snap_click_orig.svg
  30. 120
      plugins/lfo/resources/grid_snap_hover.svg
  31. 88
      plugins/lfo/resources/grid_snap_hover_orig.svg
  32. 92
      plugins/lfo/resources/grid_snap_orig.svg
  33. 99
      plugins/lfo/resources/hmirror.svg
  34. 95
      plugins/lfo/resources/hmirror_click.svg
  35. 95
      plugins/lfo/resources/hmirror_hover.svg
  36. 93
      plugins/lfo/resources/invert.svg
  37. 71
      plugins/lfo/resources/invert_orig.svg
  38. 170
      plugins/lfo/resources/range.svg
  39. 152
      plugins/lfo/resources/range_orig.svg
  40. 65
      plugins/lfo/resources/saw.svg
  41. 88
      plugins/lfo/resources/shift.svg
  42. 71
      plugins/lfo/resources/shift_orig.svg
  43. 65
      plugins/lfo/resources/sine.svg
  44. 65
      plugins/lfo/resources/square.svg
  45. 90
      plugins/lfo/resources/step.svg
  46. 86
      plugins/lfo/resources/step_active.svg
  47. 83
      plugins/lfo/resources/sync.svg
  48. 83
      plugins/lfo/resources/sync_black.svg
  49. 71
      plugins/lfo/resources/sync_black_orig.svg
  50. 71
      plugins/lfo/resources/sync_orig.svg
  51. 65
      plugins/lfo/resources/triangle.svg
  52. 99
      plugins/lfo/resources/vmirror.svg
  53. 95
      plugins/lfo/resources/vmirror_click.svg
  54. 95
      plugins/lfo/resources/vmirror_hover.svg
  55. 73
      plugins/lfo/resources/zrythm.svg
  56. 73
      plugins/lfo/resources/zrythm_hover.svg
  57. 73
      plugins/lfo/resources/zrythm_orange.svg
  58. 412
      plugins/lfo/ttl.h
  59. 2984
      plugins/lfo/ui.c
  60. 189
      plugins/lfo/ui_theme.h
  61. 4
      plugins/limitersp/common.h
  62. 0
      plugins/limitersp/dsp.c
  63. 0
      plugins/limitersp/ttl.h
  64. 46
      plugins/manifest.ttl.in
  65. 130
      plugins/manifest_gen.scm
  66. 29
      plugins/math.h
  67. 150
      plugins/meson.build
  68. 95
      plugins/phasersp/common.h
  69. 259
      plugins/phasersp/dsp.c
  70. 208
      plugins/phasersp/ttl.h
  71. 0
      plugins/saw/common.h
  72. 0
      plugins/saw/dsp.c
  73. 0
      plugins/verbsp/common.h
  74. 0
      plugins/verbsp/dsp.c
  75. 0
      plugins/verbsp/ttl.h
  76. BIN
      screenshots/2020_feb_06_zlfo.png
  77. BIN
      screenshots/2020_feb_12_zlfo.png
  78. 2
      subprojects/ztoolkit.wrap

22
.builds/archlinux.yml

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
image: archlinux
packages:
- meson
- libx11
- python
- ninja
- librsvg
- cairo
- lv2lint
- lv2
sources:
- https://git.sr.ht/~alextee/zplugins
tasks:
- setup: |
cd zplugins
meson build
- build: |
cd zplugins
ninja -C build
- test: |
cd zplugins
ninja -C build test

21
.builds/debian.yml

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
image: debian/buster
packages:
- meson
- ninja-build
- python3
- librsvg2-dev
- libx11-dev
- libcairo2-dev
- lv2-dev
sources:
- https://git.sr.ht/~alextee/zplugins
tasks:
- setup: |
cd zplugins
meson build
- build: |
cd zplugins
ninja -C build
- test: |
cd zplugins
ninja -C build test

25
.builds/fedora.yml

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
image: fedora/latest
packages:
- gcc-c++
- gcc
- pkgconfig
- python3
- gettext
- sed
- meson
- libX11-devel
- cairo-devel
- librsvg2-devel
- lv2-devel
sources:
- https://git.sr.ht/~alextee/zplugins
tasks:
- setup: |
cd zplugins
meson build
- build: |
cd zplugins
ninja -C build
- test: |
cd zplugins
ninja -C build test

23
.builds/freebsd.yml

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
image: freebsd/latest
packages:
- meson
- ninja
- python36
- pkgconf
- libX11
- cairo
- librsvg2
- lv2lint
- lv2
sources:
- https://git.sr.ht/~alextee/zplugins
tasks:
- setup: |
cd zplugins
meson build
- build: |
cd zplugins
ninja -C build
- test: |
cd zplugins
ninja -C build test

1
ext/Soundpipe/modules/meson.build

@ -22,6 +22,7 @@ soundpipe_module_files = files([ @@ -22,6 +22,7 @@ soundpipe_module_files = files([
'compressor.c',
'dist.c',
'peaklim.c',
'phaser.c',
'spa.c',
'saturator.c',
'zitarev.c',

2
meson.build

@ -19,7 +19,7 @@ project ( @@ -19,7 +19,7 @@ project (
'ZPlugins', ['c'],
version: '1.0.1',
license: 'AGPLv3+',
meson_version: '>= 0.46.0',
meson_version: '>= 0.53.0',
default_options: [
'warning_level=2',
'buildtype=debug',

5
meson_options.txt

@ -26,7 +26,10 @@ option ( @@ -26,7 +26,10 @@ option (
option (
'plugins', type : 'array',
choices : [
'Chordz', 'Compressor', 'Limiter', 'Verb', 'Saw'
'Chordz', 'Chorus', 'CompressorSP', 'Delay',
'Distortion',
'EQ', 'LFO', 'LimiterSP', 'PhaserSP', 'Saturator',
'VerbSP', 'Saw'
],
description: 'Plugins to build')

0
plugins/chordz/chordz_common.h → plugins/chordz/common.h

0
plugins/chordz/chordz.c → plugins/chordz/dsp.c

0
plugins/compressor/compressor_common.h → plugins/compressorsp/common.h

0
plugins/compressor/compressor.c → plugins/compressorsp/dsp.c

0
plugins/compressor/ttl.h → plugins/compressorsp/ttl.h

372
plugins/lfo/common.h

@ -0,0 +1,372 @@ @@ -0,0 +1,372 @@
/*
* Copyright (C) 2019-2020 Alexandros Theodotou <alex at zrythm dot org>
*
* This file is part of ZPlugins
*
* ZPlugins is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* ZPlugins 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU General Affero Public License
* along with ZPlugins. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file
*
* Common code for both the DSP and the UI.
*/
#ifndef __Z_LFO_COMMON_H__
#define __Z_LFO_COMMON_H__
#include PLUGIN_CONFIG
#include <string.h>
#include "lv2/atom/atom.h"
#include "lv2/atom/forge.h"
#include "lv2/core/lv2.h"
#include "lv2/log/log.h"
#include "lv2/urid/urid.h"
#include "lv2/time/time.h"
#include "../common.h"
/** Min, max and default frequency. */
#define MIN_FREQ 0.01f
#define DEF_FREQ 1.f
#define MAX_FREQ 60.f
typedef struct LfoUris
{
/* custom URIs for communication */
/** The object URI. */
LV2_URID ui_state;
/* object property URIs */
LV2_URID ui_state_current_sample;
LV2_URID ui_state_period_size;
LV2_URID ui_state_samplerate;
LV2_URID ui_state_saw_multiplier;
LV2_URID ui_state_sine_multiplier;
/** Messages for UI on/off. */
LV2_URID ui_on;
LV2_URID ui_off;
} LfoUris;
typedef enum PortIndex
{
/** GUI to plugin communication. */
LFO_CONTROL,
/** Plugin to UI communication. */
LFO_NOTIFY,
/** Plugin to UI communication of the current
* sample. */
LFO_SAMPLE_TO_UI,
LFO_CV_GATE,
LFO_CV_TRIGGER,
LFO_GATE,
LFO_TRIGGER,
LFO_GATED_MODE,
LFO_SYNC_RATE,
LFO_SYNC_RATE_TYPE,
LFO_FREQ,
LFO_SHIFT,
LFO_RANGE_MIN,
LFO_RANGE_MAX,
LFO_STEP_MODE,
LFO_FREE_RUNNING,
LFO_GRID_STEP,
LFO_HINVERT,
LFO_VINVERT,
LFO_SINE_TOGGLE,
LFO_SAW_TOGGLE,
LFO_SQUARE_TOGGLE,
LFO_TRIANGLE_TOGGLE,
LFO_CUSTOM_TOGGLE,
LFO_NODE_1_POS,
LFO_NODE_1_VAL,
LFO_NODE_1_CURVE,
LFO_NODE_2_POS,
LFO_NODE_2_VAL,
LFO_NODE_2_CURVE,
LFO_NODE_3_POS,
LFO_NODE_3_VAL,
LFO_NODE_3_CURVE,
LFO_NODE_4_POS,
LFO_NODE_4_VAL,
LFO_NODE_4_CURVE,
LFO_NODE_5_POS,
LFO_NODE_5_VAL,
LFO_NODE_5_CURVE,
LFO_NODE_6_POS,
LFO_NODE_6_VAL,
LFO_NODE_6_CURVE,
LFO_NODE_7_POS,
LFO_NODE_7_VAL,
LFO_NODE_7_CURVE,
LFO_NODE_8_POS,
LFO_NODE_8_VAL,
LFO_NODE_8_CURVE,
LFO_NODE_9_POS,
LFO_NODE_9_VAL,
LFO_NODE_9_CURVE,
LFO_NODE_10_POS,
LFO_NODE_10_VAL,
LFO_NODE_10_CURVE,
LFO_NODE_11_POS,
LFO_NODE_11_VAL,
LFO_NODE_11_CURVE,
LFO_NODE_12_POS,
LFO_NODE_12_VAL,
LFO_NODE_12_CURVE,
LFO_NODE_13_POS,
LFO_NODE_13_VAL,
LFO_NODE_13_CURVE,
LFO_NODE_14_POS,
LFO_NODE_14_VAL,
LFO_NODE_14_CURVE,
LFO_NODE_15_POS,
LFO_NODE_15_VAL,
LFO_NODE_15_CURVE,
LFO_NODE_16_POS,
LFO_NODE_16_VAL,
LFO_NODE_16_CURVE,
LFO_NUM_NODES,
LFO_SINE_OUT,
LFO_TRIANGLE_OUT,
LFO_SAW_OUT,
LFO_SQUARE_OUT,
LFO_CUSTOM_OUT,
NUM_LFO_PORTS,
} PortIndex;
typedef enum GridStep
{
GRID_STEP_FULL,
GRID_STEP_HALF,
GRID_STEP_FOURTH,
GRID_STEP_EIGHTH,
GRID_STEP_SIXTEENTH,
GRID_STEP_THIRTY_SECOND,
NUM_GRID_STEPS,
} GridStep;
typedef enum SyncRate
{
SYNC_1_128,
SYNC_1_64,
SYNC_1_32,
SYNC_1_16,
SYNC_1_8,
SYNC_1_4,
SYNC_1_2,
SYNC_1_1,
SYNC_2_1,
SYNC_4_1,
SYNC_8_1,
SYNC_16_1,
SYNC_32_1,
SYNC_64_1,
SYNC_128_1,
NUM_SYNC_RATES,
} SyncRate;
typedef enum SyncRateType
{
SYNC_TYPE_NORMAL,
SYNC_TYPE_DOTTED,
SYNC_TYPE_TRIPLET,
NUM_SYNC_RATE_TYPES,
} SyncRateType;
typedef enum CurveAlgorithm
{
CURVE_ALGORITHM_EXPONENT,
CURVE_ALGORITHM_SUPERELLIPSE,
} CurveAlgorithm;
typedef struct HostPosition
{
float bpm;
/** Current global frame. */
long frame;
/** Transport speed (0.0 is stopped, 1.0 is
* normal playback, -1.0 is reverse playback,
* etc.). */
float speed;
int beat_unit;
} HostPosition;
/**
* Group of variables needed by both the DSP and
* the UI.
*/
typedef struct LfoCommon
{
HostPosition host_pos;
/** URIs. */
LfoUris uris;
PluginCommon pl_common;
/** Size of 1 LFO period in samples. */
long period_size;
/**
* Current sample index in the period.
*
* This should be sent to the UI.
*/
long current_sample;
/**
* Sine multiplier.
*
* This is a pre-calculated variable that is used
* when calculating the sine value.
*/
float sine_multiplier;
float saw_multiplier;
} LfoCommon;
typedef struct NodeIndexElement
{
int index;
float pos;
} NodeIndexElement;
static inline void
map_uris (
LV2_URID_Map* urid_map,
LfoCommon * lfo_common)
{
map_common_uris (
urid_map, &lfo_common->pl_common.uris);
#define MAP(x,uri) \
lfo_common->uris.x = \
urid_map->map (urid_map->handle, uri)
/* custom URIs */
MAP (ui_on, PLUGIN_URI "#ui_on");
MAP (ui_off, PLUGIN_URI "#ui_off");
MAP (ui_state, PLUGIN_URI "#ui_state");
MAP (
ui_state_current_sample,
PLUGIN_URI "#ui_state_current_sample");
MAP (
ui_state_sine_multiplier,
PLUGIN_URI "#ui_state_sine_multiplier");
MAP (
ui_state_saw_multiplier,
PLUGIN_URI "#ui_state_saw_multiplier");
MAP (
ui_state_period_size,
PLUGIN_URI "#ui_state_period_size");
MAP (
ui_state_samplerate,
PLUGIN_URI "#ui_state_samplerate");
}
/**
* Updates the position inside HostPosition with
* the given time_Position atom object.
*/
static inline void
update_position_from_atom_obj (
LfoCommon * lfo_common,
const LV2_Atom_Object * obj)
{
PluginUris * uris = &lfo_common->pl_common.uris;
HostPosition * host_pos = &lfo_common->host_pos;
/* Received new transport position/speed */
LV2_Atom *beat = NULL,
*bpm = NULL,
*beat_unit = NULL,
*speed = NULL,
*frame = NULL;
lv2_atom_object_get (
obj, uris->time_barBeat, &beat,
uris->time_beatUnit, &beat_unit,
uris->time_beatsPerMinute, &bpm,
uris->time_frame, &frame,
uris->time_speed, &speed, NULL);
if (bpm && bpm->type == uris->atom_Float)
{
/* Tempo changed, update BPM */
host_pos->bpm = ((LV2_Atom_Float*)bpm)->body;
}
if (speed && speed->type == uris->atom_Float)
{
/* Speed changed, e.g. 0 (stop) to 1 (play) */
host_pos->speed =
((LV2_Atom_Float *) speed)->body;
}
if (beat_unit && beat_unit->type == uris->atom_Int)
{
host_pos->beat_unit =
((LV2_Atom_Int *) beat_unit)->body;
}
if (frame && frame->type == uris->atom_Long)
{
host_pos->frame =
((LV2_Atom_Int *) frame)->body;
}
if (beat && beat->type == uris->atom_Float)
{
/*const float bar_beats =*/
/*((LV2_Atom_Float *) beat)->body;*/
/*self->beat_offset = fmodf (bar_beats, 1.f);*/
}
}
/**
* Gets the val of the custom graph at x, with
* x_size corresponding to the period size.
*/
static inline float
get_custom_val_at_x (
const float prev_node_pos,
const float prev_node_val,
const float prev_node_curve,
const float next_node_pos,
const float next_node_val,
const float next_node_curve,
float x,
float x_size)
{
if (next_node_pos - prev_node_pos < 0.00000001f)
return prev_node_val;
float xratio = x / x_size;
float range = next_node_pos - prev_node_pos;
/* x relative to the start of the previous node */
float rel_x = xratio - prev_node_pos;
/* get slope */
float m =
(next_node_val - prev_node_val) / range;
return m * (rel_x) + prev_node_val;
}
#endif

775
plugins/lfo/dsp.c

@ -0,0 +1,775 @@ @@ -0,0 +1,775 @@
/*
* Copyright (C) 2019-2020 Alexandros Theodotou <alex at zrythm dot org>
*
* This file is part of ZPlugins
*
* ZPlugins is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* ZPlugins 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU General Affero Public License
* along with ZPlugins. If not, see <https://www.gnu.org/licenses/>.
*/
#include PLUGIN_CONFIG
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include "../math.h"
#include PLUGIN_COMMON
#include "lfo_math.h"
#define math_floats_almost_equal(a,b) \
(a > b ? \
(a - b) < 0.0001f : \
(b - a) < 0.0001f)
#define IS_FREERUN(x) (*x->freerun > 0.001f)
#define IS_STEP_MODE(x) (*x->step_mode > 0.001f)
#define IS_TRIGGERED(x) (*x->trigger > 0.001f)
#define IS_GATED_MODE(x) (*x->gated_mode > 0.001f)
#define IS_GATED(x) (*x->gate > 0.001f)
#define SINE_ON(x) (*x->sine_on > 0.001f)
#define SQUARE_ON(x) (*x->square_on > 0.001f)
#define TRIANGLE_ON(x) (*x->triangle_on > 0.001f)
#define SAW_ON(x) (*x->saw_on > 0.001f)
#define CUSTOM_ON(x) (*x->custom_on > 0.001f)
typedef struct LFO
{
/** Plugin ports. */
const LV2_Atom_Sequence* control;
LV2_Atom_Sequence* notify;
const float * gate;
const float * trigger;
const float * cv_gate;
const float * cv_trigger;
const float * gated_mode;
const float * freq;
const float * shift;
const float * range_min;
const float * range_max;
const float * step_mode;
const float * freerun;
const float * grid_step;
const float * sync_rate;
const float * sync_rate_type;
const float * hinvert;
const float * vinvert;
const float * sine_on;
const float * saw_on;
const float * square_on;
const float * triangle_on;
const float * custom_on;
const float * nodes[16][3];
const float * num_nodes;
/* outputs */
float * cv_out;
float * sine_out;
float * saw_out;
float * triangle_out;
float * square_out;
float * custom_out;
float * sample_to_ui;
/** This is how far we are inside a beat, from 0.0
* to 1.0. */
/*float beat_offset;*/
LfoCommon common;
/* FIXME this can be a local variable */
LV2_Atom_Forge_Frame notify_frame;
/** Whether the UI is active or not. */
int ui_active;
/** Temporary variables. */
/* whether the plugin was freerunning in the
* last cycle. this is used to detect changes
* in freerunning/sync. */
int was_freerunning;
/** Frequency during the last run. */
float last_freq;
float last_sync_rate;
float last_sync_rate_type;
/* These are used to detect changes so we
* can notify the UI. */
long last_period_size;
double last_samplerate;
/** Flag to be used to send messages to the
* UI. */
int first_run_with_ui;
} LFO;
static LV2_Handle
instantiate (
const LV2_Descriptor* descriptor,
double rate,
const char* bundle_path,
const LV2_Feature* const* features)
{
LFO * self = calloc (1, sizeof (LFO));
SET_SAMPLERATE (self, rate);
PluginCommon * pl_common = &self->common.pl_common;
int ret =
plugin_common_instantiate (
pl_common, features, 0);
if (ret)
goto fail;
/* map uris */
map_uris (pl_common->map, &self->common);
/* init atom forge */
lv2_atom_forge_init (
&pl_common->forge, pl_common->map);
/* init logger */
lv2_log_logger_init (
&pl_common->logger, pl_common->map, pl_common->log);
return (LV2_Handle) self;
fail:
free (self);
return NULL;
}
static void
recalc_multipliers (
LFO * self)
{
/* no ports connected yet */
if (!self->freerun)
return;
float sync_rate_float =
sync_rate_to_float (
*self->sync_rate,
*self->sync_rate_type);
/**
* Effective frequency.
*
* This is either the free-running frequency,
* or the frequency corresponding to the current
* sync rate.
*/
float effective_freq =
get_effective_freq (
IS_FREERUN (self), *self->freq,
&self->common.host_pos, sync_rate_float);
recalc_vars (
IS_FREERUN (self),
&self->common.sine_multiplier,
&self->common.saw_multiplier,
&self->common.period_size,
&self->common.current_sample,
&self->common.host_pos, effective_freq,
sync_rate_float,
(float) GET_SAMPLERATE (self));
}
static void
connect_port (
LV2_Handle instance,
uint32_t port,
void * data)
{
LFO * self = (LFO*) instance;
switch ((PortIndex) port)
{
case LFO_CONTROL:
self->control =
(const LV2_Atom_Sequence *) data;
break;
case LFO_NOTIFY:
self->notify =
(LV2_Atom_Sequence *) data;
break;
case LFO_CV_GATE:
self->cv_gate = (const float *) data;
break;
case LFO_CV_TRIGGER:
self->cv_trigger = (const float *) data;
break;
case LFO_GATE:
self->gate = (const float *) data;
break;
case LFO_TRIGGER:
self->trigger = (const float *) data;
break;
case LFO_GATED_MODE:
self->gated_mode = (const float *) data;
break;
case LFO_FREQ:
self->freq = (const float *) data;
break;
case LFO_SHIFT:
self->shift = (const float *) data;
break;
case LFO_RANGE_MIN:
self->range_min = (const float *) data;
break;
case LFO_RANGE_MAX:
self->range_max = (const float *) data;
break;
case LFO_STEP_MODE:
self->step_mode = (const float *) data;
break;
case LFO_FREE_RUNNING:
self->freerun = (const float *) data;
break;
case LFO_GRID_STEP:
self->grid_step = (const float *) data;
break;
case LFO_SYNC_RATE:
self->sync_rate = (const float *) data;
break;
case LFO_SYNC_RATE_TYPE:
self->sync_rate_type = (const float *) data;
break;
case LFO_HINVERT:
self->hinvert = (const float *) data;
break;
case LFO_VINVERT:
self->vinvert = (const float *) data;
break;
case LFO_SINE_TOGGLE:
self->sine_on = (const float *) data;
break;
case LFO_SAW_TOGGLE:
self->saw_on = (const float *) data;
break;
case LFO_SQUARE_TOGGLE:
self->square_on = (const float *) data;
break;
case LFO_TRIANGLE_TOGGLE:
self->triangle_on = (const float *) data;
break;
case LFO_CUSTOM_TOGGLE:
self->custom_on = (const float *) data;
break;
case LFO_SINE_OUT:
self->sine_out = (float *) data;
break;
case LFO_SAW_OUT:
self->saw_out = (float *) data;
break;
case LFO_TRIANGLE_OUT:
self->triangle_out = (float *) data;
break;
case LFO_SQUARE_OUT:
self->square_out = (float *) data;
break;
case LFO_CUSTOM_OUT:
self->custom_out = (float *) data;
break;
case LFO_SAMPLE_TO_UI:
self->sample_to_ui = (float *) data;
break;
case LFO_NUM_NODES:
self->num_nodes = (float *) data;
break;
default:
break;
}
if (port >= LFO_NODE_1_POS &&
port <= LFO_NODE_16_CURVE)
{
unsigned int prop =
(port - LFO_NODE_1_POS) % 3;
unsigned int node_id =
(port - LFO_NODE_1_POS) / 3;
self->nodes[node_id][prop] =
(const float *) data;
}
}
static void
send_position_to_ui (
LFO * self)
{
PluginCommon * pl_common = &self->common.pl_common;
/* forge container object of type time_Position */
lv2_atom_forge_frame_time (&pl_common->forge, 0);
LV2_Atom_Forge_Frame frame;
lv2_atom_forge_object (
&pl_common->forge, &frame, 0,
pl_common->uris.time_Position);
/* append property for bpm */
lv2_atom_forge_key (
&pl_common->forge,
pl_common->uris.time_beatsPerMinute);
lv2_atom_forge_float (
&pl_common->forge, self->common.host_pos.bpm);
/* append property for current sample */
lv2_atom_forge_key (
&pl_common->forge,
pl_common->uris.time_frame);
lv2_atom_forge_long (
&pl_common->forge,
self->common.host_pos.frame);
/* append speed */
lv2_atom_forge_key (
&pl_common->forge,
pl_common->uris.time_speed);
lv2_atom_forge_float (
&pl_common->forge,
self->common.host_pos.speed);
/* append beat unit */
lv2_atom_forge_key (
&pl_common->forge,
pl_common->uris.time_beatUnit);
lv2_atom_forge_int (
&pl_common->forge,
self->common.host_pos.beat_unit);
/* finish object */
lv2_atom_forge_pop (&pl_common->forge, &frame);
}
static void
send_messages_to_ui (
LFO * self,
int send_position)
{
PluginCommon * pl_common = &self->common.pl_common;
/* set up forge to write directly to notify
* output port */
const uint32_t notify_capacity =
self->notify->atom.size;
lv2_atom_forge_set_buffer (
&pl_common->forge, (uint8_t*) self->notify,
notify_capacity);
/* start a sequence in the notify output port */
lv2_atom_forge_sequence_head (
&pl_common->forge, &self->notify_frame, 0);
/* forge container object of type "ui_state" */
lv2_atom_forge_frame_time (&pl_common->forge, 0);
LV2_Atom_Forge_Frame frame;
lv2_atom_forge_object (
&pl_common->forge, &frame, 0,
self->common.uris.ui_state);
/* append property for current sample */
lv2_atom_forge_key (
&pl_common->forge,
self->common.uris.ui_state_current_sample);
lv2_atom_forge_long (
&pl_common->forge,
self->common.current_sample);
/* append property for period size */
lv2_atom_forge_key (
&pl_common->forge,
self->common.uris.ui_state_period_size);
lv2_atom_forge_long (
&pl_common->forge, self->common.period_size);
/* append samplerate */
lv2_atom_forge_key (
&pl_common->forge,
self->common.uris.ui_state_samplerate);
lv2_atom_forge_double (
&pl_common->forge, GET_SAMPLERATE (self));
/* append sine multiplier */
lv2_atom_forge_key (
&pl_common->forge,
self->common.uris.ui_state_sine_multiplier);
lv2_atom_forge_float (
&pl_common->forge,
self->common.sine_multiplier);
/* append saw multiplier */
lv2_atom_forge_key (
&pl_common->forge,
self->common.uris.ui_state_saw_multiplier);
lv2_atom_forge_float (
&pl_common->forge,
self->common.saw_multiplier);
/* finish object */
lv2_atom_forge_pop (&pl_common->forge, &frame);
if (send_position)
{
send_position_to_ui (self);
}
}
static void
activate (
LV2_Handle instance)
{
LFO * self = (LFO*) instance;
self->first_run_with_ui = 1;
recalc_multipliers (self);
}
static void
run (
LV2_Handle instance,
uint32_t n_samples)
{
LFO * self = (LFO *) instance;
PluginCommon * pl_common = &self->common.pl_common;
int xport_changed = 0;
/* read incoming events from host and UI */
LV2_ATOM_SEQUENCE_FOREACH (
self->control, ev)
{
if (lv2_atom_forge_is_object_type (
&pl_common->forge, ev->body.type))
{
const LV2_Atom_Object * obj =
(const LV2_Atom_Object*)&ev->body;
if (obj->body.otype ==
pl_common->uris.time_Position)
{
update_position_from_atom_obj (
&self->common, obj);
xport_changed = 1;
}
else if (obj->body.otype ==
self->common.uris.ui_on)
{
self->ui_active = 1;
self->first_run_with_ui = 1;
}
else if (obj->body.otype ==
self->common.uris.ui_off)
{
self->ui_active = 0;
}
}
}
int freq_changed =
!math_floats_almost_equal(
self->last_freq, *self->freq);
int is_freerunning = *self->freerun > 0.0001f;
int sync_or_freerun_mode_changed =
self->was_freerunning != is_freerunning;
int sync_rate_changed =
!(math_floats_almost_equal (
self->last_sync_rate, *self->sync_rate) &&
math_floats_almost_equal (
self->last_sync_rate_type,
*self->sync_rate_type));
/* if freq or transport changed, reset the
* multipliers */
if (xport_changed || freq_changed ||
sync_rate_changed ||
sync_or_freerun_mode_changed)
{
#if 0
fprintf (
stderr, "xport %d freq %d sync %d\n",
xport_changed, freq_changed,
sync_or_freerun_mode_changed);
#endif
recalc_multipliers (self);
}
float max_range =
MAX (*self->range_max, *self->range_min);
float min_range =
MIN (*self->range_max, *self->range_min);
float range = max_range - min_range;
float grid_step_divisor =
(float)
grid_step_to_divisor (
(GridStep) *self->grid_step);
long step_frames =
(long)
((float) self->common.period_size /
grid_step_divisor);
/* sort node curves by position */
NodeIndexElement node_indices[
(int) *self->num_nodes];
float nodes[16][3];
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 3; j++)
{
nodes[i][j] = *(self->nodes[i][j]);
}
}
sort_node_indices_by_pos (
nodes, node_indices,
(int) *self->num_nodes);
/* handle control trigger */
if (IS_TRIGGERED (self))
{
self->common.current_sample = 0;
}
for (uint32_t i = 0; i < n_samples; i++)
{
/* handle cv trigger */
if (self->cv_trigger[i] > 0.00001f)
self->common.current_sample = 0;
/* invert horizontally */
long shifted_current_sample =
invert_and_shift_xval (
self->common.current_sample,
self->common.period_size,
*self->hinvert >= 0.01f,
*self->shift);
if (IS_STEP_MODE (self))
{
/* find closest step and set the current
* sample to the middle of it */
shifted_current_sample =
(shifted_current_sample / step_frames) *
step_frames +
step_frames / 2;
}
float ratio =
(float) shifted_current_sample /
(float) self->common.period_size;
if (SINE_ON (self))
{
/* calculate sine */
self->sine_out[i] =
sinf (
((float) shifted_current_sample *
self->common.sine_multiplier));
}
if (SAW_ON (self))
{
/* calculate saw */
self->saw_out[i] =
(1.f - ratio) * 2.f - 1.f;
}
if (TRIANGLE_ON (self))
{
if (ratio > 0.4999f)
{
self->triangle_out[i] =
(1.f - ratio) * 4.f - 1.f;
}
else
{
self->triangle_out[i] =
ratio * 4.f - 1.f;
}
}
if (SQUARE_ON (self))
{
if (ratio > 0.4999f)
{
self->square_out[i] = - 1.f;
}
else
{
self->square_out[i] = 1.f;
}
}
if (CUSTOM_ON (self))
{
int prev_idx =
get_prev_idx (
node_indices, (int) * self->num_nodes,
(float) ratio);
int next_idx =
get_next_idx (
node_indices, (int) * self->num_nodes,
(float) ratio);
/* calculate custom */
self->custom_out[i] =
get_custom_val_at_x (
*self->nodes[prev_idx][0],
*self->nodes[prev_idx][1],
*self->nodes[prev_idx][2],
next_idx < 0 ? 1.f :
*self->nodes[next_idx][0],
next_idx < 0 ?
*self->nodes[0][1] :
*self->nodes[next_idx][1],
next_idx < 0 ?
*self->nodes[0][2] :
*self->nodes[next_idx][2],
shifted_current_sample,
self->common.period_size);
/* adjust for -1 to 1 */
self->custom_out[i] =
self->custom_out[i] * 2 - 1;
}
/* invert vertically */
if (*self->vinvert >= 0.01f)
{
#define INVERT(x) \
self->x##_out[i] = - self->x##_out[i]
INVERT (sine);
INVERT (saw);
INVERT (triangle);
INVERT (square);
INVERT (custom);
#undef INVERT
}
/* if in gating mode and gate is not active,
* set all output to zero */
if (IS_GATED_MODE (self) &&
!(IS_GATED (self) || self->cv_gate[i] > 0.001f))
{
self->sine_out[i] = 0.f;
self->saw_out[i] = 0.f;
self->triangle_out[i] = 0.f;
self->square_out[i] = 0.f;
self->custom_out[i] = 0.f;
}
/* adjust range */
#define ADJUST_RANGE(x) \
self->x##_out[i] = \
min_range + \
((self->x##_out[i] + 1.f) / 2.f) * range
ADJUST_RANGE (sine);
ADJUST_RANGE (saw);
ADJUST_RANGE (triangle);
ADJUST_RANGE (square);
ADJUST_RANGE (custom);
#undef ADJUST_RANGE
if (is_freerunning ||
(!is_freerunning &&
self->common.host_pos.speed >
0.00001f))
{
self->common.current_sample++;
}
if (self->common.current_sample ==
self->common.period_size)
self->common.current_sample = 0;
}
#if 0
fprintf (
stderr, "current sample %ld, "
"period size%ld\n",
self->current_sample, self->period_size);
#endif
if (self->ui_active &&
(self->common.period_size !=
self->last_period_size ||
!math_doubles_equal (
GET_SAMPLERATE (self),
self->last_samplerate) ||
xport_changed ||
self->first_run_with_ui))
{
/*fprintf (stderr, "sending messages\n");*/
send_messages_to_ui (self, xport_changed);
self->first_run_with_ui = 0;
}
/* set current sample for UI to pick up */
*self->sample_to_ui =
(float) self->common.current_sample;
/* remember values */
self->last_freq = *self->freq;
self->last_sync_rate = *self->sync_rate;
self->last_sync_rate_type = *self->sync_rate_type;
self->was_freerunning = is_freerunning;
self->last_period_size =
self->common.period_size;
self->last_samplerate = GET_SAMPLERATE (self);
}
static void
deactivate (
LV2_Handle instance)
{
}
static void
cleanup (
LV2_Handle instance)
{
free (instance);
}
static const void*
extension_data (
const char* uri)
{
return NULL;
}
static const LV2_Descriptor descriptor = {
PLUGIN_URI,
instantiate,
connect_port,
activate,
run,
deactivate,
cleanup,
extension_data
};
LV2_SYMBOL_EXPORT
const LV2_Descriptor*
lv2_descriptor (
uint32_t index)
{
switch (index)
{
case 0:
return &descriptor;
default:
return NULL;
}
}

514
plugins/lfo/lfo_math.h

@ -0,0 +1,514 @@ @@ -0,0 +1,514 @@
/*
* Copyright (C) 2019-2020 Alexandros Theodotou <alex at zrythm dot org>
*
* This file is part of ZLFO
*
* ZLFO is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* ZLFO 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU General Affero Public License
* along with ZLFO. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file
*
* Math module.
*/
#ifndef __Z_LFO_MATH_H__
#define __Z_LFO_MATH_H__
#include PLUGIN_CONFIG
#include <float.h>
#include <math.h>
#include "common.h"
static inline float
sync_rate_to_float (
SyncRate rate,
SyncRateType type)
{
float r = 0.01f;
switch (rate)
{
case SYNC_1_128:
r = 1.f / 128.f;
break;
case SYNC_1_64:
r = 1.f / 64.f;
break;
case SYNC_1_32:
r = 1.f / 32.f;
break;
case SYNC_1_16:
r = 1.f / 16.f;
break;
case SYNC_1_8:
r = 1.f / 8.f;
break;
case SYNC_1_4:
r = 1.f / 4.f;
break;
case SYNC_1_2:
r = 1.f / 2.f;
break;
case SYNC_1_1:
r = 1.f;
break;
case SYNC_2_1:
r = 2.f;
break;
case SYNC_4_1:
r = 4.f;
break;
case SYNC_8_1:
r = 8.f;
break;
case SYNC_16_1:
r = 16.f;
break;
case SYNC_32_1:
r = 32.f;
break;
case SYNC_64_1:
r = 64.f;
break;
case SYNC_128_1:
r = 128.f;
break;
default:
break;
}
switch (type)
{
case SYNC_TYPE_NORMAL:
break;
case SYNC_TYPE_DOTTED:
r *= 1.5f;
break;
case SYNC_TYPE_TRIPLET:
r *= (2.f / 3.f);
break;
default:
break;
}
return r;
}
/**
* Returns the number to use for dividing by the
* grid step.
*
* Eg., when grid step is HALF, this returns 2, the
* bottom half of "1/2".
*/
static inline int
grid_step_to_divisor (
GridStep step)
{
int ret = 0;
switch (step)
{
case GRID_STEP_FULL:
ret = 1;
break;
case GRID_STEP_HALF:
ret = 2;
break;
case GRID_STEP_FOURTH:
ret = 4;
break;
case GRID_STEP_EIGHTH:
ret = 8;
break;
case GRID_STEP_SIXTEENTH:
ret = 16;
break;
case GRID_STEP_THIRTY_SECOND:
ret = 32;
break;
default:
break;
}
return ret;
}
/**
* Gets the y value for a node at the given X coord.
*
* See https://stackoverflow.com/questions/17623152/how-map-tween-a-number-based-on-a-dynamic-curve
* @param x X-coordinate.
* @param curviness Curviness variable (1.0 is
* a straight line, 0.0 is full curved).
* @param start_higher Start at higher point.
*/
static inline double
get_y_normalized (
double x,
double curviness,
CurveAlgorithm algo,
int start_higher,
int curve_up)
{
if (!start_higher)
x = 1.0 - x;
if (curve_up)
x = 1.0 - x;
double val;
switch (algo)
{
case CURVE_ALGORITHM_EXPONENT:
val =
pow (x, curviness);
break;
case CURVE_ALGORITHM_SUPERELLIPSE:
val =
pow (
1.0 - pow (x, curviness),
(1.0 / curviness));
break;
}
if (curve_up)
{
val = 1.0 - val;
}
return val;
fprintf (
stderr, "This line should not be reached");
}
static inline float
get_frames_per_beat (
float bpm,
float samplerate)
{
return 60.0f / bpm * samplerate;
}
static inline float
get_effective_freq (
int freerunning,
float freq,
HostPosition * host_pos,
float sync_rate_float)
{
/* if beat_unit is 0 that means we don't know the
* time info yet */
if (freerunning || host_pos->beat_unit == 0)
{
if (!freerunning && host_pos->beat_unit == 0)
{
fprintf (
stderr,
"Host did not send time info. Beat "
"unit is unknown.\n");
}
return freq;
}
else /* synced */
{
/* bpm / (60 * BU * sync note) */
return
host_pos->bpm /
(60.f *
host_pos->beat_unit * sync_rate_float);
}
}
static inline uint32_t
get_period_size (
int freerunning,
HostPosition * host_pos,
float effective_freq,
float sync_rate_float,
float frames_per_beat,
float samplerate)
{
/* if beat_unit is 0 that means we don't know the
* time info yet */