Merge upstream work

sammachin-gprs
Cass May 2018-09-02 17:57:12 +01:00
commit e6df1e9053
32 changed files with 2660 additions and 8 deletions

50
3dspin/coriolis.obj Normal file
View File

@ -0,0 +1,50 @@
# Exported from Wings 3D 1.5.4
mtllib coriolis.mtl
o Cube1
#12 vertices, 14 faces
v -1.00000000 -1.00000000 0.0000000e+0
v -1.00000000 0.0000000e+0 -1.00000000
v 0.0000000e+0 -1.00000000 -1.00000000
v -1.00000000 0.0000000e+0 1.00000000
v 0.0000000e+0 -1.00000000 1.00000000
v 0.0000000e+0 1.00000000 -1.00000000
v -1.00000000 1.00000000 0.0000000e+0
v 0.0000000e+0 1.00000000 1.00000000
v 1.00000000 -1.00000000 0.0000000e+0
v 1.00000000 0.0000000e+0 -1.00000000
v 1.00000000 0.0000000e+0 1.00000000
v 1.00000000 1.00000000 0.0000000e+0
v 0.2 0.1 1.01
v 0.2 -0.1 1.01
v -0.2 -0.1 1.01
v -0.2 0.1 1.01
vn -0.70710678 -0.70710678 0.0000000e+0
vn -0.70710678 0.0000000e+0 -0.70710678
vn 0.0000000e+0 -0.70710678 -0.70710678
vn -0.70710678 0.0000000e+0 0.70710678
vn 0.0000000e+0 -0.70710678 0.70710678
vn 0.0000000e+0 0.70710678 -0.70710678
vn -0.70710678 0.70710678 0.0000000e+0
vn 0.0000000e+0 0.70710678 0.70710678
vn 0.70710678 -0.70710678 0.0000000e+0
vn 0.70710678 0.0000000e+0 -0.70710678
vn 0.70710678 0.0000000e+0 0.70710678
vn 0.70710678 0.70710678 0.0000000e+0
g Cube1_default
usemtl default
s 1
f 1//1 2//2 3//3
f 1//1 4//4 7//7 2//2
f 1//1 5//5 4//4
f 2//2 6//6 10//10 3//3
f 2//2 7//7 6//6
f 3//3 9//9 5//5 1//1
f 3//3 10//10 9//9
f 4//4 8//8 7//7
f 5//5 9//9 11//11
f 5//5 11//11 8//8 4//4
f 6//6 12//12 10//10
f 7//7 8//8 12//12 6//6
f 8//8 11//11 12//12
f 10//10 12//12 11//11 9//9
f 16 15 14 13

29
3dspin/cube.obj Normal file
View File

@ -0,0 +1,29 @@
# Exported from Wings 3D 1.5.4
mtllib cube.mtl
o Cube1
#8 vertices, 6 faces
v -1.00000000 -1.00000000 -1.00000000
v -1.00000000 -1.00000000 1.00000000
v -1.00000000 1.00000000 -1.00000000
v -1.00000000 1.00000000 1.00000000
v 1.00000000 -1.00000000 -1.00000000
v 1.00000000 -1.00000000 1.00000000
v 1.00000000 1.00000000 -1.00000000
v 1.00000000 1.00000000 1.00000000
vn -0.57735027 -0.57735027 -0.57735027
vn -0.57735027 -0.57735027 0.57735027
vn -0.57735027 0.57735027 -0.57735027
vn -0.57735027 0.57735027 0.57735027
vn 0.57735027 -0.57735027 -0.57735027
vn 0.57735027 -0.57735027 0.57735027
vn 0.57735027 0.57735027 -0.57735027
vn 0.57735027 0.57735027 0.57735027
g Cube1_default
usemtl default
s 1
f 1//1 5//5 6//6 2//2
f 2//2 4//4 3//3 1//1
f 2//2 6//6 8//8 4//4
f 3//3 7//7 5//5 1//1
f 4//4 8//8 7//7 3//3
f 5//5 7//7 8//8 6//6

59
3dspin/dodecahedron.obj Normal file
View File

@ -0,0 +1,59 @@
# Exported from Wings 3D 1.5.4
mtllib dodecahedron.mtl
o dodecahedron1
#20 vertices, 12 faces
v -0.50000000 0.0000000e+0 1.30901699
v 0.50000000 0.0000000e+0 1.30901699
v -0.80901699 -0.80901699 -0.80901699
v -0.80901699 -0.80901699 0.80901699
v -0.80901699 0.80901699 -0.80901699
v -0.80901699 0.80901699 0.80901699
v 0.80901699 -0.80901699 -0.80901699
v 0.80901699 -0.80901699 0.80901699
v 0.80901699 0.80901699 -0.80901699
v 0.80901699 0.80901699 0.80901699
v 1.30901699 0.50000000 0.0000000e+0
v 1.30901699 -0.50000000 0.0000000e+0
v -1.30901699 0.50000000 0.0000000e+0
v -1.30901699 -0.50000000 0.0000000e+0
v -0.50000000 0.0000000e+0 -1.30901699
v 0.50000000 0.0000000e+0 -1.30901699
v 0.0000000e+0 1.30901699 0.50000000
v 0.0000000e+0 1.30901699 -0.50000000
v 0.0000000e+0 -1.30901699 0.50000000
v 0.0000000e+0 -1.30901699 -0.50000000
vn -0.35682209 0.0000000e+0 0.93417236
vn 0.35682209 0.0000000e+0 0.93417236
vn -0.57735027 -0.57735027 -0.57735027
vn -0.57735027 -0.57735027 0.57735027
vn -0.57735027 0.57735027 -0.57735027
vn -0.57735027 0.57735027 0.57735027
vn 0.57735027 -0.57735027 -0.57735027
vn 0.57735027 -0.57735027 0.57735027
vn 0.57735027 0.57735027 -0.57735027
vn 0.57735027 0.57735027 0.57735027
vn 0.93417236 0.35682209 0.0000000e+0
vn 0.93417236 -0.35682209 0.0000000e+0
vn -0.93417236 0.35682209 0.0000000e+0
vn -0.93417236 -0.35682209 0.0000000e+0
vn -0.35682209 0.0000000e+0 -0.93417236
vn 0.35682209 0.0000000e+0 -0.93417236
vn 0.0000000e+0 0.93417236 0.35682209
vn 0.0000000e+0 0.93417236 -0.35682209
vn 0.0000000e+0 -0.93417236 0.35682209
vn 0.0000000e+0 -0.93417236 -0.35682209
g dodecahedron1_default
usemtl default
s 1
f 1//1 4//4 19//19 8//8 2//2
f 1//1 6//6 13//13 14//14 4//4
f 2//2 10//10 17//17 6//6 1//1
f 3//3 20//20 19//19 4//4 14//14
f 5//5 18//18 9//9 16//16 15//15
f 7//7 16//16 9//9 11//11 12//12
f 8//8 12//12 11//11 10//10 2//2
f 9//9 18//18 17//17 10//10 11//11
f 12//12 8//8 19//19 20//20 7//7
f 13//13 6//6 17//17 18//18 5//5
f 14//14 13//13 5//5 15//15 3//3
f 15//15 16//16 7//7 20//20 3//3

51
3dspin/icosahedron.obj Executable file
View File

@ -0,0 +1,51 @@
# Exported from Wings 3D 1.5.4
mtllib icosahedron.mtl
o icosahedron1
#12 vertices, 20 faces
v 0.0000000e+0 1.90211303 0.0000000e+0
v 1.70130162 0.85065081 0.0000000e+0
v 0.52573111 0.85065081 1.61803399
v -1.37638192 0.85065081 1.00000000
v -1.37638192 0.85065081 -1.00000000
v 0.52573111 0.85065081 -1.61803399
v -1.70130162 -0.85065081 0.0000000e+0
v -0.52573111 -0.85065081 -1.61803399
v 1.37638192 -0.85065081 -1.00000000
v 1.37638192 -0.85065081 1.00000000
v -0.52573111 -0.85065081 1.61803399
v 0.0000000e+0 -1.90211303 0.0000000e+0
vn 2.7942283e-17 1.00000000 -1.3971142e-17
vn 0.89442719 0.44721360 0.0000000e+0
vn 0.27639320 0.44721360 0.85065081
vn -0.72360680 0.44721360 0.52573111
vn -0.72360680 0.44721360 -0.52573111
vn 0.27639320 0.44721360 -0.85065081
vn -0.89442719 -0.44721360 0.0000000e+0
vn -0.27639320 -0.44721360 -0.85065081
vn 0.72360680 -0.44721360 -0.52573111
vn 0.72360680 -0.44721360 0.52573111
vn -0.27639320 -0.44721360 0.85065081
vn -4.1913425e-17 -1.00000000 0.0000000e+0
g icosahedron1_default
usemtl default
s 1
f 1//1 3//3 2//2
f 1//1 4//4 3//3
f 1//1 5//5 4//4
f 1//1 6//6 5//5
f 2//2 6//6 1//1
f 2//2 9//9 6//6
f 2//2 10//10 9//9
f 3//3 10//10 2//2
f 3//3 11//11 10//10
f 4//4 11//11 3//3
f 5//5 7//7 4//4
f 5//5 8//8 7//7
f 6//6 8//8 5//5
f 6//6 9//9 8//8
f 7//7 11//11 4//4
f 7//7 12//12 11//11
f 8//8 12//12 7//7
f 9//9 12//12 8//8
f 10//10 12//12 9//9
f 11//11 12//12 10//10

