[quote]Would there be any possibility of you bundling up just the important classes into a jar? I’ll make sure to put you in my game’s credits!
[/quote]
Sure. A mention would be great! We can also go back and let the recordists at FreeSound.org know as well. There is no fee–these are free–but the recordists like to hear when something has been used in an app. I’ve got links to the original files.
Actually, you can try running the jar as is, if you link it into your project. The main “excess” is the GUI class which is pretty lightweight and can just be ignored, probably.
I was noticing the other night that if I have two or three sound-playing jars open at the same time, this one starts experiencing dropouts. It runs fine, otherwise, and has low cpu usage afaik. But for sure, test it before making it a go for your game. I have been planning to investigate as to what the bottleneck might be but haven’t had a chance to follow through, yet. If it is happening in your game, please let me know and maybe we can look into it further.
Also–I can probably hone it down if you want to lose either the wind or rain parts or really do need to get rid of the GUI. The animation timer isn’t needed for the thunder, just the wind/rain.
Below is the “SoundHandler.java” class that is used to control the app. Are you able figure out how to use the jar via the public methods here? I apologize for some laziness in the coding that might cause confusion, e.g., should have renamed updateVolume() to updateParameter() since it was expanded to do more than just set volumes.
So, make an instance of SoundHandler, and call soundHandler.start() to get the audio engine rolling. Then use the other start/stops to turn things on/off, and updateVolume, using the enum of parameters, for the aspect you wish to control. The parameters updates are set to respond to normals (0…1) for the ranges.
Be sure and include the stop() method when shutting down, or else the thread pool executor in EventSchedulingThreadPool will keep running.
package com.adonax.weather;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.UnsupportedAudioFileException;
import com.adonax.pfaudio.cliptools.SuperSlicer;
import com.adonax.pfaudio.core.CoreMixer;
import com.adonax.pfaudio.core.JavaWrapper;
import com.adonax.pfaudio.events.EventSchedulingThreadPool;
import com.adonax.pfaudio.io.PFClipData;
import converter.OggVorbisToPCMFloats;
import javafx.animation.AnimationTimer;
public class SoundHandler {
private CoreMixer mixer;
private JavaWrapper jw;
private SuperSlicer windSlicer, rainSlicer;
private float baseWindVol, baseRainVol;
private float turbulence;
private ThunderAmbience thunder;
public enum Attribute { WIND_VOLUME, RAIN_VOLUME, TURBULENCE, THUNDER_VOLUME, THUNDER_INTENSITY,
THUNDER_FIXED_PAUSE, THUNDER_RANDOM_PAUSE};
public SoundHandler() throws UnsupportedAudioFileException, IOException
{
mixer = new CoreMixer();
jw = new JavaWrapper(mixer);
new EventSchedulingThreadPool(10);
float[] pcmFloats;
PFClipData clipData;
InputStream inputStream = null;
// * * * * * * * *
// Forest Wind in Trees
// * * * * * * * *
inputStream = this.getClass().getResourceAsStream(
"../wind/audio/25945__inchadney__owl__WIND_IN_TREES.ogg");
if (inputStream == null) System.out.println("inputStream not found");
pcmFloats = OggVorbisToPCMFloats.makePCMFloats(inputStream, 141_324);
clipData = new PFClipData("wind in trees ogg", pcmFloats);
windSlicer = new SuperSlicer(clipData, 44100 / 2, 1024 * 8);
mixer.addTrack(windSlicer);
// rain
inputStream = this.getClass().getResourceAsStream(
"../wind/audio/244053__lennyboy__thunder_rainclip.ogg");
if (inputStream == null) System.out.println("inputStream not found");
pcmFloats = OggVorbisToPCMFloats.makePCMFloats(inputStream, 93_904);
clipData = new PFClipData("rain ogg", pcmFloats);
rainSlicer = new SuperSlicer(clipData, 44100 / 2, 1024 * 4);
mixer.addTrack(rainSlicer);
// thunder
thunder = new ThunderAmbience();
mixer.addTrack(thunder);
LFPeriodicNoise wave = new LFPeriodicNoise(30);
AnimationTimer timer = new AnimationTimer()
{
final int TUBE_LEN = 24; // 60 = 1 second delay
float[] delayTube = new float[TUBE_LEN];
int iWrite, iRead;
void updateDelayTube()
{
iWrite++;
iRead++;
if (iWrite >= TUBE_LEN) iWrite = 0;
if (iRead >= TUBE_LEN) iRead = 0;
}
@Override
public void handle(long arg0)
{
wave.setPeriod((int)((1 - turbulence) * 60) + 30 );
float flt = wave.tick() * (turbulence/3);
delayTube[iWrite] = flt;
rainSlicer.setVolume( baseRainVol * (1 + delayTube[iRead]) );
windSlicer.setVolume( baseWindVol * (1 + flt/2) );
updateDelayTube();
}
};
timer.start();
}
// *************************
// INTERFACE METHODS
// *************************
public void start()
{
jw.start(null);
}
public void stop()
{
jw.stop();
EventSchedulingThreadPool.shutdown();
}
// Inputs should be normalized [0, 1]
public void updateVolume(Attribute attribute, float value)
{
switch(attribute)
{
case WIND_VOLUME:
baseWindVol = value / 8;
break;
case RAIN_VOLUME:
baseRainVol = value / 6;
break;
case TURBULENCE:
turbulence = value;
break;
case THUNDER_INTENSITY:
thunder.setIntensity(value);
break;
case THUNDER_VOLUME:
thunder.setMasterVolume(value);
break;
case THUNDER_FIXED_PAUSE:
thunder.setFixedPausePart(value);
break;
case THUNDER_RANDOM_PAUSE:
thunder.setRandomPausePart(value);
break;
default:
break;
}
}
public void startWind()
{
windSlicer.play(0, 0);
}
public void stopWind()
{
windSlicer.stop();
}
public void startRain()
{
rainSlicer.play(0, 0);
}
public void stopRain()
{
rainSlicer.stop();
}
public void startThunder()
{
thunder.start();
}
public void stopThunder()
{
thunder.stop();
}
}