1. शुरू करने से पहले
गेम, ऑडियो-विज़ुअल अनुभव देते हैं. Flutter, बेहतरीन विज़ुअल और यूज़र इंटरफ़ेस (यूआई) बनाने के लिए एक बेहतरीन टूल है. इससे, आपको विज़ुअल के मामले में काफ़ी मदद मिलती है. अब सिर्फ़ ऑडियो का विकल्प बाकी है. इस कोडलैब में, अपने प्रोजेक्ट में कम इंतज़ार वाले साउंड और संगीत को शामिल करने के लिए, flutter_soloud
प्लग इन का इस्तेमाल करने का तरीका बताया गया है. शुरुआत में, आपको एक बुनियादी स्कैफ़ोल्ड मिलता है, ताकि आप सीधे दिलचस्प हिस्सों पर जा सकें.
यहां बताई गई बातों का इस्तेमाल, सिर्फ़ गेम में ही नहीं बल्कि अपने ऐप्लिकेशन में भी ऑडियो जोड़ने के लिए किया जा सकता है. हालांकि, ज़्यादातर गेम में साउंड और संगीत की ज़रूरत होती है, लेकिन ज़्यादातर ऐप्लिकेशन में ऐसा नहीं होता. इसलिए, इस कोडलैब में गेम पर फ़ोकस किया गया है.
ज़रूरी शर्तें
- Flutter के बारे में बुनियादी जानकारी.
- Flutter ऐप्लिकेशन को चलाने और डीबग करने का तरीका.
आपको ये सब सीखने को मिलेगा
- एक बार में चलने वाली आवाज़ें चलाने का तरीका.
- गैपलेस संगीत लूप चलाने और उन्हें पसंद के मुताबिक बनाने का तरीका.
- साउंड को धीरे-धीरे कम और ज़्यादा करने का तरीका.
- आवाज़ों पर पर्यावरण से जुड़े इफ़ेक्ट लागू करने का तरीका.
- अपवादों को मैनेज करने का तरीका.
- इन सभी सुविधाओं को एक ही ऑडियो कंट्रोलर में कैसे शामिल करें.
आपको इन चीज़ों की ज़रूरत पड़ेगी
- Flutter SDK टूल
- आपकी पसंद का कोड एडिटर
2. सेट अप करें
- नीचे दी गई फ़ाइलें डाउनलोड करें. अगर आपका इंटरनेट धीमा है, तो चिंता न करें. आपको बाद में असल फ़ाइलों की ज़रूरत पड़ेगी. इसलिए, काम करते समय उन्हें डाउनलोड करने की अनुमति दें.
- अपनी पसंद का नाम डालकर Flutter प्रोजेक्ट बनाएं.
- प्रोजेक्ट में
lib/audio/audio_controller.dart
फ़ाइल बनाएं. - फ़ाइल में, यह कोड डालें:
lib/audio/audio_controller.dart
import 'dart:async';
import 'package:logging/logging.dart';
class AudioController {
static final Logger _log = Logger('AudioController');
Future<void> initialize() async {
// TODO
}
void dispose() {
// TODO
}
Future<void> playSound(String assetKey) async {
_log.warning('Not implemented yet.');
}
Future<void> startMusic() async {
_log.warning('Not implemented yet.');
}
void fadeOutMusic() {
_log.warning('Not implemented yet.');
}
void applyFilter() {
// TODO
}
void removeFilter() {
// TODO
}
}
जैसा कि आप देख सकते हैं, यह आने वाले समय में मिलने वाली सुविधा का सिर्फ़ एक स्केलेटन है. हम इस कोडलैब के दौरान, इन सभी को लागू करेंगे.
- इसके बाद,
lib/main.dart
फ़ाइल खोलें और उसके कॉन्टेंट को इस कोड से बदलें:
lib/main.dart
import 'dart:developer' as dev;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'audio/audio_controller.dart';
void main() async {
// The `flutter_soloud` package logs everything
// (from severe warnings to fine debug messages)
// using the standard `package:logging`.
// You can listen to the logs as shown below.
Logger.root.level = kDebugMode ? Level.FINE : Level.INFO;
Logger.root.onRecord.listen((record) {
dev.log(
record.message,
time: record.time,
level: record.level.value,
name: record.loggerName,
zone: record.zone,
error: record.error,
stackTrace: record.stackTrace,
);
});
WidgetsFlutterBinding.ensureInitialized();
final audioController = AudioController();
await audioController.initialize();
runApp(MyApp(audioController: audioController));
}
class MyApp extends StatelessWidget {
const MyApp({required this.audioController, super.key});
final AudioController audioController;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter SoLoud Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.brown),
),
home: MyHomePage(audioController: audioController),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.audioController});
final AudioController audioController;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const _gap = SizedBox(height: 16);
bool filterApplied = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Flutter SoLoud Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
OutlinedButton(
onPressed: () {
widget.audioController.playSound('assets/sounds/pew1.mp3');
},
child: const Text('Play Sound'),
),
_gap,
OutlinedButton(
onPressed: () {
widget.audioController.startMusic();
},
child: const Text('Start Music'),
),
_gap,
OutlinedButton(
onPressed: () {
widget.audioController.fadeOutMusic();
},
child: const Text('Fade Out Music'),
),
_gap,
Row(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Apply Filter'),
Checkbox(
value: filterApplied,
onChanged: (value) {
setState(() {
filterApplied = value!;
});
if (filterApplied) {
widget.audioController.applyFilter();
} else {
widget.audioController.removeFilter();
}
},
),
],
),
],
),
),
);
}
}
- ऑडियो फ़ाइलें डाउनलोड होने के बाद, अपने प्रोजेक्ट के रूट में
assets
नाम की डायरेक्ट्री बनाएं. assets
डायरेक्ट्री में, दो सबडायरेक्ट्री बनाएं. एक का नामmusic
और दूसरे का नामsounds
रखें.- डाउनलोड की गई फ़ाइलों को अपने प्रोजेक्ट में ले जाएं, ताकि गाने की फ़ाइल
assets/music/looped-song.ogg
फ़ाइल में हो और सीटों की आवाज़ें इन फ़ाइलों में हों:
assets/sounds/pew1.mp3
assets/sounds/pew2.mp3
assets/sounds/pew3.mp3
आपके प्रोजेक्ट का स्ट्रक्चर अब कुछ ऐसा दिखेगा:
फ़ाइलें सेव हो जाने के बाद, आपको Flutter को उनके बारे में बताना होगा.
pubspec.yaml
फ़ाइल खोलें. इसके बाद, फ़ाइल में सबसे नीचे मौजूदflutter:
सेक्शन को इनसे बदलें:
pubspec.yaml
...
flutter:
uses-material-design: true
assets:
- assets/music/
- assets/sounds/
flutter_soloud
पैकेज औरlogging
पैकेज पर डिपेंडेंसी जोड़ें.
flutter pub add flutter_soloud logging
आपकी pubspec.yaml
फ़ाइल में अब flutter_soloud
और logging
पैकेज पर अतिरिक्त डिपेंडेंसी होनी चाहिए.
pubspec.yaml
...
dependencies:
flutter:
sdk: flutter
flutter_soloud: ^3.1.10
logging: ^1.3.0
...
- प्रोजेक्ट चलाएं. फ़िलहाल, कुछ भी काम नहीं करेगा, क्योंकि आपने इन सेक्शन में फ़ंक्शन जोड़े हैं.
3. शुरू करना और बंद करना
ऑडियो चलाने के लिए, flutter_soloud
प्लग इन का इस्तेमाल किया जाता है. यह प्लग इन, SoLoud प्रोजेक्ट पर आधारित है. यह गेम के लिए C++ ऑडियो इंजन है. इसका इस्तेमाल Nintendo SNES Classic के साथ-साथ अन्य डिवाइसों पर भी किया जाता है.
SoLoud ऑडियो इंजन को शुरू करने के लिए, यह तरीका अपनाएं:
audio_controller.dart
फ़ाइल में,flutter_soloud
पैकेज इंपोर्ट करें और क्लास में निजी_soloud
फ़ील्ड जोड़ें.
lib/audio/audio_controller.dart
import 'dart:async';
import 'package:flutter_soloud/flutter_soloud.dart'; // ← Add this...
import 'package:logging/logging.dart';
class AudioController {
static final Logger _log = Logger('AudioController');
SoLoud? _soloud; // ← ... and this.
Future<void> initialize() async {
// TODO
}
...
ऑडियो कंट्रोलर, इस फ़ील्ड की मदद से SoLoud इंजन को मैनेज करता है और सभी कॉल को उस पर फ़ॉरवर्ड करता है.
initialize()
तरीके में, यह कोड डालें:
lib/audio/audio_controller.dart
...
Future<void> initialize() async {
_soloud = SoLoud.instance;
await _soloud!.init();
}
...
इससे _soloud
फ़ील्ड अपने-आप भर जाता है और इंटिलाइज़ेशन की प्रक्रिया शुरू हो जाती है. निम्न पर ध्यान दें:
- SoLoud, सिंगलटन
instance
फ़ील्ड उपलब्ध कराता है. एक से ज़्यादा SoLoud इंस्टेंस बनाने का कोई तरीका नहीं है. C++ इंजन ऐसा करने की अनुमति नहीं देता. इसलिए, Dart प्लग इन भी ऐसा करने की अनुमति नहीं देता. - प्लग इन को शुरू करने की प्रोसेस एसिंक्रोनस होती है. यह तब तक पूरी नहीं होती, जब तक
init()
तरीका वापस नहीं आता. - इस उदाहरण में कम शब्दों में बताने के लिए,
try/catch
ब्लॉक में गड़बड़ियों को नहीं पकड़ा जा रहा है. प्रोडक्शन कोड में, आपको ऐसा करना होगा और उपयोगकर्ता को किसी भी गड़बड़ी की शिकायत करनी होगी.
dispose()
तरीके में, यह कोड डालें:
lib/audio/audio_controller.dart
...
void dispose() {
_soloud?.deinit();
}
...
ऐप्लिकेशन से बाहर निकलने पर SoLoud को बंद करना एक अच्छा तरीका है. हालांकि, ऐसा न करने पर भी सब कुछ ठीक से काम करना चाहिए.
- ध्यान दें कि
AudioController.initialize()
फ़ंक्शन कोmain()
फ़ंक्शन से पहले ही कॉल किया जा चुका है. इसका मतलब है कि प्रोजेक्ट को हॉट-रीस्टार्ट करने पर, SoLoud बैकग्राउंड में शुरू हो जाता है. हालांकि, कुछ साउंड चलाने से पहले, इससे कोई फ़ायदा नहीं मिलेगा.
4. एक बार में चलने वाली आवाज़ें चलाना
कोई ऐसेट लोड करना और उसे चलाना
अब आपको पता है कि SoLoud, डिवाइस के चालू होने पर शुरू हो जाता है. इसलिए, आपके पास इसे आवाज़ें चलाने के लिए कहने का विकल्प है.
SoLoud, ऑडियो सोर्स और उसके "साउंड इंस्टेंस" के बीच अंतर करता है. ऑडियो सोर्स, डेटा और मेटाडेटा होता है, जिसका इस्तेमाल किसी साउंड के बारे में बताने के लिए किया जाता है. वहीं, साउंड इंस्टेंस, असल में चलने वाली साउंड होती हैं. ऑडियो सोर्स का उदाहरण, मेमोरी में लोड की गई mp3 फ़ाइल हो सकती है, जो चलाने के लिए तैयार है और AudioSource
क्लास के इंस्टेंस से दिखाई जाती है. जब भी इस ऑडियो सोर्स को चलाया जाता है, तो SoLoud एक "साउंड इंस्टेंस" बनाता है. इसे SoundHandle
टाइप से दिखाया जाता है.
इसे लोड करके, आपको AudioSource
इंस्टेंस मिलता है. उदाहरण के लिए, अगर आपकी एसेट में कोई mp3 फ़ाइल है, तो AudioSource
पाने के लिए उसे लोड किया जा सकता है. इसके बाद, SoLoud को यह AudioSource
चलाने के लिए कहें. इसे कई बार और एक साथ भी खेला जा सकता है.
किसी ऑडियो सोर्स का इस्तेमाल करने के बाद, उसे SoLoud.disposeSource()
तरीके से हटाया जा सकता है.
किसी ऐसेट को लोड करने और उसे चलाने के लिए, यह तरीका अपनाएं:
AudioController
क्लास केplaySound()
तरीके में, यह कोड डालें:
lib/audio/audio_controller.dart
...
Future<void> playSound(String assetKey) async {
final source = await _soloud!.loadAsset(assetKey);
await _soloud!.play(source);
}
...
- फ़ाइल को सेव करें, हॉट रीलोड करें, और फिर साउंड चलाएं को चुनें. आपको एक अजीब सी आवाज़ सुनाई देगी. निम्न पर ध्यान दें:
- दिया गया
assetKey
आर्ग्युमेंट,assets/sounds/pew1.mp3
जैसा ही होता है — यह वही स्ट्रिंग होती है जिसे एसेट लोड करने वाले किसी भी अन्य Flutter API को दिया जाता है, जैसे किImage.asset()
विजेट. - SoLoud इंस्टेंस,
loadAsset()
तरीका उपलब्ध कराता है. यह Flutter प्रोजेक्ट की ऐसेट से, किसी ऑडियो फ़ाइल को असिंक्रोनस तरीके से लोड करता है औरAudioSource
क्लास का इंस्टेंस दिखाता है. फ़ाइल सिस्टम (loadFile()
तरीका) से फ़ाइल लोड करने और यूआरएल (loadUrl()
तरीका) से नेटवर्क पर फ़ाइल लोड करने के तरीके एक जैसे हैं. - इसके बाद, हाल ही में हासिल किए गए
AudioSource
इंस्टेंस को SoLoud केplay()
तरीके में पास किया जाता है. यह तरीका,SoundHandle
टाइप का एक इंस्टेंस दिखाता है, जो हाल ही में चल रही आवाज़ को दिखाता है. इस हैंडल को SoLoud के अन्य तरीकों में पास किया जा सकता है, ताकि आवाज़ को रोका जा सके, बंद किया जा सके या उसकी आवाज़ कम या ज़्यादा की जा सके. play()
एक एसिंक्रोनस तरीका है, लेकिन वीडियो चलाना तुरंत शुरू हो जाता है.flutter_soloud
पैकेज, सी कोड को सीधे और सिंक्रोनस तरीके से कॉल करने के लिए, Dart के फ़ॉरेन फ़ंक्शन इंटरफ़ेस (एफ़एफ़आई) का इस्तेमाल करता है. Dart कोड और प्लैटफ़ॉर्म कोड के बीच, एक-दूसरे को भेजे जाने वाले मैसेज, ज़्यादातर Flutter प्लगिन की खास बात होती है. हालांकि, इस प्लगिन में ऐसा नहीं होता. कुछ तरीके असाइनोक्रोनस होने की एक ही वजह है. प्लग इन का कुछ कोड, अपने अलग आइसोलेट में चलता है और Dart आइसोलेट के बीच का कम्यूनिकेशन असाइनोक्रोनस होता है.- आपने दावा किया है कि
_soloud
फ़ील्ड में_soloud!
के साथ कोई वैल्यू मौजूद है. यह भी कम शब्दों में लिखने के लिए है. प्रोडक्शन कोड को इस स्थिति में आसानी से काम करना चाहिए, जब डेवलपर ऑडियो कंट्रोलर के पूरी तरह से शुरू होने से पहले ही कोई साउंड चलाने की कोशिश करता है.
अपवादों से निपटना
आपको पता चल गया होगा कि आपने फिर से संभावित अपवादों को अनदेखा किया है. अब यह समय आ गया है कि हम इस तरीके को सीखने के लिए ठीक करें. (कम शब्दों में बताने के लिए, कोडलैब इस सेक्शन के बाद, अपवादों को अनदेखा करने पर वापस आ जाता है.)
- इस मामले में अपवादों को हैंडल करने के लिए,
playSound()
तरीके की दो लाइनों कोtry/catch
ब्लॉक में रैप करें और सिर्फ़SoLoudException
के इंस्टेंस को कैच करें.
lib/audio/audio_controller.dart
...
Future<void> playSound(String assetKey) async {
try {
final source = await _soloud!.loadAsset(assetKey);
await _soloud!.play(source);
} on SoLoudException catch (e) {
_log.severe("Cannot play sound '$assetKey'. Ignoring.", e);
}
}
...
SoLoud कई तरह के अपवाद दिखाता है, जैसे कि SoLoudNotInitializedException
या SoLoudTemporaryFolderFailedException
अपवाद. हर तरीके के एपीआई दस्तावेज़ों में, उन अपवादों की सूची होती है जो ट्रिगर हो सकते हैं.
SoLoud अपने सभी अपवादों के लिए एक पैरंट क्लास भी उपलब्ध कराता है, जिसे SoLoudException
अपवाद कहा जाता है. इससे, ऑडियो इंजन की मुख्य सुविधाओं से जुड़ी सभी गड़बड़ियों का पता लगाया जा सकता है. यह सुविधा खास तौर पर उन मामलों में मददगार होती है जहां ऑडियो चलाना ज़रूरी नहीं होता. उदाहरण के लिए, जब आपको सिर्फ़ इसलिए प्लेयर के गेम सेशन को क्रैश नहीं करना है, क्योंकि कोई एक प्यू-प्यू साउंड लोड नहीं हो सका.
जैसा कि आपको उम्मीद होगी, अगर कोई ऐसी ऐसेट कुंजी दी जाती है जो मौजूद नहीं है, तो loadAsset()
तरीका भी FlutterError
गड़बड़ी दिखा सकता है. आम तौर पर, आपको उन ऐसेट को लोड करने से बचना चाहिए जो गेम के साथ बंडल नहीं हैं. इसलिए, यह एक गड़बड़ी है.
अलग-अलग आवाज़ें चलाना
आपको शायद यह पता चला हो कि आपने सिर्फ़ pew1.mp3
फ़ाइल को चलाया है, लेकिन ऐसेट डायरेक्ट्री में साउंड के दो अन्य वर्शन मौजूद हैं. आम तौर पर, गेम में एक ही साउंड के कई वर्शन होने पर और अलग-अलग वर्शन को रैंडम तरीके से या बारी-बारी से चलाने पर, साउंड ज़्यादा असली लगता है. उदाहरण के लिए, इससे यह पक्का होता है कि पैरों के आवाज़ और गोली चलने की आवाज़ एक जैसी न हो और नकली न लगे.
- ज़रूरी नहीं, लेकिन बटन पर हर बार टैप करने पर, अलग-अलग सीट की आवाज़ चलाने के लिए कोड में बदलाव करें.
5. संगीत का लूप चलाना
लंबे समय तक चलने वाली आवाज़ें मैनेज करना
कुछ ऑडियो को लंबे समय तक चलाने के लिए बनाया जाता है. संगीत इसका सबसे आसान उदाहरण है. हालांकि, कई गेम में बैकग्राउंड साउंड भी चलाया जाता है. जैसे, गलियारों में हवा का गुज़रना, दूर से आने वाले भिक्षुओं के मंत्रोच्चार की आवाज़, सदियों पुरानी धातु की खड़खड़ाहट या मरीजों की खांसी की आवाज़.
ये ऐसे ऑडियो सोर्स होते हैं जिनका प्लेटाइम मिनट में मेज़र किया जा सकता है. आपको उनका ट्रैक रखना होगा, ताकि ज़रूरत पड़ने पर उन्हें रोका या बंद किया जा सके. इनका बैकअप अक्सर बड़ी फ़ाइलों से लिया जाता है और ये ज़्यादा मेमोरी का इस्तेमाल कर सकते हैं. इसलिए, इन्हें ट्रैक करने की एक और वजह यह है कि जब AudioSource
इंस्टेंस की ज़रूरत न हो, तब उसे हटाया जा सके.
इसलिए, आपको AudioController
में एक नया निजी फ़ील्ड जोड़ना होगा. अगर कोई गाना चल रहा है, तो यह उसका हैंडल होता है. यह लाइन जोड़ें:
lib/audio/audio_controller.dart
...
class AudioController {
static final Logger _log = Logger('AudioController');
SoLoud? _soloud;
SoundHandle? _musicHandle; // ← Add this.
...
संगीत चलाना
असल में, संगीत चलाना और एक बार में चलने वाली आवाज़ चलाना, दोनों एक ही हैं. इसके लिए, आपको पहले assets/music/looped-song.ogg
फ़ाइल को AudioSource
क्लास के इंस्टेंस के तौर पर लोड करना होगा. इसके बाद, उसे चलाने के लिए SoLoud के play()
तरीके का इस्तेमाल करना होगा.
हालांकि, इस बार आपको उस साउंड हैंडल को पकड़ना है जो play()
मेथड, ऑडियो चलने के दौरान उसमें बदलाव करने के लिए दिखाता है.
- अगर आप चाहें, तो
AudioController.startMusic()
तरीका खुद लागू करें. अगर आपको कुछ जानकारी नहीं मिलती है, तो भी कोई बात नहीं. अहम बात यह है कि संगीत चलाएं चुनने पर, संगीत शुरू हो जाता है.
यहां रेफ़रंस के तौर पर लागू करने का तरीका बताया गया है:
lib/audio/audio_controller.dart
...
Future<void> startMusic() async {
if (_musicHandle != null) {
if (_soloud!.getIsValidVoiceHandle(_musicHandle!)) {
_log.info('Music is already playing. Stopping first.');
await _soloud!.stop(_musicHandle!);
}
}
final musicSource = await _soloud!.loadAsset(
'assets/music/looped-song.ogg',
mode: LoadMode.disk,
);
}
...
ध्यान दें कि आपने संगीत फ़ाइल को डिस्क मोड (LoadMode.disk
enum) में लोड किया है. इसका मतलब है कि फ़ाइल को सिर्फ़ ज़रूरत के हिसाब से, अलग-अलग हिस्सों में लोड किया जाता है. लंबे समय तक चलने वाले ऑडियो के लिए, आम तौर पर डिस्क मोड में लोड करना बेहतर होता है. छोटे साउंड इफ़ेक्ट के लिए, उन्हें मेमोरी में लोड और डिकंप्रेस करना ज़्यादा सही होता है. यह डिफ़ॉल्ट LoadMode.memory
एनम है.
हालांकि, आपको कुछ समस्याएं आ सकती हैं. पहला, वीडियो में संगीत की आवाज़ बहुत ज़्यादा है, जिसकी वजह से आवाज़ें साफ़ नहीं सुनाई दे रही हैं. ज़्यादातर गेम में, संगीत ज़्यादातर समय बैकग्राउंड में चलता है. इससे, गेम में बोली जाने वाली बातों और साउंड इफ़ेक्ट जैसे ज़्यादा जानकारी देने वाले ऑडियो को मुख्यता मिलती है. इसका मकसद, चलाने के तरीके के वॉल्यूम पैरामीटर का इस्तेमाल करके, इसे ठीक करना है. उदाहरण के लिए, _soloud!.play(musicSource, volume: 0.6)
का इस्तेमाल करके, गाने को 60% वॉल्यूम पर चलाया जा सकता है. इसके अलावा, _soloud!.setVolume(_musicHandle, 0.6)
जैसे किसी निर्देश का इस्तेमाल करके, बाद में भी आवाज़ को सेट किया जा सकता है.
दूसरी समस्या यह है कि गाना अचानक बंद हो जाता है. ऐसा इसलिए होता है, क्योंकि यह एक ऐसा गाना होता है जिसे लूप में चलाया जाना होता है और लूप का शुरुआती पॉइंट, ऑडियो फ़ाइल की शुरुआत से अलग होता है.
गेम के संगीत के लिए यह एक लोकप्रिय विकल्प है, क्योंकि इसका मतलब है कि गाना एक नैचुरल इंट्रो के साथ शुरू होता है और फिर ज़रूरत के मुताबिक तब तक चलता है, जब तक कि लूप पॉइंट न दिखे. जब गेम में चल रहे गाने को ट्रांज़िशन करना होता है, तो गाना धीरे-धीरे कम हो जाता है.
हालांकि, SoLoud में लूप में चलने वाले ऑडियो को चलाने के तरीके मौजूद हैं. play()
तरीका, looping
पैरामीटर के लिए बूलियन वैल्यू लेता है. साथ ही, loopingStartAt
पैरामीटर के तौर पर लूप के शुरुआती पॉइंट की वैल्यू भी लेता है. इससे मिलने वाला कोड कुछ ऐसा दिखता है:
lib/audio/audio_controller.dart
...
_musicHandle = await _soloud!.play(
musicSource,
volume: 0.6,
looping: true,
// ↓ The exact timestamp of the start of the loop.
loopingStartAt: const Duration(seconds: 25, milliseconds: 43),
);
...
अगर loopingStartAt
पैरामीटर सेट नहीं किया जाता है, तो यह डिफ़ॉल्ट रूप से Duration.zero
पर सेट हो जाता है. इसका मतलब है कि ऑडियो फ़ाइल की शुरुआत. अगर आपके पास ऐसा संगीत ट्रैक है जो बिना किसी शुरुआत के, एकदम सही लूप में है, तो यह आपके लिए सही है.
- यह पुष्टि करने के लिए कि ऑडियो सोर्स खत्म होने के बाद उसे सही तरीके से हटा दिया गया है, हर ऑडियो सोर्स की
allInstancesFinished
स्ट्रीम सुनें. लॉग कॉल जोड़ने के बाद,startMusic()
तरीका इस तरह दिखता है:
lib/audio/audio_controller.dart
...
Future<void> startMusic() async {
if (_musicHandle != null) {
if (_soloud!.getIsValidVoiceHandle(_musicHandle!)) {
_log.info('Music is already playing. Stopping first.');
await _soloud!.stop(_musicHandle!);
}
}
_log.info('Loading music');
final musicSource = await _soloud!.loadAsset(
'assets/music/looped-song.ogg',
mode: LoadMode.disk,
);
musicSource.allInstancesFinished.first.then((_) {
_soloud!.disposeSource(musicSource);
_log.info('Music source disposed');
_musicHandle = null;
});
_log.info('Playing music');
_musicHandle = await _soloud!.play(
musicSource,
volume: 0.6,
looping: true,
loopingStartAt: const Duration(seconds: 25, milliseconds: 43),
);
}
...
आवाज़ को धीमा करना
आपकी अगली समस्या यह है कि संगीत कभी खत्म नहीं होता. अब फ़ेड लागू करने का समय आ गया है.
फ़ेड करने का एक तरीका यह है कि आपके पास किसी तरह का ऐसा फ़ंक्शन हो जिसे हर सेकंड में कई बार कॉल किया जाता हो. जैसे, Ticker
या Timer.periodic
. साथ ही, संगीत का वॉल्यूम धीरे-धीरे कम किया जाए. यह तरीका काम करेगा, लेकिन इसमें काफ़ी समय लगेगा.
शुक्र है कि SoLoud में, ऐसा करने के लिए आसान तरीके उपलब्ध हैं. यहां बताया गया है कि पांच सेकंड में संगीत को धीमा कैसे किया जा सकता है. इसके बाद, साउंड इंस्टेंस को बंद किया जा सकता है, ताकि यह सीपीयू के संसाधनों को बेवजह खर्च न करे. fadeOutMusic()
तरीके को इस कोड से बदलें:
lib/audio/audio_controller.dart
...
void fadeOutMusic() {
if (_musicHandle == null) {
_log.info('Nothing to fade out');
return;
}
const length = Duration(seconds: 5);
_soloud!.fadeVolume(_musicHandle!, 0, length);
_soloud!.scheduleStop(_musicHandle!, length);
}
...
6. इफ़ेक्ट लागू करना
आपके पास सही ऑडियो इंजन होने का एक बड़ा फ़ायदा यह है कि आपके पास ऑडियो प्रोसेस करने का विकल्प होता है. जैसे, कुछ आवाज़ों को रिवरब, इक्वलाइज़र या लो-पास फ़िल्टर के ज़रिए रूट करना.
गेम में, इसका इस्तेमाल जगहों की आवाज़ों में अंतर करने के लिए किया जा सकता है. उदाहरण के लिए, जंगल में ताली बजाने पर उसकी आवाज़, कंक्रीट बंकर में बजाने पर सुनाई देने वाली आवाज़ से अलग होती है. जंगल में आवाज़ कम हो जाती है और उसे सोख लिया जाता है. वहीं, बंकर की दीवारें आवाज़ को वापस भेजती हैं, जिससे रिवरब होता है. इसी तरह, दीवार के दूसरी तरफ़ से सुनी गई आवाज़ें अलग तरह से सुनाई देती हैं. ठोस माध्यम से गुज़रने पर, उन आवाज़ों की ज़्यादा फ़्रीक्वेंसी ज़्यादा कम हो जाती हैं. इस वजह से, लो-पास फ़िल्टर इफ़ेक्ट होता है.
SoLoud में कई तरह के ऑडियो इफ़ेक्ट उपलब्ध हैं. इन्हें ऑडियो पर लागू किया जा सकता है.
- अगर आपको यह दिखाना है कि आपका प्लेयर किसी बड़े कमरे में है, जैसे कि कैथेड्रल या गुफा, तो
SoLoud.filters
फ़ील्ड का इस्तेमाल करें:
lib/audio/audio_controller.dart
...
void applyFilter() {
_soloud!.filters.freeverbFilter.activate();
_soloud!.filters.freeverbFilter.wet.value = 0.2;
_soloud!.filters.freeverbFilter.roomSize.value = 0.9;
}
void removeFilter() {
_soloud!.filters.freeverbFilter.deactivate();
}
...
SoLoud.filters
फ़ील्ड की मदद से, सभी तरह के फ़िल्टर और उनके पैरामीटर को ऐक्सेस किया जा सकता है. हर पैरामीटर में, धीरे-धीरे फीके होने और ऑसिलेशन जैसी सुविधाएं भी पहले से मौजूद होती हैं.
ध्यान दें: _soloud!.filters
, ग्लोबल फ़िल्टर दिखाता है. अगर आपको किसी एक सोर्स पर फ़िल्टर लागू करने हैं, तो AudioSource.filters
का इस्तेमाल करें. यह फ़िल्टर भी वैसा ही काम करता है.
पिछले कोड की मदद से, ये काम किए जा सकते हैं:
- दुनिया भर में फ़्रीवर्ब फ़िल्टर की सुविधा चालू करें.
- Wet पैरामीटर को
0.2
पर सेट करें. इसका मतलब है कि नतीजास्वरूप मिलने वाला ऑडियो 80% ओरिजनल और 20% रीवरब इफ़ेक्ट का आउटपुट होगा. अगर इस पैरामीटर को1.0
पर सेट किया जाता है, तो आपको सिर्फ़ रूम की दीवारों से आने वाली आवाज़ें सुनाई देंगी. आपको ओरिजनल ऑडियो नहीं सुनाई देगा. - Room Size पैरामीटर को
0.9
पर सेट करें. अपनी पसंद के मुताबिक इस पैरामीटर में बदलाव किया जा सकता है या इसे डाइनैमिक तौर पर भी बदला जा सकता है.1.0
एक विशाल गुफा है, जबकि0.0
एक बाथरूम है.
- अगर आप चाहें, तो कोड बदलें और इनमें से कोई एक फ़िल्टर या इन फ़िल्टर का कॉम्बिनेशन लागू करें:
biquadFilter
(इसे लो पास फ़िल्टर के तौर पर इस्तेमाल किया जा सकता है)pitchShiftFilter
equalizerFilter
echoFilter
lofiFilter
flangerFilter
bassboostFilter
waveShaperFilter
robotizeFilter
7. बधाई हो
आपने ऐसा ऑडियो कंट्रोलर लागू किया है जो आवाज़ें चलाता है, संगीत को लूप करता है, और इफ़ेक्ट लागू करता है.
ज़्यादा जानें
- ऑडियो कंट्रोलर की सुविधाओं का ज़्यादा से ज़्यादा फ़ायदा लें. जैसे, डिवाइस चालू होने पर साउंड को पहले से लोड करना, गाने को क्रम से चलाना या समय के साथ फ़िल्टर को धीरे-धीरे लागू करना.
flutter_soloud
के पैकेज के दस्तावेज़ पढ़ें.- इस्तेमाल की जा रही C++ लाइब्रेरी का होम पेज पढ़ें.
- Dart FFI के बारे में ज़्यादा पढ़ें. यह C++ लाइब्रेरी के साथ इंटरफ़ेस करने के लिए इस्तेमाल की जाने वाली टेक्नोलॉजी है.
- गेम के ऑडियो प्रोग्रामिंग के बारे में जानने के लिए, गाय सोमबर्ग का टॉक देखें. (एक और लंबा वीडियो भी है.) जब गे ऑस्टिन "मीडियमवेयर" की बात करते हैं, तो उनका मतलब SoLoud और FMOD जैसी लाइब्रेरी से है. बाकी कोड, हर गेम के हिसाब से होता है.
- अपना गेम बनाएं और उसे रिलीज़ करें.