Head First Java - creating the first music player error - java

I am having trouble with creating a very small music player following the HeadFirstJava recipe. I followed the code in the book but it still has some bugs... When I first compiled it it gave me this error:
Dez 15, 2013 4:13:02 PM java.util.prefs.WindowsPreferences
WARNING: Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5.
After googling the error I found out that I should create HKEY_LOCAL_MACHINE\Software\JavaSoft\Prefs and also give full permision for JavaSoft on regedit. That did solve the problem but only partially. The code compliles, the sound is made by the computer but the program will not close util I hit CTRL + C. Here is the code:
import javax.sound.midi.*;//importam pachetul sound.mini
public class MiniMiniMusicApp {
public static void main (String [] args) {
MiniMiniMusicApp mini = new MiniMiniMusicApp();
mini.play();
} //inchidem main
public void play() {
try {
Sequencer player = MidiSystem.getSequencer();
player.open();
Sequence seq = new Sequence(Sequence.PPQ, 4);
Track track = seq.createTrack();
//ShortMessage first = new ShortMessage();
//first.setMessage(192, 1, 102, 0);
//MidiEvent noteOn1 = new MidiEvent(first, 1);
//track.add(noteOn1);
ShortMessage a = new ShortMessage();
a.setMessage(144, 1, 44, 100);
MidiEvent noteOn = new MidiEvent(a, 1);
track.add(noteOn);
ShortMessage b = new ShortMessage();
b.setMessage(128, 1, 44, 100);
MidiEvent noteOff = new MidiEvent(b, 16);
track.add(noteOff);
player.setSequence(seq);
player.start();
} catch (Exception ex) {
ex.printStackTrace();
}
} //inchidem play
}
I would like to mention that I am not using any GUI and that I am a total novice. Any help would be appreciated. Thank you.

The MIDI sequencer is a special thread that runs in the background. As long as it is active (or, in fact, any non-daemon thread is active), Java will not exit on its own.
Try adding this after the player.start(); line:
Thread.sleep(5000);
player.close();

Command Prompt doesn't support the multi-programming. So when you run the above program, the program is in the running state, after it's play() method and wait for the some event to occur(like another Framed based program in java).
you can write System.exit() after putting some delay(so that your voice would come). Currently you are killing the process from the DOS.

The docs [MidiDevice.open()] for player.open() says:
An application opening a device explicitly with this call has to close the device by calling close. This is necessary to release system resources and allow applications to exit cleanly.
So you may use a try-with-resource-statement (Java 7+) to close it safely and wait gracefully (at the end of your try-block) for your track to finish:
try (Sequencer player = MidiSystem.getSequencer()) {
...
while (player.isRunning()) {
Thread.sleep(100);
}
} catch (Exception ex) {
ex.printStackTrace();
}
Prior to Java 7 you would have called player.close(); in a finally-block attached to your try-catch-statement.
Note: The access warning for the root users Preferences could have been suppressed by:
PlatformLogger.getLogger("java.util.prefs")
.setLevel(PlatformLogger.Level.SEVERE);

To solve the first error, just run your compiler as administrator.

Related

Eclipse "Widget is disposed" Error

