Ajoutez du son et de la musique à votre jeu Flutter

1. Avant de commencer

Les jeux sont des expériences audiovisuelles. Flutter est un excellent outil pour créer des visuels esthétiques et une UI robuste. Il vous permet d'aller encore plus loin dans l'aspect visuel. L'ingrédient manquant est l'audio. Dans cet atelier de programmation, vous allez apprendre à utiliser le plug-in flutter_soloud pour intégrer des sons et de la musique à faible latence à votre projet. Vous commencez par créer une structure de base vous permettant de passer directement aux parties intéressantes.

Illustration d'écouteurs dessinée à la main.

Vous pouvez bien sûr utiliser les connaissances acquises ici pour ajouter du contenu audio à vos applications, et pas seulement à vos jeux. Toutefois, presque tous les jeux nécessitent du son et de la musique, mais ce n'est pas le cas de la plupart des applications. Cet atelier de programmation est donc consacré aux jeux.

Prérequis

  • Connaissances de base sur Flutter
  • Savoir exécuter et déboguer des applications Flutter

Objectifs

  • Lire des sons one-shot
  • Découvrez comment diffuser et personnaliser des boucles musicales sans interruption.
  • Comment ajouter et supprimer des sons en fondu ?
  • Comment appliquer des effets environnementaux à des sons
  • Gérer les exceptions
  • Encapsuler toutes ces fonctionnalités dans un seul contrôleur audio

Ce dont vous avez besoin

  • SDK Flutter
  • L'éditeur de code de votre choix

2. Configurer

  1. Téléchargez les fichiers suivants. Si votre connexion est lente, ne vous inquiétez pas. Vous aurez besoin des fichiers ultérieurement pour pouvoir les télécharger pendant que vous travaillez.
  1. Créez un projet Flutter avec le nom de votre choix.
  1. Créez un fichier lib/audio/audio_controller.dart dans le projet.
  2. Dans le fichier, saisissez le code suivant :

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

Comme vous pouvez le voir, il ne s'agit que d'un squelette de fonctionnalités futures. Nous allons tout mettre en œuvre au cours de cet atelier de programmation.

  1. Ensuite, ouvrez le fichier lib/main.dart et remplacez son contenu par le code suivant:

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. Une fois les fichiers audio téléchargés, créez un répertoire nommé assets à la racine de votre projet.
  2. Dans le répertoire assets, créez deux sous-répertoires, l'un nommé music et l'autre sounds.
  3. Déplacez les fichiers téléchargés vers votre projet afin que le fichier du titre musical se trouve dans le fichier assets/music/looped-song.ogg et les sons du pew dans les fichiers suivants:
  • assets/sounds/pew1.mp3
  • assets/sounds/pew2.mp3
  • assets/sounds/pew3.mp3

La structure de votre projet devrait maintenant ressembler à ceci:

Arborescence du projet, avec des dossiers tels que &quot;android&quot;, &quot;ios&quot;, des fichiers tels que &quot;README.md&quot; et &quot;analysis_options.yaml&quot;. Par exemple, nous pouvons voir le répertoire &quot;assets&quot; avec les sous-répertoires &quot;music&quot; et &quot;Sounds&quot;, le répertoire &quot;lib&quot; avec &quot;main.dart&quot; et un sous-répertoire &quot;audio&quot; avec &quot;audio_controller.dart&quot; et le fichier &quot;pubspec.yaml&quot;.  Les flèches pointent vers les nouveaux répertoires, ainsi que vers les fichiers que vous avez modifiés jusqu&#39;à présent.

Maintenant que les fichiers sont là, vous devez en informer Flutter.

  1. Ouvrez le fichier pubspec.yaml, puis remplacez la section flutter: en bas du fichier par ce qui suit:

pubspec.yaml

...

flutter:
  uses-material-design: true

  assets:
    - assets/music/
    - assets/sounds/
  1. Ajoutez une dépendance entre les packages flutter_soloud et logging.

pubspec.yaml

...

dependencies:
  flutter:
    sdk: flutter

  flutter_soloud: ^2.0.0
  logging: ^1.2.0

