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);
Related
Java Doc for Function
I can't seem to figure out how to use this function. I have a Java.Midi.Sequence and the File I want to write to, but I can't figure out what "int fileType" is. There are no static int's to reference in either MidiSystem, Sequence, or MidiFileWriter. Nor does 0 help.
The Error I get when using zero is so:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: seph.reed.effigy.MidiLoader$1 cannot be cast to javax.sound.midi.ShortMessage
at com.sun.media.sound.StandardMidiFileWriter.writeTrack(StandardMidiFileWriter.java:386)
at com.sun.media.sound.StandardMidiFileWriter.getFileStream(StandardMidiFileWriter.java:204)
at com.sun.media.sound.StandardMidiFileWriter.write(StandardMidiFileWriter.java:137)
at com.sun.media.sound.StandardMidiFileWriter.write(StandardMidiFileWriter.java:153)
at javax.sound.midi.MidiSystem.write(MidiSystem.java:1060)
at seph.reed.effigy.MidiLoader.saveClipAs(MidiLoader.java:197)
at seph.reed.effigy.EffigyMenuBar$2.onClick(EffigyMenuBar.java:47)
The personal function referenced is:
public void saveClipAs(File selectedFile) {
try {
Sequence out = new Sequence(Sequence.PPQ, 256);
Track toMe = out.createTrack();
Sequencer fromMe = ANCESTOR(Effigy.class).m_gui.getCurrentClip().m_sequencer;
//traverse linked list adding notes to track
for(MidiEventEntity ptr = fromMe.m_head; ptr != null; ptr = ptr.m_next) {
byte[] midiData = new byte[3];
midiData[0] = MidiToolBox.NOTE_ON;
midiData[1] = (byte)ptr.getNote();
midiData[2] = (byte)127;
long tick = (long) (256 * ptr.getBeat()); //256 ticks per 1/4 note
MidiEvent addMe = new MidiEvent(new MidiMessage(midiData) {
#Override
public Object clone() {
return null; }
}, tick);
toMe.add(addMe);
}
//THIS LINE BELOW
MidiSystem.write(out, 0, selectedFile);
}
catch (InvalidMidiDataException e) {
e.printStackTrace(); }
catch (IOException e) {
e.printStackTrace();
}
}
Thanks for any help. I'm utterly at a loss as to what int fileType is really asking for.
EDIT: removed a dumb secondary question.
EDIT: functional code:
for(MidiEventEntity ptr = fromMe.m_head; ptr != null; ptr = ptr.m_next) {
byte status = MidiToolBox.NOTE_ON;
byte note = (byte)ptr.getNote();
byte velocity = (byte)127;
long tick = (long) (256 * ptr.getBeat()); //256 ticks per 1/4 note
ShortMessage msg = new ShortMessage(status, note, velocity);
MidiEvent addMe = new MidiEvent(msg, tick);
toMe.add(addMe);
}
It looks like the int corresponds to Midi Type 0, Midi Type 1, Midi Type 2 (more details here)
In terms of how you go about determining what midi types your system supports it looks like you can call the MidiSystem.getMidiFileTypes(Sequence sequence) method.
According to https://docs.oracle.com/javase/tutorial/sound/SPI-providing-MIDI.html :
There are three standard MIDI file formats, all of which an implementation of the Java Sound API can support: Type 0, Type 1, and Type 2. These file formats differ in their internal representation of the MIDI sequence data in the file, and are appropriate for different kinds of sequences. If an implementation doesn't itself support all three types, a service provider can supply the support for the unimplemented ones. There are also variants of the standard MIDI file formats, some of them proprietary, which similarly could be supported by a third-party vendor.
Thus the fileType is either 0, 1, or 2.
What kinds of file types your implementation supports can be seen via MidiSystem.getMidiFileTypes().
The file type of a midi file can be identified via
MidiSystem.getMidiFileFormat() (see
http://docs.oracle.com/javase/7/docs/api/javax/sound/midi/MidiSystem.html#getMidiFileFormat%28java.io.File%29
and http://docs.oracle.com/javase/7/docs/api/javax/sound/midi/MidiFileFormat.html)
I am trying to open the external cam to capture images using opencv. i wrote the below code and i also checked some questions related to this issue but, when i run the code, the external web cam does not turn the green LED ON
-the LED that indicates the web cam is ON- and word "Opened" is printed on the screen. the word "Opened", as you see below in the code indicates that the cam is ON.
please let me know why i am receiving the word "Opened" while the LED of the web cam is not ON.
Code:
public class MainClass {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
private final static int WEBCAM_SELECT = -1;
private final static int WEBCAM_BUILTIN = 0;
private final static int WEBCAM_EXTERNAL = 2;
static JFrame mediaFrame = new JFrame("Media");
public static void main(String[] args) throws InterruptedException {
Thread camThread = new Thread(new ThreadCam(), "CamThread");
camThread.setDaemon(true);
VideoCapture vidCap = new VideoCapture(WEBCAM_EXTERNAL);
vidCap.open(WEBCAM_EXTERNAL);
Thread.sleep(10000);// wait 10 sec to initilize the device;
if (vidCap.isOpened()) {
System.out.println("opened");//after 10 seconds this word will be printed
camThread.start();
}
}
Update
kindly please the Thread.sleep(10000); line and the comments beside it.
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
private final static int WEBCAM_SELECT = -1;
private final static int WEBCAM_BUILTIN = 0;
private final static int WEBCAM_EXTERNAL = 1;
static JFrame mediaFrame = new JFrame("Media");
public static void main(String[] args) throws InterruptedException {
Thread camThread = new Thread(new ThreadCam(), "CamThread");
camThread.setDaemon(true);
VideoCapture vidCap = new VideoCapture();
vidCap.open(WEBCAM_EXTERNAL);
Thread.sleep(10000);// wait 10 sec to initilize the device; upto this line the Cam is ON, but after the 10 secs, it is OFF again and the word "Opened" is printed
if (vidCap.isOpened()) {
System.out.println("opened");//after 10 seconds this word will be printed
camThread.start();
}
}
I have faced this issue before, and what i realized is, the following two lines:
VideoCapture vidCap = new VideoCapture();
vidCap.open(WEBCAM_EXTERNAL);
are to instantiate an object of VideoCapture Class and to open a specific device.
and since .isOpened returned true, this means, the device you chose is successfully opened. Being the LED of ypur device is ON before the .isOpened() and OFF after .isOpened() was called, that does not mean the device you chose to open is not ON or failed to be opened, but, actually, it is open but you are not performing any operation derived from the device you chose to open.
For an example, after .isOpened try to call vidCap.grap() or do video streaming,, then th eLED should be ON again.
Try using WEBCAM_EXTERNAL = 1; instead of WEBCAM_EXTERNAL = 2;
I'm wondering what is your hardware, a PC/MAC?
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.
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.
I can't seem to get the instrument to change. I switch the value of the instrument but get nothing different on the output. I can only get a piano instrument to play no matter what value I try. Here is the simple code below. Does anyone have any suggestions? Or am I missing a fundamental of the instrument object?
import javax.sound.midi.*;
//import javax.sound.*;
public class Drum {
static int instrument = 45;
static int note = 100;
static int timbre = 0;
static int force = 100;
public static void main(String[] args) {
Synthesizer synth = null;
try {
synth = MidiSystem.getSynthesizer();
synth.open();
}
catch (Exception e) {
System.out.println(e);
}
Soundbank soundbank = synth.getDefaultSoundbank();
Instrument[] instr = soundbank.getInstruments();
synth.loadInstrument(instr[instrument]); //Changing this int (instrument) does nothing
MidiChannel[] mc = synth.getChannels();
mc[4].noteOn(note, force);
try { Thread.sleep(1000); }
catch(InterruptedException e) {}
System.out.println(instr[instrument].getName());
synth.close();
}
}
You need to tell the channel to use the instrument. I admit I've never used MIDI in Java, but something like mc.programChange(instr.getPatch().getProgram()) sounds promising.
To play the percussion instruments you have to use the channel 10, that channel is used only for percussion instruments. (http://en.wikipedia.org/wiki/General_MIDI)
For example:
int instrument = 36;
Sequence sequence = new Sequence(Sequence.PPQ, 1);
Track track = sequence.createTrack();
ShortMessage sm = new ShortMessage( );
sm.setMessage(ShortMessage.PROGRAM_CHANGE, 9, instrument, 0); //9 ==> is the channel 10.
track.add(new MidiEvent(sm, 0));
then every note you add it will sound with percussion.
You need to send a program change event to the sequencer. How? Send a short message.
sound.setMessage(ShortMessage.PROGRAM_CHANGE, channel, instrument, channel);
long timeStam1p = -1;
Receiver rcv1r = MidiSystem.getReceiver();
rcv1r.send(sound, timeStam1p);
sound.setMessage(ShortMessage.NOTE_ON, channel, note, velocity);
long timeStamp = -1;
Receiver rcvr = MidiSystem.getReceiver();
rcvr.send(sound, timeStamp);
Variables are channel (int) note (int), instrument (int), velocity (int).
Also, I suggest to learn midi events. Events are how a midi plays notes, stops notes, change instruments, tempo change, control changes, etc. I spent 2 years using a midi program.