[beast/wip/soundfont: 812/832] Merge branch 'master' of github.com/tim-janik/beast into soundfont



commit b14b93fff1da1006a476fd0c70e02700a61ebbef
Merge: 6b6764b b4b5943
Author: Tim Janik <timj gnu org>
Date:   Tue Oct 28 15:29:12 2014 +0100

    Merge branch 'master' of github.com/tim-janik/beast into soundfont
    
    Synchronize with beast master so that patches against the newer codebase can be applied.
    
    This resolves a number of build rule and license header conflicts.

 Makefile.am                                        |   70 +-
 Makefile.decl                                      |   33 +-
 NEWS                                               |  103 +
 README                                             |   47 +-
 TODO                                               |  798 -
 acbeast.m4                                         |  211 +
 autogen.sh                                         |  160 +-
 autotools/glib-gettext.m4                          |    3 +-
 beast-gtk/.gitignore                               |   10 +-
 beast-gtk/Makefile.am                              |  175 +-
 beast-gtk/bstapp.c                                 | 1262 --
 beast-gtk/bstapp.cc                                | 1227 ++
 beast-gtk/bstapp.h                                 |  118 -
 beast-gtk/bstapp.hh                                |  101 +
 beast-gtk/bstasciipixbuf.c                         |  765 -
 beast-gtk/bstasciipixbuf.cc                        |  749 +
 beast-gtk/bstasciipixbuf.h                         |   39 -
 beast-gtk/bstasciipixbuf.hh                        |   24 +
 beast-gtk/bstauxdialogs.c                          |  412 -
 beast-gtk/bstauxdialogs.cc                         |  398 +
 beast-gtk/bstauxdialogs.h                          |   53 -
 beast-gtk/bstauxdialogs.hh                         |   38 +
 beast-gtk/bstbseutils.c                            |   88 -
 beast-gtk/bstbseutils.cc                           |   73 +
 beast-gtk/bstbseutils.h                            |   58 -
 beast-gtk/bstbseutils.hh                           |   39 +
 beast-gtk/bstbuseditor.c                           |  251 -
 beast-gtk/bstbuseditor.cc                          |  236 +
 beast-gtk/bstbuseditor.h                           |   58 -
 beast-gtk/bstbuseditor.hh                          |   43 +
 beast-gtk/bstbusmixer.c                            |  245 -
 beast-gtk/bstbusmixer.cc                           |  230 +
 beast-gtk/bstbusmixer.h                            |   54 -
 beast-gtk/bstbusmixer.hh                           |   39 +
 beast-gtk/bstbusview.c                             |  120 -
 beast-gtk/bstbusview.cc                            |  105 +
 beast-gtk/bstbusview.h                             |   52 -
 beast-gtk/bstbusview.hh                            |   37 +
 beast-gtk/bstcanvaslink.c                          |  609 -
 beast-gtk/bstcanvaslink.cc                         |  600 +
 beast-gtk/bstcanvaslink.h                          |   93 -
 beast-gtk/bstcanvaslink.hh                         |   78 +
 beast-gtk/bstcanvassource.c                        | 1082 -
 beast-gtk/bstcanvassource.cc                       | 1067 +
 beast-gtk/bstcanvassource.h                        |  105 -
 beast-gtk/bstcanvassource.hh                       |   90 +
 beast-gtk/bstcluehunter.c                          | 1027 -
 beast-gtk/bstcluehunter.cc                         | 1007 +
 beast-gtk/bstcluehunter.h                          |  104 -
 beast-gtk/bstcluehunter.hh                         |   89 +
 beast-gtk/bstcxxutils.cc                           |   74 -
 beast-gtk/bstcxxutils.h                            |   29 -
 beast-gtk/bstdbmeter.c                             | 1565 --
 beast-gtk/bstdbmeter.cc                            | 1549 ++
 beast-gtk/bstdbmeter.h                             |  148 -
 beast-gtk/bstdbmeter.hh                            |  133 +
 beast-gtk/bstdefs.h                                |  106 -
 beast-gtk/bstdefs.hh                               |   85 +
 beast-gtk/bstdial.c                                |  686 -
 beast-gtk/bstdial.cc                               |  671 +
 beast-gtk/bstdial.h                                |   96 -
 beast-gtk/bstdial.hh                               |   81 +
 beast-gtk/bsteffectview.c                          |  432 -
 beast-gtk/bsteffectview.cc                         |  417 +
 beast-gtk/bsteffectview.h                          |   77 -
 beast-gtk/bsteffectview.hh                         |   62 +
 beast-gtk/bsteventroll.c                           |  861 -
 beast-gtk/bsteventroll.cc                          |  844 +
 beast-gtk/bsteventroll.h                           |  137 -
 beast-gtk/bsteventroll.hh                          |  121 +
 beast-gtk/bsteventrollctrl.c                       |  813 -
 beast-gtk/bsteventrollctrl.cc                      |  798 +
 beast-gtk/bsteventrollctrl.h                       |   66 -
 beast-gtk/bsteventrollctrl.hh                      |   51 +
 beast-gtk/bstfiledialog.c                          |  983 -
 beast-gtk/bstfiledialog.cc                         |  969 +
 beast-gtk/bstfiledialog.h                          |  137 -
 beast-gtk/bstfiledialog.hh                         |  131 +
 beast-gtk/bstgconfig.c                             |  266 -
 beast-gtk/bstgconfig.cc                            |  251 +
 beast-gtk/bstgconfig.h                             |   49 -
 beast-gtk/bstgconfig.hh                            |   34 +
 beast-gtk/bstgrowbar.c                             |  231 -
 beast-gtk/bstgrowbar.cc                            |  216 +
 beast-gtk/bstgrowbar.h                             |   83 -
 beast-gtk/bstgrowbar.hh                            |   68 +
 beast-gtk/bstitemseqdialog.c                       |  400 -
 beast-gtk/bstitemseqdialog.cc                      |  385 +
 beast-gtk/bstitemseqdialog.h                       |   81 -
 beast-gtk/bstitemseqdialog.hh                      |   66 +
 beast-gtk/bstitemview.c                            |  402 -
 beast-gtk/bstitemview.cc                           |  387 +
 beast-gtk/bstitemview.h                            |   99 -
 beast-gtk/bstitemview.hh                           |   84 +
 beast-gtk/bstkeybindings.c                         |  720 -
 beast-gtk/bstkeybindings.cc                        |  705 +
 beast-gtk/bstkeybindings.h                         |   94 -
 beast-gtk/bstkeybindings.hh                        |   79 +
 beast-gtk/bstknob.c                                |  650 -
 beast-gtk/bstknob.cc                               |  635 +
 beast-gtk/bstknob.h                                |   88 -
 beast-gtk/bstknob.hh                               |   73 +
 beast-gtk/bstlogadjustment.c                       |  225 -
 beast-gtk/bstlogadjustment.cc                      |  210 +
 beast-gtk/bstlogadjustment.h                       |   69 -
 beast-gtk/bstlogadjustment.hh                      |   54 +
 beast-gtk/bstmain.c                                |  899 -
 beast-gtk/bstmain.cc                               |  855 +
 beast-gtk/bstmenus.c                               |  465 -
 beast-gtk/bstmenus.cc                              |  448 +
 beast-gtk/bstmenus.h                               |   91 -
 beast-gtk/bstmenus.hh                              |   85 +
 beast-gtk/bstmsgabsorb.c                           |  422 -
 beast-gtk/bstmsgabsorb.cc                          |  407 +
 beast-gtk/bstmsgabsorb.h                           |   48 -
 beast-gtk/bstmsgabsorb.hh                          |   33 +
 beast-gtk/bstparam-automation.c                    |  238 -
 beast-gtk/bstparam-automation.cc                   |  223 +
 beast-gtk/bstparam-choice.c                        |  170 -
 beast-gtk/bstparam-choice.cc                       |  155 +
 beast-gtk/bstparam-color-spinner.c                 |  119 -
 beast-gtk/bstparam-color-spinner.cc                |  104 +
 beast-gtk/bstparam-item-seq.c                      |  149 -
 beast-gtk/bstparam-item-seq.cc                     |  134 +
 beast-gtk/bstparam-note-sequence.c                 |   64 -
 beast-gtk/bstparam-note-sequence.cc                |   49 +
 beast-gtk/bstparam-note-spinner.c                  |   78 -
 beast-gtk/bstparam-note-spinner.cc                 |   63 +
 beast-gtk/bstparam-proxy.c                         |  298 -
 beast-gtk/bstparam-proxy.cc                        |  283 +
 beast-gtk/bstparam-scale.c                         |   98 -
 beast-gtk/bstparam-scale.cc                        |   83 +
 beast-gtk/bstparam-searchpath.c                    |  157 -
 beast-gtk/bstparam-searchpath.cc                   |  142 +
 beast-gtk/bstparam-time.c                          |   58 -
 beast-gtk/bstparam-time.cc                         |   43 +
 beast-gtk/bstparam.c                               |  462 -
 beast-gtk/bstparam.cc                              |  448 +
 beast-gtk/bstparam.h                               |   70 -
 beast-gtk/bstparam.hh                              |   55 +
 beast-gtk/bstparamview.c                           |  273 -
 beast-gtk/bstparamview.cc                          |  258 +
 beast-gtk/bstparamview.h                           |   72 -
 beast-gtk/bstparamview.hh                          |   57 +
 beast-gtk/bstpartdialog.c                          |  438 -
 beast-gtk/bstpartdialog.cc                         |  421 +
 beast-gtk/bstpartdialog.h                          |   66 -
 beast-gtk/bstpartdialog.hh                         |   51 +
 beast-gtk/bstpartview.c                            |  146 -
 beast-gtk/bstpartview.cc                           |  131 +
 beast-gtk/bstpartview.h                            |   52 -
 beast-gtk/bstpartview.hh                           |   37 +
 beast-gtk/bstpatterncolumns.c                      |  902 -
 beast-gtk/bstpatterncolumns.cc                     |  890 +
 beast-gtk/bstpatterncolumns.h                      |  167 -
 beast-gtk/bstpatterncolumns.hh                     |  166 +
 beast-gtk/bstpatternctrl.c                         |  561 -
 beast-gtk/bstpatternctrl.cc                        |  564 +
 beast-gtk/bstpatternctrl.h                         |   50 -
 beast-gtk/bstpatternctrl.hh                        |   35 +
 beast-gtk/bstpatternview.c                         | 1251 --
 beast-gtk/bstpatternview.cc                        | 1231 ++
 beast-gtk/bstpatternview.h                         |  157 -
 beast-gtk/bstpatternview.hh                        |  138 +
 beast-gtk/bstpianoroll.c                           | 1513 --
 beast-gtk/bstpianoroll.cc                          | 1497 ++
 beast-gtk/bstpianoroll.h                           |  135 -
 beast-gtk/bstpianoroll.hh                          |  120 +
 beast-gtk/bstpianorollctrl.c                       |  975 -
 beast-gtk/bstpianorollctrl.cc                      |  959 +
 beast-gtk/bstpianorollctrl.h                       |   70 -
 beast-gtk/bstpianorollctrl.hh                      |   55 +
 beast-gtk/bstplayback.c                            |  205 -
 beast-gtk/bstplayback.cc                           |  190 +
 beast-gtk/bstplayback.h                            |   74 -
 beast-gtk/bstplayback.hh                           |   59 +
 beast-gtk/bstplaylist.c                            |  569 -
 beast-gtk/bstplaylist.cc                           |  554 +
 beast-gtk/bstplaylist.h                            |   68 -
 beast-gtk/bstplaylist.hh                           |   53 +
 beast-gtk/bstpreferences.c                         |  400 -
 beast-gtk/bstpreferences.cc                        |  387 +
 beast-gtk/bstpreferences.h                         |   77 -
 beast-gtk/bstpreferences.hh                        |   62 +
 beast-gtk/bstprocbrowser.c                         |  272 -
 beast-gtk/bstprocbrowser.cc                        |  257 +
 beast-gtk/bstprocbrowser.h                         |   72 -
 beast-gtk/bstprocbrowser.hh                        |   57 +
 beast-gtk/bstprocedure.c                           |  594 -
 beast-gtk/bstprocedure.cc                          |  579 +
 beast-gtk/bstprocedure.h                           |   88 -
 beast-gtk/bstprocedure.hh                          |   73 +
 beast-gtk/bstprofiler.c                            |  272 -
 beast-gtk/bstprofiler.cc                           |  164 +
 beast-gtk/bstprofiler.h                            |   29 -
 beast-gtk/bstprofiler.hh                           |   14 +
 beast-gtk/bstprojectctrl.c                         |  189 -
 beast-gtk/bstprojectctrl.cc                        |  174 +
 beast-gtk/bstprojectctrl.h                         |   57 -
 beast-gtk/bstprojectctrl.hh                        |   42 +
 beast-gtk/bstqsampler.c                            | 1397 --
 beast-gtk/bstqsampler.cc                           | 1380 ++
 beast-gtk/bstqsampler.h                            |  204 -
 beast-gtk/bstqsampler.hh                           |  197 +
 beast-gtk/bstrackeditor-covers.c                   |  190 -
 beast-gtk/bstrackeditor-covers.cc                  |  177 +
 beast-gtk/bstrackeditor.c                          |  313 -
 beast-gtk/bstrackeditor.cc                         |  297 +
 beast-gtk/bstrackeditor.h                          |   70 -
 beast-gtk/bstrackeditor.hh                         |   55 +
 beast-gtk/bstrackitem.c                            |  267 -
 beast-gtk/bstrackitem.cc                           |  248 +
 beast-gtk/bstrackitem.h                            |   63 -
 beast-gtk/bstrackitem.hh                           |   48 +
 beast-gtk/bstracktable.c                           | 1018 -
 beast-gtk/bstracktable.cc                          | 1001 +
 beast-gtk/bstracktable.h                           |  111 -
 beast-gtk/bstracktable.hh                          |   96 +
 beast-gtk/bstrackview.c                            |  267 -
 beast-gtk/bstrackview.cc                           |  252 +
 beast-gtk/bstrackview.h                            |   58 -
 beast-gtk/bstrackview.hh                           |   43 +
 beast-gtk/bstrecords.idl                           |  206 +-
 beast-gtk/bstrtest.c                               |  313 -
 beast-gtk/bstrtest.cc                              |  298 +
 beast-gtk/bstsampleeditor.c                        |  544 -
 beast-gtk/bstsampleeditor.cc                       |  526 +
 beast-gtk/bstsampleeditor.h                        |   76 -
 beast-gtk/bstsampleeditor.hh                       |   61 +
 beast-gtk/bstscrollgraph.c                         |  701 -
 beast-gtk/bstscrollgraph.cc                        |  686 +
 beast-gtk/bstscrollgraph.h                         |   72 -
 beast-gtk/bstscrollgraph.hh                        |   57 +
 beast-gtk/bstsegment.c                             |  217 -
 beast-gtk/bstsegment.cc                            |  202 +
 beast-gtk/bstsegment.h                             |   79 -
 beast-gtk/bstsegment.hh                            |   64 +
 beast-gtk/bstsequence.c                            |  295 -
 beast-gtk/bstsequence.cc                           |  280 +
 beast-gtk/bstsequence.h                            |   68 -
 beast-gtk/bstsequence.hh                           |   53 +
 beast-gtk/bstservermonitor.c                       |   98 -
 beast-gtk/bstservermonitor.cc                      |   83 +
 beast-gtk/bstservermonitor.h                       |   64 -
 beast-gtk/bstservermonitor.hh                      |   49 +
 beast-gtk/bstskinconfig.c                          |  321 -
 beast-gtk/bstskinconfig.cc                         |  308 +
 beast-gtk/bstskinconfig.h                          |   50 -
 beast-gtk/bstskinconfig.hh                         |   35 +
 beast-gtk/bstsnetrouter.c                          | 1178 --
 beast-gtk/bstsnetrouter.cc                         | 1148 ++
 beast-gtk/bstsnetrouter.h                          |   81 -
 beast-gtk/bstsnetrouter.hh                         |   66 +
 beast-gtk/bstsnifferscope.c                        |  344 -
 beast-gtk/bstsnifferscope.cc                       |  329 +
 beast-gtk/bstsnifferscope.h                        |   61 -
 beast-gtk/bstsnifferscope.hh                       |   46 +
 beast-gtk/bstsplash.c                              |  475 -
 beast-gtk/bstsplash.cc                             |  436 +
 beast-gtk/bstsplash.h                              |   93 -
 beast-gtk/bstsplash.hh                             |   72 +
 beast-gtk/bststest.c                               |  770 -
 beast-gtk/bststest.cc                              |  754 +
 beast-gtk/bstsupershell.c                          |  281 -
 beast-gtk/bstsupershell.cc                         |  266 +
 beast-gtk/bstsupershell.h                          |   56 -
 beast-gtk/bstsupershell.hh                         |   41 +
 beast-gtk/bsttrackroll.c                           | 1251 --
 beast-gtk/bsttrackroll.cc                          | 1235 ++
 beast-gtk/bsttrackroll.h                           |  149 -
 beast-gtk/bsttrackroll.hh                          |  134 +
 beast-gtk/bsttrackrollctrl.c                       |  725 -
 beast-gtk/bsttrackrollctrl.cc                      |  709 +
 beast-gtk/bsttrackrollctrl.h                       |   64 -
 beast-gtk/bsttrackrollctrl.hh                      |   49 +
 beast-gtk/bsttracksynthdialog.c                    |  342 -
 beast-gtk/bsttracksynthdialog.cc                   |  326 +
 beast-gtk/bsttracksynthdialog.h                    |   89 -
 beast-gtk/bsttracksynthdialog.hh                   |   73 +
 beast-gtk/bsttrackview.c                           |  792 -
 beast-gtk/bsttrackview.cc                          |  777 +
 beast-gtk/bsttrackview.h                           |   59 -
 beast-gtk/bsttrackview.hh                          |   44 +
 beast-gtk/bsttreestores.c                          |  724 -
 beast-gtk/bsttreestores.cc                         |  704 +
 beast-gtk/bsttreestores.h                          |  104 -
 beast-gtk/bsttreestores.hh                         |   89 +
 beast-gtk/bstusermessage.c                         |  852 -
 beast-gtk/bstusermessage.cc                        |  783 +
 beast-gtk/bstusermessage.h                         |  108 -
 beast-gtk/bstusermessage.hh                        |   84 +
 beast-gtk/bstutils.c                               | 1500 --
 beast-gtk/bstutils.cc                              | 1515 ++
 beast-gtk/bstutils.h                               |  239 -
 beast-gtk/bstutils.hh                              |  234 +
 beast-gtk/bstwaveeditor.c                          |  706 -
 beast-gtk/bstwaveeditor.cc                         |  688 +
 beast-gtk/bstwaveeditor.h                          |   95 -
 beast-gtk/bstwaveeditor.hh                         |   80 +
 beast-gtk/bstwaveview.c                            |  191 -
 beast-gtk/bstwaveview.cc                           |  175 +
 beast-gtk/bstwaveview.h                            |   56 -
 beast-gtk/bstwaveview.hh                           |   41 +
 beast-gtk/bstxframe.c                              |  377 -
 beast-gtk/bstxframe.cc                             |  362 +
 beast-gtk/bstxframe.h                              |   67 -
 beast-gtk/bstxframe.hh                             |   52 +
 beast-gtk/bstxkb.c                                 |  198 -
 beast-gtk/bstxkb.cc                                |  183 +
 beast-gtk/bstxkb.h                                 |   48 -
 beast-gtk/bstxkb.hh                                |   33 +
 beast-gtk/bstzoomedwindow.c                        |  257 -
 beast-gtk/bstzoomedwindow.cc                       |  243 +
 beast-gtk/bstzoomedwindow.h                        |   63 -
 beast-gtk/bstzoomedwindow.hh                       |   48 +
 beast-gtk/dialogs/.gitignore                       |    2 +-
 beast-gtk/dialogs/Makefile.am                      |   14 +-
 beast-gtk/dialogs/radgets-beast.xml                |   12 +-
 beast-gtk/dialogs/radgets-standard.xml             |   12 +-
 beast-gtk/gxk/Makefile.am                          |   77 +-
 beast-gtk/gxk/gle-pull.sh                          |    2 +
 beast-gtk/gxk/glewidgets.c                         |  362 +-
 beast-gtk/gxk/glewidgets.h                         |    8 +-
 beast-gtk/gxk/gxk.h                                |   50 -
 beast-gtk/gxk/gxk.hh                               |   35 +
 beast-gtk/gxk/gxkaction.c                          |  992 -
 beast-gtk/gxk/gxkaction.cc                         |  977 +
 beast-gtk/gxk/gxkaction.h                          |  180 -
 beast-gtk/gxk/gxkaction.hh                         |  165 +
 beast-gtk/gxk/gxkassortment.c                      |  646 -
 beast-gtk/gxk/gxkassortment.cc                     |  631 +
 beast-gtk/gxk/gxkassortment.h                      |  114 -
 beast-gtk/gxk/gxkassortment.hh                     |   99 +
 beast-gtk/gxk/gxkauxwidgets.c                      |  819 -
 beast-gtk/gxk/gxkauxwidgets.cc                     |  804 +
 beast-gtk/gxk/gxkauxwidgets.h                      |  112 -
 beast-gtk/gxk/gxkauxwidgets.hh                     |   97 +
 beast-gtk/gxk/gxkcanvas.c                          |  246 -
 beast-gtk/gxk/gxkcanvas.cc                         |  231 +
 beast-gtk/gxk/gxkcanvas.h                          |   50 -
 beast-gtk/gxk/gxkcanvas.hh                         |   35 +
 beast-gtk/gxk/gxkcellrendererpopup.c               |  544 -
 beast-gtk/gxk/gxkcellrendererpopup.cc              |  529 +
 beast-gtk/gxk/gxkcellrendererpopup.h               |   91 -
 beast-gtk/gxk/gxkcellrendererpopup.hh              |   76 +
 beast-gtk/gxk/gxkdialog.c                          |  734 -
 beast-gtk/gxk/gxkdialog.cc                         |  717 +
 beast-gtk/gxk/gxkdialog.h                          |  132 -
 beast-gtk/gxk/gxkdialog.hh                         |  131 +
 beast-gtk/gxk/gxkglobals.c                         |   59 -
 beast-gtk/gxk/gxkglobals.cc                        |   44 +
 beast-gtk/gxk/gxkglobals.h                         |   76 -
 beast-gtk/gxk/gxkglobals.hh                        |   84 +
 beast-gtk/gxk/gxkimagecache.c                      |  199 -
 beast-gtk/gxk/gxkimagecache.cc                     |  184 +
 beast-gtk/gxk/gxkimagecache.h                      |   44 -
 beast-gtk/gxk/gxkimagecache.hh                     |   29 +
 beast-gtk/gxk/gxkled.c                             |  332 -
 beast-gtk/gxk/gxkled.cc                            |  317 +
 beast-gtk/gxk/gxkled.h                             |   66 -
 beast-gtk/gxk/gxkled.hh                            |   51 +
 beast-gtk/gxk/gxklistwrapper.c                     |  544 -
 beast-gtk/gxk/gxklistwrapper.cc                    |  526 +
 beast-gtk/gxk/gxklistwrapper.h                     |   86 -
 beast-gtk/gxk/gxklistwrapper.hh                    |   71 +
 beast-gtk/gxk/gxklogadjustment.c                   |  460 -
 beast-gtk/gxk/gxklogadjustment.cc                  |  445 +
 beast-gtk/gxk/gxklogadjustment.h                   |  117 -
 beast-gtk/gxk/gxklogadjustment.hh                  |  102 +
 beast-gtk/gxk/gxkmenubutton.c                      |  790 -
 beast-gtk/gxk/gxkmenubutton.cc                     |  775 +
 beast-gtk/gxk/gxkmenubutton.h                      |   59 -
 beast-gtk/gxk/gxkmenubutton.hh                     |   44 +
 beast-gtk/gxk/gxknotebook.c                        |  299 -
 beast-gtk/gxk/gxknotebook.cc                       |  284 +
 beast-gtk/gxk/gxknotebook.h                        |   51 -
 beast-gtk/gxk/gxknotebook.hh                       |   36 +
 beast-gtk/gxk/gxkparam-entry.c                     |   66 -
 beast-gtk/gxk/gxkparam-entry.cc                    |   51 +
 beast-gtk/gxk/gxkparam-label.c                     |   80 -
 beast-gtk/gxk/gxkparam-label.cc                    |   65 +
 beast-gtk/gxk/gxkparam-scale.c                     |  118 -
 beast-gtk/gxk/gxkparam-scale.cc                    |  103 +
 beast-gtk/gxk/gxkparam-spinner.c                   |  107 -
 beast-gtk/gxk/gxkparam-spinner.cc                  |   92 +
 beast-gtk/gxk/gxkparam-toggle.c                    |   91 -
 beast-gtk/gxk/gxkparam-toggle.cc                   |   76 +
 beast-gtk/gxk/gxkparam.c                           | 1184 --
 beast-gtk/gxk/gxkparam.cc                          | 1172 ++
 beast-gtk/gxk/gxkparam.h                           |  194 -
 beast-gtk/gxk/gxkparam.hh                          |  179 +
 beast-gtk/gxk/gxkpolygon.c                         |  594 -
 beast-gtk/gxk/gxkpolygon.cc                        |  579 +
 beast-gtk/gxk/gxkpolygon.h                         |   88 -
 beast-gtk/gxk/gxkpolygon.hh                        |   73 +
 beast-gtk/gxk/gxkrackcovers.c                      |  202 -
 beast-gtk/gxk/gxkrackcovers.cc                     |  187 +
 beast-gtk/gxk/gxkrackeditor.c                      |  681 -
 beast-gtk/gxk/gxkrackeditor.cc                     |  666 +
 beast-gtk/gxk/gxkrackeditor.h                      |   77 -
 beast-gtk/gxk/gxkrackeditor.hh                     |   62 +
 beast-gtk/gxk/gxkrackitem.c                        |  319 -
 beast-gtk/gxk/gxkrackitem.cc                       |  304 +
 beast-gtk/gxk/gxkrackitem.h                        |   63 -
 beast-gtk/gxk/gxkrackitem.hh                       |   48 +
 beast-gtk/gxk/gxkracktable.c                       |  707 -
 beast-gtk/gxk/gxkracktable.cc                      |  691 +
 beast-gtk/gxk/gxkracktable.h                       |   94 -
 beast-gtk/gxk/gxkracktable.hh                      |   79 +
 beast-gtk/gxk/gxkradget.c                          | 2465 ---
 beast-gtk/gxk/gxkradget.cc                         | 2448 +++
 beast-gtk/gxk/gxkradget.h                          |  126 -
 beast-gtk/gxk/gxkradget.hh                         |  111 +
 beast-gtk/gxk/gxkradgetfactory.c                   |  606 -
 beast-gtk/gxk/gxkradgetfactory.cc                  |  591 +
 beast-gtk/gxk/gxkradgetfactory.h                   |   92 -
 beast-gtk/gxk/gxkradgetfactory.hh                  |   77 +
 beast-gtk/gxk/gxkscrollcanvas.c                    | 1901 --
 beast-gtk/gxk/gxkscrollcanvas.cc                   | 1878 ++
 beast-gtk/gxk/gxkscrollcanvas.h                    |  250 -
 beast-gtk/gxk/gxkscrollcanvas.hh                   |  235 +
 beast-gtk/gxk/gxksimplelabel.c                     |  704 -
 beast-gtk/gxk/gxksimplelabel.cc                    |  677 +
 beast-gtk/gxk/gxksimplelabel.h                     |   58 -
 beast-gtk/gxk/gxksimplelabel.hh                    |   39 +
 beast-gtk/gxk/gxkspline.c                          |  444 -
 beast-gtk/gxk/gxkspline.cc                         |  429 +
 beast-gtk/gxk/gxkspline.h                          |   58 -
 beast-gtk/gxk/gxkspline.hh                         |   43 +
 beast-gtk/gxk/gxkstatusbar.c                       |  391 -
 beast-gtk/gxk/gxkstatusbar.cc                      |  315 +
 beast-gtk/gxk/gxkstatusbar.h                       |   69 -
 beast-gtk/gxk/gxkstatusbar.hh                      |   48 +
 beast-gtk/gxk/gxkstock.c                           |  402 -
 beast-gtk/gxk/gxkstock.cc                          |  387 +
 beast-gtk/gxk/gxkstock.h                           |   80 -
 beast-gtk/gxk/gxkstock.hh                          |   65 +
 beast-gtk/gxk/gxktest.c                            |  370 -
 beast-gtk/gxk/gxktest.cc                           |  353 +
 beast-gtk/gxk/gxktexttools.c                       | 2315 ---
 beast-gtk/gxk/gxktexttools.cc                      | 2269 +++
 beast-gtk/gxk/gxktexttools.h                       |  109 -
 beast-gtk/gxk/gxktexttools.hh                      |  101 +
 beast-gtk/gxk/gxkutils.c                           | 3971 ----
 beast-gtk/gxk/gxkutils.cc                          | 3951 ++++
 beast-gtk/gxk/gxkutils.h                           |  365 -
 beast-gtk/gxk/gxkutils.hh                          |  350 +
 beast-gtk/gxk/splinetest.c                         |  186 -
 beast-gtk/gxk/splinetest.cc                        |  170 +
 beast-gtk/icons/.gitignore                         |    2 +-
 beast-gtk/icons/Makefile.am                        |   13 +-
 beast-gtk/testgui.c                                |  161 -
 beast-gtk/testgui.cc                               |  137 +
 beast-gtk/tsmview.c                                |  104 -
 beast-gtk/tsmview.cc                               |   89 +
 beast.doap                                         |    4 +-
 birnet/.gitignore                                  |    4 -
 birnet/COPYING.LGPL                                |  504 -
 birnet/Makefile.am                                 |  137 -
 birnet/acbirnet.m4                                 |  340 -
 birnet/birnet-zintern.cc                           |  233 -
 birnet/birnet.hh                                   |   32 -
 birnet/birnetcdefs.h                               |  382 -
 birnet/birnetcpu.cc                                |  309 -
 birnet/birnetcpu.hh                                |   36 -
 birnet/birnetdebugtools.cc                         |  112 -
 birnet/birnetdebugtools.hh                         |   50 -
 birnet/birnetmath.cc                               |   21 -
 birnet/birnetmath.hh                               |   79 -
 birnet/birnetmsg.cc                                |  627 -
 birnet/birnetmsg.hh                                |  199 -
 birnet/birnettests.h                               |  349 -
 birnet/birnetthread.cc                             |  342 -
 birnet/birnetthread.hh                             |  359 -
 birnet/birnetthreadimpl.cc                         | 1780 --
 birnet/birnetutf8.cc                               |  325 -
 birnet/birnetutf8.hh                               |  210 -
 birnet/birnetutils.cc                              | 1477 --
 birnet/birnetutils.hh                              |  622 -
 birnet/configure.inc                               |  160 -
 birnet/examples/mkhost.sh                          |  370 -
 birnet/tests/.gitignore                            |    9 -
 birnet/tests/Makefile.am                           |   40 -
 birnet/tests/datalist.cc                           |  126 -
 birnet/tests/infotest.cc                           |  168 -
 birnet/tests/math.cc                               |  179 -
 birnet/tests/sorting.cc                            |  139 -
 birnet/tests/strings.cc                            |  272 -
 birnet/tests/systest.cc                            |   54 -
 birnet/tests/threads.cc                            | 1187 --
 birnet/tests/utils.cc                              |  102 -
 bse/AuxTypes.py                                    |   31 +
 bse/Makefile.am                                    |  324 +-
 bse/bse-internals.hh                               |   15 +
 bse/bse.h                                          |   46 -
 bse/bse.hh                                         |   21 +
 bse/bse.idl                                        |   30 +-
 bse/bseapi.idl                                     |   41 +
 bse/bseautodoc.c                                   |  632 -
 bse/bseautodoc.cc                                  |  606 +
 bse/bsebasics.cc                                   |   16 +
 bse/bsebasics.idl                                  |  713 +
 bse/bsebiquadfilter.c                              |  553 -
 bse/bsebiquadfilter.cc                             |  532 +
 bse/bsebiquadfilter.h                              |   94 -
 bse/bsebiquadfilter.hh                             |   71 +
 bse/bseblockutils.cc                               |   18 +-
 bse/bseblockutils.hh                               |   79 +-
 bse/bsebus.c                                       |  937 -
 bse/bsebus.cc                                      |  923 +
 bse/bsebus.h                                       |  103 -
 bse/bsebus.hh                                      |   82 +
 bse/bsebus.proc                                    |   53 +-
 bse/bsebusmodule.cc                                |   19 +-
 bse/bsebusmodule.idl                               |   39 +-
 bse/bsecategories.c                                |  366 -
 bse/bsecategories.cc                               |  348 +
 bse/bsecategories.h                                |   55 -
 bse/bsecategories.hh                               |   38 +
 bse/bsecategories.proc                             |   68 +-
 bse/bsecompat.c                                    |  100 -
 bse/bsecompat.cc                                   |   86 +
 bse/bsecompat.h                                    |   54 -
 bse/bsecompat.hh                                   |   39 +
 bse/bseconfig.h.in                                 |   35 +-
 bse/bseconstant.c                                  |  306 -
 bse/bseconstant.cc                                 |  288 +
 bse/bseconstant.h                                  |   59 -
 bse/bseconstant.hh                                 |   34 +
 bse/bseconstvalues.c                               |   19 -
 bse/bseconstvalues.cc                              |    4 +
 bse/bseconstvalues.h                               |  102 -
 bse/bseconstvalues.hh                              |   87 +
 bse/bsecontainer.c                                 | 1371 --
 bse/bsecontainer.cc                                | 1355 ++
 bse/bsecontainer.h                                 |  128 -
 bse/bsecontainer.hh                                |  106 +
 bse/bsecontainer.proc                              |   46 +-
 bse/bsecontextmerger.c                             |  226 -
 bse/bsecontextmerger.cc                            |  211 +
 bse/bsecontextmerger.h                             |   52 -
 bse/bsecontextmerger.hh                            |   27 +
 bse/bsecore.cc                                     |  202 +-
 bse/bsecore.hh                                     |   36 +
 bse/bsecore.idl                                    |  833 -
 bse/bsecsynth.c                                    |  119 -
 bse/bsecsynth.cc                                   |  104 +
 bse/bsecsynth.h                                    |   50 -
 bse/bsecsynth.hh                                   |   27 +
 bse/bsecsynth.proc                                 |   25 +-
 bse/bsecxxarg.cc                                   |   17 +-
 bse/bsecxxarg.hh                                   |   23 +-
 bse/bsecxxbase.cc                                  |   23 +-
 bse/bsecxxbase.hh                                  |   19 +-
 bse/bsecxxbase.idl                                 |   27 +-
 bse/bsecxxclosure.cc                               |   19 +-
 bse/bsecxxclosure.hh                               |   19 +-
 bse/bsecxxmodule.cc                                |   83 +-
 bse/bsecxxmodule.hh                                |   65 +-
 bse/bsecxxmodule.idl                               |   25 +-
 bse/bsecxxplugin.cc                                |   21 +-
 bse/bsecxxplugin.hh                                |   65 +-
 bse/bsecxxutils.cc                                 |   58 +-
 bse/bsecxxutils.hh                                 |   23 +-
 bse/bsecxxvalue.cc                                 |   21 +-
 bse/bsecxxvalue.hh                                 |   21 +-
 bse/bsedatahandle-fir.cc                           |   53 +-
 bse/bsedatahandle-flac.cc                          |  453 +
 bse/bsedatahandle-flac.hh                          |   38 +
 bse/bsedatahandle-resample.cc                      |   48 +-
 bse/bsedatapocket.c                                |  686 -
 bse/bsedatapocket.cc                               |  673 +
 bse/bsedatapocket.h                                |  106 -
 bse/bsedatapocket.hh                               |   81 +
 bse/bsedatapocket.proc                             |  179 +-
 bse/bsedefs.h                                      |  172 -
 bse/bsedefs.hh                                     |  146 +
 bse/bsedevice.c                                    |  517 -
 bse/bsedevice.cc                                   |  502 +
 bse/bsedevice.h                                    |  139 -
 bse/bsedevice.hh                                   |  117 +
 bse/bseeditablesample.c                            |  188 -
 bse/bseeditablesample.cc                           |  173 +
 bse/bseeditablesample.h                            |   66 -
 bse/bseeditablesample.hh                           |   36 +
 bse/bseeditablesample.proc                         |  131 +-
 bse/bseengine.c                                    | 1626 --
 bse/bseengine.cc                                   | 1515 ++
 bse/bseengine.h                                    |  242 -
 bse/bseengine.hh                                   |  225 +
 bse/bseenginemaster.c                              | 1202 --
 bse/bseenginemaster.cc                             | 1178 ++
 bse/bseenginemaster.h                              |   37 -
 bse/bseenginemaster.hh                             |   28 +
 bse/bseenginenode.h                                |  225 -
 bse/bseenginenode.hh                               |  203 +
 bse/bseengineschedule.c                            |  811 -
 bse/bseengineschedule.cc                           |  762 +
 bse/bseengineschedule.h                            |   66 -
 bse/bseengineschedule.hh                           |   51 +
 bse/bseengineutils.c                               |  860 -
 bse/bseengineutils.cc                              |  797 +
 bse/bseengineutils.h                               |   73 -
 bse/bseengineutils.hh                              |   57 +
 bse/bseenums.c                                     |  183 -
 bse/bseenums.cc                                    |  164 +
 bse/bseenums.h                                     |  156 -
 bse/bseenums.hh                                    |  152 +
 bse/bseenums.proc                                  |   43 +-
 bse/bseexports.h                                   |  187 -
 bse/bseexports.hh                                  |  169 +
 bse/bsefilter-ellf.c                               | 1607 --
 bse/bsefilter-ellf.cc                              | 1589 ++
 bse/bsefilter.cc                                   |   26 +-
 bse/bsefilter.h                                    |  110 -
 bse/bsefilter.hh                                   |   90 +
 bse/bsegconfig.c                                   |  138 -
 bse/bsegconfig.cc                                  |  218 +
 bse/bsegconfig.h                                   |   37 -
 bse/bsegconfig.hh                                  |   22 +
 bse/{bsegenclosures.h => bsegenclosures.hh}        |    0
 bse/bseglobals.c                                   |  228 -
 bse/bseglobals.cc                                  |  213 +
 bse/bseglobals.h                                   |   95 -
 bse/bseglobals.hh                                  |   80 +
 bse/bseglue.c                                      | 1177 --
 bse/bseglue.cc                                     | 1162 ++
 bse/bseglue.h                                      |   50 -
 bse/bseglue.hh                                     |   35 +
 bse/bseieee754.h                                   |  333 -
 bse/bseieee754.hh                                  |  317 +
 bse/bseincluder.h                                  |12343 -----------
 bse/bseincluder.hh                                 |12327 +++++++++++
 bse/bseinfo.c                                      |  122 -
 bse/bseinfo.cc                                     |  104 +
 bse/bseinstrument.c                                |  660 -
 bse/bseinstrument.h                                |   88 -
 bse/bseinstrument.hh                               |   73 +
 bse/bseinstrumentinput.c                           |  152 -
 bse/bseinstrumentinput.cc                          |  151 +
 bse/bseinstrumentinput.h                           |   58 -
 bse/bseinstrumentinput.hh                          |   34 +
 bse/bseinstrumentoutput.c                          |  152 -
 bse/bseinstrumentoutput.cc                         |  151 +
 bse/bseinstrumentoutput.h                          |   57 -
 bse/bseinstrumentoutput.hh                         |   32 +
 bse/bseitem.c                                      | 1268 --
 bse/bseitem.cc                                     | 1239 ++
 bse/bseitem.h                                      |  173 -
 bse/bseitem.hh                                     |  150 +
 bse/bseitem.proc                                   |  239 +-
 bse/bsejanitor.c                                   |  582 -
 bse/bsejanitor.cc                                  |  567 +
 bse/bsejanitor.h                                   |   87 -
 bse/bsejanitor.hh                                  |   67 +
 bse/bsejanitor.proc                                |  182 +-
 bse/bseladspa.cc                                   |  113 +-
 bse/bseladspa.h                                    |  107 -
 bse/bseladspa.hh                                   |   87 +
 bse/bseladspamodule.c                              |  503 -
 bse/bseladspamodule.cc                             |  488 +
 bse/bseladspamodule.h                              |   55 -
 bse/bseladspamodule.hh                             |   34 +
 bse/bseloader-aiff.c                               |  567 -
 bse/bseloader-aiff.cc                              |  549 +
 bse/bseloader-bsewave.c                            |  842 -
 bse/bseloader-bsewave.cc                           |  870 +
 bse/bseloader-flac.cc                              |  189 +
 bse/bseloader-guspatch.cc                          |  192 +-
 bse/bseloader-mad.c                                |  218 -
 bse/bseloader-mad.cc                               |  203 +
 bse/bseloader-oggvorbis.c                          |  180 -
 bse/bseloader-oggvorbis.cc                         |  165 +
 bse/bseloader-wav.c                                |  496 -
 bse/bseloader-wav.cc                               |  463 +
 bse/bseloader.c                                    |  402 -
 bse/bseloader.cc                                   |  387 +
 bse/bseloader.h                                    |  129 -
 bse/bseloader.hh                                   |  112 +
 bse/bsemain.cc                                     |  539 +-
 bse/bsemain.h                                      |  111 -
 bse/bsemain.hh                                     |   67 +
 bse/bsemath.c                                      |  342 -
 bse/bsemath.cc                                     |  253 +
 bse/bsemath.h                                      |  499 -
 bse/bsemath.hh                                     |  484 +
 bse/bsemathsignal.c                                |  743 -
 bse/bsemathsignal.cc                               |  727 +
 bse/bsemathsignal.h                                |  730 -
 bse/bsemathsignal.hh                               |  714 +
 bse/bsemidicontroller.c                            |  335 -
 bse/bsemidicontroller.cc                           |  321 +
 bse/bsemidicontroller.h                            |   64 -
 bse/bsemidicontroller.hh                           |   38 +
 bse/bsemididecoder.c                               |  560 -
 bse/bsemididecoder.cc                              |  543 +
 bse/bsemididecoder.h                               |   77 -
 bse/bsemididecoder.hh                              |   59 +
 bse/bsemididevice-null.c                           |  118 -
 bse/bsemididevice-null.cc                          |   92 +
 bse/bsemididevice-null.h                           |   48 -
 bse/bsemididevice-null.hh                          |   23 +
 bse/bsemididevice-oss.c                            |  300 -
 bse/bsemididevice-oss.cc                           |  270 +
 bse/bsemididevice-oss.h                            |   52 -
 bse/bsemididevice-oss.hh                           |   25 +
 bse/bsemididevice.c                                |   97 -
 bse/bsemididevice.cc                               |   82 +
 bse/bsemididevice.h                                |   68 -
 bse/bsemididevice.hh                               |   35 +
 bse/bsemidievent.c                                 |  276 -
 bse/bsemidievent.cc                                |  262 +
 bse/bsemidievent.h                                 |  347 -
 bse/bsemidievent.hh                                |  332 +
 bse/bsemidifile.c                                  |  367 -
 bse/bsemidifile.cc                                 |  350 +
 bse/bsemidifile.h                                  |   52 -
 bse/bsemidifile.hh                                 |   37 +
 bse/bsemidiinput.c                                 |  273 -
 bse/bsemidiinput.cc                                |  258 +
 bse/bsemidiinput.h                                 |   63 -
 bse/bsemidiinput.hh                                |   37 +
 bse/bsemidinotifier.c                              |  287 -
 bse/bsemidinotifier.cc                             |  274 +
 bse/bsemidinotifier.h                              |   59 -
 bse/bsemidinotifier.hh                             |   32 +
 bse/bsemidinotifier.proc                           |   33 +-
 bse/bsemidireceiver.cc                             |  291 +-
 bse/bsemidireceiver.h                              |  136 -
 bse/bsemidireceiver.hh                             |  116 +
 bse/bsemidisynth.c                                 |  485 -
 bse/bsemidisynth.cc                                |  466 +
 bse/bsemidisynth.h                                 |   63 -
 bse/bsemidisynth.hh                                |   35 +
 bse/bsemidivoice.c                                 |  393 -
 bse/bsemidivoice.cc                                |  378 +
 bse/bsemidivoice.h                                 |   97 -
 bse/bsemidivoice.hh                                |   73 +
 bse/bsenote.cc                                     |   57 +-
 bse/bsenote.h                                      |  108 -
 bse/bsenote.hh                                     |   93 +
 bse/bseobject.c                                    |  887 -
 bse/bseobject.cc                                   |  858 +
 bse/bseobject.h                                    |  181 -
 bse/bseobject.hh                                   |  151 +
 bse/bseparam.c                                     |  113 -
 bse/bseparam.cc                                    |   98 +
 bse/bseparam.h                                     |   78 -
 bse/bseparam.hh                                    |   63 +
 bse/bseparasite.c                                  |  751 -
 bse/bseparasite.cc                                 |  709 +
 bse/bseparasite.h                                  |   61 -
 bse/bseparasite.hh                                 |   46 +
 bse/bseparasite.proc                               |   34 +-
 bse/bsepart.c                                      | 2125 --
 bse/bsepart.cc                                     | 2109 ++
 bse/bsepart.h                                      |  301 -
 bse/bsepart.hh                                     |  270 +
 bse/bsepart.proc                                   |  264 +-
 bse/bsepattern.c                                   | 1072 -
 bse/bsepattern.h                                   |  194 -
 bse/bsepattern.hh                                  |  177 +
 bse/bsepattern.proc.c                              |  254 -
 bse/bsepatterngroup.c                              |  374 -
 bse/bsepatterngroup.h                              |   76 -
 bse/bsepatterngroup.hh                             |   59 +
 bse/bsepcmdevice-null.c                            |  169 -
 bse/bsepcmdevice-null.cc                           |  160 +
 bse/bsepcmdevice-null.h                            |   47 -
 bse/bsepcmdevice-null.hh                           |   26 +
 bse/bsepcmdevice-oss.c                             |  683 -
 bse/bsepcmdevice-oss.cc                            |  650 +
 bse/bsepcmdevice-oss.h                             |   55 -
 bse/bsepcmdevice-oss.hh                            |   26 +
 bse/bsepcmdevice.c                                 |  234 -
 bse/bsepcmdevice.cc                                |  208 +
 bse/bsepcmdevice.h                                 |  111 -
 bse/bsepcmdevice.hh                                |   79 +
 bse/bsepcminput.c                                  |  298 -
 bse/bsepcminput.cc                                 |  283 +
 bse/bsepcminput.h                                  |   62 -
 bse/bsepcminput.hh                                 |   37 +
 bse/bsepcmmodule.c                                 |  276 -
 bse/bsepcmmodule.cc                                |  256 +
 bse/bsepcmoutput.c                                 |  298 -
 bse/bsepcmoutput.cc                                |  283 +
 bse/bsepcmoutput.h                                 |   70 -
 bse/bsepcmoutput.hh                                |   43 +
 bse/bsepcmwriter.c                                 |  202 -
 bse/bsepcmwriter.cc                                |  162 +
 bse/bsepcmwriter.h                                 |   67 -
 bse/bsepcmwriter.hh                                |   46 +
 bse/bseplugin.c                                    |  807 -
 bse/bseplugin.cc                                   |  789 +
 bse/bseplugin.h                                    |  108 -
 bse/bseplugin.hh                                   |   43 +
 bse/bseprobe.cc                                    |   53 +-
 bse/bseprobe.idl                                   |   26 +-
 bse/bseprocedure.c                                 |  754 -
 bse/bseprocedure.cc                                |  716 +
 bse/bseprocedure.h                                 |  111 -
 bse/bseprocedure.hh                                |   96 +
 bse/bseprocedure.proc                              |   84 +-
 bse/bseprocidl.cc                                  |  107 +-
 bse/bseproject.c                                   | 1015 -
 bse/bseproject.cc                                  |  990 +
 bse/bseproject.h                                   |  108 -
 bse/bseproject.hh                                  |   84 +
 bse/bseproject.proc                                |  287 +-
 bse/bsequery.c                                     |  377 -
 bse/bsequery.cc                                    |  349 +
 bse/bseresampler.cc                                |   19 +-
 bse/bseresampler.hh                                |   34 +-
 bse/bseresamplerimpl.hh                            |   92 +-
 bse/bsescripthelper.c                              |  383 -
 bse/bsescripthelper.cc                             |  369 +
 bse/bsescripthelper.h                              |   64 -
 bse/bsescripthelper.hh                             |   49 +
 bse/bsescripthelper.proc                           |   35 +-
 bse/bsesequencer.cc                                |  425 +-
 bse/bsesequencer.h                                 |   45 -
 bse/bsesequencer.hh                                |   51 +
 bse/bseserver.c                                    | 1189 --
 bse/bseserver.cc                                   | 1154 ++
 bse/bseserver.h                                    |  140 -
 bse/bseserver.hh                                   |  115 +
 bse/bseserver.proc                                 |  185 +-
 bse/bsesnet.c                                      |  970 -
 bse/bsesnet.cc                                     |  951 +
 bse/bsesnet.h                                      |  136 -
 bse/bsesnet.hh                                     |  109 +
 bse/bsesnet.proc                                   |   61 +-
 bse/bsesnooper.c                                   |  244 -
 bse/bsesnooper.cc                                  |  227 +
 bse/bsesnooper.h                                   |   54 -
 bse/bsesnooper.hh                                  |   32 +
 bse/bsesong.c                                      |  806 -
 bse/bsesong.cc                                     |  780 +
 bse/bsesong.h                                      |  103 -
 bse/bsesong.hh                                     |   74 +
 bse/bsesong.proc                                   |  155 +-
 bse/bsesource.c                                    | 2082 --
 bse/bsesource.cc                                   | 2063 ++
 bse/bsesource.h                                    |  311 -
 bse/bsesource.hh                                   |  276 +
 bse/bsesource.proc                                 |  246 +-
 bse/bsestandardosc.c                               |  515 -
 bse/bsestandardosc.cc                              |  500 +
 bse/bsestandardosc.h                               |   86 -
 bse/bsestandardosc.hh                              |   55 +
 bse/bsestandardsynths.c                            |  114 -
 bse/bsestandardsynths.cc                           |   99 +
 bse/bsestandardsynths.h                            |   33 -
 bse/bsestandardsynths.hh                           |   18 +
 bse/bsestorage.c                                   | 2189 --
 bse/bsestorage.cc                                  | 2035 ++
 bse/bsestorage.h                                   |  218 -
 bse/bsestorage.hh                                  |  193 +
 bse/bsesubiport.c                                  |  336 -
 bse/bsesubiport.cc                                 |  323 +
 bse/bsesubiport.h                                  |   50 -
 bse/bsesubiport.hh                                 |   24 +
 bse/bsesuboport.c                                  |  337 -
 bse/bsesuboport.cc                                 |  324 +
 bse/bsesuboport.h                                  |   50 -
 bse/bsesuboport.hh                                 |   24 +
 bse/bsesubsynth.c                                  |  553 -
 bse/bsesubsynth.cc                                 |  538 +
 bse/bsesubsynth.h                                  |   60 -
 bse/bsesubsynth.hh                                 |   34 +
 bse/bsesuper.c                                     |  245 -
 bse/bsesuper.cc                                    |  225 +
 bse/bsesuper.h                                     |   71 -
 bse/bsesuper.hh                                    |   41 +
 bse/bsetrack.c                                     | 1131 --
 bse/bsetrack.cc                                    | 1148 ++
 bse/bsetrack.h                                     |  114 -
 bse/bsetrack.hh                                    |   88 +
 bse/bsetrack.proc                                  |   60 +-
 bse/bsetype.c                                      |  469 -
 bse/bsetype.cc                                     |  439 +
 bse/bsetype.h                                      |  207 -
 bse/bsetype.hh                                     |  201 +
 bse/bseundostack.c                                 |  425 -
 bse/bseundostack.cc                                |  403 +
 bse/bseundostack.h                                 |  111 -
 bse/bseundostack.hh                                |   96 +
 bse/bseutils.c                                     |  745 -
 bse/bseutils.cc                                    |  674 +
 bse/bseutils.h                                     |  141 -
 bse/bseutils.hh                                    |  124 +
 bse/bsewave.c                                      |  877 -
 bse/bsewave.cc                                     |  860 +
 bse/bsewave.h                                      |   99 -
 bse/bsewave.hh                                     |   71 +
 bse/bsewave.proc                                   |   77 +-
 bse/bsewaveosc.c                                   |  605 -
 bse/bsewaveosc.cc                                  |  587 +
 bse/bsewaveosc.h                                   |   81 -
 bse/bsewaveosc.hh                                  |   55 +
 bse/bsewaveosc.proc                                |   48 +-
 bse/bsewaverepo.c                                  |  207 -
 bse/bsewaverepo.cc                                 |  191 +
 bse/bsewaverepo.h                                  |   53 -
 bse/bsewaverepo.hh                                 |   27 +
 bse/bsewaverepo.proc                               |   52 +-
 bse/gsl-fftconf.sh                                 |  182 +-
 bse/gsl-fftgen.pl                                  |  136 +-
 bse/gslcommon.c                                    |  382 -
 bse/gslcommon.cc                                   |  412 +
 bse/gslcommon.h                                    |  103 -
 bse/gslcommon.hh                                   |   99 +
 bse/gsldatacache.c                                 |  640 -
 bse/gsldatacache.cc                                |  568 +
 bse/gsldatacache.h                                 |   78 -
 bse/gsldatacache.hh                                |   63 +
 bse/gsldatahandle-mad.c                            |  811 -
 bse/gsldatahandle-mad.cc                           |  778 +
 bse/gsldatahandle-mad.h                            |   39 -
 bse/gsldatahandle-mad.hh                           |   24 +
 bse/gsldatahandle-vorbis.c                         |  574 -
 bse/gsldatahandle-vorbis.cc                        |  559 +
 bse/gsldatahandle-vorbis.h                         |   54 -
 bse/gsldatahandle-vorbis.hh                        |   39 +
 bse/gsldatahandle.c                                | 1812 --
 bse/gsldatahandle.cc                               | 1745 ++
 bse/gsldatahandle.h                                |  200 -
 bse/gsldatahandle.hh                               |  182 +
 bse/gsldatautils.c                                 |  903 -
 bse/gsldatautils.cc                                |  885 +
 bse/gsldatautils.h                                 | 1456 --
 bse/gsldatautils.hh                                | 1441 ++
 bse/gsldefs.h                                      |   64 -
 bse/gsldefs.hh                                     |   50 +
 bse/gslfft.h                                       |  156 -
 bse/gslfft.hh                                      |  191 +
 bse/gslfilehash.c                                  |  510 -
 bse/gslfilehash.cc                                 |  449 +
 bse/gslfilehash.h                                  |   78 -
 bse/gslfilehash.hh                                 |   63 +
 bse/gslfilter.c                                    | 1420 --
 bse/gslfilter.cc                                   | 1401 ++
 bse/gslfilter.h                                    |  280 -
 bse/gslfilter.hh                                   |  265 +
 bse/gslincluder.c                                  |13420 ------------
 bse/gslincluder.hh                                 |13414 ++++++++++++
 bse/gslmagic.c                                     |  802 -
 bse/gslmagic.cc                                    |  775 +
 bse/gslmagic.h                                     |   77 -
 bse/gslmagic.hh                                    |   63 +
 bse/gsloscillator-aux.c                            |  213 -
 bse/gsloscillator-aux.cc                           |  198 +
 bse/gsloscillator.c                                |  234 -
 bse/gsloscillator.cc                               |  219 +
 bse/gsloscillator.h                                |   84 -
 bse/gsloscillator.hh                               |   69 +
 bse/gslosctable.c                                  |  654 -
 bse/gslosctable.cc                                 |  626 +
 bse/gslosctable.h                                  |   98 -
 bse/gslosctable.hh                                 |   84 +
 bse/gslvorbis-cutter.c                             |  413 -
 bse/gslvorbis-cutter.cc                            |  395 +
 bse/gslvorbis-cutter.h                             |   54 -
 bse/gslvorbis-cutter.hh                            |   39 +
 bse/gslvorbis-enc.c                                |  520 -
 bse/gslvorbis-enc.cc                               |  503 +
 bse/gslvorbis-enc.h                                |   81 -
 bse/gslvorbis-enc.hh                               |   66 +
 bse/gslwavechunk.c                                 |  815 -
 bse/gslwavechunk.cc                                |  800 +
 bse/gslwavechunk.h                                 |  125 -
 bse/gslwavechunk.hh                                |  110 +
 bse/gslwaveosc-aux.c                               |  200 -
 bse/gslwaveosc-aux.cc                              |  185 +
 bse/gslwaveosc.c                                   |  414 -
 bse/gslwaveosc.cc                                  |  387 +
 bse/gslwaveosc.h                                   |   97 -
 bse/gslwaveosc.hh                                  |   82 +
 bse/icons/Makefile.am                              |    5 +-
 bse/ladspa.h                                       |  603 -
 bse/ladspa.hh                                      |  584 +
 bse/ldscript.map                                   |    1 +
 bse/mkcalls.pl                                     |    1 +
 bse/mkcproc.pl                                     |    6 +-
 bse/mktypes.pl                                     |    3 +-
 bse/oldidl.idl                                     |   54 +
 bse/patch-bseserverapi.cc.diff                     |   23 +
 bse/raw2bse                                        |    1 +
 bse/testobject.cc                                  |   20 +
 bse/testobject.hh                                  |   19 +
 bse/tests/Makefile.am                              |   17 +-
 bse/tests/arrows.gp                                |    4 +-
 bse/tests/blocktests.cc                            |  153 +-
 bse/tests/filter-defs.gp                           |    4 +-
 bse/tests/filtercatalog.cc                         | 1200 +-
 bse/tests/filtertest.cc                            |  216 +-
 bse/tests/firhandle.cc                             |  122 +-
 bse/tests/loophandle.c                             |  226 -
 bse/tests/loophandle.cc                            |  205 +
 bse/tests/misctests.cc                             |   77 +-
 bse/tests/resamplehandle.cc                        |  149 +-
 bse/tests/subnormals-aux.cc                        |   21 +-
 bse/tests/subnormals.cc                            |  111 +-
 bse/tests/testcxx.cc                               |   26 +-
 bse/tests/testfft.c                                |  461 -
 bse/tests/testfft.cc                               |  577 +
 bse/zintern/Makefile.am                            |   17 +-
 bse/zintern/adsr-wave-1.bse                        |    4 +-
 bse/zintern/adsr-wave-2.bse                        |    4 +-
 bse/zintern/gus-patch.bse                          |    4 +-
 bse/zintern/plain-wave-1.bse                       |    4 +-
 bse/zintern/plain-wave-2.bse                       |    4 +-
 configure.ac                                       |  769 +
 configure.in                                       |  652 -
 data/Makefile.am                                   |    7 +-
 data/beast-splash.png                              |  Bin 39677 -> 39517 bytes
 data/bse.pc.in                                     |    2 +-
 docs/.gitignore                                    |    4 -
 docs/ChangeLog.svn                                 |    4 +-
 docs/Makefile.am                                   |  346 +-
 docs/Makefile.doxygen                              |  129 +
 docs/architecture.doxi                             |  162 -
 docs/beast-index.doxi                              |   52 -
 docs/beast.1.doxi                                  |  121 -
 docs/beastdefs.doxi                                |  111 -
 docs/bse.5.doxi                                    |   40 -
 docs/bsescm.1.doxi                                 |  122 -
 docs/bsewavetool.1.doxi                            |  364 -
 docs/coding-style.doxi                             |  255 -
 docs/docextract.py                                 |  111 +
 docs/docframe.doxi                                 |   40 -
 docs/docu-template.doxi                            |   16 -
 docs/doxygen.cfg                                   |   82 +
 docs/faq.doxi                                      |  200 -
 docs/images/Makefile.am                            |   25 +-
 docs/images/beast-components.dia                   |  Bin 3508 -> 0 bytes
 docs/images/beast-components.png                   |  Bin 34515 -> 0 bytes
 docs/images/beast-components.svg                   | 2373 +++
 docs/images/beast-progs.dia                        |  Bin 2652 -> 0 bytes
 docs/images/beast-progs.png                        |  Bin 30307 -> 0 bytes
 docs/images/beast-progs.svg                        |  665 +
 docs/images/module-voices.dia                      |  Bin 1456 -> 0 bytes
 docs/images/module-voices.png                      |  Bin 7449 -> 0 bytes
 docs/images/module-voices.svg                      |  426 +
 docs/imports/Beast-Quickstart                      |  260 -
 docs/imports/Makefile.am                           |   84 +-
 docs/imports/beast.1                               |  146 +
 docs/imports/beast.1.html                          |  195 +
 docs/imports/beastdocs.css                         |   36 -
 docs/imports/bse.5                                 |   41 +
 docs/imports/bse.5.html                            |   81 +
 docs/imports/bsescm.1                              |  150 +
 docs/imports/bsescm.1.html                         |  195 +
 docs/imports/bsewavetool.1                         |  501 +
 docs/imports/bsewavetool.1.html                    |  568 +
 docs/imports/sfidl.1                               |  102 +
 docs/imports/sfidl.1.html                          |  153 +
 docs/imports/style-append.css                      |   10 -
 docs/imports/tagfile-rapicorn.xml                  |21382 ++++++++++++++++++++
 docs/imports/tagfile-susv4.xml                     | 2981 +++
 docs/main.dox                                      |   26 +
 docs/plugin-devel.doxi                             |  439 -
 docs/sfidl-manual.doxi                             |  476 -
 docs/sfidl.1.doxi                                  |   86 -
 docs/site-navigation.xml                           |   73 -
 doxer/Code2Doxi.py                                 |  733 -
 doxer/Config.py                                    |   98 -
 doxer/Data.py                                      |  303 -
 doxer/DoxiParser.py                                | 1426 --
 doxer/HtmlGenerator.py                             | 1032 -
 doxer/Makefile.am                                  |   11 -
 doxer/ManGenerator.py                              |  443 -
 doxer/ScadParser.py                                |  148 -
 doxer/Utils.py                                     |   53 -
 doxer/changelog2doxi.py                            |  127 -
 doxer/docu-main.doxi                               |  161 -
 doxer/doxer-standard.doxi                          |  109 -
 doxer/doxer-style.css                              |   75 -
 doxer/doxer.py                                     |  536 -
 doxer/linkdict.py                                  |  393 -
 doxer/linkdict_gnome.py                            | 7655 -------
 doxer/qcomment.py                                  |  155 -
 doxer/qdoxygen.py                                  |  325 -
 doxer/qxmlparser.py                                |  498 -
 drivers/Makefile.am                                |   24 +
 drivers/bse-alsa/AUTHORS                           |    1 -
 drivers/bse-alsa/COPYING                           |  504 -
 drivers/bse-alsa/ChangeLog                         |  172 -
 drivers/bse-alsa/Makefile.am                       |   37 -
 drivers/bse-alsa/NEWS                              |   26 -
 drivers/bse-alsa/README                            |   36 -
 drivers/bse-alsa/acbeast.m4                        |  340 -
 drivers/bse-alsa/autogen.sh                        |  175 -
 drivers/bse-alsa/bsemididevice-alsa.c              |  323 -
 drivers/bse-alsa/bsemididevice-alsa.h              |   47 -
 drivers/bse-alsa/bsepcmdevice-alsa.c               |  567 -
 drivers/bse-alsa/bsepcmdevice-alsa.h               |   47 -
 drivers/bse-alsa/configure.in                      |  222 -
 drivers/bse-portaudio/Makefile.am                  |   17 +-
 drivers/bse-portaudio/README                       |    6 +-
 drivers/bse-portaudio/acbeast.m4                   |    3 +-
 drivers/bse-portaudio/bsepcmdevice-portaudio.cc    |   81 +-
 drivers/bse-portaudio/bsepcmdevice-portaudio.hh    |   41 +-
 drivers/bse-portaudio/configure.in                 |    1 +
 drivers/bsemididevice-alsa.cc                      |  347 +
 drivers/bsemididevice-alsa.hh                      |   22 +
 drivers/bsepcmdevice-alsa.cc                       |  601 +
 drivers/bsepcmdevice-alsa.hh                       |   22 +
 launchers/Makefile.am                              |   13 +-
 launchers/beaststart.c                             |   18 +-
 launchers/bseshstart.c                             |   18 +-
 launchers/suidmain.c                               |   18 +-
 launchers/suidmain.h                               |   18 +-
 ld-symbolic.m4                                     |   45 +
 library/Makefile.am                                |    5 +-
 library/demo/Makefile.am                           |    5 +-
 library/demo/partymonster.bse                      |   26 +-
 library/demo/stereo-through.bse                    |    4 +-
 library/demo/x2-midi-test.bse                      |   12 +-
 library/effects/Makefile.am                        |    5 +-
 library/effects/atan-canyon.bse                    |    6 +-
 library/effects/bqs-compressor.bse                 |    6 +-
 library/effects/bqs-reverb.bse                     |    6 +-
 library/effects/bqs-saturation-and-reverb.bse      |    6 +-
 library/instruments/Makefile.am                    |    5 +-
 library/instruments/bqs-bass-drum-e8012.bse        |    6 +-
 library/instruments/bqs-fretless-bass.bse          |    6 +-
 library/instruments/bqs-merp-pad.bse               |    6 +-
 library/instruments/bqs-moog-saw-bass.bse          |    6 +-
 library/instruments/bqs-organ.bse                  |   10 +-
 library/instruments/bqs-queek-synth.bse            |    6 +-
 library/instruments/bqs-slow-hum.bse               |    4 +-
 library/instruments/bqs-syndrum.bse                |    6 +-
 library/instruments/fsm-fresh-water-bass.bse       |    6 +-
 library/instruments/fsm-growl-bass.bse             |    6 +-
 library/instruments/fsm-synth-string-sweep.bse     |    6 +-
 library/instruments/illus-vtremolo.bse             |    6 +-
 library/instruments/stw-iron-string.bse            |    6 +-
 library/keys/Makefile.am                           |    5 +-
 library/samples/Makefile.am                        |    5 +-
 library/scripts/Makefile.am                        |    5 +-
 library/scripts/mixer-splitup-by-track.scm         |   18 +-
 library/scripts/modules2grid.scm                   |   17 +-
 library/scripts/part-harmonic-transposer.scm       |   18 +-
 library/scripts/progressor-example.scm             |   17 +-
 library/scripts/record-midi.scm                    |   17 +-
 library/scripts/song-parts-operations.scm          |   21 +-
 library/skins/Makefile.am                          |    5 +-
 library/skins/images/Makefile.am                   |    5 +-
 mkrelease.sh                                       |  295 +-
 plugins/Makefile.am                                |  105 +-
 plugins/Makefile.plugins                           |  233 +-
 plugins/artscompressor.cc                          |   26 +-
 plugins/artscompressor.idl                         |   45 +-
 plugins/bseadder.c                                 |  272 -
 plugins/bseadder.cc                                |  247 +
 plugins/bseadder.h                                 |   75 -
 plugins/bseadder.hh                                |   46 +
 plugins/bseamplifier.cc                            |   21 +-
 plugins/bseamplifier.idl                           |   49 +-
 plugins/bseatandistort.c                           |  244 -
 plugins/bseatandistort.cc                          |  225 +
 plugins/bseatandistort.h                           |   71 -
 plugins/bseatandistort.hh                          |   45 +
 plugins/bsebalance.cc                              |   17 +-
 plugins/bsebalance.idl                             |   39 +-
 plugins/bseblockutils.cc                           |   18 +-
 plugins/bsecontribsampleandhold.cc                 |   29 +-
 plugins/bsecontribsampleandhold.idl                |   31 +-
 plugins/bsefirfilter.c                             |   89 +-
 plugins/bsefirfilter.h                             |   94 -
 plugins/bsefirfilter.hh                            |   63 +
 plugins/bseiirfilter.c                             |  446 -
 plugins/bseiirfilter.cc                            |  399 +
 plugins/bseiirfilter.h                             |  101 -
 plugins/bseiirfilter.hh                            |   49 +
 plugins/bseloopback.c                              |  191 -
 plugins/bseloopback.h                              |   76 -
 plugins/bsemixer.c                                 |  375 -
 plugins/bsemixer.cc                                |  359 +
 plugins/bsemixer.h                                 |   71 -
 plugins/bsemixer.hh                                |   36 +
 plugins/bsemult.c                                  |  139 -
 plugins/bsemult.cc                                 |  118 +
 plugins/bsemult.h                                  |   76 -
 plugins/bsemult.hh                                 |   47 +
 plugins/bsenoise.cc                                |   22 +-
 plugins/bsenoise.idl                               |   26 +-
 plugins/bsequantizer.cc                            |   25 +-
 plugins/bsequantizer.idl                           |   35 +-
 plugins/bsesequencer.c                             |  387 -
 plugins/bsesequencer.cc                            |  369 +
 plugins/bsesequencer.h                             |   66 -
 plugins/bsesequencer.hh                            |   44 +
 plugins/bsesimpleadsr-aux.c                        |  112 -
 plugins/bsesimpleadsr-aux.cc                       |   97 +
 plugins/bsesimpleadsr.c                            |  443 -
 plugins/bsesimpleadsr.cc                           |  424 +
 plugins/bsesimpleadsr.h                            |   76 -
 plugins/bsesimpleadsr.hh                           |   50 +
 plugins/bsesummation.cc                            |   17 +-
 plugins/bsesummation.idl                           |   33 +-
 plugins/davbassfilter.cc                           |   24 +-
 plugins/davbassfilter.idl                          |   31 +-
 plugins/davcanyondelay.c                           |  376 -
 plugins/davcanyondelay.cc                          |  357 +
 plugins/davcanyondelay.h                           |   87 -
 plugins/davcanyondelay.hh                          |   62 +
 plugins/davchorus.cc                               |   31 +-
 plugins/davchorus.idl                              |   27 +-
 plugins/davguitar.c                                |  127 +-
 plugins/davguitar.h                                |   83 -
 plugins/davguitar.hh                               |   48 +
 plugins/davorgan.c                                 |  533 -
 plugins/davorgan.cc                                |  265 +
 plugins/davorgan.h                                 |   91 -
 plugins/davorgan.idl                               |   39 +
 plugins/davsyndrum.c                               |  380 -
 plugins/davsyndrum.cc                              |  362 +
 plugins/davsyndrum.h                               |   76 -
 plugins/davsyndrum.hh                              |   57 +
 plugins/davxtalstrings.c                           |  558 -
 plugins/davxtalstrings.cc                          |  536 +
 plugins/davxtalstrings.h                           |   83 -
 plugins/davxtalstrings.hh                          |   54 +
 plugins/evaluator/Makefile.am                      |   12 +-
 plugins/evaluator/bseevaluator.cc                  |   31 +-
 plugins/evaluator/bseevaluator.idl                 |   23 +-
 plugins/evaluator/compiler.cc                      |   16 +-
 plugins/evaluator/compiler.hh                      |   19 +-
 plugins/evaluator/cpu.cc                           |   17 +-
 plugins/evaluator/cpu.hh                           |   17 +-
 plugins/evaluator/evaluateexpr.cc                  |   19 +-
 plugins/evaluator/instruction.cc                   |   17 +-
 plugins/evaluator/instruction.hh                   |   19 +-
 plugins/evaluator/symbols.hh                       |   17 +-
 plugins/evaluator/token.hh                         |   17 +-
 plugins/fldbsepattern.c                            |  283 -
 plugins/freeverb/Makefile.am                       |   19 +-
 plugins/freeverb/allpass.hpp                       |    2 +-
 plugins/freeverb/bsefreeverb.c                     |  296 -
 plugins/freeverb/bsefreeverb.cc                    |  279 +
 plugins/freeverb/bsefreeverb.h                     |   69 -
 plugins/freeverb/bsefreeverb.hh                    |   40 +
 plugins/freeverb/bsefreeverbcpp.cpp                |   19 +-
 plugins/freeverb/bsefreeverbcpp.h                  |   70 -
 plugins/freeverb/bsefreeverbcpp.hh                 |   55 +
 plugins/freeverb/comb.hpp                          |    2 +-
 plugins/freeverb/denormals.h                       |   18 -
 plugins/freeverb/denormals.hh                      |   18 +
 plugins/freeverb/readme.txt                        |    2 +-
 plugins/freeverb/revmodel.hpp                      |    2 +-
 plugins/freeverb/tuning.h                          |   60 -
 plugins/freeverb/tuning.hh                         |   60 +
 plugins/hello-space.c                              |   68 -
 plugins/icons/Makefile.am                          |    5 +-
 plugins/standardguspatchenvelope.cc                |   23 +-
 plugins/standardguspatchenvelope.idl               |   47 +-
 plugins/standardsaturator.cc                       |   21 +-
 plugins/standardsaturator.idl                      |   60 +-
 po/Makefile.am                                     |    9 +-
 po/POTIGNORE                                       |    1 +
 po/POTSCAN                                         |  213 +-
 po/POTSKIP                                         |    4 +-
 po/ar.po                                           | 3788 ++--
 po/az.po                                           | 3704 ++--
 po/bg.po                                           | 3767 ++--
 po/ca.po                                           | 3868 ++--
 po/cs.po                                           | 3841 ++--
 po/da.po                                           | 3803 ++--
 po/de.po                                           | 3835 ++--
 po/el.po                                           | 3736 ++--
 po/en_CA.po                                        | 3824 ++--
 po/en_GB.po                                        | 3841 ++--
 po/eo.po                                           | 3706 ++--
 po/es.po                                           | 3854 ++--
 po/eu.po                                           | 3752 ++--
 po/fi.po                                           | 3735 ++--
 po/fr.po                                           | 3871 ++--
 po/hr.po                                           | 3730 ++--
 po/it.po                                           | 3842 ++--
 po/ja.po                                           | 3805 ++--
 po/mn.po                                           | 3735 ++--
 po/nb.po                                           | 3710 ++--
 po/ne.po                                           | 3825 ++--
 po/nl.po                                           | 3866 ++--
 po/oc.po                                           | 3708 ++--
 po/pa.po                                           | 3707 ++--
 po/pt.po                                           | 3808 ++--
 po/pt_BR.po                                        | 3806 ++--
 po/ru.po                                           | 3773 ++--
 po/rw.po                                           | 3811 ++--
 po/sl.po                                           | 3840 ++--
 po/sq.po                                           | 3820 ++--
 po/sr.po                                           | 3741 ++--
 po/sr Latn po                                      | 3741 ++--
 po/sv.po                                           | 3765 ++--
 po/te.po                                           | 3711 ++--
 po/uk.po                                           | 3715 ++--
 po/zh_CN.po                                        | 3731 ++--
 r+d-files/bse-ellf.c                               |  236 +-
 sfi/Makefile.am                                    |   72 +-
 sfi/gbsearcharray.h                                |  313 -
 sfi/gbsearcharray.hh                               |  294 +
 sfi/glib-extra.c                                   | 1101 -
 sfi/glib-extra.cc                                  | 1051 +
 sfi/glib-extra.h                                   |  326 -
 sfi/glib-extra.hh                                  |  330 +
 sfi/sfi.h                                          |   43 -
 sfi/sfi.hh                                         |   34 +
 sfi/sficomport.c                                   |  745 -
 sfi/sficomport.cc                                  |  714 +
 sfi/sficomport.h                                   |  125 -
 sfi/sficomport.hh                                  |  108 +
 sfi/sficomwire.c                                   | 1051 -
 sfi/sficomwire.cc                                  | 1027 +
 sfi/sficomwire.h                                   |  182 -
 sfi/sficomwire.hh                                  |  167 +
 sfi/sficxx.cc                                      |   19 +-
 sfi/sficxx.hh                                      |   29 +-
 sfi/sfidl-cbase.cc                                 |   40 +-
 sfi/sfidl-cbase.hh                                 |   21 +-
 sfi/sfidl-clientc.cc                               |   19 +-
 sfi/sfidl-clientc.hh                               |   23 +-
 sfi/sfidl-clientcxx.cc                             |   25 +-
 sfi/sfidl-clientcxx.hh                             |   17 +-
 sfi/sfidl-corec.cc                                 |  119 +-
 sfi/sfidl-corecxx.cc                               |   97 +-
 sfi/sfidl-cxxbase.cc                               |   24 +-
 sfi/sfidl-cxxbase.hh                               |   17 +-
 sfi/sfidl-factory.cc                               |   19 +-
 sfi/sfidl-factory.hh                               |   17 +-
 sfi/sfidl-generator.cc                             |   25 +-
 sfi/sfidl-generator.hh                             |   27 +-
 sfi/sfidl-hostc.cc                                 |   19 +-
 sfi/sfidl-hostc.hh                                 |   19 +-
 sfi/sfidl-namespace.cc                             |   58 +-
 sfi/sfidl-namespace.hh                             |   29 +-
 sfi/sfidl-options.cc                               |   19 +-
 sfi/sfidl-options.hh                               |   17 +-
 sfi/sfidl-parser.cc                                |  337 +-
 sfi/sfidl-parser.hh                                |   57 +-
 sfi/sfidl-typelist.cc                              |   19 +-
 sfi/sfidl-utils.cc                                 |   65 +
 sfi/sfidl-utils.hh                                 |   32 +-
 sfi/sfidl.cc                                       |   32 +-
 sfi/sfifilecrawler.c                               |  631 -
 sfi/sfifilecrawler.cc                              |  614 +
 sfi/sfifilecrawler.h                               |   77 -
 sfi/sfifilecrawler.hh                              |   62 +
 sfi/sfiglue.c                                      |  878 -
 sfi/sfiglue.cc                                     |  848 +
 sfi/sfiglue.h                                      |  233 -
 sfi/sfiglue.hh                                     |  224 +
 sfi/sfigluecodec.c                                 | 1124 -
 sfi/sfigluecodec.cc                                | 1063 +
 sfi/sfigluecodec.h                                 |  113 -
 sfi/sfigluecodec.hh                                |   91 +
 sfi/sfiglueproxy.c                                 | 1017 -
 sfi/sfiglueproxy.cc                                |  988 +
 sfi/sfiglueproxy.h                                 |  114 -
 sfi/sfiglueproxy.hh                                |   99 +
 sfi/sfimemory.c                                    |  215 -
 sfi/sfimemory.cc                                   |  169 +
 sfi/sfimemory.h                                    |   59 -
 sfi/sfimemory.hh                                   |   38 +
 sfi/sfinote.c                                      |  186 -
 sfi/sfinote.cc                                     |  171 +
 sfi/sfinote.h                                      |  101 -
 sfi/sfinote.hh                                     |   86 +
 sfi/sfiparams.c                                    | 1774 --
 sfi/sfiparams.cc                                   | 1729 ++
 sfi/sfiparams.h                                    |  334 -
 sfi/sfiparams.hh                                   |  319 +
 sfi/sfiprimitives.c                                | 1311 --
 sfi/sfiprimitives.cc                               | 1325 ++
 sfi/sfiprimitives.h                                |  251 -
 sfi/sfiprimitives.hh                               |  236 +
 sfi/sfiring.c                                      | 1173 --
 sfi/sfiring.cc                                     | 1158 ++
 sfi/sfiring.h                                      |  179 -
 sfi/sfiring.hh                                     |  164 +
 sfi/sfiserial.c                                    |  967 -
 sfi/sfiserial.cc                                   |  989 +
 sfi/sfiserial.h                                    |   56 -
 sfi/sfiserial.hh                                   |   41 +
 sfi/sfistore.c                                     |  869 -
 sfi/sfistore.cc                                    |  801 +
 sfi/sfistore.h                                     |  160 -
 sfi/sfistore.hh                                    |  132 +
 sfi/sfitests.h                                     |   61 -
 sfi/sfitests.hh                                    |   87 +
 sfi/sfitime.c                                      |  669 -
 sfi/sfitime.cc                                     |  652 +
 sfi/sfitime.h                                      |   50 -
 sfi/sfitime.hh                                     |   35 +
 sfi/sfitypes.c                                     |  255 -
 sfi/sfitypes.cc                                    |  221 +
 sfi/sfitypes.h                                     |   95 -
 sfi/sfitypes.hh                                    |   77 +
 sfi/sfiustore.c                                    |  313 -
 sfi/sfiustore.cc                                   |  298 +
 sfi/sfiustore.h                                    |   88 -
 sfi/sfiustore.hh                                   |   73 +
 sfi/sfivalues.c                                    |  833 -
 sfi/sfivalues.cc                                   |  800 +
 sfi/sfivalues.h                                    |  194 -
 sfi/sfivalues.hh                                   |  179 +
 sfi/sfivmarshal.c                                  | 1864 --
 sfi/sfivmarshal.cc                                 | 2092 ++
 sfi/sfivmarshal.h                                  |   47 -
 sfi/sfivmarshal.hh                                 |   32 +
 sfi/sfiwrapper.cc                                  |  349 +-
 sfi/sfiwrapper.h                                   |  291 -
 sfi/sfiwrapper.hh                                  |   70 +
 sfi/tests/Makefile.am                              |   23 +-
 sfi/tests/misctests.c                              |  964 -
 sfi/tests/misctests.cc                             |  761 +
 sfi/tests/ring.c                                   |  230 -
 sfi/tests/ring.cc                                  |  209 +
 sfi/tests/testcxx.cc                               |   29 +-
 sfi/tests/testidl.idl                              |   30 +-
 sfi/tests/testsfidl.cc                             |   57 +-
 sfi/toyprof-mem.c                                  |  352 -
 sfi/toyprof-mem.h                                  |   41 -
 sfi/toyprof.README                                 |   68 -
 sfi/toyprof.c                                      |  608 -
 sfi/toyprof.h                                      |   61 -
 sfi/toyprof.pl                                     |  247 -
 shell/Makefile.am                                  |   25 +-
 shell/bse-scm-glue.boot                            |   17 +-
 shell/bsescm.c                                     |  375 -
 shell/bsescm.cc                                    |  346 +
 shell/bsescminterp.c                               | 1203 --
 shell/bsescminterp.cc                              | 1189 ++
 shell/bsescminterp.h                               |   78 -
 shell/bsescminterp.hh                              |   63 +
 shell/cxxdummy.cc                                  |    1 -
 tarGSL.sh                                          |   19 -
 tests/.gitignore                                   |    1 +
 tests/Makefile.am                                  |   28 +-
 tests/audio/Makefile.am                            |    4 +-
 tests/audio/adsr-wave-1-test.bse                   |    2 +-
 tests/audio/adsr-wave-2-test.bse                   |    2 +-
 tests/audio/adsrtest.bse                           |   10 +-
 tests/audio/artscompressor.bse                     |   18 +-
 tests/audio/balance.bse                            |    2 +-
 tests/audio/bse2wav.scm                            |   17 +-
 tests/audio/bseadder.bse                           |   17 +-
 tests/audio/freak-noise.bse                        |    6 +-
 tests/audio/minisong.bse                           |    3 +-
 tests/audio/organsong.bse                          |   38 +-
 tests/audio/osc-test.bse                           |    8 +-
 tests/audio/osctranspose1.bse                      |   10 +-
 tests/audio/osctranspose2.bse                      |   10 +-
 tests/audio/plain-wave-1-test.bse                  |    2 +-
 tests/audio/plain-wave-2-test.bse                  |    2 +-
 tests/audio/simple-loop.bse                        |   22 +-
 tests/audio/sum-diff-test.bse                      |   10 +-
 tests/audio/syndrum.bse                            |   16 +-
 tests/audio/velocity.bse                           |   28 +-
 tests/audio/xtalstringssong.bse                    |   20 +-
 tests/bse/Makefile.am                              |   16 +-
 tests/bse/cxxbinding.cc                            |   27 +-
 tests/bse/filtertest.cc                            |   63 +-
 tests/bse/testplugin.cc                            |   17 +-
 tests/bse/testplugin.idl                           |   36 +-
 tests/filecheck/Makefile.am                        |   13 +-
 tests/filecheck/checkproject.scm                   |   17 +-
 tests/latency/Makefile.am                          |   15 +-
 tests/latency/bselatencytest.cc                    |   17 +-
 tests/latency/bselatencytest.idl                   |   40 +-
 tests/latency/bseplay.scm                          |   17 +-
 tests/latency/midi-latency.bse                     |   18 +-
 tests/perftest.cc                                  |   39 +-
 tests/scripts/Makefile.am                          |    2 -
 tests/testresampler.cc                             |   35 +-
 tests/testresamplerq.cc                            |  247 +
 tests/testwavechunk.c                              |  438 -
 tests/testwavechunk.cc                             |  371 +
 tools/Makefile.am                                  |   22 +-
 tools/bsefcompare.cc                               |   35 +-
 tools/bsefextract.cc                               |   96 +-
 tools/bseloopfuncs.c                               |  934 -
 tools/bseloopfuncs.cc                              |  919 +
 tools/bseloopfuncs.h                               |  130 -
 tools/bseloopfuncs.hh                              |  115 +
 tools/bsewavetool.cc                               |  207 +-
 tools/bsewavetool.hh                               |   24 +-
 tools/bwtwave.cc                                   |   41 +-
 tools/bwtwave.hh                                   |   23 +-
 tools/cutvorbis.c                                  |  167 -
 tools/cutvorbis.cc                                 |  146 +
 tools/magictest.c                                  |  124 -
 tools/magictest.cc                                 |  102 +
 tools/mathtool.c                                   |  739 -
 tools/mathtool.cc                                  |  716 +
 tools/scripts/noteplaytest.scm                     |   18 +-
 tools/scripts/retrokit.sh                          |   19 +-
 tools/scripts/waveloadtest.scm                     |   18 +-
 tools/sfiutils.c                                   |  623 -
 tools/sfiutils.cc                                  |  608 +
 tools/sfiutils.h                                   |  102 -
 tools/sfiutils.hh                                  |   87 +
 topconfig.h                                        |    2 +-
 web/Makefile.am                                    |  295 -
 web/about.doxi                                     |   43 -
 web/contact.doxi                                   |   54 -
 web/development.doxi                               |   65 -
 web/documentation.doxi                             |   47 -
 web/download.doxi                                  |  116 -
 web/doxer-docu.doxi                                |    6 -
 web/file-browser.php                               |  164 -
 web/file-upload.php                                |  177 -
 web/gallery.php                                    |  180 -
 web/historic.doxi                                  |   31 -
 web/htaccess.in                                    |  144 -
 web/logogallery.doxi                               |   20 -
 web/logogallerydir/anon-beast-iktome-long.png      |  Bin 181600 -> 0 bytes
 web/logogallerydir/anon-beast-iktome.png           |  Bin 187905 -> 0 bytes
 web/logogallerydir/cyria-bse2.png                  |  Bin 80266 -> 0 bytes
 web/logogallerydir/cyria-bse3.png                  |  Bin 130248 -> 0 bytes
 web/logogallerydir/cyria-bse4.png                  |  Bin 105787 -> 0 bytes
 web/logogallerydir/dlundin-beast2.png              |  Bin 44664 -> 0 bytes
 web/logogallerydir/dlundin-beast2_noshades.png     |  Bin 42978 -> 0 bytes
 web/logogallerydir/dlundin-beast_large.png         |  Bin 81696 -> 0 bytes
 web/logogallerydir/dlundin-beast_logo.png          |  Bin 92014 -> 0 bytes
 web/logogallerydir/dlundin-logo.png                |  Bin 50934 -> 0 bytes
 web/logogallerydir/drc-beast.png                   |  Bin 22009 -> 0 bytes
 web/logogallerydir/jimmac-01.png                   |  Bin 9768 -> 0 bytes
 web/logogallerydir/jimmac-02.png                   |  Bin 64894 -> 0 bytes
 web/logogallerydir/jimmac-03.png                   |  Bin 52702 -> 0 bytes
 web/logogallerydir/jimmac-icon.png                 |  Bin 59556 -> 0 bytes
 web/logogallerydir/jimmac-logo.png                 |  Bin 9194 -> 0 bytes
 web/logogallerydir/jimmac-splash.png               |  Bin 39677 -> 0 bytes
 web/logogallerydir/mrogers-beast-head.jpg          |  Bin 15281 -> 0 bytes
 web/logogallerydir/mrogers-beast-large.jpg         |  Bin 23065 -> 0 bytes
 web/logogallerydir/mythor-beast.png                |  Bin 50450 -> 0 bytes
 web/logogallerydir/swamp-bse-skull.jpg             |  Bin 220740 -> 0 bytes
 web/logogallerydir/sylane-beast-compo.png          |  Bin 284806 -> 0 bytes
 web/logogallerydir/tk_beast_01.png                 |  Bin 5620 -> 0 bytes
 web/logogallerydir/tk_beast_02.png                 |  Bin 4758 -> 0 bytes
 web/news.doxi                                      |   88 -
 web/oldnews.doxi                                   | 1048 -
 web/overview2003de.doxi                            |  275 -
 web/related-links.doxi                             |   58 -
 web/resources.doxi                                 |   22 -
 web/robots.txt                                     |   10 -
 web/scanimages.sh                                  |   44 -
 web/screenshotdir/stwZ01-modular_synth_bass.DSC    |    4 -
 web/screenshotdir/stwZ01-modular_synth_bass.png    |  Bin 130393 -> 0 bytes
 web/screenshotdir/stwZ02-track_view.DSC            |    2 -
 web/screenshotdir/stwZ02-track_view.png            |  Bin 83682 -> 0 bytes
 web/screenshotdir/stwZ03-piano_roll.DSC            |    4 -
 web/screenshotdir/stwZ03-piano_roll.png            |  Bin 71509 -> 0 bytes
 web/screenshotdir/stwZ04-fft_scopes.DSC            |    7 -
 web/screenshotdir/stwZ04-fft_scopes.png            |  Bin 668200 -> 0 bytes
 web/screenshotdir/stwZ05-wave_editor.DSC           |    3 -
 web/screenshotdir/stwZ05-wave_editor.png           |  Bin 51488 -> 0 bytes
 web/screenshotdir/stwZ06-skin_support.DSC          |    3 -
 web/screenshotdir/stwZ06-skin_support.png          |  Bin 415809 -> 0 bytes
 web/screenshotdir/stwZ07-audio_mixer.DSC           |    4 -
 web/screenshotdir/stwZ07-audio_mixer.png           |  Bin 93290 -> 0 bytes
 web/screenshotdir/stwZ08-pattern_editor.DSC        |    5 -
 web/screenshotdir/stwZ08-pattern_editor.png        |  Bin 80638 -> 0 bytes
 .../stwZ09-post_processing_network.DSC             |    4 -
 .../stwZ09-post_processing_network.png             |  Bin 143815 -> 0 bytes
 web/screenshotdir/z2003-01-simple-loop.DSC         |    1 -
 web/screenshotdir/z2003-01-simple-loop.png         |  Bin 115406 -> 0 bytes
 web/screenshotdir/z2003-02-wave-play.DSC           |    1 -
 web/screenshotdir/z2003-02-wave-play.png           |  Bin 12450 -> 0 bytes
 web/screenshotdir/z2003-03-synthnet.DSC            |    1 -
 web/screenshotdir/z2003-03-synthnet.png            |  Bin 97465 -> 0 bytes
 web/screenshotdir/z2003-04-piano-roll.DSC          |    1 -
 web/screenshotdir/z2003-04-piano-roll.png          |  Bin 40815 -> 0 bytes
 web/screenshotdir/z2003-05-red-flash.DSC           |    1 -
 web/screenshotdir/z2003-05-red-flash.png           |  Bin 507021 -> 0 bytes
 web/screenshotdir/z2003-06-track-roll.DSC          |    1 -
 web/screenshotdir/z2003-06-track-roll.png          |  Bin 63701 -> 0 bytes
 web/screenshotdir/z2003-07-patterned.DSC           |    1 -
 web/screenshotdir/z2003-07-patterned.png           |  Bin 10550 -> 0 bytes
 web/screenshotdir/z2003-08-synth-fm.DSC            |    1 -
 web/screenshotdir/z2003-08-synth-fm.png            |  Bin 111058 -> 0 bytes
 web/screenshotdir/z2003-95-preferences.DSC         |    1 -
 web/screenshotdir/z2003-95-preferences.png         |  Bin 52088 -> 0 bytes
 web/screenshotdir/z2003-96-trackedit.DSC           |    1 -
 web/screenshotdir/z2003-96-trackedit.png           |  Bin 53722 -> 0 bytes
 web/screenshots.doxi                               |   13 -
 web/search.doxi                                    |   43 -
 web/sound-browser.doxi                             |   22 -
 web/sound-upload.doxi                              |   18 -
 web/style/beast-bg-h5.png                          |  Bin 87 -> 0 bytes
 web/style/beast-bg.png                             |  Bin 159 -> 0 bytes
 web/style/beast-dot.png                            |  Bin 121 -> 0 bytes
 web/style/beast-left.png                           |  Bin 20630 -> 0 bytes
 web/style/beast-right.png                          |  Bin 7113 -> 0 bytes
 web/style/beast-small.png                          |  Bin 12508 -> 0 bytes
 web/style/beast-style.css                          |  185 -
 web/style/home-arrow-24x64.png                     |  Bin 158 -> 0 bytes
 web/style/plain.css                                |    6 -
 web/style/square.png                               |  Bin 137 -> 0 bytes
 web/style/title-arrow-24x64.png                    |  Bin 191 -> 0 bytes
 web/style/triangle-down-blue.png                   |  Bin 176 -> 0 bytes
 web/style/triangle-right-blue.png                  |  Bin 155 -> 0 bytes
 web/synthesis-links.doxi                           |  188 -
 web/web-images/LT-PartView512.png                  |  Bin 40596 -> 0 bytes
 web/web-images/LT-SynthView512.png                 |  Bin 84682 -> 0 bytes
 web/web-images/LT-WaveView512.png                  |  Bin 55057 -> 0 bytes
 web/web-images/back.png                            |  Bin 190 -> 0 bytes
 web/web-images/compressed.png                      |  Bin 959 -> 0 bytes
 web/web-images/favicon.ico                         |  Bin 1150 -> 0 bytes
 web/web-images/folder-open.png                     |  Bin 210 -> 0 bytes
 web/web-images/folder.png                          |  Bin 177 -> 0 bytes
 web/web-images/sound2.png                          |  Bin 199 -> 0 bytes
 web/web-images/text.png                            |  Bin 175 -> 0 bytes
 web/webframe.doxi                                  |   42 -
 web/webmenu.doxi                                   |  133 -
 web/wiki.doxi                                      |   41 -
 1618 files changed, 308039 insertions(+), 325894 deletions(-)
---
diff --cc beast-gtk/Makefile.am
index cdff047,60dcdbe..d57072f
--- a/beast-gtk/Makefile.am
+++ b/beast-gtk/Makefile.am
@@@ -22,46 -19,46 +19,46 @@@ LIBS += # -lefence # -p
  #
  # BEAST header files that don't get installed
  beast_headers = $(strip \
-       bsttrackrollctrl.h      bstxframe.h     bstscrollgraph.h        \
-       bstdbmeter.h            bstbusmixer.h   bstbuseditor.h          bstitemseqdialog.h  \
-       bstcanvassource.h       bstapp.h        bstasciipixbuf.h        bstcanvaslink.h     \
-       bstpatterncolumns.h     bstxkb.h        bstpatternview.h        bstpatternctrl.h    \
-       bstkeybindings.h        bstprofiler.h   bstgrowbar.h            bstbusview.h        \
-       bstpianorollctrl.h      bstpartview.h   bstpianoroll.h          bstplayback.h       \
-       bsttrackroll.h          bstcluehunter.h bstprojectctrl.h        bstcxxutils.h       \
-       bstauxdialogs.h         bstsegment.h    bsteventrollctrl.h      bsteventroll.h      \
-       bstsnifferscope.h       bstwaveview.h   bstfiledialog.h         bstgconfig.h        \
-       bstlogadjustment.h      bstitemview.h   bstservermonitor.h      bstknob.h           \
-       bstparamview.h          bstmenus.h      bstparam.h              bstpartdialog.h     \
-       bstprocbrowser.h        bstqsampler.h   bstpreferences.h        bstprocedure.h      \
-       bstrackeditor.h         bstrackitem.h   bstracktable.h          bstsequence.h       \
-       bstsnetrouter.h         bstsplash.h     bsttrackview.h          bstsupershell.h     \
-       bstusermessage.h        bstdial.h       bsttracksynthdialog.h   bstwaveeditor.h     \
-       bstzoomedwindow.h       bstskinconfig.h bstmsgabsorb.h          bstsampleeditor.h   \
-       bstrackview.h           bsttreestores.h bstbseutils.h           \
-       bstutils.h              bstdefs.h       bstsoundfontview.h      bstsoundfontpresetview.h  \
+       bsttrackrollctrl.hh     bstxframe.hh    bstscrollgraph.hh       \
+       bstdbmeter.hh           bstbusmixer.hh  bstbuseditor.hh         bstitemseqdialog.hh  \
+       bstcanvassource.hh      bstapp.hh       bstasciipixbuf.hh       bstcanvaslink.hh            \
+       bstpatterncolumns.hh    bstxkb.hh       bstpatternview.hh       bstpatternctrl.hh    \
+       bstkeybindings.hh       bstprofiler.hh  bstgrowbar.hh           bstbusview.hh        \
+       bstpianorollctrl.hh     bstpartview.hh  bstpianoroll.hh         bstplayback.hh      \
+       bsttrackroll.hh         bstcluehunter.hh        bstprojectctrl.hh       \
+       bstauxdialogs.hh                bstsegment.hh   bsteventrollctrl.hh     bsteventroll.hh     \
+       bstsnifferscope.hh      bstwaveview.hh  bstfiledialog.hh                bstgconfig.hh       \
+       bstlogadjustment.hh     bstitemview.hh  bstservermonitor.hh     bstknob.hh          \
+       bstparamview.hh         bstmenus.hh     bstparam.hh             bstpartdialog.hh            \
+       bstprocbrowser.hh       bstqsampler.hh  bstpreferences.hh       bstprocedure.hh     \
+       bstrackeditor.hh                bstrackitem.hh  bstracktable.hh         bstsequence.hh      \
+       bstsnetrouter.hh                bstsplash.hh    bsttrackview.hh         bstsupershell.hh            \
+       bstusermessage.hh       bstdial.hh      bsttracksynthdialog.hh  bstwaveeditor.hh            \
+       bstzoomedwindow.hh      bstskinconfig.hh        bstmsgabsorb.hh         bstsampleeditor.hh   \
+       bstrackview.hh          bsttreestores.hh        bstbseutils.hh          bstutils.hh         \
 -      bstdefs.hh \
++      bstdefs.hh              bstsoundfontview.h      bstsoundfontpresetview.h  \
  )
  EXTRA_DIST += $(beast_headers)
  # BEAST sources to build the program from
  beast_sources = $(strip \
-       bsttrackrollctrl.c      bstxframe.c     bstscrollgraph.c        \
-       bstdbmeter.c            bstbusmixer.c   bstbuseditor.c          bstitemseqdialog.c  \
-       bstcanvassource.c       bstapp.c        bstasciipixbuf.c        bstcanvaslink.c     \
-       bstpatterncolumns.c     bstxkb.c        bstpatternview.c        bstpatternctrl.c    \
-       bstkeybindings.c        bstprofiler.c   bstgrowbar.c            bstbusview.c        \
-       bstpianorollctrl.c      bstpartview.c   bstpianoroll.c          bstplayback.c       \
-       bsttrackroll.c          bstcluehunter.c bstprojectctrl.c        bstcxxutils.cc      \
-       bstauxdialogs.c         bstsegment.c    bsteventrollctrl.c      bsteventroll.c      \
-       bstsnifferscope.c       bstwaveview.c   bstfiledialog.c         bstgconfig.c        \
-       bstlogadjustment.c      bstitemview.c   bstservermonitor.c      bstknob.c           \
-       bstparamview.c          bstmenus.c      bstparam.c              bstpartdialog.c     \
-       bstprocbrowser.c        bstqsampler.c   bstpreferences.c        bstprocedure.c      \
-       bstrackeditor.c         bstrackitem.c   bstracktable.c          bstsequence.c       \
-       bstsnetrouter.c         bstsplash.c     bsttrackview.c          bstsupershell.c     \
-       bstusermessage.c        bstdial.c       bsttracksynthdialog.c   bstwaveeditor.c     \
-       bstzoomedwindow.c       bstskinconfig.c bstmsgabsorb.c          bstsampleeditor.c   \
-       bstrackview.c           bsttreestores.c bstbseutils.c           bstutils.c          \
+       bsttrackrollctrl.cc     bstxframe.cc    bstscrollgraph.cc       \
+       bstdbmeter.cc           bstbusmixer.cc  bstbuseditor.cc         bstitemseqdialog.cc \
+       bstcanvassource.cc      bstapp.cc       bstasciipixbuf.cc       bstcanvaslink.cc    \
+       bstpatterncolumns.cc    bstxkb.cc       bstpatternview.cc       bstpatternctrl.cc   \
+       bstkeybindings.cc       bstprofiler.cc  bstgrowbar.cc           bstbusview.cc       \
+       bstpianorollctrl.cc     bstpartview.cc  bstpianoroll.cc         bstplayback.cc      \
+       bsttrackroll.cc        bstcluehunter.cc bstprojectctrl.cc       \
+       bstauxdialogs.cc        bstsegment.cc   bsteventrollctrl.cc     bsteventroll.cc     \
+       bstsnifferscope.cc      bstwaveview.cc  bstfiledialog.cc        bstgconfig.cc       \
+       bstlogadjustment.cc     bstitemview.cc  bstservermonitor.cc     bstknob.cc          \
+       bstparamview.cc         bstmenus.cc     bstparam.cc             bstpartdialog.cc    \
+       bstprocbrowser.cc       bstqsampler.cc  bstpreferences.cc       bstprocedure.cc     \
+       bstrackeditor.cc        bstrackitem.cc  bstracktable.cc         bstsequence.cc      \
+       bstsnetrouter.cc        bstsplash.cc    bsttrackview.cc         bstsupershell.cc    \
+       bstusermessage.cc       bstdial.cc      bsttracksynthdialog.cc  bstwaveeditor.cc    \
+       bstzoomedwindow.cc     bstskinconfig.cc bstmsgabsorb.cc         bstsampleeditor.cc  \
+       bstrackview.cc         bsttreestores.cc bstbseutils.cc          bstutils.cc         \
 -      $(PROFILE_SOURCE) \
 +      bstsoundfontview.c      bstsoundfontpresetview.c                $(PROFILE_SOURCE)   \
  )
  # BEAST sources that get included (don't have own .lo rules)
  beast_extra_files = $(strip                                           \
diff --cc beast-gtk/bstfiledialog.cc
index 0000000,231a4a9..0e0b6ee
mode 000000,100644..100644
--- a/beast-gtk/bstfiledialog.cc
+++ b/beast-gtk/bstfiledialog.cc
@@@ -1,0 -1,922 +1,969 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #include "bstfiledialog.hh"
+ #include "bstmenus.hh"
+ #include "bsttreestores.hh"
+ #include <unistd.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <errno.h>
+ 
+ 
+ /* --- prototypes --- */
+ static void   bst_file_dialog_finalize        (GObject                *object);
+ static void   bst_file_dialog_activate        (BstFileDialog          *self);
+ 
+ 
+ /* --- functions --- */
+ G_DEFINE_TYPE (BstFileDialog, bst_file_dialog, GXK_TYPE_DIALOG);
+ 
+ static void
+ bst_file_dialog_class_init (BstFileDialogClass        *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ 
+   gobject_class->finalize = bst_file_dialog_finalize;
+ }
+ 
+ static void
+ tree_viewable_changed (BstFileDialog *self)
+ {
+   gboolean viewable = gxk_widget_viewable (GTK_WIDGET (self->tview));
+   gboolean tvisible = GTK_WIDGET_VISIBLE (gtk_widget_get_toplevel (GTK_WIDGET (self->tview)));
+ 
+   if (viewable && !self->using_file_store)
+     {
+       self->using_file_store = TRUE;
+       bst_file_store_update_list (self->file_store, self->search_path, self->search_filter);
+     }
+   else if (!tvisible && self->using_file_store)
+     {
+       self->using_file_store = FALSE;
+       bst_file_store_forget_list (self->file_store);
+     }
+ }
+ 
+ static void
+ bst_file_dialog_init (BstFileDialog *self)
+ {
+   GtkTreeSelection *tsel;
+   GtkTreeModel *smodel;
+   GtkWidget *bbox, *vbox;
+   GtkWidget *main_box = GXK_DIALOG (self)->vbox;
+ 
+   self->ignore_activate = TRUE;
+ 
+   /* configure self */
+   g_object_set (self,
+               "flags", (GXK_DIALOG_HIDE_ON_DELETE |
+                           GXK_DIALOG_PRESERVE_STATE |
+                         GXK_DIALOG_POPUP_POS |
+                         GXK_DIALOG_MODAL),
+               NULL);
+   gxk_dialog_set_sizes (GXK_DIALOG (self), -1, -1, 500, 450);
+   g_object_set (main_box,
+               "homogeneous", FALSE,
+               "spacing", 0,
+               "border_width", 0,
+               NULL);
+ 
+   /* notebook */
+   self->notebook = (GtkWidget*) g_object_new (GXK_TYPE_NOTEBOOK,
+                                               "visible", TRUE,
+                                               "show_border", TRUE,
+                                               "show_tabs", TRUE,
+                                               "scrollable", FALSE,
+                                               "tab_border", 0,
+                                               "enable_popup", TRUE,
+                                               "tab_pos", GTK_POS_TOP,
+                                               "border_width", 5,
+                                               "parent", main_box,
+                                               "enable_popup", FALSE,
+                                               NULL);
+ 
+   /* setup file selection widgets and add to notebook */
+   self->fs = (GtkFileSelection*) gtk_file_selection_new ("");
+   self->fpage = gxk_file_selection_split (self->fs, &bbox);
+   g_object_ref (self->fpage);
+   gtk_container_remove (GTK_CONTAINER (self->fpage->parent), self->fpage);
+   gxk_notebook_append (GTK_NOTEBOOK (self->notebook), self->fpage, "File Selection", TRUE);
+   g_object_unref (self->fpage);
+ 
+   /* sample selection tree */
+   self->spage = (GtkWidget*) g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+                                            "visible", TRUE,
+                                            "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+                                            "vscrollbar_policy", GTK_POLICY_ALWAYS,
+                                            "border_width", 5,
+                                            "shadow_type", GTK_SHADOW_IN,
+                                            NULL);
+   gxk_notebook_append (GTK_NOTEBOOK (self->notebook), self->spage, "Sample Selection", TRUE);
+   self->file_store = bst_file_store_create ();
+   smodel = gtk_tree_model_sort_new_with_model (self->file_store);
+   self->tview = (GtkTreeView*) g_object_new (GTK_TYPE_TREE_VIEW,
+                                              "visible", TRUE,
+                                              "can_focus", TRUE,
+                                              "model", smodel,
+                                              "rules_hint", TRUE,
+                                              "parent", self->spage,
+                                              "search_column", BST_FILE_STORE_COL_BASE_NAME,
+                                              NULL);
+   g_object_unref (smodel);
+   g_object_connect (self->tview,
+                   "swapped_signal::viewable-changed", tree_viewable_changed, self,
+                   NULL);
+   tsel = gtk_tree_view_get_selection (self->tview);
+   gtk_tree_selection_set_mode (tsel, GTK_SELECTION_BROWSE);
+   gxk_tree_selection_force_browse (tsel, smodel);
+   g_object_connect (self->tview, "swapped_object_signal::row_activated", gtk_button_clicked, 
self->fs->ok_button, NULL);
+ 
+   /* sample selection tree columns */
+   gxk_tree_view_add_text_column (self->tview, BST_FILE_STORE_COL_WAVE_NAME, "S",
+                                0.0, _("Name"), _("Sample or instrument name"),
+                                NULL, self, G_CONNECT_SWAPPED);
+   gxk_tree_view_add_text_column (self->tview, BST_FILE_STORE_COL_SIZE, "S",
+                                1.0, _("Size"), _("File size in bytes"),
+                                NULL, self, G_CONNECT_SWAPPED);
+   gchar *padstring = g_strdup (_("Format")), *tip = g_strdup (_("Detected file format"));
+   guint l = strlen (padstring), n = 14;
+   if (l < n)
+     {
+       GString *gstring = g_string_new (padstring);
+       g_free (padstring);
+       while (l++ < n)
+         g_string_append (gstring, " ");
+       padstring = g_string_free (gstring, FALSE);
+     }
+   gxk_tree_view_add_text_column (self->tview, BST_FILE_STORE_COL_LOADER, "OF",
+                                0.0, padstring, tip,
+                                NULL, self, G_CONNECT_SWAPPED);
+   g_free (padstring);
+   g_free (tip);
+   gxk_tree_view_add_text_column (self->tview, BST_FILE_STORE_COL_TIME_STR, "S",
+                                0.0, _("Time"), _("File modification time"),
+                                NULL, self, G_CONNECT_SWAPPED);
+   if (BST_DVL_HINTS)
+     gxk_tree_view_add_toggle_column (self->tview, BST_FILE_STORE_COL_LOADABLE, "",
+                                    0.0, "L", "Indication of whether a file is expected to be loadable",
+                                    NULL, self, G_CONNECT_SWAPPED);
+   gxk_tree_view_add_text_column (self->tview, BST_FILE_STORE_COL_FILE, "S",
+                                0.0, _("Filename"), NULL,
+                                NULL, self, G_CONNECT_SWAPPED);
+ 
+   /* pack separator and buttons */
+   gtk_box_pack_end (GTK_BOX (main_box), bbox, FALSE, TRUE, 0);
+   gtk_box_pack_end (GTK_BOX (main_box),
+                   (GtkWidget*) g_object_new (GTK_TYPE_HSEPARATOR,
+                                                "visible", TRUE,
+                                                NULL),
+                   FALSE, TRUE, 0);
+ 
+   /* setup save options */
+   self->osave = (GtkWidget*) g_object_new (GTK_TYPE_FRAME,
+                                            "label", _("Contents"),
+                                            "parent", self->fs->action_area,
+                                            NULL);
+   vbox = (GtkWidget*) g_object_new (GTK_TYPE_VBOX,
+                      "visible", TRUE,
+                      "parent", self->osave,
+                      NULL);
+   self->radio1 = (GtkWidget*) g_object_new (GTK_TYPE_RADIO_BUTTON,
+                                             "label", "radio-1",
+                                             "visible", TRUE,
+                                             "parent", vbox,
+                                             "can_focus", FALSE,
+                                             NULL);
+   gtk_misc_set_alignment (GTK_MISC (GTK_BIN (self->radio1)->child), 0, .5);
+   self->radio2 = (GtkWidget*) g_object_new (GTK_TYPE_RADIO_BUTTON,
+                                             "label", "radio-2",
+                                             "visible", TRUE,
+                                             "parent", vbox,
+                                             "group", self->radio1,
+                                             "can_focus", FALSE,
+                                             NULL);
+   gtk_misc_set_alignment (GTK_MISC (GTK_BIN (self->radio2)->child), 0, .5);
+ 
+   /* setup actions */
+   g_object_connect (self->fs->ok_button, "swapped_signal::clicked", bst_file_dialog_activate, self, NULL);
+   g_object_connect (self->fs->cancel_button, "swapped_signal::clicked", gxk_toplevel_delete, self, NULL);
+ 
+   /* fixup focus and default widgets */
+   gxk_dialog_set_default (GXK_DIALOG (self), self->fs->ok_button);
+   gxk_dialog_set_focus (GXK_DIALOG (self), self->fs->selection_entry);
+ 
+   /* setup remaining bits */
+   bst_file_dialog_set_mode (self, NULL, BstFileDialogMode (0), _("File Selection"), 0);
+   gtk_window_set_type_hint (GTK_WINDOW (self), GDK_WINDOW_TYPE_HINT_DIALOG);
+ }
+ 
+ static void
+ bst_file_dialog_finalize (GObject *object)
+ {
+   BstFileDialog *self = BST_FILE_DIALOG (object);
+ 
+   bst_file_dialog_set_mode (self, NULL, BstFileDialogMode (0), NULL, 0);
+   g_free (self->search_path);
+   self->search_filter = NULL;
+   bst_file_store_destroy (self->file_store);
+ 
+   /* chain parent class' handler */
+   G_OBJECT_CLASS (bst_file_dialog_parent_class)->finalize (object);
+ }
+ 
+ static BstFileDialog*
+ bst_file_dialog_global_project (void)
+ {
+   static BstFileDialog *singleton = NULL;
+   if (!singleton)
+     singleton = (BstFileDialog*) g_object_new (BST_TYPE_FILE_DIALOG, NULL);
+   return singleton;
+ }
+ 
+ static BstFileDialog*
+ bst_file_dialog_global_wave (void)
+ {
+   static BstFileDialog *singleton = NULL;
+   if (!singleton)
+     singleton = (BstFileDialog*) g_object_new (BST_TYPE_FILE_DIALOG, NULL);
+   return singleton;
+ }
+ 
+ static BstFileDialog*
++bst_file_dialog_global_sound_font (void)
++{
++  static BstFileDialog *singleton = NULL;
++  if (!singleton)
++    singleton = g_object_new (BST_TYPE_FILE_DIALOG, NULL);
++  return singleton;
++}
++
++
++static BstFileDialog*
+ bst_file_dialog_global_effect (void)
+ {
+   static BstFileDialog *singleton = NULL;
+   if (!singleton)
+     {
+       const gchar *dir = bse_server_get_custom_effect_dir (BSE_SERVER);
+       singleton = (BstFileDialog*) g_object_new (BST_TYPE_FILE_DIALOG, NULL);
+       if (dir)
+         {
+           sfi_make_dirpath (dir);
+           gtk_file_selection_complete (singleton->fs, dir);
+         }
+     }
+   return singleton;
+ }
+ 
+ static BstFileDialog*
+ bst_file_dialog_global_instrument (void)
+ {
+   static BstFileDialog *singleton = NULL;
+   if (!singleton)
+     {
+       const gchar *dir = bse_server_get_custom_instrument_dir (BSE_SERVER);
+       singleton = (BstFileDialog*) g_object_new (BST_TYPE_FILE_DIALOG, NULL);
+       if (dir)
+         {
+           sfi_make_dirpath (dir);
+           gtk_file_selection_complete (singleton->fs, dir);
+         }
+     }
+   return singleton;
+ }
+ 
+ static void
+ parent_window_destroyed (BstFileDialog *self)
+ {
+   gtk_widget_hide (GTK_WIDGET (self));
+   bst_file_dialog_set_mode (self, NULL, BstFileDialogMode (0), NULL, 0);
+   gxk_toplevel_delete (GTK_WIDGET (self));
+ }
+ 
+ void
+ bst_file_dialog_set_mode (BstFileDialog    *self,
+                         gpointer          parent_widget,
+                         BstFileDialogMode mode,
+                         const gchar      *fs_title,
+                         SfiProxy          proxy)
+ {
+   GtkWindow *window = GTK_WINDOW (self);
+ 
+   g_return_if_fail (BST_IS_FILE_DIALOG (self));
+ 
+   gtk_widget_hide (GTK_WIDGET (self));
+   gtk_widget_hide (self->osave);
+   self->mode = mode;
+   g_free (self->selected);
+   self->selected = NULL;
+ 
+   /* reset proxy handling */
+   bst_window_sync_title_to_proxy (self, proxy, fs_title);
+   self->proxy = proxy;
+   self->super = 0;
+ 
+   /* cleanup connections to old parent_window */
+   if (self->parent_window)
+     g_signal_handlers_disconnect_by_func (self->parent_window, (void*) parent_window_destroyed, self);
+   if (window->group)
+     gtk_window_group_remove_window (window->group, window);
+   gtk_window_set_transient_for (window, NULL);
+ 
+   self->parent_window = parent_widget ? (GtkWindow*) gtk_widget_get_ancestor ((GtkWidget*) parent_widget, 
GTK_TYPE_WINDOW) : NULL;
+ 
+   /* setup connections to new parent_window */
+   if (self->parent_window)
+     {
+       gtk_window_set_transient_for (window, self->parent_window);
+       if (self->parent_window->group)
+       gtk_window_group_add_window (self->parent_window->group, window);
+       g_signal_connect_object (self->parent_window, "destroy",
+                              G_CALLBACK (parent_window_destroyed),
+                              self, G_CONNECT_SWAPPED);
+     }
+ 
+   /* allow activation */
+   self->ignore_activate = FALSE;
+ 
+   /* handle tree visibility */
+   switch (mode & BST_FILE_DIALOG_MODE_MASK)
+     {
++    case BST_FILE_DIALOG_LOAD_SOUND_FONT:
+     case BST_FILE_DIALOG_LOAD_WAVE:
+       g_free (self->search_path);
+       self->search_path = g_strdup (bse_server_get_sample_path (BSE_SERVER));
+       self->search_filter = NULL;
+       gtk_widget_show (self->spage);
+       gxk_notebook_set_current_page_widget (GTK_NOTEBOOK (self->notebook), self->fpage);
+       g_object_set (self->notebook, "show_border", TRUE, "show_tabs", TRUE, NULL);
+       break;
++    case BST_FILE_DIALOG_LOAD_SOUND_FONT_LIB:
+     case BST_FILE_DIALOG_LOAD_WAVE_LIB:
+       g_free (self->search_path);
+       self->search_path = g_strdup (bse_server_get_sample_path (BSE_SERVER));
+       self->search_filter = NULL;
+       gtk_widget_show (self->spage);
+       gxk_notebook_set_current_page_widget (GTK_NOTEBOOK (self->notebook), self->spage);
+       g_object_set (self->notebook, "show_border", TRUE, "show_tabs", TRUE, NULL);
+       break;
+     case BST_FILE_DIALOG_MERGE_EFFECT:
+       g_free (self->search_path);
+       self->search_path = g_strdup (bse_server_get_effect_path (BSE_SERVER));
+       self->search_filter = "*";
+       gtk_widget_show (self->spage);
+       gxk_notebook_set_current_page_widget (GTK_NOTEBOOK (self->notebook), self->spage);
+       g_object_set (self->notebook, "show_border", TRUE, "show_tabs", TRUE, NULL);
+       break;
+     case BST_FILE_DIALOG_MERGE_INSTRUMENT:
+       g_free (self->search_path);
+       self->search_path = g_strdup (bse_server_get_instrument_path (BSE_SERVER));
+       self->search_filter = "*";
+       gtk_widget_show (self->spage);
+       gxk_notebook_set_current_page_widget (GTK_NOTEBOOK (self->notebook), self->spage);
+       g_object_set (self->notebook, "show_border", TRUE, "show_tabs", TRUE, NULL);
+       break;
+     default:
+       g_free (self->search_path);
+       self->search_path = NULL;
+       self->search_filter = NULL;
+       if (self->using_file_store)
+         {
+           self->using_file_store = FALSE;
+           bst_file_store_forget_list (self->file_store);
+         }
+       gtk_widget_hide (self->spage);
+       g_object_set (self->notebook, "show_border", FALSE, "show_tabs", FALSE, NULL);
+       break;
+     }
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_open_project (gpointer parent_widget)
+ {
+   BstFileDialog *self = bst_file_dialog_global_project ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                           BST_FILE_DIALOG_OPEN_PROJECT,
+                           _("Open Project"), 0);
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_select_file (gpointer parent_widget)
+ {
+   BstFileDialog *self = bst_file_dialog_global_project ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                           BST_FILE_DIALOG_SELECT_FILE,
+                           _("Select File"), 0);
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_select_dir (gpointer parent_widget)
+ {
+   BstFileDialog *self = bst_file_dialog_global_project ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                           BST_FILE_DIALOG_SELECT_DIR | BST_FILE_DIALOG_ALLOW_DIRS,
+                           _("Select Directory"), 0);
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ static gboolean
+ bst_file_dialog_open_project (BstFileDialog *self,
+                             const gchar   *file_name)
+ {
+   SfiProxy project = bse_server_use_new_project (BSE_SERVER, file_name);
+   BseErrorType error = bst_project_restore_from_file (project, file_name, TRUE, TRUE);
+ 
+   if (error)
+     bst_status_eprintf (error, _("Opening project `%s'"), file_name);
+   else
+     {
+       bse_project_get_wave_repo (project);
+       BstApp *app = bst_app_new (project);
+       gxk_status_window_push (app);
+       bst_status_eprintf (error, _("Opening project `%s'"), file_name);
+       gxk_status_window_pop ();
+       gxk_idle_show_widget (GTK_WIDGET (app));
+     }
+   bse_item_unuse (project);
+ 
+   return TRUE;
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_merge_project (gpointer   parent_widget,
+                                    SfiProxy   project)
+ {
+   BstFileDialog *self = bst_file_dialog_global_project ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                           BST_FILE_DIALOG_MERGE_PROJECT,
+                           _("Merge: %s"), project);
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ static gboolean
+ bst_file_dialog_merge_project (BstFileDialog *self,
+                              const gchar   *file_name)
+ {
+   SfiProxy project = bse_item_use (self->proxy);
+   BseErrorType error = bst_project_restore_from_file (project, file_name, FALSE, FALSE);
+ 
+   bst_status_eprintf (error, _("Merging project `%s'"), file_name);
+ 
+   bse_item_unuse (project);
+ 
+   return TRUE;
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_import_midi (gpointer   parent_widget,
+                                    SfiProxy   project)
+ {
+   BstFileDialog *self = bst_file_dialog_global_project ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                           BST_FILE_DIALOG_IMPORT_MIDI,
+                           _("Import MIDI: %s"), project);
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ static gboolean
+ bst_file_dialog_import_midi (BstFileDialog *self,
+                              const gchar   *file_name)
+ {
+   BseErrorType error = bst_project_import_midi_file (self->proxy, file_name);
+   bst_status_eprintf (error, _("Importing MIDI file `%s'"), file_name);
+   return TRUE;
+ }
+ 
+ static gboolean
+ store_bse_file (SfiProxy       project,
+                 SfiProxy       super,
+                 const gchar   *file_name,
+                 const gchar   *saving_message_format,
+                 gboolean       self_contained,
+                 gboolean       want_overwrite)
+ {
+   BseErrorType error = bse_project_store_bse (project, super, file_name, self_contained);
+   gchar *title = g_strdup_format (saving_message_format, bse_item_get_name (super ? super : project));
+   gboolean handled = TRUE;
+   gchar *msg = NULL;
+   /* handle file exists cases */
+   if (error == BSE_ERROR_FILE_EXISTS)
+     {
+       if (!want_overwrite)
+         {
+           gchar *text = g_strdup_format (_("Failed to save\n`%s'\nto\n`%s':\n%s"), bse_item_get_name 
(project), file_name, bse_error_blurb (error));
+           GtkWidget *choice = bst_choice_dialog_createv (BST_CHOICE_TITLE (title),
+                                                          BST_CHOICE_TEXT (text),
+                                                          BST_CHOICE_D (1, BST_STOCK_OVERWRITE, NONE),
+                                                          BST_CHOICE (0, BST_STOCK_CANCEL, NONE),
+                                                          BST_CHOICE_END);
+           g_free (text);
+           want_overwrite = bst_choice_modal (choice, 0, 0) == 1;
+           bst_choice_destroy (choice);
+         }
+       if (want_overwrite)
+         {
+           /* save to temporary file */
+           gchar *temp_file = NULL;
+           while (error == BSE_ERROR_FILE_EXISTS)
+             {
+               g_free (temp_file);
+               temp_file = g_strdup_format ("%s.tmp%06xyXXXXXX", file_name, rand() & 0xfffffd);
+               char *result = mktemp (temp_file); /* this is save, due to use of: O_CREAT | O_EXCL */
+               (void) result;
+               error = bse_project_store_bse (project, super, temp_file, self_contained);
+             }
+           /* replace file by temporary file */
+           if (error != BSE_ERROR_NONE)
+             {
+               unlink (temp_file); /* error != BSE_ERROR_FILE_EXISTS */
+               msg = g_strdup_format (_("Failed to save to file\n`%s'\ndue to:\n%s"), file_name, 
bse_error_blurb (error));
+             }
+           else if (rename (temp_file, file_name) < 0)
+             {
+               unlink (temp_file);
+               msg = g_strdup_format (_("Failed to replace file\n`%s'\ndue to:\n%s"), file_name, g_strerror 
(errno));
+             }
+           else /* success */
+             ;
+         }
+       else
+         handled = FALSE;        /* exists && !overwrite */
+     }
+   else if (error != BSE_ERROR_NONE)
+     msg = g_strdup_format (_("Failed to save to file\n`%s'\ndue to:\n%s"), file_name, bse_error_blurb 
(error));
+   /* report errors */
+   if (msg)
+     {
+       GtkWidget *choice = bst_choice_dialog_createv (BST_CHOICE_TITLE (title),
+                                                      BST_CHOICE_TEXT (msg),
+                                                      BST_CHOICE_D (0, BST_STOCK_CLOSE, NONE),
+                                                      BST_CHOICE_END);
+       g_free (msg);
+       bst_choice_modal (choice, 0, 0);
+       bst_choice_destroy (choice);
+       handled = FALSE;
+     }
+   else if (handled) /* no error */
+     bst_status_eprintf (BSE_ERROR_NONE, "%s", title);
+   g_free (title);
+   return handled;
+ }
+ 
+ static gboolean
+ bst_file_dialog_save_project (SfiProxy     proxy,
+                               gboolean     self_contained,
+                             const gchar *file_name,
+                               gboolean     apply_project_name,
+                               gboolean     want_overwrite)
+ {
+   SfiProxy project = bse_item_use (proxy);
+   gboolean handled = store_bse_file (project, 0, file_name, _("Saving project `%s'"), self_contained, 
want_overwrite);
+   if (apply_project_name)
+     {
+       bse_proxy_set_data_full (project, "beast-project-file-name", g_strdup (file_name), g_free);
+       bse_proxy_set_data (project, "beast-project-store-references", (void*) !self_contained);
+       gchar *bname = g_path_get_basename (file_name);
+       bse_project_change_name (project, bname);
+       g_free (bname);
+     }
+   if (handled)
+     bse_project_clean_dirty (project);
+   bse_item_unuse (project);
+ 
+   return handled;
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_save_project (gpointer   parent_widget,
+                                   SfiProxy   project,
+                                     gboolean   query_project_name,
+                                     gboolean   apply_project_name)
+ {
+   /* handle non-popup case */
+   const char *filename = (const char*) bse_proxy_get_data (project, "beast-project-file-name");
+   bool store_references = size_t (bse_proxy_get_data (project, "beast-project-store-references"));
+   if (filename && !query_project_name)
+     {
+       gboolean handled = bst_file_dialog_save_project (project, !store_references, filename, FALSE, TRUE);
+       if (handled)
+         return NULL;
+     }
+   /* the usual Save As scenario */
+   BstFileDialog *self = bst_file_dialog_global_project ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                           BST_FILE_DIALOG_SAVE_PROJECT,
+                           _("Save: %s"), project);
+   self->apply_project_name = apply_project_name != FALSE;
+   gtk_file_selection_set_filename (self->fs, filename ? filename : "");
+   /* setup radio buttons */
+   g_object_set (GTK_BIN (self->radio1)->child, "label", _("Fully include wave files"), NULL);
+   g_object_set (GTK_BIN (self->radio2)->child, "label", _("Store references to wave files"), NULL);
+   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->radio2), store_references);
+   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->radio1), !store_references);
+   gtk_widget_show (self->osave);
+   /* show dialog */
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_merge_effect (gpointer   parent_widget,
+                                     SfiProxy   project)
+ {
+   BstFileDialog *self = bst_file_dialog_global_effect ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                             BST_FILE_DIALOG_MERGE_EFFECT,
+                             _("Load Effect"), project);
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ static gboolean
+ bst_file_dialog_merge_effect (BstFileDialog *self,
+                               const gchar   *file_name)
+ {
+   SfiProxy project = bse_item_use (self->proxy);
+   BseErrorType error = bst_project_restore_from_file (project, file_name, FALSE, FALSE);
+ 
+   bst_status_eprintf (error, _("Merging effect `%s'"), file_name);
+ 
+   bse_item_unuse (project);
+ 
+   return TRUE;
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_save_effect (gpointer parent_widget,
+                                    SfiProxy project,
+                                    SfiProxy super)
+ {
+   BstFileDialog *self = bst_file_dialog_global_effect ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                           BST_FILE_DIALOG_SAVE_EFFECT,
+                           _("Save Effect"), project);
+   self->super = super;
+   /* show dialog */
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ static gboolean
+ bst_file_dialog_save_effect (BstFileDialog *self,
+                              const gchar   *file_name)
+ {
+   SfiProxy project = bse_item_use (self->proxy);
+   gboolean self_contained = TRUE;
+   gboolean handled = store_bse_file (project, self->super, file_name, _("Saving effect `%s'"), 
self_contained, FALSE);
+   bse_item_unuse (project);
+ 
+   return handled;
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_merge_instrument (gpointer   parent_widget,
+                                         SfiProxy   project)
+ {
+   BstFileDialog *self = bst_file_dialog_global_instrument ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                             BST_FILE_DIALOG_MERGE_INSTRUMENT,
+                             _("Load Instrument"), project);
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ static gboolean
+ bst_file_dialog_merge_instrument (BstFileDialog *self,
+                                   const gchar   *file_name)
+ {
+   SfiProxy project = bse_item_use (self->proxy);
+   BseErrorType error = bst_project_restore_from_file (project, file_name, FALSE, FALSE);
+ 
+   bst_status_eprintf (error, _("Merging instrument `%s'"), file_name);
+ 
+   bse_item_unuse (project);
+ 
+   return TRUE;
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_save_instrument (gpointer parent_widget,
+                                        SfiProxy project,
+                                        SfiProxy super)
+ {
+   BstFileDialog *self = bst_file_dialog_global_instrument ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                           BST_FILE_DIALOG_SAVE_INSTRUMENT,
+                           _("Save Instrument"), project);
+   self->super = super;
+   /* show dialog */
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ static gboolean
+ bst_file_dialog_save_instrument (BstFileDialog *self,
+                                  const gchar   *file_name)
+ {
+   SfiProxy project = bse_item_use (self->proxy);
+   gboolean self_contained = TRUE;
+   gboolean handled = store_bse_file (project, self->super, file_name, _("Saving instrument `%s'"), 
self_contained, FALSE);
+   bse_item_unuse (project);
+ 
+   return handled;
+ }
+ 
+ GtkWidget*
+ bst_file_dialog_popup_load_wave (gpointer parent_widget,
+                                SfiProxy wave_repo,
+                                gboolean show_lib)
+ {
+   BstFileDialog *self = bst_file_dialog_global_wave ();
+   GtkWidget *widget = GTK_WIDGET (self);
+ 
+   bst_file_dialog_set_mode (self, parent_widget,
+                           show_lib ? BST_FILE_DIALOG_LOAD_WAVE_LIB : BST_FILE_DIALOG_LOAD_WAVE,
+                           _("Load Wave"), wave_repo);
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ static gboolean
+ bst_file_dialog_load_wave (BstFileDialog *self,
+                          const gchar   *file_name)
+ {
+   BseErrorType error;
+ 
+   gxk_status_printf (0, NULL, _("Loading wave `%s'"), file_name);
+   error = bse_wave_repo_load_file (self->proxy, file_name);
+   bst_status_eprintf (error, _("Loading wave `%s'"), file_name);
+   if (error)
+     sfi_error (_("Failed to load wave file \"%s\": %s"), file_name, bse_error_blurb (error));
+ 
+   return TRUE;
+ }
+ 
+ GtkWidget*
++bst_file_dialog_popup_load_sound_font (gpointer parent_widget,
++                                     SfiProxy sound_font_repo,
++                                     gboolean show_lib)
++{
++  BstFileDialog *self = bst_file_dialog_global_sound_font ();
++  GtkWidget *widget = GTK_WIDGET (self);
++
++  bst_file_dialog_set_mode (self, parent_widget,
++                          show_lib ? BST_FILE_DIALOG_LOAD_SOUND_FONT_LIB : BST_FILE_DIALOG_LOAD_SOUND_FONT,
++                          _("Load Sound Font"), sound_font_repo);
++  gxk_widget_showraise (widget);
++
++  return widget;
++}
++
++static gboolean
++bst_file_dialog_load_sound_font (BstFileDialog *self,
++                               const gchar   *file_name)
++{
++  BseErrorType error;
++
++  gxk_status_printf (0, NULL, _("Loading sound font `%s'"), file_name);
++  error = bse_sound_font_repo_load_file (self->proxy, file_name);
++  bst_status_eprintf (error, _("Loading sound font `%s'"), file_name);
++  if (error)
++    sfi_error (_("Failed to load sound font \"%s\": %s"), file_name, bse_error_blurb (error));
++
++  return TRUE;
++}
++
++GtkWidget*
+ bst_file_dialog_create (void)
+ {
+   BstFileDialog *self = (BstFileDialog*) g_object_new (BST_TYPE_FILE_DIALOG, NULL);
+   bst_file_dialog_set_mode (self, NULL,
+                           BST_FILE_DIALOG_SELECT_FILE,
+                           "File Selector", 0);
+   return GTK_WIDGET (self);
+ }
+ 
+ void
+ bst_file_dialog_setup (GtkWidget        *widget,
+                        gpointer          parent_widget,
+                        const gchar      *title,
+                        const gchar      *search_path)
+ {
+   BstFileDialog *self = BST_FILE_DIALOG (widget);
+   gchar *path;
+   bst_file_dialog_set_mode (self, parent_widget,
+                             BST_FILE_DIALOG_SELECT_FILE,
+                             title, 0);
+   g_free (self->search_path);
+   self->search_path = g_strdup (search_path);
+   self->search_filter = "*";
+   path = g_strconcat (self->search_path, G_DIR_SEPARATOR_S, self->search_filter, NULL);
+   gtk_file_selection_complete (self->fs, path);
+   g_free (path);
+   tree_viewable_changed (self);
+ }
+ 
+ typedef struct {
+   BstFileDialogHandler handler;
+   gpointer             data;
+   GDestroyNotify       destroy;
+ } BstFileDialogData;
+ 
+ static void
+ bst_file_dialog_handler (BstFileDialog     *self,
+                          BstFileDialogData *data)
+ {
+   if (data->handler && self->selected)
+     data->handler (GTK_WIDGET (self), self->selected, data->data);
+   if (data->destroy)
+     data->destroy (data->data);
+   g_object_disconnect (self, "any_signal", bst_file_dialog_handler, data, NULL);
+   g_free (data);
+ }
+ 
+ void
+ bst_file_dialog_set_handler (BstFileDialog    *self,
+                              BstFileDialogHandler handler,
+                              gpointer          handler_data,
+                              GDestroyNotify    destroy)
+ {
+   BstFileDialogData *data = g_new0 (BstFileDialogData, 1);
+ 
+   g_return_if_fail (GTK_WIDGET_VISIBLE (self));
+ 
+   data->handler = handler;
+   data->data = handler_data;
+   data->destroy = destroy;
+   g_object_connect (self, "signal_after::hide", bst_file_dialog_handler, data, NULL);
+ }
+ 
+ static void
+ bst_file_dialog_activate (BstFileDialog *self)
+ {
+   GtkWindow *swin = self->parent_window;
+   gboolean popdown = TRUE;
+   gchar *file_name;
+ 
+   if (self->ignore_activate)
+     return;
+ 
+   if (self->tview && gxk_widget_viewable (GTK_WIDGET (self->tview)))
+     {
+       GtkTreeIter iter;
+       GtkTreeModel *model;
+       if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->tview), &model, &iter))
+       {
+         GValue value = { 0, };
+         gtk_tree_model_get_value (model, &iter, BST_FILE_STORE_COL_FILE, &value);
+         file_name = g_value_dup_string (&value);
+         g_value_unset (&value);
+       }
+       else
+       return;
+     }
+   else
+     file_name = g_strdup (gtk_file_selection_get_filename (self->fs));
+ 
+   if (!(self->mode & BST_FILE_DIALOG_ALLOW_DIRS) &&
+       g_file_test (file_name, G_FILE_TEST_IS_DIR))
+     {
+       gchar *tmp = g_strconcat (file_name, G_DIR_SEPARATOR_S, NULL); /* don't complete on "." but "./" */
+       gxk_notebook_set_current_page_widget (GTK_NOTEBOOK (self->notebook), self->fpage);
+       gtk_file_selection_complete (self->fs, tmp);
+       g_free (tmp);
+       g_free (file_name);
+       return;
+     }
+ 
+   if (swin)
+     gxk_status_window_push (swin);
+   switch (self->mode & BST_FILE_DIALOG_MODE_MASK)
+     {
+     case BST_FILE_DIALOG_OPEN_PROJECT:
+       popdown = bst_file_dialog_open_project (self, file_name);
+       break;
+     case BST_FILE_DIALOG_MERGE_PROJECT:
+       popdown = bst_file_dialog_merge_project (self, file_name);
+       break;
+     case BST_FILE_DIALOG_IMPORT_MIDI:
+       popdown = bst_file_dialog_import_midi (self, file_name);
+       break;
+     case BST_FILE_DIALOG_MERGE_EFFECT:
+       popdown = bst_file_dialog_merge_effect (self, file_name);
+       break;
+     case BST_FILE_DIALOG_MERGE_INSTRUMENT:
+       popdown = bst_file_dialog_merge_instrument (self, file_name);
+       break;
+     case BST_FILE_DIALOG_SAVE_PROJECT:
+       popdown = bst_file_dialog_save_project (self->proxy, GTK_TOGGLE_BUTTON (self->radio1)->active, 
file_name, self->apply_project_name, FALSE);
+       break;
+     case BST_FILE_DIALOG_SAVE_EFFECT:
+       popdown = bst_file_dialog_save_effect (self, file_name);
+       break;
+     case BST_FILE_DIALOG_SAVE_INSTRUMENT:
+       popdown = bst_file_dialog_save_instrument (self, file_name);
+       break;
+     case BST_FILE_DIALOG_SELECT_FILE:
+     case BST_FILE_DIALOG_SELECT_DIR:
+       popdown = TRUE;   /* handled via BstFileDialogHandler and ->selected */
+       break;
+     case BST_FILE_DIALOG_LOAD_WAVE:
+     case BST_FILE_DIALOG_LOAD_WAVE_LIB:
+       popdown = bst_file_dialog_load_wave (self, file_name);
+       break;
++    case BST_FILE_DIALOG_LOAD_SOUND_FONT:
++    case BST_FILE_DIALOG_LOAD_SOUND_FONT_LIB:
++      popdown = bst_file_dialog_load_sound_font (self, file_name);
++      break;
+     default: ;
+     }
+   if (swin)
+     gxk_status_window_pop ();
+   if (popdown)
+     {
+       /* ignore_activate guards against multiple clicks from long loads */
+       self->ignore_activate = TRUE;
+       g_free (self->selected);
+       self->selected = file_name;
+       gxk_toplevel_delete (GTK_WIDGET (self));
+     }
+   else
+     g_free (file_name);
+ }
diff --cc beast-gtk/bstfiledialog.hh
index 0000000,93fc348..9290588
mode 000000,100644..100644
--- a/beast-gtk/bstfiledialog.hh
+++ b/beast-gtk/bstfiledialog.hh
@@@ -1,0 -1,126 +1,131 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #ifndef __BST_FILE_DIALOG_H__
+ #define __BST_FILE_DIALOG_H__
+ 
+ #include "bstutils.hh"
+ #include "bstapp.hh"
+ 
+ G_BEGIN_DECLS
+ 
+ 
+ /* --- type macros --- */
+ #define BST_TYPE_FILE_DIALOG              (bst_file_dialog_get_type ())
+ #define BST_FILE_DIALOG(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), BST_TYPE_FILE_DIALOG, 
BstFileDialog))
+ #define BST_FILE_DIALOG_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), BST_TYPE_FILE_DIALOG, 
BstFileDialogClass))
+ #define BST_IS_FILE_DIALOG(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), BST_TYPE_FILE_DIALOG))
+ #define BST_IS_FILE_DIALOG_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), BST_TYPE_FILE_DIALOG))
+ #define BST_FILE_DIALOG_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), BST_TYPE_FILE_DIALOG, 
BstFileDialogClass))
+ 
+ 
+ /* --- typedefs --- */
+ typedef struct  _BstFileDialog            BstFileDialog;
+ typedef struct  _BstFileDialogClass BstFileDialogClass;
+ 
+ 
+ /* --- structures --- */
+ typedef enum {
 -  BST_FILE_DIALOG_OPEN_PROJECT           = 0x0001,
 -  BST_FILE_DIALOG_MERGE_PROJECT          = 0x0002,
 -  BST_FILE_DIALOG_SAVE_PROJECT           = 0x0003,
 -  BST_FILE_DIALOG_IMPORT_MIDI    = 0x0004,
 -  BST_FILE_DIALOG_SELECT_FILE    = 0x0008,
 -  BST_FILE_DIALOG_SELECT_DIR     = 0x0009,
 -  BST_FILE_DIALOG_LOAD_WAVE      = 0x0011,
 -  BST_FILE_DIALOG_LOAD_WAVE_LIB          = 0x0012,
 -  BST_FILE_DIALOG_MERGE_EFFECT     = 0x0021,
 -  BST_FILE_DIALOG_MERGE_INSTRUMENT = 0x0022,
 -  BST_FILE_DIALOG_SAVE_EFFECT      = 0x0023,
 -  BST_FILE_DIALOG_SAVE_INSTRUMENT  = 0x0024,
 -  BST_FILE_DIALOG_MODE_MASK      = 0x00ff,
 -  BST_FILE_DIALOG_ALLOW_DIRS     = 0x1000,
 -  BST_FILE_DIALOG_FLAG_MASK      = 0xff00
++  BST_FILE_DIALOG_OPEN_PROJECT              = 0x0001,
++  BST_FILE_DIALOG_MERGE_PROJECT             = 0x0002,
++  BST_FILE_DIALOG_SAVE_PROJECT              = 0x0003,
++  BST_FILE_DIALOG_IMPORT_MIDI       = 0x0004,
++  BST_FILE_DIALOG_SELECT_FILE       = 0x0008,
++  BST_FILE_DIALOG_SELECT_DIR        = 0x0009,
++  BST_FILE_DIALOG_LOAD_WAVE         = 0x0011,
++  BST_FILE_DIALOG_LOAD_WAVE_LIB             = 0x0012,
++  BST_FILE_DIALOG_LOAD_SOUND_FONT     = 0x0013,
++  BST_FILE_DIALOG_LOAD_SOUND_FONT_LIB = 0x0014,
++  BST_FILE_DIALOG_MERGE_EFFECT              = 0x0021,
++  BST_FILE_DIALOG_MERGE_INSTRUMENT    = 0x0022,
++  BST_FILE_DIALOG_SAVE_EFFECT       = 0x0023,
++  BST_FILE_DIALOG_SAVE_INSTRUMENT     = 0x0024,
++  BST_FILE_DIALOG_MODE_MASK         = 0x00ff,
++  BST_FILE_DIALOG_ALLOW_DIRS        = 0x1000,
++  BST_FILE_DIALOG_FLAG_MASK         = 0xff00
+ } BstFileDialogMode;
+ struct _BstFileDialog
+ {
+   GxkDialog       parent_instance;
+   GtkFileSelection *fs;
+   GtkWidget      *notebook;
+   GtkWidget      *fpage;      /* file selection */
+   GtkWidget      *spage;      /* sample selection */
+   GtkTreeView    *tview;      /* sample selection tree view */
+   GtkWidget      *osave;      /* save options */
+   GtkWidget      *radio1, *radio2;
+   gchar            *selected;
+   /* mode state */
+   BstFileDialogMode mode : 16;
+   guint                   ignore_activate : 1;
+   guint                   using_file_store : 1;
+   guint             apply_project_name : 1;
+   GtkTreeModel     *file_store;
+   gchar            *search_path;
+   const gchar      *search_filter;
+   GtkWindow      *parent_window;
+   SfiProxy        proxy, super;
+ };
+ struct _BstFileDialogClass
+ {
+   GxkDialogClass parent_class;
+ };
+ 
+ 
+ /* --- prototypes --- */
+ GType         bst_file_dialog_get_type                (void);
+ GtkWidget*    bst_file_dialog_popup_open_project      (gpointer          parent_widget);
+ GtkWidget*    bst_file_dialog_popup_merge_project     (gpointer          parent_widget,
+                                                        SfiProxy          project);
+ GtkWidget*    bst_file_dialog_popup_import_midi       (gpointer          parent_widget,
+                                                        SfiProxy          project);
+ GtkWidget*    bst_file_dialog_popup_save_project      (gpointer          parent_widget,
+                                                        SfiProxy          project,
+                                                          gboolean          query_project_name,
+                                                          gboolean          apply_project_name);
+ GtkWidget*      bst_file_dialog_popup_merge_effect      (gpointer          parent_widget,
+                                                          SfiProxy          project);
+ GtkWidget*    bst_file_dialog_popup_save_effect       (gpointer          parent_widget,
+                                                        SfiProxy          project,
+                                                          SfiProxy          super);
+ GtkWidget*    bst_file_dialog_popup_save_instrument   (gpointer          parent_widget,
+                                                        SfiProxy          project,
+                                                          SfiProxy          super);
+ GtkWidget*      bst_file_dialog_popup_merge_instrument  (gpointer          parent_widget,
+                                                          SfiProxy          project);
+ GtkWidget*    bst_file_dialog_popup_select_file       (gpointer          parent_widget);
+ GtkWidget*    bst_file_dialog_popup_select_dir        (gpointer          parent_widget);
+ GtkWidget*    bst_file_dialog_popup_load_wave         (gpointer          parent_widget,
+                                                        SfiProxy          wave_repo,
+                                                        gboolean          show_lib);
++GtkWidget*    bst_file_dialog_popup_load_sound_font   (gpointer          parent_widget,
++                                                         SfiProxy          sound_font_repo,
++                                                         gboolean          show_lib);
+ void          bst_file_dialog_set_mode                (BstFileDialog    *self,
+                                                        gpointer          parent_widget,
+                                                        BstFileDialogMode mode,
+                                                        const gchar      *fs_title,
+                                                        SfiProxy          project);
+ GtkWidget*      bst_file_dialog_create                  (void);
+ void            bst_file_dialog_setup                   (GtkWidget        *widget,
+                                                          gpointer          parent_widget,
+                                                          const gchar      *title,
+                                                          const gchar      *search_path);
+ typedef void  (*BstFileDialogHandler)                   (GtkWidget        *dialog,
+                                                          const gchar      *file,
+                                                          gpointer          user_data);
+ void            bst_file_dialog_set_handler             (BstFileDialog    *self,
+                                                          BstFileDialogHandler handler,
+                                                          gpointer          handler_data,
+                                                          GDestroyNotify    destroy);
+ 
+ G_END_DECLS
+ 
+ // == Flags Enumeration Operators in C++ ==
+ #ifdef __cplusplus
+ constexpr BstFileDialogMode  operator&  (BstFileDialogMode  s1, BstFileDialogMode s2) { return 
BstFileDialogMode (s1 & (long long unsigned) s2); }
+ inline    BstFileDialogMode& operator&= (BstFileDialogMode &s1, BstFileDialogMode s2) { s1 = s1 & s2; 
return s1; }
+ constexpr BstFileDialogMode  operator|  (BstFileDialogMode  s1, BstFileDialogMode s2) { return 
BstFileDialogMode (s1 | (long long unsigned) s2); }
+ inline    BstFileDialogMode& operator|= (BstFileDialogMode &s1, BstFileDialogMode s2) { s1 = s1 | s2; 
return s1; }
+ constexpr BstFileDialogMode  operator~  (BstFileDialogMode  s1)                    { return 
BstFileDialogMode (~(long long unsigned) s1); }
+ #endif // __cplusplus
+ 
+ #endif  /* __BST_FILE_DIALOG_H__ */
diff --cc beast-gtk/bstsupershell.cc
index 0000000,5f06742..224c4df
mode 000000,100644..100644
--- a/beast-gtk/bstsupershell.cc
+++ b/beast-gtk/bstsupershell.cc
@@@ -1,0 -1,249 +1,266 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #include "bstsupershell.hh"
+ #include "bstparamview.hh"
+ #include "bsttrackview.hh"
+ #include "bstpartview.hh"
+ #include "bstbusmixer.hh"
+ #include "bstbusview.hh"
+ #include "bstwaveview.hh"
+ #include "bstrackview.hh"
++#include "bstsoundfontview.h"
+ #include "bstsnetrouter.hh"
+ #include "bstgconfig.hh"
+ #include <string.h>
+ 
+ enum {
+   PROP_0,
+   PROP_SUPER
+ };
+ 
+ 
+ /* --- prototypes --- */
+ static void   bst_super_shell_destroy         (GtkObject              *object);
+ static void   bst_super_shell_finalize        (GObject                *object);
+ static void   bst_super_shell_set_property    (GObject                *object,
+                                                guint                   prop_id,
+                                                const GValue           *value,
+                                                GParamSpec             *pspec);
+ static void   bst_super_shell_get_property    (GObject                *object,
+                                                guint                   prop_id,
+                                                GValue                 *value,
+                                                GParamSpec             *pspec);
+ static void     super_shell_add_views           (BstSuperShell          *self);
+ 
+ 
+ /* --- static variables --- */
+ static BstSuperShellClass *bst_super_shell_class = NULL;
+ 
+ 
+ /* --- functions --- */
+ G_DEFINE_TYPE (BstSuperShell, bst_super_shell, GTK_TYPE_VBOX);
+ 
+ static void
+ bst_super_shell_class_init (BstSuperShellClass *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
+ 
+   bst_super_shell_class = klass;
+ 
+   gobject_class->set_property = bst_super_shell_set_property;
+   gobject_class->get_property = bst_super_shell_get_property;
+   gobject_class->finalize = bst_super_shell_finalize;
+ 
+   object_class->destroy = bst_super_shell_destroy;
+ 
+   g_object_class_install_property (gobject_class,
+                                  PROP_SUPER,
+                                  sfi_pspec_proxy ("super", NULL, NULL, SFI_PARAM_STANDARD));
+ }
+ 
+ static void
+ bst_super_shell_init (BstSuperShell *self)
+ {
+   self->super = 0;
+   gtk_widget_set (GTK_WIDGET (self),
+                   "visible", TRUE,
+                 "homogeneous", FALSE,
+                 "spacing", 0,
+                 "border_width", 0,
+                 NULL);
+ }
+ 
+ static void
+ bst_super_shell_set_property (GObject         *object,
+                             guint            prop_id,
+                             const GValue    *value,
+                             GParamSpec      *pspec)
+ {
+   BstSuperShell *self = BST_SUPER_SHELL (object);
+ 
+   switch (prop_id)
+     {
+     case PROP_SUPER:
+       bst_super_shell_set_super (self, sfi_value_get_proxy (value));
+       break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       break;
+     }
+ }
+ 
+ static void
+ bst_super_shell_get_property (GObject         *object,
+                             guint            prop_id,
+                             GValue          *value,
+                             GParamSpec      *pspec)
+ {
+   BstSuperShell *self = BST_SUPER_SHELL (object);
+ 
+   switch (prop_id)
+     {
+     case PROP_SUPER:
+       sfi_value_set_proxy (value, self->super);
+       break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       break;
+     }
+ }
+ 
+ static void
+ bst_super_shell_destroy (GtkObject *object)
+ {
+   BstSuperShell *self = BST_SUPER_SHELL (object);
+ 
+   if (self->super)
+     bst_super_shell_set_super (self, 0);
+ 
+   GTK_OBJECT_CLASS (bst_super_shell_parent_class)->destroy (object);
+ }
+ 
+ static void
+ bst_super_shell_finalize (GObject *object)
+ {
+   // BstSuperShell *self = BST_SUPER_SHELL (object);
+ 
+   G_OBJECT_CLASS (bst_super_shell_parent_class)->finalize (object);
+ }
+ 
+ void
+ bst_super_shell_set_super (BstSuperShell *self,
+                          SfiProxy       super)
+ {
+   g_return_if_fail (BST_IS_SUPER_SHELL (self));
+   if (super)
+     g_return_if_fail (BSE_IS_SUPER (super));
+ 
+   if (super != self->super)
+     {
+       if (self->super)
+       {
+           gtk_container_foreach (GTK_CONTAINER (self), (GtkCallback) gtk_widget_destroy, NULL);
+         bse_item_unuse (self->super);
+       }
+       self->super = super;
+       if (self->super)
+       {
+         bse_item_use (self->super);
+           super_shell_add_views (self);
+       }
+     }
+ }
+ 
+ GtkWidget*
+ bst_super_shell_create_label (BstSuperShell *super_shell)
+ {
+   return gxk_notebook_create_tabulator ("SuperShell", NULL, NULL);
+ }
+ 
+ static void
+ super_shell_build_song (BstSuperShell *self,
+                         GtkNotebook   *notebook)
+ {
+   SfiProxy song = self->super;
+ 
+   gtk_notebook_append_page (notebook,
+                             bst_track_view_new (song),
+                             gxk_notebook_create_tabulator (_("Tracks"), BST_STOCK_TRACKS, _("Tracks contain 
instrument definitions and parts with notes")));
+   gtk_notebook_append_page (notebook,
+                             bst_bus_mixer_new (song),
+                             gxk_notebook_create_tabulator (_("Mixer"), BST_STOCK_MIXER, _("Mix track 
outputs, adjust volume and add effects")));
+   gtk_notebook_append_page (notebook,
+                             bst_param_view_new (song),
+                             gxk_notebook_create_tabulator (_("Properties"), BST_STOCK_PROPERTIES, _("Adjust 
overall song behaviour")));
+   if (BST_DBG_EXT)
+     gtk_notebook_append_page (notebook,
+                               bst_part_view_new (song),
+                               gxk_notebook_create_tabulator (_("Parts"), BST_STOCK_PART, NULL));
+   if (BST_DBG_EXT)
+     gtk_notebook_append_page (notebook,
+                               bst_bus_view_new (song),
+                               gxk_notebook_create_tabulator (_("Busses"), BST_STOCK_BUS, NULL));
+   if (BST_DBG_EXT)
+     gtk_notebook_append_page (notebook,
+                               gtk_widget_get_toplevel (GTK_WIDGET (bst_snet_router_build_page (song))),
+                               gxk_notebook_create_tabulator (_("Routing"), BST_STOCK_MESH, NULL));
+ }
+ 
+ static void
+ super_shell_build_snet (BstSuperShell *self,
+                         GtkNotebook   *notebook)
+ {
+   SfiProxy snet = self->super;
+   GtkWidget *param_view;
+ 
+   if (BST_DBG_EXT && bse_snet_supports_user_synths (snet))
+     gtk_notebook_append_page (notebook,
+                               gtk_widget_get_toplevel (bst_rack_view_new (snet)),
+                               gxk_notebook_create_tabulator (_("Rack"), NULL, NULL));
+   if (bse_snet_supports_user_synths (snet) || BST_DBG_EXT)
+     gtk_notebook_append_page (notebook,
+                               gtk_widget_get_toplevel (GTK_WIDGET (bst_snet_router_build_page (snet))),
+                               gxk_notebook_create_tabulator (_("Routing"), BST_STOCK_MESH, _("Add, edit and 
connect synthesizer mesh components")));
+   param_view = bst_param_view_new (snet);
+   gtk_notebook_append_page (notebook,
+                             bst_param_view_new (snet),
+                             gxk_notebook_create_tabulator (_("Properties"), BST_STOCK_PROPERTIES, _("Adjust 
overall synthesizer behaviour")));
+ }
+ 
+ static void
+ super_shell_build_wave_repo (BstSuperShell *self,
+                              GtkNotebook   *notebook)
+ {
+   SfiProxy wrepo = self->super;
+ 
+   gtk_notebook_append_page (notebook,
+                             bst_wave_view_new (wrepo),
+                             gxk_notebook_create_tabulator (_("Waves"), BST_STOCK_MINI_WAVE_REPO, NULL));
+   gtk_notebook_append_page (notebook,
+                             bst_param_view_new (wrepo),
+                             gxk_notebook_create_tabulator (_("Properties"), BST_STOCK_PROPERTIES, NULL));
+ }
+ 
++static void
++super_shell_build_sound_font_repo (BstSuperShell *self,
++                                   GtkNotebook   *notebook)
++{
++  SfiProxy sfrepo = self->super;
++
++  gtk_notebook_append_page (notebook,
++                            bst_sound_font_view_new (sfrepo),
++                            gxk_notebook_create_tabulator (_("Sound Fonts"), BST_STOCK_MINI_WAVE_REPO, 
NULL));
++  gtk_notebook_append_page (notebook,
++                            bst_param_view_new (sfrepo),
++                            gxk_notebook_create_tabulator (_("Properties"), BST_STOCK_PROPERTIES, NULL));
++}
++
+ static GtkNotebook*
+ create_notebook (BstSuperShell *self)
+ {
+   GtkNotebook *notebook = (GtkNotebook*) g_object_new (GXK_TYPE_NOTEBOOK,
+                                         "scrollable", FALSE,
+                                         "tab_border", 0,
+                                         "show_border", TRUE,
+                                         "enable_popup", FALSE,
+                                         "show_tabs", TRUE,
+                                         "tab_pos", GTK_POS_TOP,
+                                         "border_width", 3,
+                                         "parent", self,
+                                         "visible", TRUE,
+                                         NULL);
+   return notebook;
+ }
+ 
+ static void
+ super_shell_add_views (BstSuperShell *self)
+ {
+   if (BSE_IS_SONG (self->super))
+     super_shell_build_song (self, create_notebook (self));
+   else if (BSE_IS_WAVE_REPO (self->super))
+     super_shell_build_wave_repo (self, create_notebook (self));
++  else if (BSE_IS_SOUND_FONT_REPO (self->super))
++    super_shell_build_sound_font_repo (self, create_notebook (self));
+   else /* BSE_IS_SNET (self->super) */
+     super_shell_build_snet (self, create_notebook (self));
+ }
diff --cc beast-gtk/bsttracksynthdialog.cc
index 0000000,dcad9d9..16ec978
mode 000000,100644..100644
--- a/beast-gtk/bsttracksynthdialog.cc
+++ b/beast-gtk/bsttracksynthdialog.cc
@@@ -1,0 -1,307 +1,326 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #include "bsttracksynthdialog.hh"
+ #include "bsttreestores.hh"
+ 
+ 
+ /* --- prototypes --- */
+ static void     bst_track_synth_dialog_finalize     (GObject                    *object);
+ static void     bst_track_synth_dialog_activate     (BstTrackSynthDialog        *self);
+ static gboolean bst_track_synth_dialog_delete_event (GtkWidget                  *widget,
+                                                      GdkEventAny                *event);
+ static void     bst_track_synth_dialog_setup        (BstTrackSynthDialog *self,
+                                                      gpointer             parent_widget,
+                                                      const gchar         *title,
+                                                      SfiProxy             proxy);
+ 
+ 
+ /* --- functions --- */
+ G_DEFINE_TYPE (BstTrackSynthDialog, bst_track_synth_dialog, GXK_TYPE_DIALOG);
+ 
+ static void
+ bst_track_synth_dialog_class_init (BstTrackSynthDialogClass *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ 
+   gobject_class->finalize = bst_track_synth_dialog_finalize;
+ 
+   widget_class->delete_event = bst_track_synth_dialog_delete_event;
+ }
+ 
+ static void
+ bst_track_synth_dialog_init (BstTrackSynthDialog *self)
+ {
+   GtkTreeSelection *tsel;
+   GtkTreeModel *smodel;
+   GtkWidget *main_box = GXK_DIALOG (self)->vbox;
+ 
+   /* configure self */
+   g_object_set (self,
+                 "flags", (GXK_DIALOG_HIDE_ON_DELETE |
+                           GXK_DIALOG_PRESERVE_STATE |
+                           GXK_DIALOG_POPUP_POS |
+                           GXK_DIALOG_MODAL),
+                 NULL);
 -  gxk_dialog_set_sizes (GXK_DIALOG (self), 550, 300, 600, 320);
++  gxk_dialog_set_sizes (GXK_DIALOG (self), 550, 300, 600, 450);
+ 
+   /* notebook */
+   self->notebook = (GtkNotebook*) g_object_new (GXK_TYPE_NOTEBOOK,
+                                                 "visible", TRUE,
+                                                 "homogeneous", TRUE,
+                                                 "show_border", TRUE,
+                                                 "show_tabs", TRUE,
+                                                 "scrollable", FALSE,
+                                                 "tab_border", 0,
+                                                 "enable_popup", TRUE,
+                                                 "tab_pos", GTK_POS_TOP,
+                                                 "border_width", 5,
+                                                 "parent", main_box,
+                                                 "enable_popup", FALSE,
+                                                 NULL);
+ 
+   /* synth list */
+   self->spage = (GtkWidget*) g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+                                            "visible", TRUE,
+                                            "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+                                            "vscrollbar_policy", GTK_POLICY_ALWAYS,
+                                            "border_width", 5,
+                                            "shadow_type", GTK_SHADOW_IN,
+                                            NULL);
+   gxk_notebook_append (self->notebook, self->spage, "synth", TRUE);
+ 
+   /* synth selection store and tree */
+   self->pstore = bst_item_seq_store_new (TRUE);
+   smodel = gtk_tree_model_sort_new_with_model (self->pstore);
+   self->tview = (GtkTreeView*) g_object_new (GTK_TYPE_TREE_VIEW,
+                                              "visible", TRUE,
+                                              "can_focus", TRUE,
+                                              "model", smodel,
+                                              "rules_hint", TRUE,
+                                              "parent", self->spage,
+                                              "search_column", BST_PROXY_STORE_NAME,
+                                              NULL);
+   g_object_unref (smodel);
+   tsel = gtk_tree_view_get_selection (self->tview);
+   gtk_tree_selection_set_mode (tsel, GTK_SELECTION_BROWSE);
+   gxk_tree_selection_force_browse (tsel, smodel);
+ 
+   /* synth selection tree columns */
+   if (BST_DVL_HINTS)
+     gxk_tree_view_add_text_column (self->tview, BST_PROXY_STORE_SEQID, "S",
+                                    0.0, "ID", NULL,
+                                    NULL, NULL, G_CONNECT_SWAPPED);
+   gxk_tree_view_add_text_column (self->tview, BST_PROXY_STORE_NAME, "S",
+                                  0.0, "Name", NULL,
+                                  NULL, NULL, G_CONNECT_SWAPPED);
+   gxk_tree_view_add_text_column (self->tview, BST_PROXY_STORE_BLURB, "",
+                                  0.0, "Comment", NULL,
+                                  NULL, NULL, G_CONNECT_SWAPPED);
+   if (BST_DVL_HINTS)
+     gxk_tree_view_add_text_column (self->tview, BST_PROXY_STORE_TYPE, "",
+                                    0.0, "Type", NULL,
+                                    NULL, NULL, G_CONNECT_SWAPPED);
+ 
+   /* wave repo view */
+   self->wpage = (GtkWidget*) g_object_new (BST_TYPE_WAVE_VIEW, "visible", TRUE, NULL);
+   gxk_notebook_append (self->notebook, self->wpage, "wave", TRUE);
+   bst_wave_view_set_editable (BST_WAVE_VIEW (self->wpage), FALSE);
++  /* sound font view */
++  self->sfont_page = g_object_new (BST_TYPE_SOUND_FONT_VIEW, "visible", TRUE, NULL);
++  gxk_notebook_append (self->notebook, self->sfont_page, "sound_font", TRUE);
+ 
+   /* provide buttons */
+   self->ok = gxk_dialog_default_action_swapped (GXK_DIALOG (self), BST_STOCK_OK, (void*) 
bst_track_synth_dialog_activate, self);
+   gxk_dialog_action (GXK_DIALOG (self), BST_STOCK_CANCEL, (void*) gxk_toplevel_delete, (GtkWidget*) self);
+ 
+   /* make row connections */
+   g_signal_connect_object (self->tview, "row_activated", G_CALLBACK (gtk_button_clicked), self->ok, 
G_CONNECT_SWAPPED);
+   g_signal_connect_object (BST_ITEM_VIEW (self->wpage)->tree, "row_activated",
+                            G_CALLBACK (gtk_button_clicked), self->ok, G_CONNECT_SWAPPED);
+ }
+ 
+ static void
+ bst_track_synth_dialog_finalize (GObject *object)
+ {
+   BstTrackSynthDialog *self = BST_TRACK_SYNTH_DIALOG (object);
+ 
+   bst_track_synth_dialog_setup (self, NULL, NULL, 0);
+ 
+   /* chain parent class' handler */
+   G_OBJECT_CLASS (bst_track_synth_dialog_parent_class)->finalize (object);
+ }
+ 
+ static gboolean
+ bst_track_synth_dialog_delete_event (GtkWidget   *widget,
+                                      GdkEventAny *event)
+ {
+   BstTrackSynthDialog *self = BST_TRACK_SYNTH_DIALOG (widget);
+   GxkFreeFunc selected_cleanup = self->selected_cleanup;
+   self->selected_callback = NULL;
+   self->selected_cleanup = NULL;
+   if (selected_cleanup)
+     selected_cleanup (self->selected_data);
+   if (self->pstore)
+     bst_item_seq_store_set (self->pstore, NULL);
+   /* chain parent class' handler */
+   return GTK_WIDGET_CLASS (bst_track_synth_dialog_parent_class)->delete_event (widget, event);
+ }
+ 
+ static void
+ parent_window_destroyed (BstTrackSynthDialog *self)
+ {
+   GxkFreeFunc selected_cleanup = self->selected_cleanup;
+   self->selected_callback = NULL;
+   self->selected_cleanup = NULL;
+   if (selected_cleanup)
+     selected_cleanup (self->selected_data);
+   gtk_widget_hide (GTK_WIDGET (self));
+   bst_track_synth_dialog_setup (self, NULL, NULL, 0);
+   gxk_toplevel_delete (GTK_WIDGET (self));
+ }
+ 
+ static void
+ bst_track_synth_dialog_setup (BstTrackSynthDialog *self,
+                               gpointer             parent_widget,
+                               const gchar         *title,
+                               SfiProxy             proxy)
+ {
+   GtkWindow *window = GTK_WINDOW (self);
+ 
+   g_return_if_fail (BST_IS_TRACK_SYNTH_DIALOG (self));
+ 
+   self->selected_callback = NULL;
+   GxkFreeFunc selected_cleanup = self->selected_cleanup;
+   self->selected_callback = NULL;
+   self->selected_cleanup = NULL;
+   if (selected_cleanup)
+     selected_cleanup (self->selected_data);
+ 
+   gtk_widget_hide (GTK_WIDGET (self));
+ 
+   /* reset proxy handling */
+   bst_window_sync_title_to_proxy (self, proxy, title);
+ 
+   /* cleanup connections to old parent_window */
+   if (self->parent_window)
+     g_signal_handlers_disconnect_by_func (self->parent_window, (void*) parent_window_destroyed, self);
+   if (window->group)
+     gtk_window_group_remove_window (window->group, window);
+   gtk_window_set_transient_for (window, NULL);
+ 
+   self->parent_window = parent_widget ? (GtkWindow*) gtk_widget_get_ancestor ((GtkWidget*) parent_widget, 
GTK_TYPE_WINDOW) : NULL;
+ 
+   /* setup connections to new parent_window */
+   if (self->parent_window)
+     {
+       gtk_window_set_transient_for (window, self->parent_window);
+       if (self->parent_window->group)
+         gtk_window_group_add_window (self->parent_window->group, window);
+       g_signal_connect_object (self->parent_window, "destroy",
+                                G_CALLBACK (parent_window_destroyed),
+                                self, G_CONNECT_SWAPPED);
+     }
+ 
+   /* allow activation */
+   self->ignore_activate = FALSE;
+   gxk_notebook_set_current_page_widget (self->notebook, self->spage);
+ }
+ 
+ static BstTrackSynthDialog*
+ bst_track_synth_dialog_singleton (void)
+ {
+   static BstTrackSynthDialog *ts_singleton = NULL;
+   if (!ts_singleton)
+     ts_singleton = (BstTrackSynthDialog*) g_object_new (BST_TYPE_TRACK_SYNTH_DIALOG, NULL);
+   return ts_singleton;
+ }
+ 
+ GtkWidget*
+ bst_track_synth_dialog_popup (gpointer     parent_widget,
+                               SfiProxy     track,
+                               const gchar *candidate_label,
+                               const gchar *candidate_tooltip,
+                               BseItemSeq  *candidates,
+                               const gchar *wrepo_label,
+                               const gchar *wrepo_tooltip,
+                               SfiProxy     wrepo,
++                              const gchar *sfrepo_label,
++                              const gchar *sfrepo_tooltip,
++                              SfiProxy     sfrepo,
+                               BstTrackSynthDialogSelected  selected_callback,
+                               gpointer                     selected_data,
+                               GxkFreeFunc                  selected_cleanup)
+ {
+   BstTrackSynthDialog *self = bst_track_synth_dialog_singleton ();
+   GtkWidget *widget = GTK_WIDGET (self);
+   if (!candidate_label)
+     candidate_label = "";
+   if (!wrepo_label)
+     wrepo_label = "";
++  if (!sfrepo_label)
++    sfrepo_label = "";
+ 
+   bst_track_synth_dialog_setup (self, NULL, NULL, 0);
+ 
+   g_object_set (gtk_notebook_get_tab_label (self->notebook, self->spage), "label", candidate_label, NULL);
+   gxk_widget_set_tooltip (self->tview, candidate_tooltip);
+   g_object_set (gtk_notebook_get_tab_label (self->notebook, self->wpage), "label", wrepo_label, NULL);
+   gxk_widget_set_tooltip (BST_ITEM_VIEW (self->wpage)->tree, wrepo_tooltip);
++  g_object_set (gtk_notebook_get_tab_label (self->notebook, self->sfont_page), "label", sfrepo_label, NULL);
++  gxk_widget_set_tooltip (BST_ITEM_VIEW (self->sfont_page)->tree, sfrepo_tooltip);
+ 
 -  bst_track_synth_dialog_set (self, candidates, wrepo);
++  bst_track_synth_dialog_set (self, candidates, wrepo, sfrepo);
+   bst_track_synth_dialog_setup (self, parent_widget,
+                                 /* TRANSLATORS: this is a dialog title and %s is replaced by an object name 
*/
+                                 _("Synthesizer Selection: %s"),
+                                 track);
+ 
+   self->selected_callback = selected_callback;
+   self->selected_data = selected_data;
+   self->selected_cleanup = selected_cleanup;
+   gxk_widget_showraise (widget);
+ 
+   return widget;
+ }
+ 
+ void
+ bst_track_synth_dialog_set (BstTrackSynthDialog *self,
+                             BseItemSeq          *iseq,
 -                            SfiProxy             wrepo)
++                            SfiProxy             wrepo,
++                          SfiProxy             sfrepo)
+ {
+   g_return_if_fail (BST_IS_TRACK_SYNTH_DIALOG (self));
+ 
+   bst_item_view_set_container (BST_ITEM_VIEW (self->wpage), wrepo);
++  bst_item_view_set_container (BST_ITEM_VIEW (self->sfont_page), sfrepo);
+   bst_item_seq_store_set (self->pstore, iseq);
 -  g_object_set (self->wpage, "visible", wrepo != 0, NULL);
+   g_object_set (self->spage, "visible", iseq != NULL, NULL);
++  g_object_set (self->wpage, "visible", wrepo != 0, NULL);
++  g_object_set (self->sfont_page, "visible", sfrepo != 0, NULL);
+ }
+ 
+ static void
+ bst_track_synth_dialog_activate (BstTrackSynthDialog *self)
+ {
+   SfiProxy proxy = 0;
+ 
+   if (self->ignore_activate)
+     return;
+ 
+   if (self->tview && gxk_widget_viewable (GTK_WIDGET (self->tview)))
+     {
+       GtkTreeIter siter;
+       GtkTreeModel *smodel;
+       if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (self->tview), &smodel, &siter))
+         {
+           GtkTreeIter piter;
+           if (GTK_IS_TREE_MODEL_SORT (smodel))
+             gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (smodel), &piter, &siter);
+           else
+             piter = siter;
+           proxy = bst_item_seq_store_get_from_iter (self->pstore, &piter);
+         }
+     }
 -  else if (self->wpage)
 -    proxy = bst_item_view_get_current (BST_ITEM_VIEW (self->wpage));
++  else if (self->wpage && gxk_widget_viewable (GTK_WIDGET (self->wpage)))
++    {
++      proxy = bst_item_view_get_current (BST_ITEM_VIEW (self->wpage));
++    }
++  else if (self->sfont_page && gxk_widget_viewable (GTK_WIDGET (self->sfont_page)))
++    {
++      proxy = bst_sound_font_view_get_preset (BST_SOUND_FONT_VIEW (self->sfont_page));
++    }
+ 
+   /* ignore_activate guards against multiple clicks */
+   self->ignore_activate = TRUE;
+   /* notify and done */
+   BstTrackSynthDialogSelected selected_callback = self->selected_callback;
+   GxkFreeFunc selected_cleanup = self->selected_cleanup;
+   gpointer selected_data = self->selected_data;
+   self->selected_callback = NULL;
+   self->selected_cleanup = NULL;
+   if (selected_callback)
+     selected_callback (selected_data, proxy, self);
+   if (selected_cleanup)
+     selected_cleanup (selected_data);
+   gxk_toplevel_delete (GTK_WIDGET (self));
+ }
diff --cc beast-gtk/bsttracksynthdialog.hh
index 0000000,df50a4f..90cbe68
mode 000000,100644..100644
--- a/beast-gtk/bsttracksynthdialog.hh
+++ b/beast-gtk/bsttracksynthdialog.hh
@@@ -1,0 -1,68 +1,73 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #ifndef __BST_TRACK_SYNTH_DIALOG_H__
+ #define __BST_TRACK_SYNTH_DIALOG_H__
+ 
+ #include "bstutils.hh"
+ #include "bstwaveview.hh"
++#include "bstsoundfontview.h"
+ 
+ G_BEGIN_DECLS
+ 
+ 
+ /* --- Gtk+ type macros --- */
+ #define BST_TYPE_TRACK_SYNTH_DIALOG            (bst_track_synth_dialog_get_type ())
+ #define BST_TRACK_SYNTH_DIALOG(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), 
BST_TYPE_TRACK_SYNTH_DIALOG, BstTrackSynthDialog))
+ #define BST_TRACK_SYNTH_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), 
BST_TYPE_TRACK_SYNTH_DIALOG, BstTrackSynthDialogClass))
+ #define BST_IS_TRACK_SYNTH_DIALOG(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), 
BST_TYPE_TRACK_SYNTH_DIALOG))
+ #define BST_IS_TRACK_SYNTH_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), 
BST_TYPE_TRACK_SYNTH_DIALOG))
+ #define BST_TRACK_SYNTH_DIALOG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
BST_TYPE_TRACK_SYNTH_DIALOG, BstTrackSynthDialogClass))
+ 
+ 
+ /* --- structures & typedefs --- */
+ typedef struct _BstTrackSynthDialog      BstTrackSynthDialog;
+ typedef struct _BstTrackSynthDialogClass BstTrackSynthDialogClass;
+ typedef void (*BstTrackSynthDialogSelected)     (gpointer                data,
+                                                  SfiProxy                proxy,
+                                                  BstTrackSynthDialog    *tsdialog);
+ struct _BstTrackSynthDialog
+ {
+   GxkDialog      parent_instance;
+   GtkNotebook   *notebook;
+   GtkWidget     *wpage;         /* wave repo item view */
+   GtkWidget     *spage;         /* synth list */
++  GtkWidget     *sfont_page;    /* sound font patch selection */
+   GtkWidget     *ok;            /* ok button */
+   GtkWindow     *parent_window;
+   guint          ignore_activate : 1;
+   GtkTreeModel  *pstore;        /* proxy store */
+   GtkTreeView   *tview;         /* synth selection tree view */
+   BstTrackSynthDialogSelected  selected_callback;
+   gpointer                     selected_data;
+   GxkFreeFunc                  selected_cleanup;
+ };
+ struct _BstTrackSynthDialogClass
+ {
+   GxkDialogClass parent_class;
+ };
+ 
+ 
+ /* --- prototypes --- */
+ GType      bst_track_synth_dialog_get_type (void);
+ GtkWidget* bst_track_synth_dialog_popup    (gpointer                     parent_widget,
+                                             SfiProxy                     track,
+                                             const gchar                 *candidate_label,
+                                             const gchar                 *candidate_tooltip,
+                                             BseItemSeq                  *candidates,
+                                             const gchar                 *wrepo_label,
+                                             const gchar                 *wrepo_tooltip,
+                                             SfiProxy                     wrepo,
++                                            const gchar                 *sfrepo_label,
++                                            const gchar                 *sfrepo_tooltip,
++                                            SfiProxy                     sfrepo,
+                                             BstTrackSynthDialogSelected  selected_callback,
+                                             gpointer                     selected_data,
+                                             GxkFreeFunc                  selected_cleanup);
+ void       bst_track_synth_dialog_set      (BstTrackSynthDialog         *self,
+                                             BseItemSeq                  *iseq,
 -                                            SfiProxy                     wrepo);
 -
++                                            SfiProxy                     wrepo,
++                                          SfiProxy                     sfrepo);
+ 
+ 
+ G_END_DECLS
+ 
+ #endif /* __BST_TRACK_SYNTH_DIALOG_H__ */
diff --cc beast-gtk/bsttrackview.cc
index 0000000,60bcc5a..fa94ea0
mode 000000,100644..100644
--- a/beast-gtk/bsttrackview.cc
+++ b/beast-gtk/bsttrackview.cc
@@@ -1,0 -1,759 +1,777 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #include "bsttrackview.hh"
+ #include "bstparam.hh"
+ #include "bstgrowbar.hh"
+ #include "bsttracksynthdialog.hh"
+ #include "bstitemseqdialog.hh"
+ #include <stdlib.h> /* strtol */
+ #include <string.h>
+ 
+ #define       SCROLLBAR_SPACING (3) /* from gtkscrolledwindow.c:DEFAULT_SCROLLBAR_SPACING */
+ 
+ /* --- prototypes --- */
+ static void   bst_track_view_finalize         (GObject                *object);
+ static gboolean track_view_action_check         (gpointer                data,
+                                                  size_t                  action,
+                                                  guint64                 action_stamp);
+ static void     track_view_action_exec          (gpointer                data,
+                                                  size_t                  action);
+ static void     track_view_set_container        (BstItemView            *self,
+                                                SfiProxy                new_container);
+ static void   track_view_listen_on            (BstItemView            *iview,
+                                                SfiProxy                item);
+ static void   track_view_unlisten_on          (BstItemView            *iview,
+                                                SfiProxy                item);
+ 
+ 
+ /* --- columns --- */
+ enum {
+   COL_SEQID,
+   COL_NAME,
+   COL_MUTE,
+   COL_VOICES,
+   COL_SYNTH,
+   COL_MIDI_CHANNEL,
+   COL_OUTPUTS,
+   COL_POST_SYNTH,
+   COL_BLURB,
+   N_COLS
+ };
+ 
+ 
+ /* --- track actions --- */
+ enum {
+   ACTION_ADD_TRACK,
+   ACTION_DELETE_TRACK
+ };
+ static const GxkStockAction track_view_actions[] = {
+   { N_("Add"),            NULL,         N_("Add a new track to this song"),
+     ACTION_ADD_TRACK,     BST_STOCK_TRACKS_ADD,
+   },
+   { N_("Delete"),         NULL,         N_("Delete the currently selected track"),
+     ACTION_DELETE_TRACK,  BST_STOCK_TRASHCAN,
+   },
+ };
+ 
+ 
+ /* --- functions --- */
+ G_DEFINE_TYPE (BstTrackView, bst_track_view, BST_TYPE_ITEM_VIEW);
+ 
+ static void
+ bst_track_view_class_init (BstTrackViewClass *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+   BstItemViewClass *item_view_class = BST_ITEM_VIEW_CLASS (klass);
+ 
+   gobject_class->finalize = bst_track_view_finalize;
+ 
+   item_view_class->set_container = track_view_set_container;
+   item_view_class->listen_on = track_view_listen_on;
+   item_view_class->unlisten_on = track_view_unlisten_on;
+ 
+   item_view_class->item_type = "BseTrack";
+ }
+ 
+ static void
+ bst_track_view_finalize (GObject *object)
+ {
+   BstTrackView *self = BST_TRACK_VIEW (object);
+ 
+   if (self->tctrl)
+     bst_track_roll_controller_unref (self->tctrl);
+ 
+   G_OBJECT_CLASS (bst_track_view_parent_class)->finalize (object);
+ }
+ 
+ GtkWidget*
+ bst_track_view_new (SfiProxy song)
+ {
+   GtkWidget *track_view;
+ 
+   g_return_val_if_fail (BSE_IS_SONG (song), NULL);
+ 
+   track_view = gtk_widget_new (BST_TYPE_TRACK_VIEW, NULL);
+   bst_item_view_set_container (BST_ITEM_VIEW (track_view), song);
+ 
+   return track_view;
+ }
+ 
+ static void
+ track_view_hzoom_changed (BstTrackView  *self,
+                         GtkAdjustment *adjustment)
+ {
+   if (self->troll)
+     bst_track_roll_set_hzoom (self->troll, adjustment->value);
+ }
+ 
+ static void
+ track_view_fill_value (BstItemView *iview,
+                      guint        column,
+                      guint        row,
+                      GValue      *value)
+ {
+   BstTrackView *self = BST_TRACK_VIEW (iview);
+   guint seqid = row + 1;
+   SfiProxy item = bse_container_get_item (iview->container, BST_ITEM_VIEW_GET_CLASS (self)->item_type, 
seqid);
+   if (!item)
+     return; // item is probably already destructed
+   switch (column)
+     {
+       const gchar *string;
+       gboolean vbool;
+       SfiInt vint;
 -      SfiProxy snet, wave;
++      SfiProxy snet, wave, sound_font_preset;
+       BseItemSeq *iseq;
+       SfiSeq *seq;
+     case COL_SEQID:
+       sfi_value_take_string (value, g_strdup_format ("%03d", seqid));
+       break;
+     case COL_NAME:
+       g_value_set_string (value, bse_item_get_name (item));
+       break;
+     case COL_MUTE:
+       bse_proxy_get (item, "muted", &vbool, NULL);
+       g_value_set_boolean (value, !vbool);
+       break;
+     case COL_VOICES:
+       bse_proxy_get (item, "n_voices", &vint, NULL);
+       sfi_value_take_string (value, g_strdup_format ("%2d", vint));
+       break;
+     case COL_SYNTH:
+       snet = 0;
 -      bse_proxy_get (item, "snet", &snet, "wave", &wave, NULL);
 -      g_value_set_string (value, snet || wave ? bse_item_get_name (snet ? snet : wave) : "");
++      wave = 0;
++      sound_font_preset = 0;
++      bse_proxy_get (item, "snet", &snet, "wave", &wave, "sound_font_preset", &sound_font_preset, NULL);
++      if (snet)
++      string = bse_item_get_name (snet);
++      else if (wave)
++      string = bse_item_get_name (wave);
++      else if (sound_font_preset)
++      string = bse_item_get_name (sound_font_preset);
++      else
++      string = "";
++      g_value_set_string (value, string);
+       break;
+     case COL_MIDI_CHANNEL:
+       bse_proxy_get (item, "midi-channel", &vint, NULL);
+       sfi_value_take_string (value, g_strdup_format ("%2d", vint));
+       break;
+     case COL_OUTPUTS:
+       bse_proxy_get (item, "outputs", &seq, NULL);
+       iseq = bse_item_seq_from_seq (seq);
+       if (iseq && iseq->n_items == 1)
+         g_value_take_string (value, g_strdup_format ("%s", bse_item_get_name_or_type (iseq->items[0])));
+       else if (iseq && iseq->n_items > 1)
+         g_value_take_string (value, g_strdup_format ("#%u", iseq ? iseq->n_items : 0));
+       else
+         g_value_set_string (value, "");
+       bse_item_seq_free (iseq);
+       break;
+     case COL_POST_SYNTH:
+       snet = 0;
+       bse_proxy_get (item, "pnet", &snet, NULL);
+       g_value_set_string (value, snet ? bse_item_get_name (snet) : "");
+       break;
+     case COL_BLURB:
+       bse_proxy_get (item, "blurb", &string, NULL);
+       g_value_set_string (value, string ? string : "");
+       break;
+     }
+ }
+ 
+ static void
+ track_view_synth_edited (BstTrackView *self,
+                        const gchar  *strpath,
+                        const gchar  *text)
+ {
+   g_return_if_fail (BST_IS_TRACK_VIEW (self));
+ 
+   if (strpath)
+     {
+       gint row = gxk_tree_spath_index0 (strpath);
+       SfiProxy item = bst_item_view_get_proxy (BST_ITEM_VIEW (self), row);
+       if (text)
+       {
+         SfiProxy proxy = 0;
+         GSList *slist = NULL;
 -        /* list possible snet/wave candidates */
++        /* list possible snet/wave/sound_font_preset candidates */
+           BsePropertyCandidates *pc = bse_item_get_property_candidates (item, "snet");
+         slist = g_slist_append (slist, pc->items);
+           pc = bse_item_get_property_candidates (item, "wave");
+         slist = g_slist_append (slist, pc->items);
++        pc = bse_item_get_property_candidates (item, "sound_font_preset");
++          slist = g_slist_append (slist, pc->items);
+         /* find best match */
+         proxy = bst_item_seq_list_match (slist, text);
+         g_slist_free (slist);
+         if (proxy && BSE_IS_SNET (proxy))
+           bse_proxy_set (item, "snet", proxy, NULL);
+         else if (proxy && BSE_IS_WAVE (proxy))
+           bse_proxy_set (item, "wave", proxy, NULL);
++        else if (proxy && BSE_IS_SOUND_FONT_PRESET (proxy))
++          bse_proxy_set (item, "sound_font_preset", proxy, NULL);
+         else
 -          bse_proxy_set (item, "snet", 0, "wave", 0, NULL);
++          bse_proxy_set (item, "snet", 0, "wave", 0, "sound_font_preset", 0, NULL);
+       }
+       else
 -      bse_proxy_set (item, "snet", 0, "wave", 0, NULL);
++      bse_proxy_set (item, "snet", 0, "wave", 0, "sound_font_preset", 0, NULL);
+     }
+ }
+ 
+ static void
+ track_view_post_synth_edited (BstTrackView *self,
+                               const gchar  *strpath,
+                               const gchar  *text)
+ {
+   g_return_if_fail (BST_IS_TRACK_VIEW (self));
+ 
+   if (strpath)
+     {
+       gint row = gxk_tree_spath_index0 (strpath);
+       SfiProxy item = bst_item_view_get_proxy (BST_ITEM_VIEW (self), row);
+       if (text)
+       {
+         SfiProxy proxy = 0;
+         GSList *slist = NULL;
+         /* list possible snet candidates */
+           BsePropertyCandidates *pc = bse_item_get_property_candidates (item, "pnet");
+         slist = g_slist_append (slist, pc->items);
+         /* find best match */
+         proxy = bst_item_seq_list_match (slist, text);
+         g_slist_free (slist);
+         if (proxy && BSE_IS_SNET (proxy))
+           bse_proxy_set (item, "pnet", proxy, NULL);
+         else
+           bse_proxy_set (item, "pnet", 0, NULL);
+       }
+       else
+       bse_proxy_set (item, "pnet", 0, NULL);
+     }
+ }
+ 
+ typedef struct {
+   BstTrackView         *self;
+   GxkCellRendererPopup *pcell;
+ } SynthPopup;
+ 
+ static void
+ track_view_synth_popup_cleanup (gpointer data)
+ {
+   SynthPopup *sdata = (SynthPopup*) data;
+   gxk_cell_renderer_popup_change (sdata->pcell, NULL, FALSE, TRUE);
+   g_free (sdata);
+ }
+ 
+ static void
+ track_view_synth_popup_cb (gpointer              data,
+                            SfiProxy              proxy,
+                            BstTrackSynthDialog  *tsdialog)
+ {
+   SynthPopup *sdata = (SynthPopup*) data;
+   gxk_cell_renderer_popup_change (sdata->pcell,
+                                   proxy ? bse_item_get_uname_path (proxy) : "",
+                                   FALSE,
+                                   proxy == 0);
+ }
+ 
+ static void
+ track_view_synth_popup (BstTrackView         *self,
+                       const gchar          *strpath,
+                       const gchar          *text,
+                       GxkCellRendererPopup *pcell)
+ {
+   g_return_if_fail (BST_IS_TRACK_VIEW (self));
+ 
+   if (strpath)
+     {
+       gint row = gxk_tree_spath_index0 (strpath);
+       SfiProxy item = bst_item_view_get_proxy (BST_ITEM_VIEW (self), row);
+       if (bse_item_editable_property (item, "snet"))
+         {
+           BsePropertyCandidates *pc = bse_item_get_property_candidates (item, "snet");
+           SynthPopup sdata = { self, pcell, };
+           GtkWidget *dialog = bst_track_synth_dialog_popup (self, item,
+                                                             pc->label, pc->tooltip, pc->items,
+                                                             _("Available Waves"),
+                                                             _("List of available waves to choose a track 
instrument from"),
+                                                             bse_project_get_wave_repo (bse_item_get_project 
(item)),
++                                                          _("Available Sound Fonts"),
++                                                          _("List of available sound fonts to choose track 
instrument from"),
++                                                          bse_project_get_sound_font_repo 
(bse_item_get_project (item)),
+                                                             track_view_synth_popup_cb, g_memdup (&sdata, 
sizeof (sdata)), track_view_synth_popup_cleanup);
+           gxk_cell_renderer_popup_dialog (pcell, dialog);
+         }
+       else
+         bst_gui_error_bell (self);
+     }
+ }
+ 
+ static void
+ track_view_post_synth_popup (BstTrackView         *self,
+                              const gchar          *strpath,
+                              const gchar          *text,
+                              GxkCellRendererPopup *pcell)
+ {
+   g_return_if_fail (BST_IS_TRACK_VIEW (self));
+ 
+   if (strpath)
+     {
+       gint row = gxk_tree_spath_index0 (strpath);
+       SfiProxy item = bst_item_view_get_proxy (BST_ITEM_VIEW (self), row);
+       if (bse_item_editable_property (item, "pnet"))
+         {
+           BsePropertyCandidates *pc = bse_item_get_property_candidates (item, "pnet");
+           SynthPopup sdata = { self, pcell, };
+           GtkWidget *dialog = bst_track_synth_dialog_popup (self, item,
+                                                             pc->label, pc->tooltip, pc->items,
+                                                             NULL, NULL, 0,
++                                                          NULL, NULL, 0,
+                                                             track_view_synth_popup_cb, g_memdup (&sdata, 
sizeof (sdata)), track_view_synth_popup_cleanup);
+           gxk_cell_renderer_popup_dialog (pcell, dialog);
+         }
+       else
+         bst_gui_error_bell (self);
+     }
+ }
+ 
+ typedef struct {
+   BstTrackView         *self;
+   GxkCellRendererPopup *pcell;
+   SfiProxy              item;
+ } OutputsPopup;
+ 
+ static void
+ track_view_outputs_cleanup (gpointer data)
+ {
+   OutputsPopup *odata = (OutputsPopup*) data;
+   gxk_cell_renderer_popup_change (odata->pcell, NULL, FALSE, FALSE);
+   g_free (odata);
+ }
+ 
+ static void
+ track_view_outputs_changed (gpointer              data,
+                             BseItemSeq           *iseq,
+                             BstItemSeqDialog     *isdialog)
+ {
+   OutputsPopup *odata = (OutputsPopup*) data;
+   gxk_cell_renderer_popup_change (odata->pcell, NULL, FALSE, FALSE);
+   SfiSeq *seq = bse_item_seq_to_seq (iseq);
+   GValue *value = sfi_value_seq (seq);
+   sfi_seq_unref (seq);
+   bse_proxy_set_property (odata->item, "outputs", value);
+   sfi_value_free (value);
+ }
+ 
+ static void
+ track_view_outputs_popup (BstTrackView         *self,
+                           const gchar          *strpath,
+                           const gchar          *text,
+                           GxkCellRendererPopup *pcell)
+ {
+   g_return_if_fail (BST_IS_TRACK_VIEW (self));
+ 
+   if (strpath)
+     {
+       gint row = gxk_tree_spath_index0 (strpath);
+       SfiProxy item = bst_item_view_get_proxy (BST_ITEM_VIEW (self), row);
+       BsePropertyCandidates *pc = bse_item_get_property_candidates (item, "outputs");
+       GParamSpec *pspec = bse_proxy_get_pspec (item, "outputs");
+       const GValue *value = bse_proxy_get_property (item, "outputs");
+       SfiSeq *seq = (SfiSeq*) g_value_get_boxed (value);
+       BseItemSeq *iseq = bse_item_seq_from_seq (seq);
+       OutputsPopup odata = { self, pcell, item };
+       GtkWidget *dialog = bst_item_seq_dialog_popup (self, item,
+                                                      pc->label, pc->tooltip, pc->items,
+                                                      g_param_spec_get_nick (pspec), g_param_spec_get_blurb 
(pspec), iseq,
+                                                      track_view_outputs_changed, g_memdup (&odata, sizeof 
(odata)), track_view_outputs_cleanup);
+       bse_item_seq_free (iseq);
+       gxk_cell_renderer_popup_dialog (pcell, dialog);
+     }
+ }
+ 
+ static void
+ track_view_mute_toggled (BstTrackView          *self,
+                        const gchar           *strpath,
+                        GtkCellRendererToggle *tcell)
+ {
+   g_return_if_fail (BST_IS_TRACK_VIEW (self));
+ 
+   if (strpath)
+     {
+       gint row = gxk_tree_spath_index0 (strpath);
+       SfiProxy item = bst_item_view_get_proxy (BST_ITEM_VIEW (self), row);
+       if (item)
+       {
+         gboolean muted;
+         bse_proxy_get (item, "muted", &muted, NULL);
+         bse_proxy_set (item, "muted", !muted, NULL);
+         bse_proxy_get (item, "muted", &muted, NULL);
+         gtk_cell_renderer_toggle_set_active (tcell, !muted);
+       }
+     }
+ }
+ 
+ static void
+ track_view_voice_edited (BstTrackView *self,
+                          const gchar  *strpath,
+                          const gchar  *text)
+ {
+   g_return_if_fail (BST_IS_TRACK_VIEW (self));
+ 
+   if (strpath)
+     {
+       gint row = gxk_tree_spath_index0 (strpath);
+       SfiProxy item = bst_item_view_get_proxy (BST_ITEM_VIEW (self), row);
+       if (item)
+       {
+         int i = strtol (text, NULL, 10);
+         if (i > 0)
+           bse_proxy_set (item, "n_voices", i, NULL);
+       }
+     }
+ }
+ 
+ static void
+ track_view_midi_channel_edited (BstTrackView *self,
+                                 const gchar  *strpath,
+                                 const gchar  *text)
+ {
+   g_return_if_fail (BST_IS_TRACK_VIEW (self));
+ 
+   if (strpath)
+     {
+       gint row = gxk_tree_spath_index0 (strpath);
+       SfiProxy item = bst_item_view_get_proxy (BST_ITEM_VIEW (self), row);
+       if (item)
+       {
+         int i = strtol (text, NULL, 10);
+         if (i >= 0)
+           bse_proxy_set (item, "midi-channel", i, NULL);
+       }
+     }
+ }
+ 
+ static SfiProxy
+ get_track (gpointer data,
+          gint     row)
+ {
+   return bst_item_view_get_proxy (BST_ITEM_VIEW (data), row);
+ }
+ 
+ static void
+ track_view_marks_changed (BstTrackView *self)
+ {
+   SfiProxy song = BST_ITEM_VIEW (self)->container;
+   if (self->troll && song)
+     {
+       SfiInt lleft, lright, pointer;
+       bse_proxy_get (song, "loop_left", &lleft, "loop_right", &lright, "tick_pointer", &pointer, NULL);
+       bst_track_roll_set_marker (self->troll, 1, lleft, lleft >= 0 ? BST_TRACK_ROLL_MARKER_LOOP : 
BST_TRACK_ROLL_MARKER_NONE);
+       bst_track_roll_set_marker (self->troll, 2, lright, lright >= 0 ? BST_TRACK_ROLL_MARKER_LOOP : 
BST_TRACK_ROLL_MARKER_NONE);
+       bst_track_roll_set_marker (self->troll, 3, pointer, pointer >= 0 ? BST_TRACK_ROLL_MARKER_POS : 
BST_TRACK_ROLL_MARKER_NONE);
+     }
+ }
+ 
+ static void
+ track_view_repeat_toggled (BstTrackView *self)
+ {
+   SfiProxy song = BST_ITEM_VIEW (self)->container;
+   if (song && self->repeat_toggle)
+     bse_proxy_set (song, "loop_enabled", GTK_TOGGLE_BUTTON (self->repeat_toggle)->active, NULL);
+ }
+ 
+ static void
+ track_view_repeat_changed (BstTrackView *self)
+ {
+   SfiProxy song = BST_ITEM_VIEW (self)->container;
+   if (song && self->repeat_toggle)
+     {
+       GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (self->repeat_toggle);
+       gboolean enabled;
+       bse_proxy_get (song, "loop_enabled", &enabled, NULL);
+       if (toggle->active != enabled)
+       gtk_toggle_button_set_active (toggle, enabled);
+     }
+ }
+ 
+ static void
+ bst_track_view_init (BstTrackView *self)
+ {
+   BstItemView *iview = BST_ITEM_VIEW (self);
+   GtkWidget *treehs, *trackgb, *vscroll;
+   GtkObject *adjustment;
+   GtkTreeView *tview;
+   GtkTreeSelection *tsel;
+   GtkTreeModel *smodel;
+   GxkListWrapper *lwrapper;
+   GxkRadget *radget;
+ 
+   /* create GUI */
+   gxk_widget_publish_actions (self, "track-view-actions",
+                               G_N_ELEMENTS (track_view_actions), track_view_actions,
+                               NULL, track_view_action_check, track_view_action_exec);
+   radget = gxk_radget_complete (GTK_WIDGET (self), "beast", "track-view", NULL);
+ 
+   /* item list model */
+   lwrapper = gxk_list_wrapper_new (N_COLS,
+                                  G_TYPE_STRING,       /* COL_SEQID */
+                                  G_TYPE_STRING,       /* COL_NAME */
+                                  G_TYPE_BOOLEAN,      /* COL_MUTE */
+                                  G_TYPE_STRING,       /* COL_VOICES */
+                                  G_TYPE_STRING,       /* COL_SYNTH */
+                                  G_TYPE_STRING,       /* COL_MIDI_CHANNEL */
+                                  G_TYPE_STRING,       /* COL_OUTPUTS */
+                                  G_TYPE_STRING,       /* COL_POST_SYNTH */
+                                  G_TYPE_STRING        /* COL_BLURB */
+                                  );
+   smodel = bst_item_view_adapt_list_wrapper (iview, lwrapper);
+   g_signal_connect_object (lwrapper, "fill-value",
+                          G_CALLBACK (track_view_fill_value),
+                          iview, G_CONNECT_SWAPPED);
+   g_object_unref (lwrapper);
+ 
+   /* scrollbars */
+   treehs = (GtkWidget*) gxk_radget_find (radget, "tree-hscrollbar");
+   trackgb = (GtkWidget*) gxk_radget_find (radget, "track-hgrow-bar");
+   vscroll = (GtkWidget*) gxk_radget_find (radget, "tree-vscrollbar");
+ 
+   /* tree view (track list) */
+   tview = (GtkTreeView*) gxk_radget_find (radget, "tree-view");
+   gtk_tree_view_set_model (tview, smodel);
+   bst_item_view_set_tree (iview, tview);
+   gtk_tree_view_set_hadjustment (iview->tree, gtk_range_get_adjustment (GTK_RANGE (treehs)));
+   gtk_tree_view_set_vadjustment (iview->tree, gtk_range_get_adjustment (GTK_RANGE (vscroll)));
+   tsel = gtk_tree_view_get_selection (iview->tree);
+   gtk_tree_selection_set_mode (tsel, GTK_SELECTION_BROWSE);
+   gxk_tree_selection_force_browse (tsel, smodel);
+   g_object_unref (smodel);
+ 
+   /* track roll */
+   self->troll = (BstTrackRoll*) g_object_new (BST_TYPE_TRACK_ROLL,
+                                               "visible", TRUE,
+                                               "parent", gxk_radget_find (radget, "track-area"),
+                                               NULL);
+   gxk_nullify_in_object (self, &self->troll);
+   gxk_scroll_canvas_set_hadjustment (GXK_SCROLL_CANVAS (self->troll), bst_grow_bar_get_adjustment 
(BST_GROW_BAR (trackgb)));
+   gxk_scroll_canvas_set_vadjustment (GXK_SCROLL_CANVAS (self->troll), gtk_range_get_adjustment (GTK_RANGE 
(vscroll)));
+   bst_track_roll_set_track_callback (self->troll, self, get_track);
+   track_view_marks_changed (self);
+ 
+   /* link track roll to tree view and list model */
+   g_signal_connect_object (tsel, "changed",
+                          G_CALLBACK (bst_track_roll_reselect),
+                          self->troll, G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+   g_signal_connect_object (self->troll, "select-row",
+                          G_CALLBACK (gxk_tree_view_focus_row),
+                          iview->tree, G_CONNECT_SWAPPED);
+   g_signal_connect_object (self->troll, "select-row",
+                          G_CALLBACK (gtk_widget_grab_focus),
+                          iview->tree, G_CONNECT_SWAPPED);
+   g_signal_connect_object (iview->wlist, "row-change",
+                          G_CALLBACK (bst_track_roll_abort_edit),
+                          self->troll, G_CONNECT_SWAPPED);
+ 
+   /* track roll controller */
+   self->tctrl = bst_track_roll_controller_new (self->troll);
+   bst_track_roll_controller_set_song (self->tctrl, iview->container);
+   gxk_widget_publish_action_list (self, "tctrl-canvas-tools", bst_track_roll_controller_canvas_actions 
(self->tctrl));
+   gxk_widget_publish_action_list (self, "tctrl-hpanel-tools", bst_track_roll_controller_hpanel_actions 
(self->tctrl));
+   gxk_widget_publish_action_list (self, "tctrl-quant-tools", bst_track_roll_controller_quant_actions 
(self->tctrl));
+ 
+   /* add repeat toggle */
+   self->repeat_toggle = (GtkWidget*) gxk_radget_find (radget, "repeat-toggle");
+   gxk_nullify_in_object (self, &self->repeat_toggle);
+   g_object_connect (self->repeat_toggle, "swapped_signal::toggled", track_view_repeat_toggled, self, NULL);
+   track_view_repeat_changed (self);
+ 
+   /* add zoom spinner */
+   adjustment = gtk_adjustment_new (50, 1, 100, 1, 5, 0);
+   g_object_connect (adjustment,
+                   "swapped_signal_after::value_changed", track_view_hzoom_changed, self,
+                   NULL);
+   gxk_radget_add (self, "hzoom-area",
+                   g_object_new (GTK_TYPE_SPIN_BUTTON,
+                                 "visible", TRUE,
+                                 "adjustment", adjustment,
+                                 "digits", 0,
+                                 "width_request", 2 * gxk_size_width (GXK_ICON_SIZE_TOOLBAR),
+                                 NULL));
+ 
+   /* add list view columns */
+   if (BST_DVL_HINTS)
+     gxk_tree_view_add_text_column (iview->tree, COL_SEQID, "S",
+                                    0.0, "ID", NULL,
+                                    NULL, NULL, GConnectFlags (0));
+   gxk_tree_view_add_text_column (iview->tree, COL_NAME, "S",
+                                0.0, _("Name"), NULL,
+                                (void*) bst_item_view_name_edited, self, G_CONNECT_SWAPPED);
+   gxk_tree_view_add_toggle_column (iview->tree, COL_MUTE, "",
+                                  0.5, "M", _("Notes from unchecked tracks are ignored by the sequencer 
during playback"),
+                                  (void*) track_view_mute_toggled, self, G_CONNECT_SWAPPED);
+   gxk_tree_view_add_text_column (iview->tree, COL_VOICES, "",
+                                0.5, "V", _("Maximum number of voices for simultaneous playback"),
+                                (void*) track_view_voice_edited, self, G_CONNECT_SWAPPED);
+   gxk_tree_view_add_popup_column (iview->tree, COL_SYNTH, "#",
+                                 0.5, "Synth", _("Synthesis network or wave to be used as instrument by this 
track"),
+                                   (void*) track_view_synth_edited, (void*) track_view_synth_popup, self, 
G_CONNECT_SWAPPED);
+   gxk_tree_view_add_text_column (iview->tree, COL_MIDI_CHANNEL, "",
+                                  0.5, "Ch", _("Midi channel assigned to this track, 0 uses private 
per-track channel"),
+                                  (void*) track_view_midi_channel_edited, self, G_CONNECT_SWAPPED);
+   gxk_tree_view_add_popup_column (iview->tree, COL_OUTPUTS, "#",
+                                 0.5, "Outputs", _("Mixer busses connected to track output"),
+                                 NULL, (void*) track_view_outputs_popup, self, G_CONNECT_SWAPPED);
+   gxk_tree_view_add_popup_column (iview->tree, COL_POST_SYNTH, "",
+                                 0.5, "Post", _("Synthesis network to be used as postprocessor"),
+                                 (void*) track_view_post_synth_edited, (void*) track_view_post_synth_popup, 
self, G_CONNECT_SWAPPED);
+   gxk_tree_view_add_text_column (iview->tree, COL_BLURB, "",
+                                0.0, _("Comment"), NULL,
+                                (void*) bst_item_view_blurb_edited, self, G_CONNECT_SWAPPED);
+ }
+ 
+ static void
+ track_changed (SfiProxy      track,
+              BstTrackView *self)
+ {
+   if (self->troll)
+     {
+       gint row = bst_item_view_get_proxy_row (BST_ITEM_VIEW (self), track);
+       bst_track_roll_queue_row_change (self->troll, row);
+     }
+ }
+ 
+ static void
+ track_view_pointer_changed (BstTrackView *self,
+                           SfiInt        position)
+ {
+   if (self->troll)
+     bst_track_roll_set_marker (self->troll, 3, position, position >= 0 ? BST_TRACK_ROLL_MARKER_POS : 
BST_TRACK_ROLL_MARKER_NONE);
+ }
+ 
+ static void
+ track_view_set_container (BstItemView *iview,
+                         SfiProxy     new_container)
+ {
+   BstTrackView *self = BST_TRACK_VIEW (iview);
+   if (BSE_IS_SONG (iview->container))
+     bse_proxy_disconnect (iview->container,
+                         "any_signal", track_view_pointer_changed, self,
+                         "any_signal", track_view_marks_changed, self,
+                         "any_signal", track_view_repeat_changed, self,
+                         NULL);
+   BST_ITEM_VIEW_CLASS (bst_track_view_parent_class)->set_container (iview, new_container);
+   if (self->troll)
+     bst_track_roll_setup (self->troll, iview->container ? iview->tree : NULL, iview->container);
+   if (BSE_IS_SONG (iview->container))
+     {
+       bst_track_roll_controller_set_song (self->tctrl, iview->container);
+       bse_proxy_connect (iview->container,
+                        "swapped_signal::pointer-changed", track_view_pointer_changed, self,
+                        "swapped_signal::property-notify::loop-left", track_view_marks_changed, self,
+                        "swapped_signal::property-notify::loop-right", track_view_marks_changed, self,
+                        "swapped_signal::property-notify::tick-pointer", track_view_marks_changed, self,
+                        "swapped_signal::property-notify::loop-enabled", track_view_repeat_changed, self,
+                        NULL);
+       track_view_marks_changed (self);
+       track_view_repeat_changed (self);
+     }
+ }
+ 
+ static void
+ track_property_changed (SfiProxy     item,
+                         const gchar *property_name,
+                         BstItemView *iview)
+ {
+   bst_item_view_refresh (iview, item);
+ }
+ 
+ static void
+ track_view_listen_on (BstItemView *iview,
+                     SfiProxy     item)
+ {
+   BST_ITEM_VIEW_CLASS (bst_track_view_parent_class)->listen_on (iview, item);
+   bse_proxy_connect (item,
+                    "signal::changed", track_changed, iview,
+                    NULL);
+   bse_proxy_connect (item,
+                      /* COL_SEQID handled by GxkListWrapper */
+                      /* COL_NAME handled by GxkListWrapper */
+                      "signal::property-notify::muted", track_property_changed, iview, /* COL_MUTE */
+                      "signal::property-notify::n-voices", track_property_changed, iview, /* COL_VOICES */
+                      "signal::property-notify::snet", track_property_changed, iview, /* COL_SYNTH */
+                      "signal::property-notify::midi-channel", track_property_changed, iview, /* 
COL_MIDI_CHANNEL */
+                      "signal::property-notify::outputs", track_property_changed, iview, /* COL_OUTPUTS */
+                      "signal::property-notify::pnet", track_property_changed, iview, /* COL_POST_SYNTH */
+                      /* COL_BLURB handled by GxkListWrapper */
+                      NULL);
+ }
+ 
+ static void
+ track_view_unlisten_on (BstItemView *iview,
+                       SfiProxy     item)
+ {
+   bse_proxy_disconnect (item,
+                       "any_signal", track_changed, iview,
+                       "any_signal", track_property_changed, iview,
+                       NULL);
+   BST_ITEM_VIEW_CLASS (bst_track_view_parent_class)->unlisten_on (iview, item);
+ }
+ 
+ static void
+ track_view_action_exec (gpointer data,
+                         size_t   action)
+ {
+   BstTrackView *self = BST_TRACK_VIEW (data);
+   BstItemView *item_view = BST_ITEM_VIEW (self);
+   SfiProxy song = item_view->container;
+ 
+   switch (action)
+     {
+       SfiProxy item;
+       guint i;
+     case ACTION_ADD_TRACK:
+       bse_item_group_undo (song, "Add Track");
+       item = bse_song_create_track (song);
+       if (item)
+       {
+         gchar *string = g_strdup_format ("Track-%02X", bse_item_get_seqid (item));
+         bse_item_set_name (item, string);
+         g_free (string);
+         bst_item_view_select (item_view, item);
+           bse_track_ensure_output (item);
+       }
+       bse_item_ungroup_undo (song);
+       break;
+     case ACTION_DELETE_TRACK:
+       item = bst_item_view_get_current (item_view);
+       bse_item_group_undo (song, "Delete Track");
+       BseItemSeq *iseq = bse_track_list_parts_uniq (item);
+       bse_song_remove_track (song, item);
+       for (i = 0; i < iseq->n_items; i++)
+         if (!bse_song_find_any_track_for_part (song, iseq->items[i]))
+           bse_song_remove_part (song, iseq->items[i]);
+       bse_item_ungroup_undo (song);
+       break;
+     }
+   gxk_widget_update_actions_downwards (self);
+ }
+ 
+ static gboolean
+ track_view_action_check (gpointer data,
+                          size_t   action,
+                          guint64  action_stamp)
+ {
+   BstTrackView *self = BST_TRACK_VIEW (data);
+   BstItemView *item_view = BST_ITEM_VIEW (self);
+ 
+   switch (action)
+     {
+       SfiProxy item;
+     case ACTION_ADD_TRACK:
+       return TRUE;
+     case ACTION_DELETE_TRACK:
+       item = bst_item_view_get_current (item_view);
+       return item != 0;
+     default:
+       return FALSE;
+     }
+ }
diff --cc beast-gtk/bstutils.cc
index 0000000,af7ad9d..90a1afa
mode 000000,100644..100644
--- a/beast-gtk/bstutils.cc
+++ b/beast-gtk/bstutils.cc
@@@ -1,0 -1,1512 +1,1515 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #include "bstutils.hh"
+ 
+ #include "bstgconfig.hh"
+ #include "bstmenus.hh"
+ #include "bsttrackview.hh"
+ #include "bstwaveview.hh"
++#include "bstsoundfontview.h"
+ #include "bstpartview.hh"
+ #include "bstbusmixer.hh"
+ #include "bstbuseditor.hh"
+ #include "bstbusview.hh"
+ #include "bstpianoroll.hh"
+ #include "bstpatternview.hh"
+ #include "bsteventroll.hh"
+ #include "bstgrowbar.hh"
+ #include "bstdbmeter.hh"
+ #include "bstscrollgraph.hh"
++
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <unistd.h>
+ #include <string.h>
+ /* --- generated enums --- */
+ #include "bstenum_arrays.cc"     /* enum string value arrays plus include directives */
+ 
+ /* --- prototypes --- */
+ static void     _bst_init_idl                   (void);
+ /* --- variables --- */
+ static GtkIconFactory *stock_icon_factory = NULL;
+ Bse::ServerH bse_server;
+ 
+ /* --- functions --- */
+ void
+ _bst_init_utils (void)
+ {
+   g_assert (stock_icon_factory == NULL);
+   stock_icon_factory = gtk_icon_factory_new ();
+   gtk_icon_factory_add_default (stock_icon_factory);
+   /* initialize generated type ids */
+   {
+     static struct {
+       const char       *type_name;
+       GType             parent;
+       GType            *type_id;
+       gconstpointer     pointer1;
+     } builtin_info[] = {
+ #include "bstenum_list.cc"       /* type entries */
+     };
+     guint i;
+     for (i = 0; i < sizeof (builtin_info) / sizeof (builtin_info[0]); i++)
+       {
+         GType type_id = 0;
+ 
+         if (builtin_info[i].parent == G_TYPE_ENUM)
+           type_id = g_enum_register_static (builtin_info[i].type_name, (const GEnumValue*) 
builtin_info[i].pointer1);
+         else if (builtin_info[i].parent == G_TYPE_FLAGS)
+           type_id = g_flags_register_static (builtin_info[i].type_name, (const GFlagsValue*) 
builtin_info[i].pointer1);
+         else
+           g_assert_not_reached ();
+         g_assert (g_type_name (type_id) != NULL);
+         *builtin_info[i].type_id = type_id;
+       }
+   }
+ 
+   /* initialize IDL types */
+   _bst_init_idl ();
+ 
+   /* initialize stock icons (included above) */
+   {
+     /* generated stock icons */
+ #include "beast-gtk/icons/bst-stock-gen.cc"
+ 
+     gxk_stock_register_icons (G_N_ELEMENTS (stock_icons), stock_icons);
+   }
+ 
+   /* initialize stock actions */
+   {
+     static const GxkStockItem stock_items[] = {
+       { BST_STOCK_CLONE,                "_Clone",       GTK_STOCK_COPY,                 },
+       { BST_STOCK_DISMISS,              "_Dismiss",     GTK_STOCK_CLOSE,                },
+       { BST_STOCK_DEFAULT_REVERT,       "_Defaults",    GTK_STOCK_UNDO,                 },
+       { BST_STOCK_LOAD,                 "_Load",        NULL,                           },
+       { BST_STOCK_OVERWRITE,            "_Overwrite",   GTK_STOCK_SAVE,                 },
+       { BST_STOCK_REVERT,               "_Revert",      GTK_STOCK_UNDO,                 },
+     };
+     gxk_stock_register_items (G_N_ELEMENTS (stock_items), stock_items);
+   }
+ }
+ 
+ #include "beast-gtk/dialogs/beast-xml-zfiles.cc"
+ void
+ _bst_init_radgets (void)
+ {
+   gchar *text;
+   gxk_radget_define_widget_type (BST_TYPE_TRACK_VIEW);
+   gxk_radget_define_widget_type (BST_TYPE_HGROW_BAR);
+   gxk_radget_define_widget_type (BST_TYPE_VGROW_BAR);
+   gxk_radget_define_widget_type (BST_TYPE_WAVE_VIEW);
++  gxk_radget_define_widget_type (BST_TYPE_SOUND_FONT_VIEW);
+   gxk_radget_define_widget_type (BST_TYPE_PART_VIEW);
+   gxk_radget_define_widget_type (BST_TYPE_BUS_EDITOR);
+   gxk_radget_define_widget_type (BST_TYPE_BUS_MIXER);
+   gxk_radget_define_widget_type (BST_TYPE_BUS_VIEW);
+   gxk_radget_define_widget_type (BST_TYPE_PIANO_ROLL);
+   gxk_radget_define_widget_type (BST_TYPE_EVENT_ROLL);
+   gxk_radget_define_widget_type (BST_TYPE_DB_BEAM);
+   gxk_radget_define_widget_type (BST_TYPE_DB_LABELING);
+   gxk_radget_define_widget_type (BST_TYPE_DB_METER);
+   gxk_radget_define_widget_type (BST_TYPE_SCROLLGRAPH);
+   gxk_radget_define_widget_type (BST_TYPE_PATTERN_VIEW);
+   gxk_radget_define_widget_type (BST_TYPE_ZOOMED_WINDOW);
+   text = gxk_zfile_uncompress (BST_RADGETS_STANDARD_SIZE, BST_RADGETS_STANDARD_DATA, G_N_ELEMENTS 
(BST_RADGETS_STANDARD_DATA));
+   gxk_radget_parse_text ("beast", text, -1, NULL, NULL);
+   g_free (text);
+   text = gxk_zfile_uncompress (BST_RADGETS_BEAST_SIZE, BST_RADGETS_BEAST_DATA, G_N_ELEMENTS 
(BST_RADGETS_BEAST_DATA));
+   gxk_radget_parse_text ("beast", text, -1, NULL, NULL);
+   g_free (text);
+ }
+ 
+ GtkWidget*
+ bst_stock_button (const gchar *stock_id)
+ {
+   GtkWidget *w = gtk_button_new_from_stock (stock_id);
+   gtk_widget_show_all (w);
+   return w;
+ }
+ 
+ GtkWidget*
+ bst_stock_dbutton (const gchar *stock_id)
+ {
+   GtkWidget *w = bst_stock_button (stock_id);
+   g_object_set (w, "can-default", TRUE, NULL);
+   return w;
+ }
+ 
+ GtkWidget*
+ bst_stock_icon_button (const gchar *stock_id)
+ {
+   GtkWidget *w = (GtkWidget*) g_object_new (GTK_TYPE_BUTTON,
+                                "visible", TRUE,
+                                "child", gtk_image_new_from_stock (stock_id, GXK_ICON_SIZE_BUTTON),
+                                "can-focus", FALSE,
+                                NULL);
+   gtk_widget_show_all (w);
+   return w;
+ }
+ 
+ void
+ bst_stock_register_icon (const gchar    *stock_id,
+                          guint           bytes_per_pixel,
+                          guint           width,
+                          guint           height,
+                          guint           rowstride,
+                          const guint8   *pixels)
+ {
+   g_return_if_fail (bytes_per_pixel == 3 || bytes_per_pixel == 4);
+   g_return_if_fail (width > 0 && height > 0 && rowstride >= width * bytes_per_pixel);
+ 
+   if (!gtk_icon_factory_lookup (stock_icon_factory, stock_id))
+     {
+       GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data ((guchar*) g_memdup (pixels, rowstride * height),
+                                                     GDK_COLORSPACE_RGB, bytes_per_pixel == 4,
+                                                     8, width, height,
+                                                     width * bytes_per_pixel,
+                                                     (GdkPixbufDestroyNotify) g_free, NULL);
+       GtkIconSet *iset = gtk_icon_set_new_from_pixbuf (pixbuf);
+       g_object_unref (pixbuf);
+       gtk_icon_factory_add (stock_icon_factory, stock_id, iset);
+       gtk_icon_set_unref (iset);
+     }
+ }
+ 
+ /* --- beast/bse specific extensions --- */
+ void
+ bst_status_set_error (BseErrorType error, const std::string &message)
+ {
+   if (error)
+     gxk_status_set (GXK_STATUS_ERROR, message.c_str(), bse_error_blurb (error));
+   else
+     gxk_status_set (GXK_STATUS_DONE, message.c_str(), NULL);
+ }
+ 
+ void
+ bst_gui_error_bell (gpointer widget)
+ {
+   g_return_if_fail (GTK_IS_WIDGET (widget));
+ 
+   if (GTK_WIDGET_DRAWABLE (widget) && BST_GUI_ENABLE_ERROR_BELL)
+     {
+ #if GTK_CHECK_VERSION (2, 12, 0)
+       gdk_window_beep (GTK_WIDGET (widget)->window);
+ #else
+       gdk_beep();
+ #endif
+     }
+ }
+ 
+ typedef struct {
+   GtkWindow *window;
+   SfiProxy   proxy;
+   gchar     *title1;
+   gchar     *title2;
+ } TitleSync;
+ 
+ static void
+ sync_title (TitleSync *tsync)
+ {
+   const gchar *name = bse_item_get_name (tsync->proxy);
+   gchar *s;
+ 
+   s = g_strconcat (tsync->title1, name ? name : "<NULL>", tsync->title2, NULL);
+   g_object_set (tsync->window, "title", s, NULL);
+   g_free (s);
+ }
+ 
+ static void
+ free_title_sync (gpointer data)
+ {
+   TitleSync *tsync = (TitleSync*) data;
+ 
+   bse_proxy_disconnect (tsync->proxy,
+                         "any_signal", sync_title, tsync,
+                         NULL);
+   g_free (tsync->title1);
+   g_free (tsync->title2);
+   g_free (tsync);
+ }
+ 
+ void
+ bst_window_sync_title_to_proxy (gpointer     window,
+                                 SfiProxy     proxy,
+                                 const gchar *title_format)
+ {
+   const char *p;
+ 
+   g_return_if_fail (GTK_IS_WINDOW (window));
+   if (proxy)
+     {
+       g_return_if_fail (BSE_IS_ITEM (proxy));
+       g_return_if_fail (title_format != NULL);
+       /* g_return_if_fail (strstr (title_format, "%s") != NULL); */
+     }
+   p = title_format ? strstr (title_format, "%s") : NULL;
+   if (proxy && p)
+     {
+       TitleSync *tsync = g_new0 (TitleSync, 1);
+       tsync->window = (GtkWindow*) window;
+       tsync->proxy = proxy;
+       tsync->title1 = g_strndup (title_format, p - title_format);
+       tsync->title2 = g_strdup (p + 2);
+       bse_proxy_connect (tsync->proxy,
+                          "swapped_signal::property-notify::uname", sync_title, tsync,
+                          NULL);
+       g_object_set_data_full ((GObject*) window, "bst-title-sync", tsync, free_title_sync);
+       sync_title (tsync);
+     }
+   else
+     {
+       g_object_set_data ((GObject*) window, "bst-title-sync", NULL);
+       g_object_set (window, "title", title_format, NULL);
+     }
+ }
+ 
+ typedef struct {
+   gboolean       (*handler) (gpointer data);
+   gpointer         data;
+   void           (*free_func) (gpointer data);
+ } BackgroundHandler;
+ 
+ static SfiRing *background_handlers1 = NULL;
+ static SfiRing *background_handlers2 = NULL;
+ 
+ static gboolean
+ bst_background_handlers_timeout (gpointer timeout_data)
+ {
+   GDK_THREADS_ENTER();
+   if (background_handlers1 || background_handlers2)
+     {
+       gxk_status_set (GXK_STATUS_PROGRESS, _("Updating View"), NULL);
+       BackgroundHandler *bgh = (BackgroundHandler*) sfi_ring_pop_head (&background_handlers1);
+       gint prio = 1;
+       if (!bgh)
+         {
+           prio = 2;
+           bgh = (BackgroundHandler*) sfi_ring_pop_head (&background_handlers2);
+         }
+       if (bgh->handler (bgh->data))
+         {
+           if (prio == 1)
+             background_handlers1 = sfi_ring_append (background_handlers1, bgh);
+           else
+             background_handlers2 = sfi_ring_append (background_handlers2, bgh);
+         }
+       else
+         {
+           if (bgh->free_func)
+             bgh->free_func (bgh->data);
+           g_free (bgh);
+         }
+       if (background_handlers1 || background_handlers2)
+         gxk_status_set (GXK_STATUS_PROGRESS, _("Updating View"), NULL);
+     }
+   if (!background_handlers1 && !background_handlers2)
+     gxk_status_set (100, _("Updating View"), NULL); /* done */
+   GDK_THREADS_LEAVE();
+   /* re-queue instead of returning TRUE to start a new delay cycle */
+   if (background_handlers1 || background_handlers2)
+     g_timeout_add_full (G_PRIORITY_LOW - 100,
+                         30, /* milliseconds */
+                         bst_background_handlers_timeout, NULL, NULL);
+   return FALSE;
+ }
+ 
+ static void
+ bst_background_handler_add (gboolean       (*handler) (gpointer data),
+                             gpointer         data,
+                             void           (*free_func) (gpointer data),
+                             gint             prio)
+ {
+   g_return_if_fail (handler != NULL);
+   BackgroundHandler *bgh = g_new0 (BackgroundHandler, 1);
+   bgh->handler = handler;
+   bgh->data = data;
+   bgh->free_func = free_func;
+   if (!background_handlers1 && !background_handlers2)
+     g_timeout_add_full (G_PRIORITY_LOW - 100,
+                         20, /* milliseconds */
+                         bst_background_handlers_timeout, NULL, NULL);
+   if (prio == 1)
+     background_handlers1 = sfi_ring_append (background_handlers1, bgh);
+   else
+     background_handlers2 = sfi_ring_append (background_handlers2, bgh);
+ }
+ 
+ void
+ bst_background_handler1_add (gboolean       (*handler) (gpointer data),
+                              gpointer         data,
+                              void           (*free_func) (gpointer data))
+ {
+   bst_background_handler_add (handler, data, free_func, 1);
+ }
+ 
+ void
+ bst_background_handler2_add (gboolean       (*handler) (gpointer data),
+                              gpointer         data,
+                              void           (*free_func) (gpointer data))
+ {
+   bst_background_handler_add (handler, data, free_func, 2);
+ }
+ 
+ /* --- packing utilities --- */
+ #define SPACING 3
+ static void
+ bst_util_pack (GtkWidget   *widget,
+                const gchar *location,
+                guint        spacing,
+                va_list      args)
+ {
+   GtkBox *box = GTK_BOX (widget);
+   while (location)
+     {
+       gchar *t, **toks = g_strsplit (location, ":", -1);
+       guint border = 0, padding = 0, i = 0;
+       gboolean fill = FALSE, expand = FALSE, start = TRUE;
+       GtkWidget *child;
+       t = toks[i++];
+       if (t && t[0] >= '0' && t[0] <= '9')
+         {
+           border = g_ascii_strtoull (t, NULL, 10);
+           t = toks[i++];
+         }
+       if (t && t[0] == '+')
+         {
+           expand = TRUE;
+           t = toks[i++];
+         }
+       if (t && t[0] == '*')
+         {
+           expand = fill = TRUE;
+           t = toks[i++];
+         }
+       if (t && t[0] == 'H')
+         {
+           gtk_box_set_homogeneous (box, TRUE);
+           expand = fill = TRUE;
+           t = toks[i++];
+         }
+       if (t && t[0] == 's')
+         {
+           start = TRUE;
+           t = toks[i++];
+         }
+       if (t && t[0] == 'e')
+         {
+           start = FALSE;
+           t = toks[i++];
+         }
+       if (t && t[0] == 'p')
+         {
+           padding = g_ascii_strtoull (t + 1, NULL, 10);
+           t = toks[i++];
+         }
+       g_strfreev (toks);
+       child = va_arg (args, GtkWidget*);
+       if (child)
+         {
+           if (border)
+             child = (GtkWidget*) g_object_new (GTK_TYPE_ALIGNMENT,
+                                                "child", child,
+                                                "border_width", border * spacing,
+                                                NULL);
+           if (start)
+             gtk_box_pack_start (box, child, expand, fill, padding);
+           else
+             gtk_box_pack_end (box, child, expand, fill, padding);
+         }
+       location = va_arg (args, gchar*);
+     }
+ }
+ 
+ GtkWidget*
+ bst_vpack (const gchar *first_location,
+            ...)
+ {
+   va_list args;
+   GtkWidget *box = (GtkWidget*) g_object_new (GTK_TYPE_VBOX,
+                                  "spacing", SPACING,
+                                  NULL);
+   va_start (args, first_location);
+   bst_util_pack (box, first_location, SPACING, args);
+   va_end (args);
+   gtk_widget_show_all (box);
+   return box;
+ }
+ 
+ GtkWidget*
+ bst_hpack (const gchar *first_location,
+            ...)
+ {
+   va_list args;
+   GtkWidget *box = (GtkWidget*) g_object_new (GTK_TYPE_HBOX,
+                                  "spacing", SPACING,
+                                  NULL);
+   va_start (args, first_location);
+   bst_util_pack (box, first_location, SPACING, args);
+   va_end (args);
+   gtk_widget_show_all (box);
+   return box;
+ }
+ 
+ GtkWidget*
+ bst_vpack0 (const gchar *first_location,
+             ...)
+ {
+   va_list args;
+   GtkWidget *box = (GtkWidget*) g_object_new (GTK_TYPE_VBOX,
+                                  "spacing", 0,
+                                  NULL);
+   va_start (args, first_location);
+   bst_util_pack (box, first_location, SPACING, args);
+   va_end (args);
+   gtk_widget_show_all (box);
+   return box;
+ }
+ 
+ GtkWidget*
+ bst_hpack0 (const gchar *first_location,
+             ...)
+ {
+   va_list args;
+   GtkWidget *box = (GtkWidget*) g_object_new (GTK_TYPE_HBOX,
+                                  "spacing", 0,
+                                  NULL);
+   va_start (args, first_location);
+   bst_util_pack (box, first_location, SPACING, args);
+   va_end (args);
+   gtk_widget_show_all (box);
+   return box;
+ }
+ 
+ void
+ bst_action_list_add_cat (GxkActionList          *alist,
+                          BseCategory            *cat,
+                          guint                   skip_levels,
+                          const gchar            *stock_fallback,
+                          GxkActionCheck          acheck,
+                          GxkActionExec           aexec,
+                          gpointer                user_data)
+ {
+   const gchar *p, *stock_id;
+ 
+   if (cat->icon)
+     {
+       BseIcon *icon = cat->icon;
+       g_assert (icon->width * icon->height == int (icon->pixel_seq->n_pixels));
+       bst_stock_register_icon (cat->category, 4,
+                                icon->width, icon->height,
+                                icon->width * 4,
+                                (guchar*) icon->pixel_seq->pixels);
+       stock_id = cat->category;
+     }
+   else
+     stock_id = stock_fallback;
+ 
+   p = cat->category[0] == '/' ? cat->category + 1 : cat->category;
+   while (skip_levels--)
+     {
+       const gchar *d = strchr (p, '/');
+       p = d ? d + 1 : p;
+     }
+ 
+   gxk_action_list_add_translated (alist, NULL, p, NULL,
+                                   gxk_factory_path_get_leaf (cat->category),
+                                   cat->category_id, stock_id,
+                                   acheck, aexec, user_data);
+ }
+ 
+ GxkActionList*
+ bst_action_list_from_cats_pred (BseCategorySeq  *cseq,
+                                 guint            skip_levels,
+                                 const gchar     *stock_fallback,
+                                 GxkActionCheck   acheck,
+                                 GxkActionExec    aexec,
+                                 gpointer         user_data,
+                                 BstActionListCategoryP predicate,
+                                 gpointer         predicate_data)
+ {
+   GxkActionList *alist = gxk_action_list_create ();
+   guint i;
+ 
+   g_return_val_if_fail (cseq != NULL, alist);
+ 
+   for (i = 0; i < cseq->n_cats; i++)
+     if (!predicate || predicate (predicate_data, cseq->cats[i]))
+       bst_action_list_add_cat (alist, cseq->cats[i], skip_levels, stock_fallback, acheck, aexec, user_data);
+   return alist;
+ }
+ 
+ GxkActionList*
+ bst_action_list_from_cats (BseCategorySeq         *cseq,
+                            guint                   skip_levels,
+                            const gchar            *stock_fallback,
+                            GxkActionCheck          acheck,
+                            GxkActionExec           aexec,
+                            gpointer                user_data)
+ {
+   return bst_action_list_from_cats_pred (cseq, skip_levels, stock_fallback, acheck, aexec, user_data, NULL, 
NULL);
+ }
+ 
+ 
+ /* --- field mask --- */
+ static GQuark gmask_quark = 0;
+ typedef struct {
+   GtkWidget   *parent;
+   GtkWidget   *prompt;
+   GtkWidget   *aux1;
+   GtkWidget   *aux2;            /* auto-expand */
+   GtkWidget   *aux3;
+   GtkWidget   *action;
+   gchar       *tip;
+   guint        column : 16;
+   guint        gpack : 8;
+ } GMask;
+ #define GMASK_GET(o)    ((GMask*) g_object_get_qdata (G_OBJECT (o), gmask_quark))
+ 
+ static void
+ gmask_destroy (gpointer data)
+ {
+   GMask *gmask = (GMask*) data;
+ 
+   if (gmask->parent)
+     g_object_unref (gmask->parent);
+   if (gmask->prompt)
+     g_object_unref (gmask->prompt);
+   if (gmask->aux1)
+     g_object_unref (gmask->aux1);
+   if (gmask->aux2)
+     g_object_unref (gmask->aux2);
+   if (gmask->aux3)
+     g_object_unref (gmask->aux3);
+   g_free (gmask->tip);
+   g_free (gmask);
+ }
+ 
+ static gpointer
+ gmask_form (GtkWidget   *parent,
+             GtkWidget   *action,
+             BstGMaskPack gpack)
+ {
+   GMask *gmask;
+ 
+   g_return_val_if_fail (GTK_IS_TABLE (parent), NULL);
+   g_return_val_if_fail (GTK_IS_WIDGET (action), NULL);
+ 
+   if (!gmask_quark)
+     gmask_quark = g_quark_from_static_string ("GMask");
+ 
+   gmask = GMASK_GET (action);
+   g_return_val_if_fail (gmask == NULL, NULL);
+ 
+   gmask = g_new0 (GMask, 1);
+   g_object_set_qdata_full (G_OBJECT (action), gmask_quark, gmask, gmask_destroy);
+   gmask->parent = (GtkWidget*) g_object_ref (parent);
+   gtk_object_sink (GTK_OBJECT (parent));
+   gmask->action = action;
+   gmask->gpack = gpack;
+ 
+   return action;
+ }
+ 
+ /**
+  * @param border_width           Border width of this GUI mask
+  * @param dislodge_columns Provide expandable space between columns
+  * @return               GUI field mask container
+  *
+  * Create a container capable to hold GUI field masks.
+  * This is the container to be passed into bst_gmask_form().
+  * In case multiple field mask columns are packed into the
+  * container (by using bst_gmask_set_column() on the filed
+  * masks), @a dislodge_columns specifies whether the field
+  * mask columns are to be closely aligned.
+  */
+ GtkWidget*
+ bst_gmask_container_create (guint    border_width,
+                             gboolean dislodge_columns)
+ {
+   GtkWidget *container = gtk_widget_new (GTK_TYPE_TABLE,
+                                          "visible", TRUE,
+                                          "homogeneous", FALSE,
+                                          "n_columns", 2,
+                                          "border_width", border_width,
+                                          NULL);
+   if (dislodge_columns)
+     g_object_set_data (G_OBJECT (container), "GMask-dislodge", GUINT_TO_POINTER (TRUE));
+ 
+   return container;
+ }
+ 
+ /**
+  * @param gmask_container    container created with bst_gmask_container_create()
+  * @param action             valid GtkWidget
+  * @param gpack       BstGMaskPack packing type
+  * @return                 a new GUI field mask
+  *
+  * Create a new GUI field mask with @a action as action widget.
+  * Each GUI field mask consists of an action widget which may
+  * be neighboured by pre and post action widgets, the action
+  * widget is usually something like a GtkEntry input widget.
+  * Also, most field masks have a prompt widget, usually a
+  * GtkLabel, labeling the field mask with a name.
+  * Optionally, up to three auxillary widgets are supported
+  * per field mask, layed out between the prompt and the
+  * action widgets.
+  * The second auxillary widget will expand if additional
+  * space is available. Other layout details are configured
+  * through the @a gpack packing type:
+  * @li @c BST_GMASK_FIT - the action widget is not expanded,
+  * @li @c BST_GMASK_INTERLEAVE - allow the action widget to expand across auxillary
+  * columns if it requests that much space,
+  * @li @c BST_GMASK_BIG - force expansion of the action widget across all possible
+  * columns up to the prompt,
+  * @li @c BST_GMASK_CENTER - center the action widget within space across all possible
+  * columns up to the prompt.
+  * @li @c BST_GMASK_MULTI_SPAN - span aux2 widget across multiple gmask columns.
+  */
+ BstGMask*
+ bst_gmask_form (GtkWidget   *gmask_container,
+                 GtkWidget   *action,
+                 BstGMaskPack gpack)
+ {
+   return (BstGMask*) gmask_form (gmask_container, action, gpack);
+ }
+ 
+ /**
+  * @param mask           valid BstGMask
+  * @param tip_text tooltip text
+  *
+  * Set the tooltip text of this GUI field @a mask.
+  */
+ void
+ bst_gmask_set_tip (BstGMask    *mask,
+                    const gchar *tip_text)
+ {
+   GMask *gmask;
+ 
+   g_return_if_fail (GTK_IS_WIDGET (mask));
+   gmask = GMASK_GET (mask);
+   g_return_if_fail (gmask != NULL);
+ 
+   g_free (gmask->tip);
+   gmask->tip = g_strdup (tip_text);
+ }
+ 
+ /**
+  * @param mask         valid BstGMask
+  * @param widget valid GtkWidget
+  *
+  * Set the prompt widget of this GUI field @a mask.
+  */
+ void
+ bst_gmask_set_prompt (BstGMask *mask,
+                       gpointer  widget)
+ {
+   GMask *gmask;
+ 
+   g_return_if_fail (GTK_IS_WIDGET (mask));
+   gmask = GMASK_GET (mask);
+   g_return_if_fail (gmask != NULL);
+   g_return_if_fail (GTK_IS_WIDGET (widget));
+ 
+   if (gmask->prompt)
+     g_object_unref (gmask->prompt);
+   gmask->prompt = (GtkWidget*) g_object_ref (widget);
+   gtk_object_sink (GTK_OBJECT (widget));
+ }
+ 
+ /**
+  * @param mask         valid BstGMask
+  * @param widget valid GtkWidget
+  *
+  * Set the first auxillary widget of this GUI field @a mask.
+  */
+ void
+ bst_gmask_set_aux1 (BstGMask *mask,
+                     gpointer  widget)
+ {
+   GMask *gmask;
+ 
+   g_return_if_fail (GTK_IS_WIDGET (mask));
+   gmask = GMASK_GET (mask);
+   g_return_if_fail (gmask != NULL);
+   g_return_if_fail (GTK_IS_WIDGET (widget));
+ 
+   if (gmask->aux1)
+     g_object_unref (gmask->aux1);
+   gmask->aux1 = (GtkWidget*) g_object_ref (widget);
+   gtk_object_sink (GTK_OBJECT (widget));
+ }
+ 
+ /**
+  * @param mask         valid BstGMask
+  * @param widget valid GtkWidget
+  *
+  * Set the second auxillary widget of this GUI field @a mask.
+  * In contrast to the first and third auxillary widget, this
+  * one is expanded if extra space is available.
+  */
+ void
+ bst_gmask_set_aux2 (BstGMask *mask,
+                     gpointer  widget)
+ {
+   GMask *gmask;
+ 
+   g_return_if_fail (GTK_IS_WIDGET (mask));
+   gmask = GMASK_GET (mask);
+   g_return_if_fail (gmask != NULL);
+   g_return_if_fail (GTK_IS_WIDGET (widget));
+ 
+   if (gmask->aux2)
+     g_object_unref (gmask->aux2);
+   gmask->aux2 = (GtkWidget*) g_object_ref (widget);
+   gtk_object_sink (GTK_OBJECT (widget));
+ }
+ 
+ /**
+  * @param mask         valid BstGMask
+  * @param widget valid GtkWidget
+  *
+  * Set the third auxillary widget of this GUI field @a mask.
+  */
+ void
+ bst_gmask_set_aux3 (BstGMask *mask,
+                     gpointer  widget)
+ {
+   GMask *gmask;
+ 
+   g_return_if_fail (GTK_IS_WIDGET (mask));
+   gmask = GMASK_GET (mask);
+   g_return_if_fail (gmask != NULL);
+   g_return_if_fail (GTK_IS_WIDGET (widget));
+ 
+   if (gmask->aux3)
+     g_object_unref (gmask->aux3);
+   gmask->aux3 = (GtkWidget*) g_object_ref (widget);
+   gtk_object_sink (GTK_OBJECT (widget));
+ }
+ 
+ /**
+  * @param mask         valid BstGMask
+  * @param column column number
+  *
+  * Set the field mask column. By default all field masks are
+  * packed into column 0, so that only vertical packing occours.
+  */
+ void
+ bst_gmask_set_column (BstGMask *mask,
+                       guint     column)
+ {
+   GMask *gmask;
+ 
+   g_return_if_fail (GTK_IS_WIDGET (mask));
+   gmask = GMASK_GET (mask);
+   g_return_if_fail (gmask != NULL);
+ 
+   gmask->column = column;
+ }
+ 
+ /**
+  * @param mask        valid BstGMask
+  * @return    the requested GtkWidget or NULL
+  *
+  * Retrieve the prompt widget of this GUI field @a mask.
+  */
+ GtkWidget*
+ bst_gmask_get_prompt (BstGMask *mask)
+ {
+   GMask *gmask;
+ 
+   g_return_val_if_fail (GTK_IS_WIDGET (mask), NULL);
+   gmask = GMASK_GET (mask);
+   g_return_val_if_fail (gmask != NULL, NULL);
+ 
+   return gmask->prompt;
+ }
+ 
+ /**
+  * @param mask        valid BstGMask
+  * @return    the requested GtkWidget or NULL
+  *
+  * Retrieve the first auxillary widget of this GUI field @a mask.
+  */
+ GtkWidget*
+ bst_gmask_get_aux1 (BstGMask *mask)
+ {
+   GMask *gmask;
+ 
+   g_return_val_if_fail (GTK_IS_WIDGET (mask), NULL);
+   gmask = GMASK_GET (mask);
+   g_return_val_if_fail (gmask != NULL, NULL);
+ 
+   return gmask->aux1;
+ }
+ 
+ /**
+  * @param mask        valid BstGMask
+  * @return    the requested GtkWidget or NULL
+  *
+  * Retrieve the second auxillary widget of this GUI field @a mask.
+  */
+ GtkWidget*
+ bst_gmask_get_aux2 (BstGMask *mask)
+ {
+   GMask *gmask;
+ 
+   g_return_val_if_fail (GTK_IS_WIDGET (mask), NULL);
+   gmask = GMASK_GET (mask);
+   g_return_val_if_fail (gmask != NULL, NULL);
+ 
+   return gmask->aux2;
+ }
+ 
+ /**
+  * @param mask        valid BstGMask
+  * @return    the requested GtkWidget or NULL
+  *
+  * Retrieve the third auxillary widget of this GUI field @a mask.
+  */
+ GtkWidget*
+ bst_gmask_get_aux3 (BstGMask *mask)
+ {
+   GMask *gmask;
+ 
+   g_return_val_if_fail (GTK_IS_WIDGET (mask), NULL);
+   gmask = GMASK_GET (mask);
+   g_return_val_if_fail (gmask != NULL, NULL);
+ 
+   return gmask->aux3;
+ }
+ 
+ /**
+  * @param mask        valid BstGMask
+  * @return    the requested GtkWidget or NULL
+  *
+  * Retrieve the action widget of this GUI field @a mask.
+  */
+ GtkWidget*
+ bst_gmask_get_action (BstGMask *mask)
+ {
+   GMask *gmask;
+ 
+   g_return_val_if_fail (GTK_IS_WIDGET (mask), NULL);
+   gmask = GMASK_GET (mask);
+   g_return_val_if_fail (gmask != NULL, NULL);
+ 
+   return gmask->action;
+ }
+ 
+ /**
+  * @param mask        valid BstGMask
+  * @param func        foreach function as: void func(GtkWidget*, gpointer data);
+  * @param data        data passed in to @a func
+  *
+  * Invoke @a func() with each of the widgets set for this
+  * field mask.
+  */
+ void
+ bst_gmask_foreach (BstGMask *mask,
+                    gpointer  func,
+                    gpointer  data)
+ {
+   GMask *gmask;
+   GtkCallback callback = GtkCallback (func);
+ 
+   g_return_if_fail (GTK_IS_WIDGET (mask));
+   gmask = GMASK_GET (mask);
+   g_return_if_fail (gmask != NULL);
+   g_return_if_fail (func != NULL);
+ 
+   if (gmask->prompt)
+     callback (gmask->prompt, data);
+   if (gmask->aux1)
+     callback (gmask->aux1, data);
+   if (gmask->aux2)
+     callback (gmask->aux2, data);
+   if (gmask->aux3)
+     callback (gmask->aux3, data);
+   if (gmask->action)
+     callback (gmask->action, data);
+ }
+ 
+ static GtkWidget*
+ get_toplevel_and_set_tip (GtkWidget   *widget,
+                           const gchar *tip)
+ {
+   GtkWidget *last;
+ 
+   if (!widget)
+     return NULL;
+   else if (!tip)
+     return gtk_widget_get_toplevel (widget);
+   do
+     {
+       if (!GTK_WIDGET_NO_WINDOW (widget))
+         {
+           gxk_widget_set_tooltip (widget, tip);
+           return gtk_widget_get_toplevel (widget);
+         }
+       last = widget;
+       widget = last->parent;
+     }
+   while (widget);
+   /* need to create a tooltips sensitive parent */
+   widget = gtk_widget_new (GTK_TYPE_EVENT_BOX,
+                            "visible", TRUE,
+                            "child", last,
+                            NULL);
+   gxk_widget_set_tooltip (widget, tip);
+   return widget;
+ }
+ 
+ static guint
+ table_max_bottom_row (GtkTable *table,
+                       guint     left_col,
+                       guint     right_col)
+ {
+   guint max_bottom = 0;
+   GList *list;
+ 
+   for (list = table->children; list; list = list->next)
+     {
+       GtkTableChild *child = (GtkTableChild*) list->data;
+ 
+       if (child->left_attach < right_col && child->right_attach > left_col)
+         max_bottom = MAX (max_bottom, child->bottom_attach);
+     }
+   return max_bottom;
+ }
+ 
+ /**
+  * @param mask        valid BstGMask
+  *
+  * After the GUI field mask is fully configured, by setting
+  * all associated widgets on it, column tooltip text, etc.,
+  * this function actually packs it into its container. The
+  * field mask setters shouldn't be used after this point.
+  */
+ void
+ bst_gmask_pack (BstGMask *mask)
+ {
+   GtkWidget *prompt, *aux1, *aux2, *aux3, *action;
+   GtkTable *table;
+   gboolean dummy_aux2 = FALSE;
+   guint row, n, c, dislodge_columns;
+   GMask *gmask;
+ 
+   g_return_if_fail (GTK_IS_WIDGET (mask));
+   gmask = GMASK_GET (mask);
+   g_return_if_fail (gmask != NULL);
+ 
+   /* GUI mask layout:
+    * row: |Prompt|Aux1| Aux2 |Aux3| PreAction#Action#PostAction|
+    * FILL: allocate all possible (Pre/Post)Action space to the action widget
+    * INTERLEAVE: allow the action widget to facilitate unused Aux2/Aux3 space
+    * BIG: allocate maximum (left extendeded) possible space to Action
+    * Aux2 expands automatically
+    */
+ 
+   /* retrieve children and set tips */
+   prompt = get_toplevel_and_set_tip (gmask->prompt, gmask->tip);
+   aux1 = get_toplevel_and_set_tip (gmask->aux1, gmask->tip);
+   aux2 = get_toplevel_and_set_tip (gmask->aux2, gmask->tip);
+   aux3 = get_toplevel_and_set_tip (gmask->aux3, gmask->tip);
+   action = get_toplevel_and_set_tip (gmask->action, gmask->tip);
+   dislodge_columns = g_object_get_data (G_OBJECT (gmask->parent), "GMask-dislodge") != NULL;
+   table = GTK_TABLE (gmask->parent);
+ 
+   /* ensure expansion happens outside of columns */
+   if (dislodge_columns)
+     {
+       gchar *dummy_name = g_strdup_format ("GMask-dummy-dislodge-%u", MAX (gmask->column, 1) - 1);
+       GtkWidget *dislodge = (GtkWidget*) g_object_get_data (G_OBJECT (table), dummy_name);
+ 
+       if (!dislodge)
+         {
+           dislodge = (GtkWidget*) g_object_new (GTK_TYPE_ALIGNMENT, "visible", TRUE, NULL);
+           g_object_set_data_full (G_OBJECT (table), dummy_name, g_object_ref (dislodge), g_object_unref);
+           c = MAX (gmask->column, 1) * 6;
+           gtk_table_attach (table, dislodge, c - 1, c, 0, 1, GTK_EXPAND, GtkAttachOptions (0), 0, 0);
+         }
+       g_free (dummy_name);
+     }
+ 
+   /* pack gmask children, options: GTK_EXPAND, GTK_SHRINK, GTK_FILL */
+   gboolean span_multi_columns = aux2 && gmask->gpack == BST_GMASK_MULTI_SPAN;
+   c = span_multi_columns ? 0 : 6 * gmask->column;
+   row = table_max_bottom_row (table, c, 6 * gmask->column + 6);
+   if (prompt)
+     {
+       gtk_table_attach (table, prompt, c, c + 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0);
+       gtk_table_set_col_spacing (table, c, 2); /* seperate prompt from rest */
+     }
+   c++;
+   if (aux1)
+     {
+       gtk_table_attach (table, aux1, c, c + 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0);
+       gtk_table_set_col_spacing (table, c, 3); /* aux1 spacing */
+     }
+   c++;
+   if (!aux2 && !dislodge_columns)
+     {
+       char *dummy_name = g_strdup_format ("GMask-dummy-aux2-%u", gmask->column);
+       aux2 = (GtkWidget*) g_object_get_data (G_OBJECT (table), dummy_name);
+ 
+       /* need to have at least 1 (dummy) aux2-child per table column to eat up
+        * expanding space in this column if !dislodge_columns
+        */
+       if (!aux2)
+         {
+           aux2 = gtk_widget_new (GTK_TYPE_ALIGNMENT, "visible", TRUE, NULL);
+           g_object_set_data_full (G_OBJECT (table), dummy_name, g_object_ref (aux2), g_object_unref);
+         }
+       else
+         aux2 = NULL;
+       g_free (dummy_name);
+       dummy_aux2 = TRUE;
+     }
+   if (aux2)
+     {
+       guint left_col = c;
+       if (span_multi_columns)
+         c += 6 * gmask->column;
+       gtk_table_attach (table, aux2,
+                         left_col, c + 1,
+                         row, row + 1, GTK_EXPAND | GTK_FILL, GtkAttachOptions (0), 0, 0);
+       if (dummy_aux2)
+         aux2 = NULL;
+       if (aux2)
+         gtk_table_set_col_spacing (table, c, 3); /* aux2 spacing */
+     }
+   c++;
+   if (aux3)
+     {
+       gtk_table_attach (table, aux3, c, c + 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0);
+       gtk_table_set_col_spacing (table, c, 3); /* aux3 spacing */
+     }
+   c++;
+   n = c;
+   if (gmask->gpack == BST_GMASK_BIG || gmask->gpack == BST_GMASK_CENTER ||
+       gmask->gpack == BST_GMASK_INTERLEAVE)     /* extend action to the left when possible */
+     {
+       if (!aux3)
+         {
+           n--;
+           if (!aux2)
+             {
+               n--;
+               if (!aux1 && (gmask->gpack == BST_GMASK_BIG ||
+                             gmask->gpack == BST_GMASK_CENTER))
+                 {
+                   n--;
+                   if (!prompt)
+                     n--;
+                 }
+             }
+         }
+     }
+   if (gmask->gpack == BST_GMASK_FIT ||
+       gmask->gpack == BST_GMASK_INTERLEAVE) /* align to right without expansion */
+     action = gtk_widget_new (GTK_TYPE_ALIGNMENT,
+                              "visible", TRUE,
+                              "child", action,
+                              "xalign", 1.0,
+                              "xscale", 0.0,
+                              "yscale", 0.0,
+                              NULL);
+   else if (gmask->gpack == BST_GMASK_CENTER)
+     action = gtk_widget_new (GTK_TYPE_ALIGNMENT,
+                              "visible", TRUE,
+                              "child", action,
+                              "xalign", 0.5,
+                              "yalign", 0.5,
+                              "xscale", 0.0,
+                              "yscale", 0.0,
+                              NULL);
+   gtk_table_attach (table, action,
+                     n, c + 1, row, row + 1,
+                     GTK_SHRINK | GTK_FILL,
+                     GTK_FILL,
+                     0, 0);
+   gtk_table_set_col_spacing (table, c - 1, 3); /* seperate action from rest */
+   c = 6 * gmask->column;
+   if (c)
+     gtk_table_set_col_spacing (table, c - 1, 5); /* spacing between gmask columns */
+ }
+ 
+ /**
+  * @param gmask_container container created with bst_gmask_container_create()
+  * @param column        column number for bst_gmask_set_column()
+  * @param prompt        valid GtkWidget for bst_gmask_set_prompt()
+  * @param action        valid GtkWidget as with bst_gmask_form()
+  * @param tip_text      text for bst_gmask_set_tip()
+  * @return              an already packed GUI field mask
+  *
+  * Shorthand to form a GUI field mask in @a column of type BST_GMASK_INTERLEAVE,
+  * with @a prompt and @a tip_text. Note that this function already calls
+  * bst_gmask_pack(), so the returned field mask already can't be modified
+  * anymore.
+  */
+ BstGMask*
+ bst_gmask_quick (GtkWidget   *gmask_container,
+                  guint        column,
+                  const gchar *prompt,
+                  gpointer     action,
+                  const gchar *tip_text)
+ {
+   BstGMask *mask = bst_gmask_form (gmask_container, (GtkWidget*) action, BST_GMASK_INTERLEAVE);
+ 
+   if (prompt)
+     bst_gmask_set_prompt (mask, g_object_new (GTK_TYPE_LABEL,
+                                               "visible", TRUE,
+                                               "label", prompt,
+                                               NULL));
+   if (tip_text)
+     bst_gmask_set_tip (mask, tip_text);
+   bst_gmask_set_column (mask, column);
+   bst_gmask_pack (mask);
+ 
+   return mask;
+ }
+ 
+ 
+ /* --- named children --- */
+ static GQuark quark_container_named_children = 0;
+ typedef struct {
+   GData *qdata;
+ } NChildren;
+ static void
+ nchildren_free (gpointer data)
+ {
+   NChildren *children = (NChildren*) data;
+ 
+   g_datalist_clear (&children->qdata);
+   g_free (children);
+ }
+ static void
+ destroy_nchildren (GtkWidget *container)
+ {
+   g_object_set_qdata (G_OBJECT (container), quark_container_named_children, NULL);
+ }
+ void
+ bst_container_set_named_child (GtkWidget *container,
+                                GQuark     qname,
+                                GtkWidget *child)
+ {
+   NChildren *children;
+ 
+   g_return_if_fail (GTK_IS_CONTAINER (container));
+   g_return_if_fail (qname > 0);
+   g_return_if_fail (GTK_IS_WIDGET (child));
+   if (child)
+     g_return_if_fail (gtk_widget_is_ancestor (child, container));
+ 
+   if (!quark_container_named_children)
+     quark_container_named_children = g_quark_from_static_string ("BstContainer-named_children");
+ 
+   children = (NChildren*) g_object_get_qdata (G_OBJECT (container), quark_container_named_children);
+   if (!children)
+     {
+       children = g_new (NChildren, 1);
+       g_datalist_init (&children->qdata);
+       g_object_set_qdata_full (G_OBJECT (container), quark_container_named_children, children, 
nchildren_free);
+       g_object_connect (container,
+                         "signal::destroy", destroy_nchildren, NULL,
+                         NULL);
+     }
+   g_object_ref (child);
+   g_datalist_id_set_data_full (&children->qdata, qname, child, g_object_unref);
+ }
+ 
+ GtkWidget*
+ bst_container_get_named_child (GtkWidget *container,
+                                GQuark     qname)
+ {
+   NChildren *children;
+ 
+   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
+   g_return_val_if_fail (qname > 0, NULL);
+ 
+   children = quark_container_named_children ? (NChildren*) g_object_get_qdata (G_OBJECT (container), 
quark_container_named_children) : NULL;
+   if (children)
+     {
+       GtkWidget *child = (GtkWidget*) g_datalist_id_get_data (&children->qdata, qname);
+ 
+       if (child && !gtk_widget_is_ancestor (child, container))
+         {
+           /* got removed meanwhile */
+           g_datalist_id_set_data (&children->qdata, qname, NULL);
+           child = NULL;
+         }
+       return child;
+     }
+   return NULL;
+ }
+ 
+ GtkWidget*
+ bst_xpm_view_create (const gchar **xpm,
+                      GtkWidget    *colormap_widget)
+ {
+   GtkWidget *pix;
+   GdkPixmap *pixmap;
+   GdkBitmap *mask;
+ 
+   g_return_val_if_fail (xpm != NULL, NULL);
+   g_return_val_if_fail (GTK_IS_WIDGET (colormap_widget), NULL);
+ 
+   pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, gtk_widget_get_colormap (colormap_widget),
+                                                   &mask, NULL, (gchar**) xpm);
+   pix = gtk_pixmap_new (pixmap, mask);
+   gdk_pixmap_unref (pixmap);
+   gdk_pixmap_unref (mask);
+   gtk_widget_set (pix,
+                   "visible", TRUE,
+                   NULL);
+   return pix;
+ }
+ 
+ 
+ /* --- misc utils --- */
+ gint
+ bst_fft_size_to_int (BstFFTSize fft_size)
+ {
+   switch (fft_size)
+     {
+ #if 0
+     case BST_FFT_SIZE_1:          return 1;
+ #endif
+     case BST_FFT_SIZE_2:          return 2;
+     case BST_FFT_SIZE_4:          return 4;
+     case BST_FFT_SIZE_8:          return 8;
+     case BST_FFT_SIZE_16:         return 16;
+     case BST_FFT_SIZE_32:         return 32;
+     case BST_FFT_SIZE_64:         return 64;
+     case BST_FFT_SIZE_128:        return 128;
+     case BST_FFT_SIZE_256:        return 256;
+     case BST_FFT_SIZE_512:        return 512;
+     case BST_FFT_SIZE_1024:       return 1024;
+     case BST_FFT_SIZE_2048:       return 2048;
+     case BST_FFT_SIZE_4096:       return 4096;
+     case BST_FFT_SIZE_8192:       return 8192;
+     case BST_FFT_SIZE_16384:      return 16384;
+     case BST_FFT_SIZE_32768:      return 32768;
+     case BST_FFT_SIZE_65536:      return 65536;
+ #if 0
+     case BST_FFT_SIZE_131072:     return 131072;
+     case BST_FFT_SIZE_262144:     return 262144;
+     case BST_FFT_SIZE_524288:     return 524288;
+     case BST_FFT_SIZE_1048576:    return 1048576;
+     case BST_FFT_SIZE_2097152:    return 2097152;
+     case BST_FFT_SIZE_4194304:    return 4194304;
+     case BST_FFT_SIZE_8388608:    return 8388608;
+     case BST_FFT_SIZE_16777216:   return 16777216;
+     case BST_FFT_SIZE_33554432:   return 33554432;
+     case BST_FFT_SIZE_67108864:   return 67108864;
+     case BST_FFT_SIZE_134217728:  return 134217728;
+     case BST_FFT_SIZE_268435456:  return 268435456;
+     case BST_FFT_SIZE_536870912:  return 536870912;
+     case BST_FFT_SIZE_1073741824: return 1073741824;
+     case BST_FFT_SIZE_2147483648: return 2147483648;
+     case BST_FFT_SIZE_4294967296: return 4294967296;
+ #endif
+     default:                      return 0;
+     }
+ }
+ 
+ BstFFTSize
+ bst_fft_size_from_int (guint sz)
+ {
+   const struct { BstFFTSize fft_size; guint sz; } sizes[] = {
+ #if 0
+     { BST_FFT_SIZE_1, 1 },
+ #endif
+     { BST_FFT_SIZE_2, 2 },
+     { BST_FFT_SIZE_4, 4 },
+     { BST_FFT_SIZE_8, 8 },
+     { BST_FFT_SIZE_16,    16 },
+     { BST_FFT_SIZE_32,    32 },
+     { BST_FFT_SIZE_64,    64 },
+     { BST_FFT_SIZE_128,   128 },
+     { BST_FFT_SIZE_256,   256 },
+     { BST_FFT_SIZE_512,   512 },
+     { BST_FFT_SIZE_1024,  1024 },
+     { BST_FFT_SIZE_2048,  2048 },
+     { BST_FFT_SIZE_4096,  4096 },
+     { BST_FFT_SIZE_8192,  8192 },
+     { BST_FFT_SIZE_16384, 16384 },
+     { BST_FFT_SIZE_32768, 32768 },
+     { BST_FFT_SIZE_65536, 65536 },
+ #if 0
+     { BST_FFT_SIZE_131072,     131072 },
+     { BST_FFT_SIZE_262144,     262144 },
+     { BST_FFT_SIZE_524288,     524288 },
+     { BST_FFT_SIZE_1048576,    1048576 },
+     { BST_FFT_SIZE_2097152,    2097152 },
+     { BST_FFT_SIZE_4194304,    4194304 },
+     { BST_FFT_SIZE_8388608,    8388608 },
+     { BST_FFT_SIZE_16777216,   16777216 },
+     { BST_FFT_SIZE_33554432,   33554432 },
+     { BST_FFT_SIZE_67108864,   67108864 },
+     { BST_FFT_SIZE_134217728,  134217728 },
+     { BST_FFT_SIZE_268435456,  268435456 },
+     { BST_FFT_SIZE_536870912,  536870912 },
+     { BST_FFT_SIZE_1073741824, 1073741824 },
+     { BST_FFT_SIZE_2147483648, 2147483648 },
+     { BST_FFT_SIZE_4294967296, 4294967296 },
+ #endif
+   };
+   /* find size via bisection */
+   guint offset = 0, n = G_N_ELEMENTS (sizes);
+   while (offset + 1 < n)
+     {
+       guint i = (offset + n) >> 1;
+       if (sz < sizes[i].sz)
+         n = i;
+       else
+         offset = i;
+     }
+   return sizes[offset].fft_size;
+ }
+ 
+ #include <sfi/sfistore.hh>
+ 
+ gchar*
+ bst_file_scan_find_key (const gchar *file,
+                         const gchar *key,
+                         const gchar *value_prefix)
+ {
+   SfiRStore *rstore;
+ 
+   g_return_val_if_fail (file != NULL, NULL);
+ 
+   rstore = sfi_rstore_new_open (file);
+   if (rstore)
+     {
+       guint l = value_prefix ? strlen (value_prefix) : 0;
+       gchar *name = NULL;
+       while (!g_scanner_eof (rstore->scanner))
+         {
+           if (g_scanner_get_next_token (rstore->scanner) == '(' &&
+               g_scanner_peek_next_token (rstore->scanner) == G_TOKEN_IDENTIFIER)
+             {
+               g_scanner_get_next_token (rstore->scanner);
+               if (strcmp (rstore->scanner->value.v_identifier, key) == 0 &&
+                   g_scanner_peek_next_token (rstore->scanner) == G_TOKEN_STRING)
+                 {
+                   g_scanner_get_next_token (rstore->scanner);
+                   if (!l || strncmp (rstore->scanner->value.v_string, value_prefix, l) == 0)
+                     {
+                       name = g_strdup (rstore->scanner->value.v_string + l);
+                       break;
+                     }
+                 }
+             }
+         }
+       sfi_rstore_destroy (rstore);
+       return name;
+     }
+   else
+     return NULL;
+ }
+ 
+ 
+ /* --- generated marshallers --- */
+ #include "bstmarshal.cc"
+ 
+ 
+ /* --- IDL pspecs --- */
+ #define sfidl_pspec_Bool(group, name, nick, blurb, dflt, hints) \
+   sfi_pspec_set_group (sfi_pspec_bool (name, nick, blurb, dflt, hints), group)
+ #define sfidl_pspec_Bool_default(group, name) \
+   sfi_pspec_set_group (sfi_pspec_bool (name, NULL, NULL, FALSE, SFI_PARAM_STANDARD), group)
+ #define sfidl_pspec_Int(group, name, nick, blurb, dflt, min, max, step, hints) \
+   sfi_pspec_set_group (sfi_pspec_int (name, nick, blurb, dflt, min, max, step, hints), group)
+ #define sfidl_pspec_Int_default(group, name) \
+   sfi_pspec_set_group (sfi_pspec_int (name, NULL, NULL, 0, G_MININT, G_MAXINT, 256, SFI_PARAM_STANDARD), 
group)
+ #define sfidl_pspec_UInt(group, name, nick, blurb, dflt, hints) \
+   sfi_pspec_set_group (sfi_pspec_int (name, nick, blurb, dflt, 0, G_MAXINT, 1, hints), group)
+ #define sfidl_pspec_Real(group, name, nick, blurb, dflt, min, max, step, hints) \
+   sfi_pspec_set_group (sfi_pspec_real (name, nick, blurb, dflt, min, max, step, hints), group)
+ #define sfidl_pspec_Real_default(group, name) \
+   sfi_pspec_set_group (sfi_pspec_real (name, NULL, NULL, 0, -SFI_MAXREAL, SFI_MAXREAL, 10, 
SFI_PARAM_STANDARD), group)
+ #define sfidl_pspec_Note(group, name, nick, blurb, dflt, hints) \
+   sfi_pspec_set_group (sfi_pspec_note (name, nick, blurb, dflt, hints), group)
+ #define sfidl_pspec_Choice(group, name, nick, blurb, dval, options, cvalues) \
+   sfi_pspec_set_group (sfi_pspec_choice (name, nick, blurb, dval, cvalues, SFI_PARAM_STANDARD), group)
+ #define sfidl_pspec_Choice_default(group, name, cvalues) \
+   sfidl_pspec_Choice (group, name, NULL, NULL, NULL, SFI_PARAM_STANDARD, cvalues)
+ #define sfidl_pspec_String(group, name, nick, blurb, dflt, options) \
+   sfi_pspec_set_group (sfi_pspec_string (name, nick, blurb, dflt, options), group)
+ #define sfidl_pspec_String_default(group, name) \
+   sfidl_pspec_String (group, name, NULL, NULL, NULL, SFI_PARAM_STANDARD)
+ #define sfidl_pspec_BBlock(group, name, nick, blurb, options) \
+   sfi_pspec_set_group (sfi_pspec_bblock (name, nick, blurb, options), group)
+ #define sfidl_pspec_BBlock_default(group, name) \
+   sfidl_pspec_BBlock (group, name, NULL, NULL, SFI_PARAM_STANDARD)
+ #define sfidl_pspec_FBlock(group, name, nick, blurb, options) \
+   sfi_pspec_set_group (sfi_pspec_fblock (name, nick, blurb, options), group)
+ #define sfidl_pspec_FBlock_default(group, name) \
+   sfidl_pspec_FBlock (group, name, NULL, NULL, SFI_PARAM_STANDARD)
+ #define sfidl_pspec_Rec(group, name, nick, blurb, options) \
+   sfi_pspec_set_group (sfi_pspec_rec_generic (name, nick, blurb, options), group)
+ #define sfidl_pspec_Rec_default(group, name, fields) \
+   sfidl_pspec_Rec (group, name, NULL, NULL, SFI_PARAM_STANDARD)
+ #define sfidl_pspec_Record(group, name, nick, blurb, options, fields) \
+   sfi_pspec_set_group (sfi_pspec_rec (name, nick, blurb, fields, options), group)
+ #define sfidl_pspec_Record_default(group, name, fields) \
+   sfidl_pspec_Record (group, name, NULL, NULL, SFI_PARAM_STANDARD, fields)
+ #define sfidl_pspec_Sequence(group, name, nick, blurb, options, element) \
+   sfi_pspec_set_group (sfi_pspec_seq (name, nick, blurb, element, options), group)
+ #define sfidl_pspec_Sequence_default(group, name, element) \
+   sfidl_pspec_Sequence (group, name, NULL, NULL, SFI_PARAM_STANDARD, element)
+ #define sfidl_pspec_Proxy_default(group, name) \
+   sfi_pspec_set_group (sfi_pspec_proxy (name, NULL, NULL, SFI_PARAM_STANDARD), group)
+ /* --- generated type IDs and SFIDL types --- */
+ #include "bstgentypes.cc"       /* type id defs */
+ 
+ // == mouse button checks ==
+ static bool
+ shift_event (GdkEvent *event)
+ {
+   return (event->button.state & GDK_SHIFT_MASK) != 0;
+ }
+ 
+ static bool
+ alt_event (GdkEvent *event)
+ {
+   return (event->button.state & GDK_MOD1_MASK) != 0;
+ }
+ 
+ static bool
+ button_event (GdkEvent *event)
+ {
+   return event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE;
+ }
+ 
+ bool
+ bst_mouse_button_activate (GdkEvent *event)
+ {
+   return button_event (event) && event->button.button == 1;
+ }
+ 
+ bool
+ bst_mouse_button_activate1 (GdkEvent *event)
+ {
+   return !shift_event (event) && button_event (event) && event->button.button == 1;
+ }
+ 
+ bool
+ bst_mouse_button_activate2 (GdkEvent *event)
+ {
+   return shift_event (event) && button_event (event) && event->button.button == 1;
+ }
+ 
+ bool
+ bst_mouse_button_move (GdkEvent *event)
+ {
+   return button_event (event) && (event->button.button == 2 ||
+                                   (alt_event (event) && event->button.button == 1));
+ }
+ 
+ bool
+ bst_mouse_button_context (GdkEvent *event)
+ {
+   return button_event (event) && event->button.button == 3;
+ }
diff --cc bse/Makefile.am
index f562cf9,cda233c..0d16dbb
--- a/bse/Makefile.am
+++ b/bse/Makefile.am
@@@ -30,73 -26,74 +26,77 @@@ bse_public_headers = $(strip 
        \
        bsegentypes.h \
        \
-       bse.h   bsedefs.h       bseexports.h    bseconfig.h     bsegenclosures.h \
-       bseincluder.h   ladspa.h        bseenginenode.h bseieee754.h \
-       \
-       bseengine.h             bseenginemaster.h       bseengineschedule.h             bseengineutils.h \
-       bsebus.h                bsecategories.h         \
-       bsefilter.h             bsebiquadfilter.h       \
-       bseconstant.h           bseconstvalues.h        bsecontainer.h                  bsecontextmerger.h \
-       bsedatapocket.h         bseeditablesample.h     bseenums.h                      bsegconfig.h \
-       bseglobals.h            bseglue.h               bseitem.h                       bsejanitor.h \
-       bsemain.h               bsemath.h               bsemathsignal.h                 bseladspa.h \
-       bsemidicontroller.h     bsemididevice.h         bsedevice.h                     \
-       bsemididevice-null.h    bsemididevice-oss.h     bsemidievent.h                  bsemidinotifier.h \
-       bsemidireceiver.h       bsemidisynth.h          bseobject.h                     bsepart.h \
-       bsepcminput.h           bsepcmoutput.h          bseparam.h                      bseparasite.h \
-       bsepcmdevice.h          bsepcmdevice-oss.h      bsepcmdevice-null.h             bseplugin.h \
-       bseprocedure.h          bseproject.h            bsescripthelper.h               bseserver.h \
-       bsesnet.h               bsesnooper.h            bsesong.h                       bsesequencer.h \
-       bsesource.h             bsestandardosc.h        bsestandardsynths.h             bsestorage.h \
-       bseinstrumentoutput.h   bsesubiport.h           bseinstrumentinput.h            bsesuboport.h \
-       bsesubsynth.h           bsesuper.h              bsetrack.h                      bsetype.h \
-       bseutils.h              bsemidivoice.h          bsewave.h                       bsewaveosc.h \
-       bsecsynth.h             bsewaverepo.h           bseladspamodule.h               bsepcmwriter.h \
-       bsecompat.h             bseundostack.h          bsemidiinput.h                  bsemididecoder.h \
-       bsenote.h               bsemidifile.h           bseblockutils.hh                \
+       bse.hh  bsedefs.hh      bseexports.hh   bseconfig.h     bsegenclosures.hh \
+       bseincluder.hh  ladspa.hh       bseenginenode.hh bseieee754.hh \
+       bsecore.hh              \
+       bseengine.hh            bseenginemaster.hh      bseengineschedule.hh            bseengineutils.hh \
+       bsebus.hh               bsecategories.hh        \
+       bsefilter.hh                    bsebiquadfilter.hh      \
+       bseconstant.hh          bseconstvalues.hh       bsecontainer.hh                 bsecontextmerger.hh \
+       bseclientapi.hh         \
+       bsedatapocket.hh                bseeditablesample.hh    bseenums.hh                     bsegconfig.hh 
\
+       bseglobals.hh           bseglue.hh              bseitem.hh                      bsejanitor.hh \
+       bsemain.hh              bsemath.hh              bsemathsignal.hh                        bseladspa.hh \
+       bsemidicontroller.hh    bsemididevice.hh                bsedevice.hh                    \
+       bsemididevice-null.hh   bsemididevice-oss.hh    bsemidievent.hh                 bsemidinotifier.hh \
+       bsemidireceiver.hh      bsemidisynth.hh         bseobject.hh                    bsepart.hh \
+       bsepcminput.hh          bsepcmoutput.hh         bseparam.hh                     bseparasite.hh \
+       bsepcmdevice.hh         bsepcmdevice-oss.hh     bsepcmdevice-null.hh            bseplugin.hh \
+       bseprocedure.hh         bseproject.hh           bsescripthelper.hh              bseserver.hh \
+       bsesnet.hh              bsesnooper.hh           bsesong.hh                      bsesequencer.hh \
+       bsesource.hh            bsestandardosc.hh       bsestandardsynths.hh            bsestorage.hh \
+       bseinstrumentoutput.hh  bsesubiport.hh          bseinstrumentinput.hh           bsesuboport.hh \
++        bsesoundfont.h          bsesoundfontpreset.h    bsesoundfontosc.h               \
+       bsesubsynth.hh          bsesuper.hh             bsetrack.hh                     bsetype.hh \
+       bseutils.hh             bsemidivoice.hh         bsewave.hh                      bsewaveosc.hh \
+       bsecsynth.hh            bsewaverepo.hh          bseladspamodule.hh              bsepcmwriter.hh \
+       bsecompat.hh            bseundostack.hh         bsemidiinput.hh                 bsemididecoder.hh \
+       bsenote.hh              bsemidifile.hh          bseblockutils.hh                \
        bsecxxvalue.hh          bsecxxutils.hh          bsecxxbase.hh                   bsecxxclosure.hh \
-       bsecxxarg.hh            bsecxxmodule.hh         bsecxxplugin.hh                 bseloader.h \
-       bseresampler.hh         bseresamplerimpl.hh     bsesoundfontrepo.h              bsesoundfont.h  \
-       bsesoundfontpreset.h    bsesoundfontosc.h       \
+       bsecxxarg.hh            bsecxxmodule.hh         bsecxxplugin.hh                 bseloader.hh \
+       bseresampler.hh         bseresamplerimpl.hh     bsedatahandle-flac.hh           \
+       testobject.hh           \
  )
  # BSE C & C++ sources
  bse_sources = $(strip \
-       gslfft.c                gsloscillator.c gsldatahandle.c gslwavechunk.c \
-       gslfilter.c             gslcommon.c \
-       gsldatahandle-vorbis.c  gslvorbis-enc.c gsldatacache.c  gslvorbis-cutter.c \
-       gsldatahandle-mad.c                     gslfilehash.c   gsldatautils.c  \
-       gslwaveosc.c            gslosctable.c   gslmagic.c      \
-       \
-       bseengine.c             bseenginemaster.c       bseengineschedule.c             bseengineutils.c \
-       bsebus.c                bsecategories.c         \
-       bsefilter.cc            bsebiquadfilter.c       bsefilter-ellf.c        \
-       bseconstant.c           bseconstvalues.c        bsecontainer.c                  bsecontextmerger.c \
-       bsedatapocket.c         bseeditablesample.c     bseenums.c                      bsegconfig.c \
-       bseglobals.c            bseglue.c               bseitem.c                       bsejanitor.c \
-       bsemain.cc              bsemath.c               bsemathsignal.c                 bseladspa.cc \
-       bsemidicontroller.c     bsemididevice.c         bsedevice.c                     \
-       bsemididevice-null.c    bsemididevice-oss.c     bsemidievent.c                  bsemidinotifier.c \
-       bsemidireceiver.cc      bsemidisynth.c          bseobject.c                     bsepart.c \
-       bsepcminput.c           bsepcmoutput.c          bseparam.c                      bseparasite.c \
-       bsepcmdevice.c          bsepcmdevice-oss.c      bsepcmdevice-null.c             bseplugin.c \
-       bseprocedure.c          bseproject.c            bsescripthelper.c               bseserver.c \
-       bsesnet.c               bsesnooper.c            bsesong.c                       bsesequencer.cc \
-       bsesource.c             bsestandardosc.c        bsestandardsynths.c             bsestorage.c \
-       bseinstrumentoutput.c   bsesubiport.c           bseinstrumentinput.c            bsesuboport.c \
-       bsesubsynth.c           bsesuper.c              bsetrack.c                      bsetype.c \
-       bseutils.c              bsemidivoice.c          bsewave.c                       bsewaveosc.c \
-       bsecsynth.c             bsewaverepo.c           bseladspamodule.c               bsepcmwriter.c \
-       bsecompat.c             bseundostack.c          bsemidiinput.c                  bsemididecoder.c \
-       bsenote.cc              bsemidifile.c           bseblockutils.cc                \
+       gslfft.cc               gsloscillator.cc        gsldatahandle.cc        gslwavechunk.cc \
+       gslfilter.cc            gslcommon.cc \
+       gsldatahandle-vorbis.cc gslvorbis-enc.cc        gsldatacache.cc gslvorbis-cutter.cc \
+       gsldatahandle-mad.cc                    gslfilehash.cc  gsldatautils.cc \
+       gslwaveosc.cc           gslosctable.cc  gslmagic.cc                      \
+       bsecore.cc              \
+       bseengine.cc            bseenginemaster.cc      bseengineschedule.cc            bseengineutils.cc \
+       bsebus.cc               bsecategories.cc        \
+       bsefilter.cc            bsebiquadfilter.cc      bsefilter-ellf.cc       \
+       bseconstant.cc          bseconstvalues.cc       bsecontainer.cc                 bsecontextmerger.cc \
+       bsedatapocket.cc        bseeditablesample.cc    bseenums.cc                     bsegconfig.cc \
+       bseglobals.cc           bseglue.cc              bseitem.cc                      bsejanitor.cc \
+       bsemain.cc              bsemath.cc              bsemathsignal.cc                bseladspa.cc \
+       bsemidicontroller.cc    bsemididevice.cc        bsedevice.cc                    \
+       bsemididevice-null.cc   bsemididevice-oss.cc    bsemidievent.cc                 bsemidinotifier.cc \
+       bsemidireceiver.cc      bsemidisynth.cc         bseobject.cc                    bsepart.cc \
+       bsepcminput.cc          bsepcmoutput.cc         bseparam.cc                     bseparasite.cc \
+       bsepcmdevice.cc         bsepcmdevice-oss.cc     bsepcmdevice-null.cc            bseplugin.cc \
+       bseprocedure.cc         bseproject.cc           bsescripthelper.cc              bseserver.cc \
+       bsesnet.cc              bsesnooper.cc           bsesong.cc                      bsesequencer.cc \
++        bsesoundfont.c          bsesoundfontrepo.c      bsesoundfontpreset.c            bsesoundfontosc.c \
++      bsesoundfontrepo.c      bsesoundfont.c          bsesoundfontpreset.c            bsesoundfontosc.c \
+       bsesource.cc            bsestandardosc.cc       bsestandardsynths.cc            bsestorage.cc \
+       bseinstrumentoutput.cc  bsesubiport.cc          bseinstrumentinput.cc           bsesuboport.cc \
+       bsesubsynth.cc          bsesuper.cc             bsetrack.cc                     bsetype.cc \
+       bseutils.cc             bsemidivoice.cc         bsewave.cc                      bsewaveosc.cc \
+       bsecsynth.cc            bsewaverepo.cc          bseladspamodule.cc              bsepcmwriter.cc \
+       bsecompat.cc            bseundostack.cc         bsemidiinput.cc                 bsemididecoder.cc \
+       bsenote.cc              bsemidifile.cc          bseblockutils.cc                \
        bsecxxvalue.cc          bsecxxutils.cc          bsecxxbase.cc                   bsecxxclosure.cc \
-       bsecxxarg.cc            bsecxxmodule.cc         bsecxxplugin.cc                 bseloader.c \
+       bsecxxarg.cc            bsecxxmodule.cc         bsecxxplugin.cc                 bseloader.cc \
        bseresampler.cc         bsedatahandle-resample.cc                               bsedatahandle-fir.cc \
-       bseloader-aiff.c        bseloader-guspatch.cc   bseloader-oggvorbis.c           bseloader-bsewave.c \
-       bseloader-mad.c         bseloader-wav.c         \
+       bseloader-aiff.cc       bseloader-guspatch.cc   bseloader-oggvorbis.cc          bseloader-bsewave.cc \
+       bseloader-mad.cc        bseloader-wav.cc        bseloader-flac.cc               bsedatahandle-flac.cc 
\
        bsebusmodule.cc         \
-       bsecore.cc              \
+       bsebasics.cc            \
        bseprobe.cc             \
-       bsesoundfontrepo.c      bsesoundfont.c          bsesoundfontpreset.c            bsesoundfontosc.c \
+       testobject.cc           \
  )
  # BSE Synthesis Modules
  bse_idl_sources =
@@@ -118,22 -117,19 +120,20 @@@ bse_proc_sources = $(strip 
        bsejanitor.proc         bsepart.proc            bseparasite.proc        bseprocedure.proc       
bseproject.proc bsescripthelper.proc    \
        bseserver.proc          bsesong.proc            bsebus.proc             bsesource.proc          
bsecsynth.proc  bsesnet.proc            \
        bsetrack.proc           bseitem.proc            bsewave.proc            bsewaveosc.proc         
bsewaverepo.proc                        \
 +      bsesoundfontrepo.proc   \
  )
- bse_proc_gen_sources = $(bse_proc_sources:.proc=.genprc.c)
+ bse_proc_gen_sources = $(bse_proc_sources:.proc=.genprc.cc)
  # non-compile and non-install sources required
  EXTRA_DIST += $(strip \
-       bsecore.idl     bse.idl                                 \
+       bsebasics.idl   bse.idl                                 \
        mktypes.pl      mkcalls.pl      mkcproc.pl              \
-       bseconfig.h.in  bsepcmmodule.c                          \
+       bseconfig.h.in  bsepcmmodule.cc                         \
        bsewave.header                                          \
-       gsl-fftgen.pl   gsl-fftconf.sh  gsloscillator-aux.c     \
-       gslincluder.c   gslwaveosc-aux.c                        \
+       gsl-fftgen.pl   gsl-fftconf.sh  gsloscillator-aux.cc    \
+       gslincluder.hh  gslwaveosc-aux.cc                       \
+       bse-internals.hh                                        \
  )
  
- # -pthread -> -lpthread hack (required for libtool library linkage)
- pthread_2_lpthread = $(if $(findstring -pthread, $1), -lpthread)
- 
  #
  # BSE library
  #
diff --cc bse/bsedefs.hh
index 0000000,634e5df..f1f962e
mode 000000,100644..100644
--- a/bse/bsedefs.hh
+++ b/bse/bsedefs.hh
@@@ -1,0 -1,140 +1,146 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #ifndef __BSE_DEFS_H__
+ #define __BSE_DEFS_H__
+ 
+ #undef   G_DISABLE_ASSERT
+ #undef   G_DISABLE_CHECKS
+ #include <libintl.h>
+ #include <sfi/sfi.hh>
+ #include <sfi/sfistore.hh>    // FIXME
+ #include <sfi/sficomwire.hh>  // FIXME
+ #include <bse/bseconfig.h>
+ 
+ G_BEGIN_DECLS
+ 
+ 
+ /* --- some globally used macros --- */
+ #define BSE_VERSION_CMP(v1_major, v1_minor, v1_micro, v2_major, v2_minor, v2_micro) ( \
+                                     (v1_major != v2_major) ? (v1_major > v2_major ? +1 : -1) : \
+                                     (v1_minor != v2_minor) ? (v1_minor > v2_minor ? +1 : -1) : \
+                                     (v1_micro < v2_micro ? -1 : v1_micro > v2_micro))
+ 
+ 
+ /* --- BSE objects, classes & interfaces --- */
+ typedef struct  _BseBinData                BseBinData;
+ typedef struct  _BseBinDataClass           BseBinDataClass;
+ struct BseBus;
+ struct BseBusClass;
+ typedef struct  _BseCapture                BseCapture;
+ typedef struct  _BseCaptureClass           BseCaptureClass;
+ struct BseContainer;
+ struct BseContainerClass;
+ struct BseContextMerger;
+ struct BseContextMergerClass;
+ struct BseCSynth;
+ struct BseCSynthClass;
+ struct BseEditableSample;
+ struct BseEditableSampleClass;
+ struct BseItem;
+ struct BseItemClass;
+ struct BseJanitor;
+ struct BseJanitorClass;
+ struct BseMidiDecoder;
+ struct BseMidiNotifier;
+ struct BseMidiNotifierClass;
+ struct BseMidiReceiver;
+ struct BseMidiSynth;
+ struct BseMidiSynthClass;
+ struct BseMidiContext;
+ struct BseObject;
+ struct BseObjectClass;
+ struct BseParasite;
+ struct BsePart;
+ struct BsePartClass;
+ struct BsePcmWriter;
+ struct BsePcmWriterClass;
+ typedef struct  _BseProcedureClass         BseProcedureClass;
+ struct BseProject;
+ struct BseProjectClass;
+ typedef struct  _BseScriptControl          BseScriptControl;
+ typedef struct  _BseScriptControlClass     BseScriptControlClass;
+ struct BseServer;
+ struct BseServerClass;
+ struct BseSNet;
+ struct BseSNetClass;
+ struct BseSong;
+ struct BseSongClass;
+ typedef struct  _BseSongSequencer          BseSongSequencer;
++typedef struct  _BseSoundFont              BseSoundFont;
++typedef struct  _BseSoundFontClass         BseSoundFontClass;
++typedef struct  _BseSoundFontPreset        BseSoundFontPreset;
++typedef struct  _BseSoundFontPresetClass   BseSoundFontPresetClass;
++typedef struct  _BseSoundFontRepo          BseSoundFontRepo;
++typedef struct  _BseSoundFontRepoClass     BseSoundFontRepoClass;
+ struct BseSource;
+ struct BseSourceClass;
+ struct BseStorage;
+ struct BseStorageClass;
+ struct BseSubSynth;
+ struct BseSubSynthClass;
+ struct BseSuper;
+ struct BseSuperClass;
+ struct BseTrack;
+ struct BseTrackClass;
+ typedef struct  _BseTrans                  BseTrans;
+ typedef struct  _BseUndoStack            BseUndoStack;
+ typedef struct  _BseUndoStep               BseUndoStep;
+ typedef struct  _BseVirtualThroughput      BseVirtualThroughput;
+ typedef struct  _BseVirtualThroughputClass BseVirtualThroughputClass;
+ typedef struct  _BseVoice                BseVoice;
+ struct BseWave;
+ struct BseWaveRepo;
+ struct BseWaveRepoClass;
+ /* --- BseModule special handling --- */
+ typedef struct _BseModule                  BseModule;
+ typedef struct _BseModuleClass             BseModuleClass;
+ typedef struct _BseIStream                 BseIStream;
+ typedef struct _BseJStream                 BseJStream;
+ typedef struct _BseOStream                 BseOStream;
+ /* dereference some BseModule members without including bseengine.hh */
+ #define       BSE_MODULE_GET_USER_DATA(bsemodule)     (((gpointer*) bsemodule)[1])
+ #define       BSE_MODULE_GET_ISTREAMSP(bsemodule)     (((gpointer*) bsemodule)[2])
+ #define       BSE_MODULE_GET_JSTREAMSP(bsemodule)     (((gpointer*) bsemodule)[3])
+ #define       BSE_MODULE_GET_OSTREAMSP(bsemodule)     (((gpointer*) bsemodule)[4])
+ /* --- Bse Loader --- */
+ struct BseLoader;
+ typedef struct _BseWaveDsc              BseWaveDsc;
+ typedef struct _BseWaveChunkDsc         BseWaveChunkDsc;
+ /* --- BSE aux structures --- */
+ typedef struct  _BseExportNode          BseExportNode;
+ typedef struct  _BseExportNodeBoxed   BseExportNodeBoxed;
+ typedef struct  _BseGlobals             BseGlobals;
+ struct BsePlugin;
+ struct BsePluginClass;
+ /* --- BSE function types --- */
+ typedef void          (*BseFunc)             (void);
+ typedef void          (*BseFreeFunc)         (gpointer           data);
+ typedef gboolean      (*BseIOWatch)        (gpointer           data,
+                                               guint              n_pfds,
+                                             GPollFD           *pfd);
+ typedef GTokenType    (*BseTryStatement)     (gpointer           context_data,
+                                               BseStorage        *storage,
+                                               GScanner          *scanner,
+                                               gpointer           user_data);
+ typedef BseObject*    (*BseUPathResolver)    (gpointer           func_data,
+                                               GType              required_type,
+                                               const gchar       *path,
+                                             gchar            **error);
+ typedef gboolean      (*BseProcedureShare)   (gpointer           func_data,
+                                               const gchar       *proc_name,
+                                               gfloat             progress);
+ typedef gboolean      (*BseCategoryForeach)  (const gchar       *category_path,
+                                               GType              type,
+                                               gpointer           user_data);
+ typedef void          (*BseEngineAccessFunc) (BseModule         *module,
+                                               gpointer           data); 
+ 
+ 
+ 
+ /* --- i18n and gettext helpers --- */
+ const gchar* bse_gettext (const gchar *text);
+ #define _(str)        bse_gettext (str)
+ #define N_(str) (str)
+ 
+ G_END_DECLS
+ 
+ #endif /* __BSE_DEFS_H__ */
diff --cc bse/bsemidireceiver.cc
index e831b2e,b72aa52..5ce7e47
--- a/bse/bsemidireceiver.cc
+++ b/bse/bsemidireceiver.cc
@@@ -1,48 -1,27 +1,29 @@@
- /* BSE - Bedevilled Sound Engine
-  * Copyright (C) 1996-1999, 2000-2004 Tim Janik
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2.1 of the License, or (at your option) any later version.
-  *
-  * This library 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
-  * Lesser General Public License for more details.
-  *
-  * A copy of the GNU Lesser General Public License should ship along
-  * with this library; if not, see http://www.gnu.org/copyleft/.
-  */
- #include "bsemidireceiver.h"
- 
- #include "bsemain.h"
- #include "gslcommon.h"
- #include "bseengine.h"
- #include "bsemathsignal.h"
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #include "bsemidireceiver.hh"
+ 
+ #include "bsemain.hh"
+ #include "gslcommon.hh"
+ #include "bseengine.hh"
+ #include "bsemathsignal.hh"
  #include "bsecxxutils.hh"
- #include "bsemidinotifier.h"
+ #include "bsemidinotifier.hh"
  #include <string.h>
- #include <sfi/gbsearcharray.h>
+ #include <sfi/gbsearcharray.hh>
  #include <map>
  #include <set>
 +#include <list>
 +
  namespace {
  using namespace Bse;
- using namespace Birnet;
  using namespace std;
  
- static SFI_MSG_TYPE_DEFINE (debug_midi_receiver, "midi-receiver", SFI_MSG_DEBUG, NULL);
- #define DEBUG(...)              sfi_debug (debug_midi_receiver, __VA_ARGS__)
- static SFI_MSG_TYPE_DEFINE (debug_midi_events, "midi-events", SFI_MSG_DEBUG, NULL);
- #define DEBUG_EVENTS(...)       sfi_debug (debug_midi_events, __VA_ARGS__)
+ #define MDEBUG(...)     BSE_KEY_DEBUG ("midi-receiver", __VA_ARGS__)
+ #define EDEBUG(...)     BSE_KEY_DEBUG ("midi-events", __VA_ARGS__)
  
  /* --- variables --- */
- static BirnetMutex                         global_midi_mutex = { 0, };
- #define       BSE_MIDI_RECEIVER_LOCK()        GSL_SPIN_LOCK (&global_midi_mutex)
- #define       BSE_MIDI_RECEIVER_UNLOCK()      GSL_SPIN_UNLOCK (&global_midi_mutex)
- 
+ static Bse::Mutex global_midi_mutex;
+ #define       BSE_MIDI_RECEIVER_LOCK()        global_midi_mutex.lock()
+ #define       BSE_MIDI_RECEIVER_UNLOCK()      global_midi_mutex.unlock()
  
  /********************************************************************************
   *
@@@ -2103,85 -1938,79 +2062,85 @@@ midi_receiver_process_event_L (BseMidiR
    if (event->delta_time <= max_tick_stamp)
      {
        BseTrans *trans = bse_trans_open ();
 +      MidiChannel *mchannel = self->peek_channel (event->channel);
        self->events = sfi_ring_remove_node (self->events, self->events);
 -      switch (event->status)
 +
 +      bool event_handled = false;
 +      if (mchannel)
 +      event_handled = mchannel->call_event_handlers (event, trans);
 +
 +      if (!event_handled)
        {
 -          MidiChannel *mchannel;
 -        case BSE_MIDI_NOTE_ON:
 -          mchannel = self->peek_channel (event->channel);
 -        EDEBUG ("MidiChannel[%u]: NoteOn  %fHz Velo=%f (stamp:%llu)", event->channel,
 -                        event->data.note.frequency, event->data.note.velocity, event->delta_time);
 -        if (mchannel)
 -            mchannel->start_note (event->delta_time,
 -                                  event->data.note.frequency,
 -                                  event->data.note.velocity,
 -                                  trans);
 -          else
 -            sfi_diag ("ignoring note-on (%fHz) for foreign midi channel: %u", event->data.note.frequency, 
event->channel);
 -        break;
 -      case BSE_MIDI_KEY_PRESSURE:
 -      case BSE_MIDI_NOTE_OFF:
 -          mchannel = self->peek_channel (event->channel);
 -          EDEBUG ("MidiChannel[%u]: %s %fHz (stamp:%llu)", event->channel,
 -                        event->status == BSE_MIDI_NOTE_OFF ? "NoteOff" : "NotePressure",
 -                        event->data.note.frequency, event->delta_time);
 -          if (mchannel)
 -            {
 -              gboolean sustained_note = event->status == BSE_MIDI_NOTE_OFF &&
 -                                        (BSE_GCONFIG (invert_sustain) ^
 -                                         (self->get_control (event->channel, BSE_MIDI_SIGNAL_CONTROL_64) >= 
0.5));
 -              mchannel->adjust_note (event->delta_time,
 -                                     event->data.note.frequency, event->status,
 -                                     event->data.note.velocity, sustained_note, trans);
 -            }
 -        break;
 -      case BSE_MIDI_CONTROL_CHANGE:
 -        EDEBUG ("MidiChannel[%u]: Control %2u Value=%f (stamp:%llu)", event->channel,
 -                        event->data.control.control, event->data.control.value, event->delta_time);
 -        process_midi_control_L (self, event->channel, event->delta_time,
 -                                event->data.control.control, event->data.control.value,
 -                                FALSE,
 -                                  trans);
 -        break;
 -      case BSE_MIDI_X_CONTINUOUS_CHANGE:
 -        EDEBUG ("MidiChannel[%u]: X Continuous Control %2u Value=%f (stamp:%llu)", event->channel,
 -                        event->data.control.control, event->data.control.value, event->delta_time);
 -        process_midi_control_L (self, event->channel, event->delta_time,
 -                                event->data.control.control, event->data.control.value,
 -                                  TRUE,
 -                                trans);
 -        break;
 -      case BSE_MIDI_PROGRAM_CHANGE:
 -        EDEBUG ("MidiChannel[%u]: Program %u (Value=%f) (stamp:%llu)", event->channel,
 -                        event->data.program, event->data.program / (gfloat) 0x7f, event->delta_time);
 -        update_midi_signal_L (self, event->channel, event->delta_time,
 -                              BSE_MIDI_SIGNAL_PROGRAM, event->data.program / (gfloat) 0x7f,
 -                              trans);
 -        break;
 -      case BSE_MIDI_CHANNEL_PRESSURE:
 -        EDEBUG ("MidiChannel[%u]: Channel Pressure Value=%f (stamp:%llu)", event->channel,
 -                        event->data.intensity, event->delta_time);
 -        update_midi_signal_L (self, event->channel, event->delta_time,
 -                              BSE_MIDI_SIGNAL_PRESSURE, event->data.intensity,
 -                              trans);
 -        break;
 -      case BSE_MIDI_PITCH_BEND:
 -        EDEBUG ("MidiChannel[%u]: Pitch Bend Value=%f (stamp:%llu)", event->channel,
 -                        event->data.pitch_bend, event->delta_time);
 -        update_midi_signal_L (self, event->channel, event->delta_time,
 -                              BSE_MIDI_SIGNAL_PITCH_BEND, event->data.pitch_bend,
 -                              trans);
 -        break;
 -      default:
 -        EDEBUG ("MidiChannel[%u]: Ignoring Event %u (stamp:%llu)", event->channel,
 -                        event->status, event->delta_time);
 -        break;
 +        switch (event->status)
 +          {
 +          case BSE_MIDI_NOTE_ON:
-             DEBUG_EVENTS ("MidiChannel[%u]: NoteOn  %fHz Velo=%f (stamp:%llu)", event->channel,
-                           event->data.note.frequency, event->data.note.velocity, event->delta_time);
++            EDEBUG ("MidiChannel[%u]: NoteOn  %fHz Velo=%f (stamp:%llu)", event->channel,
++                      event->data.note.frequency, event->data.note.velocity, event->delta_time);
 +            if (mchannel)
 +              mchannel->start_note (event->delta_time,
 +                                    event->data.note.frequency,
 +                                    event->data.note.velocity,
 +                                    trans);
 +            else
 +              sfi_diag ("ignoring note-on (%fHz) for foreign midi channel: %u", event->data.note.frequency, 
event->channel);
 +            break;
 +          case BSE_MIDI_KEY_PRESSURE:
 +          case BSE_MIDI_NOTE_OFF:
-             DEBUG_EVENTS ("MidiChannel[%u]: %s %fHz (stamp:%llu)", event->channel,
-                           event->status == BSE_MIDI_NOTE_OFF ? "NoteOff" : "NotePressure",
-                           event->data.note.frequency, event->delta_time);
++            EDEBUG ("MidiChannel[%u]: %s %fHz (stamp:%llu)", event->channel,
++                      event->status == BSE_MIDI_NOTE_OFF ? "NoteOff" : "NotePressure",
++                      event->data.note.frequency, event->delta_time);
 +            if (mchannel)
 +              {
 +                gboolean sustained_note = event->status == BSE_MIDI_NOTE_OFF &&
 +                                          (BSE_GCONFIG (invert_sustain) ^
 +                                           (self->get_control (event->channel, BSE_MIDI_SIGNAL_CONTROL_64) 
= 0.5));
 +                mchannel->adjust_note (event->delta_time,
 +                                       event->data.note.frequency, event->status,
 +                                       event->data.note.velocity, sustained_note, trans);
 +              }
 +            break;
 +          case BSE_MIDI_CONTROL_CHANGE:
-             DEBUG_EVENTS ("MidiChannel[%u]: Control %2u Value=%f (stamp:%llu)", event->channel,
-                           event->data.control.control, event->data.control.value, event->delta_time);
++            EDEBUG ("MidiChannel[%u]: Control %2u Value=%f (stamp:%llu)", event->channel,
++                      event->data.control.control, event->data.control.value, event->delta_time);
 +            process_midi_control_L (self, event->channel, event->delta_time,
 +                                    event->data.control.control, event->data.control.value,
 +                                    FALSE,
 +                                    trans);
 +            break;
 +          case BSE_MIDI_X_CONTINUOUS_CHANGE:
-             DEBUG_EVENTS ("MidiChannel[%u]: X Continuous Control %2u Value=%f (stamp:%llu)", event->channel,
-                           event->data.control.control, event->data.control.value, event->delta_time);
++            EDEBUG ("MidiChannel[%u]: X Continuous Control %2u Value=%f (stamp:%llu)", event->channel,
++                      event->data.control.control, event->data.control.value, event->delta_time);
 +            process_midi_control_L (self, event->channel, event->delta_time,
 +                                    event->data.control.control, event->data.control.value,
 +                                    TRUE,
 +                                    trans);
 +            break;
 +          case BSE_MIDI_PROGRAM_CHANGE:
-             DEBUG_EVENTS ("MidiChannel[%u]: Program %u (Value=%f) (stamp:%llu)", event->channel,
-                           event->data.program, event->data.program / (gfloat) 0x7f, event->delta_time);
++            EDEBUG ("MidiChannel[%u]: Program %u (Value=%f) (stamp:%llu)", event->channel,
++                      event->data.program, event->data.program / (gfloat) 0x7f, event->delta_time);
 +            update_midi_signal_L (self, event->channel, event->delta_time,
 +                                  BSE_MIDI_SIGNAL_PROGRAM, event->data.program / (gfloat) 0x7f,
 +                                  trans);
 +            break;
 +          case BSE_MIDI_CHANNEL_PRESSURE:
-             DEBUG_EVENTS ("MidiChannel[%u]: Channel Pressure Value=%f (stamp:%llu)", event->channel,
-                           event->data.intensity, event->delta_time);
++            EDEBUG ("MidiChannel[%u]: Channel Pressure Value=%f (stamp:%llu)", event->channel,
++                      event->data.intensity, event->delta_time);
 +            update_midi_signal_L (self, event->channel, event->delta_time,
 +                                  BSE_MIDI_SIGNAL_PRESSURE, event->data.intensity,
 +                                  trans);
 +            break;
 +          case BSE_MIDI_PITCH_BEND:
-             DEBUG_EVENTS ("MidiChannel[%u]: Pitch Bend Value=%f (stamp:%llu)", event->channel,
-                           event->data.pitch_bend, event->delta_time);
++            EDEBUG ("MidiChannel[%u]: Pitch Bend Value=%f (stamp:%llu)", event->channel,
++                      event->data.pitch_bend, event->delta_time);
 +            update_midi_signal_L (self, event->channel, event->delta_time,
 +                                  BSE_MIDI_SIGNAL_PITCH_BEND, event->data.pitch_bend,
 +                                  trans);
 +            break;
 +          default:
-             DEBUG_EVENTS ("MidiChannel[%u]: Ignoring Event %u (stamp:%llu)", event->channel,
-                           event->status, event->delta_time);
++            EDEBUG ("MidiChannel[%u]: Ignoring Event %u (stamp:%llu)", event->channel,
++                      event->status, event->delta_time);
 +            break;
 +          }
        }
        if (self->notifier)
        {
diff --cc bse/bsemidireceiver.hh
index 0000000,915de2c..d7a1de6
mode 000000,100644..100644
--- a/bse/bsemidireceiver.hh
+++ b/bse/bsemidireceiver.hh
@@@ -1,0 -1,102 +1,116 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #ifndef __BSE_MIDI_RECEIVER_H__
+ #define __BSE_MIDI_RECEIVER_H__
+ 
+ #include        <bse/bseobject.hh>
+ #include        <bse/bsemidievent.hh>
+ 
+ G_BEGIN_DECLS
+ 
+ 
+ /* --- API --- */
+ #define       BSE_MIDI_CONTROL_MODULE_N_CHANNELS                 (4)
+ #define       BSE_MIDI_VOICE_MODULE_N_CHANNELS                   (4)
+ #define       BSE_MIDI_VOICE_N_CHANNELS                          (3)
+ typedef void   (*BseMidiControlHandler)                    (gpointer           handler_data,
+                                                             guint64            tick_stamp,
+                                                             BseMidiSignalType  signal_type,
+                                                             gfloat             control_value,
+                                                             guint              n_modules,
+                                                             BseModule  *const *modules,
+                                                             gpointer           user_data,
+                                                             BseTrans          *trans);
++typedef void   (*BseMidiEventHandler)                      (gpointer           handler_data,
++                                                          BseModule         *module,
++                                                            const BseMidiEvent *event,
++                                                            BseTrans          *trans);
+ BseMidiReceiver* bse_midi_receiver_new                     (const gchar       *receiver_name);
+ BseMidiReceiver* bse_midi_receiver_ref                     (BseMidiReceiver   *self);
+ void             bse_midi_receiver_unref                   (BseMidiReceiver   *self);
+ void             bse_midi_receiver_push_event              (BseMidiReceiver   *self,
+                                                             BseMidiEvent      *event);
+ void             bse_midi_receiver_process_events          (BseMidiReceiver   *self,
+                                                             guint64            max_tick_stamp);
+ BseModule*       bse_midi_receiver_retrieve_control_module (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             BseMidiSignalType  
signals[BSE_MIDI_CONTROL_MODULE_N_CHANNELS],
+                                                             BseTrans          *trans);
+ void             bse_midi_receiver_discard_control_module  (BseMidiReceiver   *self,
+                                                             BseModule         *cmodule,
+                                                             BseTrans          *trans);
+ gboolean         bse_midi_receiver_add_control_handler     (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             BseMidiSignalType  signal_type,
+                                                             BseMidiControlHandler handler_func,
+                                                             gpointer           handler_data,
+                                                             BseModule         *module);
+ void             bse_midi_receiver_set_control_handler_data(BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             BseMidiSignalType  signal_type,
+                                                             BseMidiControlHandler handler_func,
+                                                             gpointer           handler_data,
+                                                             gpointer           extra_data,
+                                                             BseFreeFunc        extra_free); /* UserThread */
+ void             bse_midi_receiver_remove_control_handler  (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             BseMidiSignalType  signal_type,
+                                                             BseMidiControlHandler handler_func,
+                                                             gpointer           handler_data,
+                                                             BseModule         *module);
++void             bse_midi_receiver_add_event_handler       (BseMidiReceiver   *self,
++                                                            guint              midi_channel,
++                                                            BseMidiEventHandler handler_func,
++                                                            gpointer           handler_data,
++                                                            BseModule         *module);
++void             bse_midi_receiver_remove_event_handler    (BseMidiReceiver   *self,
++                                                            guint              midi_channel,
++                                                            BseMidiEventHandler handler_func,
++                                                            gpointer           handler_data,
++                                                            BseModule         *module);
+ BseModule*       bse_midi_receiver_retrieve_mono_voice     (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             BseTrans          *trans);
+ void             bse_midi_receiver_discard_mono_voice      (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             BseModule         *fmodule,
+                                                             BseTrans          *trans);
+ void             bse_midi_receiver_channel_enable_poly     (BseMidiReceiver   *self,
+                                                             guint              midi_channel);
+ void             bse_midi_receiver_channel_disable_poly    (BseMidiReceiver   *self,
+                                                             guint              midi_channel);
+ guint            bse_midi_receiver_create_poly_voice       (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             BseTrans          *trans);
+ void             bse_midi_receiver_discard_poly_voice      (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             guint              voice_id,
+                                                             BseTrans          *trans);
+ BseModule*       bse_midi_receiver_get_poly_voice_input    (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             guint              voice_id);
+ BseModule*       bse_midi_receiver_get_poly_voice_output   (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             guint              voice_id);
+ BseModule*       bse_midi_receiver_create_sub_voice        (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             guint              voice_id,
+                                                             BseTrans          *trans);
+ void             bse_midi_receiver_discard_sub_voice       (BseMidiReceiver   *self,
+                                                             guint              midi_channel,
+                                                             guint              voice_id,
+                                                             BseModule         *fmodule,
+                                                             BseTrans          *trans);
+ void             bse_midi_receiver_set_notifier            (BseMidiReceiver   *self,
+                                                             BseMidiNotifier   *notifier);
+ gboolean         bse_midi_receiver_has_notify_events       (BseMidiReceiver   *self);
+ SfiRing*         bse_midi_receiver_fetch_notify_events     (BseMidiReceiver   *self);
+ gboolean         bse_midi_receiver_voices_pending          (BseMidiReceiver   *self,
+                                                             guint              midi_channel);
+ void             bse_midi_receiver_enter_farm              (BseMidiReceiver   *self);
+ void             bse_midi_receiver_farm_distribute_event   (BseMidiEvent      *event);
+ void             bse_midi_receiver_farm_process_events     (guint64            max_tick_stamp);
+ void             bse_midi_receiver_leave_farm              (BseMidiReceiver   *self);
+ 
+ G_END_DECLS
+ 
+ #endif /* __BSE_MIDI_RECEIVER_H__ */
diff --cc bse/bseproject.cc
index 0000000,e278a35..039c21b
mode 000000,100644..100644
--- a/bse/bseproject.cc
+++ b/bse/bseproject.cc
@@@ -1,0 -1,965 +1,990 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #include "bseproject.hh"
+ 
+ #include "bsesuper.hh"
+ #include "bsestorage.hh"
+ #include "bsesong.hh"
+ #include "bsesnet.hh"
+ #include "bsecsynth.hh"
+ #include "bsewaverepo.hh"
+ #include "bsesequencer.hh"
+ #include "bseserver.hh"
+ #include "bseundostack.hh"
+ #include "bsemain.hh"
+ #include "bsestandardsynths.hh"
+ #include "bsemidireceiver.hh"
+ #include "bsemidinotifier.hh"
+ #include "gslcommon.hh"
+ #include "bseengine.hh"
++#include "bsesoundfontrepo.h"
+ #include <string.h>
+ #include <stdlib.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <errno.h>
+ 
+ 
+ typedef struct {
+   GType    base_type;
+   gboolean intern_children;
+   guint    max_items;
+   GSList  *items;
+ } StorageTrap;
+ 
+ /* --- macros --- */
+ #define parse_or_return         bse_storage_scanner_parse_or_return
+ #define peek_or_return          bse_storage_scanner_peek_or_return
+ 
+ enum {
+   PARAM_0,
+   PARAM_DIRTY
+ };
+ 
+ 
+ /* --- prototypes --- */
+ static void   bse_project_class_init          (BseProjectClass        *klass);
+ static void   bse_project_class_finalize      (BseProjectClass        *klass);
+ static void   bse_project_init                (BseProject             *project,
+                                                gpointer                rclass);
+ static void     bse_project_set_property        (GObject                *object,
+                                                  guint                   param_id,
+                                                  const GValue           *value,
+                                                  GParamSpec             *pspec);
+ static void     bse_project_get_property        (GObject                *object,
+                                                  guint                   param_id,
+                                                  GValue                 *value,
+                                                  GParamSpec             *pspec);
+ static void   bse_project_finalize            (GObject                *object);
+ static void   bse_project_release_children    (BseContainer           *container);
+ static void   bse_project_dispose             (GObject                *object);
+ static void   bse_project_add_item            (BseContainer           *container,
+                                                BseItem                *item);
+ static void   bse_project_remove_item         (BseContainer           *container,
+                                                BseItem                *item);
+ static void   bse_project_forall_items        (BseContainer           *container,
+                                                BseForallItemsFunc      func,
+                                                gpointer                data);
+ static BseItem* bse_project_retrieve_child    (BseContainer           *container,
+                                                GType                   child_type,
+                                                const gchar            *uname);
+ static void   bse_project_prepare             (BseSource              *source);
+ static gboolean project_check_restore         (BseContainer           *container,
+                                                const gchar            *child_type);
+ static BseUndoStack* bse_project_get_undo       (BseItem                *item);
+ 
+ 
+ /* --- variables --- */
+ static GTypeClass *parent_class = NULL;
+ static guint       signal_state_changed = 0;
+ static GQuark      quark_storage_trap = 0;
+ 
+ 
+ /* --- functions --- */
+ BSE_BUILTIN_TYPE (BseProject)
+ {
+   static const GTypeInfo project_info = {
+     sizeof (BseProjectClass),
+ 
+     (GBaseInitFunc) NULL,
+     (GBaseFinalizeFunc) NULL,
+     (GClassInitFunc) bse_project_class_init,
+     (GClassFinalizeFunc) bse_project_class_finalize,
+     NULL /* class_data */,
+ 
+     sizeof (BseProject),
+     0 /* n_preallocs */,
+     (GInstanceInitFunc) bse_project_init,
+   };
+ 
+   return bse_type_register_static (BSE_TYPE_CONTAINER,
+                                  "BseProject",
+                                  "BSE Super container type",
+                                    __FILE__, __LINE__,
+                                    &project_info);
+ }
+ 
+ static void
+ bse_project_class_init (BseProjectClass *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+   BseObjectClass *object_class = BSE_OBJECT_CLASS (klass);
+   BseItemClass *item_class = BSE_ITEM_CLASS (klass);
+   BseSourceClass *source_class = BSE_SOURCE_CLASS (klass);
+   BseContainerClass *container_class = BSE_CONTAINER_CLASS (klass);
+ 
+   parent_class = (GTypeClass*) g_type_class_peek_parent (klass);
+   quark_storage_trap = g_quark_from_static_string ("bse-project-storage-trap");
+ 
+   gobject_class->set_property = bse_project_set_property;
+   gobject_class->get_property = bse_project_get_property;
+   gobject_class->dispose = bse_project_dispose;
+   gobject_class->finalize = bse_project_finalize;
+ 
+   item_class->get_undo = bse_project_get_undo;
+ 
+   source_class->prepare = bse_project_prepare;
+ 
+   container_class->add_item = bse_project_add_item;
+   container_class->remove_item = bse_project_remove_item;
+   container_class->forall_items = bse_project_forall_items;
+   container_class->check_restore = project_check_restore;
+   container_class->retrieve_child = bse_project_retrieve_child;
+   container_class->release_children = bse_project_release_children;
+ 
+   bse_object_class_add_param (object_class, "State",
+                               PARAM_DIRTY,
+                               sfi_pspec_bool ("dirty", NULL, "Whether project needs saving",
+                                               FALSE, "r"));
+ 
+   signal_state_changed = bse_object_class_add_signal (object_class, "state-changed",
+                                                     G_TYPE_NONE,
+                                                     1, BSE_TYPE_PROJECT_STATE);
+ }
+ 
+ static void
+ bse_project_class_finalize (BseProjectClass *klass)
+ {
+ }
+ 
+ static void
+ undo_notify (BseProject     *project,
+              BseUndoStack   *ustack,
+              gboolean        step_added)
+ {
+   g_object_notify ((GObject*) project, "dirty");
+   if (step_added && !project->in_redo)
+     {
+       bse_undo_stack_force_dirty (project->undo_stack);
+       bse_undo_stack_clear (project->redo_stack);
+     }
+ }
+ 
+ static void
+ redo_notify (BseProject     *project,
+              BseUndoStack   *ustack,
+              gboolean        step_added)
+ {
+   g_object_notify ((GObject*) project, "dirty");
+ }
+ 
+ static void
+ bse_project_init (BseProject *self,
+                 gpointer    rclass)
+ {
+   self->state = BSE_PROJECT_INACTIVE;
+   self->supers = NULL;
+   self->items = NULL;
+   self->in_undo = FALSE;
+   self->in_redo = FALSE;
+   self->undo_stack = bse_undo_stack_new (self, undo_notify);
+   self->redo_stack = bse_undo_stack_new (self, redo_notify);
+   self->deactivate_usecs = 3 * 1000000;
+   self->midi_receiver = bse_midi_receiver_new ("BseProjectReceiver");
+   bse_midi_receiver_enter_farm (self->midi_receiver);
+   /* we always have a wave-repo */
 -  BseWaveRepo *wrepo = (BseWaveRepo*) bse_container_new_child (BSE_CONTAINER (self), BSE_TYPE_WAVE_REPO, 
"uname", "Wave-Repository", NULL);
++  BseWaveRepo *wrepo = bse_container_new_child (BSE_CONTAINER (self), BSE_TYPE_WAVE_REPO,
++                                                "uname", "Wave-Repository",
++                                                NULL);
++  BseSoundFontRepo *sfrepo = bse_container_new_child (BSE_CONTAINER (self), BSE_TYPE_SOUND_FONT_REPO,
++                                                      "uname", "Sound-Font-Repository",
++                                                      NULL);
+   /* with fixed uname */
+   BSE_OBJECT_SET_FLAGS (wrepo, BSE_OBJECT_FLAG_FIXED_UNAME);
++  BSE_OBJECT_SET_FLAGS (sfrepo, BSE_OBJECT_FLAG_FIXED_UNAME);
+ }
+ 
+ static void
+ bse_project_set_property (GObject                *object,
+                           guint                   param_id,
+                           const GValue           *value,
+                           GParamSpec             *pspec)
+ {
+   BseProject *self = BSE_PROJECT (object);
+ 
+   switch (param_id)
+     {
+     case PARAM_DIRTY:
+       break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
+       break;
+     }
+ }
+ 
+ static void
+ bse_project_get_property (GObject                *object,
+                           guint                   param_id,
+                           GValue                 *value,
+                           GParamSpec             *pspec)
+ {
+   BseProject *self = BSE_PROJECT (object);
+ 
+   switch (param_id)
+     {
+     case PARAM_DIRTY:
+       sfi_value_set_bool (value, bse_undo_stack_dirty (self->undo_stack));
+       break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
+       break;
+     }
+ }
+ 
+ static void
+ bse_project_release_children (BseContainer *container)
+ {
+   BseProject *project = BSE_PROJECT (container);
+ 
+   while (project->items)
+     bse_container_remove_item (BSE_CONTAINER (project), (BseItem*) project->items->data);
+   while (project->supers)
+     bse_container_remove_item (BSE_CONTAINER (project), (BseItem*) project->supers->data);
+ 
+   /* chain parent class' handler */
+   BSE_CONTAINER_CLASS (parent_class)->release_children (container);
+ }
+ 
+ static void
+ bse_project_dispose (GObject *object)
+ {
+   BseProject *self = BSE_PROJECT (object);
+ 
+   bse_project_deactivate (self);
+ 
+   bse_undo_stack_limit (self->undo_stack, 0);
+   bse_undo_stack_limit (self->redo_stack, 0);
+ 
+   /* chain parent class' handler */
+   G_OBJECT_CLASS (parent_class)->dispose (object);
+ }
+ 
+ static void
+ bse_project_finalize (GObject *object)
+ {
+   BseProject *self = BSE_PROJECT (object);
+ 
+   bse_midi_receiver_unref (self->midi_receiver);
+   self->midi_receiver = NULL;
+ 
+   /* chain parent class' handler */
+   G_OBJECT_CLASS (parent_class)->finalize (object);
+ 
+   bse_undo_stack_destroy (self->undo_stack);
+   bse_undo_stack_destroy (self->redo_stack);
+ }
+ 
+ static BseUndoStack*
+ bse_project_get_undo (BseItem *item)
+ {
+   BseProject *self = BSE_PROJECT (item);
+   return self->in_undo ? self->redo_stack : self->undo_stack;
+ }
+ 
+ void
+ bse_project_clear_undo (BseProject *self)
+ {
+   g_return_if_fail (BSE_IS_PROJECT (self));
+   if (!self->in_undo && !self->in_redo)
+     {
+       bse_undo_stack_clear (self->undo_stack);
+       bse_undo_stack_clear (self->redo_stack);
+       g_object_notify ((GObject*) self, "dirty");
+     }
+ }
+ 
+ void
+ bse_project_clean_dirty (BseProject *self)
+ {
+   g_return_if_fail (BSE_IS_PROJECT (self));
+   bse_undo_stack_clean_dirty (self->undo_stack);
+   bse_undo_stack_clean_dirty (self->redo_stack);
+   g_object_notify ((GObject*) self, "dirty");
+ }
+ 
+ static void
+ project_undo_do_deactivate (BseUndoStep  *ustep,
+                             BseUndoStack *ustack)
+ {
+   BseProject *self = (BseProject*) bse_undo_pointer_unpack ((const char*) ustep->data[0].v_pointer, ustack);
+   bse_project_deactivate (self);
+ }
+ 
+ static void
+ project_undo_do_deactivate_free (BseUndoStep *ustep)
+ {
+   g_free (ustep->data[0].v_pointer);
+ }
+ 
+ void
+ bse_project_push_undo_silent_deactivate (BseProject *self)
+ {
+   g_return_if_fail (BSE_IS_PROJECT (self));
+ 
+   /* certain things work only (can only be undone/redone) in deactivated projects,
+    * so we need to push an undo step here. this step isn't required however
+    * if there're no undo steps pushed so far, and it shouldn't be visible
+    * as a seperate undo step to the user either. so what we do is to push
+    * an "add-on" step, which just prepares state for execution of further
+    * undo steps, if there are any pending.
+    */
+   if (self->state != BSE_PROJECT_INACTIVE)
+     {
+       BseUndoStack *ustack = bse_item_undo_open (self, "deactivate-project");
+       BseUndoStep *ustep = bse_undo_step_new (project_undo_do_deactivate, project_undo_do_deactivate_free, 
1);
+       ustep->data[0].v_pointer = bse_undo_pointer_pack (self, ustack);
+       bse_undo_stack_push_add_on (ustack, ustep);
+       bse_item_undo_close (ustack);
+ 
+       gboolean in_undo = self->in_undo;
+       self->in_undo = !in_undo;             /* swap undo<=>redo */
+       ustack = bse_item_undo_open (self, "deactivate-project");
+       ustep = bse_undo_step_new (project_undo_do_deactivate, project_undo_do_deactivate_free, 1);
+       ustep->data[0].v_pointer = bse_undo_pointer_pack (self, ustack);
+       bse_undo_stack_push_add_on (ustack, ustep);
+       bse_item_undo_close (ustack);
+       self->in_undo = in_undo;              /* swap undo<=>redo */
+     }
+ }
+ 
+ static void
+ bse_project_add_item (BseContainer *container,
+                     BseItem      *item)
+ {
+   BseProject *self = BSE_PROJECT (container);
+ 
+   if (BSE_IS_SUPER (item))
+     self->supers = g_slist_append (self->supers, item);
+   else
+     self->items = g_slist_append (self->items, item);
+ 
+   /* chain parent class' add_item handler */
+   BSE_CONTAINER_CLASS (parent_class)->add_item (container, item);
+ }
+ 
+ static void
+ bse_project_remove_item (BseContainer *container,
+                        BseItem      *item)
+ {
+   BseProject *self = BSE_PROJECT (container);
+ 
+   /* chain parent class' remove_item handler */
+   BSE_CONTAINER_CLASS (parent_class)->remove_item (container, item);
+ 
+   if (BSE_IS_SUPER (item))
+     self->supers = g_slist_remove (self->supers, item);
+   else
+     self->items = g_slist_remove (self->items, item);
+ }
+ 
+ static void
+ bse_project_forall_items (BseContainer      *container,
+                         BseForallItemsFunc func,
+                         gpointer           data)
+ {
+   BseProject *self = BSE_PROJECT (container);
+   GSList *slist;
+ 
+   slist = self->supers;
+   while (slist)
+     {
+       BseItem *item = (BseItem*) slist->data;
+       slist = slist->next;
+       if (!func (item, data))
+       return;
+     }
+ 
+   slist = self->items;
+   while (slist)
+     {
+       BseItem *item = (BseItem*) slist->data;
+       slist = slist->next;
+       if (!func (item, data))
+       return;
+     }
+ }
+ 
+ static BseItem*
+ bse_project_retrieve_child (BseContainer *container,
+                           GType         child_type,
+                           const gchar  *uname)
+ {
+   BseProject *self = BSE_PROJECT (container);
+ 
+   /* always hand out the same wave repo */
+   if (g_type_is_a (child_type, BSE_TYPE_WAVE_REPO))
+     {
+       GSList *slist;
+ 
+       for (slist = self->supers; slist; slist = slist->next)
+       if (g_type_is_a (G_OBJECT_TYPE (slist->data), BSE_TYPE_WAVE_REPO))
+         return (BseItem*) slist->data;
+       g_warning ("%s: no wave-repo found in project\n", G_STRLOC);
+       return NULL;    /* shouldn't happen */
+     }
++  else if (g_type_is_a (child_type, BSE_TYPE_SOUND_FONT_REPO))        /* and the same sound font repo */
++    {
++      BseSoundFontRepo *sfrepo = bse_project_get_sound_font_repo (self);
++      if (!sfrepo)
++      g_warning ("%s: no sound-font-repo found in project\n", G_STRLOC);
++      return BSE_ITEM (sfrepo);
++    }
+   else
+     {
+       BseItem *item = BSE_CONTAINER_CLASS (parent_class)->retrieve_child (container, child_type, uname);
+       StorageTrap *strap = (StorageTrap*) g_object_get_qdata ((GObject*) self, quark_storage_trap);
+       if (item && strap)
+       {
+           if (strap->intern_children)
+             bse_item_set_internal (item, TRUE);
+         strap->items = g_slist_prepend (strap->items, item);
+         strap->max_items--;
+       }
+       return item;
+     }
+ }
+ 
+ static gboolean
+ add_item_upaths (BseItem *item,
+                gpointer data_p)
+ {
+   gpointer *data = (void**) data_p;
+   BseStringSeq *sseq = (BseStringSeq*) data[0];
+   GType item_type = (GType) data[1];
+   BseContainer *container = (BseContainer*) data[2];
+ 
+   if (g_type_is_a (BSE_OBJECT_TYPE (item), item_type))
+     {
+       gchar *upath = bse_container_make_upath (container, item);
+       bse_string_seq_append (sseq, upath);
+       g_free (upath);
+     }
+   if (BSE_IS_CONTAINER (item))
+     bse_container_forall_items (BSE_CONTAINER (item), add_item_upaths, data);
+ 
+   return TRUE;
+ }
+ 
+ BseStringSeq*
+ bse_project_list_upaths (BseProject *self,
+                        GType       item_type)
+ {
+   gpointer data[3];
+   BseStringSeq *sseq;
+ 
+   g_return_val_if_fail (BSE_IS_PROJECT (self), NULL);
+   g_return_val_if_fail (g_type_is_a (item_type, BSE_TYPE_ITEM), NULL);
+ 
+   sseq = bse_string_seq_new ();
+   data[0] = sseq;
+   data[1] = (gpointer) item_type;
+   data[2] = self;
+   bse_container_forall_items (BSE_CONTAINER (self), add_item_upaths, data);
+ 
+   return sseq;
+ }
+ 
+ static GSList*
+ compute_missing_supers (BseProject *self,
+                         BseStorage *storage)
+ {
+   BseItem *project_item = BSE_ITEM (self);
+   GSList *targets = NULL, *missing = sfi_ppool_slist (storage->referenced_items);
+   while (missing)
+     {
+       BseItem *item = (BseItem*) g_slist_pop_head (&missing);
+       BseSuper *super = bse_item_get_super (item);
+       if (BSE_ITEM (super)->parent == project_item &&
+           !sfi_ppool_lookup (storage->stored_items, super))
+         targets = g_slist_prepend (targets, super);
+     }
+   return targets;
+ }
+ 
+ BseErrorType
+ bse_project_store_bse (BseProject  *self,
+                        BseSuper    *super,
+                      const gchar *bse_file,
+                      gboolean     self_contained)
+ {
+   BseStorage *storage;
+   GSList *slist = NULL;
+   gchar *string;
+   guint l, flags;
+   gint fd;
+ 
+   g_return_val_if_fail (BSE_IS_PROJECT (self), BSE_ERROR_INTERNAL);
+   if (super)
+     {
+       g_return_val_if_fail (BSE_IS_SUPER (super), BSE_ERROR_INTERNAL);
+       g_return_val_if_fail (BSE_ITEM (super)->parent == BSE_ITEM (self), BSE_ERROR_INTERNAL);
+     }
+   g_return_val_if_fail (bse_file != NULL, BSE_ERROR_INTERNAL);
+ 
+   fd = open (bse_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
+   if (fd < 0)
+     return bse_error_from_errno (errno, BSE_ERROR_FILE_OPEN_FAILED);
+ 
+   storage = (BseStorage*) g_object_new (BSE_TYPE_STORAGE, NULL);
+   flags = 0;
+   if (self_contained)
+     flags |= BSE_STORAGE_SELF_CONTAINED;
+   bse_storage_prepare_write (storage, BseStorageMode (flags));
+ 
+   slist = g_slist_prepend (slist, super ? (void*) super : (void*) self);
+   while (slist)
+     {
+       BseItem *item = (BseItem*) g_slist_pop_head (&slist);
+       if (item == (BseItem*) self)
+         bse_storage_store_item (storage, item);
+       else
+         bse_storage_store_child (storage, item);
+       slist = g_slist_concat (compute_missing_supers (self, storage), slist);
+     }
+ 
+   string = g_strdup_format ("; BseProject\n\n"); /* %010o mflags */
+   do
+     l = write (fd, string, strlen (string));
+   while (l < 0 && errno == EINTR);
+   g_free (string);
+ 
+   BseErrorType error = bse_storage_flush_fd (storage, fd);
+   if (close (fd) < 0 && error == BSE_ERROR_NONE)
+     error = bse_error_from_errno (errno, BSE_ERROR_FILE_WRITE_FAILED);
+   bse_storage_reset (storage);
+   g_object_unref (storage);
+ 
+   return error;
+ }
+ 
+ BseErrorType
+ bse_project_restore (BseProject *self,
+                    BseStorage *storage)
+ {
+   GScanner *scanner;
+   GTokenType expected_token = G_TOKEN_NONE;
+ 
+   g_return_val_if_fail (BSE_IS_PROJECT (self), BSE_ERROR_INTERNAL);
+   g_return_val_if_fail (BSE_IS_STORAGE (storage), BSE_ERROR_INTERNAL);
+ 
+   scanner = bse_storage_get_scanner (storage);
+   g_return_val_if_fail (scanner != NULL, BSE_ERROR_INTERNAL);
+ 
+   g_object_ref (self);
+ 
+   expected_token = bse_storage_restore_item (storage, BSE_ITEM (self));
+   if (expected_token != G_TOKEN_NONE)
+     bse_storage_unexp_token (storage, expected_token);
+ 
+   bse_storage_finish_parsing (storage);
+ 
+   GSList *slist = self->supers;
+   while (slist)
+     {
+       BseSuper *super = (BseSuper*) slist->data;
+       slist = slist->next;
+       BseSuperClass *super_class = BSE_SUPER_GET_CLASS (super);
+       super_class->compat_finish (super, storage->major_version, storage->minor_version, 
storage->micro_version);
+     }
+ 
+   bse_undo_stack_force_dirty (self->undo_stack);
+ 
+   g_object_unref (self);
+ 
+   return (scanner->parse_errors >= scanner->max_parse_errors ?
+         BSE_ERROR_PARSE_ERROR :
+         BSE_ERROR_NONE);
+ }
+ 
+ BseObject*
+ bse_project_upath_resolver (gpointer     func_data,
+                           GType        required_type,
+                           const gchar *upath,
+                           gchar      **error_p)
+ {
+   BseProject *self = (BseProject*) func_data;
+   gpointer item = NULL;
+ 
+   if (error_p)
+     *error_p = NULL;
+   g_return_val_if_fail (BSE_IS_PROJECT (self), NULL);
+   g_return_val_if_fail (upath != NULL, NULL);
+ 
+   /* FIXME: need error handling, warnings.... */
+ 
+   if (g_type_is_a (required_type, BSE_TYPE_ITEM))
+     item = bse_container_resolve_upath (BSE_CONTAINER (self), upath);
+   else if (error_p)
+     *error_p = g_strdup_format ("unable to resolve object of type `%s' from upath: %s", g_type_name 
(required_type), upath);
+ 
+   return (BseObject*) item;
+ }
+ 
+ BseItem*
+ bse_project_lookup_typed_item (BseProject  *self,
+                              GType        item_type,
+                              const gchar *uname)
+ {
+   BseItem *item;
+ 
+   g_return_val_if_fail (BSE_IS_PROJECT (self), NULL);
+   g_return_val_if_fail (uname != NULL, NULL);
+ 
+   item = bse_container_lookup_item (BSE_CONTAINER (self), uname);
+   if (item && G_OBJECT_TYPE (item) == item_type)
+     return item;
+ 
+   return NULL;
+ }
+ 
+ BseWaveRepo*
+ bse_project_get_wave_repo (BseProject *self)
+ {
+   g_return_val_if_fail (BSE_IS_PROJECT (self), NULL);
+   GSList *slist;
+   for (slist = self->supers; slist; slist = slist->next)
+     if (BSE_IS_WAVE_REPO (slist->data))
+       return (BseWaveRepo*) slist->data;
+   return NULL;
+ }
+ 
++BseSoundFontRepo*
++bse_project_get_sound_font_repo (BseProject *self)
++{
++  g_return_val_if_fail (BSE_IS_PROJECT (self), NULL);
++  GSList *slist;
++  for (slist = self->supers; slist; slist = slist->next)
++    if (BSE_IS_SOUND_FONT_REPO (slist->data))
++      return slist->data;
++  return NULL;
++}
++
+ BseSong*
+ bse_project_get_song (BseProject *self)
+ {
+   g_return_val_if_fail (BSE_IS_PROJECT (self), NULL);
+   GSList *slist;
+   for (slist = self->supers; slist; slist = slist->next)
+     if (BSE_IS_SONG (slist->data))
+       return (BseSong*) slist->data;
+   return NULL;
+ }
+ 
+ static gboolean
+ project_check_restore (BseContainer *container,
+                      const gchar  *child_type)
+ {
+   if (BSE_CONTAINER_CLASS (parent_class)->check_restore (container, child_type))
+     {
+       StorageTrap *strap = (StorageTrap*) g_object_get_qdata ((GObject*) container, quark_storage_trap);
+       if (!strap)
+       return TRUE;
+       if (!g_type_is_a (g_type_from_name (child_type), strap->base_type))
+       return FALSE;
+       if (strap->max_items < 1)
+       return FALSE;
+       return TRUE;
+     }
+   else
+     return FALSE;
+ }
+ 
+ BseSNet*
+ bse_project_create_intern_synth (BseProject  *self,
+                                const gchar *synth_name,
+                                GType        check_type)
+ {
+   BseItem *synth = NULL;
+   gchar *bse_synth;
+ 
+   g_return_val_if_fail (BSE_IS_PROJECT (self), NULL);
+   g_return_val_if_fail (synth_name != NULL, NULL);
+ 
+   bse_synth = bse_standard_synth_inflate (synth_name, NULL);
+   if (bse_synth)
+     {
+       BseStorage *storage = (BseStorage*) g_object_new (BSE_TYPE_STORAGE, NULL);
+       BseErrorType error = BSE_ERROR_NONE;
+       StorageTrap strap = { 0, TRUE, }, *old_strap = (StorageTrap*) g_object_get_qdata ((GObject*) self, 
quark_storage_trap);
+       bse_storage_input_text (storage, bse_synth, "<builtin-lib>");
+       g_object_set_qdata ((GObject*) self, quark_storage_trap, &strap);
+       strap.max_items = 1;
+       strap.base_type = check_type;
+       strap.items = NULL;
+       if (!error)
+       error = bse_project_restore (self, storage);
+       bse_storage_reset (storage);
+       g_object_unref (storage);
+       g_free (bse_synth);
+       if (error || !strap.items)
+       g_warning ("failed to create internal synth \"%s\": %s",
+                  synth_name, bse_error_blurb (error ? error : BSE_ERROR_NO_ENTRY));
+       else
+       synth = (BseItem*) strap.items->data;
+       g_slist_free (strap.items);
+       g_object_set_qdata ((GObject*) self, quark_storage_trap, old_strap);
+     }
+   return BSE_SNET (synth);
+ }
+ 
+ BseCSynth*
+ bse_project_create_intern_csynth (BseProject *self,
+                                   const char *base_name)
+ {
+   BseCSynth *csynth = (BseCSynth*) bse_container_new_child_bname (BSE_CONTAINER (self), BSE_TYPE_CSYNTH, 
base_name, NULL);
+   bse_item_set_internal (BSE_ITEM (csynth), TRUE);
+   return csynth;
+ }
+ 
+ BseMidiNotifier*
+ bse_project_get_midi_notifier (BseProject *self)
+ {
+   GSList *slist;
+   for (slist = self->items; slist; slist = slist->next)
+     if (BSE_IS_MIDI_NOTIFIER (slist->data))
+       return (BseMidiNotifier*) slist->data;
+ 
+   BseMidiNotifier *mnot = (BseMidiNotifier*) bse_container_new_child_bname (BSE_CONTAINER (self), 
BSE_TYPE_MIDI_NOTIFIER,
+                                                                             "%bse-intern-midi-notifier", 
NULL);
+   bse_midi_notifier_set_receiver (mnot, self->midi_receiver);
+   bse_item_set_internal (BSE_ITEM (mnot), TRUE);
+   return mnot;
+ }
+ 
+ static void
+ bse_project_prepare (BseSource *source)
+ {
+   BseProject *self = BSE_PROJECT (source);
+   GSList *slist;
+ 
+   /* make sure Wave repositories are prepared first */
+   for (slist = self->supers; slist; slist = slist->next)
+     if (BSE_IS_WAVE_REPO (slist->data))
+       bse_source_prepare ((BseSource*) slist->data);
+ 
+   /* chain parent class' handler to prepare the rest */
+   BSE_SOURCE_CLASS (parent_class)->prepare (source);
+ }
+ 
+ static gboolean
+ auto_deactivate (gpointer data)
+ {
+   BseProject *self = BSE_PROJECT (data);
+   self->deactivate_timer = 0;
+   if (self->state == BSE_PROJECT_ACTIVE)
+     bse_project_deactivate (self);
+   return FALSE;
+ }
+ 
+ void
+ bse_project_state_changed (BseProject     *self,
+                          BseProjectState state)
+ {
+   g_return_if_fail (BSE_IS_PROJECT (self));
+ 
+   if (self->deactivate_timer)
+     {
+       bse_idle_remove (self->deactivate_timer);
+       self->deactivate_timer = 0;
+     }
+   self->state = state;
+   if (self->state == BSE_PROJECT_ACTIVE && self->deactivate_usecs >= 0)
+     {
+       SfiTime stamp = Bse::TickStamp::current();
+       SfiTime delay_usecs = 0;
+       if (SfiTime (self->deactivate_min_tick) > stamp)
+       delay_usecs = (self->deactivate_min_tick - stamp) * 1000000 / bse_engine_sample_freq ();
+       self->deactivate_timer = bse_idle_timed (self->deactivate_usecs + delay_usecs, auto_deactivate, self);
+     }
+   g_signal_emit (self, signal_state_changed, 0, state);
+ }
+ 
+ void
+ bse_project_keep_activated (BseProject *self,
+                           guint64     min_tick)
+ {
+   g_return_if_fail (BSE_IS_PROJECT (self));
+ 
+   if (min_tick > self->deactivate_min_tick)
+     {
+       self->deactivate_min_tick = min_tick;
+       if (self->deactivate_timer)
+       bse_project_state_changed (self, self->state);
+     }
+ }
+ 
+ BseErrorType
+ bse_project_activate (BseProject *self)
+ {
+   BseErrorType error;
+   BseTrans *trans;
+   GSList *slist;
+ 
+   g_return_val_if_fail (BSE_IS_PROJECT (self), BSE_ERROR_INTERNAL);
+ 
+   if (self->state != BSE_PROJECT_INACTIVE)
+     return BSE_ERROR_NONE;
+ 
+   g_return_val_if_fail (BSE_SOURCE_PREPARED (self) == FALSE, BSE_ERROR_INTERNAL);
+ 
+   error = bse_server_open_devices (bse_server_get ());
+   if (error)
+     return error;
+ 
+   bse_source_prepare (BSE_SOURCE (self));
+   self->deactivate_min_tick = 0;
+ 
+   trans = bse_trans_open ();
+   for (slist = self->supers; slist; slist = slist->next)
+     {
+       BseSuper *super = BSE_SUPER (slist->data);
+       if (BSE_SUPER_NEEDS_CONTEXT (super))
+       {
+           BseMidiContext mcontext = { 0, 0, 0 };
+         BseSNet *snet = BSE_SNET (super);
+           mcontext.midi_receiver = self->midi_receiver;
+           mcontext.midi_channel = 1; /* midi channel default */
+         super->context_handle = bse_snet_create_context (snet, mcontext, trans);
+         bse_source_connect_context (BSE_SOURCE (snet), super->context_handle, trans);
+       }
+       else
+       super->context_handle = ~0;
+     }
+   bse_trans_commit (trans);
+   bse_project_state_changed (self, BSE_PROJECT_ACTIVE);
+   return BSE_ERROR_NONE;
+ }
+ 
+ void
+ bse_project_start_playback (BseProject *self)
+ {
+   BseTrans *trans;
+   GSList *slist;
+   guint seen_synth = 0;
+ 
+   g_return_if_fail (BSE_IS_PROJECT (self));
+ 
+   if (self->state != BSE_PROJECT_ACTIVE)
+     return;
+   g_return_if_fail (BSE_SOURCE_PREPARED (self) == TRUE);
+ 
+   SfiRing *songs = NULL;
+   trans = bse_trans_open ();
+   for (slist = self->supers; slist; slist = slist->next)
+     {
+       BseSuper *super = BSE_SUPER (slist->data);
+       if (BSE_SUPER_NEEDS_CONTEXT (super) &&
+         super->context_handle == ~uint (0))
+       {
+           BseMidiContext mcontext = { 0, 0, 0 };
+           BseSNet *snet = BSE_SNET (super);
+           mcontext.midi_receiver = self->midi_receiver;
+           mcontext.midi_channel = 1; /* midi channel default */
+           super->context_handle = bse_snet_create_context (snet, mcontext, trans);
+         bse_source_connect_context (BSE_SOURCE (snet), super->context_handle, trans);
+       }
+       if (BSE_SUPER_NEEDS_CONTEXT (super))
+         seen_synth++;
+       if (BSE_IS_SONG (super))
+       songs = sfi_ring_append (songs, super);
+     }
+   /* enfore MasterThread roundtrip */
+   bse_trans_add (trans, bse_job_nop());
+   bse_trans_commit (trans);
+   /* first, enforce integrated (and possibly scheduled) modules; */
+   bse_engine_wait_on_trans();
+   /* update state */
+   if (seen_synth || songs)
+     bse_project_state_changed (self, BSE_PROJECT_PLAYING);
+   /* then, start the sequencer */
+   while (songs)
+     Bse::Sequencer::instance().start_song ((BseSong*) sfi_ring_pop_head (&songs), 0);
+ }
+ 
+ void
+ bse_project_stop_playback (BseProject *self)
+ {
+   BseTrans *trans;
+   GSList *slist;
+ 
+   g_return_if_fail (BSE_IS_PROJECT (self));
+ 
+   if (self->state != BSE_PROJECT_PLAYING)
+     return;
+   g_return_if_fail (BSE_SOURCE_PREPARED (self) == TRUE);
+ 
+   trans = bse_trans_open ();
+   for (slist = self->supers; slist; slist = slist->next)
+     {
+       BseSuper *super = BSE_SUPER (slist->data);
+       if (BSE_IS_SONG (super))
+         Bse::Sequencer::instance().remove_song (BSE_SONG (super));
+       if (super->context_handle != ~uint (0) && BSE_SUPER_NEEDS_CONTEXT (super))
+       {
+         BseSource *source = BSE_SOURCE (super);
+         bse_source_dismiss_context (source, super->context_handle, trans);
+         super->context_handle = ~0;
+       }
+     }
+   /* enfore MasterThread roundtrip */
+   bse_trans_add (trans, bse_job_nop());
+   bse_trans_commit (trans);
+   /* wait until after all modules have actually been dismissed */
+   bse_engine_wait_on_trans ();
+   /* update state */
+   bse_project_state_changed (self, BSE_PROJECT_ACTIVE);
+ }
+ 
+ void
+ bse_project_check_auto_stop (BseProject *self)
+ {
+   g_return_if_fail (BSE_IS_PROJECT (self));
+ 
+   if (self->state == BSE_PROJECT_PLAYING)
+     {
+       GSList *slist;
+       for (slist = self->supers; slist; slist = slist->next)
+       {
+         BseSuper *super = BSE_SUPER (slist->data);
+         if (super->context_handle != ~uint (0))
+           {
+             if (!BSE_IS_SONG (super) || !BSE_SONG (super)->sequencer_done_SL)
+               return;
+           }
+       }
+       bse_project_stop_playback (self);
+     }
+ }
+ 
+ void
+ bse_project_deactivate (BseProject *self)
+ {
+   BseTrans *trans;
+   GSList *slist;
+ 
+   g_return_if_fail (BSE_IS_PROJECT (self));
+ 
+   if (self->state == BSE_PROJECT_INACTIVE)
+     return;
+   g_return_if_fail (BSE_SOURCE_PREPARED (self) == TRUE);
+ 
+   bse_project_stop_playback (self);
+ 
+   trans = bse_trans_open ();
+   for (slist = self->supers; slist; slist = slist->next)
+     {
+       BseSuper *super = BSE_SUPER (slist->data);
+       if (super->context_handle != ~uint (0))
+       {
+         BseSource *source = BSE_SOURCE (super);
+         bse_source_dismiss_context (source, super->context_handle, trans);
+         super->context_handle = ~0;
+       }
+     }
+   bse_trans_commit (trans);
+   /* wait until after all modules have actually been dismissed */
+   bse_engine_wait_on_trans ();
+   bse_source_reset (BSE_SOURCE (self));
+   bse_project_state_changed (self, BSE_PROJECT_INACTIVE);
+ 
+   bse_server_close_devices (bse_server_get ());
+ }
diff --cc bse/bseproject.hh
index 0000000,f4ebe16..48877b0
mode 000000,100644..100644
--- a/bse/bseproject.hh
+++ b/bse/bseproject.hh
@@@ -1,0 -1,83 +1,84 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #ifndef __BSE_PROJECT_H__
+ #define __BSE_PROJECT_H__
+ 
+ #include        <bse/bsecontainer.hh>
+ 
+ G_BEGIN_DECLS
+ 
+ 
+ /* --- object type macros --- */
+ #define       BSE_TYPE_PROJECT              (BSE_TYPE_ID (BseProject))
+ #define BSE_PROJECT(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), BSE_TYPE_PROJECT, BseProject))
+ #define BSE_PROJECT_CLASS(class)      (G_TYPE_CHECK_CLASS_CAST ((class), BSE_TYPE_PROJECT, BseProjectClass))
+ #define BSE_IS_PROJECT(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), BSE_TYPE_PROJECT))
+ #define BSE_IS_PROJECT_CLASS(class)   (G_TYPE_CHECK_CLASS_TYPE ((class), BSE_TYPE_PROJECT))
+ #define BSE_PROJECT_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), BSE_TYPE_PROJECT, 
BseProjectClass))
+ 
+ 
+ /* --- BseProject object --- */
+ typedef enum {
+   BSE_PROJECT_INACTIVE,
+   BSE_PROJECT_ACTIVE,
+   BSE_PROJECT_PLAYING
+ } BseProjectState;
+ 
+ struct BseProject : BseContainer {
+   GSList           *supers;
+   GSList           *items;
+   guint               in_undo : 1;
+   guint               in_redo : 1;
+   BseUndoStack       *undo_stack;
+   BseUndoStack       *redo_stack;
+   BseProjectState     state;
+   guint                     deactivate_timer;
+   gint64            deactivate_usecs;
+   guint64           deactivate_min_tick;
+   BseMidiReceiver    *midi_receiver;
+ };
+ struct BseProjectClass : BseContainerClass
+ {};
+ 
+ BseErrorType  bse_project_activate            (BseProject     *project);
+ void          bse_project_start_playback      (BseProject     *project);
+ void          bse_project_stop_playback       (BseProject     *project);
+ void          bse_project_check_auto_stop     (BseProject     *project);
+ void          bse_project_deactivate          (BseProject     *project);
+ void          bse_project_set_auto_deactivate (BseProject     *project,
+                                                gint64          usecs);
+ void          bse_project_keep_activated      (BseProject     *project,
+                                                guint64         min_tick);
+ void          bse_project_state_changed       (BseProject     *project,
+                                                BseProjectState state);
+ BseStringSeq* bse_project_list_upaths         (BseProject     *project,
+                                                GType           item_type);
+ BseErrorType  bse_project_restore             (BseProject     *project,
+                                                BseStorage     *storage);
+ BseErrorType  bse_project_store_bse           (BseProject     *project,
+                                                BseSuper       *super,
+                                                const gchar    *bse_file,
+                                                gboolean        self_contained);
+ BseObject*    bse_project_upath_resolver      (gpointer        project /* func_data */,
+                                                GType           required_type,
+                                                const gchar    *upath,
+                                                gchar         **error_p);
+ BseItem*      bse_project_lookup_typed_item   (BseProject     *project,
+                                                GType           item_type,
+                                                const gchar    *uname);
+ BseWaveRepo*  bse_project_get_wave_repo       (BseProject     *project);
++BseSoundFontRepo* bse_project_get_sound_font_repo (BseProject   *project);
+ BseSong*      bse_project_get_song            (BseProject     *project);
+ BseSNet*      bse_project_create_intern_synth (BseProject     *project,
+                                                const gchar    *synth_name,
+                                                GType           check_type);
+ BseCSynth*      bse_project_create_intern_csynth(BseProject     *project,
+                                                  const char     *base_name);
+ BseMidiNotifier*bse_project_get_midi_notifier   (BseProject     *project);
+ void            bse_project_clear_undo          (BseProject     *project);
+ void            bse_project_clean_dirty         (BseProject     *project);
+ void    bse_project_push_undo_silent_deactivate (BseProject     *self);
+ 
+ 
+ G_END_DECLS
+ 
+ #endif /* __BSE_PROJECT_H__ */
diff --cc bse/bseproject.proc
index 1bd9d77,ff4a8d5..2dc1d52
--- a/bse/bseproject.proc
+++ b/bse/bseproject.proc
@@@ -1,36 -1,21 +1,21 @@@
- /* BSE - Bedevilled Sound Engine        -*-mode: c;-*-
-  * Copyright (C) 2000-2005 Tim Janik
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2.1 of the License, or (at your option) any later version.
-  *
-  * This library 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
-  * Lesser General Public License for more details.
-  *
-  * A copy of the GNU Lesser General Public License should ship along
-  * with this library; if not, see http://www.gnu.org/copyleft/.
-  */
- #include <bse/bseplugin.h>
- #include <bse/bseprocedure.h>
- #include <bse/bseproject.h>
- #include <bse/bsestorage.h>
- #include <bse/bsesong.h>
- #include <bse/bseundostack.h>
- #include <bse/bsewaverepo.h>
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #include <bse/bseplugin.hh>
+ #include <bse/bseprocedure.hh>
+ #include <bse/bseproject.hh>
+ #include <bse/bsestorage.hh>
+ #include <bse/bsesong.hh>
+ #include <bse/bseundostack.hh>
+ #include <bse/bsewaverepo.hh>
 +#include <bse/bsesoundfontrepo.h>
- #include <bse/bsecsynth.h>
- #include <bse/bsemidisynth.h>
- #include <bse/bsedatapocket.h>
- #include <bse/bsemidifile.h>
- #include <bse/bsemidireceiver.h>
- #include <bse/bsemidinotifier.h>
- #include <bse/bseengine.h>
- 
+ #include <bse/bsecsynth.hh>
+ #include <bse/bsemidisynth.hh>
+ #include <bse/bsedatapocket.hh>
+ #include <bse/bsemidifile.hh>
+ #include <bse/bsemidireceiver.hh>
+ #include <bse/bsemidinotifier.hh>
+ #include <bse/bseengine.hh>
+ #include "bsecxxplugin.hh"
  
 -
  AUTHORS = "Tim Janik <timj gtk org>";
  LICENSE = "GNU Lesser General Public License";
  
diff --cc bse/bsestorage.cc
index 0000000,22438e2..e62eb4e
mode 000000,100644..100644
--- a/bse/bsestorage.cc
+++ b/bse/bsestorage.cc
@@@ -1,0 -1,1685 +1,2035 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #include "bsestorage.hh"
+ #include "bseitem.hh"
+ #include "gsldatahandle.hh"
+ #include "gsldatahandle-vorbis.hh"
+ #include "bsedatahandle-flac.hh"
+ #include "gsldatautils.hh"
+ #include "gslcommon.hh"
+ #include "bseproject.hh"
+ #include "bseparasite.hh"
+ #include "bsecxxplugin.hh"
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <errno.h>
++#include <sys/types.h>
++#include <signal.h>
+ 
+ using Bse::Flac1Handle;
+ 
+ /* --- macros --- */
+ #define parse_or_return sfi_scanner_parse_or_return
+ #define peek_or_return  sfi_scanner_peek_or_return
+ 
+ /* --- typedefs --- */
+ struct _BseStorageDBlock
+ {
+   gulong         id;
+   GslDataHandle *dhandle;
+   guint          n_channels : 16;
+   guint          needs_close : 1;
+   gfloat         mix_freq;
+   gfloat         osc_freq;
+ };
+ struct _BseStorageItemLink
+ {
+   BseItem              *from_item;
+   BseStorageRestoreLink restore_link;
+   gpointer              data;
+   guint                 pbackup;
+   gchar                *upath;
+   BseItem              *to_item;
+   gchar                *error;
+ };
 -
++struct _BseStorageBlob
++{
++  SfiMutex    mutex;
++  char       *file_name;
++  int       ref_count;
++  gboolean    is_temp_file;
++  gulong      id;
++};
+ 
+ /* --- prototypes --- */
+ static void       bse_storage_init                 (BseStorage       *self);
+ static void       bse_storage_class_init           (BseStorageClass  *klass);
+ static void       bse_storage_finalize             (GObject          *object);
+ static void       storage_path_table_insert        (BseStorage       *self,
+                                                     BseContainer     *container,
+                                                     const gchar      *uname,
+                                                     BseItem          *item);
+ static BseItem*   storage_path_table_resolve_upath (BseStorage       *self,
+                                                     BseContainer     *container,
+                                                     gchar            *upath);
+ static guint      uname_child_hash                 (gconstpointer     uc);
+ static gint       uname_child_equals               (gconstpointer     uc1,
+                                                     gconstpointer     uc2);
+ static void       uname_child_free                 (gpointer          uc);
+ static GTokenType compat_parse_data_handle         (BseStorage       *self,
+                                                     GslDataHandle   **data_handle_p,
+                                                     guint            *n_channels_p,
+                                                     gfloat           *mix_freq_p,
+                                                     gfloat           *osc_freq_p);
+ 
+ 
+ /* --- variables --- */
+ static gpointer parent_class = NULL;
+ static GQuark   quark_raw_data_handle = 0;
++static GQuark   quark_blob = 0;
++static GQuark   quark_blob_id = 0;
+ static GQuark   quark_vorbis_data_handle = 0;
+ static GQuark   quark_flac_data_handle = 0;
+ static GQuark   quark_dblock_data_handle = 0;
+ static GQuark   quark_bse_storage_binary_v0 = 0;
+ 
+ 
+ /* --- functions --- */
+ BSE_BUILTIN_TYPE (BseStorage)
+ {
+   static const GTypeInfo storage_info = {
+     sizeof (BseStorageClass),
+     (GBaseInitFunc) NULL,
+     (GBaseFinalizeFunc) NULL,
+     (GClassInitFunc) bse_storage_class_init,
+     (GClassFinalizeFunc) NULL,
+     NULL /* class_data */,
+     sizeof (BseStorage),
+     0 /* n_preallocs */,
+     (GInstanceInitFunc) bse_storage_init,
+   };
+ 
+   g_assert (BSE_STORAGE_FLAGS_USHIFT < BSE_OBJECT_FLAGS_MAX_SHIFT);
+ 
+   return bse_type_register_static (BSE_TYPE_OBJECT, "BseStorage",
+                                    "Storage object for item serialization",
+                                    __FILE__, __LINE__,
+                                    &storage_info);
+ }
+ 
+ static void
+ bse_storage_class_init (BseStorageClass *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ 
+   parent_class = g_type_class_peek_parent (klass);
+ 
+   quark_raw_data_handle = g_quark_from_static_string ("raw-data-handle");
+   quark_vorbis_data_handle = g_quark_from_static_string ("vorbis-data-handle");
+   quark_flac_data_handle = g_quark_from_static_string ("flac-data-handle");
+   quark_dblock_data_handle = g_quark_from_static_string ("dblock-data-handle");
+   quark_bse_storage_binary_v0 = g_quark_from_static_string ("BseStorageBinaryV0");
++  quark_blob = g_quark_from_string ("blob");
++  quark_blob_id = g_quark_from_string ("blob-id");
++
++  bse_storage_blob_clean_files(); /* FIXME: maybe better placed in bsemain.c */
+ 
+   gobject_class->finalize = bse_storage_finalize;
+ }
+ 
+ static void
+ bse_storage_init (BseStorage *self)
+ {
+   /* writing */
+   self->wstore = NULL;
+   self->stored_items = NULL;
+   self->referenced_items = NULL;
+   /* reading */
+   self->rstore = NULL;
+   self->path_table = NULL;
+   self->item_links = NULL;
+   self->restorable_objects = NULL;
+   /* misc */
+   self->dblocks = NULL;
+   self->n_dblocks = 0;
+   self->free_me = NULL;
++  self->blobs = NULL;
++  self->n_blobs = 0;
+ 
+   bse_storage_reset (self);
+ }
+ 
+ static void
+ bse_storage_finalize (GObject *object)
+ {
+   BseStorage *self = BSE_STORAGE (object);
+ 
+   bse_storage_reset (self);
+ 
+   /* chain parent class' handler */
+   G_OBJECT_CLASS (parent_class)->finalize (object);
+ }
+ 
+ void
+ bse_storage_turn_readable (BseStorage  *self,
+                            const gchar *storage_name)
+ {
+   BseStorageDBlock *dblocks;
++  BseStorageBlob **blobs;
+   const gchar *cmem;
+   gchar *text;
 -  guint n_dblocks, l;
++  guint n_dblocks, n_blobs, l;
+ 
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (BSE_STORAGE_DBLOCK_CONTAINED (self));
+   g_return_if_fail (self->wstore);
+   g_return_if_fail (self->wstore->flushed == FALSE);
+   g_return_if_fail (self->wstore->bblocks == NULL);
+   g_return_if_fail (self->free_me == NULL);
+ 
+   bse_storage_break (self);
+ 
+   cmem = sfi_wstore_peek_text (self->wstore, &l);
+   text = (char*) g_memdup (cmem, l + 1);
+   dblocks = self->dblocks;
+   n_dblocks = self->n_dblocks;
++  blobs = self->blobs;
++  n_blobs = self->n_blobs;
+   self->dblocks = NULL;
+   self->n_dblocks = 0;
++  self->blobs = NULL;
++  self->n_blobs = 0;
+ 
+   bse_storage_input_text (self, text, storage_name);
+   self->free_me = text;
+   self->dblocks = dblocks;
+   self->n_dblocks = n_dblocks;
++  self->blobs = blobs;
++  self->n_blobs = n_blobs;
+   BSE_OBJECT_SET_FLAGS (self, BSE_STORAGE_DBLOCK_CONTAINED);
+ }
+ 
+ void
+ bse_storage_reset (BseStorage *self)
+ {
+   guint i;
+ 
+   g_return_if_fail (BSE_IS_STORAGE (self));
+ 
+   if (self->rstore)
+     {
+       bse_storage_finish_parsing (self);
+       g_hash_table_destroy (self->path_table);
+       self->path_table = NULL;
+       sfi_rstore_destroy (self->rstore);
+       self->rstore = NULL;
+       if (self->restorable_objects)
+         sfi_ppool_destroy (self->restorable_objects);
+       self->restorable_objects = NULL;
+     }
+ 
+   if (self->wstore)
+     sfi_wstore_destroy (self->wstore);
+   self->wstore = NULL;
+   if (self->stored_items)
+     sfi_ppool_destroy (self->stored_items);
+   self->stored_items = NULL;
+   if (self->referenced_items)
+     sfi_ppool_destroy (self->referenced_items);
+   self->referenced_items = NULL;
+ 
+   self->major_version = BST_MAJOR_VERSION;
+   self->minor_version = BST_MINOR_VERSION;
+   self->micro_version = BST_MICRO_VERSION;
+ 
+   for (i = 0; i < self->n_dblocks; i++)
+     {
+       bse_id_free (self->dblocks[i].id);
+       if (self->dblocks[i].needs_close)
+         gsl_data_handle_close (self->dblocks[i].dhandle);
+       gsl_data_handle_unref (self->dblocks[i].dhandle);
+     }
+   g_free (self->dblocks);
+   self->dblocks = NULL;
+   self->n_dblocks = 0;
+ 
++  for (i = 0; i < self->n_blobs; i++)
++    bse_storage_blob_unref (self->blobs[i]);
++  g_free (self->blobs);
++  self->blobs = NULL;
++  self->n_blobs = 0;
++
+   g_free (self->free_me);
+   self->free_me = NULL;
+ 
+   BSE_OBJECT_UNSET_FLAGS (self, BSE_STORAGE_MODE_MASK);
+ }
+ 
+ static gulong
+ bse_storage_add_dblock (BseStorage    *self,
+                         GslDataHandle *dhandle)
+ {
+   guint i = self->n_dblocks++;
+   self->dblocks = g_renew (BseStorageDBlock, self->dblocks, self->n_dblocks);
+   self->dblocks[i].id = bse_id_alloc ();
+   self->dblocks[i].dhandle = gsl_data_handle_ref (dhandle);
+   if (GSL_DATA_HANDLE_OPENED (dhandle))
+     {
+       /* keep data handles opened to protect against rewrites */
+       gsl_data_handle_open (dhandle);
+       self->dblocks[i].needs_close = TRUE;
+     }
+   else
+     self->dblocks[i].needs_close = FALSE;
+   self->dblocks[i].n_channels = gsl_data_handle_n_channels (dhandle);
+   self->dblocks[i].mix_freq = gsl_data_handle_mix_freq (dhandle);
+   self->dblocks[i].osc_freq = gsl_data_handle_osc_freq (dhandle);
+   return self->dblocks[i].id;
+ }
+ 
++static gulong
++bse_storage_add_blob (BseStorage     *self,
++                      BseStorageBlob *blob)
++{
++  guint i = self->n_blobs++;
++  self->blobs = g_renew (BseStorageBlob *, self->blobs, self->n_blobs);
++  self->blobs[i] = bse_storage_blob_ref (blob);
++  return self->blobs[i]->id;
++}
++
+ static BseStorageDBlock*
+ bse_storage_get_dblock (BseStorage    *self,
+                         gulong         id)
+ {
+   guint i;
+   for (i = 0; i < self->n_dblocks; i++)
+     if (id == self->dblocks[i].id)
+       return self->dblocks + i;
+   return NULL;
+ }
+ 
+ void
+ bse_storage_prepare_write (BseStorage    *self,
+                            BseStorageMode mode)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+ 
+   bse_storage_reset (self);
+   self->wstore = sfi_wstore_new ();
+   self->stored_items = sfi_ppool_new ();
+   self->referenced_items = sfi_ppool_new ();
+   mode = BseStorageMode (mode & BSE_STORAGE_MODE_MASK);
+   if (mode & BSE_STORAGE_DBLOCK_CONTAINED)
+     mode = BseStorageMode (mode | BSE_STORAGE_SELF_CONTAINED);
+   BSE_OBJECT_SET_FLAGS (self, mode);
+   bse_storage_break (self);
+   bse_storage_printf (self, "(bse-version \"%u.%u.%u\")\n\n", BST_MAJOR_VERSION, BST_MINOR_VERSION, 
BST_MICRO_VERSION);
+ }
+ 
+ void
+ bse_storage_input_text (BseStorage  *self,
+                         const gchar *text,
+                         const gchar *text_name)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+ 
+   if (!text)
+     text = "";
+ 
+   bse_storage_reset (self);
+   self->rstore = sfi_rstore_new ();
+   self->rstore->parser_this = self;
+   sfi_rstore_input_text (self->rstore, text, text_name);
+   self->path_table = g_hash_table_new_full (uname_child_hash, uname_child_equals, NULL, uname_child_free);
+   self->restorable_objects = sfi_ppool_new ();
+ }
+ 
+ BseErrorType
+ bse_storage_input_file (BseStorage  *self,
+                         const gchar *file_name)
+ {
+   g_return_val_if_fail (BSE_IS_STORAGE (self), BSE_ERROR_INTERNAL);
+   g_return_val_if_fail (file_name != NULL, BSE_ERROR_INTERNAL);
+ 
+   bse_storage_reset (self);
+   self->rstore = sfi_rstore_new_open (file_name);
+   if (!self->rstore)
+     return bse_error_from_errno (errno, BSE_ERROR_FILE_OPEN_FAILED);
+   self->rstore->parser_this = self;
+   self->path_table = g_hash_table_new_full (uname_child_hash, uname_child_equals, NULL, uname_child_free);
+   self->restorable_objects = sfi_ppool_new ();
+ 
+   return BSE_ERROR_NONE;
+ }
+ 
+ static GTokenType
+ storage_parse_bse_version (BseStorage *self)
+ {
+   GScanner *scanner = bse_storage_get_scanner (self);
+   gchar *vstring, *pminor, *pmicro, *ep = NULL;
+   gboolean parsed_version = FALSE;
+   parse_or_return (scanner, G_TOKEN_IDENTIFIER);        /* eat bse-version */
+   parse_or_return (scanner, G_TOKEN_STRING);            /* fetch "version" */
+   peek_or_return (scanner, ')');                        /* check for closing paren */
+   vstring = g_strdup (scanner->value.v_string);
+   pminor = strchr (vstring, '.');
+   pmicro = !pminor ? NULL : strchr (pminor + 1, '.');
+   if (pmicro)
+     {
+       glong vmajor, vminor = -1, vmicro = -1;
+       *pminor++ = 0;
+       *pmicro++ = 0;
+       vmajor = strtol (vstring, &ep, 10);
+       if (!ep || *ep == 0)
+         vminor = strtol (pminor, &ep, 10);
+       if (!ep || *ep == 0)
+         vmicro = strtol (pmicro, &ep, 10);
+       if ((!ep || *ep == 0 || ep > pmicro) && vmajor >= 0 && vminor >= 0 && vmicro >= 0 &&
+           BSE_VERSION_CMP (vmajor, vminor, vmicro, 0, 0, 0) > 0)
+         {
+           parsed_version = TRUE;
+           if (BSE_VERSION_CMP (vmajor, vminor, vmicro, 0, 5, 0) >= 0)
+             {
+               self->major_version = vmajor;
+               self->minor_version = vminor;
+               self->micro_version = vmicro;
+             }
+         }
+     }
+   g_free (vstring);
+   if (!parsed_version)
+     bse_storage_warn (self, "ignoring invalid version string: %s", scanner->value.v_string);
+   parse_or_return (scanner, ')');               /* eat closing paren */
+   if (0)
+     g_printerr ("bse-version: code: %u.%u.%u file: %u.%u.%u feature(current):%d compat(current):%d 
compat(-1):%d\n",
+                 BST_MAJOR_VERSION, BST_MINOR_VERSION, BST_MICRO_VERSION,
+                 self->major_version, self->minor_version, self->micro_version,
+                 BSE_STORAGE_VERSION (self, BST_MAJOR_VERSION, BST_MINOR_VERSION, BST_MICRO_VERSION),
+                 BSE_STORAGE_COMPAT (self, BST_MAJOR_VERSION, BST_MINOR_VERSION, BST_MICRO_VERSION),
+                 BSE_STORAGE_COMPAT (self, BST_MAJOR_VERSION, BST_MINOR_VERSION, BST_MICRO_VERSION - 1));
+   return G_TOKEN_NONE;
+ }
+ 
+ static BseStorageItemLink*
+ storage_add_item_link (BseStorage           *self,
+                        BseItem              *from_item,
+                        BseStorageRestoreLink restore_link,
+                        gpointer              data,
+                        gchar                *error)
+ {
+   BseStorageItemLink *ilink = g_new0 (BseStorageItemLink, 1);
+   self->item_links = sfi_ring_append (self->item_links, ilink);
+   ilink->from_item = (BseItem*) g_object_ref (from_item);
+   ilink->restore_link = restore_link;
+   ilink->data = data;
+   ilink->error = error;
+ 
+   return ilink;
+ }
+ 
+ void
+ bse_storage_add_restorable (BseStorage             *self,
+                             BseObject              *object)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (self->rstore);
+   g_return_if_fail (self->restorable_objects);
+   g_return_if_fail (BSE_IS_OBJECT (object));
+   g_return_if_fail (BSE_OBJECT_IN_RESTORE (object));
+ 
+   sfi_ppool_set (self->restorable_objects, object);
+ }
+ 
+ static gboolean
+ storage_restorable_objects_foreach (gpointer        data,
+                                     gpointer        pointer)
+ {
+   BseStorage *self = BSE_STORAGE (data);
+   BseObject *object = BSE_OBJECT (pointer);
+   bse_object_restore_finish (object, self->major_version, self->minor_version, self->micro_version);
+   return TRUE;
+ }
+ 
+ void
+ bse_storage_finish_parsing (BseStorage *self)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (self->rstore != NULL);
+ 
+   while (self->item_links)
+     {
+       BseStorageItemLink *ilink = (BseStorageItemLink*) sfi_ring_pop_head (&self->item_links);
+ 
+       if (ilink->error)
+         {
+           gchar *error = g_strdup_format ("unable to resolve link path for item `%s': %s",
+                                           BSE_OBJECT_UNAME (ilink->from_item),
+                                           ilink->error);
+           ilink->restore_link (ilink->data, self, ilink->from_item, NULL, error);
+           g_free (error);
+           if (ilink->to_item)
+             g_object_unref (ilink->to_item);
+           g_free (ilink->error);
+         }
+       else if (ilink->to_item)
+         {
+           ilink->restore_link (ilink->data, self, ilink->from_item, ilink->to_item, NULL);
+           g_object_unref (ilink->to_item);
+         }
+       else if (!ilink->upath)
+         {
+           ilink->restore_link (ilink->data, self, ilink->from_item, NULL, NULL);
+         }
+       else
+         {
+           BseItem *child = NULL, *parent = ilink->from_item;
+           guint pbackup = ilink->pbackup;
+           gchar *error = NULL;
+ 
+           while (pbackup && parent)
+             {
+               pbackup--;
+               parent = parent->parent;
+             }
+           if (!parent)
+             error = g_strdup_format ("failed to find ancestor of item `%s' (branch depth: -%u, "
+                                      "number of parents: %u) while resolving link path \"%s\"",
+                                      BSE_OBJECT_UNAME (ilink->from_item),
+                                      ilink->pbackup,
+                                      ilink->pbackup - pbackup + 1,
+                                      ilink->upath);
+           else
+             {
+               child = storage_path_table_resolve_upath (self, BSE_CONTAINER (parent), ilink->upath);
+               if (!child)
+                 error = g_strdup_format ("failed to find object for item `%s' while resolving link path 
\"%s\" from ancestor `%s'",
+                                          BSE_OBJECT_UNAME (ilink->from_item),
+                                          ilink->upath, BSE_OBJECT_UNAME (parent));
+             }
+           ilink->restore_link (ilink->data, self, ilink->from_item, child, error);
+           g_free (error);
+         }
+       g_object_unref (ilink->from_item);
+       g_free (ilink->upath);
+       g_free (ilink);
+     }
+ 
+   /* finish restorables */
+   sfi_ppool_foreach (self->restorable_objects, storage_restorable_objects_foreach, self);
+   /* clear pool */
+   sfi_ppool_destroy (self->restorable_objects);
+   self->restorable_objects = sfi_ppool_new();
+ }
+ 
+ const gchar*
+ bse_storage_item_get_compat_type (BseItem *item)
+ {
+   const gchar *type = (const char*) g_object_get_data ((GObject*) item, "BseStorage-compat-type");
+   if (!type)
+     type = G_OBJECT_TYPE_NAME (item);
+   return type;
+ }
+ 
+ typedef struct {
+   BseContainer *container;
+   gchar        *uname;
+   BseItem      *item;
+ } UNameChild;
+ 
+ static guint
+ uname_child_hash (gconstpointer uc)
+ {
+   const UNameChild *uchild = (const UNameChild*) uc;
+   guint h = g_str_hash (uchild->uname);
+   h ^= G_HASH_LONG ((long) uchild->container);
+   return h;
+ }
+ 
+ static gint
+ uname_child_equals (gconstpointer uc1,
+                     gconstpointer uc2)
+ {
+   const UNameChild *uchild1 = (const UNameChild*) uc1;
+   const UNameChild *uchild2 = (const UNameChild*) uc2;
+   return (bse_string_equals (uchild1->uname, uchild2->uname) &&
+           uchild1->container == uchild2->container);
+ }
+ 
+ static void
+ uname_child_free (gpointer uc)
+ {
+   UNameChild *uchild = (UNameChild*) uc;
+   g_object_unref (uchild->container);
+   g_free (uchild->uname);
+   g_object_unref (uchild->item);
+   g_free (uchild);
+ }
+ 
+ static void
+ storage_path_table_insert (BseStorage   *self,
+                            BseContainer *container,
+                            const gchar  *uname,
+                            BseItem      *item)
+ {
+   UNameChild key;
+   key.container = container;
+   key.uname = (char*) uname;
+   UNameChild *uchild = (UNameChild*) g_hash_table_lookup (self->path_table, &key);
+   if (!uchild)
+     {
+       uchild = g_new (UNameChild, 1);
+       uchild->container = (BseContainer*) g_object_ref (container);
+       uchild->uname = g_strdup (uname);
+       uchild->item = NULL;
+       g_hash_table_insert (self->path_table, uchild, uchild);
+     }
+   if (uchild->item)
+     g_object_unref (uchild->item);
+   uchild->item = (BseItem*) g_object_ref (item);
+   // DEBUG ("INSERT: (%p,%s) => %p", container, uname, item);
+ }
+ 
+ static inline BseItem*
+ storage_path_table_lookup (BseStorage   *self,
+                            BseContainer *container,
+                            const gchar  *uname)
+ {
+   UNameChild key, *uchild;
+   key.container = container;
+   key.uname = (gchar*) uname;
+   uchild = (UNameChild*) g_hash_table_lookup (self->path_table, &key);
+   // DEBUG ("LOOKUP: (%p,%s) => %p", container, uname, uchild ? uchild->item : NULL);
+   if (uchild)
+     return uchild->item;
+   /* we resort to container lookups in case
+    * object links refer across external
+    * containers.
+    */
+   return bse_container_lookup_item (container, uname);
+ }
+ 
+ static BseItem*
+ storage_path_table_resolve_upath (BseStorage   *self,
+                                   BseContainer *container,
+                                   gchar        *upath)
+ {
 -  gchar *next_uname = strchr (upath, ':');
++  char *next_upath = strchr (upath, ':');
+   /* upaths consist of colon seperated unames from the item's ancestry */
 -  if (next_uname)
++  if (next_upath) /* A:B[:...] */
+     {
++      char *next_next_upath = strchr (next_upath + 1, ':');
+       BseItem *item;
 -      next_uname[0] = 0;
 -      item = storage_path_table_lookup (self, container, upath);
 -      next_uname[0] = ':';
++      next_upath[0] = 0;
++      if (next_next_upath)
++      next_next_upath[0] = 0;
++      /* lookup A */
++      item = storage_path_table_resolve_upath (self, container, upath);
++      next_upath[0] = ':';
++      if (next_next_upath)
++      next_next_upath[0] = ':';
++      /* lookup B[:...] in A */
+       if (BSE_IS_CONTAINER (item))
 -        return storage_path_table_lookup (self, BSE_CONTAINER (item), next_uname + 1);
++      return storage_path_table_resolve_upath (self, BSE_CONTAINER (item), next_upath + 1);
+       else
 -        return NULL;
++      return NULL;
+     }
 -  else
 -    return storage_path_table_lookup (self, container, upath);
++  return storage_path_table_lookup (self, container, upath);
+ }
+ 
+ static void
+ item_link_resolved (gpointer     data,
+                     BseStorage  *self,
+                     BseItem     *item,
+                     BseItem     *dest_item,
+                     const gchar *error)
+ {
+   if (error)
+     bse_storage_warn (self, "%s", error);
+   else
+     {
+       GParamSpec *pspec = (GParamSpec*) data;
+       GValue value = { 0, };
+       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+       g_value_set_object (&value, dest_item);
+       g_object_set_property (G_OBJECT (item), /* no undo */
+                              pspec->name, &value);
+       g_value_unset (&value);
+     }
+ }
+ 
+ static GTokenType item_restore_try_statement (gpointer item, BseStorage *self, GScanner *scanner, gpointer 
user_data);
+ static GTokenType
+ restore_item_property (BseItem    *item,
+                        BseStorage *self)
+ {
+   GScanner *scanner = bse_storage_get_scanner (self);
+   GTokenType expected_token;
+   GParamSpec *pspec;
+   GValue value = { 0, };
+   /* check identifier */
+   if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
+     return SFI_TOKEN_UNMATCHED;
+   /* in theory, we should only find SFI_PARAM_SERVE_STORAGE
+    * properties here, but due to version changes or even
+    * users editing their files, we will simply parse all
+    * kinds of properties (we might want to at least restrict
+    * them to SFI_PARAM_SERVE_STORAGE and SFI_PARAM_SERVE_GUI
+    * at some point...)
+    */
+   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (item), scanner->next_value.v_identifier);
+   if (!pspec)
+     return SFI_TOKEN_UNMATCHED;
+   parse_or_return (scanner, G_TOKEN_IDENTIFIER);        /* eat pspec name */
+   /* parse value, special casing object references */
+   if (g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (pspec), BSE_TYPE_ITEM))
+     {
+       expected_token = bse_storage_parse_item_link (self, item, item_link_resolved, pspec);
+       if (expected_token != G_TOKEN_NONE)
+         return expected_token;
+       parse_or_return (scanner, ')');
+       /* we cannot provide the object value at this time */
+       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+       g_value_set_object (&value, NULL);
+     }
+   else if (g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (pspec), G_TYPE_OBJECT))
+     return bse_storage_warn_skip (self, "unable to restore object property \"%s\" of type `%s'",
+                                   pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
+   else
+     {
+       /* parse the value for this pspec, including the closing ')' */
+       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+       expected_token = bse_storage_parse_param_value (self, &value, pspec);
+       if (expected_token != G_TOKEN_NONE)
+         {
+           g_value_unset (&value);
+           return expected_token;
+         }
+     }
+   /* set property value while preserving the object uname */
+   if ((pspec->flags & G_PARAM_WRITABLE) && !(pspec->flags & G_PARAM_CONSTRUCT_ONLY))
+     g_object_set_property (G_OBJECT (item), /* no undo */
+                            pspec->name, &value);
+   else
+     bse_storage_warn (self, "ignoring non-writable object property \"%s\" of type `%s'",
+                       pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
+   g_value_unset (&value);
+   return G_TOKEN_NONE;
+ }
+ 
+ static GTokenType
+ restore_source_automation (BseItem    *item,
+                            BseStorage *self)
+ {
+   GScanner *scanner = bse_storage_get_scanner (self);
+   /* check identifier */
+   if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER ||
+       !bse_string_equals ("source-automate", scanner->next_value.v_identifier))
+     return SFI_TOKEN_UNMATCHED;
+   /* check object type */
+   if (!BSE_IS_SOURCE (item))
+     return SFI_TOKEN_UNMATCHED;
+   /* eat source-automate */
+   parse_or_return (scanner, G_TOKEN_IDENTIFIER);
+   /* read pspec name */
+   parse_or_return (scanner, G_TOKEN_STRING);
+   /* find pspec */
+   GParamSpec *pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (item), scanner->value.v_string);
+   if (!pspec || !sfi_pspec_check_option (pspec, "automate"))
+     return bse_storage_warn_skip (self, "not an automatable property: \"%s\"", pspec->name);
+   /* parse midi channel */
+   parse_or_return (scanner, G_TOKEN_INT);
+   gint midi_channel = scanner->value.v_int64;
+   /* parse control type */
+   parse_or_return (scanner, G_TOKEN_IDENTIFIER);
+   BseMidiControlType control_type = (BseMidiControlType) sfi_choice2enum (scanner->value.v_identifier, 
BSE_TYPE_MIDI_CONTROL_TYPE);
+   /* close statement */
+   parse_or_return (scanner, ')');
+   BseErrorType error = bse_source_set_automation_property (BSE_SOURCE (item), pspec->name, midi_channel, 
BseMidiSignalType (control_type));
+   if (error)
+     bse_storage_warn (self, "failed to automate property \"%s\": %s", pspec->name, bse_error_blurb (error));
+   return G_TOKEN_NONE;
+ }
+ 
+ static GTokenType
+ restore_container_child (BseContainer *container,
+                          BseStorage   *self)
+ {
+   GScanner *scanner = bse_storage_get_scanner (self);
+   GTokenType expected_token;
+   BseItem *item;
+   const gchar *uname;
+   gchar *type_name, *tmp, *compat_type = NULL;
+   /* check identifier */
+   if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER ||
+       !bse_string_equals ("container-child", scanner->next_value.v_identifier))
+     return SFI_TOKEN_UNMATCHED;
+   parse_or_return (scanner, G_TOKEN_IDENTIFIER);        /* eat identifier */
+   /* parse and validate type::uname argument */
+   parse_or_return (scanner, G_TOKEN_STRING);
+   uname = strchr (scanner->value.v_string, ':');
+   if (!uname || uname[1] != ':')
+     {
+       bse_storage_error (self, "invalid object handle: \"%s\"", scanner->value.v_string);
+       return G_TOKEN_ERROR;
+     }
+   type_name = g_strndup (scanner->value.v_string, uname - scanner->value.v_string);
+   uname += 2;
+   /* handle different versions */
+   tmp = bse_compat_rewrite_type_name (self, type_name);
+   if (tmp)
+     {
+       compat_type = type_name;
+       type_name = tmp;
+     }
+   /* check container's storage filter */
+   if (!bse_container_check_restore (container, type_name))
+     {
+       g_free (type_name);
+       g_free (compat_type);
+       return bse_storage_warn_skip (self, "ignoring child: \"%s\"", scanner->value.v_string);
+     }
+   /* create container child */
+   tmp = g_strconcat (type_name, "::", uname, NULL);
+   g_free (type_name);
+   item = bse_container_retrieve_child (container, tmp);
+   if (item)
+     g_object_set_data_full ((GObject*) item, "BseStorage-compat-type", compat_type, g_free);
+   else
+     g_free (compat_type);
+   g_free (tmp);
+   if (!item)
+     return bse_storage_warn_skip (self, "failed to create object from (invalid?) handle: \"%s\"",
+                                   scanner->value.v_string);
+   /* provide compatibility setup (e.g. property defaults) */
+   bse_item_compat_setup (item, self->major_version, self->minor_version, self->micro_version);
+   storage_path_table_insert (self, container, uname, item);
+   /* restore_item reads out closing parenthesis */
+   g_object_ref (item);
+   expected_token = bse_storage_parse_rest (self, item, item_restore_try_statement, NULL);
+   g_object_unref (item);
+   return expected_token;
+ }
+ 
+ static GTokenType
+ item_restore_try_statement (gpointer    _item,
+                             BseStorage *self,
+                             GScanner   *scanner,
+                             gpointer    user_data)
+ {
+   BseItem *item = BSE_ITEM (_item);
+   GTokenType expected_token = SFI_TOKEN_UNMATCHED;
+   /* ensure that the statement starts out with an identifier */
+   if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
+     {
+       g_scanner_get_next_token (scanner);
+       return G_TOKEN_IDENTIFIER;
+     }
+   /* this is pretty much the *only* place where something else than
+    * G_TOKEN_NONE may be returned without erroring out. return values:
+    * G_TOKEN_NONE        - statement got parsed, advance to next statement
+    * SFI_TOKEN_UNMATCHED - statement not recognized, try further
+    * anything else       - encountered (syntax/semantic) error during parsing
+    */
+   bse_object_restore_start (BSE_OBJECT (item), self);
+   if (expected_token == SFI_TOKEN_UNMATCHED)
+     expected_token = restore_item_property (item, self);
+   if (expected_token == SFI_TOKEN_UNMATCHED)
+     expected_token = restore_source_automation (item, self);
+   if (expected_token == SFI_TOKEN_UNMATCHED)
+     expected_token = BSE_OBJECT_GET_CLASS (item)->restore_private ((BseObject*) item, self, scanner);
+   if (expected_token == SFI_TOKEN_UNMATCHED)
+     expected_token = bse_parasite_restore ((BseObject*) item, self);
+   if (expected_token == SFI_TOKEN_UNMATCHED && BSE_IS_CONTAINER (item))
+     expected_token = restore_container_child ((BseContainer*) item, self);
+   if (expected_token == SFI_TOKEN_UNMATCHED && strcmp (scanner->next_value.v_identifier, "bse-version") == 
0)
+     expected_token = storage_parse_bse_version (self);
+   return expected_token;
+ }
+ 
+ GTokenType
+ bse_storage_restore_item (BseStorage *self,
+                           gpointer    item)
+ {
+   GTokenType expected_token;
+   g_return_val_if_fail (BSE_IS_STORAGE (self), G_TOKEN_ERROR);
+   g_return_val_if_fail (BSE_IS_ITEM (item), G_TOKEN_ERROR);
+   g_object_ref (self);
+   g_object_ref (item);
+   expected_token = sfi_rstore_parse_until (self->rstore, G_TOKEN_EOF, item,
+                                            (SfiStoreParser) item_restore_try_statement, NULL);
+   g_object_unref (item);
+   g_object_unref (self);
+   return expected_token;
+ }
+ 
+ GTokenType
+ bse_storage_parse_rest (BseStorage     *self,
+                         gpointer        context_data,
+                         BseTryStatement try_statement,
+                         gpointer        user_data)
+ {
+   g_return_val_if_fail (BSE_IS_STORAGE (self), G_TOKEN_ERROR);
+   g_return_val_if_fail (self->rstore != NULL, G_TOKEN_ERROR);
+   return sfi_rstore_parse_until (self->rstore, GTokenType (')'), context_data, (SfiStoreParser) 
try_statement, user_data);
+ }
+ 
+ gboolean
+ bse_storage_check_parse_negate (BseStorage *self)
+ {
+   g_return_val_if_fail (BSE_IS_STORAGE (self), FALSE);
+   if (g_scanner_peek_next_token (bse_storage_get_scanner (self)) == '-')
+     {
+       g_scanner_get_next_token (bse_storage_get_scanner (self));
+       return TRUE;
+     }
+   else
+     return FALSE;
+ }
+ 
+ void
+ bse_storage_put_param (BseStorage   *self,
+                        const GValue *value,
+                        GParamSpec   *pspec)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (self->wstore);
+   g_return_if_fail (G_IS_VALUE (value));
+   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+   sfi_wstore_put_param (self->wstore, value, pspec);
+ }
+ 
+ GTokenType
+ bse_storage_parse_param_value (BseStorage *self,
+                                GValue     *value,
+                                GParamSpec *pspec)
+ {
+   g_return_val_if_fail (BSE_IS_STORAGE (self), G_TOKEN_ERROR);
+   g_return_val_if_fail (self->rstore, G_TOKEN_ERROR);
+   return sfi_rstore_parse_param (self->rstore, value, pspec);
+ }
+ 
+ void
+ bse_storage_put_item_link (BseStorage *self,
+                            BseItem    *from_item,
+                            BseItem    *to_item)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (self->wstore);
+   g_return_if_fail (BSE_IS_ITEM (from_item));
+   g_return_if_fail (BSE_IS_ITEM (to_item));
+   if (!to_item)                                         /* special case (1) */
+     {
+       bse_storage_puts (self, SFI_SERIAL_NULL_TOKEN);
+     }
+   else          /* ordinary object link within a project or other container */
+     {
+       BseItem *tmp, *common_ancestor;
+       guint pbackup = 0;
+       gchar *upath, *epath;
+       g_return_if_fail (BSE_IS_ITEM (to_item));
+       common_ancestor = bse_item_common_ancestor (from_item, to_item);
+       g_return_if_fail (BSE_IS_CONTAINER (common_ancestor));
+       sfi_ppool_set (self->referenced_items, to_item);
+       /* figure number of parent backup levels to reach common ancestor */
+       for (tmp = from_item; tmp != common_ancestor; tmp = tmp->parent)
+         pbackup++;
+       /* path to reach to_item */
+       upath = bse_container_make_upath (BSE_CONTAINER (common_ancestor), to_item);
+       /* store path reference */
+       epath = g_strescape (upath, NULL);
+       bse_storage_printf (self, "(link %u \"%s\")", pbackup, epath);
+       g_free (epath);
+       g_free (upath);
+     }
+ }
+ 
+ #ifdef DOXER
+ /**
+  * @param data                user data
+  * @param storage     BseStorage instance
+  * @param from_item   link owner
+  * @param to_item     link target or NULL
+  * @param error       error string describing failing link lookups
+  *
+  * BseStorageRestoreLink() is a user supplied handler to be called
+  * at the end of a parsing stage, once object references could be
+  * resolved. Failing resolutions are indicated by non NULL @a error
+  * strings.
+  */
+ typedef void (*BseStorageRestoreLink)   (gpointer        data,
+                                          BseStorage     *storage,
+                                          BseItem        *from_item,
+                                          BseItem        *to_item,
+                                          const gchar    *error);
+ #endif
+ 
+ /**
+  * @param self        valid BseStorage
+  * @param from_item   link owner
+  * @param restore_link        BseStorageRestoreLink handler to be called once the link was resolved
+  * @param data                user data passed into @a restore_link()
+  * @return            expected token in case of a parsing error (G_TOKEN_NONE on success)
+  *
+  * Parse an item link statement and return the expected token if a parsing
+  * error occours. Item links are resolved at the end of the parsing stage
+  * by calling the user supplied handler @a restore_link() with the link target
+  * amongst its arguments (see BseStorageRestoreLink()).
+  */
+ GTokenType
+ bse_storage_parse_item_link (BseStorage           *self,
+                              BseItem              *from_item,
+                              BseStorageRestoreLink restore_link,
+                              gpointer              data)
+ {
+   GScanner *scanner;
+   BseStorageItemLink *ilink;
+   GTokenType expected_token;
+   g_return_val_if_fail (BSE_IS_STORAGE (self), G_TOKEN_ERROR);
+   g_return_val_if_fail (self->rstore, G_TOKEN_ERROR);
+   g_return_val_if_fail (BSE_IS_ITEM (from_item), G_TOKEN_ERROR);
+   g_return_val_if_fail (restore_link != NULL, G_TOKEN_ERROR);
+   scanner = bse_storage_get_scanner (self);
+ #define parse_or_goto(etoken,label) \
+   { expected_token = (etoken); if (g_scanner_get_next_token (scanner) != expected_token) goto label; }
+ #define peek_or_goto(etoken,label)  \
+   { expected_token = (etoken); if (g_scanner_peek_next_token (scanner) != expected_token) \
+     { g_scanner_get_next_token (scanner); goto label; } }
+   g_scanner_get_next_token (scanner);
+   bse_object_restore_start (BSE_OBJECT (from_item), self);
+   if (sfi_serial_check_parse_null_token (scanner))
+     {
+       ilink = storage_add_item_link (self, from_item, restore_link, data, NULL);
+     }
+   else if (scanner->token == '(')
+     {
+       parse_or_goto (G_TOKEN_IDENTIFIER, error_parse_link);
+       if (strcmp (scanner->value.v_identifier, "link") == 0)
+         {
+           guint pbackup = 0;
+           if (g_scanner_peek_next_token (scanner) == G_TOKEN_INT)
+             {
+               g_scanner_get_next_token (scanner);       /* eat int */
+               pbackup = scanner->value.v_int64;
+             }
+           parse_or_goto (G_TOKEN_STRING, error_parse_link);
+           peek_or_goto (GTokenType (')'), error_parse_link);
+           ilink = storage_add_item_link (self, from_item, restore_link, data, NULL);
+           ilink->upath = g_strdup (scanner->value.v_string);
+           ilink->pbackup = pbackup;
+         }
+       else
+         {
+           expected_token = G_TOKEN_IDENTIFIER;
+           goto error_parse_link;
+         }
+       parse_or_goto (GTokenType (')'), error_parse_link);
+     }
+   else
+     {
+       expected_token = GTokenType ('(');
+       goto error_parse_link;
+     }
+   return G_TOKEN_NONE;
+ #undef  parse_or_goto
+ #undef  peek_or_goto
+  error_parse_link:
+   ilink = storage_add_item_link (self, from_item, restore_link, data, g_strdup ("failed to parse link 
path"));
+   return expected_token;
+ }
+ 
+ void
+ bse_storage_warn_str (BseStorage *self, const std::string &string)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   if (self->rstore)
+     sfi_rstore_warn (self->rstore, string);
+   else
+     g_printerr ("BseStorage: while storing: %s", string.c_str());
+ }
+ 
+ GTokenType
+ bse_storage_skip (BseStorage *self, const std::string &string)
+ {
+   GTokenType token;
+   g_return_val_if_fail (BSE_IS_STORAGE (self), G_TOKEN_ERROR);
+   g_return_val_if_fail (self->rstore != NULL, G_TOKEN_ERROR);
+   token = sfi_rstore_warn_skip (self->rstore, string);
+   return token;
+ }
+ 
+ void
+ bse_storage_error_str (BseStorage *self, const std::string &string)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   if (self->rstore)
+     sfi_rstore_error (self->rstore, string);
+   else
+     g_printerr ("BseStorage: ERROR: while storing: %s\n", string.c_str());
+ }
+ 
+ static void
+ bse_item_store_property (BseItem    *item,
+                          BseStorage *storage,
+                          GValue     *value,
+                          GParamSpec *pspec)
+ {
+   if (g_type_is_a (G_VALUE_TYPE (value), BSE_TYPE_ITEM))
+     {
+       bse_storage_break (storage);
+       bse_storage_putc (storage, '(');
+       bse_storage_puts (storage, pspec->name);
+       bse_storage_putc (storage, ' ');
+       bse_storage_put_item_link (storage, item, (BseItem*) g_value_get_object (value));
+       bse_storage_putc (storage, ')');
+     }
+   else if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_OBJECT))
+     g_warning ("%s: unable to store object property \"%s\" of type `%s'",
+                G_STRLOC, pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
+   else
+     bse_storage_put_param (storage, value, pspec);
+ }
+ 
+ static void
+ bse_source_store_automation (BseSource  *source,
+                              BseStorage *storage,
+                              GParamSpec *pspec)
+ {
+   guint midi_channel = 0;
+   BseMidiSignalType signal_type = BseMidiSignalType (0);
+   bse_source_get_automation_property (source, pspec->name, &midi_channel, &signal_type);
+   BseMidiControlType control_type = BseMidiControlType (signal_type);
+   if (control_type)
+     {
+       bse_storage_break (storage);
+       bse_storage_printf (storage, "(source-automate \"%s\" %u %s)", pspec->name,
+                           midi_channel, sfi_enum2choice (control_type, BSE_TYPE_MIDI_CONTROL_TYPE));
+     }
+ }
+ 
+ static void
+ store_item_properties (BseItem    *item,
+                        BseStorage *storage)
+ {
+   GParamSpec **pspecs;
+   guint n;
+   /* dump the object properties, starting out at the base class */
+   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (item), &n);
+   while (n--)
+     {
+       GParamSpec *pspec = pspecs[n];
+       if (sfi_pspec_check_option (pspec, "S")) /* check serializable */
+         {
+           GValue value = { 0, };
+           g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+           g_object_get_property (G_OBJECT (item), pspec->name, &value);
+           if (!g_param_value_defaults (pspec, &value) ||
+               !sfi_pspec_check_option (pspec, "skip-default"))
+             bse_item_store_property (item, storage, &value, pspec);
+           g_value_unset (&value);
+           if (sfi_pspec_check_option (pspec, "automate") && BSE_IS_SOURCE (item))
+             bse_source_store_automation (BSE_SOURCE (item), storage, pspec);
+         }
+     }
+   g_free (pspecs);
+ }
+ 
+ void
+ bse_storage_store_item (BseStorage *self, BseItem *item)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (self->wstore);
+   g_return_if_fail (BSE_IS_ITEM (item));
+   g_object_ref (self);
+   g_object_ref (item);
+   sfi_ppool_set (self->stored_items, item);
+   store_item_properties (item, self);
+   BSE_OBJECT_GET_CLASS (item)->store_private (BSE_OBJECT (item), self);
+   bse_parasite_store (BSE_OBJECT (item), self);
+   if (BSE_IS_CONTAINER (item))
+     bse_container_store_children ((BseContainer*) item, self);
+   g_object_unref (item);
+   g_object_unref (self);
+ }
+ 
+ void
+ bse_storage_store_child (BseStorage *self, BseItem *item)
+ {
+   gchar *uname;
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (self->wstore);
+   g_return_if_fail (BSE_IS_ITEM (item));
+   uname = g_strescape (BSE_OBJECT_UNAME (item), NULL);
+   bse_storage_break (self);
+   bse_storage_printf (self, "(%s \"%s::%s\"", "container-child", G_OBJECT_TYPE_NAME (item), uname);
+   g_free (uname);
+   bse_storage_push_level (self);
+   bse_storage_store_item (self, item);
+   bse_storage_pop_level (self);
+   bse_storage_putc (self, ')');
+ }
+ 
+ void
+ bse_storage_putf (BseStorage *self,
+                   gfloat      vfloat)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (self->wstore);
+   sfi_wstore_putf (self->wstore, vfloat);
+ }
+ 
+ void
+ bse_storage_putd (BseStorage *self,
+                   gdouble     vdouble)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (self->wstore);
+   sfi_wstore_putd (self->wstore, vdouble);
+ }
+ 
+ void
+ bse_storage_putr (BseStorage     *self,
+                   SfiReal         vreal,
+                   const gchar    *hints)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (self->wstore);
+   if (hints && g_option_check (hints, "f"))     /* check float option */
+     bse_storage_putf (self, vreal);
+   else
+     bse_storage_putd (self, vreal);
+ }
+ 
+ void
+ bse_storage_put_xinfos (BseStorage *self,
+                         gchar     **xinfos)
+ {
+   xinfos = bse_xinfos_dup_consolidated (xinfos, FALSE);
+   if (xinfos && xinfos[0])
+     {
+       bse_storage_break (self);
+       gchar *str = g_strescape (xinfos[0], NULL);
+       bse_storage_printf (self, " (\"%s\"", str);
+       g_free (str);
+       guint i;
+       bse_storage_push_level (self);
+       for (i = 1; xinfos[i]; i++)
+         {
+           bse_storage_break (self);
+           str = g_strescape (xinfos[i], NULL);
+           bse_storage_printf (self, "\"%s\"", str);
+           g_free (str);
+         }
+       bse_storage_pop_level (self);
+       bse_storage_puts (self, ")");
+     }
+   else
+     bse_storage_printf (self, "#f");
+   g_strfreev (xinfos);
+ }
+ 
+ GTokenType
+ bse_storage_parse_xinfos (BseStorage *self,
+                           gchar    ***xinfosp)
+ {
+   GScanner *scanner = bse_storage_get_scanner (self);
+   g_scanner_get_next_token (scanner);
+   if (scanner->token == '#')    /* parse "#f" => NULL */
+     {
+       g_scanner_get_next_token (scanner);
+       if (scanner->token == 'f' || scanner->token == 'F')
+         {
+           *xinfosp = NULL;
+           return G_TOKEN_NONE;
+         }
+       /* everything else, even #t is bogus */
+       return GTokenType ('f');
+     }
+   else if (scanner->token == '(')
+     {
+       gchar **xinfos = NULL;
+       while (g_scanner_get_next_token (scanner) != ')')
+         {
+           if (scanner->token == G_TOKEN_STRING)
+             xinfos = bse_xinfos_parse_assignment (xinfos, scanner->value.v_string);
+           else
+             return G_TOKEN_STRING;
+         }
+       *xinfosp = bse_xinfos_dup_consolidated (xinfos, FALSE);
+       g_strfreev (xinfos);
+       return G_TOKEN_NONE;
+     }
+   else
+     return GTokenType ('(');
+ }
+ 
+ static GTokenType
+ parse_dblock_data_handle (BseStorage     *self,
+                           GslDataHandle **data_handle_p,
+                           guint          *n_channels_p,
+                           gfloat         *mix_freq_p,
+                           gfloat         *osc_freq_p)
+ {
+   GScanner *scanner = bse_storage_get_scanner (self);
+   BseStorageDBlock *dblock;
+   gulong id;
+   parse_or_return (scanner, G_TOKEN_INT);
+   id = scanner->value.v_int64;
+   parse_or_return (scanner, ')');
+   dblock = bse_storage_get_dblock (self, id);
+   if (!dblock)
+     {
+       bse_storage_error (self, "failed to lookup internal data handle with id: %lu", id);
+       return G_TOKEN_ERROR;
+     }
+   *data_handle_p = gsl_data_handle_ref (dblock->dhandle);       /* fake "creating" a data handle */
+   if (n_channels_p)
+     *n_channels_p = dblock->n_channels;
+   if (mix_freq_p)
+     *mix_freq_p = dblock->mix_freq;
+   if (osc_freq_p)
+     *osc_freq_p = dblock->osc_freq;
+   return G_TOKEN_NONE;
+ }
+ 
+ typedef struct {
+   GslDataHandle *dhandle;
+   guint          opened : 1;
+   guint          bpv, format, byte_order;
+   BseStorage    *storage;
+   guint          length;
+ } WStoreDHandle;
+ 
+ static void
+ wstore_data_handle_destroy (gpointer data)
+ {
+   WStoreDHandle *wh = (WStoreDHandle*) data;
+   if (wh->opened)
+     gsl_data_handle_close (wh->dhandle);
+   gsl_data_handle_unref (wh->dhandle);
+   g_free (wh);
+ }
+ 
+ static gint /* -errno || length */
+ wstore_data_handle_reader (gpointer data,
+                            void    *buffer,
+                            guint    blength)
+ {
+   WStoreDHandle *wh = (WStoreDHandle*) data;
+   GslLong n;
+   if (!wh->opened)
+     {
+       BseErrorType error = gsl_data_handle_open (wh->dhandle);
+       if (error)
+         {
+           bse_storage_error (wh->storage, "failed to open data handle: %s", bse_error_blurb (error));
+           return -ENOENT;
+         }
+       wh->opened = TRUE;
+     }
+   /* catch end */
+   if (wh->length >= gsl_data_handle_length (wh->dhandle))
+     return 0;
+   do
+     n = gsl_data_handle_read (wh->dhandle, wh->length, blength / sizeof (gfloat), (float*) buffer);
+   while (n < 0 && errno == EINTR);
+   if (n < 0)    /* bail out */
+     {
+       bse_storage_error (wh->storage, "failed to read from data handle");
+       return -EIO;
+     }
+   wh->length += n;
+   return gsl_conv_from_float_clip (GslWaveFormatType (wh->format), wh->byte_order, (const float*) buffer, 
buffer, n);
+ }
+ 
+ void
+ bse_storage_put_data_handle (BseStorage    *self,
+                              guint          significant_bits,
+                              GslDataHandle *dhandle)
+ {
+   g_return_if_fail (BSE_IS_STORAGE (self));
+   g_return_if_fail (self->wstore);
+   g_return_if_fail (dhandle != NULL);
+   g_return_if_fail (GSL_DATA_HANDLE_OPENED (dhandle));
+   if (BSE_STORAGE_DBLOCK_CONTAINED (self))
+     {
+       /* stored as binary data block in memory for undo storage */
+       gulong id = bse_storage_add_dblock (self, dhandle);
+       bse_storage_break (self);
+       bse_storage_printf (self, "(%s %lu)", g_quark_to_string (quark_dblock_data_handle), id);
+       return;
+     }
+   GslDataHandle *test_handle, *tmp_handle = dhandle;
+   do    /* skip comment or cache handles */
+     {
+       test_handle = tmp_handle;
+       tmp_handle = gsl_data_handle_get_source (test_handle);
+     }
+   while (tmp_handle);   /* skip comment or cache handles */
+   GslVorbis1Handle *vhandle = gsl_vorbis1_handle_new (test_handle, gsl_vorbis_make_serialno());
+   Flac1Handle      *flac_handle = Flac1Handle::create (test_handle);
+   if (vhandle)  /* save already compressed Ogg/Vorbis data */
+     {
+       bse_storage_break (self);
+       bse_storage_printf (self, "(%s ", g_quark_to_string (quark_vorbis_data_handle));
+       bse_storage_putf (self, gsl_data_handle_osc_freq (dhandle));
+       bse_storage_push_level (self);
+       bse_storage_break (self);
+       gsl_vorbis1_handle_put_wstore (vhandle, self->wstore);
+       bse_storage_pop_level (self);
+       bse_storage_putc (self, ')');
+     }
+   else if (flac_handle) /* save flac compressed handle */
+     {
+       bse_storage_break (self);
+       bse_storage_printf (self, "(%s ", g_quark_to_string (quark_flac_data_handle));
+       bse_storage_putf (self, gsl_data_handle_osc_freq (dhandle));
+       bse_storage_push_level (self);
+       bse_storage_break (self);
+       flac_handle->put_wstore (self->wstore);
+       bse_storage_pop_level (self);
+       bse_storage_putc (self, ')');
+     }
+   else          /* save raw data handle */
+     {
+       if (significant_bits < 1)
+         significant_bits = 32;
+       const uint bitdepth = gsl_data_handle_bit_depth (dhandle);
+       significant_bits = MIN (bitdepth, significant_bits);
+       GslWaveFormatType format;
+       if (significant_bits > 16)
+         format = GSL_WAVE_FORMAT_FLOAT;
+       else if (significant_bits <= 8)
+         format = GSL_WAVE_FORMAT_SIGNED_8;
+       else
+         format = GSL_WAVE_FORMAT_SIGNED_16;
+       bse_storage_break (self);
+       bse_storage_printf (self,
+                           "(%s %u %s %s",
+                           g_quark_to_string (quark_raw_data_handle),
+                           gsl_data_handle_n_channels (dhandle),
+                           gsl_wave_format_to_string (format),
+                           gsl_byte_order_to_string (G_LITTLE_ENDIAN));
+       bse_storage_puts (self, " ");
+       bse_storage_putf (self, gsl_data_handle_mix_freq (dhandle));
+       bse_storage_puts (self, " ");
+       bse_storage_putf (self, gsl_data_handle_osc_freq (dhandle));
+       bse_storage_push_level (self);
+       bse_storage_break (self);
+       WStoreDHandle *wh = g_new0 (WStoreDHandle, 1);
+       wh->dhandle = gsl_data_handle_ref (dhandle);
+       wh->format = format;
+       wh->byte_order = G_LITTLE_ENDIAN;
+       wh->bpv = gsl_wave_format_byte_width (format);
+       wh->storage = self;
+       sfi_wstore_put_binary (self->wstore, wstore_data_handle_reader, wh, wstore_data_handle_destroy);
+       bse_storage_pop_level (self);
+       bse_storage_putc (self, ')');
+     }
+ }
+ 
+ static GTokenType
+ parse_raw_data_handle (BseStorage     *self,
+                        GslDataHandle **data_handle_p,
+                        guint          *n_channels_p,
+                        gfloat         *mix_freq_p,
+                        gfloat         *osc_freq_p)
+ {
+   GScanner *scanner = bse_storage_get_scanner (self);
+   guint n_channels, byte_order;
+   gfloat mix_freq, osc_freq;
+   SfiNum offset, length;
+   GTokenType token;
+   parse_or_return (scanner, G_TOKEN_INT);
+   n_channels = scanner->value.v_int64;
+   if (n_channels <= 0 || n_channels > 256)
+     return bse_storage_warn_skip (self, "invalid number of channels: %u", n_channels);
+   parse_or_return (scanner, G_TOKEN_IDENTIFIER);
+   GslWaveFormatType format = gsl_wave_format_from_string (scanner->value.v_identifier);
+   if (format == GSL_WAVE_FORMAT_NONE)
+     return bse_storage_warn_skip (self, "unknown format for data handle: %s", scanner->value.v_identifier);
+   parse_or_return (scanner, G_TOKEN_IDENTIFIER);
+   byte_order = gsl_byte_order_from_string (scanner->value.v_identifier);
+   if (!byte_order)
+     return bse_storage_warn_skip (self, "unknown byte-order for data handle: %s", 
scanner->value.v_identifier);
+   g_scanner_get_next_token (scanner);
+   if (scanner->token == G_TOKEN_INT)
+     mix_freq = scanner->value.v_int64;
+   else if (scanner->token == G_TOKEN_FLOAT)
+     mix_freq = scanner->value.v_float;
+   else
+     return G_TOKEN_FLOAT;
+   g_scanner_get_next_token (scanner);
+   if (scanner->token == G_TOKEN_INT)
+     osc_freq = scanner->value.v_int64;
+   else if (scanner->token == G_TOKEN_FLOAT)
+     osc_freq = scanner->value.v_float;
+   else
+     return G_TOKEN_FLOAT;
+   if (osc_freq <= 0 || mix_freq < 4000 || osc_freq >= mix_freq / 2)
+     return bse_storage_warn_skip (self, "invalid oscillating/mixing frequencies: %.7g/%.7g", osc_freq, 
mix_freq);
+   token = sfi_rstore_parse_binary (self->rstore, &offset, &length);
+   if (token != G_TOKEN_NONE)
+     return token;
+   length /= gsl_wave_format_byte_width (format);
+   parse_or_return (scanner, ')');
+   if (length < 1)
+     {
+       bse_storage_warn (self, "encountered empty data handle");
+       *data_handle_p = NULL;
+     }
+   else
+     *data_handle_p = gsl_wave_handle_new (self->rstore->fname,
+                                           n_channels, format, byte_order,
+                                           mix_freq, osc_freq,
+                                           offset, length, NULL);
+   if (n_channels_p)
+     *n_channels_p = n_channels;
+   if (mix_freq_p)
+     *mix_freq_p = mix_freq;
+   if (osc_freq_p)
+     *osc_freq_p = osc_freq;
+   return G_TOKEN_NONE;
+ }
+ 
+ static GTokenType
+ parse_vorbis_or_flac_data_handle (BseStorage     *self,
+                                   GQuark          quark,
+                                   GslDataHandle **data_handle_p,
+                                   guint          *n_channels_p,
+                                   gfloat         *mix_freq_p,
+                                   gfloat         *osc_freq_p)
+ {
+   GScanner *scanner = bse_storage_get_scanner (self);
+   GTokenType token;
+   gfloat osc_freq;
+   g_scanner_get_next_token (scanner);
+   if (scanner->token == G_TOKEN_INT)
+     osc_freq = scanner->value.v_int64;
+   else if (scanner->token == G_TOKEN_FLOAT)
+     osc_freq = scanner->value.v_float;
+   else
+     return G_TOKEN_FLOAT;
+   if (osc_freq <= 0)
+     return bse_storage_warn_skip (self, "invalid oscillating frequency: %.7g", osc_freq);
+   if (osc_freq_p)
+     *osc_freq_p = osc_freq;
+   SfiNum offset, length;
+   token = sfi_rstore_parse_zbinary (self->rstore, &offset, &length);
+   if (token != G_TOKEN_NONE)
+     return token;
+   parse_or_return (scanner, ')');
+   if (length < 1)
+     {
+       bse_storage_warn (self, "encountered empty data handle");
+       *data_handle_p = NULL;
+     }
+   else
+     {
+       gfloat mix_freq;
+       if (quark == quark_vorbis_data_handle)
+         {
+           *data_handle_p = gsl_data_handle_new_ogg_vorbis_zoffset (self->rstore->fname, osc_freq,
+                                                                    offset, length, n_channels_p, &mix_freq);
+         }
+       else if (quark == quark_flac_data_handle)
+         {
+           *data_handle_p = bse_data_handle_new_flac_zoffset (self->rstore->fname, osc_freq,
+                                                              offset, length, n_channels_p, &mix_freq);
+         }
+       else
+         {
+           return bse_storage_warn_skip (self, "unknown compressed data handle type in 
parse_vorbis_or_flac_data_handle");
+         }
+       if (osc_freq <= 0 || mix_freq < 4000 || osc_freq >= mix_freq / 2)
+         return bse_storage_warn_skip (self, "invalid oscillating/mixing frequencies: %.7g/%.7g", osc_freq, 
mix_freq);
+       if (mix_freq_p)
+         *mix_freq_p = mix_freq;
+     }
+   return G_TOKEN_NONE;
+ }
+ 
+ gboolean
+ bse_storage_match_data_handle (BseStorage *self,
+                                GQuark      quark)
+ {
+   if (BSE_STORAGE_DBLOCK_CONTAINED (self) &&
+       quark == quark_dblock_data_handle)
+     return TRUE;
+   if (quark == quark_raw_data_handle ||
+       quark == quark_vorbis_data_handle ||
+       quark == quark_flac_data_handle)
+     return TRUE;
+   return FALSE;
+ }
+ 
+ static GTokenType
+ parse_data_handle_trampoline (BseStorage     *self,
+                               gboolean        statement_opened,
+                               GslDataHandle **data_handle_p,
+                               guint          *n_channels_p,
+                               gfloat         *mix_freq_p,
+                               gfloat         *osc_freq_p)
+ {
+   GScanner *scanner = bse_storage_get_scanner (self);
+   GQuark quark;
+   *data_handle_p = NULL;
+   if (n_channels_p)
+     *n_channels_p = 0;
+   if (mix_freq_p)
+     *mix_freq_p = 0;
+   if (osc_freq_p)
+     *osc_freq_p = 0;
+   if (!statement_opened)
+     parse_or_return (scanner, '(');
+   parse_or_return (scanner, G_TOKEN_IDENTIFIER);
+   quark = g_quark_try_string (scanner->value.v_identifier);
+   if (BSE_STORAGE_DBLOCK_CONTAINED (self) && quark == quark_dblock_data_handle)
+     return parse_dblock_data_handle (self, data_handle_p, n_channels_p, mix_freq_p, osc_freq_p);
+   if (quark == quark_raw_data_handle)
+     return parse_raw_data_handle (self, data_handle_p, n_channels_p, mix_freq_p, osc_freq_p);
+   else if (quark == quark_vorbis_data_handle || quark == quark_flac_data_handle)
+     return parse_vorbis_or_flac_data_handle (self, quark, data_handle_p, n_channels_p, mix_freq_p, 
osc_freq_p);
+   if (BSE_STORAGE_COMPAT (self, 0, 5, 1) && quark == quark_bse_storage_binary_v0)
+     return compat_parse_data_handle (self, data_handle_p, n_channels_p, mix_freq_p, osc_freq_p);
+   bse_storage_error (self, "unknown data handle keyword: %s", scanner->value.v_identifier);
+   return G_TOKEN_ERROR;
+ }
+ 
+ GTokenType
+ bse_storage_parse_data_handle (BseStorage     *self,
+                                GslDataHandle **data_handle_p,
+                                guint          *n_channels_p,
+                                gfloat         *mix_freq_p,
+                                gfloat         *osc_freq_p)
+ {
+   g_return_val_if_fail (BSE_IS_STORAGE (self), G_TOKEN_ERROR);
+   g_return_val_if_fail (self->rstore, G_TOKEN_ERROR);
+   g_return_val_if_fail (data_handle_p != NULL, G_TOKEN_ERROR);
+   return parse_data_handle_trampoline (self, FALSE, data_handle_p, n_channels_p, mix_freq_p, osc_freq_p);
+ }
+ 
+ GTokenType
+ bse_storage_parse_data_handle_rest (BseStorage     *self,
+                                     GslDataHandle **data_handle_p,
+                                     guint          *n_channels_p,
+                                     gfloat         *mix_freq_p,
+                                     gfloat         *osc_freq_p)
+ {
+   g_return_val_if_fail (BSE_IS_STORAGE (self), G_TOKEN_ERROR);
+   g_return_val_if_fail (self->rstore, G_TOKEN_ERROR);
+   g_return_val_if_fail (data_handle_p != NULL, G_TOKEN_ERROR);
+   return parse_data_handle_trampoline (self, TRUE, data_handle_p, n_channels_p, mix_freq_p, osc_freq_p);
+ }
+ 
++/* blobs */
++
++BseStorageBlob *
++bse_storage_blob_ref (BseStorageBlob *blob)
++{
++  g_return_val_if_fail (blob != NULL, NULL);
++  g_return_val_if_fail (blob->ref_count > 0, NULL);
++
++  GSL_SPIN_LOCK (&blob->mutex);
++  blob->ref_count++;
++  GSL_SPIN_UNLOCK (&blob->mutex);
++
++  return blob;
++}
++
++const gchar *
++bse_storage_blob_file_name (BseStorageBlob *blob)
++{
++  g_return_val_if_fail (blob != NULL, NULL);
++  g_return_val_if_fail (blob->ref_count > 0, NULL);
++
++  GSL_SPIN_LOCK (&blob->mutex);
++  const gchar *file_name = blob->file_name;
++  GSL_SPIN_UNLOCK (&blob->mutex);
++
++  return file_name;
++}
++
++void
++bse_storage_blob_unref (BseStorageBlob *blob)
++{
++  g_return_if_fail (blob != NULL);
++  g_return_if_fail (blob->ref_count > 0);
++
++  GSL_SPIN_LOCK (&blob->mutex);
++  blob->ref_count--;
++  gboolean destroy = blob->ref_count == 0;
++  GSL_SPIN_UNLOCK (&blob->mutex);
++  if (destroy)
++    {
++      if (blob->is_temp_file)
++      {
++        unlink (blob->file_name);
++        /* FIXME: check error code and do what? */
++      }
++      sfi_mutex_destroy (&blob->mutex);
++      g_free (blob->file_name);
++      blob->file_name = NULL;
++      bse_id_free (blob->id);
++      g_free (blob);
++    }
++}
++
++/* search in /tmp for files called "bse-<user>-<pid>*"
++ * delete files if the pid does not exist any longer
++ */
++void
++bse_storage_blob_clean_files()
++{
++  GError *error;
++  const char *tmp_dir = g_get_tmp_dir();
++  GDir *dir = g_dir_open (tmp_dir, 0, &error);
++  if (dir)
++    {
++      char *pattern = g_strdup_printf ("bse-%s-", g_get_user_name());
++      const char *file_name;
++      while ((file_name = g_dir_read_name (dir)))
++      {
++        if (strncmp (pattern, file_name, strlen (pattern)) == 0)
++          {
++            int pid = atoi (file_name + strlen (pattern));
++
++              if (kill (pid, 0) == -1 && errno == ESRCH)
++              {
++                char *path = g_strdup_printf ("%s/%s", tmp_dir, file_name);
++                unlink (path);
++                g_free (path);
++              }
++          }
++      }
++      g_free (pattern);
++      g_dir_close (dir);
++    }
++}
++
++BseStorageBlob *
++bse_storage_blob_new_from_file (const char *file_name,
++                                gboolean    is_temp_file)
++{
++  BseStorageBlob *blob = g_new0 (BseStorageBlob, 1);
++  blob->file_name = g_strdup (file_name);
++  blob->ref_count = 1;
++  blob->is_temp_file = is_temp_file;
++  blob->id = bse_id_alloc();
++  sfi_mutex_init (&blob->mutex);
++  return blob;
++}
++
++gboolean
++bse_storage_blob_is_temp_file (BseStorageBlob *blob)
++{
++  g_return_val_if_fail (blob != NULL, FALSE);
++  g_return_val_if_fail (blob->ref_count > 0, FALSE);
++
++  GSL_SPIN_LOCK (&blob->mutex);
++  gboolean is_temp_file = blob->is_temp_file;
++  GSL_SPIN_UNLOCK (&blob->mutex);
++
++  return is_temp_file;
++}
++
++typedef struct
++{
++  BseStorageBlob *blob;
++  BseStorage     *storage;
++  int             fd;
++} WStoreBlob;
++
++static WStoreBlob *
++wstore_blob_new (BseStorage *storage,
++                 BseStorageBlob *blob)
++{
++  WStoreBlob *wsb = (WStoreBlob *) g_new0 (WStoreBlob, 1);
++  wsb->blob = bse_storage_blob_ref (blob);
++  wsb->storage = storage;
++  wsb->fd = -1;
++  return wsb;
++}
++
++static gint /* -errno || length */
++wstore_blob_reader (gpointer data,
++                  void    *buffer,
++                  guint    blength)
++{
++  WStoreBlob *wsb = data;
++  if (wsb->fd == -1)
++    {
++      do
++      wsb->fd = open (bse_storage_blob_file_name (wsb->blob), O_RDONLY);
++      while (wsb->fd == -1 && errno == EINTR);
++      if (wsb->fd == -1)
++      {
++        bse_storage_error (wsb->storage, "file %s could not be opened: %s", bse_storage_blob_file_name 
(wsb->blob), strerror (errno));
++        return -errno;
++      }
++    }
++  int n;
++  do
++    n = read (wsb->fd, buffer, blength);
++  while (n == -1 && errno == EINTR);
++  if (n < 0)
++    return -errno;
++  else
++    return n;
++}
++
++static void
++wstore_blob_destroy (gpointer data)
++{
++  WStoreBlob *wblob = data;
++  if (wblob->fd >= 0)
++    close (wblob->fd);
++  bse_storage_blob_unref (wblob->blob);
++}
++
++void
++bse_storage_put_blob (BseStorage      *self,
++                      BseStorageBlob  *blob)
++{
++  if (BSE_STORAGE_DBLOCK_CONTAINED (self))
++    {
++      gulong id = bse_storage_add_blob (self, blob);
++      bse_storage_break (self);
++      bse_storage_printf (self, "(%s %lu)", g_quark_to_string (quark_blob_id), id);
++    }
++  else
++    {
++      bse_storage_break (self);
++      bse_storage_printf (self, "(%s ", g_quark_to_string (quark_blob));
++      bse_storage_push_level (self);
++      bse_storage_break (self);
++      sfi_wstore_put_binary (self->wstore, wstore_blob_reader, wstore_blob_new (self, blob), 
wstore_blob_destroy);
++      bse_storage_pop_level (self);
++      bse_storage_putc (self, ')');
++    }
++}
++
++GTokenType
++bse_storage_parse_blob (BseStorage             *self,
++                        BseStorageBlob        **blob)
++{
++  GScanner *scanner = bse_storage_get_scanner (self);
++  int bse_fd = -1;
++  int tmp_fd = -1;
++  char *file_name = g_strdup_printf ("%s/bse-%s-%u-%08x", g_get_tmp_dir(), g_get_user_name(), getpid(), 
g_random_int());
++
++  *blob = NULL; /* on error, the resulting blob should be NULL */
++
++  parse_or_return (scanner, '(');
++  parse_or_return (scanner, G_TOKEN_IDENTIFIER);
++  if (g_quark_try_string (scanner->value.v_identifier) == quark_blob)
++    {
++      SfiNum offset, length;
++      GTokenType token = sfi_rstore_parse_binary (self->rstore, &offset, &length);
++      if (token != G_TOKEN_NONE)
++      return token;
++
++      char buffer[1024];
++      bse_fd = open (self->rstore->fname, O_RDONLY);
++      if (bse_fd < 0)
++      {
++        bse_storage_error (self, "couldn't open file %s for reading: %s\n", self->rstore->fname, strerror 
(errno));
++        goto return_with_error;
++      }
++      tmp_fd = open (file_name, O_CREAT | O_WRONLY, 0600);
++      if (tmp_fd < 0)
++      {
++        bse_storage_error (self, "couldn't open file %s for writing: %s\n", file_name, strerror (errno));
++        goto return_with_error;
++      }
++      int result = lseek (bse_fd, offset, SEEK_SET);
++      if (result != offset)
++      {
++        bse_storage_error (self, "could not seek to position %lld in bse file %s\n", offset, 
self->rstore->fname);
++        goto return_with_error;
++      }
++      int bytes_todo = length;
++      while (bytes_todo > 0)
++      {
++        int rbytes, wbytes;
++
++          do
++            rbytes = read (bse_fd, buffer, MIN (bytes_todo, 1024));
++          while (rbytes == -1 && errno == EINTR);
++
++        if (rbytes == -1)
++          {
++            bse_storage_error (self, "error while reading file %s: %s\n", self->rstore->fname, strerror 
(errno));
++            goto return_with_error;
++          }
++        if (rbytes == 0)
++          {
++            bse_storage_error (self, "end-of-file occured too early in file %s\n", self->rstore->fname);
++            goto return_with_error;
++          }
++
++        int bytes_written = 0;
++        while (bytes_written != rbytes)
++          {
++            do
++              wbytes = write (tmp_fd, &buffer[bytes_written], rbytes - bytes_written);
++            while (wbytes == -1 && errno == EINTR);
++            if (wbytes == -1)
++              {
++                bse_storage_error (self, "error while writing file %s: %s\n", self->rstore->fname, strerror 
(errno));
++                goto return_with_error;
++              }
++            bytes_written += wbytes;
++          }
++
++        bytes_todo -= rbytes;
++      }
++      close (bse_fd);
++      close (tmp_fd);
++      *blob = bse_storage_blob_new_from_file (file_name, TRUE);
++      g_free (file_name);
++    }
++  else if (g_quark_try_string (scanner->value.v_identifier) == quark_blob_id)
++    {
++      int i;
++      gulong id;
++      parse_or_return (scanner, G_TOKEN_INT);
++      id = scanner->value.v_int64;
++      *blob = NULL;
++      for (i = 0; i < self->n_blobs; i++)
++      {
++        if (self->blobs[i]->id == id)
++          *blob = bse_storage_blob_ref (self->blobs[i]);
++      }
++      if (!*blob)
++      {
++        g_warning ("failed to lookup storage blob with id=%ld\n", id);
++        goto return_with_error;
++      }
++     }
++  else
++    {
++      goto return_with_error;
++    }
++  parse_or_return (scanner, ')');
++
++  return G_TOKEN_NONE;
++
++return_with_error:
++  if (bse_fd != -1)
++    close (bse_fd);
++  if (tmp_fd != -1)
++    {
++      close (tmp_fd);
++      unlink (file_name);
++    }
++  return G_TOKEN_ERROR;
++}
++
+ BseErrorType
+ bse_storage_flush_fd (BseStorage *self,
+                       gint        fd)
+ {
+   g_return_val_if_fail (BSE_IS_STORAGE (self), BSE_ERROR_INTERNAL);
+   g_return_val_if_fail (self->wstore, BSE_ERROR_INTERNAL);
+   g_return_val_if_fail (fd >= 0, BSE_ERROR_INTERNAL);
+   bse_storage_break (self);
+   gint nerrno = sfi_wstore_flush_fd (self->wstore, fd);
+   return bse_error_from_errno (-nerrno, BSE_ERROR_FILE_WRITE_FAILED);
+ }
+ 
+ void
+ bse_storage_compat_dhreset (BseStorage     *self)
+ {
+   self->n_channels = 1;
+   self->mix_freq = 44100;
+   self->osc_freq = 440;
+ }
+ 
+ void
+ bse_storage_compat_dhmixf (BseStorage     *self,
+                            gfloat          mix_freq)
+ {
+   self->mix_freq = mix_freq;
+ }
+ 
+ void
+ bse_storage_compat_dhoscf (BseStorage     *self,
+                            gfloat          osc_freq)
+ {
+   self->osc_freq = osc_freq;
+ }
+ 
+ void
+ bse_storage_compat_dhchannels (BseStorage     *self,
+                                guint           n_channels)
+ {
+   self->n_channels = n_channels;
+ }
+ 
+ static GTokenType
+ compat_parse_data_handle (BseStorage     *self,
+                           GslDataHandle **data_handle_p,
+                           guint          *n_channels_p,
+                           gfloat         *mix_freq_p,
+                           gfloat         *osc_freq_p)
+ {
+   guint offset, bytes_per_value, length, vlength, byte_order = G_LITTLE_ENDIAN;
+   GScanner *scanner = bse_storage_get_scanner (self);
+   GTokenType token;
+   gchar *string;
+ 
+   parse_or_return (scanner, G_TOKEN_INT);
+   offset = scanner->value.v_int64;
+ 
+   parse_or_return (scanner, G_TOKEN_IDENTIFIER);
+   string = scanner->value.v_identifier;
+   if (string[0] == 'L' || string[0] == 'l')
+     byte_order = G_LITTLE_ENDIAN;
+   else if (string[0] == 'B' || string[0] == 'b')
+     byte_order = G_BIG_ENDIAN;
+   else
+     string = NULL;
+   if (string && string[1] != ':')
+     string = NULL;
+   if (string)
+     {
+       gchar *f = NULL;
+ 
+       bytes_per_value = strtol (string + 2, &f, 10);
+       if ((bytes_per_value != 1 && bytes_per_value != 2 && bytes_per_value != 4) ||
+           (f && *f != 0))
+         string = NULL;
+     }
+   if (!string)
+     return bse_storage_warn_skip (self,
+                                   "unknown value type `%s' in binary data definition",
+                                   scanner->value.v_identifier);
+ 
+   parse_or_return (scanner, G_TOKEN_INT);
+   length = scanner->value.v_int64;
+   if (length < bytes_per_value)
+     return G_TOKEN_INT;
+ 
+   if (g_scanner_peek_next_token (scanner) == G_TOKEN_INT)
+     {
+       g_scanner_get_next_token (scanner);
+       vlength = scanner->value.v_int64;
+       if (vlength < 1 || vlength * bytes_per_value > length)
+         return G_TOKEN_INT;
+     }
+   else
+     vlength = length / bytes_per_value;
+ 
+   parse_or_return (scanner, ')');
+ 
+   token = sfi_rstore_ensure_bin_offset (self->rstore);
+   if (token != G_TOKEN_NONE)
+     return token;
+ 
+   if (n_channels_p)
+     *n_channels_p = self->n_channels;
+   if (mix_freq_p)
+     *mix_freq_p = self->mix_freq;
+   if (osc_freq_p)
+     *osc_freq_p = self->osc_freq;
+   *data_handle_p = gsl_wave_handle_new (self->rstore->fname, self->n_channels,
+                                         bytes_per_value == 1 ? GSL_WAVE_FORMAT_SIGNED_8 :
+                                         bytes_per_value == 2 ? GSL_WAVE_FORMAT_SIGNED_16 :
+                                         GSL_WAVE_FORMAT_FLOAT,
+                                         byte_order,
+                                         self->mix_freq, self->osc_freq,
+                                         sfi_rstore_get_bin_offset (self->rstore) + offset,
+                                         vlength, NULL);
+   return G_TOKEN_NONE;
+ }
diff --cc bse/bsestorage.hh
index 0000000,676fae0..c7f8645
mode 000000,100644..100644
--- a/bse/bsestorage.hh
+++ b/bse/bsestorage.hh
@@@ -1,0 -1,177 +1,193 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #ifndef __BSE_STORAGE_H__
+ #define __BSE_STORAGE_H__
+ 
+ #include <bse/bseobject.hh>
+ #include <bse/gsldefs.hh>
+ 
+ G_BEGIN_DECLS
+ 
+ /* --- object type macros --- */
+ #define BSE_TYPE_STORAGE                 (BSE_TYPE_ID (BseStorage))
+ #define BSE_STORAGE(object)              (G_TYPE_CHECK_INSTANCE_CAST ((object), BSE_TYPE_STORAGE, 
BseStorage))
+ #define BSE_STORAGE_CLASS(class)         (G_TYPE_CHECK_CLASS_CAST ((class), BSE_TYPE_STORAGE, 
BseStorageClass))
+ #define BSE_IS_STORAGE(object)           (G_TYPE_CHECK_INSTANCE_TYPE ((object), BSE_TYPE_STORAGE))
+ #define BSE_IS_STORAGE_CLASS(class)      (G_TYPE_CHECK_CLASS_TYPE ((class), BSE_TYPE_STORAGE))
+ #define BSE_STORAGE_GET_CLASS(object)    (G_TYPE_INSTANCE_GET_CLASS ((object), BSE_TYPE_STORAGE, 
BseStorageClass))
+ 
+ 
+ /* --- macros --- */
+ #define BSE_STORAGE_VERSION(self, vmaj, min, vmic)      ( /* whether file uses >=vARGS features */ \
+   BSE_VERSION_CMP (self->major_version, self->minor_version, self->micro_version, vmaj, min, vmic) >= 0)
+ #define BSE_STORAGE_COMPAT(self, vmaj, min, vmic)       ( /* whether file needs <=vARGS compat code */ \
+   BSE_VERSION_CMP (self->major_version, self->minor_version, self->micro_version, vmaj, min, vmic) <= 0)
+ #define BSE_STORAGE_SELF_CONTAINED(st)   ((BSE_OBJECT_FLAGS (st) & BSE_STORAGE_SELF_CONTAINED) != 0)
+ #define BSE_STORAGE_DBLOCK_CONTAINED(st) ((BSE_OBJECT_FLAGS (st) & BSE_STORAGE_DBLOCK_CONTAINED) != 0)
+ #define BSE_STORAGE_IS_UNDO(st)          BSE_STORAGE_DBLOCK_CONTAINED (st)
+ typedef enum    /*< skip >*/
+ {
+   BSE_STORAGE_SELF_CONTAINED      = 1 << (BSE_OBJECT_FLAGS_USHIFT + 0),
+   BSE_STORAGE_DBLOCK_CONTAINED    = 1 << (BSE_OBJECT_FLAGS_USHIFT + 1)
+ } BseStorageMode;
+ #define BSE_STORAGE_FLAGS_USHIFT         (BSE_OBJECT_FLAGS_USHIFT + 2)
+ #define BSE_STORAGE_MODE_MASK            (BSE_STORAGE_SELF_CONTAINED | BSE_STORAGE_DBLOCK_CONTAINED)
+ 
+ 
+ /* --- compatibility --- */
+ #define bse_storage_scanner_parse_or_return     sfi_scanner_parse_or_return
+ #define bse_storage_scanner_peek_or_return      sfi_scanner_peek_or_return
+ 
+ 
+ /* --- BseStorage --- */
+ typedef struct _BseStorageDBlock   BseStorageDBlock;
+ typedef struct _BseStorageItemLink BseStorageItemLink;
++typedef struct _BseStorageBlob     BseStorageBlob;
+ typedef void (*BseStorageRestoreLink)   (gpointer        data,
+                                          BseStorage     *storage,
+                                          BseItem        *from_item,
+                                          BseItem        *to_item,
+                                          const gchar    *error);
+ struct BseStorage : BseObject {
+   /* writing */
+   SfiWStore             *wstore;
+   SfiPPool              *stored_items;
+   SfiPPool              *referenced_items;
+   /* parsing */
+   SfiRStore             *rstore;
+   guint                  major_version;
+   guint                  minor_version;
+   guint                  micro_version;
+   GHashTable            *path_table;
+   SfiRing               *item_links;
+   SfiPPool              *restorable_objects;
+   /* internal data */
+   guint                  n_dblocks;
+   BseStorageDBlock      *dblocks;
++  guint                  n_blobs;
++  BseStorageBlob       **blobs;
+   gchar                 *free_me;
+   /* compat */ // VERSION-FIXME: needed only for <= 0.5.1
+   gfloat                 mix_freq;
+   gfloat                 osc_freq;
+   guint                  n_channels;
+ };
+ struct BseStorageClass : BseObjectClass
+ {};
+ 
+ /* --- compatibility file parsing --- */
+ void         bse_storage_compat_dhreset         (BseStorage             *self);
+ void         bse_storage_compat_dhmixf          (BseStorage             *self,
+                                                  gfloat                  mix_freq);
+ void         bse_storage_compat_dhoscf          (BseStorage             *self,
+                                                  gfloat                  osc_freq);
+ void         bse_storage_compat_dhchannels      (BseStorage             *self,
+                                                  guint                   n_channels);
+ 
+ 
+ /* --- prototypes -- */
+ void         bse_storage_reset                  (BseStorage             *self);
+ void         bse_storage_prepare_write          (BseStorage             *self,
+                                                  BseStorageMode          mode);
+ void         bse_storage_turn_readable          (BseStorage             *self,
+                                                  const gchar            *storage_name);
+ BseErrorType bse_storage_input_file             (BseStorage             *self,
+                                                  const gchar            *file_name);
+ void         bse_storage_input_text             (BseStorage             *self,
+                                                  const gchar            *text,
+                                                  const gchar            *text_name);
+ GTokenType   bse_storage_restore_item           (BseStorage             *self,
+                                                  gpointer                item);
+ void         bse_storage_store_item             (BseStorage             *self,
+                                                  BseItem                *item);
+ void         bse_storage_store_child            (BseStorage             *self,
+                                                  BseItem                *item);
+ const gchar* bse_storage_item_get_compat_type   (BseItem                *item);
+ 
+ 
+ /* --- writing --- */
+ void         bse_storage_putf                   (BseStorage             *self,
+                                                  gfloat                  vfloat);
+ void         bse_storage_putd                   (BseStorage             *self,
+                                                  gdouble                 vdouble);
+ void         bse_storage_putr                   (BseStorage             *self,
+                                                  SfiReal                 vreal,
+                                                  const gchar            *hints);
+ void         bse_storage_put_param              (BseStorage             *self,
+                                                  const GValue           *value,
+                                                  GParamSpec             *pspec);
+ void         bse_storage_put_item_link          (BseStorage             *self,
+                                                  BseItem                *from_item,
+                                                  BseItem                *to_item);
+ void         bse_storage_put_data_handle        (BseStorage             *self,
+                                                  guint                   significant_bits,
+                                                  GslDataHandle          *dhandle);
++void         bse_storage_put_blob               (BseStorage             *self,
++                                                 BseStorageBlob         *blob);
+ void         bse_storage_put_xinfos             (BseStorage             *self,
+                                                  gchar                 **xinfos);
+ BseErrorType bse_storage_flush_fd               (BseStorage             *self,
+                                                  gint                    fd);
+ 
+ 
+ /* --- reading --- */
+ #define      bse_storage_error(s, ...)          bse_storage_error_str (s, Rapicorn::string_format 
(__VA_ARGS__).c_str())
+ void         bse_storage_error_str              (BseStorage *self, const std::string &string);
+ #define      bse_storage_warn(s, ...)           bse_storage_warn_str (s, Rapicorn::string_format 
(__VA_ARGS__).c_str())
+ void         bse_storage_warn_str               (BseStorage *self, const std::string &string);
+ #define      bse_storage_warn_skip(s, ...)      bse_storage_skip (s, Rapicorn::string_format 
(__VA_ARGS__).c_str())
+ GTokenType   bse_storage_skip                   (BseStorage *self, const std::string &string);
+ GTokenType   bse_storage_parse_param_value      (BseStorage             *self,
+                                                  GValue                 *value,
+                                                  GParamSpec             *pspec);
+ GTokenType   bse_storage_parse_item_link        (BseStorage             *self,
+                                                  BseItem                *from_item,
+                                                  BseStorageRestoreLink   restore_link,
+                                                  gpointer                data);
+ void         bse_storage_add_restorable         (BseStorage             *self,
+                                                  BseObject              *object);
+ void         bse_storage_finish_parsing         (BseStorage             *self);
+ GTokenType   bse_storage_parse_data_handle      (BseStorage             *self,
+                                                  GslDataHandle         **data_handle_p,
+                                                  guint                  *n_channels_p,
+                                                  gfloat                 *mix_freq_p,
+                                                  gfloat                 *osc_freq_p);
+ gboolean     bse_storage_match_data_handle      (BseStorage             *self,
+                                                  GQuark                  quark);
+ GTokenType   bse_storage_parse_data_handle_rest (BseStorage             *self,
+                                                  GslDataHandle         **data_handle_p,
+                                                  guint                  *n_channels_p,
+                                                  gfloat                 *mix_freq_p,
+                                                  gfloat                 *osc_freq_p);
+ GTokenType   bse_storage_parse_xinfos           (BseStorage             *self,
+                                                  gchar                ***xinfosp);
+ GTokenType   bse_storage_parse_rest             (BseStorage             *self,
+                                                  gpointer                context_data,
+                                                  BseTryStatement         try_statement,
+                                                  gpointer                user_data);
++GTokenType   bse_storage_parse_blob             (BseStorage             *self,
++                                                 BseStorageBlob        **blob);
+ gboolean     bse_storage_check_parse_negate     (BseStorage             *self);
+ 
++/* --- bse storage blob --- */
++
++BseStorageBlob  *bse_storage_blob_ref               (BseStorageBlob         *self);
++const gchar     *bse_storage_blob_file_name         (BseStorageBlob         *self);
++gboolean         bse_storage_blob_is_temp_file      (BseStorageBlob         *self);
++void             bse_storage_blob_unref             (BseStorageBlob         *self);
++BseStorageBlob  *bse_storage_blob_new_from_file     (const gchar            *file_name,
++                                                     gboolean                is_temp_file);
++void             bse_storage_blob_clean_files       (void);
+ 
+ /* --- short-hands --- */
+ #define bse_storage_get_scanner(s)      ((s)->rstore->scanner)
+ #define bse_storage_unexp_token(s,et)   sfi_rstore_unexp_token ((s)->rstore, et)
+ #define bse_storage_push_level(s)       sfi_wstore_push_level ((s)->wstore)
+ #define bse_storage_pop_level(s)        sfi_wstore_pop_level ((s)->wstore)
+ #define bse_storage_break(s)            sfi_wstore_break ((s)->wstore)
+ #define bse_storage_putc(s,c)           sfi_wstore_putc ((s)->wstore, c)
+ #define bse_storage_puts(s,b)           sfi_wstore_puts ((s)->wstore, b)
+ #define bse_storage_printf(s, ...)      bse_storage_puts (s, Rapicorn::string_format (__VA_ARGS__).c_str())
+ 
+ G_END_DECLS
+ 
+ #endif /* __BSE_STORAGE_H__ */
diff --cc bse/bsetrack.cc
index 0000000,84677c6..b1fbba9
mode 000000,100644..100644
--- a/bse/bsetrack.cc
+++ b/bse/bsetrack.cc
@@@ -1,0 -1,1058 +1,1148 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #include "bsetrack.hh"
+ 
+ #include "bseglobals.hh"
+ #include "bsestorage.hh"
+ #include "bsecsynth.hh"
+ #include "bsewave.hh"
+ #include "bsepart.hh"
+ #include "bsebus.hh"
+ #include "bsesequencer.hh"
+ #include "gslcommon.hh"
+ #include "bsesubsynth.hh"
+ #include "bseproject.hh"
+ #include "bsesong.hh"
+ #include "bsemidivoice.hh"
+ #include "bsemidireceiver.hh"
+ #include "bsewaverepo.hh"
++#include "bsesoundfontrepo.h"
++#include "bsesoundfontpreset.h"
++#include "bsesoundfont.h"
+ #include "bsecxxplugin.hh"
++
+ #include <string.h>
+ 
+ #define XREF_DEBUG(...) BSE_KEY_DEBUG ("xref", __VA_ARGS__)
+ 
+ #define upper_power2(uint_n)  sfi_alloc_upper_power2 (MAX ((uint_n), 4))
+ #define parse_or_return               bse_storage_scanner_parse_or_return
+ #define peek_or_return                bse_storage_scanner_peek_or_return
+ 
+ enum {
+   PROP_0,
+   PROP_MUTED,
+   PROP_SNET,
+   PROP_WAVE,
++  PROP_SOUND_FONT_PRESET,
+   PROP_MIDI_CHANNEL,
+   PROP_N_VOICES,
+   PROP_PNET,
+   PROP_OUTPUTS
+ };
+ 
+ /* --- prototypes --- */
+ static void         bse_track_class_init          (BseTrackClass *klass);
+ static void         bse_track_init                (BseTrack      *self);
+ static void         bse_track_dispose             (GObject       *object);
+ static void         bse_track_finalize            (GObject       *object);
+ static void         bse_track_set_property        (GObject       *object,
+                                                    guint          param_id,
+                                                    const GValue  *value,
+                                                    GParamSpec    *pspec);
+ static void         bse_track_get_property        (GObject       *object,
+                                                    guint          param_id,
+                                                    GValue        *value,
+                                                    GParamSpec    *pspec);
+ static void         bse_track_store_private       (BseObject     *object,
+                                                    BseStorage    *storage);
+ static GTokenType   bse_track_restore_private     (BseObject     *object,
+                                                    BseStorage    *storage,
+                                                    GScanner      *scanner);
+ static void         bse_track_update_midi_channel (BseTrack      *self);
+ 
+ 
+ /* --- variables --- */
+ static GTypeClass *parent_class = NULL;
+ static guint     signal_changed = 0;
+ 
+ 
+ /* --- functions --- */
+ BSE_BUILTIN_TYPE (BseTrack)
+ {
+   static const GTypeInfo track_info = {
+     sizeof (BseTrackClass),
+ 
+     (GBaseInitFunc) NULL,
+     (GBaseFinalizeFunc) NULL,
+     (GClassInitFunc) bse_track_class_init,
+     (GClassFinalizeFunc) NULL,
+     NULL /* class_data */,
+ 
+     sizeof (BseTrack),
+     0 /* n_preallocs */,
+     (GInstanceInitFunc) bse_track_init,
+   };
+ 
+   return bse_type_register_static (BSE_TYPE_CONTEXT_MERGER,
+                                  "BseTrack",
+                                  "BSE track type",
+                                    __FILE__, __LINE__,
+                                    &track_info);
+ }
+ 
+ static gulong
+ alloc_id_above (guint n)
+ {
+   gulong tmp, id = bse_id_alloc ();
+   if (id > n)
+     return id;
+   tmp = id;
+   id = alloc_id_above (n);
+   bse_id_free (tmp);
+   return id;
+ }
+ 
+ static void
+ bse_track_init (BseTrack *self)
+ {
+   BSE_OBJECT_SET_FLAGS (self, BSE_SOURCE_FLAG_PRIVATE_INPUTS);
+   self->snet = NULL;
+   self->pnet = NULL;
++  self->sound_font_preset = NULL;
++  self->wave = NULL;
++  self->wnet = NULL;
+   self->max_voices = 16;
+   self->muted_SL = FALSE;
+   self->n_entries_SL = 0;
+   self->entries_SL = g_renew (BseTrackEntry, NULL, upper_power2 (self->n_entries_SL));
+   self->channel_id = alloc_id_above (BSE_MIDI_MAX_CHANNELS);
+   self->midi_channel_SL = self->channel_id;
+   self->track_done_SL = FALSE;
+ }
+ 
+ static void
+ bse_track_dispose (GObject *object)
+ {
+   BseTrack *self = BSE_TRACK (object);
+ 
+   /* we may assert removal here, since if these assertions fail,
+    * our parent (BseSong) doesn't properly implement track support
+    */
+   g_assert (self->sub_synth == NULL);
+ 
+   /* check uncrossed references */
+   g_assert (self->snet == NULL);
+   g_assert (self->pnet == NULL);
+   g_assert (self->n_entries_SL == 0);
+ 
+   /* chain parent class' handler */
+   G_OBJECT_CLASS (parent_class)->dispose (object);
+ 
+   g_assert (self->bus_outputs == NULL);
+ }
+ 
+ static void
+ bse_track_finalize (GObject *object)
+ {
+   BseTrack *self = BSE_TRACK (object);
+ 
+   g_assert (self->bus_outputs == NULL);
+ 
+   g_assert (self->n_entries_SL == 0);
+   g_free (self->entries_SL);
+   bse_id_free (self->channel_id);
+ 
+   /* chain parent class' handler */
+   G_OBJECT_CLASS (parent_class)->finalize (object);
+ }
+ 
+ static void   track_uncross_part      (BseItem *owner,
+                                        BseItem *ref_item);
+ 
+ static BseTrackEntry*
+ track_add_entry (BseTrack *self,
+                guint     index,
+                guint     tick,
+                BsePart  *part)
+ {
+   guint n, size;
+ 
+   g_return_val_if_fail (index <= self->n_entries_SL, NULL);
+   if (index > 0)
+     g_return_val_if_fail (self->entries_SL[index - 1].tick < tick, NULL);
+   if (index < self->n_entries_SL)
+     g_return_val_if_fail (self->entries_SL[index].tick > tick, NULL);
+ 
+   BSE_SEQUENCER_LOCK ();
+   n = self->n_entries_SL++;
+   size = upper_power2 (self->n_entries_SL);
+   if (size > upper_power2 (n))
+     self->entries_SL = g_renew (BseTrackEntry, self->entries_SL, size);
+   memmove (self->entries_SL + index + 1, self->entries_SL + index, (n - index) * sizeof 
(self->entries_SL[0]));
+   self->entries_SL[index].tick = tick;
+   self->entries_SL[index].id = bse_id_alloc ();
+   self->entries_SL[index].part = part;
+   self->track_done_SL = FALSE;        /* let sequencer recheck if playing */
+   BSE_SEQUENCER_UNLOCK ();
+   bse_item_cross_link (BSE_ITEM (self), BSE_ITEM (part), track_uncross_part);
+   XREF_DEBUG ("cross-link: %p %p", self, part);
+   bse_object_proxy_notifies (part, self, "changed");
+   bse_object_reemit_signal (part, "notify::last-tick", self, "changed");
+   return self->entries_SL + index;
+ }
+ 
+ static void
+ track_delete_entry (BseTrack *self,
+                   guint     index)
+ {
+   g_return_if_fail (index < self->n_entries_SL);
+ 
+   BsePart *part = self->entries_SL[index].part;
+   bse_object_remove_reemit (part, "notify::last-tick", self, "changed");
+   bse_object_unproxy_notifies (part, self, "changed");
+   XREF_DEBUG ("cross-unlink: %p %p", self, part);
+   bse_item_cross_unlink (BSE_ITEM (self), BSE_ITEM (part), track_uncross_part);
+   BSE_SEQUENCER_LOCK ();
+   self->n_entries_SL -= 1;
+   bse_id_free (self->entries_SL[index].id);
+   memmove (self->entries_SL + index, self->entries_SL + index + 1, (self->n_entries_SL - index) * sizeof 
(self->entries_SL[0]));
+   BSE_SEQUENCER_UNLOCK ();
+ }
+ 
+ static BseTrackEntry*
+ track_lookup_entry (BseTrack *self,
+                   guint     tick)
+ {
+   BseTrackEntry *nodes = self->entries_SL;
+   guint n = self->n_entries_SL, offs = 0, i = 0;
+ 
+   while (offs < n)
+     {
+       gint cmp;
+       i = (offs + n) >> 1;
+       cmp = tick > nodes[i].tick ? +1 : tick < nodes[i].tick ? -1 : 0;
+       if (!cmp)
+       return nodes + i;
+       else if (cmp < 0)
+       n = i;
+       else /* (cmp > 0) */
+       offs = i + 1;
+     }
+ 
+   /* return the closest entry with tick <= requested tick if possible */
+   if (!self->n_entries_SL)
+     return NULL;
+   if (nodes[i].tick > tick)
+     return i > 0 ? nodes + i - 1 : NULL;      /* previous entry */
+   else
+     return nodes + i;                         /* closest match */
+ }
+ 
+ static void
+ track_uncross_part (BseItem *owner,
+                   BseItem *item)
+ {
+   BseTrack *self = BSE_TRACK (owner);
+   BsePart *part = BSE_PART (item);
+   guint i;
+   for (i = 0; i < self->n_entries_SL; i++)
+     if (self->entries_SL[i].part == part)
+       {
+         guint tick = self->entries_SL[i].tick;
+       XREF_DEBUG ("uncrossing[start]: %p %p (%d)", self, part, tick);
+         /* delete track via procedure so deletion is recorded to undo */
+         bse_item_exec_void (owner, "remove-tick", tick);
+       XREF_DEBUG ("uncrossing[done]: %p %p (%d)", self, part, tick);
+       return;
+       }
+ }
+ 
+ static void
+ bse_track_get_candidates (BseItem               *item,
+                           guint                  param_id,
+                           BsePropertyCandidates *pc,
+                           GParamSpec            *pspec)
+ {
+   BseTrack *self = BSE_TRACK (item);
+   switch (param_id)
+     {
+       BseProject *project;
+       SfiRing *ring;
+     case PROP_WAVE:
+       bse_property_candidate_relabel (pc, _("Available Waves"), _("List of available waves to choose as 
track instrument"));
+       project = bse_item_get_project (item);
+       if (project)
+       {
+         BseWaveRepo *wrepo = bse_project_get_wave_repo (project);
+         bse_item_gather_items_typed (BSE_ITEM (wrepo), pc->items, BSE_TYPE_WAVE, BSE_TYPE_WAVE_REPO, FALSE);
+       }
+       break;
++    case PROP_SOUND_FONT_PRESET:
++      bse_property_candidate_relabel (pc, _("Sound Fonts"), _("List of available sound font presets to 
choose as track instrument"));
++      project = bse_item_get_project (item);
++      if (project)
++      bse_sound_font_repo_list_all_presets (bse_project_get_sound_font_repo (project), pc->items);
++      break;
+     case PROP_SNET:
+       bse_property_candidate_relabel (pc, _("Available Synthesizers"), _("List of available synthesis 
networks to choose a track instrument from"));
+       bse_item_gather_items_typed (item, pc->items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
+       break;
+     case PROP_PNET:
+       bse_property_candidate_relabel (pc, _("Available Postprocessors"), _("List of available synthesis 
networks to choose a postprocessor from"));
+       bse_item_gather_items_typed (item, pc->items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
+       break;
+     case PROP_OUTPUTS:
+       bse_property_candidate_relabel (pc, _("Available Outputs"), _("List of available mixer busses to be 
used as track output"));
+       bse_bus_or_track_list_output_candidates (BSE_ITEM (self), pc->items);
+       /* remove existing outputs */
+       for (ring = self->bus_outputs; ring; ring = sfi_ring_walk (ring, self->bus_outputs))
+         bse_item_seq_remove (pc->items, (BseItem*) ring->data);
+       break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
+       break;
+     }
+ }
+ 
+ static void
+ track_uncross_snet (BseItem *owner,
+                   BseItem *ref_item)
+ {
+   BseTrack *self = BSE_TRACK (owner);
+   bse_item_set (self, "snet", NULL, NULL);
+ }
+ 
+ static void
+ track_uncross_pnet (BseItem *owner,
+                   BseItem *ref_item)
+ {
+   BseTrack *self = BSE_TRACK (owner);
+   bse_item_set (self, "pnet", NULL, NULL);
+ }
+ 
+ static void
+ track_uncross_wave (BseItem *owner,
+                   BseItem *ref_item)
+ {
+   BseTrack *self = BSE_TRACK (owner);
+   bse_item_set (self, "wave", NULL, NULL);
+ }
+ 
+ static void
+ set_amp_master_volume (BseSNet *snet, const char *amp_name, gchar **xinfos)
+ {
+   const gchar *master_volume_db = bse_xinfos_get_value (xinfos, "master-volume-db");
+   if (master_volume_db)
+     {
+       BseItem *amp = bse_container_resolve_upath (BSE_CONTAINER (snet), amp_name);
+       double volume = 0;
+       g_object_get (amp, "master-volume", &volume, NULL);
+       volume *= bse_db_to_factor (g_ascii_strtod (master_volume_db, NULL));
+       g_object_set (amp, "master-volume", volume, NULL);
+     }
+ }
++
+ static void
+ set_adsr_params (BseSNet *snet, const char *adsr_name, gchar **xinfos)
+ {
+   const gchar *adsr_release_time = bse_xinfos_get_value (xinfos, "adsr-release-time");
+   if (adsr_release_time)
+     {
+       BseItem *adsr = bse_container_resolve_upath (BSE_CONTAINER (snet), adsr_name);
+       g_object_set (adsr, "release_time", g_ascii_strtod (adsr_release_time, NULL), NULL);
+     }
+   const gchar *adsr_attack_time = bse_xinfos_get_value (xinfos, "adsr-attack-time");
+   if (adsr_attack_time)
+     {
+       BseItem *adsr = bse_container_resolve_upath (BSE_CONTAINER (snet), adsr_name);
+       g_object_set (adsr, "attack_time", g_ascii_strtod (adsr_attack_time, NULL), NULL);
+     }
+ }
++
++static void
++track_uncross_sound_font_preset (BseItem *owner,
++                                 BseItem *ref_item)
++{
++  BseTrack *self = BSE_TRACK (owner);
++  bse_item_set (self, "sound-font-preset", NULL, NULL);
++}
++
+ static void
+ create_wnet (BseTrack *self,
+            BseWave  *wave)
+ {
+   g_return_if_fail (self->wnet == NULL);
+ 
+   const gchar *play_type = bse_xinfos_get_value (wave->xinfos, "play-type");
+   const gchar *synthesis_network = play_type ? play_type : "adsr-wave-1";
+ 
+   self->wnet = bse_project_create_intern_synth (bse_item_get_project (BSE_ITEM (self)),
+                                               synthesis_network,
+                                               BSE_TYPE_SNET);
+ 
+   bse_item_cross_link (BSE_ITEM (self), BSE_ITEM (self->wnet), track_uncross_wave);
+ 
+   if (self->sub_synth)
+     g_object_set (self->sub_synth, /* no undo */
+                 "snet", self->wnet,
+                 NULL);
+ 
+   if (strcmp (synthesis_network, "adsr-wave-1") == 0 ||
+       strcmp (synthesis_network, "plain-wave-1") == 0)
+     {
+       g_object_set (bse_container_resolve_upath (BSE_CONTAINER (self->wnet), "wave-osc"), /* no undo */
+                                                "wave", wave,
+                                                NULL);
+       set_amp_master_volume (self->wnet, "amplifier", wave->xinfos);
+       set_adsr_params (self->wnet, "adsr", wave->xinfos);
+     }
+   else if (strcmp (synthesis_network, "adsr-wave-2") == 0 ||
+            strcmp (synthesis_network, "plain-wave-2") == 0)
+     {
+       g_object_set (bse_container_resolve_upath (BSE_CONTAINER (self->wnet), "wave-osc-left"), /* no undo */
+                                                "wave", wave,
+                                                NULL);
+       g_object_set (bse_container_resolve_upath (BSE_CONTAINER (self->wnet), "wave-osc-right"), /* no undo 
*/
+                                                "wave", wave,
+                                                NULL);
+       set_amp_master_volume (self->wnet, "amplifier-left", wave->xinfos);
+       set_amp_master_volume (self->wnet, "amplifier-right", wave->xinfos);
+       set_adsr_params (self->wnet, "adsr", wave->xinfos);
+     }
+   else if (strcmp (synthesis_network, "gus-patch") == 0)
+     {
+       g_object_set (bse_container_resolve_upath (BSE_CONTAINER (self->wnet), "wave-osc"), /* no undo */
+                                                "wave", wave,
+                                                NULL);
+       g_object_set (bse_container_resolve_upath (BSE_CONTAINER (self->wnet), "gus-patch-envelope"), /* no 
undo */
+                                                "wave", wave,
+                                                NULL);
+     }
+   else
+     {
+       g_warning ("track: waves with the play-type \"%s\" are not supported by this version of beast\n",
+                synthesis_network);
+     }
+ 
+ }
+ 
+ static void
 -clear_snet_and_wave (BseTrack *self)
++create_sound_font_net (BseTrack           *self,
++                       BseSoundFontPreset *preset)
++{
++  g_return_if_fail (self->sound_font_net == NULL);
++
++  self->sound_font_net =  bse_project_create_intern_synth (bse_item_get_project (BSE_ITEM (self)),
++                                                         "sound-font-snet",
++                                                         BSE_TYPE_SNET);
++
++  bse_item_cross_link (BSE_ITEM (self), BSE_ITEM (self->sound_font_net), track_uncross_sound_font_preset);
++
++  if (self->sub_synth)
++    {
++      g_object_set (self->sub_synth, /* no undo */
++                  "snet", self->sound_font_net,
++                  NULL);
++    }
++
++  g_object_set (bse_container_resolve_upath (BSE_CONTAINER (self->sound_font_net), "sound-font-osc"), /* no 
undo */
++              "preset", preset,
++              NULL);
++}
++static void
++clear_snet_and_wave_and_sfpreset (BseTrack *self)
+ {
+   g_return_if_fail (!self->sub_synth || !BSE_SOURCE_PREPARED (self->sub_synth));
+ 
+   if (self->sub_synth)
+     g_object_set (self->sub_synth, /* no undo */
+                 "snet", NULL,
+                 NULL);
+   if (self->snet)
+     {
+       bse_object_unproxy_notifies (self->snet, self, "changed");
+       bse_item_cross_unlink (BSE_ITEM (self), BSE_ITEM (self->snet), track_uncross_snet);
+       self->snet = NULL;
+       g_object_notify ((GObject*) self, "snet");
+     }
+   if (self->wave)
+     {
+       bse_object_unproxy_notifies (self->wave, self, "changed");
+       bse_item_cross_unlink (BSE_ITEM (self), BSE_ITEM (self->wave), track_uncross_wave);
+       self->wave = NULL;
+       g_object_notify ((GObject*) self, "wave");
+     }
+   if (self->wnet)
+     {
+       BseSNet *wnet = self->wnet;
+       bse_item_cross_unlink (BSE_ITEM (self), BSE_ITEM (self->wnet), track_uncross_wave);
+       self->wnet = NULL;
+       bse_container_remove_item (BSE_CONTAINER (bse_item_get_project (BSE_ITEM (self))), BSE_ITEM (wnet));
+     }
++  if (self->sound_font_preset)
++    {
++      bse_object_unproxy_notifies (self->sound_font_preset, self, "changed");
++      bse_item_cross_unlink (BSE_ITEM (self), BSE_ITEM (self->sound_font_preset), 
track_uncross_sound_font_preset);
++      self->sound_font_preset = NULL;
++      g_object_notify (self, "sound_font_preset");
++    }
++  if (self->sound_font_net)
++    {
++      BseSNet *sound_font_net = self->sound_font_net;
++      bse_item_cross_unlink (BSE_ITEM (self), BSE_ITEM (self->sound_font_net), 
track_uncross_sound_font_preset);
++      self->sound_font_net = NULL;
++      bse_container_remove_item (BSE_CONTAINER (bse_item_get_project (BSE_ITEM (self))), BSE_ITEM 
(sound_font_net));
++    }
+ }
+ 
+ static void
+ bse_track_set_property (GObject      *object,
+                       guint         param_id,
+                       const GValue *value,
+                       GParamSpec   *pspec)
+ {
+   BseTrack *self = BSE_TRACK (object);
+ 
+   switch (param_id)
+     {
+       guint i;
+     case PROP_MUTED:
+       BSE_SEQUENCER_LOCK ();
+       self->muted_SL = sfi_value_get_bool (value);
+       BSE_SEQUENCER_UNLOCK ();
+       break;
+     case PROP_SNET:
+       if (!self->sub_synth || !BSE_SOURCE_PREPARED (self))
+       {
+         BseSNet *snet = (BseSNet*) bse_value_get_object (value);
+         if (snet || self->snet)
+           {
 -            clear_snet_and_wave (self);
++            clear_snet_and_wave_and_sfpreset (self);
+             self->snet = snet;
+             if (self->snet)
+               {
+                 bse_item_cross_link (BSE_ITEM (self), BSE_ITEM (self->snet), track_uncross_snet);
+                 bse_object_proxy_notifies (self->snet, self, "changed");
+               }
+             if (self->sub_synth)
+               g_object_set (self->sub_synth, /* no undo */
+                             "snet", self->snet,
+                             NULL);
+           }
+       }
+       break;
+     case PROP_WAVE:
+       if (!self->sub_synth || !BSE_SOURCE_PREPARED (self->sub_synth))
+       {
+         BseWave *wave = (BseWave*) bse_value_get_object (value);
+         if (wave || self->wave)
+           {
 -            clear_snet_and_wave (self);
++            clear_snet_and_wave_and_sfpreset (self);
+ 
+             self->wave = wave;
+             if (self->wave)
+               {
+                 create_wnet (self, wave);
+                 bse_item_cross_link (BSE_ITEM (self), BSE_ITEM (self->wave), track_uncross_wave);
+                 bse_object_proxy_notifies (self->wave, self, "changed");
+               }
+           }
+       }
+       break;
++    case PROP_SOUND_FONT_PRESET:
++      if (!self->sub_synth || !BSE_SOURCE_PREPARED (self->sub_synth))
++      {
++        BseSoundFontPreset *sound_font_preset = bse_value_get_object (value);
++        if (sound_font_preset || self->sound_font_preset)
++          {
++            clear_snet_and_wave_and_sfpreset (self);
++
++            self->sound_font_preset = sound_font_preset;
++            if (self->sound_font_preset)
++              {
++                create_sound_font_net (self, sound_font_preset);
++                bse_item_cross_link (BSE_ITEM (self), BSE_ITEM (self->sound_font_preset), 
track_uncross_sound_font_preset);
++                bse_object_proxy_notifies (self->sound_font_preset, self, "changed");
++              }
++          }
++      }
++      break;
+     case PROP_N_VOICES:
+       if (!self->postprocess || !BSE_SOURCE_PREPARED (self->postprocess))
+         self->max_voices = sfi_value_get_int (value);
+       break;
+     case PROP_MIDI_CHANNEL:
+       i = sfi_value_get_int (value);
+       if (i != self->midi_channel_SL && !BSE_SOURCE_PREPARED (self))
+         {
+           self->midi_channel_SL = i > 0 ? i : self->channel_id;
+           bse_track_update_midi_channel (self);
+         }
+       break;
+     case PROP_PNET:
+       if (!self->postprocess || !BSE_SOURCE_PREPARED (self))
+       {
+           if (self->pnet)
+             {
+               bse_object_unproxy_notifies (self->pnet, self, "notify::pnet");
+               bse_item_cross_unlink (BSE_ITEM (self), BSE_ITEM (self->pnet), track_uncross_pnet);
+               self->pnet = NULL;
+             }
+           self->pnet = (BseSNet*) bse_value_get_object (value);
+           if (self->pnet)
+             {
+               bse_item_cross_link (BSE_ITEM (self), BSE_ITEM (self->pnet), track_uncross_pnet);
+               bse_object_proxy_notifies (self->pnet, self, "notify::pnet");
+             }
+           if (self->postprocess)
+             g_object_set (self->postprocess, /* no undo */
+                           "snet", self->pnet,
+                           NULL);
+       }
+       break;
+     case PROP_OUTPUTS:
+       bse_bus_or_track_set_outputs (BSE_ITEM (self), (BseItemSeq*) g_value_get_boxed (value));
+       break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
+       break;
+     }
+ }
+ 
+ static void
+ bse_track_get_property (GObject    *object,
+                       guint       param_id,
+                       GValue     *value,
+                       GParamSpec *pspec)
+ {
+   BseTrack *self = BSE_TRACK (object);
+ 
+   switch (param_id)
+     {
+       BseItemSeq *iseq;
+       SfiRing *ring;
+     case PROP_MUTED:
+       sfi_value_set_bool (value, self->muted_SL);
+       break;
+     case PROP_SNET:
+       bse_value_set_object (value, self->snet);
+       break;
+     case PROP_PNET:
+       bse_value_set_object (value, self->pnet);
+       break;
+     case PROP_OUTPUTS:
+       iseq = bse_item_seq_new();
+       for (ring = self->bus_outputs; ring; ring = sfi_ring_walk (ring, self->bus_outputs))
+         bse_item_seq_append (iseq, (BseItem*) ring->data);
+       g_value_take_boxed (value, iseq);
+       break;
+     case PROP_WAVE:
+       bse_value_set_object (value, self->wave);
+       break;
++    case PROP_SOUND_FONT_PRESET:
++      bse_value_set_object (value, self->sound_font_preset);
++      break;
+     case PROP_N_VOICES:
+       sfi_value_set_int (value, self->max_voices);
+       break;
+     case PROP_MIDI_CHANNEL:
+       sfi_value_set_int (value, self->midi_channel_SL <= BSE_MIDI_MAX_CHANNELS ? self->midi_channel_SL : 0);
+       break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
+       break;
+     }
+ }
+ 
+ guint
+ bse_track_insert_part (BseTrack *self,
+                      guint     tick,
+                      BsePart  *part)
+ {
+   BseTrackEntry *entry;
+ 
+   g_return_val_if_fail (BSE_IS_TRACK (self), BSE_ERROR_INTERNAL);
+   g_return_val_if_fail (BSE_IS_PART (part), BSE_ERROR_INTERNAL);
+ 
+   entry = track_lookup_entry (self, tick);
+   if (entry && entry->tick == tick)
+     return 0;
+   else
+     {
+       gint i = entry ? entry - self->entries_SL : 0;
+       entry = track_add_entry (self, entry ? i + 1 : 0, tick, part);
+     }
+   bse_part_links_changed (part);
+   g_signal_emit (self, signal_changed, 0);
+   return entry ? entry->id : 0;
+ }
+ 
+ void
+ bse_track_remove_tick (BseTrack *self,
+                      guint     tick)
+ {
+   BseTrackEntry *entry;
+ 
+   g_return_if_fail (BSE_IS_TRACK (self));
+ 
+   entry = track_lookup_entry (self, tick);
+   if (entry && entry->tick == tick)
+     {
+       BsePart *part = entry->part;
+       track_delete_entry (self, entry - self->entries_SL);
+       bse_part_links_changed (part);
+       g_signal_emit (self, signal_changed, 0);
+     }
+ }
+ 
+ static BseTrackPartSeq*
+ bse_track_list_parts_intern (BseTrack *self,
+                              BsePart  *part)
+ {
+   BseItem *item = BSE_ITEM (self);
+   BseSong *song = NULL;
+   if (BSE_IS_SONG (item->parent))
+     song = BSE_SONG (item->parent);
+   BseSongTiming timing;
+   bse_song_timing_get_default (&timing);
+   BseTrackPartSeq *tps = bse_track_part_seq_new ();
+   gint i;
+   for (i = 0; i < self->n_entries_SL; i++)
+     {
+       BseTrackEntry *entry = self->entries_SL + i;
+       if (entry->part && (entry->part == part || !part))
+       {
+         BseTrackPart tp = { 0, };
+         tp.tick = entry->tick;
+         tp.part = entry->part;
+         if (song)
+           bse_song_get_timing (song, tp.tick, &timing);
+         tp.duration = MAX (timing.tpt, entry->part->last_tick_SL);
+         if (i + 1 < self->n_entries_SL)
+           tp.duration = MIN (tp.duration, entry[1].tick - entry->tick);
+         bse_track_part_seq_append (tps, &tp);
+       }
+     }
+   return tps;
+ }
+ 
+ BseTrackPartSeq*
+ bse_track_list_parts (BseTrack *self)
+ {
+   g_return_val_if_fail (BSE_IS_TRACK (self), NULL);
+   return bse_track_list_parts_intern (self, NULL);
+ }
+ 
+ BseTrackPartSeq*
+ bse_track_list_part (BseTrack *self,
+                      BsePart  *part)
+ {
+   g_return_val_if_fail (BSE_IS_TRACK (self), NULL);
+   g_return_val_if_fail (BSE_IS_PART (part), NULL);
+   return bse_track_list_parts_intern (self, part);
+ }
+ 
+ gboolean
+ bse_track_find_part (BseTrack *self,
+                    BsePart  *part,
+                    guint    *start_p)
+ {
+   guint i;
+ 
+   g_return_val_if_fail (BSE_IS_TRACK (self), FALSE);
+   g_return_val_if_fail (BSE_IS_PART (part), FALSE);
+ 
+   for (i = 0; i < self->n_entries_SL; i++)
+     if (self->entries_SL[i].part == part)
+       {
+       if (start_p)
+         *start_p = self->entries_SL[i].tick;
+       return TRUE;
+       }
+   return FALSE;
+ }
+ 
+ BseTrackEntry*
+ bse_track_lookup_tick (BseTrack               *self,
+                      guint                   tick)
+ {
+   BseTrackEntry *entry;
+ 
+   g_return_val_if_fail (BSE_IS_TRACK (self), NULL);
+ 
+   entry = track_lookup_entry (self, tick);
+   if (entry && entry->tick == tick)
+     return entry;
+   return NULL;
+ }
+ 
+ BseTrackEntry*
+ bse_track_find_link (BseTrack *self,
+                      guint     id)
+ {
+   guint i;
+ 
+   g_return_val_if_fail (BSE_IS_TRACK (self), NULL);
+ 
+   for (i = 0; i < self->n_entries_SL; i++)
+     if (self->entries_SL[i].id == id)
+       return self->entries_SL + i;
+   return NULL;
+ }
+ 
+ BsePart*
+ bse_track_get_part_SL (BseTrack *self,
+                      guint     tick,
+                      guint    *start,
+                      guint    *next)
+ {
+   BseTrackEntry *entry;
+ 
+   g_return_val_if_fail (BSE_IS_TRACK (self), NULL);
+ 
+   /* we return the nearest part with start <= tick and
+    * set *next to the start of the following part if any
+    */
+ 
+   entry = track_lookup_entry (self, tick);
+   if (entry)
+     {
+       guint i = entry - self->entries_SL;
+       if (i + 1 < self->n_entries_SL)
+       *next = self->entries_SL[i + 1].tick;
+       else
+       *next = 0;      /* no next part */
+       *start = entry->tick;
+       return entry->part;
+     }
+   *start = 0;
+   *next = self->n_entries_SL ? self->entries_SL[0].tick : 0;
+   return NULL;
+ }
+ 
+ void
+ bse_track_add_modules (BseTrack        *self,
+                      BseContainer    *container,
+                        BseMidiReceiver *midi_receiver)
+ {
+   g_return_if_fail (BSE_IS_TRACK (self));
+   g_return_if_fail (BSE_IS_CONTAINER (container));
+   g_return_if_fail (self->sub_synth == NULL);
+   g_return_if_fail (midi_receiver != NULL);
+ 
+   /* midi voice input */
+   self->voice_input = (BseSource*) bse_container_new_child (container, BSE_TYPE_MIDI_VOICE_INPUT, NULL);
+   bse_item_set_internal (self->voice_input, TRUE);
+ 
+   /* sub synth */
+   self->sub_synth = (BseSource*) bse_container_new_child_bname (container, BSE_TYPE_SUB_SYNTH, 
"Track-Instrument",
+                                                                 "in_port_1", "frequency",
+                                                                 "in_port_2", "gate",
+                                                                 "in_port_3", "velocity",
+                                                                 "in_port_4", "aftertouch",
+                                                                 "out_port_1", "left-audio",
+                                                                 "out_port_2", "right-audio",
+                                                                 "out_port_3", "unused",
+                                                                 "out_port_4", "synth-done",
+                                                                 "snet", self->snet,
+                                                                 NULL);
+   bse_item_set_internal (self->sub_synth, TRUE);
+ 
+   /* voice input <-> sub-synth */
+   bse_source_must_set_input (self->sub_synth, 0,
+                            self->voice_input, BSE_MIDI_VOICE_INPUT_OCHANNEL_FREQUENCY);
+   bse_source_must_set_input (self->sub_synth, 1,
+                            self->voice_input, BSE_MIDI_VOICE_INPUT_OCHANNEL_GATE);
+   bse_source_must_set_input (self->sub_synth, 2,
+                            self->voice_input, BSE_MIDI_VOICE_INPUT_OCHANNEL_VELOCITY);
+   bse_source_must_set_input (self->sub_synth, 3,
+                            self->voice_input, BSE_MIDI_VOICE_INPUT_OCHANNEL_AFTERTOUCH);
+ 
+   /* midi voice switch */
+   self->voice_switch = (BseSource*) bse_container_new_child (container, BSE_TYPE_MIDI_VOICE_SWITCH, NULL);
+   bse_item_set_internal (self->voice_switch, TRUE);
+   bse_midi_voice_input_set_voice_switch (BSE_MIDI_VOICE_INPUT (self->voice_input), BSE_MIDI_VOICE_SWITCH 
(self->voice_switch));
+ 
+   /* sub-synth <-> voice switch */
+   bse_source_must_set_input (self->voice_switch, BSE_MIDI_VOICE_SWITCH_ICHANNEL_LEFT,
+                            self->sub_synth, 0);
+   bse_source_must_set_input (self->voice_switch, BSE_MIDI_VOICE_SWITCH_ICHANNEL_RIGHT,
+                            self->sub_synth, 1);
+   bse_source_must_set_input (self->voice_switch, BSE_MIDI_VOICE_SWITCH_ICHANNEL_DISCONNECT,
+                            self->sub_synth, 3);
+ 
+   /* midi voice switch <-> context merger */
+   bse_source_must_set_input (BSE_SOURCE (self), 0,
+                            self->voice_switch, BSE_MIDI_VOICE_SWITCH_OCHANNEL_LEFT);
+   bse_source_must_set_input (BSE_SOURCE (self), 1,
+                            self->voice_switch, BSE_MIDI_VOICE_SWITCH_OCHANNEL_RIGHT);
+ 
+   /* postprocess */
+   self->postprocess = (BseSource*) bse_container_new_child_bname (container, BSE_TYPE_SUB_SYNTH, 
"Track-Postprocess", NULL);
+   bse_item_set_internal (self->postprocess, TRUE);
+   bse_sub_synth_set_null_shortcut (BSE_SUB_SYNTH (self->postprocess), TRUE);
+ 
+   /* context merger <-> postprocess */
+   bse_source_must_set_input (self->postprocess, 0, BSE_SOURCE (self), 0);
+   bse_source_must_set_input (self->postprocess, 1, BSE_SOURCE (self), 1);
+ 
+   /* propagate midi channel to modules */
+   bse_track_update_midi_channel (self);
+ }
+ 
+ BseSource*
+ bse_track_get_output (BseTrack *self)
+ {
+   return self->postprocess;
+ }
+ 
+ guint
+ bse_track_get_last_tick (BseTrack *self)
+ {
+   int last_tick = 0;
+ 
+   /* find last part */
+   BsePart *part = NULL;
+   guint i, offset = 0;
+   for (i = 0; i < self->n_entries_SL; i++)
+     if (self->entries_SL[i].part)
+       {
+         part = self->entries_SL[i].part;
+         offset = self->entries_SL[i].tick;
+       }
+   if (part)
+     {
+       BseItem *item = BSE_ITEM (self);
+       BseSongTiming timing;
+       g_object_get (part, "last-tick", &last_tick, NULL);
+       if (BSE_IS_SONG (item->parent))
+         bse_song_get_timing (BSE_SONG (item->parent), offset, &timing);
+       else
+         bse_song_timing_get_default (&timing);
+       last_tick = MAX (last_tick, timing.tpt);  /* MAX duration with tact size, see bse_track_list_parts() 
*/
+       last_tick += offset;
+     }
+   else
+     last_tick += 1;     /* always return one after */
+ 
+   return last_tick;
+ }
+ 
+ static void
+ bse_track_update_midi_channel (BseTrack *self)
+ {
+   if (self->voice_switch)
 -    {
 -      bse_sub_synth_set_midi_channel (BSE_SUB_SYNTH (self->sub_synth), self->midi_channel_SL);
 -      bse_sub_synth_set_midi_channel (BSE_SUB_SYNTH (self->postprocess), self->midi_channel_SL);
 -      bse_midi_voice_switch_set_midi_channel (BSE_MIDI_VOICE_SWITCH (self->voice_switch), 
self->midi_channel_SL);
 -    }
++  {
++    bse_sub_synth_set_midi_channel (BSE_SUB_SYNTH (self->sub_synth), self->midi_channel_SL);
++    bse_sub_synth_set_midi_channel (BSE_SUB_SYNTH (self->postprocess), self->midi_channel_SL);
++    bse_midi_voice_switch_set_midi_channel (BSE_MIDI_VOICE_SWITCH (self->voice_switch), 
self->midi_channel_SL);
++  }
+ }
+ 
+ static void
+ bse_track_context_create (BseSource      *source,
+                           guint           context_handle,
+                           BseTrans       *trans)
+ {
+   BseTrack *self = BSE_TRACK (source);
+   BseMidiContext mcontext = bse_snet_get_midi_context (bse_item_get_snet (BSE_ITEM (self)), context_handle);
+   if (self->snet || self->wave)
+     bse_midi_receiver_channel_enable_poly (mcontext.midi_receiver, self->midi_channel_SL);
+   /* chain parent class' handler */
+   BSE_SOURCE_CLASS (parent_class)->context_create (source, context_handle, trans);
+ }
+ 
+ static void
+ bse_track_context_dismiss (BseSource      *source,
+                            guint           context_handle,
+                            BseTrans       *trans)
+ {
+   BseTrack *self = BSE_TRACK (source);
+   BseMidiContext mcontext = bse_snet_get_midi_context (bse_item_get_snet (BSE_ITEM (self)), context_handle);
+   if (self->snet || self->wave)
+     bse_midi_receiver_channel_disable_poly (mcontext.midi_receiver, self->midi_channel_SL);
+   /* chain parent class' handler */
+   BSE_SOURCE_CLASS (parent_class)->context_dismiss (source, context_handle, trans);
+ }
+ 
+ void
+ bse_track_remove_modules (BseTrack     *self,
 -                        BseContainer *container)
++                          BseContainer *container)
+ {
+   g_return_if_fail (BSE_IS_TRACK (self));
+   g_return_if_fail (BSE_IS_CONTAINER (container));
+   g_return_if_fail (self->sub_synth != NULL);
+ 
+   bse_container_remove_item (container, BSE_ITEM (self->sub_synth));
+   self->sub_synth = NULL;
+   bse_container_remove_item (container, BSE_ITEM (self->voice_input));
+   self->voice_input = NULL;
+   bse_container_remove_item (container, BSE_ITEM (self->voice_switch));
+   self->voice_switch = NULL;
+   bse_container_remove_item (container, BSE_ITEM (self->postprocess));
+   self->postprocess = NULL;
+ }
+ 
+ void
+ bse_track_clone_voices (BseTrack       *self,
 -                      BseSNet        *snet,
 -                      guint           context,
++                        BseSNet        *snet,
++                        guint           context,
+                         BseMidiContext  mcontext,
 -                      BseTrans       *trans)
++                        BseTrans       *trans)
+ {
+   guint i;
+ 
+   g_return_if_fail (BSE_IS_TRACK (self));
+   g_return_if_fail (BSE_IS_SNET (snet));
+   g_return_if_fail (trans != NULL);
 -
 -  for (i = 0; i < self->max_voices - 1; i++)
 -    bse_snet_context_clone_branch (snet, context, BSE_SOURCE (self), mcontext, trans);
++  if (!self->sound_font_preset)
++    {
++      for (i = 0; i < self->max_voices - 1; i++)
++      bse_snet_context_clone_branch (snet, context, BSE_SOURCE (self), mcontext, trans);
++    }
+ }
+ 
+ static void
+ bse_track_store_private (BseObject  *object,
+                        BseStorage *storage)
+ {
+   BseTrack *self = BSE_TRACK (object);
+   BseItem *item = BSE_ITEM (self);
+   guint i;
+ 
+   /* chain parent class' handler */
+   if (BSE_OBJECT_CLASS (parent_class)->store_private)
+     BSE_OBJECT_CLASS (parent_class)->store_private (object, storage);
+ 
+   for (i = 0; i < self->n_entries_SL; i++)
+     {
+       BseTrackEntry *e = self->entries_SL + i;
+       if (e->part)
+       {
+         bse_storage_break (storage);
+         bse_storage_printf (storage, "(insert-part %u ",
+                             e->tick);
+         bse_storage_put_item_link (storage, item, BSE_ITEM (e->part));
+         bse_storage_putc (storage, ')');
+       }
+     }
+ }
+ 
+ static void
+ part_link_resolved (gpointer        data,
+                   BseStorage     *storage,
+                   BseItem        *from_item,
+                   BseItem        *to_item,
+                   const gchar    *error)
+ {
+   BseTrack *self = BSE_TRACK (from_item);
+ 
+   if (error)
+     bse_storage_warn (storage, "%s", error);
+   else if (!BSE_IS_PART (to_item))
+     bse_storage_warn (storage, "skipping invalid part reference: %s", bse_object_debug_name (to_item));
+   else if (to_item->parent != from_item->parent)
+     bse_storage_warn (storage, "skipping out-of-branch part reference: %s", bse_object_debug_name 
(to_item));
+   else
+     {
+       guint tick = GPOINTER_TO_UINT (data);
+       if (bse_track_insert_part (self, tick, BSE_PART (to_item)) < 1)
+       bse_storage_warn (storage, "failed to insert part reference to %s",
+                         bse_object_debug_name (to_item));
+     }
+ }
+ 
+ static GTokenType
+ bse_track_restore_private (BseObject  *object,
+                          BseStorage *storage,
+                            GScanner   *scanner)
+ {
+   BseTrack *self = BSE_TRACK (object);
+ 
+   if (g_scanner_peek_next_token (scanner) == G_TOKEN_IDENTIFIER &&
+       bse_string_equals ("insert-part", scanner->next_value.v_identifier))
+     {
+       GTokenType token;
+       guint tick;
+ 
+       g_scanner_get_next_token (scanner);       /* eat quark */
+ 
+       parse_or_return (scanner, G_TOKEN_INT);
+       tick = scanner->value.v_int64;
+       token = bse_storage_parse_item_link (storage, BSE_ITEM (self), part_link_resolved, GUINT_TO_POINTER 
(tick));
+       if (token != G_TOKEN_NONE)
+       return token;
+       parse_or_return (scanner, ')');
+       return G_TOKEN_NONE;
+     }
+   else /* chain parent class' handler */
+     return BSE_OBJECT_CLASS (parent_class)->restore_private (object, storage, scanner);
+ }
+ 
+ static void
+ bse_track_class_init (BseTrackClass *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+   BseObjectClass *object_class = BSE_OBJECT_CLASS (klass);
+   BseItemClass *item_class = BSE_ITEM_CLASS (klass);
+   BseSourceClass *source_class = BSE_SOURCE_CLASS (klass);
+ 
+   parent_class = (GTypeClass*) g_type_class_peek_parent (klass);
+ 
+   gobject_class->set_property = bse_track_set_property;
+   gobject_class->get_property = bse_track_get_property;
+   gobject_class->dispose = bse_track_dispose;
+   gobject_class->finalize = bse_track_finalize;
+ 
+   object_class->store_private = bse_track_store_private;
+   object_class->restore_private = bse_track_restore_private;
+ 
+   item_class->get_candidates = bse_track_get_candidates;
+ 
+   source_class->context_create = bse_track_context_create;
+   source_class->context_dismiss = bse_track_context_dismiss;
+ 
+   bse_source_class_inherit_channels (BSE_SOURCE_CLASS (klass));
+ 
+   bse_object_class_add_param (object_class, _("Adjustments"),
+                             PROP_MUTED,
+                             sfi_pspec_bool ("muted", _("Muted"), NULL,
+                                             FALSE, SFI_PARAM_STANDARD ":skip-default"));
+   bse_object_class_add_param (object_class, _("Synth Input"),
+                             PROP_SNET,
+                             bse_param_spec_object ("snet", _("Synthesizer"), _("Synthesis network to be 
used as instrument"),
+                                                    BSE_TYPE_CSYNTH,
+                                                    SFI_PARAM_STANDARD ":unprepared"));
+   bse_object_class_add_param (object_class, _("Synth Input"),
+                             PROP_WAVE,
+                             bse_param_spec_object ("wave", _("Wave"), _("Wave to be used as instrument"),
+                                                    BSE_TYPE_WAVE,
+                                                    SFI_PARAM_STANDARD ":unprepared"));
+   bse_object_class_add_param (object_class, _("Synth Input"),
++                            PROP_SOUND_FONT_PRESET,
++                              bse_param_spec_object (("sound_font_preset"), _("Sound Font Preset"),
++                                                     _("Sound font preset to be used as instrument"),
++                                                   BSE_TYPE_SOUND_FONT_PRESET,
++                                                   SFI_PARAM_STANDARD ":unprepared"));
++  bse_object_class_add_param (object_class, _("Synth Input"),
+                             PROP_N_VOICES,
+                             sfi_pspec_int ("n_voices", _("Max Voices"), _("Maximum number of voices for 
simultaneous playback"),
+                                            16, 1, 256, 1,
+                                            SFI_PARAM_GUI SFI_PARAM_STORAGE ":scale:unprepared"));
+   bse_object_class_add_param (object_class, _("MIDI Instrument"),
+                               PROP_MIDI_CHANNEL,
+                               sfi_pspec_int ("midi_channel", _("MIDI Channel"),
+                                              _("Midi channel assigned to this track, 0 uses internal 
per-track channel"),
+                                              0, 0, BSE_MIDI_MAX_CHANNELS, 1,
+                                              SFI_PARAM_GUI SFI_PARAM_STORAGE 
":scale:skip-default:unprepared"));
+   bse_object_class_add_param (object_class, _("MIDI Instrument"),
+                             PROP_PNET,
+                             bse_param_spec_object ("pnet", _("Postprocessor"), _("Synthesis network to be 
used as postprocessor"),
+                                                    BSE_TYPE_CSYNTH, SFI_PARAM_STANDARD ":unprepared"));
+   bse_object_class_add_param (object_class, _("Signal Outputs"),
+                               PROP_OUTPUTS,
+                               bse_param_spec_boxed ("outputs", _("Output Signals"),
+                                                     _("Mixer busses used as output for this track"),
+                                                     BSE_TYPE_ITEM_SEQ, SFI_PARAM_GUI ":item-sequence"));
+   signal_changed = bse_object_class_add_asignal (object_class, "changed", G_TYPE_NONE, 0);
+ }
diff --cc bse/bsetrack.hh
index 0000000,83a06a7..deb50df
mode 000000,100644..100644
--- a/bse/bsetrack.hh
+++ b/bse/bsetrack.hh
@@@ -1,0 -1,83 +1,88 @@@
+ // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+ #ifndef __BSE_TRACK_H__
+ #define __BSE_TRACK_H__
+ 
+ #include <bse/bseitem.hh>
+ #include <bse/bsesnet.hh>
+ #include <bse/bsecontextmerger.hh>
+ 
+ G_BEGIN_DECLS
+ 
+ /* --- BSE type macros --- */
+ #define BSE_TYPE_TRACK                    (BSE_TYPE_ID (BseTrack))
+ #define BSE_TRACK(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), BSE_TYPE_TRACK, BseTrack))
+ #define BSE_TRACK_CLASS(class)            (G_TYPE_CHECK_CLASS_CAST ((class), BSE_TYPE_TRACK, BseTrackClass))
+ #define BSE_IS_TRACK(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), BSE_TYPE_TRACK))
+ #define BSE_IS_TRACK_CLASS(class)   (G_TYPE_CHECK_CLASS_TYPE ((class), BSE_TYPE_TRACK))
+ #define BSE_TRACK_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), BSE_TYPE_TRACK, BseTrackClass))
+ 
+ struct BseTrackEntry {
+   guint    tick;
+   guint    id;
+   BsePart *part;
+ };
+ struct BseTrack : BseContextMerger {
+   guint            channel_id;
+   guint                  max_voices;
+   BseSNet       *snet;
+   BseSNet         *pnet;
+   /* wave synthesis */
+   BseWave       *wave;
+   BseSNet       *wnet;
++
++  /* sound font synthesis */
++  BseSoundFontPreset  *sound_font_preset;
++  BseSNet         *sound_font_net;
++
+   /* playback intergration */
+   BseSource       *sub_synth;
+   BseSource       *voice_input;
+   BseSource       *voice_switch;
+   BseSource       *postprocess;
+   SfiRing         *bus_outputs; /* maintained by bsebus.[hc] */
+   /* fields protected by sequencer mutex */
+   guint                  n_entries_SL : 30;
+   guint                  muted_SL : 1;
+   BseTrackEntry         *entries_SL;
+   guint            midi_channel_SL;
+   gboolean       track_done_SL;
+ };
+ struct BseTrackClass : BseContextMergerClass
+ {};
+ 
+ /* --- prototypes -- */
+ void  bse_track_add_modules           (BseTrack               *self,
+                                        BseContainer           *container,
+                                          BseMidiReceiver        *midi_receiver);
+ void  bse_track_remove_modules        (BseTrack               *self,
+                                        BseContainer           *container);
+ void  bse_track_clone_voices          (BseTrack               *self,
+                                        BseSNet                *snet,
+                                        guint                   context,
+                                          BseMidiContext          mcontext,
+                                        BseTrans               *trans);
+ BseSource*       bse_track_get_output   (BseTrack               *self);
+ guint          bse_track_get_last_tick(BseTrack               *self);
+ guint          bse_track_insert_part  (BseTrack               *self,
+                                        guint                   tick,
+                                        BsePart                *part);
+ void           bse_track_remove_tick  (BseTrack               *self,
+                                        guint                   tick);
+ BseTrackPartSeq* bse_track_list_parts (BseTrack               *self);
+ BseTrackPartSeq* bse_track_list_part  (BseTrack               *self,
+                                          BsePart                *part);
+ gboolean       bse_track_find_part    (BseTrack               *self,
+                                        BsePart                *part,
+                                        guint                  *start_p);
+ BseTrackEntry*         bse_track_lookup_tick  (BseTrack               *self,
+                                        guint                   tick);
+ BseTrackEntry*   bse_track_find_link    (BseTrack               *self,
+                                          guint                   id);
+ BsePart*       bse_track_get_part_SL  (BseTrack               *self,
+                                        guint                   tick,
+                                        guint                  *start,
+                                        guint                  *next);
+ 
+ G_END_DECLS
+ 
+ #endif /* __BSE_TRACK_H__ */
diff --cc configure.ac
index 0000000,a7d9f28..1ae3882
mode 000000,100644..100644
--- a/configure.ac
+++ b/configure.ac
@@@ -1,0 -1,764 +1,769 @@@
+ # Licensed GNU LGPL v2 or later: http://www.gnu.org/licenses/lgpl.html
+ 
+ # include various m4 macros
+ m4_include(acbeast.m4)dnl # include special macros
+ m4_include(ld-symbolic.m4)dnl # include special macros
+ m4_include(autotools/glib-gettext.m4)
+ 
+ 
+ #
+ # Configure script for BEAST/BSE
+ #
+ AC_PREREQ(2.57)
+ # VERSION: MAJOR.MINOR.MICRO-RC:
+ # * MAJOR, MINOR: increment on ABI/API changes
+ # * MICRO: increment when ABI compatible, development versions are odd
+ # * RC: release candidate, may be rc[0-9]+ or empty
+ AC_INIT([beast], [0.9.1]) # defines PACKAGE_NAME, PACKAGE_VERSION, PACKAGE_STRING
+ AC_CONFIG_SRCDIR([bse/bseconfig.h.in])
+ AC_CONFIG_AUX_DIR([autotools])
+ AC_CONFIG_MACRO_DIR([autotools])
+ AC_CANONICAL_TARGET                                   # architecture information
+ AM_INIT_AUTOMAKE(tar-pax no-define -Wno-portability)  # don't define PACKAGE and VERSION
+ AM_CONFIG_HEADER(configure.h)
+ # version handling
+ BST_VERSION="$PACKAGE_VERSION"
+ [BST_MAJOR_VERSION=`echo $PACKAGE_VERSION | sed 's/\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)\(.*\)/\1/'`]
+ [BST_MINOR_VERSION=`echo $PACKAGE_VERSION | sed 's/\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)\(.*\)/\2/'`]
+ [BST_MICRO_VERSION=`echo $PACKAGE_VERSION | sed 's/\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)\(.*\)/\3/'`]
+ [BIN_VERSION=`echo $PACKAGE_VERSION | sed 's/\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)\(.*\)/\1.\2.\3/'`]
+ case "$BST_VERSION" in
+ 0.99.*)     BST_VERSION_HINT=BETA ;;
+ 0.*)        BST_VERSION_HINT="ALPHA" ;;
+ *)          BST_VERSION_HINT="Stable Release"
+             test `expr $BST_MICRO_VERSION \% 2` = 1 && BST_VERSION_HINT="Development Build" ;;
+ esac
+ AC_DEFINE_UNQUOTED(BST_VERSION, "$BST_VERSION", [BEAST Version])
+ AC_DEFINE_UNQUOTED(BIN_VERSION, "$BIN_VERSION", [Binary Version])
+ AC_DEFINE_UNQUOTED(BST_VERSION_HINT, "$BST_VERSION_HINT", [Version classification])
+ AC_SUBST(BST_VERSION)
+ AC_SUBST(BST_MAJOR_VERSION)
+ AC_SUBST(BST_MINOR_VERSION)
+ AC_SUBST(BST_MICRO_VERSION)
+ AC_SUBST(BIN_VERSION)
+ 
+ # compute libtool versions
+ LT_RELEASE=$BST_MAJOR_VERSION.$BST_MINOR_VERSION
+ LT_CURRENT=$BST_MICRO_VERSION
+ LT_REVISION=0
+ LT_AGE=$BST_MICRO_VERSION
+ AC_SUBST(LT_RELEASE)
+ AC_SUBST(LT_CURRENT)
+ AC_SUBST(LT_REVISION)
+ AC_SUBST(LT_AGE)
+ if test 1 = $(($BST_MICRO_VERSION & 1)) ; then
+   DEFINE__FILE_DIR__='-D__FILE_DIR__=\"${abs_srcdir}\"'
+ else
+   DEFINE__FILE_DIR__='-D__FILE_DIR__=\"beast/${subdir}\"'
+ fi
+ AC_SUBST(DEFINE__FILE_DIR__)
+ 
+ # Build tree checks
+ AC_MSG_CHECKING([for git repository])
+ test -f "${srcdir}/.git/index" && INGIT= || INGIT='#'
+ AC_SUBST(INGIT)
+ result=$(test -z "$INGIT" && echo yes || echo no)
+ AC_MSG_RESULT($result)
+ 
+ dnl # AC_CANONICAL_HOST is provided by AC_CANONICAL_TARGET
+ AC_DEFINE_UNQUOTED(BST_ARCH_NAME, "$target", [Architecture Description])
+ 
+ # We have subdirectories.
+ AC_PROG_MAKE_SET
+ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+ 
+ # declare --enable-* args and collect ac_help strings
+ AC_ARG_ENABLE(debug,      [  --enable-debug=no/minimum/yes  turn on debugging, 
default=yes],,enable_debug=yes)
+ AC_ARG_ENABLE(devel-mode, [  --enable-devel-mode=[no/yes]   turn on development mode, 
default=no],,enable_devel_mode=no)
+ AC_ARG_ENABLE(distcheck-tests, [  --enable-distcheck-tests       turn on resource and time consuming 
distcheck tests],,enable_distcheck_tests=no)
+ 
+ # set BEAST_BUILD_DEFAULTS from configure's BEAST_BUILD env
+ BEAST_BUILD_DEFAULTS="$BEAST_BUILD_DEFAULTS"
+ test "$enable_distcheck_tests" = yes && BEAST_BUILD_DEFAULTS="$BEAST_BUILD_DEFAULTS:distcheck-tests:"
+ AC_SUBST(BEAST_BUILD_DEFAULTS)
+ 
+ dnl # setup DEBUG defaults
+ if test "x$enable_debug" = "xyes"; then
+   DEBUG_FLAGS="-g -DG_ENABLE_DEBUG"
+ else if test "x$enable_debug" = "xno"; then
+   DEBUG_FLAGS="-DG_DISABLE_CHECKS -DG_DISABLE_CAST_CHECKS" # -DG_DISABLE_ASSERT
+ else
+   DEBUG_FLAGS="-DG_DISABLE_CAST_CHECKS"
+ fi fi
+ if test -z "$CFLAGS"; then
+   CFLAGS="$DEBUG_FLAGS"
+ else
+   CFLAGS="$CFLAGS $DEBUG_FLAGS"
+ fi
+ if test -z "$CXXFLAGS"; then
+   CXXFLAGS="$DEBUG_FLAGS"
+ else
+   CXXFLAGS="$CXXFLAGS $DEBUG_FLAGS"
+ fi
+ 
+ dnl # Foreign defaults:
+ MC_IF_VAR_EQ(enable_static, yes, , enable_static=no)
+ MC_IF_VAR_EQ(enable_shared, no, , enable_shared=yes)
+ 
+ # compiler, linker & libtool
+ saved_CFLAGS="$CFLAGS"
+ AC_PROG_CC
+ CFLAGS="$saved_CFLAGS"                # AC_PROG_CC_G called internally consistently breaks $CFLAGS
+ saved_CXXFLAGS="$CFLAGS"
+ AC_PROG_CPP
+ CXXFLAGS="$saved_CXXFLAGS"    # AC_PROG_CXX_G called internally consistently breaks $CXXFLAGS
+ AC_PROG_CXX
+ AC_PROG_CXXCPP
+ AC_PROG_LD
+ AC_LANG_CPLUSPLUS     # use CXX for compilation tests
+ AC_LIB_PROG_LD
+ AC_LIB_PROG_LD_GNU
+ ACX_PROG_LD_GNU_SYMBOLIC
+ AC_SUBST([SYMBOLIC_LDFLAGS])
+ ACX_PROG_LD_GNU_DYNAMIC_LIST_CPP_NEW
+ AC_SUBST([DYNAMIC_LIST_CPP_NEW_LDFLAGS])
+ AM_PROG_LIBTOOL
+ AC_LIBTOOL_DLOPEN
+ 
+ # AM_LDFLAGS, optimize linker to use faster ELF symbol hashing if we have compiler and linker support
+ AC_MSG_CHECKING([whether CC and LD support gnu.hash sections])
+ if ${CC-cc} -dumpspecs | grep -q -- '--hash-style=\(both\|gnu\).*--as-needed' && \
+    ${LD-ld} --help     | grep -q -- '--hash-style=.*\(both\|gnu\)' ; then
+   MC_EVAR_ADD(AM_LDFLAGS, [-Wl,--hash-style=both -Wl,--as-needed -Wl,-O1])
+   AC_MSG_RESULT(yes)
+ else
+   AC_MSG_RESULT(no)
+ fi
+ MC_EVAR_ADD(AM_LDFLAGS, -pthread)
+ MC_EVAR_ADD(AM_LDFLAGS, -lrt)
+ MC_EVAR_ADD(AM_LDFLAGS, -Wl,--no-undefined)
+ AC_SUBST(AM_LDFLAGS)
+ 
+ # Pick C++ dialect, needed in CXXFLAGS for compile tests
+ MC_CXX_TRY_OPTION(CXXFLAGS,  -std=gnu++0x)
+ 
+ # AM_CFLAGS & AM_CXXFLAGS
+ MC_CXX_TRY_OPTION(AM_CXXFLAGS,  -std=gnu++0x)
+ BOTHCCXXFLAGS=
+ if test "x$enable_debug" = "xyes"; then
+   MC_EVAR_ADD(BOTHCCXXFLAGS,      -DG_ENABLE_DEBUG)
+   MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -g)
+   MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -ggdb3)
+   MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -fno-omit-frame-pointer)
+   MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -fverbose-asm)
+   dnl # MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -Q -ftime-report -fmem-report)
+ elif test "x$enable_debug" = "xno"; then
+   MC_EVAR_ADD(BOTHCCXXFLAGS, [-DG_DISABLE_CHECKS -DG_DISABLE_CAST_CHECKS]) # -DG_DISABLE_ASSERT
+ else
+   : # minimum debugging
+ fi
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -fmessage-length=0)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -fdiagnostics-color=auto)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -Wall)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -Wdeprecated)
+ MC_CC_TRY_OPTION(AM_CFLAGS,     -Wmissing-prototypes)
+ MC_CC_TRY_OPTION(AM_CFLAGS,     -Wno-pointer-sign)
+ MC_CC_TRY_OPTION(AM_CFLAGS,     -Wnested-externs)
+ MC_CC_TRY_OPTION(AM_CFLAGS,     -fno-cond-mismatch)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -Wmissing-declarations)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -Wpointer-arith)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -Wredundant-decls)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -Werror=format-security)
+ MC_CXX_TRY_OPTION(AM_CXXFLAGS,  -Wsign-promo)
+ MC_CXX_TRY_OPTION(AM_CXXFLAGS,  -Woverloaded-virtual)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -rdynamic)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -pipe)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -O2)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -ftracer)
+ MC_CC_TRY_OPTION(BOTHCCXXFLAGS, -mcx16)
+ dnl # MC_CXX_TRY_OPTION(AM_CXXFLAGS,  -Wno-invalid-offsetof)
+ MC_EVAR_ADD(AM_CFLAGS,   "$BOTHCCXXFLAGS")
+ MC_EVAR_ADD(AM_CXXFLAGS, "$BOTHCCXXFLAGS")
+ AC_SUBST(AM_CFLAGS)
+ AC_SUBST(AM_CXXFLAGS)
+ AC_SUBST(AM_CPPFLAGS)
+ 
+ # == CPU Optimizations ==
+ # MMX and SSE instruction sets have been introduced way more than a decade ago:
+ # Intel Pentium 3: CMOV MMX SSE (1999)
+ # VIA C3 Nehemiah: CMOV MMX SSE (2003)
+ # Athlon Palomino: CMOV MMX SSE 3DNow (2001)
+ MMX_SSE_FLAGS=
+ MC_CC_TRY_OPTION(MMX_SSE_FLAGS, -mmmx)
+ MC_CC_TRY_OPTION(MMX_SSE_FLAGS, -msse)
+ # Note, -mfpmath=sse can harm FPU-algorithm performance
+ # Note, -funroll-loops can harm SSE loop performance
+ #MC_CC_TRY_OPTION(MMX_SSE_FLAGS, -funroll-loops)
+ #AC_SUBST(MMX_SSE_FLAGS)
+ # Expect the target architecture to support MMX/SSE if the compiler does it.
+ MC_EVAR_ADD(AM_CFLAGS,   "$MMX_SSE_FLAGS")
+ MC_EVAR_ADD(AM_CXXFLAGS, "$MMX_SSE_FLAGS")
+ # Newer vectorization instruction sets, should be optionally supported
+ # SSE >= 2, AVX
+ SSEAVX_FLAGS=
+ MC_CC_TRY_OPTION(SSEAVX_FLAGS, -msse2)
+ MC_CC_TRY_OPTION(SSEAVX_FLAGS, -msse3)
+ MC_CC_TRY_OPTION(SSEAVX_FLAGS, -mssse3)
+ MC_CC_TRY_OPTION(SSEAVX_FLAGS, -msse4)
+ MC_CC_TRY_OPTION(SSEAVX_FLAGS, -msse4.1)
+ MC_CC_TRY_OPTION(SSEAVX_FLAGS, -msse4.2)
+ MC_CC_TRY_OPTION(SSEAVX_FLAGS, -msse4a)
+ MC_CC_TRY_OPTION(SSEAVX_FLAGS, -mavx)
+ MC_CC_TRY_OPTION(SSEAVX_FLAGS, -mavx2)
+ AC_SUBST(SSEAVX_FLAGS)
+ 
+ # == OPTIMIZE_FAST ==
+ # Some critical code paths should be optimized to run as fast as possible
+ OPTIMIZE_FAST=
+ MC_CC_TRY_OPTION(OPTIMIZE_FAST, -O3)
+ MC_CC_TRY_OPTION(OPTIMIZE_FAST, -ftree-vectorize)
+ MC_CC_TRY_OPTION(OPTIMIZE_FAST, -finline-functions)
+ MC_CC_TRY_OPTION(OPTIMIZE_FAST, -minline-all-stringops)
+ AC_SUBST(OPTIMIZE_FAST)
+ 
+ # == Bse Plugin FLAGS ==
+ # * -funroll-loops significantly boosts FPU performance
+ # * -mfpmath=sse harms FPU-algorithm performance
+ # * -funroll-loops harms SSE loop performance
+ MC_CXX_TRY_OPTION(FAST_MATH_FLAGS, -ftree-loop-ivcanon)
+ MC_CXX_TRY_OPTION(FAST_MATH_FLAGS, -ftree-loop-linear)
+ MC_CXX_TRY_OPTION(FAST_MATH_FLAGS, -ftree-loop-im)
+ MC_CXX_TRY_OPTION(FAST_MATH_FLAGS, -ffast-math)
+ MC_CXX_TRY_OPTION(FAST_MATH_FLAGS, -fivopts)
+ AC_SUBST(FAST_MATH_FLAGS)
+ MC_CXX_TRY_OPTION(FPU_FLAGS, -funroll-loops)
+ AC_SUBST(FPU_FLAGS)
+ MMX_SSE_FLAGS="$MMX_SSE_FLAGS"
+ AC_SUBST(MMX_SSE_FLAGS)
+ 
+ # == SSE Build Conditionals ==
+ lacking_mmx_sse=`echo "$MMX_SSE_FLAGS" | grep 'mmx.*sse' -q ; echo $?` # sh truth values: 1 (without sse) 
or 0 (with sse)
+ AM_CONDITIONAL(WITH_MMX_SSE, test 0 == $lacking_mmx_sse)
+ AC_DEFINE_UNQUOTED(BSE_WITH_MMX_SSE, [(0 == $lacking_mmx_sse)], [wether MMX and SSE are supported])
+ 
+ # C & C++ idioms
+ AC_C_CONST
+ AC_C_INLINE
+ AC_HEADER_STDC
+ 
+ # Checks for programs
+ AC_PROG_INSTALL
+ AC_PROG_LN_S
+ 
+ # require pkg-config
+ MC_ASSERT_PROG(PKG_CONFIG, pkg-config, [pkg-config can be found at 
http://www.freedesktop.org/software/pkgconfig/])
+ 
+ dnl #
+ dnl # Define package requirements.
+ dnl #
+ AC_DEFUN([AC_I18N_REQUIREMENTS],
+ [
+   # LINGUAS
+   ALL_LINGUAS=`cat "$srcdir/po/LINGUAS" | grep -v '^#' | xargs echo -n `
+   AC_SUBST(ALL_LINGUAS)
+   AC_SUBST([CONFIG_STATUS_DEPENDENCIES], ['$(top_srcdir)/po/LINGUAS'])
+ 
+   # versioned BEAST gettext domain (po/)
+   BST_GETTEXT_DOMAIN=beast-v$BIN_VERSION    # version without -rcZ
+   AC_SUBST(BST_GETTEXT_DOMAIN)
+   AC_DEFINE_UNQUOTED(BST_GETTEXT_DOMAIN, "$BST_GETTEXT_DOMAIN", [Versioned BEAST gettext domain])
+   GETTEXT_PACKAGE=$BST_GETTEXT_DOMAIN
+   AC_SUBST(GETTEXT_PACKAGE)
+ 
+   # locale directory for all domains
+   # (AM_GLIB_DEFINE_LOCALEDIR() could do this if it would do AC_SUBST())
+   saved_prefix="$prefix"              ; saved_exec_prefix="$exec_prefix"
+   test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+   test "x$exec_prefix" = xNONE && exec_prefix="$prefix"
+   if test "x$CATOBJEXT" = "x.mo" ; then
+     beastlocaledir=`eval echo "${libdir}/locale"`
+   else
+     beastlocaledir=`eval echo "${datadir}/locale"`
+   fi
+   exec_prefix="$saved_exec_prefix"    ; prefix="$saved_prefix"
+   AC_SUBST(beastlocaledir)
+ 
+   # check for proper gettext support
+   AM_GLIB_GNU_GETTEXT([external])
+   test -z "$ac_cv_path_XGETTEXT" && {
+     AC_MSG_ERROR(["Failed to detect gettext, required for internationalization." \
+       "GNU gettext is available from: http://www.gnu.org/software/gettext/";])
+   }
+ 
+   # check for gettext utilities
+   AC_PATH_PROG(ICONV, iconv, iconv)
+   AC_PATH_PROG(MSGFMT, msgfmt, msgfmt)
+   AC_PATH_PROG(MSGMERGE, msgmerge, msgmerge)
+   AC_PATH_PROG(XGETTEXT, xgettext, xgettext)
+   AC_SUBST(ac_aux_dir) dnl # needed to ship various intlfix scripts
+   INTLMERGE='$(top_builddir)/$(ac_aux_dir)/intltool-merge'
+   AC_SUBST(INTLMERGE) dnl # AC_PATH_PROG(INTLMERGE, intltool-merge, intltool-merge)
+ ])
+ AC_DEFUN([AC_SFI_REQUIREMENTS],
+ [
+     dnl # check for GLib libs
+     PKG_CHECK_MODULES(GLIB_GOMT, glib-2.0 >= 2.32.3 gobject-2.0 gmodule-no-export-2.0 gthread-2.0)
+     AC_SUBST(GLIB_GOMT_CFLAGS)
+     AC_SUBST(GLIB_GOMT_LIBS)
+     SFI_CPPFLAGS="$GLIB_GOMT_CFLAGS"
+     SFI_LIBS="$GLIB_GOMT_LIBS"
+     AC_SUBST(SFI_CPPFLAGS)
+     AC_SUBST(SFI_LIBS)
+ 
+     AC_CHECK_FUNCS(getpwnam_r getpwnam)
+     AC_CHECK_FUNCS(timegm)
+ 
+     dnl # --- SFI directories ---
+     sfidlstdincdir=${includedir}
+     AC_SUBST(sfidlstdincdir)
+ ])
+ AC_DEFUN([AC_BSE_REQUIREMENTS],
+ [
+     dnl # require Rapicorn
+     PKG_CHECK_MODULES(RAPICORN, rapicorn1410 >= 14.10.0)
+     MC_ASSERT_PROG(AIDACC, aidacc-1410, [aidacc gets shipped with Rapicorn])
+ 
+     dnl # --- Ogg/Vorbis check ---
+     PKG_CHECK_MODULES(OV, ogg >= 1.2.2 vorbis >= 1.3.2 vorbisfile >= 1.3.2 vorbisenc >= 1.3.2)
+ 
+     dnl # --- FLAC check ---
+     PKG_CHECK_MODULES(FLAC, flac)
+ 
+     dnl # old FLAC versions use "-I/usr/.../include/FLAC" as pkg-config --cflags
+     dnl # new FLAC versions use "-I/usr/.../include" as pkg-config --cflags
+     dnl #
+     dnl # to support both, we strip /FLAC from FLAC_CFLAGS and use #include <FLAC/foo.h>
+     FLAC_CFLAGS=`echo $FLAC_CLFAGS | $SED "s/FLAC$//"`
+ 
+     dnl # --- libmad MPEG decoder check ---
+     dnl # libmad doesn't come with a mad.pc file (just its debian package)
+     dnl # PKG_CHECK_MODULES(MAD, mad >= 0.14.2,
+     dnl #     BSE_HAVE_LIBMAD=1
+     dnl #     ,
+     dnl #     BSE_HAVE_LIBMAD=0
+     dnl #     AC_MSG_WARN([failed to detect libmad (MPEG I-III audio decoder) or headers])
+     dnl # )
+     MAD_LIBS=
+     mad_tests=0
+     AC_CHECK_LIB(mad, mad_stream_errorstr,
+         [AC_CHECK_HEADER(mad.h, mad_tests=`expr $mad_tests + 1`)]
+         ,
+         mad_tests=0, -lm)
+     if test $mad_tests = 1 ; then
+       BSE_HAVE_LIBMAD=1
+         MAD_LIBS="-lmad -lm"
+     else
+         AC_MSG_WARN([failed to detect libmad (MPEG I-III audio decoder) or headers])
+       BSE_HAVE_LIBMAD=0
+     fi
+     AC_DEFINE_UNQUOTED(BSE_HAVE_LIBMAD, $BSE_HAVE_LIBMAD, [Whether bse links against libmad])
+ 
+     dnl # --- check codec requirements ---
+     AC_MSG_CHECKING([the required GSL-Loader library set])
+     if echo " $OV_LIBS" | grep ".*-lvorbis.*" >/dev/null ; then
+       AC_MSG_RESULT([complete])
+     else
+       AC_MSG_RESULT([])
+       AC_MSG_ERROR([Ogg/Vorbis is missing, but required])
+     fi
+ 
++    dnl Check for FluidSynth
++    PKG_CHECK_MODULES(FLUID, fluidsynth >= 1.0.6)
++
+     dnl # --- complete CFLAGS/LIBS setup ---
+     BSE_CFLAGS="$MAD_CFLAGS $FLAC_CFLAGS $SFI_CPPFLAGS"
+     BSE_LIBS="$OV_LIBS $MAD_LIBS $FLAC_LIBS $SFI_LIBS"
++    BSE_CFLAGS="$FLUID_CFLAGS $BSE_CFLAGS"
++    BSE_LIBS="$FLUID_LIBS $BSE_LIBS"
+     AC_SUBST(BSE_CFLAGS)
+     AC_SUBST(BSE_LIBS)
+     dnl # --- figure stuff for bse.pc ---
+     BSE_PC_REQUIRE=
+     dnl # except for debian, libmad doesn't ship a mad.pc file
+     dnl #if test $BSE_HAVE_LIBMAD = 1 ; then
+     dnl #     BSE_PC_REQUIRE=mad
+     dnl #fi
+     BSE_PC_CFLAGS=
+     BSE_PC_LIBS="$OV_LIBS"
+     AC_SUBST(BSE_PC_REQUIRE)
+     AC_SUBST(BSE_PC_CFLAGS)
+     AC_SUBST(BSE_PC_LIBS)
+ 
+     dnl # --- sizeof types ---
+     GLIB_SIZEOF([#include <pthread.h>], pthread_mutex_t, pth_mutex_t)
+     SFI_SIZEOF_PTH_MUTEX_T="$glib_cv_sizeof_pth_mutex_t"
+     AC_SUBST(SFI_SIZEOF_PTH_MUTEX_T)
+     GLIB_SIZEOF([#include <pthread.h>], pthread_cond_t, pth_cond_t)
+     SFI_SIZEOF_PTH_COND_T="$glib_cv_sizeof_pth_cond_t"
+     AC_SUBST(SFI_SIZEOF_PTH_COND_T)
+ 
+     dnl # --- pthread_mutexattr_settype ---
+     AC_MSG_CHECKING([for pthread_mutexattr_settype()])
+     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+       #define _XOPEN_SOURCE   600
+       #include <pthread.h>
+     ]], [[
+       int (*attr_settype) (pthread_mutexattr_t *__attr, int __kind) = pthread_mutexattr_settype;
+       int val = PTHREAD_MUTEX_RECURSIVE;
+       attr_settype = 0; val = 0;
+     ]])],[
+       SFI_HAVE_MUTEXATTR_SETTYPE=1
+       AC_MSG_RESULT(yes)
+     ],[
+       SFI_HAVE_MUTEXATTR_SETTYPE=0
+       AC_MSG_RESULT(no)
+     ])
+     AC_SUBST(SFI_HAVE_MUTEXATTR_SETTYPE)
+ 
+     dnl # --- math.h glibc extensions
+     AC_CHECK_LIB(m, sincos,
+       AC_DEFINE(HAVE_SINCOS, 1, [Define if you have the sincos function in <math.h>]))
+ 
+     # --- setup BSE search/install paths ---
+     bseplugindir=\${libdir}/bse/v$BIN_VERSION/plugins
+     AC_SUBST(bseplugindir)
+     bsedriverdir=\${libdir}/bse/v$BIN_VERSION/drivers
+     AC_SUBST(bsedriverdir)
+     bseladspapath=${libdir}/ladspa
+     AC_SUBST(bseladspapath)
+     bseunversionedsampledir=\${datadir}/bse/samples
+     AC_SUBST(bseunversionedsampledir)
+     bsedatadir=\${datadir}/bse/v$BIN_VERSION
+     bseeffectdir=$bsedatadir/effects
+     AC_SUBST(bseeffectdir)
+     bseinstrumentdir=$bsedatadir/instruments
+     AC_SUBST(bseinstrumentdir)
+     bsesampledir=$bsedatadir/samples
+     AC_SUBST(bsesampledir)
+     bsescriptdir=$bsedatadir/scripts
+     AC_SUBST(bsescriptdir)
+     bsedemodir=$bsedatadir/demo
+     AC_SUBST(bsedemodir)
+     bseuserdatadir='~/beast'
+     AC_SUBST(bseuserdatadir)
+ ])
+ AC_DEFUN([AC_ASOUND_CHECK],
+ [
+     saved_cflags="$CFLAGS"
+     saved_cxxflags="$CXXFLAGS"
+     saved_ldflags="$LDFLAGS"
+     dnl # automatically search for libasound under the BSE prefix
+     CFLAGS="$CFLAGS $BSE_CFLAGS"
+     CXXFLAGS="$CFLAGS $BSE_CFLAGS"
+     LDFLAGS="$LDFLAGS $BSE_LIBS"
+     AC_LANG_SAVE
+ 
+     dnl --- find asoundlib.h ---
+     found_asoundlibh=0
+     AC_CHECK_HEADERS(alsa/asoundlib.h, found_asoundlibh=1)
+     if test $found_asoundlibh = 0 ; then
+       AC_MSG_ERROR([failed to detect asoundlib.h, ALSA not present?])
+     fi
+ 
+     dnl --- check for ALSA >= 1.0.5 ---
+     AC_MSG_CHECKING([for ALSA with version >= 1.0])
+     found_alsa1=0
+     AC_TRY_COMPILE([#include <alsa/asoundlib.h>],[
+             #if SND_LIB_MAJOR >= 1
+               /* ALSA >= 1.0 present */
+           #else
+               #error ALSA version <= 1.0
+           #endif
+     ], [ found_alsa1=1; AC_MSG_RESULT(present); ], [ AC_MSG_RESULT(not present); ])
+     if test $found_alsa1 = 0; then
+       AC_MSG_ERROR([ALSA version 1.0.5 is required to build this package])
+     fi
+ 
+     dnl --- check for -lasound ---
+     found_libasound=0
+     dnl snd_asoundlib_version() was introduced in ALSA 1.0.5
+     cflags=$CFLAGS
+     ldflags=$LDFLAGS
+     CFLAGS=""
+     LDFLAGS=""
+     AC_CHECK_LIB(asound, snd_asoundlib_version, ALSA_LIBS="-lasound"; found_libasound=1)
+     CFLAGS="$cflags"
+     LDFLAGS="$ldflags"
+     if test $found_libasound = 0; then
+       AC_MSG_ERROR([ALSA version 1.0.5 is required to build this package])
+     fi
+     AC_SUBST(ALSA_LIBS)
+ 
+     AC_LANG_RESTORE
+     CFLAGS="$saved_cflags"
+     CXXFLAGS="$saved_cxxflags"
+     LDFLAGS="$saved_ldflags"
+ ])
+ AC_DEFUN([AC_BSESCM_REQUIREMENTS],
+ [
+     BSESCM_CFLAGS="$BSE_CFLAGS"
+     BSESCM_LIBS="$BSE_LIBS"
+ 
+     dnl # --- libguile check ---
+     guile_tests=0
+     GUILE_VERSION=none
+     REQUIRED_VERSION=1.6
+     AC_PATH_PROG(GUILE_CONFIG, guile-config)
+     if test -n "$GUILE_CONFIG"; then
+       guile_tests=`expr $guile_tests + 1`
+       GUILE_VERSION=`$GUILE_CONFIG info guileversion`
+       GUILE_CFLAGS=`$GUILE_CONFIG compile`
+       GUILE_LDFLAGS=`$GUILE_CONFIG link`
+       MC_CHECK_VERSION($GUILE_VERSION, $REQUIRED_VERSION, [guile_tests=`expr $guile_tests + 1`])
+       dnl # check headers seperately, since some distributions ship on-devel guile packages with 
guile-config
+       AC_CHECK_HEADER(guile/gh.h, guile_tests=`expr $guile_tests + 1`)
+       AC_CHECK_HEADER(libguile/properties.h, guile_tests=`expr $guile_tests + 1`) dnl # guile-1.6 headerfile
+     fi
+     if test $guile_tests = 4 ; then
+       BSESCM_CFLAGS="$GUILE_CFLAGS $BSESCM_CFLAGS"
+       BSESCM_LIBS="$GUILE_LDFLAGS $BSESCM_LIBS" 
+     else
+       EMSG="failed to detect guile headers and library v$REQUIRED_VERSION"
+       EMSG="$EMSG (available from http://www.gnu.org/software/guile/guile.html)"
+       EMSG="$EMSG - detected library version: $GUILE_VERSION"
+       AC_MSG_ERROR([$EMSG])
+     fi
+ 
+     AC_SUBST(BSESCM_CFLAGS)
+     AC_SUBST(BSESCM_LIBS)
+ ])
+ AC_DEFUN([AC_GXK_REQUIREMENTS],
+ [
+     dnl # required libraries, defines LIB*_CFLAGS and LIB*_LIBS:
+     PKG_CHECK_MODULES(LIBPANGO, pangoft2 >= 1.4.0)
+     PKG_CHECK_MODULES(LIBGTK, gtk+-2.0 >= 2.12.12)
+     PKG_CHECK_MODULES(LIBART, libart-2.0 >= 2.3.8)
+     PKG_CHECK_MODULES(LIBGNOMECANVAS, libgnomecanvas-2.0 >= 2.4.0)
+     GXK_CFLAGS="$LIBPANGO_CFLAGS $LIBGTK_CFLAGS $LIBART_CFLAGS $LIBGNOMECANVAS_CFLAGS"
+     GXK_LIBS="$LIBPANGO_LIBS $LIBGTK_LIBS $LIBART_LIBS $LIBGNOMECANVAS_LIBS"
+     AC_SUBST(GXK_CFLAGS)
+     AC_SUBST(GXK_LIBS)
+ ])
+ AC_DEFUN([AC_BEAST_REQUIREMENTS],
+ [
+     dnl # start where GXK left off
+     BEAST_CFLAGS="$GXK_CFLAGS"
+     BEAST_LIBS="$GXK_LIBS"
+     AC_SUBST(BEAST_CFLAGS)
+     AC_SUBST(BEAST_LIBS)
+ 
+     dnl # Feature XKB extension if present
+     cflags=$CFLAGS
+     ldflags=$LDFLAGS
+     CFLAGS=$BEAST_CFLAGS
+     LDFLAGS=$BEAST_LIBS
+     have_xkb=
+     AC_CHECK_LIB(X11, XkbOpenDisplay, have_xkb=1$have_xkb)
+     AC_CHECK_LIB(X11, XkbGetKeyboard, have_xkb=2$have_xkb)
+     AC_CHECK_HEADER(X11/XKBlib.h, have_xkb=3$have_xkb)
+     AC_CHECK_HEADER(X11/extensions/XKBgeom.h, have_xkb=4$have_xkb, , X11/Xlib.h)
+     MC_IF_VAR_EQ(have_xkb, 4321,
+       AC_DEFINE_UNQUOTED(BST_WITH_XKB, 1, [XKB present]),
+     )
+     CFLAGS=$cflags
+     LDFLAGS=$ldflags
+ 
+     # --- BEAST paths ---
+     beastbasedir=\${datadir}/beast
+     beastimagesdir=$beastbasedir/v$BIN_VERSION/images
+     AC_SUBST(beastimagesdir)
+     beastkeysdir=$beastbasedir/v$BIN_VERSION/keys
+     AC_SUBST(beastkeysdir)
+     beastskinsdir=$beastbasedir/v$BIN_VERSION/skins
+     AC_SUBST(beastskinsdir)
+ ])
+ AC_DEFUN([AC_SUIDMAIN_REQUIREMENTS],
+ [
+     dnl # figure everything required by the suid wrapper
+     AC_CHECK_FUNCS(seteuid)
+     AC_CHECK_FUNCS(setreuid)
+ ])
+ AC_DEFUN([AC_BSE_SNDDEV_CHECK],
+ [
+     dnl # OSS-Lite driver check
+     AC_CHECK_HEADERS(sys/soundcard.h soundcard.h, have_oss_header=yes, have_oss_header=no)
+     AC_ARG_ENABLE(osspcm,
+       [  --enable-osspcm=DEVICE  force DEVICE as OSS PCM device name],
+       [AC_MSG_WARN([Ignoring detection of PCM device])],
+       [enable_osspcm=""])
+     AC_ARG_ENABLE([ossmidi],
+       [  --enable-ossmidi=DEVICE force DEVICE as OSS MIDI device name],
+       [AC_MSG_WARN([Ignoring detection of MIDI device])],
+       [enable_ossmidi=""])
+ 
+     dnl # === OSS PCM device ===
+     AC_MSG_CHECKING([for available OSS audio devices])
+     result=
+     if test -n "$enable_osspcm" ; then
+       dev="$enable_osspcm"
+     else
+       for dev in /dev/dsp /dev/sound \
+           /dev/dsp0 /dev/dsp1 /dev/dsp2 /dev/dsp3 ; do
+         if test -c $dev ; then
+             break;
+         else
+             dev=""
+         fi
+         done
+     fi
+     if test -n "$dev" ; then
+       bse_found_pcmdev=yes
+       AC_DEFINE_UNQUOTED(BSE_PCM_DEVICE_CONF_OSS, "$dev", [Device used for PCM I/O])
+       result="PCM:$dev "
+     else
+       bse_found_pcmdev=no
+       AC_DEFINE_UNQUOTED(BSE_PCM_DEVICE_CONF_OSS, "/dev/dsp", [Device used for PCM I/O])
+       result="PCM:none (assuming PCM:/dev/dsp)"
+     fi
+     AC_MSG_RESULT($result)
+ 
+     dnl # === OSS MIDI device ===
+     AC_MSG_CHECKING([for available OSS midi devices])
+     if test -n "$enable_ossmidi" ; then
+         dev="$enable_ossmidi"
+     else
+       for dev in /dev/midi \
+           /dev/midi0  /dev/midi1  /dev/midi2  /dev/midi3 \
+           /dev/rmidi0 /dev/rmidi1 /dev/rmidi2 /dev/rmidi3 ; do
+         if test -c $dev ; then
+             break;
+         else
+             dev=""
+         fi
+         done
+     fi
+     if test -n "$dev" ; then
+       bse_found_mididev=yes
+         AC_DEFINE_UNQUOTED(BSE_MIDI_DEVICE_CONF_OSS, "$dev", [Device used for MID I/O])
+         result="MIDI:$dev "
+     else
+       bse_found_mididev=no
+         AC_DEFINE_UNQUOTED(BSE_MIDI_DEVICE_CONF_OSS, "/dev/midi", [Device used for MID I/O])
+         result="MIDI:none (assuming MIDI:/dev/midi)"
+     fi
+     AC_MSG_RESULT($result)
+ 
+     dnl # == Complain about mising devices ===
+     if test "$bse_found_pcmdev $bse_found_mididev" \!= "yes yes"; then
+       AC_MSG_WARN([failed to detect proper sound device files])
+     fi
+ ])
+ AC_DEFUN([AC_DOC_REQUIREMENTS],
+ [
+ ])
+ 
+ # find installation utilities
+ AC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database)
+ 
+ # --enable-devel-mode: check for development build rules, i.e. autogen.sh
+ # based builds with .git repository; these enable additional build rules
+ # for files that are pre-packaged in tarballs.
+ if test x"$enable_devel_mode" = xyes ; then
+   TEST_SRCDIR=$(cd $srcdir ; /bin/pwd)
+   TEST_BUILDDIR=$(cd . ; /bin/pwd)
+   test "$TEST_SRCDIR" == "$TEST_BUILDDIR" || {
+     AC_MSG_ERROR([development build rules require srcdir == builddir])
+   }
+   git cat-file commit af82337c966c1182e 2>&1 | fgrep -q bb4f6e48724a6731 || { # 0.8.0
+     AC_MSG_ERROR([development build rules require a beast.git repository])
+   }
+   DEVELMODE="" ; NOTDEVELMODE="#"
+   # devel mode build tools
+   MC_ASSERT_PROG(XMLLINT, xmllint, [See: http://xmlsoft.org/xmllint.html])
+   MC_ASSERT_PROG(PYTHON, python2.7)
+   if test -z "$PYTHON" || $PYTHON -c "import sys; sys.exit (sys.hexversion >= 0x2070500)" 2>/dev/null ; then
+      AC_MSG_ERROR([failed to detect python (version >= 2.7.5) required for development mode])
+   fi
+ else
+   DEVELMODE="#"; NOTDEVELMODE=""
+ fi
+ AC_SUBST(DEVELMODE)
+ AC_SUBST(NOTDEVELMODE)
+ 
+ AC_MSG_CHECKING(whether source dir equals build dir)
+ TEST_SRCDIR=`cd $srcdir ; /bin/pwd`
+ TEST_BUILDDIR=`cd . ; /bin/pwd`
+ if test "$TEST_SRCDIR" = "$TEST_BUILDDIR" ; then
+     AC_MSG_RESULT(yes)
+     SRCEQBUILDRULE=''
+ else
+     AC_MSG_RESULT(no)
+     AC_MSG_WARN([disabling some build rules because srcdir != builddir])
+     SRCEQBUILDRULE='#'
+ fi
+ AC_CHECK_PROGS(PERL, perl5 perl)
+ if test -z "$PERL" || $PERL -e 'exit ($] >= 5.002)' >/dev/null ; then
+     AC_MSG_WARN([failed to detect perl (version >= 5.002), disabling dependent build rules])
+     PERLRULE='#'
+ else
+     PERLRULE="$SRCEQBUILDRULE"
+ fi
+ AC_SUBST(PERLRULE)
+ AM_CONDITIONAL(WITH_PERLRULE, [test "$PERLRULE" != "#"])
+ 
+ # Check requirement sets
+ AC_I18N_REQUIREMENTS
+ AC_SFI_REQUIREMENTS
+ AC_BSE_REQUIREMENTS
+ AC_ASOUND_CHECK
+ AC_BSESCM_REQUIREMENTS
+ AC_BSE_SNDDEV_CHECK
+ AC_GXK_REQUIREMENTS
+ AC_BEAST_REQUIREMENTS
+ AC_SUIDMAIN_REQUIREMENTS
+ AC_DOC_REQUIREMENTS
+ 
+ # Automake @VARIABLE@ exports.
+ AC_SUBST(CFLAGS)
+ AC_SUBST(CXXFLAGS)
+ AC_SUBST(CPPFLAGS)
+ AC_SUBST(LDFLAGS)
+ 
+ 
+ # create output files
+ AC_CONFIG_FILES([
+ Makefile
+ data/Makefile
+ data/bse.pc
+ data/beast.applications
+ sfi/Makefile
+ sfi/tests/Makefile
+ bse/bseconfig.h
+ bse/Makefile
+ bse/icons/Makefile
+ bse/zintern/Makefile
+ bse/tests/Makefile
+ plugins/Makefile
+ plugins/icons/Makefile
+ plugins/freeverb/Makefile
+ drivers/Makefile
+ shell/Makefile
+ beast-gtk/Makefile
+ beast-gtk/gxk/Makefile
+ beast-gtk/dialogs/Makefile
+ beast-gtk/icons/Makefile
+ launchers/Makefile
+ library/Makefile
+ library/effects/Makefile
+ library/instruments/Makefile
+ library/samples/Makefile
+ library/scripts/Makefile
+ library/demo/Makefile
+ library/keys/Makefile
+ library/skins/Makefile
+ library/skins/images/Makefile
+ tools/Makefile
+ tools/scripts/Makefile
+ po/Makefile
+ tests/Makefile
+ tests/latency/Makefile
+ tests/scripts/Makefile
+ tests/bse/Makefile
+ tests/audio/Makefile
+ tests/filecheck/Makefile
+ docs/Makefile
+ docs/images/Makefile
+ docs/imports/Makefile
+ ])
+ 
+ AC_OUTPUT
diff --cc po/POTSCAN
index a921515,aadb347..8a75ee0
--- a/po/POTSCAN
+++ b/po/POTSCAN
@@@ -1,108 -1,106 +1,108 @@@
  #0 List of source files to scan for translatable strings
  #0 Please keep alphabetically sorted
- beast-gtk/bstapp.c
- beast-gtk/bstauxdialogs.c
- beast-gtk/bstbuseditor.c
- beast-gtk/bstbusmixer.c
- beast-gtk/bstbusview.c
- beast-gtk/bstcanvaslink.c
- beast-gtk/bstcanvassource.c
- beast-gtk/bstdbmeter.c
- beast-gtk/bsteventrollctrl.c
- beast-gtk/bstfiledialog.c
- beast-gtk/bstgrowbar.c
- beast-gtk/bstitemseqdialog.c
- beast-gtk/bstitemview.c
- beast-gtk/bstkeybindings.c
- beast-gtk/bstmain.c
- beast-gtk/bstmsgabsorb.c
- beast-gtk/bstparam-automation.c
- beast-gtk/bstparam-choice.c
- beast-gtk/bstparam-color-spinner.c
- beast-gtk/bstparam-item-seq.c
- beast-gtk/bstparam-note-sequence.c
- beast-gtk/bstparam-note-spinner.c
- beast-gtk/bstparam-proxy.c
- beast-gtk/bstparam-scale.c
- beast-gtk/bstparam-searchpath.c
- beast-gtk/bstparam-time.c
- beast-gtk/bstpartdialog.c
- beast-gtk/bstpartview.c
- beast-gtk/bstpatterncolumns.c
- beast-gtk/bstpatternctrl.c
- beast-gtk/bstpianorollctrl.c
- beast-gtk/bstplayback.c
- beast-gtk/bstpreferences.c
- beast-gtk/bstprocedure.c
- beast-gtk/bstprofiler.c
- beast-gtk/bstprojectctrl.c
- beast-gtk/bstrackeditor.c
- beast-gtk/bstrackitem.c
- beast-gtk/bstrackview.c
+ beast-gtk/bstapp.cc
+ beast-gtk/bstauxdialogs.cc
+ beast-gtk/bstbuseditor.cc
+ beast-gtk/bstbusmixer.cc
+ beast-gtk/bstbusview.cc
+ beast-gtk/bstcanvaslink.cc
+ beast-gtk/bstcanvassource.cc
+ beast-gtk/bstdbmeter.cc
+ beast-gtk/bsteventrollctrl.cc
+ beast-gtk/bstfiledialog.cc
+ beast-gtk/bstgrowbar.cc
+ beast-gtk/bstitemseqdialog.cc
+ beast-gtk/bstitemview.cc
+ beast-gtk/bstkeybindings.cc
+ beast-gtk/bstmain.cc
+ beast-gtk/bstmsgabsorb.cc
+ beast-gtk/bstparam-automation.cc
+ beast-gtk/bstparam-choice.cc
+ beast-gtk/bstparam-color-spinner.cc
+ beast-gtk/bstparam-item-seq.cc
+ beast-gtk/bstparam-note-sequence.cc
+ beast-gtk/bstparam-note-spinner.cc
+ beast-gtk/bstparam-proxy.cc
+ beast-gtk/bstparam-scale.cc
+ beast-gtk/bstparam-searchpath.cc
+ beast-gtk/bstparam-time.cc
+ beast-gtk/bstpartdialog.cc
+ beast-gtk/bstpartview.cc
+ beast-gtk/bstpatterncolumns.cc
+ beast-gtk/bstpatternctrl.cc
+ beast-gtk/bstpianorollctrl.cc
+ beast-gtk/bstplayback.cc
+ beast-gtk/bstpreferences.cc
+ beast-gtk/bstprocedure.cc
+ beast-gtk/bstprofiler.cc
+ beast-gtk/bstprojectctrl.cc
+ beast-gtk/bstrackeditor.cc
+ beast-gtk/bstrackitem.cc
+ beast-gtk/bstrackview.cc
  beast-gtk/bstrecords.idl
- beast-gtk/bstsampleeditor.c
- beast-gtk/bstscrollgraph.c
- beast-gtk/bstsnetrouter.c
- beast-gtk/bstsupershell.c
- beast-gtk/bsttrackrollctrl.c
- beast-gtk/bsttracksynthdialog.c
- beast-gtk/bsttrackview.c
- beast-gtk/bstusermessage.c
- beast-gtk/bstutils.c
- beast-gtk/bstwaveeditor.c
- beast-gtk/bstwaveview.c
+ beast-gtk/bstsampleeditor.cc
+ beast-gtk/bstscrollgraph.cc
+ beast-gtk/bstsnetrouter.cc
++beast-gtk/bstsoundfontview.c
+ beast-gtk/bstsupershell.cc
+ beast-gtk/bsttrackrollctrl.cc
+ beast-gtk/bsttracksynthdialog.cc
+ beast-gtk/bsttrackview.cc
+ beast-gtk/bstusermessage.cc
+ beast-gtk/bstutils.cc
+ beast-gtk/bstwaveeditor.cc
+ beast-gtk/bstwaveview.cc
  beast-gtk/dialogs/radgets-beast.xml
  beast-gtk/dialogs/radgets-standard.xml
- beast-gtk/gxk/gxklistwrapper.c
- beast-gtk/gxk/gxkparam-entry.c
- beast-gtk/gxk/gxkparam-label.c
- beast-gtk/gxk/gxkparam-scale.c
- beast-gtk/gxk/gxkparam-spinner.c
- beast-gtk/gxk/gxkparam-toggle.c
- beast-gtk/gxk/gxksimplelabel.c
- birnet/birnetmsg.cc
- birnet/birnetutils.cc
- bse/bseautodoc.c
- bse/bsebiquadfilter.c
- bse/bsebus.c
+ beast-gtk/gxk/gxklistwrapper.cc
+ beast-gtk/gxk/gxkparam-entry.cc
+ beast-gtk/gxk/gxkparam-label.cc
+ beast-gtk/gxk/gxkparam-scale.cc
+ beast-gtk/gxk/gxkparam-spinner.cc
+ beast-gtk/gxk/gxkparam-toggle.cc
+ beast-gtk/gxk/gxksimplelabel.cc
+ bse/bseautodoc.cc
+ bse/bsebasics.idl
+ bse/bsebiquadfilter.cc
+ bse/bsebus.cc
  bse/bsebusmodule.idl
  bse/bsebus.proc
- bse/bseconstant.c
+ bse/bseconstant.cc
  bse/bsecontainer.proc
- bse/bsecore.idl
- bse/bsedevice.c
- bse/bseenums.c
- bse/bseinstrumentinput.c
- bse/bseinstrumentoutput.c
- bse/bsejanitor.c
- bse/bseladspamodule.c
+ bse/bsedevice.cc
+ bse/bseenums.cc
+ bse/bseinstrumentinput.cc
+ bse/bseinstrumentoutput.cc
+ bse/bsejanitor.cc
+ bse/bseladspamodule.cc
  bse/bsemain.cc
- bse/bsemidicontroller.c
- bse/bsemididevice-null.c
- bse/bsemididevice-oss.c
- bse/bsemidiinput.c
- bse/bsemidisynth.c
- bse/bsemidivoice.c
- bse/bseobject.c
+ bse/bsemidicontroller.cc
+ bse/bsemididevice-null.cc
+ bse/bsemididevice-oss.cc
+ bse/bsemidiinput.cc
+ bse/bsemidisynth.cc
+ bse/bsemidivoice.cc
+ bse/bseobject.cc
  bse/bseparasite.proc
- bse/bsepcmdevice-null.c
- bse/bsepcmdevice-oss.c
- bse/bsepcminput.c
- bse/bsepcmoutput.c
- bse/bseserver.c
- bse/bsesnooper.c
- bse/bsesong.c
+ bse/bsepcmdevice-null.cc
+ bse/bsepcmdevice-oss.cc
+ bse/bsepcminput.cc
+ bse/bsepcmoutput.cc
+ bse/bseserver.cc
+ bse/bsesnooper.cc
+ bse/bsesong.cc
  bse/bsesong.proc
++bse/bsesoundfontosc.c
  bse/bsesource.proc
- bse/bsestandardosc.c
- bse/bsesubiport.c
- bse/bsesuboport.c
- bse/bsesubsynth.c
- bse/bsesuper.c
- bse/bsetrack.c
+ bse/bsestandardosc.cc
+ bse/bsesubiport.cc
+ bse/bsesuboport.cc
+ bse/bsesubsynth.cc
+ bse/bsesuper.cc
+ bse/bsetrack.cc
  bse/bsetrack.proc
- bse/bsewave.c
- bse/bsewaveosc.c
+ bse/bsewave.cc
+ bse/bsewaveosc.cc
  data/beast.desktop.in
  data/beast.xml.in
  data/bse.keys.in



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]