361
3dspin/main.py Normal file
View File

@ -0,0 +1,361 @@
"""3d rotating polyhedra. 2016 badge competition winner, ported for 2018!"""
___name___ = "3D Spin"
___license___ = "MIT"
___categories___ = ["Demo"]
___dependencies___ = ["app", "ugfx_helper", "random", "sleep", "buttons"]
import ugfx
from tilda import Buttons
import math
from uos import listdir
import time
# from imu import IMU
import gc
# import pyb
import app
app_path = './3dspin'
from math import sqrt
class Vector3D:
def __init__(self, x=0.0, y=0.0, z=0.0):
self.x = x
self.y = y
self.z = z
def magnitude(self):
return sqrt(self.x*self.x+self.y*self.y+self.z*self.z)
def __sub__(self, v):
return Vector3D(self.x-v.x, self.y-v.y, self.z-v.z)
def normalize(self):
mag = self.magnitude()
if (mag > 0.0):
self.x /= mag
self.y /= mag
self.z /= mag
else:
raise Exception('*** Vector: error, normalizing zero vector! ***')
def cross(self, v): #cross product
return Vector3D(self.y*v.z-self.z*v.y, self.z*v.x-self.x*v.z, self.x*v.y-self.y*v.x)
#The layout of the matrix (row- or column-major) matters only when the user reads from or writes to the matrix (indexing). For example in the multiplication function we know that the first components of the Matrix-vectors need to be multiplied by the vector. The memory-layout is not important
class Matrix:
''' Column-major order '''
def __init__(self, createidentity=True):# (2,2) creates a 2*2 Matrix
# if rows < 2 or cols < 2:
# raise Exception('*** Matrix: error, getitem((row, col)), row, col problem! ***')
self.rows = 4
self.cols = 4
self.m = [[0.0]*self.rows for x in range(self.cols)]
#If quadratic matrix then create identity one
if createidentity:
for i in range(self.rows):
self.m[i][i] = 1.0
def mul(self, right):
if isinstance(right, Matrix):
r = Matrix(False)
for i in range(self.rows):
for j in range(right.cols):
for k in range(self.cols):
r.m[i][j] += self.m[i][k]*right.m[k][j]
return r
elif isinstance(right, Vector3D): #Translation: the last column of the matrix. Remains unchanged due to the the fourth coord of the vector (1).
# if self.cols == 4:
r = Vector3D()
addx = addy = addz = 0.0
if self.rows == self.cols == 4:
addx = self.m[0][3]
addy = self.m[1][3]
addz = self.m[2][3]
r.x = self.m[0][0]*right.x+self.m[0][1]*right.y+self.m[0][2]*right.z+addx
r.y = self.m[1][0]*right.x+self.m[1][1]*right.y+self.m[1][2]*right.z+addy
r.z = self.m[2][0]*right.x+self.m[2][1]*right.y+self.m[2][2]*right.z+addz
#In 3D game programming we use homogenous coordinates instead of cartesian ones in case of Vectors in order to be able to use them with a 4*4 Matrix. The 4th coord (w) is not included in the Vector-class but gets computed on the fly
w = self.m[3][0]*right.x+self.m[3][1]*right.y+self.m[3][2]*right.z+self.m[3][3]
if (w != 1 and w != 0):
r.x = r.x/w;
r.y = r.y/w;
r.z = r.z/w;
return r
else:
raise Exception('*** Matrix: error, matrix multiply with not matrix, vector or int or float! ***')
def loadObject(filename):
print(filename)
if (".obj" in filename):
loadObj(filename)
if (".dat" in filename):
loadDat(filename)
def loadDat(filename):
global obj_vertices
global obj_faces
obj_vertices = []
obj_faces = []
f = open(app_path + "/" + filename)
for line in f:
if line[:2] == "v ":
parts = line.split(" ")
obj_vertices.append(
Vector3D(
float(parts[1]),
float(parts[2]),
float(parts[3])
)
)
gc.collect()
elif line[:2] == "f ":
parts = line.split(" ")
face = []
for part in parts[1:]:
face.append(int(part.split("/",1)[0])-1)
obj_faces.append(face)
gc.collect()
f.close()
def loadObj(filename):
global obj_vertices
global obj_faces
obj_vertices = []
obj_faces = []
f = open(app_path + "/" + filename)
for line in f:
if line[:2] == "v ":
parts = line.split(" ")
obj_vertices.append(
Vector3D(
float(parts[1]),
float(parts[2]),
float(parts[3])
)
)
gc.collect()
elif line[:2] == "f ":
parts = line.split(" ")
face = []
for part in parts[1:]:
face.append(int(part.split("/",1)[0])-1)
obj_faces.append(face)
gc.collect()
f.close()
def toScreenCoords(pv):
px = int((pv.x+1)*0.5*240)
py = int((1-(pv.y+1)*0.5)*320)
return [px, py]
def createCameraMatrix(x,y,z):
camera_transform = Matrix()
camera_transform.m[0][3] = x
camera_transform.m[1][3] = y
camera_transform.m[2][3] = z
return camera_transform
def createProjectionMatrix(horizontal_fov, zfar, znear):
s = 1/(math.tan(math.radians(horizontal_fov/2)))
proj = Matrix()
proj.m[0][0] = s * (320/240) # inverse aspect ratio
proj.m[1][1] = s
proj.m[2][2] = -zfar/(zfar-znear)
proj.m[3][2] = -1.0
proj.m[2][3] = -(zfar*znear)/(zfar-znear)
return proj
def createRotationMatrix(x_rotation, y_rotation, z_rotation):
rot_x = Matrix()
rot_x.m[1][1] = rot_x.m[2][2] = math.cos(x_rotation)
rot_x.m[2][1] = math.sin(x_rotation)
rot_x.m[1][2] = -rot_x.m[2][1]
rot_y = Matrix()
rot_y.m[0][0] = rot_y.m[2][2] = math.cos(y_rotation)
rot_y.m[0][2] = math.sin(y_rotation)
rot_y.m[2][0] = -rot_y.m[0][2]
rot_z = Matrix()
rot_z.m[0][0] = rot_z.m[1][1] = math.cos(z_rotation)
rot_z.m[1][0] = math.sin(z_rotation)
rot_z.m[0][1] = -rot_z.m[1][0]
return rot_z.mul(rot_x).mul(rot_y)
def normal(face, vertices, normalize = True):
# Work out the face normal for lighting
normal = (vertices[face[1]]-vertices[face[0]]).cross(vertices[face[2]]-vertices[face[0]])
if normalize == True:
normal.normalize()
return normal
def clear_screen():
# Selectively clear the screen by re-rendering the previous frame in black
global last_polygons
global last_mode
for poly in last_polygons:
if last_mode == FLAT:
ugfx.fill_polygon(0,0, poly, ugfx.BLACK)
ugfx.polygon(0,0, poly, ugfx.BLACK)
def render(mode, rotation):
# Rotate all the vertices in one go
vertices = [rotation.mul(vertex) for vertex in obj_vertices]
# Calculate normal for each face (for lighting)
if mode == FLAT:
face_normal_zs = [normal(face, vertices).z for face in obj_faces]
# Project (with camera) all the vertices in one go as well
vertices = [camera_projection.mul(vertex) for vertex in vertices]
# Calculate projected normals for each face
if mode != WIREFRAME:
proj_normal_zs = [normal(face, vertices, False).z for face in obj_faces]
# Convert to screen coordinates all at once
# We could do this faster by only converting vertices that are
# in faces that will be need rendered, but it's likely that test
# would take longer.
vertices = [toScreenCoords(v) for v in vertices]
# Render the faces to the screen
vsync()
clear_screen()
global last_polygons
global last_mode
last_polygons = []
last_mode = mode
for index in range(len(obj_faces)):
# Only render things facing towards us (unless we're in wireframe mode)
if (mode == WIREFRAME) or (proj_normal_zs[index] > 0):
# Convert polygon
poly = [vertices[v] for v in obj_faces[index]]
# Calculate colour and render
ugcol = ugfx.WHITE
if mode == FLAT:
# Simple lighting calculation
colour5 = int(face_normal_zs[index] * 31)
colour6 = int(face_normal_zs[index] * 63)
# Create a 5-6-5 grey
ugcol = (colour5 << 11) | (colour6 << 5) | colour5
# Render polygon
ugfx.fill_polygon(0,0, poly, ugcol)
# Always draw the wireframe in the same colour to fill gaps left by the
# fill_polygon method
ugfx.polygon(0,0, poly, ugcol)
last_polygons.append(poly)
def vsync():
None
# while(tear.value() == 0):
# pass
# while(tear.value()):
# pass
def calculateRotation(smoothing, accelerometer):
# Keep a list of recent rotations to smooth things out
global x_rotation
global z_rotation
# First, pop off the oldest rotation
# if len(x_rotations) >= smoothing:
# x_rotations = x_rotations[1:]
# if len(z_rotations) >= smoothing:
# z_rotations = z_rotations[1:]
# Now append a new rotation
pi_2 = math.pi / 2
#x_rotations.append(-accelerometer['z'] * pi_2)
#z_rotations.append(accelerometer['x'] * pi_2)
# Calculate rotation matrix
return createRotationMatrix(
# this averaging isn't correct in the first <smoothing> frames, but who cares
math.radians(x_rotation),
math.radians(y_rotation),
math.radians(z_rotation)
)
print("Hello 3DSpin")
# Initialise hardware
ugfx.init()
ugfx.clear(ugfx.BLACK)
# imu=IMU()
# buttons.init()
# Enable tear detection for vsync
# ugfx.enable_tear()
# tear = pyb.Pin("TEAR", pyb.Pin.IN)
#ugfx.set_tear_line(1)
print("Graphics initalised")
# Set up static rendering matrices
camera_transform = createCameraMatrix(0, 0, -5.0)
proj = createProjectionMatrix(45.0, 100.0, 0.1)
camera_projection = proj.mul(camera_transform)
print("Camera initalised")
# Get the list of available objects, and load the first one
obj_vertices = []
obj_faces = []
print("available objects: {}", listdir(app_path))
objects = [x for x in listdir(app_path) if (((".obj" in x) | (".dat" in x)) & (x[0] != "."))]
selected = 0
loadObject(objects[selected])
print("loaded object {}", objects[selected])
# Set up rotation tracking arrays
x_rotation = 0
z_rotation = 0
y_rotation = 0
# Smooth rotations over 5 frames
smoothing = 5
# Rendering modes
BACKFACECULL = 1
FLAT = 2
WIREFRAME = 3
# Start with backface culling mode
mode = BACKFACECULL
last_polygons = []
last_mode = WIREFRAME
# Main loop
run = True
while run:
gc.collect()
# Render the scene
render(
mode,
calculateRotation(smoothing, None)
)
# Button presses
y_rotation += 5
x_rotation += 3
z_rotation += 1
if Buttons.is_pressed(Buttons.JOY_Left):
y_rotation -= 5
if Buttons.is_pressed(Buttons.JOY_Right):
y_rotation += 5
if Buttons.is_pressed(Buttons.JOY_Center):
y_rotation = 0
if Buttons.is_pressed(Buttons.BTN_B):
selected += 1
if selected >= len(objects):
selected = 0
loadObject(objects[selected])
time.sleep_ms(500) # Wait a while to avoid skipping ahead if the user still has the button down
if Buttons.is_pressed(Buttons.BTN_A):
mode += 1
if mode > 3:
mode = 1
time.sleep_ms(500) # Wait a while to avoid skipping ahead if the user still has the button down
if Buttons.is_pressed(Buttons.BTN_Menu):
run = False
app.restart_to_default()

