In March of 2012 Michael acquired 4 Genelec nearfield monitors and a sub. While it would have been preferable to work with an 8.1 system, economics determined a 4.1 system would have to suffice. This turned out to be fortuitous because in simplifying the system down to 4 channels a new spatial paradigm began to emerge… one based upon a Cartesian coordinate system.
As one can see from looking at the diagram, this is a two dimensional view of a square room with a speaker placed in each of the four corners. The Cartesian plane laid over it ranges from 0 to 1 in both the X and the Y axis. The coordinates (0, 1) represent the position of speaker 1, which sits in the left front position. speaker 2, right front, is in position (1, 1), speaker 3, left rear, is in position (0, 0) and speaker 4, right rear, is in position (1, 0).
This coordinate system provides a concise way to determine the placement of any musical event along the 4 channel speaker array’s perimeter. Further, by using decimal values between 0 and 1, for either X and/or Y coordinates we can precisely place the sound anywhere within the room. To get an idea of how this works first consider that the values of the Cartesian coordinates not only determine the placement of the event but also provide an amplitude multiplier for the same event depending on the rule and subsequent speakers to which it is applied. An amplitude multiplier value of “1” represents full amplitude of any event, a value of “0” represents no amplitude multiplier, a .5 represents half amplitude multiplier and etc. It is by precisely balancing these amplitudes that we achieve the perception of the location of any given event.
It is pertinent to mention that these amplitude location queues are relative to the listener’s position within the room. The ideal listening position with regard to intended spatial location of the events would be in the exact center of the room. However, any position within the room should provide for an interesting spatial rendition of the composition.
Through the use of the rules listed on the lower left of the diagram and the programming model to the lower right as well as the amplitude relationships mentioned above we can see that we can place a sound anywhere within a given space by determining the amplitude of each of the four speakers for any given event at any given time.
For those familiar with Csound, a programming language meant for musical composition, from there we envision a bit of Csound code, within a Csound instrument, that will provide this functionality. However, one more aspect of this model needs to be considered first and that is to allow for the sound moving from one set of coordinates to another using a given line or curve. To do this we implemented the envelope opcodes available in Csound. Within any given score that will drive our instrument we use a stochastic event generator to determine the beginning coordinates of a given event and then a third value to determine the envelope along which it will move over the duration of the event. Below is an excerpt of the Csound code used to implement this Cartesian Panning Matrix model.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;panning algorithms
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ixval = p17 ;x coordinate
iyval = p18 ;y coordinate
kpan = p19 ;pan select
kxenv11 linseg (1 – ixval), idur * .5, ixval ;linear 1:1
kxenv12 linseg ixval, idur * .5, (1 – ixval)
kyenv11 linseg (1 – iyval), idur * .5, iyval
kyenv12 linseg iyval, idur * .5, (1 – iyval)
kxenv21 linseg (1 – ixval), idur * .2, ixval, idur * .2, 0, idur * .2, ixval, idur * .2, (1 – ixval), idur * .2, ixval
kxenv22 linseg ixval, idur * .2, (1 – ixval), idur * .2, ixval, idur * .2, 0, idur * .2, 0, idur * .2, 0
kxenv23 linseg 0, idur * .2, ixval, idur * .2, (1 – ixval), idur * .2, ixval, idur * .2, 0, idur * .2, 0
kxenv24 linseg 0, idur * .2, 0, idur * .2, ixval, idur * .2, (1 – ixval), idur * .2, ixval, idur * .2, 0
kxenv31 linseg ixval, idur * .2, (1 – ixval), idur * .2, 0, idur * .2, (1 – ixval), idur * .2, ixval, idur * .2, (1 – ixval)
kxenv32 linseg (1 – ixval), idur * .2, ixval, idur * .2, (1 – ixval), idur * .2, 0, idur * .2, 0, idur * .2, 0
kxenv33 linseg 0, idur * .2, (1 – ixval), idur * .2, ixval, idur * .2, (1 – ixval), idur * .2, 0, idur * .2, 0
kxenv34 linseg 0, idur * .2, 0, idur * .2, (1 – ixval), idur * .2, ixval, idur * .2, (1 – ixval), idur * .2, 0
if kpan == 1 goto pan1
if kpan == 2 goto pan2
if kpan == 3 goto pan3
if kpan == 4 goto pan4
if kpan == 5 goto pan5
pan1:
if kxval == 0 && kyval == 1 goto end01
if kxval == 1 && kyval == 1 goto end02
if kxval == 0 && kyval == 0 goto end03
if kxval == 1 && kyval == 0 goto end04
goto end05
end01:
a10000 = a1000 * kyval
a20000 = a1000 * 0
a30000 = a1000 * (1 – kyval)
a40000 = a1000 * 0
a50000 = a5000
goto end06
end02:
a10000 = a1000 * 0
a20000 = a1000 * kyval
a30000 = a1000 * 0
a40000 = a1000 * (1 – kyval)
a50000 = a5000
goto end06
end03:
a10000 = a1000 * kxval
a20000 = a1000 * 0
a30000 = a1000 * (1 – kxval)
a40000 = a1000 * 0
a50000 = a5000
goto end06
end04:
a10000 = a1000 * 0
a20000 = a1000 * 0
a30000 = a1000 * (1 – kxval)
a40000 = a1000 * kxval
a50000 = a1000
goto end06
end05:
a10000 = a1000 * kyval * .5
a20000 = a1000 * kxval * .5
a30000 = (a1000 * (1 – kyval)) * .5
a40000 = (a1000 * (1 – kxval)) * .5
a50000 = a5000
goto end06
pan2:
if kxval == 0 && kyval == 1 goto end11
if kxval == 1 && kyval == 1 goto end12
if kxval == 1 && kyval == 0 goto end13
if kxval == 0 && kyval == 0 goto end14
goto end15 ;if kxval && kyval /= 1
end11: ;linear pan from 1 – 2
a10000 = a1000 * kxenv11
a20000 = a1000 * kxenv12
a30000 = a1000 * 0
a40000 = a1000 * 0
a50000 = a5000
goto end06
end12: ;linear pan from 2 – 4
a10000 = a1000 * 0
a20000 = a1000 * kyenv12
a30000 = a1000 * 0
a40000 = a1000 * kyenv11
a50000 = a5000
goto end06
end13: ;linear pan from 4 – 3
a10000 = a1000 * 0
a20000 = a1000 * 0
a30000 = a1000 * kxenv11
a40000 = a1000 * kxenv12
a50000 = a5000
goto end06
end14: ;linear pan from 3 – 1
a10000 = a1000 * kyenv12
a20000 = a1000 * 0
a30000 = a1000 * kyenv11
a40000 = a1000 * 0
a50000 = a5000
goto end06
end15:
a10000 = a1000 * kyenv11 * .5
a20000 = a1000 * kxenv11 * .5
a30000 = a1000 * kyenv12 * .5
a40000 = a1000 * kxenv12 * .5
a50000 = a5000
goto end06
pan3:
if kxval == 0 && kyval == 1 goto end21
if kxval == 1 && kyval == 1 goto end22
if kxval == 1 && kyval == 0 goto end23
if kxval == 0 && kyval == 0 goto end24
goto end25 ;if kxval && kyval /= 1
end21: ;linear pan from 1 – 4
a10000 = a1000 * kxenv11
a20000 = a1000 * 0
a30000 = a1000 * 0
a40000 = a1000 * kxenv12
a50000 = a5000
goto end06
end22: ;linear pan from 2 – 3
a10000 = a1000 * 0
a20000 = a1000 * kyenv12
a30000 = a1000 * kyenv11
a40000 = a1000 * 0
a50000 = a5000
goto end06
end23: ;linear pan from 4 – 1
a10000 = a1000 * kxenv11
a20000 = a1000 * 0
a30000 = a1000 * 0
a40000 = a1000 * kxenv12
a50000 = a5000
goto end06
end24: ;linear pan from 3 – 2
a10000 = a1000 * 0
a20000 = a1000 * kyenv12
a30000 = a1000 * kyenv11
a40000 = a1000 * 0
a50000 = a5000
goto end06
end25:
a10000 = a1000 * kyenv12 * .5
a20000 = a1000 * kxenv12 * .5
a30000 = a1000 * kyenv11 * .5
a40000 = a1000 * kxenv11 * .5
a50000 = a5000
goto end06
pan4:
if kxval == 0 && kyval == 1 goto end31 ;linear pan from 1,3,4,2
if kxval == 1 && kyval == 1 goto end32 ;linear pan from 2,1,3,4
if kxval == 0 && kyval == 0 goto end33 ;linear pan from 3,4,2,1
if kxval == 1 && kyval == 0 goto end34 ;linear pan from 4,2,1,3
goto end35
end31:
a10000 = a1000 * kxenv21
a20000 = a1000 * kxenv24
a30000 = a1000 * kxenv22
a40000 = a1000 * kxenv23
a50000 = a5000
goto end06
end32:
a10000 = a1000 * kxenv32
a20000 = a1000 * kxenv31
a30000 = a1000 * kxenv33
a40000 = a1000 * kxenv34
a50000 = a5000
goto end06
end33:
a10000 = a1000 * kxenv24
a20000 = a1000 * kxenv23
a30000 = a1000 * kxenv21
a40000 = a1000 * kxenv22
a50000 = a5000
goto end06
end34:
a10000 = a1000 * kxenv33
a20000 = a1000 * kxenv32
a30000 = a1000 * kxenv34
a40000 = a1000 * kxenv31
a50000 = a5000
goto end06
end35:
a10000 = a1000 * kxenv21 * .5
a20000 = a1000 * kxenv22 * .5
a30000 = a1000 * kxenv23 * .5
a40000 = a1000 * kxenv24 * .5
a50000 = a5000
goto end06
pan5:
if kxval == 0 && kyval == 1 goto end41 ;linear pan from 2,4,3,1
if kxval == 1 && kyval == 1 goto end42 ;linear pan from 4,3,1,2
if kxval == 0 && kyval == 0 goto end43 ;linear pan from 1,2,4,3
if kxval == 1 && kyval == 0 goto end44 ;linear pan from 3,1,2,4
goto end 45
end41:
a10000 = a1000 * kxenv24
a20000 = a1000 * kxenv21
a30000 = a1000 * kxenv23
a40000 = a1000 * kxenv22
a50000 = a5000
goto end06
end42:
a10000 = a1000 * kxenv33
a20000 = a1000 * kxenv34
a30000 = a1000 * kxenv32
a40000 = a1000 * kxenv31
a50000 = a5000
goto end06
end43:
a10000 = a1000 * kxenv21
a20000 = a1000 * kxenv22
a30000 = a1000 * kxenv24
a40000 = a1000 * kxenv23
a50000 = a5000
goto end06
end44:
a10000 = a1000 * kxenv32
a20000 = a1000 * kxenv33
a30000 = a1000 * kxenv31
a40000 = a1000 * kxenv34
a50000 = a5000
goto end06
end45:
a10000 = a1000 * kxenv24 * .5
a20000 = a1000 * kxenv23 * .5
a30000 = a1000 * kxenv22 * .5
a40000 = a1000 * kxenv21 * .5
a50000 = a5000
goto end06
end06:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;