spat3d

spat3d --  Positions the input sound in a 3D space and allows moving the sound at k-rate.

Description

This opcode positions the input sound in a 3D space, with optional simulation of room acoustics, in various output formats. spat3d allows moving the sound at k-rate (this movement is interpolated internally to eliminate "zipper noise" if sr not equal to kr).

Syntax

aW, aX, aY, aZ spat3d ain, kX, kY, kZ, idist, ift, imode, imdel, iovr [, istor]

Initialization

idist -- For modes 0 to 3, idist is the unit circle distance in meters. For mode 4, idist is the distance between microphones.

The following formulas describe amplitude and delay as a function of sound source distance from microphone(s):

amplitude = 1 / (0.1 + distance)
      

delay = distance / 340 (in seconds)
      

Distance can be calculated as:

distance = sqrt(iX^2 + iY^2 + iZ^2)
      

In Mode 4, distance can be calculated as:

distance from left mic = sqrt((iX + idist/2)^2 + iY^2 + iZ^2)
distance from right mic = sqrt((iX - idist/2)^2 + iY^2 + iZ^2)
      

With spat3d the distance between the sound source and any microphone should be at least (340 * 18) / sr meters. Shorter distances will work, but may produce artifacts in some cases. There is no such limitation for spat3di and spat3dt.

Sudden changes or discontinuities in sound source location can result in pops or clicks. Very fast movement may also degrade quality.

ift -- Function table storing room parameters (for free field spatialization, set it to zero or negative). Table size is 64. The values in the table are:

Room ParameterPurpose
0Early reflection recursion depth (0 is the sound source, 1 is the first reflection etc.) for spat3d and spat3di. The number of echoes for four walls (front, back, right, left) is: N = (2*R + 2) * R. If all six walls are enabled: N = (((4*R + 6)*R + 8)*R) / 3
1Late reflection recursion depth (used by spat3dt only). spat3dt skips early reflections and renders echoes up to this level. If early reflection depth is negative, spat3d and spat3di will output zero, while spat3dt will start rendering from the sound source.
2imdel for spat3d. Overrides opcode parameter if non-negative.
3irlen for spat3dt. Overrides opcode parameter if non-negative.
4idist value. Overrides opcode parameter if >= 0.
5Random seed (0 - 65535) -1 seeds from current time.
6 - 53wall parameters (w = 6: ceil, w = 14: floor, w = 22: front, w = 30: back, w = 38: right, w = 46: left)
w + 0Enable reflections from this wall (0: no, 1: yes)
w + 1Wall distance from listener (in meters)
w + 2Randomization of wall distance (0 - 1) (in units of 1 / (wall distance))
w + 3Reflection level (-1 - 1)
w + 4Parametric equalizer frequency in Hz.
w + 5Parametric equalizer level (1.0: no filtering)
w + 6Parametric equalizer Q (0.7071: no resonance)
w + 7Parametric equalizer mode (0: peak EQ, 1: low shelf, 2: high shelf)

imode -- Output mode

Mode 0 is the cheapest to calculate, while mode 4 is the most expensive.

In Mode 4, The optional lowpass filters can change the frequency response depending on direction. For example, if the sound source is located left to the listener then the high frequencies are attenuated in the right channel and slightly increased in the left. This effect can be disabled by not using filters. You can also experiment with other filters (tone etc.) for better effect.

Note that mode 4 is most useful for listening with headphones, and is also more expensive to calculate than the B-format (0 to 3) modes. The idist parameter in this case sets the distance between left and right microphone; for headphones, values between 0.2 - 0.25 are recommended, although higher settings up to 0.4 may be used for wide stereo effects.

More information about B format can be found here: http://www.york.ac.uk/inst/mustech/3d_audio/ambis2.htm

imdel -- Maximum delay time for spat3d in seconds. This has to be longer than the delay time of the latest reflection (depends on room dimensions, sound source distance, and recursion depth; using this formula gives a safe (although somewhat overestimated) value:

imdel = (R + 1) * sqrt(W*W + H*H + D*D) / 340.0
       

where R is the recursion depth, W, H, and D are the width, height, and depth of the room, respectively).

iovr -- Oversample ratio for spat3d (1 to 8). Setting it higher improves quality at the expense of memory and CPU usage. The recommended value is 2.

istor (optional, default=0) -- Skip initialization if non-zero (default: 0).

Performance

aW, aX, aY, aZ -- Output signals

 mode 0mode 1mode 2mode 3mode 4
aWW outW outW outW outleft chn / low freq.
aX00X outX outleft chn / high frq.
aY0Y outY outY outright chn / low frq.
aZ000Z outright chn / high fr.

ain -- Input signal

kX, kY, kZ -- Sound source coordinates (in meters)

If you encounter very slow performance (up to 100 times slower), it may be caused by denormals (this is also true of many other IIR opcodes, including butterlp, pareq, hilbert, and many others). Underflows can be avoided by:

Examples

Here is a example of the spat3d opcode that outputs a stereo file. It uses the files spat3d_stereo.orc and spat3d_stereo.sco.

