Developer Guide - Events, Signals and Time

(Relevant reading: generator.h)

Events

There are two kinds of event commonly used in gAlan - GDK/GTK events, dealing with the user interface, and audio-events or (commonly in this developer guide) simply events. I will not deal with GDK/GTK events here - the GTK Tutorial (combined with judicious header-file-reading) deals with that topic nicely.

Audio events are mostly used for setting parameters associated with Generators - they are used to send numeric values along the edges of the vertical directed graph the user draws on the main sheet, and are also emitted by Controls when their values are changed. Audio events (from here on AEvents, to avoid confusion with GDK/GTK events) are also used to signal to interested Generators that real-time has elapsed. These two uses are reflected in the different values for AEvent.kind: AE_NUMBER for parameter-setting and general typeless communication, and AE_REALTIME for notifications of real-time events.

Each AEvent has associated with it an item of variable data stored in AEvent.d. AE_NUMBER events always use AEvent.d.number, and AE_REALTIME and AE_MASTER_PLAY events always use AEvent.d.integer. Use the macro GEN_DOUBLE_TO_INT to convert AEvent.d.number to an integer.

Items from generator.h useful when dealing with AEvents:

gen_init_aevent
Initialises the fields in an AEvent. Use this when you have allocated an AEvent on the stack. Usually for the time parameter you will want the result of gen_get_sampletime(). (It is also common to reuse the time field from an existing AEvent - for instance when a Generator is simply passing an AEvent through.)

gen_send_events
Sends an event out an outbound event-connector of a generator. You choose which event queue with the index parameter, and if you want to send to all generators attached to that queue, you pass -1 for the attachment_number parameter - otherwise pass the index of the connecting generator you want to direct the event to.

gen_post_aevent
Puts an AEvent into the system queue, to be delivered to its recipient when the realtime counter reaches the time specified when gen_init_aevent was called. This is the most common way of actually sending an AEvent off.

Signals

Signals are the actual audio data that is manipulated by the various generators. A signal is represented in gAlan only indirectly - as the buffer and buflen arguments to a callback function. Signals are mostly used to represent straight audio data, but they have interesting other uses as well - as signals are just a stream (at sample-resolution) of double-precision floating-point numbers, they also make an ideal time-varying control source. For instance, using a signal-to-event adaptor, you can convert a signal stream to a series of AEvents. This is useful to implement a low-frequency oscillator as a control device for some other generator, among other things.

When a generator needs a buffer-full of audio data to process, it calls gen_read_realtime_input or gen_read_randomaccess_input (depending on the way the generator wants to process its input) with the buffer to fill with the input audio signal. The callback that was configured by the call to gen_new_generatorclass is called, which may either fill the buffer on its own (if it's a "sample source"), or read its own inputs in turn, processing the result before handing it back to the caller.

The two kinds of signal output that a generator can produce reflect the two different access methods - random-access and realtime. Random-access can be useful in situations such as

  • timestretching - the number of samples input does not equal the number of samples output
  • resampling - same problem
  • reversal or looping of a sample
The default access method is realtime - samples are 'streamed' out of a realtime sound source: once the master clock advances, you can't ask for a previous batch of realtime samples the way you can with a random-access sample-producer.

Time

Time is dealt with in gAlan with the concept of a "master clock". Each generator in the system has the opportunity to register a clock (with gen_register_clock()) that may be selected by the user as the master clock for use in providing accurate information about the passing of time. The master clock's job is to accurately schedule calls to gen_mainloop_once(), gen_send_realtime_fns() and gen_advance_clock(). Examples of clocks registered by plugins include:

  • the Default Clock - registered by gui.c as a fallback clock for use when there are no audio/file output clocks in action.
  • the OSS Output clock - registered (and selected!) by oss_output.c when the OSS Output generator is instantiated. Uses gdk_add_input to determine when the sound card is ready for more samples to be sent to it.
  • generators which stream audio data to a file - these may have two clocks: one for streaming samples as quickly as possible, with no user interaction (ie. for "offline" use), and one for streaming samples at approximately realtime, so that the user can interact with the program while the samples are being saved (ie. for "online" use). Note that it's probably best, if monitoring the output as it is being saved, to use the OSS Output clock instead.

Currently the program keeps track of realtime in a global variable, gen_current_sampletime. Note that you should not access this variable directly - use gen_get_sampletime() instead.

The program's idea of realtime is updated every time gen_advance_clock() is called. This is usually when an AE_REALTIME event has been sent to all the realtime-functions, in order to retrieve an audio snippet for playback.

Next Section