gyorgyf@30: #!/usr/bin/env python gyorgyf@30: # encoding: utf-8 gyorgyf@30: """ gyorgyf@30: visclient.py gyorgyf@30: gyorgyf@30: Created by George Fazekas on 2012-06-17. gyorgyf@30: Copyright (c) 2012 . All rights reserved. gyorgyf@30: """ gyorgyf@30: gyorgyf@30: import sys,os,math,time,copy gyorgyf@30: import pygame as pg gyorgyf@30: from pygame.locals import * gyorgyf@30: import httplib as ht gyorgyf@30: from pygame import midi gyorgyf@30: gyorgyf@30: import gradients gyorgyf@30: from gradients import genericFxyGradient gyorgyf@30: gyorgyf@30: from threading import Thread gyorgyf@30: from random import random gyorgyf@30: import numpy as np gyorgyf@30: gyorgyf@30: import colorsys as cs gyorgyf@30: gyorgyf@30: NOTE_OFF_CH0 = [[[0xb0,0x7b,0],0]] gyorgyf@30: gyorgyf@30: # 1 HONKY TONK 0x1 / 0x4 (5) gyorgyf@30: # 2 SITAR 0x9 / 0x0 (1) gyorgyf@30: # 3 Melancholia gyorgyf@30: # 4 Rock GITAR 0x3 / 0x2C (45) gyorgyf@30: gyorgyf@30: IMAP = {1 : (0x1,0x4), 2: (0x9,0x0), 3:(0x8,0xb), 4:(0x3,0x2c) } gyorgyf@30: gyorgyf@30: gyorgyf@30: # from pytagcloud import create_tag_image, make_tags gyorgyf@30: # from pytagcloud.lang.counter import get_tag_counts gyorgyf@30: gyorgyf@30: # YOUR_TEXT = "A tag cloud is a visual representation for text data, typically\ gyorgyf@30: # used to depict keyword metadata on websites, or to visualize free form text." gyorgyf@30: # gyorgyf@30: # tags = make_tags(get_tag_counts(YOUR_TEXT), maxsize=120) gyorgyf@30: # gyorgyf@30: # create_tag_image(tags, 'cloud_large.png', size=(900, 600), fontname='Lobster') gyorgyf@30: gyorgyf@30: scol = (0,255,0,255) gyorgyf@30: ecol = (0,0,0,255) gyorgyf@30: gyorgyf@30: # X,Y=1140,900 gyorgyf@30: # X,Y = 600,400 gyorgyf@30: X,Y = 800,600 gyorgyf@30: gyorgyf@30: # Fullscreen resolution: gyorgyf@30: # XF,YF = 1280,900 gyorgyf@30: # XF,YF = 1440,900 gyorgyf@30: XF,YF = 1344,900 gyorgyf@30: # display calibrated gyorgyf@30: gyorgyf@30: # detect display resolution gyorgyf@30: import subprocess gyorgyf@30: screenres = subprocess.Popen('xrandr | grep "\*" | cut -d" " -f4',shell=True, stdout=subprocess.PIPE).communicate()[0] gyorgyf@30: screenres = map(lambda x: int(x.strip()), screenres.split('x')) gyorgyf@30: XF,YF = screenres gyorgyf@30: print "Screen resolution: ",XF,YF gyorgyf@30: gyorgyf@30: NBLOBS = 18 gyorgyf@30: BLOBSIZE = 25 gyorgyf@30: G=110 gyorgyf@30: FADE = 15 gyorgyf@30: DIST = 0.15 # blob equivalence tolerance gyorgyf@30: FRAMERATE = 60 gyorgyf@30: gyorgyf@30: # Connection: gyorgyf@30: # IP = "127.0.0.1:8030" gyorgyf@30: # IP = "192.168.2.158:8030" gyorgyf@30: IP = "138.37.95.215" gyorgyf@30: HTTP_TIMEOUT = 3 gyorgyf@30: SERVER_UPDATE_INTERVAL = 0.8 gyorgyf@30: gyorgyf@30: gyorgyf@30: class Indicator(object): gyorgyf@30: gyorgyf@30: off_color = pg.Color(110,0,0) gyorgyf@30: on_color = pg.Color(0,120,0) gyorgyf@30: gyorgyf@30: def __init__(self,bg,pos): gyorgyf@30: self.visible = True gyorgyf@30: self.ison = True gyorgyf@30: self.x,self.y = pos gyorgyf@30: self.xs = int(self.x * X) gyorgyf@30: self.ys = int(Y - (self.y * Y)) gyorgyf@30: self.c = self.off_color gyorgyf@30: self.size = 6 gyorgyf@30: self.bg = bg gyorgyf@30: gyorgyf@30: def reinit(self,bg): gyorgyf@30: self.bg = bg gyorgyf@30: self.xs = int(self.x * X) gyorgyf@30: self.ys = int(Y - (self.y * Y)) gyorgyf@30: gyorgyf@30: def draw(self): gyorgyf@30: if self.visible : gyorgyf@30: pg.draw.circle(self.bg, self.c, (self.xs,self.ys),self.size,0) gyorgyf@30: gyorgyf@30: def toggle(self): gyorgyf@30: if self.ison == True : gyorgyf@30: self.off() gyorgyf@30: else : gyorgyf@30: self.on() gyorgyf@30: return self gyorgyf@30: gyorgyf@30: def on(self): gyorgyf@30: self.c = self.on_color gyorgyf@30: self.ison = True gyorgyf@30: return self gyorgyf@30: gyorgyf@30: def off(self): gyorgyf@30: self.c = self.off_color gyorgyf@30: self.ison = False gyorgyf@30: return self gyorgyf@30: gyorgyf@30: gyorgyf@30: class Blob(object): gyorgyf@30: gyorgyf@30: def __init__(self,bg,x,y,color=(255,255,255),mood=None,fade=FADE): gyorgyf@30: # print x,y gyorgyf@30: self.x = x gyorgyf@30: self.y = y gyorgyf@30: self.quadrant = self.get_quadrant_number(x,y) gyorgyf@30: self.xs = x * X gyorgyf@30: self.ys = Y - (y * Y) gyorgyf@30: self.bg = bg gyorgyf@30: self.size = BLOBSIZE gyorgyf@30: self.time = time.time() gyorgyf@30: self.alpha = 255 gyorgyf@30: self.c = color gyorgyf@30: self.count = 1 gyorgyf@30: self.visible = True gyorgyf@30: self.FADE = fade gyorgyf@30: if mood and mood.color : gyorgyf@30: self.c = mood.color gyorgyf@30: gyorgyf@30: def get_quadrant_number(self,x,y): gyorgyf@30: if x > 0.5 and y > 0.5 : gyorgyf@30: return 1 gyorgyf@30: if x > 0.5 and y < 0.5 : gyorgyf@30: return 2 gyorgyf@30: if x < 0.5 and y < 0.5 : gyorgyf@30: return 3 gyorgyf@30: if x < 0.5 and y > 0.5 : gyorgyf@30: return 4 gyorgyf@30: gyorgyf@30: gyorgyf@30: def __cmp__(self,other): gyorgyf@30: d = math.sqrt( math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2) ) gyorgyf@30: if d < DIST : gyorgyf@30: return 0 gyorgyf@30: else : gyorgyf@30: return -1 gyorgyf@30: gyorgyf@30: def draw(self): gyorgyf@30: if not self.visible : return gyorgyf@30: d=int(self.size) gyorgyf@30: 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@30: self.alpha = 255 - int(self.age()*self.FADE) gyorgyf@30: if self.alpha < 5 : gyorgyf@30: self.alpha = 1 gyorgyf@30: self.visible = False gyorgyf@30: gyorgyf@30: def age(self): gyorgyf@30: return time.time() - self.time gyorgyf@30: gyorgyf@30: def increment(self,count): gyorgyf@30: self.time = time.time() gyorgyf@30: self.count = count gyorgyf@30: # self.size = int(BLOBSIZE * int(self.count/1.5)) gyorgyf@30: self.to = int(BLOBSIZE * int(self.count/1.5)) gyorgyf@30: self.start_animate() gyorgyf@30: gyorgyf@30: def get_distance(self,x,y): gyorgyf@30: return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) ) gyorgyf@30: gyorgyf@30: def fade(self,fade): gyorgyf@30: if not fade : self.alpha = 255 gyorgyf@30: self.FADE = fade gyorgyf@30: gyorgyf@30: def reset_time(self): gyorgyf@30: self.time = time.time() gyorgyf@30: gyorgyf@30: def start_animate(self): gyorgyf@30: self.thread = Thread(target = self.animate) gyorgyf@30: self.thread.daemon = True gyorgyf@30: self.thread.start() gyorgyf@30: gyorgyf@30: def animate(self): gyorgyf@30: '''Animate the way bubbles are grown.''' gyorgyf@30: while self.size < self.to : gyorgyf@30: self.size += 1 gyorgyf@30: time_inc = 20.0 / (pow(1.2, self.to-self.size) * 200.0) gyorgyf@30: time.sleep(0.02+time_inc) gyorgyf@30: gyorgyf@30: gyorgyf@30: gyorgyf@30: gyorgyf@30: class Mood(): gyorgyf@30: def __init__(self,word,x,y): gyorgyf@30: self.word = word gyorgyf@30: self.x = float(x) gyorgyf@30: self.y = float(y) gyorgyf@30: self.color = [] gyorgyf@30: gyorgyf@30: def get_distance(self,x,y): gyorgyf@30: return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) ) gyorgyf@30: gyorgyf@30: gyorgyf@30: gyorgyf@30: class VisualClient(object): gyorgyf@30: '''Main visualisation client.''' gyorgyf@30: gyorgyf@30: def __init__(self): gyorgyf@30: # self.conn = ht.HTTPConnection("192.168.2.184:8030") gyorgyf@30: # self.conn = ht.HTTPConnection("138.37.95.215") gyorgyf@30: self.s_age = 10 gyorgyf@30: self.s_dist = DIST gyorgyf@30: self.s_ninp = 18 gyorgyf@30: gyorgyf@30: pg.init() gyorgyf@30: gyorgyf@30: # fontObj = pg.font.Font("freesansbold.ttf",18) gyorgyf@30: white = ( 255, 255, 255) gyorgyf@30: black = ( 0,0,0) gyorgyf@30: gyorgyf@30: self.fpsClock = pg.time.Clock() gyorgyf@30: self.screen = pg.display.set_mode((X, Y)) gyorgyf@30: pg.display.set_caption('Mood Conductor') gyorgyf@30: self.bg = pg.Surface(self.screen.get_size()) gyorgyf@30: self.bg = self.bg.convert() gyorgyf@30: self.bg.fill((0,0,0)) gyorgyf@30: pg.display.set_gamma(100.0) gyorgyf@30: gyorgyf@30: gyorgyf@30: self.scol = (0,255,0,255) gyorgyf@30: self.ecol = (0,0,0,255) gyorgyf@30: coordstxt = "test" gyorgyf@30: gyorgyf@30: self.blobs = [] gyorgyf@30: self.moods = [] gyorgyf@30: self.read_mood_data() gyorgyf@30: gyorgyf@30: self.FADE = FADE gyorgyf@30: gyorgyf@30: self.indicators = { gyorgyf@30: "conn":Indicator(self.bg,(0.98,0.02)), gyorgyf@30: "update":Indicator(self.bg,(0.96,0.02)), gyorgyf@30: "data":Indicator(self.bg,(0.94,0.02)), gyorgyf@30: "receive":Indicator(self.bg,(0.92,0.02))} gyorgyf@30: gyorgyf@30: self.thread = None gyorgyf@30: self.running = False gyorgyf@30: self.fullscreen = False gyorgyf@30: self.init_reconnect = False gyorgyf@30: gyorgyf@30: pg.midi.init() gyorgyf@30: gyorgyf@30: print pg.midi.get_device_info(4) gyorgyf@30: self.midi_out = pg.midi.Output(4,0) gyorgyf@30: self.midi_out.set_instrument(6) gyorgyf@30: gyorgyf@30: # self.midi_out.note_on(23,128,1) gyorgyf@30: # self.midi_out.write([[[0xc0,0,0],20000],[[0x90,60,100],20500]]) gyorgyf@30: gyorgyf@30: self.active_quadrant = 1 gyorgyf@30: self.prev_quadrant = 1 gyorgyf@30: gyorgyf@30: pass gyorgyf@30: gyorgyf@30: gyorgyf@30: def read_mood_data(self): gyorgyf@30: '''Read the mood position and color information form csv file.''' gyorgyf@30: with open('moods.csv') as mf: gyorgyf@30: data = mf.readlines()[1:] gyorgyf@30: for line in data : gyorgyf@30: l = line.split(',') gyorgyf@30: mood = Mood(l[0],l[1],l[2]) gyorgyf@30: self.moods.append(mood) gyorgyf@30: with open('colors.txt') as ff: gyorgyf@30: data = ff.readlines()[1:] gyorgyf@30: data = map(lambda x: x.split(','),data) gyorgyf@30: for mood in self.moods : gyorgyf@30: d = cd = sys.float_info.max gyorgyf@30: for colors in data : gyorgyf@30: d = mood.get_distance(float(colors[0]),float(colors[1])) gyorgyf@30: if d < cd : gyorgyf@30: cd = d gyorgyf@30: # mood.color = tuple(map(lambda x: int(pow(math.atan((float(x)/7.0)),12.5)),(colors[2],colors[3],colors[4]))) gyorgyf@30: mood.color = self.set_color(tuple(map(lambda x: int(x),(colors[2],colors[3],colors[4])))) gyorgyf@30: return True gyorgyf@30: gyorgyf@30: def set_color(self,color): gyorgyf@30: '''Move to HLS colour space and manipulate saturation there.''' gyorgyf@30: # TODO: ideally, we need a non-linear compressor of the lightness and saturation values gyorgyf@30: r,g,b = map(lambda x: (1.0*x/255.0), color) gyorgyf@30: h,l,s = cs.rgb_to_hls(r,g,b) gyorgyf@30: s = 1.0 #1.0 - (1.0 / pow(50.0,s)) gyorgyf@30: l = 1.0 - (1.0 / pow(20.0,l)) #0.6 gyorgyf@30: r,g,b = map(lambda x: int(x*255), cs.hls_to_rgb(h,l,s)) gyorgyf@30: return r,g,b gyorgyf@30: gyorgyf@30: def start_update_thread(self): gyorgyf@30: '''Start the thread that reads data from the server.''' gyorgyf@30: self.running = True gyorgyf@30: self.thread = Thread(target = self.update_thread) gyorgyf@30: self.thread.daemon = True gyorgyf@30: self.thread.start() gyorgyf@30: gyorgyf@30: def stop_update_thread(self): gyorgyf@30: '''Stop the thread and allow some time fot the connections to close.''' gyorgyf@30: self.running = False gyorgyf@30: try : gyorgyf@30: self.thread.join(2) gyorgyf@30: except : gyorgyf@30: print "No update thread to join." gyorgyf@30: gyorgyf@30: def update_thread(self): gyorgyf@30: '''The server update thread''' gyorgyf@30: while self.running : gyorgyf@30: try : gyorgyf@30: self.update() gyorgyf@30: # self.indicators["update"].visible = True gyorgyf@30: except Exception, e: gyorgyf@30: if str(e).strip() : print "Exception: ", str(e), type(e), len(str(e).strip()) gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: # self.indicators["update"].visible = False gyorgyf@30: time.sleep(SERVER_UPDATE_INTERVAL) gyorgyf@30: gyorgyf@30: gyorgyf@30: def update(self): gyorgyf@30: '''Update the blob list from the server. This should be in a thread.''' gyorgyf@30: gyorgyf@30: # indicate connection health by toggling an indictor gyorgyf@30: self.indicators["update"].toggle() gyorgyf@30: gyorgyf@30: # delete invisibles gyorgyf@30: for blob in self.blobs : gyorgyf@30: if not blob.visible : gyorgyf@30: self.blobs.remove(blob) gyorgyf@30: gyorgyf@30: # get new coordinates from the server gyorgyf@30: self.conn.putrequest("GET","/moodconductor/result", skip_host=True) gyorgyf@30: self.conn.putheader("Host", "www.isophonics.net") gyorgyf@30: self.conn.endheaders() gyorgyf@30: res = self.conn.getresponse() gyorgyf@30: data = res.read() gyorgyf@30: data = eval(data) gyorgyf@30: if not data : gyorgyf@30: self.conn.close() gyorgyf@30: self.indicators["data"].toggle() gyorgyf@30: return False gyorgyf@30: for d in data : gyorgyf@30: # coordstxt = "x:%s y:%s c:%s" %d gyorgyf@30: x,y,count = d gyorgyf@30: self.add_blob(x,y,count) gyorgyf@30: self.indicators["receive"].toggle() gyorgyf@30: self.conn.close() gyorgyf@30: self.blobs = self.blobs[:NBLOBS] gyorgyf@30: self.compute_quadrant_weighting() gyorgyf@30: self.self_change_instrument() gyorgyf@30: return True gyorgyf@30: gyorgyf@30: def compute_quadrant_weighting(self): gyorgyf@30: quadrant_dict = {1:[],2:[],3:[],4:[]} gyorgyf@30: # sort blobs into quadrants gyorgyf@30: for blob in self.blobs : gyorgyf@30: quadrant_dict[blob.quadrant].append(blob) gyorgyf@30: # get weight for each gyorgyf@30: quadrant_weights = [] gyorgyf@30: for q,blob_list in quadrant_dict.iteritems() : gyorgyf@30: quadrant_weights.append(sum(map(lambda x: x.alpha * x.size,blob_list))) gyorgyf@30: self.active_quadrant = np.argmax(quadrant_weights) + 1 gyorgyf@30: print self.active_quadrant gyorgyf@30: return self.active_quadrant gyorgyf@30: gyorgyf@30: def self_change_instrument(self): gyorgyf@30: if self.active_quadrant != self.prev_quadrant : gyorgyf@30: self.prev_quadrant = self.active_quadrant gyorgyf@30: args = IMAP[self.active_quadrant] gyorgyf@30: self.send_midi_patch_change_GR20(*args) gyorgyf@30: print args gyorgyf@30: gyorgyf@30: def add_blob(self,x,y,count=1): gyorgyf@30: '''Insert a blob to the list of blobs''' gyorgyf@30: # find mood correxponding to x,y gyorgyf@30: cmood = None gyorgyf@30: d = cd = sys.float_info.max gyorgyf@30: for mood in self.moods : gyorgyf@30: d = mood.get_distance(x,y) gyorgyf@30: if d < cd : gyorgyf@30: cd = d gyorgyf@30: cmood = mood gyorgyf@30: # create new blob or increase click count on existing one gyorgyf@30: new = Blob(self.bg,x,y,mood=cmood,fade=self.FADE) gyorgyf@30: if not new in self.blobs : gyorgyf@30: self.blobs.insert(0,new) gyorgyf@30: # self.send_midi() gyorgyf@30: elif count > self.blobs[self.blobs.index(new)].count: gyorgyf@30: self.blobs[self.blobs.index(new)].increment(count) gyorgyf@30: pass gyorgyf@30: gyorgyf@30: def send_midi(self): gyorgyf@30: # self.midi_out.write([[[0xc0,0,0],20000],[[0x90,60,100],20500]]) gyorgyf@30: self.midi_out.write([[[0x90,60,100],0],[[0x90,60,100],500]]) gyorgyf@30: gyorgyf@30: def send_midi_patch_change_GR20(self,bank,instrument): gyorgyf@30: '''PIANO = BANK 1, Patch 5.. bank starts from 1, patch starts from 0 so I have to substract one...''' gyorgyf@30: self.midi_out.write([[[0xB0,0x0,bank],0],[[0xC0,instrument],100]]) gyorgyf@30: # Control change (B) followed by patch change (C): gyorgyf@30: # midi_out.write([[[0xB0,0x0,0x9],0],[[0xC0,0x0],100]]) gyorgyf@30: # midi_out.write([[[0xB0,0x0,int(bank)],0],[[0xC0,int(instrument)-1],100]]) gyorgyf@30: # 1 HONKY TONK 0x1 / 0x4 (5) gyorgyf@30: # 2 SITAR 0x9 / 0x0 (1) gyorgyf@30: # 3 Melancholia gyorgyf@30: # 4 Rock GITAR 0x3 / 0x2C (45) gyorgyf@30: gyorgyf@30: gyorgyf@30: def draw(self): gyorgyf@30: self.bg.fill((0,0,0)) gyorgyf@30: # self.bg.blit(gradients.radial(19, self.scol, self.ecol), (rect_x,rect_y)) gyorgyf@30: l = copy.copy(self.blobs) gyorgyf@30: l.reverse() gyorgyf@30: for blob in l : gyorgyf@30: blob.draw() gyorgyf@30: gyorgyf@30: # axis gyorgyf@30: pg.draw.line(self.bg, (G,G,G), (int(X/2.0),0),(int(X/2.0),Y), 1) gyorgyf@30: pg.draw.line(self.bg, (G,G,G), (0,int(Y/2.0)),(X,int(Y/2.0)), 1) gyorgyf@30: gyorgyf@30: # indicators gyorgyf@30: for i in self.indicators.itervalues() : gyorgyf@30: i.draw() gyorgyf@30: gyorgyf@30: def read_keys(self): gyorgyf@30: '''Read keys''' gyorgyf@30: for event in pg.event.get() : gyorgyf@30: # Quit (event) gyorgyf@30: if event.type == QUIT: gyorgyf@30: self.midi_out.write(NOTE_OFF_CH0) gyorgyf@30: self.quit() gyorgyf@30: elif event.type == KEYDOWN : gyorgyf@30: # Post Quit: Esc, q gyorgyf@30: if event.key == K_ESCAPE or event.key == K_q : gyorgyf@30: pg.event.post(pg.event.Event(QUIT)) gyorgyf@30: # Reset: Space gyorgyf@30: elif event.key == K_SPACE : gyorgyf@30: self.blobs = [] gyorgyf@30: # Random : r gyorgyf@30: elif event.key == K_r : gyorgyf@30: self.add_blob(random(),random(),count=5) gyorgyf@30: # Connection : c gyorgyf@30: elif event.key == K_c : gyorgyf@30: self.init_reconnect = True gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: # Fullscreen: f gyorgyf@30: elif event.key == K_f : gyorgyf@30: # pg.display.toggle_fullscreen() gyorgyf@30: self.toggle_screen_mode() gyorgyf@30: # Toggle fade: s gyorgyf@30: elif event.key == K_s : gyorgyf@30: if self.FADE : gyorgyf@30: print "fade off" gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: self.FADE = 0 gyorgyf@30: for blob in self.blobs : gyorgyf@30: blob.fade(0) gyorgyf@30: else: gyorgyf@30: print "fade on" gyorgyf@30: self.indicators["conn"].on() gyorgyf@30: self.FADE = 15 gyorgyf@30: for blob in self.blobs : gyorgyf@30: blob.fade(15) gyorgyf@30: blob.reset_time() gyorgyf@30: # inc age gyorgyf@30: elif event.key == K_1 : gyorgyf@30: self.s_age += 1 gyorgyf@30: self.update_server_config(self.s_age,self.s_dist,self.s_ninp) gyorgyf@30: # dec age gyorgyf@30: elif event.key == K_2 : gyorgyf@30: self.s_age -= 1 gyorgyf@30: self.update_server_config(self.s_age,self.s_dist,self.s_ninp) gyorgyf@30: # inc dist gyorgyf@30: elif event.key == K_3 : gyorgyf@30: self.s_dist += 0.025 gyorgyf@30: self.update_server_config(self.s_age,self.s_dist,self.s_ninp) gyorgyf@30: # dec dist gyorgyf@30: elif event.key == K_4 : gyorgyf@30: self.s_dist -= 0.025 gyorgyf@30: if self.s_dist < 0.025 : self.s_dist = 0.025 gyorgyf@30: self.update_server_config(self.s_age,self.s_dist,self.s_ninp) gyorgyf@30: # inc ninp gyorgyf@30: elif event.key == K_5 : gyorgyf@30: self.s_ninp += 1 gyorgyf@30: self.update_server_config(self.s_age,self.s_dist,self.s_ninp) gyorgyf@30: # dec ninp gyorgyf@30: elif event.key == K_6 : gyorgyf@30: self.s_ninp -= 1 gyorgyf@30: if self.s_ninp < 2 : self.s_ninp = 2 gyorgyf@30: self.update_server_config(self.s_age,self.s_dist,self.s_ninp) gyorgyf@30: gyorgyf@30: pass gyorgyf@30: pass gyorgyf@30: gyorgyf@30: def toggle_screen_mode(self): gyorgyf@30: '''Go back and forth between full screen mode.''' gyorgyf@30: if self.fullscreen == False: gyorgyf@30: globals()['_X'] = globals()['X'] gyorgyf@30: globals()['_Y'] = globals()['Y'] gyorgyf@30: globals()['X'] = XF gyorgyf@30: globals()['Y'] = YF gyorgyf@30: self.screen = pg.display.set_mode((X, Y)) gyorgyf@30: # self.screen = pg.display.set_mode((0,0),pg.FULLSCREEN) gyorgyf@30: self.fullscreen = True gyorgyf@30: self.bg = pg.Surface(self.screen.get_size()) gyorgyf@30: self.bg = self.bg.convert() gyorgyf@30: self.bg.fill((0,0,0)) gyorgyf@30: for i in self.indicators.itervalues() : gyorgyf@30: i.reinit(self.bg) gyorgyf@30: i.draw() gyorgyf@30: else : gyorgyf@30: globals()['X'] = globals()['_X'] gyorgyf@30: globals()['Y'] = globals()['_Y'] gyorgyf@30: self.screen = pg.display.set_mode((X, Y)) gyorgyf@30: self.fullscreen = False gyorgyf@30: self.bg = pg.Surface(self.screen.get_size()) gyorgyf@30: self.bg = self.bg.convert() gyorgyf@30: self.bg.fill((0,0,0)) gyorgyf@30: for i in self.indicators.itervalues() : gyorgyf@30: i.reinit(self.bg) gyorgyf@30: i.draw() gyorgyf@30: pg.display.toggle_fullscreen() gyorgyf@30: gyorgyf@30: gyorgyf@30: gyorgyf@30: def run(self): gyorgyf@30: gyorgyf@30: # setup connection gyorgyf@30: self.connect() gyorgyf@30: gyorgyf@30: # main loop gyorgyf@30: while True : gyorgyf@30: # pg.draw.circle(screen, pg.Color(255,0,0), (300,50),20,0) gyorgyf@30: # screen.blit(gradients.radial(99, scol, ecol), (401, 1)) gyorgyf@30: gyorgyf@30: self.read_keys() gyorgyf@30: gyorgyf@30: # Draw gyorgyf@30: self.draw() gyorgyf@30: gyorgyf@30: # update display gyorgyf@30: self.screen.blit(self.bg, (0, 0)) gyorgyf@30: pg.display.flip() gyorgyf@30: self.fpsClock.tick(FRAMERATE) gyorgyf@30: gyorgyf@30: if self.init_reconnect: gyorgyf@30: self.reconnect() gyorgyf@30: gyorgyf@30: return True gyorgyf@30: gyorgyf@30: def configure_server(self): gyorgyf@30: '''Send the server some configuration data.''' gyorgyf@30: # age = 10.0 gyorgyf@30: # dist = DIST gyorgyf@30: # ninp = 18 gyorgyf@30: self.update_server_config(self.s_age,self.s_dist,self.s_ninp) gyorgyf@30: gyorgyf@30: gyorgyf@30: def update_server_config(self,age,dist,ninp,retry = 3): gyorgyf@30: '''Send the server some configuration data.''' gyorgyf@30: try : gyorgyf@30: self.conn.putrequest("GET","/moodconductor/config?age=%(age)s&dist=%(dist)s&ninp=%(ninp)s" %locals(), skip_host=True) gyorgyf@30: self.conn.putheader("Host", "www.isophonics.net") gyorgyf@30: self.conn.endheaders() gyorgyf@30: res = self.conn.getresponse() gyorgyf@30: if not res.status == 200 : gyorgyf@30: print "Server response:", res.status, res.reason gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: time.sleep(0.5) gyorgyf@30: self.conn.putrequest("GET","/moodconductor/getconf", skip_host=True) gyorgyf@30: self.conn.putheader("Host", "www.isophonics.net") gyorgyf@30: self.conn.endheaders() gyorgyf@30: res = self.conn.getresponse() gyorgyf@30: if not res.status == 200 : gyorgyf@30: print "Server response:", res.status, res.reason gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: print "Server configuration:", res.read() gyorgyf@30: except: gyorgyf@30: time.sleep(2) gyorgyf@30: retry -= 1 gyorgyf@30: self.update_server_config(age,dist,ninp,retry) gyorgyf@30: gyorgyf@30: gyorgyf@30: def connect(self,retry = 5): gyorgyf@30: '''Connect to the server and test connection.''' gyorgyf@30: if not retry : gyorgyf@30: print "Server unreachable" gyorgyf@30: pg.quit() gyorgyf@30: raise SystemExit gyorgyf@30: if retry < 5 : gyorgyf@30: time.sleep(3) gyorgyf@30: try : gyorgyf@30: self.conn = ht.HTTPConnection(IP,timeout=HTTP_TIMEOUT) gyorgyf@30: # self.start_update_thread() gyorgyf@30: self.indicators["conn"].on() gyorgyf@30: except : gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: self.connect(retry = retry-1) gyorgyf@30: gyorgyf@30: try: gyorgyf@30: self.conn.putrequest("GET","/moodconductor/index.html", skip_host=True) gyorgyf@30: self.conn.putheader("Host", "www.isophonics.net") gyorgyf@30: self.conn.endheaders() gyorgyf@30: res = self.conn.getresponse() gyorgyf@30: if res.status == 200 : gyorgyf@30: self.indicators["conn"].on() gyorgyf@30: else : gyorgyf@30: print "Server response:", res.status, res.reason gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: if not hasattr(self,"noretry") and raw_input("Go offline? ") in ['y',''] : gyorgyf@30: return False gyorgyf@30: else : gyorgyf@30: self.noretry = None gyorgyf@30: self.connect(retry = retry-1) gyorgyf@30: except : gyorgyf@30: print "Exception while testing connection." gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: # comment out in offline mode gyorgyf@30: if not hasattr(self,"noretry") and raw_input("Go offline? ") in ['y',''] : gyorgyf@30: return False gyorgyf@30: else : gyorgyf@30: self.noretry = None gyorgyf@30: self.connect(retry = retry-1) gyorgyf@30: self.configure_server() gyorgyf@30: self.start_update_thread() gyorgyf@30: return True gyorgyf@30: gyorgyf@30: gyorgyf@30: gyorgyf@30: def reconnect(self): gyorgyf@30: '''Called when c is pressed.''' gyorgyf@30: self.init_reconnect = False gyorgyf@30: # self.indicators["conn"].off().draw() gyorgyf@30: # self.screen.blit(self.bg, (0, 0)) gyorgyf@30: # pg.display.flip() gyorgyf@30: gyorgyf@30: self.stop_update_thread() gyorgyf@30: time.sleep(1) gyorgyf@30: try : gyorgyf@30: self.conn.close() gyorgyf@30: except : gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: try : gyorgyf@30: self.conn = ht.HTTPConnection(IP,timeout=HTTP_TIMEOUT) gyorgyf@30: self.conn.connect() gyorgyf@30: self.indicators["conn"].on() gyorgyf@30: print "Reconnected." gyorgyf@30: except : gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: print "Error while reconnecting." gyorgyf@30: self.start_update_thread() gyorgyf@30: gyorgyf@30: gyorgyf@30: def quit(self): gyorgyf@30: print "Quitting.." gyorgyf@30: self.indicators["conn"].off() gyorgyf@30: self.stop_update_thread() gyorgyf@30: self.conn.close() gyorgyf@30: pg.quit() gyorgyf@30: sys.exit() gyorgyf@30: gyorgyf@30: gyorgyf@30: gyorgyf@30: gyorgyf@30: gyorgyf@30: def main(): gyorgyf@30: gyorgyf@30: v = VisualClient() gyorgyf@30: v.run() gyorgyf@30: gyorgyf@30: gyorgyf@30: if __name__ == '__main__': gyorgyf@30: pass gyorgyf@30: main() gyorgyf@30: