flutter 効果音・BGMをループ再生 audioplayers

# ◎初めに
``audioplayers``というパッケージを利用し、**効果音やBGMをループ再生させる方法**を記述します。
デモとして、標準のカウントアップアプリに効果音をループで実装してみます。
右下のfloatingActionButtonを押すと効果音が流れるようにします。
![](https://storage.googleapis.com/zenn-user-upload/67ba14b55dfa-20220726.png)
### 前提
```
Flutter 3.0.2
audioplayers 0.20.1
```
### 参考
https://pub.dev/packages/audioplayers/versions/0.20.1
https://www.youtube.com/watch?v=MB3YGQ-O1lk

# ◎audioplayers実装
## 1:audioplayersパッケージのインストール
pubspec.yamlに下記を追加
```
audioplayers: ^0.20.1
```
ターミナルでpubgetを実行
```
flutter pub get
```
## 2:音声ファイルの用意
プロジェクト直下にassetsフォルダを作成し、その中に利用したい音声ファイルを入れる。
![](https://storage.googleapis.com/zenn-user-upload/f59fd044df4d-20220726.png)
``pubspec.yaml``ファイルに下記を記述
```
  assets:
    - assets/
```
## 2:main.dartへの実装
### ①main.dart内の``_MyHomePageState``の中に変数を2つ定義
```
  final audioPlayer = AudioPlayer();
  bool isPlaying = false; //再生中か否かを判断する為
```
### ②initStateを作成し、モードの指定と、listenを行う
``audioPlayer.setReleaseMode(ReleaseMode.LOOP);``でReleaseModeの中に用意されている、LOOP再生を指定。(詳細は参考の公式ドキュメントを確認)
``isPlaying = state == PlayerState.PLAYING;``で初めに定義した変数``isPlaying``を更新。
```
  @override
  void initState() {
    super.initState();
    //LOOPの設定
    audioPlayer.setReleaseMode(ReleaseMode.LOOP);

    //再生中か停止中かの状態を取得
    audioPlayer.onPlayerStateChanged.listen((state) {
      setState(() {
        isPlaying = state == PlayerState.PLAYING;
      });
    });
  }
```
### ③floatingActionButton内の処理を記述
floatingActionButtonを下記のように書き換えます。
```
      floatingActionButton: FloatingActionButton(
        onPressed: () async{
          if (isPlaying){
            await audioPlayer.pause();
          }else{
            final player = AudioCache(prefix: 'assets/');
            final url = await player.load('roulette_bgm.mp3');
            await audioPlayer.play(url.path, isLocal: true);
          }
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
```
再生中だった場合は、停止させる。
```
if (isPlaying){
  await audioPlayer.pause();
```
else内は、停止中だった場合に、再生させる処理
下記2行でFlutterプロジェクトファイル内の音声ファイルを読み込みセットする
```
  final player = AudioCache(prefix: 'assets/');
  final url = await player.load('roulette_bgm.mp3');
```
下記1行でセットした音声を再生
```
await audioPlayer.play(url.path, isLocal: true);
```
## エラーが出る場合
自分が動かした際に、音声が短すぎた為か、2回目以降のLOOP再生に入った後に停止ボタンがうまく作動しなくなりました。(loopに入るとisPlayingがfalseに戻ってしまう)
根本的に修正することはできておりませんが、即席代替案として、ボタンをクリックする度にカウントアップを行い判断する形で解消しました。
```
var isPlayingnum = 1; //２の倍数なら再生中、それ以外は停止中

if (isPlayingnum % 2 != 0){
  await audioPlayer.pause();
}else{
  final player = AudioCache(prefix: 'assets/');
  final url = await player.load('roulette_bgm.mp3');
  await audioPlayer.play(url.path, isLocal: true);
}
```
# 終わりに😁
Twitterでも情報発信しておりますので、ぜひフォローお願い致します!
https://mobile.twitter.com/tatsuki_kt

# 全コード
```
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final audioPlayer = AudioPlayer();
  bool isPlaying = false; //再生中か否かを判断する

  @override
  void initState() {
    super.initState();
    audioPlayer.setReleaseMode(ReleaseMode.LOOP);

    audioPlayer.onPlayerStateChanged.listen((state) {
      setState(() {
        isPlaying = state == PlayerState.PLAYING;
      });
    });
    
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async{
          if (isPlaying){
            await audioPlayer.pause();
          }else{
            // audioPlayer.setReleaseMode(ReleaseMode.LOOP);
            final player = AudioCache(prefix: 'assets/');
            final url = await player.load('roulette_bgm.mp3');
            await audioPlayer.play(url.path, isLocal: true);
          }
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
```