PythonのKivyで音楽プレイヤー




# はじめに

[Kivyで、シンプルなミュージックプレイヤー① - naritoブログ](https://torina.top/detail/302/)

[Kivyで、シンプルなミュージックプレイヤー② - naritoブログ](https://torina.top/detail/303/)

こちらの記事を参考にちょい足ししました。

![clipboard01](https://user-images.githubusercontent.com/8291395/40877855-852b3700-66c2-11e8-92f5-8d9c407d3063.jpg)

例のごとくコードはGitHubに。

[https://github.com/mkgask/kivySimplePlayer/tree/v0.1](https://github.com/mkgask/kivySimplePlayer/tree/v0.1)

スクリーンショットの通り想定環境はWindowsですが、日本語フォントの表示以外は他のOSも同等のはずです。
Python 3.6.5、kivy 1.10.0 で作成しました。

続きました。
[PythonのKivyで音楽プレイヤー その2 ファイル分割 - Qiita](https://qiita.com/mkgask/items/f2b0a8a23d0d11608f45)

*2018/06/03追記：GitHubでタグ切ったのでURL差し替え*
*2018/06/04追記：Python、kivyの利用バージョンを追加*
*2018/06/09追記：続きを書くことになるとは思ってませんでした*



# 参考ページの内容から変更した箇所

- ドラッグ＆ドロップでファイルの受け入れの追加
- Stopボタン追加
- 音量ボタンを音量バーに変更
- 日本語ファイル名の対応



### ドラッグ＆ドロップでファイルの受け入れの追加

```python:main.py（MusicPlayerクラスに追加）
    def __init__(self, **kwargs):
        print('__init__')
        super(MusicPlayer, self).__init__(**kwargs)

        self._file = Window.bind(
            on_dropfile = self._on_file_drop
        )

    def _on_file_drop(self, window, file_path):
        print('_on_file_drop')
        self.select(file_path.decode('utf-8'))
        return
```

D&Dで受け取れるファイル名はバイト文字列なので、Pythonが内部で利用できるようにdecode('utf-8')でunicodeにする必要があります。



### Stopボタン追加

```yml:mainwindow.kv
    Button:
        id: stop_button
        text: 'Stop'
        on_release: root.stop()
```

```python:main.py（MusicPlayerクラスに追加）
    def stop(self):
        print('stop')
        if self.is_playing:
            self._stop()

    def _stop(self, pause=False):
        print('_stop')

        self.sound.stop()
        Clock.unschedule(self._timer)

        if not pause:
            self.is_pausing = False
            self.is_playing = False
            self.pause_pos = 0
            self.time_bar.value = 0
            
            self.time_text.text = self._time_string(
                self.time_bar.value,
                self.lengh
            )

        self.play_button.text = 'Play'
        self.status.text = 'Stop {}'.format(self.sound_name)

    def _pause(self):
        print('_pause')
        self.pause_pos = self.sound.get_pos()
        self._stop(True)
        self.is_pausing = True
```

_stopと_pauseの切り分けがあまりうまく出来てなくて、_stop内でフラグ分けしてしまっています。
停止と一時停止の2パターン以上に停止の処理が増えることも考えられないですし、これだけ差があると完全に別処理にしてしまったほうが後々楽かもと思ってしまいますね。

ちなみにVS Codeのkvファイル用の拡張機能は、KivyとKvLangと2つあるのですが、
[Python Kivyの使い方②　～電卓を作成する～ - Qiita](https://qiita.com/dario_okazaki/items/910abf09344a60dd7823)
のkvファイルがKivyではシンタックスハイライトが崩れてしまい、うまく表示してくれませんでした。
一例だけで判断するのもあまり良くないのですが、今のところKivyは無効化してKvLangを使っています。
（Qiitaではkvのシンタックスハイライトが（まだ）無いようなので、本記事では一番綺麗に出るymlを指定しています）

*2018/06/03追記：_stopメソッドが残念な記述になっていたのを微調整*



### 音量ボタンを音量バーに変更

```yml:mainwindow.kv
    Label:
        id: volume_text
        text: '50'
    
    Slider:
        id: volume_bar
        max: 100
        value: 0
        on_value: root.volume_change(self.value)
```

```python:main.py（MusicPlayerクラスに追加）
    def volume_change(self, value):
        self._volume(value)

    def _volume(self, vol):
        print('_volume')
        vol = round(vol)
        vol_value = vol / 100

        self.volume_text.text = str(vol)
        self.volume_bar.value = vol

        if not self.sound:
            return

        self.sound.volume = vol_value
```

sound.volumeは0.0～1.0の正規化した値で受け取りますが、スライダーの数値は分かりやすく0～100としてあるので、そこの変換を入れてあります。



### 日本語ファイル名の対応

kvファイルの変更は不要でした。

```python:main.py
from kivy.core.text import LabelBase, DEFAULT_FONT
from kivy.resources import resource_add_path

resource_add_path('{}\\{}'.format(os.environ['SYSTEMROOT'], 'Fonts'))
LabelBase.register(DEFAULT_FONT, 'MSGOTHIC.ttc')
```

調べてみると、IPAやM+のフォントを配下ディレクトリに設置してーとやっている方が多いようだったのですが、システムフォルダにあるFontsフォルダから日本語フォント引っ張ればいいじゃん？ということでこの形に。
Windowsではこれでいけるのですが、ちょっと調べた感じではMacやLinuxではこの処理でフォントディレクトリのパスは取れなさそうなので、それぞれで対応が必要になりそうです。

メイリオはmeiryo.ttc、游ゴシックは4種類あって、YuGothB.ttc、YuGothM.ttc、YuGothL.ttc、YuGothR.ttcが使えますが、どれもあんまり綺麗に出ないです。
これらのフォントを使う場合はフォントレンダリングの処理も必要そうです。



# 問題点

### kivyのFileChooser

ディレクトリの選択は1クリックなのに、ファイルの選択はダブルクリックが必要で、普段のエクスプローラの操作ではダブルクリックでフォルダ移動してたので、私にはあまり直感的でなかったです。

この辺の操作体系は選べると嬉しいなぁというところです。

### 非アクティブ時のクリックが取れない

ウィンドウが非アクティブの時の最初の1クリックは、スライダーやボタンの操作が出来ず、ウィンドウをアクティブにするだけとなります。

Windowsアプリケーションでは操作が出来るところなので、これも出来れば改善して欲しいなぁと思います。


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">簡単に言うけどほならね、自分でやってみろって話ですよ（自分に刺していく</p>&mdash; みかげあすか (@mkgask) <a href="https://twitter.com/mkgask/status/997701183174131712?ref_src=twsrc%5Etfw">2018年5月19日</a></blockquote>


# Nuitkaの対応

Nuitkaのセットアップが終わっていれば、そのままコンパイル出来ます。

```sh
nuitka --mingw --recurse-none --run main.py
```


# 参考文献

[【Python Kivy】ドラッグ＆ドロップでファイルパス取得方法 - Qiita](https://qiita.com/AkihikoKumasaka/items/0c6c105362bab744decf)

[Window — Kivy 1.10.0 ドキュメント class kivy.core.window.WindowBase(**kwargs) on_dropfile(filename)]
(https://pyky.github.io/kivy-doc-ja/api-kivy.core.window.html?highlight=on_dropfile#kivy.core.window.WindowBase.on_dropfile)

[游フォントがとにかくややこしい話 - アセトアミノフェンの気ままな日常](http://d.hatena.ne.jp/acetaminophen/20160215/1455544209)

[kivyで日本語表示 - なんかメモ](http://yukirinmk2.hatenablog.com/entry/2014/06/02/220608)

[python3の四捨五入でハマったのでメモ - Qiita](https://qiita.com/sak_2/items/b2dd8bd1c4e4b0788e9a)

[python3で小数点以下を四捨五入で計算する簡単な方法 - Qiita](https://qiita.com/beatdown0514/items/361d6c213c2a1f2f5767)

[GitHubでREADME.mdに画像を使用したい - Qiita](https://qiita.com/brainya/items/06dd096e7ed1acce4b1e)

*2018/06/09追記：on_dropfieの参考文献を追加*