مرحبا يا هبر! أقدم إليكم ترجمة المقال
"Java Sound، Getting Started، Part 1، Playback" .
الصوت في JAVA ، الجزء الأول ، البداية. لعب الصوت
هذه هي بداية سلسلة من ثمانية دروس ستعرفك تمامًا على Java Sound API.
ما هو الصوت في الإدراك البشري؟ هذا هو الشعور الذي نشعر به عندما ينتقل تغيير في ضغط الهواء إلى المناطق الحسية الدقيقة داخل آذاننا.
والهدف الرئيسي لإنشاء Sound API هو تزويدك بوسائل لكتابة الكود ، مما سيساعد في نقل موجات الضغط إلى آذان الموضوع المناسب في الوقت المناسب.
أنواع الصوت في جافا:
- تدعم واجهة برمجة تطبيقات Java Sound نوعين رئيسيين من الصوت (صوت).
- الصوت رقمنة وتسجيلها مباشرة كملف
- سجل كملف MIDI. بعيد جدًا ، ولكنه مشابه للترميز الموسيقي ، حيث يتم تشغيل الآلات الموسيقية بالترتيب المطلوب.
هذه الأنواع مختلفة تمامًا في جوهرها ، وسنركز على الأول ، حيث أننا في معظم الحالات نتعامل مع الصوت الذي يحتاج إما إلى الرقمنة للتسجيل من مصدر خارجي إلى ملف أو العكس بالعكس لإنتاج صوت مسجل مسبقًا من هذا الملف.
معاينة
تعتمد واجهة برمجة تطبيقات Java Sound على مفهوم
الخطوط والخلاطات.التالي:
سنصف الخصائص الفيزيائية والكهربائية للتمثيل التناظري للصوت المطبق على
الخلاط الصوتي .
سوف ننتقل إلى سيناريو فرقة الروك الأولى ، والتي تستخدم ستة ميكروفونات وسماعتين ستيريو في هذه الحالة. نحن بحاجة إلى هذا لفهم تشغيل خلاط الصوت.
بعد ذلك ، ننظر إلى عدد من سمات Java Sound للبرمجة ، مثل الخطوط ، الخلاطات ، تنسيقات البيانات الصوتية ، وأكثر من ذلك.
سوف نفهم العلاقات القائمة بين الكائنات SourceDataLine و Clip و Mixer و AudioFormat وإنشاء برنامج بسيط يعيد إنتاج الصوت.
فيما يلي مثال على هذا البرنامج ، والذي يمكنك استخدامه لتسجيل الصوت المسجل ثم تشغيله.
في المستقبل ، سوف نقدم شرحًا كاملًا لرمز البرنامج المستخدم لهذا الغرض. لكن بأي حال من الأحوال تماما في هذا الدرس.
مثال التعليمات البرمجية والنظر
الخصائص الفيزيائية والكهربائية للصوت التناظريةالغرض من درسنا هو تعريفك بأساسيات برمجة Java باستخدام Java Sound API.
تعتمد Java Sound API على مفهوم خلاط الصوت ، وهو جهاز شائع الاستخدام عند تشغيل الصوت في أي مكان تقريبًا: من حفلات موسيقى الروك إلى الاستماع إلى أقراص مضغوطة في المنزل. ولكن قبل الشروع في شرح مفصل لتشغيل الخلاط الصوتي ، سيكون من المفيد أن تتعرف على الخصائص الفيزيائية والكهربائية للصوت التناظري نفسه.
انظر إلى الشكل 1
فاسيا Pupyrkin يدفع خطاب.
يوضح هذا الشكل قيام Vasya بإلقاء خطاب باستخدام نظام معروف باسم نظام واسع العنوان. يشتمل هذا النظام عادةً على ميكروفون ومكبر صوت ومكبر صوت. الغرض من هذا النظام هو تعزيز صوت Vasya بحيث يمكن سماعه حتى في حشد كبير.
تمايل في الهواءلفترة وجيزة ، عندما يتحدث Vasya ، تتسبب حباله الصوتية في تهتز جزيئات الهواء في الحنجرة. يؤدي ذلك إلى ظهور موجات صوتية ، والتي بدورها تتسبب في اهتزاز غشاء الميكروفون ثم يتحول إلى اهتزازات كهربائية صغيرة السعة للغاية ، والتي تحاكي تمامًا الاهتزازات الصوتية التي تم إنشاؤها أصلاً بواسطة Vasya. يضخم مكبر الصوت ، كما يوحي اسمه ، هذه الاهتزازات الكهربائية. ثم يصلون إلى مكبر الصوت ، الذي يؤدي التحول العكسي للاهتزازات الكهربائية المتضخمة إلى موجات صوتية مضخمة للغاية ، لكن مع ذلك يكرر بالضبط نفس الموجات التي تم إنشاؤها في الحبال الصوتية لفاسيا بوبيركين.
ميكروفون ديناميكيالآن دعونا ننظر إلى الشكل. 2 ، مما يدل على الرسم التخطيطي للميكروفون يسمى ديناميكية.
شكل 2 دائرة ميكروفون ديناميكيالاهتزازات الصوتية تؤثر على الغشاءيعمل ضغط الاهتزازات الصوتية على غشاء مرن داخل الميكروفون. يؤدي هذا إلى تهتز الغشاء ، بينما تكرر اهتزازات الغشاء اهتزازات الأمواج الصوتية.
نقل لفائفيتم إرفاق ملف من الأسلاك الرفيعة بغشاء الميكروفون. عندما يتذبذب الغشاء ، يقوم الملف أيضًا بحركات ترددية في المجال المغناطيسي للجزء الرئيسي المصنوع من مغناطيس دائم قوي. وكما أسس فاراداي ، ينشأ تيار كهربائي في الملف.
تتبع الإشارة الكهربائية شكل الموجات الصوتية.وبالتالي ، من تيار ضعيف للغاية يحدث في الملف ، يتم الحصول على إشارة كهربائية متناوبة ، لتكرار شكل الموجات الصوتية التي تعمل على غشاء الميكروفون. علاوة على ذلك ، يتم تغذية هذه الإشارة في شكل الجهد بالتناوب لإدخال مكبر للصوت من الشكل. 1.
مكبر الصوتفي الواقع ، يكرر مبدأ تشغيل السماعة جهاز الميكروفون الديناميكي ، ويتم تشغيله فقط في الاتجاه المعاكس.
(وبطبيعة الحال ، في هذه الحالة ، تكون الأسلاك الملفوفة أكثر سماكة ، والغشاء أكبر بكثير لضمان التشغيل بإشارة تضخيم)