...
  1. Exécuter le projet Pour le moment, rien ne fonctionne, car vous avez ajouté la fonctionnalité dans les sections suivantes.

10f0f751c9c47038.png

/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];

Ceux-ci proviennent de la bibliothèque C++ SoLoud sous-jacente. Elles n'ont aucune incidence sur les fonctionnalités et peuvent être ignorées en toute sécurité.

3. Initialiser et arrêter

Pour lire des fichiers audio, utilisez le plug-in flutter_soloud. Ce plug-in est basé sur le projet SoLoud, un moteur audio C++ pour les jeux utilisé, entre autres, par Nintendo SNES Classic.

7ce23849b6d0d09a.png

Pour initialiser le moteur audio SoLoud, procédez comme suit:

  1. Dans le fichier audio_controller.dart, importez le package flutter_soloud et ajoutez un champ _soloud privé à la classe.

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
  }

  ...

Le contrôleur audio gère le moteur SoLoud sous-jacent via ce champ et lui transmet tous les appels.

  1. Dans la méthode initialize(), saisissez le code suivant:

lib/audio/audio_controller.dart

...

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

...

Cela renseigne le champ _soloud et attend l'initialisation. Veuillez noter les points suivants :

  • SoLoud fournit un champ Singleton instance. Il n'existe aucun moyen d'instancier plusieurs instances SoLoud. Le moteur C++ ne le permet pas. Le plug-in Dart ne l'autorise pas non plus.
  • L'initialisation du plug-in est asynchrone et n'est terminée que lorsque la méthode init() est renvoyée.
  • Par souci de concision de cet exemple, vous n'interceptez pas d'erreurs dans un bloc try/catch. Dans le code de production, vous souhaitez le faire et signaler toute erreur à l'utilisateur.
  1. Dans la méthode dispose(), saisissez le code suivant:

lib/audio/audio_controller.dart

...

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

...

Il est recommandé d'arrêter SoLoud à la fermeture de l'application, même si tout devrait fonctionner correctement, même si vous négligez de le faire.

  1. Notez que la méthode AudioController.initialize() est déjà appelée à partir de la fonction main(). Cela signifie qu'un redémarrage à chaud du projet initialise SoLoud en arrière-plan, mais cela n'est d'aucune utilité tant que vous n'avez pas encore joué.

4. Émettre des sons ponctuels

Charger un élément et le lire

Maintenant que vous savez que SoLoud est initialisé au démarrage, vous pouvez lui demander d'émettre des sons.

SoLoud différencie une source audio, qui correspond aux données et métadonnées utilisées pour décrire un son, et ses "instances sonores", qui sont les sons réellement diffusés. Il peut s'agir, par exemple, d'un fichier mp3 chargé dans la mémoire, prêt à être lu et représenté par une instance de la classe AudioSource. Chaque fois que vous lancez cette source audio, SoLoud crée une "instance de son". qui est représenté par le type SoundHandle.

Vous obtenez une instance AudioSource en la chargeant. Par exemple, si vos éléments comportent un fichier mp3, vous pouvez le charger pour obtenir un fichier AudioSource. Ensuite, dites à SoLoud de jouer ce AudioSource. Vous pouvez l'écouter plusieurs fois, même simultanément.

Lorsque vous n'avez plus besoin d'une source audio, vous la supprimez à l'aide de la méthode SoLoud.disposeSource().

Pour charger un asset et le lire, procédez comme suit:

  1. Dans la méthode playSound() de la classe AudioController, saisissez le code suivant:

