Menambahkan suara dan musik ke game Flutter Anda

1. Sebelum memulai

Game adalah pengalaman audiovisual. Flutter adalah alat yang bagus untuk membuat visual yang menarik dan UI yang solid, sehingga Anda dapat melakukan banyak hal di sisi visual. Bahan yang tidak ada yang tersisa adalah audio. Dalam codelab ini, Anda akan mempelajari cara menggunakan plugin flutter_soloud untuk memperkenalkan suara dan musik latensi rendah ke project Anda. Anda memulai dengan scaffold dasar agar dapat langsung memasuki bagian-bagian yang menarik.

Ilustrasi headphone yang digambar tangan.

Tentu saja, Anda dapat menggunakan hal-hal yang Anda pelajari di sini untuk menambahkan audio ke aplikasi, bukan hanya game. Meskipun hampir semua game memerlukan suara dan musik, sebagian besar aplikasi tidak memerlukannya, sehingga codelab ini berfokus pada game.

Prasyarat

  • Pemahaman dasar tentang Flutter.
  • Pengetahuan tentang cara menjalankan dan men-debug aplikasi Flutter.

Yang Anda pelajari

  • Cara memutar suara one-shot.
  • Cara memutar dan menyesuaikan loop musik tanpa jeda.
  • Cara memudar suara masuk dan keluar.
  • Cara menerapkan efek lingkungan ke suara.
  • Cara menangani pengecualian.
  • Cara mengenkapsulasi semua fitur ini ke dalam satu pengontrol audio.

Yang Anda perlukan

  • Flutter SDK
  • Editor kode pilihan Anda

2. Siapkan

  1. Download file berikut. Jika Anda memiliki koneksi yang lambat, jangan khawatir. Anda memerlukan file sebenarnya nanti, jadi Anda dapat membiarkannya didownload saat Anda bekerja.
  1. Buat project Flutter dengan nama pilihan Anda.
  1. Buat file lib/audio/audio_controller.dart dalam project.
  2. Dalam file tersebut, masukkan kode berikut:

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
  }
}

Seperti yang dapat Anda lihat, ini hanyalah kerangka untuk fungsi mendatang. Kita akan menerapkan semuanya selama codelab ini.

  1. Selanjutnya, buka file lib/main.dart, lalu ganti kontennya dengan kode berikut:

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();
                    }
                  },
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
  1. Setelah file audio didownload, buat direktori di root project Anda yang bernama assets.
  2. Di direktori assets, buat dua subdirektori, satu bernama music dan yang lainnya bernama sounds.
  3. Pindahkan file yang didownload ke project Anda sehingga file lagu berada dalam file assets/music/looped-song.ogg dan suara bangku gereja berada dalam file berikut:
  • assets/sounds/pew1.mp3
  • assets/sounds/pew2.mp3
  • assets/sounds/pew3.mp3

Struktur project Anda sekarang akan terlihat seperti ini:

Tampilan hierarki project, dengan folder seperti `android`, `ios`, file seperti `README.md` dan `analysis_options.yaml`.   Di antara folder tersebut, kita dapat melihat direktori `assets` dengan subdirektori `music` dan `sounds`, direktori `lib` dengan `main.dart` dan subdirektori `audio` dengan `audio_controller.dart`, serta file `pubspec.yaml`.  Panah mengarah ke direktori baru, dan file yang telah Anda sentuh sejauh ini.

Setelah file tersebut ada, Anda perlu memberi tahu Flutter tentang file tersebut.

  1. Buka file pubspec.yaml, lalu ganti bagian flutter: di bagian bawah file dengan kode berikut:

pubspec.yaml

...

flutter:
  uses-material-design: true

  assets:
    - assets/music/
    - assets/sounds/
  1. Tambahkan dependensi pada paket flutter_soloud dan paket logging.
flutter pub add flutter_soloud logging

File pubspec.yaml Anda sekarang akan memiliki dependensi tambahan pada paket flutter_soloud dan logging.

pubspec.yaml

...

dependencies:
  flutter:
    sdk: flutter

  flutter_soloud: ^3.1.10
  logging: ^1.3.0

...
  1. Menjalankan project. Belum ada yang berfungsi karena Anda menambahkan fungsi di bagian berikut.

