****** WARNING ******* A lot of this stuff will be out dated, while Smurf undergoes major changes. Most of the low level sound font functions will be moved to an external libsoundfont library, and many changes relating to sound font item access, etc. Josh Green April 13, 2001 ****** WARNING ******* So you want to try to add something.. Fix something.. Figure out something with the Smurf source code ehh?? Perhaps this document will help you. I welcome any questions or suggestions relating to the Smurf Sound Font Editor, so don't hesitate to send me an email. Other helpful documentation: ---------------- GTK Tutorial GTK Reference Manual GLib Reference Manual These documents can be found at http://www.gtk.org GLib is heavily used in the Smurf Sound Font Editor and GTK itself uses it. GLib defines many simple data types like linked lists, hashes, dynamic arrays and strings etc.; and has routines for effecient memory management, portability functions and many other nice things. In short.. It kicks ass. Generally speaking any data type starting with a 'G' that isn't 'Gtk' is probably from GLib. Don't confuse glib (nice utility library) to glibc (essential libraries, the heart of Linux programs). Source file descriptions ---------------- Lets start off by listing all the source files and what they contain. All permanent source or header files contain a description (at the beginning of the file) of what should be found inside it. src/ ---------------- glade_callbacks.c Currently empty, just to make Glade happy glade_interface.c Auto generated by glade, not to be changed directly midi.c External MIDI input sample.c Audio file and sample related routines sequencer.c Sequencer output routines sfdofunc.c Undo/Redo item specific functions sfdump.c Sound font dump to text file routines (for debugging) sfload.c Sound font file loading sfont.c Sound font data manipulation sfsave.c Sound font file saving sfundo.c Undo/Redo system smurf.c main() which starts everything smurfcfg.c Configuration file routines splash.c Intro splash image routines splash_png.c Auto generated by tools/cdump of pixmaps/splash.png uif_help.c Tips, about, and help (when it becomes available) uif_menutbar.c Menu and tool bar uif_piano.c Virtual piano keyboard uif_pianospan.c Note/Velocity ranges below piano uif_pref.c Preferences uif_sample.c Sample related user interface routines uif_samview.c Sample viewer user interface uif_selections.c Operations on multiple sound font items uif_sfgen.c Sound font generator user interface (effects) uif_sfont.c User interface related sound font routines uif_sftree.c Sound font tree uif_sfundo.c Undo/Redo user interface uif_treemenu.c Right click tree menus uif_wavegen.c Sample waveform generator uiface.c main user interface routines (ties it all together) util.c error handling and other utility functions wavetable.c wavetable (patch loading) routines src/drivers ---------------- midi_alsaraw.c ALSA external raw MIDI thru driver midi_alsaseq.c ALSA sequencer based MIDI thru driver midi_oss.c OSS MIDI thru seq_alsa.c ALSA sequencer routines seq_oss.c OSS sequencer routines wtbl_awe.c OSS AWE wavetable routines wtbl_awefx.c OSS AWE effects routines wtbl_awepatch.c OSS AWE patch loading routines wtbl_aweunits.c SF->AWE unit conversion routines wtbl_gus.c OSS GUS driver (yeah right, should just kill it) wtbl_guspatch.c Patch loading (stupid single sample loading) src/widgets ---------------- keyspan.c Note/velocity range widget piano.c Piano widget popdog.c Pop up dialog convenience widget (is it really?) ptrstrip.c Pointers on a strip widget samview.c Sample viewer widget NOTE: If there is a file I didn't list there that you think should be, its probably new and I just forgot to add it to here. Definitions and terms ---------------- Here is a list of terms I will use throughout this document and a description of what each means. I'm only going to list terms that are unique to Smurf or my own terminology.. etc. I'm not going to describe sound fonts, this info can be found in other documents. I've written an un-official "Intro to sound fonts" which is on the Smurf web site (http://smurf.sourceforge.net). You can find more in-depth application level information in the SoundFont specification which can be found in PostScript or perhaps PDF format if you can find it. Try www.soundfont.com or ftp.creaf.com for the official SoundFont specification. sound font item A preset, instrument, sample, preset zone or instrument zone sound font tree The Smurf GUI sound font tree Lower level sound font representation - sfont.[ch], uif_sfont.[ch] ---------------- You may want to try to understand how sound fonts are represented internally in the Smurf Sound Font Editor. I'll attempt to describe that here. uisf_sfonts (Linked list) | |-[+] (UISFont *) untitled SF 1 | |-[-] (UISFont *) untitled SF 2 | | | |-- (SFTreeNodes *) nodes (pointers to nodes in the GUI tree) | | | *-[-] (SFData *) sf | | | |-- preset (linked list of SFPresets) | |-- inst (linked list of SFInsts) | *-- sample (linked list of SFSamples) | *-[+] (UISFont *) untitled SF 3 SFPreset (SFInst is the same except for extra preset related info) |-- Name, prenum, bank, etc. *-- zone (linked list of SFZones) SFZone (structure) |-- instsamp (pointer to an instrument or sample) |-- gen (linked list of generators, effects) *-- mod (linked list of moderators, MIDI controls modulating effects) Most of the low level sound font manipulation occurs in sfont.c with uif_sfont.c being the user interface (GUI) routines. uisf_sfonts is a linked list of the currently open sound fonts. Each pointer in this list points to a UISFont structure which essentially combines the non-GUI SFData structure with SFTreeNodes. SFTreeNodes is a structure with pointers to nodes in the GTK sound font CTree widget of the top level branches for that sound font. Fields: sfont (sfont root node), preset (preset root node), melodic (preset melodic branch) etc. Unique sound font item identifiers (not pointers!) - uif_sftree.[ch] ---------------- When dealing with user selections of sound font items and undo/redo functionality, it becomes necessary to have a unique identifier for each item. This identifier should not be dependant on a memory location (a pointer for instance). Why not pointers you ask? Example scenario when using pointers (skip if you're in a hurry :) <scenario> The user pops a preset rename dialog and gets distracted with something else. The dialog gets hidden by some other app and the user forgets all about it. Later when she comes back to editing the sound font, she decides to destroy that particular preset. All is well right? Well yes, until she finds that rename dialog again. Not really thinking about it she just says okay. Smurf seg faults :( Passing around non-static pointer references in a GUI environment is not a good idea. The rename dialog used a pointer to a preset that no longer exists. </scenario> Rather than making all dialogs "modal" (all other user interface functions are frozen until dialog closes) a unique integer is used to identify each item and a lookup is done to get the pointer to the data. NULL is returned if a non-existing ID is looked up, allowing Smurf to handle the situation, instead of crash (most often the item is just skipped silently). A GLib "keyed data list" is used to map a unique integer ID to a pointer to the item data. Each item is assigned a unique ID when it is added to the sound font tree. This key is removed when the item is destroyed. The data type used for the unique integer ID is called a GQuark. Sound font tree - uif_sftree.[ch] ---------------- The pointer obtained from a GQuark lookup in the sound font item keyed data list, is a pointer to a GtkCTreeNode in the sound font tree. A pointer can be stored in each GtkCTreeNode in a CTree. /* each node in the tree points to one of these */ typedef struct _SFTreeRef { SFNodeType type; /* the type of node */ GQuark quarkid; /* sound font item keyed data list ID */ gpointer dptr; /* pointer to data associated with this type */ } SFTreeRef; This structure contains a type enum which describes the item's type (NODE_SFONT, NODE_PRESET, etc), the node's quarkid (the same ID we started with, so we can get the GQuark id given a GtkCTreeNode *), pointer to data associated with this node. 'dptr' in SFTreeRef points to different types of data, depending on the 'type'. Here is what it will point to for different types of nodes: type | dptr data type ---------------------------------------- NODE_SFONT | UISFont *dptr (UISFont struct associated with the sound font) NODE_PRESET | GList *dptr->data = SFPreset * NODE_INST | GList *dptr->data = SFInst * NODE_SAMPLE | GList *dptr->data = SFSample * NODE_PZONE | GList *dptr->data = SFZone * NODE_IZONE | GList *dptr->data = SFZone * others | NULL Notice that for most item types dptr points to a GList item. These are the same GLists that are referenced by the SFData structure (described above). This system essentially binds the GUI related variables (GtkCTreeNode *) and the lower level SFData, SFPreset, SFInst, etc structures. Here is an example routine that expects a GQuark sfitem identifier and closes the sound font that owns the sfitem. We'll use some of the macros defined in uif_sftree.h to help us. void example_close_function (GQuark sfquark) { UISFont *uisf; GtkCTreeNode *node; SFTreeRef *ref; /* look up the quark in the sftree_items keyed data list */ node = SFTREE_LOOKUP_QUARK (sfquark); /* node would equal NULL if item doesn't exist anymore */ if (!node) return; /* we now have the (GtkCTreeNode *) which references a node in the GUI sound font CTree */ /* find this node's root sound font node (type = NODE_SFONT) and fetch the UISFont structure from it */ uisf = SFTREE_UPFIND_UISF (node); /* close the sound font, sfont_close expects (SFData *) */ sfont_close (uisf->sf); } Smurf undo system ---------------- Smurf has a rather flexible undo system. The undo system is based on a tree rather than queue or list. This means that, from the user point of view, multiple changes can be easily tested. Performing an action, undoing it, then performing another action would cause the state information for the first action to be destroyed when using a traditional undo LIST. But with a TREE, another branch is started instead. sfundo.c contains the undo system functions. sfdofunc.c contains the functions for saving/restoring the state of specific actions. The word "do" is used to signify things having to do with both undo/redo stuff. The tree is based on the GNode glib data type, which defines a data type and functions for manipulating N-ary trees (a tree with arbitrary # of branches). SFDoTree sfdo_tree (structure) |-- GNode *root (dummy root node of tree, root->data = NULL) |-- GNode *curpos (current position in undo history) *-- GList *groups (list of currently active groups and sub groups) GNode *example_item (an example of an item in the sfdo_tree) |-- GNode *next, *prev (point to next and previous siblings, i.e. branches) |-- GNode *parent (parent of this node, NULL for root node) |-- GNode *children (first child or NULL if last node of this branch) *-- SFDoEntry *data (actually a gpointer which is equiv to a void *) |-- gchar *descr (description of this action) *-- GList *items (multiple do items "grouped" by this SFDoEntry) |-<list> |-[-] SFDoItem * | |-- guint16 type | *-- gpointer state *-[+] SFDoItem * A "do" tree consists of a tree of SFDoEntries which are linked lists of SFDoItems. The SFDoEntries are groups of SFDoItems essentially and many operations act on them as a group. Each SFDoItem has an enumerated type (generator, sample, sampledata, preset, etc) and a pointer to the associated "state" data which can be used to restore the state of that type of object. Only a new entry (curpos) can be used for grouping. Groups can be nested. The same SFDoEntry is used for nested groups. A list of SFDoItems is kept in the tree, each is a pointer to the last node of the previous group. This list is temporary and exists only while the entry is opened as a group. Therefore sub groups are only available while they are open. Sub groups are useful for operations that call apon other functions that act on many items and group them. Should one of these functions fail, it would undo its own group of changes, and return FAIL. The calling routine could then undo all the other group data. Bye bye now ------------------ Okay, so that was some info about the Smurf Sound Font Editor source code. I'm sure there are a lot of other things that would be helpful to put in here, but I don't want to do it right now. If there is something that you can't figure out, let me know. Perhaps I'll add it to this document. Happy hacking.. Josh Green <jgreen@users.sourceforge.net>