This is the Beast manual, Beast is a music synthesis and composition program.
The manual is structured into sections covering tutorial material, Howto descriptions, Man pages, file formats and conventions, background discussions concerning development considerations and an API reference.
It is written in Markdown and contributions are welcome, e.g. as pull requests or via the Beast issue tracker.
Start Beast, it will open up with an empty project by default.
Select Project
→ New Song
, in order to add notes, tracks and instruments for some music composition.
Select the Add Track
icon button, so the song has at least one track which corresponds to a playable instrument.
Select the tracks Synth
field and select an instrument to be played back for this track.
Create a new part within the track by clicking into the tracks timeline. A part contains the notes that the instrument will play when playback is actiavted for this song.
This space is for Howto articels about how to do things.
From the command line, list the known PCM / MIDI devices: beast --bse-driver-list
Start Beast with a selected MIDI device, e.g.: beast -m alsa=hw:0,0
Select and play Demo
→ MIDI Test
to test notes from devices like MIDI keyboards.
NAME
beast - Music composition and modular synthesis application
SYNOPSIS
beast [OPTIONS] [FILES...]
DESCRIPTION
Beast is the BEtter Audio SysTem. It is a music composition and modular synthesis application released as free software under the GNU LGPL.
Beast comes with various synthesis modules which can be arranged in networks for modular synthesis. It is capable of monophonic and polyphonic voice processing, provides MIDI sequencer functionality and supports external sequencer sources. A huge set of extra modules is available through the support for LADSPA (Linux Audio Developer's Simple Plugin API) plugins.
OPTIONS
Beast follows the usual GNU command line syntax, with long options starting with two dashes ('-').
General options
--bse-pcm-driver DRIVER-CONF
--bse-midi-driver DRIVER-CONF
Development Options
Gtk+ Options
SEE ALSO
bse(5), sfidl(1), Beast/Bse Website
NAME
bsewavetool - A tool for editing the native multisample format of Beast and Bse
SYNOPSIS
bsewavetool [tool-options] command <file.bsewave> [command-arguments]
DESCRIPTION
Bsewavetool is a command line tool for editing the native multisample format for Beast and Bse, the Bsewave format. Some common operations are creating new Bsewave files, adding chunks to an existing file, encoding the sample data, adding meta information or exporting chunks.
Common uses for Bsewave files are:
OPTIONS
A number of options can be used with bsewavetool in combination with the commands:
COMMANDS
Store
store
Store the input Bsewave as output Bsewave. If both file names are the same, the Bsewave file is simply rewritten. Allthough no explicit modifications are performed on the Bsewave, externally referenced sample files will be inlined, chunks may be reordered, and other changes related to the Bsewave storage process may occour.
Create
create <n_channels> [options]
Create an empty Bsewave file, <n_channels>=1 (mono) and <n_channels>=2 (stereo) are currently supported.
Options:
Oggenc
oggenc [options]
Compress all chunks with the Vorbis audio codec and store the wave data as Ogg/Vorbis streams inside the Bsewave file.
Options:
Add Chunk
add-chunk [options] {-m=midi-note|-f=osc-freq} <sample-file> ...
Add a new chunk containing <sample-file> to the wave file. For each chunk, a unique oscillator frequency must be given to determine what note the chunk is to be played back for. Multi oscillator frequency + sample-file option combinations may be given on the command line to add multiple wave chunks. The -f and -m options can be omitted for a sample file, if the oscillator frequency can be determined through auto extract options.
Options:
Add Raw Chunk
add-raw-chunk [options] {-m=midi-note|-f=osc-freq} <sample-file> ...
Add a new chunk just like with 'add-chunk', but load raw sample data. Additional raw sample format options are supported.
Options:
Del Chunk
del-chunk {-m=midi-note|-f=osc-freq|--chunk-key=key|--all-chunks}
Removes one or more chunks from the Bsewave file.
Options:
XInfo
xinfo {-m=midi-note|-f=osc-freq|--chunk-key=key|--all-chunks|--wave} key=[value] ...
Add, change or remove an XInfo string of a Bsewave file. Omission of [value] deletes the XInfo associated with the key. Key and value pairs may be specified multiple times, optionally preceeded by location options to control what portion of a Bsewave file (the wave, individual wave chunks or all wave chunks) should be affected.
Options:
Info
info {-m=midi-note|-f=osc-freq|--chunk-key=key|--all-chunks|--wave} [options]
Print information about the chunks of a Bsewave file.
Options:
Valid wave or chunk fields:
Valid wave fields:
Valid chunk fields:
Chunk fields that can be computed for the signal:
The script output consists of one line per chunk. The individual fields of a line are separated by a single space. Special characters are escaped, such as spaces, tabs, newlines and backslashes. So each line of script parsable output can be parsed using the read(P) shell command. Optional fields will printed as a single (escaped) space.
The human readable output formats (--pretty) may vary in future versions and are not recommended as script input.
Clip
clip {-m=midi-note|-f=osc-freq|--chunk-key=key|--all-chunks} [options]
Clip head and or tail of a wave chunk and produce fade-in ramps at the beginning. Wave chunks which are clipped to an essential 0-length will automatically be deleted.
Options:
Normalize
normalize {-m=midi-note|-f=osc-freq|--chunk-key=key|--all-chunks} [options]
Normalize wave chunk. This is used to extend (or compress) the signal range to optimally fit the available unclipped dynamic range.
Options:
Loop
loop {-m=midi-note|-f=osc-freq|--all-chunks} [options]
Find suitable loop points.
Options:
Highpass
highpass [options]
Apply highpass filter to wave data.
Options:
Lowpass
lowpass [options]
Apply lowpass filter to wave data.
Options:
Upsample2
upsample2 [options]
Resample wave data to twice the sampling frequency.
Options:
Downsample2
downsample2 [options]
Resample wave data to half the sampling frequency.
Options:
Export
export {-m=midi-note|-f=osc-freq|--chunk-key=key|--all-chunks|-x=filename} [options]
Export chunks from Bsewave as WAV file.
Options:
The export filename can contain the following extra information:
List Chunks
list-chunks [options]
Prints a list of chunk keys of the chunks contained in the Bsewave file. A chunk key for a given chunk identifies the chunk uniquely and stays valid if other chunks are inserted and deleted.
This bash script shows the length of all chunks (like info --all-chunks):
for key in `bsewavetool list-chunks foo.bsewave` ; do
bsewavetool info foo.bsewave --chunk-key $key --script length ;
done
SEE ALSO
beast(1), Beast/Bse Website, Samples and Wave Files in Beast
NAME
BSE - Better Sound Engine File Format
SYNOPSIS
filename.bse
DESCRIPTION
The Bse file format is used by the Bse library and dependent programs to save projects, songs, instruments and sample collections.
FORMAT
Bse files start out with a special magic string "; BseProject\n"
and then contain nested expressions in scheme syntax using the ASCII charset. Binary data may be appended to a *.bse
file if it is separated from the preceeding ASCII text by one or more literal NUL characters ('\0'
). This mechanism is used to store arbitrary binary data like WAV or Ogg/Vorbis files in Bse projects, while keeping the actual content user editable - text editors that preserve binary sections have to be used, such as vi(1) or emacs(1).
COMPATIBILITY
The exact format and sets of objects and properties used in a Bse file depend highly on the library version that was used to save the file. Compatibility functions are supplied by the library itself, so old Bse files can be converted when the file is loaded. To enable this mechanism, all Bse files contain a "bse-version"
directive which indicates the Bse file format version of the supplied content.
SEE ALSO
beast(1), bsewavetool(1), BSE Reference
NAME
sfidl - SFI IDL Compiler (Beast internal)
SYNOPSIS
sfidl [OPTIONS] input.idl
DESCRIPTION
Sfidl generates glue code for Bse objects and plugins from interface definition language files.
OPTIONS
Language bindings:
Language binding options:
SEE ALSO
A *.bse
file is an Ascii file with occasional binary appendix and contains various data proccessed by the BSE library. The readable (Ascii) part of a .bse
file is held in lisp syntax and mostly build up out of (keyword value) pairs.
[NOTE: currently (1999-12-21) the identification tag support is disabled, and subject for general overhaul. A new implementation is likely to come soon and will probably (roughly) follow this specification.]
Each file has a special identification tag in the first line:
(BSE-Data V1 0000000004); -*- scheme -*-
^^^^^^^^ ^^ ^^^^^^^^^^
| | |
| | ten-digit octal flag
| |
| version tag
|
BSE data-identifier
and is matched against a regexp pattern (in grep -E syntax):
^\(BSE-Data\ V1\ [0-7]{10}\);.*$
Note that the ';'
at the end of the right parenthesis is actually part of the expression and needs to directly follow the right parenthesis, whereas the space inbetween the ';'
and the line end '\n'
can contain any number of, or even no characters at all. The ten-digit octal value is a short hand flag to identify the various kinds of data held in the current file. Its value corresponds to the enum definiton BseIoDataFlags in <bse/bseenums.h>.
Main statement keywords - prefixed by a left parenthesis, to start a certain statement - are:
Substatement keywords depend on the object (main statement) they apply to, and should be mostly self explanatory ;)
One object invariant substatement keyword is "BseBinStorageV0
", it's syntax is as follows:
<UOFFSET>
<ENDIANESS>
<N_BITS>
<ULENGTH>
Binary appendices are stored after the ascii part of a .bse file. A NUL ('\0'
) byte character unambiguously marks the end of the ascii portion. Directly following this NUL byte the binary appendix starts out, containing binary data as specified through the various BseBinStorageV0 statements within the ascii portion. Files without binary appendix may not contain the terminating NUL byte.
Space for notes about the synthesis engine, undo/redo stacks and other technical bits.
On a high level, Beast constitutes the front-end to the libbse sound engine.
The BSE sound engine spawns a separate (main) thread separate from the UI for all sound related management and a number of digital signal processing (DSP) sub threads to facilitate parallelized synthesis.
Invocations of the libbse API are automatically relayed to the BSE thread via an IPC mechanism.
The main BSE thread is where the API facing BSE objects live. For actual sound synthesis, these objects spawn synthesis engine modules that process audio buffers from within the DSP threads. The number of parallel DSP threads usually corresponds to the number of cores available to libbse.
Additionally, libbse spawns a separate sequencer thread that generates note-on
, note-off
and related commands from the notes, parts and tracks contained in a project. The synchronization required by the sequencer thread with the main thread and the DSP threads is fairly complicated, which is why this is planned to be merged into the DSP threads at some point.
Aida is used to communicate with a regular API between threads and to cross programming language barriers. At the heart of Aida is the IDL file which defines Enums, Records, Sequences and interfaces. Interface methods can be called from one thread and executed on class instances living in other threads. Additionally, callback execution can be scheduled across thread boundaries by attaching them to Event emissions of an instance living in another thread.
Within Beast, Aida is used to bridge between the UI logic (the "Beast-GUI" or "EBeast-module" threads) and the sound synthesis control logic (the "BseMain" thread).
For an IDL interface Foo
, Aida generates a "client-side" C++ class FooHandle
and a "server-side" C++ class FooIface
. The Iface
classes contain pure virtual method definitions that need to be implemented by the server-side logic. The Handle
classes contain corresponding method wrappers that call the Iface
methods across thread boundaries. The Handle
methods are implemented non-virtual to reduce the risk of ABI breakage for use cases where only the client-side API is exposed.
At the outermost scope, an IDL file contains a namespace definition. Interfaces, enums, records and sequences all need to be defined with namespaces in IDL files.
The primitive types supported in IDL files are enums, bool, integer, float and string types. The supported compound types are sequences - a typed variable length array, records - a set of named and typed variables with meta data, Any - a variant type, and inheritable interfaces.
Enum values are defined with integer values and allow VALUE = Enum (N, strings...)
syntax to add meta data to enum values.
An interface can contain methods and property definitions and inherit from other interfaces. Properties defined on an interface are largely sugar for generating two idiomatic getter and setter access methods, but the set of properties and associated meta data of an interface can be accessed programmatically through the __access__()
method. The Bse::Object
implementation makes use of this facility to implement the dynamic property API set_prop()
, get_prop()
, find_prop()
, list_props()
. The syntax for property definitions with meta data is TYPE property_name = Auxillary (strings...);
, the Auxillary()
constructor can take various forms, but ultimately just constructs a list of UTF-8 key=value
strings that can be retrieved at runtime.
An Any is a variant type that can contain any of the other primitive types. It is most useful to represent dynamically typed values in C++ which are common in languages like Python or Javascript. If an Any is set to store an IDL Enum value, it also records the Enum type name, to allow later re-identification. In general, Any should only be needed for languages that do not have dynamic variable types (like C++), and should not normally need to be exposed in dynamic languages (like Python, Javascript). E.g. converting an enum property value stored in an Any to a native type in a dynamic language, a pair could be returned, like (1, "Bse::FooEnum")
.
The Vue components used in EBEAST are usually composed of a single file that provides:
The Vue component object is defined as part of (d). We often use <canvas>
elements for EBEAST specific displays, and Vue canvas handling comes with certain caveats:
Use of the Util.vue_mixins.dom_updates
mixin (now default) allows to trigger the dom_update()
component method for $forceUpdate()
invocations and related events.
A methods: { dom_update() {}, }
component entry should be provided that triggers the actual canvas rendering logic.
Using a document.fonts.ready
promise, EBEAST re-renders all Vue components via $forceUpdate()
once all webfonts have been loaded, <canvas>
elements containing text usually need to re-render themselves in this case.
A b-modaldialog that displays version information about Beast.
Events:
A Vue container for tight packing of buttons.
Slots:
A button element that responds to clicks.
Props:
Events:
Slots:
Vue template to display a color picker popup.
Props:
data:
A modal popup that displays contextmenu choices, see B-MENUITEM, B-MENUSEPARATOR. Using the popup()
method, the menu can be popped up from the parent component, and setting up an onclick
handler can be used to handle menuitem actions. Example:
<div @contextmenu.prevent="$refs.cmenu.popup">
<b-contextmenu ref="cmenu" @click="menuactivation">...</b-contextmenu>
</div>
Props:
Events:
role
of the submenu is provided as argument.
Methods:
event
coordinates are used for positioning, the origin
is a
Editor for editing of modules.
Props:
Panel for editing of devices.
Props:
A collection of Vue documentation pointers and notes on idiomatic use.
Attr:
Attributes set on a component are by default transferred to its root element, see: inheritAttrs: false. The component can access the attributes through this.$attrs
, this can e.g. be used for initial prop values.
Props:
Parents can set values on child component via the props
array, the child itself must not change its props
, see: Passing Data to Child Components with Props
Property:
Child components can contain computed properties that are get/set-able from the parent via the computed
arraay, see: Computed Properties and Watchers
Slots:
Child components can embed parent DOM contents via the v-slot
mechanism, see: Content Distribution with Slots
A field-editor for integer or floating point number ranges. The input value
will be constrained to take on an amount between min
and max
inclusively.
Properties:
value
can take on.
value
can take on.
true
, numbers are constrained to integer values.
Events:
A field-editor for object input. A copy of the input value is edited, update notifications are provided via an input
event.
Properties:
input
event notifications.
Events:
A field-editor for picklist input.
Properties:
Events:
A field-editor switch to change between on and off.
Properties:
Events:
A field-editor for text input.
Properties:
Events:
A flex container for horizontal layouting (or vertical in the case of B-VFLEX
).
Props:
A vertical variant of the B-HFLEX container for vertical layouting.
A grid container for grid layouting (visual cheatsheet.
Props:
Vue template to display a horizontal scrollbar.
Props:
This element displays icons from various icon fonts. Note, to style the color of icon font symbols, simply apply the color
CSS property to this element (styling fill
as for SVG elements is not needed).
Props:
fa
, mi
, uc
.
A menuitem element to be used as a descendant of a B-CONTEXTMENU. The menuitem can be activated via keyboard focus or mouse click and will notify its B-CONTEXTMENU about the click and its role
, unless the @click.prevent
modifier is used. If no role
is specified, the B-CONTEXTMENU will still be notified to be closed, unless $event.preventDefault()
is called.
Props:
onclick
.
Events:
preventDefault()
to avoid closing the menu on clicks.
Slots:
Menuitems are packed horizontally inside a menurow.
Props:
Slots:
A menu element that serves as a visual separator between other elements.
An element to be used as menu title.
Slots:
A dialog component that disables and dims everything else for exclusive dialog use. Using b-modaldialog with v-if enables a modal dialog that dims all other elements while it is visible and constrains the focus chain. A close event is emitted on clicks outside of the dialog area, if Escape is pressed or the default Close button is actiavted.
Props:
v-model
bindings.
Events:
false
is emitted when the "Close" button activated.
Slots:
CSS Classes:
A Vue template to display a list of Bse.Part instances.
Props:
A Vue template to display a thumbnail for a Bse.Part.
Props:
A Vue template to display a Bse.part as a piano roll.
Props:
Data:
part
property.
A container holding the play and seek controls for a Bse.song.
Props:
b-projectshell.project
.
b-positionview - Display of the song positoin pointer and related information
Props:
A b-modaldialog to edit Beast preferences.
Events:
Shell for editing and display of a Bse.Project.
Props:
A container for vertical display of Bse.Track instances.
Props:
A Vue template to display a song's Bse.Track.
Props:
An element representing an entry of a B-TREESELECTOR, which allows selections.
A b-modaldialog that displays a tree and allows selections.
Events:
Members declared within the Bse
namespace.
// namespace Bse
void
init_async (int *argc,
char **argv,
const char *app_name,
const StringVector &args);
Initialize and start BSE. Initialize the BSE library and start the main BSE thread. Arguments specific to BSE are removed from argc
/ argv
.
Historic notes and writeups that are likely outdated or obsolete.
Description of the BSE types and its type system around 1999, before the migration to GObject.
A BseChunk contains header informations for sample value blocks passed around during sound processing, and a pointer to the associated sample data itself. The pure sample data blocks are referred to as "Hunk"s. A hunk's size is determined by the size of each sample value: sizeof (BseSampleValue)
, the number of tracks contained in a hunk (for instance a stereo hunk contains 2 tracks) and a global variable that designates the block (hunk's) size for the current sound processing run: BSE_TRACK_LENGTH
(bse_globals->track_length
). The sample values themselves are layed out interleaved within the hunk, e.g. a 2 track stereo hunk with a hunk_length
of 16 would contain:
Each chunk is associated with a certain output channel of a specific source, and applies to a distinct time frame. The actuall time frame length is determined through BSE_TRACK_LENGTH
and the current mixing frequency BSE_MIX_FREQ
.
A parameter that can be get/set on an object. Each parameter has a parameter specification associated with it.
A parameter specification similar to an object's class or to procedure classes, but for a given parameter type multiple parameter specifications may exist (e.g. to implement integer parameters with different ranges). Thus the type system actually implements parameters as "unclassed" types.
BseObject implements basic structure operations and provides the necessary cruft for objects to have classes.
A class associated with each objects instance. A class is referenced by its object instances. introduces per-object parameters.
A BseProcedure is a a special classed-only (i.e. not-object) type that holds parameter specifications in it's calss structure and can be called. Work is in progress to map certain procedures to certain object types, so they can be thought of as special object-methods to do perform certain object specific modifications.
A plugin handle that holds information about existing plugins, such as where the actuall plugin's implementation is stored on disk and what types of objects are implemented by the plugin.
Plugin can provide:
type ids are provided for objects & classes, object interfaces, parameters, procedures, enum & flags definitions.
BSE features a single inheritance object hierarchy with multiple interfaces. It therefore contains a type system that registers several object and non-object types. The type system features unclassed types (parameters), classed types (enumerations and procedures) and object types (also classed). The type system implemented by BSE has several analogies to the Gtk+ type system and several type system related code portions have been traded between the two projects. However, the BSE type system got furtherly enhanced (read: complicated ;) in some regards by featuring dynamic types to allow certain implementations to reside in dynamic plugins.
Usually, all types get registered with their name, description and inheritance information upon startup and for static types the implementation related type information is also stored right away. This information cannot be stored right away for dynamic types since the implementation related type information contains function pointers that will not remaind valid across the life time of plugins (a plugin being loaded, unloaded and the reloaded again will most certainly end up in a different memory location than before). When class or object instances of a dynamic type need to be created, the corresponding plugin will be loaded into memory and the required implementation related type information will be retrieved.
Upon destruction of the instance, the type info is released again and the plugin will be unloaded. So for dynamic types, the only things that stays persistent across plugin life times are the type's name, description, inheritance information and type id, as well as additional information about what plugin this type is implemented by.
Parameter types are unclassed and do not feature inheritance, they are merely variable type ids to distinguish between e.g. strings and integers. Enumeration types are classed, with flags being a certain kind of enumerations in that their values only feature certain bits. For enumertaions, a flat hierarchy is supported, where every enumeration or flags type derives from BSE_TYPE_ENUM
or BSE_TYPE_FLAGS
respectively.
Object types are classed as well, and may exist in multiple instances per type id. They feature single inheritance and multiple interfaces, where an interface type denotes a certain alternate class-based vtable that is required to adress similar object methods from different heirarchy branches with the same API. Type inheritance can be examined by testing their is_a
relationships, e.g. for a type parent
and a type child
deriving from parent
, the following holds true: child is_a parent
, while the reverse: parent is_a child
would fail, because child
inherits all of parent
's facilities, but not the other way around.
Whether a certain object type implements a specific interface, can be tested through the conforms_to
relationship, e.g. for an interface I
requirering a method implementation foo
and a base type B
, not implementing foo
with it's two child types C
and D
, both carrying different imlpementations of foo
, the following applies:
B conforms_to I
: FALSE
C conforms_to I
: TRUE
D conforms_to I
: TRUE
We will now outline the several steps that are taken by the type system to create/destroy classes and objects. This is actually the guide line for the type system's implementation, so feel free to skip this over ;) In the below, unreferencing of certain objects may automatically cause their destruction, info structure retrival and releasing may (for dynamic types) accompany plugin loading/unloading.
Each source can have an (conceptually) infinite amount of input channels and serve a source network (BseSNet) with multiple output channels. Per source, a list of input channels is kept (source pointer and output channel id, along with an associated history hint). Sources also keep back links to other sources using its output channels, this is required to maintain automated history updates and purging.
A BSE Source Network is an accumulation of BseSources that are interconnected to controll sample data flow. The net as a whole is maintained by a BseSNet object which keeps references of all sources contained in the net and provides means to store/retrieve undo/redo information for the whole net and implements the corresponding requirements to save and load the complete net at a certain configuration.
Implementation details:
Description of the BSE categories around 2003, before the removal of procedures.
The purpose of BSE Categories is to provide a mapping of functionality provided by BSE and its plugins to GUI frontends. Categories are used to provide a hirarchical structure, to group certain services and to aid the user in finding required functionality.
BSE objects and procedures are "categorized" to easily integrate them into menu or similar operation structures in GUIs.
Objects that are derived from the BseSource class with the main intend to be used as synthesis modules in a synthesis network are categorized under the /Modules/
toplevel category, ordered by operational categories.
Procedures provided by the BSE core are categorized under a subcategory of the /Methods/
toplevel category. The object type a procedure operates on is appended to the toplevel category to form a category name starting with /Methods/<ObjectType>/
. Procedures implementing object methods need to take the object as first argument and follow a special naming convention (for the procedure name). To construct the procedure type name, the object type and method named are concatenated to form <ObjectType>+<MethodName>
. This ensure proper namespacing of method names to avoid clashes with equally named methods of distinct object types. Some special internal procedures may also be entered under the /Proc/
toplevel category.
Procedures implementing utility functionality, usually implemented as scripts, are entered into one of the below listed categories. Depending on the category, some procedure arguments are automatically provided by the GUI, the name and type of automatic arguments are listed with the category in the following table:
Category | Automatic arguments as (name:type) pairs |
---|---|
/Project/ | project:BseProject |
/SNet/ | snet:BseSNet |
/Song/ | song:BseSong |
/Part/ | part:BsePart |
/CSynth/ | csynth:BseCSynth |
/WaveRepo/ | wave_repo:BseWaveRepo |
/Wave/ | wave:BseWave |
The set of automatic arguments provided upon invocation is not restricted by te above lists, so caution should be taken when naming multiple arguments to a procedure auto_*
.
A certain BSE type (procedure or object) may be entered under several categories simultaneously, thus allowing multiple categories to refer (alias) to the same type (functionality).
Category | TypeName | Comment |
---|---|---|
/Methods/BseProject/File/Store | BseProject+store-bse | BseProject procedure |
/Modules/Spatial/Balance | BseBalance | synthesis module |
/SNet Utility/Utils/Grid Align | modules2grid | scheme script |
BSE's heart is a unique globally existing object of type BseHeart which takes care of glueing the PCM devices and the internal network structure together and handle syncronization issues.
BseHeart brings the internal network to work by incrementing a global BSE index variable, cycling all active BseSources to that new index, collecting their output chunks and writing them into the output PCM devices. As of now there are still some unsolved syncronization problems, such as having multiple PCM devices that run at different speeds. While this could be solved for multiples/fractions of their mixing frequencies, such as one device (card) running at 44100Hz and another one at 22050Hz, problems still remain for slight alterations in their oscilaltors if a device e.g. runs at 44099Hz (such as the es1371 from newer PCI SB cards).
For the time being, we do not handle different output/input frequencies at all and use our own syncronization within BSE, bound to GLib's main loop mechanism by BseHeart attaching a GSource.
To support user defined latencies, PCM Devices implement their own output buffer queue which is used for temporary storage of output buffers if the specified latency forces a delay greater than what can be achived through the device driver's queue. The devices also maintain an input queue for recorded data to avoid overruns in the PCM drivers, ideally these queues will immediatedly be emptied again because output is also required.
FIXME: A check may be necessary to catch indefinitely growing input queues due to input->output frequency differences. We will also need to catch input underruns here, though handling that is somwhat easier in that we can simply slide in a zero pad chunk there.
The fundamental BSE cycling (block-wise processing of all currently active sources) is bound to the PCM devices output requirements, according to the current latency setting. Integrated into GLib's main loop, we perform the following steps:
With four sample values \(V_{0}\), \(V_{1}\), \(V_{2}\) and \(V_{3}\), cubic interpolation approximates the curve segment connecting \(V_{1}\) and \(V_{2}\), by using the beginning and ending slope, the curvature and the rate of curvature change to construct a cubic polynomial.
The cubic polynomial starts out as:
Where \(0 <= x <= 1\), specifying the sample value of the curve segment between \(V_{1}\) and \(V_{2}\) to obtain.
To calculate the coefficients \(w_{0},…,w_{3}\), we set out the following conditions:
We obtain \(V_{1}'\) and \(V_{2}'\) from the respecting slope triangles:
With (6) → (4) and (7) → (5) we get:
The derivation of \(f(x)\) is:
From \(x=0\) → (1), i.e. (2), we obtain \(w_{0}\) and from \(x=0\) → (10), i.e. (8), we obtain \(w_{1}\). With \(w_{0}\) and \(w_{1}\) we can solve the linear equation system formed by (3) → (1) and (5) → (10) to obtain \(w_{2}\) and \(w_{3}\).
With the resulting coefficients:
\[ \begin{aligned} w_{0} &= V_{1} & &(initial\:value) \\ w_{1} &= \frac{V_{2} - V_{0}} {2} & &(initial\:slope) \\ w_{2} &= \frac{-V_{3} + 4 V_{2} - 5 V_{1} + 2 V_{0}} {2} & &(initial\:curvature) \\ w_{3} &= \frac{V_{3} - 3 V_{2} + 3 V_{1} - V_{0}} {2} & &(rate\:change\:of\:curvature) \end{aligned} \]
Reformulating (1) to involve just multiplications and additions (eliminating power), we get:
Based on \(V_{0},…,V_{3}\), \(w_{0},…,w_{3}\) and (13), we can now approximate all values of the curve segment between \(V_{1}\) and \(V_{2}\).
However, for practical resampling applications where only a specific precision is required, the number of points we need out of the curve segment can be reduced to a finite amount. Lets assume we require \(n\) equally spread values of the curve segment, then we can precalculate \(n\) sets of \(W_{0,…,3}[i]\), \(i=[0,…,n]\), coefficients to speed up the resampling calculation, trading memory for computational performance. With \(w_{0,…,3}\) in (1):
\[ \begin{alignedat} {2} f(x) \ &= & \frac{V_{3} - 3 V_{2} + 3 V_{1} - V_{0}} 2 x^3 \ + & \\ & & \frac{-V_{3} + 4 V_{2} - 5 V_{1} + 2 V_{0}} 2 x^2 \ + & \\ & & \frac{V_{2} - V_{0}} 2 x \ + & \\ & & V1 \ \ & \end{alignedat} \]
sorted for \(V_{0},…,V_{4}\), we have:
With (14) we can solve \(f(x)\) for all \(x = \frac i n\), where \(i = [0, 1, 2, …, n]\) by substituting \(g(i) = f(\frac i n)\) with
and using \(n\) precalculated coefficients \(W_{0,…,3}\) according to:
\[ \begin{alignedat}{4} m &= \frac i n \\ W_{3}[i] &=& 0.5 m^3 & - & 0.5 m^2 & & \\ W_{2}[i] &=& -1.5 m^3 & + & 2 m^2 & + 0.5 m & \\ W_{1}[i] &=& 1.5 m^3 & - & 2.5 m^2 & & + 1 \\ W_{0}[i] &=& -0.5 m^3 & + & m^2 & - 0.5 m & \end{alignedat} \]
We now need to setup \(W_{0,…,3}[0,…,n]\) only once, and are then able to obtain up to \(n\) approximation values of the curve segment between \(V_{1}\) and \(V_{2}\) with four multiplications and three additions using (15), given \(V_{0},…,V_{3}\).
There seems to be a lot of inconsistency in the behaviour of modifiers (shift and/or control) with regards to GUI operations like selections and drag and drop behaviour.
According to the Gtk+ implementation, modifiers relate to DND operations according to the following list:
Modifier | Operation | Note / X-Cursor | |
---|---|---|---|
none | → | copy | (else move (else link)) |
SHIFT |
→ | move | GDK_FLEUR |
CTRL |
→ | copy | GDK_PLUS , GDK_CROSS |
SHIFT+CTRL |
→ | link | GDK_UL_ANGLE |
Regarding selections, the following email provides a short summary:
From: Tim Janik <timj@gtk.org> To: Hacking Gnomes <Gnome-Hackers@gnome.org> Subject: modifiers for the second selection Message-ID: <Pine.LNX.4.21.0207111747190.12292-100000@rabbit.birnet.private> Date: Thu, 11 Jul 2002 18:10:52 +0200 (CEST) hi all, in the course of reimplementing drag-selection for a widget, i did a small survey of modifier behaviour in other (gnome/ gtk) programs and had to figure that there's no current standard behaviour to adhere to: for all applications, the first selection works as expected, i.e. press-drag-release selects the region (box) the mouse was draged over. also, starting a new selection without pressing any modifiers simply replaces the first one. differences occour when holding a modifier (shift or ctrl) when starting the second selection. Gimp: Shift upon button press: the new seleciton is added to the existing one Ctrl upon button press: the new selection is subtracted from the existing one Shift during drag: the selection area (box or circle) has fixed aspect ratio Ctrl during drag: the position of the initial button press serves as center of the selected box/circle, rather than the upper left corner Gnumeric: Shift upon button press: the first selection is resized Ctrl upon button press: the new seleciton is added to the existing one Abiword (selecting text regions): Shift upon button press: the first selection is resized Ctrl upon button press: triggers a compound (word) selection that replaces the first selection Mozilla (selecting text regions): Shift upon button press: the first selection is resized Nautilus: Shift or Ctrl upon buttn press: the new selection is added to or subtracted from the first selection, depending on whether the newly selected region was selected before. i.e. implementing XOR integration of the newly selected area into the first. i'm not pointing this out to start a flame war over what selection style is good or bad and i do realize that different applications have different needs (i.e. abiword does need compound selection, and the aspect-ratio/centering style for gimp wouldn't make too much sense for text), but i think for the benfit of the (new) users, there should me more consistency regarding modifier association with adding/subtracting/resizing/xoring to/from existing selections. --- ciaoTJ