-
Notifications
You must be signed in to change notification settings - Fork 46
Expand file tree
/
Copy pathMP4.py
More file actions
264 lines (234 loc) · 8.26 KB
/
MP4.py
File metadata and controls
264 lines (234 loc) · 8.26 KB
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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
"""This is Katie and Audrey's Software Design Mini-Project 4. It uses pygame to load a music visualizer that you can jump on"""
import pygame
from pygame.locals import QUIT, KEYDOWN, KEYUP #our only controller should be the keyboard (and music) so no need to import mouse stuff
import time
from random import choice
import alsaaudio as aa
import audioop
import pickle
import math
import numpy as np
from struct import unpack
def calculate_levels(data, chunk,sample_rate):
"""This code, which we got from somebody else's project at https://www.raspberrypi.org/forums/viewtopic.php?p=314087, performs a fourier transform on the incoming audio stream, finding the amplitudes of 16 frequencies"""
# Convert raw data to numpy array
data = unpack("%dh"%(len(data)/2),data)
data = np.array(data, dtype='h')
# Apply FFT - real data so rfft used
fourier=np.fft.rfft(data)
# Remove last element in array to make it the same size as chunk
fourier=np.delete(fourier,len(fourier)-1)
# Find amplitude
power = np.log10(np.abs(fourier))**2
# Arrange array into 16 rows
power = np.reshape(power,(16,chunk/16))
matrix= (np.average(power, axis=1))
#This was part of testing how the music affected the transform by displaying it in the command line
#pretty_matrix = np.int_(matrix)
#print pretty_matrix
#Convert out of the weird numpy types
matrix=matrix.tolist()
return matrix
pygame.font.init
print pygame.font.get_default_font()
print pygame.font.match_font('freesansbold')
class PygameView(object):
""" Visualizes the music game in a pygame window """
def __init__(self, model, screen):
""" Initialize the view with the specified model
and screen. """
self.model = model
self.screen = screen
self.font = pygame.font.Font("freesansbold.ttf",30)
def draw(self):
""" Draw the game state to the screen """
self.screen.fill(pygame.Color('black')) #have a black background
#draw the music bars to the screen
for bar in self.model.bars:
pygame.draw.rect(self.screen, pygame.Color(bar.color),bar)
#draw the character to the screen
pygame.draw.rect(self.screen, pygame.Color('white'), self.model.character)
pygame.display.update()
def count(self):
counter = str(self.model.character.num_count)
text = self.font.render(counter,True,(255,255,255))
self.screen.blit(text,(10,10))
pygame.display.update()
class Bar(pygame.Rect):
"""A single vertical rectangle in the music visualizer"""
def __init__(self, left, top, width, height):
self.left = left
self.top = top
self.width = width
self.height = height
self.color = choice(['red','blue','green','orange','purple']) #TODO: make this more interesting colors
class Character(pygame.Rect):
""" Our little main character (also a rectanlge) """
def __init__(self, left, top, width, height):
""" Initialize our character """
self.left = left
self.top = top
self.width = width
self.height = height
self.bottom = self.top+self.height
self.vx = 0 #horizontal velocity
self.vy = 0 #vertical velocity
self.a = -20 #acceleration
self.on_ground = False
self.which_bar = None
self.num_count = 0
self.is_right = True
class MusicGameModel(object):
""" Stores the game state for our visualizer game """
def __init__(self):
#Initialize bars
self.bars = []
self.MARGIN = 5
self.BAR_WIDTH = 50
self.BAR_HEIGHT = 20
lc = self.MARGIN
for i in range(0,16):
tc = 480-self.BAR_HEIGHT
bar = Bar(lc, tc, self.BAR_WIDTH, self.BAR_HEIGHT)
lc += self.MARGIN +self.BAR_WIDTH
self.bars.append(bar)
#initialize character
self.character = Character(self.MARGIN, self.MARGIN + 20, 20, 50)
#Turn stuff into actual pygame objects - MUAHAHAHA INHERITANCE
def update_physics(self, vx=0, vy=0):
"""Adjust position and velocity"""
self.character.vx = vx
self.character.vy = vy - self.character.a
self.character.left += self.character.vx
self.character.top += self.character.vy
self.character.bottom = self.character.top+self.character.height
def detect_collisions(self):
"""checks if there are collisions with anything. If so, moves the character up out of the way"""
# #Turn stuff into actual pygame objects - unnecessary because inheritance!
for bar in self.bars:
i = self.bars.index(bar)
#check if the bar and character are colliding
if bar.colliderect(self.character):
#check if it approached from the top (the top row of the bar is inside character rectangle)
right_point=(bar.left+bar.width+10, bar.top-30)
left_point=(bar.left, bar.top-30)
if bar.collidepoint(right_point):
self.character.move(-5,0)
#print 'COLLIDE RIGHT'
break
if bar.collidepoint(left_point):
self.character.move(5,0)
#print 'COLLIDE LEFT'
break
for point in range(bar.left,bar.left+bar.width):
if bar.collidepoint:
self.character.on_ground = True
self.character.top -= 1
self.character.which_bar = self.bars[i]
#print 'COLLIDE BOTTOM'
break
#checks for collisions with the bottom of the screen
if self.character.bottom > 480:
self.character.top = 480-self.character.height
self.character.on_ground = True
#checks for collisions with the top of the screen
if self.character.top < 0:
self.character.top = 0
#checks for collisions with the left of the screen
if self.character.left < 0:
self.character.left = 0
if not self.character.is_right:
self.character.num_count+=1
self.character.is_right = True
#checks for collisions with the right of the screen
if self.character.left > 640-self.character.width:
self.character.left = 640 - self.character.width
if self.character.is_right:
self.character.num_count +=1
self.character.is_right = False
def jump(self):
"""Keeps character from jumping in mid-air, and adjust bar-sitting to false"""
if self.character.on_ground:
self.update_physics(0,-100)
else:
self.update_physics()
self.character.on_ground = False
self.character.which_bar = None
def sit_on_bar(self):
"""Makes the character sit on the bar when not jumping"""
if self.character.which_bar != None:
self.character.top = self.character.which_bar.top - self.character.height - 18
class PyGameKeyboardController(object):
# class PyGameController(object):
def __init__(self, model):
self.model = model
pygame.key.set_repeat(10,20)
def handle_event(self, event):
""" Look for keypresses to
modify the x adn y positions of the character"""
if event.type == KEYDOWN:
if event.key == pygame.K_LEFT:
self.model.update_physics(-10)
self.model.detect_collisions()
elif event.key == pygame.K_RIGHT:
self.model.update_physics(10)
self.model.detect_collisions()
if event.key == pygame.K_UP:
self.model.jump()
self.model.detect_collisions()
class MusicController(object):
def __init__(self, model):
self.model = model
def adjust_bars(self, music_chunk):
"""Changes the bars heights in the model based on the current values for music"""
mc_sum = 0
for i in range(len(music_chunk[:-1])):
mc_sum += music_chunk[i+1]
avg_mc = mc_sum/len(music_chunk[1:-1])
for i in range(len(music_chunk[:-1])):
bars_list=self.model.bars
current_bar=bars_list[i-1]
current_bar.height=300-100*math.fabs(music_chunk[i]-avg_mc)
current_bar.top=480-current_bar.height
if __name__ == '__main__':
pygame.init()
size = (640, 480)
screen = pygame.display.set_mode(size)
model = MusicGameModel()
view = PygameView(model, screen)
controller = PyGameKeyboardController(model)
music = MusicController(model)
#Music setup
sample_rate = 44100
no_channels = 2
chunk = 512 # Use a multiple of 8
data_in = aa.PCM(aa.PCM_CAPTURE, aa.PCM_NORMAL)#'front:CARD=PCH,DEV=0'
data_in.setchannels(no_channels)
data_in.setrate(sample_rate)
data_in.setformat(aa.PCM_FORMAT_S16_LE)
data_in.setperiodsize(chunk)
running = True
while running:
#Quit Game
for event in pygame.event.get():
if event.type == QUIT:
running = False
controller.handle_event(event)
#Music Controls
l,data = data_in.read()
data_in.pause(1)
if l:
# catch frame error
try:
current_levels=calculate_levels(data, chunk, sample_rate)
music.adjust_bars(current_levels)
model.sit_on_bar()
except audioop.error, e:
if e.message !="not a whole number of frames":
raise e
model.detect_collisions()
model.update_physics()
view.draw()
view.count()
time.sleep(.1)
data_in.pause(0)