13 years
edited 8 years
This library will allow you to simulate a 3D sound. It will have most of the features of a 3D sound, except for cones and velocity. Most of these are guesstimates, but when I compared it to the regular 3D sounds, they were very similar.
I don't have a 100% concrete grasp on what each field does, so if you have more insight on it, feel free to share. I interpreted it from a lot of testing, but even then there are still a few things I can't account for.
Anyway, why have this system? (1) 3D sounds are incredibly annoying. As far as I can tell, mp3's and 2-channel sounds don't work as them. This will allow you to use it as a regular sound, so you won't have to worry about any of that. (2) If you have a 3D sound, you cannot use SetSoundPlayPosition(...). If your sound is not 3D, you cannot have 3D features (obviously). This system will serve as a compromise, having the sound as non-3D and emulating the features of 3D sounds to get the best aspects of both sides.
Enjoy.
EDIT: Updated with test map and support for SoundTools. (just use call BindSound...(soundObject.run()) or whatever the method is.
I don't have a 100% concrete grasp on what each field does, so if you have more insight on it, feel free to share. I interpreted it from a lot of testing, but even then there are still a few things I can't account for.
Anyway, why have this system? (1) 3D sounds are incredibly annoying. As far as I can tell, mp3's and 2-channel sounds don't work as them. This will allow you to use it as a regular sound, so you won't have to worry about any of that. (2) If you have a 3D sound, you cannot use SetSoundPlayPosition(...). If your sound is not 3D, you cannot have 3D features (obviously). This system will serve as a compromise, having the sound as non-3D and emulating the features of 3D sounds to get the best aspects of both sides.
Enjoy.
1 library Simulate3DSound /* v.1.0.1.1
2 *********************************************************************3 *4 * Simulates a 3D Sound using a regular sound. This extends the5 * functionality for regular sounds, allowing you to apply 3D 6 * sound effects and positioning. In addition, you can use the7 * sound functions that require the sound to be normal (non-3D).8 *9 * This will allow you to use sounds that normally wouldn't work10 * as 3D (for example, 2-channel wav).11 *12 *********************************************************************13 *14 * */uses/*
15 * 16 * */ TimerUtils /* [url]http://www.wc3c.net/showthread.php?t=101322[/url]
17 *18 ********************************************************************19 *20 * Description of Arguments21 *22 * sound s23 *24 * - The base sound to be played. The function will play 25 * the sound for you. This sound must already exist as 26 * an object (you have to create it). 27 * 28 * unit u29 * 30 * - The sound will follow this unit around. The closer31 * the camera is to this unit, the louder the sound.32 *33 * real x, y34 *35 * - The sound will project from this point. The volume36 * is loudest within the point's area. 37 *38 * real minD (minimum distance)39 *40 * - Determines how far the camera can go without attenuating41 * the volume. From the origin to this distance, the sound's42 * volume will be 100%. 43 *44 * real maxD (maximum distance)45 *46 * - Once the camera is past the minimum distance, it will47 * gradually reduce until it hits the maximum distance. 48 * Once it is at the maximum distance or beyond, it will49 * no longer lose volume unless it hits the distance cutoff.50 *51 * real distCutoff (distance cutoff)52 *53 * - The sound will fade to 0% volume once it hits this distance.54 * If the camera is farther than "distCutoff" when the sound55 * is played, the sound will not be heard by that player. 56 *57 ********************************************************************58 *59 * Functions60 *61 * function BindSoundToUnit takes sound s, unit u, real minD, real maxD, real distCut returns Sim3DSound62 * - Attaches a regular sound to a unit. 63 * function BindSoundToPoint takes sound s, real x, real y, real minD, real maxD, real distCut returns Sim3DSound64 * - Attaches a regular sound to a point. 65 * function SetSoundUnit takes Sim3DSound s, unit u returns nothing66 * - Allows you to switch the unit the sound is projecting from. 67 * function SetSoundCoordinates takes Sim3DSound s, real x, real y returns nothing68 * - Allows you to move the sound to another point. 69 * function BindSoundToUnitForPlayer takes player p, sound s, unit u, real minD, real maxD, real distCut returns Sim3DSound70 * function BindSoundToPointForPlayer takes player p, sound s, real x, real y, real minD, real maxD, real distCut returns Sim3DSound71 *72 ********************************************************************73 *74 * Bugs75 *76 * This doesn't behave 100% like Warcraft 3 3D sounds. It does77 * not increase volume in relation to zoom (I may add that feature78 * in the future), and the "minimum distance" does not behave79 * exactly like Warcraft 3's. I'm still trying to figure it out. 80 * However, it is realistic and works well. 81 *82 ********************************************************************/83 84 globals85 // Determines how often the volume is updated86 private constant real PERIOD = 0.2
87 endglobals88 89 private struct Sim3DSound
90 private sound snd
91 private unit source
92 private real sourceX
93 private real sourceY
94 private boolean adjust
95
96 private real initial
97 private real factor
98 private real dur
99 private real maxD
100 private real distCut
101
102 private static method expire takes nothing returns nothing
103 local thistype this = GetTimerData(GetExpiredTimer())
104 local real dx
105 local real dy
106 local real dist
107 local integer volume = 0
108
109 if this.source == null then
110 set dx = this.sourceX - GetCameraTargetPositionX()
111 set dy = this.sourceY - GetCameraTargetPositionY()
112 else113 set dx = GetUnitX(this.source) - GetCameraTargetPositionX()
114 set dy = GetUnitY(this.source) - GetCameraTargetPositionY()
115 endif116 set dist = SquareRoot(dx * dx + dy * dy)
117
118 if this.adjust then
119 if dist > maxD and dist < distCut then
120 call SetSoundVolume(snd, R2I(this.initial - maxD * this.factor))
121 else122 set volume = R2I(this.initial - dist * this.factor) // linear reduction
123 if volume < 0 then
124 call SetSoundVolume(snd, 1)
125 else126 call SetSoundVolume(snd, volume)
127 endif128 endif129 endif130 if this.dur <= 0 then
131 call ReleaseTimer(GetExpiredTimer())
132 endif133 set this.dur = this.dur - PERIOD
134 endmethod135
136 method setSoundPosition takes real x, real y returns nothing
137 set this.sourceX = x
138 set this.sourceY = y
139 endmethod140
141 method setSource takes unit u returns nothing
142 set this.source = u
143 endmethod144
145 static method createOnPoint takes sound s, real x, real y, real minDist, real maxDist, real distCutoff returns thistype
146 local thistype this = thistype.create()
147 local real dx = x - GetCameraTargetPositionX()
148 local real dy = y - GetCameraTargetPositionY()
149 local real dist = dx*dx + dy*dy
150
151 set this.snd = s
152 set this.source = null
153 set this.sourceX = x
154 set this.sourceY = y
155 set this.distCut = distCutoff
156 set this.factor = 127 / distCutoff
157 set this.initial = 127 + minDist * this.factor
158 set this.maxD = maxDist
159 set this.dur = GetSoundDuration(s) * 0.001
160 set this.adjust = dist < distCutoff * distCutoff
161 if not this.adjust then
162 call SetSoundVolume(s, 1)
163 endif164
165 call TimerStart(NewTimerEx(this), PERIOD, true, function thistype.expire)
166 return this
167 endmethod168
169 static method attachToUnit takes sound s, unit u, real minDist, real maxDist, real distCutoff returns thistype
170 local thistype this = thistype.create()
171 local real dx = GetUnitX(u) - GetCameraTargetPositionX()
172 local real dy = GetUnitY(u) - GetCameraTargetPositionY()
173 local real dist = dx*dx + dy*dy
174
175 set this.snd = s
176 set this.source = u
177 set this.distCut = distCutoff
178 set this.factor = 127 / distCutoff
179 set this.initial = 127 + minDist * this.factor
180 set this.maxD = maxDist
181 set this.dur = GetSoundDuration(s) * 0.001
182 set this.adjust = dist < distCutoff * distCutoff
183 if not this.adjust then
184 call SetSoundVolume(s, 1)
185 endif186
187 call TimerStart(NewTimerEx(this), PERIOD, true, function thistype.expire)
188 return this
189 endmethod190 endstruct191
192 function BindSoundToUnit takes sound s, unit u, real minD, real maxD, real distCut returns Sim3DSound
193 if not GetSoundIsPlaying(s) then
194 call StartSound(s)
195 endif196 return Sim3DSound.attachToUnit(s, u, minD, maxD, distCut)
197 endfunction198
199 function BindSoundToPoint takes sound s, real x, real y, real minD, real maxD, real distCut returns Sim3DSound
200 if not GetSoundIsPlaying(s) then
201 call StartSound(s)
202 endif203 return Sim3DSound.createOnPoint(s, x, y, minD, maxD, distCut)
204 endfunction205
206 function SetSoundUnit takes Sim3DSound s, unit u returns nothing
207 call s.setSource(u)
208 endfunction209
210 function SetSoundCoordinates takes Sim3DSound s, real x, real y returns nothing
211 call s.setSoundPosition(x, y)
212 endfunction213
214 function BindSoundToUnitForPlayer takes player p, sound s, unit u, real minD, real maxD, real distCut returns Sim3DSound
215 if GetLocalPlayer() == p then
216 if not GetSoundIsPlaying(s) then
217 call StartSound(s)
218 endif219 endif220 return Sim3DSound.attachToUnit(s, u, minD, maxD, distCut)
221 endfunction222
223 function BindSoundToPointForPlayer takes player p, sound s, real x, real y, real minD, real maxD, real distCut returns Sim3DSound
224 if GetLocalPlayer() == p then
225 if not GetSoundIsPlaying(s) then
226 call StartSound(s)
227 endif228 endif229 return Sim3DSound.createOnPoint(s, x, y, minD, maxD, distCut)
230 endfunction231
232 endlibrary
EDIT: Updated with test map and support for SoundTools. (just use call BindSound...(soundObject.run()) or whatever the method is.