java sound, fadeIn effect, using FloatControl - java

Im trying to implement fade in effect to my mp3 player.
I´m using
FloatControl volumeControl = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN);
because FloatControl.Type.VOLUME throws an exception(Unavaliable Control) I dont know why.
I need some help with the algorithm, because its not working ok.
Heres the code:
public class FloatControlFader
{
public static void fadeIn(final FloatControl control, final float from,
final float to, final int seconds)
{
final float vps = ((to-from) / (seconds*10));//Volume incrased/100millisecond
control.setValue(from);
Thread t = new Thread(new Runnable(){
public void run() {
for(int i=0; i < seconds*10; i++)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException ex)
{
}
System.out.println(control.getValue()); //for DEBUG
control.setValue(control.getValue() + vps);
}
}
});
t.start();
}
}
Would appreciate any help, thanks!

Remember the human ear does not hear linearly so increasing by a steady X vps is not going to sound like a smooth fade. You need to put a log function in there. Then you need to map the linear increases to log values. This is of course all assuming the volume control units are not in decibels. If you're increasing by db then you're fine.

Related

SourceDataLine delay to much for real time playing (synth)

I tried making a synth and it works and I can play music with them. However the first synth that I made had delay and you couldn't play fast songs. So I tried again using sourceDataline.flush() method to speed it up. Well it somewhat fixes it but delay is to much. I tried also reducing sample rate but delay is to much.
Edit: turns out you can comment the line keyStateInterface.setFlush(false);
it improves the delay however you still can't play fast songs
here is the code:
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class SoundLine implements Runnable{
KeyStateInterface keyStateInterface;
public SoundLine(KeyStateInterface arg){
keyStateInterface=arg;
}
#Override
public void run() {
AudioFormat audioFormat = new AudioFormat(44100,8,1,true,false);
try {
SourceDataLine sourceDataLine = AudioSystem.getSourceDataLine(audioFormat);
sourceDataLine.open(audioFormat);
sourceDataLine.start();
SynthMain synthMain = new SynthMain();
int v = 0;
while (true) {
int bytesAvailable = sourceDataLine.available();
if (bytesAvailable > 0) {
int sampling = 256/(64);
byte[] bytes = new byte[sampling];
for (int i = 0; i < sampling; i++) {
//bytes[i] = (byte) (Math.sin(angle) * 127f);
float t = (float) (synthMain.makeSound((double)v,44100,keyStateInterface)* 127f);
bytes[i] = (byte) (t);
v += 1;
}
if(keyStateInterface.getFlush()){
sourceDataLine.flush();
}
sourceDataLine.write(bytes, 0, sampling);
//if(!keyStateInterface.isCacheKeysSame())sourceDataLine.flush();
//System.out.println(bytesWritten);
} else {
Thread.sleep(1);
}
//System.out.println(bytesAvailable);
//System.out.println();
//if((System.currentTimeMillis()-mil)%50==0)freq+=0.5;
}
}catch (Exception e){
}
}
}
public class SynthMain {
double[] noteFrequency = {
466.1637615181,
493.8833012561,
523.2511306012,
554.3652619537,
587.3295358348,
622.2539674442,
659.2551138257,
698.4564628660,
739.9888454233,
783.9908719635,
830.6093951599,
880.0000000000,
932.3275230362,
987.7666025122,
1046.5022612024,
1108.7305239075,
1174.6590716696,
1244.5079348883,
1318.5102276515,
1396.9129257320,
1479.9776908465,
1567.9817439270,
1661.2187903198,
1760.0000000000,
1864.6550460724,
1975.5332050245,
2093.0045224048,
2217.4610478150,
2349.3181433393,
2489.0158697766,
2637.0204553030,
2793.8258514640,
2959.9553816931,
3135.9634878540,
3322.4375806396,
3520.0000000000,
3729.3100921447,
};
boolean[] keys = new boolean[noteFrequency.length];
public double makeSound(double dTime,double SampleRate,KeyStateInterface keyStateInterface){
if(keyStateInterface.getSizeOfMidiKey()>0){
keyStateInterface.setFlush(true);
for(int i=0;i<keyStateInterface.getSizeOfMidiKey();i++) {
KeyRequest keyRequest = keyStateInterface.popMidiKey();
if(keyRequest.getCommand()==-112){
if(keyRequest.getVelocity()>0)keys[keyRequest.getArg1()] = true;
if(keyRequest.getVelocity()<1)keys[keyRequest.getArg1()] = false;
System.out.println(keyRequest.getVelocity());
}
}
}else{
keyStateInterface.setFlush(false);
}
//System.out.println("makeSound");
double a = 0.0;
for(int i=0;i<keys.length;i++){
if(keys[i]){
a+=Oscillate(dTime,noteFrequency[i],(int)SampleRate);
}
}
return a*0.4;
}
public double Oscillate(double dTime,double dFreq,int sampleRate){
double period = (double)sampleRate / dFreq;
return Math.sin(2.0 * Math.PI * (int)dTime / period);
}
}
import java.util.ArrayList;
import java.util.Stack;
public class KeyState implements KeyStateInterface{
boolean isFlush;
ArrayList<KeyRequest> keyRequest = new ArrayList<KeyRequest>();
ArrayList<KeyRequest> midiKeyRequest = new ArrayList<KeyRequest>();
#Override
public void pushKey(int keyCode, boolean press) {
keyRequest.add(new KeyRequest(KeyRequest.KEY,keyCode,press));
}
#Override
public void pushMidiKey(int command, int arg1, int velocity) {
midiKeyRequest.add(new KeyRequest(KeyRequest.MIDI_KEY,command,arg1,velocity));
}
#Override
public KeyRequest popKey() {
KeyRequest t = keyRequest.get(keyRequest.size());
return t;
}
#Override
public KeyRequest popMidiKey() {
KeyRequest t = midiKeyRequest.get(keyRequest.size());
midiKeyRequest.remove(keyRequest.size());
return t;
}
#Override
public int getSizeOfKey() {
return keyRequest.size();
}
#Override
public int getSizeOfMidiKey() {
return midiKeyRequest.size();
}
#Override
public boolean getFlush() {
boolean v = isFlush;
isFlush = false;
return v;
}
#Override
public void setFlush(boolean arg) {
isFlush=arg;
}
}
I haven't dug deep into your code, but perhaps the following info will be useful.
The SourceDataLine.write() method uses a blocking queue internally. It will only progress as fast as the data can be processed. So, there is no need to test for available capacity before populating and shipping bytes.
I'd give the SDL thread a priority of 10, since most of it's time is spent in a blocked state anyway.
Also, I'd leave the line open and running. I first got that advice from Neil Smith of Praxis Live. There is a cost associated with continually rebuilding it. And it looks to me like you are creating a new SDL for every 4 bytes of audio data. That would be highly inefficient. I suspect that shipping somewhere in the range of 256 to 8K on a line that is left open would be a better choice, but I don't have hard facts to back that up that opinion. Neil wrote about having all the transporting arrays be the same size (e.g., the array of data produced by the synth be the same size as the SDL write).
I've made a real-time theremin with java, where the latency includes the task of reading the mouse click and position, then sending that to the synth that is generating the audio data. I wouldn't claim thay my latency down to a precision that allows "in the pocket" starts and stops to notes, but it still is pretty good. I suspect further optimization possible on my end.
I think Neil (mentioned earlier) has had better results. He's spoken of achieving latencies in the range of 5 milliseconds and less, as far back as 2011.