تؤثر تذبذبات غشاء السماعة الخارجية على جزيئات الهواء وتخلق موجات صوتية قوية. يكرر شكل هذه الموجات تمامًا شكل الموجات الصوتية ذات الكثافة المنخفضة جدًا الناتجة عن الحبال الصوتية لفاسيا. ولكن كثافة الموجات الجديدة كافية الآن لضمان وصول اهتزازات الصوت من فازيا إلى آذان الأشخاص الذين يقفون حتى في الصفوف الخلفية لحشد كبير.
حفل موسيقى الروكبحلول هذا الوقت ، قد تتساءل ، ما علاقة كل هذا بـ Java Sound API؟ لكن انتظر لفترة أطول قليلاً ، نحن نقود الطريق إلى أساسيات خلاط الصوت.
الدائرة المذكورة أعلاه كانت بسيطة للغاية. وتألفت من فاسيا بوبيركين وميكروفون واحد ومكبر صوت ومكبر صوت. الآن النظر في الدائرة مع الشكل. 4 ، والذي يعرض المرحلة المعدة لحفل موسيقى الروك للمجموعة الموسيقية الأولى.
ستة ميكروفونات وسماعتينفي الشكل توجد 4 ست ميكروفونات على المسرح. توجد مكبّرات صوت (مكبرات صوت) على جانبي المسرح. عندما يبدأ الحفل الموسيقي ، يغني المؤدون أو يعزفون الموسيقى في كل من الميكروفونات الستة. وفقا لذلك ، سيكون لدينا ست إشارات كهربائية ، والتي يجب تضخيمها بشكل فردي ومن ثم تغذيتها لكلا المتحدثين. بالإضافة إلى ذلك ، يمكن لفناني الأداء استخدام المؤثرات الصوتية الخاصة المختلفة ، على سبيل المثال ، تردد ، والتي سوف تحتاج أيضًا إلى تحويلها إلى إشارات كهربائية قبل تطبيقها على السماعات.
تم تصميم متكلمين على جانبي المسرح لإنشاء تأثير صوت ستيريو. أي أن الإشارة الكهربائية القادمة من الميكروفون الموجود على المسرح إلى اليمين يجب أن تقع في السماعة الموجودة على اليمين أيضًا. وبالمثل ، ينبغي تغذية الإشارة من الميكروفون إلى اليسار للمتكلم الموجود على يسار المشهد. لكن الإشارات الكهربائية من الميكروفونات الأخرى الموجودة بالقرب من مركز المرحلة يجب أن تنتقل بالفعل إلى كلا السماعتين بنسب مناسبة. وينبغي أن اثنين من الميكروفونات الحق في المركز نقل إشارة إلى كل المتكلمين على قدم المساواة.
خلاط الصوتيتم تنفيذ المهمة التي تمت مناقشتها أعلاه فقط بواسطة جهاز إلكتروني يسمى خلاط الصوت.
خط الصوت (قناة)على الرغم من أن المؤلف ليس خبيرًا في خلاطات الصوت ، إلا أنه في فهمه المتواضع ، فإن الخلاط الصوتي النموذجي لديه القدرة على تلقي عدد معين من المستقلين عند كل إشارة مستقلة عن كل إشارات كهربائية أخرى ، يمثل كل منها إشارة أو خط الصوت الأصلي
(القناة).(سيصبح مفهوم القناة الصوتية مهمًا للغاية عندما نبدأ في فهم Java Sound API بالتفصيل.
معالجة مستقلة لكل قناة صوتيةفي أي حال ، فإن خلاط الصوت القياسي لديه القدرة على تضخيم كل خط صوت بشكل مستقل عن القنوات الأخرى. كما أن الخلاط عادة ما يكون لديه القدرة على فرض مؤثرات صوتية خاصة ، على سبيل المثال ، تردد في أي من خطوط الصوت. في النهاية ، يمكن للخلاط ، كما يوحي اسمه ، مزج جميع الإشارات الكهربائية الفردية في قنوات الإخراج كما سيتم ضبطها ، وذلك للتحكم في مساهمة كل خط صوت في قنوات الإخراج. (عادة ما يطلق على هذا التحكم عموم أو عموم - التوزيع في الفضاء).
العودة إلى صوت ستيريووهكذا ، في الرسم البياني مع الشكل. 4 ، يمتلك مهندس الصوت في الخلاط الصوتي القدرة على الجمع بين الإشارات من ستة ميكروفونات للحصول على إشارة خرج اثنين ، يتم إرسال كل منها إلى مكبر الصوت الخاص بها.
للتشغيل الناجح ، يجب توفير الإشارة من كل ميكروفون بالنسب المناسبة ، اعتمادًا على الموقع الفعلي للميكروفون على المسرح. (عن طريق تغيير الخلفية ، يمكن لمهندس صوت مؤهل تغيير مساهمة كل ميكروفون إذا لزم الأمر ، إذا ، على سبيل المثال ، يتحرك المنشد الرئيسي حول المسرح أثناء الحفل الموسيقي).
حان الوقت للعودة إلى عالم البرمجةدعونا الآن نعود من العالم المادي إلى عالم البرمجة. وفقًا لـ Sun:
"صوت Java لا يتضمن أي تكوين خاص للأجهزة ؛ تم تصميمه للسماح بمكونات الصوت المختلفة ليتم تثبيتها على النظام وإتاحتها للمستخدم من خلال API. يدعم Java Sound وظائف الإدخال والإخراج القياسية من بطاقة صوت (على سبيل المثال ، لتسجيل وتشغيل الملفات الصوتية) ، وكذلك القدرة على مزج تدفقات صوتية متعددة "الخلاطات والقنواتكما ذكرنا سابقًا ، تم تصميم Java Sound API على مفهوم الخلاطات والقنوات. إذا انتقلت من العالم المادي إلى عالم البرمجة ، فستكتب Sun ما يلي بخصوص الخلاط:
"الخلاط عبارة عن جهاز صوتي به قناة أو أكثر. لكن الخلاط الذي يمزج الإشارة الصوتية يجب أن يحتوي على عدة قنوات إدخال لمصادر المصدر وقناة واحدة على الأقل لإخراج الخرج. "يمكن أن تكون خطوط الإدخال مثيلات للفئات التي تحتوي على كائنات SourceDataLine ، ويمكن أن تكون خطوط الإخراج كائنات TargetDataLine. يمكن للخلاط أيضًا استلام الصوت المسجَّل مسبقًا والمحلل كمدخلات ، وتحديد قنوات مصدر الدخل الخاصة به كحالات لكائنات فئة تنفذ واجهة Clip.
واجهة خط القناة.
تقوم Sun بالإبلاغ عن ما يلي من واجهة الخط: "
الخط هو عنصر من خطوط أنابيب الصوت الرقمية مثل منفذ إدخال أو إخراج الصوت أو الخلاط أو مسار الصوت من أو إلى خلاط. يمكن أن تكون البيانات الصوتية التي تمر عبر القناة أحادية أو متعددة القنوات (على سبيل المثال ، ستيريو). ... يمكن أن تحتوي القناة على عناصر تحكم ، مثل الكسب ، التحريك ، والتكرار. "وضع الشروط معالذلك ، يقتبس أعلاه من صن يدل على الشروط التالية
المصدر
Targetgetataline
ميناء
مقطع
الضوابط
شكل يُظهر 5 مثال على استخدام هذه المصطلحات لإنشاء برنامج إخراج صوتي بسيط.
البرنامج النصيمن وجهة نظر البرنامج يُظهر 5 كائن Mixer الحصول عليها مع كائن Clip واحد وكائنات SourceDataLine.
ما هو مقطعالمقطع هو كائن عند إدخال الخلاط ، لا تتغير محتوياته مع مرور الوقت. بمعنى آخر ، يمكنك تحميل بيانات الصوت إلى كائن القصاصة قبل تشغيلها. قد يتم تشغيل المحتوى الصوتي للكائن Clip مرة واحدة أو أكثر. يمكنك استعادة المقطع ثم سيتم تشغيل المحتوى مرارًا وتكرارًا.
تيار الإدخالكائن SourceDataLine ، من ناحية أخرى ، هو كائن دفق عند إدخال الخلاط. يمكن للكائن من هذا النوع تلقي دفق من البيانات الصوتية وإرسالها إلى خلاط في الوقت الحقيقي. يمكن الحصول على البيانات الصوتية الضرورية من مصادر مختلفة ، مثل ملفات الصوت أو اتصال الشبكة أو مخزن الذاكرة المؤقت.
أنواع مختلفة من القنواتوبالتالي ، يمكن اعتبار الكائنات Clip و SourceDataLine كقنوات إدخال للكائن Mixer. يمكن أن يكون لكل قناة من قنوات الإدخال الخاصة بها: عموم ، ربح ، تردد.
تشغيل محتوى الصوتفي مثل هذا النظام البسيط ، يقوم Mixer بقراءة البيانات من خطوط الإدخال ، ويستخدم التحكم لخلط إشارات الدخل ، ويوفر المخرجات لقناة إخراج واحدة أو أكثر ، مثل السماعة ومخرج الخط ومقبس السماعة وما إلى ذلك.
تعرض القائمة 11 برنامجًا بسيطًا يلتقط البيانات الصوتية من منفذ الميكروفون ، ويخزن هذه البيانات في الذاكرة ، ثم يقوم بتشغيلها عبر منفذ السماعة.
سنناقش فقط التقاط وتشغيل. معظم البرنامج أعلاه هو إنشاء نافذة وواجهة رسومية للمستخدم بحيث يمكن التحكم في التسجيل والتشغيل. لن نناقش هذا الجزء باعتباره يتجاوز الهدف. ولكن بعد ذلك سننظر في التقاط البيانات وتشغيلها. سنناقش الخسارة في هذا الدرس ، ونناقشها في التالي. على طول الطريق ، سنوضح استخدام قناة الصوت مع Java Sound API.
يتم تخزين البيانات الملتقطة في كائن ByteArrayOutputStream.
يوفر مقتطف الشفرة المقتطف الشفري قراءة بيانات الصوت من ميكروفون وتخزينها ككائن ByteArrayOutputStream.
الطريقة ، تسمى playAudio ، والتي تبدأ في القائمة 1 ، تقوم بتشغيل بيانات الصوت التي تم التقاطها وتخزينها في كائن ByteArrayOutputStream.
private void playAudio() { try{ byte audioData[] = byteArrayOutputStream. toByteArray(); InputStream byteArrayInputStream = new ByteArrayInputStream( audioData);
قائمة 1نبدأ مع الكود القياسي.في الواقع ، لا يرتبط مقتطف البرنامج في القائمة 1 بـ Java Sound.
والغرض منه هو:
- تحويل البيانات المحفوظة مسبقا إلى مجموعة من نوع بايت.
- الحصول على دفق الإدخال لصفيف بيانات بايت.
نحتاج إلى ذلك لتوفير بيانات صوتية للتشغيل لاحقًا.
انتقل إلى واجهة برمجة تطبيقات الصوتيرتبط سطر الكود في القائمة 2 بالفعل بـ Java Sound API.
AudioFormat audioFormat = getAudioFormat();
ادراج 2نحن هنا نتطرق باختصار إلى الموضوع الذي سيتم مناقشته بالتفصيل في الدرس التالي.
شكلين مستقلينغالبًا ما نتعامل مع تنسيقين مستقلين للبيانات الصوتية.
تنسيق الملف (أي) الذي يحتوي على بيانات صوتية (في برنامجنا لم يتم بعد ، حيث يتم تخزين البيانات في الذاكرة)
تنسيق البيانات الصوتية المقدمة في حد ذاته.
ما هو تنسيق الصوت؟إليكم ما يكتبه صن حول هذا الموضوع:
"لكل قناة بيانات تنسيق صوتي خاص بها مرتبط بدفق البيانات الخاص بها. يحدد التنسيق (مثيل AudioFormat) ترتيب البايت لدفق الصوت. يمكن أن تكون معلمات التنسيق هي عدد القنوات وتردد أخذ العينات وبتة الكمي وطريقة الترميز وما إلى ذلك. يمكن أن تكون طرق الترميز المعتادة عبارة عن تعديل خطي للرمز النبضي لجهاز PCM ومتغيراته. "بايت تسلسلالبيانات الصوتية المصدر هي سلسلة بايت من البيانات الثنائية. هناك العديد من الخيارات لكيفية تنظيم وتفسير هذا التسلسل. لن نبدأ في التعامل مع كل هذه الخيارات بالتفصيل ، لكننا سنناقش قليلاً تنسيق الصوت الذي نستخدمه هنا في برنامجنا.
استطراد صغيرهنا نترك طريقة playAudio في الوقت الحالي وننظر إلى طريقة getAudioFormat من القائمة 2.
يتم عرض طريقة getAudioFormat الكاملة في القائمة 3. private AudioFormat getAudioFormat(){ float sampleRate = 8000.0F; int sampleSizeInBits = 16; int channels = 1; boolean signed = true; boolean bigEndian = false; return new AudioFormat( sampleRate, sampleSizeInBits, channels, signed, bigEndian); }
قائمة 3بالإضافة إلى التصريح عن المتغيرات التي تمت تهيئتها ، يحتوي الكود الموجود في القائمة 3 على تعبير واحد قابل للتنفيذ.
كائن تنسيق الصوتالأسلوب getAudioFormat بإنشاء وإرجاع مثيل كائن من فئة AudioFormat. إليكم ما يكتبه صن عن هذا الفصل:
تحدد فئة AudioFormat الترتيب المحدد للبيانات في دفق الصوت. بالانتقال إلى حقول كائن AudioFormat ، يمكنك الحصول على معلومات حول كيفية ترجمة البتات بشكل صحيح في دفق بيانات ثنائي. "نحن نستخدم أبسط المنشئتحتوي فئة AudioFormat على نوعين من المنشئات (سنأخذ الفئة الأكثر تافهة). المعلمات التالية مطلوبة لهذا المنشئ:
- معدل أخذ العينات أو معدل العينة في الثانية (القيم المتاحة: 8000 ، 11025 ، 16000 ، 22050 ، 44100 عينة في الثانية)
- عمق بت البيانات (8 و 16 بت لكل عدد متاح)
- عدد القنوات (قناة واحدة للأحادية واثنتان للاستريو)
- البيانات الموقعة أو غير الموقعة المستخدمة في الدفق (على سبيل المثال ، تختلف القيمة من 0 إلى 255 أو من -127 إلى +127)
- ترتيب بايت Big endian أو endian قليلاً. (إذا كنت تقوم بنقل تيار بايت قيم 16 بت ، فمن المهم معرفة البايت الذي يأتي أولاً - منخفض أو مرتفع ، حيث يوجد كلا الخيارين).
كما ترون في القائمة 3 ، في حالتنا ، استخدمنا المعلمات التالية لمثيل كائن AudioFormat.
- 8000 عينة في الثانية
- 16 حجم البيانات
- بيانات مهمة
- ترتيب endian قليلا
بشكل افتراضي ، يتم تشفير البيانات بواسطة PCM خطي.
ينشئ المنشئ الذي استخدمناه مثيلًا لكائن AudioFormat باستخدام تعديل رمز النبض الخطي والمعلمات الموضحة أعلاه (سنعود إلى PCM الخطي وطرق الترميز الأخرى في الدروس التالية)
العودة إلى طريقة playAudio مرة أخرىوالآن بعد أن فهمنا كيفية عمل تنسيق بيانات الصوت في صوت Java ، دعنا نعود إلى طريقة playAudio. بمجرد أن نريد تشغيل بيانات الصوت المتوفرة ، نحتاج إلى كائن من الفئة AudioInputStream. حصلنا على مثيل لها في القائمة 4.
audioInputStream = new AudioInputStream( byteArrayInputStream, audioFormat, audioData.length/audioFormat. getFrameSize());
قائمة 4معلمات منشئ AudioInputStream- يتطلب مُنشئ فئة AudioInputStream المعلمات الثلاثة التالية:
- مجموعة البث التي سيتم فيها بناء مثيل كائن AudioInputStream (كما نرى لهذا الغرض ، نستخدم مثيل كائن ByteArrayInputStream الذي تم إنشاؤه مسبقًا)
- تنسيق بيانات الصوت لهذا الدفق (لهذا الغرض أنشأنا بالفعل مثيل لكائن AudioFormat)
- حجم الإطار (الإطار) للبيانات الموجودة في هذا الدفق (انظر الوصف أدناه)
- المعلمتان الأوليان واضحان من الكود في القائمة 4. ومع ذلك ، فإن المعلمة الثالثة ليست واضحة في حد ذاتها.
الحصول على حجم الإطاركما نرى من قائمة 4 ، يتم إنشاء قيمة المعلمة الثالثة باستخدام العمليات الحسابية. هذه مجرد واحدة من سمات تنسيق الصوت الذي لم نذكره من قبل ، ويسمى إطار.
ما هو الإطار؟للحصول على PCM خطي بسيط يستخدم في برنامجنا ، يحتوي الإطار على مجموعة من العينات لجميع القنوات في وقت معين.
وبالتالي ، فإن حجم الإطار يساوي حجم العد بالبايت ضرب عدد القنوات.
كما كنت قد خمنت ، تقوم طريقة تسمى getFrameSize بإرجاع حجم الإطار بالبايت.
حساب حجم الإطاروبالتالي ، يمكن حساب طول البيانات الصوتية في إطار بتقسيم العدد الإجمالي للبايتات في تسلسل البيانات الصوتية على عدد البايتات في إطار واحد. يتم استخدام هذا الحساب للمعلمة الثالثة في قائمة 4.
الحصول على كائن SourceDataLineالجزء التالي من البرنامج الذي سنناقشه هو نظام إخراج صوتي بسيط. كما نرى من الشكل في الشكل 5 ، لحل هذه المشكلة ، نحتاج إلى كائن SourceDataLine.
هناك عدة طرق للحصول على مثيل للكائن SourceDataLine ، وكلها صعبة للغاية. استرداد رمز في سرد 5 ويخزن مرجع إلى مثيل كائن SourceDataLine.
(لاحظ أن هذا الرمز لا يقوم فقط بإنشاء مثيل لعنصر SourceDataLine. إنه يحصل عليه بطريقة ملتوية.)
DataLine.Info dataLineInfo = new DataLine.Info( SourceDataLine.class, audioFormat); sourceDataLine = (SourceDataLine) AudioSystem.getLine( dataLineInfo);
ادراج 5ما هو كائن SourceDataLine؟
حول هذا ، صن كتب ما يلي:
"SourceDataLine هي قناة بيانات يمكن من خلالها كتابة البيانات. يعمل كمدخل لخلاط. يكتب تطبيق تسلسل بايت إلى SourceDataLine ، والذي يقوم بتخزين البيانات مؤقتًا ويقوم بتسليمها إلى الخلاط الخاص بها. يمكن للخلاط نقل البيانات التي يعالجها للمرحلة التالية ، على سبيل المثال ، إلى منفذ الإخراج.
لاحظ أن اصطلاح التسمية لهذا الاقتران يعكس العلاقة بين القناة وخلاطها. "طريقة GetLine لفئة AudioSystemإحدى طرق الحصول على مثيل لكائن SourceDataLine هي استدعاء الأسلوب getLine الثابت من فئة AudioSystem (سيكون لدينا الكثير للإبلاغ عنه في الدروس التالية).
تتطلب طريقة getLine معلمة إدخال من النوع Line.Info وإرجاع كائن خط يطابق الوصف الموجود في كائن Line.Info المحدد بالفعل.
استطراد قصير آخرتقارير Sun المعلومات التالية حول كائن Line.Info:
"تحتوي القناة على كائن معلومات خاص بها (مثيل لـ Line.Info) ، والذي يعرض الخلاط (إن وجد) الذي يرسل البيانات الصوتية المختلطة كإخراج مباشرةً إلى القناة ، وأي خلاط (إن وجد) يستقبل بيانات الصوت كمدخلات مباشرة من القناة. يمكن أن تتوافق أنواع متنوعة من Line مع الفئات الفرعية من Line.Info ، والتي تتيح لك تحديد أنواع أخرى من المعلمات المتعلقة بأنواع محددة من القنوات "
كائن DataLine.Infoينشئ التعبير الأول في قائمة 5 نسخة جديدة من كائن DataLine.Info ، وهو نموذج خاص (فئة فرعية) لكائن Line.Info.
هناك العديد من المنشئات overloaded لفئة DataLine.Info. لقد اخترنا أسهل للاستخدام. هذا المنشئ يتطلب معلمتين.
كائن فئةالمعلمة الأولى هي Class ، والتي تمثل الفئة التي عرفناها على أنها SourceDataLine.class
تحدد المعلمة الثانية تنسيق البيانات المطلوب للقناة. نستخدم مثيل كائن AudioFormat له ، والذي تم تعريفه مسبقًا من قبل.
أين نحن بالفعل؟لسوء الحظ ، ما زلنا لا نملك الكائن SourceDataLine المطلوب. حتى الآن ، لدينا كائن يوفر فقط معلومات حول كائن SourceDataLine الذي نحتاجه.
الحصول على كائن SourceDataLineيقوم التعبير الثاني في "الإدراج 5" أخيرًا بإنشاء مثيل SourceDataLine وتخزينه. يحدث هذا عن طريق استدعاء getLine للأسلوب الثابت لفئة AudioSystem وتمرير dataLineInfo كمعلمة. (في الدرس التالي ، سننظر في كيفية الحصول على كائن الخط ، والعمل مباشرة مع كائن خلاط).
إرجاع الأسلوب getLine مرجع إلى كائن من النوع Line ، وهو الأصل SourceDataLine. لذلك ، مطلوب downcast هنا قبل حفظ قيمة الإرجاع كـ SourceDataLine.
دعنا نستعد لاستخدام كائن SourceDataLineبمجرد الحصول على مثيل لكائن SourceDataLine ، نحتاج إلى إعداده للفتح والتشغيل ، كما هو موضح في القائمة 6.
sourceDataLine.open(audioFormat); sourceDataLine.start();
قائمة 6طريقة فتحكما ترون من القائمة 6 ، أرسلنا كائن AudioFormat إلى طريقة فتح كائن SourceDataLine.
حسب صن ، هذه طريقة:
"يفتح خطًا (قناة) بتنسيق محدد مسبقًا ، مما يسمح له بتلقي أي موارد نظام يحتاجها ويكون في حالة عمل (يعمل)"اكتشاف الدولةهناك القليل الذي يكتبه صن حوله في هذا الموضوع.
"فتح وإغلاق القناة يؤثر على توزيع موارد النظام. يضمن الافتتاح الناجح للقناة توفير جميع الموارد اللازمة للقناة.
يتضمن فتح الخلاط ، الذي يحتوي على منافذ الإدخال والإخراج الخاصة ببيانات الصوت ، من بين أشياء أخرى ، استخدام أجهزة النظام الأساسي التي يتم فيها العمل وتهيئة مكونات البرامج الضرورية.
فتح قناة ، وهو طريق لبيانات الصوت إلى أو من خلاط ، يتضمن كلا من تهيئة وتلقي بأي حال من الأحوال موارد خلاط غير محدودة. بمعنى آخر ، يحتوي الخلاط على عدد محدود من القنوات ، لذا يجب أن تشترك عدة تطبيقات مع احتياجات قنواتها الخاصة (وحتى في بعض الأحيان تطبيق واحد) بشكل صحيح في موارد الخلاط) "استدعاء طريقة البداية على قناةوفقًا لـ Sun ، فإن استدعاء طريقة البدء للقناة تعني ما يلي:
"يُسمح للقناة باستخدام خطوط الإدخال / الإخراج. إذا تم إجراء محاولة لاستخدام خط التشغيل بالفعل ، فإن الطريقة لا تفعل شيئًا. ولكن بعد أن يكون المخزن المؤقت للبيانات فارغًا ، يستأنف الخط بدء تشغيل I / O ، بدءًا من الإطار الأول الذي لم يتمكن من معالجته بعد تحميل المخزن المؤقت بالكامل. "في حالتنا ، بالطبع ، لم تتوقف القناة. منذ أن أطلقناها لأول مرة.
الآن لدينا تقريبا كل ما نحتاجهفي هذه المرحلة ، تلقينا جميع موارد الصوت التي نحتاج إليها لتشغيل بيانات الصوت التي سبق أن سجلناها وخزنناها في مثيل للكائن ByteArrayOutputStream. (تذكر أن هذا الكائن موجود فقط في ذاكرة الوصول العشوائي للكمبيوتر).
نبدأ التدفقاتسنقوم بإنشاء وبدء الدفق لتشغيل الصوت. ينشئ الكود في قائمة 7 هذا الخيط ويبدأ تشغيله.
(لا تخلط بين استدعاء أسلوب البدء في هذا مؤشر الترابط والاستدعاء إلى أسلوب البدء في كائن SourceDataLine من قائمة 6. هذه عمليات مختلفة تماما)
Thread playThread = new Thread(new PlayThread()); playThread.start(); } catch (Exception e) { System.out.println(e); System.exit(0); }
قائمة 7رمز متواضعيظهر مقتطف البرنامج في List 7 ، رغم أنه بسيط للغاية ، مثالاً على البرمجة متعددة الخيوط في Java. إذا لم تفهمها ، فعليك أن تتعرف على هذا الموضوع في مواضيع متخصصة لتعلم جافا.
بمجرد بدء البث ، سيعمل حتى يتم تشغيل جميع بيانات الصوت المسجلة مسبقًا حتى النهاية.
كائن موضوع جديدينشئ الكود الموجود في "سرد 7" مثيل كائن مؤشر الترابط من فئة PlayThread. يتم تعريف هذه الفئة كطبقة داخلية في برنامجنا. وصفه يبدأ في قائمة 8.
class PlayThread extends Thread{ byte tempBuffer[] = new byte[10000];
ادراج 8طريقة التشغيل في فئة الموضوعباستثناء تعريف متغير tempBuffer (الذي يشير إلى صفيف وحدات البايت) ، التعريف الكامل لهذه الفئة هو مجرد تعريف لطريقة التشغيل. كما يجب أن تعرف بالفعل ، يؤدي استدعاء أسلوب البدء على كائن مؤشر الترابط إلى تنفيذ طريقة تشغيل هذا الكائن
طريقة التشغيل لهذا مؤشر الترابط تبدأ في سرد 9.
public void run(){ try{ int cnt;
قائمة 9الجزء الأول من جزء البرنامج في طريقة التشغيلتحتوي طريقة التشغيل على جزأين مهمين ، يظهر الجزء الأول في القائمة رقم 9.
باختصار ، يتم استخدام حلقة هنا لقراءة بيانات الصوت من AudioInputStream وتمريرها إلى SourceDataLine.
يتم نقل البيانات المرسلة إلى كائن SourceDataLine تلقائيًا إلى إخراج الصوت الافتراضي. يمكن أن يكون مكبر صوت مدمج أو إخراج خط مدمج. (سنتعلم كيفية تحديد أجهزة الصوت اللازمة في الدروس التالية). يتم استخدام cnt متغير و tempBuffer البيانات المخزن المؤقت للتحكم في تدفق البيانات بين عمليات القراءة والكتابة.
قراءة البيانات من AudioInputStreamتقرأ دورة القراءة من كائن AudioInputStream الحد الأقصى المحدد للبايت من البيانات من AudioInputStream وتضع صفيف البايت الخاص بها.
قيمة الإرجاععلاوة على ذلك ، تُرجع هذه الطريقة إجمالي عدد وحدات البايت المقروءة أو -1 إذا تم الوصول إلى نهاية التسلسل المسجل. يتم تخزين عدد وحدات البايت المقروءة في متغير cnt.
SourceDataLine كتابة حلقةإذا كان عدد وحدات البايت المقروءة أكبر من الصفر ، فهناك انتقال إلى دورة كتابة البيانات إلى SourceDataLine. في هذه الحلقة ، تدخل البيانات الصوتية إلى الخلاط. تتم قراءة البايتات من صفيف البايت وفقًا لمؤشراتها وتتم كتابتها إلى المخزن المؤقت للقناة.
عندما يجف تيار الإدخالعندما تُرجع حلقة القراءة -1 ، فهذا يعني أن جميع بيانات الصوت المسجلة مسبقًا قد انتهت وتمرير المزيد من التحكم إلى جزء البرنامج في القائمة 10.
sourceDataLine.drain(); sourceDataLine.close(); }catch (Exception e) { System.out.println(e); System.exit(0); }
قائمة 10قفل وانتظريستدعي التعليمة البرمجية في قائمة 10 أسلوب الصرف على كائن SourceDataLine بحيث يمكن للبرنامج حظر وانتظر المخزن المؤقت الداخلي لإفراغ في SourceDataLine. عندما يكون المخزن المؤقت فارغًا ، فهذا يعني أن الجزء التالي بأكمله يتم تسليمه إلى إخراج الصوت بجهاز الكمبيوتر.
إغلاق SourceDataLineثم يقوم البرنامج باستدعاء طريقة الإغلاق لإغلاق القناة ، مما يدل على أن جميع موارد النظام المستخدمة من قبل القناة أصبحت مجانية الآن. صن تعلن عن إغلاق القناة التالي:
"إغلاق إشارات القناة أنه يمكن تحرير جميع الموارد المتعلقة بهذه القناة. لتحرير الموارد ، يجب أن يغلق التطبيق القنوات ، سواء كانت متورطة بالفعل أم لا بالفعل ، وكذلك عند انتهاء التطبيق. من المفترض أن الخلاطات تشترك في موارد النظام ويمكن إغلاقها وفتحها بشكل متكرر. قد تدعم أو لا تدعم القنوات الأخرى إعادة فتحها بعد إغلاقها. بشكل عام ، تختلف آليات فتح الخطوط باختلاف الأنواع الفرعية ".والآن نهاية القصةلذلك قدمنا هنا شرحًا لكيفية استخدام برنامجنا لـ Java Sound API لضمان تسليم بيانات الصوت من الذاكرة الداخلية لجهاز الكمبيوتر إلى بطاقة الصوت.
قم بتشغيل البرنامجيمكنك الآن ترجمة وتشغيل البرنامج من القائمة 11 ، والتي تتوج نهاية درسنا.
التقاط وتشغيل البيانات الصوتيةيوضح البرنامج القدرة على تسجيل البيانات من الميكروفون وتشغيلها من خلال بطاقة الصوت بجهاز الكمبيوتر الخاص بك. تعليمات استخدامه بسيطة للغاية.
قم بتشغيل البرنامج. يجب أن تظهر واجهة المستخدم الرسومية البسيطة ، والتي تظهر في الشكل 6 ، على الشاشة.

- انقر فوق زر الالتقاط وسجل أي أصوات على الميكروفون.
- انقر فوق الزر "إيقاف" لإيقاف التسجيل.
- انقر فوق الزر "تشغيل" لتشغيل التسجيل من خلال إخراج الصوت بجهاز الكمبيوتر الخاص بك.
إذا لم تسمع أي شيء ، فحاول زيادة حساسية الميكروفون أو مستوى صوت السماعة.
يحفظ البرنامج سجلاً في ذاكرة الكمبيوتر ، لذا كن حذرًا. إذا حاولت حفظ الكثير من بيانات الصوت ، فقد تنفد ذاكرة الوصول العشوائي.
الخاتمة- اكتشفنا أن واجهة برمجة تطبيقات Java Sound تستند إلى مفهوم القنوات والخلاطات.
- حصلنا على المعلومات الأولية حول الخصائص الفيزيائية والكهربائية للصوت التناظرية ، من أجل فهم جهاز الخلاط الصوتي.
- استخدمنا سيناريو حفلة روك هواة باستخدام ستة ميكروفونات وسماعتي استريو لوصف إمكانية استخدام خلاط صوتي.
- لقد ناقشنا عددًا من موضوعات برمجة Java Sound ، بما في ذلك الخلاطات والقنوات وتنسيق البيانات والمزيد.
- شرحنا العلاقة العامة بين الكائنات SourceDataLine و Clip و Mixer و AudioFormat والمنافذ في برنامج بسيط لإخراج البيانات الصوتية.
- تعرفنا على برنامج يتيح لنا تسجيل البيانات الصوتية وتشغيلها أولاً.
- تلقينا شرحًا مفصلاً للرمز المستخدم لتشغيل بيانات الصوت المسجلة مسبقًا في ذاكرة الكمبيوتر.
ما التالي؟في هذا البرنامج التعليمي ، اكتشفنا أن واجهة برمجة تطبيقات Java Sound تستند إلى مفهوم الخلاطات والقنوات. ومع ذلك ، فإن الكود الذي ناقشناه لم يتضمن الخلاطات بشكل صريح. زودتنا فئة AudioSystem بطرق ثابتة تتيح لك كتابة برامج معالجة الصوت دون الوصول مباشرة إلى الخلاطات. وبعبارة أخرى ، فإن هذه الطرق الثابتة تأخذ الخلاطات بعيداً عنا.
في الدرس التالي ، نقدم شفرة التقاط بيانات معدلة مقارنة بالرمز الوارد في هذا الدرس. سيستخدم الإصدار الجديد بشكل صريح الخلاطات لتوضيح كيفية استخدامها عند الحاجة إليها. import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; import javax.sound.sampled.*; public class AudioCapture01 extends JFrame{ boolean stopCapture = false; ByteArrayOutputStream byteArrayOutputStream; AudioFormat audioFormat; TargetDataLine targetDataLine; AudioInputStream audioInputStream; SourceDataLine sourceDataLine; public static void main( String args[]){ new AudioCapture01(); }
قائمة 11