Closed yoshakami closed 2 years ago
Is this happening on linux? If so there might be issues with permissions for opening the usb port. Try running with sudo and see if it works. If it does, then you need to add extra permissions to the user running the script to make it work without sudo (should be similar to step 4 in these instructions)
ah, I forgot to mention I'm on Windows 10 and Python 3.9.9
I got some ideas to find out why, I've put some print in push2_python/display.py and I found that it's executing this code (meanwhile lighting up pads and launching functions when pressing buttons work well)
def send_to_display(self, prepared_frame):
if self.usb_endpoint is None:
try:
self.configure_usb_device()
except Push2USBDeviceNotFoundas e:
print("Push2USBDeviceNotFound") #it prints this out
log_error = False
if self.push.simulator_controller is not None:
[....]
else:
log_error = True
print("else") # it prints this out
if log_error:
print(e)
logging.error('Could not initialize Push 2 Display: {0}'.format(e))
Hi again, It could be then that the expected name of the MIDI device in Windows is not correct. I never tested on windows so I'm not sure about that. This is the function which checks whether a MIDI device port name corresponds to Push or not: https://github.com/ffont/push2-python/blob/884a3f06fdf4d78d0e99afc9a7cf6623bb7622d1/push2_python/constants.py#L14-L34
If you add some prints in the elif platform.system() == "Windows":
(for example print port_name
) you can probably see what is failing and update the logic so that it works properly.
still cannot make it run, thanks for pointing out this function, as it appears you've swapped out user port and live port names for both in and out, but putting them to something random makes the pad colour fonction no longer work, so I guess they're the right name as specified in the documentation, though "Ableton Push 2" and "Ableton Push" both work for both midi live port names
also, after this function, usb_device is equal to none (in display.py / configure_usb_device)
usb_device = usb.core.find(idVendor=ABLETON_VENDOR_ID, idProduct=PUSH2_PRODUCT_ID)
yeah the main problem isn't the midi ports as the display isn't a midi signal as the documentation says here https://github.com/Ableton/push-interface/blob/master/doc/AbletonPush2MIDIDisplayInterface.asc#12-architecture-overview
it's rather than the whole list(usb.core.find(find_all=True))
is an empty list
OH WOW, thanks for responding, I found out the only little problem is that you've swapped out the midi port names, these should be the corrected functions
def is_push_midi_in_port_name(port_name, use_user_port=False):
"""Returns True if the given 'port_name' is the MIDI port name corresponding to Push2 MIDI
input for the current OS platform. If 'use_user_port', it will check against Push2 User port instead
of Push2 Live port.
See https://github.com/Ableton/push-interface/blob/master/doc/AbletonPush2MIDIDisplayInterface.asc#21-midi-interface-access
"""
if platform.system() == "Linux":
if not use_user_port:
return 'Ableton Push' in port_name and port_name.endswith(':0') # 'Ableton Push 2 nn:0', with nn being a variable number
else:
return 'Ableton Push' in port_name and port_name.endswith(':1') # 'Ableton Push 2 nn:1', with nn being a variable number
elif platform.system() == "Windows":
if not use_user_port:
print("live port on windows")
return 'Ableton Push 2' in port_name # 'Ableton Push 2 nn', with nn being a variable number
else:
print("user port on windows")
return 'MIDIIN2 (Ableton Push 2)' in port_name # 'MIDIIN2 (Ableton Push 2) nn', with nn being a variable number
else: #macOS
if not use_user_port:
return 'Ableton Push 2 Live Port' in port_name
else:
return 'Ableton Push 2 User Port' in port_name
def is_push_midi_out_port_name(port_name, use_user_port=False):
"""Returns True if the given 'port_name' is the MIDI port name corresponding to Push2 MIDI
output for the current OS platform. If 'use_user_port', it will check against Push2 User port instead
of Push2 Live port.
See https://github.com/Ableton/push-interface/blob/master/doc/AbletonPush2MIDIDisplayInterface.asc#21-midi-interface-access
"""
if platform.system() == "Linux":
if not use_user_port:
return 'Ableton Push' in port_name and port_name.endswith(':0') # 'Ableton Push 2 nn:0', with nn being a variable number
else:
return 'Ableton Push' in port_name and port_name.endswith(':1') # 'Ableton Push 2 nn:1', with nn being a variable number
elif platform.system() == "Windows":
if not use_user_port:
return 'Ableton Push 2' in port_name # 'Ableton Push 2 nn', with nn being a variable number
else:
return 'MIDIOUT2 (Ableton Push 2)' in port_name # 'MIDIIN2 (Ableton Push 2) nn', with nn being a variable number
else: #macOS
if not use_user_port:
return 'Ableton Push 2 Live Port' == port_name
else:
return 'Ableton Push 2 User Port' == port_name
tested on Windows and working perfectly :D
this is the link that made me think it's a py_usb silent fail not finding any libusb-1.0.dll
https://stackoverflow.com/questions/8555930/pyusb-cant-find-device
if anyone on windows ever wants to display a static frame on push2, you'll need to paste "libusb-1.0.dll" in a folder contained in the PATH variable, such as "C:/Windows" or "C:/Windows/System32"
you can find this dll in "C:\ProgramData\Ableton\\
NOTE: as specified in ableton documentation, a frame will only last 2 seconds then drop off to a black screen, so you'll need to send the same one before 2 seconds each time
by the way, you don't need git to install this repo, you can put the folder on your local machine then run pip install ./push2-python-master
./ before the folder name specifies it's a relative path that pip will not search online
Glad so see you got it working! Do you want to make a PR with the change of port names in windows?
I can make one, I've also been making a function to save a prepared frame to get over encoding the same frame each time
I'm running on linux and facing permission difficulties for sending to the display...
usb.core.USBError: [Errno 13] Access denied (insufficient permissions)
Can light up the pads just fine, already had a lot of fun with that so thanks for this lib!
I'm also not receiving the inputs on callback apparently... could you give me a clue on how to continue? did you have to register push2-python as a service like in pysha? I tried adding a rule in etc/udev/rules.d/50-push2.rules and following those instructions but found no success.
Thanks!
Hi,
Did you try running as root to see if it works and confirm it is a permissions issue? If that is the case maybe you need some alternative to the etc/udev/rules.d/50-push2.rules
trick, but something like that should work.
About the callbacks this is a bit strange as if you're able to set pads and therefore communicate with Push successfully, you should be receiving callbacks as well. Are you sure your "app loop" is correct? Are you running the code from some of the examples?
let me know how it goes...
Hi,
Did you try running as root to see if it works and confirm it is a permissions issue? If that is the case maybe you need some alternative to the
etc/udev/rules.d/50-push2.rules
trick, but something like that should work.About the callbacks this is a bit strange as if you're able to set pads and therefore communicate with Push successfully, you should be receiving callbacks as well. Are you sure your "app loop" is correct? Are you running the code from some of the examples?
let me know how it goes...
I resumed yesterday developings with your library and found that when triggering events with the simulation page everything works, but not with the code from the examples.... got stuck with that, but the images are displayed correctly when triggering the display event with an event from the simulator! can't get it to work yet with the push2 itself. For example this example code:
@push2_python.on_button_pressed(push2_python.constants.BUTTON_PLAY)
def on_play_pressed(push):
print('Play!')
doesn't work in the context of a code snippet with a while True loop that is correctly lighting up pads:
import push2_python
import random
import numpy
from PIL import Image
import time
# Init Push2
push = push2_python.Push2(run_simulator=True)
print(dir(push))
# Define util function to generate a frame with some colors to be shown in the display
# Frames are created as matrices of shape 960x160 and with colors defined in bgr565 format
# This function is defined in a rather silly way, could probably be optimized a lot ;)
def generate_3_color_frame():
colors = ['{b:05b}{g:06b}{r:05b}'.format(
r=int(31*random.random()), g=int(63*random.random()), b=int(31*random.random())),
'{b:05b}{g:06b}{r:05b}'.format(
r=int(31*random.random()), g=int(63*random.random()), b=int(31*random.random())),
'{b:05b}{g:06b}{r:05b}'.format(
r=int(31*random.random()), g=int(63*random.random()), b=int(31*random.random()))]
colors = [int(c, 2) for c in colors]
line_bytes = []
for i in range(0, 960): # 960 pixels per line
if i <= 960 // 3:
line_bytes.append(colors[0])
elif 960 // 3 < i <= 2 * 960 // 3:
line_bytes.append(colors[1])
else:
line_bytes.append(colors[2])
frame = []
for i in range(0, 160): # 160 lines
frame.append(line_bytes)
return numpy.array(frame, dtype=numpy.uint16).transpose()
# Pre-generate different color frames
color_frames = list()
for i in range(0, 20):
color_frames.append(generate_3_color_frame())
# Now crate an extra frame which loads an image from a file. Image must be 960x160 pixels.
img = Image.open('test.png') #_img_960x160.png')
frame = numpy.array(img)
frame = frame/255 # Convert rgb values to [0.0, 1.0] floats
# Now lets configure some action handlers which will display frames in Push2's display in
# reaction to pad and button presses
@push2_python.on_pad_pressed()
def on_pad_pressed(push, pad_n, pad_ij, velocity):
print("pad PRESSED")
# Display one of the three color frames on the display
random_frame = random.choice(color_frames)
push.display.display_frame(random_frame)
@push2_python.on_button_pressed()
def on_button_pressed(push, button_name):
print("button PRESSED")
# Display the frame with the loaded image
push.display.display_frame(frame, input_format=push2_python.constants.FRAME_FORMAT_RGB)
@push2_python.on_button_pressed(push2_python.constants.BUTTON_PLAY)
def on_play_pressed(push):
print('Play!')
# Start infinite loop so the app keeps running
print('App runnnig...')
colors = ['black','orange','yellow','turquoise','dark_gray','purple','pink','light_gray','white','light_gray','dark_gray','blue', 'green','red', 'white']
import numpy
#push.display.display_frame(numpy.array(img,dtype=numpy.uint16), input_format=push2_python.constants.FRAME_FORMAT_RGB)
@push2_python.on_touchstrip()
def on_touchstrip(push, value):
print('Touchstrip touched with value', value)
color = "green"
while True:
push.buttons.set_all_buttons_color("white")
for i in range(0,8):
for j in range(0,8):
pad_ij = (i, j) # Fourth pad of the top row
color = random.choice(colors)
push.pads.set_pad_color(pad_ij,color=color)
time.sleep(.1)
the code example provided in the readme gives out this error. I tried some workarounds to get the display working such as turning it off then on once the program is launched, or displaying a png, trying to set "use the user port" to false, but it's the same result
here's the full code, I made some edits so it would run without pressing any button (sorry about the extension, github restricts the file extension we can upload lol) push2-display-example.txt