Java audio playback, because it must rely on the local environment, JAVA has little advantage in audio processing, or in other words, it does not consider the audio playback factors when developing the Java system. You should know that in the earliest Java 1.1 version, there was no later javax.sound package, and the audio can only be retrieved through the Applet package...
Unfortunately, in the development of graphics programs, our programs inevitably need to use background music, effect sounds, etc. to cooperate with image operations. Alas, this is really a joke that Master Sun has played to us. Fortunately, Master Sun opened his eyes and provided the javax.sound package to save us from dire straits~
But the subsequent problem is that in the use of the javax.sound package, like a common problem in Java multimedia tool class, there is no very complete release mechanism. If we do Windows development, calling MediaPlayer again and again may not be a big deal, but in Java, if the audio program runs repeatedly, it is very easy to experience memory cumulative loss, so that a java.lang.OutOfMemoryError is thrown, and then... the program hangs, the user is stupid, and we go crazy...
This is already a question of "Is it tolerable"? In view of this, in my Loonframework framework development, I have secondaryly integrated the relevant methods under sound, striving to create the most complete audio control class with the simplest code. Now that Loonframework-game has not yet achieved great success, we will first excerpt some of the methods for everyone to take a look at them!
Corresponding to network resource calls, our own uri class is established in Loonframework. The basic content is as follows:
(Where StreamHelper is Loonframework's own streaming control class, please replace the getHttpStream method yourself.)
package org.loon.framework.game.net;import org.loon.framework.game.helper.StreamHelper;/** *//** * <p> * Title: LoonFramework * </p> * <p> * Description:Loonframework dedicated uri (unified resource identifier) * </p> * <p> * Copyright: Copyright (c) 2007 * </p> * <p> * Company: LoonFramework * </p> * * @author chenpeng * @email: [email protected] * @version 0.1 */public class URI ...{ //Transport protocol type public static final int _L_URI_HTTP = 1; public static final int _L_URI_UDP = 2; private String _uri; private int _type; /** *//** * Destructor, used to inject uri and type * * @param uri * @param type */ public URI(String uri, int type) ...{ _uri = new String(uri); _type = type; } /** *//** * Destructor, used to inject uri * * @param type uri */ public URI(String uri) ...{ _uri = new String(uri); _type = URI._L_URI_HTTP; } /** *//** * Returns the byte array of the resource where the uri is located. * * @return */ public byte[] getData() ...{ if (_uri == null) ...{ return null; } return StreamHelper.getHttpStream(_uri); } public String getURI() ...{ return _uri; } public int getType() ...{ return _type; }} In the Loonframework framework, a basic SoundData class is customized to uniformly manage audio data sources. package org.loon.framework.game.sound;import org.loon.framework.game.helper.StreamHelper;import org.loon.framework.game.net.URI;/** *//** * <p> * Title: LoonFramework * </p> * <p> * Description: Used to obtain and cache sound file data (for further information, see the Loonframework-game framework) * </p> * <p> * Copyright: Copyright (c) 2007 * </p> * <p> * Company: LoonFramework * </p> * * @author chenpeng * @email:[email protected] * @version 0.1 */public class SoundData ...{ private byte[] _data; private boolean _loop; private int _type; public static final int _L_SOUNDTYPE_MIDI = 1; public static final int _L_SOUNDTYPE_WAV = 2; /** *//** * Destructor, used to inject uri, type,loop * * @param uri * @param type * @param loop */ public SoundData(URI uri, int type, boolean loop) ...{ if (uri != null) ...{ _data = uri.getData(); } _type = type; _loop = loop; } /** *//** * Destructor, used to inject data, type,loop * * @param data * @param type * @param loop */ public SoundData(byte[] data, int type, boolean loop) ...{ if (data != null && data.length > 0) ...{ _data = new byte[data.length]; // Direct copy byte array System.arraycopy(data, 0, _data, 0, _data.length); } _type = type; _loop = loop; } /** *//** * Destructor, used to inject resName, type,loop * @param resName * @param type * @param loop */ public SoundData(String resName, int type, boolean loop) ...{ this(StreamHelper.GetDataSource(resName),type,loop); } public byte[] getData() ...{ return _data; } public boolean getLoop() ...{ return _loop; } public void setLoop(boolean loop) ...{ _loop = loop; } public int getType() ...{ return _type; }}
Loonframework encapsulates audio playback related methods and SoundPlay. Programmers can ignore the internal details of javax.sound and directly call SoundPlay to complete related operations.
package org.loon.framework.game.sound;import java.io.ByteArrayInputStream;import javax.sound.midi.MetaEventListener;import javax.sound.midi.MetaMessage;import javax.sound.midi.MidiSystem;import javax.sound.midi.Sequence;import javax.sound.midi.Sequencer;import javax.sound.sampled.AudioFileFormat;import javax.sound.sampled.AudioSystem;import javax.sound.sampled.Clip;import javax.sound.sampled.DataLine;import org.loon.framework.game.net.URI;/** *//** * <p> * Title: LoonFramework * </p> * <p> * Description: Used to perform sound file operations (only some methods in Loonframework, see the Loonframework-game framework for more details) * </p> * <p> * Copyright: Copyright (c) 2007 * </p> * <p> * Company: LoonFramework * </p> * * @author chenpeng * @email:[email protected] * @version 0.1 */public class SoundPlay implements MetaEventListener, Runnable ...{ private int _sleepTime; private Clip _audio; private Sequencer _midi; private boolean _loop; private int _soundType; private boolean _playing; private Thread _thread = null; private boolean _isRun = false; /** *//** * destructor, initialize SoundPlay * */ public SoundPlay() ...{ _loop = false; _soundType = 0; _sleepTime = 1000; _playing = false; } // Load the sound file public boolean load(SoundData data) ...{ reset(); if (data == null || data.getData() == null) ...{ return false; } return init(data.getData(), data.getType(), data.getLoop()); } /** *//** * Direct playback of the url file* * @param uri * @param ftype * @param loop * @return */ public boolean load(URI uri, int ftype, boolean loop) ...{ // Refresh data reset(); if (uri == null) ...{ return false; } // Get SoundData SoundData data = new SoundData(uri, ftype, loop); if (data == null || data.getData() == null) ...{ return false; } return init(data.getData(), data.getType(), data.getLoop()); } /** *//** * Initialize sound-related data* * @param data * @param ftype * @param loop * @return */ private boolean init(byte[] data, int ftype, boolean loop) ...{ boolean result = false; ByteArrayInputStream bis = null; try ...{ bis = new ByteArrayInputStream(data); } catch (Exception e) ...{ bis = null; } if (bis == null) ...{ return false; } // judging type switch (ftype) ...{ // MIDI case SoundData._L_SOUNDTYPE_MIDI: // When MIDI does not exist if (_midi == null) ...{ try ...{ // Get Sequencer _midi = MidiSystem.getSequencer(); _midi.open(); } catch (Exception ex) ...{ _midi = null; } if (_midi != null) ...{ _midi.addMetaEventListener(this); } } // When MIDI is still not obtained if (_midi != null) ...{ // Recreate Sequence Sequence sc = null; try ...{ sc = MidiSystem.getSequence(bis); } catch (Exception e) ...{ sc = null; } if (sc != null) ...{ try ...{ _midi.setSequence(sc); // Get whether to loop_loop = loop; // Get whether to load result = true; } catch (Exception ee) ...{ } // Get sound type_soundType = SoundData._L_SOUNDTYPE_MIDI; } } try ...{ bis.close(); } catch (Exception ee) ...{ } break; // Wav case SoundData._L_SOUNDTYPE_WAV: AudioFileFormat type = null; // Get Audio try ...{ type = AudioSystem.getAudioFileFormat(bis); } catch (Exception e) ...{ type = null; } // Close stream try ...{ bis.close(); } catch (Exception ex) ...{ } if (type == null) ...{ return false; } // Construct the information object of the data row based on the specified information DataLine.Info di = new DataLine.Info(Clip.class, type.getFormat()); // Convert to Clip try ...{ _audio = (Clip) AudioSystem.getLine(di); } catch (Exception e) ...{ } // Play file try ...{ _audio.open(type.getFormat(), data, 0, data.length); _loop = loop; result = true; } catch (Exception e) ...{ } // Get file type _soundType = SoundData._L_SOUNDTYPE_WAV; break; } return result; } public boolean play(SoundData data) ...{ if (!load(data)) ...{ return false; } return play(); } public boolean play() ...{ switch (_soundType) ...{ case SoundData._L_SOUNDTYPE_MIDI: try ...{ _midi.start(); _playing = true; _soundType = SoundData._L_SOUNDTYPE_MIDI; } catch (Exception ee) ...{ } break; case SoundData._L_SOUNDTYPE_WAV: if (_audio != null) ...{ if (_loop) ...{ // Set loop _audio.setLoopPoints(0, -1); _audio.setFramePosition(0); _audio.loop(Clip.LOOP_CONTINUOUSLY); } else ...{ // Force the playback position to 0 _audio.setFramePosition(0); _audio.start(); } _playing = true; } break; } return _playing; } /** *//** * Automatic playback, the loop ends after the stop. * * @param data * @return */ public boolean AutoPlay(SoundData data) ...{ if (!load(data)) ...{ return false; } return AutoPlay(); } /** *//** * Automatic playback, the loop ends after the stop. * * @return */ public boolean AutoPlay() ...{ _isRun = true; _thread = new Thread(this); _thread.start(); return _playing; } /** *//** * Stop playing*/ public void stop() ...{ if (_audio != null && _audio.isActive()) ...{ try ...{ _audio.stop(); } catch (Exception e) ...{ } } if (_midi != null) ...{ _midi.stop(); } _playing = false; _isRun = false; } /** *//** * Release data* */ public void reset() ...{ stop(); _loop = false; _soundType = 0; if (_midi != null) ...{ _midi.close(); _midi = null; } if (_audio != null && _audio.isOpen()) ...{ _audio.close(); _audio = null; } _isRun = false; _thread = null; } /** *//** * Set MetaMessage */ public void meta(MetaMessage meta) ...{ // Determine whether to play MIDI loop if (_loop && _soundType == SoundData._L_SOUNDTYPE_MIDI && meta.getType() == 47) ...{ if (_midi != null && _midi.isOpen()) ...{ _midi.setMicrosecondPosition(0); _midi.start(); } } } public void run() ...{ while (_isRun) ...{ play(); // Because the playback type is unique, only one _playing result will be returned to determine this. if (_midi != null) ...{ _playing = _midi.isRunning(); } if (_audio != null) ...{ _playing = _audio.isRunning(); } // When playback stops if (!_playing) ...{ // Release reset(); } try ...{ Thread.sleep(_sleepTime); } catch (InterruptedException e) ...{ e.printStackTrace(); } } } public int getSleepTime() ...{ return _sleepTime; } /** *//** * Set the AutoPlay thread loop time. * * @param time */ public void setSleepTime(int time) ...{ _sleepTime = time; }}
At this time, what we need to face is only SoundData data and SoundPlay operations encapsulated as entities, without having to deal with the complicated javax.sound again.
The call method is as follows:
package org.test;import org.loon.framework.game.helper.StreamHelper;import org.loon.framework.game.net.URI;import org.loon.framework.game.sound.SoundData;import org.loon.framework.game.sound.SoundPlay;/** *//** * <p>Title: LoonFramework</p> * <p>Description:SoundPlay playback test</p> * <p>Copyright: Copyright (c) 2007</p> * <p>Company: LoonFramework</p> * @author chenpeng * @email: [email protected] * @version 0.1 */public class SoundPlayTest ...{ static void selectPlay(int ftype)..{ SoundData data=null; switch(ftype)..{ //Play music from the network through the uri under loonframework case 0: data=new SoundData(new URI("http://looframework.sourceforge.net/midi/Who is the big hero.mid"),SoundData._L_SOUNDTYPE_MIDI,false); break; //Play music through the byte[] object of the music file under the local resource case 1: byte[] bytes=StreamHelper.GetResourceData("/midi/Who is the Big Hero.mid"); data=new SoundData(bytes,SoundData._L_SOUNDTYPE_MIDI,false); break; //Play music through the music file path case 2: data=new SoundData("C:/Who is the Big Hero.mid",SoundData._L_SOUNDTYPE_MIDI,false); break; } SoundPlay play=new SoundPlay(); //The difference between AutoPlay and Play methods is that AutoPlay will automatically stop and release resources after playing, and the play needs to be manually aborted. //play.play(data); play.AutoPlay(data); } public static void main(String[]args)..{ selectPlay(2); } }
A more detailed method will be explained after the Loonframework-game is fully announced.
In addition: Since StreamHelper is associated with other Loonframework methods, it will not be given yet. The inputStream to byte[] can be written as follows:
//is is the obtained inputStream ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();//Used to undertake byte[] byte[] arrayByte = null; try ...{ // The size of each transfer is 4096 byte[] bytes = new byte[4096]; bytes = new byte[is.available()]; int read; while ((read = is.read(bytes)) >= 0) ...{ byteArrayOutputStream.write(bytes, 0, read); } arrayByte = byteArrayOutputStream.toByteArray(); } catch (IOException e) ...{ return null; } finally ...{ try ...{ if (byteArrayOutputStream != null) ...{ byteArrayOutputStream.close(); byteArrayOutputStream = null; } if (is != null) ...{ is.close(); is = null; } } catch (IOException e) ...{ } }