การเล่นเสียง Java เนื่องจากต้องพึ่งพาสภาพแวดล้อมในท้องถิ่น Java มีข้อได้เปรียบเล็กน้อยในการประมวลผลเสียงหรือกล่าวอีกนัยหนึ่งมันไม่ได้พิจารณาปัจจัยการเล่นเสียงเมื่อพัฒนาระบบ Java คุณควรรู้ว่าในเวอร์ชัน Java 1.1 ที่เก่าแก่ที่สุดไม่มีแพ็คเกจ Javax.sound ในภายหลังและสามารถเรียกคืนเสียงได้ผ่านแพ็คเกจ Applet ...
น่าเสียดายที่ในการพัฒนาโปรแกรมกราฟิกโปรแกรมของเราจำเป็นต้องใช้เพลงพื้นหลังเสียงเอฟเฟกต์ ฯลฯ อย่างหลีกเลี่ยงไม่ได้เพื่อร่วมมือกับการดำเนินงานภาพ อนิจจานี่เป็นเรื่องตลกที่ Master Sun ได้เล่นกับเรา โชคดีที่ Master Sun เปิดตาของเขาและจัดเตรียมแพ็คเกจ javax.sound เพื่อช่วยเราจากช่องแคบที่น่ากลัว ~
แต่ปัญหาที่ตามมาคือในการใช้แพ็คเกจ javax.sound เช่นปัญหาทั่วไปในคลาสเครื่องมือมัลติมีเดีย Java ไม่มีกลไกการปล่อยที่สมบูรณ์แบบมาก หากเราทำการพัฒนา Windows การโทรหา MediaPlayer ซ้ำแล้วซ้ำอีกอาจไม่ใช่เรื่องใหญ่ แต่ใน Java หากโปรแกรมเสียงทำงานซ้ำ ๆ มันเป็นเรื่องง่ายมากที่จะได้สัมผัสกับการสูญเสียหน่วยความจำสะสม
นี่เป็นคำถามของ "มันทนได้" หรือไม่? ในมุมมองนี้ในการพัฒนาเฟรมเวิร์ก Loonframework ของฉันฉันได้รวมวิธีการที่เกี่ยวข้องภายใต้เสียงเป็นครั้งที่สองโดยพยายามสร้างคลาสควบคุมเสียงที่สมบูรณ์ที่สุดด้วยรหัสที่ง่ายที่สุด ตอนนี้เกม Loonframework ยังไม่ประสบความสำเร็จอย่างยิ่งใหญ่ฉันจะแยกวิธีการบางอย่างให้คุณดูพวกเขา!
สอดคล้องกับการเรียกทรัพยากรเครือข่ายคลาส URI ของเราเองถูกสร้างขึ้นใน LoonFramework เนื้อหาพื้นฐานมีดังนี้:
(โดยที่ StreamHelper เป็นคลาสควบคุมสตรีมมิ่งของ Loonframework โปรดแทนที่วิธี GethttpStream ด้วยตัวคุณเอง)
แพ็คเกจ org.loon.framework.game.net; นำเข้า org.loon.framework.game.helper.streamhelper;/** * // ** * <p> * ชื่อเรื่อง: loonframework * </p> * <p> * คำอธิบาย: loonframework </p> * <p> * บริษัท : loonframework * </p> * * @author chenpeng * @email: [email protected] * @version 0.1 */URI คลาสสาธารณะ ... public Static Final int _l_uri_udp = 2; สตริงส่วนตัว _uri; INT ส่วนตัว _type; /** * // ** * destructor ใช้ในการฉีด URI และพิมพ์ * * @param uri * @param ประเภท */URI สาธารณะ (uri String, int ประเภท) ... {_uri = สตริงใหม่ (uri); _type = type; }/** * // ** * destructor ใช้ในการฉีด uri * * @param type uri */public uri (String uri) ... {_uri = สตริงใหม่ (uri); _type = uri._l_uri_http; }/*** // *** ส่งคืนอาร์เรย์ไบต์ของทรัพยากรที่อยู่ที่ URI * * @return */ ไบต์สาธารณะ [] getData () ... {ถ้า (_uri == null) ... {return null; } return streamhelper.gethttpstream (_uri); } สตริงสาธารณะ geturi () ... {return _uri; } public int getType () ... {return _type; }} ในเฟรมเวิร์ก LoonFramework คลาส SoundData พื้นฐานได้รับการปรับแต่งเพื่อจัดการแหล่งข้อมูลเสียงอย่างสม่ำเสมอ แพ็คเกจ org.loon.framework.game.sound; นำเข้า org.loon.framework.game.helper.streamhelper; นำเข้า org.loon.framework.game.net.uri;/** * // ** * <p> * เฟรมเวิร์ก LOONFRAMEWORK-GAME) * </p> * <p> * ลิขสิทธิ์: ลิขสิทธิ์ (c) 2007 * </p> * <p> * บริษัท : loonframework * </p> * * @author chenpeng * @email: [email protected] * @version 0.1 บูลีนส่วนตัว _loop; INT ส่วนตัว _type; public Static Final int _l_soundtype_midi = 1; สาธารณะคงที่สาธารณะสุดท้าย _l_soundtype_wav = 2; /** * // ** * destructor, ใช้ในการฉีด uri, พิมพ์, ลูป * * @param uri * @param ประเภท * @param loop */sounddata สาธารณะ (uri uri, ประเภท int, boolean loop) ... {ถ้า (uri! = null) ... {_data = uri.getdata (); } _type = type; _loop = ลูป; }/** * // ** * destructor, ใช้ในการฉีดข้อมูล, พิมพ์, ลูป * * @param data * @param type * @param loop */sounddata สาธารณะ (byte [] data, ประเภท int, boolean loop) ... {if (data! = null && data.length> 0) ... // สำเนาโดยตรงไบต์อาร์เรย์ System.arrayCopy (ข้อมูล, 0, _data, 0, _data.length); } _type = type; _loop = ลูป; }/** * // ** * destructor, ใช้ในการฉีด resname, พิมพ์, วนลูป * @param resname * @param type * @param loop */sounddata สาธารณะ (สตริง resname, ประเภท int, boolean loop) ... } ไบต์สาธารณะ [] getData () ... {return _data; } บูลีนสาธารณะ getLoop () ... {return _loop; } โมฆะสาธารณะ setloop (ลูปบูลีน) ... {_loop = ลูป; } public int getType () ... {return _type; -
LOONFRAMEWORK ห่อหุ้มวิธีการเล่นเสียงและการเล่นเสียง โปรแกรมเมอร์สามารถเพิกเฉยต่อรายละเอียดภายในของ javax.sound และเรียก SoundPlay โดยตรงเพื่อดำเนินการที่เกี่ยวข้อง
แพ็คเกจ org.loon.framework.game.sound; นำเข้า java.io.bytearrayinputstream นำเข้า Javax.sound.midi.metaeventListener; นำเข้า Javax.sound.midi.metamessage; นำเข้า Javax.sound.midi.midisy javax.sound.midi.equencer; นำเข้า Javax.sound.sampled.audiofileformat; นำเข้า Javax.sound.sampled.audiosystem; นำเข้า Javax.sound.sampled.clip; นำเข้า javax.sound.sampled.dataline; ชื่อเรื่อง: LOONFRAMEWORK * </p> * <p> * คำอธิบาย: ใช้ในการดำเนินการไฟล์เสียง (เฉพาะบางวิธีใน loonframework โปรดดูกรอบการทำงานของ Loonframework-Game สำหรับรายละเอียดเพิ่มเติม) * </p> * <p> * Copyright: Copyright (C) 2007 * </p> @Email: [email protected] * @version 0.1 */Soundplay คลาสสาธารณะใช้ metaeventListener, runnable ... {ส่วนตัว int _sleeptime; คลิปส่วนตัว _audio; Sequencer ส่วนตัว _midi; บูลีนส่วนตัว _loop; INT ส่วนตัว _SoundType; บูลีนส่วนตัว _playing; เธรดส่วนตัว _thread = null; บูลีนส่วนตัว _isrun = false; /** * // ** * destructor, เริ่มต้น soundplay * */soundplay สาธารณะ () ... {_loop = false; _SoundType = 0; _sleeptime = 1,000; _playing = false; } // โหลดไฟล์เสียงสาธารณะแบบบูลีน (ข้อมูล sounddata) ... {reset (); if (data == null || data.getData () == null) ... {return false; } return init (data.getData (), data.getType (), data.getLoop ()); }/** * // ** * การเล่นโดยตรงของไฟล์ url * * @param uri * @param ftype * @param loop * @return */โหลดบูลีนสาธารณะ (Uri uri, int ftype, boolean loop) ... {// รีเซ็ตข้อมูลรีเฟรช (); if (uri == null) ... {return false; } // รับ data sounddata sounddata = sounddata ใหม่ (URI, ftype, วนซ้ำ); if (data == null || data.getData () == null) ... {return false; } return init (data.getData (), data.getType (), data.getLoop ()); }/** * // ** * เริ่มต้นข้อมูลที่เกี่ยวข้องกับเสียง * * @param data * @param ftype * @param loop * @return */private boolean init (byte [] ข้อมูล, int ftype, boolean loop) ... {boolean result = false; ByteArrayInputStream bis = null; ลอง ... {bis = ใหม่ byteArrayInputStream (ข้อมูล); } catch (Exception e) ... {bis = null; } ถ้า (bis == null) ... {return false; } // สวิตช์ประเภทการตัดสิน (ftype) ... {// // midi case sounddata._l_soundtype_midi: // เมื่อ midi ไม่มีอยู่ถ้า (_midi == null) ... {ลอง ... {// รับ sequencer _midi = midisystem.get _midi.open (); } catch (exception ex) ... {_midi = null; } if (_midi! = null) ... {_midi.addmetaeventListener (นี่); }} // เมื่อ MIDI ยังไม่ได้รับถ้า (_midi! = null) ... {// สร้างลำดับลำดับ sc = null; ลอง ... {sc = midisystem.getSequence (bis); } catch (ข้อยกเว้น e) ... {sc = null; } if (sc! = null) ... {ลอง ... {_midi.setSequence (sc); // รับว่าจะ loop_loop = loop; // รับว่าจะโหลดผลลัพธ์ = true; } catch (Exception ee) ... {} // รับ sound type_soundtype = sounddata._l_soundtype_midi; }} ลอง ... {bis.close (); } catch (Exception ee) ... {} break; // wav case sounddata._l_soundtype_wav: AudioFileFormat type = null; // รับเสียงลอง ... {type = audiosystem.getaudiofileformat (bis); } catch (Exception e) ... {type = null; } // ปิดสตรีมลอง ... {bis.close (); } catch (exception ex) ... {} if (type == null) ... {return false; } // สร้างวัตถุข้อมูลของแถวข้อมูลตามข้อมูลที่ระบุ dataline.info di = ใหม่ dataline.info (clip.class, type.getFormat ()); // แปลงเป็นคลิปลอง ... {_audio = (คลิป) Audiosystem.getLine (DI); } catch (exception e) ... {} // play file ลอง ... {_audio.open (type.getFormat (), ข้อมูล, 0, data.length); _loop = ลูป; ผลลัพธ์ = จริง; } catch (Exception e) ... {} // รับประเภทไฟล์ _soundType = sounddata._l_soundtype_wav; หยุดพัก; } ผลตอบแทนผลลัพธ์; } การเล่นบูลีนสาธารณะ (ข้อมูล sounddata) ... {ถ้า (! โหลด (data)) ... {return false; } return play (); } Public Boolean play () ... {switch (_soundtype) ... {case sounddata._l_soundtype_midi: ลอง ... {_midi.start (); _playing = true; _SoundType = sounddata._l_soundtype_midi; } catch (Exception ee) ... {} break; case sounddata._l_soundtype_wav: ถ้า (_audio! = null) ... {ถ้า (_loop) ... {// ตั้งค่าลูป _audio.setlooptins (0, -1); _audio.setFramePosition (0); _audio.loop (clip.loop_continously); } else ... {// บังคับตำแหน่งการเล่นเป็น 0 _audio.setFramePosition (0); _audio.start (); } _playing = true; } หยุดพัก; } return _playing; }/*** // *** การเล่นอัตโนมัติลูปจะสิ้นสุดหลังจากหยุด * * @param data * @return */ Public Boolean Autoplay (ข้อมูล sounddata) ... {ถ้า (! โหลด (data)) ... {return false; } return autoplay (); }/*** // *** การเล่นอัตโนมัติสิ้นสุดลงหลังจากการวนซ้ำหยุด * * @return */ Public Boolean Autoplay () ... {_isrun = true; _thread = เธรดใหม่ (นี่); _thread.start (); กลับ _playing; }/***// ***หยุดเล่น*/โมฆะสาธารณะหยุด () ... {ถ้า (_audio! = null && _audio.isactive ()) ... {ลอง ... {_audio.stop (); } catch (exception e) ... {}} ถ้า (_midi! = null) ... {_midi.stop (); } _playing = false; _isrun = false; }/*** // *** ข้อมูลปล่อย**/โมฆะสาธารณะรีเซ็ต () ... {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; }/***// ***ตั้งค่า metamessage*/meta โมฆะสาธารณะ (metamessage meta) ... {// กำหนดว่าจะเล่น midi loop ถ้า (_loop && _soundtype == sounddata._l_soundtype_midi && meta.gettype () _midi.isopen ()) ... {_midi.setmicrosecondposition (0); _midi.start (); }}} โมฆะสาธารณะเรียกใช้ () ... {ในขณะที่ (_isrun) ... {play (); // เนื่องจากประเภทการเล่นไม่ซ้ำกันผล _playing เพียงหนึ่งเดียวเท่านั้นที่จะถูกส่งกลับเพื่อกำหนดสิ่งนี้ if (_midi! = null) ... {_playing = _midi.isrunning (); } if (_audio! = null) ... {_playing = _audio.isrunning (); } // เมื่อการเล่นหยุดถ้า (! _playing) ... {// release reset (); } ลอง ... {thread.sleep (_sleeptime); } catch (interruptedException e) ... {E.printStackTrace (); }}} int สาธารณะ getSleeptime () ... {return _sleeptime; }/*** // *** ตั้งค่าเวลาวนซ้ำเธรดอัตโนมัติ * * เวลา @param */ โมฆะสาธารณะ setSleeptime (เวลา int) ... {_sleeptime = เวลา; -
ในเวลานี้สิ่งที่เราต้องเผชิญคือข้อมูล sounddata และการดำเนินการ soundplay ที่ห่อหุ้มเป็นเอนทิตีโดยไม่ต้องจัดการกับ Javax.sound ที่ซับซ้อนอีกครั้ง
วิธีการโทรมีดังนี้:
แพ็คเกจ org.test; นำเข้า org.loon.framework.game.helper.streamhelper; นำเข้า org.loon.framework.game.net.uri; นำเข้า org.loon.framework.game.sound.sounddata; นำเข้า org.loon.framework.game. LOONFRAMEWORK </p> * <p> คำอธิบาย: การทดสอบการเล่นเสียง </p> * <p> ลิขสิทธิ์: ลิขสิทธิ์ (c) 2007 </p> * <p> บริษัท : loonframework </p> * @author chenpeng * @email: [email protected] * @version 0.1 ftype) .. {sounddata data = null; สวิตช์ (ftype) .. {// เล่นเพลงจากเครือข่ายผ่าน URI ภายใต้กรณี loonframework 0: data = new sounddata (uri ใหม่ ("http://looframework.sourceforge.net/midi/who เป็นฮีโร่ขนาดใหญ่ หยุดพัก; // เล่นเพลงผ่านวัตถุไบต์ [] ของไฟล์เพลงภายใต้กรณีทรัพยากรท้องถิ่น 1: ไบต์ [] bytes = streamhelper.getResourceData ("/midi/ใครเป็นฮีโร่ตัวใหญ่"); data = new sounddata (ไบต์, sounddata._l_soundtype_midi, false); หยุดพัก; // เล่นเพลงผ่านเส้นทางไฟล์เพลง 2: data = new SoundData ("C:/ใครคือ Big Hero.mid", sounddata._l_soundtype_midi, false); หยุดพัก; } soundplay play = new soundplay (); // ความแตกต่างระหว่างวิธีการเล่นอัตโนมัติและวิธีการเล่นคือการเล่นอัตโนมัติจะหยุดและปล่อยทรัพยากรโดยอัตโนมัติหลังจากเล่นและการเล่นจะต้องถูกยกเลิกด้วยตนเอง //play.play(Data); play.autoplay (ข้อมูล); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) .. {selectplay (2); -
จะมีการอธิบายวิธีการโดยละเอียดเพิ่มเติมหลังจากประกาศเกม Loonframework อย่างเต็มที่
นอกจากนี้: เนื่องจาก Streamhelper เชื่อมโยงกับวิธีการ loonframework อื่น ๆ จึงยังไม่ได้รับ สามารถเขียน InputStream to byte [] ได้ดังนี้:
// คือ IS IS INPUTSTREAM BYTeArrayOutputStream ByTeArrayOutputStream = New ByteArrayOutputStream (); // ใช้เพื่อดำเนินการ BYTE [] byte [] arrayByte = null; ลอง ... {// ขนาดของการถ่ายโอนแต่ละครั้งคือ 4096 ไบต์ [] ไบต์ = ไบต์ใหม่ [4096]; ไบต์ = ไบต์ใหม่ [is.available ()]; int อ่าน; ในขณะที่ ((read = is.read (bytes))> = 0) ... {byteArrayOutputStream.write (ไบต์, 0, อ่าน); } arrayByte = byteArrayOutputStream.tobyteArray (); } catch (ioexception e) ... {return null; } ในที่สุด ... {ลอง ... {if (byteArrayOutputStream! = null) ... {byteArrayOutputStream.close (); ByTeArrayOutputStream = null; } ถ้า (คือ! = null) ... {is.close (); IS = NULL; }} catch (ioexception e) ... {}}