.. note::

    こんにちは、SunFounderのRaspberry Pi & Arduino & ESP32愛好家コミュニティへようこそ！Facebook上でRaspberry Pi、Arduino、ESP32についてもっと深く掘り下げ、他の愛好家と交流しましょう。

    **参加する理由は？**

    - **エキスパートサポート**：コミュニティやチームの助けを借りて、販売後の問題や技術的な課題を解決します。
    - **学び＆共有**：ヒントやチュートリアルを交換してスキルを向上させましょう。
    - **独占的なプレビュー**：新製品の発表や先行プレビューに早期アクセスしましょう。
    - **特別割引**：最新製品の独占割引をお楽しみください。
    - **祭りのプロモーションとギフト**：ギフトや祝日のプロモーションに参加しましょう。

    👉 私たちと一緒に探索し、創造する準備はできていますか？[|link_sf_facebook|]をクリックして今すぐ参加しましょう！

.. _4.1.2_py:

4.1.2 ミュージックプレイヤー
===============================

はじめに
--------------------

プロジェクト :ref:`3.1.3_py` では、スピーカーで曲を再生しました。今回は、音楽の再生/一時停止と音量を制御するための3つのボタンを追加します。

必要な部品
------------------------------

このプロジェクトで必要なコンポーネントは以下の通りです。

.. image:: ../img/musicplayer_list.png
  :width: 800
  :align: center

一式をまとめて購入するのが便利です。リンクはこちら：

.. list-table::
    :widths: 20 20 20
    :header-rows: 1

    *   - 名前
        - このキットのアイテム
        - リンク
    *   - Raphael Kit
        - 337
        - |link_Raphael_kit|

以下のリンクから個別に購入することもできます。

.. list-table::
    :widths: 30 20
    :header-rows: 1

    *   - コンポーネントの紹介
        - 購入リンク
    *   - :ref:`cpn_gpio_board`
        - |link_gpio_board_buy|
    *   - :ref:`cpn_breadboard`
        - |link_breadboard_buy|
    *   - :ref:`cpn_wires`
        - |link_wires_buy|
    *   - :ref:`cpn_resistor`
        - |link_resistor_buy|
    *   - :ref:`cpn_audio_speaker`
        - \-
    *   - :ref:`cpn_button`
        - |link_button_buy|

回路図
-----------------------

============ ======== ======== ===
T-Board Name physical wiringPi BCM
GPIO17       ピン11   0        17
GPIO18       ピン12   1        18
GPIO27       ピン13   2        27
============ ======== ======== ===

.. image:: ../img/3.1.16_schematic.png
   :width: 600
   :align: center

実験手順
------------------------------

**ステップ1:** 回路を組み立てる。

.. image:: ../img/3.1.16fritzing.png
  :width: 800
  :align: center

上記の図に従って回路を組み立てたら、Raspberry Piの3.5mmオーディオジャックにオーディオケーブルを挿入します。

.. image:: ../img/audio4.png
    :width: 400
    :align: center

**ステップ2:** コードのフォルダに移動する。

.. raw:: html

   <run></run>

.. code-block::

    cd ~/raphael-kit/python/

**ステップ3:** 実行する。

.. raw:: html

   <run></run>

.. code-block::

    python3 4.1.2_MusicPlayer.py

コードが実行された後、Raspberry Piは ``~/raphael-kit/music`` ディレクトリ内の ``my_music.mp3`` ファイルを再生します。

* ボタン1で音楽を一時停止/再生します。
* ボタン2で音量を下げます。
* ボタン3で音量を上げます。

他の音楽ファイルをRaspberry Piにアップロードしたい場合は、 :ref:`Filezilla Software` を参照してください。

**コード**

.. note::
    以下のコードは **修正/リセット/コピー/実行/停止** が可能です。ただし、それに先立って、 ``raphael-kit/python`` のようなソースコードのパスに移動する必要があります。コードを修正した後、直接実行して効果を確認することができます。

