Config files for console and chamber are compiled differently, but are constructed exactly the same way. To understand the config process, it is first important to understand the way the hardware works.
There are two card scan processes per cycle: Input Scanning and Output Driving. The config file is therefore split into two parts: Input Scanning and Output Driving.
In a console, combination action spans both parts – inputs (pistons) are read and the resulting coil driving occurs when driving outputs.
Input cards are read sequentially, in order. Once they’re read, the data needs to be mapped to a buffer. During the output section, the input cards “become invisible” and the controller communicates directly with the output cards.
IMPORTANT: The “mode switch” between input mode and output mode happens when the system sees the first coupler. As soon as it reaches that coupler, it converts input card buffers to output card buffers. Therefore you can not reference an input card pin after the first coupler, nor can you reference an output card pin before the same coupler. It also processes any pending combination action work at this divide point.
Dissecting A Simple Config File Line By Line
A simple config file with one keyboard, and 3 stops would look like this:
card_in ( 1 , 0 ) map ( 1 , 1 , 61 , Swell ) map ( 1 , 62 , 3 , TI1 ) stp_cplr ( low , gr_k , gr_k , p_8 ) Stp_seg ( Stop_1 , p_4 , Sw_k ) Stp_seg ( Stop_2 , p_8 , Sw_k ) Stp_seg ( Stop_3 , p_16 , Sw_k ) rank_trim ( 61 , P_8 ) rnk_seg ( 61 , 1 , 1 )
Broken down, piece by piece:
card_in ( 1 , 0 )
This tells the config that there is an input card attached to the first card chain. If there were two or three input cards, it would look like this:
card_in ( 1 , 0 ) card_in ( 2 , 0 )
card_in ( 1 , 0 ) card_in ( 2 , 0 ) card_in ( 3 , 0 )
At this point, the system knows there are two input cards, and has reached out and scanned them. The data is stored in temporary buffers, waiting to be distributed.
map ( 1 , 1 , 61 , Swell )
The map function copies data from one place to another. This function works like this:
map ( card_number , starting_pin , number_of_pins_to_copy , destination_buffer )
So the example above is copying from card 1, pin 1, (through 61) to the swell keying buffers.
map ( 1 , 62 , 3 , TI1 )
Much like the example above, this is taking pins 62-64 and copying them to TI1. TI (Tab Input) buffer #1 holds the first 64 stop bits. TI2 holds stops 65-128, TI3 holds stops 129-192, etc.
stp_cplr ( low , gr_k , gr_k , p_8 )
This is a coupler. The first variable is the bit (stop number or name) that activates the coupler. “Low” means never on. There is therefore, a coupler that can not be activated. But it serves as a placeholder to begin the transition from inputting to outputting. This was described in greater detail on the previous page. Taking a moment to describe couplers, the layout is:
stp_cplr ( stop_name , from , to , pitch )
So a Great to Pedal 8 operated from stop #15 would be:
stp_cplr ( Stop_15 , gr_k , pd_k , p_8 )
If multiple pitches are assigned the same origination and destination keyboard, they must be listed in a certain order: Unison Off (p_0), then highest pitch to lowest pitch:
stp_cplr ( Stop_23 , gr_k , gr_k , p_0 ) stp_cplr ( Stop_24 , gr_k , gr_k , p_4 ) stp_cplr ( Stop_25 , gr_k , gr_k , p_16 )
Back to the example above… Once the first coupler is seen, outputs can be defined. That is not to say they should be – all couplers should be processed before driving pipes. The above example only has one rank to output, played from 3 different tabs (at 3 different pitches). When defining a series of segments of the stop, they must follow the same order as the couplers (highest pitch first). So these are merely defining which stop names, pitches, and keyboard they are playing from:
Stp_seg ( Stop_1 , p_4 , Sw_k ) Stp_seg ( Stop_2 , p_8 , Sw_k ) Stp_seg ( Stop_3 , p_16 , Sw_k )
Once the segments are all defined, it is conceivable that pipes have been defined that don’t exist. Opus-Two coupled keying buffers are 128 bits wide, and that entire buffer width is available to drive each and every rank. A 16′ stop can easily play from an 8′ set of pipes (that would normally be marked TC). Likewise, a 2′ stop can play from a 97 note Bourdon with no trouble. If the relay is aware of this, it will merely ignore the first 12 notes. A rank_trim defines the number of notes and the pitch of the lowest pipe in the rank:
rank_trim ( 61 , P_8 )
That particular set of stop segments has now been trimmed to only include 61 notes, starting at 8′ C.
The trimmed data now needs to be sent somewhere, and this moves it to a driver card:
rnk_seg ( 61 , 1 , 1 )
The rank segment is a chunk of the rank, defined as:
rnk_seg ( number_of_notes , card_number , pin_number )
Because sometimes different parts of ranks are wired to different locations (or borrowed from other ranks), each rnk_seg line simply tells it where to find the next part of the rank. It will continue to look until it has filled the number of pipes defined in the trim (or run out of segment definitions). If they were wired to multiple locations, it would look like this:
rnk_seg ( 12 , 1 , 1 ) rnk_seg ( 36 , 2 , 17 ) rnk_seg ( 13 , 10 , 1 )
The above example has the first octave wired to board 1, pin 1-12. Next 3 octaves wired to board 2 pins 17-53, and the last 13 notes wired to card 17, pins 1-13.