Phat Beat and piCorePlayer

So I got hold of a Phat Beat, a Pi Zero W and the image for the piCorePlayer [1] (which is based on TinyCore, I believe).
I have it all set up now and audio is streaming successfully. However, I’d like to be able to make use of the LEDs as a VU meter, but unfortunately the distro doesn’t make life easy for somebody wanting to build packages. I was woindering if there was any experience out there for making and installing the required software to get this up and running with a minimum of fuss. I’d be grateful for any pointers to the process.

Thanks in advance

[1] - https://sites.google.com/site/picoreplayer/home

any specialist distro whose scope would not be particularly concerned by handling access to the gpio is going to be a massive headache. I haven’t looked at PiCorePlayer before but suspect that is far from their design aims.

… and even if you get access to gpio, there is then the software layers required to get our pivumeter lib working, which the tool provided by the distro (to configure audio) may not be too happy sharing control of.

not what you want to hear I’m sure, but right now, the matter of the fact is that the smaller the demand the less likely we are to look into the nuts and bolts of a particular environment and see how it could work.

as a matter of interested, what specific features of PiCorePLayer made you settle on it?

No worries, thanks for at least reading. :)
I run the Logitech Media Server at home anyway for three or four network players. I bought into the ecosystem when it was still SlimP3 and I love it. This was just a distro that worked OOTB. I understand all the packages are available for installation on a Raspbian image so I may well try that instead, for the sake of a 6 quid SD card and a couple of hours of playing. I guess I’d be best upgrading to a full Pi3, so as soon as the Leeds Hackspace account is set up I’ll be placing a large order for stuff I don’t need and can’t afford. ;)

1 Like

OK, so a rebuild with a base install of raspbian lite (latest so I get the new firmware as well), install the squeezelite and LMS software, a bit of fiddling with python the deal with button presses on the Phat Beat and I’m almost set.

Still no LED VU meter, but I guess I can live without that for now - I did install the PahtBeat from the installer, and that did also install pivumeter, and set it up in /etc/asound.conf bit the software doesn’t seem to want to access the LEDs. It may be just a player thing - I don’t know.

edit setting the output card config to “pivumeter” got the LEDs working. :) Unfortunately it introduces a significant amount of low end noise to the sound output - almost like strong wind blowing across a mic type noise. I’ve reverted to having no VU.

hum, bizarre I can’t imagine why it would introduce noise… could be the high demand on CPU that does… something… @gadgetoid, any idea?

I’ll try to grab a quick “top”

Hmmm… Well…

Is now a good time to say that it might be cpu related, but probably down to a small python script I have running to monitor button presses on the Phat? Stopping my script fixes things.

Blooming Heck.

Could you post the script here? Use code formatting:

```
your code here
```

Just rebooting into the machine of doom to pull out the script of shame…

Bear in mind I’m still learning python, and physical hardware ain’t my thing. I hide behind abstractions a lot in my day job (C#)

Also, fwd and rev buttons seem to be reversed (based on the pinout diagram at https://pinout.xyz/pinout/phat_beat vs. the diagram on the board.

import RPi.GPIO as GPIO
import time
import urllib

GPIO.setmode(GPIO.BCM)

GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(6, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)

isPlaying = False
isOn = True;

def SendSlimRequest(requestBody):
	f = urllib.urlopen("http://127.0.0.1:9000/jsonrpc.js", requestBody)
	print f.read()


while True:
    input_state = GPIO.input(6)
    if input_state == False:
        print('Play/Pause')
	    if isPlaying == False:
            SendSlimRequest("{\"method\":\"slim.request\",\"id\":1,\"params\":[\"b8:27:eb:9c:3c:8e\",[\"play\"]],\"result\":{}}")
            isPlaying = True
        else:
            SendSlimRequest("{\"method\":\"slim.request\",\"id\":1,\"params\":[\"b8:27:eb:9c:3c:8e\",[\"pause\"]],\"result\":{}}")
            isPlaying = False
	time.sleep(0.2)

    power_state = GPIO.input(12)
    if power_state == False:
        print "Power"
        if isOn == False:
                SendSlimRequest("{\"id\":1,\"method\":\"slim.request\",\"params\":[\"b8:27:eb:9c:3c:8e\",[\"power\",\"1\"]]}")
                isOn = True
        else:
                SendSlimRequest("{\"id\":1,\"method\":\"slim.request\",\"params\":[\"b8:27:eb:9c:3c:8e\",[\"power\",\"0\"]]}")
                isOn = False
        time.sleep(0.2)

    ff_state = GPIO.input(5)
    if ff_state == False:
        print "Fast Forward"
        SendSlimRequest("{\"method\":\"slim.request\",\"result\":{},\"id\":1,\"params\":[\"b8:27:eb:9c:3c:8e\",[\"button\",\"jump_fwd\"]]}")
        time.sleep(0.2)

    rw_state = GPIO.input(13)
    if rw_state == False:
        print "Rewind"
        SendSlimRequest("{\"method\":\"slim.request\",\"result\":{},\"id\":1,\"params\":[\"b8:27:eb:9c:3c:8e\",[\"button\",\"jump_rew\"]]}")
        time.sleep(0.2)

    volup_state = GPIO.input(16)
    if volup_state == False:
        print "Volume Up"
        SendSlimRequest("{\"id\":1,\"method\":\"slim.request\",\"params\":[\"b8:27:eb:9c:3c:8e\",[\"mixer\",\"volume\",\"+5\"]]}")
        time.sleep(0.2)

    voldown_state = GPIO.input(26)
    if voldown_state == False:
        print "Volumne Down"
        SendSlimRequest("{\"id\":1,\"method\":\"slim.request\",\"params\":[\"b8:27:eb:9c:3c:8e\",[\"mixer\",\"volume\",\"-5\"]]}")
        time.sleep(0.2)

hum, no I think it’s correct… but I can see why you would think that… the silk screen is quite misleading as the Play/Pause symbol is upside down. I think it is very confusing yes.

1 Like

Good spot! I’ll take the blame for this, as we flipped the whole board 180 degrees a few days before sending the PCBs off for production. We’ll try to tweak it for the next batch. :-)

It isn’t a problem as I’ll probably be taking the buttons off and linking to externally mounted ones anyways…

Oh for crying out loud. No wonder I was hogging all the CPU I could find - it was only "sleep"ing when it detcted a button press. The rest of the time it was looping like crazy. Refactored code (with a time.sleep(0.1) and event detection brings CPU down from “whatever I can grab” to 0.2%.

Learning curve.

import RPi.GPIO as GPIO
import time
import urllib

isPlaying = False
isOn = True;
requestBody = ""

GPIO.setmode(GPIO.BCM)

GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(6, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def SendSlimRequest(requestType):
	f = urllib.urlopen("http://127.0.0.1:9000/jsonrpc.js", requestType)
	print f.read()

def myCallback(channel):
  global isPlaying
  global isOn
  global requestBody

  if channel == 6:
    if isPlaying == False:
      requestBody = "{\"method\":\"slim.request\",\"id\":1,\"params\":[\"b8:27:eb:9c:3c:8e\",[\"play\"]],\"result\":{}}"
      isPlaying = True
    else:
      requestBody = "{\"method\":\"slim.request\",\"id\":1,\"params\":[\"b8:27:eb:9c:3c:8e\",[\"pause\"]],\"result\":{}}"
      isPlaying = False

  if channel == 12:
    if isOn == False:
      requestBody = "{\"id\":1,\"method\":\"slim.request\",\"params\":[\"b8:27:eb:9c:3c:8e\",[\"power\",\"1\"]]}"
      isOn = True
    else:
      requestBody = "{\"id\":1,\"method\":\"slim.request\",\"params\":[\"b8:27:eb:9c:3c:8e\",[\"power\",\"0\"]]}"
      isOn = False

  if channel == 5:
    requestBody = "{\"method\":\"slim.request\",\"result\":{},\"id\":1,\"params\":[\"b8:27:eb:9c:3c:8e\",[\"button\",\"jump_fwd\"]]}"

  if channel == 13:
    requestBody = "{\"method\":\"slim.request\",\"result\":{},\"id\":1,\"params\":[\"b8:27:eb:9c:3c:8e\",[\"button\",\"jump_rew\"]]}"

  if channel == 16:
    requestBody = "{\"id\":1,\"method\":\"slim.request\",\"params\":[\"b8:27:eb:9c:3c:8e\",[\"mixer\",\"volume\",\"+5\"]]}"

  if channel == 26:
    requestBody = "{\"id\":1,\"method\":\"slim.request\",\"params\":[\"b8:27:eb:9c:3c:8e\",[\"mixer\",\"volume\",\"-5\"]]}"

  SendSlimRequest(requestBody)
  

GPIO.add_event_detect(5, GPIO.FALLING, callback=myCallback, bouncetime=200)
GPIO.add_event_detect(6, GPIO.FALLING, callback=myCallback, bouncetime=200)
GPIO.add_event_detect(13, GPIO.FALLING, callback=myCallback, bouncetime=200)
GPIO.add_event_detect(26, GPIO.FALLING, callback=myCallback, bouncetime=200)
GPIO.add_event_detect(12, GPIO.FALLING, callback=myCallback, bouncetime=50) 
GPIO.add_event_detect(16, GPIO.FALLING, callback=myCallback, bouncetime=50)

while True:
	pass
  time.sleep(0.1)
2 Likes

I have tried unsuccessfully to use the above examples to get music to play from LMS so I have used PyLMS (https://github.com/jinglemansweep/PyLMS) instead.

sudo pip install pylms
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
from pylms.server import Server
from pylms.player import Player

sc = Server(hostname="<LMS server>", port=9090, username="", password="")
sc.connect()

#print "Logged in: %s" % sc.logged_in
#print "Version: %s" % sc.get_version()

sq = sc.get_player("<MAC of Raspberry Pi")

GPIO.setmode(GPIO.BCM)

GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(6, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def myCallback(channel):
  if channel == 6:
    sq.toggle()
  if channel == 12:
    isOn = sq.get_power_state()
    if isOn:
        sq.set_power_state(0)
    else:
        sq.set_power_state(1)
  if channel == 5:
    sq.next()
  if channel == 13:
    sq.prev()
  if channel == 16:
    sq.volume_up(amount=5)
  if channel == 26:
    sq.volume_down(amount=5)

GPIO.add_event_detect(5, GPIO.FALLING, callback=myCallback, bouncetime=200)
GPIO.add_event_detect(6, GPIO.FALLING, callback=myCallback, bouncetime=200)
GPIO.add_event_detect(13, GPIO.FALLING, callback=myCallback, bouncetime=200)
GPIO.add_event_detect(26, GPIO.FALLING, callback=myCallback, bouncetime=200)
GPIO.add_event_detect(12, GPIO.FALLING, callback=myCallback, bouncetime=50) 
GPIO.add_event_detect(16, GPIO.FALLING, callback=myCallback, bouncetime=50)

while True:
	pass
time.sleep(0.2)

Change to the address of the server and to the MAC address of the player which can be found using ifconfig.

I’m hoping to rewrite the code for changing the volume so that the VU meter shows the volume whilst the buttons are being used.

There’s a pending update to Pi VU Meter which allows you to stream the VU data across to a Python script that can potentially then switch between showing volume/status/VU info on the LEDs. Here’s the pHAT BEAT script: https://github.com/pimoroni/pivumeter/blob/devel/python_server/examples/phatbeat-server.py

You need to build/install the devel branch of Pi VU Meter and use the “socket” output device for these to work.

If you can retrieve the current volume, that may also help for scaling the VU better to low volumes- I still haven’t found a satisfactory fix to that problem.

For anyone coming across this as I did just to let you know the hyperpixel display works fine with piCorePlayer.
Just clone the HyperPixel4 repository
mount the boot partition to allow editing of config.txt (instructions elsewhere)
tweak the install.sh script to point at the right place for \boot
run the installer
then hyperpixel4-init gets the display going