.. raw:: html

    <run></run>

.. code-block:: python

    from pygame import mixer
    import RPi.GPIO as GPIO
    import time
    import os
    user = os.getlogin()
    user_home = os.path.expanduser(f'~{user}')

    BtnPin1 = 18
    BtnPin2 = 17
    BtnPin3 = 27
    volume = 0.7

    status = False
    upPressed = False
    downPressed = False
    playPressed = False

    def setup():
        mixer.init()
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(BtnPin1, GPIO.IN, GPIO.PUD_UP)
        GPIO.setup(BtnPin2, GPIO.IN, GPIO.PUD_UP)
        GPIO.setup(BtnPin3, GPIO.IN, GPIO.PUD_UP)

    def clip(x,min,max):
        if x < min:
            return min
        elif x > max:
            return max
        return x

    def play(pin):
        global playPressed
        playPressed = True

    def volDown(pin):
        global downPressed
        downPressed = True

    def volUp(pin):
        global upPressed
        upPressed = True

    def main():
        global volume, status
        global downPressed, upPressed, playPressed
        mixer.music.load(f'{user_home}/raphael-kit/music/my_music.mp3')
        mixer.music.set_volume(volume)
        mixer.music.play()
        GPIO.add_event_detect(BtnPin1, GPIO.FALLING, callback=play)
        GPIO.add_event_detect(BtnPin2, GPIO.FALLING, callback=volDown)
        GPIO.add_event_detect(BtnPin3, GPIO.FALLING, callback=volUp)
        while True:
            if upPressed:
                volume = volume + 0.1
                upPressed = False
            if downPressed:
                volume = volume - 0.1
                downPressed = False
            if playPressed:
                if status:
                    mixer.music.pause()
                    status = not status
                else:
                    mixer.music.unpause()
                    status = not status
                playPressed = False
                time.sleep(0.5)
            volume = clip(volume,0.2,1)
            mixer.music.set_volume(volume)
            time.sleep(0.1)

    def destroy():
        # Release resource
        GPIO.cleanup()
        mixer.music.stop()

    # If run this script directly, do:
    if __name__ == '__main__':
        setup()
        try:
            main()
        # When 'Ctrl+C' is pressed, the program 
        # destroy() will be  executed.
        except KeyboardInterrupt:
            destroy()

**コードの説明**

.. code-block:: python

    from pygame import mixer

    mixer.init()

``pygame`` ライブラリの ``Mixer`` メソッドをインポートし、メソッドを初期化します。

.. code-block:: python

    BtnPin1 = 18
    BtnPin2 = 17
    BtnPin3 = 27
    volume = 0.7

三つのボタンのピンポートを定義し、初期音量を0.7に設定します。

.. code-block:: python

    upPressed = False
    downPressed = False
    playPressed = False

``upPressed`` 、 ``downPressed`` 、 ``playPressed`` はすべて割り込みフラグであり、 ``True`` の場合に対応するタスクが実行されます。

.. code-block:: python

    def clip(x,min,max):
    if x < min:
        return min
    elif x > max:
        return max
    return x

``clip()`` 関数は、入力パラメータの上限と下限を設定するために使用されます。

.. code-block:: python

    GPIO.add_event_detect(BtnPin1, GPIO.FALLING, callback=play)
    GPIO.add_event_detect(BtnPin2, GPIO.FALLING, callback=volDown)
    GPIO.add_event_detect(BtnPin3, GPIO.FALLING, callback=volUp)

``BtnPin1`` 、 ``BtnPin2`` 、 ``BtnPin3`` のキー検出イベントを設定します。

* ``BtnPin1`` が押された場合、割り込み関数 ``play()`` が実行されます。
* ``BtnPin2`` が押された場合、割り込み関数 ``volDown()`` が実行されます。
* ``BtnPin3`` が押された場合、割り込み関数 ``volUp()`` が実行されます。

現象の画像
-----------------------

.. image:: ../img/4.1.2musicplayer.JPG
   :align: center