27
3dspin/octohedron.obj Normal file
View File

@ -0,0 +1,27 @@
# Exported from Wings 3D 2.0.5
mtllib octohedron.mtl
o octahedron1
#6 vertices, 8 faces
v 2.00000000 0.0000000e+0 0.0000000e+0
v -2.00000000 0.0000000e+0 0.0000000e+0
v 0.0000000e+0 2.00000000 0.0000000e+0
v 0.0000000e+0 -2.00000000 0.0000000e+0
v 0.0000000e+0 0.0000000e+0 2.00000000
v 0.0000000e+0 0.0000000e+0 -2.00000000
vn 1.00000000 0.0000000e+0 0.0000000e+0
vn -1.00000000 0.0000000e+0 0.0000000e+0
vn 0.0000000e+0 1.00000000 0.0000000e+0
vn 0.0000000e+0 -1.00000000 0.0000000e+0
vn 0.0000000e+0 0.0000000e+0 1.00000000
vn 0.0000000e+0 0.0000000e+0 -1.00000000
g octahedron1_default
usemtl default
s 1
f 1//1 5//5 4//4
f 1//1 6//6 3//3
f 2//2 5//5 3//3
f 2//2 6//6 4//4
f 3//3 5//5 1//1
f 3//3 6//6 2//2
f 4//4 5//5 2//2
f 4//4 6//6 1//1

81
3dspin/octotoad.obj Normal file
View File

@ -0,0 +1,81 @@
# Exported from Wings 3D 2.0.5
mtllib octoad.mtl
o octotoad1
#24 vertices, 26 faces
v 1.66800000 0.55600000 0.55600000
v 1.66800000 0.55600000 -0.55600000
v 1.66800000 -0.55600000 0.55600000
v 1.66800000 -0.55600000 -0.55600000
v -1.66800000 0.55600000 0.55600000
v -1.66800000 0.55600000 -0.55600000
v -1.66800000 -0.55600000 0.55600000
v -1.66800000 -0.55600000 -0.55600000
v 0.55600000 1.66800000 0.55600000
v 0.55600000 1.66800000 -0.55600000
v 0.55600000 -1.66800000 0.55600000
v 0.55600000 -1.66800000 -0.55600000
v 0.55600000 0.55600000 1.66800000
v 0.55600000 0.55600000 -1.66800000
v 0.55600000 -0.55600000 1.66800000
v 0.55600000 -0.55600000 -1.66800000
v -0.55600000 1.66800000 0.55600000
v -0.55600000 1.66800000 -0.55600000
v -0.55600000 -1.66800000 0.55600000
v -0.55600000 -1.66800000 -0.55600000
v -0.55600000 0.55600000 1.66800000
v -0.55600000 0.55600000 -1.66800000
v -0.55600000 -0.55600000 1.66800000
v -0.55600000 -0.55600000 -1.66800000
vn 0.85476344 0.36700100 0.36700100
vn 0.85476344 0.36700100 -0.36700100
vn 0.85476344 -0.36700100 0.36700100
vn 0.85476344 -0.36700100 -0.36700100
vn -0.85476344 0.36700100 0.36700100
vn -0.85476344 0.36700100 -0.36700100
vn -0.85476344 -0.36700100 0.36700100
vn -0.85476344 -0.36700100 -0.36700100
vn 0.36700100 0.85476344 0.36700100
vn 0.36700100 0.85476344 -0.36700100
vn 0.36700100 -0.85476344 0.36700100
vn 0.36700100 -0.85476344 -0.36700100
vn 0.36700100 0.36700100 0.85476344
vn 0.36700100 0.36700100 -0.85476344
vn 0.36700100 -0.36700100 0.85476344
vn 0.36700100 -0.36700100 -0.85476344
vn -0.36700100 0.85476344 0.36700100
vn -0.36700100 0.85476344 -0.36700100
vn -0.36700100 -0.85476344 0.36700100
vn -0.36700100 -0.85476344 -0.36700100
vn -0.36700100 0.36700100 0.85476344
vn -0.36700100 0.36700100 -0.85476344
vn -0.36700100 -0.36700100 0.85476344
vn -0.36700100 -0.36700100 -0.85476344
g octotoad1_default
usemtl default
s 1
f 1//1 3//3 4//4 2//2
f 1//1 13//13 15//15 3//3
f 2//2 10//10 9//9 1//1
f 2//2 14//14 10//10
f 3//3 11//11 12//12 4//4
f 3//3 15//15 11//11
f 4//4 16//16 14//14 2//2
f 5//5 17//17 18//18 6//6
f 5//5 21//21 17//17
f 6//6 8//8 7//7 5//5
f 6//6 22//22 24//24 8//8
f 7//7 23//23 21//21 5//5
f 8//8 20//20 19//19 7//7
f 8//8 24//24 20//20
f 9//9 13//13 1//1
f 9//9 17//17 21//21 13//13
f 10//10 18//18 17//17 9//9
f 11//11 19//19 20//20 12//12
f 12//12 16//16 4//4
f 12//12 20//20 24//24 16//16
f 13//13 21//21 23//23 15//15
f 14//14 22//22 18//18 10//10
f 15//15 23//23 19//19 11//11
f 16//16 24//24 22//22 14//14
f 18//18 22//22 6//6
f 19//19 23//23 7//7

19
3dspin/tetrahedron.obj Normal file
View File

@ -0,0 +1,19 @@
# Exported from Wings 3D 1.5.4
mtllib tetrahedron.mtl
o tetrahedron1
#4 vertices, 4 faces
v 0.0000000e+0 1.08866211 0.0000000e+0
v 0.0000000e+0 -0.54433105 1.15470054
v -1.00000000 -0.54433105 -0.57735027
v 1.00000000 -0.54433105 -0.57735027
vn 0.0000000e+0 1.00000000 -1.1102230e-16
vn 0.0000000e+0 -0.33333333 0.94280904
vn -0.81649658 -0.33333333 -0.47140452
vn 0.81649658 -0.33333333 -0.47140452
g tetrahedron1_default
usemtl default
s 1
f 1//1 3//3 2//2
f 1//1 4//4 3//3
f 2//2 4//4 1//1
f 3//3 4//4 2//2

