Reading piano notes on Python - python

I'd like to listen to the port having my midi output device (a piano) with my RPi, running on Debian. I've looked into pygame.midi, I managed to listen to the port, but somehow can not extract all midi information. Please find code below [edited code snippet]
EDIT: Fixed, thanks a lot!

First of all you need to find out which device-id your keyboard has inside pygame. I wrote this little function to find out:
import pygame.midi
def print_devices():
for n in range(pygame.midi.get_count()):
print (n,pygame.midi.get_device_info(n))
if __name__ == '__main__':
pygame.midi.init()
print_devices()
It looks something like this:
(0, ('MMSystem', 'Microsoft MIDI Mapper', 0, 1, 0))
(1, ('MMSystem', '6- Saffire 6USB', 1, 0, 0))
(2, ('MMSystem', 'MK-249C USB MIDI keyboard', 1, 0, 0))
(3, ('MMSystem', 'Microsoft GS Wavetable Synth', 0, 1, 0))
From the pygame manual you can learn that the first One inside this info-tuple determines this device as a suitable Input-Device.
So let's read some data from it in an endless-loop:
def readInput(input_device):
while True:
if input_device.poll():
event = input_device.read(1)
print (event)
if __name__ == '__main__':
pygame.midi.init()
my_input = pygame.midi.Input(2) #only in my case the id is 2
readInput(my_input)
That shows:
[[[144, 24, 120, 0], 1321]]
that we have a list of a list with 2 items:
A list of midi-data and
a timestamp
The second value is the one you're interested in. So we print it out as a note:
def number_to_note(number):
notes = ['c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b']
return notes[number%12]
def readInput(input_device):
while True:
if input_device.poll():
event = input_device.read(1)[0]
data = event[0]
timestamp = event[1]
note_number = data[1]
velocity = data[2]
print (number_to_note(note_number), velocity)
I hope this helped. It's my first answer, I hope it's not too long. :)

Related

blender 2.92 python overriding

