-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSingingGame.py
221 lines (172 loc) · 8 KB
/
SingingGame.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
from pythonosc import dispatcher
from pythonosc import osc_server
import pygame
import numpy as np
import argparse
import sys
class KaraokeGame:
def gameTrack(tupArray):
noteArray = []
for note, duration in tupArray:
noteArray += [note for i in range(duration)]
return (noteArray)
def __init__(self, max_history=20, canvas_size=(800, 300), padding=50, players=[]):
self.canvas_size = canvas_size
self.min_y_pos = padding
self.y_range = canvas_size[1] - (2 * padding)
self.players = players
arr1 = np.linspace(0,1,300)
arr2 = np.linspace(1,0,300)
arr3 = np.linspace(0, 0.5, 100)
arr4 = np.linspace(0.5,0,200)
arr5 =[np.abs(np.sin(i)) for i in np.linspace(-np.pi, np.pi, 500)]
arr6 = np.linspace(0,0.2,100)
arr7 = np.linspace(0.2,0.2,100)
arr8 = np.linspace(0.7,0.7,100)
arr9 = np.linspace(0.7,0,200)
arr10 = [np.abs(np.sin(i)) for i in np.linspace(-np.pi, np.pi, 700)]
arr11 = list(arr1) + list(arr2) +list(arr3) +list(arr4) +list(arr5) +list(arr6) + list(arr7) + list(arr8) + list(arr9) + list(arr10)
self.song = arr11
# Place a red bar every 500 notes
for i in range(0, len(self.song)):
if (i % 500 == 0):
self.song[i] = -1
self.time = 0
self.scores = []
# Define max histoy size and initialize default (empty) history.
self.max_history = max_history
self.history = []
# Define color hex.
#self.colors = {'black': (0,0,0),
# 'white': (255,255,255),
# 'red': (255,0, 0),
# 'green': (0,255,0),
# 'blue': (0,0,255)}
# Define player colors.
#self.player_colors = {1: 'white',
# 2: 'green',
# 3: 'blue',
# 4: 'red'}
self.current_player = players[0]
# Initialize pygame
pygame.init()
# Initialize pygame font module (used to display text)
pygame.font.init()
self.myfont = pygame.font.SysFont('Comic Sans MS', 30)
# Initialize white game canvas
self.game_canvas = pygame.display.set_mode(canvas_size)
self.game_canvas.fill((255,255,255))
pygame.display.set_caption('Hello World!')
def update_history(self, y):
# If the len(history) < max_history, append y to history and take mean.
# Do not pop from history until history has reach max history size.
if len(self.history) < self.max_history:
self.history.append(y)
y_avg = np.mean(self.history)
# If len(history) == max_history, append y to end of history, pop
# first element of history, and take mean.
elif y > 0.1:
self.history.append(y)
self.history.pop(0)
y_avg = np.mean(self.history)
# If y < 0.1, do not change history. Use 0 for y_avg.
else:
y_avg = 0
return(y_avg)
def calc_y_pos(self, y):
# The range of y is defined as the y dimension of the canvas -
# 2 * padding.
# y_pos is found by scaling y_range with y_avg, and then adding the
# minimum y position (the padding).
y_pos = self.canvas_size[1] - (int(y * self.y_range) + self.min_y_pos)
return(y_pos)
def calc_score(self, y, y_hat):
# Calculate score as difference of y and y_hat.
# Append score to self.scores, and return score for display.
#if ((note < 0) and (self.current_player is not self.players[0])):
if (y < 0) and (self.current_player is not self.players[0]):
self.score = -100 * (len(self.current_player.scores)/2)
self.current_player.scores = self.current_player.scores + [self.score]
return(self.score)
else:
self.score = 100 - (int(np.abs(y - y_hat) * 100))
self.current_player.scores = self.current_player.scores + [self.score]
return(self.score)
def display_score(self, score):
textsurface = self.myfont.render('{}'.format(score), False, (0, 155, 155))
textsurface_score_1 = self.myfont.render('Score: {}'.format(int(np.mean(self.players[1].scores))), False, (0, 255, 0))
#textsurface_total_2 = self.myfont.render('Score: {}'.format(int(np.mean(self.players[2].scores))), False, (0, 0, 255))
#textsurface_total_3 = self.myfont.render('Score: {}'.format(int(np.mean(self.players[3].scores))), False, (255, 0, 0))
self.game_canvas.blit(textsurface,(0,0))
self.game_canvas.blit(textsurface_score_1,(0,250))
#self.game_canvas.blit(textsurface_total_2,(0,210))
#self.game_canvas.blit(textsurface_total_3,(0,250))
def update_display(self, signal_name, y):
# Check if game window has been closed.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
y_avg = self.update_history(y)
# only use every 5 updates because we get updates too frequently
if self.time % 5 != 0:
self.time += 1
return
self.game_canvas.fill((255,255,255))
for note_index in range(self.time, (self.time + self.canvas_size[0])):
try:
note = self.song[note_index]
except:
note = 0
if(note > 0):
pygame.draw.circle(self.game_canvas,
(0,0,0),
(50 + (note_index - self.time), self.calc_y_pos(note)),
30,
0)
if(note < 0):
r = pygame.Rect(50 + (note_index - self.time), 0, 30, self.canvas_size[1])
pygame.draw.rect(self.game_canvas, (255,0,0), r)
# If y_avg > 0, update display using y_avg to calculate the y-position
# of the feedback circle.
if y_avg > 0:
y_pos = self.calc_y_pos(y_avg)
# Circle color is the color mapped to the given player stored in
# current_player.
circle_color = self.current_player.color
pygame.draw.circle(self.game_canvas,
circle_color,
(50, y_pos),
20,
0)
score = self.calc_score(self.song[self.time], y_avg)
self.display_score(score)
self.time += 1
pygame.display.update()
def singer_handler(self, signal_name, singer):
self.current_player = self.players[int(singer-1)]
class Player:
def __init__(self, color=(0,0,0), scores=[0], name="Somebody"):
self.color = color
self.scores = scores
self.name = name
if __name__ == "__main__":
p0 = Player(color=(255,255,255), name="Nobody")
p1 = Player(color=(0,255,0))
singers = [p0,p1]
game = KaraokeGame(players=singers)
# Parse arguments for host ip and port.
parser = argparse.ArgumentParser()
parser.add_argument("--ip",
default='127.0.0.1', help="The ip to listen on")
parser.add_argument("--port",
type=int, default='12000', help="The port to listen on")
args = parser.parse_args()
# Create dispatcher to handle incoming OSC messages.
dispatcher = dispatcher.Dispatcher()
dispatcher.map("/wek/update", game.update_display)
dispatcher.map("/wek/singer", game.singer_handler)
server = osc_server.ThreadingOSCUDPServer(
(args.ip, args.port), dispatcher)
print("Serving on {}".format(server.server_address))
server.serve_forever()