Java sound api - Scanning for midi devices - java

I'm working on a java project that receives midi events from midi hardware using the javax.sound.midi library. In the documentation, it says that MidiSystem.getMidiDeviceInfo() returns a list of all connected midi hardware. It works for me, but the problem is, it only works once. It takes a moment the first time to actually scan for the devices, but each time after that it will immediately return that same list even if new devices have been connected. Is there a way to force it to rescan? It will rescan if the application is restarted, but I don't want my users to have to restart if they connect a new midi device.
BTW, I'm using Mac OS X... it's been pointed out that behavior may be different for different OS's.

The MidiSystem.getMidiDeviceInfo() gets the full providers list, and extracts the info of the device from each provider.
The MIDIs provider list is recovered from the JDK underlaying class com.sun.media.sound.JDK13Services, through the static method getProviders()
public static synchronized List getProviders(Class serviceClass)
Obtains a List containing installed
instances of the providers for the
requested service. The List of
providers is cached for the period of
time given by cachingPeriod . During
this period, the same List instance is
returned for the same type of
provider. After this period, a new
instance is constructed and returned.
The returned List is immutable.
So, it seems that this class holds thee Providers list in a cache, wich will be reloaded after a certain period. You can set this period to a custom value using the method setCachingPeriod(int seconds). As long as I know, the default caching period is set to 60 seconds.
As an example, to refresh this cache every second, you coud add this line to your code:
com.sun.media.sound.JDK13Services.setCachingPeriod(1);
Please, note that this solution makes use of a Sun propietary class, so it could not be 100% portable.

Lacking any MIDI devices on my work PC, or indeed any kind of Mac, I doubt I'll be able to test it properly, but...
The MidiSystem class seems to use com.sun.media.sound.JDK13Services.getProviders(Class providerClass) to find the list of devices on the system. The API docs for this class state that the list is recreated on a successive call outside of a cachingPeriod, which can be conveniently set by calling setCachingPeriod(int seconds).
With any luck you can just call this once at the start of your application and set it to 5 seconds or something, and it'll magically work. However, the docs also state "This method is only intended for testing.", so I'm not sure quite how effective this approach will be.
Hopefully this is enough to get you started, and I'll keep poking around in the meantime to see if I can find a cleaner way to do this.

I answered this is Update list of Midi Devices in Java as well, but for folks who wind up here, there's now a library that supports this correctly: https://github.com/DerekCook/CoreMidi4J
The library acts a device provider for the MIDI Subsystem, so it's basically a drop-in and all your existing code will work.
I am not the author, but it works well for my needs, and it took a fair bit of searching to find, so I'm posting it here for others who encounter the problem.

I found a solution which uses the JavaFX thread. For some reason this works at least on MacOSX. On a normal thread it doesn't work.
import fx.FX_Platform;
import javafx.embed.swing.JFXPanel;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
public class miditest {
static public void main( String[] args ) {
// **** Just to init FX platform
new JFXPanel();
new Thread( () -> {
for( int ix=0; ix<1000; ix++ ) {
try {
Thread.sleep(2000);
} catch( InterruptedException e ) {
}
FX_Platform.runLater( () -> {
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
System.out.println("FOUND: " + infos.length);
for( MidiDevice.Info midiinfo : infos ) {
System.out.println(midiinfo);
}
});
}
}).start();
}
}

