Fixing columns
[tu-mathvis-ws13:luisvera-tu-mathvis-ws13.git] / src / experiments / audio / WhisperingGallery.java
1 package experiments.audio;
2
3
4 import java.io.ByteArrayInputStream;
5 import java.io.ByteArrayOutputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8
9 import javax.sound.sampled.*;
10
11 import experiments.audio.JRViewer;
12 import experiments.audio.JRViewer.ContentType;
13 import de.jtem.discretegroup.core.DiscreteGroupConstraint;
14 import de.jtem.discretegroup.core.DiscreteGroupSceneGraphRepresentation;
15 import de.jtem.discretegroup.core.DiscreteGroupSimpleConstraint;
16 import de.jtem.discretegroup.groups.*;
17 import de.jreality.math.Matrix;
18 import de.jreality.math.MatrixBuilder;
19 import de.jreality.plugin.scene.Avatar;
20 import de.jreality.plugin.scene.Sky;
21 import de.jreality.plugin.scene.Terrain;
22 import de.jreality.geometry.Primitives;
23 import de.jreality.scene.Appearance;
24 import de.jreality.scene.DirectionalLight;
25 import de.jreality.scene.Light;
26 import de.jreality.scene.Scene;
27 import de.jreality.scene.SceneGraphComponent;
28 import de.jreality.scene.SceneGraphPath;
29 import de.jreality.scene.SceneGraphPathObserver;
30 import de.jreality.scene.Transformation;
31 import de.jreality.shader.DefaultGeometryShader;
32 import de.jreality.shader.DefaultPolygonShader;
33 import de.jreality.shader.ShaderUtility;
34 import de.jreality.shader.ImageData;
35 import de.jreality.shader.TextureUtility;
36 import de.jreality.shader.TwoSidePolygonShader;
37 import de.jreality.tools.DraggingTool;
38 import de.jreality.tools.RotateTool;
39 import de.jreality.util.ArrayUtility;
40 import de.jreality.util.Input;
41 import de.jreality.util.SceneGraphUtility;
42 import de.jreality.audio.javasound.AudioInputStreamSource;
43 import de.jreality.audio.javasound.CachedAudioInputStreamSource;
44 import de.jreality.scene.AudioSource;
45 import de.jreality.scene.event.TransformationEvent;
46 import de.jreality.scene.event.TransformationListener;
47
48 public class WhisperingGallery  {        
49          
50          static String whichSource = "micro"; // "NYH1V5_SO.wav";
51          static int count = 100;
52          static double side = 0.999;
53          static double ceiling = 1;
54          static double factor = 3;
55          static double vertical = 1.65/factor; // 1.65 is the height of the eyes of the avatar
56          static double[] floor = {0,0,0}, vert = {-0.5,-0.5,-ceiling/2};
57          
58          static boolean running;
59          static private ByteArrayOutputStream out = new ByteArrayOutputStream();
60          static private int latencyParameter = 10; // the bigger the less latency (the combinations 80 800, 5 400, 20 400 used to work)
61          static private int bufferParameter = 800; // sets the copies of the buffer to be stored into the buffer2; should be multiple of the latency
62          
63          static int whichGroup = 2; // 0, 5 = XX, 6 = **, 7 = *2222 (the solid room), 8 = 22*, 9 = 22X; 
64          static private DiscreteGroupSceneGraphRepresentation dgsgr;
65          static private WallpaperGroup gr;
66          static private SceneGraphComponent base = new SceneGraphComponent();
67          static SceneGraphComponent room;
68          static SceneGraphComponent speaker = SceneGraphUtility.createFullSceneGraphComponent("speaker");
69          static SceneGraphComponent columns;
70          static boolean roomIsVisible = false;
71          static boolean speakersAreVisible = false;
72          static boolean columnsAreVisible = false;
73          
74         
75          // -Xms512M -Xmx1024M as VM Argument for the run configuration is supposed to improve the use of memory
76          
77          public static SceneGraphComponent getSpace() throws Exception {
78                  
79                 /**SceneGraphComponent SGCList = SceneGraphUtility.createFullSceneGraphComponent("list");*/
80                 SceneGraphComponent world = SceneGraphUtility.createFullSceneGraphComponent("world");
81                 
82                 Room.constructRoom();
83                 room = Room.getRoom();
84                 room.setVisible(roomIsVisible);
85                 
86                 Columns.constructColumns();
87                 columns = Columns.getColumns();
88                 columns.setVisible(columnsAreVisible);
89
90                 speaker.setGeometry(Primitives.box(0.1, 0.1, 0.1, true));
91                 speaker.setPickable(false);
92                 speaker.setVisible(speakersAreVisible);
93                 // the conical sound directions are the red AND white faces' directions, and the cardioid is the red face's direction
94                 world.addChild(speaker);
95                 world.addChild(columns);
96                 
97                 gr = WallpaperGroup.instanceOfGroup(whichGroup);
98                 dgsgr = new DiscreteGroupSceneGraphRepresentation(gr);
99                 DiscreteGroupConstraint dgc = new DiscreteGroupSimpleConstraint(count);
100                 gr.setConstraint(dgc); 
101                 dgsgr.setWorldNode(world);
102                 dgsgr.update();
103                 dgsgr.getSceneGraphRepn().addChild(room);
104                 MatrixBuilder.euclidean().rotateX(-Math.PI/2).scale(factor).assignTo(dgsgr.getSceneGraphRepn());
105                 
106                 return dgsgr.getSceneGraphRepn();
107         }
108          
109          public static void updateGroup() throws Exception{
110                 base.removeAllChildren();
111                 Columns.removeColumns();
112                 base.addChild(getSpace());
113                 System.out.println(gr.getName());
114          }
115          
116          public static void updateVisibility() {
117                  room.setVisible(roomIsVisible);
118                  speaker.setVisible(speakersAreVisible);
119                  columns.setVisible(columnsAreVisible);
120          }
121         
122         private static AudioFormat format() {
123                 // these are the parameters that work in my computer
124             float sampleRate = 44100;
125             int sampleSizeInBits = 16;
126             int channels = 1;
127             boolean signed = true;
128             boolean bigEndian = false;
129             return new AudioFormat(sampleRate,sampleSizeInBits, channels, signed, bigEndian);
130           }
131         
132         public static void captureAudio() {
133                 try {
134                     DataLine.Info info = new DataLine.Info(TargetDataLine.class, format());
135                     final TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
136                     line.open(format());
137                     line.start();
138                     Runnable runner = new Runnable() { 
139                         public void run() { 
140                                 int bufferCount = 0;
141                                 int bufferSize = (int) format().getSampleRate()*format().getFrameSize() / latencyParameter;     
142                                 byte buffer[] = new byte[bufferSize];;
143                                         byte buffer2[] = new byte[bufferParameter*bufferSize];
144                                         InputStream input;
145                                         AudioInputStream stream;
146                                         AudioSource source;
147                                 running = true;
148                                         // TODO review the buffer system, because sometimes the application collapses
149                                 try {
150                                         while (running) {
151                                                         int count = line.read(buffer, 0, buffer.length);
152                                                         out.write(buffer, 0, count);
153                                                         for (int j=0; j < buffer.length; j++ ){
154                                                                 buffer2[j + bufferCount*buffer.length] = buffer[j];
155                                                         }
156                                                         
157                                                         bufferCount = (bufferCount + 1) % bufferParameter;
158                                                         //System.out.println(count);
159                                                         //System.out.println(bufferCount);
160                                                         if (bufferCount == 1) {
161                                                                 /**sadly we have to create this strange double buffer, 
162                                                                  * because AudioSource does not admit simultaneous reproductions, 
163                                                                  * and a longer buffer is required to get the properly delayed sound
164                                                                  */
165                                                                 System.out.println("Buffer restarted");
166                                                                 input = new ByteArrayInputStream(buffer2);
167                                                                 stream = new AudioInputStream(input, format(), buffer2.length);
168                                                                 source = new AudioInputStreamSource("micro", stream);
169                                                                 speaker.setAudioSource(source); 
170                                                                 source.start();
171                                                         }
172                                                         out.reset();
173                                         }               
174                                         out.close();
175                                 } 
176                                 catch (IOException e) {
177                                         System.err.println("I/O problems: " + e);
178                                         System.exit(-1);
179                                 }
180                         }
181                     };
182                       
183                       Thread captureThread = new Thread(runner);
184                       captureThread.start();
185                     } catch (LineUnavailableException e) {
186                       System.err.println("Line unavailable: " + e);
187                       System.exit(-2);
188                     }
189                   }
190         
191         public static void constructJRV() throws Exception{
192                 
193                 final JRViewer jrv = new JRViewer(true);
194                 jrv.addAudioSupport();
195                 // TODO arrange AudioAttributes
196                 jrv.registerPlugin(Avatar.class);
197                 jrv.registerPlugin(Terrain.class);
198                 jrv.registerPlugin(Sky.class);
199                 jrv.addContentUI();
200                 base.addChild(getSpace());
201                 jrv.setContent(base);
202                 jrv.registerPlugin(new SpaceOptions());
203                 jrv.registerPlugin(new MicrophoneOptions());
204                 jrv.startup();
205                 
206                 jrv.setShowPanelSlots(true, false, false, false);
207                 jrv.getPlugin(Avatar.class).setAvatarPosition(0.5, 0., 0.5);
208                 jrv.getPlugin(Avatar.class).setNavigationSpeed(0.3);
209                 jrv.getPlugin(Avatar.class).getAvatar().setLight(new DirectionalLight());
210                                         
211                 SceneGraphPath scp = new SceneGraphPath(jrv.getViewer().getSceneRoot(), jrv.getPlugin(Avatar.class).getAvatar());
212                 SceneGraphPathObserver scpo = new SceneGraphPathObserver(scp);
213                 TransformationListener listener = new TransformationListener() {
214                         public void transformationMatrixChanged(TransformationEvent ev) {
215                                 // TODO optimize this mess, if possible
216                                 Matrix m = new Matrix(jrv.getPlugin(Avatar.class).getAvatar().getTransformation());
217                                 double[] aux = m.getColumn(1);
218                                 m.setColumn(1, m.getColumn(2));
219                                 m.setColumn(2, aux);
220                                 aux = m.getRow(1);
221                                 m.setRow(1, m.getRow(2));
222                                 m.setRow(2, aux);
223                                 m.setEntry(1, 3, -m.getEntry(1, 3));
224                                 m.setEntry(0, 1, m.getEntry(1, 0));
225                                 m.setEntry(1, 0, -m.getEntry(0, 1));
226                                 m.setEntry(2, 3, m.getEntry(2, 3) + vertical);
227                                 m.multiplyOnRight(MatrixBuilder.euclidean().rotateX(-Math.PI/2).getMatrix());
228                                 Transformation trans = new Transformation();
229                                 m.assignTo(trans);
230                                 //System.out.println(m);
231                                 speaker.setTransformation(trans);
232                         }
233                 };              
234                 scpo.addTransformationListener(listener);
235         }
236         
237         
238         public static void main(String[] args) throws Exception {
239                 
240                 WhisperingGallery.constructJRV();
241                 
242                  if (whichSource.equals("micro") == false) {
243                          InputStream wavFile = WhisperingGallery.class.getResourceAsStream(whichSource);
244                          AudioSource source = new CachedAudioInputStreamSource(whichSource, Input.getInput(whichSource, wavFile), true); 
245                          speaker.setAudioSource(source);
246                          source.start();
247                  }
248         }               
249 }
250
251         // TODO as final target, extend everything to real 3D groups
252         // TODO "map" of the sound, i.e., graphic of the amount of sound we hear depending on the position and the angle of vision
253
254