低価格シングルコンピュータRaspberry piを使って、ハイレゾ・オーディオシステムを作成する「ラズパイ・オーディオ」が、オーディオファンの間で流行っているようですね。低価格でネットワーク対応の超高音質オーディオマシンが試せるのが魅力のようです。
5ドルのラズパイRaspberryPi Zeroが出た時に同好会メンバーそれぞれで購入したものの、何に使うか思いつかないまま放置していました。そのうちカメラ接続用のI/Fが搭載されたVersion1.3がリリースされ、これもまた同好会メンバーで即購入。最初に購入したゼロが完全に余ってしまいましたので、ちょっと改良して、ラズパイ・オーディオを楽しむことにしましょう。
しかもこのサイズ!これはもう、コンパクトなオーディオを作るしかないですよね!ということで次の目標を立てました。
- 超小型ラズパイ・オーディオ
- 当然ハイレゾ対応
- バッテリー内蔵
それではこれらをさくっと作ってしまいましょう。
まずはDAC選び。DAC(ダック)というのは、Digital/Analog converterの略。ラズパイに保存されたデジタルデータはそのままでは再生できないので、スピーカーで再生できるようにするために、デジタル信号をアナログ信号に変換するのがDACの仕事。このときの変換が音の決め手になります。
当然サイズの小さいながらも、高音質のものをチョイスしたいところ。ちょうど手元に、Zeroと一緒に購入したhatの中に(hatというのはHardware Attached on Topの事で、ラズパイにぽんと乗っければ使えるようになっている基盤の事です)pHAT DACがあったのでこれにしましょう。
pHAT DAC
そうそう、ゼロにはオーディオアウトが(HDMIだけしか)ないので不便だと思って買っておいたのでした。
このDACがなかなかの高性能で、筆者が愛用しているTEAC HA-P50-Bというポタアン(ポタアンってのはポータブル・アンプの事。持ち歩けるアンプですね)にも使われている、BurrBrown PCM5102の後継PCM5102Aがつかわれているのです。ってことは音の味付けはTEACのポタアンとほぼ同じって事です。どんな風に音の違いがでるか楽しみです。
また、このDACはI2S接続でラズパイとつながります。I2S(IC間サウンド)とは、IC間でデジタル音声データをシリアル転送するための規格で、通常、DACやADCといった、音響機器内部のIC間で音声デジタル信号を直接やり取りするための規格。
で、これが何がすごいのかというと、通常PCでハイレゾ・オーディオを楽しむためには、パソコンと外付けのDAC、そしてアンプとスピーカーを用意して、パソコンとDACを「USB」接続します。しかし、ラズパイゼロとpHAT DACを接続するのにUSBは使いません。ここがすごいところ。元々PCで外付けDACでは、やれUSBケーブルの相性だの、OSドライバがアシンクロナスモード対応してないだの、ドライバの出来に左右されるだの、といった色々面倒な気遣いが必要だったんですが、ラズパイ・オーディオではUSBを使わずIC間で直接やり取りするもっと「生」なデータで転送ができるわけで、より高品質なオーディオ再生が期待できるわけです。
次に、ポタアン化にあたり、ヘッドホンアンプが必要になります。値段も手頃でそこそこ音のいいものをチョイスしたいところ。外で気軽に高音質というのがコンセプトのポタアンにオーバースペックなアンプは必要ないでしょう。ちょうど秋月にポータブルヘッドホン用のアンプキットがあるのでこれを使用することにしました。
ポータブルヘッドフォンアンプキット
電源を用意するのは手間なので、適当なモバイルバッテリーと合わせる事にします。Zeroへの給電はUSBケーブル経由だと全体のサイズが大きくなってしまうため、モバイルバッテリーのUSBソケットの根本からラズパイに直接電源を接続します。電源のOFFをどうすのか、という点が心配になりますが、これはモバイルバッテリーに電源のON/OFFがあるため、問題ありません。
赤いコードが+
ちょこっとここで欲が出てきました。できれば、ディスプレイ表示も欲しいですよね。という訳で、LCDを購入。
Raspberry Pi用I2C接続のLCDキット
この製品はI2Cインタフェースになっており比較的に簡単に接続が可能です。
という訳で、準備が整いました。さて、組み上げて行きましょう。
まずはRaspberry pi zero と pHAT DACの接続です。
全部のピンを接続しちゃってもいいのですが、基盤を見ながら、必要そうなやつだけ半田付けしていきます。まずはI2Sは必須ですね、あとは電源。具体的には以下のピンをハンダ付けします。
Pin 1 (3.3V)
Pin 2 (5V)
Pin 12 (GPIO 18)
Pin 35 (GPIO 19)
Pin 39 (Ground)
Pin 40 (GPIO 21)
LCDもサイトの説明通りハンダ付けすればOK。I2Cなので接続する本数は信号線2本、電源2本の合計4本だけで済みます。
後はDACのLINE OUTをヘッドフォンアンプのLINE INへ接続します。
では、肝心のOS部分とプログラミング部分です。今回オーディオ用ディストリビューションとしてVolumioを採用しました。ただここで問題が発生。現状VolumioのイメージはRaspberry Pi Zeroに対応しておらず、起動しないことがわかりました。
対応としては、まずRaspberry Pi 2で起動し、アップデートを済ませてからZeroで起動する必要があります。結構面倒ですね。また、バージョンアップによりSambaのバージョンが上がり、動作しなくなります。これも面倒な修正が必要です。
まずは、Volumio 1.55 のイメージをダウンロードしましょう。
https://sourceforge.net/projects/volumio/files/Raspberry%20PI/1.5/Volumio1.55PI.img.zip/download
ダウンロードしたイメージを16GB SDHCカードに書き込みます。次はMacの場合の例です。rdisk2はSDカードの場所です。環境にあわせて変更する必要があります。間違った場所を指定すると、PCのデータが消えてしまうので十分に注意しましょう。SDカードを指す前と、差した後にそれぞれdf -hを実行して、差分がSDカードだとわかります。
df -h sudo diskutil unmount /dev/disk2s1 sudo dd bs=1m if=Volumio1.55PI.img of=/dev/rdisk2
このSDカードとRaspberry Pi 2で起動します。
su -
コマンドで rootになります。パスワードは volumio です。
次のコマンドを実行します。
apt-get -y update && apt-get -y upgrade && apt-get dist-upgrade && apt-get -y autoremove && apt-get -y autoclean
binutilsをインストールします。
apt-get install binutils
rpi-updateを実行します。
rpi-update
再起動します。しかし、エラーが発生してSMBが起動しません。次のコマンドで修正します。
apt-get install samba samba-doc samba-common smbclient
apt-get remove samba samba-doc samba-common smbclient --purge apt-get autoclean apt-get autoremove apt-get install samba samba-doc samba-common smbclient
これで下準備はOKです。poweroff後Raspberry Pi 2からSDカードを抜き、Pi Zeroに挿し直します。
無事起動したら、pHAT DACの設定を行います。
su - curl -sS get.pimoroni.com/phatdac | bash
パイゼロと同じネットワーク上のPCから、ラズパイのアドレスを打ち込んで volumioの画面を開きます。
設定します。
MENU > Systemを開きます。
I2S driverの項目で I2S DACにHifiberryを選択します。
MENU > Turn offを開きます。
REBOOTします。
16GBのSDHCを使いましたが、ほとんど使われていません。これを使えるようにしましょう。
volumio@volumio:~$ df -h Filesystem Size Used Avail Use% Mounted on /dev/root 1.5G 1.1G 379M 74% / devtmpfs 237M 0 237M 0% /dev tmpfs 49M 260K 48M 1% /run tmpfs 5.0M 4.0K 5.0M 1% /run/lock Ramdisk 256M 0 256M 0% /run/shm /dev/mmcblk0p1 75M 30M 46M 40% /boot
パーティションを用意
root@volumio:~# fdisk /dev/mmcblk0
root@volumio:~# fdisk /dev/mmcblk0 Command (m for help): p(現在のパーティションを確認) Disk /dev/mmcblk0: 15.8 GB, 15819866112 bytes 4 heads, 16 sectors/track, 482784 cylinders, total 30898176 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x00043284 Device Boot Start End Blocks Id System /dev/mmcblk0p1 * 2048 155647 76800 b W95 FAT32 /dev/mmcblk0p3 155648 3411967 1628160 83 Linux Command (m for help): n(新しいパーティションを作成) Partition type: p primary (2 primary, 0 extended, 2 free) e extended Select (default p): p(プライマリ) Partition number (1-4, default 2): 4(パーティション4) First sector (3411968-30898175, default 3411968): エンター押す Using default value 3411968 Last sector, +sectors or +size{K,M,G} (3411968-30898175, default 30898175): エンター押す Using default value 30898175 Command (m for help): p(結果を確認) Disk /dev/mmcblk0: 15.8 GB, 15819866112 bytes 4 heads, 16 sectors/track, 482784 cylinders, total 30898176 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x00043284 Device Boot Start End Blocks Id System /dev/mmcblk0p1 * 2048 155647 76800 b W95 FAT32 /dev/mmcblk0p3 155648 3411967 1628160 83 Linux /dev/mmcblk0p4 3411968 30898175 13743104 83 Linux Command (m for help): w(作業を書き込んで終了) The partition table has been altered! Calling ioctl() to re-read partition table. WARNING: Re-reading the partition table failed with error 16: Device or resource busy. The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8) Syncing disks.
再起動します。
reboot
再起動したら、次のコマンドで新規パーティションをフォーマットします。
mkfs.ext4 /dev/mmcblk0p4 volumio@volumio:~$ su - Password: root@volumio:~# mkfs.ext4 /dev/mmcblk0p4 mke2fs 1.42.12 (29-Aug-2014) Discarding device blocks: done Creating filesystem with 3435776 4k blocks and 860160 inodes Filesystem UUID: ce7a4f52-e1e6-4858-9cb4-27b43a74956a Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208 Allocating group tables: done Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done
パーティションのマウント設定を行います。
root@volumio:~# vi /etc/fstab # /etc/fstab: static file system information. # #/dev/mmcblk0p3 / ext4 noatime,discard,data=writeback,journal_async_commit,nouser_xattr,barrier=0,errors=remount-ro 0 1 /dev/mmcblk0p3 / ext4 noatime,nouser_xattr,errors=remount-ro 0 1 /dev/mmcblk0p1 /boot vfat utf8,user,rw,umask=111,dmask=000 0 0 /dev/mmcblk0p4 /mnt/USB ext4 defaults 0 0 Ramdisk /run/shm tmpfs defaults,size=256M,noexec,nodev,nosuid 0 0
設定を有効にするため再起動します。
reboot
13GBの領域が確保されました。
volumio@volumio:~$ df -h Filesystem Size Used Avail Use% Mounted on /dev/root 1.5G 1.1G 379M 74% / devtmpfs 237M 0 237M 0% /dev tmpfs 49M 264K 48M 1% /run tmpfs 5.0M 4.0K 5.0M 1% /run/lock Ramdisk 256M 0 256M 0% /run/shm /dev/mmcblk0p1 75M 30M 46M 40% /boot /dev/mmcblk0p4 13G 33M 13G 1% /mnt/USB
samba設定ファイルの変更
sambaの再インストールにより設定ファイルが書き換わっています。先ほど拡張したmicroUSBの領域が他のコンピュータからアクセスできるように設定しましょう。
nano /etc/samba/smb.conf
[share] comment = MPD directory (/mnt/USB/) path = /mnt/USB/ guest ok = yes read only = no writable = yes available = yes browsable = yes public = yes follow symlinks = yes wide links = yes create mode = 0777 directory mode = 0777 share modes = yes
LCDのインストール
sudo apt-get install python-smbus sudo apt-get install i2c-tools
volumio@volumio:~$ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
20が表示されていれば接続はOK
サンプルコードの実行 sudo apt-get update sudo apt-get install build-essential python-dev python-smbus python-pip git sudo pip install RPi.GPIO su - git clone https://github.com/adafruit/Adafruit_Python_CharLCD.git cd Adafruit_Python_CharLCD sudo python setup.py install
実行
cd examples sudo python char_lcd_plate.py
サンプルが実行されます。このサンプルを見ながら、LCDディスプレイに現在表示中の曲名を表示するプログラムを作成していきます。
ポイントは、Music Player Daemon(mpc)コマンドです。このコマンドで曲名の取得、次曲、前曲、再生、一時停止などを行います。
コードは次のようになりました。突貫で作成したので所々無駄なコードが残っています。
#!/usr/bin/python # Example using a character LCD plate. import time import os import sys import threading import commands import Adafruit_CharLCD as LCD import logging import time import subprocess import signal isLcdOn = True runFlg = True lcdTimer = None #logging.basicConfig(level=logging.DEBUG, # format='(%(threadName)-10s) %(message)s', # ) # Initialize the LCD using the pins lcd = LCD.Adafruit_CharLCDPlate() def lcd_off(): global lcdTimer lcd.set_backlight(0) lcdTimer=None def show_song(): while runFlg: # show song name. wait change event by 'mpc idle' command global idle global lcdTimer idle = subprocess.Popen('mpc idle player', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) sts = idle.communicate() if sts !='': st = commands.getoutput('mpc | kakasi -Jk -Hk -Kk -Ea -s -i utf-8 -o sjis') st = st.replace('(kigou)','-') spl=st.splitlines(True) if len(spl)== 3: song=spl[0].split(" - ",1) lcd.clear() lcd.message(song[1][0:16].strip() + '\n' + song[0][0:16].strip()) if not(lcdTimer is None): lcdTimer.cancel() lcdTimer=threading.Timer(5,lcd_off) lcdTimer.start() print('stop show_song thread') # create some custom characters lcd.create_char(1, [2, 3, 2, 2, 14, 30, 12, 0]) lcd.create_char(2, [0, 1, 3, 22, 28, 8, 0, 0]) lcd.create_char(3, [0, 14, 21, 23, 17, 14, 0, 0]) lcd.create_char(4, [31, 17, 10, 4, 10, 17, 31, 0]) lcd.create_char(5, [8, 12, 10, 9, 10, 12, 8, 0]) lcd.create_char(6, [2, 6, 10, 18, 10, 6, 2, 0]) lcd.create_char(7, [31, 17, 21, 21, 21, 21, 17, 31]) # Show some basic colors. lcd.set_color(1.0, 0.0, 0.0) lcd.clear() # Make list of button value, text, and backlight color. buttons = ( (LCD.SELECT, 'Play/Pause', 'mpc toggle'), (LCD.LEFT, 'Prev' , 'mpc prev'), (LCD.UP, 'LCD ON/OFF', ' '), (LCD.DOWN, 'POWER OFF ?\nYES NO' , 'mpc seek +00:00:10'), (LCD.RIGHT, 'Next' , 'mpc next') ) print('Press Ctrl-C to quit.') t=threading.Thread(target=show_song) t.daemon = True t.start() # do finish process when pressed Ctrl+C def func_stop(signal, handler): lcd.clear() lcd.set_color(0.0, 0.0, 0.0) runFlg = False idle.terminate() print('ext') time.sleep(1) sys.exit(0) signal.signal(signal.SIGINT, func_stop) signal.signal(signal.SIGTERM, func_stop) while True: # Loop through each button and check if it is pressed. for button in buttons: if lcd.is_pressed(button[0]): lcd.set_backlight(1) # Button is pressed, change the message and backlight. logging.debug(button[1]) if button[0]!=LCD.UP: lcd.clear() lcd.message(button[1]) #lcd.set_color(button[2][0], button[2][1], button[2][2]) if button[0]==LCD.UP: if isLcdOn==True: lcd.set_backlight(0) isLcdOn=False print('LCD OFF') else: lcd.set_backlight(1) isLcdOn=True print('LCD ON') elif button[0]==LCD.DOWN: while True: if lcd.is_pressed(LCD.LEFT): lcd.message('power off') time.sleep(0.5) lcd.set_backlight(0) os.system('poweroff') elif lcd.is_pressed(LCD.RIGHT): break else: os.system(button[2]) time.sleep(1.0)
Raspberry Pi Zeroの起動時にこのスクリプトを起動するようにしておけばバッチリです。
最初はアクリル板で作成していましたが、同好会メンバーが木箱を作ってくれました。木箱にあわせてアクリルをミラー調スプレーで塗装すると、かなりいい雰囲気がでました!
木製のケースに収めている所。ミラー調のアクリルと合わせていい雰囲気です。
音楽再生アプリケーションとしては定番のVolumioを使っています。そのため、Volumioでできることはひと通り出来ます。持ち歩かない場合にはネットワークオーディオとして楽しむことが出来ます。
・SDカード内の音楽ファイル再生
・USB接続されたストレージ内の音楽再生
・NAS上の音楽ファイル再生
・ネットラジオ
・DLNA対応
・Airplay対応
・ブラウザ等からコントロール可能
PCのブラウザやiPhoneから操作することも可能
さて、これで一通り完成です!今回はLCDディスプレイが結構大きくて、採用すべきかどうか最後まで悩みました。最終的には利便性を優先して採用しましたが、全体の半分近いサイズを占有しており、まだ満足してません。今後はLCDディスプレイを「電子ペーパー」に置き換え、劇的にコンパクトなプレイヤーに仕上げたいと画策中です!
[…] PHAT DACとZEROの組み合わせはココが分かりやすい? www.smartphone-zine.com ラズパイ・オーディオにチャレンジ!Pi:ゼロから始めるハイレゾ対応ポータブルアン…http://www.smartphone-zine.com/ […]