comparison org/ear.org @ 29:cdf320cb5949

updated test suite
author Robert McIntyre <rlm@mit.edu>
date Sat, 10 Dec 2011 21:42:50 -0600
parents f4c7260d397a
children 32c69ba451d9
comparison
equal deleted inserted replaced
28:1fc162d84343 29:cdf320cb5949
88 clojure. 88 clojure.
89 89
90 ** =send.c= 90 ** =send.c=
91 91
92 ** Header 92 ** Header
93 #+srcname: send-header 93 #+name: send-header
94 #+begin_src C 94 #+begin_src C
95 #include "config.h" 95 #include "config.h"
96 #include <stdlib.h> 96 #include <stdlib.h>
97 #include "alMain.h" 97 #include "alMain.h"
98 #include "AL/al.h" 98 #include "AL/al.h"
148 which are in the master context. 148 which are in the master context.
149 - =limitContext()= and =unLimitContext()= make it possible to render 149 - =limitContext()= and =unLimitContext()= make it possible to render
150 only one context at a time. 150 only one context at a time.
151 151
152 ** Necessary State 152 ** Necessary State
153 #+srcname: send-state 153 #+name: send-state
154 #+begin_src C 154 #+begin_src C
155 //////////////////// State 155 //////////////////// State
156 156
157 typedef struct context_data { 157 typedef struct context_data {
158 ALfloat ClickRemoval[MAXCHANNELS]; 158 ALfloat ClickRemoval[MAXCHANNELS];
176 parallel. The solution is to create a copy of this normally global 176 parallel. The solution is to create a copy of this normally global
177 device state for each context, and copy it back and forth into and out 177 device state for each context, and copy it back and forth into and out
178 of the actual device state whenever a context is rendered. 178 of the actual device state whenever a context is rendered.
179 179
180 ** Synchronization Macros 180 ** Synchronization Macros
181 #+srcname: sync-macros 181 #+name: sync-macros
182 #+begin_src C 182 #+begin_src C
183 //////////////////// Context Creation / Synchronization 183 //////////////////// Context Creation / Synchronization
184 184
185 #define _MAKE_SYNC(NAME, INIT_EXPR, GET_EXPR, SET_EXPR) \ 185 #define _MAKE_SYNC(NAME, INIT_EXPR, GET_EXPR, SET_EXPR) \
186 void NAME (ALuint sourceID1, ALuint sourceID2, \ 186 void NAME (ALuint sourceID1, ALuint sourceID2, \
219 completely synchronize two sources, it is necessary to use all of 219 completely synchronize two sources, it is necessary to use all of
220 them. These macros help to condense the otherwise repetitive 220 them. These macros help to condense the otherwise repetitive
221 synchronization code involving these similar low-level =OpenAL= functions. 221 synchronization code involving these similar low-level =OpenAL= functions.
222 222
223 ** Source Synchronization 223 ** Source Synchronization
224 #+srcname: sync-sources 224 #+name: sync-sources
225 #+begin_src C 225 #+begin_src C
226 void syncSources(ALsource *masterSource, ALsource *slaveSource, 226 void syncSources(ALsource *masterSource, ALsource *slaveSource,
227 ALCcontext *masterCtx, ALCcontext *slaveCtx){ 227 ALCcontext *masterCtx, ALCcontext *slaveCtx){
228 ALuint master = masterSource->source; 228 ALuint master = masterSource->source;
229 ALuint slave = slaveSource->source; 229 ALuint slave = slaveSource->source;
292 same between the master and slave sources. I'd like to take this 292 same between the master and slave sources. I'd like to take this
293 moment to salute the [[http://connect.creativelabs.com/openal/Documentation/Forms/AllItems.aspx][=OpenAL= Reference Manual]], which provides a very 293 moment to salute the [[http://connect.creativelabs.com/openal/Documentation/Forms/AllItems.aspx][=OpenAL= Reference Manual]], which provides a very
294 good description of =OpenAL='s internals. 294 good description of =OpenAL='s internals.
295 295
296 ** Context Synchronization 296 ** Context Synchronization
297 #+srcname: sync-contexts 297 #+name: sync-contexts
298 #+begin_src C 298 #+begin_src C
299 void syncContexts(ALCcontext *master, ALCcontext *slave){ 299 void syncContexts(ALCcontext *master, ALCcontext *slave){
300 /* If there aren't sufficient sources in slave to mirror 300 /* If there aren't sufficient sources in slave to mirror
301 the sources in master, create them. */ 301 the sources in master, create them. */
302 ALCcontext *current = alcGetCurrentContext(); 302 ALCcontext *current = alcGetCurrentContext();
330 =syncSources()=. The only thing that =syncContexts()= has to worry 330 =syncSources()=. The only thing that =syncContexts()= has to worry
331 about is automatically creating new sources whenever a slave context 331 about is automatically creating new sources whenever a slave context
332 does not have the same number of sources as the master context. 332 does not have the same number of sources as the master context.
333 333
334 ** Context Creation 334 ** Context Creation
335 #+srcname: context-creation 335 #+name: context-creation
336 #+begin_src C 336 #+begin_src C
337 static void addContext(ALCdevice *Device, ALCcontext *context){ 337 static void addContext(ALCdevice *Device, ALCcontext *context){
338 send_data *data = (send_data*)Device->ExtraData; 338 send_data *data = (send_data*)Device->ExtraData;
339 // expand array if necessary 339 // expand array if necessary
340 if (data->numContexts >= data->maxContexts){ 340 if (data->numContexts >= data->maxContexts){
359 device-wide =ExtraData= structure. The =renderBuffer= that is created 359 device-wide =ExtraData= structure. The =renderBuffer= that is created
360 here is where the rendered sound samples for this slave context will 360 here is where the rendered sound samples for this slave context will
361 eventually go. 361 eventually go.
362 362
363 ** Context Switching 363 ** Context Switching
364 #+srcname: context-switching 364 #+name: context-switching
365 #+begin_src C 365 #+begin_src C
366 //////////////////// Context Switching 366 //////////////////// Context Switching
367 367
368 /* A device brings along with it two pieces of state 368 /* A device brings along with it two pieces of state
369 * which have to be swapped in and out with each context. 369 * which have to be swapped in and out with each context.
405 the Device's context list to put the desired context-to-be-rendered 405 the Device's context list to put the desired context-to-be-rendered
406 into position 0, we can get trick =OpenAL= into rendering each slave 406 into position 0, we can get trick =OpenAL= into rendering each slave
407 context separate from all the others. 407 context separate from all the others.
408 408
409 ** Main Device Loop 409 ** Main Device Loop
410 #+srcname: main-loop 410 #+name: main-loop
411 #+begin_src C 411 #+begin_src C
412 //////////////////// Main Device Loop 412 //////////////////// Main Device Loop
413 413
414 /* Establish the LWJGL context as the master context, which will 414 /* Establish the LWJGL context as the master context, which will
415 * be synchronized to all the slave contexts 415 * be synchronized to all the slave contexts
462 a way to transport this information to Java, and also a way to drive 462 a way to transport this information to Java, and also a way to drive
463 this device from Java. The following JNI interface code is inspired 463 this device from Java. The following JNI interface code is inspired
464 by the way LWJGL interfaces with =OpenAL=. 464 by the way LWJGL interfaces with =OpenAL=.
465 465
466 *** step 466 *** step
467 #+srcname: jni-step 467 #+name: jni-step
468 #+begin_src C 468 #+begin_src C
469 //////////////////// JNI Methods 469 //////////////////// JNI Methods
470 470
471 #include "com_aurellem_send_AudioSend.h" 471 #include "com_aurellem_send_AudioSend.h"
472 472
489 simulate 1 second of AI-time would miss almost all of the sound in 489 simulate 1 second of AI-time would miss almost all of the sound in
490 its environment. 490 its environment.
491 491
492 492
493 *** getSamples 493 *** getSamples
494 #+srcname: jni-get-samples 494 #+name: jni-get-samples
495 #+begin_src C 495 #+begin_src C
496 /* 496 /*
497 * Class: com_aurellem_send_AudioSend 497 * Class: com_aurellem_send_AudioSend
498 * Method: ngetSamples 498 * Method: ngetSamples
499 * Signature: (JLjava/nio/ByteBuffer;III)V 499 * Signature: (JLjava/nio/ByteBuffer;III)V
520 520
521 =addListener=, =setNthListenerf=, and =setNthListener3f= are 521 =addListener=, =setNthListenerf=, and =setNthListener3f= are
522 necessary to change the properties of any listener other than the 522 necessary to change the properties of any listener other than the
523 master one, since only the listener of the current active context is 523 master one, since only the listener of the current active context is
524 affected by the normal =OpenAL= listener calls. 524 affected by the normal =OpenAL= listener calls.
525 #+srcname: listener-manage 525 #+name: listener-manage
526 #+begin_src C 526 #+begin_src C
527 /* 527 /*
528 * Class: com_aurellem_send_AudioSend 528 * Class: com_aurellem_send_AudioSend
529 * Method: naddListener 529 * Method: naddListener
530 * Signature: (J)V 530 * Signature: (J)V
587 587
588 =getAudioFormat= is a convenience function that uses JNI to build up a 588 =getAudioFormat= is a convenience function that uses JNI to build up a
589 =javax.sound.sampled.AudioFormat= object from data in the Device. This 589 =javax.sound.sampled.AudioFormat= object from data in the Device. This
590 way, there is no ambiguity about what the bits created by =step= and 590 way, there is no ambiguity about what the bits created by =step= and
591 returned by =getSamples= mean. 591 returned by =getSamples= mean.
592 #+srcname: jni-init 592 #+name: jni-init
593 #+begin_src C 593 #+begin_src C
594 /* 594 /*
595 * Class: com_aurellem_send_AudioSend 595 * Class: com_aurellem_send_AudioSend
596 * Method: ninitDevice 596 * Method: ninitDevice
597 * Signature: (J)V 597 * Signature: (J)V
640 #+end_src 640 #+end_src
641 641
642 ** Boring Device management stuff 642 ** Boring Device management stuff
643 This code is more-or-less copied verbatim from the other =OpenAL= 643 This code is more-or-less copied verbatim from the other =OpenAL=
644 backends. It's the basis for =OpenAL='s primitive object system. 644 backends. It's the basis for =OpenAL='s primitive object system.
645 #+srcname: device-init 645 #+name: device-init
646 #+begin_src C 646 #+begin_src C
647 //////////////////// Device Initialization / Management 647 //////////////////// Device Initialization / Management
648 648
649 static const ALCchar sendDevice[] = "Multiple Audio Send"; 649 static const ALCchar sendDevice[] = "Multiple Audio Send";
650 650
747 simple. Just as there were =SceneProcessors= for vision, there are 747 simple. Just as there were =SceneProcessors= for vision, there are
748 now =SoundProcessors= for hearing. 748 now =SoundProcessors= for hearing.
749 749
750 #+include "../../jmeCapture/src/com/aurellem/capture/audio/SoundProcessor.java" src java 750 #+include "../../jmeCapture/src/com/aurellem/capture/audio/SoundProcessor.java" src java
751 751
752 #+srcname: ears 752 #+name: ears
753 #+begin_src clojure 753 #+begin_src clojure
754 (ns cortex.hearing 754 (ns cortex.hearing
755 "Simulate the sense of hearing in jMonkeyEngine3. Enables multiple 755 "Simulate the sense of hearing in jMonkeyEngine3. Enables multiple
756 listeners at different positions in the same world. Passes vectors 756 listeners at different positions in the same world. Passes vectors
757 of floats in the range [-1.0 -- 1.0] in PCM format to any arbitrary 757 of floats in the range [-1.0 -- 1.0] in PCM format to any arbitrary
793 listener)) 793 listener))
794 #+end_src 794 #+end_src
795 795
796 * Example 796 * Example
797 797
798 #+srcname: test-hearing 798 #+name: test-hearing
799 #+begin_src clojure :results silent 799 #+begin_src clojure :results silent
800 (ns test.hearing 800 (ns cortex.test.hearing
801 (:use (cortex world util hearing)) 801 (:use (cortex world util hearing))
802 (:import (com.jme3.audio AudioNode Listener)) 802 (:import (com.jme3.audio AudioNode Listener))
803 (:import com.jme3.scene.Node)) 803 (:import com.jme3.scene.Node
804 com.jme3.system.AppSettings))
804 805
805 (defn setup-fn [world] 806 (defn setup-fn [world]
806 (let [listener (Listener.)] 807 (let [listener (Listener.)]
807 (add-ear world listener #(println-repl (nth % 0))))) 808 (add-ear world listener #(println-repl (nth % 0)))))
808 809
810 (if (not value) 811 (if (not value)
811 (do 812 (do
812 (.playSource (.getAudioRenderer world) node)))) 813 (.playSource (.getAudioRenderer world) node))))
813 814
814 (defn test-basic-hearing [] 815 (defn test-basic-hearing []
815 (.start
816 (let [node1 (AudioNode. (asset-manager) "Sounds/pure.wav" false false)] 816 (let [node1 (AudioNode. (asset-manager) "Sounds/pure.wav" false false)]
817 (world 817 (world
818 (Node.) 818 (Node.)
819 {"key-space" (partial play-sound node1)} 819 {"key-space" (partial play-sound node1)}
820 setup-fn 820 setup-fn
821 no-op)))) 821 no-op)))
822
823 (defn test-advanced-hearing
824 "Testing hearing:
825 You should see a blue sphere flying around several
826 cubes. As the sphere approaches each cube, it turns
827 green."
828 []
829 (doto (com.aurellem.capture.examples.Advanced.)
830 (.setSettings
831 (doto (AppSettings. true)
832 (.setAudioRenderer "Send")))
833 (.setShowSettings false)
834 (.setPauseOnLostFocus false)))
835
822 #+end_src 836 #+end_src
823 837
824 This extremely basic program prints out the first sample it encounters 838 This extremely basic program prints out the first sample it encounters
825 at every time stamp. You can see the rendered sound begin printed at 839 at every time stamp. You can see the rendered sound being printed at
826 the REPL. 840 the REPL.
827 841
828 - As a bonus, this method of capturing audio for AI can also be used 842 - As a bonus, this method of capturing audio for AI can also be used
829 to capture perfect audio from a jMonkeyEngine application, for use 843 to capture perfect audio from a jMonkeyEngine application, for use
830 in demos and the like. 844 in demos and the like.
834 848
835 #+begin_src clojure :tangle ../../cortex/src/cortex/hearing.clj 849 #+begin_src clojure :tangle ../../cortex/src/cortex/hearing.clj
836 <<ears>> 850 <<ears>>
837 #+end_src 851 #+end_src
838 852
839 #+begin_src clojure :tangle ../../cortex/src/test/hearing.clj 853 #+begin_src clojure :tangle ../../cortex/src/cortex/test/hearing.clj
840 <<test-hearing>> 854 <<test-hearing>>
841 #+end_src 855 #+end_src
842
843 856
844 #+begin_src C :tangle ../Alc/backends/send.c 857 #+begin_src C :tangle ../Alc/backends/send.c
845 <<send-header>> 858 <<send-header>>
846 <<send-state>> 859 <<send-state>>
847 <<sync-macros>> 860 <<sync-macros>>