Planet XMMS2

October 29, 2011

XMMS2 Offical News Channel

GSoC Summit 2011


The Summit was a blast as usual... glasses of beer got emptied.. sweet sweet CA sun was thoroughly enjoyed... future development conspiracies got planned.. very cool announcements were heard.. bits and bytes got exchanged.. visions were born.. hope to see you next year!




by Daniel Svensson (noreply@blogger.com) at October 29, 2011 06:09 PM

October 20, 2011

XMMS2 Offical News Channel

XMMS2 0.8 DrO_o is out!

Finally!

A long long long overdue release, mostly due to the developers having more fun with the next release, DrParnassus, instead of getting this release out (~300 commits screaming to be merged).

DrO_o can be considered a service/polish release to DrNo, and should not contain any big surprises to the end user. On the development side there are some new nice features that we've been wanting on for a long time now.

As usual there was a lot (33!) of people...

Adam Nielsen, Anders Waldenborg, Anthony Garcia, Benjamin Drung, Benjamin Schmitz, Brad Jorsch, Christopher Rosell, Daniel Svensson, David Richards, Dries Harnie, Erik Massop, Fabian Roth, Frank Dischner, Frank Terbeck, Guilherme Gonçalves, Henrik Gustafsson, Hugh Davenport, Igor Byelogurov, Jan Braun, Jari Aalto, Juan Antonio Osorio, Juho Vähä-Herttua, Raphaël Bois, Richard Kralovic, Rémi Vanicat, Sebastien Cevey, Sergei Trofimovich, Thomas Frauendorfer, Tilman Sauerbeck, Timo Paulssen, Tobias Hieta, Uli Franke, Yang Zhe

...involved in in getting this release out, they have our gratitude!

It's available for download over at SourceForge as usual:

by Daniel Svensson (noreply@blogger.com) at October 20, 2011 07:49 PM

September 04, 2011

Juho Vähä-Herttua

What's left to be done now

The GSoC project time is officially over, but the multichannel and resampler project of XMMS2 is not quite over yet. Biggest setback that came up was the fact that libresample and other related libraries didn't support multichannel interleaving, so that needs to be done manually instead. My attempt at hacking it into the sample.c was a big failure and resulted in spaghetti code, so it's better to do it properly. The list of things to do now is somewhat:
  1. Write a clean resampler interface that can use both libresample (LGPL) and libsamplerate (GPL) and doesn't depend on XMMS2. If it is possible to make it resemble libsamplerate API a lot of other applications might benefit from it as well.
  2. Patch the current sample.c code to use the cleaner resampler interface, which should be quite straightforward.
  3. Write the converter plugin support for multichannel, it would need a lot of thinking, but that can be avoided pretty much by looking at the logic presented in PulseAudio calc_map_table found from src/pulsecore/resampler.c
  4. Add channelmap support for pulse output plugin, add multichannel support to ALSA output plugin, add multichannel support for waveout plugin (easiest, but who's gonna test?)
  5. Write tests and make sure everything works, especially coerce needs new tests because it's a bit broken already now. (output plugins with no channel count defined don't work nicely)

by juhovh (noreply@blogger.com) at September 04, 2011 02:02 PM

August 17, 2011

Guilherme Gonçalves

Further steps towards RPC

In the last progress update, I talked about how we were moving to the client side of the Service Clients implementation.

Things have progressed quite a bit since then, but unfortunately that part of the project is nowhere near ready (nor will it be by the end of GSoC, which is right around the corner). Anyway, I thought I’d share a bit of what I’ve been working on during the past weeks of coding.

The lower level of what we have in mind for the client side is complete and somewhat solid. This means it is possible for clients to pass messages and replies around reliably, using the server as a bridge. The plan now is to use that capability to model the Service Client functionality.

As a demonstration/proof-of-concept, we decided to brush up the very first two service clients that were conceived, sumclient and sumservice, and add them to the xmms2-tutorials submodule as tut9 and tut10.

I’m currently working on a higher level layer on top of that, which is the actual modelling of remote procedure calls and introspection. As a general concept, we agreed on allowing service clients to define and expose three types of basic entities to other clients: namespaces, methods and broadcasts. This means offering a service will be a matter of defining one (or more (or nested)) namespaces containing methods and broadcasts which can be accessed by regular clients by sending a specially-formatted message to the service client.

My work on this last week of GSoC has been on the code that defines these entities, which (I think) started to take shape around this commit. That code hasn’t yet been reviewed and may soon suffer alterations.

With that out of the way, the remaining work roughly boils down to implementing the code that articulates these data structures to offer the Service Client functionality. Basically that code should be a callback to the MESSAGE broadcast (which carries client-to-client messages routed through the server) that reacts to predefined types of messages, thus being able to dispatch method calls, reply to introspection calls, record a subscription to a broadcast and so on.


by guilherme_pg at August 17, 2011 09:26 PM

August 14, 2011

Andres Cabrera

Pencils down notes

Work status

Things are moving on, but they are never as simple as they look on the surface. For example, when changing the properties to store an xmmsv_t value instead of a GTree * containing xmms_config_property_t nodes, I had not realized that the fact that xmms_config_property_t is an xmms_object is very significant, as signals are registered to the objects, and callbacks depend on this. So I’ve had to do a bit of a kludge, but it’s the best I could think of… I added a void pointer to the xmmsv_t structure which holds an xmms_object_t whenever a callback is registered to it. The other issue is that since the xmmsv_t values are always copied on insert, as it would be unsafe to use only references since the tree can be modified in any way, the object pointer will be destroyed when xmmsv_t is released, so I’ve had to manually transfer ownership of the object when necessary. This is really close to working but there are a few bugs and kinks to iron out.