This sounds like is could be an OS specifx bug but I can think of a get around.
In java you can run external commands to the OS. (A quick google, gave me this example http://www.javafaq.nu/java-example-code-186.html it looks OK and gives you the idea).
On checking for new devices you could send an external command to run a simple java program that quickly queries the midi devices using MidiSystem.getMidiDeviceInfo() and outputs the results to a text file or you could grab the output from the BufferedReader object.
Also remember that the external program used to query midi devices doesn't have to be written in Java incase Java causes you more problems. Alternatively you could just query the OS for connected devices and use grep to filter the results.
Hope this helps.

Related

Using Java to gather specific system information: monitor (screen) details

I know it is possible to get system information in Java and have searched SO for this particular question but have come up empty.
Question:
Can I gather complete system information about all attached monitors? Particularly I am hoping to get a unique ID, model number, or manufacturer of each monitor.
Wayan Saryada for example demonstrated a simple example here that gets basic information about all connected monitors. Code follows to protect from link rot:
//
// Get local graphics environment
//
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] devices = env.getScreenDevices();
int sequence = 1;
for (GraphicsDevice device : devices) {
System.out.println("Screen Number [" + (sequence++) + "]");
System.out.println("Width : " + device.getDisplayMode().getWidth());
System.out.println("Height : " + device.getDisplayMode().getHeight());
System.out.println("Refresh Rate: " + device.getDisplayMode().getRefreshRate());
System.out.println("Bit Depth : " + device.getDisplayMode().getBitDepth());
System.out.println("");
}
This code however produces nothing unique. Its just generic information that is helpful but does not meet my end goal.
Use Case / End Goal:
My intentions is to make a portable application that tracks (detects) what computer/ computer setup you are using and displays the appropriate desktop. One example is on my work computer with a large monitor it lays out my desktop one way and then on my laptop it hides some things; long story short it would show an alternate desktop display (less icons, only the ones I need for work/ home).
I have all that extra stuff worked out but I need a way to track not just what computer I am on but which monitors I have attached at the time. Essentially a "MAC address" for attached monitors; I know that is not a thing. This way on a triple monitor setup for example my application knows what goes where. Then if I remove one monitor it knows what to change to.
So long story short there just is no way to accurately detect in Java which monitor is which in the GraphicsDevice API. There are several other ways to detect this information but again Java runs into the same problem. Java just auto increments the monitors it finds like so:
Display0,
Display1,
Display2
...And so on.
Each time the computer turns on different monitor assignments can happen and each time a monitor turns off the order can change. The same is true if the graphics driver crashes or reboots while in use.
One Solution
This does not solve my original issue: The OP's questions. However I know it is extremely hard to get full human readable system information with Java, especially all attached monitors. I put in a request to dbwiddis on GitHub and he was able to add this feature to Oshi. His Java library pulls everything you need to know about every attached monitor to a computer. A perfect all in one solution for Network Admins.
The Issue Still / Hack
There still is no way (including using other API's accessible through other programming languages) to detect which monitor is which. The "MAC Address" of all your attached monitors if you will. The only way to do this reliably (really a hack) is to pop up a terminal that outputs information that you then can grab with Java. This way Java can manually make the matches. It can go out to Display2 and read the terminal window that is open on it and now we know which monitor is Display2.
I have no code for this right now because it is extremely unreliable and not guaranteed to be cross OS compatible. It should work fine in windows but your will need to execute a batch file or powershell script to get the terminals on the monitors you want.
Just look at the GraphicsDevice API:
https://docs.oracle.com/javase/7/docs/api/java/awt/GraphicsDevice.html#getIDstring%28%29

ScreenDevice.getIDstring() strange value

I am creating a Java application that will run on both Linux and Windows. The application will execute native code for multiple-monitor configurations. Because of this, I want to pass the monitor's ID from Java to the native code. This has lead me to Java's ScreenDevice.getIDstring().
Javadocs claim that this method is useful for debugging, but that it also uniquely identifies a monitor. For Linux devices, it returns a usable ID string that allows the native code to quickly retrieve the desired monitor object.
On Windows, however, the method simply returns /display0 for the first display, and then counts upwards for every following display (regardless if a graphics card contains both monitors, or if the monitors are on separate graphics cards).
When it comes to Windows C++ code, I have tried using EnumDisplayDevices and looking at the respective DeviceIDs and DeviceStrings. These do not match the values of Java:
First Monitor - Java = /display0, Windows = \\.\DISPLAY1
Second Monitor - Java = /display1, Windows = \\.\DISPLAY7
I am really confused as to where this /display# ID value is coming from... Where can I acquire the same /display# value when running native Windows C++ code?
Note: It would technically be possible to cycle through all existing displays to try and match the X/Y/width/height between the OS native code and Java, but this would be a lot of work and not very efficient. I would see this as a possible solution, but it is not very ideal.

JavaFx Audio Output Selection

I'm looking for a way to specify an output device with JavaFx
I have a similar issue as this question: JavaFX specific Audio Output, but with different needs.
I need a way to get a list of all possible Audio Output devices (like the one you see in your user preferences) and allow the user to select which one they want the audio to come out of in JavaFx. This seems like a really basic feature that should be in any music/media API, and is essential for most audio software.
I'm using the MediaPlayer in JavaFx, though if there is another class I'm happy to use it. Note though that I need the same functionality for video (specifying audio output), so I need a class/solution that works for both.
If there's something in JavaFx 8 that will help, I can always wait until it is released.
What I really expected there to be was the same thing as the Screens class:
Screen.getScreens() // Gets an observable list of all screens.
I'm fine with hackish solutions. Really, anything that works.
For years it has been a very unfortunate limitation of the Java implementation for OS X, being BTW particular for that platform, that "Java Sound Audio Engine" is the only programmatically available output audio line. In consequence, whatever you send to this line, i.e. out from any java application that you make, will always be routed to what has been set as the default output in the OS X, typically internal speakers. So the JSAE is just Java terminology for "default audio out". To our understanding - sadly - this is still the case with latest release.
Why unfortunate ? Because it effectively disables even humble audio routing. We are working with these matters on a daily basis, and it calls for all sorts of added complexity. There are work arounds, but via third party apps as SoundFlower and HiJack Pro. www.soundPimp.com for example.
As assylias has pointed out getmixerinfo method can help you
Info[] mixerInfo = AudioSystem.getMixerInfo();
for(int i = 0; i < mixerInfo.length; i++)
{
System.out.println(mixerInfo[i].getName());
}
You can explore further details here

How to benchmark android application?

At work I am using Ubuntu and at home I am using windows 7. I would like to know how can I benchmark my android application on Ubuntu and windows 7.
You can use DDMS and Systrace to break down what your app is doing and for how long.
As for "benchmarking," what do you mean by that? Do you want to see how long it takes to do something in your app?
It's usually more useful to just make sure you're doing things in the fastest way possible, rather than within a certain time window.
I wrote a code to specifically benchmark specific part of the code that I want. you can find it here:
http://farzad.devbro.com/android_benchmark/Devbro_Benchmark.java
Here is an example of the code to use:
Devbro_Benchmark.markStart("Label2"); //mark a begining
for(int i=0;i<1000;i++)
{
//you can create multiple markers at once. If you use the same marker name
//it will simply add up the times for you
Devbro_Benchmark.markStart("Label1");
//some random code
Devbro_Benchmark.markEnd("Label");
}
Devbro_Benchmark.markEnd("Label2"); // mark an ending
//once you are done with your markers you can display an extensive report which will be
//shown using the Log.d
Devbro_Benchmark.print_report();
//once you are done you can reset before redoing it.
Devbro_Benchmark.reset();
There are now two Jetpack benchmarking libraries. from the Android team.
Macrobenchmarking: Allows you to benchmark entire workflows
Microbenchmarking: Enables benchmarking specific code in isolation.

Is constant polling in RXTX necessary?

While trying to figure out this problem (any help there is appreciated), I ran RXTX while monitoring its activity using PortMon and noticed that RXTX constantly checks if data is available, even when the Java client reads from the gnu.io.SerialPort object only through a SerialPortEventListener.
Why is this? Is it a poor implementation choice by the RXTX folks, a poor API choice by Sun (since RXTX follows the javax.comm API), or a limitation of running Java supported by native code?
Hyperterminal, on the other hand, does no polling (and works without a problem). Does it have access to some hidden Windows system calls that let it do this?
No it's not due to the javax.xomm API. Rxtx can be used through that API or not by the way.
Rxtx internals are a bit different/weird though and has some bugs.
Short version, this is how it is supposed to work: You have two parameters to play with: timeout and threshold. According to the source code setting the timeout to 0 (none) and threshold to 1 (requiring at least 1 byte before returning) should give us normal, by InputStream defined, blocking reads.
The problem is that even when setting it up like this there is a bug in the current stable release (2.1.7r2). The threshold parameter is always set to 0! From the source code:
/* TESTING ttyset.c_cc[ VMIN ] = threshold; */
ttyset.c_cc[ VMIN ] = 0;
The confusing part is that this was also the case in 2004 and reported on the mailing list and fixed, but it was either not really fixed or has come back again (a regression). There is actually a new bug report that for some reason I couldn’t find at first. I eventually found it going throw the pre-release package source code and found an otherwise not published change log (the web page doesn’t show change logs after the last stable version, its available in CVS though).
Solution
It is fixed on HEAD, so you can use the latest pre-release version
(2.2-series) or compile it from CVS.
Make an ugly workaround along the lines of:
int read(InputStream in) throws IOException {
int b;
while ((b=in.read()) == -1) {
try { Thread.sleep(10); } catch (InterruptedException e) { }
}
return b;
}
Then you do: read(in) instead of in.read().
I actually wrote a blog entry about this 2 years ago so I wouldn't forget.

Categories