Voicer:
Filter:
ddwVoicer/Classes (extension) | Libraries > Voicer

Voicer
ExtensionExtension

A programmatically-controlled voice-stealing node manager. Written by H. James Harkins, jamshark70@gmail.com
 

Description

Voicer is an evolution on sc2's Voicer.ar. The SC2 voicer class did not implement MIDI. In contrast, a DDW Voicer, can be placed in a VoicerMIDISocket, which includes all the necessary intelligence for note on/off, continuous controllers, and pitch bend messages. Multiple sockets can be created on the same channel with different Voicers and different key ranges, allowing complex keysplit configurations to be created.

Features

SynthDefs & Instr's used with voicer require the following features:

For example:

If you want the instrument to be velocity-sensitive, Latch the gate argument to get the velocity:

Class Methods

.new

Arguments:

voices

the maximum number of voices that can be played by this instance

things

what should go into the nodes. If you supply a single thing, each node will use the same SynthDef. If you supply an array or other collection, the nodes will cycle through the collection. (This is another way to do the sc2 trick of the pattern that plays its successive events on different SynthDefs.)

You will find information about using Voicer with Event Patterns for sequencing in the Using Voicer Guide.

args

can be a single argument array, such as [\ffreq, 10000], or an array of arg arrays: [ [\ffreq, 10000], [\ffreq, 15000] ].

If args is an array, the arg arrays will be referenced using wrapAt and assigned sequentially to the Voicer nodes. These arguments will be stored with each node and sent to every Synth that is placed on the server.

NOTE: Argument arrays should always be written [name, value, name1, value1...] — even for Instr's. This is different from the standard crucial library usage.
bus

the output bus to use.

target

anything that responds to .asTarget. If you supply a MixerChannel, both the bus and the target will be set appropriately. Default is Server.local.

addAction

where the Synths will be placed in relation to the target. This setting will be ignored by Patch nodes.

Discussion:

Each note that is triggered on this last voicer will place two Synths on the server: one for the harpsi, and another for the filter. They will all use the same bus: meaning that if you trigger several notes at once, the effect of the filter will be compounded for each note. This may not be the result you want. In general, you should use simple, self-contained Instr's or synthdefs in a voicer.