44
SketchyEtch/main.py Normal file
View File

@ -0,0 +1,44 @@
"""Accidentally created etcher sketch..."""
___name___ = "Sketchy Etch"
___title___ = "Sketchy Etch"
___license___ = "MIT"
___dependencies___ = ["ugfx_helper"]
___categories___ = ["Games"]
import ugfx, ugfx_helper, app
from tilda import Buttons
from time import sleep
ugfx_helper.init()
ugfx.clear()
ugfx.area(0, 0, ugfx.width(), ugfx.height(), ugfx.BLACK)
i = int(ugfx.width() / 2)
j = int(ugfx.height() / 2)
while (not Buttons.is_pressed(Buttons.BTN_A)) and (not Buttons.is_pressed(Buttons.BTN_B)) and (not Buttons.is_pressed(Buttons.BTN_Menu)):
changed = False
if Buttons.is_pressed(Buttons.JOY_Right) and (i < (ugfx.width() - 1)):
i += 1
changed = True
elif Buttons.is_pressed(Buttons.JOY_Left) and (i > 0):
i -= 1
changed = True
if Buttons.is_pressed(Buttons.JOY_Down) and (j < (ugfx.height() - 1)):
j += 1
changed = True
elif Buttons.is_pressed(Buttons.JOY_Up) and (j > 0):
j -= 1
changed = True
if changed:
ugfx.area((i - 1) if i > 0 else 0, (j - 1) if j > 0 else 0, 3 if (i > 0 and i < (ugfx.width() - 1)) else 2, 3 if (j > 0 and j < (ugfx.height() - 1)) else 2, ugfx.WHITE)
sleep(0.05)
ugfx.clear()
app.restart_to_default()

76
btscan/main.py Normal file
View File

@ -0,0 +1,76 @@
"""Scan for and display nearby bluetooth devices"""
___name___ = "Bluetooth Scan"
___license___ = "MIT"
___dependencies___ = ["sleep", "app", "sim800"]
___categories___ = ["Other", "System"]
import ugfx, app
from machine import Neopix
np = Neopix()
import sim800
from tilda import Buttons
from time import sleep
btrestore = False
duration = 10
status_height = 20
ugfx.init()
ugfx.clear()
ugfx.set_default_font(ugfx.FONT_FIXED)
def instructions(duration):
ugfx.Label(5, 180, 240, 30, "Press A to start, B to change scan length or MENU to exit")
ugfx.Label(5, 210, 240, 15, "Scan requires ~{0} seconds".format(duration))
if not sim800.btison():
sim800.btpoweron()
btrestore = True
instructions(duration)
# while (not Buttons.is_pressed(Buttons.BTN_A)) and (not Buttons.is_pressed(Buttons.BTN_B)) and (not Buttons.is_pressed(Buttons.BTN_Menu)):
while not Buttons.is_pressed(Buttons.BTN_Menu):
a = Buttons.is_pressed(Buttons.BTN_A)
b = Buttons.is_pressed(Buttons.BTN_B)
if not a and not b:
ugfx.poll()
continue
if b:
duration = duration + 5
if duration > 60:
duration = 5
ugfx.clear()
instructions(duration)
continue
ugfx.clear()
np.display([0,0])
np.display([0x000099, 0x000099])
devs = sim800.btscan(duration*1000)
np.display([0x00, 0x00])
if len(devs) == 0:
ugfx.Label(0, 0, 240, 25, "No devices found")
np.display([0x110000,0x110000])
sleep(1)
np.display([0,0])
else:
if type(devs[0]) == int:
devs = [devs]
y = 0
for dev in devs[:20]:
ugfx.Label(0, y, 240, 25, "{3}dB {1}".format(*dev))
y += status_height
instructions(duration)
## App quitting...
if btrestore:
sim800.btpoweroff()
ugfx.clear()
app.restart_to_default()

85
emfcampqueer_home/main.py Normal file
View File

@ -0,0 +1,85 @@
"""
emfcampqueer theme by ganbariley
"""
___name___ = "EMFCamp Rainbow Homescreen"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen"]
___launchable___ = False
___bootstrapped___ = False
import ugfx
from homescreen import *
import time
# Padding for name
intro_height = 30
intro_text = "Hi! I'm"
name_height = 60
status_height = 20
info_height = 30
logo_path = "emfcampqueer_home/pridelogo.png"
logo_height = 150
logo_width = 56
# Maximum length of name before downscaling
max_name = 8
# Background stuff
init()
ugfx.clear(ugfx.html_color(0x800080))
# Colour stuff
style = ugfx.Style()
style.set_enabled([ugfx.WHITE, ugfx.html_color(0x800080), ugfx.html_color(0x800080), ugfx.html_color(0x800080)])
style.set_background(ugfx.html_color(0x800080))
ugfx.set_default_style(style)
# Logo stuff
ugfx.display_image(
int((ugfx.width() - logo_width) / 2),
int((ugfx.height() - logo_height) / 2),
logo_path
)
# Draw for people to see
ugfx.orientation(90)
# Draw introduction
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.Label(0, ugfx.height() - name_height - intro_height, ugfx.width(), intro_height, intro_text, justification=ugfx.Label.CENTER)
# Process name
name_setting = name("Set your name in the settings app")
if len(name_setting) <= max_name:
ugfx.set_default_font(ugfx.FONT_NAME)
else:
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
# Draw name
ugfx.Label(0, ugfx.height() - name_height, ugfx.width(), name_height, name_setting, justification=ugfx.Label.CENTER)
# Draw for wearer to see
ugfx.orientation(270)
# Title
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.Label(0, ugfx.height() - info_height * 2, ugfx.width(), info_height, "TiLDA Mk4", justification=ugfx.Label.CENTER)
# info
ugfx.Label(0, ugfx.height() - info_height, ugfx.width(), info_height, "Press MENU", justification=ugfx.Label.CENTER)
ugfx.set_default_font(ugfx.FONT_SMALL)
status = ugfx.Label(0, ugfx.height() - info_height * 2 - status_height, ugfx.width(), status_height, "", justification=ugfx.Label.CENTER)
# update loop
while True:
text = "";
value_wifi_strength = wifi_strength()
value_battery = battery()
if value_wifi_strength:
text += "Wi-Fi: %s%%, " % int(value_wifi_strength)
if value_battery:
text += "Battery: %s%%" % int(value_battery)
status.text(text)
sleep_or_exit(0.5)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

75
enby/main.py Normal file
View File

@ -0,0 +1,75 @@
"""enby flag homescreen
Similar to the default homescreen, but the
background is the enby flag. Based on Pride Flag Homescreen by marekventur
"""
___name___ = "Enby"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "app"]
from app import restart_to_default
import ugfx
import homescreen
homescreen.init()
ugfx.clear(ugfx.html_color(0xFF0000))
# Used for placement around text
name_height = 55
info_height = 20
# Maximum length of name before downscaling
max_name = 8
# Orientation for other people to see
ugfx.orientation(90)
# enby flag colours
colours = [0xfff433, 0xffffff, 0x9b59d0, 0x000000]
# Draw each "band" of colour in the flag
colour_width = ugfx.width() / len(colours)
for num, colour in enumerate(colours):
width_loc = int(num * colour_width)
ugfx.area(width_loc, 0, int(colour_width), 320, ugfx.html_color(colour))
ugfx.set_default_font(ugfx.FONT_NAME)
# Calc center of screen
center = (int(ugfx.width() / 2), int(ugfx.height() / 2))
# Process name
given_name = homescreen.name("Set your name in the settings app")
if len(given_name) <= max_name:
ugfx.set_default_font(ugfx.FONT_NAME)
else:
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
# Draw name
ugfx.Label(0, ugfx.height() - name_height, ugfx.width(), name_height, given_name, justification=ugfx.Label.CENTER)
# Draw for the user to see
ugfx.orientation(270)
ugfx.set_default_font(ugfx.FONT_SMALL)
# WiFi/Battery update loop
while True:
ugfx.area(0, ugfx.height() - info_height, ugfx.width(), info_height, ugfx.WHITE)
wifi_strength_value = homescreen.wifi_strength()
if wifi_strength_value:
wifi_message = 'WiFi: %s%%' % int(wifi_strength_value)
wifi_text = ugfx.text(center[0], ugfx.height() - info_height, wifi_message, ugfx.BLACK)
battery_value = homescreen.battery()
if battery_value:
battery_message = 'Battery: %s%%' % int(battery_value)
battery_text = ugfx.text(0, ugfx.height() - info_height, battery_message, ugfx.BLACK)
homescreen.sleep_or_exit(1.5)
restart_to_default()

BIN
holland/eu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

242
holland/main.py Normal file
View File

