Commit df67bce1 authored by Hanspeter Portner's avatar Hanspeter Portner

make Options interface fully dynamic.

* now returns full atoms.
parent 656faa60
......@@ -7,4 +7,4 @@
* doc: Parameter
* api: simplify forge:vector
* api: simplify forge:set
* api: design Options interface as function
* api: Options iterator
......@@ -407,6 +407,31 @@ _log(lua_State *L)
return 0;
}
__realtime static int
_options(lua_State *L)
{
moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
const LV2_URID key = luaL_checkinteger(L, 1);
if(moony->opts)
{
for(LV2_Options_Option *opt = moony->opts;
(opt->key != 0) && (opt->value != NULL);
opt++)
{
if(opt->key == key)
{
const LV2_Atom *atom = (const LV2_Atom *)&opt->size;
_latom_body_new(L, atom, opt->value, false);
return 1;
}
}
}
lua_pushnil(L); // not found
return 1;
}
__realtime LV2_Atom_Forge_Ref
_sink_rt(LV2_Atom_Forge_Sink_Handle handle, const void *buf, uint32_t size)
{
......@@ -1092,6 +1117,8 @@ __non_realtime int
moony_init(moony_t *moony, const char *subject, double sample_rate,
const LV2_Feature *const *features, size_t mem_size, bool testing)
{
moony->sample_rate = sample_rate;
atomic_init(&moony->state_atom_new, 0);
atomic_init(&moony->vm_new, 0);
atomic_init(&moony->err_new, 0);
......@@ -1114,7 +1141,6 @@ moony_init(moony_t *moony, const char *subject, double sample_rate,
return -1;
}
LV2_Options_Option *opts = NULL;
bool load_default_state = false;
for(unsigned i=0; features[i]; i++)
......@@ -1128,7 +1154,7 @@ moony_init(moony_t *moony, const char *subject, double sample_rate,
else if(!strcmp(features[i]->URI, LV2_LOG__log))
moony->log = features[i]->data;
else if(!strcmp(features[i]->URI, LV2_OPTIONS__options))
opts = features[i]->data;
moony->opts = features[i]->data;
else if(!strcmp(features[i]->URI, LV2_OSC__schedule))
moony->osc_sched = features[i]->data;
else if(!strcmp(features[i]->URI, LV2_STATE__loadDefaultState))
......@@ -1180,15 +1206,6 @@ moony_init(moony_t *moony, const char *subject, double sample_rate,
moony->uris.midi_event = moony->map->map(moony->map->handle, LV2_MIDI__MidiEvent);
moony->uris.bufsz_min_block_length = moony->map->map(moony->map->handle,
LV2_BUF_SIZE__minBlockLength);
moony->uris.bufsz_max_block_length = moony->map->map(moony->map->handle,
LV2_BUF_SIZE__maxBlockLength);
moony->uris.bufsz_sequence_size = moony->map->map(moony->map->handle,
LV2_BUF_SIZE__sequenceSize);
moony->uris.ui_update_rate= moony->map->map(moony->map->handle,
LV2_UI__updateRate);
moony->uris.patch.self = moony->map->map(moony->map->handle, subject);
moony->uris.patch.get = moony->map->map(moony->map->handle, LV2_PATCH__Get);
......@@ -1288,24 +1305,6 @@ moony_init(moony_t *moony, const char *subject, double sample_rate,
assert(pos == DRIVER_HASH_MAX);
qsort(latom_driver_hash, DRIVER_HASH_MAX, sizeof(latom_driver_hash_t), _hash_sort);
if(opts)
{
for(LV2_Options_Option *opt = opts;
(opt->key != 0) && (opt->value != NULL);
opt++)
{
if(opt->key == moony->uris.bufsz_min_block_length)
moony->opts.min_block_length = *(int32_t *)opt->value;
else if(opt->key == moony->uris.bufsz_max_block_length)
moony->opts.max_block_length = *(int32_t *)opt->value;
else if(opt->key == moony->uris.bufsz_sequence_size)
moony->opts.sequence_size = *(int32_t *)opt->value;
else if(opt->key == moony->uris.ui_update_rate)
moony->opts.update_rate = *(float *)opt->value;
}
}
moony->opts.sample_rate = sample_rate;
moony->dirty_out = true; // trigger update of UI
moony->props_out = true; // trigger update of UI
......@@ -1433,8 +1432,6 @@ moony_open(moony_t *moony, moony_vm_t *vm, lua_State *L)
urid; \
})
LV2_URID core_sample_rate;
lua_newtable(L);
{
SET_MAP(L, LV2_CORE__, ControlPort);
......@@ -1529,7 +1526,6 @@ moony_open(moony_t *moony, moony_vm_t *vm, lua_State *L)
lua_newtable(L);
{
core_sample_rate = SET_MAP(L, LV2_CORE__, sampleRate);
SET_MAP(L, LV2_CORE__, minimum);
SET_MAP(L, LV2_CORE__, maximum);
SET_MAP(L, LV2_CORE__, scalePoint);
......@@ -1683,53 +1679,22 @@ moony_open(moony_t *moony, moony_vm_t *vm, lua_State *L)
{
SET_MAP(L, MOONY__, color);
SET_MAP(L, MOONY__, syntax);
//TODO more
}
lua_setglobal(L, "Moony");
lua_newtable(L);
{
SET_MAP(L, LUA__, lang);
SET_MAP(L, LV2_PARAMETERS__, sampleRate);
//TODO more
}
lua_setglobal(L, "Lua");
lua_setglobal(L, "Param");
lua_newtable(L);
{
if(moony->opts.min_block_length)
{
lua_pushinteger(L, moony->uris.bufsz_min_block_length);
lua_pushinteger(L, moony->opts.min_block_length);
lua_rawset(L, -3);
}
if(moony->opts.max_block_length)
{
lua_pushinteger(L, moony->uris.bufsz_max_block_length);
lua_pushinteger(L, moony->opts.max_block_length);
lua_rawset(L, -3);
}
if(moony->opts.sequence_size)
{
lua_pushinteger(L, moony->uris.bufsz_sequence_size);
lua_pushinteger(L, moony->opts.sequence_size);
lua_rawset(L, -3);
}
if(moony->opts.sample_rate)
{
lua_pushinteger(L, core_sample_rate);
lua_pushnumber(L, moony->opts.sample_rate);
lua_rawset(L, -3);
}
if(moony->opts.update_rate)
{
lua_pushinteger(L, moony->uris.ui_update_rate);
lua_pushnumber(L, moony->opts.update_rate);
lua_rawset(L, -3);
}
SET_MAP(L, LUA__, lang);
}
lua_setglobal(L, "Options");
lua_setglobal(L, "Lua");
// create userdata caches
lua_newtable(L);
......@@ -1745,6 +1710,11 @@ moony_open(moony_t *moony, moony_vm_t *vm, lua_State *L)
lua_pushcclosure(L, _log, 2);
lua_setglobal(L, "print");
// Options
lua_pushlightuserdata(L, moony); // @ upvalueindex 1
lua_pushcclosure(L, _options, 1);
lua_setglobal(L, "Options");
// MIDIResponder metatable
luaL_newmetatable(L, "lmidiresponder");
lua_pushlightuserdata(L, moony); // @ upvalueindex 1
......
......@@ -137,6 +137,21 @@ _latom_vec_foreach_itr(lua_State *L);
int
_latom_seq_multiplex_itr(lua_State *L);
__realtime static inline latom_t *
_latom_body_new(lua_State *L, const LV2_Atom *atom, const void *body, bool cache)
{
moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
latom_t *latom = moony_newuserdata(L, moony, MOONY_UDATA_ATOM, cache);
if(atom)
{
latom->atom = atom;
latom->body.raw = body;
}
return latom;
}
__realtime static inline latom_t *
_latom_new(lua_State *L, const LV2_Atom *atom, bool cache)
{
......
......@@ -296,7 +296,7 @@ _ltimeresponder(lua_State *L)
// TODO do we want to cache/reuse this, too?
timely_t *timely = lua_newuserdata(L, sizeof(timely_t)); // userdata
timely_init(timely, moony->map, moony->opts.sample_rate, mask,
timely_init(timely, moony->map, moony->sample_rate, mask,
_ltimeresponder_cb, L);
timely_set_multiplier(timely, multiplier);
......
......@@ -43,6 +43,7 @@
#include <lv2/lv2plug.in/ns/ext/buf-size/buf-size.h>
#include <lv2/lv2plug.in/ns/ext/options/options.h>
#include <lv2/lv2plug.in/ns/ext/patch/patch.h>
#include <lv2/lv2plug.in/ns/ext/parameters/parameters.h>
#include <lv2/lv2plug.in/ns/lv2core/lv2.h>
#include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
#include <lv2/lv2plug.in/ns/extensions/units/units.h>
......@@ -216,6 +217,8 @@ struct _patch_t {
struct _moony_t {
LV2_URID_Map *map;
LV2_URID_Unmap *unmap;
LV2_Options_Option *opts;
LV2_Atom_Forge forge;
LV2_Atom_Forge state_forge;
LV2_Atom_Forge stash_forge;
......@@ -224,6 +227,8 @@ struct _moony_t {
LV2_Atom_Forge_Frame notify_frame;
LV2_Atom_Forge_Ref notify_ref;
double sample_rate;
struct {
LV2_URID moony_code;
LV2_URID moony_selection;
......@@ -242,11 +247,6 @@ struct _moony_t {
LV2_URID midi_event;
LV2_URID bufsz_max_block_length;
LV2_URID bufsz_min_block_length;
LV2_URID bufsz_sequence_size;
LV2_URID ui_update_rate;
patch_t patch;
LV2_URID rdfs_label;
......@@ -268,14 +268,6 @@ struct _moony_t {
LV2_URID atom_frame_time;
} uris;
struct {
uint32_t max_block_length;
uint32_t min_block_length;
uint32_t sequence_size;
float sample_rate;
float update_rate;
} opts;
LV2_OSC_URID osc_urid;
LV2_OSC_Schedule *osc_sched;
......
......@@ -1654,7 +1654,7 @@ function stash(forge)
tup:char(string.byte('c')) -- 'c'char
tup:rgba(0xbb0000ff) -- reddish, 'r'gba
tup:midi(MIDI.NoteOn, Note['C-0'], 64) -- 'm'idi
tup:urid(Core.sampleRate) -- 'S'ymbol
tup:urid(Param.sampleRate) -- 'S'ymbol
end
end
end</code></pre>
......@@ -3009,24 +3009,24 @@ assert(io.body == 13)</code></pre>
If the host exports those values, they may be queried via the options table.</p>
<dl>
<dt class="func">Options:__index(key) | Options[key]</dt>
<dt class="func">Options:__call(key)</dt>
<dt>key (integer)</dt>
<dd>key to index options table with as integer URID, valid keys are:
Core.sampleRate, Buf_Size.sequenceSize, Buf_Size.minBlockLength, Buf_Size.maxBlockLength</dd>
<dt class="ret">(integer)</dt>
<dd>value of index key</dd>
<dd>key to index options table with as integer URID, e.g. valid keys are:
Param.sampleRate, Buf_Size.sequenceSize, Buf_Size.minBlockLength, Buf_Size.maxBlockLength, Ui.updateRate</dd>
<dt class="ret">(userdata)</dt>
<dd>value of indexed key as atom object</dd>
</dl>
<pre><code data-ref="options">-- Options
-- sample rate is always available
local sampleRate = Options[Core.sampleRate]
assert(sampleRate == 48000)
local sampleRate = Options(Param.sampleRate)
assert(sampleRate.body == 48000)
-- only available if exported by host
local sequenceSize = Options[Buf_Size.sequenceSize]
local minBlockLength = Options[Buf_Size.minBlockLength]
local maxBlockLength = Options[Buf_Size.maxBlockLength]</code></pre>
local sequenceSize = Options(Buf_Size.sequenceSize)
local minBlockLength = Options(Buf_Size.minBlockLength)
local maxBlockLength = Options(Buf_Size.maxBlockLength)</code></pre>
</div>
<!-- Responder -->
......@@ -3812,6 +3812,7 @@ assert(ascii85.decode(encoded) == value)</code></pre>
local ctx = {
core = HashMap('http://lv2plug.in/ns/lv2core#'),
param = HashMap('http://lv2plug.in/ns/ext/parameters#'),
atom = HashMap('http://lv2plug.in/ns/ext/atom#'),
time = HashMap('http://lv2plug.in/ns/ext/time#'),
midi = HashMap('http://lv2plug.in/ns/ext/midi#'),
......@@ -3819,7 +3820,7 @@ local ctx = {
patch = HashMap('http://lv2plug.in/ns/ext/patch#'),
units = HashMap('http://lv2plug.in/ns/extensions/units#'),
osc = HashMap('http://open-music-kontrollers.ch/lv2/osc#'),
rdf = HashMap('http://www.w3.org/1999/02/22-rdf-syntax-ns#'),
rdf = HashMap('http://www.w3.org/1999/02/22-rdf-syntax-ns#'),
rdfs = HashMap('http://www.w3.org/2000/01/rdf-schema#'),
}
......@@ -3882,8 +3883,10 @@ assert(OSC.Impulse == ctx.osc.Impulse)
assert(OSC.Char == ctx.osc.Char)
assert(OSC.RGBA == ctx.osc.RGBA)
-- LV2 Param URID constants
assert(Param.sampleRate == ctx.param.sampleRate)
-- LV2 Core URID constants
assert(Core.sampleRate == ctx.core.sampleRate)
assert(Core.minimum == ctx.core.minimum)
assert(Core.maximum == ctx.core.maximum)
assert(Core.scalePoint == ctx.core.scalePoint)
......
......@@ -474,7 +474,6 @@ local osc_lib = lib_const('OSC', {
})
local core_lib = lib_const('Core', {
'sampleRate', --FIXME Properties
'minimum',
'maximum',
'scalePoint'
......@@ -617,9 +616,13 @@ local lua_lib = lib_const('Lua', {
'lang'
})
local param_lib = lib_const('Param', {
'sampleRate'
})
local api_lib = atom_lib + midi_lib + time_lib + osc_lib + core_lib + bufsz_lib
+ patch_lib + rdfs_lib + rdf_lib + units_lib + ui_lib + canvas_lib + moony_lib
+ lua_lib
+ lua_lib + param_lib
-- Field functions
local field_func = token(T.OPERATOR, S('.:')) * token(T.FUNCTION, word_match{
......
......@@ -678,7 +678,7 @@ local chord = {0, 3, 7, 11} -- table with chord note offsets
local offset = 0.1 -- time offset between notes in seconds
local schedule = {} -- table to store Note events
local dur = math.floor(offset * Options[Core.sampleRate]) -- time offset in frames
local dur = math.floor(offset * Options(Param.sampleRate).body) -- time offset in frames
-- compare function to sort scheduled messages according to frame time
local function cmp(a, b)
......
......@@ -204,6 +204,23 @@ main(int argc, char **argv)
.vprintf = _vprintf
};
const LV2_URID param_sampleRate = map.map(map.handle, LV2_PARAMETERS__sampleRate);
const LV2_URID atom_Float = map.map(map.handle, LV2_ATOM__Float);
const float srate = 48000.f;
LV2_Options_Option opts [] = {
{
.key = param_sampleRate,
.size = sizeof(float),
.type = atom_Float,
.value = &srate
},
{
.key = 0,
.value =NULL
}
};
const LV2_Feature feat_map = {
.URI = LV2_URID__map,
.data = &map
......@@ -220,17 +237,22 @@ main(int argc, char **argv)
.URI = LV2_LOG__log,
.data = &log
};
const LV2_Feature feat_opts = {
.URI = LV2_OPTIONS__options,
.data = opts
};
const LV2_Feature *const features [] = {
&feat_map,
&feat_unmap,
&feat_sched,
&feat_log,
&feat_opts,
NULL
};
if(moony_init(&handle.moony, "http://open-music-kontrollers.ch/lv2/moony#test",
48000, features, 0x800000, true)) // 8MB initial memory
srate, features, 0x800000, true)) // 8MB initial memory
{
return -1;
}
......
......@@ -1261,12 +1261,10 @@ end
-- Options
print('[test] Options')
do
assert(Core.sampleRate == Map['http://lv2plug.in/ns/lv2core#sampleRate'])
assert(Options[Core.sampleRate] == 48000)
assert(Options[Buf_Size.minBlockLength] == nil)
assert(Options[Buf_Size.maxBlockLength] == nil)
assert(Options[Buf_Size.sequenceSize] == nil)
assert(Options(Param.sampleRate).body == 48000)
assert(Options(Buf_Size.minBlockLength) == nil)
assert(Options(Buf_Size.maxBlockLength) == nil)
assert(Options(Buf_Size.sequenceSize) == nil)
end
-- Patch
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment