Pianohat & Drumhat causing error

Hello!
I am trying to use piano and drumhat together, so I did the wiring “by hand” on a breadboard. It worked, but the cables fell out. Now I rewired it, but both hats are disfunctional. I get a long errorlist on both hats, similar:


File “simple-piano.py”, line 14, in .
import pianohat
File “/usr/lib/python2.7/dist-packages/pianohat.py”,line 175 in <module|>
_piano_ctog = cap1xxx.Cap1188(i2c_addr=0x28, alert_pin=4)
File “/usr/lib/python2.7/dist-packages/cap1xxx.py”, line 282",in init
self.product_id = self._get_product_id()
File “/usr/lib/python2.7/dist-packages/cap1xxx.py”, line 486",in _get_product_id
return self._read_byte(R_PRODUCT_ID)
File “/usr/lib/python2.7/dist-packages/cap1xxx.py”, line 493",in read_byte
return self.i2c._read_byte_data(self.i2c_addr,register)
IO Error: [Errno5] Input/output error


Does anybody know what that means and where my mistake is? I checked the wiring about ten times (there was a mistake first, but now it´s set up correctly, I hope).

Thanks in advance, Stefan

I’ve bumped your user level to member; you should now be able to share some pictures of your setup.

Did you use pinout.xyz to figure out which pins need to be hooked up?

And what do you see if you run: sudo i2cdetect -y 1

Thanks for the reply! I was fearing that I have shorted the Hat when wiring everything up, but I checked, and found the problem. For anybody interested: My setup is a pi 2 with both piano and drumhat. Sound output is via usb soundcard. I ran into problems installing the usb-soundcard, but the tutorial from adafruit helped in the end:
https://cdn-learn.adafruit.com/downloads/pdf/usb-audio-cards-with-a-raspberry-pi.pdf (hope links are ok!?)
I changed the soundcard to default output and eventually the classic “sudo apt-get update/upgrade” pulled things off. Please note that on Jessie the usb-soundcard is configured dirfferently than on wheezy!

I did the wiring according to the pictures on pinout.xyz!

The Hat works now when I plug it in directly, I will get the wiring fixed now. Thank you for the support!

1 Like

Great news, thanks for keeping us updated :D Happy musical adventures ;)

Well, I am not done yet… I did the wiring and it seems OK (checked 10 times). The Drumhat works perfectly, playing audio over usb soundcard. (runing on Jessie). The Pianohat does not play sound. The LEDs light up and the software detects the keypresses!? I2cdetect shows 3 entries: “28” on 20:8, “2b” on 20:b and “2c” on 20:c.

On the console I get an error:

“Traceback (most recent calls last): File “simple-piano.py”, line 38, in pygame.mixer.init() pygame.error: No availiable audio device.”

Funny, since the drumhat plays OK. I found out that the pygame.mixer seems to be used with the pythonscript, but I have no idea what is wrong and how to fix it. Could somebody point me in the right direction please?

This seems to be because the Drum HAT is “consuming” the only available audio device. You cannot have two separate Python scripts both using pygame.mxier.init().

The trick would be to merge the Drum HAT and Piano HAT scripts into one. It shouldn’t be too tricky- start by pasting the Drum HAT script at the bottom of the Piano HAT script, and then remove any duplicate PyGame import and setup code.

I am a total noob, sry. How do you merge files? I used nano, but could not mark any text for copying. Also, I am wondering: do I need the “soundfiles” as well? Do i have to remove duplicate “import” lines also? Can I just put the new *.py file in a new directory together with the referenced soundfiles? And how?

Also funny: It used to work, so somehow the pygame.mixer managed to serve two scripts, didn´t it? Funny ol´ world… ;-)

Thank you!!!

if you are on jessie with a X environment I recommend you use Geany as a IDE, though you could use a combination of cat and nano if you don’t have access to the desktop environment.

by convention all imports should be at the top (of your collated script), and cleaning up duplicates makes sense.

samples should be brought along so that their relative location match what the script expect, so they should be next to the new script (though that could be tweaked as desired in the code if you wanted to restructure the folders).

It does not work.I did a clean new install from scratch, to make sure no old bugs keep messing things up. Then I merged both python scripts and cleaned them for duplicates. However, there is still only one hat actively playing sound at one time. Seperately they work perfectly, together they don´t. Could you please look at my code for the script? (not sure how to format!?)

    #!/usr/bin/env python

import glob
import os
import re
import signal
import time
from sys import exit

try:
import pygame
except ImportError:
exit("This script requires the pygame module\nInstall with: sudo pip install pygame")

import pianohat
import drumhat
DRUM_FOLDER = "drums2"

BANK = os.path.join(os.path.dirname(__file__), "sounds")

print("""
This example gives you a simple, ready-to-play instrument which uses .wav files.

For it to work, you must place directories of wav files in:

{}

We've supplied a piano and drums for you to get started with!

Press CTRL+C to exit.
""".format(BANK))

FILETYPES = ['*.wav', '*.ogg']
samples = []
files = []
octave = 0
octaves = 0

pygame.mixer.pre_init(44100, -16, 1, 512)
pygame.mixer.init()
pygame.mixer.set_num_channels(32)

patches = glob.glob(os.path.join(BANK, '*'))
patch_index = 0

if len(patches) == 0:
exit("Couldn't find any .wav files in: {}".format(BANK))
def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
return [int(text) if text.isdigit() else text.lower() for text in re.split(_nsre, s)]
def load_samples(patch):
global samples, files, octaves, octave
files = []
print('Loading Samples from: {}'.format(patch))
for filetype in FILETYPES:
files.extend(glob.glob(os.path.join(patch, filetype)))
files.sort(key=natural_sort_key)
octaves = len(files) / 12
samples = [pygame.mixer.Sound(sample) for sample in files]
octave = int(octaves / 2)
pianohat.auto_leds(True)
def handle_note(channel, pressed):
channel = channel + (12 * octave)
if channel &lt; len(samples) and pressed:
print('Playing Sound: {}'.format(files[channel]))
samples[channel].play(loops=0)
def handle_instrument(channel, pressed):
global patch_index
if pressed:
patch_index += 1
patch_index %= len(patches)
print('Selecting Patch: {}'.format(patches[patch_index]))
load_samples(patches[patch_index])
def handle_octave_up(channel, pressed):
global octave
if pressed and octave &lt; octaves:
octave += 1
print('Selected Octave: {}'.format(octave))
def handle_octave_down(channel, pressed):
global octave
if pressed and octave &gt; 0:
octave -= 1
print('Selected Octave: {}'.format(octave))
pianohat.on_note(handle_note)
pianohat.on_octave_up(handle_octave_up)
pianohat.on_octave_down(handle_octave_down)
pianohat.on_instrument(handle_instrument)

load_samples(patches[patch_index])

signal.pause()

_____________________
BANK = os.path.join(os.path.dirname(__file__), DRUM_FOLDER)

files = glob.glob(os.path.join(BANK, "*.wav"))
files.sort()
def handle_hit(event):
(#) event.channel is a zero based channel index for each pad
(#) event.pad is the pad number from 1 to 8
samples[event.channel].play(loops=0)
print("You hit pad {}, playing: {}".format(event.pad,files[event.channel]))

def handle_release():
pass

drumhat.on_hit(drumhat.PADS, handle_hit)
drumhat.on_release(drumhat.PADS, handle_release)

while True:
time.sleep(1)

Looks like your indentation went wrong there, but I think you need to drop signal.pause() since this stops the script, and nothing after this point will be run.

I can’t see any other gotchas yet so hopefully that will work!

It is funny: I removed the “signal.pause()” line. Called script, saw an error (not sure which one). Pianohat did not work. After some keypresses on the drumpad the pianohat started working. So I restarted to console, tried simple-piano.py and drums.py, both worked. Edited crontab to run the script for both hats @ reboot, rebooted and got pianosound from the drumhat while the pianohat only shows the leds @keypress. Checked if single scripts work: they do. Manually starting the combined script gives the following errormessage:

Loading Samples from: sounds/piano
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/cap1xxx.py", line 449, in _handle_alert
self._trigger_handler(x, inputs[x])
File "/usr/lib/python2.7/dist-packages/cap1xxx.py", line 463, in _trigger_handler
self.handlers[event][channel](CapTouchEvent(channel, event, self.input_delta[channel]))
File "/usr/lib/python2.7/dist-packages/pianohat.py", line 183, in <lambda>
_piano_ctog.on(x,event='press',  handler=lambda evt: _handle_event(0,evt,PRESSED ))
File "/usr/lib/python2.7/dist-packages/pianohat.py", line 72, in _handle_event
_on_note(channel, state)
File "beide.py", line 74, in handle_note
print('Playing Sound: {}'.format(files[channel]))
IndexError: list index out of range
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/cap1xxx.py", line 449, in _handle_alert
self._trigger_handler(x, inputs[x])
File "/usr/lib/python2.7/dist-packages/cap1xxx.py", line 463, in _trigger_handler
self.handlers[event][channel](CapTouchEvent(channel, event, self.input_delta[channel]))
File "/usr/lib/python2.7/dist-packages/pianohat.py", line 185, in <lambda>
_piano_atoc.on(x,event='press',  handler=lambda evt: _handle_event(1,evt,PRESSED ))
File "/usr/lib/python2.7/dist-packages/pianohat.py", line 72, in _handle_event
_on_note(channel, state)
File "beide.py", line 74, in handle_note
print('Playing Sound: {}'.format(files[channel]))
IndexError: list index out of range

Drat, I missed the line:

print('Playing Sound: {}'.format(files[channel]))

Which looks back at the files variable and, for the piano keys at least, expects it to be n elements long. Unfortunately the drum example is then replacing this variable and causing havoc.

You’ll need to rename the instances of files used in the Drum example to something different, like drum_files to avoid the variable clash.

I feel I should tweak these to make future combinations easier :D Specially after I setup Drum/Piano HAT carefully so they could work together.

Not sure if we are making progress or running in circles…

I did what you suggested as good as possible. This is what I used:

BANK = os.path.join(os.path.dirname(__file__), DRUM_FOLDER)

drum_files = glob.glob(os.path.join(BANK, "*.wav"))
drum_files.sort()

**(1)**    samples = [pygame.mixer.Sound(f) for f in drum_files]

def handle_hit(event):
# event.channel is a zero based channel index for each pad
# event.pad is the pad number from 1 to 8
samples[event.channel].play(loops=0)
**(2)**    print("You hit pad {}, playing: {}".format(event.pad,drum_files[event.channel]))

def handle_release():
pass

drumhat.on_hit(drumhat.PADS, handle_hit)
drumhat.on_release(drumhat.PADS, handle_release)

while True:
time.sleep(1)

OK… This is what happened: Initially the line marked with (1) was missing, since you first told me to remove it due to double usage of alsamixer. What both hats did was to play pianosound. The drumhat too. So I added line (1), which got me back to square 1 (only this time the other way around): pianohat working, drumhat not working.

I was not sure if I had to change line (2), but I tried both and it did not make a difference.

As you can see I am not a programmer, not much idea what I am doing.

Awww. You were making some great progress and I hope you’d make it. For someone who’s not a programmer you did pretty well, though!

Answer on the back page:

#!/usr/bin/env python

import glob
import os
import re
import signal

try:
    import pygame
except ImportError:
    exit("This script requires the pygame module\nInstall with: sudo pip install pygame")

import pianohat
import drumhat


PIANO_BANK = os.path.join(os.path.dirname(__file__), "sounds")

print("""
This example gives you a simple, ready-to-play instrument which uses .wav files.

For it to work, you must place directories of wav files in:

{}

We've supplied a piano and drums for you to get started with!

Press CTRL+C to exit.
""".format(PIANO_BANK))

FILETYPES = ['*.wav', '*.ogg']
samples = []
files = []
octave = 0
octaves = 0

pygame.mixer.pre_init(44100, -16, 1, 512)
pygame.mixer.init()
pygame.mixer.set_num_channels(32)

patches = glob.glob(os.path.join(PIANO_BANK, '*'))
patch_index = 0

if len(patches) == 0:
    exit("Couldn't find any .wav files in: {}".format(BANK))


def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
    return [int(text) if text.isdigit() else text.lower() for text in re.split(_nsre, s)]


def load_samples(patch):
    global samples, files, octaves, octave
    files = []
    print('Loading Samples from: {}'.format(patch))
    for filetype in FILETYPES:
        files.extend(glob.glob(os.path.join(patch, filetype)))
    files.sort(key=natural_sort_key)
    octaves = len(files) / 12
    samples = [pygame.mixer.Sound(sample) for sample in files]
    octave = int(octaves / 2)


pianohat.auto_leds(True)


def handle_note(channel, pressed):
    channel = channel + (12 * octave)
    if channel < len(samples) and pressed:
        print('Playing Sound: {}'.format(files[channel]))
        samples[channel].play(loops=0)


def handle_instrument(channel, pressed):
    global patch_index
    if pressed:
        patch_index += 1
        patch_index %= len(patches)
        print('Selecting Patch: {}'.format(patches[patch_index]))
        load_samples(patches[patch_index])


def handle_octave_up(channel, pressed):
    global octave
    if pressed and octave < octaves:
        octave += 1
        print('Selected Octave: {}'.format(octave))


def handle_octave_down(channel, pressed):
    global octave
    if pressed and octave > 0:
        octave -= 1
        print('Selected Octave: {}'.format(octave))


pianohat.on_note(handle_note)
pianohat.on_octave_up(handle_octave_up)
pianohat.on_octave_down(handle_octave_down)
pianohat.on_instrument(handle_instrument)

load_samples(patches[patch_index])



DRUM_FOLDER = "drums2"

print("""This example lets you play the drums with Drum HAT!

Pads are mapped like so:

7 = Rim hit, 1 = Whistle, 2 = Clash
6 = Hat,     8 = Clap,   3 = Cowbell
      5 = Snare,   4 = Base

Press CTRL+C to exit!
""")

DRUM_BANK = os.path.join(os.path.dirname(__file__), DRUM_FOLDER)

drum_files = glob.glob(os.path.join(DRUM_BANK, "*.wav"))
drum_files.sort()

drum_samples = [pygame.mixer.Sound(f) for f in drum_files]

def handle_hit(event):
    # event.channel is a zero based channel index for each pad
    # event.pad is the pad number from 1 to 8
    drum_samples[event.channel].play(loops=0)
    print("You hit pad {}, playing: {}".format(event.pad,drum_files[event.channel]))

def handle_release():
    pass

drumhat.on_hit(drumhat.PADS, handle_hit)
drumhat.on_release(drumhat.PADS, handle_release)

signal.pause() 

Oh dear. It’s really addictive to play!

1 Like

Cool, thank you! I needed to setup everything again because windows killed the sd card when I tried to do a backup. But now it works!!!

For anybody interested:
-install jessie with gui
-in gui select usb soundcard
-via console install pianohat and drumhat, full install
-copy files from Pimoroni/pianohat/examples/ and Pimoroni/drumhat/examples/ in new folder
-make new file in this folder with code above: *.py
-edit crontab to @reboot python ~/new_folder/new_script.py
-sudo raspi-config -> boot to console with autologin

Reboot and play around…

2 Likes