I have seen quite a few questions regarding this issue, and I have not been able to wrap my head around it.
So here is a concrete example.
I create a cube and in edit mode I add loopcuts. No sweat!
I copy the code from the info window and I try it out in a script and I get the ominous RuntimeError: Operator bpy.ops.mesh.loopcut_slide.poll() expected a view3d region & editmesh error message.
I understand now that it is about first giving python the right context by overriding. And alas, I do not know how to do it!
Here is the code:
import bpy
import os
os.system("cls")
# remove the default cube...
objs = bpy.data.objects
for obj in objs:
if obj.name.find("Cube") == 0:
bpy.data.objects.remove(obj, do_unlink=True)
# add a cube!
bpy.ops.mesh.primitive_cube_add(size=2, enter_editmode=True, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
# do something to it to be sure that we have it...
bpy.data.objects['Cube'].scale[0] = 10
# THE CODE BELOW GIVES THE RuntimeError: Operator bpy.ops.mesh.loopcut_slide.poll() expected a view3d region & editmesh error message.
# What is the override code I have to use to fix it????????
bpy.ops.mesh.loopcut_slide(MESH_OT_loopcut={"number_cuts":16, "smoothness":0, "falloff":'INVERSE_SQUARE', "object_index":0, "edge_index":4, "mesh_select_mode_init":(True, False, False)}, TRANSFORM_OT_edge_slide={"value":0, "single_side":False, "use_even":False, "flipped":False, "use_clamp":True, "mirror":True, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "correct_uv":True, "release_confirm":False, "use_accurate":False})
import bpy
import os
os.system("cls")
objs = bpy.data.objects
for obj in objs:
if obj.name.find("Cube") == 0:
bpy.data.objects.remove(obj, do_unlink=True)
# add a cube!
bpy.ops.mesh.primitive_cube_add(size=2, enter_editmode=True, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
# do something to it to be sure that we have it...
bpy.data.objects['Cube'].scale[0] = 10
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
for region in area.regions:
if region.type == 'WINDOW':
override = {'area': area, 'region': region, 'edit_object':bpy.context.edit_object}
bpy.ops.mesh.loopcut_slide(override,MESH_OT_loopcut={"number_cuts":16, "smoothness":0, "falloff":'INVERSE_SQUARE', "object_index":0, "edge_index":4, "mesh_select_mode_init":(True, False, False)}, TRANSFORM_OT_edge_slide={"value":0, "single_side":False, "use_even":False, "flipped":False, "use_clamp":True, "mirror":True, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "correct_uv":True, "release_confirm":False, "use_accurate":False})

Passing array contents into function not working correctly

When trying to pass an array into a function it doesn't do anything at all. My code is below
main.py
import items
import npcs.py
def pickup(item):
global player_weight_max,player_weight,player_inv
#Calculates if item's weight will make player_weight go over player_weight_max
if player_weight + item[5] <= player_weight_max:
player_inv.append(item)
player_weight = player_weight + item[5]
else:
print("You're not able to carry this item.")
def npc(npc):
#Prints NPC speech
if npc[2] != None:
print("".join(npc[1]) + ": " + "".join(npc[2]))
else:
pass
for function in npc[3]:
if function[0] == 'pickup':
pickup(function[1])
if function[0] == 'battle':
battle(function[1])
npcs.py
import items
#art,name,speech,functions
test_guy = [["art"],["name"],["speech"],[
[['pickup'],[items.armour[0]],
[['pickup'],[items.armour[1]],
]
]
items.py
armour = [
[str(""),str("Tin Helmet"),int(1),int(20),str("head"),int(2),int(0),int(2)],
[str(""),str("Tin Chestplate"),int(1),int(20),str("torso"),int(0),int(1),int(2)],
[str(""),str("Tin Pants"),int(1),int(20),str("legs"),int(3),int(0),int(2)],
[str(""),str("Tin Boots"),int(1),int(20),str("feet"),int(2),int(0),int(2)],
]
Why is pickup() not appending the information obtained from items.py
I have already verified pickup() works when doing pickup(items.armour[0]) which should just be passing the array at that location into pickup(), why can the same not be done with the information contained in test_guy[3][0] and test_guy[3][1]?
updated the code as follows:
def npc(npc):
#Prints NPC speech
if npc[2] != None:
print("".join(npc[1]) + ": " + "".join(npc[2]))
else:
pass
for function in npc[3]:
print(function[1][0])
if function[0][0] == 'pickup':
pickup(function[1][0])
if function[0][0] == 'battle':
battle(function[1][0])
upon running:
npc(npcs.test_guy)
print(player_inv)
the output is now correct:
name: speech
['', 'Tin Helmet', 1, 20, 'head', 2, 0, 2]
['', 'Tin Chestplate', 1, 20, 'torso', 0, 1, 2]
[['', 'Tin Helmet', 1, 20, 'head', 2, 0, 2], ['', 'Tin Chestplate', 1, 20, 'torso', 0, 1, 2]]
Thank you!
(Yes I know this is not the most efficient way to do things, I'm still learning and just trying to get things working for now)
Whilst avoiding the unnecessary complexity of this code..
Your items are within another array so item[0] will never equal pickup/battle and equally, item[1] will never be the item, it will be an array with an item.
So first fix the missing brackets of your functions part of test_guy, and then reference the functions inner array first
item[0][0] and item[0][1]

Print a threading function in curses, Python

In my project I have to print some data stored in a database on the console. I have two functions that return string. I should print those data in two columns.
I thought of using the module curses in python to create those two columns.
So far all is good.
Another thing, is that my two function use the threading.Timer. So the string generated changes every 10 seconds for example if I set my Timer on 10.
So when I put the result of my function on the addstr() of a column, it prints the first String correctly, but nothing changes even if my string change. Otherwise when I resize for example the console, I notice that the string changes.
Here is my code :
import sys,os
import curses , curses.panel
import datetime
import time
import threading
def time_func():
printStr = threading.Timer(10,time_func)
printStr.start()
s = "Simple example that display datetime \n" + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return s
def draw_menu():
k = 0
cursor_x = 0
cursor_y = 0
# Clear and refresh the screen
stdscr = curses.initscr()
stdscr.clear()
stdscr.refresh()
# Initialize colors in curses
curses.start_color()
curses.init_pair(1, curses.COLOR_CYAN, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE)
curses.curs_set(0)
# Loop where k is the last character pressed
while (k != ord('q')):
# Declaration of strings
statusbarstr = "Press 'q' to exit | STATUS BAR "
'''Draw borders of the different columns'''
height, width = stdscr.getmaxyx()
stdscr.border()
stdscr.vline(1, 3 * height // 4, '|', width - 2)
stdscr.vline(1, height // 4, '|', width - 2)
stdscr.refresh()
'''Initialize the Statistics column'''
column_one = curses.newwin(height - 2, 3 * width // 4, 1,
1)
_, a_x = column_one.getmaxyx()
column_one.attron(curses.color_pair(1))
column_one.attron(curses.A_BOLD)
column_one.addstr(0, a_x // 2 - 2, "column one")
column_one.hline(1, 0, '-', a_x)
column_one.attroff(curses.color_pair(1))
column_one.attroff(curses.A_BOLD)
# I want to add my string here for example :
line = time_func()
column_one.addstr(3,1, line)
column_one.noutrefresh()
'''Initialize the Alerts column'''
column_two = curses.newwin(height - 2, width // 4, 1,
3 * width // 4 )
_, s_x = column_two.getmaxyx()
column_two.attron(curses.color_pair(1))
column_two.attron(curses.A_BOLD)
column_two.addstr(0, s_x // 2 - 5, "column two")
column_two.hline(1, 0, '-', s_x)
column_two.attroff(curses.color_pair(1))
column_two.attroff(curses.A_BOLD)
column_two.addstr(3, s_x // 2 - 5,"test")
column_two.noutrefresh()
# Render status bar
stdscr.attron(curses.color_pair(3))
stdscr.addstr(height-1, 0, statusbarstr)
stdscr.addstr(height-1, len(statusbarstr), " " * (width - len(statusbarstr) - 1))
stdscr.attroff(curses.color_pair(3))
# Turning on attributes for title
stdscr.attron(curses.color_pair(2))
stdscr.attron(curses.A_BOLD)
# Rendering title
# Turning off attributes for title
stdscr.attroff(curses.color_pair(2))
stdscr.attroff(curses.A_BOLD)
# Print rest of text
stdscr.move(height - 2, width - 2)
# Refresh the screen
stdscr.refresh()
# Wait for next input
k = stdscr.getch()
def main():
curses.wrapper(draw_menu())
if __name__ == "__main__":
main()
The curses function draw_menu is waiting for input at the end of the loop. If you resize the terminal, that
k = stdscr.getch()
returns a KEY_RESIZE, and runs through the loop again.
You could change that to wait a short time before giving up on the getch. That would return a -1.
Usually that's done using timeout (in curses), e.g., 50 milliseconds. There's a wrapper for that in Python (and by the way its description is incorrect). You should read the ncurses manual page for timeout.
Sometimes people say to use nodelay, which is usually poor advice since it would make the draw_menu thread use most of the CPU time.

python vtk XMLPolyDataWriter write solid tetrahedrons

I need to write a xml vtk file in python with solids tetrahedrons. Specifically in a Polydata. I have a collection of tetrahedrons with x,y,z coordinates of each edge. I try to use vtk.vtkXMLPolyDataWriter() but I get this (only 2D triangles):
enter image description here
My code :
#!/usr/bin/env python
import vtk
points = vtk.vtkPoints()
points.InsertNextPoint(0, 0, 0)
points.InsertNextPoint(1, 0, 0)
points.InsertNextPoint(1, 1, 0)
points.InsertNextPoint(0, 1, 1)
tetra = vtk.vtkTetra()
tetra.GetPointIds().SetId(0, 0)
tetra.GetPointIds().SetId(1, 1)
tetra.GetPointIds().SetId(2, 2)
tetra.GetPointIds().SetId(3, 3)
cellArray = vtk.vtkCellArray()
cellArray.InsertNextCell(tetra)
polydata = vtk.vtkPolyData()
polydata.SetPoints(points)
polydata.SetPolys(cellArray)
polydata.Modified()
if vtk.VTK_MAJOR_VERSION <= 5:
polydata.Update()
writer = vtk.vtkXMLPolyDataWriter()
writer.SetFileName("Primal_geo.vtp");
if vtk.VTK_MAJOR_VERSION <= 5:
writer.SetInput(polydata)
else:
writer.SetInputData(polydata)
writer.Write()
So, how can i write this file?
Thanks!
XML is information in tags. It is kind of a free hand json.
So here we go.
Now let me start by saying that I am not familiar with vtk or it's features, so while I hope the code I provide here serves your purposes I am not sure that a more satisfactory (preexisting piece of vtk) doesn't exist.
That said I wrote this little something up.
#!/usr/bin/env python
import vtk
class vtkXMLparser:
points = None
scellArray = None
def tagSplit(self,line):
for n,k in enumerate(line):
go = none
fin = none
if(k == ">"):
if(go == none):
if(n>0):
if(line[n-1]!="\\"):
go = n+1
if(go != none):
if(k == "<"):
if(n>0):
if(line[n-1]!="\\"):
if(n<len(line)-1):
if(line[n+1]=="/"):
fin = n+1
tag = line[fin+2:len(line)-1]
content = line[go:fin]
return([tag,content])
def addNice(self,di,key,cont):
try:
di[key].append(cont)
except(KeyError):
di[key]=[]
di[key].append(cont)
def parse(self,f):
input = open(f,"r")
xml = input.read()
xml = xml.split("\n")
data = {}
for lineNumber,line in enumerate(xml):
parsedXmlLine = self.tagSplit(line)
self.addNice(data,parsedXmlLine[0],parsedXmlLine[1])
self.self.points(data)
self.tetra(data)
self.write()
def self.points(self,di):
self.points = vtk.vtkself.points()
for point in di["point"]:
self.points.InsertNextPoint(eval(point))
def tetra(self,di):
tetra = vtk.vtkTetra()
for id in di["tetra"]:
tetra.GetPointIds().SetId(eval(id))
self.cellArray = vtk.vtkself.cellArray()
self.cellArray.InsertNextCell(tetra)
def write(self):
polydata = vtk.vtkPolyData()
polydata.Setself.points(self.points)
polydata.SetPolys(self.cellArray)
polydata.Modified()
if vtk.VTK_MAJOR_VERSION <= 5:
polydata.Update()
writer = vtk.vtkXMLPolyDataWriter()
writer.SetFileName("Primal_geo.vtp");
if vtk.VTK_MAJOR_VERSION <= 5:
writer.SetInput(polydata)
else:
writer.SetInputData(polydata)
writer.Write()
i = vtkXMLparser()
i.parse("input.xml")
I would write an input file that looks something like this for your example.
<point>0, 0, 0</point>
<point>1, 0, 0</point>
<point>1, 1, 0</point>
<point>0, 1, 1</point>
<tetra>0, 0</tetra>
<tetra>1, 1</tetra>
<tetra>2, 2</tetra>
<tetra>3, 3</tetra>
I hope this helps!

Can't attach widget to my grid

I'm trying to create widgets with a loop. This is what I tried :
def set_runways(self, airfield):
i = 0
for rwy in airfield['Runways']:
frame = Gtk.Frame()
frame.set_label('-'.join([rwy['Runway_1'], rwy['Runway_2']]))
frame.set_shadow_type(1)
self.runways_layout.attach(frame, (i / 2), (i % 2), 1, 1)
rwy_layout = Gtk.Grid()
frame.add(rwy_layout)
# Just for testing :
label = Gtk.Label('Hello, World')
rwy_layout.attach(label, 0, 0, 1, 1)
I import my runways_layout in my __init__ with self.runways_layout = builder.get_object('runwaysGrid') which is a Gtk.Grid and I call my function after with self.set_runways(airfield). But even with this, my window doesn't show Hello World, I have a blank window... Why ?
I specify that my rwy isn't empty.
Thanks for your help.
EDIT :
Okay I tried this simple thing :
self.runways_layout = builder.get_object('runwaysGrid')
label = Gtk.Label('Coucou')
self.runways_layout.attach(label, 0, 0, 1, 1)
And it doesn't work too... O_o
Okay I found a solution, I have to do :
self.runways_layout = builder.get_object('runwaysGrid')
label = Gtk.Label('Coucou')
self.runways_layout.attach(label, 0, 0, 1, 1)
label.show() # Add this and it works...
But why ?

Categories