* when releasing do:
  * make check
  * cd po;intltool-update -M
  * make dist
  * wget http://www.gnu.org/licenses/lgpl-2.1.txt; mv lgpl-2.1.txt COPYING; 


* test infrastructure
  * add a stub song-io saver
  * add a stub processor machine
  * have a means to make a copy of log-files for passing tests
    * this could help to check 'what changed'
    * we'd need to also do xml output from check to run the log compare for
      failed tests
  * use https://github.com/martinpitt/umockdev for btic tests


* review tests
  * ensure we follow Arrange/Act/assert or Given/When/Then style
    http://en.wikipedia.org/wiki/Behavior_Driven_Development
  * check that all public api is used in tests
    nm --defined-only .libs/libbuzztrax-core.a | grep " T " | cut -d' ' -f3 | grep -v "marshal" | sort >/tmp/m1.txt;
    nm --undefined-only .libs/libbtcore-check.a | grep " U bt" | cut -c20- | sort | uniq >/tmp/m2.txt;
    comm -2 -3 /tmp/m{1,2}.txt
    
    grep ");" src/lib/core/core.h | cut -d'(' -f1 | cut -d' ' -f2 | cut -d'*' -f2
    find src/lib/core -name "*.h" -exec grep ");" {} \; | cut -d'(' -f1 | cut -d' ' -f2 | cut -d'*' -f2

  * check that we use loop-tests
    find tests/lib/ -name "*.c" -exec egrep -Hn "(for|while)\s*\(" {} \; | egrep -v "(:\s*\*|://)"


