1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
|
/*
* Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package javax.media.j3d;
import javax.vecmath.Point2f;
import javax.vecmath.Point3f;
/**
* The PointSoundRetained node (a sub-class of the SoundRetained node) defines
* a spatially-located sound source whose waves radiate uniformly in all
* directions from a given location in space.
*/
class PointSoundRetained extends SoundRetained {
/**
* Origin of Sound source in Listener's space.
*/
Point3f position = new Point3f(0.0f, 0.0f, 0.0f);
/**
* The transformed position of this sound
*/
Point3f xformPosition = new Point3f();
Transform3D trans = new Transform3D();
// Pairs of distances and gain scale factors that define piecewise linear
// gain attenuation between each pair.
float[] attenuationDistance;
float[] attenuationGain;
PointSoundRetained() {
this.nodeType = NodeRetained.POINTSOUND;
}
/**
* Sets this sound's location from the vector provided.
* @param position the new location
*/
void setPosition(Point3f position) {
if (staticTransform != null) {
staticTransform.transform.transform(position, this.position);
} else {
this.position.set(position);
}
getLastLocalToVworld().transform(position, xformPosition);
dispatchAttribChange(POSITION_DIRTY_BIT, (new Point3f(this.position)));
if (source != null && source.isLive()) {
notifySceneGraphChanged(false);
}
}
/**
* Sets this sound's position from the three values provided.
* @param x the new x position
* @param y the new y position
* @param z the new z position
*/
void setPosition(float x, float y, float z) {
position.x = x;
position.y = y;
position.z = z;
if (staticTransform != null) {
staticTransform.transform.transform(this.position);
}
getLastLocalToVworld().transform(position, xformPosition);
dispatchAttribChange(POSITION_DIRTY_BIT, (new Point3f(this.position)));
if (source != null && source.isLive()) {
notifySceneGraphChanged(false);
}
}
/**
* Retrieves this sound's location and places it in the vector provided.
* @param position the variable to receive the location vector
*/
void getPosition(Point3f position) {
if (staticTransform != null) {
Transform3D invTransform = staticTransform.getInvTransform();
invTransform.transform(this.position, position);
} else {
position.set(this.position);
}
}
void getXformPosition(Point3f position) {
position.set(this.xformPosition);
}
/**
* Sets this sound's distance gain attenuation - where gain scale factor
* is applied to sound based on distance listener is from sound source.
* @param distance attenuation pairs of (distance,gain-scale-factor)
*/
void setDistanceGain(Point2f[] attenuation) {
// if attenuation array null set both attenuation components to null
if (attenuation == null) {
this.attenuationDistance = null;
this.attenuationGain = null;
// QUESTION: is this needed so that dispatch***() doesn't
// fail with null?
return;
}
int attenuationLength = attenuation.length;
this.attenuationDistance = new float[attenuationLength];
this.attenuationGain = new float[attenuationLength];
for (int i = 0; i < attenuationLength; i++) {
this.attenuationDistance[i] = attenuation[i].x;
this.attenuationGain[i] = attenuation[i].y;
}
dispatchAttribChange(DISTANCE_GAIN_DIRTY_BIT, attenuation);
if (source != null && source.isLive()) {
notifySceneGraphChanged(false);
}
}
/**
* Sets this sound's distance gain given separate arrays.
* applied to sound based on distance listener is from sound source.
* @param distance array of monotonically-increasing floats.
* @param gain array of amplitude scale factors associated with distances.
*/
void setDistanceGain(float[] distance, float[] gain) {
// if distance or gain arrays are null then treat both as null
if (distance == null) {
this.attenuationDistance = null;
this.attenuationGain = null;
// QUESTION: is this needed so that dispatch***() doesn't
// fail with null?
return;
}
int gainLength = gain.length;
int distanceLength = distance.length;
this.attenuationDistance = new float[distanceLength];
this.attenuationGain = new float[distanceLength];
// Copy the distance array into nodes field
System.arraycopy(distance, 0, this.attenuationDistance, 0, distanceLength);
// Copy the gain array an array of same length as the distance array
if (distanceLength <= gainLength) {
System.arraycopy(gain, 0, this.attenuationGain, 0, distanceLength);
}
else {
System.arraycopy(gain, 0, this.attenuationGain, 0, gainLength);
// Extend gain array to length of distance array
// replicate last gain values.
for (int i=gainLength; i< distanceLength; i++) {
this.attenuationGain[i] = gain[gainLength - 1];
}
}
Point2f [] attenuation = new Point2f[distanceLength];
for (int i=0; i<distanceLength; i++) {
attenuation[i] = new Point2f(this.attenuationDistance[i],
this.attenuationGain[i]);
}
dispatchAttribChange(DISTANCE_GAIN_DIRTY_BIT, attenuation);
if (source != null && source.isLive()) {
notifySceneGraphChanged(false);
}
}
/**
* Gets this sound's distance attenuation array length
* @return distance gain attenuation array length
*/
int getDistanceGainLength() {
if (attenuationDistance == null)
return 0;
else
return this.attenuationDistance.length;
}
/**
* Retieves sound's distance attenuation
* Put the contents of the two separate distance and gain arrays into
* an array of Point2f.
* @param attenuation containing distance attenuation pairs
*/
void getDistanceGain(Point2f[] attenuation) {
// write into arrays passed in, don't do a new
if (attenuation == null)
return;
if (this.attenuationDistance == null ||
this.attenuationGain == null)
return;
int attenuationLength = attenuation.length;
// attenuationDistance and Gain array lengths should be the same
int distanceLength = this.attenuationDistance.length;
if (distanceLength > attenuationLength)
distanceLength = attenuationLength;
for (int i=0; i< distanceLength; i++) {
attenuation[i].x = attenuationDistance[i];
attenuation[i].y = attenuationGain[i];
}
}
/**
* Retieves this sound's attenuation distance and gain arrays, returned in
* separate arrays.
* @param distance array of monotonically-increasing floats.
* @param gain array of amplitude scale factors associated with distances.
*/
void getDistanceGain(float[] distance, float[] gain) {
// write into arrays passed in, don't do a new
if (distance == null || gain == null)
return;
if (this.attenuationDistance == null || this.attenuationGain == null)
return;
// These two array length should be the same
int attenuationLength = this.attenuationDistance.length;
int distanceLength = distance.length;
if (distanceLength > attenuationLength)
distanceLength = attenuationLength;
System.arraycopy(this.attenuationDistance, 0, distance, 0, distanceLength);
attenuationLength = this.attenuationDistance.length;
int gainLength = gain.length;
if (gainLength > attenuationLength)
gainLength = attenuationLength;
System.arraycopy(this.attenuationGain, 0, gain, 0, gainLength);
}
/**
* This updates the positional fields of point sound.
*
* Distance gain attenuation field not maintained in mirror object.
*/
@Override
void updateMirrorObject(Object[] objs) {
if (debugFlag)
debugPrint("PointSoundRetained:updateMirrorObj()");
int component = ((Integer)objs[1]).intValue();
int numSnds = ((Integer)objs[2]).intValue();
SoundRetained[] mSnds = (SoundRetained[]) objs[3];
if (component == -1) {
// update every field
initMirrorObject(((PointSoundRetained)objs[2]));
return;
}
if ((component & POSITION_DIRTY_BIT) != 0) {
for (int i = 0; i < numSnds; i++) {
PointSoundRetained point = (PointSoundRetained) mSnds[i];
Object o = objs[4];
if (o instanceof Point3f) {
point.position = (Point3f) objs[4];
point.getLastLocalToVworld().transform(point.position,
point.xformPosition);
}
}
}
// call the parent's mirror object update routine
super.updateMirrorObject(objs);
}
synchronized void initMirrorObject(PointSoundRetained ms) {
super.initMirrorObject(ms);
ms.position.set(this.position);
ms.xformPosition.set(this.xformPosition);
}
// Called on the mirror object
@Override
void updateTransformChange() {
super.updateTransformChange();
getLastLocalToVworld().transform(position, xformPosition);
// set flag looked at by Scheduler to denote Transform change
// this flag will force resneding transformed position to AudioDevice
if (debugFlag)
debugPrint("PointSoundRetained xformPosition is (" + xformPosition.x +
", " + xformPosition.y + ", "+ xformPosition.z + ")");
}
@Override
void mergeTransform(TransformGroupRetained xform) {
super.mergeTransform(xform);
xform.transform.transform(position, position);
}
}
|