Alright so I'm using Eclipse Oxygen here (I think that's important since it looks like this is an Eclipse-generated error). I've seen several other posts on this specific error, but none of them worked for me/weren't things I had already tried. So my goal is to have a while loop and have it get the db sound level every second and update a label.
Unfortunately, that didn't work like 5 times in a row. The first, the window didn't open, and I realized it was because the while loop was keeping the window from opening, so I put it into a thread. And then like 5 attempts to fix it later, I'm still getting a "Widget is disposed" error in my code. Here's the code for opening the window (that's the only code I've changed since I made the project):
public void open() throws InterruptedException, LineUnavailableException {
Display display = Display.getDefault();
shlAudioAdjuster = new Shell();
shlAudioAdjuster.setSize(450, 300);
shlAudioAdjuster.setText("Audio Adjuster");
Label lblCurrentDecibelLevel = new Label(shlAudioAdjuster, SWT.NONE);
lblCurrentDecibelLevel.setFont(SWTResourceManager.getFont("Muli", 14, SWT.NORMAL));
ProgressBar progressBar = new ProgressBar(shlAudioAdjuster, SWT.NONE);
progressBar.setSelection(30);
progressBar.setBounds(143, 168, 170, 17);
shlAudioAdjuster.open();
shlAudioAdjuster.layout();
while (!shlAudioAdjuster.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
AudioFormat audioFormat = getAudioFormat();
TargetDataLine targetDataLine;
try {
targetDataLine = (TargetDataLine) AudioSystem.getTargetDataLine(audioFormat);
targetDataLine.open();
targetDataLine.start();
byte [] buffer = new byte[2000];
while (true) {
int bytesRead = targetDataLine.read(buffer,0,buffer.length);
int max;
if (bytesRead >=0) {
max = (short) (buffer[0] + (buffer[1] << 8));
for (int p=2;p<bytesRead-1;p+=2) {
short thisValue = (short) (buffer[p] + (buffer[p+1] << 8));
if (thisValue>max) max=thisValue;
}
progressBar.setSelection((int)(20 * Math.log10(max)));
}
}
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
And the error confirms there is a problem with progressBar.setSelection((int)(20 * Math.log10(max)));. Here's the full error:
org.eclipse.swt.SWTException: Widget is disposed
at org.eclipse.swt.SWT.error(SWT.java:4533)
at org.eclipse.swt.SWT.error(SWT.java:4448)
at org.eclipse.swt.SWT.error(SWT.java:4419)
at org.eclipse.swt.widgets.Widget.error(Widget.java:482)
at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:354)
at org.eclipse.swt.widgets.ProgressBar.setSelection(ProgressBar.java:322)
at MainWindow.open(MainWindow.java:90)
at MainWindow.main(MainWindow.java:34)
P.S The last line of error saying 34 is the caller for that function, the first is the progress-bar-change line. Any ideas?
The Shell window is only displayed while the while (!shlAudioAdjuster.isDisposed()) loop is running. Once that loop has exited all the controls in the shell are disposed and cannot be used anymore. So you can't put your code after that while loop.
You will have to put the code playing the sound in a separate thread which you start when you open the shell. But you can't update the progress bar directly in a background thread, instead you need to use Display.asyncExec to run the progress bar update in the UI thread:
Display.getDefault().asyncExec(() -> progressBar.setSelection((int)(20 * Math.log10(max))));
You might also want to check if the progress bar has been disposed and stop the thread:
if (progressBar.isDisposed()) {
// TODO exit the thread
}

Screen recording of a test execution in selenium using JAVA

I have created an automation program using java selenium.I have used TestNG framework.
I want to record (video) of the screen those are getting executed during the script execution so it is better to track the failed/passed scenario and view the execution process.
Can any one help me with this, how to record the screen during running the automation suite execution.
Problems with solution mentioned before :-
All solutions answered to record video, records test execution from start to end. If automation suite run for hours then this won't be practical and optimal solution.
Main purpose of record video is to SEE what exactly happened when automation test case failed. So precisely testers need video recording of LAST 15 SECONDS BEFORE TEST CASE FAILED. They don't need any recording for PASSED test cases
Solution in theory :-
On Windows 10 onwards, Windows Xbox Game bar [Windows+G] has ability to capture LAST 15 seconds [customizable] of video. Keyboard shortcut Windows+Alt+G is use to capture last 15 seconds of video using XBox Game Bar and it would be stored in folder mentioned in settings.
Selenium automation can exploit this recording feature of Windows Xbox Game bar.
In your testNG automation project, in onTestFailure method of testNG listener just add code to keypress Windows+Alt+G to capture last 15 seconds video. This would capture video for ONLY failed test cases and never for PASS test cases. If you are using Java then you can use Robot library to send keypress programatically.
Screenshots showing Windows XBox game Bar and it's setting to capture last 15 seconds.
Solution in Code :-
I am calling below recordFailedTCVideo() method from testNG listner's
public void onTestFailure(ITestResult result) method.
This will just record last 15 seconds of video ONLY for failed test cases.[and not for PASS test cases]
Video explanation :- https://www.youtube.com/watch?v=p6tJ1fVaRxw
public void recordFailedTCVideo(ITestResult result) {
//private void pressKey() {
System.out.println("In recordFailedTCVideo::***In Try Block *** Video for test case failed " + result.getName());
commonUtility.logger.error("BaseTest::recordFailedTCVideo::***In Try Block *** Video for test case failed " + result.getName());
try {
// Useing Robot class to keypres Win+Alt+G which will capture last 15 seconds of video
Robot r = new Robot();
r.keyPress(KeyEvent.VK_WINDOWS );
Thread.sleep(1000);
r.keyPress(KeyEvent.VK_ALT );
Thread.sleep(1000);
r.keyPress(KeyEvent.VK_G );
Thread.sleep(5000);
r.keyRelease(KeyEvent.VK_WINDOWS);
Thread.sleep(1000);
r.keyRelease(KeyEvent.VK_ALT);
Thread.sleep(1000);
r.keyRelease(KeyEvent.VK_G);
Thread.sleep(5000);
/// Copy Video saved to desired location
File srcDir = new File(commonUtility.prop.getProperty("VIDEO_CAPTURE_DEFAULT_LOCATION"));
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd HHmmss");
LocalDateTime now = LocalDateTime.now();
String destination = ".\\ScreenshotsAndVideos\\" + dtf.format(now) ;
File destDir = new File(destination);
try {
System.out.println("In RecordFailedTCVideo::Source Folder is "+ srcDir +" Destination Folder = " + destDir);
commonUtility.logger.error("In RecordFailedTCVideo::Source Folder is "+ srcDir +" Destination Folder = " + destDir);
FileUtils.moveDirectory(srcDir, destDir);
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
System.out.println("In recordFailedTCVideo::***In Catch Block ***\n" +e);
commonUtility.logger.error("BaseTest::recordFailedTCVideo::***In Catch Block *** \n"+e );
e.printStackTrace();
}
//}
}
Further Video explanation :-
https://www.youtube.com/watch?v=p6tJ1fVaRxw
Constraints :-
This solution is not for non-Windows platforms.
XBar Game utility would not record Windows Explorer , text files etc. Although it records browsers without problem.
See this API (Monte Library): http://www.seleniummonster.com/boost-up-your-selenium-tests-with-video-recording-capability/
and this link: http://unmesh.me/2012/01/13/recording-screencast-of-selenium-tests-in-java/
Example Code (from above links):
public void startRecording() throws Exception
{
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
this.screenRecorder = new ScreenRecorder(gc,
new Format(MediaTypeKey, MediaType.FILE, MimeTypeKey, MIME_AVI),
new Format(MediaTypeKey, MediaType.VIDEO, EncodingKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,
CompressorNameKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,DepthKey, 24, FrameRateKey, Rational.valueOf(15),QualityKey, 1.0f,KeyFrameIntervalKey, 15 * 60),new Format(MediaTypeKey,MediaType.VIDEO, EncodingKey, "black",FrameRateKey, Rational.valueOf(30)),null);
this.screenRecorder.start();
}
public void stopRecording() throws Exception
{
this.screenRecorder.stop();
}

InvalidMidiDataException: command out of range

I have this app from Head First Java
import javax.sound.midi.*;
public class MiniMiniMusicApp{
public static void main(String[] args){
MiniMiniMusicApp mini = new MiniMiniMusicApp();
mini.play();
}
public void play(){
try{
Sequencer player = MidiSystem.getSequencer();
player.open();
Sequence seq = new Sequence(Sequence.PPQ,4);
Track track = seq.createTrack();
ShortMessage a = new ShortMessage();
a.setMessage(114,1,44,100);
MidiEvent noteOn = new MidiEvent(a,1);
track.add(noteOn);
ShortMessage b = new ShortMessage();
b.setMessage(128,1,44,100);
MidiEvent noteOff = new MidiEvent(b,16);
track.add(noteOff);
player.setSequence(seq);
player.start();
} catch(Exception ex){
ex.printStackTrace();
System.out.println("damn");
}
}
}
And this throws the following exception at runtime
javax.sound.midi.InvalidMidiDataException: command out of range: 0x72
at javax.sound.midi.ShortMessage.setMessage(ShortMessage.java:280)
at MiniMiniMusicApp.play(MiniMiniMusicApp.java:15)
at MiniMiniMusicApp.main(MiniMiniMusicApp.java:6)
I read some docs on setMessage and it seems the exception is thrown when you pass an invalid MidiMessage but I'm simply following the example from the book. I've read on other forums and it appears that this code works for other people.
Any idea on what is causing the issue? Can you try running this on your end and see if it works? At least that'll tell me if it's something on my environment.
You probably want to send a NoteOn message (144, not 114). The class ShortMessage contains constants which prevent such mistakes. You could use it like this:
import static javax.sound.midi.ShortMessage.*;
a.setMessage(NOTE_ON, 1, 44, 100);
Such code is probably easier to read for most people than directly using the numbers.
Figured it out
a.setMessage(114,1,44,100);
should be
a.setMessage(144,1,44,100);

MidiSystem.start() makes no sound

Im new to java and im creating a test application demonstrating creating sounds. i have this test code:
public class MiniMiniMusicApp {
public MiniMiniMusicApp(){
}
public void play(){
try{
Sequencer player = MidiSystem.getSequencer();
player.open();
Sequence seq = new Sequence(Sequence.PPQ, 4);
Track track = seq.createTrack();
ShortMessage a = new ShortMessage();
a.setMessage(144,1,20,100);
MidiEvent noteOn = new MidiEvent(a, 1);
track.add(noteOn);
ShortMessage b = new ShortMessage();
a.setMessage(128, 1, 44, 100);
MidiEvent noteOff = new MidiEvent(b, 3);
track.add(noteOn);
Track[] t = seq.getTracks();
player.setSequence(seq);
player.start();
System.out.println("Done");
}
catch (Exception ex){
System.out.println("Ooops something went wrong");
ex.printStackTrace();
}
}
}
and i can hear no sound. I've read somewhere that i need a soundbank, so i downloaded the deluxe version from here and i have copied it into C:\Program File\Java\jdk1.7.0_45\jre\lib created a folder called audio and copied soundbank.gm in there. What am i missing here?
I don't have enough rep to comment on the question - but do you mean to have this line
track.add(noteOn);
in there twice?
Also you call
a.setMessage(...)
twice.
There's a couple of other strange things going on, creating an array that's never used etc.
I suggest cleaning up your code a little.

How to speed up card absent detection on PC/SC reader in Java?

an application I am working on requires to detect, as quick as possible (in 500 ms maximum), that a card is removed from the field.
Here is what I did to test the time needed to detect that absence of the card:
public static long timeToGetCardAbsent(int version) throws CardException{
TerminalFactory factory = TerminalFactory.getDefault();
CardTerminals terminalList = factory.terminals();
CardTerminal ct = terminalList.list().get(0);
long connectTime = 0, disconnectTime = 0;
ct.waitForCardPresent(0);
connectTime = new Date().getTime();
ct.waitForCardAbsent(0);
disconnectTime = new Date().getTime();
return disconnectTime - connectTime;
}
When the program is running, I tap a (DESFire) contactless card on the reader and remove it immediatly.
Here are the outputs:
1437
1437
1438
1437
1422
I means that the reader (or the program?) needs almost 1.5 seconds to detect that the card is absent, which too long time for me.
Is there a way to speed up this detection? I am currently using javax.smartcardio, would I get better results with another library? I actually don't know what else I could use, do you have leads?
Thanks,
GChabot
I actually managed to improve the detection time a lot today. I was looking at that web page from "NFC Wizard" and noticed that they were very fast at detecting my card removal. This javascript web page communicates with the reader through a Java applet, so it really uses nothing more than I have.
SpringCard, the creators of NFC Wizard, actually provides complete documentation and even source code for a similar application at that page, under Other resources > Java and "SpringCard PC/SC SDK (ZIP archive)".
While browsing their code, I noticed that after performing operations on the card, the use the card.disconnect(false); function (I had tried to use card.disconnect(true); but had the same results as before...bad luck).
So here is now what I do :
import java.util.Date;
import javax.smartcardio.*;
public class NewMethod {
private long connectTime = -1;
private long disconnectTime = -1;
private TerminalFactory factory;
private CardTerminals terminalList;
private CardTerminal ct;
public NewMethod() throws CardException{
factory = TerminalFactory.getDefault();
terminalList = factory.terminals();
ct = terminalList.list().get(0);
}
public long waitForCardPresent(){
try {
ct.waitForCardPresent(0);
} catch (CardException e) { }
return new Date().getTime();
}
public long waitForCardAbsent(){
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e1) { }
try{
ct.connect("*").disconnect(false);
}
catch(Exception e) {
return new Date().getTime();
}
}
}
public void run(){
while(true){
connectTime = waitForCardPresent();
disconnectTime = waitForCardAbsent();
System.out.println((disconnectTime-connectTime));
}
}
public static void main(String[] args){
NewMethod nm;
try {
nm = new NewMethod();
nm.run();
} catch (CardException e) {
e.printStackTrace();
}
}
}
(The thread part is optional but I got the same results with or without it so I preferred to save a bit of processor consumption)
Here are the times I got with the threaded version: 531, 437, 656, 657, 735, 657, 547, 844, 15, 766, 859, 563, 765, 562, 422, 437, 563, 562, 562, 672, 672, 16, 547, 546, 672, 15, 344
and here with the unthreaded version: 984, 547, 796, 656, 796, 718, 656, 812, 625, 781, 813, 547, 797, 532, 407, 609, 719, 328, 469, 328, 0, 546, 625, 0, 843, 703
We may notice that the results are quite unstable (and quite better with the threaded version actually), this might come from the way I tap the card against the reader but I believe this is not the only reason.
It looks good enough for me now. I just hope I won't get a too great variability when I will actually use it on my application.
I've tested a bit on Linux, and in Linux, the default PCSC deamon is polling the driver each 400-500ms. Unstable drivers seem to remove this polling and use a different method, if the PCSC Lite information that I found is correct.
The Java method seems to return almost instantly, so that's not likely to be the culprit. Try and update your PCSC implementation, firmware and drivers to the latest version. If that does not work you've got no choice to work around it.
That answer did cost me an installation of PCSC on Linux + SCM SDI010 driver installation and the test of 3 firmware's. But I wanted the info myself anyway. I'll update the answer if I get a newer version of PCSC lite to work.

Categories

Resources