Jogamp
www/devmaster/lesson*.html: net.java.games.joal.* -> com.jogamp.openal.*
[joal-demos.git] / www / devmaster / lesson5.html
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2 <html>
3 <head>
4 <title>JOAL OpenAL Tutorials from DevMaster.net Lesson 5: Sources Sharing Buffers</title>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6 <link rel="stylesheet" type="text/css" href="general.css">
7 </head>
8 <body>
9 <a href="../index.html"><img src="../../../images/jogamp_symbols/website_final_blue_joal_346x70pel.png" alt="JOAL Symbol"></a><a href="http://www.openal.org"><img src="../openal_c.gif"></a>
10 <br>
11 OpenAL Tutorials from DevMaster.net. Reprinted with Permission.<br>
12 <br>
13 <table border="0" cellspacing="0" style="border-collapse: collapse" width="100%" cellpadding="0" id="AutoNumber1" height="12" bgcolor="#666699">
14   <tr> 
15     <td width="47%" height="12" valign="middle"><p><b><font color="#FFFFFF">OpenAL 
16         Tutorials</font></b></p></td>
17     <td width="53%" height="12" align="right" valign="middle"><p align="right"><a href="http://devmaster.net/"><font color="#66FF99">DevMaster.net</font></a></p></td>
18   </tr>
19 </table>
20 <p class="ArticleTitle"><font size="5">Sources Sharing Buffers<br>
21   </font><strong><font size="4">Lesson 5</font></strong></p>
22 <p align="right" class="ArticleAuthor">Author: <a href="mailto:lightonthewater@hotmail.com">Jesse 
23   Maurais<br>
24   </a>Adapted For Java By: <a href="athomas@dev.java.net">Athomas 
25   Goldberg </a></p>
26
27 <p><a href="../../../deployment/jogamp-current/joal-demos/jnlp-files/joal-lesson5.jnlp">Launch the Demo via Java Web Start</a></p>
28 <p align="justify">This is a translation of <a href="http://devmaster.net/posts/2892/openal-lesson-5-sources-sharing-buffers">
29 OpenAL Lesson 5: Sources Sharing Buffers</a>
30 tutorial from <a href="http://devmaster.net/">DevMaster.net</a> to JOAL.
31
32 </p>
33 <p align="justify">At this point in the OpenAL series I will show one method of 
34   having your buffers be shared among many sources. This is a very logical and 
35   natural step, and it is so easy that some of you may have already done this 
36   yourself. If you have you may just skip this tutorial in total and move on. 
37   But for those keeners who want to read all of the info I've got to give, you 
38   may find this interesting. Plus, we will be implementing the Alc layer directly 
39   so that we can use some of that knowledge gained in lesson 4. On top of that 
40   we will create a program you might even use!</p>
41 <p align="justify">Well, here we go. <!-- I've decided to only go over bits of the 
42   code that are significant, since most of the code has been repeated so far in 
43   the series. Check out the full source code in the download.--></p>
44 <pre class=code>
45 <font color="#0000FF">import</font> java.io.*;
46 <font color="#0000FF">import</font> java.nio.*;
47 <font color="#0000FF">import</font> java.util.*;
48
49 <font color="#0000FF">import</font> com.jogamp.openal.*;
50 <font color="#0000FF">import</font> com.jogamp.openal.util.*;
51
52 <font color="#0000FF">public</font> <font color="#0000FF">class</font> SourceSharingBuffers {
53
54 <span class=codeComment><font color="#0000FF">static</font> ALC alc;
55 <font color="#0000FF">static</font> AL al;<font color="#006600">
56
57 // These index the buffers.</font></span>
58 <span class=codeKeyword><font color="#0000FF">public static final int</font></span> THUNDER      = 0;
59 <span class=codeKeyword><font color="#0000FF">public static final int</font></span> WATERDROP   = 1;
60 <span class=codeKeyword><font color="#0000FF">public static final int</font></span> STREAM      = 2;
61 <span class=codeKeyword><font color="#0000FF">public static final int</font></span> RAIN        = 3;
62
63 <span class=codeKeyword><font color="#0000FF">public static final int</font></span> CHIMES      = 4;
64 <span class=codeKeyword><font color="#0000FF">public static final int</font></span> OCEAN       = 5;
65 <span class=codeKeyword><font color="#0000FF">public static final int</font></span> NUM_BUFFERS = 6;
66
67 <font color="#006600"><span class=codeComment>// Buffers hold sound data.</span>
68 </font><font color="#0000FF">static int</font>[] buffers = <font color="#0000FF">new int</font>[NUM_BUFFERS];
69
70 <span class=codeComment><font color="#006600">// A list of sources for multiple emissions.</font></span>
71 static List sources = <font color="#0000FF">new </font>ArrayList();
72
73 //  Position of the source sounds.
74 static float[] sourcePos = { 0.0f, 0.0f, 0.0f };
75
76 //  Velocity of the source sounds.
77 static float[] sourceVel = { 0.0f, 0.0f, 0.0f };
78
79
80 //  Position of the listener.
81 static float[] listenerPos = { 0.0f, 0.0f, 0.0f };
82
83 //  Velocity of the listener.
84 static float[] listenerVel = { 0.0f, 0.0f, 0.0f };
85
86 //  Orientation of the listener. (first 3 elements are "at", second 3 are "up")
87 static float[] listenerOri = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f };
88 </pre>
89 <p align="justify">First I've written out a few macros that we can use to index 
90   the buffer array. We will be using several wav files so we need quite a few 
91   buffers here. Instead of using an array for storing the sources we will use 
92   a Vector. We chose to do this because it allows us to have a dynamic number 
93   of sources. We can just keep adding sources to the scene until OpenAL runs out 
94   of them. This is also the first tutorial where we will deal with sources as 
95   being a resource that will run out. And yes, they will run out; they are finite.</p>
96 <pre class=code><font color="#0000FF">static int </font>initOpenAL() {
97     al = ALFactory.getAL();
98     alc = ALFactory.getALC(); 
99     ALCdevice device;
100     ALCcontext context;
101     String deviceSpecifier;
102     String deviceName = &quot;DirectSound3D&quot;; // You may choose to open a specific OpenAL device if you know its name.
103     deviceName = <font color="#0000FF">null</font>; // Passing a null String to alcOpenDevice will open the default device on your system!
104
105     <span class=codeComment><font color="#006600">// Get handle to device.</font></span>
106     device = alc.alcOpenDevice(deviceName);
107
108     <font color="#006600"><span class=codeComment>// Get the device specifier.</span></font>
109     deviceSpecifier = alc.alcGetString(device, ALC.ALC_DEVICE_SPECIFIER);
110
111     System.out.println(&quot;Using device &quot; + deviceSpecifier);
112
113     <span class=codeComment><font color="#006600">// Create audio context.</font></span>
114     context = alc.alcCreateContext(device, <font color="#0000FF">null</font>);
115
116     <span class=codeComment><font color="#006600">// Set active context.</font></span>
117     alc.alcMakeContextCurrent(context);
118
119     <span class=codeComment><font color="#006600">// Check for an error.</font></span>
120     <span class=codeKeyword><font color="#0000FF">if </font></span>(alc.alcGetError(device) != ALC.ALC_NO_ERROR)
121         <span class=codeKeyword><font color="#0000FF">return</font></span> AL.AL_FALSE;
122
123     <span class=codeKeyword><font color="#0000FF">return</font></span> AL.AL_TRUE;
124 }
125 </pre>
126 <p align="justify">This is some sample code from what we learned in the last tutorial. 
127   We get a handle to the device &quot;DirectSound3D&quot;, and then obtain a rendering 
128   context for our application. This context is set to current and the function 
129   will check if everything went smoothly before we return success.</p>
130 <pre class=code><span class=codeKeyword><font color="#0000FF">static void</font></span> exitOpenAL() {
131     ALCcontext curContext;
132     ALCdevice curDevice;
133
134     <font color="#006600"><span class=codeComment>// Get the current context.</span></font>
135     curContext = alc.alcGetCurrentContext();
136
137     <span class=codeComment><font color="#006600">// Get the device used by that context.</font></span>
138     curDevice = alc.alcGetContextsDevice(curContext);
139
140 <font color="#006600">    <span class=codeComment>// Reset the current context to NULL.</span>
141 </font>    alc.alcMakeContextCurrent(<font color="#0000FF">null</font>);
142
143 <font color="#006600">    <span class=codeComment>// Release the context and the device.</span>
144 </font>    alc.alcDestroyContext(curContext);
145     alc.alcCloseDevice(curDevice);
146 }
147 </pre>
148 <p align="justify">This will do the opposite we did in the previous code. It retrieves 
149   the context and device that our application was using and releases them. It 
150   also sets the current context to null (the default) which will suspend the processing 
151   of any data sent to OpenAL. It is important to reset the current context to 
152   null or else you will have an invalid context trying to process data. The results 
153   of doing this can be unpredictable.</p>
154 <p align="justify">If you are using a multi-context application you may need to 
155   have a more advanced way of dealing with initialization and shutdown. I would 
156   recommend making all devices and contexts global and closing them individually, 
157   rather than retrieving the current context.</p>
158 <pre class=code><font color="#0000FF">static int </font>loadALData() {
159     <font color="#006600"><span class=codeComment>// Variables to load into.</span></font>
160     <font color="#0000FF">int</font>[] format = new <font color="#0000FF">int</font>[1];
161     <font color="#0000FF">int</font>[] size = new <font color="#0000FF">int</font>[1];
162     ByteBuffer[] data = new ByteBuffer[1];
163     <font color="#0000FF">int</font>[] freq = new <font color="#0000FF">int</font>[1];
164     <font color="#0000FF">int</font>[] loop = new <font color="#0000FF">int</font>[1];
165
166     <span class=codeComment><font color="#006600">// Load wav data into buffers.</font></span>
167     al.alGenBuffers(NUM_BUFFERS, buffers, 0);
168
169     <span class=codeKeyword><font color="#0000FF">if</font></span>(al.alGetError() != AL.AL_NO_ERROR)
170         <span class=codeKeyword><font color="#0000FF">return</font></span> AL.AL_FALSE;
171
172     ALut.alutLoadWAVFile("wavdata/thunder.wav", format, data, size, freq, loop);
173     al.alBufferData(buffers[THUNDER], format[0], data[0], size[0], freq[0]);
174 <!--    ALut.alutUnloadWAV(format[0], data[0], size[0], freq[0]); -->
175
176     ALut.alutLoadWAVFile("wavdata/waterdrop.wav", format, data, size, freq, loop);
177     al.alBufferData(buffers[WATERDROP], format[0], data[0], size[0], freq[0]);
178 <!--    ALut.alutUnloadWAV(format[0], data[0], size[0], freq[0]); -->
179
180     ALut.alutLoadWAVFile("wavdata/stream.wav", format, data, size, freq, loop);
181     al.alBufferData(buffers[STREAM], format[0], data[0], size[0], freq[0]);
182 <!--    ALut.alutUnloadWAV(format[0], data[0], size[0], freq[0]); -->
183
184     ALut.alutLoadWAVFile("wavdata/rain.wav", format, data, size, freq, loop);
185     al.alBufferData(buffers[RAIN], format[0], data[0], size[0], freq[0]);
186 <!--    ALut.alutUnloadWAV(format[0], data[0], size[0], freq[0]); -->
187
188     ALut.alutLoadWAVFile("wavdata/ocean.wav", format, data, size, freq, loop);
189     al.alBufferData(buffers[OCEAN], format[0], data[0], size[0], freq[0]);
190 <!--    ALut.alutUnloadWAV(format[0], data[0], size[0], freq[0]); -->
191
192     ALut.alutLoadWAVFile("wavdata/chimes.wav", format, data, size, freq, loop);
193     al.alBufferData(buffers[CHIMES], format[0], data[0], size[0], freq[0]);
194 <!--    ALut.alutUnloadWAV(format[0], data[0], size[0], freq[0]); -->
195
196 <font color="#006600">    <span class=codeComment>// Do another error check and return.</span>
197     </font><span class=codeKeyword><font color="#0000FF">if</font> </span>(al.alGetError() != AL.AL_NO_ERROR)
198         <span class=codeKeyword><font color="#0000FF">return</font></span> AL.AL_FALSE;
199
200     <span class=codeKeyword><font color="#0000FF">return</font></span> AL.AL_TRUE;
201 }
202 </pre>
203 <p align="justify">We've totally removed the source generation from this function. 
204   That's because from now on we will be initializing the sources separately.</p>
205 <pre class=code><span class=codeKeyword><font color="#0000FF">static void</font></span><font color="#0000FF"> </font>addSource(int type) {
206     <font color="#0000FF">int[]</font> source = <font color="#0000FF">new int</font>[1];
207
208     al.alGenSources(1, source, 0);
209
210     <span class=codeKeyword><font color="#0000FF">if</font> </span>(al.alGetError() != AL.AL_NO_ERROR) {
211         System.err.println("Error generating audio source.");
212         System.exit(1);
213     }
214
215     al.alSourcei (source[0], AL.AL_BUFFER,   buffers[type]);
216     al.alSourcef (source[0], AL.AL_PITCH,    1.0f         );
217     al.alSourcef (source[0], AL.AL_GAIN,     1.0f         );
218     al.alSourcefv(source[0], AL.AL_POSITION, sourcePos    , 0);
219     al.alSourcefv(source[0], AL.AL_VELOCITY, sourceVel    , 0);
220     al.alSourcei (source[0], AL.AL_LOOPING,  AL.AL_TRUE      );
221
222     al.alSourcePlay(source[0]);
223
224     sources.add(new Integer(source[0]));
225 }
226
227 static void setListenerValues() {
228     al.alListenerfv(AL.AL_POSITION,    listenerPos, 0);
229     al.alListenerfv(AL.AL_VELOCITY,    listenerVel, 0);
230     al.alListenerfv(AL.AL_ORIENTATION, listenerOri, 0);
231 }
232 </pre>
233 <p align="justify">Here's the function that will generate the sources for us. 
234   This function will generate a single source for any one of the loaded buffers 
235   we generated in the previous source. Given the buffer index 'type', which is 
236   one of the macros we created right from the start of this tutorial. We do an 
237   error check to make sure we have a source to play (like I said, they are finite). 
238   If a source cannot be allocated then the program will exit.</p>
239 <pre class=code><span class=codeKeyword><font color="#0000FF">static void</font></span><font color="#0000FF"> </font>killALData() {
240
241     Iterator iter = sources.iterator();
242     <span class=codeKeyword><font color="#000000">while</font></span>(iter.hasNext()) {
243         al.alDeleteSources(1, <font color="#0000FF">new int</font>[] { ((Integer)iter.next()).intValue() }, 0);
244     }
245     sources.clear();
246     al.alDeleteBuffers(NUM_BUFFERS, buffers, 0);
247     exitOpenAL();
248 }
249 </pre>
250 <p align="justify">This function has been modified a bit to accommodate the List. 
251   We have to delete each source in the list individually and then clear the list 
252   which will effectively destroy it.</p>
253 <pre class=code>
254   public static void main(String[] args) {
255     try {
256       initOpenAL();
257     } catch (ALException e) {
258       e.printStackTrace();
259       System.exit(1);
260     }
261     if (loadALData() == AL.AL_FALSE)
262       System.exit(1);
263     setListenerValues();
264
265 <font color="#0000FF">    char</font>[] c = <font color="#0000FF">new char</font>[1];
266
267 <font color="#0000FF">    </font><font color="#0000FF">while</font>(c[0] != 'q') {      
268 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">try</font> {
269 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font>BufferedReader buf =
270 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">new</font> BufferedReader(<font color="#0000FF">new</font> InputStreamReader(System.in));
271 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font>System.out.println(&quot;Press a key and hit ENTER: \n&quot; +
272 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">   </font>&quot;\t'w' for Water Drop\n&quot; +
273 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">   </font>&quot;\t't' for Thunder\n&quot; +
274 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">   </font>&quot;\t's' for Stream\n&quot; +
275 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">   </font>&quot;\t'r' for Rain\n&quot; +
276 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">   </font>&quot;\t'o' for Ocean\n&quot; +
277 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">   </font>&quot;\t'c' for Chimes\n&quot; +
278 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">   </font>&quot;\n'q' to Quit\n&quot;);
279 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font>buf.read(c);
280 <font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">    </font><font color="#0000FF">switch</font>(c[0]) {
281 <font color="#0000FF">                case</font> 'w': addSource(WATERDROP); <font color="#0000FF">break</font>;
282 <font color="#0000FF"></font><font color="#0000FF">                case</font> 't': addSource(THUNDER); <font color="#0000FF">break</font>;
283 <font color="#0000FF"></font><font color="#0000FF">                case</font> 's': addSource(STREAM); <font color="#0000FF">break</font>;
284 <font color="#0000FF"></font><font color="#0000FF">                case</font> 'r': addSource(RAIN); <font color="#0000FF">break</font>;
285 <font color="#0000FF"></font><font color="#0000FF">                case</font> 'o': addSource(OCEAN); <font color="#0000FF">break</font>;
286 <font color="#0000FF"></font><font color="#0000FF">                case</font> 'c': addSource(CHIMES); <font color="#0000FF">break</font>;
287 <font color="#0000FF"></font>            }
288 <font color="#0000FF">    </font><font color="#0000FF">    </font>} <font color="#0000FF">catch</font> (IOException e) {
289                         System.exit(1);
290 <font color="#0000FF">    </font><font color="#0000FF">    </font>}
291 <font color="#0000FF">    </font>}
292     killALData();
293   } // main
294 } // class</pre>
295 <p align="justify"> Here is the programs inner loop<!-- taken straight out of our main-->. 
296   Basically it waits for some keyboard input and on certain key hits it will create 
297   a new source of a certain type and add it to the audio scene. Essentially what 
298   we have created here is something like one of those nature tapes that people 
299   listen to for relaxation. Ours is a little better since it allows the user to 
300   customize which sounds that they want in the background. Pretty neat eh? I've 
301   been listening to mine while I code. It's a Zen experience (I'm listening to 
302   it right now).</p>
303 <p align="justify">The program can be expanded for using more wav files, and have 
304   the added feature of placing the sources around the scene in arbitrary positions. 
305   You could even allow for sources to play with a given frequency rather than 
306   have them loop. However this would require GUI routines that go beyond the scope 
307   of the tutorial. A full featured &quot;Weathering Engine&quot; would be a nifty 
308   program to make though. ;)</p>
309 <table border="0" cellspacing="1" style="border-collapse: collapse" width="100%" id="AutoNumber2" bgcolor="#666699">
310   <tr> 
311     <td width="40%"> <p dir="ltr"><font color="#FFFFFF" size="2">© 2003 DevMaster.net. 
312         All rights reserved.</font></td>
313     <td width="60%"> <p align="right" dir="ltr"><font size="2"><a href="mailto:webmaster@devmaster.net"> 
314         <font color="#FFFFFF">Contact us</font></a><font color="#FFFFFF"> if you 
315         want to write for us or for any comments, suggestions, or feedback.</font></font></td>
316   </tr>
317 </table>
318 </body>
319 </html>
http://JogAmp.org git info: FAQ, tutorial and man pages.