Example 1. Stereo example of the spat3d opcode.

/* spat3d_stereo.orc */
/* Written by Istvan Varga */
sr      =  48000
kr      =  1000
ksmps   =  48
nchnls  =  2

/* room parameters */

idep    =  3    /* early reflection depth       */

itmp    ftgen   1, 0, 64, -2,                                           \
		/* depth1, depth2, max delay, IR length, idist, seed */ \
		idep, 48, -1, 0.01, 0.25, 123,                          \
		1, 21.982, 0.05, 0.87, 4000.0, 0.6, 0.7, 2, /* ceil  */ \
		1,  1.753, 0.05, 0.87, 3500.0, 0.5, 0.7, 2, /* floor */ \
		1, 15.220, 0.05, 0.87, 5000.0, 0.8, 0.7, 2, /* front */ \
		1,  9.317, 0.05, 0.87, 5000.0, 0.8, 0.7, 2, /* back  */ \
		1, 17.545, 0.05, 0.87, 5000.0, 0.8, 0.7, 2, /* right */ \
		1, 12.156, 0.05, 0.87, 5000.0, 0.8, 0.7, 2  /* left  */

	instr 1

/* some source signal */

a1      phasor 150              ; oscillator
a1      butterbp a1, 500, 200   ; filter
a1      =  taninv(a1 * 100)
a2      phasor 3                ; envelope
a2      mirror 40*a2, -100, 5
a2      limit a2, 0, 1
a1      =  a1 * a2 * 9000

kazim   line 0, 2.5, 360        ; move sound source around
kdist   line 1, 10, 4           ; distance

; convert polar coordinates
kX      =  sin(kazim * 3.14159 / 180) * kdist
kY      =  cos(kazim * 3.14159 / 180) * kdist
kZ      =  0

a1      =  a1 + 0.000001 * 0.000001     ; avoid underflows

imode   =  1    ; change this to 3 for 8 spk in a cube,
		; or 1 for simple stereo

aW, aX, aY, aZ  spat3d a1, kX, kY, kZ, 1.0, 1, imode, 2, 2

aW      =  aW * 1.4142

; stereo
;
aL     =  aW + aY              /* left                 */
aR     =  aW - aY              /* right                */

; quad (square)
;
;aFL     =  aW + aX + aY         /* front left           */
;aFR     =  aW + aX - aY         /* front right          */
;aRL     =  aW - aX + aY         /* rear left            */
;aRR     =  aW - aX - aY         /* rear right           */

; eight channels (cube)
;
;aUFL   =  aW + aX + aY + aZ    /* upper front left     */
;aUFR   =  aW + aX - aY + aZ    /* upper front right    */
;aURL   =  aW - aX + aY + aZ    /* upper rear left      */
;aURR   =  aW - aX - aY + aZ    /* upper rear right     */
;aLFL   =  aW + aX + aY - aZ    /* lower front left     */
;aLFR   =  aW + aX - aY - aZ    /* lower front right    */
;aLRL   =  aW - aX + aY - aZ    /* lower rear left      */
;aLRR   =  aW - aX - aY - aZ    /* lower rear right     */

	outs aL, aR

	endin
/* spat3d_stereo.orc */
        
/* spat3d_stereo.sco */
/* Written by Istvan Varga */
i 1 0 10
e
/* spat3d_stereo.sco */
        

Here is a example of the spat3d opcode that outputs a UHJ file. It uses the files spat3d_UHJ.orc and spat3d_UHJ.sco.

Example 2. UHJ example of the spat3d opcode.

/* spat3d_UHJ.orc */
/* Written by Istvan Varga */
sr	=  48000
kr	=  750
ksmps	=  64
nchnls	=  2

itmp    ftgen   1, 0, 64, -2,                                           \
		/* depth1, depth2, max delay, IR length, idist, seed */ \
		3, 48, -1, 0.01, 0.25, 123,				\
		1, 21.982, 0.05, 0.87, 4000.0, 0.6, 0.7, 2, /* ceil  */ \
		1,  1.753, 0.05, 0.87, 3500.0, 0.5, 0.7, 2, /* floor */ \
		1, 15.220, 0.05, 0.87, 5000.0, 0.8, 0.7, 2, /* front */ \
		1,  9.317, 0.05, 0.87, 5000.0, 0.8, 0.7, 2, /* back  */ \
		1, 17.545, 0.05, 0.87, 5000.0, 0.8, 0.7, 2, /* right */ \
		1, 12.156, 0.05, 0.87, 5000.0, 0.8, 0.7, 2  /* left  */

	instr 1

p3	=  p3 + 1.0

kazim	line 0.0, 4.0, 360.0		; azimuth
kelev	line 40, p3 - 1.0, -20		; elevation
kdist	=  2.0				; distance
; convert coordinates
kX	=  kdist * cos(kelev * 0.01745329) * sin(kazim * 0.01745329)
kY	=  kdist * cos(kelev * 0.01745329) * cos(kazim * 0.01745329)
kZ	=  kdist * sin(kelev * 0.01745329)

