/* CMP_network.h version 1.35 by Pieter Suurmond, june 17, 2004. Defines the syntax of ComParser network files and the C API functions to do things with networks in memory. Latest version available at: http://kmt.hku.nl/~pieter/SOFT/ Copyright (c) 2001-2004 Schreck Ensemble - Pieter Suurmond Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. (* SYNTAX OF COMPARSER NETWORK FILES ================================= Using Extended Backus Naur Form (EBNF) according to ISO/IEC 14977 : 1996(E) (see http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html or the official document) where square brackets [] denote zero or one time; curly brackets {} denote zero or more times; commas denote concatenation; and vertical bars denote options. Additional restrictions that cannot be expressed in EBNF (contextual grammar and semantics) are mentioned in the form of comments. A ComParser network file prescribes one single network. Empty lines and lines starting with a # character are ignored. A network starts with a single fps line and is followed by one or more node lines. When more than one node line is pre- sent, node lines must be separated by one or more avalanche lines. *) network = {new line | cmp comment}, fps line, node line, { avalanche line, {avalanche line}, node line }; (* The fps line, which is mandatory, specifies the number of feature vectors per second to be used during audio analysis. This way, audiofiles with different samplerates can be combined in one network: ComParser chooses the appropriate FFT-size (1024, 2048 or 4096 input points). *) fps line = ('F'|'f'), ('P'|'p'), ('S'|'s'), '=', fps, new line, {new line | cmp comment}; fps = decimal digit, 2 * [decimal digit], ['.', [7 * decimal digit]]; (* 5 =< fps =< 200. *) (* A node line starts with the node name followed by a colon, optionally followed by a number of responses. A node name must contain at least contain 1 character, andmay contain no colons. *) node line = node name, ':', {response}, [hspace], new line, {new line | cmp comment}; node name = nodechar, {nodechar}; nodechar = letter | decimal digit | hspace | '@' | '.' | '-' | '_' | '/' | '\'; (* A node's response consists of a number of midimessages and or pauses. For simplicity, we don't completely define midimessages, we just assume they consist of one ore more bytes. Notice, however, that pauses may not be put inside a midimessage! *) (* Allow empty (). *) response = [hspace], pause | midimessage; pause = '(', 3 * [decimal digit], ')'; midimessage = midibyte, {hspace, midibyte}; midibyte = decimal digit, 2 * [decimal digit]; (* An avalanche line starts with one or more horizontal white space characters, followed by a pathname, which may then be followed by a starttime and endtime. Notice that files longer than one hour cannot be used when times are specified. *) avalanche line = hspace, pathname, [hspace, starttime, hspace, endtime], [hspace], {new line | cmp comment}; pathname = pathchar, 62 * [pathchar]; pathchar = letter | decimal digit | '@' | '.' | '-' | '_' | '/' | '\' | ':'; starttime = minutes, ":", seconds, ".", milliseconds; endtime = minutes, ":", seconds, ".", milliseconds; minutes = 2 * decimal digit; (* May not be greater than 59. *) seconds = 2 * decimal digit; (* May not be greater than 59. *) milliseconds = 3 * decimal digit; (* May not be greater than 999. *) (* Global definitions. *) hspace = (' ' | ?ISO 6429 character Horizontal Tabulation?), {' ' | ?ISO 6429 character Horizontal Tabulation?}; cmp comment = '#', {character}, new line; (* As in ISO/IEC 14977 EBNF. *) decimal digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"; letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" | "C" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"; new line = {? ISO 6429 character Carriage Return ?}, ? ISO 6429 character Line Feed ?, {? ISO 6429 character Carriage Return ?}; (* End of definitions. *) */ /*--------------------------------------------------------------------------------------*/ typedef struct NODE_STRUCT* NODE; struct NODE_STRUCT { /* Read-only members written once by load_NETWORK() (function add_NODE() actually): */ NODE next; /* Succesive node or NULL. */ char* name; /* Dynamically allocated C-string. */ AVALANCHE avalanches; /* Linked list of parallel avalanches. */ short* action; /* Some MIDI bytes. Not terminted by \0, first short */ /* contains the number of shorts that follow (<32768). */ /* Runtime member cleared by reset_runtime_NETWORK, written by follow_NETWORK(): */ short rt_activity; /* Highest output activity of all parallel avalanches. */ }; /*--------------------------------------------------------------------------------------*/ /* A NETWORK object (in memory) holds all NODES and AVALANCHES, related filenames, para- meters, etc. A NETWORK object is created by function load_NETWORK(). Besides read-only data, a NETWORK also holds runtime data, so the NETWORK itself "knows where we are" during (realtime) following. Function reset_runtime_NETWORK() initialises the runtime parts of the structure. */ typedef struct NETWORK_STRUCT* NETWORK; /* Embeds all nodes and avalanches. */ struct NETWORK_STRUCT { /* Read-only members, written once by function NETWORK_load(): */ char* filename; /* Pathname of textfile used to construct this */ /* object, absolute or relative to the executable. */ NODE nodes; /* Root of linked list of nodes or NULL. */ double fps; /* Feature vectors per second, as read from the */ /* network file. Function load_NETWORK() should */ /* ensure that all avalanches have same fps! */ double bfq; /* Base-frequency (of the FFT analysis). */ /* Runtime members initialised by NETWORK_reset(), used by NETWORK_follow(): */ NODE rt_follow_node; /* When pointing to same address as 'nodes' above, */ /* we are at the beginning. When NULL, we're done. */ long rt_repeat; /* Decremented by follow_NETWORK(). */ int rt_debug_avalanches; /* 0, 1 ('d' option) or 2 ('dd' option). */ }; /*-----------------------------------------------------------------------------------*/ /* Loads a complete NETWORK from file (and subfiles) and builds-up a memory structure. Returns zero in case of success, the address of the created object is then written to *handle. Returns nonzero in case of failure, then NULL is written to *handle. Besides storing the network data in memory, load_NETWORK() also allocates (but not fully initialises!) the runtime datastructures. The address that argument linesRead points to receives the number of lines read. The pathname supplied as 3rd argument is copied into the newly created NETWORK object, so the caller is not obliged to hold that string there after returning from load_NETWORK(). Whenever a network file refers to .AVL or .AIFF files with relative paths, these paths are relative to the network file! instead of relative to the application or PD-external. When last argument is not NULL, messages may be written to it (by AVALANCHE_read() which is called by NETWORK_load()). */ int NETWORK_load(NETWORK* handle, const char* name_version, const char* pathname, long* linesRead, FILE* msg); /*----------------------------------------------------------------------------*/ /* Initialises the runtime memory structures of a network, created earlier with load_NETWORK(). Must be called once before calling follow_NETWORK() for the first time. Argument debug may be 0, 1 or 2. */ int NETWORK_reset(NETWORK ptr, long repeat, int debug); /*----------------------------------------------------------------------------*/ /* Removes a network object, created earlier by load_NETWORK(), from memory. */ int NETWORK_destruct(NETWORK* handle); /*----------------------------------------------------------------------------*/ /* Processes exactly 1 incoming feature vector. Returns zero on success, non-zero on failure. After return, *node contains NULL, or a ptr to a NODE structure at state transtions. You may also call this function to force a state transition (hop to another node) by setting *node to something else prior to calling. */ int NETWORK_follow(NETWORK network, const short* vector, NODE* node, /* Caller receives current node here. */ FILE* msg); /* May be NULL. */ /*----------------------------------------------------------------------------*/ /* Prints to open filestream msg the whole network. If argument gen_jpg is not NULL, audiofingerprints in JPEG format will be generated of all the AVALANCHES in the network. JPEG files may even be generated whith msg=NULL. */ void NETWORK_info(NETWORK network, const char* name_version, const char* gen_jpg, FILE* msg);