Better optimization for changing audio's volume JavaSwing - java

Been testing a new system for increasing/decreasing the audio within my JavaSwing application using a fade in and fade out effect. This works on one hand though by doing my own research, it's not as optimal as one hoped to be since it utilizes Thread.sleep(x); rather than using Timer(); from JavaSwing.
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
value = (value <= 0.0) ? 0.0001 : ((value > 1.0) ? 1.0 : value);
try {
float db = (float) (Math.log(percent) / Math.log(10.0) * 20.0);
gainControl.setValue(db);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void shiftVolumeTo(double value) {
value = (value <= 0.0) ? 0.0001 : ((value > 1.0) ? 1.0 : value);
targetDB = (float)(Math.log(value)/Math.log(10.0)*20.0);
if (!fading) {
Thread t = new Thread();
t.start();
}
}
public static void run() {
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
fading = true;
if(currDB > targetDB) {
while (currDB > targetDB) {
currDB -= fadePerStep;
gainControl.setValue(currDB);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} else if (currDB < targetDB) {
while(currDB < targetDB) {
currDB += fadePerStep;
gainControl.setValue(currDB);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
fading = false;
currDB = targetDB;
}
public static void volTest() {
setVolume(1);
shiftVolumeTo(.2);
run();
}
Again, this works properly when run(); is called, but it puts the entire application to sleep within the duration of the while loop's runtime. Which is what I'm having an issue with. I've tried setting up a JavaSwing Timer(); within the code though I couldn't figure out how to set it up properly to make the delay run like the Thread.sleep(x); method. Whether it is adding the code from run(); into the ActionListener created or utilized by the timer or just having run(); within the ActionListener. Unlike Thread.sleep(x);, the program will just jump values without taking it's time to decrease the volume as there's no delay between the incremental increase/decrease of the while loop.
What would be the optimal way to utilize a JavaSwing Timer(); that would work similar to a Thread.sleep(x); in this situation?

I'm not clear what you are doing from the given code. I suspect you are mixing up aspects of the util.Timer with the swing.Timer (not uncommon).
With the util.Timer, one extends TimerTask, and within that, one overrides the run() method. The run() method is never static, afaik.
With the swing.Timer, the code to be executed resides in the actionPerformed() method of the ActionListener.
Another alternative, and likely a better way to manage the separate thread would be to use a ScheduledThreadPoolExecutor.
I'd consider using the util.Timer in this case. I think the calls to change the value of the FloatControl could be set up to be thread safe if you are careful about limiting the calls to a single sound at a time. (Here is a link for more about Swing's Event Dispatch Thread) It would be necessary to use the swing.Timer if thread safety is an issue.
But you understand here that you can only fade in or out a single sound at a time, and ALL sounds playing at that moment will also be affected? The FloatControl.MASTER_GAIN controls all playing sounds. Also, I don't think there are no guarantees that the FloatControls are implemented on a given computer. There are many listed in the documentation that I have discovered do not function on various PCs I own.
Another issue is that sometimes it can be difficult to find the best interval for the updates and corresponding amount to vary the volume. Sometimes we get as soft, fast sequence of clicks, like the sound of scraping a thumbnail over the tines of a comb, if the individual volume changes are too large.
I'd like to mention a library for you to consider that bypasses the use of the FloatControl: AudioCue. The class is basically a rewrite of the Clip but with a built in, dynamic, volume controller. When you alter the volume of a given playback instance, it will only affect that single instance. (The class supports playing back concurrent instances.) All the amplitude computations are done internally, within the code of the class.
The library can be run as a Maven resource. The project is a work in progress: I've just added a lot of test code that I'm about to push to the master. I'm working to publish it on Maven Central. (Learning as I go.) But if you fork the project and run the Maven install command, it will create a resource that you can reference locally via the Maven pom file.
I'm considering adding an optional duration argument to the dynamic controls. Then (if implemented) one could specify both the desired volume and the number of frames or milliseconds over which the change should be applied. Seems like a good addition for version 1.2 (after 1.1 is up on Maven central!)
With AudioCue, changes are applied per individual frames. I'm not sure what the situation is with FloatControl and Clips. The changes might be limited in granularity to some internal buffer size.

Related

How to detect a pressed key globally, in a window without focus in java? [duplicate]

I'm making a small program in Java using the Robot class. The program takes over the mouse. while in the course of debugging if it starts acting in a way that I don't want it's hard to quit the program, since I can't move the mouse over to the terminate button in eclipse, and I can't use hotkeys to hit it because the mouse is constant clicking in another window, giving that window focus instead.
What I'd like to do is just hook up a keylistener so that when I hit q I can quit the program, but the only way I know how to do this involves making a window, and that window needs focus to capture the input. Is there a way to listen for keyboard or mouse input from anywhere, regardless of what has focus?
There is a library that does the hard work for you:
https://github.com/kwhat/jnativehook
This is not a trivial problem and Java doesn't give you a way to do it elegantly. You can use a solution like banjollity suggested but even that won't work all the time if your errant mouse clicks open another fullsized window currently open in your taskbar for example.
The fact is, Java by default gives developers very little control over the OS. This is due to 2 main reasons: security (as citied by java documentation) and the fact that different operating systems handle events completely differently and making one unified model to represent all of these would probably not make a whole lot of sense.
So to answer your question, I imagine what you want is some kind of behaviour for your program where it listens for keypresses globally, not just in your application. Something like this will require that you access the functionality offered by your OS of choice, and to access it in Java you are going to need to do it through a Java Native Interface (JNI) layer.
So what you want to do is:
Implement a program in C that will listen for global keypresses on your OS, if this OS is Windows than look for documentation on windows hooks which is well docuemented by Microsoft and MSDN on the web and other places. If your OS is Linux or Mac OS X then you will need to listen for global keypresses using the X11 development libraries. This can be done on an ubunutu linux distro according to a Howto that I wrote at http://ubuntuforums.org/showthread.php?t=864566
Hook up your C code to your Java code through JNI. This step is actually the easier step. Follow the procedure that I use in my tutorial at http://ubuntuforums.org/showthread.php?t=864566 under both windows and linux as the procedure for hooking up your C code to your Java code will be identical on both OSes.
The important thing to remember is that its much easier to get your JNI code working if you first code and debug your C/C++ code and make sure that it is working. Then integrating it with Java is easy.
Had same problem. In my case, robot just controlled a single Windows App, that was maximized. I placed these lines at top of main loop driving the robot:
Color iconCenterColor = new Color(255,0,0); // if program icon is red
if (iconCenterColor.equals(robot.getPixelColor(10,15)))
throw new IllegalStateException("robot not interacting with the right app.");
To cancel the robot, just alt-tab to another app. Works great for a simple one app driving robot.
Start the program from a command line in a terminal and use Ctrl-C to terminate it.
(As mentioned by #MasterID and shown on JNativeHook's documentation for native keyboard input detection {main GitHub project here}),
This code should be enough to listen to any key without app focus (press and/or release):
>>Remember to add the jnativehook library in your project to be able to use all its utilities.<<
public class yourClass implements NativeKeyListener {//<-- Remember to add the jnativehook library
public void nativeKeyPressed(NativeKeyEvent e) {
System.out.println("Key Pressed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}
public void nativeKeyReleased(NativeKeyEvent e) {
System.out.println("Key Released: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}
public void nativeKeyTyped(NativeKeyEvent e) {
System.out.println("Key Typed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}
public static void main(String args[]){
//Just put this into your main:
try {
GlobalScreen.registerNativeHook();
}
catch (NativeHookException ex) {
System.err.println("There was a problem registering the native hook.");
System.err.println(ex.getMessage());
System.exit(1);
}
GlobalScreen.addNativeKeyListener(new yourClass());
//Remember to include this^ ^- Your class
}
}
For this particular problem, use the nativeKeyPressed method like this:
public void nativeKeyPressed(NativeKeyEvent e) {
System.out.println("Key Pressed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
if (e.getKeyCode() == NativeKeyEvent.VC_Q){
System.exit(1);
}
}
Note that JNativeHook by default shows a lot of stuff in your console that you might not want, to change that, just add this right before the try-catch that you used in the main function as shown (this is also going to turn off warning and error messages, more info here):
//(From here)
Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
logger.setLevel(Level.OFF);
logger.setUseParentHandlers(false);
//(To there-^)
try {
GlobalScreen.registerNativeHook();
}
catch (NativeHookException ex) {
System.err.println("There was a problem registering the native hook.");
System.err.println(ex.getMessage());
System.exit(1);
}
Disclaimer: I know this question was solved years ago, I just hope someone finds this a little easier to find/use.
Have your program open a second window which displays underneath your main window but is maximised, then your errant mouse clicks will all be received by the maximised window, and it can receive your keyboard input.
Here's a pure Java way to do it to solve the problem you've described (not the KeyListener problem... the quit test early when using robot problem):
Throughout your test, compare the mouse position with one that your test has recently set it to. If it doesn't match, quit the test. Note: the important part of this code is the testPosition method. Here's code that I used recently:
public void testSomething() throws Exception {
try {
// snip
// you can even extract this into a method "clickAndTest" or something
robot.mouseMove(x2, y2);
click();
testPosition(x2, y2);
// snip
} catch (ExitEarlyException e) {
// handle early exit
}
}
private static void click() throws InterruptedException {
r.mousePress(InputEvent.BUTTON1_DOWN_MASK);
Thread.sleep(30 + rand.nextInt(50));
r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
Thread.sleep(30 + rand.nextInt(50));
}
private static void testPosition(int x2, int y2) throws ExitEarlyException {
Point p = MouseInfo.getPointerInfo().getLocation();
if(p.x != x2 || p.y != y2) throw new ExitEarlyException();
}

can I control the refresh rate of a Java listener?

I'm struggling with this issue since some days ago and I'm not able to find a solution.
I have a listener which receives market data (orders at bid and ask). If market is quiet (pre-market or post-market (low volatility)) everything works fine. But once the market is open the listener receives events too fast. So after a couple of minutes my app freezes.
Right now the listener only assigns the received data to a var.
orderBookBid.getBuyOrders().addListener(new ObservableListModelListener<Order>() {
#Override
public void modelChanged(final Change<? extends Order> change) {
System.out.println("bid event");
bidChange = change.getSource();
}
});
The program only freezes when uses real data. When market is closed and uses test data from a local file works fine.
Is there any way to set the maximum number of events per second? Or any way to ignore events for a short time period?
Any idea on how can I handle this would be very appreciated.
Thanks.
You could put a load balancer in your application, that way it will create a queue and will not freeze the application.
If you want to let go some events, in the logic of your listener, you should have something that check if it's been X time since the last time you managed the event.
private long timeSinceLastEventManaged = 0;
private final static long MINIMUM_TIME = 2000; //2 seconds
In your listener
public void modelChanged(final Change<? extends Order> change) {
long timeSystem = System.currentTimeMillis();
if(timeSystem - timeSinceLastEventManaged > MINIMUM_TIME){
//do your stuff
timeSinceLastEventManaged = timeSystem;
}
}
First of all you should get rid of the println as it is really slow
The rest depends on what you are doing. Right now it seems that you are just getting the value and writing it to a variable. You will only see the latest change that way and if that is what you want the solution #TyMarc suggested will work fine.
If what you showed us is just an example and you really need every change things get a bit more complicated. Your modelChanged method should be changed to add the current value to a queue (e.g a LinkedList or Stack).
public void modelChanged(final Change<? extends Order> change)
{
syncronized(syncObject)
{
//add to your preffered queue
syncObject.notifyAll()
}
}
This frees your listener from the real work and it can keep collecting data.
I added a syncronized as someone has to do the work. For this you can use a Thread that runs something like this:
Order current;
while(keeprunning)
{
syncronized(syncObject)
{
if(queue.hasNext())
{
current = queue.getNext()
}
else
{
Thread.wait()
}
}
//do the real work here
}
Now someone else has the problem. Literally. If the Thread can't handle the inflow of data the queue will grow in size until you run out of memory or hit some other limit. But that's another story.
And yes, nothing of this will compile as I only wanted to show an example

delay processing in java application

Can someone please help me out. I have an application that creates a file to be processed by an external application. I need to somehow delay my code to wait until there is a file created from the external application. But I am having issues finding anything that cause a delay in the Java.
Thanks in advance
Pretty rudimentary and crude but technically, Thread.sleep() induces delay.
As per comment, simple, but crude:
File f = new File("your-file.txt");
for (;;)
{
try
{
if (f.isFile())
{
break;
}
}
catch (Exception e)
{
e.printStackTrace();
// Or some other appropriate
// handling of the exception.
}
try
{
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
delay my code to wait until there is a file created
It is better to activate methods in your code when something happens. To do that I would suggest a separate Thread that runs and checks the condition, then calls your apps. method if needed. For an app. with a GUI, this would typically be achieved using a Swing Timer, but I believe it can also be achieved using a java.util.Timer.
you can try
while(!file.exists());
Instead of polling for a file change with a timer, you could just use the Java file API and wait for a file modification event. Here are the docs:
http://docs.oracle.com/javase/tutorial/essential/io/notification.html
and here is a small example:
http://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java

Playing clips in sequence with possible interruptions from other clips (using javax.sound)

I would like to create a simple PlayClipManager class to manage the playback of audio clips. It would have the following two methods:
public void addAndPlay(Clip clip)
{
...
}
public void interruptAndPlay(Clip clip)
{
...
}
The first method should add a clip to a queue and play it as soon as the other clips in the queue have finished. The second method accepts a clip that interrupts the current playback, flushes the queue and adds itself to it (where it plays immediately because it's the only clip in the queue).
This would be easy if one had access to the Java Thread managing audio playback, but unless I'm mistaken, I don't think there's one (there is an AudioSystem class but it is of no help for that purpose). I saw there were posts here showing how one can use a LineListener to check when a clip has finished playing, but I'm not sure how I can use that concretely in my example. Also, with the method to interrupt a clip, I guess there might also be some concurrency problems.
Any help on how I could tackle this very appreciated.
Thanks.
If I'm not mistaken, a Clip bundles the playback line with the audio data.
Do you plan to queue up actual Clips? How big are they? That can take up a LOT of memory. If you are storing the addresses of the sound files, and making/loading new Clips at the time of playback, you might be better off using SourceDataLine, as it will launch more quickly. A Clip has to load the entire file into memory before it can start playing.
Above is the tutorial for adding a line listener. I think it is just myClip.addLineListener(YourLineListener). You can code the LineListener to alert whatever is managing the Queue to fire up the next Clip, and use this same LineListener for all the Clips.
Or maybe something like this would be helpful, call it on a new thread when you are ready to play the queue, and have the LineListener be part of the runnable that plays the Clip.
class PlayClipRunnable implements Runnable, LineListener {
private Clip currentClip;
private QueueManager queueManager;
public PlayPadRunnable (Clip currentClip,
QueueManager myQueueManager) {
this.currentClip = currentClip;
this.myQueueManager = myQueueManager;
}
public void run()
{
try
{
currentClip.addLineListener(this);
currentClip.start();
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Override
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
queueManager.clipIsStopped();
}
}
}
I'm not sure about when the Clip should be opened. I'm also not sure how to put in a hook for interrupting the Clip. Maybe if the QueueManager does a currentClip.close() that will work? Having the currentClip be volatile in that case might be helpful. But I am getting out of my depth.
I hope the ideas are worth exploring and lead you to your solution.

java mouse capture

How do I capture the mouse in a Java application so that all mouse events (even ones that happen if the mouse is moved outside the app window) are seen by the Java app? This is like the Windows SetCapture function.
You don't; the JVM, or more specifically AWT, only generates input events when Windows sends it input events, and the JVM only registers for those events which occur within it's window.
You might be able to pull it off using JNI, but then again you might not - it will depend if you can get your hands on the information required by the underlying API. Since that's likely to be a window handle, you won't have what you need to invoke the API, even from JNI.
You have to hook the mouse at the operating system level. Windows(Swing, AWT, MFC, etc....) are only aware of mouse movements within their bounds. If you need a way to access the current position of the mouse regardless of where the mouse is on the screen, you need to write an Input Hook: Input Hooks. You can then use JNI or read the STDOUT from a win32 console application designed to use the Input Hook to forward mouse events/positions to your Java code. I use the latter method in some of my user interface test cases with success.
I needed to do that too!
I after searching the web I found that its possible to use the moveMouse in java.awt.Robot.
Basically use Robot to move the mouse into center of your frame. If user moves it: check how much and move it back to center.
No additional packets or JNI are needed for this (my demo uses JOGL and vecmath but that's for the graphics). Is it good enough? Try the demo, its here:
http://www.eit.se/hb/misc/java/examples/FirstPersonJavaProtoGame/
If the above solution is not good enough then perhaps lwjgl is what you need:
http://www.lwjgl.org/javadoc/org/lwjgl/input/Mouse.html
/Henrik Björkman
Just use the system-hook library available on gitHub https://github.com/kristian/system-hook
This only apply to windows-based systems but really simple to implement.
Sample usage
import lc.kra.system.keyboard.GlobalKeyboardHook;
import lc.kra.system.keyboard.event.GlobalKeyAdapter;
import lc.kra.system.keyboard.event.GlobalKeyEvent;
public class GlobalKeyboardExample {
private static boolean run = true;
public static void main(String[] args) {
// might throw a UnsatisfiedLinkError if the native library fails to load or a RuntimeException if hooking fails
GlobalKeyboardHook keyboardHook = new GlobalKeyboardHook();
System.out.println("Global keyboard hook successfully started, press [escape] key to shutdown.");
keyboardHook.addKeyListener(new GlobalKeyAdapter() {
#Override public void keyPressed(GlobalKeyEvent event) {
System.out.println(event);
if(event.getVirtualKeyCode()==GlobalKeyEvent.VK_ESCAPE)
run = false;
}
#Override public void keyReleased(GlobalKeyEvent event) {
System.out.println(event); }
});
try {
while(run) Thread.sleep(128);
} catch(InterruptedException e) { /* nothing to do here */ }
finally { keyboardHook.shutdownHook(); }
}
}

Categories

Resources