lib/audio/audio_controller.dart

  ...

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

  ...
  1. Enregistrez le fichier, effectuez un hot reload, puis sélectionnez Faire sonner. Vous devriez entendre un son de boudge loufoque. Veuillez noter les points suivants :
  • L'argument assetKey fourni est semblable à assets/sounds/pew1.mp3, la même chaîne que vous fourniriez à toute autre API Flutter de chargement d'éléments, comme le widget Image.asset().
  • L'instance SoLoud fournit une méthode loadAsset() qui charge de manière asynchrone un fichier audio à partir des éléments du projet Flutter et renvoie une instance de la classe AudioSource. Il existe des méthodes équivalentes pour charger un fichier à partir du système de fichiers (méthode loadFile()) et pour le charger sur le réseau à partir d'une URL (méthode loadUrl()).
  • L'instance AudioSource nouvellement acquise est ensuite transmise à la méthode play() de SoLoud. Cette méthode renvoie une instance du type SoundHandle qui représente le nouveau son. Ce handle peut, à son tour, être transmis à d'autres méthodes SoLoud pour faire des choses comme mettre en pause, arrêter ou modifier le volume du son.
  • Bien que play() soit une méthode asynchrone, la lecture démarre pratiquement instantanément. Le package flutter_soloud utilise l'interface de fonction étrangère (FFI) de Dart pour appeler le code C directement et de manière synchrone. Les échanges habituels entre le code Dart et le code de la plate-forme, qui sont propres à la plupart des plug-ins Flutter, sont introuvables. Certaines méthodes sont asynchrones, car une partie du code du plug-in s'exécute dans son propre élément isolé, et la communication entre les isols Dart est asynchrone.
  • Il vous suffit d'affirmer que le champ _soloud n'est pas nul avec _soloud!. Encore une fois, par souci de concision. Le code de production doit pouvoir gérer de manière optimale le cas où le développeur tente d'émettre un son avant que la commande audio n'ait pu s'initialiser complètement.

Gérer les exceptions

Vous avez peut-être remarqué que, là encore, vous ignorez peut-être d'éventuelles exceptions. Corrigeons cela pour cette méthode particulière à des fins d'apprentissage. (Par souci de concision, l'atelier de programmation revient sur le fait d'ignorer les exceptions après cette section.)

  • Pour gérer les exceptions dans ce cas, encapsulez les deux lignes de la méthode playSound() dans un bloc try/catch et n'interceptez que les instances de 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 génère diverses exceptions, telles que les exceptions SoLoudNotInitializedException ou SoLoudTemporaryFolderFailedException. La documentation relative aux API de chaque méthode répertorie les types d'exceptions qui peuvent être générés.

SoLoud fournit également une classe parente à toutes ses exceptions, l'exception SoLoudException, afin que vous puissiez détecter toutes les erreurs liées aux fonctionnalités du moteur audio. Cela est particulièrement utile lorsqu'il n'est pas nécessaire de lire le contenu audio. C'est le cas, par exemple, lorsque vous ne voulez pas faire planter la session de jeu du joueur uniquement parce que l'un des sons du banc d'exercice n'a pas pu être chargé.

Comme prévu, la méthode loadAsset() peut également générer une erreur FlutterError si vous fournissez une clé d'élément qui n'existe pas. Vous devez généralement résoudre les problèmes de chargement d'éléments qui ne sont pas regroupés avec le jeu. Il s'agit donc d'une erreur.

Lire différents sons

Vous avez peut-être remarqué que vous ne lisez que le fichier pew1.mp3, mais il existe deux autres versions du son dans le répertoire des éléments. Cela semble souvent plus naturel lorsque les jeux ont plusieurs versions du même son et jouent les différentes versions de manière aléatoire ou alternée. Cela permet, par exemple, d'éviter que les pas et les coups de feu ne semblent trop uniformes et donc faux.

  • Si vous le souhaitez, vous pouvez modifier le code afin d'émettre un son de banc différent chaque fois que l'utilisateur appuie sur le bouton.

Une illustration de

5. Lire des boucles musicales

Gérer les sons de longue durée

Certains contenus audio sont conçus pour être lus pendant de longues périodes. La musique en est l'exemple évident, mais de nombreux jeux jouent également un rôle d'ambiance, comme le vent qui hurle dans les couloirs, les chants de moines au loin, le grincement de métal séculaire ou la toux au loin des patients.