; source signal
a1	phasor 160.0
a2	delay1 a1
a1	=  a1 - a2
kffrq1	port 200.0, 0.8, 12000.0
affrq	upsamp kffrq1
affrq	pareq affrq, 5.0, 0.0, 1.0, 2
kffrq	downsamp affrq
aenv4	phasor 3.0
aenv4	limit 2.0 - aenv4 * 8.0, 0.0, 1.0
a1	butterbp a1 * aenv4, kffrq, 160.0
aenv	linseg 1.0, p3 - 1.0, 1.0, 0.04, 0.0, 1.0, 0.0
a_	=  4000000 * a1 * aenv + 0.00000001

; spatialize
a_W, a_X, a_Y, a_Z	spat3d a_, kX, kY, kZ, 1.0, 1, 2, 2.0, 2

; convert to UHJ format (stereo)
aWre, aWim	hilbert a_W
aXre, aXim	hilbert a_X
aYre, aYim	hilbert a_Y

aWXre	=  0.0928*aXre + 0.4699*aWre
aWXim	=  0.2550*aXim - 0.1710*aWim

aL	=  aWXre + aWXim + 0.3277*aYre
aR	=  aWXre - aWXim - 0.3277*aYre

	outs aL, aR

	endin
/* spat3d_UHJ.orc */
        
/* spat3d_UHJ.sco */
/* Written by Istvan Varga */
t 0 60

i 1 0.0 8.0
e
/* spat3d_UHJ.sco */
        

Here is a example of the spat3d opcode that outputs a quadrophonic file. It uses the files spat3d_quad.orc and spat3d_quad.sco.

Example 3. Quadrophonic example of the spat3d opcode.

/* spat3d_quad.orc */
/* Written by Istvan Varga */
sr      =  48000
kr      =  1000
ksmps   =  48
nchnls  =  4

/* room parameters */

idep    =  3    /* early reflection depth       */

itmp    ftgen   1, 0, 64, -2,                                           \
		/* depth1, depth2, max delay, IR length, idist, seed */ \
		idep, 48, -1, 0.01, 0.25, 123,                          \
		1, 21.982, 0.05, 0.87, 4000.0, 0.6, 0.7, 2, /* ceil  */ \
		1,  1.753, 0.05, 0.87, 3500.0, 0.5, 0.7, 2, /* floor */ \
		1, 15.220, 0.05, 0.87, 5000.0, 0.8, 0.7, 2, /* front */ \
		1,  9.317, 0.05, 0.87, 5000.0, 0.8, 0.7, 2, /* back  */ \
		1, 17.545, 0.05, 0.87, 5000.0, 0.8, 0.7, 2, /* right */ \
		1, 12.156, 0.05, 0.87, 5000.0, 0.8, 0.7, 2  /* left  */

	instr 1

/* some source signal */

a1      phasor 150              ; oscillator
a1      butterbp a1, 500, 200   ; filter
a1      =  taninv(a1 * 100)
a2      phasor 3                ; envelope
a2      mirror 40*a2, -100, 5
a2      limit a2, 0, 1
a1      =  a1 * a2 * 9000

kazim   line 0, 2.5, 360        ; move sound source around
kdist   line 1, 10, 4           ; distance

; convert polar coordinates
kX      =  sin(kazim * 3.14159 / 180) * kdist
kY      =  cos(kazim * 3.14159 / 180) * kdist
kZ      =  0

a1      =  a1 + 0.000001 * 0.000001     ; avoid underflows

imode   =  2    ; change this to 3 for 8 spk in a cube,
		; or 1 for simple stereo

aW, aX, aY, aZ  spat3d a1, kX, kY, kZ, 1.0, 1, imode, 2, 2

aW      =  aW * 1.4142

; stereo
;
;aL     =  aW + aY              /* left                 */
;aR     =  aW - aY              /* right                */

; quad (square)
;
aFL     =  aW + aX + aY         /* front left           */
aFR     =  aW + aX - aY         /* front right          */
aRL     =  aW - aX + aY         /* rear left            */
aRR     =  aW - aX - aY         /* rear right           */

; eight channels (cube)
;
;aUFL   =  aW + aX + aY + aZ    /* upper front left     */
;aUFR   =  aW + aX - aY + aZ    /* upper front right    */
;aURL   =  aW - aX + aY + aZ    /* upper rear left      */
;aURR   =  aW - aX - aY + aZ    /* upper rear right     */
;aLFL   =  aW + aX + aY - aZ    /* lower front left     */
;aLFR   =  aW + aX - aY - aZ    /* lower front right    */
;aLRL   =  aW - aX + aY - aZ    /* lower rear left      */
;aLRR   =  aW - aX - aY - aZ    /* lower rear right     */

	outq aFL, aFR, aRL, aRR

	endin
/* spat3d_quad.orc */
        
/* spat3d_quad.sco */
/* Written by Istvan Varga */
t 0 60
i 1 0 10
e
/* spat3d_quad.sco */
        

See Also

spat3di, spat3dt

Credits

Author: Istvan Varga

2001

New in version 4.12

Updated April 2002 by Istvan Varga