| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]--><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Asciidoctor 1.5.4"><title>Capture Audio/Video to a File</title><link rel="stylesheet" href="./asciidoctor.css">
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css">
- <link rel="stylesheet" href="./coderay-asciidoctor.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css"><link rel="stylesheet" href="/home/travis/build/jMonkeyEngine/wiki/build/asciidoc/html5/jme3/advanced/twemoji-awesome.css"></head><body class="article toc2 toc-left"><div id="header"><div id="toolbar"><a href="https://github.com/jMonkeyEngine/wiki/edit/master/src/docs/asciidoc/jme3/advanced/capture_audio_video_to_a_file.adoc"><i class="fa fa-pencil-square" aria-hidden="true"></i></a><a href="https://github.com/jMonkeyEngine/wiki/new/master/src/docs/asciidoc/jme3/advanced/"><i class="fa fa-plus-square" aria-hidden="true"></i></a><input dir="auto" style="position: relative; vertical-align: top;" spellcheck="false" autocomplete="off" class="searchbox__input aa-input" id="doc-search" name="search" placeholder="Search in the doc" required="required" type="search"></div><h1>Capture Audio/Video to a File</h1><div class="details"><span class="author" id="author"></span><br><span id="revnumber">version ,</span> <span id="revdate">2016/03/17 20:48</span></div><div id="toc" class="toc2"><div id="toctitle">Table of Contents</div><ul class="sectlevel1"><li><a href="#simple-way">Simple Way</a></li><li><a href="#advanced-way">Advanced Way</a><ul class="sectlevel2"><li><a href="#basic-example">Basic Example</a></li><li><a href="#how-it-works">How it works</a></li><li><a href="#advanced-example">Advanced Example</a></li><li><a href="#using-advanced-features-to-record-from-more-than-one-perspective-at-once">Using Advanced features to Record from more than one perspective at once</a></li></ul></li><li><a href="#more-information">More Information</a></li></ul></div></div><div id="content"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p>So you’ve made your cool new JMonkeyEngine3 game and you want to
- create a demo video to show off your hard work. Or maybe you want to
- make a cutscene for your game using the physics and characters in the
- game itself. Screen capturing is the most straightforward way to do
- this, but it can slow down your game and produce low-quality video and
- audio as a result. A better way is to record video and audio directly
- from the game while it is running using VideoRecorderAppState.</p></div>
- <div class="admonitionblock tip"><table><tr><td class="icon"><i class="fa icon-tip" title="Tip"></i></td><td class="content"><div class="paragraph"><p>Combine this method with jMonkeyEngine’s
- <a href="../../jme3/advanced/cinematics.html">Cinematics</a>
- feature to record high-quality game trailers!</p></div></td></tr></table></div></div></div>
- <div class="sect1"><h2 id="simple-way">Simple Way</h2><div class="sectionbody"><div class="paragraph"><p>First off, if all you need is to record video at 30fps with no sound, then look
- no further than jMonkeyEngine 3’s built in <code>VideoRecorderAppState</code>
- class.</p></div>
- <div class="paragraph"><p>Add the following code to your <code>simpleInitApp()</code> method.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">stateManager.attach(<span class="keyword">new</span> VideoRecorderAppState()); <span class="comment">//start recording</span></code></pre></div></div>
- <div class="paragraph"><p>The game will run slow, but the recording will be in high-quality and
- normal speed. Recording starts when the state is
- attached, and ends when the application quits or the state is detached.</p></div>
- <div class="paragraph"><p>The video files will be stored in your <strong>user home directory</strong>.
- If you want to save to another path, specify a File object in the
- VideoRecorderAppState constructor.</p></div>
- <div class="paragraph"><p>That’s all!</p></div></div></div>
- <div class="sect2"><h3 id="advanced-way">Advanced Way</h3><div class="admonitionblock note"><table><tr><td class="icon"><i class="fa icon-note" title="Note"></i></td><td class="content"><div class="paragraph"><p>This way of A/V recording is still in development.
- It works for all of jMonkeyEngine’s test cases.
- If you experience any problems or
- if something isn’t clear, please <a href="http://jmonkeyengine.org/members/bortreb/">let me know</a>. – bortreb</p></div></td></tr></table></div>
- <div class="paragraph"><p>If you want to record audio as well, record at different framerates,
- or record from multiple viewpoints at once, then there’s a full
- solution for doing this already made for you here:</p></div>
- <div class="paragraph"><p><a href="http://www.aurellem.com/releases/jmeCapture-latest.zip">http://www.aurellem.com/releases/jmeCapture-latest.zip</a></p></div>
- <div class="paragraph"><p><a href="http://www.aurellem.com/releases/jmeCapture-latest.tar.bz2">http://www.aurellem.com/releases/jmeCapture-latest.tar.bz2</a></p></div>
- <div class="paragraph"><p>Download the archive in your preferred format, extract,
- add the jars to your project, and you are ready to go.</p></div>
- <div class="paragraph"><p>The javadoc is here:
- <a href="http://www.aurellem.com/jmeCapture/docs/">http://www.aurellem.com/jmeCapture/docs/</a></p></div>
- <div class="paragraph"><p>To capture video and audio you use the
- <code>com.aurellem.capture.Capture</code> class, which has two methods,
- <code>captureAudio()</code> and <code>captureVideo()</code>, and the
- <code>com.aurellem.capture.IsoTimer</code> class, which sets the audio and
- video framerate.</p></div>
- <div class="paragraph"><p>The steps are:</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">yourApp.setTimer(<span class="keyword">new</span> IsoTimer(desiredFramesPerSecond));</code></pre></div></div>
- <div class="paragraph"><p>This causes jMonkeyEngine to take as much time as it needs to fully
- calculate every frame of the video and audio. You will see your game
- speed up and slow down depending on how computationally demanding your
- game is, but the final recorded audio and video will be perfectly
- sychronized and will run at exactly the fps which you specified.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">captureVideo(yourApp, targetVideoFile);
- captureAudio(yourApp, targetAudioFile);</code></pre></div></div>
- <div class="paragraph"><p>These will cause the app to record audio and video when it is run.
- Audio and video will stop being recorded when the app stops. Your
- audio will be recorded as a 44,100 Hz linear PCM wav file, while the
- video will be recorded according to the following rules:</p></div>
- <div class="paragraph"><p>1.) (Preferred) If you supply an empty directory as the file, then
- the video will be saved as a sequence of .png files, one file per
- frame. The files start at 0000000.png and increment from there.
- You can then combine the frames into your preferred
- container/codec. If the directory is not empty, then writing
- video frames to it will fail, and nothing will be written.</p></div>
- <div class="paragraph"><p>2.) If the filename ends in “.avi then the frames will be encoded as
- a RAW stream inside an AVI 1.0 container. The resulting file
- will be quite large and you will probably want to re-encode it to
- your preferred container/codec format. Be advised that some
- video payers cannot process AVI with a RAW stream, and that AVI
- 1.0 files generated by this method that exceed 2.0GB are invalid
- according to the AVI 1.0 <abbr title="specification">spec</abbr> (but many programs can still deal
- with them.) Thanks to
- <a href="http://www.randelshofer.ch/blog/2008/08/writing-avi-videos-in-pure-java/">Werner Randelshofer</a>
- for his excellent work which made the AVI file writer option possible.</p></div>
- <div class="paragraph"><p>3.) Any non-directory file ending in anything other than “.avi will
- be processed through Xuggle. Xuggle provides the option to use
- many codecs/containers, but you will have to install it on your
- system yourself in order to use this option. Please visit
- <a href="http://www.xuggle.com/">http://www.xuggle.com/</a> to learn how to do this.</p></div>
- <div class="paragraph"><p>Note that you will not hear any sound if you choose to record sound to
- a file.</p></div>
- <div class="sect2"><h3 id="basic-example">Basic Example</h3><div class="paragraph"><p>Here is a complete example showing how to capture both audio and video
- from one of jMonkeyEngine3’s advanced demo applications.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">import</span> <span class="include">java.io.File</span>;
- <span class="keyword">import</span> <span class="include">java.io.IOException</span>;
- <span class="keyword">import</span> <span class="include">jme3test.water.TestPostWater</span>;
- <span class="keyword">import</span> <span class="include">com.aurellem.capture.Capture</span>;
- <span class="keyword">import</span> <span class="include">com.aurellem.capture.IsoTimer</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.app.SimpleApplication</span>;
- <span class="comment">/**
- * Demonstrates how to use basic Audio/Video capture with a
- * jMonkeyEngine application. You can use these techniques to make
- * high quality cutscenes or demo videos, even on very slow laptops.
- *
- * @author Robert McIntyre
- */</span>
- <span class="directive">public</span> <span class="type">class</span> <span class="class">Basic</span> {
- <span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span><span class="type">[]</span> ignore) <span class="directive">throws</span> <span class="exception">IOException</span>{
- <span class="predefined-type">File</span> video = <span class="predefined-type">File</span>.createTempFile(<span class="string"><span class="delimiter">"</span><span class="content">JME-water-video</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">.avi</span><span class="delimiter">"</span></span>);
- <span class="predefined-type">File</span> audio = <span class="predefined-type">File</span>.createTempFile(<span class="string"><span class="delimiter">"</span><span class="content">JME-water-audio</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">.wav</span><span class="delimiter">"</span></span>);
- SimpleApplication app = <span class="keyword">new</span> TestPostWater();
- app.setTimer(<span class="keyword">new</span> IsoTimer(<span class="integer">60</span>));
- app.setShowSettings(<span class="predefined-constant">false</span>);
- Capture.captureVideo(app, video);
- Capture.captureAudio(app, audio);
- app.start();
- <span class="predefined-type">System</span>.out.println(video.getCanonicalPath());
- <span class="predefined-type">System</span>.out.println(audio.getCanonicalPath());
- }
- }</code></pre></div></div></div>
- <div class="sect2"><h3 id="how-it-works">How it works</h3><div class="paragraph"><p>A standard JME3 application that extends <code>SimpleApplication</code> or
- <code>Application</code> tries as hard as it can to keep in sync with
- <em>user-time</em>. If a ball is rolling at 1 game-mile per game-hour in the
- game, and you wait for one user-hour as measured by the clock on your
- wall, then the ball should have traveled exactly one game-mile. In
- order to keep sync with the real world, the game throttles its physics
- engine and graphics display. If the computations involved in running
- the game are too intense, then the game will first skip frames, then
- sacrifice physics accuracy. If there are particuraly demanding
- computations, then you may only get 1 fps, and the ball may tunnel
- through the floor or obstacles due to inaccurate physics simulation,
- but after the end of one user-hour, that ball will have traveled one
- game-mile.</p></div>
- <div class="paragraph"><p>When we’re recording video, we don’t care if the game-time syncs with
- user-time, but instead whether the time in the recorded video
- (video-time) syncs with user-time. To continue the analogy, if we
- recorded the ball rolling at 1 game-mile per game-hour and watched the
- video later, we would want to see 30 fps video of the ball rolling at
- 1 video-mile per <em>user-hour</em>. It doesn’t matter how much user-time it
- took to simulate that hour of game-time to make the high-quality
- recording.</p></div>
- <div class="paragraph"><p>The IsoTimer ignores real-time and always reports that the same amount
- of time has passed every time it is called. That way, one can put code
- to write each video/audio frame to a file without worrying about that
- code itself slowing down the game to the point where the recording
- would be useless.</p></div></div>
- <div class="sect2"><h3 id="advanced-example">Advanced Example</h3><div class="paragraph"><p>The package from aurellem.com was made for AI research and can do more
- than just record a single stream of audio and video. You can use it
- to:</p></div>
- <div class="paragraph"><p>1.) Create multiple independent listeners that each hear the world
- from their own perspective.</p></div>
- <div class="paragraph"><p>2.) Process the sound data in any way you wish.</p></div>
- <div class="paragraph"><p>3.) Do the same for visual data.</p></div>
- <div class="paragraph"><p>Here is a more advanced example, which can also be found along with
- other examples in the jmeCapture.jar file included in the
- distribution.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">com.aurellem.capture.examples</span>;
- <span class="keyword">import</span> <span class="include">java.io.File</span>;
- <span class="keyword">import</span> <span class="include">java.io.IOException</span>;
- <span class="keyword">import</span> <span class="include">java.lang.reflect.Field</span>;
- <span class="keyword">import</span> <span class="include">java.nio.ByteBuffer</span>;
- <span class="keyword">import</span> <span class="include">javax.sound.sampled.AudioFormat</span>;
- <span class="keyword">import</span> <span class="include">org.tritonus.share.sampled.FloatSampleTools</span>;
- <span class="keyword">import</span> <span class="include">com.aurellem.capture.AurellemSystemDelegate</span>;
- <span class="keyword">import</span> <span class="include">com.aurellem.capture.Capture</span>;
- <span class="keyword">import</span> <span class="include">com.aurellem.capture.IsoTimer</span>;
- <span class="keyword">import</span> <span class="include">com.aurellem.capture.audio.CompositeSoundProcessor</span>;
- <span class="keyword">import</span> <span class="include">com.aurellem.capture.audio.MultiListener</span>;
- <span class="keyword">import</span> <span class="include">com.aurellem.capture.audio.SoundProcessor</span>;
- <span class="keyword">import</span> <span class="include">com.aurellem.capture.audio.WaveFileWriter</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.app.SimpleApplication</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.audio.AudioNode</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.audio.Listener</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.cinematic.MotionPath</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.cinematic.events.AbstractCinematicEvent</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.cinematic.events.MotionTrack</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.material.Material</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.math.ColorRGBA</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.math.FastMath</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.math.Quaternion</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.math.Vector3f</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.scene.Geometry</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.scene.Node</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.scene.shape.Box</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.scene.shape.Sphere</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.system.AppSettings</span>;
- <span class="keyword">import</span> <span class="include">com.jme3.system.JmeSystem</span>;
- <span class="comment">/**
- *
- * Demonstrates advanced use of the audio capture and recording
- * features. Multiple perspectives of the same scene are
- * simultaneously rendered to different sound files.
- *
- * A key limitation of the way multiple listeners are implemented is
- * that only 3D positioning effects are realized for listeners other
- * than the main LWJGL listener. This means that audio effects such
- * as environment settings will *not* be heard on any auxiliary
- * listeners, though sound attenuation will work correctly.
- *
- * Multiple listeners as realized here might be used to make AI
- * entities that can each hear the world from their own perspective.
- *
- * @author Robert McIntyre
- */</span>
- <span class="directive">public</span> <span class="type">class</span> <span class="class">Advanced</span> <span class="directive">extends</span> SimpleApplication {
- <span class="comment">/**
- * You will see three grey cubes, a blue sphere, and a path which
- * circles each cube. The blue sphere is generating a constant
- * monotone sound as it moves along the track. Each cube is
- * listening for sound; when a cube hears sound whose intensity is
- * greater than a certain threshold, it changes its color from
- * grey to green.
- *
- * Each cube is also saving whatever it hears to a file. The
- * scene from the perspective of the viewer is also saved to a
- * video file. When you listen to each of the sound files
- * alongside the video, the sound will get louder when the sphere
- * approaches the cube that generated that sound file. This
- * shows that each listener is hearing the world from its own
- * perspective.
- *
- */</span>
- <span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span><span class="type">[]</span> args) {
- Advanced app = <span class="keyword">new</span> Advanced();
- AppSettings settings = <span class="keyword">new</span> AppSettings(<span class="predefined-constant">true</span>);
- settings.setAudioRenderer(AurellemSystemDelegate.SEND);
- JmeSystem.setSystemDelegate(<span class="keyword">new</span> AurellemSystemDelegate());
- app.setSettings(settings);
- app.setShowSettings(<span class="predefined-constant">false</span>);
- app.setPauseOnLostFocus(<span class="predefined-constant">false</span>);
- <span class="keyword">try</span> {
- Capture.captureVideo(app, <span class="predefined-type">File</span>.createTempFile(<span class="string"><span class="delimiter">"</span><span class="content">advanced</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">.avi</span><span class="delimiter">"</span></span>));
- Capture.captureAudio(app, <span class="predefined-type">File</span>.createTempFile(<span class="string"><span class="delimiter">"</span><span class="content">advanced</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">.wav</span><span class="delimiter">"</span></span>));
- }
- <span class="keyword">catch</span> (<span class="exception">IOException</span> e) {e.printStackTrace();}
- app.start();
- }
- <span class="directive">private</span> Geometry bell;
- <span class="directive">private</span> Geometry ear1;
- <span class="directive">private</span> Geometry ear2;
- <span class="directive">private</span> Geometry ear3;
- <span class="directive">private</span> AudioNode music;
- <span class="directive">private</span> MotionTrack motionControl;
- <span class="directive">private</span> IsoTimer motionTimer = <span class="keyword">new</span> IsoTimer(<span class="integer">60</span>);
- <span class="directive">private</span> Geometry makeEar(Node root, Vector3f position){
- Material mat = <span class="keyword">new</span> Material(assetManager, <span class="string"><span class="delimiter">"</span><span class="content">Common/MatDefs/Misc/Unshaded.j3md</span><span class="delimiter">"</span></span>);
- Geometry ear = <span class="keyword">new</span> Geometry(<span class="string"><span class="delimiter">"</span><span class="content">ear</span><span class="delimiter">"</span></span>, <span class="keyword">new</span> <span class="predefined-type">Box</span>(<span class="float">1.0f</span>, <span class="float">1.0f</span>, <span class="float">1.0f</span>));
- ear.setLocalTranslation(position);
- mat.setColor(<span class="string"><span class="delimiter">"</span><span class="content">Color</span><span class="delimiter">"</span></span>, ColorRGBA.Green);
- ear.setMaterial(mat);
- root.attachChild(ear);
- <span class="keyword">return</span> ear;
- }
- <span class="directive">private</span> Vector3f<span class="type">[]</span> path = <span class="keyword">new</span> Vector3f<span class="type">[]</span>{
- <span class="comment">// loop 1</span>
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, <span class="integer">0</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, -<span class="integer">10</span>),
- <span class="keyword">new</span> Vector3f(-<span class="integer">2</span>, <span class="integer">0</span>, -<span class="integer">14</span>),
- <span class="keyword">new</span> Vector3f(-<span class="integer">6</span>, <span class="integer">0</span>, -<span class="integer">20</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, -<span class="integer">26</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">6</span>, <span class="integer">0</span>, -<span class="integer">20</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, -<span class="integer">14</span>),
- <span class="keyword">new</span> Vector3f(-<span class="integer">6</span>, <span class="integer">0</span>, -<span class="integer">20</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, -<span class="integer">26</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">6</span>, <span class="integer">0</span>, -<span class="integer">20</span>),
- <span class="comment">// loop 2</span>
- <span class="keyword">new</span> Vector3f(<span class="integer">5</span>, <span class="integer">0</span>, -<span class="integer">5</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">7</span>, <span class="integer">0</span>, <span class="float">1.5f</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">14</span>, <span class="integer">0</span>, <span class="integer">2</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">20</span>, <span class="integer">0</span>, <span class="integer">6</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">26</span>, <span class="integer">0</span>, <span class="integer">0</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">20</span>, <span class="integer">0</span>, -<span class="integer">6</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">14</span>, <span class="integer">0</span>, <span class="integer">0</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">20</span>, <span class="integer">0</span>, <span class="integer">6</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">26</span>, <span class="integer">0</span>, <span class="integer">0</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">20</span>, <span class="integer">0</span>, -<span class="integer">6</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">14</span>, <span class="integer">0</span>, <span class="integer">0</span>),
- <span class="comment">// loop 3</span>
- <span class="keyword">new</span> Vector3f(<span class="integer">8</span>, <span class="integer">0</span>, <span class="float">7.5f</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">7</span>, <span class="integer">0</span>, <span class="float">10.5f</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">6</span>, <span class="integer">0</span>, <span class="integer">20</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, <span class="integer">26</span>),
- <span class="keyword">new</span> Vector3f(-<span class="integer">6</span>, <span class="integer">0</span>, <span class="integer">20</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, <span class="integer">14</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">6</span>, <span class="integer">0</span>, <span class="integer">20</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, <span class="integer">26</span>),
- <span class="keyword">new</span> Vector3f(-<span class="integer">6</span>, <span class="integer">0</span>, <span class="integer">20</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, <span class="integer">14</span>),
- <span class="comment">// begin ellipse</span>
- <span class="keyword">new</span> Vector3f(<span class="integer">16</span>, <span class="integer">5</span>, <span class="integer">20</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, <span class="integer">26</span>),
- <span class="keyword">new</span> Vector3f(-<span class="integer">16</span>, -<span class="integer">10</span>, <span class="integer">20</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, <span class="integer">14</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">16</span>, <span class="integer">20</span>, <span class="integer">20</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span>, <span class="integer">26</span>),
- <span class="keyword">new</span> Vector3f(-<span class="integer">10</span>, -<span class="integer">25</span>, <span class="integer">10</span>),
- <span class="keyword">new</span> Vector3f(-<span class="integer">10</span>, <span class="integer">0</span>, <span class="integer">0</span>),
- <span class="comment">// come at me!</span>
- <span class="keyword">new</span> Vector3f(-<span class="float">28.00242f</span>, <span class="float">48.005623f</span>, -<span class="float">34.648228f</span>),
- <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span> , -<span class="integer">20</span>),
- };
- <span class="directive">private</span> <span class="type">void</span> createScene() {
- Material mat = <span class="keyword">new</span> Material(assetManager, <span class="string"><span class="delimiter">"</span><span class="content">Common/MatDefs/Misc/Unshaded.j3md</span><span class="delimiter">"</span></span>);
- bell = <span class="keyword">new</span> Geometry( <span class="string"><span class="delimiter">"</span><span class="content">sound-emitter</span><span class="delimiter">"</span></span> , <span class="keyword">new</span> Sphere(<span class="integer">15</span>,<span class="integer">15</span>,<span class="integer">1</span>));
- mat.setColor(<span class="string"><span class="delimiter">"</span><span class="content">Color</span><span class="delimiter">"</span></span>, ColorRGBA.Blue);
- bell.setMaterial(mat);
- rootNode.attachChild(bell);
- ear1 = makeEar(rootNode, <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span> ,-<span class="integer">20</span>));
- ear2 = makeEar(rootNode, <span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="integer">0</span> ,<span class="integer">20</span>));
- ear3 = makeEar(rootNode, <span class="keyword">new</span> Vector3f(<span class="integer">20</span>, <span class="integer">0</span> ,<span class="integer">0</span>));
- MotionPath track = <span class="keyword">new</span> MotionPath();
- <span class="keyword">for</span> (Vector3f v : path){
- track.addWayPoint(v);
- }
- track.setCurveTension(<span class="float">0.80f</span>);
- motionControl = <span class="keyword">new</span> MotionTrack(bell,track);
- <span class="comment">// for now, use reflection to change the timer...</span>
- <span class="comment">// motionControl.setTimer(new IsoTimer(60));</span>
- <span class="keyword">try</span> {
- <span class="predefined-type">Field</span> timerField;
- timerField = AbstractCinematicEvent.class.getDeclaredField(<span class="string"><span class="delimiter">"</span><span class="content">timer</span><span class="delimiter">"</span></span>);
- timerField.setAccessible(<span class="predefined-constant">true</span>);
- <span class="keyword">try</span> {timerField.set(motionControl, motionTimer);}
- <span class="keyword">catch</span> (<span class="exception">IllegalArgumentException</span> e) {e.printStackTrace();}
- <span class="keyword">catch</span> (<span class="exception">IllegalAccessException</span> e) {e.printStackTrace();}
- }
- <span class="keyword">catch</span> (<span class="exception">SecurityException</span> e) {e.printStackTrace();}
- <span class="keyword">catch</span> (<span class="exception">NoSuchFieldException</span> e) {e.printStackTrace();}
- motionControl.setDirectionType(MotionTrack.Direction.PathAndRotation);
- motionControl.setRotation(<span class="keyword">new</span> Quaternion().fromAngleNormalAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y));
- motionControl.setInitialDuration(<span class="float">20f</span>);
- motionControl.setSpeed(<span class="float">1f</span>);
- track.enableDebugShape(assetManager, rootNode);
- positionCamera();
- }
- <span class="directive">private</span> <span class="type">void</span> positionCamera(){
- <span class="local-variable">this</span>.cam.setLocation(<span class="keyword">new</span> Vector3f(-<span class="float">28.00242f</span>, <span class="float">48.005623f</span>, -<span class="float">34.648228f</span>));
- <span class="local-variable">this</span>.cam.setRotation(<span class="keyword">new</span> Quaternion(<span class="float">0.3359635f</span>, <span class="float">0.34280345f</span>, -<span class="float">0.13281013f</span>, <span class="float">0.8671653f</span>));
- }
- <span class="directive">private</span> <span class="type">void</span> initAudio() {
- org.lwjgl.input.Mouse.setGrabbed(<span class="predefined-constant">false</span>);
- music = <span class="keyword">new</span> AudioNode(assetManager, <span class="string"><span class="delimiter">"</span><span class="content">Sound/Effects/Beep.ogg</span><span class="delimiter">"</span></span>, <span class="predefined-constant">false</span>);
- rootNode.attachChild(music);
- audioRenderer.playSource(music);
- music.setPositional(<span class="predefined-constant">true</span>);
- music.setVolume(<span class="float">1f</span>);
- music.setReverbEnabled(<span class="predefined-constant">false</span>);
- music.setDirectional(<span class="predefined-constant">false</span>);
- music.setMaxDistance(<span class="float">200.0f</span>);
- music.setRefDistance(<span class="float">1f</span>);
- <span class="comment">//music.setRolloffFactor(1f);</span>
- music.setLooping(<span class="predefined-constant">false</span>);
- audioRenderer.pauseSource(music);
- }
- <span class="directive">public</span> <span class="type">class</span> <span class="class">Dancer</span> <span class="directive">implements</span> SoundProcessor {
- Geometry entity;
- <span class="type">float</span> scale = <span class="integer">2</span>;
- <span class="directive">public</span> Dancer(Geometry entity){
- <span class="local-variable">this</span>.entity = entity;
- }
- <span class="comment">/**
- * this method is irrelevant since there is no state to cleanup.
- */</span>
- <span class="directive">public</span> <span class="type">void</span> cleanup() {}
- <span class="comment">/**
- * Respond to sound! This is the brain of an AI entity that
- * hears its surroundings and reacts to them.
- */</span>
- <span class="directive">public</span> <span class="type">void</span> process(<span class="predefined-type">ByteBuffer</span> audioSamples, <span class="type">int</span> numSamples, <span class="predefined-type">AudioFormat</span> format) {
- audioSamples.clear();
- <span class="type">byte</span><span class="type">[]</span> data = <span class="keyword">new</span> <span class="type">byte</span>[numSamples];
- <span class="type">float</span><span class="type">[]</span> out = <span class="keyword">new</span> <span class="type">float</span>[numSamples];
- audioSamples.get(data);
- FloatSampleTools.byte2floatInterleaved(data, <span class="integer">0</span>, out, <span class="integer">0</span>,
- numSamples/format.getFrameSize(), format);
- <span class="type">float</span> max = <span class="predefined-type">Float</span>.NEGATIVE_INFINITY;
- <span class="keyword">for</span> (<span class="type">float</span> f : out){<span class="keyword">if</span> (f > max) max = f;}
- audioSamples.clear();
- <span class="keyword">if</span> (max > <span class="float">0.1</span>){entity.getMaterial().setColor(<span class="string"><span class="delimiter">"</span><span class="content">Color</span><span class="delimiter">"</span></span>, ColorRGBA.Green);}
- <span class="keyword">else</span> {entity.getMaterial().setColor(<span class="string"><span class="delimiter">"</span><span class="content">Color</span><span class="delimiter">"</span></span>, ColorRGBA.Gray);}
- }
- }
- <span class="directive">private</span> <span class="type">void</span> prepareEar(Geometry ear, <span class="type">int</span> n){
- <span class="keyword">if</span> (<span class="local-variable">this</span>.audioRenderer <span class="keyword">instanceof</span> MultiListener){
- MultiListener rf = (MultiListener)<span class="local-variable">this</span>.audioRenderer;
- Listener auxListener = <span class="keyword">new</span> Listener();
- auxListener.setLocation(ear.getLocalTranslation());
- rf.addListener(auxListener);
- WaveFileWriter aux = <span class="predefined-constant">null</span>;
- <span class="keyword">try</span> {aux = <span class="keyword">new</span> WaveFileWriter(<span class="predefined-type">File</span>.createTempFile(<span class="string"><span class="delimiter">"</span><span class="content">advanced-audio-</span><span class="delimiter">"</span></span> + n, <span class="string"><span class="delimiter">"</span><span class="content">.wav</span><span class="delimiter">"</span></span>));}
- <span class="keyword">catch</span> (<span class="exception">IOException</span> e) {e.printStackTrace();}
- rf.registerSoundProcessor(auxListener,
- <span class="keyword">new</span> CompositeSoundProcessor(<span class="keyword">new</span> Dancer(ear), aux));
- }
- }
- <span class="directive">public</span> <span class="type">void</span> simpleInitApp() {
- <span class="local-variable">this</span>.setTimer(<span class="keyword">new</span> IsoTimer(<span class="integer">60</span>));
- initAudio();
- createScene();
- prepareEar(ear1, <span class="integer">1</span>);
- prepareEar(ear2, <span class="integer">1</span>);
- prepareEar(ear3, <span class="integer">1</span>);
- motionControl.play();
- }
- <span class="directive">public</span> <span class="type">void</span> simpleUpdate(<span class="type">float</span> tpf) {
- motionTimer.update();
- <span class="keyword">if</span> (music.getStatus() != AudioSource.Status.Playing){
- music.play();
- }
- Vector3f loc = cam.getLocation();
- Quaternion rot = cam.getRotation();
- listener.setLocation(loc);
- listener.setRotation(rot);
- music.setLocalTranslation(bell.getLocalTranslation());
- }
- }</code></pre></div></div>
- <div class="paragraph"><p><span class="image"><img src="http://www.youtube.com/v/oCEfK0yhDrY?.swf" alt="oCEfK0yhDrY?.swf" width="400" height=""></span></p></div></div>
- <div class="sect2"><h3 id="using-advanced-features-to-record-from-more-than-one-perspective-at-once">Using Advanced features to Record from more than one perspective at once</h3><div class="paragraph"><p><span class="image"><img src="http://www.youtube.com/v/WIJt9aRGusc?.swf" alt="WIJt9aRGusc?.swf" width="400" height=""></span></p></div></div></div>
- <div class="sect1"><h2 id="more-information">More Information</h2><div class="sectionbody"><div class="paragraph"><p>This is the old page showing the first version of this idea
- <a href="http://aurellem.org/cortex/html/capture-video.html">http://aurellem.org/cortex/html/capture-video.html</a></p></div>
- <div class="paragraph"><p>All source code can be found here:</p></div>
- <div class="paragraph"><p><a href="http://hg.bortreb.com/audio-send">http://hg.bortreb.com/audio-send</a></p></div>
- <div class="paragraph"><p><a href="http://hg.bortreb.com/jmeCapture">http://hg.bortreb.com/jmeCapture</a></p></div>
- <div class="paragraph"><p>More information on the modifications to OpenAL to support multiple
- listeners can be found here.</p></div>
- <div class="paragraph"><p><a href="http://aurellem.org/audio-send/html/ear.html">http://aurellem.org/audio-send/html/ear.html</a></p></div></div></div></div><div id="footer"><div id="footer-text">Version <br>Last updated 2019-12-20 23:30:51 +00:00</div></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script><script>docsearch({
- apiKey: 'a736b6d93de805e26ec2f49b55013fbd',
- indexName: 'jmonkeyengine',
- inputSelector: '#doc-search',
- debug: false // Set debug to true if you want to inspect the dropdown
- });</script></body></html>
|