تشغيل Java Audio ، لأنه يجب أن يعتمد على البيئة المحلية ، فإن Java لديها ميزة ضئيلة في معالجة الصوت ، أو بعبارة أخرى ، لا تنظر في عوامل تشغيل الصوت عند تطوير نظام Java. يجب أن تعلم أنه في أول إصدار من Java 1.1 ، لم يكن هناك حزمة Javax.sound لاحقًا ، ولا يمكن استرداد الصوت إلا من خلال حزمة Applet ...
لسوء الحظ ، في تطوير برامج الرسومات ، تحتاج برامجنا حتما إلى استخدام موسيقى الخلفية ، وأصوات التأثير ، وما إلى ذلك للتعاون مع عمليات الصور. للأسف ، هذه حقًا مزحة لعبتها لنا Master Sun. لحسن الحظ ، فتح ماستر صن عينيه وقدم حزمة جافاكس.
لكن المشكلة اللاحقة هي أنه في استخدام حزمة Javax.sound ، مثل مشكلة شائعة في فئة أدوات الوسائط المتعددة Java ، لا توجد آلية إطلاق كاملة للغاية. إذا قمنا بتطوير Windows ، فقد لا يكون الاتصال بـ MediaPlayer مرارًا وتكرارًا مشكلة كبيرة ، ولكن في Java ، إذا كان برنامج الصوت يعمل مرارًا وتكرارًا ، فمن السهل جدًا تجربة الخسارة التراكمية للذاكرة ، بحيث يتم إلقاء java.lang.outofmemory ، ثم ... يعلق البرنامج ، ونحن على الجنون ...
هذه بالفعل مسألة "هل هذا مقبول"؟ في ضوء ذلك ، في تطوير إطار عمل LoonFramework الخاص بي ، قمت بدمج الأساليب ذات الصلة الثانوية ضمن الصوت ، وسعت جاهدة لإنشاء فئة التحكم في الصوت الأكثر اكتمالا مع أبسط رمز. الآن بعد أن لم تحقق لعبة LoonFramework نجاحًا كبيرًا ، سأستخرج أولاً بعض الطرق لك لإلقاء نظرة عليها!
المقابلة لمكالمات موارد الشبكة ، يتم إنشاء فئة URI الخاصة بنا في LoonFramework. المحتوى الأساسي هو كما يلي:
(حيث يكون StreamHelper فئة التحكم في البث الخاصة بـ LoonFramework ، يرجى استبدال طريقة GethTtpstream بنفسك.)
package org.loon.framework.game.net ؛ استيراد org.loon.framework.game.helper.streamhelper ؛/** * // ** * <p> * العنوان: loonframework * </p> * <p> * الوصف: loonframework uri (uniped Resource Identifier) </p> * <p> * الشركة: loonframework * </p> * * Author Chenpeng * @email: [email protected] * version 0.1 */public class uri ... {// transfer protocol type public static int _l_http = 1 ؛ int int _l_uri_udp = 2 ؛ سلسلة خاصة _uri ؛ private int _type ؛ /** * // ** * DestRuctor ، يستخدم لحقن URI و type * * param uri * param type */public uri (string uri ، int type) ... {_uri = new string (uri) ؛ _type = type ؛ }/** * // ** * DestRuctor ، يستخدم لحقن uri * * param type uri */public uri (string uri) ... {_uri = new string (uri) ؛ _type = uri._l_uri_http ؛ }/*** // *** إرجاع صفيف البايت للمورد الذي يوجد فيه URI. * * return */ public byte [] getData () ... {if (_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 LoonFramework-Game Framework) * </p> * <p> * حقوق الطبع والنشر: حقوق الطبع والنشر (C) 2007 * </p> * <p> * الشركة: loonframework * </p> * * * Author chenpeng * email: [email protected] * @version 0.1/public class sounddata ... منطقية خاصة _loop ؛ private int _type ؛ int int _l_soundtype_midi = 1 ؛ Final Static Final int _l_soundtype_wav = 2 ؛ /** * // ** * Destructor ، يستخدم لحقن URI ، النوع ، حلقة * * param uri * param type * param loop */public sounddata (uri uri ، int type ، loop boolean) ... {if (uri! = null) ... {_data = uri.getdata () ؛ } _type = type ؛ _loop = حلقة ؛ }/** * // ** * DestRuctor ، يستخدم لحقن البيانات ، النوع ، الحلقة * * param data * param type * param loop */public sounddata (byte [] data ، type int ، loop boolean) ... {if (data! = data! // Direct Copy Byte Array System.ArrayCopy (Data ، 0 ، _data ، 0 ، _data.length) ؛ } _type = type ؛ _loop = حلقة ؛ }/*: } البايت العام [] getData () ... {return _data ؛ } boolean public getLoop () ... {return _loop ؛ } public void setLoop (حلقة منطقية) ... {_loop = loop ؛ } public int gettype () ... {return _type ؛ }}
LOONFRAMework يغلف الأساليب المتعلقة بتشغيل الصوت وملعب الصوت. يمكن للمبرمجين تجاهل التفاصيل الداخلية لـ javax.sound واتصلوا مباشرة إلى soundplay لإكمال العمليات ذات الصلة.
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 ؛ javax.sound.midi.sequencer ؛ استيراد javax.sound.sampled.audiofileformat <p> * العنوان: loonframework * </p> * <p> * الوصف: يستخدم لأداء عمليات ملفات الصوت (فقط بعض الطرق في loonframework ، راجع إطار لعبة loonframework لمزيد من التفاصيل) eMail: [email protected] * version 0.1 */public class soundplay تنفذ metaeventListener ، runnable ... {private int _sleeptime ؛ مقطع خاص _audio ؛ جهاز التسلسل الخاص _midi ؛ منطقية خاصة _loop ؛ int _soundtype الخاص ؛ المنطقية الخاصة _playing ؛ موضوع خاص _Thread = null ؛ منطقية خاصة _isrun = false ؛ /** * // ** * DestRuctor ، تهيئة SoundPlay * */public soundplay () ... {_loop = false ؛ _soundType = 0 ؛ _sleeptime = 1000 ؛ _playing = false ؛ } // تحميل ملف SOUND Public Boolean Load (SoundData Data) ... {reset () ؛ if (data == null || data.getData () == null) ... {return false ؛ } إرجاع init (data.getData () ، data.getType () ، data.getLoop ()) ؛ }/** * // ** * التشغيل المباشر لملف url * * param uri * param ftype * param loop * regurn */public boolean load (uri uri ، int ftype ، loop boolean) ... {// refrate data () ؛ if (uri == null) ... {return false ؛ } // GET SOUNDDATA SOUNDDATA DATA = NEW SOUNDDATA (URI ، FTYPE ، LOOP) ؛ if (data == null || data.getData () == null) ... {return false ؛ } إرجاع init (data.getData () ، data.getType () ، data.getLoop ()) ؛ }/** * // ** * تهيئة البيانات المتعلقة بالصوت * * param data * param ftype * param loop * return */private boolean init (byte [] data ، int ftype ، boolean loop) ... {boolean result = false ؛ bytearrayinputStream BIS = NULL ؛ حاول ... {bis = new bytearrayinputStream (data) ؛ } catch (استثناء e) ... {bis = null ؛ } if (bis == null) ... {return false ؛ } // مفتاح نوع التحكيم (ftype) ... {// midi case sounddata._l_soundtype_midi: // عندما لا يكون midi موجودًا إذا (_midi == null) ... {try ... {// get sequencer _midi = midisystem.getsuregencer () ؛ _midi.open () ؛ } catch (استثناء ex) ... {_midi = null ؛ } if (_midi! = null) ... {_midi.addmetaeventListener (this) ؛ }} // عندما لا يزال MIDI لا يتم الحصول عليه إذا (_midi! = null) ... {// إعادة إنشاء تسلسل التسلسل sc = null ؛ حاول ... {sc = midisystem.getSequence (bis) ؛ } catch (استثناء e) ... {sc = null ؛ } if (sc! = null) ... {try ... {_midi.setSequence (sc) ؛ // الحصول على ما إذا كنت تريد loop_loop = loop ؛ // الحصول على ما إذا كان يجب تحميل نتيجة = صواب ؛ } catch (استثناء EE) ... {} // الحصول على sound type_soundtype = sounddata._l_soundtype_midi ؛ }} حاول ... {bis.close () ؛ } catch (استثناء ee) ... {} break ؛ // wav case sounddata._l_soundtype_wav: audiofileformat type = null ؛ // الحصول على الصوت جرب ... {type = audiosystem.getaudiofileformat (bis) ؛ } catch (استثناء e) ... {type = null ؛ } // إغلاق دفق حاول ... {bis.close () ؛ } catch (استثناء ex) ... {} if (type == null) ... {return false ؛ }. // convert to clip try ... {_audio = (clip) Audiosystem.getLine (di) ؛ } catch (استثناء e) ... {} // play file try ... {_audio.open (type.getFormat () ، data ، 0 ، data.length) ؛ _loop = حلقة ؛ النتيجة = صواب ؛ } catch (استثناء e) ... {} // الحصول على نوع الملف _soundtype = sounddata._l_soundtype_wav ؛ استراحة؛ } نتيجة الإرجاع ؛ } 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 (استثناء ee) ... {} break ؛ case sounddata._l_soundtype_wav: if (_audio! = null) ... {if (_loop) ... {// set loop _audio.setLoopPoints (0 ، -1) ؛ _audio.setframeposition (0) ؛ - } آخر ... {// فرض موضع التشغيل إلى 0 _audio.setFramePosition (0) ؛ _audio.start () ؛ } _playing = true ؛ } استراحة؛ } return _playing ؛ }/*** // *** التشغيل التلقائي ، تنتهي الحلقة بعد التوقف. * * param data * return */ public boolean autoplay (SoundData Data) ... {if (! load (data)) ... {return false ؛ } إرجاع autoplay () ؛ }/*** // *** التشغيل التلقائي ، ينتهي بعد توقف الحلقة. * * regurn */ public boolean autoplay () ... {_isrun = true ؛ _Thread = موضوع جديد (هذا) ؛ _thread.start () ؛ العودة _playing ؛ }/***// ***توقف عن اللعب*/public void stop () ... {if (_audio! = null && _audio.isactive ()) ... {try ... {_audio.stop () ؛ } catch (استثناء e) ... {}} if (_midi! = null) ... {_midi.stop () ؛ } _playing = false ؛ _isrun = false ؛ }/*** // *** بيانات الإصدار**/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 ؛ }/***// ***تعيين metamessage*/public void meta (metamessage meta) ... {// حدد ما إذا كان سيتم تشغيل حلقة midi إذا (_loop && _soundtype == sounddata._l_soundtype_midi && meta.gettype () == 47) ... _midi.isopen ()) ... {_midi.setmicrosecondposition (0) ؛ _midi.start () ؛ }}} public void run () ... {بينما (_isrun) ... {play () ؛ // لأن نوع التشغيل فريد من نوعه ، سيتم إرجاع نتيجة واحدة فقط لتحديد ذلك. if (_midi! = null) ... {_playing = _midi.isrunning () ؛ } if (_audio! = null) ... {_playing = _audio.isrunning () ؛ } // عندما يتوقف التشغيل if (! _playing) ... {// relext reset () ؛ } حاول ... {thread.sleep (_sleeptime) ؛ } catch (interruptedException e) ... {E.PrintStackTrace () ؛ }}} public int getleeptime () ... {return _sleeptime ؛ }/*** // *** قم بتعيين وقت حلقة مؤشر ترابط التشغيل التلقائي. * * param time */ public void setSleeptime (int time) ... {_sleeptime = time ؛ }}
في هذا الوقت ، ما نحتاج إلى مواجهته هو فقط بيانات SoundData وعمليات الصوتية المغطاة ككيانات ، دون الحاجة إلى التعامل مع Javax.sound المعقدة مرة أخرى.
طريقة الاتصال على النحو التالي:
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.soundplay. loonframework </p> * <p> الوصف: اختبار تشغيل soundplay </p> * <p> حقوق الطبع والنشر: حقوق الطبع والنشر (c) 2007 </p> * <p> الشركة: loonframework </p> * @Author chenpeng * @email: ceponline.com. ftype) .. {sounddata data = null ؛ Switch (ftype) .. {// تشغيل الموسيقى من الشبكة من خلال URI تحت حالة LoonFramework 0: Data = new SoundData (New Uri ("http://looframework.sourceforge.net/midi/who هو البطل الكبير") استراحة؛ // قم بتشغيل الموسيقى من خلال كائن Byte [] في ملف الموسيقى ضمن حالة الموارد المحلية 1: Byte [] Bytes = StreamHelper.getResourCedata ("/Midi/Who the Big Hero.mid") ؛ data = new SoundData (bytes ، sounddata._l_soundtype_midi ، false) ؛ استراحة؛ // تشغيل الموسيقى من خلال حالة مسار ملف الموسيقى 2: Data = New SoundData ("C:/Who the Big Hero.mid" ، sounddata._l_soundtype_midi ، false) ؛ استراحة؛ } soundplay play = new SoundPlay () ؛ // الفرق بين طرق التشغيل التلقائي واللعب هو أن التشغيل التلقائي سيتوقف تلقائيًا ويصدر الموارد بعد اللعب ، ويجب إحباط المسرحية يدويًا. //play.play(data) ؛ play.autoplay (البيانات) ؛ } public static void main (string [] args) .. {selectPlay (2) ؛ }}سيتم شرح طريقة أكثر تفصيلاً بعد الإعلان بالكامل عن لعبة LoonFramework.
بالإضافة إلى ذلك: نظرًا لأن StreamHelper يرتبط بطرق LoonFramework الأخرى ، فلن يتم تقديمه بعد. يمكن كتابة InputStream to Byte [] على النحو التالي:
// هو IS هو المدخلات التي تم الحصول عليها bytearrayoutputstream bytearrayoutputstream = جديد bytearrayoutputstream () ؛ // المستخدمة للقيام بايت [] byte [] ArrayByte = null ؛ حاول ... {// حجم كل نقل هو 4096 بايت [] بايت = بايت جديد [4096] ؛ bytes = new byte [is.availival ()] ؛ القراءة بينما ((read = is.read (bytes))> = 0) ... {bytearrayoutputstream.write (bytes ، 0 ، read) ؛ } arraybyte = bytearrayoutputstream.tobytearray () ؛ } catch (ioException e) ... {return null ؛ } أخيرًا ... {try ... {if (bytearrayoutputStream! = null) ... {bytearrayoutputstream.close () ؛ bytearrayoutputStream = null ؛ } if (is! = null) ... {is.close () ؛ هو = فارغ. }} catch (ioException e) ... {}}