Menambahkan suara dan musik ke game Flutter Anda

1. Sebelum memulai

Game merupakan pengalaman audiovisual. Flutter adalah alat yang hebat untuk membangun visual yang indah dan UI yang solid, sehingga memberi Anda pemahaman yang jauh tentang hal-hal visual. Bahan yang tidak ada 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 Anda dapat langsung memasuki bagian-bagian yang menarik.

Ilustrasi headphone yang digambar tangan.

Tentu saja, Anda dapat menggunakan apa yang Anda pelajari di sini untuk menambahkan audio ke aplikasi Anda, bukan hanya game. Namun, meskipun hampir semua game membutuhkan suara dan musik, sebagian besar aplikasi tidak memerlukan suara 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 satu kali.
  • Cara memutar dan menyesuaikan loop musik tanpa jeda.
  • Cara memudarkan suara.
  • Cara menerapkan efek lingkungan pada 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 koneksi Anda lambat, jangan khawatir. Anda memerlukan file yang sebenarnya nanti, jadi Anda dapat mengizinkannya didownload saat Anda bekerja.
  1. Buat project Flutter dengan nama pilihan Anda.
  1. Buat file lib/audio/audio_controller.dart di 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 pada masa 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),
        useMaterial3: true,
      ),
      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. Dalam direktori assets, buat dua subdirektori, satu bernama music dan satu lagi bernama sounds.
  3. Pindahkan file yang didownload ke project Anda sehingga file lagu tersebut berada di file assets/music/looped-song.ogg dan suara bangku berada di 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`, dan file seperti `README.md` dan `analysis_options.yaml`. Di antaranya, kita dapat melihat direktori `assets` dengan subdirektori `music` dan `sounds`, direktori `lib` dengan `main.dart` dan subdirektori `audio` dengan `audio_controller.dart`, dan file `pubspec.yaml`.  Panah menunjuk ke direktori baru, dan file yang telah Anda sentuh sejauh ini.

Setelah file tersebut muncul, 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.

pubspec.yaml

...

dependencies:
  flutter:
    sdk: flutter

  flutter_soloud: ^2.0.0
  logging: ^1.2.0

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

10f0f751c9c47038.pngS

/flutter_soloud/src/filters/filters.cpp:21:24: warning: implicit conversion loses integer precision: 'decltype(__x.base() - __y.base())' (aka 'long') to 'int' [-Wshorten-64-to-32];

Ini berasal dari library C++ SoLoud yang mendasarinya. Parameter ini tidak berpengaruh pada fungsi dan dapat diabaikan dengan aman.

3. Melakukan inisialisasi dan mematikan

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

7ce23849b6d0d09a.pngS

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

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

lib/audio/audio_controller.dart

import 'dart:ui';

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 dalamnya.

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

lib/audio/audio_controller.dart

...

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

...

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

  • SoLoud menyediakan kolom instance singleton. Tidak ada cara untuk membuat beberapa instance SoLoud. Ini bukan sesuatu yang diizinkan oleh mesin C++, sehingga juga tidak diizinkan oleh plugin Dart.
  • Inisialisasi plugin bersifat asinkron dan tidak selesai hingga metode init() ditampilkan.
  • Agar contoh ini lebih singkat, Anda tidak menangkap error dalam blok try/catch. Di kode produksi, Anda perlu melakukannya dan melaporkan error kepada pengguna.
  1. Di metode dispose(), masukkan kode berikut:

lib/audio/audio_controller.dart

...

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

...

Mematikan 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() telah dipanggil dari fungsi main(). Artinya, hot-restart proyek akan melakukan inisialisasi SoLoud di latar belakang, tetapi tidak akan ada gunanya sebelum Anda benar-benar memutar beberapa suara.

4. Putar suara satu kali

Memuat aset, lalu memutarnya

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

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

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

Setelah selesai dengan sumber audio, Anda membuangnya 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, hot reload, lalu pilih Putar suara. Anda akan mendengar bunyi pepatah konyol. Perhatikan hal berikut:
  • Argumen assetKey yang diberikan adalah seperti assets/sounds/pew1.mp3—string yang sama dengan yang akan Anda berikan ke Flutter API pemuatan aset lainnya, seperti widget Image.asset().
  • Instance SoLoud menyediakan metode loadAsset() yang secara asinkron memuat file audio 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. Tuas 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 biasa 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 sebagian kode plugin berjalan di isolasinya sendiri, dan komunikasi antar-isolasi Dart bersifat asinkron.
  • Anda hanya perlu menegaskan bahwa kolom _soloud bukan null dengan _soloud!. Sekali lagi, ini lebih singkat. Kode produksi harus mampu menangani situasi dengan baik ketika developer mencoba memutar suara sebelum pengontrol audio sempat melakukan inisialisasi sepenuhnya.

Menangani pengecualian

Anda mungkin telah memperhatikan bahwa Anda, sekali lagi, mengabaikan kemungkinan pengecualian. Mari kita perbaiki untuk metode khusus ini demi tujuan pembelajaran. (Agar lebih singkat, codelab akan kembali ke mengabaikan pengecualian setelah bagian ini.)

  • Untuk menangani pengecualian dalam kasus 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. Setiap dokumen API metode mencantumkan jenis pengecualian yang mungkin diterapkan.

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

Seperti yang mungkin Anda harapkan, metode loadAsset() juga dapat menampilkan error FlutterError jika Anda memberikan kunci aset yang tidak ada. Mencoba memuat aset yang tidak dipaketkan dengan game biasanya adalah sesuatu yang harus Anda tangani, oleh karena itu, ini merupakan error.

Putar suara yang berbeda

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

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

Ilustrasi

5. Memutar loop musik

Kelola suara yang berdurasi lebih lama

Beberapa audio dimaksudkan untuk diputar dalam waktu yang lama. Musik adalah contoh yang jelas, tetapi banyak game juga memainkan suasana, seperti angin menerpa koridor, nyanyian biksu dari kejauhan, derit logam berusia berabad-abad, atau suara batuk pasien dari kejauhan.

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

Oleh karena itu, Anda akan memperkenalkan kolom pribadi baru ke AudioController. Ini adalah nama sebutan channel untuk lagu yang sedang 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.

  ...

Mulai musik

Intinya, memutar musik tidak berbeda dengan memutar suara satu kali. Anda tetap harus memuat file assets/music/looped-song.ogg sebagai instance class AudioSource terlebih dahulu, lalu menggunakan metode play() SoLoud untuk memutarnya.

Namun, kali ini, Anda menahan handel suara yang ditampilkan oleh metode play() untuk memanipulasi audio saat diputar.

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

Berikut adalah penerapan 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);
    _musicHandle = await _soloud!.play(musicSource);
  }

...

Perhatikan bahwa Anda memuat file musik dalam mode disk (enum LoadMode.disk). Ini berarti bahwa {i>file<i} itu hanya dimuat dalam potongan sesuai kebutuhan. Untuk audio yang berjalan lebih lama, sebaiknya muat dalam mode disk. Untuk efek suara pendek, sebaiknya muat dan dekompresi ke dalam memori (enum LoadMode.memory default).

Namun, Anda memiliki beberapa masalah. Pertama, musiknya terlalu nyaring, sehingga membuat suara terlalu keras. Dalam sebagian besar game, musik selalu menjadi latar belakang, sehingga audio yang lebih informatif seperti ucapan dan efek suara menjadi pusat perhatian. Masalah ini mudah diperbaiki menggunakan parameter volume metode putar. Misalnya, Anda dapat mencoba _soloud!.play(musicSource, volume: 0.6) untuk memutar lagu dengan volume 60%. Atau, Anda dapat menyetel volume kapan saja dengan perintah seperti _soloud!.setVolume(_musicHandle, 0.6).

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

88d2c57fffdfe996.pngS

Ini adalah pilihan populer untuk musik game karena artinya lagu dimulai dengan pengantar alami, lalu diputar selama diperlukan tanpa titik loop yang jelas. Jika game perlu bertransisi dari lagu yang sedang diputar, tindakan ini akan memudarkan lagu.

Untungnya, SoLoud menyediakan cara untuk memutar audio berulang. Metode play() mengambil 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 menyetel parameter loopingStartAt, parameter akan ditetapkan secara default ke Duration.zero (dengan kata lain, awal file audio). Jika Anda memiliki trek musik yang merupakan loop sempurna tanpa pengenalan apa pun, ini yang Anda inginkan.

  • Untuk memastikan bahwa sumber audio dibuang dengan benar setelah selesai diputar, dengarkan streaming allInstancesFinished yang disediakan oleh setiap sumber audio. Dengan panggilan log tambahan, 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. Mari kita implementasikan fade.

Salah satu cara Anda dapat mengimplementasikan fade adalah dengan membuat semacam fungsi yang dipanggil beberapa kali dalam satu detik, seperti Ticker atau Timer.periodic, dan menurunkan volume musik dengan pengurangan kecil. Cara ini akan berhasil, tetapi membutuhkan banyak upaya.

Untungnya, SoLoud menyediakan metode tembakan dan lupakan yang nyaman untuk Anda. Berikut ini cara Anda memudarkan musik dalam waktu lima detik, lalu menghentikan instance suara agar tidak menghabiskan resource CPU. 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 dengan memiliki mesin audio yang tepat adalah Anda dapat melakukan pemrosesan audio, seperti mengarahkan beberapa suara melalui gaung, equalizer, atau filter low-pass.

Dalam game, perilaku ini dapat digunakan untuk membedakan lokasi dengan suara. Misalnya, suara tepuk tangan di hutan berbeda dengan suara di bungker beton. Sementara hutan membantu menghilangkan dan menyerap suara, dinding bungker yang kosong memantulkan kembali gelombang suara, yang menghasilkan gaung. Demikian pula, suara orang terdengar berbeda saat didengar melalui dinding. Semakin tinggi frekuensi suara tersebut, semakin mudah dilemahkan saat melintas melalui medium padat, sehingga menghasilkan efek filter low-pass.

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

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

  • Untuk membuatnya terdengar seperti pemain berada di ruangan besar, seperti katedral atau gua, gunakan enum FilterType.freeverbFilter:

lib/audio/audio_controller.dart

...

  void applyFilter() {
    _soloud!.addGlobalFilter(FilterType.freeverbFilter);
    _soloud!.setFilterParameter(FilterType.freeverbFilter, 0, 0.2);
    _soloud!.setFilterParameter(FilterType.freeverbFilter, 2, 0.9);
  }

  void removeFilter() {
    _soloud!.removeGlobalFilter(FilterType.freeverbFilter);
  }

...

Seperti yang Anda lihat, dengan filter, Anda mempelajari wilayah yang lebih rendah. Menyetel parameter filter dilakukan dengan indeks parameter. Misalnya, parameter Wet freeverb memiliki indeks 0, dan parameter Ukuran Kamar memiliki indeks 2.

Dengan kode sebelumnya, Anda melakukan hal berikut:

  • Aktifkan filter kata kerja bebas secara global, atau ke seluruh campuran audio, bukan hanya satu suara.
  • Setel parameter Wet ke 0.2, yang berarti audio yang dihasilkan akan 80% asli dan 20% output efek gema. Jika Anda menyetel parameter ini ke 1.0, parameter ini akan seperti hanya mendengar gelombang suara yang kembali kepada Anda dari dinding ruangan di kejauhan tanpa ada audio asli.
  • Setel parameter Ukuran Kamar ke 0.9. Anda dapat menyesuaikan parameter ini sesuai keinginan atau bahkan mengubahnya secara dinamis. 1.0 adalah gua yang sangat besar, sedangkan 0.0 adalah kamar mandi.
  • Jika Anda siap, ubah kode dan terapkan salah satu filter berikut atau kombinasi filter berikut:
  • FilterType.biquadResonantFilter (dapat digunakan sebagai filter low pass)
  • FilterType.eqFilter
  • FilterType.echoFilter
  • FilterType.lofiFilter
  • FilterType.flangerFilter
  • FilterType.bassboostFilter
  • FilterType.waveShaperFilter
  • FilterType.robotizeFilter
  • FilterType.freeverbFilter

7. Selamat

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

Pelajari lebih lanjut

  • Coba gunakan pengontrol audio lebih lanjut dengan fitur seperti pramuat suara 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 perbincangan Guy Somberg tentang pemrograman audio game untuk mendapatkan inspirasi. (Ada juga yang lebih panjang.) Ketika Guy berbicara tentang "middleware", yang dia maksudkan adalah perpustakaan seperti SoLoud dan FMOD. Kode lainnya cenderung spesifik untuk setiap game.
  • Bangun game Anda dan rilis.

Ilustrasi headphone