Il s'agit de sources audio dont les durées de lecture peuvent être mesurées en minutes. Vous devez en garder une trace afin de pouvoir les mettre en pause ou les arrêter si nécessaire. Ils sont également souvent sauvegardés par des fichiers volumineux et peuvent consommer une grande quantité de mémoire. Vous pouvez donc les suivre afin de pouvoir supprimer l'instance AudioSource lorsqu'elle n'est plus nécessaire.

Pour cette raison, vous allez introduire un nouveau champ privé pour AudioController. Il s'agit de l'identifiant du titre en cours de lecture, le cas échéant. Ajoutez la ligne suivante :

lib/audio/audio_controller.dart

...

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

  SoLoud? _soloud;

  SoundHandle? _musicHandle;    // ← Add this.

  ...

Lancer la musique

Concrètement, écouter de la musique n'est pas différent de la diffusion d'un son one-shot. Vous devez d'abord charger le fichier assets/music/looped-song.ogg en tant qu'instance de la classe AudioSource, puis utiliser la méthode play() de SoLoud pour le lire.

Cette fois, cependant, vous reprenez la poignée du son renvoyée par la méthode play() pour manipuler l'audio pendant sa lecture.

  • Si vous le souhaitez, implémentez vous-même la méthode AudioController.startMusic(). Pas de problème si vous ne comprenez pas tous les détails. L'important est que la musique démarre lorsque vous sélectionnez Lancer la musique.

Voici une implémentation de référence:

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

...

Notez que vous chargez le fichier musical en mode disque (énumération LoadMode.disk). Cela signifie simplement que le fichier n'est chargé en fragments que si nécessaire. Pour les contenus audio de longue durée, il est généralement préférable de les charger en mode disque. Pour les effets sonores courts, il est plus logique de les charger et de les décompresser en mémoire (l'énumération LoadMode.memory par défaut).

Cependant, vous avez quelques problèmes. Tout d'abord, le volume de la musique est trop élevé, ce qui perturbe le son. Dans la plupart des jeux, la musique est en fond sonore la plupart du temps, ce qui donne le devant de la scène au contenu audio le plus informatif, comme la parole et les effets sonores. Ce problème peut être facilement résolu à l'aide du paramètre de volume de la méthode de lecture. Vous pouvez, par exemple, essayer _soloud!.play(musicSource, volume: 0.6) pour lire le titre à 60% du volume. Vous pouvez également régler le volume ultérieurement avec une commande comme _soloud!.setVolume(_musicHandle, 0.6).

Deuxième problème : la chanson s'arrête brusquement. En effet, le titre est censé être lu en boucle, et le point de départ de la boucle n'est pas le début du fichier audio.

88d2c57fffdfe996.png

Il s'agit d'un choix populaire pour la musique de jeu, car cela signifie que le titre commence par une introduction naturelle, puis est lu aussi longtemps que nécessaire, sans point de boucle évidente. Lorsque le jeu doit quitter le titre en cours de lecture, il l'efface en fondu.

Heureusement, SoLoud propose des options de lecture de contenus audio en boucle. La méthode play() utilise une valeur booléenne pour le paramètre looping, ainsi que la valeur du point de départ de la boucle en tant que paramètre loopingStartAt. Le code obtenu se présente comme suit:

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

...