Losing AWT DrawingSurface when Canvas is hidden

I am writing 3d rendering module for an AWT/Swing application.
To provide good FPS, I can't draw using Swing/AWT methods and graphics. Instead, I obtain the Drawing Surface from the Canvas element, and then render directly to it. Something like this:
public class Window {
private Component canvas;
private JAWTDrawingSurface ds;
public static final JAWT awt;
static {
awt = JAWT.calloc();
awt.version(JAWT_VERSION_1_4);
if (!JAWT_GetAWT(awt))
throw new AssertionError("GetAWT failed");
}
public void lock() throws AWTException {
int lock = JAWT_DrawingSurface_Lock(ds, ds.Lock());
if ((lock & JAWT_LOCK_ERROR) != 0)
throw new AWTException("JAWT_DrawingSurface_Lock() failed");
}
public void unlock() throws AWTException {
JAWT_DrawingSurface_Unlock(ds, ds.Unlock());
}
public void Init2()
{
this.ds = JAWT_GetDrawingSurface(canvas, awt.GetDrawingSurface());
try
{
lock();
// Create GL Capabilities
unlock();
}
}
It works fine when I call it the first time.
But when I hide the canvas for any reason (for example minimizing window or displaying another panel instead of Canvas), the ds variable remains the same, but it doesn't work after that.
Basically, even if I make sure I call the variable only when it is visible and on top - any call using ds will throw an exception. For example lock() function stops working.
I'm wondering why's that?
Also I tried to basically obtain a new DS if I minimize and then maximize the window again, but this also doesn't work - the new DS address is returned as it should, but I can't use that new object just as I couldn't use the original one.
There's probably something stupid I'm missing here, but I can't figure out what.
Please help me sort this out. Thank you!
The solution:
When the Canvas is hidden, call eglMakeCurrent(eglDisplay,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT) to unbind the current context.
When you need to start drawing again, you need to do something like this:
public void Reinit()
{
System.err.println("Context Reinit()");
this.ds = JAWT_GetDrawingSurface(canvas, awt.GetDrawingSurface());
try
{
lock();
try
{
JAWTDrawingSurfaceInfo dsi = JAWT_DrawingSurface_GetDrawingSurfaceInfo(ds, ds.GetDrawingSurfaceInfo());
JAWTX11DrawingSurfaceInfo dsiWin = JAWTX11DrawingSurfaceInfo.create(dsi.platformInfo());
this.display = dsiWin.display();
this.drawable = dsiWin.drawable();
eglDisplay = eglGetDisplay(display);
surface = eglCreateWindowSurface(eglDisplay,fbConfigs.get(0),drawable,(int[])null);
eglMakeCurrent(eglDisplay,surface,surface,context);
GLES.setCapabilities(glesCaps);
JAWT_DrawingSurface_FreeDrawingSurfaceInfo(dsi, ds.FreeDrawingSurfaceInfo());
}
finally
{
unlock();
System.err.printf("Unlock \n");
}
}
catch (Exception e)
{
System.err.println("JAWT Failed" + e.getMessage());
}
}
As You can see, I re-create the display and surface, but I use the previously created context for rendering, without needing to re-create it.

Sound Pool in android

I trying to make an app, with a lot of short sounds(more than 20), using Sound Pool.
But when i load that sounds, it take like 3-10 sec to load it.
How can i improve speed of loading?
Here is Function of loading
private int loadSound(String filename) {
AssetFileDescriptor assetFileDescriptor;
try {
assetFileDescriptor = assetManager.openFd(filename);
}
catch (IOException e){
e.printStackTrace();
return -1;
}
return soundPool.load(assetFileDescriptor,1);
}
Use .OGG files at the lowest sample rate you can tolerate, like 96kb/s. This will create the smallest files so they load faster. I had a lot of problems with loading/playing sounds using .WAV files, they all went away when I converted them to .OGG files.
Do your sound loading off the main UI thread. If you need to know when the sound is loaded, use an OnLoadCompleteListener:
mSoundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
Log.d(TAG, "soundpool onLoadComplete, sampleId = " + sampleId + ", status = " + status);
// ... sound is ready to play
}
});
// sound load should happen off the UI thread
new Thread() {
#Override
public void run() {
mSoundId = mSoundPool.load(getActivity(), R.raw.sound1, 1);
// ... load other sounds here
}
}.start();
I embedded the audio files so I could use raw resource ids. If you have to load from files, grab all your filenames and send them off to a load method inside a non-UI thread.