* quality checks
  for file in src/lib/core/*.c; do gtkdoc-depscan -v --book gstreamer-1.0:1.2.0 $file; done


* sparse
  make CC=cgcc


* build with clang
  export CC=/usr/bin/clang; export CXX=/usr/bin/clang++; ./autoregen.sh


* generate a dependency matrix
  * 'make ctags' creates tags files per directory containing symbol locations
  * 'ctags -x --recurse src tests >xref' creates a single xref table containing
    all symbol locations
  * 'find . -name "*.o" -exec nm --undefined-only {} \; | grep " bt_"'
    creates a list of externally called entries


= feature =

* controller api
- we might want to allow to attach a controller to a parameter and control
  the controllers parameters in the pattern instead, e.g.:
  - user attaches LFO to Filter-CutOff, in the pattern he can now edit:
    center-value, depth, shape, freq (controlable values of the control-source)
  - user attaches an Arpeggiator to a Note property
- we setup extra controller-functions to scale and shift the value (or
  introduce a special binding for that)
- we need a controlbinding-router so that on pattern basis we can select which
  controlsource is used (pattern, lfo, arpeggiator)
- song format
  - we store it per pattern before the data
- ui
  - we need some extra buttons in the parameter header to select between
    {manual,automation}


* OSC support
  * settings
    - the OSC port for listening
    - add song to path (/<song>/...)
  * namespace
    - ../<machine>/set_{wire,global,voice}_param 
    - ../<machine>/set_{mute,solo,bypass}
    - ../<machine>/<pattern>/set_{wire,global,voice}_event
    - ../{play,stop,pause}
  * ui (if osc enabled)
    - show the osc path both in machine and pattern view
    - eventually make it editable (ensure unique)
    - store with song

  * we can also expose osc as a 'device' in the btic
    - it will support the learn-iface
    - learning will echo all received controls
    - one can then name it and store
    - it would be nice to somehow bundle learned controls as a 'device'
      - then we can have presets per app
      - we could have a "new osc device" menu item in the control menu
        and put the learn item under the new device

  * nice client for android: control
    http://charlie-roberts.com/Control/?page_id=19
    * we can push custom surfaces via osc
      http://charlie-roberts.com/Control/?page_id=32
    * can be discovered via avahi:
      > avahi-browse -a
      +  wlan0 IPv4 Control_75846                                 _osc._udp            local
      +  wlan0 IPv4 Control_66257                                 _osc._udp            local


* undo/redo/journaling
  - links
    http://www.buzztrax.org/index.php/Undo,_redo
    http://www.buzztrax.org/index.php/Song_autosaving
  - we do that on the ui level (also the journalling and the replay of it)
  - singleton journal object
    - each undo/redo capabale object registeres with its name there
    - on replay we can take the prefix og the entry and dispatch
    - on journalling we can probably add the prefix
    - it is a stack of journal entries
  - classes that implement unod/redo implement the change_logger_interface()
    and usually have a BtChangeLog reference in their instance struct
  - pending parts that need undo/redo
    - machine view
      - machine/wire parameters
    - wavetable view
    - info view
  - order of serialisation and destruction
    - see main-page-machines.c:bt_main_page_machines_delete_machine()
    - use g_signal_connect_after() for the '-removed' handler that are
      destructive (search for '-removed",G_CALLBACK') can help
    - g_object_add_weak_ref is not useful as the object is already gone
    - example: bt_setup_remove_machine
      - what we want:
        machine data {
          track data
          pattern data 0
          ...
          pattern data n
        }
      - what happens:
        emit "removed" signal
          pre:
            main-page-machines:on_machine_removed: beg log undo/redo + machine-data
            main-page-sequence:on_machine_removed: track data + remove track
          default: bt_setup_on_machine_removed ?
            foreach pattern do: bt_machine_remove_pattern
              emit "removed" signal
                pre:
                  main-page-patterns:on_pattern_removed: beg log undo/redo + pattern data
                  main-page-sequence:on_pattern_removed: no track -> skip
                default: bt_machine_on_pattern_removed ?
                  -
                after:
                  end log undo/redo
              remove & unref
          after:
            end log undo/redo
        remove & unref
    - generic phases:
      1) owner:before_xxx_removed: beg log undo/redo + xxx data
      2) others:on_xxx_removed: log other object
      3) children: emit 'removed'
      4) owner: after_xxx_removed: end log undo/redo
      5) remove & unref
    - one problem is that objects that gets removed have children and are part of
      other objects:
      - machine has patterns and
      - sequence has tracks that reference machines
    - it is probably easier to have explicit api in the participating UI object
      - we should split functions like:
        void bt_main_page_machines_delete_machine (const BtMainPageMachines * self, BtMachine * machine)
        void bt_main_page_machines_delete_wire (const BtMainPageMachines * self, BtWire * wire)
        to serialize and to actually delete afterwards, this way we can trigger
        the deletion of the top-level after serialisation is done 
      - examples:
        bt_main_page_machines_delete_machine(self, machine) {
          bt_main_page_machines_serialize_machine(self, machine) {
            // 1) serialize own data (properties)
            // 2) serialize data from object that have a ref to this machine by
            g_signal_emit(BtMainPageMachines::machine-delete-event, machine);
              // bt_main_page_sequence_on_machine_delete_event() -> bt_main_page_sequence_delete_track()
            // 3) serialize all children
            foreach(pattern) { bt_main_page_patterns_serialize(self,pattern); } 
          }
          bt_setup_remove_machine(setup, machine);
        }
        bt_main_page_machines_delete_wire(self, wire) {
          bt_main_page_machines_serialize_wire(self, wire) {
            // 1) serialize own data (properties)
            // 2) serialize data from object that have a ref to this wire by
            g_signal_emit(BtMainPageMachines::wire-delete-event, wire);
            // 3) serialize all children
            foreach(pattern) { bt_main_page_patterns_serialize_value_group(self,pattern,wire_value_group); }              
          }
          bt_setup_remove_wire(setup, wire);
        }
        bt_main_page_patterns_delete_pattern() {
          bt_main_page_patterns_serialize_pattern(self, pattern) {
            // 1) serialize own data (properties, value-groups)
            foreach(value-group) bt_main_page_patterns_serialize_value_group(self, pattern, value-group)
            // 2) serialize data from object that have a ref to this pattern by
            g_signal_emit(BtMainPagePatterns::pattern-delete-event, pattern);
              // bt_main_page_sequence_on_pattern_delete_event() -> serialize tracks data for this pattern
            // 3) serialize all children
            // - no children -
          }
          bt_machine_remove_pattern(machine, pattern);
        }
        bt_main_page_sequence_delete_track(self, sequence, track_id) {
          // no refs, no children
        }
        bt_main_page_waves_delete_wave() {
          bt_main_page_waves_serialize_wave(self, wave) {
            // 1) serialize own data (properties)
            // 2) serialize data from object that have a ref to this wave by
            // TODO: we probably don't want this, as we won't clear wave-refs in
            //       pattern when e.g. loading a new wave into an existing slot
            g_signal_emit(BtMainPagePatterns::wave-delete-event, wave);            
            // 3) serialize all children
            // - no children -
          }
          bt_wavetable_remove_wave(wavetable, wave);
        }


* Hide libxml2 use behind a PersistenceIO interface in a XMLPersistenceIO
  implementation. The API would also allow to change the implementation to use
  e.g. json or a binary representation instead. We need an API like:
  PersistenceIONode: opaque handle
  // for saving
  PersistenceIONode *bt_persistence_io_new_node(PersistenceIONode *parent, gchar *name);
  gboolean bt_persistence_io_set_value(PersistenceIONode *parent, gchar *value);
  gboolean bt_persistence_io_set_attribute(PersistenceIONode *parent, gchar *name, gchar *value);
  // a varargs function that takes (gchar *name, GType type, <type> value)
  // triplets, terminated by NULL 
  gboolean bt_persistence_io_set_attributes(PersistenceIONode *parent, 
    gchar *name, ...);
  // collection api ...
  gboolean bt_persistence_io_set_attributes_from_hash_table(PersistenceIONode *parent, GHashTable *hash_table);
  
  // for loading
  GList *bt_persistence_io_get_nodes(PersistenceIONode *parent);
  gchar *bt_persistence_io_get_value(PersistenceIONode *parent);
  gchar *bt_persistence_io_get_attribute(PersistenceIONode *parent, gchar *name);
  // a varargs function that takes (gchar *name, GType type, <type *> value)
  // triplets, terminated by NULL 
  gboolean bt_persistence_io_get_attributes(PersistenceIONode *parent, 
    gchar *name, ...);


* CPU load per machine
  - as we always plug the tee-elements on each machine and each wire starts with
    a queue we could do CPU load per thread
    - sources start their own thread
    - effects and the sink live in the thread of one of the incoming wires
    - build a thread_id<->machine mapping
      - a hackish way would be to run a pad_probe before the machine and
        send a message to the bus with the thread-id<->machine association
      - a better way would be to use gst_message_parse_stream_status
        see src/lib/core/song.c::on_song_stream_status()
  - ideally we show it on the machine view
    - extra dialog from tools menu?
    - enable/disable from the view menu
  - buzztrax-cmd could have a profile option (for play/encode) and print a summary
    at the end


* eventually merge machine-rename dialog with machine properties
  - we now have inplace rename in the sequence headers as a quick alternative


* control machines (no in/out)
  - color=gray
    it is never connected and thus, does not need a desaturated shade
  - scheduling
    - from a property notifies on sink-bin
      - need ts
    - run a GstTask and sync to the clock
      - need to implement tempo iface
      - need to hande seeks (to know direction :/)
  - we can use that for midi-out
    - global params: midi-device (enum)
    - voice params: midi-channel, note, velocity, controller1, control-value1, ... 
  - subclass the control-machines from GstElement
    - no pads (and therefore no _loop() or _chain() function
    - we see them in the registry


* change presets via controller
  * for midi we can expose program change message
    * although our presents don't have stable ordering
    * a rel-range control? (prev/next)
  * we need a way in the ui to attach such a controller to the preset pane


* play machines via midi (interaction controller)
  - we have machines with one or more note-params
    - sometimes only one is a trigger though
    cd bml/tests/testmachine
    grep -H PT_NOTE *.txt.* | sort | uniq -c | sort -g
  - we have machines with one or more value trigger parames (drum machines)
  - we need to have the idle_loop playing when having keyboard assignments
  - gui workflow:
    - v1: start from the key-controllers
      - a toolbar on the bottom
        - show/hide in the view menu
        - left a combobox to select the device (keyboard, midi, ...)
        - next the piano key graphics
        - next two comboboxes for key assignment and velocity assignment
          - velocity assignment is empty, when selecting machine+key,
            it will show possible velocity targets
          - for drum-machines, we select the parameter with the key and put the
            velecity into the respective parameter
      - mark a key-range, assign to machine/note-param (with key offset)
      - select a key-range, unassign
      - move key-ranges
    - v2: start from pattern column headings
      - have bind/unbind like in machine window
      - define split'ed devices elsewhere
    - v3: add controller to context menu on machine-canvas 
  - how to easily assign a series of key to a series of triggers in one machine
    - have a trigger group  (and assign to white keys only)
    - this would manage both key-number and velocity as we'd only bind a series
      of abs-value-controls (velocity) to the drum-machine triggers
  - how to assign velocity to the machines velocity param
    - it works for monophonic machines
  - poly key-press events
    - the current code in machine.c (_poly_control_) would increment the
      voice_ct on each control event
      - we would need to set both key and velocity though
      - we also need to ensure to set velocity first and then the key
      - each controller has a separate voice_ct
      - when assinging a controller to a voice-param, should we always poly-bind
        it?

  - it would be nice to have a pc-keys interaction controller for playing notes
    - we can register this from the ui (it would be part of "ui/edit"
      - the machine view would start-stop it on focus (if bound)
      - eventually we could use it in pattern-view too and implicitely bind it
        if "play-notes" is active


* text parameters in machines
  * for a:
    * text to speech machine we'd like to have strings in the pattern
    * cmd-out machine we'd like to send a dbus command, run a script etc.
  * like we have a wavetable, we could have a text table
    * a list of text snipped (more than 256!)
    * each snippet has a label and a text block (multiline)
  * in a text to speech machine we can use text-table index (gint 16 bit),
    text offset (gint 16 bit char offset), length (unset, to the end) and
    direction (forward, backward)
  * in a command out machine, we use the text table index (gint 16 bit) and
    ev. script parameters (passed as $1, $2, ...)


* wave table
  * we can just keep the buffers from fakesink/appsink in a list and consolidate
    on eos
  * record audio
    * need device selection on the source
  * record from song
    * need some special setup on sink-bin/encodebin
    * load raw wave on song::playing==FALSE


* one framerate for animations
  * we have a couple of things that we update in intervals:
    * 10fps: main-page-waves.c: preview_update_id=g_timeout_add_full(G_PRIORITY_HIGH,1000/10,on_preview_playback_update,(gpointer)self,NULL);
    * 10fps: main-toolbar.c: playback_update_id=g_timeout_add_full(G_PRIORITY_HIGH,1000/10,on_song_playback_update,(gpointer)song,NULL);
    * 10fps: machine.c: g_object_set(PART_*LEVEL,"interval",(GstClockTime)(0.1*GST_SECOND),...
    * 10fps: signal-analysis-dialog: g_object_set(ANALYZER_*, "interval",(GstClockTime)(0.1*GST_SECOND),...
  * we should have one #define somewhere for the UPDATE_INTERVAL
  * ideally we ensure that the framerate is an integer multiple of it
  * it would be nice to avoid a setting, but for slow machines it might be worth it
    (or for fast machine, people could pick a higher rate)
  * we could use configure and have the define in config.h


* pattern and main-page-patterns still contain bits of duplicated code
  * review the pattern api and check if we should use the groups directly
    (run ./api-cleanup.sh to get a report of where the api is used)


* create & add is a bad idea
  * machines and wires are automatically added to the setup
  * patterns are automatically added to the machine
  * this causes trouble for pattern_copy (which we work-around now)


* change tempo while playing
  * we would like to ensure that playback continues at the same position, just
    at different speed
  * when changing the tempo, we'd need to take a snapshot of the playback pos as
    time and ticks


* embedded lua (see design/lua) or js (see design/{gjs,seed})
  * tools menu
  * pattern editor
    * register scripts that provide commands to manipulate the patterns
    * the app does undo/redo, but comparing the before after state
    * script will needs to provide a name
    * if we have a keybinding editor, we can associate the function with the key
      there
    * we could also have an eval entry in the editor, that would fill a selection
      with result of cell(tick) = map(f(tick)). tick could either be the absolute
      tick or 0.0 ... 1,0 and map will project the function return from 0.0 ... 1.0
      to the value vange of the selected property
  * interaction controller ?
  * do we need to store some of them with the song?


* machine UIs
  * instead of adding more metadata to the paramspecs we could also use 
    GtkBuilder xml file. This way machines can ship a customized layout.
  * if not present in the filesystem we generate them on
    the fly, maybe also expose this as a standalone tool
  * the xml file only covers the parameter boxes


* single window UI
  * like we have main-window.c, add a extra-window.c, where the extra window
    only has a main-pages widget
  * on each tab we have a context menu to move it to the 'next'/'prev' window
  * each page is only part of one window
  * the settings store how many extra windows we have and for each page in which
    one it is docked
  * when we close an extra window, we move the pages to the previous window
  * the edit-application stores the list of the windows that are open
  * see design/gui/multiscreen.c, when saving the monitor positions
    gdk_screen_get_monitor_at_point()


* physical remotes
  * physical remotes to control synths
  * each synth could generate the required arduino sketch + instructions for the
    hw
  * arduino/esp2866
    * https://www.adafruit.com/products/1085: 4ch @ 16bit: 15$
    * https://www.adafruit.com/products/1083: 4ch @ 12bit: 10$
    * https://www.adafruit.com/products/856:  8ch @ 10bit:  3.75$
    * Arduino Uno: 6ch @ 10bit (mine)
    * Arduino Micro: 12ch @ 10bit
    * Teensy 3.1: 21ch @ 10bit (12ch on the headers)
  * controls
    * trigger button
      https://www.arduino.cc/en/tutorial/button
    * toggle button
      https://www.arduino.cc/en/Tutorial/Switch
    * poti
      https://www.arduino.cc/en/Tutorial/AnalogInput
    * many buttons on 1 ADC pin
      http://www.instructables.com/id/How-to-access-5-buttons-through-1-Arduino-input/?ALLSTEPS
      useful also for rotary switches like e.g.
      https://www.sparkfun.com/products/10064?_ga=1.108337922.1878275335.1438803671
      http://www.conrad.de/ce/de/Search.html?search=Encoder+5+V%2FDC+0.01+A+Schaltpositionen+16&searchType=mainSearchBar
      e.g. for mode-selectors
  * send osc events
    http://trippylighting.com/2014/10/12/touchosc-arduino-tutorial/


* internet exchange for ic-profiles
  * store ic-profiles also on files.buzztrax.org/ic-profiles
  * when plugging a ic-device, check if we find a profile online
  * from the profile-settings, add a button to submit a profile
    * ideally upload through a the mailing-list/wordpress/...
    * if we upload to files.buzztrax.org, upload to a staging area, where the uploads
      are limited by ip/size/... and files are checked immediately after upload
      for the file-type
    * if we upload to wordpress, we'd need to do OAuth2 to avoid storing the
      password in the settings
  * maybe do something similar for presets