10f0f751c9c47038.png

3. Melakukan inisialisasi dan menonaktifkan

Untuk memutar audio, Anda menggunakan plugin flutter_soloud. Plugin ini didasarkan pada project SoLoud, mesin audio C++ untuk game yang digunakan—di antara yang lainnya—oleh Nintendo SNES Classic.

7ce23849b6d0d09a.png

Untuk melakukan inisialisasi mesin audio SoLoud, ikuti langkah-langkah berikut:

  1. Di file audio_controller.dart, impor paket flutter_soloud dan tambahkan kolom _soloud pribadi ke class.

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
  }

  ...

Pengontrol audio mengelola mesin SoLoud yang mendasarinya melalui kolom ini dan akan meneruskan semua panggilan ke mesin tersebut.

  1. Dalam metode initialize(), masukkan kode berikut:

lib/audio/audio_controller.dart

...

  Future<void> initialize() async {
    _soloud = SoLoud.instance;
    await _soloud!.init();
  }

...

Tindakan ini akan mengisi kolom _soloud dan menunggu inisialisasi. Perhatikan hal berikut:

  • SoLoud menyediakan kolom instance singleton. Tidak ada cara untuk membuat instance beberapa instance SoLoud. Hal ini tidak diizinkan oleh mesin C++, sehingga tidak diizinkan oleh plugin Dart.
  • Inisialisasi plugin bersifat asinkron dan tidak selesai hingga metode init() ditampilkan.
  • Untuk mempersingkat contoh ini, Anda tidak menangkap error dalam blok try/catch. Dalam kode produksi, Anda ingin melakukannya dan melaporkan error apa pun kepada pengguna.
  1. Dalam metode dispose(), masukkan kode berikut:

lib/audio/audio_controller.dart

...

  void dispose() {
    _soloud?.deinit();
  }

...

Menutup SoLoud saat keluar dari aplikasi adalah praktik yang baik, meskipun semuanya akan berfungsi dengan baik meskipun Anda lalai melakukannya.

  1. Perhatikan bahwa metode AudioController.initialize() sudah dipanggil dari fungsi main(). Artinya, memulai ulang project secara langsung akan melakukan inisialisasi SoLoud di latar belakang, tetapi tidak akan berguna sebelum Anda benar-benar memutar beberapa suara.

4. Memutar suara satu kali

Memuat aset dan memutarnya

Setelah mengetahui bahwa SoLoud diinisialisasi saat startup, Anda dapat memintanya untuk memutar suara.

SoLoud membedakan antara sumber audio, yang merupakan data dan metadata yang digunakan untuk mendeskripsikan suara, dan "instance suara"-nya, yang merupakan suara yang sebenarnya diputar. Contoh sumber audio dapat berupa file mp3 yang dimuat ke dalam memori, siap diputar, dan direpresentasikan oleh instance class AudioSource. Setiap kali Anda memutar sumber audio ini, SoLoud akan membuat "instance suara" yang direpresentasikan oleh jenis SoundHandle.

Anda mendapatkan instance AudioSource dengan memuat instance tersebut. Misalnya, jika memiliki file mp3 di aset, Anda dapat memuat file tersebut untuk mendapatkan AudioSource. Kemudian, Anda memberi tahu SoLoud untuk memutar AudioSource ini. Anda dapat memainkannya berkali-kali, bahkan secara bersamaan.

Setelah selesai menggunakan sumber audio, Anda akan menghapusnya dengan metode SoLoud.disposeSource().

Untuk memuat aset dan memutarnya, ikuti langkah-langkah berikut:

  1. Di metode playSound() class AudioController, masukkan kode berikut:

