= Technical Specification =

Weed Events 1.0 final version.

CHANGELOG
28/04/2006
Changed "owner" to "owners" for FILTER_INIT event (allow multiple
track owners for a filter)
Added optional "audio_state" leaf to FRAME event.

02/06/2006
Amended "audio_state" to "audio_seek".

22/06/2006
Remove "owners"

04/09/2006
Update audio details for FRAME events. Add "ignore" leaf for
PARAM_CHANGE events.

22/11/2006
Add optional leaves to event_list

11/12/2006
Change plantptr to voidptr (plantptr only to be used for sub-plants).
Added "weed_event_api_version" leaf to EVENT_LIST plant.
Added definitions section.

12/09/2008
Added "audio_volume_tracks" and "audio_volume_values". API unchanged
since optional.

18/03/2015
Removed "first" and "last" since these do not need to be saved to disk. Added "track_label_tracks" and "track_label_values".

29/02/2016
Added WEED_AUDIO_LITTLE_ENDIAN and WEED_AUDIO_BIG_ENDIAN symbols.


(C) Gabriel "Salsaman" Finch 2005 - 2016

== WEED_EVENT_API_VERSION ==
This is defined as 120 for this version of the specification. This
number will be increased for future revisions of the spec. if a
function or a symbol is changed or added.


== PLANT TYPES ==
This document describes the different 'plant types' in the weed events system, and their mandatory
and optional 'leaves'.


== PLANT TYPE EVENT_LIST ==

Event lists contain events which are linked as a singly or doubly
linked list. Events may be held in an event list.
Some kinds of plugins (timeline plugins) can take an event_list input
and produce an event_list output.

Event lists can also be serialised and passed between applications.

Unlike some systems where event lists (or Edit Decision Lists) are
forced to be held per-track/channel, Weed allows both this mode, and/or use of a global
event list for all tracks/channels.


 * "type" == WEED_PLANT_EVENT_LIST

'''Mandatory leaves''':[[BR]]
 
 * "weed_event_api_version" : WEED_SEED_INT : API version of this
   spec. (currently 120) [as of version 120]

 * "fps" : WEED_SEED_DOUBLE : framerate of timeline; all events in the
   timeline MUST be quantised to this rate. An "fps" of 0 indicates
   variable framerate.


'''Optional leaves''': [[BR]]


 * "width" : WEED_SEED_INT : frame width in pixels (must be >0)

 * "height" : WEED_SEED_INT : frame height in pixels (must be >0)

 * "audio_channels" : WEED_SEED_INT : number of audio channels. 0
   to force no audio. Must be >=0

 * "audio_rate" : WEED_SEED_INT : audio rate in Hz, must be >0 if "audio_channels" > 0

 * "audio_sample_size" : WEED_SEED_INT : audio sample size in bits per
   sample (e.g. 8 or 16), must be >0 if "audio_channels" > 0

 * "audio_signed" : WEED_SEED_BOOLEAN : WEED_TRUE means signed,
   WEED_FALSE, unsigned

 * "audio_endian" : WEED_SEED_INT : May be WEED_AUDIO_LITTLE_ENDIAN (0) or WEED_AUDIO_BIG_ENDIAN (1)
   endian, other values are invalid

 * "audio_volume_tracks" : WEED_SEED_INT : an array that maps "audio_volume_values" to tracks. Track
   numbers < 0 are floating (backing) audio tracks. If there are fewer
   values in "audio_volume_values" than in "audio_volume_tracks", then
   the tracks without corresponding values are assumed to be "ganged"
   to the last track with a corresponding value (i.e they are locked
   to the same value).

* "audio_volume_values" : WEED_SEED_DOUBLE : array of coarse control
  (0.0 - 1.0) volume values for tracks. Mapping to tracks is done
  through "audio_volume_tracks"
 
* "track_label_tracks" : WEED_SEED_INT : an array that maps "track_label_values" to tracks.  Track
   numbers < 0 are floating (backing) audio tracks. If a track does not have a label, it may be given a default label (e.g "Video 1")

* "track_label_values" : WEED_SEED_STRING : an array of (short) track labels. Mapping of the values to tracks is done via "track_label_tracks".




== PLANT TYPE EVENT ==

 * "type" == WEED_PLANT_EVENT

'''Mandatory leaves''':[[BR]]

 * "hint"	  : WEED_SEED_INT : hint denoting the event type [see
   below, Event Hints]

 * "timecode"	  : WEED_SEED_INT64 : the timecode of the event

It is recommended that timecodes be in ascending order, and that events (at least frames) are quantised to the event_list framerate. However, there may exist occasions when this is not possible, so it should not be assumed...


== Order of events at one timecode ==