I’ve also started to add the new config schema API to the LADSPA host plugin, by exposing the config API to xform plugins, which has also served to ponder on improvements to the new API, which should be as simple to use as possible. One idea is to use more const references, which will get rid of many xmmsv_unrefs and g_frees which make the new API a big risk for leaks as it’s easy to forget to free that data. This could lead to stale pointers, but it would simplify usage greatly.

What’s left

IRC chats after this post will probably reveal more thinkgs I hadn’t counted on, but I would think this is what I have left to do:

  1. Get the callback mechanism working again
    1. Make sure callbacks work for old and new API
    2. Implement ideas for callbacks from next section
  2. Allow nyxmms to set lists (and to handle schemas correctly (e.g. set a n int when the schema is of int type)
  3. Get the LADSPA host to accept a list of plugins instead of a single plugin.
  4. Any other lurking bugs or improvements that come up.

Other possible improvements are:

  1. Use more references for the schema API to simplify its usage
  2. Mark old API as deprecated so that a compile time warning encourages devs to use the new API

Ideas on how callbacks should work with schema properties

Callbacks can be registered for any node in the config tree, including dicts and lists.

When a callback is set for a certain dict, it should be triggered whenever anything inside it changes, be it a single value change or  a new node added or deleted, so when triggering callbacks, all parent nodes need to be checked for callbacks and call them.

Also whenever a large xmmsv_t structure is set (e.g. when you set a number of parameters at once, or even a list of parameters within a dict) all callbacks for the changed items should be triggered.


by mantaraya36 at August 14, 2011 02:43 PM

August 12, 2011

Sébastien Cevey (theefer)

Auto-installing packages in Emacs with ELPA and el-get

Those who live in emacs all know the pain of manually installing extra modes and extensions, especially on different hosts. System packages sometimes help, but they differ on every OS (Debian packages, MacPorts, etc.), don’t always exist, and need to be installed manually.

A better alternative is to use emacs itself to manage, install and update all the required extra code. The ELPA project provides a way to install packages from different repositories, while el-get can help you declare recipes to install and update code from ELPA, or even Github or Emacswiki.

First, let’s setup some code that tries to load ELPA and el-get, and installs them if they are not present.

; derived from ELPA installation
; http://tromey.com/elpa/install.html
(defun eval-url (url)
  (let ((buffer (url-retrieve-synchronously url)))
  (save-excursion
    (set-buffer buffer)
    (goto-char (point-min))
    (re-search-forward "^$" nil 'move)
    (eval-region (point) (point-max))
    (kill-buffer (current-buffer)))))

;; Load ELPA
(add-to-list 'load-path "~/.emacs.d/elpa")

(defun install-elpa ()
  (eval-url "http://tromey.com/elpa/package-install.el"))

(if (require 'package nil t)
    (progn
      ;; Emacs 24+ includes ELPA, but requires some extra setup
      ;; to use the (better) tromey repo
      (if (>= emacs-major-version 24)
          (setq package-archives
                (cons '("tromey" . "http://tromey.com/elpa/")
                package-archives)))
      (package-initialize))
  (install-elpa))

;; Load el-get
(add-to-list 'load-path "~/.emacs.d/el-get/el-get")

(defun install-el-get ()
  (eval-url
   "https://github.com/dimitri/el-get/raw/master/el-get-install.el"))

(unless (require 'el-get nil t)
  (install-el-get))

Note that when using emacs 24, package.el is distributed with emacs but it points to the GNU package repository; the code above adds tromey’s more complete ELPA repository to the sources.

Unfortunately, the ELPA installer script appends a snippet of code to the end of the ~/.emacs file to auto-load package.el on startup. To avoid any problem, it is best to manually remove that code any only keep the load-or-install code above.

Now that ELPA and el-get are setup, we can declare all the packages we want installed. They will be installed the first time emacs is started, and simply loaded in the future.

; extra recipes for packages unknown to el-get (yet)
(setq el-get-sources
      '((:name css-mode :type elpa)
        (:name js2-mode-mooz
               :type git
               :url "git://github.com/mooz/js2-mode.git"
               :load "js2-mode.el"
               :compile ("js2-mode.el")
               :features js2-mode)))

; list all packages you want installed
(setq my-el-get-packages
      (append
       '(css-mode egg gist js2-mode-mooz)
       (mapcar 'el-get-source-name el-get-sources)))

(el-get 'sync my-el-get-packages)

The el-get 'sync call does all the magic, based on all the packages past in argument (as my-el-get-packages). Any packages for which el-get has a recipe can be installed.

The el-get-sources variable allows to declare extra custom recipes for code to install. In the example above, css-mode is simply pulled from the ELPA repository, while js2-mode-mooz is fetched directly from Github.

Replicating this code in all your ~/.emacs files is a very easy and convenient way to bootstrap the same emacs environment on multiple hosts.

by seb at August 12, 2011 11:05 PM

August 10, 2011

Sébastien Cevey (theefer)

It’s been a while

So this tech blog is back with a new theme after a long hiatus (and major hardware failure).

Hopefully, I’ll be talking about Ruby, Javascript, thick web apps, REST, Git, emacs and other things here soon.

Let’s see how long I can keep it going.

by seb at August 10, 2011 02:42 PM

August 08, 2011

Daniel Svensson (nano)

Improving quality of life in GDB

Having spent quite a few total hours in GDB over the past weeks it started to get boring to print *res->value.list->… etc over and over to see what weird value was harassing my tests. I had heard that GDB had gained Python support  some time ago and decided to write some useful tools for debugging XMMS2 related code.

This is now what it looks like when you print a xmmsv_coll_t:

(gdb) print *coll
$11 = {
  "attributes": {
    "type": "id"
  },
  "type": "XMMS_COLLECTION_TYPE_ORDER",
  "idlist": [],
  "operands": [
    {
      "attributes": {},
      "type": "XMMS_COLLECTION_TYPE_UNIVERSE",
      "idlist": [],
      "operands": []
    }
  ]
}

…and a regular xmmsv_t:

(gdb) print *fetch
$15 = {
  "type": "cluster-list",
  "data": {
    "type": "organize",
    "data": {
      "id": {
        "aggregate": "first",
        "type": "metadata",
        "get": [
          "id"
        ]
      }
    }
  },
  "cluster-by": "id"
}

The code is a bit under 100 lines of Python and should be a nice inspiration for people who still haven’t added this huge help to their projects. The code can be found here, and checked out via:

git clone git://git.xmms.se/xmms2/xmmsgdb.git


by Daniel Svensson at August 08, 2011 11:10 AM

July 29, 2011

Andres Cabrera

Update on Schema properties

My original proposal has of course changed substantially! First, instead of defining a new data structure with multiple types, I’ve started using xmmsv_t which already exists and does most of the work (IPC interchange, value serializing, memory mangement). I only needed to add support for floats. Easy, right?

It turned out to be very complicated as there is no way to serialize float values in a portable manner, because locales would interfere (if you plan to use sprintf) and because you cannot guarantee how floats will be stored in memory on all platforms (especially those which are not IEEE 754 compliant!). So I ended up with a comprimise which is using frexp to separate the float values mantissa and exponent, and encode them as two integers. This appears to give on simple testing a presicion of about 6 or 7 significant figures, which should be sufficient for XMMS2 config values. This is now available at my git repo:

https://github.com/mantaraya36/xmms2-mantaraya36/tree/config-schemas

I’ve also started work on the config properties side, and have settled on the following API for the new system:

/*
 * New config properties using schemas
 */
 xmms_config_node_t *xmms_config_node_lookup (const gchar *path);
 xmms_config_node_t *xmms_config_node_create (const gchar *name, xmmsv_type_t type);
/* Register nodes in the property tree. Callbacks are ignored for lists and dicts */
 xmms_config_node_t *xmms_config_node_register (xmms_config_node_t *node, xmms_object_handler_t cb, gpointer userdata);
gboolean xmms_config_node_unregister (xmms_config_node_t *node);
/* check node types */
 gboolean xmms_config_node_is_type (xmms_config_node_t *node, xmmsv_type_t type);
/* node query operations. Will return the first element if node is a list or array*/
 gint32 xmms_config_node_get_int (xmms_config_node_t *node, gboolean *ok); /* ok can be NULL */
 gfloat xmms_config_node_get_float (xmms_config_node_t *node, gboolean *ok);
 const gchar *xmms_config_node_get_string (xmms_config_node_t *node, gboolean *ok);
 xmms_config_node_t *xmms_config_node_get_index_node (xmms_config_node_t *parent_node, gint index);
 xmms_config_node_t *xmms_config_node_get_key_node (xmms_config_node_t *parent_node, const gchar *name);
/* node value setters. will set the vaue for the first element if node is a list or array */
 void xmms_config_node_set_int (xmms_config_node_t *node, gint value, gboolean *ok);
 void xmms_config_node_set_float (xmms_config_node_t *node, gfloat value, gboolean *ok);
 void xmms_config_node_set_string (xmms_config_node_t *node, const gchar *value, gboolean *ok);
 /* for dicts only: */
 void xmms_config_node_set_from_hash (xmms_config_node_t *parent_node, GHashTable *table);
 /* for lists only: */
 void xmms_config_node_set_from_array (xmms_config_node_t *parent_node, GArray *list);
/* element operations (for lists and dicts) */
 gint xmms_config_node_element_count (xmms_config_node_t *node);
 void xmms_config_node_element_remove_index (xmms_config_node_t *parent_node, gint index, gboolean *ok);
 void xmms_config_node_element_remove_key (xmms_config_node_t *parent_node, xmms_config_node_t *node, gboolean *ok);
/* query node elements values */
 gint xmms_config_node_get_element_int (xmms_config_node_t *parent_node, gint index, gboolean *ok);
 gfloat xmms_config_node_get_element_float (xmms_config_node_t *parent_node, gint index, gboolean *ok);
 const gchar *xmms_config_node_get_element_string (xmms_config_node_t *parent_node, gint index, gboolean *ok);
/* set node elements values */
 void xmms_config_node_set_element_int (xmms_config_node_t *parent_node, gint index, gint value, gboolean *ok);
 void xmms_config_node_set_element_float (xmms_config_node_t *parent_node, gint index, gfloat value, gboolean *ok);
 void xmms_config_node_set_element_string (xmms_config_node_t *parent_node, gint index, const gchar* value, gboolean *ok);
/* list node operations */
 void xmms_config_node_resize (xmms_config_node_t *node, gint size, gboolean *ok);
 void xmms_config_node_append (xmms_config_node_t *parent_node, xmms_config_node_t *node, gboolean *ok);
 void xmms_config_node_insert (xmms_config_node_t *parent_node, gint index, xmms_config_node_t *node, gboolean *ok);
/* callbacks (can only be set for value nodes) */
 void xmms_config_node_callback_set (xmms_config_node_t *node, xmms_object_handler_t cb, gpointer userdata);
 void xmms_config_node_callback_remove (xmms_config_node_t *node, xmms_object_handler_t cb, gpointer userdata);

Nodes will hold a copy of the value in the tree and the node’s address,, so any operations on nodes can be made thread-safe.


by mantaraya36 at July 29, 2011 07:59 AM

July 10, 2011

Andres Cabrera

Schema properties

OK, so here are my ideas to enhance the server config properties system. This is my initial proposal which will surely have changes after a round of feedback.

Current state

Currently properties are stored in a GTree structure in the file config.c, in a global variable from the following struct:

00085 struct xmms_config_St {
00086     xmms_object_t obj;
00087
00088     const gchar *filename;
00089     GTree *properties;
00090
00091     /* Lock on globals are great! */
00092     GMutex *mutex;
00093
00094     /* parsing */
00095     gboolean is_parsing;
00096     GQueue *states;
00097     GQueue *sections;
00098     gchar *value_name;
00099     guint version;
00100 };

The properties themselves are very simple, and basically contain a name and a string value:

00105 struct xmms_config_property_St {
00106     xmms_object_t obj;
00107
00108     /** Name of the config directive */
00109     const gchar *name;
00110     /** The data */
00111     gchar *value;
00112 };

Important considerations

  1. The new system must support (at least initially) the current one, to avoid breaking plugins. It’s likely that once the new system is in place, a simple script could be run to modify all code to use the new system, and the old methods removed or left with compiler deprecated warnings.
  2. The new system must support reading the xml config file, and from it produce the config tree for the new system. I’m thinking of breaking backwards compatibility of the xml file, so once you run a version with the new system, the properties will be written with a few additional elements which are not understood by the old parser.

Proposal

The new system will store the properties in a tree structure made up of linked nodes. I decided against using GNode or GVariant chains as they offer more functionality than needed which would make it easier to introduce bugs if you use the wrong way to put data in. Nodes will have :

struct xmms_config_node_St {
    xmms_object_t obj;
    const gchar *name;
    node_type_t type;
    node_data_t *data;

    struct xmms_config_node_St *parent_node;
}

The data for each node can be of type: CONFIG_LIST, CONFIG_ARRAY, CONFIG_INT, CONFIG_FLOAT, or CONFIG_STRING. The last three will be final nodes in the chain, where actual values are stored. These three types hold values directly in the data pointer as gint, gfloat or gchar*.

CONFIG_LIST nodes hold a GList whose elements are nodes. This should cover hierarchical properties, starting from the root node, like:

alsa.device = default
alsa.mixer = PCM
alsa.mixer_dev = default
alsa.mixer_index = 0

where the node called “alsa” has data of type CONFIG_LIST, and it holds a list with four nodes of type string,string, string and int. It is important to note that no to nodes in a list can have the same name.

The root node is of type CONFIG_LIST, and all config options are appended as new nodes to that list. The name of the root node is ignored.

CONFIG_ARRAY is similar to CONFIG_LIST, but it is designed to handle numbered properties, as in:

effect.order.0
effect.order.1

So the nodes that comprise CONFIG_ARRAYS, do not have names, as they take the name according to their order in the GList. Counting starts from 0. The main limitation this introduces is that numbered lists will not allow named elements, for example this would not be allowed:

effect.order.0
effect.order.1
effect.order.type

as the “order” node contains a numbered list, so “type” is not a valid name in this case.

Naturally, lists can be nested within lists or arrays and viceversa.

Interface

The interface to the new system will look like:

xmms_config_node_t *xmms_config_node_lookup (const gchar *path);
xmms_config_node_t *xmms_config_node_new (node_type_t type, const gchar *name = "");

/* frees a node and its children recursively */
void xmms_config_node_free (xmms_config_node_t *);

gboolean xmms_config_node_is_list (xmms_config_node_t *node);
gboolean xmms_config_node_is_array (xmms_config_node_t *node);

gboolean xmms_config_node_is_value (xmms_config_node_t *node);
gboolean xmms_config_node_is_int (xmms_config_node_t *node);
gboolean xmms_config_node_is_float (xmms_config_node_t *node);
gboolean xmms_config_node_is_string (xmms_config_node_t *node);

void xmms_config_node_get_path (xmms_config_node_t *node, gchar *path);

const gchar* xmms_config_node_get_name (xmms_config_node_t *node);
void xmms_config_node_set_name (xmms_config_node_t *node, const gchar *name);
/* callbacks can only be set for value nodes */
void xmms_config_node_callback_set (xmms_config_property_t *prop, xmms_object_handler_t cb, gpointer userdata);
void xmms_config_node_callback_remove (xmms_config_property_t *prop, xmms_object_handler_t cb, gpointer userdata);

/* value node operations. Will return the first element if node is a list or array*/
gint xmms_config_node_get_int (xmms_config_node_t *node, gboolean *ok = NULL);
gfloat xmms_config_node_get_float (xmms_config_node_t *node, gboolean *ok = NULL);
const gchar *xmms_config_node_get_string (xmms_config_node_t *node, gboolean *ok = NULL);

/* will set the vaue for the first element if node is a list or array */
void xmms_config_node_set_int (xmms_config_node_t *node, gint value, gboolean *ok = NULL);
void xmms_config_node_set_float (xmms_config_node_t *node, gfloat value, gboolean *ok = NULL);
void xmms_config_node_set_string (xmms_config_node_t *node, const gchar *value, gboolean *ok = NULL);

/* array and list node operations */
void xmms_config_node_resize (xmms_config_node_t *node, gint size, gboolean *ok = NULL);
void xmms_config_node_append (xmms_config_node_t *parent_node, xmms_config_node_t *node, gboolean *ok = NULL);
void xmms_config_node_insert (xmms_config_node_t *parent_node, gint index, xmms_config_node_t *node, gboolean *ok = NULL);
gint xmms_config_node_element_count (xmms_config_node_t *node);
void xmms_config_node_element_remove (xmms_config_node_t *parent_node, gint index, gboolean *ok = NULL);
void xmms_config_node_element_remove (xmms_config_node_t *parent_node, xmms_config_node_t *node, gboolean *ok = NULL);

xmms_config_node_t *xmms_config_node_get_element (xmms_config_node_t *parent_node, gint index);
xmms_config_node_t *xmms_config_node_get_element (xmms_config_node_t *parent_node, const gchar *name);

gint xmms_config_node_get_element_int (xmms_config_node_t *parent_node, gint index, gboolean *ok = NULL);
gfloat xmms_config_node_get_element_float (xmms_config_node_t *parent_node, gint index, gboolean *ok = NULL);
const gchar *xmms_config_node_get_element_string (xmms_config_node_t *parent_node, gint index, gboolean *ok = NULL);

void xmms_config_node_set_element_int (xmms_config_node_t *parent_node, gint index, gint value, gboolean *ok = NULL);
void xmms_config_node_set_element_float (xmms_config_node_t *parent_node, gint index, gfloat value, gboolean *ok = NULL);
void xmms_config_node_set_element_string (xmms_config_node_t *parent_node, gint index, const gchar* value, gboolean *ok = NULL);

void xmms_config_node_set_from_hash (xmms_config_node_t *parent_node, GHashTable table);

Command Line interaction

The command line client will be able to manipulate values in the usual way, so it only needs to be enhanced for array and list usage.

You will be able to set the elements for exisitng elements of a list or array from the command line by separating the values by commas. They values will be converted internally to the type for each node. So for example for the config properties:

alsa.device = default
alsa.mixer = PCM
alsa.mixer_dev = default
alsa.mixer_index = 0

You will be able to do:

nyxmms server config alsa default,PCM,default,0

The user can also dynamically resize lists and arrays. The command line user will be able to make lists longer, but not shorter (as the server might count on some properties it created being there). So for example, the user could set a chain of ladspa plugins like this:

nyxmms server config ladpsa.plugin amp.so,tap_reverb.so,tap_tubewarmth.so

and the ladspa plugin list will be resized to accomodate them if it can’t already.


by mantaraya36 at July 10, 2011 09:06 PM

July 02, 2011

Andres Cabrera

Dynamic effect chains

The goal of this part of the project is to make changes in the effects chain have effect immediately, so if you add a ladspa plugin, or Eq to the chain, you won’t have to wait for the next song, when the chain is rebuilt, to hear it.

So, I’ve been looking at the code that builds the xform chain, the code that processes the chain, and the code that handles changes in effect chain config properties (currently only the effect.order.X properties exist).

Current behavior

Chains are created in the xmms_output_filler() function in output.c. This function runs a loop continuously filling the output buffer from the output of the xform chain, but it checks if the chain exists before doing this. If the chain doesn’t exist, it calls the xmms_xform_chain_setup() function from xform.c.This function returns the pointer to the last element of the chain. It calls xmms_xform_chain_setup_url() which finds the correct decoder for the current media, inserts a segment plugin (to keep track of time) after it and then builds the effects chain by calling add_effects(). This function needs to be passed as arguments the last xform, where the effects chain will be attached, the medialib entry url and the goal formats. Finally, the add_effects() function scans the effect.order.X config properties, intializing the plugins.

In the xform.c file, the update_effect_properties() function is the callback when effect chain properties change. This callback currently only checks whether the plugin exists, registers the “enabled” property for it and creates a new empty effect.order slot after the last one.

What needs to be done

My plan is that when a change in the effect.order.X config properties takes place (the update_effect_propeties() function is called), it will force a rebuild of the effects part of the xform chain. I toyed with the idea of just moving and inserting new items, but that would require more subtantial modifications to the xform basic structures, to make the chain more aware of its members and its state. This is something I think is unnecessary in this context, as rebuilding the chain should be fast enough for most situations and where there could be minor glitches in the audio, that could be something the user would expect and accept since he is adding or removing an effect.

What will happen is that whenever the config property is changed, the xform object will be marked as needing refresh. This will be picked up by the loop in xmms_output_filler and thelower part of the chain will be rebuilt.

The data passed to the update_effect_properties callback needs to be changed to include enough to do number 1 above and to mark that the chain needs remaking. Currently the callback data is used to pass only the number of effects in the chain, to be able to add an empty element at the end.

For each effect, their seek function must be called, in case they depend on the current song position and time. The value must be acquired from the segment plugin just before building the chain.


by mantaraya36 at July 02, 2011 03:24 PM

June 26, 2011

Guilherme Gonçalves

On to the client side…

Now that the server side of the Service Clients implementation has taken shape, it’s time to turn our attention to the design of the client side implementation, which is still somewhat immature.

The basic idea is that, now that the server is capable of dumbly passing messages and replies among clients, we can use that capability to model the actual Service Client functionality on the client-side. In other words, we want the clients to establish a protocol for remote procedure calls and introspection with the server, unaware of what is really going on, simply forwarding messages and replies back and forth between clients.

Our plan for the actual implementation will require, as expected, changes to libxmmsclient, but also the development of a new library, so far called libxmmsclient-sc. The new functionality added to libxmmsclient will merely facilitate message exchanging between clients, while the actual Service Client sugar will be laid on top of that in libxmmsclient-sc.

We already had some sketches for the client side of the implementation, most notably this one by nesciens, which gives a pretty good idea of where we are headed. Last week I published a sketch of my own, with an updated and slightly more concrete view of the implementation details now that we know what the server is capable of. It also contained a few more ideas.

While we have not yet throughly discussed these sketches and turned them into a more solid idea, they do provide a good basis we can work on refining over the next weeks.

One aspect of these sketches we had quite a lengthy discussion about was the alterations needed to accommodate the new message passing functionality in the asynchronous result mechanism in libxmmsclient. With valuable input from vdust, we reached a nice idea that I began implementing with this commit. It still needs some testing and polishing, which I will be doing in the next days.


by guilherme_pg at June 26, 2011 01:54 PM

Andres Cabrera

LADSPA Host now working. Please try it!

After some more work, I have now the LADSPA host in a nice working state. One of the harder things was allowing hot swapping of the LADSPA plugin while xmms2 was playing. And after a talk with oneman, I decided to do it the *perfect* way by allocating the new plugin and structures separately and then locking the structure only to swap the pointers, after which the old plugin, buffers and structures are freed.

The LADSPA host currently supports both S16 and float samples so it should be compatible with most (if not all) of your music. Please give it a go and report any bugs! Also any ideas or suggestions are very welcome. My git repo is here:

https://github.com/mantaraya36/xmms2-mantaraya36

So how is it used?

After building and installing the ladspahost  xform plugin, you have to add the LADSPA host to the effects chain:

nyxmms2 server config effects.order.0 ladspa

Then you need to choose the plugin you want to use from your LADSPA plugins. They are usually found on /usr/lib/ladspa. The xmms2 LADSPA host will look for plugins which don’t have an absolute path in the LADSPA_PATH environment variable, and if it’s not available in /usr/lib/ladspa, so you only need to do:

nyxmms2 server config ladspa.plugin amp.so

to load the /usr/lib/ladspa/amp.so plugin.

LADSPA plugin libraries can actually contain more than one plugin. If you don’t specify which one you want, the first plugin in the library is loaded. You can find out about the contents of particular plugins by using the LADSPA analyseplugin tool, like this:

analyseplugin amp.so

which will produce:

Plugin Name: "Mono Amplifier"
Plugin Label: "amp_mono"
Plugin Unique ID: 1048
Maker: "Richard Furse (LADSPA example plugins)"
Copyright: "None"
Must Run Real-Time: No
Has activate() Function: No
Has deativate() Function: No
Has run_adding() Function: No
Environment: Normal or Hard Real-Time
Ports:    "Gain" input, control, 0 to ..., default 1, logarithmic
    "Input" input, audio
    "Output" output, audio

Plugin Name: "Stereo Amplifier"
Plugin Label: "amp_stereo"
Plugin Unique ID: 1049
Maker: "Richard Furse (LADSPA example plugins)"
Copyright: "None"
Must Run Real-Time: No
Has activate() Function: No
Has deativate() Function: No
Has run_adding() Function: No
Environment: Normal or Hard Real-Time
Ports:    "Gain" input, control, 0 to ..., default 1, logarithmic
    "Input (Left)" input, audio
    "Output (Left)" output, audio
    "Input (Right)" input, audio
    "Output (Right)" output, audio

As you can see, this plugin library has two plugins inside. To specify which plugin you want to use, you need to add the plugin name, plugin label or unique ID (any one of these will work) after the library name with a colon, like this:

nyxmms2 server config ladspa.plugin amp.so:1049

Once you have loaded a plugin, you can see the available controls by checking the ladspa properties, which will have adjusted to the plugin, an easy way is:

nyxmms2 server config | grep ladspa

which can show something like:

effect.order.0 = ladspa
ladspa.control.0 = 7000
ladspa.control.1 = -90
ladspa.control.2 = 30
ladspa.control.3 = 1
ladspa.control.4 = 1.000000
ladspa.control.5 = 1.000000
ladspa.control.6 = 1.000000
ladspa.control.7 = 0.000000
ladspa.controlname.0 = Decay [ms]
ladspa.controlname.1 = Dry Level [dB]
ladspa.controlname.2 = Wet Level [dB]
ladspa.controlname.3 = Comb Filters
ladspa.controlname.4 = Allpass Filters
ladspa.controlname.5 = Bandpass Filter
ladspa.controlname.6 = Enhanced Stereo
ladspa.controlname.7 = Reverb Type
ladspa.enabled = 1
ladspa.plugin = tap_reverb.so
ladspa.priority.audio/pcm = 50

You can change the control values for a plugin like you would any other xmms2 property:

nyxmms2 server config ladspa.control.3 0

Properties will be retained and used across songs and across server reboots, but will be lost if you change the plugin.

Current limitations and future work

  • Since configuration parameters can’t be removed, if the previous plugin you loaded had more controls, there will be some useless controls (which you can identify because they will have no name). Additionally since config parameters live on, you will always tend to have more controls than the plugin actually supports. When arrays are implemented, it is likely that this problem will be resolved as configuration keys that are arrays should resize automatically to the number of elements in the array.
  • Although the internal data structures are designed to support plugin chains, this is not yet exposed to the user, as I’m waiting to implement the schema system for properties, which will allow doing this simply (See my previous posts).

by mantaraya36 at June 26, 2011 10:13 AM

June 20, 2011

Juho Vähä-Herttua

GSoC 2011 progress lately

I haven't had an update for a while, mostly because a childbirth and related affairs have kept me busy these days. I think I'm quite back on track again and started doing the more annoying work. I think the commits might become a bit larger so I'm keeping them in the gsoc11 branch from now on.

I looked at the problem I mentioned last time about XMMS_STREAM_TYPE_FMT_CHANNELS missing and xmms_stream_type_coerce failing. In case of pulse this is not an issue, because pulse accepts input data with any samplerate and therefore converter plugin never gets into the picture. However one can simply define some rather uncommon samplerate into the pulse plugin (like 48000) and suddenly all files will fail. There are tests for coerce and I should extend them to include some more multichannel support.

I've also added initial support for XMMS_STREAM_TYPE_FMT_CHANNELMASK and added a helper function that can be used to get the default channel mask for audio streams that have from 1 to 6 channels to help the transition. All existing plugins will have the channel mask XMMS_CHANNEL_MASK_UNDEFINED which should be mapped to the correct mask in the output. If the channels are in wrong order, the decoder should fix the order before outputting data.

I have the multichannel wave plugin almost finished, now I should just adapt it to use the new channel mask and make sure that it gets transferred to output correctly. The coerce function for converter should also be modified to take the channel mask into account, that might be slightly complicated.

by juhovh (noreply@blogger.com) at June 20, 2011 01:14 PM

June 14, 2011

Konrad Scorciapino

A first screencast on GIMME

I. I recorded a screencast showing how to use GIMME. It features playlist operations as well as working with collections, on both filter-view, which displays it as if it were a playlist, and bookmark-view, which gives an overview of the available collections. There are actually two screencasts, one in english and another in portuguese, and I'm already planning on showing how to install GIMME in a major distro in another video.


<object height="480" width="640"><param name="movie" value="http://www.youtube.com/v/BWlzWVNQRLM?version=3&amp;hl=en_US"/><param name="allowFullScreen" value="true"/><param name="allowscriptaccess" value="always"/><embed allowfullscreen="true" allowscriptaccess="always" height="480" src="http://www.youtube.com/v/BWlzWVNQRLM?version=3&amp;hl=en_US" type="application/x-shockwave-flash" width="640"></embed></object>

<object height="480" width="640"><param name="movie" value="http://www.youtube.com/v/nKClvESaaek?version=3&amp;hl=en_US"/><param name="allowFullScreen" value="true"/><param name="allowscriptaccess" value="always"/><embed allowfullscreen="true" allowscriptaccess="always" height="480" src="http://www.youtube.com/v/nKClvESaaek?version=3&amp;hl=en_US" type="application/x-shockwave-flash" width="640"></embed></object>

June 14, 2011 03:00 AM

June 12, 2011

Andres Cabrera

More on LADSPA modes

After an IRC chat with vdust, he suggested the automatic modes might work most of the time, but that it might be good to allow more flexible connections for other type of streams like 5.1. Thinking about that later, I realized this might be very useful to do time delay compensation, and individual loudspeaker eq. I’ve thought about this, and I’ve come up with an idea, which could serve the purpose and builds on the work that’s already done.

Currently, the LADSPA host I wrote creates LADSPA plugin nodes which can actually hold several instances of a plugin (e.g. for MONO mode), but the plugin parameters are shared between all the instances, as well as any intermediate buffers. But for flexibility, it might be desirable to allow arbitrary routing of inputs and outputs, as well as independent control of plugin parameters. I think this can be accomplished in a sensible way through a new structure called stage that can wrap nodes and create complex chains.

Three separate configuration options have to be set. One is the list of plugins, one will determine routing and another will control the parameters.

Plugins and routing

To create a chain, you would pass a list like:

[ "pluglib1.so:plugmono_name", "pluglib2.so:plugstereo_name2" ]

This will create a chain that looks like:

input => pluglib1.so:plugmono_name => pluglib2.so:plugstereo_name2 =>output

Notice that both the plugin library and the plugin name are given in the string, and they are separated by a colon.

On the routing config option, the inputs and outputs will be specified. Each element of the plugins list is a stage, so you need to declare the inputs to each of the stages and lastly the way the outputs from the last stage are mapped to the outputs, for example:

[ [1,2], [3, 4], [5,6] ]

Would mean that the first stage takes as input channels 1 and 2 (if channels don’t match the automatic modes for channel assignment are used), the second stage takes channels 3 and 4 from the previous stage, and finally outputs 5 and 6 from the second stage are passed to the two channels of the chain. This will give great flexibility in routing. One thing that is not supported is mixing channels from the config. A special LADSPA plugin downmixer would need to be used for this. Also note that to determine the number of channels for each stage, it must look both at input and output and use the largest number.

A more complex chain can look like:

[ ["plug1.so:plug1",  "plug2.so:plug2"], "plug3.so:plug3" ]

The first stage will have plug1 and plug2 in parallel, which then feed plug3. You can specify routings like:

[ [ [1] , [2] ], [1, 2, 3, 4], [1, 4] ]

This means that the first plugin of stage 1 takes input channel 1, and the second takes 2. Assuming the plugins are mono to stereo, this means that although two channels enter the stage, 4 will come out. These will be numbered sequentially, for each consecutive plugin, so in this case, the second stage will take the output from plug1 on inputs 1 and 2 and the output of plug2 on inputs 3 and 4. Finally, the second stage will send outputs 1 and 4 out the xform chain.

Parameters

A third config option deals with plugin parameters. These will use a JSON style schema notation, and will look like:

[ [  {"stage1param1":value , "stage1param2":value}, {"stage1param1":value, "stage1param2":value} ], {"stage2param1":value} ]

A dictionary will represent the parameters for each node within each stage. If a parameter name is not listed, it should take its default value.

Fallback

When a single node is the whole stage, there is no need to put the node’s configuration options with an array of a single element. In this case just using the element directly is preferred.

When arrays are not used (i.e. only the pluginlib name is given not as part of an array), the LADSPA host will fall back to using a single node with automatic modes.

This proposal will wait implementation until the next stage of GSoC dealing with the implementation of schemas is done.


by mantaraya36 at June 12, 2011 04:41 PM

June 08, 2011

Guilherme Gonçalves

It’s ALIVE!

It’s been two weeks since I began coding for GSoC, and it’s time to share some of the progress we’ve made.
For the anxious: the courier object, as described in the last post, is already crawling on its own. I have implemented and briefly tested both methods described in the wiki, as well as a few other features to ipc.c and GenIPC.

My first attempt at implementing the courier object was to expose some data structures from ipc.c to courier.c and let the latter manipulate them at will.
After discussing this design with the community, we settled for hiding these data structures and only exposing through new functions the bare minimum necessary for the courier to operate.
That is how this commit came to be. Since some of the new functions are mere copies of code that already existed elsewhere in the same file, they could be used instead of that code. I should add “cleaning up ipc.c” to my TODO list.

At that point I was planning on not making the courier a xmms_object_t, and have it special-cased for commands and replies in ipc.c (just like the SIGNAL object). This works for the two methods described in the wiki, but would complicate things for the other methods we have in mind. So after discussing the issue with nesciens, we decided to adapt GenIPC to our needs.
This means making it possible to specify that the server should not automatically send replies to clients that call a server object’s method, and that it instead should leave that responsibility to the method itself.
This set of changes was made in a separate branch of my repository, which has now been merged into master. This is the most relevant commit, describing the changes. The other commits are fixes and cleanups both to new and old code.

With that issue out of the way, I integrated the courier object to GenIPC with these two commits. It should now be fairly easy to implement the remaining methods we have in mind. So far, we are planning on implementing a method that returns a list of ids of connected clients, and a method for clients to consult their own id.

Today I made a small breakthrough by writing a very silly but functional service client. In order to do that, I had to hack support for the courier object in libxmmsclient and main.c. I didn’t commit such ugly code, but it helped me test what I already had and, after a few hours of debugging, I had sumservice, the client that accepts messages containing a list of two integers from other clients, sums them and returns the result, and sumclient, the client that takes two integers from the command line and sends them for summation :)

Next steps: Aside from the remaining methods for the courier, I’m still unsure how to integrate this new object in main.c (i.e., its initialization and destruction). Also, the code written so far still needs revision and testing, as I may (as in, probably) have screwed up refcounting and other tricky parts.

See you soon!


by guilherme_pg at June 08, 2011 11:16 PM

XMMS2 Offical News Channel

World IPv6 Day with XMMS2

Today the world embraces IPv6. Since we migrated to our new host we've been serving you the latest and greatest bug reports, git checkouts, etc via IPv6. This was actually the last area surrounding the project to be fixed since XMMS2 has had support for client communication over IPv6 since mid 2005, and cURL gives us Shoutcast/Icecast streaming over IPv6 for free. Anyways.. here comes some hints on how to configure XMMS2 to listen to IPv6...

Out of the box XMMS2 only listens on UNIX sockets by default on Unices. This is easily verified with:

$ xmms2 server config core.ipcsocket
core.ipcsocket = unix:///tmp/xmms-ipc-you

Lets add some IPv6 to the mix (assuming your system is already IPv6 enabled):
$ xmms2 server config core.ipcsocket "unix:///tmp/xmms-ipc-you;tcp://[::]:9667"

And verify:
$ xmms2 server config core.ipcsocket
core.ipcsocket = unix:///tmp/xmms-ipc-you;tcp://[::]:9667

$ netstat -an | grep 9667
tcp6 0 0 :::9667 :::* LISTEN

You are now able to connect to XMMS2 via IPv6, verify:
$ XMMS_PATH=tcp://[::1]:9667 xmms2 list


Oh.. and of course you also want to play some music over IPv6:
$ xmms2 add http://v6.scenesat.com:8000/scenesatmax
...satisfaction guaranteed.

(you might need to substitute 'xmms2' with 'nyxmms2' if you're using an older version)

by Daniel Svensson (noreply@blogger.com) at June 08, 2011 06:44 AM

June 03, 2011

Andres Cabrera

Instantiation modes for LADSPA host

Frequently, the number of channels of the xform chain will not match the number of channels of a LADSPA plugin, e.g. the chain is stereo and the plugin is mono. Additionally, many LADSPA plugins have different number of inputs and outputs, e.g. a reverb which has mono input but stereo output. So I’ve started coding to allow automatic routing and instantiation, according to the following modes:

  • DIRECT: The xform chain and the LADSPA plugin have the same number of channels, and the number of inputs and outputs on the LADSPA plugin is the same, so there is no need to do any special routing as all channels are matched.
  • MONO: The LADSPA plugin has only one input and only one output, but the xform chain has more than 1 channel. In this case, the plugin is instantiated multiple times to match the number of channels of the chain, and each instance will independently handle a single channel from the chain. All instances of the LADSPA plugin will share the same control parameters.
  • BALANCE: For the common case where the LADSPA plugin is mono to stereo and the xform chain is stereo, a balance mode is proposed, where the plugin is instantiated twice, and each instance takes the input from the left and right channels respectively. The two stereo outputs are then added but according to the value of a balance parameter, to allow a range from complete separation of the outputs (downmixing to mono for each side) to complete mix where the left outputs are added into the left channel, and the right outputs go to the right.
  • OTHER: For any other cases, a simple circular mapping is applied to the channels, e.g. for a mono xform chain and a stereo plugin, the input will go to both plugin inputs and both plugin outputs will go to the xform output. and for a six channel chain and a stereo plugin, three instances will be created, which will take input from 1-2, 3-4 and 5-6 respectively and output in the same way.

I think this should cover the relevant cases for xmms2 (which certainly differ to the usage in a multitrack DAW). Additionally this enables the eventual addition of a plugin into the LADSPA host (in series), without having to change the current structure of inputs and outputs.


by mantaraya36 at June 03, 2011 12:55 PM

June 01, 2011

Andres Cabrera

LADSPA host proof of concept

Proof of concept code for LADSPA hosting is now up in github. This code is still very inflexible, as you can’t even select the plugin you want to use (it uses a simple gain plugin amp.so, sorry oneman!), but it shows a working LADSPA host, which can take parameters from the server config. If you try it out, you will be able to modify the gain by using:

nyxmms2 server config ladspa.parameter0 1.0

Where the last number is the gain value for the LADSPA plugin.

This xform plugin accepts both S16 and float samples, and creates internal buffers to pass to the LADSPA plugin. If you have a look, there are still many TODOs, but most infrastructure is there, even to support multiple LADSPA plugins within the same xform.

I had done a LADSPA host before, so I tried first to write the host from a quick look at the LADSPA header. This turned out to be a bad idea, as there were many small details and problems which I could’ve avoided by reading some documentation like:

http://gdam.ffem.org/ladspa-doc/ladspa-4.html

In particular it is important in LADSPA to remember to allocate buffers for all ports (both audio and control), even the ones you are not going to use.

One of the challenges now is deciding how to handle different channel counts between the chain and plugins, and try to get input from the xmms2 devs regarding a way to define config properties from the init function rather than the setup function. Most xforms are OK with setting their properties in setup, but a LADSPA host definitely needs to register the config properties in the init function where the plugins are initialized. It should also be able to dynamically create and delete properties in case the plugin is changed in the middle of a song.


by mantaraya36 at June 01, 2011 10:23 PM