The "performance" of events takes place via voice objects. Event properties are assumed to be independent of the parameters of any synthesis instrument or algorithm. A voice object is a "property-to-parameter mapper" that knows about one or more output or input formats for Smoke data. There are voice "device drivers" for common file storage formats--such as note lists file formats for various software sound synthesis packages or MIDI files--or for use with real-time schedulers connected to MIDI, OSC, CSL, or SuperCollider drivers. These classes can be refined to add new event and signal file formats or multilevel mapping (e.g., for MIDI system exclusive messages) in an abstract way.
Voice objects can also read input streams (e.g., real-time controller data or output from a coprocess), and send messages to other voices, schedulers, event modifiers or event generators. This is how one uses the system for real-time control of complex structures.
The actual property-to-parameter mapping is often controlled by a dictionary or a block (the parameter map) that takes the properties of an event and creates a statement or command for some output format. This allows the user to customize the voices at run-time (see the OSCVoice for good examples).
Voices and Schedulers
Some voices are "timeless" (e.g., MIDI file readers); they operate at full speed regardless of the relative time of the event list they read or write. Others assume that some scheduler hands events to their voices in real time during performance. The EventScheduler does just this; it can be used to sequence and synchronize event lists that may include a variety of voices.
Examples
Create a random event list and write it out to notelist files in any of several formats. Edit the file.
[CmixVoice randomExampleToFileAndEdit]
[CmusicVoice randomExampleToFileAndEdit]
[CsoundVoice randomExampleToFileAndEdit]
[SuperColliderVoice randomExampleToFileAndEdit]
Create an event list of 20 notes with semi-random values and play it on a MIDI output voice.
[(EventList randomExample: 20) playOn: MIDIVoice default]
Use the same random list creation method, but add three lists in parallel.
[((EventList newNamed: #pRand)
addAll: (EventList randomExample: 40);
addAll: (EventList randomExample: 40);
addAll: (EventList randomExample: 40))
playOn: MIDIVoice new]
Complex Multimedia Example: Generate and play a mixed-voice event list; a cloud plays alternating notes on MIDI and built-in synthesis, and a list of action events flashes screen rectangles in parallel.
[ | el |
el := (Cloud dur: 6 "Create a 6-second stochastic cloud"
pitch: (48 to: 60) "choose pitches in this range"
ampl: (40 to: 70) "choose amplitudes in this range"
"select from these 2 voices"
voice: (Array with: (MIDIVoice default) with: (OSCVoice default))
density: 5) eventList. "play 5 notes per sec. and get the events"
"add some animation events"
el addAll: ActionEvent listExample.
el play] "and play the merged event list"
Defaults
The Voice class has a default subclass. This can be changed with the SirenUtility GUI.
[Voice default] i
This can be changed with the Siren Utility view.
As with EventLists, Voices can also be stored in a global dictionary and acccessed by name.
[SirenSession voice: #oscFM put: (OSCVoice map: #pMapForCSLSimpleFM)] d
[SirenSession voice: #defaultMIDI put: (MIDIVoice named: 'oboe' onDevice: (MIDIDevice on: 1) channel: 1)] d
[SirenSession voiceNamed: #oscFM] i
MIDI Input Voices
The MIDI file voice can read standard MIDI file format and generate a Siren event list, as in the example below.
(MIDIFileVoice newOn: 'K194.MID')
readOnto: (EventList newNamed: #K194).
(EventList named: #K194) open.
Extending the Voice Framework
By adding new voice classes, you can add parsers and generators for new score file formats, or extend the system with new real-time output driver interfaces. Look at the uses of the parameter maps in the notelist voices, or the OSC and CSL voices.