It is strongly suggested that the order and number of events at each timecode
should be:

 * 0 or more filter init events
 * 0 or more parameter change events
 * 0 or 1 filter map events
 * 0 or more parameter change events
 * 1 FRAME event [either a blank frame or a real frame]
 * 0 or more filter deinit events
 * 0 or 1 filter map events

 * Marker events can exist anywhere in the event_list.

== EVENT HINTS ==

The "hint" is a mandatory WEED_SEED_INT leaf of every event; the defined values are:

 * WEED_EVENT_HINT_UNDEFINED
 * WEED_EVENT_HINT_FRAME
 * WEED_EVENT_HINT_FILTER_INIT
 * WEED_EVENT_HINT_FILTER_DEINIT
 * WEED_EVENT_HINT_FILTER_MAP
 * WEED_EVENT_HINT_PARAM_CHANGE
 * WEED_EVENT_HINT_MARKER

Depending on the "hint" parameter seed type additional leaves are:

=== WEED_EVENT_HINT_UNDEFINED ===
This is not actually a true event type, but for example a function can return this as the hint value for a NULL event.
As of API version 110.


=== WEED_EVENT_HINT_FRAME ===
A FRAME event can contain video and/or audio.

The video part of a FRAME represents a stack of clip/frame pairs. Number of elements for "clips" and "frames" MUST be equal.

Mandatory leaves for all frames:

 * "clips" : WEED_SEED_INT : array of clips (clip number >=1)  [clip <=0 means no frame/blank frame at that position]
 * "frames" : WEED_SEED_INT : array of frames (frame number >=1) [frame <=0 means a blank frame at that position]

 "clips"==-1, "frames"==0 is strongly suggested for a blank frame.


Mandatory leaves for frames with audio:

The audio part of a FRAME can be represented by an array of 4 numbers:
track_number, clip_number, seek_time, velocity. Number of elements for "audio_clips" and "audio_frames" MUST be
equal.

 * "audio_clips" : WEED_SEED_INT : array of audio clips as pairs:
		 track_number, clip_number. Track number can be used to link the
		 audio track visually and functionally with a video track (e.g. 0 =
		 linked to first video track, <0 = "floating" audio track). In addition if new values appear on the same 
		 track as a previous audio event, the previous audio should be stopped (as if velocity 0.0 were sent). 
		 Clip number is the clip number where the audio is taken from. Clip
		 number <=0 means ignore the value. This is useful
		 if leaves cannot be deleted. To create an ignore event, e.g. use values
		 "-1,-1,0.,0." for "audio_clips" and "audio_seek".

 * "audio_seeks" : WEED_SEED_DOUBLE : an array of double pairs, giving audio
		   seek times in seconds (the player should quantise
		   this to the nearest sample), followed by velocity
		   (velocity 1. == normal play, 0.5 == half speed, -1.
		   == play backwards, etc). Number of elements MUST match number of
		   elements in "audio_clips", and the elements
		   correspond in order pair-by-pair. Seek values must be >=0. 

		   If clip number is <=0 in "audio_clips" - ignore, the corresponding "audio_seeks" pair
		   is ignored. 

		   A velocity of "0." with clip number >0 will switch
		   audio off for that track, e.g. "-1,1,0.,0."
		   switches off audio on track -1.

		   The seek value may be < 0., this is to allow a
		   small adjustment to synch audio with the video
		   frame.


   There is no volume or pan setting: audio samples can be mixed using a filter (see the WEED AUDIO
   extension); this may require audio rendering.

   Audio continues playing at the specified velocity until the audio
      is marked off (clip_number <= 0), or the end of the audio file is
   reached, i.e. values are sparse: only "on", "off", "seek" and "velocity" changes need to
   be recorded.

Audio and video frames should be combined where possible. I.e. there
should only be one frame event at a particular timecode.

Note that audio events take place at the start of the video frame. Thus to ensure that all audio is turned off at the end of timeline it 
may be necessary to add an additional blank frame.



=== WEED_EVENT_HINT_FILTER_INIT ===
    This event is used to init a filter instance.

 * "filter" : WEED_SEED_STRING :the HASHNAME of a Weed filter [See the main Weed
     spec. for a definition of the Hashname]


     The following two leaves are used to construct a FILTER_INSTANCE
     from a FILTER_INIT event [see the Weed Spec.]

 * "in_count" : WEED_SEED_INT : array describing the number (count)
     of instances of each in channel template; 0 means disabled, 1 means enabled,
     >1 can be used where repeated channels are allowed : optional if
     "filter" has no in channels, otherwise number of
     elements and order must match filter "in_channel_templates"

 * "out_count" : WEED_SEED_INT : array describing the number
     (count) of instances of each out channel template; 0 means disabled, 1 means enabled,
     >1 can be used where repeated channels are allowed : optional if
     "filter" has no out channel templates, otherwise number of
     elements and order must match filter "out_channel_templates"



 * "in_tracks" : WEED_SEED_INT : array of tracks [matches subsequent
     FRAME events to effect in_channels], starts at 0 for video : optional if
     "filter" has no in channels : [an in_track of -1 represents a
     separated audio track - see the WEED audio extension]

 * "out_tracks" : WEED_SEED_INT : array of tracks [matches subsequent
     FRAME events to effect out_channels], starts at 0 for video : optional if
     "filter" has no out channels : [an out track of -1 represents a
     separated audio track - see the WEED audio extension]

 * "event_id" : WEED_SEED_INT64 : used to refer to this filter_init by filter_map, filter_deinit and param_change events.


