1. Hinweis
Spiele sind audiovisuelle Erlebnisse. Flutter ist ein hervorragendes Tool, um visuell ansprechende Bilder und eine solide Benutzeroberfläche zu erstellen. Die fehlende Zutat ist Audio. In diesem Codelab erfährst du, wie du mit dem flutter_soloud
-Plug-in Sound und Musik mit niedriger Latenz in dein Projekt einführst. Sie beginnen mit einem einfachen Gerüst, sodass Sie direkt zu den interessanten Stellen springen können.
Sie können das Gelernte natürlich nicht nur für Spiele, sondern auch für Apps verwenden. Während fast alle Spiele Ton und Musik erfordern, ist das bei den meisten Apps nicht der Fall. Daher liegt der Schwerpunkt dieses Codelabs auf Spielen.
Vorbereitung
- Grundkenntnisse in Flutter
- Kenntnisse zum Ausführen und Entwickeln von Flutter-Apps
Lerninhalte
- Einmalig wiedergegebene Töne abspielen
- Unterbrechungsfreie Musikschleifen abspielen und anpassen
- Ton ein- und ausblenden
- So wendest du Umgebungseffekte auf Geräusche an.
- So gehen Sie mit Ausnahmen um.
- Wie Sie alle diese Funktionen in einem einzigen Audiocontroller kapseln.
Voraussetzungen
- Das Flutter SDK
- Einen Code-Editor Ihrer Wahl
2. Einrichten
- Laden Sie die folgenden Dateien herunter. Keine Sorge, wenn Ihre Verbindung langsam ist. Sie benötigen die Dateien später, sodass Sie sie während der Arbeit herunterladen können.
- Erstellen Sie ein Flutter-Projekt mit einem beliebigen Namen.
- Erstellen Sie im Projekt eine
lib/audio/audio_controller.dart
-Datei. - Geben Sie in die Datei den folgenden Code ein:
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
}
}
Wie Sie sehen, ist dies nur ein Gerüst für zukünftige Funktionen. Wir werden das alles in diesem Codelab implementieren.
- Öffnen Sie als Nächstes die Datei
lib/main.dart
und ersetzen Sie ihren Inhalt durch den folgenden Code:
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();
}
},
),
],
),
],
),
),
);
}
}
- Nachdem die Audiodateien heruntergeladen wurden, erstellen Sie im Stammverzeichnis Ihres Projekts ein Verzeichnis mit dem Namen
assets
. - Erstellen Sie im Verzeichnis
assets
zwei Unterverzeichnisse, das einemusic
und das anderesounds
. - Verschiebe die heruntergeladenen Dateien in dein Projekt, sodass sich die Songdatei in der Datei
assets/music/looped-song.ogg
und die Kirchenbänken-Sounds in den folgenden Dateien befinden:
assets/sounds/pew1.mp3
assets/sounds/pew2.mp3
assets/sounds/pew3.mp3
Die Projektstruktur sollte jetzt in etwa so aussehen:
Nachdem Sie die Dateien erstellt haben, müssen Sie Flutter darüber informieren.
- Öffnen Sie die Datei
pubspec.yaml
und ersetzen Sie den Abschnittflutter:
am Ende der Datei durch Folgendes:
pubspec.yaml
...
flutter:
uses-material-design: true
assets:
- assets/music/
- assets/sounds/
- Fügen Sie eine Abhängigkeit vom Paket
flutter_soloud
und dem Paketlogging
hinzu.
pubspec.yaml
...
dependencies:
flutter:
sdk: flutter
flutter_soloud: ^2.0.0
logging: ^1.2.0
...
- Führen Sie das Projekt aus. Noch nichts funktioniert, da Sie die Funktionalität in den folgenden Abschnitten hinzugefügt haben.
/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];
Diese stammen aus der zugrunde liegenden SoLoud
-C++-Bibliothek. Sie haben keine Auswirkungen auf die Funktionalität und können ignoriert werden.
3. Initialisieren und Herunterfahren
Zum Abspielen von Audioinhalten verwenden Sie das flutter_soloud
-Plug-in. Dieses Plug-in basiert auf dem SoLoud-Projekt, einer C++-Audio-Engine für Spiele, die unter anderem von Nintendo SNES Classic verwendet wird.
So initialisieren Sie die SoLoud-Audio-Engine:
- Importieren Sie in der Datei
audio_controller.dart
das Paketflutter_soloud
und fügen Sie der Klasse ein privates Feld vom Typ_soloud
hinzu.
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
}
...
Der Audio-Controller verwaltet die zugrunde liegende SoLoud-Engine über dieses Feld und leitet alle Aufrufe an diese weiter.
- Geben Sie in der Methode
initialize()
den folgenden Code ein:
lib/audio/audio_controller.dart
...
Future<void> initialize() async {
_soloud = SoLoud.instance;
await _soloud!.init();
}
...
Dadurch wird das Feld _soloud
ausgefüllt und wartet auf die Initialisierung. Wichtige Hinweise:
- SoLoud bietet ein Singleton-Feld
instance
. Es ist nicht möglich, mehrere SoLoud-Instanzen zu erstellen. Die C++-Engine lässt dies nicht zu und wird vom Dart-Plug-in ebenfalls nicht zugelassen. - Die Initialisierung des Plug-ins ist asynchron und wird erst abgeschlossen, wenn die
init()
-Methode zurückgegeben wird. - Der Einfachheit halber werden in diesem Beispiel keine Fehler in einem
try/catch
-Block erfasst. Im Produktionscode sollten Sie dies tun und dem Nutzer eventuelle Fehler melden.
- Geben Sie in der Methode
dispose()
den folgenden Code ein:
lib/audio/audio_controller.dart
...
void dispose() {
_soloud?.deinit();
}
...
Es ist empfehlenswert, SoLoud beim Schließen der App zu beenden. Alles sollte jedoch auch dann einwandfrei funktionieren, wenn Sie das nicht tun.
- Beachten Sie, dass die Methode
AudioController.initialize()
bereits über die Funktionmain()
aufgerufen wird. Das bedeutet, dass SoLoud beim Hot-Neustart des Projekts im Hintergrund initialisiert wird, aber erst funktioniert, wenn Sie tatsächlich Töne abspielen.
4. Töne aus einer Aufnahme abspielen
Asset laden und abspielen
Da Sie jetzt wissen, dass SoLoud beim Start initialisiert wird, können Sie es bitten, Töne abzuspielen.
SoLoud unterscheidet zwischen einer Audioquelle, d. h. den Daten und Metadaten, die zur Beschreibung eines Tons verwendet werden, und ihren „Toninstanzen“, d. h. den tatsächlich abgespielten Tönen. Ein Beispiel für eine Audioquelle ist eine MP3-Datei, die in den Arbeitsspeicher geladen und zur Wiedergabe bereit ist und durch eine Instanz der Klasse AudioSource
dargestellt wird. Jedes Mal, wenn du diese Audioquelle abspielst, erstellt SoLoud eine „Toninstanz“ der durch den Typ SoundHandle
dargestellt wird.
Sie erhalten eine AudioSource
-Instanz, indem Sie sie laden. Wenn deine Assets beispielsweise eine MP3-Datei enthalten, kannst du sie laden, um eine AudioSource
zu erhalten. Dann bitten Sie SoLoud, diese AudioSource
abzuspielen. Sie können sie beliebig oft und sogar gleichzeitig abspielen.
Wenn Sie mit einer Audioquelle fertig sind, können Sie sie mit der Methode SoLoud.disposeSource()
entsorgen.
So laden Sie ein Asset und spielen es ab:
- Geben Sie in der Methode
playSound()
der KlasseAudioController
den folgenden Code ein:
lib/audio/audio_controller.dart
...
Future<void> playSound(String assetKey) async {
final source = await _soloud!.loadAsset(assetKey);
await _soloud!.play(source);
}
...
- Speichern Sie die Datei, aktualisieren Sie sie bei Bedarf und wählen Sie dann Ton abspielen aus. Sie sollten ein albernes Pew-Geräusch hören. Wichtige Hinweise:
- Das angegebene
assetKey
-Argument ist beispielsweiseassets/sounds/pew1.mp3
– derselbe String, den Sie für jede andere Flutter API zum Laden von Assets angeben würden, z. B. für dasImage.asset()
-Widget. - Die SoLoud-Instanz bietet eine
loadAsset()
-Methode, die eine Audiodatei asynchron aus den Assets des Flutter-Projekts lädt und eine Instanz der KlasseAudioSource
zurückgibt. Es gibt gleichwertige Methoden, um eine Datei aus dem Dateisystem (loadFile()
-Methode) und über das Netzwerk von einer URL (loadUrl()
-Methode) zu laden. - Die neu gewonnene
AudioSource
-Instanz wird dann an dieplay()
-Methode von SoLoud übergeben. Diese Methode gibt eine Instanz des TypsSoundHandle
zurück, die den gerade abgespielten Ton darstellt. Dieser Handle kann wiederum an andere SoLoud-Methoden übergeben werden, um beispielsweise den Ton zu pausieren, anzuhalten oder die Lautstärke zu ändern. - Obwohl
play()
eine asynchrone Methode ist, beginnt die Wiedergabe praktisch sofort. Dasflutter_soloud
-Paket verwendet die Foreign Function Interface (FFI) von Dart, um C-Code direkt und synchron aufzurufen. Die übliche Kommunikation zwischen Dart-Code und Plattformcode, die für die meisten Flutter-Plug-ins charakteristisch ist, ist nirgendwo zu finden. Einige Methoden sind nur asynchron, da ein Teil des Codes des Plug-ins in einem eigenen Isola ausgeführt wird und die Kommunikation zwischen Dart-Isolierungen asynchron ist. - Sie bestätigen einfach mit
_soloud!
, dass das Feld_soloud
nicht null ist. Dies dient der Kürze. Der Produktionscode sollte mit Situationen umgehen können, in denen der Entwickler versucht, einen Ton abzuspielen, bevor der Audio-Controller vollständig initialisiert werden konnte.
Ausnahmen für den Deal
Sie haben vielleicht bemerkt, dass Sie wieder einmal mögliche Ausnahmen ignorieren. Korrigieren wir das für diese Methode zu Lernzwecken. Der Einfachheit halber werden im Codelab Ausnahmen nach diesem Abschnitt ignoriert.
- Um in diesem Fall mit Ausnahmen umzugehen, können Sie die beiden Zeilen der
playSound()
-Methode in einentry/catch
-Block einschließen und nur Instanzen vonSoLoudException
abfangen.
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 löst verschiedene Ausnahmen aus, z. B. die Ausnahmen SoLoudNotInitializedException
oder SoLoudTemporaryFolderFailedException
. In der API-Dokumentation der einzelnen Methoden sind die Arten von Ausnahmen aufgeführt, die möglicherweise ausgelöst werden.
SoLoud bietet auch eine übergeordnete Klasse für alle Ausnahmen, die SoLoudException
-Ausnahme, damit du alle Fehler im Zusammenhang mit der Funktionalität der Audio-Engine abfangen kannst. Das ist besonders hilfreich, wenn das Abspielen von Audio nicht kritisch ist. Das ist beispielsweise der Fall, wenn Sie die Spielsitzung des Spielers nicht zum Absturz bringen möchten, nur weil eines der Töne von Peng-Pew nicht geladen werden konnte.
Wie zu erwarten wäre, kann die Methode loadAsset()
auch den Fehler FlutterError
ausgeben, wenn Sie einen nicht vorhandenen Assetschlüssel angeben. Der Versuch, Assets zu laden, die nicht im Lieferumfang des Spiels enthalten sind, sollte in der Regel behoben werden. Daher ist dies ein Fehler.
Verschiedene Töne abspielen
Vielleicht hast du bemerkt, dass du nur die Datei pew1.mp3
wiedergibst, aber im Asset-Verzeichnis befinden sich zwei weitere Versionen des Tons. Es klingt oft natürlicher, wenn Spiele mehrere Versionen desselben Tons haben und die verschiedenen Versionen nach dem Zufallsprinzip oder im Wechsel abspielen. So klingen beispielsweise Schritte und Schüsse nicht zu einheitlich und damit unecht.
- Als optionale Übung können Sie den Code so ändern, dass bei jedem Antippen der Schaltfläche ein anderer Pew-Ton abgespielt wird.
5. Musikschleifen abspielen
Länger laufende Töne verwalten
Einige Audioinhalte sind für einen längeren Zeitraum gedacht. Musik ist das offensichtliche Beispiel, aber viele Spiele spielen auch eine Atmosphäre, beispielsweise der Wind, der durch die Gänge heult, das Gesang der Mönche aus der Ferne, das Knarren jahrhundertealter Metalle oder das Husten von Patienten in der Ferne.
Das sind Audioquellen mit einer Wiedergabezeit, die in Minuten gemessen werden kann. Sie müssen sie im Auge behalten, damit Sie sie bei Bedarf pausieren oder stoppen können. Außerdem werden sie häufig von großen Dateien unterstützt und können viel Arbeitsspeicher verbrauchen. Ein weiterer Grund, sie zu überwachen, ist, dass Sie die AudioSource
-Instanz entsorgen können, wenn sie nicht mehr benötigt wird.
Aus diesem Grund führen Sie ein neues privates Feld für AudioController
ein. Ein Handle für den aktuell abgespielten Song, falls vorhanden. Fügen Sie folgende Zeile hinzu:
lib/audio/audio_controller.dart
...
class AudioController {
static final Logger _log = Logger('AudioController');
SoLoud? _soloud;
SoundHandle? _musicHandle; // ← Add this.
...
Musik starten
Im Wesentlichen unterscheidet sich das Abspielen von Musik nicht vom Abspielen eines Sounds mit einer Aufnahme. Du musst trotzdem zuerst die Datei assets/music/looped-song.ogg
als Instanz der AudioSource
-Klasse laden und dann die play()
-Methode von SoLoud verwenden, um sie abzuspielen.
Dieses Mal greifen Sie jedoch auf den Audio-Handle zu, der von der play()
-Methode zurückgegeben wird, um das Audio während der Wiedergabe zu manipulieren.
- Sie können die
AudioController.startMusic()
-Methode auch selbst implementieren. Es ist in Ordnung, wenn Sie einige Details nicht richtig wiedergeben. Wichtig ist, dass die Musik startet, wenn Sie Musik starten auswählen.
Hier eine Referenzimplementierung:
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);
}
...
Beachte, dass du die Musikdatei im Laufwerkmodus (LoadMode.disk
-Enum) lädst. Das bedeutet einfach, dass die Datei nur bei Bedarf in Teilen geladen wird. Bei Audioinhalten mit einer längeren Laufzeit empfiehlt es sich im Allgemeinen, den Datenträger im Datenträgermodus zu laden. Bei kurzen Soundeffekten ist es sinnvoller, sie in den Arbeitsspeicher zu laden und dort zu dekomprimieren (das Standard-LoadMode.memory
-Enum).
Es gibt jedoch ein paar Probleme. Erstens: Die Musik ist zu laut und übertönt die Geräusche. In den meisten Spielen läuft die Musik meistens im Hintergrund, sodass die aussagekräftigeren Audioinhalte wie Sprache und Soundeffekte im Vordergrund stehen. Das lässt sich ganz einfach mit dem Lautstärkeparameter der Wiedergabemethode beheben. Sie können beispielsweise _soloud!.play(musicSource, volume: 0.6)
sagen, um den Titel mit 60 % der Lautstärke abzuspielen. Alternativ kannst du die Lautstärke später mit einem Wert wie _soloud!.setVolume(_musicHandle, 0.6)
einstellen.
Das zweite Problem ist, dass der Song abrupt stoppt. Das liegt daran, dass der Titel in einer Schleife abgespielt werden sollte und der Startpunkt der Schleife nicht der Anfang der Audiodatei ist.
Dies ist eine beliebte Wahl für Spielemusik, da der Song mit einem natürlichen Intro beginnt und dann so lange wie nötig abgespielt wird – ohne einen offensichtlichen Schleifenpunkt. Wenn im Spiel ein Übergang vom aktuell abgespielten Song erforderlich ist, wird der Song einfach ausgeblendet.
Zum Glück bietet SoLoud die Möglichkeit, Audioschleifen abzuspielen. Die Methode play()
verwendet einen booleschen Wert für den Parameter looping
sowie den Wert für den Startpunkt der Schleife als Parameter loopingStartAt
. Der Code sieht dann so aus:
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),
);
...
Wenn Sie den Parameter loopingStartAt
nicht festlegen, wird standardmäßig Duration.zero
verwendet (also der Anfang der Audiodatei). Wenn du einen Musiktitel hast, der sich perfekt ohne Einleitung in einem Loop abspielen lässt, ist das die richtige Option.
- Damit die Audioquelle nach der Wiedergabe ordnungsgemäß entsorgt wird, solltest du den
allInstancesFinished
-Stream der jeweiligen Audioquelle abspielen. Mit hinzugefügten Logaufrufen sieht die MethodestartMusic()
dann so aus:
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),
);
}
...
Ton ausblenden
Das nächste Problem ist, dass die Musik nie zu Ende ist. Lassen Sie uns eine Blende implementieren.
Eine Möglichkeit, die Ausblendung zu implementieren, wäre eine Funktion, die mehrmals pro Sekunde aufgerufen wird, z. B. Ticker
oder Timer.periodic
, und die Lautstärke der Musik dabei geringfügig zu verringern. Das würde funktionieren, ist aber aufwendig.
Glücklicherweise bietet SoLoud praktische Fire-and-Forget-Methoden, die dies für dich erledigen. So können Sie die Musik über einen Zeitraum von fünf Sekunden ausblenden und dann die Audioinstanz beenden, damit sie nicht unnötig CPU-Ressourcen verbraucht: Ersetzen Sie die fadeOutMusic()
-Methode durch diesen Code:
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. Effekte anwenden
Ein großer Vorteil einer richtigen Audio-Engine ist, dass du Audiosignale verarbeiten kannst, z. B. indem du einige Töne durch einen Hall, einen Equalizer oder einen Tiefpassfilter leitest.
In Spielen kann dies zur akustischen Unterscheidung von Orten verwendet werden. Zum Beispiel klingt ein Klatschen im Wald anders als in einem Betonbunker. Während ein Wald dazu beiträgt, den Schall zu verteilen und zu absorbieren, reflektieren die kahlen Wände eines Bunkers die Schallwellen zurück, was zu einem Nachhall führt. Ähnlich klingen die Stimmen von Menschen anders, wenn sie durch eine Wand gehört werden. Die höheren Frequenzen dieser Töne werden beim Durchlaufen des festen Mediums leichter gedämpft, was zu einem Tiefpassfiltereffekt führt.
SoLoud bietet verschiedene Audioeffekte, die Sie auf Audio anwenden können.
- Wenn es sich so anfühlen soll, als befinde sich der Player in einem großen Raum, z. B. einer Kathedrale oder einer Höhle, verwenden Sie das Feld
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();
}
...
Über das Feld SoLoud.filters
haben Sie Zugriff auf alle Filtertypen und ihre Parameter. Jeder Parameter hat außerdem integrierte Funktionen wie ein allmähliches Ausblenden und eine Oszillation.
Hinweis: _soloud!.filters
gibt globale Filter an. Wenn Sie Filter auf eine einzelne Quelle anwenden möchten, verwenden Sie das Gegenstück AudioSource.filters
.
Mit dem vorherigen Code geschieht Folgendes:
- Aktivieren Sie global den Freeverb-Filter.
- Lege den Parameter Wet auf
0.2
fest. Das bedeutet, dass das resultierende Audiosignal zu 80 % aus dem Original und zu 20 % aus der Ausgabe des Halleffekts besteht. Wenn Sie diesen Parameter auf1.0
festlegen, hören Sie nur die Schallwellen, die von den entfernten Wänden des Raums zu Ihnen zurückkommen, und nichts vom ursprünglichen Audiosignal. - Legen Sie für den Parameter Raumgröße den Wert
0.9
fest. Sie können diesen Parameter nach Belieben anpassen oder sogar dynamisch ändern.1.0
ist eine riesige Höhle und0.0
ein Badezimmer.
- Wenn Sie möchten, können Sie den Code ändern und einen oder mehrere der folgenden Filter anwenden:
biquadFilter
(kann als Tiefpassfilter verwendet werden)pitchShiftFilter
equalizerFilter
echoFilter
lofiFilter
flangerFilter
bassboostFilter
waveShaperFilter
robotizeFilter
7. Glückwunsch
Sie haben einen Audio-Controller implementiert, der Klänge abspielt, Musik als Schleife wiedergeben und Effekte anwendet.
Weitere Informationen
- Mit Funktionen wie dem Vorladen von Tönen beim Starten, dem Abspielen von Titeln in einer bestimmten Reihenfolge oder dem schrittweisen Anwenden eines Filters können Sie den Audiocontroller noch weiter optimieren.
- Lesen Sie die Paketdokumentation für
flutter_soloud
. - Lesen Sie die Startseite der zugrunde liegenden C++-Bibliothek.
- Weitere Informationen zu Dart FFI, der Technologie für die Schnittstelle zur C++-Bibliothek
- Sehen Sie sich Guy Sombergs Vortrag zum Thema Audioprogrammierung für Spiele an, um sich inspirieren zu lassen. (Es gibt auch eine längere.) Wenn Guy von „Middleware“ spricht, meint er Bibliotheken wie SoLoud und FMOD. Der Rest des Codes ist tendenziell für jedes Spiel spezifisch.
- Entwickeln Sie Ihr Spiel und veröffentlichen Sie es.