@ -0,0 +1,242 @@
"""Camp Holland app
"""
___name___ = "Holland"
___license___ = "MIT"
___dependencies___ = ["app", "sim800", "ugfx_helper"]
___categories___ = ["Villages"]
___bootstrapped___ = True
from app import *
from dialogs import *
import ugfx
import ugfx_helper
from machine import Neopix
def show_screen(color1, color2, text, text2="", flip=False):
if flip:
ugfx.orientation(90)
ugfx.clear(ugfx.html_color(color1))
ugfx.set_default_font(ugfx.FONT_NAME)
ugfx.text(0, 100, text, ugfx.html_color(color2))
ugfx.set_default_font(ugfx.FONT_SMALL)
ugfx.text(0, 200, text2, ugfx.html_color(color2))
if flip:
ugfx.orientation(270)
def show_vip(inv):
if (inv):
show_screen(0xFFFFFF, 0xFFA400, "Dutch VIP", "", True)
else:
show_screen(0xFFA400, 0xFFFFFF, "Dutch VIP", "", True)
def show_flag():
ugfx.display_image(0, 0, "holland/nederland.png")
def show_boot():
ugfx.display_image(0, 0, "holland/start.png")
ugfx_helper.init()
ugfx.clear()
show_boot()
import sim800
import time
from tilda import Buttons
sim800.poweron()
n = Neopix()
vip = False
vip_inv = False
strobe = False
def cbButtonA(button_id):
global vip
vip = False
show_flag()
def cbButtonB(button_id):
global vip
vip = True
show_vip(vip_inv)
def load():
global vip
vip = False
show_screen(0x000000, 0xFFFFFF, "LOADING")
print("Copy AMR")
sim800.fscreate("REC\\1.AMR")
f = open('holland/wilhelmus.amr', 'r')
data = f.read(256)
c = len(data)
sim800.fswrite("REC\\1.AMR", data, True)
pr = c
while (c>0):
data = f.read(256)
c = len(data)
sim800.fswrite("REC\\1.AMR", data, False)
pr = pr + c
show_screen(0x000000, 0xFFFFFF, "LOADING", str(pr))
print(str(pr))
f.close()
show_screen(0x000000, 0xFFFFFF, "DONE")
wilhelmus = (
("D", 300), ("G", 300), ("G", 300), ("A", 300), ("B", 300), ("C2", 300), ("A", 300), ("B", 300), ("A", 300), ("B", 300), ("C2", 300), ("B", 300), ("A", 300), ("G", 300), ("A", 600), ("G", 600), ("D", 300),
("G", 300), ("G", 300), ("A", 300), ("B", 300), ("C2", 300), ("A", 300), ("B", 300), ("A", 300), ("B", 300), ("C", 300), ("B", 300), ("A", 600), ("G", 600), ("A", 600), ("G", 600), ("B", 300), ("C", 300),
)
freq = {
"C": 2616,
"D": 2936,
"E": 3296,
"F": 3492,
"G": 3920,
"A": 4400,
"B": 4938,
"C2": 5322,
}
def cbButtonCall(button_id):
sim800.speakervolume(100)
show_screen(0x000000, 0xFFFFFF, "TONE")
for note, length in wilhelmus:
sim800.playtone(freq.get(note, 9000), length, False)
def cbButton1(button_id):
global vip
vip = False
ugfx.display_image(0, 0, "holland/eu.png")
def cbButton2(button_id):
show_screen(0x000000, 0xFFFFFF, "PLAY")
a = sim800.startplayback(1,0,100)
if not a:
sim800.fsrm("REC\\1.AMR")
sim800.fsrm("REC\\2.AMR")
sim800.fsrm("REC\\3.AMR")
load()
show_screen(0x000000, 0xFFFFFF, "PLAY")
sim800.startplayback(1,0,100)
def cbButton3(button_id):
show_screen(0x000000, 0xFFFFFF, "STOP")
sim800.stopplayback()
def cbButton4(button_id):
global vip
vip = False
ugfx.display_image(0, 0, "holland/otter.png")
def cbButton5(button_id):
n.display([0xFFFFFF, 0xFFFFFF])
def cbButton6(button_id):
n.display([0x000000, 0x000000])
def cbButton7(button_id):
global vip
vip = False
show_boot()
def cbButton8(button_id):
global strobe
strobe = True
def cbButton9(button_id):
global strobe
strobe = False
Buttons.enable_interrupt(
Buttons.BTN_Call,
cbButtonCall,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_A,
cbButtonA,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_B,
cbButtonB,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_1,
cbButton1,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_2,
cbButton2,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_3,
cbButton3,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_4,
cbButton4,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_5,
cbButton5,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_6,
cbButton6,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_7,
cbButton7,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_8,
cbButton8,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_9,
cbButton9,
on_press=True,
on_release=False);
vip = True
aaa = False
while True:
if vip_inv:
vip_inv = False
else:
vip_inv = True
if vip:
show_vip(vip_inv)
if strobe:
if aaa:
n.display([0xFFA500, 0xFFA500])
aaa = False
else:
n.display([0x000000, 0x000000])
aaa = True
else:
time.sleep(0.1)

BIN
holland/nederland.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
holland/otter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
holland/start.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
holland/wilhelmus.amr Normal file

Binary file not shown.

View File

@ -83,6 +83,6 @@ while True:
if value_battery:
text += "Battery: %s%%" % int(value_battery)
status.text(text)
sleep_or_exit(5.0)
sleep_or_exit(0.5)
app.restart_to_default()

BIN
home_trans/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

175
home_trans/main.py Normal file
View File

@ -0,0 +1,175 @@
"""Trans homescreen
A version of the home screen that has a trans flag.
Press 0 to go back to normal or 8 to show the flag.
Hold * to activate all LEDs for use as a torch.
"""
___name___ = "Homescreen (Trans)"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "shared/logo.png"]
___launchable___ = False
___bootstrapped___ = False
import ugfx
from homescreen import *
import time
from tilda import Buttons
from machine import Pin
from machine import Neopix
torch = Pin(Pin.GPIO_FET)
neo = Neopix()
init()
# Padding for name
intro_height = 30
intro_text = "Hi! I'm"
name_height = 64
status_height = 20
info_height = 30
logo_path = "shared/logo.png"
trans_logo_path = "home_trans/logo.png"
logo_height = 150
logo_width = 56
# Maximum length of name before downscaling
max_name = 8
torch_on = False
# Background stuff
ugfx.clear(ugfx.html_color(0x55cdfc))
# Colour stuff
style = ugfx.Style()
style.set_enabled([ugfx.BLACK, ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc)])
style.set_background(ugfx.html_color(0x55cdfc))
ugfx.set_default_style(style)
ugfx.display_image(0, 0, "home_trans/trans.png")
# Logo stuff
ugfx.display_image(
int((ugfx.width() - logo_width) / 2),
int((ugfx.height() - logo_height) / 2)+9,
trans_logo_path
)
# Draw for people to see
ugfx.orientation(90)
# Draw introduction
style.set_enabled([ugfx.BLACK, ugfx.html_color(0xf8b0be), ugfx.html_color(0xf8b0be), ugfx.html_color(0xf8b0be)])
style.set_background(ugfx.html_color(0xf8b0be))
ugfx.set_default_style(style)
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.Label(0, ugfx.height() - name_height - intro_height, ugfx.width(), intro_height, intro_text, justification=ugfx.Label.CENTER)
# Prepare to draw name
style.set_enabled([ugfx.BLACK, ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc)])
style.set_background(ugfx.html_color(0x55cdfc))
ugfx.set_default_style(style)
# Process name
name_setting = name("Set your name in the settings app")
if len(name_setting) <= max_name:
ugfx.set_default_font(ugfx.FONT_NAME)
else:
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
# Draw name
ugfx.Label(0, ugfx.height() - name_height, ugfx.width(), name_height, name_setting, justification=ugfx.Label.CENTER)
# Draw for wearer to see
ugfx.orientation(270)
ugfx.set_default_font(ugfx.FONT_SMALL)
status = ugfx.Label(0, ugfx.height() - status_height, ugfx.width(), status_height, "", justification=ugfx.Label.LEFT)
def draw_badge():
style.set_enabled([ugfx.WHITE, ugfx.html_color(0x800080), ugfx.html_color(0x800080), ugfx.html_color(0x800080)])
style.set_background(ugfx.html_color(0x800080))
ugfx.clear(ugfx.html_color(0x800080))
ugfx.set_default_style(style)
# Logo stuff
ugfx.display_image(
int((ugfx.width() - logo_width) / 2),
int((ugfx.height() - logo_height) / 2),
logo_path
)
# Draw for people to see
ugfx.orientation(90)
# Draw introduction
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.Label(0, ugfx.height() - name_height - intro_height, ugfx.width(), intro_height, intro_text, justification=ugfx.Label.CENTER)
# Process name
name_setting = name("Set your name in the settings app")
if len(name_setting) <= max_name:
ugfx.set_default_font(ugfx.FONT_NAME)
else:
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
# Draw name
ugfx.Label(0, ugfx.height() - name_height, ugfx.width(), name_height, name_setting, justification=ugfx.Label.CENTER)
# Draw for wearer to see
ugfx.orientation(270)
ugfx.set_default_font(ugfx.FONT_SMALL)
status = ugfx.Label(0, ugfx.height() - status_height, ugfx.width(), status_height, "", justification=ugfx.Label.LEFT)
def draw_trans():
style.set_enabled([ugfx.BLACK, ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc)])
style.set_background(ugfx.html_color(0x55cdfc))
ugfx.set_default_style(style)
ugfx.display_image(0, 0, "home_trans/trans.png")
# Logo stuff
ugfx.display_image(
int((ugfx.width() - logo_width) / 2),
int((ugfx.height() - logo_height) / 2)+9,
trans_logo_path
)
# Draw for people to see
ugfx.orientation(90)
# Draw introduction
style.set_enabled([ugfx.BLACK, ugfx.html_color(0xf8b0be), ugfx.html_color(0xf8b0be), ugfx.html_color(0xf8b0be)])
style.set_background(ugfx.html_color(0xf8b0be))
ugfx.set_default_style(style)
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.Label(0, ugfx.height() - name_height - intro_height, ugfx.width(), intro_height, intro_text, justification=ugfx.Label.CENTER)
# Prepare to draw name
style.set_enabled([ugfx.BLACK, ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc)])
style.set_background(ugfx.html_color(0x55cdfc))
ugfx.set_default_style(style)
# Process name
name_setting = name("Set your name in the settings app")
if len(name_setting) <= max_name:
ugfx.set_default_font(ugfx.FONT_NAME)
else:
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
# Draw name
ugfx.Label(0, ugfx.height() - name_height, ugfx.width(), name_height, name_setting, justification=ugfx.Label.CENTER)
# Draw for wearer to see
ugfx.orientation(270)
ugfx.set_default_font(ugfx.FONT_SMALL)
status = ugfx.Label(0, ugfx.height() - status_height, ugfx.width(), status_height, "", justification=ugfx.Label.LEFT)
# update loop
while True:
text = "";
value_battery = battery()
if value_battery:
text += "%s%%" % int(value_battery)
if Buttons.is_pressed(Buttons.BTN_Star):
if torch_on:
torch_on = False
torch.off()
neo.display([0,0])
else:
torch_on = True
torch.on()
neo.display([0xffffff,0xffffff])
if Buttons.is_pressed(Buttons.BTN_8):
draw_trans()
if Buttons.is_pressed(Buttons.BTN_0):
draw_badge()
status.text(text)
sleep_or_exit(0.5)