lib/audio/audio_controller.dart

  ...

  Future<void> playSound(String assetKey) async {
    final source = await _soloud!.loadAsset(assetKey);
    await _soloud!.play(source);
  }

  ...
  1. Simpan file, lakukan hot reload, lalu pilih Putar suara. Anda akan mendengar suara pew yang lucu. Perhatikan hal berikut:
  • Argumen assetKey yang diberikan adalah sesuatu seperti assets/sounds/pew1.mp3 — string yang sama dengan yang Anda berikan ke API Flutter pemuatan aset lainnya, seperti widget Image.asset().
  • Instance SoLoud menyediakan metode loadAsset() yang memuat file audio secara asinkron dari aset project Flutter dan menampilkan instance class AudioSource. Ada metode yang setara untuk memuat file dari sistem file (metode loadFile()), dan untuk memuat melalui jaringan dari URL (metode loadUrl()).
  • Instance AudioSource yang baru diperoleh kemudian diteruskan ke metode play() SoLoud. Metode ini menampilkan instance jenis SoundHandle yang mewakili suara yang baru diputar. Selanjutnya, handle ini dapat diteruskan ke metode SoLoud lainnya untuk melakukan hal-hal seperti menjeda, menghentikan, atau mengubah volume suara.
  • Meskipun play() adalah metode asinkron, pemutaran pada dasarnya dimulai secara instan. Paket flutter_soloud menggunakan antarmuka fungsi asing (FFI) Dart untuk memanggil kode C secara langsung dan sinkron. Pesan yang biasa terjadi antara kode Dart dan kode platform yang merupakan karakteristik sebagian besar plugin Flutter tidak dapat ditemukan. Satu-satunya alasan beberapa metode bersifat asinkron adalah karena beberapa kode plugin berjalan di isolasinya sendiri dan komunikasi antar-isolasi Dart bersifat asinkron.
  • Anda menyatakan bahwa kolom _soloud bukan null dengan _soloud!. Sekali lagi, hal ini untuk mempersingkat. Kode produksi harus menangani situasi dengan baik saat developer mencoba memutar suara sebelum pengontrol audio memiliki kesempatan untuk melakukan inisialisasi sepenuhnya.

Menangani pengecualian

Anda mungkin telah memperhatikan bahwa Anda, sekali lagi, mengabaikan kemungkinan pengecualian. Saatnya memperbaikinya untuk metode khusus ini untuk tujuan pembelajaran. (Agar singkat, codelab akan kembali mengabaikan pengecualian setelah bagian ini.)

  • Untuk menangani pengecualian dalam hal ini, gabungkan dua baris metode playSound() dalam blok try/catch dan hanya tangkap instance 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 menampilkan berbagai pengecualian, seperti pengecualian SoLoudNotInitializedException atau SoLoudTemporaryFolderFailedException. Dokumen API setiap metode mencantumkan jenis pengecualian yang mungkin ditampilkan.

SoLoud juga menyediakan class induk untuk semua pengecualian, pengecualian SoLoudException, sehingga Anda dapat menangkap semua error yang terkait dengan fungsi mesin audio. Hal ini sangat membantu jika memutar audio tidak penting. Misalnya, saat Anda tidak ingin membuat sesi game pemain error hanya karena salah satu suara pew-pew tidak dapat dimuat.

Seperti yang mungkin Anda duga, metode loadAsset() juga dapat menampilkan error FlutterError jika Anda memberikan kunci aset yang tidak ada. Mencoba memuat aset yang tidak dipaketkan dengan game biasanya merupakan hal yang harus Anda atasi, sehingga ini merupakan error.

Memutar suara yang berbeda

Anda mungkin telah memperhatikan bahwa Anda hanya memutar file pew1.mp3, tetapi ada dua versi suara lainnya di direktori aset. Suara sering kali terdengar lebih alami jika game memiliki beberapa versi suara yang sama, dan memutar versi yang berbeda secara acak atau secara bergantian. Hal ini mencegah, misalnya, suara langkah kaki dan tembakan terdengar terlalu seragam sehingga palsu.

  • Sebagai latihan opsional, ubah kode untuk memutar suara bangku gereja yang berbeda setiap kali tombol diketuk.

Ilustrasi

5. Memutar loop musik

Mengelola suara yang berjalan lebih lama

Beberapa audio dimaksudkan untuk diputar dalam jangka waktu yang lama. Musik adalah contoh yang jelas, tetapi banyak game juga memutar ambience, seperti angin yang menderu di koridor, suara mantra para biksu di kejauhan, derit logam berusia berabad-abad, atau batuk pasien di kejauhan.

