Mercurial > audio-send
view RecordAudioRenderer.java @ 1:c41d773a85fb
moved org files, ignored html files
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Tue, 25 Oct 2011 13:03:35 -0700 |
parents | f9476ff7637e |
children |
line wrap: on
line source
1 package com.jme3.capture;3 import static org.lwjgl.openal.AL10.AL_BUFFER;4 import static org.lwjgl.openal.AL10.AL_BUFFERS_PROCESSED;5 import static org.lwjgl.openal.AL10.AL_CONE_INNER_ANGLE;6 import static org.lwjgl.openal.AL10.AL_CONE_OUTER_ANGLE;7 import static org.lwjgl.openal.AL10.AL_CONE_OUTER_GAIN;8 import static org.lwjgl.openal.AL10.AL_DIRECTION;9 import static org.lwjgl.openal.AL10.AL_FALSE;10 import static org.lwjgl.openal.AL10.AL_FORMAT_MONO16;11 import static org.lwjgl.openal.AL10.AL_FORMAT_MONO8;12 import static org.lwjgl.openal.AL10.AL_FORMAT_STEREO16;13 import static org.lwjgl.openal.AL10.AL_FORMAT_STEREO8;14 import static org.lwjgl.openal.AL10.AL_GAIN;15 import static org.lwjgl.openal.AL10.AL_LOOPING;16 import static org.lwjgl.openal.AL10.AL_MAX_DISTANCE;17 import static org.lwjgl.openal.AL10.AL_ORIENTATION;18 import static org.lwjgl.openal.AL10.AL_PAUSED;19 import static org.lwjgl.openal.AL10.AL_PITCH;20 import static org.lwjgl.openal.AL10.AL_POSITION;21 import static org.lwjgl.openal.AL10.AL_REFERENCE_DISTANCE;22 import static org.lwjgl.openal.AL10.AL_RENDERER;23 import static org.lwjgl.openal.AL10.AL_SOURCE_RELATIVE;24 import static org.lwjgl.openal.AL10.AL_SOURCE_STATE;25 import static org.lwjgl.openal.AL10.AL_STOPPED;26 import static org.lwjgl.openal.AL10.AL_TRUE;27 import static org.lwjgl.openal.AL10.AL_VELOCITY;28 import static org.lwjgl.openal.AL10.AL_VENDOR;29 import static org.lwjgl.openal.AL10.AL_VERSION;30 import static org.lwjgl.openal.AL10.alBufferData;31 import static org.lwjgl.openal.AL10.alDeleteBuffers;32 import static org.lwjgl.openal.AL10.alDeleteSources;33 import static org.lwjgl.openal.AL10.alGenBuffers;34 import static org.lwjgl.openal.AL10.alGenSources;35 import static org.lwjgl.openal.AL10.alGetError;36 import static org.lwjgl.openal.AL10.alGetSourcei;37 import static org.lwjgl.openal.AL10.alGetString;38 import static org.lwjgl.openal.AL10.alListener;39 import static org.lwjgl.openal.AL10.alListener3f;40 import static org.lwjgl.openal.AL10.alListenerf;41 import static org.lwjgl.openal.AL10.alSource3f;42 import static org.lwjgl.openal.AL10.alSourcePause;43 import static org.lwjgl.openal.AL10.alSourcePlay;44 import static org.lwjgl.openal.AL10.alSourceQueueBuffers;45 import static org.lwjgl.openal.AL10.alSourceStop;46 import static org.lwjgl.openal.AL10.alSourceUnqueueBuffers;47 import static org.lwjgl.openal.AL10.alSourcef;48 import static org.lwjgl.openal.AL10.alSourcei;50 import java.lang.reflect.Field;51 import java.nio.ByteBuffer;52 import java.nio.FloatBuffer;53 import java.nio.IntBuffer;54 import java.util.ArrayList;55 import java.util.Vector;56 import java.util.concurrent.atomic.AtomicBoolean;57 import java.util.logging.Level;58 import java.util.logging.Logger;60 import org.lwjgl.LWJGLException;61 import org.lwjgl.openal.AL;62 import org.lwjgl.openal.AL11;63 import org.lwjgl.openal.ALC10;64 import org.lwjgl.openal.ALCdevice;65 import org.lwjgl.openal.EFX10;66 import org.lwjgl.openal.OpenALException;68 import com.jme3.audio.AudioBuffer;69 import com.jme3.audio.AudioData;70 import com.jme3.audio.AudioNode;71 import com.jme3.audio.AudioNode.Status;72 import com.jme3.audio.AudioParam;73 import com.jme3.audio.AudioRenderer;74 import com.jme3.audio.AudioStream;75 import com.jme3.audio.Environment;76 import com.jme3.audio.Filter;77 import com.jme3.audio.Listener;78 import com.jme3.audio.ListenerParam;79 import com.jme3.audio.LowPassFilter;80 import com.jme3.math.Vector3f;81 import com.jme3.util.BufferUtils;85 public class RecordAudioRenderer implements AudioRenderer, Runnable {89 public static void getMainSamples(){91 }94 private static final Logger logger = Logger.getLogger(RecordAudioRenderer.class.getName());96 // When multiplied by STREAMING_BUFFER_COUNT, will equal 44100 * 2 * 297 // which is exactly 1 second of audio.98 private static final int BUFFER_SIZE = 35280;99 private static final int STREAMING_BUFFER_COUNT = 5;101 private final static int MAX_NUM_CHANNELS = 2;102 private IntBuffer ib = BufferUtils.createIntBuffer(1);103 private final FloatBuffer fb = BufferUtils.createVector3Buffer(2);104 private final ByteBuffer nativeBuf = BufferUtils.createByteBuffer(BUFFER_SIZE);105 private final byte[] arrayBuf = new byte[BUFFER_SIZE];107 private int[] channels;108 private AudioNode[] chanSrcs;109 private int nextChan = 0;110 private ArrayList<Integer> freeChans = new ArrayList<Integer>();112 private Listener listener;113 private boolean audioDisabled = false;115 private boolean supportEfx = false;116 private int auxSends = 0;117 private int reverbFx = -1;118 private int reverbFxSlot = -1;120 // RLM: this is to call the native methods which require the OpenAL device ID.121 // currently it is obtained through reflection.122 private long deviceID;124 // Update audio 20 times per second125 private static final float UPDATE_RATE = 0.05f;127 private final Thread audioThread = new Thread(this, "jME3 Audio Thread");128 private final AtomicBoolean threadLock = new AtomicBoolean(false);130 public RecordAudioRenderer(){131 }133 public static native void helloEveryone();136 public static native void nstep(long device);137 public void step(){138 nstep(this.deviceID);139 }143 public void getMainSamples(ByteBuffer buffer){144 ngetMainSamples(this.deviceID, buffer, buffer.position());145 }146 public static native void ngetMainSamples(long device, ByteBuffer buffer, int position);149 public void getAuxSamples(ByteBuffer buffer){150 ngetAuxSamples(this.deviceID, buffer, buffer.position());151 }152 public static native void ngetAuxSamples(long device, ByteBuffer buffer, int position);156 public void initialize(){157 if (!audioThread.isAlive()){158 audioThread.setDaemon(true);159 audioThread.setPriority(Thread.NORM_PRIORITY+1);160 audioThread.start();161 }else{162 throw new IllegalStateException("Initialize already called");163 }164 }166 private void checkDead(){167 if (audioThread.getState() == Thread.State.TERMINATED)168 throw new IllegalStateException("Audio thread is terminated");169 }171 public void run(){172 initInThread();173 synchronized (threadLock){174 threadLock.set(true);175 threadLock.notifyAll();176 }179 helloEveryone();180 System.out.println("AudioRecorder: Trying to call native methods.");181 System.out.println("our device ID is : " + this.deviceID);186 long updateRateNanos = (long) (UPDATE_RATE * 1000000000);187 mainloop: while (true){188 long startTime = System.nanoTime();190 if (Thread.interrupted())191 break;193 synchronized (threadLock){194 updateInThread(UPDATE_RATE);195 }197 long endTime = System.nanoTime();198 long diffTime = endTime - startTime;200 if (diffTime < updateRateNanos){201 long desiredEndTime = startTime + updateRateNanos;202 while (System.nanoTime() < desiredEndTime){203 try{204 Thread.sleep(1);205 }catch (InterruptedException ex){206 break mainloop;207 }208 }209 }210 }212 synchronized (threadLock){213 cleanupInThread();214 }215 }217 public void initInThread(){218 try{219 if (!AL.isCreated()){220 AL.create("Aurellem", 44100, 15, false);221 }222 }catch (OpenALException ex){223 logger.log(Level.SEVERE, "Failed to load audio library", ex);224 audioDisabled = true;225 return;226 }catch (LWJGLException ex){227 logger.log(Level.SEVERE, "Failed to load audio library", ex);228 audioDisabled = true;229 return;230 }232 ALCdevice device = AL.getDevice();234 // RLM: use reflection to grab the ID of our device for use later.235 try {236 Field deviceIDField;237 deviceIDField = ALCdevice.class.getDeclaredField("device");238 deviceIDField.setAccessible(true);239 try {deviceID = (Long)deviceIDField.get(device);}240 catch (IllegalArgumentException e) {e.printStackTrace();}241 catch (IllegalAccessException e) {e.printStackTrace();}242 deviceIDField.setAccessible(false);}243 catch (SecurityException e) {e.printStackTrace();}244 catch (NoSuchFieldException e) {e.printStackTrace();}248 String deviceName = ALC10.alcGetString(device, ALC10.ALC_DEVICE_SPECIFIER);250 logger.log(Level.FINER, "Audio Device: {0}", deviceName);251 logger.log(Level.FINER, "Audio Vendor: {0}", alGetString(AL_VENDOR));252 logger.log(Level.FINER, "Audio Renderer: {0}", alGetString(AL_RENDERER));253 logger.log(Level.FINER, "Audio Version: {0}", alGetString(AL_VERSION));255 // Find maximum # of sources supported by this implementation256 // RLM: this may not be wise -- exceeding the number of available channels257 // can crash some versions of OpenAL258 ArrayList<Integer> channelList = new ArrayList<Integer>();259 for (int i = 0; i < MAX_NUM_CHANNELS; i++){260 int chan = alGenSources();261 if (alGetError() != 0){262 break;263 }else{264 channelList.add(chan);265 }266 }268 channels = new int[channelList.size()];269 for (int i = 0; i < channels.length; i++){270 channels[i] = channelList.get(i);271 }273 ib = BufferUtils.createIntBuffer(channels.length);274 chanSrcs = new AudioNode[channels.length];276 logger.log(Level.INFO, "AudioRenderer supports {0} channels", channels.length);278 supportEfx = ALC10.alcIsExtensionPresent(device, "ALC_EXT_EFX");279 // RLM: disable this for now.280 supportEfx = false;281 logger.log(Level.FINER, "Audio EFX support: {0}", supportEfx);283 if (supportEfx){284 ib.position(0).limit(1);285 ALC10.alcGetInteger(device, EFX10.ALC_EFX_MAJOR_VERSION, ib);286 int major = ib.get(0);287 ib.position(0).limit(1);288 ALC10.alcGetInteger(device, EFX10.ALC_EFX_MINOR_VERSION, ib);289 int minor = ib.get(0);290 logger.log(Level.INFO, "Audio effect extension version: {0}.{1}", new Object[]{major, minor});292 ALC10.alcGetInteger(device, EFX10.ALC_MAX_AUXILIARY_SENDS, ib);293 auxSends = ib.get(0);294 logger.log(Level.INFO, "Audio max auxilary sends: {0}", auxSends);296 // create slot297 ib.position(0).limit(1);298 EFX10.alGenAuxiliaryEffectSlots(ib);299 reverbFxSlot = ib.get(0);301 // create effect302 ib.position(0).limit(1);303 EFX10.alGenEffects(ib);304 reverbFx = ib.get(0);305 EFX10.alEffecti(reverbFx, EFX10.AL_EFFECT_TYPE, EFX10.AL_EFFECT_REVERB);307 // attach reverb effect to effect slot308 // EFX10.alAuxiliaryEffectSloti(reverbFxSlot, EFX10.AL_EFFECTSLOT_EFFECT, reverbFx);309 }310 }312 public void cleanupInThread(){315 if (audioDisabled){316 AL.destroy();317 return;318 }320 // delete channel-based sources321 ib.clear();322 ib.put(channels);323 ib.flip();324 alDeleteSources(ib);326 if (supportEfx){327 ib.position(0).limit(1);328 ib.put(0, reverbFx);329 EFX10.alDeleteEffects(ib);331 ib.position(0).limit(1);332 ib.put(0, reverbFxSlot);333 EFX10.alDeleteAuxiliaryEffectSlots(ib);334 }336 // XXX: Delete other buffers/sources337 AL.destroy();338 }340 public void cleanup(){341 // kill audio thread343 if (audioThread.isAlive()){344 audioThread.interrupt();345 }347 Byte[] data1 = new Byte[this.fullWaveData1.size()];348 data1 = this.fullWaveData1.toArray(data1);350 Byte[] data2 = new Byte[this.fullWaveData2.size()];351 data2 = this.fullWaveData2.toArray(data2);352 System.out.println(this.fullWaveData1.size());353 System.out.println("Saving WAVE data!");354 /*for (int i = 0; i < data1.length;i++){355 System.out.print(data1[i]+",");356 if (i%32 ==0){System.out.println();}357 }358 */361 StdAudio.save("/home/r/wave-output/data2.wav", data2);362 StdAudio.save("/home/r/wave-output/data1.wav", data1);363 }365 private void updateFilter(Filter f){366 int id = f.getId();367 if (id == -1){368 ib.position(0).limit(1);369 EFX10.alGenFilters(ib);370 id = ib.get(0);371 f.setId(id);372 }374 if (f instanceof LowPassFilter){375 LowPassFilter lpf = (LowPassFilter) f;376 EFX10.alFilteri(id, EFX10.AL_FILTER_TYPE, EFX10.AL_FILTER_LOWPASS);377 EFX10.alFilterf(id, EFX10.AL_LOWPASS_GAIN, lpf.getVolume());378 EFX10.alFilterf(id, EFX10.AL_LOWPASS_GAINHF, lpf.getHighFreqVolume());379 }else{380 throw new UnsupportedOperationException("Filter type unsupported: "+381 f.getClass().getName());382 }384 f.clearUpdateNeeded();385 }387 public void updateSourceParam(AudioNode src, AudioParam param){388 checkDead();389 synchronized (threadLock){390 while (!threadLock.get()){391 try {392 threadLock.wait();393 } catch (InterruptedException ex) {394 }395 }396 if (audioDisabled)397 return;399 // There is a race condition in AudioNode that can400 // cause this to be called for a node that has been401 // detached from its channel. For example, setVolume()402 // called from the render thread may see that that AudioNode403 // still has a channel value but the audio thread may404 // clear that channel before setVolume() gets to call405 // updateSourceParam() (because the audio stopped playing406 // on its own right as the volume was set). In this case,407 // it should be safe to just ignore the update408 if (src.getChannel() < 0)409 return;411 assert src.getChannel() >= 0;413 int id = channels[src.getChannel()];414 switch (param){415 case Position:416 if (!src.isPositional())417 return;419 Vector3f pos = src.getWorldTranslation();420 alSource3f(id, AL_POSITION, pos.x, pos.y, pos.z);421 break;422 case Velocity:423 if (!src.isPositional())424 return;426 Vector3f vel = src.getVelocity();427 alSource3f(id, AL_VELOCITY, vel.x, vel.y, vel.z);428 break;429 case MaxDistance:430 if (!src.isPositional())431 return;433 alSourcef(id, AL_MAX_DISTANCE, src.getMaxDistance());434 break;435 case RefDistance:436 if (!src.isPositional())437 return;439 alSourcef(id, AL_REFERENCE_DISTANCE, src.getRefDistance());440 break;441 case ReverbFilter:442 if (!src.isPositional() || !src.isReverbEnabled())443 return;445 int filter = EFX10.AL_FILTER_NULL;446 if (src.getReverbFilter() != null){447 Filter f = src.getReverbFilter();448 if (f.isUpdateNeeded()){449 updateFilter(f);450 }451 filter = f.getId();452 }453 AL11.alSource3i(id, EFX10.AL_AUXILIARY_SEND_FILTER, reverbFxSlot, 0, filter);454 break;455 case ReverbEnabled:456 if (!src.isPositional())457 return;459 if (src.isReverbEnabled()){460 updateSourceParam(src, AudioParam.ReverbFilter);461 }else{462 AL11.alSource3i(id, EFX10.AL_AUXILIARY_SEND_FILTER, 0, 0, EFX10.AL_FILTER_NULL);463 }464 break;465 case IsPositional:466 if (!src.isPositional()){467 // play in headspace468 alSourcei(id, AL_SOURCE_RELATIVE, AL_TRUE);469 alSource3f(id, AL_POSITION, 0,0,0);470 alSource3f(id, AL_VELOCITY, 0,0,0);471 }else{472 alSourcei(id, AL_SOURCE_RELATIVE, AL_FALSE);473 updateSourceParam(src, AudioParam.Position);474 updateSourceParam(src, AudioParam.Velocity);475 updateSourceParam(src, AudioParam.MaxDistance);476 updateSourceParam(src, AudioParam.RefDistance);477 updateSourceParam(src, AudioParam.ReverbEnabled);478 }479 break;480 case Direction:481 if (!src.isDirectional())482 return;484 Vector3f dir = src.getDirection();485 alSource3f(id, AL_DIRECTION, dir.x, dir.y, dir.z);486 break;487 case InnerAngle:488 if (!src.isDirectional())489 return;491 alSourcef(id, AL_CONE_INNER_ANGLE, src.getInnerAngle());492 break;493 case OuterAngle:494 if (!src.isDirectional())495 return;497 alSourcef(id, AL_CONE_OUTER_ANGLE, src.getOuterAngle());498 break;499 case IsDirectional:500 if (src.isDirectional()){501 updateSourceParam(src, AudioParam.Direction);502 updateSourceParam(src, AudioParam.InnerAngle);503 updateSourceParam(src, AudioParam.OuterAngle);504 alSourcef(id, AL_CONE_OUTER_GAIN, 0);505 }else{506 alSourcef(id, AL_CONE_INNER_ANGLE, 360);507 alSourcef(id, AL_CONE_OUTER_ANGLE, 360);508 alSourcef(id, AL_CONE_OUTER_GAIN, 1f);509 }510 break;511 case DryFilter:512 if (src.getDryFilter() != null){513 Filter f = src.getDryFilter();514 if (f.isUpdateNeeded()){515 updateFilter(f);517 // NOTE: must re-attach filter for changes to apply.518 alSourcei(id, EFX10.AL_DIRECT_FILTER, f.getId());519 }520 }else{521 alSourcei(id, EFX10.AL_DIRECT_FILTER, EFX10.AL_FILTER_NULL);522 }523 break;524 case Looping:525 if (src.isLooping()){526 if (!(src.getAudioData() instanceof AudioStream)){527 alSourcei(id, AL_LOOPING, AL_TRUE);528 }529 }else{530 alSourcei(id, AL_LOOPING, AL_FALSE);531 }532 break;533 case Volume:534 alSourcef(id, AL_GAIN, src.getVolume());535 break;536 case Pitch:537 alSourcef(id, AL_PITCH, src.getPitch());538 break;539 }540 }541 }543 private void setSourceParams(int id, AudioNode src, boolean forceNonLoop){544 if (src.isPositional()){545 Vector3f pos = src.getWorldTranslation();546 Vector3f vel = src.getVelocity();547 alSource3f(id, AL_POSITION, pos.x, pos.y, pos.z);548 alSource3f(id, AL_VELOCITY, vel.x, vel.y, vel.z);549 alSourcef(id, AL_MAX_DISTANCE, src.getMaxDistance());550 alSourcef(id, AL_REFERENCE_DISTANCE, src.getRefDistance());551 alSourcei(id, AL_SOURCE_RELATIVE, AL_FALSE);553 if (src.isReverbEnabled()){554 int filter = EFX10.AL_FILTER_NULL;555 if (src.getReverbFilter() != null){556 Filter f = src.getReverbFilter();557 if (f.isUpdateNeeded()){558 updateFilter(f);559 }560 filter = f.getId();561 }562 AL11.alSource3i(id, EFX10.AL_AUXILIARY_SEND_FILTER, reverbFxSlot, 0, filter);563 }564 }else{565 // play in headspace566 alSourcei(id, AL_SOURCE_RELATIVE, AL_TRUE);567 alSource3f(id, AL_POSITION, 0,0,0);568 alSource3f(id, AL_VELOCITY, 0,0,0);569 }571 if (src.getDryFilter() != null){572 Filter f = src.getDryFilter();573 if (f.isUpdateNeeded()){574 updateFilter(f);576 // NOTE: must re-attach filter for changes to apply.577 alSourcei(id, EFX10.AL_DIRECT_FILTER, f.getId());578 }579 }581 if (forceNonLoop){582 alSourcei(id, AL_LOOPING, AL_FALSE);583 }else{584 alSourcei(id, AL_LOOPING, src.isLooping() ? AL_TRUE : AL_FALSE);585 }586 alSourcef(id, AL_GAIN, src.getVolume());587 alSourcef(id, AL_PITCH, src.getPitch());588 alSourcef(id, AL11.AL_SEC_OFFSET, src.getTimeOffset());590 if (src.isDirectional()){591 Vector3f dir = src.getDirection();592 alSource3f(id, AL_DIRECTION, dir.x, dir.y, dir.z);593 alSourcef(id, AL_CONE_INNER_ANGLE, src.getInnerAngle());594 alSourcef(id, AL_CONE_OUTER_ANGLE, src.getOuterAngle());595 alSourcef(id, AL_CONE_OUTER_GAIN, 0);596 }else{597 alSourcef(id, AL_CONE_INNER_ANGLE, 360);598 alSourcef(id, AL_CONE_OUTER_ANGLE, 360);599 alSourcef(id, AL_CONE_OUTER_GAIN, 1f);600 }601 }603 public void updateListenerParam(Listener listener, ListenerParam param){604 checkDead();605 synchronized (threadLock){606 while (!threadLock.get()){607 try {608 threadLock.wait();609 } catch (InterruptedException ex) {610 }611 }612 if (audioDisabled)613 return;615 switch (param){616 case Position:617 Vector3f pos = listener.getLocation();618 alListener3f(AL_POSITION, pos.x, pos.y, pos.z);619 break;620 case Rotation:621 Vector3f dir = listener.getDirection();622 Vector3f up = listener.getUp();623 fb.rewind();624 fb.put(dir.x).put(dir.y).put(dir.z);625 fb.put(up.x).put(up.y).put(up.z);626 fb.flip();627 alListener(AL_ORIENTATION, fb);628 break;629 case Velocity:630 Vector3f vel = listener.getVelocity();631 alListener3f(AL_VELOCITY, vel.x, vel.y, vel.z);632 break;633 case Volume:634 alListenerf(AL_GAIN, listener.getVolume());635 break;636 }637 }638 }640 private void setListenerParams(Listener listener){641 Vector3f pos = listener.getLocation();642 Vector3f vel = listener.getVelocity();643 Vector3f dir = listener.getDirection();644 Vector3f up = listener.getUp();646 alListener3f(AL_POSITION, pos.x, pos.y, pos.z);647 alListener3f(AL_VELOCITY, vel.x, vel.y, vel.z);648 fb.rewind();649 fb.put(dir.x).put(dir.y).put(dir.z);650 fb.put(up.x).put(up.y).put(up.z);651 fb.flip();652 alListener(AL_ORIENTATION, fb);653 alListenerf(AL_GAIN, listener.getVolume());654 }656 private int newChannel(){657 if (freeChans.size() > 0)658 return freeChans.remove(0);659 else if (nextChan < channels.length){660 return nextChan++;661 }else{662 return -1;663 }664 }666 private void freeChannel(int index){667 if (index == nextChan-1){668 nextChan--;669 } else{670 freeChans.add(index);671 }672 }674 public void setEnvironment(Environment env){675 checkDead();676 synchronized (threadLock){677 while (!threadLock.get()){678 try {679 threadLock.wait();680 } catch (InterruptedException ex) {681 }682 }683 if (audioDisabled)684 return;686 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DENSITY, env.getDensity());687 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DIFFUSION, env.getDiffusion());688 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_GAIN, env.getGain());689 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_GAINHF, env.getGainHf());690 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DECAY_TIME, env.getDecayTime());691 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_DECAY_HFRATIO, env.getDecayHFRatio());692 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_REFLECTIONS_GAIN, env.getReflectGain());693 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_REFLECTIONS_DELAY, env.getReflectDelay());694 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_LATE_REVERB_GAIN, env.getLateReverbGain());695 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_LATE_REVERB_DELAY, env.getLateReverbDelay());696 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_AIR_ABSORPTION_GAINHF, env.getAirAbsorbGainHf());697 EFX10.alEffectf(reverbFx, EFX10.AL_REVERB_ROOM_ROLLOFF_FACTOR, env.getRoomRolloffFactor());699 // attach effect to slot700 EFX10.alAuxiliaryEffectSloti(reverbFxSlot, EFX10.AL_EFFECTSLOT_EFFECT, reverbFx);701 }702 }704 private boolean fillBuffer(AudioStream stream, int id){705 int size = 0;706 int result;708 while (size < arrayBuf.length){709 result = stream.readSamples(arrayBuf, size, arrayBuf.length - size);711 if(result > 0){712 size += result;713 }else{714 break;715 }716 }718 if(size == 0)719 return false;721 nativeBuf.clear();722 nativeBuf.put(arrayBuf, 0, size);723 nativeBuf.flip();725 alBufferData(id, convertFormat(stream), nativeBuf, stream.getSampleRate());727 return true;728 }730 private boolean fillStreamingSource(int sourceId, AudioStream stream){731 if (!stream.isOpen())732 return false;734 boolean active = true;735 int processed = alGetSourcei(sourceId, AL_BUFFERS_PROCESSED);737 // while((processed--) != 0){738 if (processed > 0){739 int buffer;741 ib.position(0).limit(1);742 alSourceUnqueueBuffers(sourceId, ib);743 buffer = ib.get(0);745 active = fillBuffer(stream, buffer);747 ib.position(0).limit(1);748 ib.put(0, buffer);749 alSourceQueueBuffers(sourceId, ib);750 }752 if (!active && stream.isOpen())753 stream.close();755 return active;756 }758 private boolean attachStreamToSource(int sourceId, AudioStream stream){759 boolean active = true;760 for (int id : stream.getIds()){761 active = fillBuffer(stream, id);762 ib.position(0).limit(1);763 ib.put(id).flip();764 alSourceQueueBuffers(sourceId, ib);765 }766 return active;767 }769 private boolean attachBufferToSource(int sourceId, AudioBuffer buffer){770 alSourcei(sourceId, AL_BUFFER, buffer.getId());771 return true;772 }774 private boolean attachAudioToSource(int sourceId, AudioData data){775 if (data instanceof AudioBuffer){776 return attachBufferToSource(sourceId, (AudioBuffer) data);777 }else if (data instanceof AudioStream){778 return attachStreamToSource(sourceId, (AudioStream) data);779 }780 throw new UnsupportedOperationException();781 }783 private void clearChannel(int index){784 // make room at this channel785 if (chanSrcs[index] != null){786 AudioNode src = chanSrcs[index];788 int sourceId = channels[index];789 alSourceStop(sourceId);791 if (src.getAudioData() instanceof AudioStream){792 AudioStream str = (AudioStream) src.getAudioData();793 ib.position(0).limit(STREAMING_BUFFER_COUNT);794 ib.put(str.getIds()).flip();795 alSourceUnqueueBuffers(sourceId, ib);796 }else if (src.getAudioData() instanceof AudioBuffer){797 alSourcei(sourceId, AL_BUFFER, 0);798 }800 if (src.getDryFilter() != null){801 // detach filter802 alSourcei(sourceId, EFX10.AL_DIRECT_FILTER, EFX10.AL_FILTER_NULL);803 }804 if (src.isPositional()){805 AudioNode pas = (AudioNode) src;806 if (pas.isReverbEnabled()) {807 AL11.alSource3i(sourceId, EFX10.AL_AUXILIARY_SEND_FILTER, 0, 0, EFX10.AL_FILTER_NULL);808 }809 }811 chanSrcs[index] = null;812 }813 }815 public void update(float tpf){816 //ByteBuffer test = BufferUtils.createByteBuffer(1);817 //AurellemTransport.getAuxSamples(AL.getDevice(), test);818 }820 Vector<Byte> fullWaveData1 = new Vector<Byte>();821 Vector<Byte> fullWaveData2 = new Vector<Byte>();823 public void updateInThread(float tpf){824 if (audioDisabled)825 return;827 step();828 ByteBuffer test = BufferUtils.createByteBuffer(4096);829 test.clear();830 this.getMainSamples(test);831 byte[] waveData = new byte[4096];832 test.get(waveData, 0, 4096);833 //System.out.println("J DATA:");834 /*for (int j = 0; j < 1; j++){835 for(int i = 64 * j; i < (64*j) + 64; i++){836 System.out.print(waveData[i]);837 }838 System.out.println();839 }*/841 ByteBuffer test2 = BufferUtils.createByteBuffer(4096);842 test2.clear();843 this.getAuxSamples(test2);844 byte[] waveData2 = new byte[4096];845 test2.get(waveData2, 0, 4096);846 //System.out.print("wave1:");847 //for (int j = 0; j< 32; j++){848 // System.out.print(waveData[j]+",");849 // }850 //System.out.println();851 //System.out.print("wave2:");852 // for (int j = 0; j< 4096; j++){853 // if (waveData2[j] != 0){854 // System.out.println("fucked at : " + j);855 // }857 /* System.out.print(waveData2[j]+",");858 if (0 == (j % 64)){System.out.println();}*/859 //}860 //System.out.println();862 for (byte b : waveData){863 this.fullWaveData1.add(b);864 }866 for (byte b : waveData2){867 this.fullWaveData2.add(b);868 }871 for (int i = 0; i < channels.length; i++){872 AudioNode src = chanSrcs[i];873 if (src == null)874 continue;876 int sourceId = channels[i];878 // is the source bound to this channel879 // if false, it's an instanced playback880 boolean boundSource = i == src.getChannel();882 // source's data is streaming883 boolean streaming = src.getAudioData() instanceof AudioStream;885 // only buffered sources can be bound886 assert (boundSource && streaming) || (!streaming);888 int state = alGetSourcei(sourceId, AL_SOURCE_STATE);889 boolean wantPlaying = src.getStatus() == Status.Playing;890 boolean stopped = state == AL_STOPPED;892 if (streaming && wantPlaying){893 AudioStream stream = (AudioStream) src.getAudioData();894 if (stream.isOpen()){895 fillStreamingSource(sourceId, stream);896 if (stopped)897 alSourcePlay(sourceId);899 }else{900 if (stopped){901 // became inactive902 src.setStatus(Status.Stopped);903 src.setChannel(-1);904 clearChannel(i);905 freeChannel(i);907 // And free the audio since it cannot be908 // played again anyway.909 deleteAudioData(stream);910 }911 }912 }else if (!streaming){913 boolean paused = state == AL_PAUSED;915 // make sure OAL pause state & source state coincide916 assert (src.getStatus() == Status.Paused && paused) || (!paused);918 if (stopped){919 if (boundSource){920 src.setStatus(Status.Stopped);921 src.setChannel(-1);922 }923 clearChannel(i);924 freeChannel(i);925 }926 }927 }928 }930 public void setListener(Listener listener) {931 checkDead();932 synchronized (threadLock){933 while (!threadLock.get()){934 try {935 threadLock.wait();936 } catch (InterruptedException ex) {937 }938 }939 if (audioDisabled)940 return;942 if (this.listener != null){943 // previous listener no longer associated with current944 // renderer945 this.listener.setRenderer(null);946 }948 this.listener = listener;949 this.listener.setRenderer(this);950 setListenerParams(listener);951 }952 }954 public void playSourceInstance(AudioNode src){955 checkDead();956 synchronized (threadLock){957 while (!threadLock.get()){958 try {959 threadLock.wait();960 } catch (InterruptedException ex) {961 }962 }963 if (audioDisabled)964 return;966 if (src.getAudioData() instanceof AudioStream)967 throw new UnsupportedOperationException(968 "Cannot play instances " +969 "of audio streams. Use playSource() instead.");971 if (src.getAudioData().isUpdateNeeded()){972 updateAudioData(src.getAudioData());973 }975 // create a new index for an audio-channel976 int index = newChannel();977 if (index == -1)978 return;980 int sourceId = channels[index];982 clearChannel(index);984 // set parameters, like position and max distance985 setSourceParams(sourceId, src, true);986 attachAudioToSource(sourceId, src.getAudioData());987 chanSrcs[index] = src;989 // play the channel990 alSourcePlay(sourceId);991 }992 }995 public void playSource(AudioNode src) {996 checkDead();997 synchronized (threadLock){998 while (!threadLock.get()){999 try {1000 threadLock.wait();1001 } catch (InterruptedException ex) {1002 }1003 }1004 if (audioDisabled)1005 return;1007 //assert src.getStatus() == Status.Stopped || src.getChannel() == -1;1009 if (src.getStatus() == Status.Playing){1010 return;1011 }else if (src.getStatus() == Status.Stopped){1013 // allocate channel to this source1014 int index = newChannel();1015 if (index == -1) {1016 logger.log(Level.WARNING, "No channel available to play {0}", src);1017 return;1018 }1019 clearChannel(index);1020 src.setChannel(index);1022 AudioData data = src.getAudioData();1023 if (data.isUpdateNeeded())1024 updateAudioData(data);1026 chanSrcs[index] = src;1027 setSourceParams(channels[index], src, false);1028 attachAudioToSource(channels[index], data);1029 }1031 alSourcePlay(channels[src.getChannel()]);1032 src.setStatus(Status.Playing);1033 }1034 }1037 public void pauseSource(AudioNode src) {1038 checkDead();1039 synchronized (threadLock){1040 while (!threadLock.get()){1041 try {1042 threadLock.wait();1043 } catch (InterruptedException ex) {1044 }1045 }1046 if (audioDisabled)1047 return;1049 if (src.getStatus() == Status.Playing){1050 assert src.getChannel() != -1;1052 alSourcePause(channels[src.getChannel()]);1053 src.setStatus(Status.Paused);1054 }1055 }1056 }1059 public void stopSource(AudioNode src) {1060 synchronized (threadLock){1061 while (!threadLock.get()){1062 try {1063 threadLock.wait();1064 } catch (InterruptedException ex) {1065 }1066 }1067 if (audioDisabled)1068 return;1070 if (src.getStatus() != Status.Stopped){1071 int chan = src.getChannel();1072 assert chan != -1; // if it's not stopped, must have id1074 src.setStatus(Status.Stopped);1075 src.setChannel(-1);1076 clearChannel(chan);1077 freeChannel(chan);1079 if (src.getAudioData() instanceof AudioStream) {1081 AudioStream stream = (AudioStream)src.getAudioData();1082 if (stream.isOpen()) {1083 stream.close();1084 }1086 // And free the audio since it cannot be1087 // played again anyway.1088 deleteAudioData(src.getAudioData());1089 }1090 }1091 }1092 }1094 private int convertFormat(AudioData ad){1095 switch (ad.getBitsPerSample()){1096 case 8:1097 if (ad.getChannels() == 1)1098 return AL_FORMAT_MONO8;1099 else if (ad.getChannels() == 2)1100 return AL_FORMAT_STEREO8;1102 break;1103 case 16:1104 if (ad.getChannels() == 1)1105 return AL_FORMAT_MONO16;1106 else1107 return AL_FORMAT_STEREO16;1108 }1109 throw new UnsupportedOperationException("Unsupported channels/bits combination: "+1110 "bits="+ad.getBitsPerSample()+", channels="+ad.getChannels());1111 }1113 private void updateAudioBuffer(AudioBuffer ab){1114 int id = ab.getId();1115 if (ab.getId() == -1){1116 ib.position(0).limit(1);1117 alGenBuffers(ib);1118 id = ib.get(0);1119 ab.setId(id);1120 }1122 ab.getData().clear();1123 alBufferData(id, convertFormat(ab), ab.getData(), ab.getSampleRate());1124 ab.clearUpdateNeeded();1125 }1127 private void updateAudioStream(AudioStream as){1128 if (as.getIds() != null){1129 deleteAudioData(as);1130 }1132 int[] ids = new int[STREAMING_BUFFER_COUNT];1133 ib.position(0).limit(STREAMING_BUFFER_COUNT);1134 alGenBuffers(ib);1135 ib.position(0).limit(STREAMING_BUFFER_COUNT);1136 ib.get(ids);1138 as.setIds(ids);1139 as.clearUpdateNeeded();1140 }1142 private void updateAudioData(AudioData ad){1143 if (ad instanceof AudioBuffer){1144 updateAudioBuffer((AudioBuffer) ad);1145 }else if (ad instanceof AudioStream){1146 updateAudioStream((AudioStream) ad);1147 }1148 }1150 public void deleteAudioData(AudioData ad){1151 synchronized (threadLock){1152 while (!threadLock.get()){1153 try {1154 threadLock.wait();1155 } catch (InterruptedException ex) {1156 }1157 }1158 if (audioDisabled)1159 return;1161 if (ad instanceof AudioBuffer){1162 AudioBuffer ab = (AudioBuffer) ad;1163 int id = ab.getId();1164 if (id != -1){1165 ib.put(0,id);1166 ib.position(0).limit(1);1167 alDeleteBuffers(ib);1168 ab.resetObject();1169 }1170 }else if (ad instanceof AudioStream){1171 AudioStream as = (AudioStream) ad;1172 int[] ids = as.getIds();1173 if (ids != null){1174 ib.clear();1175 ib.put(ids).flip();1176 alDeleteBuffers(ib);1177 as.resetObject();1178 }1179 }1180 }1181 }1183 }