Si vous ne définissez pas le paramètre loopingStartAt, il est défini par défaut sur Duration.zero (en d'autres termes, le début du fichier audio). Si vous avez un morceau dont la boucle est parfaite sans aucune introduction, c'est l'option que vous voulez.

  • Pour vous assurer que la source audio sera correctement supprimée une fois la lecture terminée, écoutez le flux allInstancesFinished fourni par chaque source audio. Une fois les appels de journaux ajoutés, la méthode startMusic() se présente comme suit:

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

...

Fondu sonore

Le problème suivant, c'est que la musique ne s'arrête jamais. Implémentons un fondu.

Pour implémenter le fondu, vous pouvez utiliser une sorte de fonction appelée plusieurs fois par seconde, comme Ticker ou Timer.periodic, et baisser légèrement le volume de la musique. Cela fonctionnerait, mais cela représente beaucoup de travail.

Heureusement, SoLoud propose des méthodes "fire and forget" pratiques qui le font pour vous. Voici comment effectuer un fondu sonore pendant cinq secondes, puis arrêter l'instance sonore afin qu'elle ne consomme pas inutilement les ressources du processeur. Remplacez la méthode fadeOutMusic() par le code suivant:

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. Appliquer des effets

L'un des grands avantages d'avoir un moteur audio approprié à votre disposition est que vous pouvez effectuer du traitement audio, par exemple en acheminant certains sons par une réverbération, un égaliseur ou un filtre passe-bas.

Dans les jeux, elle peut servir à différencier les lieux de manière auditive. Par exemple, le son des clap est différent dans une forêt et dans un bunker en béton. Tandis qu'une forêt aide à se dissiper et à absorber le son, les murs nus d'un bunker reflètent les ondes sonores, ce qui donne lieu à de la réverbération. De même, la voix des personnes qui se fait entendre à travers un mur est différente. Les fréquences les plus élevées de ces sons sont plus facilement atténuées à mesure qu'elles traversent le milieu solide, ce qui génère un effet de filtre passe-bas.

Illustration représentant deux personnes qui discutent dans une pièce Non seulement les ondes sonores vont d&#39;une personne à l&#39;autre directement, mais elles rebondissent également sur les murs et le plafond.

SoLoud propose plusieurs effets audio que vous pouvez appliquer à l'audio.

  • Pour donner l'impression que le lecteur se trouve dans une grande pièce, comme une cathédrale ou une grotte, utilisez l'énumération 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);
  }

...

Comme vous pouvez le voir, les filtres permettent d'explorer une zone plus spécifique. La définition d'un paramètre de filtre s'effectue à l'aide de l'index du paramètre. Par exemple, le paramètre Wet du freeverbe a l'index 0 et le paramètre Room Size a l'index 2.

Avec le code précédent, vous effectuez les opérations suivantes:

  • Activez le filtre "Freeverb" de manière globale ou sur l'ensemble du mix audio, et pas seulement sur un seul son.
  • Définissez le paramètre Wet sur 0.2. Ainsi, le son sera à 80% d'origine et à 20% de la sortie de l'effet de réverbération. Si vous définissez ce paramètre sur 1.0, cela revient à n'entendre que les ondes sonores qui reviennent vers vous depuis les murs de la pièce au loin, et non le son d'origine.
  • Définissez le paramètre Taille de la pièce sur 0.9. Vous pouvez ajuster ce paramètre à votre convenance, voire le modifier de façon dynamique. 1.0 est une immense caverne, tandis que 0.0 est une salle de bain.
  • Si vous le souhaitez, modifiez le code et appliquez l'un des filtres suivants ou une combinaison des filtres suivants:
  • FilterType.biquadResonantFilter (peut être utilisé comme filtre passe-bas)
  • FilterType.eqFilter
  • FilterType.echoFilter
  • FilterType.lofiFilter
  • FilterType.flangerFilter
  • FilterType.bassboostFilter
  • FilterType.waveShaperFilter
  • FilterType.robotizeFilter
  • FilterType.freeverbFilter

7. Félicitations

Vous avez implémenté une commande audio qui lit des sons, lit la musique en boucle et applique des effets.

En savoir plus

  • Essayez d'aller encore plus loin avec la commande audio avec des fonctionnalités comme le préchargement des sons au démarrage, la lecture de chansons dans une séquence ou l'application progressive d'un filtre au fil du temps.
  • Lisez la documentation sur le package de flutter_soloud.
  • Lisez la page d'accueil de la bibliothèque C++ sous-jacente.
  • Apprenez-en plus sur Dart FFI, la technologie utilisée pour l'interface avec la bibliothèque C++.
  • Inspirez-vous de la présentation de Guy Somberg sur la programmation audio pour les jeux vidéo. (Il existe également un modèle plus long.) Lorsque Guy parle de middleware, il fait référence à des bibliothèques telles que SoLoud et FMOD. Le reste du code est généralement spécifique à chaque jeu.
  • Créez votre jeu, puis publiez-le.

Illustration d&#39;un casque