BIN
home_trans/trans.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -4,6 +4,7 @@ ___license___ = "MIT"
___dependencies___ = ["buttons", "sleep"]
import ugfx, buttons, sleep
from buttons import Buttons
import time
default_style_badge = ugfx.Style()
@ -71,7 +72,7 @@ def prompt_boolean(text, title="TiLDA", true_text="Yes", false_text="No", font=F
if button_no: button_no.destroy()
label.destroy()
def prompt_text(description, init_text="", true_text="OK", false_text="Back", font=FONT_MEDIUM_BOLD, style=default_style_badge):
def prompt_text(description, init_text="", true_text="OK", false_text="Back", font=FONT_MEDIUM_BOLD, style=default_style_badge, numeric=False):
"""Shows a dialog and keyboard that allows the user to input/change a string
Returns None if user aborts with button B
@ -101,7 +102,7 @@ def prompt_text(description, init_text="", true_text="OK", false_text="Back", fo
if buttons.is_triggered(buttons.Buttons.BTN_A): return edit.text()
if buttons.is_triggered(buttons.Buttons.BTN_B): return None
if buttons.is_triggered(buttons.Buttons.BTN_Menu): return edit.text()
handle_keypad(edit)
handle_keypad(edit, numeric)
finally:
window.hide()
@ -115,7 +116,7 @@ def prompt_text(description, init_text="", true_text="OK", false_text="Back", fo
last_key = None
last_keytime = None
def handle_keypad(edit):
def handle_keypad(edit, numeric):
global last_key, last_keytime
threshold = 1000
keymap = {
@ -135,7 +136,9 @@ def handle_keypad(edit):
for key, chars in keymap.items():
if buttons.is_triggered(key):
if key != last_key:
if numeric:
edit.text(edit.text() + chars[-1])
elif key != last_key:
edit.text(edit.text() + chars[0])
else:
if last_keytime is None or (time.ticks_ms() - last_keytime) > threshold:
@ -210,6 +213,39 @@ def prompt_option(options, index=0, text = None, title=None, select_text="OK", n
return options[options_list.selected_index()]
if button_none and buttons.is_triggered(buttons.Buttons.BTN_B): return None
if button_none and buttons.is_triggered(buttons.Buttons.BTN_Menu): return None
# These are indexes for selected_index, 1 means "First item", ie index 0. 0 is treated as if it were 10
button_nums = {
Buttons.BTN_1: 0,
Buttons.BTN_2: 1,
Buttons.BTN_3: 2,
Buttons.BTN_4: 3,
Buttons.BTN_5: 4,
Buttons.BTN_6: 5,
Buttons.BTN_7: 6,
Buttons.BTN_8: 7,
Buttons.BTN_9: 8,
Buttons.BTN_0: 9,
}
for key, num in button_nums.items():
if buttons.is_triggered(key):
# No need to check for too large an index; gwinListSetSelected validates this.
options_list.selected_index(num)
break
if buttons.is_triggered(Buttons.BTN_Hash):
# Page down
idx = options_list.selected_index() + 10
cnt = options_list.count()
if idx >= cnt:
idx = cnt - 1
options_list.selected_index(idx)
continue
if buttons.is_triggered(Buttons.BTN_Star):
# Page up
idx = options_list.selected_index() - 10
if idx < 0:
idx = 0
options_list.selected_index(idx)
continue
finally:
window.hide()

View File

@ -558,7 +558,7 @@ def btscan(timeout=30000):
response = command("AT+BTSCAN=1," + str(int(timeout/1000)), timeout+8000, "+BTSCAN: 1")
for entry in extractvals("+BTSCAN: 0,", response):
splitentry = entry.split(",")
result = [int(splitentry[0]), splitentry[1].strip("\""), splitentry[2], int(splitentry[3])]
result.append([int(splitentry[0]), splitentry[1].strip("\""), splitentry[2], int(splitentry[3])])
return result
# Get the requesting paring device name

188
mario/main.py Normal file
View File

@ -0,0 +1,188 @@
"""
App Plays the Mario Theme.
TODO : Implement a break to exit the app if a user pushes any button whilst playing.
Gracefully reboot into main menu on Menu Press.
Replay Track when user pushes a button.
"""
___name___ = "Mario Theme"
___license___ = ""
___categories___ = ["Sound"]
___dependencies___ = ["speaker", "buttons", "ugfx_helper", "app", "wifi", "http", "sleep" ]
import ugfx_helper, os, wifi, ugfx, http, time, sleep, app,speaker
from tilda import Buttons
from buttons import *
from app import restart_to_default
from homescreen import *
import time
speaker.enabled(True)
ugfx_helper.init()
ugfx.clear()
ugfx.text(5, 5, "Loading Mario Image...", ugfx.BLACK)
try:
image = http.get("https://wiki.emfcamp.org/w/images/5/56/Screen.png").raise_for_status().content
ugfx.display_image(0,0,bytearray(image))
except:
ugfx.clear()
ugfx.text(5, 5, "Couldn't download Mario Image", ugfx.BLACK)
NOTE_B0 = 31
NOTE_C1 = 33
NOTE_CS1 = 35
NOTE_D1 = 37
NOTE_DS1 = 39
NOTE_E1 = 41
NOTE_F1 = 44
NOTE_FS1 = 46
NOTE_G1 = 49
NOTE_GS1 = 52
NOTE_A1 = 55
NOTE_AS1 = 58
NOTE_B1 = 62
NOTE_C2 = 65
NOTE_CS2 = 69
NOTE_D2 = 73
NOTE_DS2 = 78
NOTE_E2 = 82
NOTE_F2 = 87
NOTE_FS2 = 93
NOTE_G2 = 98
NOTE_GS2 = 104
NOTE_A2 = 110
NOTE_AS2 = 117
NOTE_B2 = 123
NOTE_C3 = 131
NOTE_CS3 = 139
NOTE_D3 = 147
NOTE_DS3 = 156
NOTE_E3 = 165
NOTE_F3 = 175
NOTE_FS3 = 185
NOTE_G3 = 196
NOTE_GS3 = 208
NOTE_A3 = 220
NOTE_AS3 = 233
NOTE_B3 = 247
NOTE_C4 = 262
NOTE_CS4 = 277
NOTE_D4 = 294
NOTE_DS4 = 311
NOTE_E4 = 330
NOTE_F4 = 349
NOTE_FS4 = 370
NOTE_G4 = 392
NOTE_GS4 = 415
NOTE_A4 = 440
NOTE_AS4 = 466
NOTE_B4 = 494
NOTE_C5 = 523
NOTE_CS5 = 554
NOTE_D5 = 587
NOTE_DS5 = 622
NOTE_E5 = 659
NOTE_F5 = 698
NOTE_FS5 = 740
NOTE_G5 = 784
NOTE_GS5 = 831
NOTE_A5 = 880
NOTE_AS5 = 932
NOTE_B5 = 988
NOTE_C6 = 1047
NOTE_CS6 = 1109
NOTE_D6 = 1175
NOTE_DS6 = 1245
NOTE_E6 = 1319
NOTE_F6 = 1397
NOTE_FS6 = 1480
NOTE_G6 = 1568
NOTE_GS6 = 1661
NOTE_A6 = 1760
NOTE_AS6 = 1865
NOTE_B6 = 1976
NOTE_C7 = 2093
NOTE_CS7 = 2217
NOTE_D7 = 2349
NOTE_DS7 = 2489
NOTE_E7 = 2637
NOTE_F7 = 2794
NOTE_FS7 = 2960
NOTE_G7 = 3136
NOTE_GS7 = 3322
NOTE_A7 = 3520
NOTE_AS7 = 3729
NOTE_B7 = 3951
NOTE_C8 = 4186
NOTE_CS8 = 4435
NOTE_D8 = 4699
NOTE_DS8 = 4978
def buzz(freq,timetorun):
speaker.frequency(freq)
sleep.sleep(0.001*timetorun)
speaker.stop()
melody = [
NOTE_E7, NOTE_E7, 0, NOTE_E7,
0, NOTE_C7, NOTE_E7, 0,
NOTE_G7, 0, 0, 0,
NOTE_G6, 0, 0, 0,
NOTE_C7, 0, 0, NOTE_G6,
0, 0, NOTE_E6, 0,
0, NOTE_A6, 0, NOTE_B6,
0, NOTE_AS6, NOTE_A6, 0,
NOTE_G6, NOTE_E7, NOTE_G7,
NOTE_A7, 0, NOTE_F7, NOTE_G7,
0, NOTE_E7, 0, NOTE_C7,
NOTE_D7, NOTE_B6, 0, 0,
NOTE_C7, 0, 0, NOTE_G6,
0, 0, NOTE_E6, 0,
0, NOTE_A6, 0, NOTE_B6,
0, NOTE_AS6, NOTE_A6, 0,
NOTE_G6, NOTE_E7, NOTE_G7,
NOTE_A7, 0, NOTE_F7, NOTE_G7,
0, NOTE_E7, 0, NOTE_C7,
NOTE_D7, NOTE_B6, 0, 0
]
tempo = [
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
9, 9, 9,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
9, 9, 9,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
]
size = len(melody)
for thisNote in range(0, size):
noteDuration = 1800 / tempo[thisNote];
buzz(melody[thisNote], noteDuration)
pauseBetweenNotes = noteDuration * 1.30;

48
party/main.py Normal file
View File

@ -0,0 +1,48 @@
'''Party thing
'''
___author___ = 'Skybound - ECS'
___name___ = 'Party'
___license___ = 'MIT'
___categories___ = ['LEDs']
___bootstrapped___ = False
from app import restart_to_default
import random
from machine import Neopix
from tilda import Buttons
n = Neopix()
mapping = {
0: 0x000001,
1: 0x000100,
2: 0x010000
}
exit = False
def breakout(x):
global exit
exit = True
Buttons.enable_interrupt(
Buttons.BTN_Menu,
breakout,
on_press=True,
on_release=False
)
while True:
store = [0, 0]
incs = [random.randint(0, 2) for _ in range(2)]
for i in range(0xff):
store[0] += mapping[incs[0]]
store[1] += mapping[incs[1]]
n.display(store)
if exit:
break
restart_to_default()

View File

@ -19,7 +19,7 @@ ugfx.clear()
def makecall():
notocall = prompt_text("Number to call:")
notocall = prompt_text("Number to call:", numeric=True)
if (notocall):
sim800.call(notocall)

82
screendisco/main.py Normal file

File diff suppressed because one or more lines are too long

BIN
shared/sw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -24,7 +24,7 @@ def send_message():
number = ""
message = ""
while True:
number = prompt_text("Number to message:", init_text=number)
number = prompt_text("Number to message:", init_text=number, numeric=True)
if number is None:
return
message = prompt_text("Message:", init_text=message)

924
star_wars/main.py Normal file
View File

@ -0,0 +1,924 @@
"""
Will play music, maybe
"""
___name___ = "Play Music"
___license___ = "MIT"
___categories___ = ["Sound"]
___dependencies___ = ["speaker", "shared/sw.png", "buttons"]
import random, ugfx, speaker, buttons, ugfx_helper
import time
import utime
from machine import Neopix
from tilda import LED
from homescreen import init, sleep_or_exit
from tilda import Buttons, Sensors
ledColours = [
0xFF0000,
0xFFFF00,
0x00FF00,
0x008000,
0x00FFFF,
0x0000FF,
0xFF00FF,
0xFA8072,
]
ledColourCount = len(ledColours)
logo_path = "shared/sw.png"
logo_height = 121
logo_width = 240
mute = False
# Setup
init()
neopix = Neopix()
ugfx_helper.init()
speaker.enabled(True)
####################
####################
####################
notes = [
{
"name": "G3",
"midi": 55,
"time": 1.5,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666666
},
{
"name": "G3",
"midi": 55,
"time": 1.6666666666666665,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666666
},
{
"name": "G3",
"midi": 55,
"time": 1.833333333333333,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666666
},
{
"name": "G3",
"midi": 55,
"time": 9.5,
"velocity": 0.6299212598425197,
"duration": 0.3156250000000007
},
{
"name": "G3",
"midi": 55,
"time": 9.833333333333334,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666675
},
{
"name": "G3",
"midi": 55,
"time": 17.5,
"velocity": 0.6299212598425197,
"duration": 0.3156250000000007
},
{
"name": "G3",
"midi": 55,
"time": 17.833333333333336,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "A3",
"midi": 57,
"time": 18,
"velocity": 0.6299212598425197,
"duration": 0.7114583333333329
},
{
"name": "A3",
"midi": 57,
"time": 18.75,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "A3",
"midi": 57,
"time": 20.833333333333336,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "B3",
"midi": 59,
"time": 21,
"velocity": 0.6299212598425197,
"duration": 0.47395833333333215
},
{
"name": "G3",
"midi": 55,
"time": 21.5,
"velocity": 0.6299212598425197,
"duration": 0.3156250000000007
},
{
"name": "G3",
"midi": 55,
"time": 21.833333333333336,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "A3",
"midi": 57,
"time": 22,
"velocity": 0.6299212598425197,
"duration": 0.7114583333333329
},
{
"name": "A3",
"midi": 57,
"time": 22.75,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "G3",
"midi": 55,
"time": 25.833333333333336,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "A3",
"midi": 57,
"time": 26,
"velocity": 0.6299212598425197,
"duration": 0.7114583333333329
},
{
"name": "A3",
"midi": 57,
"time": 26.75,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "A3",
"midi": 57,
"time": 28.833333333333336,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "B3",
"midi": 59,
"time": 29,
"velocity": 0.6299212598425197,
"duration": 0.47395833333333215
},
{
"name": "G3",
"midi": 55,
"time": 29.5,
"velocity": 0.6299212598425197,
"duration": 0.3156250000000007
},
{
"name": "G3",
"midi": 55,
"time": 29.833333333333336,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "G3",
"midi": 55,
"time": 32.5,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "G3",
"midi": 55,
"time": 32.666666666666664,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "G3",
"midi": 55,
"time": 32.83333333333333,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "G3",
"midi": 55,
"time": 32.99999999999999,
"velocity": 0.6299212598425197,
"duration": 0.4739583333333357
},
{
"name": "G3",
"midi": 55,
"time": 33.49999999999999,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333144
},
{
"name": "G3",
"midi": 55,
"time": 33.74999999999999,
"velocity": 0.6299212598425197,
"duration": 0.11770833333333286
},
{
"name": "G3",
"midi": 55,
"time": 33.87499999999999,
"velocity": 0.6299212598425197,
"duration": 0.11770833333333286
},
{
"name": "A3",
"midi": 57,
"time": 33.99999999999999,
"velocity": 0.6299212598425197,
"duration": 0.7114583333333329
},
{
"name": "C4",
"midi": 60,
"time": 34.74999999999999,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333144
},
{
"name": "G3",
"midi": 55,
"time": 37.49999999999999,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "G3",
"midi": 55,
"time": 37.66666666666666,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "G3",
"midi": 55,
"time": 37.83333333333332,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "G3",
"midi": 55,
"time": 45.499999999999986,
"velocity": 0.6299212598425197,
"duration": 0.31562499999999716
},
{
"name": "G3",
"midi": 55,
"time": 45.833333333333314,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "G3",
"midi": 55,
"time": 53.49999999999998,
"velocity": 0.6299212598425197,
"duration": 0.31562499999999716
},
{
"name": "G3",
"midi": 55,
"time": 53.83333333333331,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "C4",
"midi": 60,
"time": 2,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333336
},
{
"name": "G4",
"midi": 67,
"time": 3.0000000000000004,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333331
},
{
"name": "F4",
"midi": 65,
"time": 4,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666666
},
{
"name": "E4",
"midi": 64,
"time": 4.166666666666667,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666666
},
{
"name": "D4",
"midi": 62,
"time": 4.333333333333334,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666666
},
{
"name": "C5",
"midi": 72,
"time": 4.500000000000001,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333336
},
{
"name": "G4",
"midi": 67,
"time": 5.500000000000001,
"velocity": 0.6299212598425197,
"duration": 0.47395833333333304
},
{
"name": "F4",
"midi": 65,
"time": 6.000000000000001,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666666
},
{
"name": "E4",
"midi": 64,
"time": 6.166666666666668,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666666
},
{
"name": "D4",
"midi": 62,
"time": 6.333333333333335,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666666
},
{
"name": "C5",
"midi": 72,
"time": 6.500000000000002,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333336
},
{
"name": "G4",
"midi": 67,
"time": 7.500000000000002,
"velocity": 0.6299212598425197,
"duration": 0.47395833333333304
},
{
"name": "F4",
"midi": 65,
"time": 8.000000000000002,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666675
},
{
"name": "E4",
"midi": 64,
"time": 8.16666666666667,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666675
},
{
"name": "F4",
"midi": 65,
"time": 8.333333333333337,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666675
},
{
"name": "D4",
"midi": 62,
"time": 8.500000000000005,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333336
},
{
"name": "C4",
"midi": 60,
"time": 10.000000000000005,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333336
},
{
"name": "G4",
"midi": 67,
"time": 11.000000000000005,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333336
},
{
"name": "F4",
"midi": 65,
"time": 12.000000000000005,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666675
},
{
"name": "E4",
"midi": 64,
"time": 12.166666666666673,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666675
},
{
"name": "D4",
"midi": 62,
"time": 12.333333333333341,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666675
},
{
"name": "C5",
"midi": 72,
"time": 12.500000000000009,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333336
},
{
"name": "G4",
"midi": 67,
"time": 13.500000000000009,
"velocity": 0.6299212598425197,
"duration": 0.4739583333333339
},
{
"name": "F4",
"midi": 65,
"time": 14.000000000000009,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666675
},
{
"name": "E4",
"midi": 64,
"time": 14.166666666666677,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666675
},
{
"name": "D4",
"midi": 62,
"time": 14.333333333333345,
"velocity": 0.6299212598425197,
"duration": 0.1572916666666675
},
{
"name": "C5",
"midi": 72,
"time": 14.500000000000012,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333336
},
{
"name": "G4",
"midi": 67,
"time": 15.500000000000012,
"velocity": 0.6299212598425197,
"duration": 0.4739583333333339
},
{
"name": "F4",
"midi": 65,
"time": 16.000000000000014,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "E4",
"midi": 64,
"time": 16.16666666666668,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "F4",
"midi": 65,
"time": 16.333333333333343,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "D4",
"midi": 62,
"time": 16.500000000000007,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333336
},
{
"name": "F4",
"midi": 65,
"time": 19.000000000000007,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "E4",
"midi": 64,
"time": 19.250000000000007,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "D4",
"midi": 62,
"time": 19.500000000000007,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "C4",
"midi": 60,
"time": 19.750000000000007,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "C4",
"midi": 60,
"time": 20.000000000000007,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "D4",
"midi": 62,
"time": 20.16666666666667,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "E4",
"midi": 64,
"time": 20.333333333333336,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "D4",
"midi": 62,
"time": 20.5,
"velocity": 0.6299212598425197,
"duration": 0.3156250000000007
},
{
"name": "F4",
"midi": 65,
"time": 23,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "E4",
"midi": 64,
"time": 23.25,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "D4",
"midi": 62,
"time": 23.5,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "C4",
"midi": 60,
"time": 23.75,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "G4",
"midi": 67,
"time": 24,
"velocity": 0.6299212598425197,
"duration": 0.47395833333333215
},
{
"name": "D4",
"midi": 62,
"time": 24.5,
"velocity": 0.6299212598425197,
"duration": 0.9489583333333336
},
{
"name": "F4",
"midi": 65,
"time": 27,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "E4",
"midi": 64,
"time": 27.25,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "D4",
"midi": 62,
"time": 27.5,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "C4",
"midi": 60,
"time": 27.75,
"velocity": 0.6299212598425197,
"duration": 0.236458333333335
},
{
"name": "C4",
"midi": 60,
"time": 28,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "D4",
"midi": 62,
"time": 28.166666666666664,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "E4",
"midi": 64,
"time": 28.33333333333333,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "D4",
"midi": 62,
"time": 28.499999999999993,
"velocity": 0.6299212598425197,
"duration": 0.3156250000000007
},
{
"name": "C5",
"midi": 72,
"time": 29.999999999999993,
"velocity": 0.6299212598425197,
"duration": 0.3156250000000007
},
{
"name": "A#4",
"midi": 70,
"time": 30.33333333333333,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "G#4",
"midi": 68,
"time": 30.499999999999993,
"velocity": 0.6299212598425197,
"duration": 0.3156250000000007
},
{
"name": "G4",
"midi": 67,
"time": 30.83333333333333,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "F4",
"midi": 65,
"time": 30.999999999999993,
"velocity": 0.6299212598425197,
"duration": 0.3156250000000007
},
{
"name": "D#4",
"midi": 63,
"time": 31.33333333333333,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "D4",
"midi": 62,
"time": 31.499999999999993,
"velocity": 0.6299212598425197,
"duration": 0.3156250000000007
},
{
"name": "C4",
"midi": 60,
"time": 31.83333333333333,
"velocity": 0.6299212598425197,
"duration": 0.15729166666666572
},
{
"name": "G4",
"midi": 67,
"time": 31.999999999999993,
"velocity": 0.6299212598425197,
"duration": 0.4739583333333357
},
{
"name": "F4",
"midi": 65,
"time": 34.99999999999999,
"velocity": 0.6299212598425197,
"duration": 0.4739583333333357
},
{
"name": "D4",
"midi": 62,
"time": 35.49999999999999,
"velocity": 0.6299212598425197,
"duration": 1.8989583333333329
},
]
noteCount = len(notes)
notes.sort(key=lambda x: x['time'])
####################
####################
####################
def _random():
return (utime.ticks_ms() % 100) / 100
def _randrange(start, stop=None):
"""Return a randomly selected element from range(start, stop)"""
if stop is None:
stop = start
start = 0
random = _random()
randomRange = round(start + (random * (stop - start)))
return randomRange
def playMusic(stopTime = 99999):
global noteCount, notes
index = 0
startTime = utime.ticks_ms()
while True:
# Stop playing
if index >= noteCount or buttons.is_pressed(Buttons.BTN_A):
speaker.stop()
break
# How long have we been playing for
currentTime = utime.ticks_ms()
timeDiff = currentTime - startTime
# End early if told
if timeDiff > stopTime:
speaker.stop()
break
# Play note
note = notes[index]
if timeDiff > (note['time'] * 1000):
if 'midi' in note:
freq = 27.5 * pow(2, (note['midi'] - 21) / 12)
speaker.frequency(round(freq))
else:
speaker.stop()
index += 1
sleep_or_exit(0.1)
def doLights():
# LED Flash
if _randrange(1, 10) <= 5:
LED(LED.RED).on()
else:
LED(LED.RED).off()
if _randrange(1, 10) <= 5:
LED(LED.GREEN).on()
else:
LED(LED.GREEN).off()
# NEO Pixels
colorNum1 = _randrange(0, ledColourCount - 1)
colorNum2 = _randrange(0, ledColourCount - 1)
neopix.display([ledColours[colorNum1], ledColours[colorNum2]])
maxHeight = ugfx.height()
yPos = maxHeight
logo = ugfx.Image(logo_path, True)
def doScroll():
global yPos, maxHeight, logo
# Blank previous logo location
ugfx.area(0, yPos, ugfx.width(), yPos + logo_height, 0)
# Move up and wrap
yPos -= 20
if (yPos <= -logo_height):
yPos = maxHeight
# Draw logo
ugfx.display_image(
int((ugfx.width() - logo_width) / 2),
int(yPos),
logo
)
def blankScreen():
ugfx.clear(ugfx.BLACK)
def drawLogo():
# Return to default
ugfx.display_image(
int((ugfx.width() - logo_width) / 2),
int((ugfx.height() - logo_height) / 2),
logo
)
def drawTutorial():
ugfx.orientation(270)
# Draw for user
blankScreen()
ugfx.text(5, 5, "Buttons: A = music, B = lights", ugfx.WHITE)
ugfx.text(5, 25, "JoyStick Click = scrolling", ugfx.WHITE)
ugfx.text(5, ugfx.height() - 20, "By Pez (@Pezmc)", ugfx.WHITE)
def boot():
drawTutorial()
ugfx.orientation(90) # Draw for others
drawLogo()
playMusic(9500)
blankScreen()
#############
#############
#############
boot()
enableLights = False
enableScroll = True
while True:
# Toggle lights
if buttons.is_triggered(Buttons.BTN_B):
enableLights = not enableLights
neopix.display([0, 0]) # Lights off
# Play music
elif buttons.is_triggered(Buttons.BTN_A):
neopix.display([0, 0]) # Lights off
drawTutorial()
drawLogo()
playMusic()
# Toggle scroll
elif buttons.is_triggered(Buttons.JOY_Center):
enableScroll = not enableScroll
if not enableScroll:
blankScreen()
drawLogo()
else:
if enableLights:
doLights()
if enableScroll:
doScroll()
sleep_or_exit(0.1)