Positions the input sound in a 3D space and allows moving the sound at k-rate.
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).
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 54. The values in the table are:
Room Parameter
Purpose
0
Early 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 = (2R + 2) * R. If all six walls are enabled: N = (((4R + 6)R + 8)R) / 3
1
Late 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.
2
imdel for spat3d. Overrides opcode parameter if non-negative.
3
irlen for spat3dt. Overrides opcode parameter if non-negative.
4
idist value. Overrides opcode parameter if >= 0.
5
Random seed (0 - 65535) -1 seeds from current time.
6 - 53
wall parameters (w = 6: ceil, w = 14: floor, w = 22: front, w = 30: back, w = 38: right, w = 46: left)
w + 0
Enable reflections from this wall (0: no, 1: yes)
w + 1
Wall distance from listener (in meters)
w + 2
Randomization of wall distance (0 - 1) (in units of 1 / (wall distance))
4: Simulates a pair of microphones (stereo output)
aWbutterlpaW,ifreq; recommended values for ifreqaYbutterlpaY,ifreq; are around 1000 Hzaleft=aW+aXaright=aY+aZ
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.
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 0
mode 1
mode 2
mode 3
mode 4
aW
W out
W out
W out
W out
left chn / low freq.
aX
0
0
X out
X out
left chn / high freq.
aY
0
Y out
Y out
Y out
right chn / low freq.
aZ
0
0
0
Z out
right chn / high freq.
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:
mixing low level DC or noise to the input signal, e.g.
atmprnd311/1e24,0,0aW,aX,aY,aZspa3diain+atmp,...
or
aW,aX,aY,aZspa3diain+1/1e24,...
reducing irlen in the case of spat3dt (which does not have an input signal). A value of about 0.005 is suitable for most uses, although it also depends on EQ settings. If the equalizer is not used, “irlen” can be set to 0.
Examples
Here is an example of the spat3d opcode that outputs a stereo file. It uses the file spat3d_stereo.csd.
<CsoundSynthesizer><CsOptions>; Select audio/midi flags here according to platform; Audio out Audio in No messages-odac -iadc -d ;;;RT audio I/O; For Non-realtime ouput leave only the line below:; -o spat3d_stereo.wav -W ;;; for file output any platform</CsOptions><CsInstruments>/* Written by Istvan Varga */sr=48000kr=1000ksmps=48nchnls=2/* room parameters */idep=3/* early reflection depth */itmpftgen1,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 */instr1/* some source signal */a1phasor150; oscillatora1butterbpa1,500,200; filtera1=taninv(a1*100)a2phasor3; envelopea2mirror40*a2,-100,5a2limita2,0,1a1=a1*a2*9000kazimline0,2.5,360; move sound source aroundkdistline1,10,4; distance; convert polar coordinateskX=sin(kazim*3.14159/180)*kdistkY=cos(kazim*3.14159/180)*kdistkZ=0a1=a1+0.000001*0.000001; avoid underflowsimode=1; change this to 3 for 8 spk in a cube,; or 1 for simple stereoaW,aX,aY,aZspat3da1,kX,kY,kZ,1.0,1,imode,2,2aW=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 */outsaL,aRendin</CsInstruments><CsScore>/* Written by Istvan Varga */i1010e</CsScore></CsoundSynthesizer>
Here is an example of the spat3d opcode that outputs a UHJ file. It uses the file spat3d_UHJ.csd.
<CsoundSynthesizer><CsOptions>; Select audio/midi flags here according to platform; Audio out Audio in No messages-odac -iadc -d ;;;RT audio I/O; For Non-realtime ouput leave only the line below:; -o spat3d_UHJ.wav -W ;;; for file output any platform</CsOptions><CsInstruments>/* Written by Istvan Varga */sr=48000kr=750ksmps=64nchnls=2itmpftgen1,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 */instr1p3=p3+1.0kazimline0.0,4.0,360.0; azimuthkelevline40,p3-1.0,-20; elevationkdist=2.0; distance; convert coordinateskX=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 signala1phasor160.0a2delay1a1a1=a1-a2kffrq1port200.0,0.8,12000.0affrqupsampkffrq1affrqpareqaffrq,5.0,0.0,1.0,2kffrqdownsampaffrqaenv4phasor3.0aenv4limit2.0-aenv4*8.0,0.0,1.0a1butterbpa1*aenv4,kffrq,160.0aenvlinseg1.0,p3-1.0,1.0,0.04,0.0,1.0,0.0a_=4000000*a1*aenv+0.00000001; spatializea_W,a_X,a_Y,a_Zspat3da_,kX,kY,kZ,1.0,1,2,2.0,2; convert to UHJ format (stereo)aWre,aWimhilberta_WaXre,aXimhilberta_XaYre,aYimhilberta_YaWXre=0.0928*aXre+0.4699*aWreaWXim=0.2550*aXim-0.1710*aWimaL=aWXre+aWXim+0.3277*aYreaR=aWXre-aWXim-0.3277*aYreoutsaL,aRendin</CsInstruments><CsScore>/* Written by Istvan Varga */t060i10.08.0e</CsScore></CsoundSynthesizer>
Here is an example of the spat3d opcode that outputs a quadrophonic file. It uses the file spat3d_quad.csd.
<CsoundSynthesizer><CsOptions>; Select audio/midi flags here according to platform; Audio out Audio in No messages-odac -iadc -d ;;;RT audio I/O; For Non-realtime ouput leave only the line below:; -o spat3d_quad.wav -W ;;; for file output any platform</CsOptions><CsInstruments>/* Written by Istvan Varga */sr=48000kr=1000ksmps=48nchnls=4/* room parameters */idep=3/* early reflection depth */itmpftgen1,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 */instr1/* some source signal */a1phasor150; oscillatora1butterbpa1,500,200; filtera1=taninv(a1*100)a2phasor3; envelopea2mirror40*a2,-100,5a2limita2,0,1a1=a1*a2*9000kazimline0,2.5,360; move sound source aroundkdistline1,10,4; distance; convert polar coordinateskX=sin(kazim*3.14159/180)*kdistkY=cos(kazim*3.14159/180)*kdistkZ=0a1=a1+0.000001*0.000001; avoid underflowsimode=2; change this to 3 for 8 spk in a cube,; or 1 for simple stereoaW,aX,aY,aZspat3da1,kX,kY,kZ,1.0,1,imode,2,2aW=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 */outqaFL,aFR,aRL,aRRendin</CsInstruments><CsScore>/* Written by Istvan Varga */t060i1010e</CsScore></CsoundSynthesizer>