=== WEED_EVENT_HINT_FILTER_DEINIT ===
    This event deinits a filter instance.

 * "init_event" : WEED_SEED_INT64 : refers to the "event_id" of FILTER_INIT which must occur earlier in the event_list. 
 Each FILTER_INIT event must have exactly one corresponding FILTER_DEINIT.


=== WEED_EVENT_HINT_FILTER_MAP ===
   This event type defines the order in which filters are applied to any
   subsequent FRAME events.

 * "init_events" : WEED_SEED_INT64 : an array which refers to "event_id"s of FILTER_INITs with "timecode" <= this
   event's timecode. The associated FILTER_DEINITs must have "timecode" >= this event's timecode.


=== WEED_EVENT_HINT_PARAM_CHANGE ===
    Parameters are assumed to be smoothly interpolated from one value
    to the next. In order to implement an instantaneous change, the
    filter should either do its own interpolation, or the old value
    should be duplicated at the (quantised) timecode immediately before the instantaneous change. 

 * "init_event" : WEED_SEED_INT64 : refers to the "event_id" of a FILTER_INIT with "timecode" <= this
   event's timecode. The associated FILTER_DEINIT must have "timecode" >= this event's timecode

 * "index" : WEED_SEED_INT : 0 based index of in_parameter numbers

 * "value" : WEED_SEED_* : "value" of the in_parameter at "timecode". The type must be the same as the type of the in_parameter "value".
 The number of elements must be valid for the in_parameter "value".


Optional leaves


 * "ignore" : array of WEED_SEED_BOOLEAN : for interpolation of in parameters with
	      multiple elements in "value", "ignore" can be used to block "value"
	      elements which are to be ignored at that timecode (i.e
	      they are just "filler" values in the array). Thus, if
	      present, the number of elements in "ignore" should be = the number of elements in
	      "value" at the timecode (for COLOR parameters,
	      the number of elements in "value" is divided by 3
	      or 4 depending on "colorspace" - see the Weed Filter specification). A setting of WEED_TRUE indicates the
	      corresponding element in "value" should *not* be considered an
	      interpolation point (i.e. it is just a "filler"
	      element). A missing element in "ignore" is considered to be
	      WEED_FALSE. Extra elements in "ignore" are ignored.


=== WEED_EVENT_HINT_MARKER ===

This is a host specfic marker event. Leaves can vary from host to
host. Markers which are not recognised should be removed from the event_list.







Addendum:
== Serialising of event_lists ==

Event_lists may be serialised for transfer between applications. The
process is:

 * serialise the event_list plant
 * serialise the event plants in the order in which they appear in the event_list

The serialisation format of each plant shall be as follows:

(uint32_t) number_of_properties

then for each property:

(uint32_t) name_len | (char *) property_name | (uint32_t) seed_type |
(uint32_t) num_elems |
where name_len == strlen(property_name)
property_name is ASCII, not NUL-terminated
then for each element:

(uint32_t) byte_size | (void *) value
[strings are utf-8, not NUL terminated]

| is shown for clarity only and is not written to the output.
Byte order is little-endian.

Note: the "type" leaf should be serialised first, in order to assist
reconstruction of the deserialised plant.


Format shall be little endian for all types (except string).




== definitions ==
The weed-events.h header currently contains the following definitions:

#define WEED_EVENT_API_VERSION_100
#define WEED_EVENT_API_VERSION_110
#define WEED_EVENT_API_VERSION_120

#define WEED_EVENT_API_VERSION 120


Summary:

== EVENT_HINTS ==

 * WEED_EVENT_HINT_FRAME
 * WEED_EVENT_HINT_FILTER_INIT
 * WEED_EVENT_HINT_FILTER_DEINIT
 * WEED_EVENT_HINT_FILTER_MAP
 * WEED_EVENT_HINT_PARAM_CHANGE
 * WEED_EVENT_HINT_MARKER



== ENDIAN ==
* WEED_AUDIO_LITTLE_ENDIAN
* WEED_AUDIO_BIG_ENDIAN
