78 changed files with 9773 additions and 91 deletions
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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; |
||||
} |
||||
} |
@ -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 */ |