audio_controller.dart 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright 2022, the Flutter project authors. Please see the AUTHORS file
  2. // for details. All rights reserved. Use of this source code is governed by a
  3. // BSD-style license that can be found in the LICENSE file.
  4. import 'package:flutter/widgets.dart';
  5. import 'package:image_puzzle/settings/settings_controller.dart';
  6. import 'package:jc_audio_player/jc_audio_player.dart';
  7. import 'package:logging/logging.dart';
  8. enum SfxType { drop, click, tap, kick, pop, appear, alert, star, success, flip, card }
  9. //AudioLogger.logLevel = AudioLogLevel.info;
  10. /// Allows playing music and sound. A facade to `package:audioplayers`.
  11. class AudioController {
  12. static final _log = Logger('AudioController');
  13. SettingsController? _settings;
  14. ValueNotifier<AppLifecycleState>? _lifecycleNotifier;
  15. final JcAudioPlayer _audioPlayer = JcAudioPlayer();
  16. AudioController() {
  17. _audioPlayer.addMusic(1, 'assets/audio/bgm/loop.mp3');
  18. // _audioPlayer.addMusic(1, 'assets/audio/bgm/loop4.mp3');
  19. // _audioPlayer.addMusic(1, 'assets/audio/bgm/loop7.mp3');
  20. _audioPlayer.addSound(SfxType.drop.index, 'assets/audio/sfx/button_click8.mp3');
  21. _audioPlayer.addSound(SfxType.click.index, 'assets/audio/sfx/click2.mp3');
  22. _audioPlayer.addSound(SfxType.tap.index, 'assets/audio/sfx/tap.mp3');
  23. _audioPlayer.addSound(SfxType.kick.index, 'assets/audio/sfx/kick.mp3');
  24. _audioPlayer.addSound(SfxType.pop.index, 'assets/audio/sfx/pop.mp3');
  25. _audioPlayer.addSound(SfxType.appear.index, 'assets/audio/sfx/appear.mp3');
  26. _audioPlayer.addSound(SfxType.alert.index, 'assets/audio/sfx/alert.mp3');
  27. _audioPlayer.addSound(SfxType.star.index, 'assets/audio/sfx/star.mp3');
  28. _audioPlayer.addSound(SfxType.success.index, 'assets/audio/sfx/success3.mp3');
  29. // _audioPlayer.addSound(SfxType.success.index, 'assets/audio/sfx/success5.mp3');
  30. // _audioPlayer.addSound(SfxType.success.index, 'assets/audio/sfx/success4.mp3');
  31. _audioPlayer.addSound(SfxType.card.index, 'assets/audio/sfx/card.mp3');
  32. _audioPlayer.addSound(SfxType.flip.index, 'assets/audio/sfx/flip.mp3');
  33. }
  34. void initialize() {
  35. _startMusic();
  36. }
  37. void dispose() {
  38. _lifecycleNotifier?.removeListener(_handleAppLifecycle);
  39. _stopMusic();
  40. _stopSound();
  41. }
  42. /// Enables the [AudioController] to listen to [AppLifecycleState] events,
  43. /// and therefore do things like stopping playback when the game
  44. /// goes into the background.
  45. void attachLifecycleNotifier(ValueNotifier<AppLifecycleState> lifecycleNotifier) {
  46. _lifecycleNotifier?.removeListener(_handleAppLifecycle);
  47. lifecycleNotifier.addListener(_handleAppLifecycle);
  48. _lifecycleNotifier = lifecycleNotifier;
  49. }
  50. /// Enables the [AudioController] to track changes to settings.
  51. /// Namely, when any of [SettingsController.muted],
  52. /// [SettingsController.musicOn] or [SettingsController.soundsOn] changes,
  53. /// the audio controller will act accordingly.
  54. void attachSettings(SettingsController settingsController) {
  55. if (_settings == settingsController) {
  56. // Already attached to this instance. Nothing to do.
  57. return;
  58. }
  59. // Remove handlers from the old settings controller if present
  60. final oldSettings = _settings;
  61. if (oldSettings != null) {
  62. oldSettings.music.removeListener(_musicOnHandler);
  63. oldSettings.sound.removeListener(_soundOnHandler);
  64. }
  65. _settings = settingsController;
  66. // Add handlers to the new settings controller
  67. settingsController.music.addListener(_musicOnHandler);
  68. settingsController.sound.addListener(_soundOnHandler);
  69. }
  70. /// Plays a single sound effect, defined by [type].
  71. ///
  72. /// The controller will ignore this call when the attached settings'
  73. /// [SettingsController.soundsOn] is `false`.
  74. void playSfx(SfxType type, {Duration? duration}) async {
  75. final soundsOn = _settings?.sound.value ?? false;
  76. if (!soundsOn) {
  77. _log.info(() => 'Ignoring playing sound ($type) because sounds are turned off.');
  78. return;
  79. }
  80. _audioPlayer.playSound(type.index);
  81. if (duration != null) {
  82. Future.delayed(duration, () => _audioPlayer.stopSound());
  83. }
  84. }
  85. void _handleAppLifecycle() {
  86. switch (_lifecycleNotifier!.value) {
  87. case AppLifecycleState.paused:
  88. case AppLifecycleState.detached:
  89. case AppLifecycleState.hidden:
  90. case AppLifecycleState.inactive:
  91. _pauseMusic();
  92. break;
  93. case AppLifecycleState.resumed:
  94. _startMusic();
  95. break;
  96. }
  97. }
  98. void _musicOnHandler() {
  99. if (_settings!.music.value) {
  100. // Music got turned on.
  101. // _resumeMusic();
  102. _startMusic();
  103. } else {
  104. // Music got turned off.
  105. _stopMusic();
  106. }
  107. }
  108. void _soundOnHandler() {}
  109. void _startMusic() {
  110. _log.info('starting music');
  111. final musicOn = _settings?.music.value ?? false;
  112. if (!musicOn) {
  113. _log.info(() => 'Ignoring playing music because music are turned off.');
  114. return;
  115. }
  116. _audioPlayer.playMusic(1, volume: 0.5);
  117. }
  118. void _stopMusic() {
  119. _log.info('Stopping music');
  120. _audioPlayer.stopMusic();
  121. }
  122. void _pauseMusic() {
  123. _log.info('pause music');
  124. _audioPlayer.pauseMusic();
  125. }
  126. Future<void> _resumeMusic() async {
  127. _log.info('Resuming music');
  128. _audioPlayer.resumeMusic();
  129. }
  130. void _stopSound() {
  131. _audioPlayer.stopSound();
  132. }
  133. }