libgdx lag when sound.play() while collecting apple

I'am doing simple libgdx game. I have lag (game stop for 0. 5 sec) when i use sound.play()
edit this bug apear on android 4.0 on 2.3 everything is running fine.
method. I play sound by this code:
if(CollisionDetector.detect(touchArea, hoodie.getTouchArea())){
GameScreen.totalScore++;
setPosition();
System.out.println("played");
Assets.eatSound.play();
}
And i use this method to load sound:
static long waitForLoadCompleted(Sound sound,float volume) {
long id;
while ((id = sound.play(volume)) == -1) {
long t = TimeUtils.nanoTime();
while (TimeUtils.nanoTime() - t < 100000000);
}
return id;
}
What am i doing wrong? Or what can i do to fix this lag ?
edit:
I have just tried to do thread with sound.play() but it also doesn't work:
new Thread(new Runnable() {
#Override
public void run() {
// do something important here, asynchronously to the rendering thread
// post a Runnable to the rendering thread that processes the result
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
// process the result, e.g. add it to an Array<Result> field of the ApplicationListener.
eatSound2.play();
}
});
}
}).start();
My Sound asset class looks like this but i still have lag with sound.
package com.redHoodie;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.utils.Disposable;
public class SoundEffect implements Disposable {
private static final int WaitLimit = 1000;
private static final int ThrottleMs = 100;
Sound eatSound;
Sound endSound;
public SoundEffect(){
eatSound = Gdx.audio.newSound(Gdx.files.internal("eatSound.ogg"));
endSound = Gdx.audio.newSound(Gdx.files.internal("sadend.wav"));
checkedPlay(eatSound);
}
protected long checkedPlay (Sound sound) {
return checkedPlay(sound, 1);
}
protected long checkedLoop (Sound sound) {
return checkedLoop(sound, 1);
}
protected long checkedPlay (Sound sound, float volume) {
int waitCounter = 0;
long soundId = 0;
boolean ready = false;
while (!ready && waitCounter < WaitLimit) {
soundId = sound.play(volume);
ready = (soundId != 0);
waitCounter++;
try {
Thread.sleep(ThrottleMs);
} catch (InterruptedException e) {
}
}
return soundId;
}
protected long checkedLoop (Sound sound, float volume) {
int waitCounter = 0;
long soundId = 0;
boolean ready = false;
while (!ready && waitCounter < WaitLimit) {
soundId = sound.loop(volume);
ready = (soundId != 0);
waitCounter++;
try {
Thread.sleep(ThrottleMs);
} catch (InterruptedException e) {
}
}
return soundId;
}
#Override
public void dispose() {
// TODO Auto-generated method stub
}
}
I had the same problem. It was because my .mp3 file was too short. Mine was 0.167 seconds long. I added 1.2 seconds of silence with Audacity, and it fixed the problem.
Lately I run into the same issue (except I'm using wav instead mp3 files). My app was lagging when I play many (like 10 or 20) sounds at the same time (same render method). "Solved" this by playing only 1 sound at the time. Generally it's hard to distinct many sounds at the same time. Also on desktop it works fine, but problem appears on android (9 or 8).
If someone still facing this issue as me there is the alternative solution with one limitation: no option to use sound id.
You can change default LibGDX behavior and use AsynchronousAndroidAudio by overriding this method in your AndroidLauncher class:
#Override
public AndroidAudio createAudio(Context context, AndroidApplicationConfiguration config) {
return new AsynchronousAndroidAudio(context, config);
}
See the official documentation for more info and also the pull request
Also, if for any reasons you need sound id you can take this implementation as an example and find a workaround for your project.
Fix is available starting from LibGDX 1.9.12

Disable screen saver / sleep mode through a website

I am working on a web application that needs to be active on the monitor sometimes for hours without anyone touch the computer.
The problem is that some computers have their screen saver, or worse - sleep mode while their inactive.
I'm trying to think of a way to bypass it. I searched for java applets or maybe a flash file that does only that. I found nothing, unfortunately.
I'm sorry for the too general question but I'm pretty helpless with this subject
I've written the Java applet for you. It will move the mouse cursor one pixel to the right and back every 59 seconds, effectively preventing the screen saver from kicking in.
Note that because of security restrictions this applet will need to be signed and granted the createRobot permission to work on the client, otherwise it will fail to initialize the Robot class. But that's a problem outside this question's scope.
import java.applet.Applet;
import java.awt.*;
import java.util.Timer;
import java.util.TimerTask;
/**
* Moves the mouse cursor once in a minute to prevent the screen saver from
* kicking in.
*/
public class ScreenSaverDisablerApplet extends Applet {
private static final int PERIOD = 59;
private Timer screenSaverDisabler;
#Override
public void start() {
screenSaverDisabler = new Timer();
screenSaverDisabler.scheduleAtFixedRate(new TimerTask() {
Robot r = null;
{
try {
r = new Robot();
} catch (AWTException headlessEnvironmentException) {
screenSaverDisabler.cancel();
}
}
#Override
public void run() {
Point loc = MouseInfo.getPointerInfo().getLocation();
r.mouseMove(loc.x + 1, loc.y);
r.mouseMove(loc.x, loc.y);
}
}, 0, PERIOD*1000);
}
#Override
public void stop() {
screenSaverDisabler.cancel();
}
}

Categories

Resources