Ini adalah sumber audio dengan waktu pemutaran yang dapat diukur dalam hitungan menit. Anda harus melacaknya agar dapat menjeda atau menghentikannya saat diperlukan. Instance ini juga sering didukung oleh file besar dan dapat menghabiskan banyak memori, sehingga alasan lain untuk melacaknya adalah agar Anda dapat membuang instance AudioSource jika tidak lagi diperlukan.

Oleh karena itu, Anda akan memperkenalkan kolom pribadi baru ke AudioController. Ini adalah nama sebutan untuk lagu yang diputar, jika ada. Tambahkan baris berikut:

lib/audio/audio_controller.dart

...

class AudioController {
  static final Logger _log = Logger('AudioController');

  SoLoud? _soloud;

  SoundHandle? _musicHandle;    // ← Add this.

  ...

Memulai musik

Pada dasarnya, memutar musik tidak berbeda dengan memutar suara one-shot. Anda masih perlu memuat file assets/music/looped-song.ogg terlebih dahulu sebagai instance class AudioSource, lalu menggunakan metode play() SoLoud untuk memutarnya.

Namun, kali ini, Anda akan mengambil handle suara yang ditampilkan metode play() untuk memanipulasi audio saat diputar.

  • Jika mau, terapkan metode AudioController.startMusic() sendiri. Tidak apa-apa jika Anda tidak memahami beberapa detail dengan benar. Yang penting, musik akan dimulai saat Anda memilih Mulai musik.

Berikut adalah implementasi referensi:

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,
    );
  }

...

Perhatikan bahwa Anda memuat file musik dalam mode disk (enum LoadMode.disk). Artinya, file hanya dimuat dalam potongan sesuai kebutuhan. Untuk audio yang berjalan lebih lama, sebaiknya muat dalam mode disk. Untuk efek suara singkat, sebaiknya muat dan dekompresi efek suara tersebut ke dalam memori (enum LoadMode.memory default).

Namun, Anda memiliki beberapa masalah. Pertama, musiknya terlalu keras, sehingga mengalahkan suara. Di sebagian besar game, musik biasanya diputar di latar belakang, sehingga audio yang lebih informatif, seperti ucapan dan efek suara, menjadi fokus utama. Hal ini untuk memperbaiki penggunaan parameter volume metode play. Misalnya, Anda dapat mencoba _soloud!.play(musicSource, volume: 0.6) untuk memutar lagu dengan volume 60%. Atau, Anda dapat menetapkan volume kapan saja dengan sesuatu seperti _soloud!.setVolume(_musicHandle, 0.6).

Masalah kedua adalah lagu berhenti tiba-tiba. Hal ini karena lagu tersebut seharusnya diputar dalam loop dan titik awal loop bukan awal file audio.

88d2c57fffdfe996.png

Ini adalah pilihan populer untuk musik game karena berarti lagu dimulai dengan intro yang alami, lalu diputar selama diperlukan tanpa titik loop yang jelas. Saat game perlu bertransisi dari lagu yang sedang diputar, game akan memudarkan lagu.

Untungnya, SoLoud menyediakan cara untuk memutar audio berulang. Metode play() menggunakan nilai boolean untuk parameter looping, dan juga nilai untuk titik awal loop sebagai parameter loopingStartAt. Kode yang dihasilkan akan terlihat seperti ini:

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),
);

...

Jika Anda tidak menetapkan parameter loopingStartAt, parameter tersebut akan ditetapkan secara default ke Duration.zero (dengan kata lain, awal file audio). Jika Anda memiliki trek musik yang merupakan loop sempurna tanpa pengantar, ini adalah yang Anda inginkan.

  • Untuk memverifikasi bahwa sumber audio dihapus dengan benar setelah selesai diputar, dengarkan streaming allInstancesFinished yang disediakan setiap sumber audio. Dengan panggilan log yang ditambahkan, metode startMusic() akan terlihat seperti ini:

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),
    );
  }

...

Suara memudar

Masalah Anda berikutnya adalah musik tidak pernah berakhir. Saatnya menerapkan efek memudar.

Salah satu cara untuk menerapkan fade adalah dengan memiliki semacam fungsi yang dipanggil beberapa kali per detik, seperti Ticker atau Timer.periodic, dan menurunkan volume musik dengan pengurangan kecil. Cara ini akan berhasil, tetapi membutuhkan banyak pekerjaan.