NOTE: With Instr, any argument you supply as a SimpleNumber will be wrapped in a KrNumberEditor so you can change its value later. This is different from Patch. If you want a SimpleNumber to serve as a fixed argument, make it a Ref: [\fixed_filter_freq, `12500].

MIDI output, as of 8/2022, uses the ddwMIDIMessageSend quark. Create a Voicer with a MIDISender or VSTPluginMIDISender object as the "thing." In the args array, write chan: midichannel_num to specify the output channel. Because MIDI notes don't encapsulate any parameters other than velocity, all other args will be ignored.

GlobalControlMIDIOut is the interface between a global control on this Voicer, and a MIDI CC on the remote device. First, create the global control. (The name doesn't matter.) Then attach a GlobalControlMIDIOut; a shortcut syntax is to call connectMIDIOut on the global control. All value changes will be forwarded to MIDI from this point forward.

.clock

Now deprecated - the gate method uses thisThread.clock instead of a preset clock.

If you want to do sequencing with this Voicer, you should set the clock to a TempoClock, preferably just after creation:

If you do this, v.gate will only work within a Routine or Task that plays on the same TempoClock. If you will want to gate things from the command line, leave the clock as SystemClock, the default.

.free

Removes all Synth objects associated with this voicer from the server, cleans up its GUI window, and disconnects the Voicer from MIDI.

Instance Methods

.set

Sends the same /n_set message to each node in this voicer. Global controls (see below) send the value to the associated kr bus.

Arguments:

args

See above in *new

lat

Server latency -- see below in trigger1 / trigger.

.trigger1

.trigger

Arguments:

freq

in Hz

gate

default = 1

args

see above in *new

lat

see Discussion below

Discussion:

Trigger a note (trigger1), or several notes (trigger). For trigger1, freq must be a float or int. For trigger, freq can be a single value or a collection. If you are triggering several notes, args can also be a collection of argument arrays e.g. [ [\filter, 300], [\filter, 500], [\filter, 700] ]. Each set of args will be sent in succession to the nodes as they're triggered (using wrapAt). In this case, the first node triggered will get \filter = 300, the second \filter = 500, etc.

lat is the server latency to use for this event. The following values are allowed for all methods with a "lat" argument:

Negative number / <0:
use the Voicer's default latency (set by myVoicer.latency = 1)
Non-negative number / >=0:
use this number as the latency for this event
nil
No latency: Server will play the message as soon as received

.release1

.release

Arguments:

freq

in Hz

lat

see trigger1 / trigger discussion above

Discussion:

Returns the node played, or a collection of nodes played.

.gate1

.gate

Arguments:

freq
dur
gate
args
lat

Discussion:

Find the earliest-triggered note(s) with the frequency/frequencies given and send [\gate,0] to it. release1 allows only one frequency to be given; release works with either a single value or a collection. If there is no node with a given frequency, that frequency is ignored.

Returns the node(s) released.

Triggers the notes and schedules their releases. If freq is a collection, dur and args may be the same thing for every node, or you can supply collections to have different arguments and different release times for each node.

Returns the node(s) played.

.releaseNow1

.releaseNow

Arguments:

freq
sec

Discussion:

Uses a negative gate to cause an instant release. Sec determines how long the release takes. Unlike gate, you may not supply a collection for sec. (Sec is converted to the negative gate by sec.abs.neg-1)

.panic

Stops all active Synths belonging to this Voicer immediately.

.trace

Sends the n_trace message to all active synths. Useful for debugging SynthDefs. You can also trace a single playing node using the following:

.gui

Creates a window showing all global controls (see mapGlobal) and processes (see addProcess).

Voicer-gui uses a proxy system so that you can display different Voicers without incurring the overhead of removing views, resizing the window, adding views, and resizing again. For normal use, this process is transparent to the user. To change the Voicer shown in a particular GUI, drag an expression that evaluates to the Voicer (usually a variable name) into the drag sink immediately to the right of the Voicer GUI label.

.mapGlobal

.unmapGlobal

Arguments:

name
bus
value
spec
allowGUI

Discussion:

Creates an input to the Synth global, by using the supplied kr bus or creating a new one if no bus is supplied; input is mapped to that bus in each Voicer node. Newly triggered Voicer nodes will be mapped automatically. This lets you control filter cutoff frequencies, pitch bends, etc. globally for all nodes in a Voicer. A kr Synth can be played on the bus to provide an LFO.

.addProcess

Arguments:

states
type

Discussion:

Adds a VoicerProcessGroup to this Voicer. The group will be displayed as a button or pop-up menu in the Voicer's GUI. For a button, specify type as \toggle in the addProcess message. See the VoicerProcessGroup help file for the correct syntax for states. Returns the new process group.

This allows you to add graphically triggered sequencers and other processes directly to the Voicer GUI.

VoicerProcessGroups belong to the Voicer's proxy, not to the Voicer itself. This means you can change the Voicer that is to play the sequence while the sequence is playing -- provided both Voicers use the same clock as the sequence. As with Voicer-gui, under normal circumstances this is transparent to the user.

VoicerProcesses and VoicerProcessGroups are deprecated and no longer maintained.

.removeProcess

Stops the process group if playing and removes it from the voicer and GUI.

.stealer

Chooses the algorithm the voicer uses to find the next node to play. Your choices are:

\preferLate:
prefers nodes that were more recently played
\preferEarly:
the default setting; prefers nodes that were played longer ago
\random:
chooses a non-playing node at random
\cycle:
cycles through the nodes in sequence, skipping nodes that are playing
\strictCycle:
cycles through the nodes in sequence, always in order whether they're playing or not

.latency

Sets the default latency for this Voicer. Default latency should be a positive number and can be overridden using the lat argument in trigger, release, gate, and set method calls.