annotate visualclient2/visclient.py @ 54:c0b34039917a tip

Server: added an exposed function to log the start time of a performance (for log-to-audio sync)
author Mathieu Barthet <mathieu.barthet@eecs.qmul.ac.uk>
date Wed, 14 Oct 2015 19:20:08 +0100
parents 2db17c224664
children 874ac833c8e3
rev   line source
gyorgyf@37 1 #!/usr/bin/env python
gyorgyf@37 2 # encoding: utf-8
gyorgyf@37 3 """
gyorgyf@37 4 visclient.py
gyorgyf@37 5
gyorgyf@37 6 Created by George Fazekas on 2012-06-17.
gyorgyf@37 7 Copyright (c) 2012 . All rights reserved.
gyorgyf@37 8 """
gyorgyf@37 9
gyorgyf@37 10 import sys,os,math,time,copy
gyorgyf@37 11 import pygame as pg
gyorgyf@37 12 from pygame.locals import *
gyorgyf@37 13 from pygame import gfxdraw as gd
gyorgyf@37 14 import httplib as ht
gyorgyf@37 15
gyorgyf@37 16 import gradients
gyorgyf@37 17 from gradients import genericFxyGradient
gyorgyf@37 18
gyorgyf@37 19 from threading import Thread
gyorgyf@37 20 from random import random
gyorgyf@37 21
gyorgyf@37 22 import colorsys as cs
gyorgyf@37 23
gyorgyf@37 24 scol = (0,255,0,255)
gyorgyf@37 25 ecol = (0,0,0,255)
gyorgyf@37 26
gyorgyf@37 27 xavg=0
gyorgyf@37 28 yavg=0
gyorgyf@37 29 countavg=0
gyorgyf@37 30 moods = []
gyorgyf@37 31
gyorgyf@37 32
gyorgyf@37 33 # X,Y=1140,900
gyorgyf@37 34 # X,Y = 600,400
gyorgyf@37 35 X,Y = 800,600
gyorgyf@37 36 # X,Y = 1024,768
gyorgyf@37 37
gyorgyf@37 38 # Fullscreen resolution:
gyorgyf@37 39 # XF,YF = 1280,900
gyorgyf@37 40 # XF,YF = 1440,900
gyorgyf@37 41 XF,YF = 1344,900
gyorgyf@37 42 # display calibrated
gyorgyf@37 43
gyorgyf@37 44 # detect display resolution
gyorgyf@37 45 import subprocess
gyorgyf@37 46 screenres = subprocess.Popen('xrandr | grep "\*" | cut -d" " -f4',shell=True, stdout=subprocess.PIPE).communicate()[0]
gyorgyf@37 47 screenres = map(lambda x: int(x.strip()), screenres.split('x'))
gyorgyf@37 48 XF,YF = screenres
gyorgyf@37 49 print "Screen resolution: ",XF,YF
gyorgyf@37 50
gyorgyf@37 51
gyorgyf@37 52 # NBLOBS = 18
gyorgyf@37 53 # BLOBSIZE = 25
gyorgyf@37 54 # G=110
gyorgyf@37 55 # FADE = 15
gyorgyf@37 56 # DIST = 0.15 # blob equivalence tolerance
gyorgyf@37 57 # FRAMERATE = 60
gyorgyf@37 58
gyorgyf@37 59 # new parameters
gyorgyf@37 60 NBLOBS = 18
gyorgyf@37 61 BLOBSIZE = 25
gyorgyf@37 62 G=110
gyorgyf@37 63 FADE = 25
gyorgyf@37 64 DIST = 0.10 # blob equivalence tolerance
gyorgyf@37 65 FRAMERATE = 120
gyorgyf@37 66
gyorgyf@37 67
gyorgyf@37 68 # Connection:
gyorgyf@37 69 # IP = "127.0.0.1:8030"
gyorgyf@37 70 # IP = "192.168.2.158:8030"
gyorgyf@37 71 IP = "138.37.95.215" # this is the IP of kakapo<=>golden
gyorgyf@37 72 HTTP_TIMEOUT = 3
gyorgyf@37 73 SERVER_UPDATE_INTERVAL = 0.8
gyorgyf@37 74
gyorgyf@37 75
gyorgyf@37 76 class Indicator(object):
gyorgyf@37 77
gyorgyf@37 78
gyorgyf@37 79 def __init__(self,bg,pos,invisible=False):
gyorgyf@37 80
gyorgyf@37 81 self.off_color = pg.Color(110,0,0)
gyorgyf@37 82 self.on_color = pg.Color(0,120,0)
gyorgyf@37 83 if invisible :
gyorgyf@37 84 self.off_color = pg.Color(0,0,0)
gyorgyf@37 85 self.on_color = pg.Color(0,0,120)
gyorgyf@37 86 self.visible = True
gyorgyf@37 87 self.ison = True
gyorgyf@37 88 self.x,self.y = pos
gyorgyf@37 89 self.xs = int(self.x * X)
gyorgyf@37 90 self.ys = int(Y - (self.y * Y))
gyorgyf@37 91 self.c = self.off_color
gyorgyf@37 92 self.size = 6
gyorgyf@37 93 self.bg = bg
gyorgyf@37 94
gyorgyf@37 95 def reinit(self,bg):
gyorgyf@37 96 self.bg = bg
gyorgyf@37 97 self.xs = int(self.x * X)
gyorgyf@37 98 self.ys = int(Y - (self.y * Y))
gyorgyf@37 99
gyorgyf@37 100 def draw(self):
gyorgyf@37 101 if self.visible :
gyorgyf@37 102 # pg.draw.circle(self.bg, self.c, (self.xs,self.ys),self.size,0)
gyorgyf@37 103 # gd.aacircle(self.bg, self.xs, self.ys, self.size+1, self.c)
gyorgyf@37 104 gd.filled_circle(self.bg, self.xs, self.ys, self.size, self.c)
gyorgyf@37 105 gd.aacircle(self.bg, self.xs, self.ys, self.size, self.c)
gyorgyf@37 106
gyorgyf@37 107
gyorgyf@37 108 def toggle(self):
gyorgyf@37 109 if self.ison == True :
gyorgyf@37 110 self.off()
gyorgyf@37 111 else :
gyorgyf@37 112 self.on()
gyorgyf@37 113 return self
gyorgyf@37 114
gyorgyf@37 115 def on(self):
gyorgyf@37 116 self.c = self.on_color
gyorgyf@37 117 self.ison = True
gyorgyf@37 118 return self
gyorgyf@37 119
gyorgyf@37 120 def off(self):
gyorgyf@37 121 self.c = self.off_color
gyorgyf@37 122 self.ison = False
gyorgyf@37 123 return self
gyorgyf@37 124
gyorgyf@37 125 def now(self,screen):
gyorgyf@37 126 # for i in self.indicators.itervalues() :
gyorgyf@37 127 # i.draw()
gyorgyf@37 128 self.draw()
gyorgyf@37 129 screen.blit(self.bg, (0, 0))
gyorgyf@37 130 pg.display.flip()
gyorgyf@37 131 return self
gyorgyf@37 132
gyorgyf@37 133 class MovingBlob(object):
gyorgyf@37 134
gyorgyf@37 135 black_color = pg.Color(0,0,0)
gyorgyf@37 136
gyorgyf@37 137 def __init__(self,bg,x,y,color=(255,255,255),mood=None,fade=FADE):
gyorgyf@37 138 self.x = x
gyorgyf@37 139 self.y = y
gyorgyf@37 140 self.xs = x * X
gyorgyf@37 141 self.ys = Y - (y * Y)
gyorgyf@37 142 self.bg = bg
gyorgyf@37 143 self.size = BLOBSIZE
gyorgyf@37 144 self.time = time.time()
gyorgyf@37 145 self.alpha = 255
gyorgyf@37 146 self.c = color
gyorgyf@37 147 self.count = 1
gyorgyf@37 148 self.visible = True
gyorgyf@37 149 self.FADE = fade
gyorgyf@37 150 self.mood = mood
gyorgyf@37 151 if mood and mood.color :
gyorgyf@37 152 self.c = mood.color
gyorgyf@37 153 self.title = mood.word
gyorgyf@37 154 self.speed_factor = 80.0
gyorgyf@37 155 self.target_x = 0.0
gyorgyf@37 156 self.target_y = 0.0
gyorgyf@37 157
gyorgyf@37 158 def set_target(self,x,y):
gyorgyf@37 159 self.target_x = x
gyorgyf@37 160 self.target_y = y
gyorgyf@37 161
gyorgyf@37 162 def draw(self):
gyorgyf@37 163 if not self.visible : return
gyorgyf@37 164
gyorgyf@37 165 global xavg,yavg,moods
gyorgyf@37 166 # xspeed = (xavg - self.x) / self.speed_factor
gyorgyf@37 167 # yspeed = (yavg - self.y) / self.speed_factor
gyorgyf@37 168 # self.x = self.x + xspeed
gyorgyf@37 169 # self.y = self.y + yspeed
gyorgyf@37 170 self.x = self.x + (self.target_x - self.x) / self.speed_factor
gyorgyf@37 171 self.y = self.y + (self.target_y - self.y) / self.speed_factor
gyorgyf@37 172
gyorgyf@37 173 #self.size = countavg//TODO
gyorgyf@37 174 self.xs = self.x * X
gyorgyf@37 175 self.ys = Y - (self.y * Y)
gyorgyf@37 176 #d=int(self.size)
gyorgyf@37 177
gyorgyf@37 178 d = cd = sys.float_info.max
gyorgyf@37 179
gyorgyf@37 180 for mood in moods :
gyorgyf@37 181 d = mood.get_distance(self.x,self.y)
gyorgyf@37 182 if d < cd :
gyorgyf@37 183 cd = d
gyorgyf@37 184 self.mood = mood
gyorgyf@37 185 self.c = mood.color
gyorgyf@37 186 self.title = mood.word
gyorgyf@37 187
gyorgyf@37 188 # self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,self.alpha)), (self.xs-BLOBSIZE,self.ys-BLOBSIZE))
gyorgyf@37 189 d=int(self.size)
gyorgyf@37 190 # print d
gyorgyf@37 191 self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,self.alpha)), (self.xs-d,self.ys-d))
gyorgyf@37 192 gd.aacircle(self.bg, int(self.xs), int(self.ys), int(self.size), self.black_color)
gyorgyf@37 193 gd.aacircle(self.bg, int(self.xs), int(self.ys), int(self.size-1), self.black_color)
gyorgyf@37 194
gyorgyf@37 195
gyorgyf@37 196 font = pg.font.Font(None, 36)
gyorgyf@37 197 text = font.render(self.title, 1, self.c)
gyorgyf@37 198 textpos = text.get_rect()
gyorgyf@37 199 #print textpos.width
gyorgyf@37 200 if self.xs > X- textpos.width:
gyorgyf@37 201 if self.ys > Y- textpos.height:
gyorgyf@37 202 self.bg.blit(text, (self.xs - textpos.width,self.ys - textpos.height))
gyorgyf@37 203 else:
gyorgyf@37 204 self.bg.blit(text, (self.xs - textpos.width,self.ys))
gyorgyf@37 205
gyorgyf@37 206 else :
gyorgyf@37 207 if self.ys > Y- textpos.height:
gyorgyf@37 208 self.bg.blit(text, (self.xs,self.ys - textpos.height))
gyorgyf@37 209 else:
gyorgyf@37 210 self.bg.blit(text, (self.xs,self.ys))
gyorgyf@37 211 #self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,self.alpha)), (self.xs-d,self.ys-d))
gyorgyf@37 212 #self.alpha = 255 - int(self.age()*self.FADE)
gyorgyf@37 213 #if self.alpha < 5 :
gyorgyf@37 214 # self.alpha = 1
gyorgyf@37 215 # self.visible = False
gyorgyf@37 216
gyorgyf@37 217 def age(self):
gyorgyf@37 218 return time.time() - self.time
gyorgyf@37 219
gyorgyf@37 220 def resize(self,count):
gyorgyf@37 221 if self.count == count :
gyorgyf@37 222 return None
gyorgyf@37 223 self.time = time.time()
gyorgyf@37 224 self.count = count
gyorgyf@37 225 # self.size = int(BLOBSIZE * int(self.count/1.5))
gyorgyf@37 226 self.to = int(BLOBSIZE * int(self.count/1.5))
gyorgyf@37 227 if self.to < BLOBSIZE :
gyorgyf@37 228 self.to = BLOBSIZE
gyorgyf@37 229 if self.to and self.size != self.to:
gyorgyf@37 230 self.start_animate()
gyorgyf@37 231 # print "resize to",count,self.to
gyorgyf@37 232
gyorgyf@37 233 def get_distance(self,x,y):
gyorgyf@37 234 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) )
gyorgyf@37 235
gyorgyf@37 236 def fade(self,fade):
gyorgyf@37 237 if not fade : self.alpha = 255
gyorgyf@37 238 self.FADE = fade
gyorgyf@37 239
gyorgyf@37 240 def reset_time(self):
gyorgyf@37 241 self.time = time.time()
gyorgyf@37 242
gyorgyf@37 243 def reinit(self,bg):
gyorgyf@37 244 self.bg = bg
gyorgyf@37 245 self.xs = int(self.x * X)
gyorgyf@37 246 self.ys = int(Y - (self.y * Y))
gyorgyf@37 247
gyorgyf@37 248 def start_animate(self):
gyorgyf@37 249 self.thread = Thread(target = self.animate)
gyorgyf@37 250 self.thread.daemon = True
gyorgyf@37 251 self.thread.start()
gyorgyf@37 252
gyorgyf@37 253 def animate(self):
gyorgyf@37 254 '''Animate the way bubbles are grown.'''
gyorgyf@37 255 tolerance = 5
gyorgyf@37 256 # while self.size > self.to-tolerance and self.size < self.to+tolerance :
gyorgyf@37 257 while self.size != self.to :
gyorgyf@37 258 self.size = int(self.size + int(self.to-self.size) * 0.1)
gyorgyf@37 259 time_inc = 20.0 / (pow(1.2, abs(self.to-self.size)) * 200.0)
gyorgyf@37 260 time.sleep(0.02+time_inc)
gyorgyf@37 261 # print "sizing to ", self.to
gyorgyf@37 262
gyorgyf@37 263
gyorgyf@37 264 class Blob(object):
gyorgyf@37 265
gyorgyf@37 266 def __init__(self,bg,x,y,color=(255,255,255),mood=None,fade=FADE):
gyorgyf@37 267 self.x = x
gyorgyf@37 268 self.y = y
gyorgyf@37 269 self.xs = x * X
gyorgyf@37 270 self.ys = Y - (y * Y)
gyorgyf@37 271 self.bg = bg
gyorgyf@37 272 self.size = BLOBSIZE #pixels
gyorgyf@37 273 self.time = time.time() #s
gyorgyf@37 274 self.const_time = time.time() #s
gyorgyf@37 275 self.alpha = 255 #8-bit alpha channel value
gyorgyf@37 276 self.c = color #RGB colour 3-tuple
gyorgyf@37 277 self.count = 1
gyorgyf@37 278 self.visible = True
gyorgyf@37 279 self.FADE = fade
gyorgyf@37 280 if mood and mood.color :
gyorgyf@37 281 self.c = mood.color
gyorgyf@37 282 self.title = mood.word
gyorgyf@37 283 self.inactivity_delay = 75.0 #s
gyorgyf@37 284 self.proximity_delay = 35.0 #s
gyorgyf@37 285 self.proximity_tolerance = 0.13
gyorgyf@37 286 self.target_in_proximity = None
gyorgyf@37 287
gyorgyf@37 288 def __cmp__(self,other):
gyorgyf@37 289 if other is None :
gyorgyf@37 290 return -1
gyorgyf@37 291 d = math.sqrt( math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2) )
gyorgyf@37 292 if d < DIST :
gyorgyf@37 293 return 0
gyorgyf@37 294 else :
gyorgyf@37 295 return -1
gyorgyf@37 296
gyorgyf@37 297 def object_in_proximity(self,other):
gyorgyf@37 298 if other is None :
gyorgyf@37 299 return False
gyorgyf@37 300 d = math.sqrt( math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2) )
gyorgyf@37 301 if d < self.proximity_tolerance :
gyorgyf@37 302 return True
gyorgyf@37 303 else :
gyorgyf@37 304 return False
gyorgyf@37 305
gyorgyf@37 306 def check_target_proximity(self,target):
gyorgyf@37 307 '''Check if the moving bubble is in proximity of this object. As soon as it is there, mark the time.
gyorgyf@37 308 We do not want to reset this time just wait until this bubble dies due to inactivity in its region.'''
gyorgyf@37 309 prox = self.object_in_proximity(target)
gyorgyf@37 310 if self.target_in_proximity is None and prox is True :
gyorgyf@37 311 self.target_in_proximity = time.time()
gyorgyf@37 312 # if prox is False :
gyorgyf@37 313 # self.target_in_proximity = None
gyorgyf@37 314
gyorgyf@37 315 def draw(self):
gyorgyf@37 316 if not self.visible : return
gyorgyf@37 317
gyorgyf@37 318 d=int(self.size)
gyorgyf@37 319 self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,self.alpha)), (self.xs-d,self.ys-d))
gyorgyf@37 320 self.alpha = 255 - int(self.age()*self.FADE)
gyorgyf@37 321 if self.alpha < 5 :
gyorgyf@37 322 self.alpha = 1
gyorgyf@37 323 self.visible = False
gyorgyf@37 324
gyorgyf@37 325 def age(self):
gyorgyf@37 326 return time.time() - self.time
gyorgyf@37 327
gyorgyf@37 328 def real_age(self):
gyorgyf@37 329 return time.time() - self.const_time
gyorgyf@37 330
gyorgyf@37 331 def age_weight(self):
gyorgyf@37 332 age_s = time.time() - self.const_time
gyorgyf@37 333 if age_s < self.inactivity_delay :
gyorgyf@37 334 return 1.0
gyorgyf@37 335 return 1.0 / ((age_s-self.inactivity_delay+1)*10.0)
gyorgyf@37 336
gyorgyf@37 337 def proximity_weight(self):
gyorgyf@37 338 if self.target_in_proximity == None :
gyorgyf@37 339 return 1.0
gyorgyf@37 340 age_s = time.time() - self.target_in_proximity
gyorgyf@37 341 if age_s < self.proximity_delay :
gyorgyf@37 342 return 1.0
gyorgyf@37 343 return 1.0 / ((age_s-self.proximity_delay+1)*10.0)
gyorgyf@37 344
gyorgyf@37 345 def increment(self,count):
gyorgyf@37 346 self.time = time.time()
gyorgyf@37 347 self.count = count
gyorgyf@37 348 # self.size = int(BLOBSIZE * int(self.count/1.5))
gyorgyf@37 349 self.to = int(BLOBSIZE * int(self.count/1.5))
gyorgyf@37 350 if self.to < 250 :
gyorgyf@37 351 self.start_animate()
gyorgyf@37 352
gyorgyf@37 353 def get_distance(self,x,y):
gyorgyf@37 354 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) )
gyorgyf@37 355
gyorgyf@37 356 def fade(self,fade):
gyorgyf@37 357 if not fade : self.alpha = 255
gyorgyf@37 358 self.FADE = fade
gyorgyf@37 359
gyorgyf@37 360 def reset_time(self):
gyorgyf@37 361 self.time = time.time()
gyorgyf@37 362
gyorgyf@37 363 def start_animate(self):
gyorgyf@37 364 self.thread = Thread(target = self.animate)
gyorgyf@37 365 self.thread.daemon = True
gyorgyf@37 366 self.thread.start()
gyorgyf@37 367
gyorgyf@37 368 def animate(self):
gyorgyf@37 369 '''Animate the way bubbles are grown.'''
gyorgyf@37 370 while self.size < self.to :
gyorgyf@37 371 self.size += 1
gyorgyf@37 372 time_inc = 20.0 / (pow(1.2, self.to-self.size) * 200.0)
gyorgyf@37 373 time.sleep(0.02+time_inc)
gyorgyf@37 374
gyorgyf@37 375 def force(self,other):
gyorgyf@37 376 '''Calculate the force between this object and another'''
gyorgyf@37 377 if other is None :
gyorgyf@37 378 return 0.0,0.0,False
gyorgyf@37 379 captured = False
gyorgyf@37 380 ds = math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2)
gyorgyf@37 381 if ds < 0.005 :
gyorgyf@37 382 return 0.0,0.0,False
gyorgyf@37 383 d = math.sqrt(ds)
gyorgyf@37 384 if d < 0.07 :
gyorgyf@37 385 captured = True
gyorgyf@37 386 # return 0.0,0.0,False
gyorgyf@37 387 m1,m2 = self.size,other.size
gyorgyf@37 388 G = 6.674 * 0.000001
gyorgyf@37 389 f = - G * (m1*m2) / ds
gyorgyf@37 390 x = f * (other.x-self.x) / d
gyorgyf@37 391 y = f * (other.y-self.y) / d
gyorgyf@37 392 return x,y,captured
gyorgyf@37 393
gyorgyf@37 394
gyorgyf@37 395 class BlobTrail(object):
gyorgyf@37 396
gyorgyf@37 397 def __init__(self,bg,x,y,color=(255,255,255),mood=None,fade=FADE):
gyorgyf@37 398 self.x = x
gyorgyf@37 399 self.y = y
gyorgyf@37 400 self.xs = x * X
gyorgyf@37 401 self.ys = Y - (y * Y)
gyorgyf@37 402 self.bg = bg
gyorgyf@37 403 self.size = BLOBSIZE
gyorgyf@37 404 self.time = time.time()
gyorgyf@37 405 self.alpha = 255
gyorgyf@37 406 self.c = color
gyorgyf@37 407 self.count = 1
gyorgyf@37 408 self.visible = True
gyorgyf@37 409 self.FADE = fade
gyorgyf@37 410 if mood and mood.color :
gyorgyf@37 411 self.c = mood.color
gyorgyf@37 412 self.title = mood.word
gyorgyf@37 413
gyorgyf@37 414 def __cmp__(self,other):
gyorgyf@37 415 d = math.sqrt( math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2) )
gyorgyf@37 416 if d < DIST :
gyorgyf@37 417 return 0
gyorgyf@37 418 else :
gyorgyf@37 419 return -1
gyorgyf@37 420
gyorgyf@37 421 def draw(self):
gyorgyf@37 422 if not self.visible : return
gyorgyf@37 423
gyorgyf@37 424 d=int(self.size)
gyorgyf@37 425 self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,0)), (self.xs-d,self.ys-d))
gyorgyf@37 426 self.alpha = 255 - int(self.age()*self.FADE)
gyorgyf@37 427 if self.alpha < 5 :
gyorgyf@37 428 self.alpha = 1
gyorgyf@37 429 self.visible = False
gyorgyf@37 430
gyorgyf@37 431 def age(self):
gyorgyf@37 432 return time.time() - self.time
gyorgyf@37 433
gyorgyf@37 434 def increment(self,count):
gyorgyf@37 435 self.time = time.time()
gyorgyf@37 436 self.count = count
gyorgyf@37 437 # self.size = int(BLOBSIZE * int(self.count/1.5))
gyorgyf@37 438 self.to = int(BLOBSIZE * int(self.count/1.5))
gyorgyf@37 439 self.start_animate()
gyorgyf@37 440
gyorgyf@37 441 def get_distance(self,x,y):
gyorgyf@37 442 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) )
gyorgyf@37 443
gyorgyf@37 444 def fade(self,fade):
gyorgyf@37 445 if not fade : self.alpha = 255
gyorgyf@37 446 self.FADE = fade
gyorgyf@37 447
gyorgyf@37 448 def reset_time(self):
gyorgyf@37 449 self.time = time.time()
gyorgyf@37 450
gyorgyf@37 451 def start_animate(self):
gyorgyf@37 452 self.thread = Thread(target = self.animate)
gyorgyf@37 453 self.thread.daemon = True
gyorgyf@37 454 self.thread.start()
gyorgyf@37 455
gyorgyf@37 456 def animate(self):
gyorgyf@37 457 '''Animate the way bubbles are grown.'''
gyorgyf@37 458 while self.size < self.to :
gyorgyf@37 459 self.size += 1
gyorgyf@37 460 time_inc = 20.0 / (pow(1.2, self.to-self.size) * 200.0)
gyorgyf@37 461 time.sleep(0.02+time_inc)
gyorgyf@37 462
gyorgyf@37 463
gyorgyf@37 464 class Mood():
gyorgyf@37 465
gyorgyf@37 466 def __init__(self,word,x,y):
gyorgyf@37 467 self.word = word
gyorgyf@37 468 self.x = (float(x)/ 2.0) + 0.5
gyorgyf@37 469 self.y = (float(y)/ 2.0) + 0.5
gyorgyf@37 470 self.color = []
gyorgyf@37 471
gyorgyf@37 472 def get_distance(self,x,y):
gyorgyf@37 473 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) )
gyorgyf@37 474
gyorgyf@37 475 def __repr__(self):
gyorgyf@37 476 return "Mood(%s,%3.2f,%3.2f)" %(self.word,self.x,self.y)
gyorgyf@37 477
gyorgyf@37 478
gyorgyf@37 479
gyorgyf@37 480 class VisualClient(object):
gyorgyf@37 481 '''Main visualisation client.'''
gyorgyf@37 482 global moods,blobTrail
gyorgyf@37 483
gyorgyf@37 484 def __init__(self):
gyorgyf@37 485 # self.conn = ht.HTTPConnection("192.168.2.184:8030")
gyorgyf@37 486 # self.conn = ht.HTTPConnection("138.37.95.215")
gyorgyf@37 487 self.s_age = 10
gyorgyf@37 488 self.s_dist = DIST
gyorgyf@37 489 self.s_ninp = 18
gyorgyf@37 490
gyorgyf@37 491 pg.init()
gyorgyf@37 492 pg.font.init()
gyorgyf@37 493
gyorgyf@37 494 # fontObj = pg.font.Font("freesansbold.ttf",18)
gyorgyf@37 495 white = ( 255, 255, 255)
gyorgyf@37 496 black = ( 0,0,0)
gyorgyf@37 497
gyorgyf@37 498 self.fpsClock = pg.time.Clock()
gyorgyf@37 499 self.screen = pg.display.set_mode((X, Y))
gyorgyf@37 500 pg.display.set_caption('Mood Conductor')
gyorgyf@37 501 self.bg = pg.Surface(self.screen.get_size())
gyorgyf@37 502 self.bg = self.bg.convert()
gyorgyf@37 503 self.bg.fill((0,0,0))
gyorgyf@37 504 pg.display.set_gamma(100.0)
gyorgyf@37 505
gyorgyf@37 506
gyorgyf@37 507 self.scol = (0,255,0,255)
gyorgyf@37 508 self.ecol = (0,0,0,255)
gyorgyf@37 509 coordstxt = "test"
gyorgyf@37 510
gyorgyf@37 511 self.blobs = []
gyorgyf@37 512 #self.moods = []
gyorgyf@37 513 self.bt=[]
gyorgyf@37 514
gyorgyf@37 515 self.movingBlob = None
gyorgyf@37 516
gyorgyf@37 517 self.read_mood_data()
gyorgyf@37 518
gyorgyf@37 519 self.FADE = FADE
gyorgyf@37 520
gyorgyf@37 521 self.indicators = {
gyorgyf@37 522 "conn":Indicator(self.bg,(0.98,0.02)), # connection active
gyorgyf@37 523 "update":Indicator(self.bg,(0.96,0.02)), # update thread executing
gyorgyf@37 524 "data":Indicator(self.bg,(0.94,0.02)), # data status changed
gyorgyf@37 525 "receive":Indicator(self.bg,(0.92,0.02)), # data received
gyorgyf@37 526 "grow":Indicator(self.bg,(0.90,0.02)), # blob growth active
gyorgyf@37 527 "ignore":Indicator(self.bg,(0.88,0.02),True), # little AI: ignore some clusters in certain condition
gyorgyf@37 528 "suspend":Indicator(self.bg,(0.86,0.02),True), # prevent adding new blobs (key: d)
gyorgyf@37 529 "config":Indicator(self.bg,(0.84,0.02),True), # sending config data
gyorgyf@37 530 "fade":Indicator(self.bg,(0.82,0.02),True)} # fade on/off (key: s)
gyorgyf@37 531
gyorgyf@37 532 self.thread = None
gyorgyf@37 533 self.running = False
gyorgyf@37 534 self.fullscreen = False
gyorgyf@37 535 self.init_reconnect = False
gyorgyf@37 536 self.suspend = False
gyorgyf@37 537
gyorgyf@37 538 pass
gyorgyf@37 539
gyorgyf@37 540
gyorgyf@37 541 def read_mood_data(self):
gyorgyf@37 542 '''Read the mood position and color information form csv file.'''
gyorgyf@37 543 # file = 'moods.csv'
gyorgyf@37 544 file = '../tags/mc_moodtags_lfm_curated2.csv'
gyorgyf@37 545 with open(file) as mf:
gyorgyf@37 546 data = mf.readlines()[1:]
gyorgyf@37 547 for line in data :
gyorgyf@37 548 l = line.split(',')
gyorgyf@37 549 l = map(lambda x:x.replace("'","").strip(),l)
gyorgyf@37 550 mood = Mood(l[0],l[1],l[2])
gyorgyf@37 551 moods.append(mood)
gyorgyf@37 552 print moods
gyorgyf@37 553 for mood in moods:
gyorgyf@37 554 print"['%s',%2.2f,%2.2f,0,0]," %(mood.word,mood.x,mood.y)
gyorgyf@37 555
gyorgyf@37 556 with open('colors.txt') as ff:
gyorgyf@37 557 data = ff.readlines()[1:]
gyorgyf@37 558 data = map(lambda x: x.split(','),data)
gyorgyf@37 559 for mood in moods :
gyorgyf@37 560 d = cd = sys.float_info.max
gyorgyf@37 561 for colors in data :
gyorgyf@37 562 d = mood.get_distance(float(colors[0]),float(colors[1]))
gyorgyf@37 563 if d < cd :
gyorgyf@37 564 cd = d
gyorgyf@37 565 # mood.color = tuple(map(lambda x: int(pow(math.atan((float(x)/7.0)),12.5)),(colors[2],colors[3],colors[4])))
gyorgyf@37 566 mood.color = self.set_color(tuple(map(lambda x: int(x),(colors[2],colors[3],colors[4]))))
gyorgyf@37 567 return True
gyorgyf@37 568
gyorgyf@37 569 def set_color(self,color):
gyorgyf@37 570 '''Move to HLS colour space and manipulate saturation there.'''
gyorgyf@37 571 # TODO: ideally, we need a non-linear compressor of the lightness and saturation values
gyorgyf@37 572 r,g,b = map(lambda x: (1.0*x/255.0), color)
gyorgyf@37 573 h,l,s = cs.rgb_to_hls(r,g,b)
gyorgyf@37 574 s = 1.0 #1.0 - (1.0 / pow(50.0,s))
gyorgyf@37 575 l = 1.0 - (1.0 / pow(20.0,l)) #0.6
gyorgyf@37 576 r,g,b = map(lambda x: int(x*255), cs.hls_to_rgb(h,l,s))
gyorgyf@37 577 return r,g,b
gyorgyf@37 578
gyorgyf@37 579 def start_update_thread(self):
gyorgyf@37 580 '''Start the thread that reads data from the server.'''
gyorgyf@37 581 time.sleep(SERVER_UPDATE_INTERVAL)
gyorgyf@37 582 self.thread = Thread(target = self.update_thread)
gyorgyf@37 583 self.thread.daemon = True
gyorgyf@37 584 self.running = True
gyorgyf@37 585 self.thread.start()
gyorgyf@37 586 print "OK. Update thread started."
gyorgyf@37 587
gyorgyf@37 588 def stop_update_thread(self):
gyorgyf@37 589 '''Stop the thread and allow some time fot the connections to close.'''
gyorgyf@37 590 self.running = False
gyorgyf@37 591 try :
gyorgyf@37 592 self.thread.join(2)
gyorgyf@37 593 self.indicators["conn"].off()
gyorgyf@37 594 self.indicators["update"].off()
gyorgyf@37 595 except :
gyorgyf@37 596 print "No update thread to join."
gyorgyf@37 597
gyorgyf@37 598 def update_thread(self):
gyorgyf@37 599 '''The server update thread'''
gyorgyf@37 600 print "Thread reporting..."
gyorgyf@37 601 while self.running :
gyorgyf@37 602 # self.update()
gyorgyf@37 603 try :
gyorgyf@37 604 self.update()
gyorgyf@37 605 # self.indicators["update"].visible = True
gyorgyf@37 606 except Exception, e:
gyorgyf@37 607 if str(e).strip() : print "Exception: ", str(e), type(e), len(str(e).strip())
gyorgyf@37 608 self.indicators["conn"].off()
gyorgyf@37 609 # self.indicators["update"].visible = False
gyorgyf@37 610 try :
gyorgyf@37 611 time.sleep(SERVER_UPDATE_INTERVAL)
gyorgyf@37 612 except :
gyorgyf@37 613 if str(e).strip() : print "Exception: ", str(e), type(e), len(str(e).strip())
gyorgyf@37 614 self.indicators["conn"].off()
gyorgyf@37 615
gyorgyf@37 616
gyorgyf@37 617 def update(self):
gyorgyf@37 618 '''Update the blob list from the server. This should be in a thread.'''
gyorgyf@37 619 # global xavg, yavg, countavg
gyorgyf@37 620 # indicate connection health by toggling an indictor
gyorgyf@37 621 self.indicators["update"].toggle()
gyorgyf@37 622
gyorgyf@37 623 # delete invisibles
gyorgyf@37 624 for blob in self.blobs :
gyorgyf@37 625 if not blob.visible :
gyorgyf@37 626 self.blobs.remove(blob)
gyorgyf@37 627
gyorgyf@37 628 # get new coordinates from the server
gyorgyf@37 629 self.conn.putrequest("GET","/moodconductor/result", skip_host=True)
gyorgyf@37 630 self.conn.putheader("Host", "www.isophonics.net")
gyorgyf@37 631 self.conn.endheaders()
gyorgyf@37 632 res = self.conn.getresponse()
gyorgyf@37 633 data = res.read()
gyorgyf@37 634 data = eval(data)
gyorgyf@37 635 if not data :
gyorgyf@37 636 self.conn.close()
gyorgyf@37 637 self.indicators["data"].toggle()
gyorgyf@37 638 return False
gyorgyf@37 639
gyorgyf@37 640 tempx = 0
gyorgyf@37 641 tempy = 0
gyorgyf@37 642 tempcount = 0
gyorgyf@37 643
gyorgyf@37 644 for d in data :
gyorgyf@37 645 # coordstxt = "x:%s y:%s c:%s" %d
gyorgyf@37 646 x,y,count = d
gyorgyf@37 647
gyorgyf@37 648 tempx = tempx + x*count
gyorgyf@37 649 tempy = tempy + y*count
gyorgyf@37 650 tempcount = tempcount + count
gyorgyf@37 651
gyorgyf@37 652 self.add_blob(x,y,count)
gyorgyf@37 653 self.indicators["receive"].toggle()
gyorgyf@37 654
gyorgyf@37 655 xavg = tempx/tempcount
gyorgyf@37 656 yavg = tempy/tempcount
gyorgyf@37 657 countavg = tempcount/len(data)
gyorgyf@37 658 # print xavg, yavg, countavg
gyorgyf@37 659 # if not self.blobs :
gyorgyf@37 660 # self.add_blob(xavg,yavg,countavg)
gyorgyf@37 661 # self.indicators["receive"].toggle()
gyorgyf@37 662
gyorgyf@37 663 self.conn.close()
gyorgyf@37 664 self.blobs = self.blobs[:NBLOBS]
gyorgyf@37 665 return True
gyorgyf@37 666
gyorgyf@37 667
gyorgyf@37 668 def add_blob(self,x,y,count=1):
gyorgyf@37 669 '''Insert a blob to the list of blobs'''
gyorgyf@37 670 # find mood correxponding to x,y
gyorgyf@37 671 if self.suspend :
gyorgyf@37 672 return None
gyorgyf@37 673 cmood = None
gyorgyf@37 674 d = cd = sys.float_info.max
gyorgyf@37 675 for mood in moods :
gyorgyf@37 676 d = mood.get_distance(x,y)
gyorgyf@37 677 if d < cd :
gyorgyf@37 678 cd = d
gyorgyf@37 679 cmood = mood
gyorgyf@37 680 # create new blob or increase click count on existing one
gyorgyf@37 681 new = Blob(self.bg,x,y,mood=cmood,fade=self.FADE)
gyorgyf@37 682 if self.movingBlob == None :
gyorgyf@37 683 self.movingBlob = MovingBlob(self.bg,x,y,mood=cmood,fade=self.FADE)
gyorgyf@37 684 if not new in self.blobs :
gyorgyf@37 685 self.blobs.insert(0,new)
gyorgyf@37 686 elif count > self.blobs[self.blobs.index(new)].count:
gyorgyf@37 687 self.blobs[self.blobs.index(new)].increment(count)
gyorgyf@37 688 self.indicators["grow"].toggle()
gyorgyf@37 689 pass
gyorgyf@37 690
gyorgyf@37 691
gyorgyf@37 692 def draw(self):
gyorgyf@37 693 '''Draw all objects'''
gyorgyf@37 694 global xavg, yavg, countavg
gyorgyf@37 695
gyorgyf@37 696 self.bg.fill((0,0,0,1))
gyorgyf@37 697 # self.bg.blit(gradients.radial(19, self.scol, self.ecol), (rect_x,rect_y))
gyorgyf@37 698 forces = []
gyorgyf@37 699 l = copy.copy(self.blobs)
gyorgyf@37 700 l.reverse()
gyorgyf@37 701 xt,yt = 0.0,0.0
gyorgyf@37 702 bs = 1
gyorgyf@37 703 c = 1
gyorgyf@37 704 # captured_by = None
gyorgyf@37 705
gyorgyf@37 706 # calculate exponential weighted average of the visible blobs
gyorgyf@37 707 ignore = False
gyorgyf@37 708 for blob in l :
gyorgyf@37 709 blob.draw()
gyorgyf@37 710 c = c + blob.count
gyorgyf@37 711 # aw = blob.age_weight()
gyorgyf@37 712 aw = blob.proximity_weight()
gyorgyf@37 713 if aw < 1.0 : ignore = True
gyorgyf@37 714 w = math.pow(blob.size+(blob.alpha/2.0),7) * aw
gyorgyf@37 715 xt = xt + blob.x * w
gyorgyf@37 716 yt = yt + blob.y * w
gyorgyf@37 717 bs = bs + w
gyorgyf@37 718 if self.movingBlob != None :
gyorgyf@37 719 blob.check_target_proximity(self.movingBlob)
gyorgyf@37 720 xavg = xt / bs
gyorgyf@37 721 yavg = yt / bs
gyorgyf@37 722 # countavg = bs/(len(l)+1)
gyorgyf@37 723 countavg = int(c/(len(l)+1))
gyorgyf@37 724 if ignore :
gyorgyf@37 725 self.indicators["ignore"].on()
gyorgyf@37 726 else :
gyorgyf@37 727 self.indicators["ignore"].off()
gyorgyf@37 728
gyorgyf@37 729 # compute gravity force
gyorgyf@37 730 # if self.movingBlob != None :
gyorgyf@37 731 # x,y,c = blob.force(self.movingBlob)
gyorgyf@37 732 # forces.append((x,y))
gyorgyf@37 733 # if c : captured_by = blob
gyorgyf@37 734 # tx,ty = reduce(lambda a,b:(a[0]+b[0],a[1]+b[1]), forces, (0.5,0.5))
gyorgyf@37 735
gyorgyf@37 736 # print tx,ty
gyorgyf@37 737 # if tx>1.0 : tx = 1.0
gyorgyf@37 738 # if tx<0.0 : tx = 0.0
gyorgyf@37 739 # if ty>1.0 : ty = 1.0
gyorgyf@37 740 # if ty<0.0 : ty = 0.0
gyorgyf@37 741
gyorgyf@37 742 # xavg,yavg = tx,ty
gyorgyf@37 743
gyorgyf@37 744 # if tx <= 1.0 and tx >= 0.0 and ty <= 1.0 and ty >= 0.0 :
gyorgyf@37 745 # xavg,yavg = tx,ty
gyorgyf@37 746 # countavg = 15
gyorgyf@37 747 # print tx,ty
gyorgyf@37 748 # else :
gyorgyf@37 749 # print "out of bounds:",tx,ty
gyorgyf@37 750 # if captured_by != None :
gyorgyf@37 751 # xavg,yavg = captured_by.x,captured_by.y
gyorgyf@37 752 l = copy.copy(self.bt)
gyorgyf@37 753 l.reverse()
gyorgyf@37 754 for trail in l:
gyorgyf@37 755 trail.draw()
gyorgyf@37 756 if self.movingBlob != None :
gyorgyf@37 757 # self.movingBlob.resize(countavg)
gyorgyf@37 758 self.movingBlob.set_target(xavg,yavg)
gyorgyf@37 759 self.movingBlob.draw()
gyorgyf@37 760 new = BlobTrail(self.bg,self.movingBlob.x,self.movingBlob.y,mood=self.movingBlob.mood,fade=18)
gyorgyf@37 761 self.bt.insert(0,new)
gyorgyf@37 762 # axis
gyorgyf@37 763 pg.draw.line(self.bg, (G,G,G), (int(X/2.0),0),(int(X/2.0),Y), 1)
gyorgyf@37 764 pg.draw.line(self.bg, (G,G,G), (0,int(Y/2.0)),(X,int(Y/2.0)), 1)
gyorgyf@37 765
gyorgyf@37 766 # indicators
gyorgyf@37 767 for i in self.indicators.itervalues() :
gyorgyf@37 768 i.draw()
gyorgyf@37 769
gyorgyf@37 770 def read_keys(self):
gyorgyf@37 771 '''Read keys'''
gyorgyf@37 772 for event in pg.event.get() :
gyorgyf@37 773 # Quit (event)
gyorgyf@37 774 if event.type == QUIT:
gyorgyf@37 775 self.quit()
gyorgyf@37 776 elif event.type == KEYDOWN :
gyorgyf@37 777 # Post Quit: Esc, q
gyorgyf@37 778 if event.key == K_ESCAPE or event.key == K_q :
gyorgyf@37 779 pg.event.post(pg.event.Event(QUIT))
gyorgyf@37 780 # Reset: Space
gyorgyf@37 781 elif event.key == K_SPACE :
gyorgyf@37 782 if not self.blobs :
gyorgyf@37 783 self.bt = []
gyorgyf@37 784 self.blobs = []
gyorgyf@37 785 # Random : r
gyorgyf@37 786 elif event.key == K_r :
gyorgyf@37 787 self.add_blob(random(),random(),count=5)
gyorgyf@37 788 # Connection : c
gyorgyf@37 789 elif event.key == K_c :
gyorgyf@37 790 self.init_reconnect = True
gyorgyf@37 791 self.indicators["conn"].off()
gyorgyf@37 792 # Fullscreen: f
gyorgyf@37 793 elif event.key == K_f :
gyorgyf@37 794 # pg.display.toggle_fullscreen()
gyorgyf@37 795 self.toggle_screen_mode()
gyorgyf@37 796 # Toggle suspend: d
gyorgyf@37 797 elif event.key == K_d :
gyorgyf@37 798 if self.suspend :
gyorgyf@37 799 print "suspend off"
gyorgyf@37 800 self.indicators["suspend"].off()
gyorgyf@37 801 self.suspend = False
gyorgyf@37 802 else:
gyorgyf@37 803 print "suspend on"
gyorgyf@37 804 self.indicators["suspend"].on()
gyorgyf@37 805 self.suspend = True
gyorgyf@37 806 # Toggle fade: s
gyorgyf@37 807 elif event.key == K_s :
gyorgyf@37 808 if self.FADE > 0:
gyorgyf@37 809 print "fade off"
gyorgyf@37 810 self.indicators["fade"].off()
gyorgyf@37 811 self.FADE = 0
gyorgyf@37 812 for blob in self.blobs :
gyorgyf@37 813 blob.fade(0)
gyorgyf@37 814 else:
gyorgyf@37 815 print "fade on"
gyorgyf@37 816 self.indicators["fade"].on()
gyorgyf@37 817 self.FADE = FADE
gyorgyf@37 818 for blob in self.blobs :
gyorgyf@37 819 blob.fade(FADE)
gyorgyf@37 820 blob.reset_time()
gyorgyf@37 821 # inc age
gyorgyf@37 822 elif event.key == K_1 :
gyorgyf@37 823 self.s_age += 1
gyorgyf@37 824 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
gyorgyf@37 825 # dec age
gyorgyf@37 826 elif event.key == K_2 :
gyorgyf@37 827 self.s_age -= 1
gyorgyf@37 828 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
gyorgyf@37 829 # inc dist
gyorgyf@37 830 elif event.key == K_3 :
gyorgyf@37 831 self.s_dist += 0.025
gyorgyf@37 832 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
gyorgyf@37 833 # dec dist
gyorgyf@37 834 elif event.key == K_4 :
gyorgyf@37 835 self.s_dist -= 0.025
gyorgyf@37 836 if self.s_dist < 0.025 : self.s_dist = 0.025
gyorgyf@37 837 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
gyorgyf@37 838 # inc ninp
gyorgyf@37 839 elif event.key == K_5 :
gyorgyf@37 840 self.s_ninp += 1
gyorgyf@37 841 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
gyorgyf@37 842 # dec ninp
gyorgyf@37 843 elif event.key == K_6 :
gyorgyf@37 844 self.s_ninp -= 1
gyorgyf@37 845 if self.s_ninp < 2 : self.s_ninp = 2
gyorgyf@37 846 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
gyorgyf@37 847 # choose different app and restart server
gyorgyf@37 848 elif event.key == K_9 :
gyorgyf@37 849 self.choose_app()
gyorgyf@37 850
gyorgyf@37 851 pass
gyorgyf@37 852 pass
gyorgyf@37 853
gyorgyf@37 854 def toggle_screen_mode(self):
gyorgyf@37 855 '''Go back and forth between full screen mode.'''
gyorgyf@37 856 if self.fullscreen == False:
gyorgyf@37 857 globals()['_X'] = globals()['X']
gyorgyf@37 858 globals()['_Y'] = globals()['Y']
gyorgyf@37 859 globals()['X'] = XF
gyorgyf@37 860 globals()['Y'] = YF
gyorgyf@37 861 self.screen = pg.display.set_mode((X, Y))
gyorgyf@37 862 # self.screen = pg.display.set_mode((0,0),pg.FULLSCREEN)
gyorgyf@37 863 self.fullscreen = True
gyorgyf@37 864 self.bg = pg.Surface(self.screen.get_size())
gyorgyf@37 865 self.bg = self.bg.convert()
gyorgyf@37 866 self.bg.fill((0,0,0))
gyorgyf@37 867 for i in self.indicators.itervalues() :
gyorgyf@37 868 i.reinit(self.bg)
gyorgyf@37 869 i.draw()
gyorgyf@37 870 if self.movingBlob != None :
gyorgyf@37 871 self.movingBlob.reinit(self.bg)
gyorgyf@37 872 self.movingBlob.draw()
gyorgyf@37 873 else :
gyorgyf@37 874 globals()['X'] = globals()['_X']
gyorgyf@37 875 globals()['Y'] = globals()['_Y']
gyorgyf@37 876 self.screen = pg.display.set_mode((X, Y))
gyorgyf@37 877 self.fullscreen = False
gyorgyf@37 878 self.bg = pg.Surface(self.screen.get_size())
gyorgyf@37 879 self.bg = self.bg.convert()
gyorgyf@37 880 self.bg.fill((0,0,0))
gyorgyf@37 881 for i in self.indicators.itervalues() :
gyorgyf@37 882 i.reinit(self.bg)
gyorgyf@37 883 i.draw()
gyorgyf@37 884 if self.movingBlob != None :
gyorgyf@37 885 self.movingBlob.reinit(self.bg)
gyorgyf@37 886 self.movingBlob.draw()
gyorgyf@37 887 pg.display.toggle_fullscreen()
gyorgyf@37 888
gyorgyf@37 889
gyorgyf@37 890
gyorgyf@37 891 def run(self):
gyorgyf@37 892
gyorgyf@37 893 # setup connection
gyorgyf@37 894 self.connect()
gyorgyf@37 895
gyorgyf@37 896 # main loop
gyorgyf@37 897 while True :
gyorgyf@37 898 # pg.draw.circle(screen, pg.Color(255,0,0), (300,50),20,0)
gyorgyf@37 899 # screen.blit(gradients.radial(99, scol, ecol), (401, 1))
gyorgyf@37 900
gyorgyf@37 901 self.read_keys()
gyorgyf@37 902
gyorgyf@37 903 # Draw
gyorgyf@37 904 self.draw()
gyorgyf@37 905
gyorgyf@37 906 # update display
gyorgyf@37 907 self.screen.blit(self.bg, (0, 0))
gyorgyf@37 908 pg.display.flip()
gyorgyf@37 909 self.fpsClock.tick(FRAMERATE)
gyorgyf@37 910
gyorgyf@37 911 if self.init_reconnect:
gyorgyf@37 912 self.reconnect()
gyorgyf@37 913
gyorgyf@37 914 return True
gyorgyf@37 915
gyorgyf@37 916 def choose_app(self):
gyorgyf@37 917 '''Experimental function for chaging served apps remotely. Disabled for now...'''
gyorgyf@37 918 return False
gyorgyf@37 919 try :
gyorgyf@37 920 print "Changing app and restarting... the connection will be lost."
gyorgyf@37 921 self.conn.putrequest("GET","/moodconductor/changeapp", skip_host=True)
gyorgyf@37 922 self.conn.putheader("Host", "www.isophonics.net")
gyorgyf@37 923 self.conn.endheaders()
gyorgyf@37 924 res = self.conn.getresponse()
gyorgyf@37 925 res.read()
gyorgyf@37 926 except :
gyorgyf@37 927 pass
gyorgyf@37 928
gyorgyf@37 929 def configure_server(self):
gyorgyf@37 930 '''Send the server some configuration data.'''
gyorgyf@37 931 # age = 10.0
gyorgyf@37 932 # dist = DIST
gyorgyf@37 933 # ninp = 18
gyorgyf@37 934 self.update_server_config(self.s_age,self.s_dist,self.s_ninp)
gyorgyf@37 935
gyorgyf@37 936
gyorgyf@37 937 def update_server_config(self,age,dist,ninp,retry = 3):
gyorgyf@37 938 '''Send the server some configuration data.'''
gyorgyf@37 939 self.indicators["config"].on().now(self.screen)
gyorgyf@37 940 try :
gyorgyf@37 941 print "Sending configuration data."
gyorgyf@37 942 self.conn.putrequest("GET","/moodconductor/config?age=%(age)s&dist=%(dist)s&ninp=%(ninp)s" %locals(), skip_host=True)
gyorgyf@37 943 self.conn.putheader("Host", "www.isophonics.net")
gyorgyf@37 944 self.conn.endheaders()
gyorgyf@37 945 res = self.conn.getresponse()
gyorgyf@37 946 res.read()
gyorgyf@37 947 if not res.status == 200 :
gyorgyf@37 948 print "Server response:", res.status, res.reason
gyorgyf@37 949 self.indicators["conn"].off()
gyorgyf@37 950 time.sleep(0.5)
gyorgyf@37 951 self.conn.putrequest("GET","/moodconductor/getconf", skip_host=True)
gyorgyf@37 952 self.conn.putheader("Host", "www.isophonics.net")
gyorgyf@37 953 self.conn.endheaders()
gyorgyf@37 954 res = self.conn.getresponse()
gyorgyf@37 955 if not res.status == 200 :
gyorgyf@37 956 print "Server response:", res.status, res.reason
gyorgyf@37 957 self.indicators["conn"].off()
gyorgyf@37 958 # self.indicators["config"].on()
gyorgyf@37 959 print "Server configuration:", res.read()
gyorgyf@37 960 self.indicators["config"].off()
gyorgyf@37 961 self.indicators["conn"].on()
gyorgyf@37 962 except:
gyorgyf@37 963 print "Failed to send configuration data."
gyorgyf@37 964 time.sleep(2)
gyorgyf@37 965 retry -= 1
gyorgyf@37 966 self.update_server_config(age,dist,ninp,retry)
gyorgyf@37 967
gyorgyf@37 968
gyorgyf@37 969 def connect(self,retry = 5):
gyorgyf@37 970 '''Connect to the server and test connection.'''
gyorgyf@37 971 if not retry :
gyorgyf@37 972 print "Server unreachable"
gyorgyf@37 973 pg.quit()
gyorgyf@37 974 raise SystemExit
gyorgyf@37 975 if retry < 5 :
gyorgyf@37 976 time.sleep(3)
gyorgyf@37 977 try :
gyorgyf@37 978 print "connecting to server..."
gyorgyf@37 979 self.conn = ht.HTTPConnection(IP,timeout=HTTP_TIMEOUT)
gyorgyf@37 980 self.indicators["conn"].on()
gyorgyf@37 981 except :
gyorgyf@37 982 self.indicators["conn"].off()
gyorgyf@37 983 self.connect(retry = retry-1)
gyorgyf@37 984 print "connection failed."
gyorgyf@37 985
gyorgyf@37 986 try:
gyorgyf@37 987 print "Testing connection."
gyorgyf@37 988 # self.conn.putrequest("GET","/moodconductor/index.html", skip_host=True)
gyorgyf@37 989 self.conn.putrequest("GET","/moodconductor/test", skip_host=True)
gyorgyf@37 990 self.conn.putheader("Host", "www.isophonics.net")
gyorgyf@37 991 self.conn.endheaders()
gyorgyf@37 992 res = self.conn.getresponse()
gyorgyf@37 993 print res.read()
gyorgyf@37 994 if res.status == 200 :
gyorgyf@37 995 self.indicators["conn"].on()
gyorgyf@37 996 else :
gyorgyf@37 997 print "Server response:", res.status, res.reason
gyorgyf@37 998 self.indicators["conn"].off()
gyorgyf@37 999 if not hasattr(self,"noretry") and raw_input("Go offline? ") in ['y',''] :
gyorgyf@37 1000 return False
gyorgyf@37 1001 else :
gyorgyf@37 1002 print "Failed. retrying."
gyorgyf@37 1003 self.noretry = None
gyorgyf@37 1004 self.connect(retry = retry-1)
gyorgyf@37 1005 except Exception as e:
gyorgyf@37 1006 print "Exception while testing connection.", e
gyorgyf@37 1007 self.indicators["conn"].off()
gyorgyf@37 1008 # comment out in offline mode
gyorgyf@37 1009 if not hasattr(self,"noretry") and raw_input("Go offline? ") in ['y',''] :
gyorgyf@37 1010 return False
gyorgyf@37 1011 else :
gyorgyf@37 1012 self.noretry = None
gyorgyf@37 1013 self.connect(retry = retry-1)
gyorgyf@37 1014 self.configure_server()
gyorgyf@37 1015 print "OK. Starting update thread..."
gyorgyf@37 1016 self.start_update_thread()
gyorgyf@37 1017 return True
gyorgyf@37 1018
gyorgyf@37 1019
gyorgyf@37 1020
gyorgyf@37 1021 def reconnect(self):
gyorgyf@37 1022 '''Called when c is pressed.'''
gyorgyf@37 1023 self.indicators["config"].on().now(self.screen)
gyorgyf@37 1024 self.init_reconnect = False
gyorgyf@37 1025
gyorgyf@37 1026 self.stop_update_thread()
gyorgyf@37 1027 time.sleep(1)
gyorgyf@37 1028 try :
gyorgyf@37 1029 self.conn.close()
gyorgyf@37 1030 except :
gyorgyf@37 1031 self.indicators["conn"].off()
gyorgyf@37 1032 try :
gyorgyf@37 1033 self.conn = ht.HTTPConnection(IP,timeout=HTTP_TIMEOUT)
gyorgyf@37 1034 self.conn.connect()
gyorgyf@37 1035 self.indicators["conn"].on()
gyorgyf@37 1036 print "Reconnected."
gyorgyf@37 1037 except :
gyorgyf@37 1038 self.indicators["conn"].off()
gyorgyf@37 1039 print "Error while reconnecting."
gyorgyf@37 1040 self.start_update_thread()
gyorgyf@37 1041 self.indicators["config"].off().now(self.screen)
gyorgyf@37 1042
gyorgyf@37 1043
gyorgyf@37 1044 def quit(self):
gyorgyf@37 1045 print "Quitting.."
gyorgyf@37 1046 self.indicators["conn"].off()
gyorgyf@37 1047 self.stop_update_thread()
gyorgyf@37 1048 self.conn.close()
gyorgyf@37 1049 pg.quit()
gyorgyf@37 1050 sys.exit()
gyorgyf@37 1051
gyorgyf@37 1052
gyorgyf@37 1053 def main():
gyorgyf@37 1054
gyorgyf@37 1055 v = VisualClient()
gyorgyf@37 1056 v.run()
gyorgyf@37 1057
gyorgyf@37 1058 if __name__ == '__main__':
gyorgyf@37 1059 pass
gyorgyf@37 1060 main()
gyorgyf@37 1061