Untungnya, SoLoud menyediakan metode fire-and-forget yang praktis dan melakukannya untuk Anda. Berikut cara memudarkan musik selama lima detik, lalu menghentikan instance suara agar tidak menggunakan resource CPU secara tidak perlu. Ganti metode fadeOutMusic() dengan kode ini:

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. Menerapkan efek

Salah satu keuntungan besar dari memiliki mesin audio yang tepat adalah Anda dapat melakukan pemrosesan audio, seperti merutekan beberapa suara melalui reverb, equalizer, atau filter low-pass.

Dalam game, hal ini dapat digunakan untuk diferensiasi auditori lokasi. Misalnya, suara tepukan terdengar berbeda di hutan daripada di bunker beton. Meskipun hutan membantu menyerap dan menghilangkan suara, dinding bunker yang kosong memantulkan gelombang suara kembali, sehingga menghasilkan reverb. Demikian pula, suara orang terdengar berbeda saat didengar melalui dinding. Frekuensi yang lebih tinggi dari suara tersebut akan lebih dilemahkan saat merambat melalui media padat, sehingga menghasilkan efek filter low-pass.

Ilustrasi dua orang yang sedang berbicara di sebuah ruangan. Gelombang suara tidak hanya bergerak dari satu orang ke orang lain secara langsung, tetapi juga memantul dari dinding dan langit-langit.

SoLoud menyediakan beberapa efek audio yang berbeda, yang dapat Anda terapkan ke audio.

  • Agar terdengar seperti pemain berada di ruangan besar, seperti katedral atau gua, gunakan kolom 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();
  }

...

Kolom SoLoud.filters memberi Anda akses ke semua jenis filter dan parameternya. Setiap parameter juga memiliki fungsi bawaan seperti memudar dan berosilasi secara bertahap.

Catatan: _soloud!.filters mengekspos filter global. Jika Anda ingin menerapkan filter ke satu sumber, gunakan AudioSource.filters pasangan yang berfungsi sama.

Dengan kode sebelumnya, Anda melakukan hal berikut:

  • Aktifkan filter freeverb secara global.
  • Tetapkan parameter Wet ke 0.2, yang berarti audio yang dihasilkan akan menjadi 80% asli dan 20% output efek reverb. Jika Anda menetapkan parameter ini ke 1.0, Anda hanya akan mendengar gelombang suara yang kembali kepada Anda dari dinding ruangan yang jauh dan tidak ada audio asli.
  • Tetapkan parameter Room Size ke 0.9. Anda dapat menyesuaikan parameter ini sesuai keinginan atau bahkan mengubahnya secara dinamis. 1.0 adalah gua besar, sedangkan 0.0 adalah kamar mandi.
  • Jika Anda siap, ubah kode dan terapkan salah satu filter berikut atau kombinasi filter berikut:
  • biquadFilter (dapat digunakan sebagai filter low pass)
  • pitchShiftFilter
  • equalizerFilter
  • echoFilter
  • lofiFilter
  • flangerFilter
  • bassboostFilter
  • waveShaperFilter
  • robotizeFilter

7. Selamat

Anda telah menerapkan pengontrol audio yang memutar suara, memutar musik secara berulang, dan menerapkan efek.

Pelajari lebih lanjut

  • Coba tingkatkan kontrol audio dengan fitur seperti memuat suara secara otomatis saat memulai, memutar lagu secara berurutan, atau menerapkan filter secara bertahap dari waktu ke waktu.
  • Baca dokumentasi paket flutter_soloud.
  • Baca halaman beranda library C++ yang mendasarinya.
  • Baca selengkapnya tentang Dart FFI, teknologi yang digunakan untuk berinteraksi dengan library C++.
  • Tonton presentasi Guy Somberg tentang pemrograman audio game untuk mendapatkan inspirasi. (Ada juga video yang lebih panjang.) Saat Guy berbicara tentang "middleware", ia mengacu pada library seperti SoLoud dan FMOD. Kode lainnya cenderung spesifik untuk setiap game.
  • Build game dan rilis.

Ilustrasi headphone