Tags: IDMIL/libmapper
Tags
Changes from 0.4 to 1.0 ----------------------- Released Jan 4, 2016. This is release includes many API changes, improvements, and new features since 0.4. They are summarized very briefly here: The data structures in libmapper have been reconceived to increase consistency and clarity. Some data structures have been merged and/or renamed: * `mapper_device` + `mapper_db_device` ––> `mapper_device` * `mapper_signal` + `mapper_db_signal` ––> `mapper_signal` * `mapper_link` + `mapper_db_link` ––> `mapper_link` * `mapper_connection` + `mapper_db_connection` ––> `mapper_map` * `mapper_admin` ––> `mapper_network` * `mapper_monitor` ––> (removed) * `mapper_db` ––> `mapper_database` This means that the database now represents remote devices and signals using the same data structures that are used for local devices and signals. Property getter and setter functions for these structures are the same whether the entity is local or remote. The property getter `<object>_is_local()` can be used to retrieve whether the data structure represents a local resource. The `mapper_map` structure is now a "top-level" object, and is used for creating, modifying, and destroying mapping connections. Changes to a map (and to other structures that represent non-local resources) must be explicitly synchronized with the network using the `_push()` function, e.g.: mapper_map map = mapper_map_new(num_srcs, outsigs, insig); mapper_map_set_expression(map, "y=x+2"); mapper_map_push(map); Or in C++: mapper::Map map(outsig, insig); map.set_expression("y=x+2"); map.push(); Or in Python: map = mapper.map(outsig, insig) map.expression = "y=x+2" map.push() Or in Java: mapper.Map map = new mapper.Map(outsig, insig); map.setExpression("y=x+2"); map.push(); In all these cases the arguments for the map constructor are no longer the *names* of the signals in question, but are **signal objects**: `mapper_signal` in C, `mapper::Signal` in C++, etc. These could be local signals or signals retrieved from the database. There is also a new data structure called `mapper_slot` for representing map endpoints (see below under **convergent mapping**). This means that for properties such as minimum, maximum, and boundary behaviours it is the *slot* property that needs to be set. The names of many functions have been changed to make them consistent with the names of the data structures they concern, e.g. `mdev_poll()` has been renamed to `mapper_device_poll()`. Previous versions of libmapper contained many duplicate functions for accessing e.g. signals belonging to a device: one for retrieving them from a `mapper_device` and another for retrieving them from the database. In version 0.5 all object queries have been unified, and children of objects (e.g. signals, maps) are retrieved by querying their parent. For example, all devices can be retrieved from the database like this: mapper_device *devs = mapper_database_devices(db); while (devs) { printf("retrieved device '%s'\n", mapper_device_name(*devs)); devs = mapper_device_query_next(devs); } The old way of retrieving the output signals belonging to a particular device was to call: mapper_db_signal *sigs = mapper_db_get_outputs_by_device_name(db, name); and the new way: mapper_device dev = mapper_database_device_by_name(db, name); mapper_signal *sigs = mapper_device_signals(dev, MAPPER_DIR_OUTGOING); Queries can be combined using `union`, `intersection`, or `difference` operators, making it easy to e.g. find maps with a specific source and destination device without requiring a dedicated function to do so: mapper_map *src, *dst, *combo; src = mapper_device_maps(src_dev, MAPPER_DIR_OUTGOING); dst = mapper_device_maps(dst_dev, MAPPER_DIR_INCOMING); combo = mapper_map_query_intersection(src, dst); while (combo) { mapper_map_pp(*combo); maps = mapper_map_query_next(combo); } The data structures `mapper_device`, `mapper_signal`, and `mapper_map` can also now be queried by arbitrary property, making it quite easy to build arbitrary queries: // retrieve all maps with the property 'foo' where its value is < 10 int value = 10; mapper_map *maps = mapper_database_maps_by_property(db, "foo", 1, 'i', &value, MAPPER_OP_LESS_THAN); *Convergent* (or *many-to-one*) mapping refers to scenarios in which multiple source signals are connected to the same destination signal. Prior to 0.5, libmapper would allow a naïve implementation of convergent mapping: multiple sources could be connected to a given destination, but their values would overwrite each other at each source update. Starting with version 0.5, three other methods for convergent mapping are also available: * _Updating specific vector elements or element ranges_. By using the vector indexing functionality mentioned above, parts of vector destinations can be updated by different sources; vectors updates are now null-padded so elements not addressed in the expression property will not be overwritten * _Destination value reference_. References to past values of the destination in the expression string (e.g. `y=y{-1}+x`) now refer to the _actual value_ of the destination signal rather than the output of the expression. If the past behaviour is desired, a user-defined variable can be used to cache the expression output (e.g. `foo=foo+x; y=foo`). Note that if the destination value is referenced in the expression string, libmapper will automatically move signal processing to the destination device. * _Multi-source maps_. Lastly, maps can now be created with multiple source signals, and expressions can specify arbitrary combinations of the source values. To support this functionality, the endpoints of maps are now represented using the `mapper_slot` data structure; each map has a single destination slot and at least one source slot. Several properties that used to belong to connections have been moved to the map slots: * `map->range` ––> `slot->minimum` and `slot->maximum` * `map->bound_max` ––> `slot->bound_max` * `map->bound_min` ––> `slot->bound_min` * `map->send_as_instance` ––> `slot->use_as_instance` Calibration used to be specified using the connection mode `MO_CALIBRATE`. It is specified using the slot property `calibrating`. If all source slots belong to the same device, signal processing will be handled by the source device by default, otherwise the destination will handle evaluation of the expression. This can be controlled by setting the `process_location` property of a map to either `MAPPER_LOC_SOURCE` or `MAPPER_LOC_DESTINATION`. If a map has sources from different devices, or if the map expression references the value of the destination (`y{-n}`) the processing location will be set to `MAPPER_LOC_DESTINATION`. The `mode` property of maps has changed a bit: * `MO_BYPASS` has been removed since it didn't really describe what was going on - although the expression evaluator was not being called the updates were still undergoing type-coercion and vector padding/truncation. There is a new mode called `MAPPER_MODE_RAW` that is used internally only when setting up convergent maps. * `MO_REVERSE` has been removed and replaced with directed maps; if a map from a sink signal to a source signal is desired it is simply set up that way, e.g. `mapper_map_new(sink_sig, source_sig)`. * `MO_CALIBRATE` has been removed and replaced with the `mapper_slot` property `calibrating`. * `MO_EXPRESSION` has been renamed `MAPPER_MODE_EXPRESSION` * `MO_LINEAR` has been renamed `MAPPER_MODE_LINEAR` There have also been a number of internal improvements that have minimal effect on the API but improve memory-management and add functionality * *Memory management:* Memory is now recovered from dropped connections, e.g. when a peer device crashes or doesn't disconnect properly. * *Links.* Devices now create network links automatically as needed. * *Protocol changes:* In addition to the database subscription changes, some other updates have been made to the libmapper protocol: * null-padding of incomplete vector updates * references to maps in the protocol now have an explicit direction, e.g. `/map ,sss "/srcdev.1/srcsig" "->" "/dstdev.1/dstsig"`. This means that maps can now be defined between **any** set of signals, including `output->input` (a "normal" connection), `input->output` (was a "reverse-mode" connection in previous versions), `output->output`, and `input->input` * instance updates are explicitly tagged with their index, i.e. `@instance 2` * *Efficient polling:* select() is now used internally to wait on servers, resulting in less wasted processing and more responsive performance. * *C++.* Headers and tests for C++ have been added to the distribution, and are mostly complete. * *Python.* The SWIG/Python bindings have been largely rewritten to support API changes in libmapper and for consistency with other object-oriented libmapper bindings (C++, Java). * *Java.* The jni bindings have been largely rewritten to support API changes in libmapper and to improve consistency.