audio_controller.dart 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // // puzzleweave/audio/audio_controller.dart
  2. // import 'package:flutter/widgets.dart';
  3. // import 'package:audioplayers/audioplayers.dart';
  4. // import 'package:puzzleweave/settings/settings_controller.dart';
  5. // import 'package:logging/logging.dart';
  6. // enum SfxType { drop, click, tap, pop, appear, alert, star, success, flip, card, cardShort, panstart, panend, panend2 }
  7. // /// 允许播放音乐和声音效果。
  8. // class AudioControllerX {
  9. // static final _log = Logger('AudioController');
  10. // SettingsController? _settings;
  11. // ValueNotifier<AppLifecycleState>? _lifecycleNotifier;
  12. // // 1. BGM 播放器 (使用常规模式进行流式传输,专用于音乐)
  13. // final AudioPlayer _musicPlayer = AudioPlayer();
  14. // // 2. 音效音频池 (用于低延迟播放 SFX)
  15. // // Key: SfxType, Value: AudioPool 实例
  16. // final Map<SfxType, AudioPool> _sfxPools = {};
  17. // // 预加载的 BGM 文件路径
  18. // final String _bgmAsset = 'audio/bgm/canon.mp3';
  19. // // 所有音效文件映射
  20. // static const Map<SfxType, String> _sfxPaths = {
  21. // SfxType.drop: 'audio/sfx/button_click8.mp3',
  22. // SfxType.click: 'audio/sfx/click2.mp3',
  23. // SfxType.tap: 'audio/sfx/tap.mp3',
  24. // SfxType.pop: 'audio/sfx/pop.mp3',
  25. // SfxType.appear: 'audio/sfx/appear.mp3',
  26. // SfxType.alert: 'audio/sfx/alert.mp3',
  27. // SfxType.star: 'audio/sfx/star.mp3',
  28. // SfxType.success: 'audio/sfx/win.mp3',
  29. // SfxType.card: 'audio/sfx/card.mp3',
  30. // SfxType.cardShort: 'audio/sfx/card2.mp3',
  31. // SfxType.flip: 'audio/sfx/flip.mp3',
  32. // SfxType.panstart: 'audio/sfx/pan_start.mp3',
  33. // SfxType.panend: 'audio/sfx/pan_end.mp3',
  34. // SfxType.panend2: 'audio/sfx/pan_end2.mp3',
  35. // };
  36. // AudioControllerX() {
  37. // // 配置 BGM 播放器:设置为循环模式
  38. // _musicPlayer.setReleaseMode(ReleaseMode.loop);
  39. // }
  40. // /// 在应用启动时异步调用,用于预加载所有音乐和音效。
  41. // Future<void> initialize() async {
  42. // // 1. 预加载 BGM
  43. // await _musicPlayer.setSource(AssetSource(_bgmAsset));
  44. // // 2. 预加载所有 SFX 到 AudioPool 中 (实现真正的低延迟)
  45. // final futures = _sfxPaths.entries.map((entry) async {
  46. // final type = entry.key;
  47. // final path = entry.value;
  48. // // ⚠️ 修复:使用 AudioPool.createFromAssetSource 替换 fromAsset
  49. // final pool = await AudioPool.createFromAsset(
  50. // path: path, // 直接传入 String 路径
  51. // maxPlayers: type == SfxType.card ? 10 : 3,
  52. // );
  53. // _sfxPools[type] = pool;
  54. // }).toList();
  55. // await Future.wait(futures);
  56. // _log.info('All sounds and music preloaded successfully via AudioPool.');
  57. // }
  58. // void dispose() {
  59. // _lifecycleNotifier?.removeListener(_handleAppLifecycle);
  60. // stopMusic();
  61. // // 停止并清理所有的音频池,释放原生资源
  62. // for (final pool in _sfxPools.values) {
  63. // pool.dispose();
  64. // }
  65. // _sfxPools.clear();
  66. // _musicPlayer.dispose();
  67. // }
  68. // /// Enables the [AudioController] to listen to [AppLifecycleState] events...
  69. // void attachLifecycleNotifier(ValueNotifier<AppLifecycleState> lifecycleNotifier) {
  70. // _lifecycleNotifier?.removeListener(_handleAppLifecycle);
  71. // lifecycleNotifier.addListener(_handleAppLifecycle);
  72. // _lifecycleNotifier = lifecycleNotifier;
  73. // }
  74. // /// Enables the [AudioController] to track changes to settings...
  75. // void attachSettings(SettingsController settingsController) {
  76. // if (_settings == settingsController) return;
  77. // final oldSettings = _settings;
  78. // if (oldSettings != null) {
  79. // oldSettings.music.removeListener(_musicOnHandler);
  80. // oldSettings.sound.removeListener(_soundOnHandler);
  81. // }
  82. // _settings = settingsController;
  83. // settingsController.music.addListener(_musicOnHandler);
  84. // settingsController.sound.addListener(_soundOnHandler);
  85. // }
  86. // /// Plays a single sound effect, defined by [type].
  87. // /// 使用 AudioPool 实现极低延迟播放。
  88. // void playSfx(SfxType type, {Duration? duration}) async {
  89. // final soundsOn = _settings?.sound.value ?? false;
  90. // if (!soundsOn) {
  91. // _log.info(() => 'Ignoring playing sound ($type) because sounds are turned off.');
  92. // return;
  93. // }
  94. // final pool = _sfxPools[type];
  95. // if (pool == null) {
  96. // _log.severe('Missing audio pool for SFX type: $type');
  97. // return;
  98. // }
  99. // // 核心优化:从 AudioPool 快速启动播放。
  100. // await pool.start(volume: 1.0);
  101. // if (duration != null) {
  102. // _log.warning('Duration control is complex with AudioPool; generally SFX should be short.');
  103. // }
  104. // }
  105. // void _handleAppLifecycle() {
  106. // switch (_lifecycleNotifier!.value) {
  107. // case AppLifecycleState.paused:
  108. // case AppLifecycleState.detached:
  109. // case AppLifecycleState.hidden:
  110. // case AppLifecycleState.inactive:
  111. // pauseMusic();
  112. // break;
  113. // case AppLifecycleState.resumed:
  114. // startMusic();
  115. // break;
  116. // }
  117. // }
  118. // void _musicOnHandler() {
  119. // if (_settings!.music.value) {
  120. // startMusic();
  121. // } else {
  122. // stopMusic();
  123. // }
  124. // }
  125. // void _soundOnHandler() {
  126. // // 声音设置关闭时,不需要特殊处理 AudioPool 播放的短音效
  127. // }
  128. // void setMusicVolume(double volume) {
  129. // _musicPlayer.setVolume(volume);
  130. // _log.info('Music volume set to $volume');
  131. // }
  132. // void startMusic() async {
  133. // _log.info('starting music');
  134. // final musicOn = _settings?.music.value ?? false;
  135. // if (!musicOn) {
  136. // _log.info(() => 'Ignoring playing music because music are turned off.');
  137. // return;
  138. // }
  139. // // 假设我们希望 BGM 默认音量为 0.5
  140. // const double defaultBGMVolume = 0.1;
  141. // final state = _musicPlayer.state;
  142. // if (state == PlayerState.playing) return;
  143. // // 如果音乐已经停止或未播放,则重新设置源并播放
  144. // if (state == PlayerState.stopped || state == PlayerState.disposed) {
  145. // await _musicPlayer.setSource(AssetSource(_bgmAsset));
  146. // await _musicPlayer.setVolume(defaultBGMVolume);
  147. // await _musicPlayer.resume();
  148. // } else {
  149. // // 从暂停状态恢复
  150. // await _musicPlayer.resume();
  151. // }
  152. // }
  153. // void stopMusic() {
  154. // _log.info('Stopping music');
  155. // _musicPlayer.stop();
  156. // }
  157. // void pauseMusic() {
  158. // _log.info('pause music');
  159. // _musicPlayer.pause();
  160. // }
  161. // Future<void> resumeMusic() async {
  162. // _log.info('Resuming music');
  163. // final musicOn = _settings?.music.value ?? false;
  164. // if (musicOn) {
  165. // _musicPlayer.resume();
  166. // }
  167. // }
  168. // void _stopSound() {
  169. // // AudioPool 播放的短音效不需要手动停止
  170. // }
  171. // }