def __init__(self, gradient, img_path, duration=5000): """ Inits graphical components gradient: A gradient object to act as background img_path: path to images duration: duration of intro sequence in milliseconds """ self.screen = gradient self.duration = duration #knob image img = pygame.image.load(img_path + 'knob.png') #img = pygame.transform.scale(img, (150, 150)) #plates rust = pygame.image.load(img_path + 'rust.png') rust = pygame.transform.scale(rust, (120, 120)) #petrolium petrol = pygame.image.load(img_path + 'petrol.png') petrol = pygame.transform.scale(petrol, (120, 120)) for i in range(2): knob = Knob(img) knob.set_shadow((-6, -4), 150, 25) self.knobs.append(knob) #the two diffrent plates in a pattern self.knobs[0].set_plate(rust) self.knobs[1].set_plate(petrol) #position the knobs img_center = img.get_rect().center self.pos.append((125 - img_center[0], 125 - img_center[1])) self.pos.append((275 - img_center[0], 125 - img_center[1])) #texts center = self.screen.get_rect().center #screen center #logo font = pygame.font.Font(pygame.font.get_default_font(), 40) logo = font.render('PyTone', True, BLACK) logo_cnt = logo.get_rect().center # texts center logo = (logo, (center[0] - logo_cnt[0], 250 - logo_cnt[1]) ) #storing surface & position in a tuple self.surfaces.append(logo) #credits font = pygame.font.Font(img_path + 'Actor-Regular.ttf', 10) credits = font.render('MIKAEL SVENSSON 2013', True, BLACKER) cred_cnt = credits.get_rect().center credits = (credits, (center[0] - cred_cnt[0], 364 - cred_cnt[1]) ) #storing surface & position in a tuple self.surfaces.append(credits) self.clock = pygame.time.Clock()
def __init__(self, gradient, img_path, duration=5000): """ Inits graphical components gradient: A gradient object to act as background img_path: path to images duration: duration of intro sequence in milliseconds """ self.screen = gradient self.duration = duration #knob image img = pygame.image.load(img_path + 'knob.png') #img = pygame.transform.scale(img, (150, 150)) #plates rust = pygame.image.load(img_path + 'rust.png') rust = pygame.transform.scale(rust, (120, 120)) #petrolium petrol = pygame.image.load(img_path + 'petrol.png') petrol = pygame.transform.scale(petrol, (120, 120)) for i in range(2): knob = Knob(img) knob.set_shadow((-6,-4), 150, 25) self.knobs.append(knob) #the two diffrent plates in a pattern self.knobs[0].set_plate(rust) self.knobs[1].set_plate(petrol) #position the knobs img_center = img.get_rect().center self.pos.append((125 - img_center[0], 125 - img_center[1])) self.pos.append((275 - img_center[0], 125 - img_center[1])) #texts center = self.screen.get_rect().center #screen center #logo font = pygame.font.Font(pygame.font.get_default_font(), 40) logo = font.render('PyTone', True, BLACK) logo_cnt = logo.get_rect().center # texts center logo = (logo, (center[0] - logo_cnt[0], 250 - logo_cnt[1])) #storing surface & position in a tuple self.surfaces.append(logo) #credits font = pygame.font.Font(img_path + 'Actor-Regular.ttf', 10) credits = font.render('MIKAEL SVENSSON 2013', True, BLACKER) cred_cnt = credits.get_rect().center credits = (credits, (center[0] - cred_cnt[0], 364 - cred_cnt[1])) #storing surface & position in a tuple self.surfaces.append(credits) self.clock = pygame.time.Clock()
def __init__(self, gradient, path): """ gradient: A gradient object to act as background path: path to media """ start = 330 stop = 60 self.screen = gradient img = pygame.image.load(path + 'switch.png') self.switch = Knob(img, self.snap, (start, stop)) snd = pygame.mixer.Sound(path + 'switch_snd.ogg') self.switch.set_sound(snd) self.switch.set_volume(0.5) self.path = path
def initGUI(self): """ Inits the graphical components """ #clear background self.screen.clear() self.screen.draw() #knob image img = pygame.image.load(self.path + 'knob.png') #plates self.plate = pygame.image.load(self.path + 'rust.png') self.knob = Knob(img) self.knob.set_plate(self.plate) #self.knob.set_shadow((-6,-4), 150, 25) knb_center = self.knob.get_rect().center self.knob = (self.knob, (self.center[0]-knb_center[0], self.center[1]-knb_center[1])) # also stores knob.rect at blit time self.center = self.screen.get_rect().center #"back" back_img = pygame.image.load(self.path + 'back.png') back_pos = (30,30) #tuple width the image and it's position and a third element containting elements Rect. self.back = (back_img, (30,30), self.screen.blit(back_img, back_pos)) #arrow arrow_img = pygame.image.load(self.path + 'arrow.png') self.arrow = (arrow_img, (self.center[0] - arrow_img.get_width()/2, 104)) #instructions, texts instrs = ['UP', 'DOWN', 'FINE UP', 'FINE DOWN', 'PRESS ENTER TO CONFIRM'] font = pygame.font.Font(self.path + 'Actor-Regular.ttf', 10) #instructions, key images key_images = pygame.Surface((184, 69), pygame.SRCALPHA, 32) #collecting those images in a surface, for flexible positioning. key_images_cp = key_images.get_rect().center img = pygame.image.load(self.path + 'key.png') up = pygame.transform.rotozoom(img, 90, 1) key_images.blit(up, (key_images_cp[0] - up.get_size()[0]/2, 0)) #up arrow key_images.blit(font.render(instrs[0], True, BLACK), (key_images_cp[0] - font.size(instrs[0])[0]/2, 9)) #up text key_images.blit(font.render(instrs[3], True, BLACK), (0, key_images_cp[1] - font.size(instrs[3])[1]/2)) #left text left = pygame.transform.rotozoom(img, 180, 1) key_images.blit(left, (font.size(instrs[3])[0] + 5, key_images_cp[1] - left.get_size()[1]/2)) #left arrow right = img key_images.blit(right, (key_images.get_width() - font.size(instrs[3])[0] - 5 - right.get_size()[0], key_images_cp[1] - right.get_size()[1]/2)) #right arrow (reflects left) key_images.blit(font.render(instrs[2], True, BLACK), (key_images.get_width() - font.size(instrs[3])[0] + 5 - right.get_size()[0], key_images_cp[1] - font.size(instrs[2])[1]/2)) #right text key_images.blit(font.render(instrs[1], True, BLACK), (key_images_cp[0] - font.size(instrs[1])[0]/2, 44)) #down text down = pygame.transform.rotozoom(img, 270, 1) key_images.blit(down, (key_images_cp[0] - down.get_size()[0]/2, 69 - down.get_size()[1])) #up arrow #public parent container for instructions self.instructions = pygame.Surface((self.screen.get_width(), 115), pygame.SRCALPHA, 32) self.instructions.blit(key_images, (self.instructions.get_rect().center[0] - key_images_cp[0], 0)) self.instructions.blit(font.render(instrs[4], True, BLACK),(self.instructions.get_rect().center[0] - font.size(instrs[4])[0]/2, key_images.get_height() + 20))
def __init__(self, controller, canvas, idPiste): super().__init__(canvas) self.canvas = canvas self.controller = controller self.window = None self.idPiste = idPiste self.suivant = None self.precedent = None self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 1', height=2) self.spacerLabel.pack() self.removeButton = Button(self, text="Supprimer", command=self.askRemovePiste, width=8, cursor="hand2", background='red', font="Helvetica 8 bold", foreground="white", activebackground="#EA0000", activeforeground="#EAEAEA") self.removeButton.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 2', height=1) self.spacerLabel.pack() self.idLabel = Label(self, text="CH " + str(self.idPiste), background="white", font='Helvetica 16 bold', foreground="#A0A0A0") self.idLabel.pack() self.nameLabel = Label(self, text="Veuillez charger un son", background="white", font='Helvetica 8 ', width=19, height=1) self.nameLabel.pack() self.LoadButton = Button(self, text="Charger", command=self.open_file, width=14, cursor="hand2", background='#C8C8C8', font="Helvetica 12 bold", activebackground="#B9B9B9", height=1) self.LoadButton.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 3', height=1) self.spacerLabel.pack() self.stereoLabel = Label(self, text="Stéréo", background="white", font="Helvetica 11 bold") self.stereoLabel.pack() self.stereoKnob = Knob(self, -1, 1, self.modifyStereoValue) self.stereoKnob.pack() self.spacerLabel = Label( self, text="", background='#FFFFFF', font='Helvetica 1', height=1, ) self.spacerLabel.pack() self.volumeLabel = Label(self, text="Volume", background="white", font="Helvetica 11 bold") self.volumeLabel.pack() self.volumeSlider = Scale(self, orient=VERTICAL, command=self.modifyVolumeValue, background="white", troughcolor='#C8C8C8', activebackground="#D9D9D9", font='Helvetica 10 bold', width=20, length=125, cursor="hand2", highlightthickness=0) self.volumeSlider.config(from_=150, to=0) self.setVolumeValue(100) self.volumeSlider.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 1', height=1) self.spacerLabel.pack() self.speedLabel = Label(self, text="Pitch", background="white", font="Helvetica 11 bold") self.speedLabel.pack() self.speedKnob = Knob(self, 0, 2, self.modifySpeedValue) self.speedKnob.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 1', height=1) self.spacerLabel.pack() self.muteLabel = Label(self, text="Mute", background="white", font="Helvetica 11 bold") self.muteLabel.pack() self.muteButtonState = False soundOn = PhotoImage(file="Images/unMute.png", master=self.canvas) self.muteButton = Button(self, image=soundOn, command=self.modifyMuteState, cursor="hand2") self.muteButton.image = soundOn self.muteButton.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 5', height=1) self.spacerLabel.pack() self.effectButton = Button(self, text="Effet", width=14, background='#C8C8C8', font="Helvetica 11 bold", cursor="hand2", command=self.modifyEffet, activebackground="#B9B9B9") self.effectButton.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 1', height=1) self.spacerLabel.pack() self.crossFadeButtonState = False self.crossFadeButton = Button(self, text="CrossFade", width=14, cursor="hand2", background='#C8C8C8', font="Helvetica 11 bold", command=self.modifyCrossFade, activebackground="#B9B9B9") self.crossFadeButton.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 1', height=1) self.spacerLabel.pack() self.randomNbRepFrame = Frame(self) self.nbRepText = Text(self.randomNbRepFrame, height=1, width=4) self.nbRepText.insert(INSERT, "0") self.nbRepText.pack(side=LEFT) self.nbRepLabel = Label(self.randomNbRepFrame, text="apparitions", height=1, width=13, background='#C8C8C8') self.nbRepLabel.pack(side=RIGHT) self.randomNbRepFrame.pack() self.randomTimeFrame = Frame(self) self.timeText = Text(self.randomTimeFrame, height=1, width=4) self.timeText.insert(INSERT, "0") self.timeText.pack(side=LEFT) self.timeLabel = Label(self.randomTimeFrame, text="secondes", height=1, width=13, background='#C8C8C8') self.timeLabel.pack(side=RIGHT) self.randomTimeFrame.pack() self.randomButton = Button(self, text="Random", width=14, cursor="hand2", background='#C8C8C8', font="Helvetica 11 bold", command=self.modifyRandom, activebackground="#B0B0B0") self.randomButton.pack() self.configure(background="#FFF") self.pack(side=LEFT)
class PresentationPiste(Frame): """ Constructeur Paramètres ------------------ Presentation self : Objet créé Controller controller : Controller de la piste Canvas canvas : Canvas où sera affichée Presentation de la piste. # MODIF scrollbar int idPiste : Numéro attribué à la piste pour se repérer """ def __init__(self, controller, canvas, idPiste): super().__init__(canvas) self.canvas = canvas self.controller = controller self.window = None self.idPiste = idPiste self.suivant = None self.precedent = None self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 1', height=2) self.spacerLabel.pack() self.removeButton = Button(self, text="Supprimer", command=self.askRemovePiste, width=8, cursor="hand2", background='red', font="Helvetica 8 bold", foreground="white", activebackground="#EA0000", activeforeground="#EAEAEA") self.removeButton.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 2', height=1) self.spacerLabel.pack() self.idLabel = Label(self, text="CH " + str(self.idPiste), background="white", font='Helvetica 16 bold', foreground="#A0A0A0") self.idLabel.pack() self.nameLabel = Label(self, text="Veuillez charger un son", background="white", font='Helvetica 8 ', width=19, height=1) self.nameLabel.pack() self.LoadButton = Button(self, text="Charger", command=self.open_file, width=14, cursor="hand2", background='#C8C8C8', font="Helvetica 12 bold", activebackground="#B9B9B9", height=1) self.LoadButton.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 3', height=1) self.spacerLabel.pack() self.stereoLabel = Label(self, text="Stéréo", background="white", font="Helvetica 11 bold") self.stereoLabel.pack() self.stereoKnob = Knob(self, -1, 1, self.modifyStereoValue) self.stereoKnob.pack() self.spacerLabel = Label( self, text="", background='#FFFFFF', font='Helvetica 1', height=1, ) self.spacerLabel.pack() self.volumeLabel = Label(self, text="Volume", background="white", font="Helvetica 11 bold") self.volumeLabel.pack() self.volumeSlider = Scale(self, orient=VERTICAL, command=self.modifyVolumeValue, background="white", troughcolor='#C8C8C8', activebackground="#D9D9D9", font='Helvetica 10 bold', width=20, length=125, cursor="hand2", highlightthickness=0) self.volumeSlider.config(from_=150, to=0) self.setVolumeValue(100) self.volumeSlider.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 1', height=1) self.spacerLabel.pack() self.speedLabel = Label(self, text="Pitch", background="white", font="Helvetica 11 bold") self.speedLabel.pack() self.speedKnob = Knob(self, 0, 2, self.modifySpeedValue) self.speedKnob.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 1', height=1) self.spacerLabel.pack() self.muteLabel = Label(self, text="Mute", background="white", font="Helvetica 11 bold") self.muteLabel.pack() self.muteButtonState = False soundOn = PhotoImage(file="Images/unMute.png", master=self.canvas) self.muteButton = Button(self, image=soundOn, command=self.modifyMuteState, cursor="hand2") self.muteButton.image = soundOn self.muteButton.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 5', height=1) self.spacerLabel.pack() self.effectButton = Button(self, text="Effet", width=14, background='#C8C8C8', font="Helvetica 11 bold", cursor="hand2", command=self.modifyEffet, activebackground="#B9B9B9") self.effectButton.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 1', height=1) self.spacerLabel.pack() self.crossFadeButtonState = False self.crossFadeButton = Button(self, text="CrossFade", width=14, cursor="hand2", background='#C8C8C8', font="Helvetica 11 bold", command=self.modifyCrossFade, activebackground="#B9B9B9") self.crossFadeButton.pack() self.spacerLabel = Label(self, text="", background='#FFFFFF', font='Helvetica 1', height=1) self.spacerLabel.pack() self.randomNbRepFrame = Frame(self) self.nbRepText = Text(self.randomNbRepFrame, height=1, width=4) self.nbRepText.insert(INSERT, "0") self.nbRepText.pack(side=LEFT) self.nbRepLabel = Label(self.randomNbRepFrame, text="apparitions", height=1, width=13, background='#C8C8C8') self.nbRepLabel.pack(side=RIGHT) self.randomNbRepFrame.pack() self.randomTimeFrame = Frame(self) self.timeText = Text(self.randomTimeFrame, height=1, width=4) self.timeText.insert(INSERT, "0") self.timeText.pack(side=LEFT) self.timeLabel = Label(self.randomTimeFrame, text="secondes", height=1, width=13, background='#C8C8C8') self.timeLabel.pack(side=RIGHT) self.randomTimeFrame.pack() self.randomButton = Button(self, text="Random", width=14, cursor="hand2", background='#C8C8C8', font="Helvetica 11 bold", command=self.modifyRandom, activebackground="#B0B0B0") self.randomButton.pack() self.configure(background="#FFF") self.pack(side=LEFT) def open_file(self): """ Méthode qui signale l'importation d'un son. """ self.controller.listenerLoadTrack(self.idPiste) def setName(self, name): """ Méthode qui change le nom affiché du son Paramètre ----------- name : String nom à afficher """ self.nameLabel.config(text=name) def remove(self): """ Méthode qui détruit la presentation. """ self.destroy() def setID(self, id): """ Méthode qui attribut le numéro d'identifiant de la piste Paramètre ---------- id : int numéro d'identification de la piste """ self.idPiste = id self.idLabel.configure(text="CH " + str(self.idPiste)) def getID(self): """ Méthode qui renvoie le numéro d'identifiant de la piste Return ------------ int numéro d'identification de la piste """ return self.idPiste def getSuivant(self): """ Méthode qui renvoie la Presentation de la piste suivante Return -------------- Presentation Presentation de la piste suivante """ return self.suivant def setSuivant(self, suivant): """ Méthode qui attribut la Presentation de la piste suivante Parametres ------------------ suivant : Presentation de la piste suivante """ self.suivant = suivant def getPrecedent(self): """ Méthode qui renvoie la Presentation de la piste précédente Return -------------- Presentation Presentation de la piste précédente """ return self.precedent def setPrecedent(self, precedent): """ Méthode qui attribut la Presentation de la piste précédente Parametres ------------ precedent : Presentation de la piste précédente """ self.precedent = precedent def isMuted(self): """ Méthode qui retourne le boolean de si ça a été mise en sourdine Return ------------ boolean : si le son est en sourdine """ return self.muteButtonState def isInCrossFade(self): """ Méthode qui retourne le boolean de si ça a été mise en crossfade Return ------------ boolean : si le son est en crossfade """ return self.crossFadeButtonState def refreshMuteState(self, muteState): """ Méthode qui met à jour l'état du bouton mute Parametres ------------ muteState : boolean nouvelle état du bouton mute """ if muteState: soundOff = PhotoImage(file="Images/mute.png", master=self.canvas) self.muteButton.config(image=soundOff) self.muteButton.image = soundOff else: soundOn = PhotoImage(file="Images/unMute.png", master=self.canvas) self.muteButton.config(image=soundOn) self.muteButton.image = soundOn self.muteButtonState = muteState def refreshCrossFadeState(self, crossfade): self.crossFadeButtonState = crossfade def setVolumeValue(self, volumeValue): """ Méthode qui change la valeur du VolumeSlider. Parametres ------------- volumeValue : float Valeur du volume de la piste. """ self.volumeSlider.set(volumeValue) def setStereoValue(self, stereoValue): """ Méthode qui change la valeur du StéréoKnob. Parametres ------------ stereoValue : float Valeur du stéréo de la piste. """ self.stereoKnob.setValue(stereoValue) def setSpeedValue(self, SpeedValue): """ Méthode qui change la valeur du SpeedValue. Parametres ------------ SpeedValue : float Valeur du speed de la piste. """ self.speedKnob.setValue(SpeedValue) def resetRandomTexts(self): """ Méthode qui met à zero les textes pour le random. """ self.nbRepText.delete("1.0", 'end-1c') self.timeText.delete("1.0", 'end-1c') self.nbRepText.insert("1.0", "0") self.timeText.insert("1.0", "0") """ --- Méthodes associées aux boutons --- """ def modifyStereoValue(self): """ Méthode qui signale au contoller de modifier (si possible) la valeur du stéreo de la piste. """ self.controller.listenerStereo(self.stereoKnob.getValue(), self.idPiste) def modifySpeedValue(self): """ Méthode qui signale au contoller de modifier (si possible) la valeur de la vitesse de la piste. """ self.controller.listenerPitch(self.speedKnob.getValue(), self.idPiste) def modifyVolumeValue(self, vol): """ Méthode qui signale au contoller de modifier (si possible) la valeur du volume de la piste. """ self.controller.listenerVolume(int(vol), self.idPiste) def askRemovePiste(self): """ Méthode qui signale au contoller d'activer ou de désactiver le Random. """ self.controller.removeChannelID(self.idPiste) self.controller.controllerTop.scrollablePistesFrame.sortPresentation() self.controller.controllerTop.scrollablePistesFrame.updateScrollregion( ) def modifyMuteState(self): """ Méthode qui signale au contoller d'activer ou désactiver la mise en sourdine. """ self.controller.listenerMute(not (self.isMuted()), self.getID()) def modifyCrossFade(self): """ Méthode qui signale une demande de CrossFade. """ self.controller.listenerCrossFade(not (self.isInCrossFade()), self.getID()) def modifyRandom(self): """ Méthode qui signale une demande de Random. """ try: nbRep = (int)(self.nbRepText.get("1.0", 'end-1c')) timeRandom = (int)(self.timeText.get("1.0", 'end-1c')) self.controller.listenerRandom(nbRep, timeRandom, self.getID()) except ValueError: self.resetRandomTexts() def modifyEffet(self): """ Méthode qui signale une demande d'appliquer un effet """ self.controller.listenerEffet(self.getID())
#from gpiozero.pins.mock import MockFactory import os os.environ['GPIOZERO_PIN_FACTORY'] = os.environ.get('GPIOZERO_PIN_FACTORY', 'mock') import gpiozero import vlc from radioplayer import RadioPlayer from gpiozero import Button, Device from knob import Knob #Device.pin_factory = MockFactory() player = RadioPlayer() RADIOCOMERCIALButton = Button(22) #insert pin RFMButton = Button(21) #insert pin volumeKnob = Knob(16, 17, pin_button=7) # insert pins RFMButton.when_pressed = player.changeToRFM RFMButton.when_released = player.stopRFM RADIOCOMERCIALButton.when_pressed = player.changeToRADIOCOMERCIAL RADIOCOMERCIALButton.when_released = player.stopRADIOCOMERCIAL volumeKnob.on_rotate_left(player.volumeDown) volumeKnob.on_rotate_right(player.volumeUp) volumeKnob.on_press(player.toggleMute) #Device.pin_factory.pin(16).drive_low() #Device.pin_factory.pin(16).drive_high() #Device.pin_factory.pin(16).drive_low() #Device.pin_factory.pin(16).drive_high() #evice.pin_factory.pin(17).drive_low() #Device.pin_factory.pin(17).drive_high()
def print(self, lines): for k, line in enumerate(lines): if line is not None: self.lcd.setCursor(0, k) self.lcd.print(line) ## set up led led = Pin(25, Pin.OUT) ## set up lcd display 0 display0 = Screen(0, sda=8, scl=9) display1 = Screen(1, sda=6, scl=7) ## setup rotary angle sensors knob0 = Knob(26) knob1 = Knob(27) ## setup ultra-sonic distance sensor on Pin 20 sensor = UltrasonicSensor(20) ## set up servo motor servo = Servo(16) start = time.time() ball_position = 0 while time.time() - start < 20: ball_position = sensor.get_distance_cm() ball_setpoint = 50*knob0.get_value()/100
class Game: """ The main game class. This deals with two oscillators, of which one is adjustable. The diffrence between those frequencies are measured and compared to the wanted interval. Margin of errors is given i cents. """ screen = None center = None #screen center instructions = None #instructions surface interval = None #interval surface result = None # surface for result displaying path = None #for resources #GUI elements knob = None knob_rect = None plate = None running = False #state check intevals = None #interval array guide_osc = None # guide note oscillator guide = None # guide_osc frequency osc = None # user ajustable oscillator guide_ch = None #Audio channel osc_ch = None #Audio channel pitch = None # osc frequency steps = 1 # number of musical notes. Level one starts at an octave prev_steps = [] #stores old game settings max_freq = 0 # 4 x base oscillator frequency (two octaves) min_freq = 0 # bace oscillator frequency level = 1 #level pause = False # pausing main loop practise = False tuner = None acceptable_off = 10 # how many cents off for a corrects answer? def __init__(self, gradient, path): """ gradient: A gradient object to act as background path: path to images """ self.screen = gradient self.center = self.screen.get_rect().center self.path = path # interval class self.intervals = Interval() self.instr_str = 'UP AND DOWN ARROWS COARSE TUNE. USE LEFT AND RIGHT FOR FINE ADJUSTMENT' self.conf_str = 'PRESS ENTER TO CONFIRM' self.setLevel(self.level) self.initGUI() #self.initAudio() def initGUI(self): """ Inits the graphical components """ #clear background self.screen.clear() self.screen.draw() #knob image img = pygame.image.load(self.path + 'knob.png') #plates self.plate = pygame.image.load(self.path + 'rust.png') self.knob = Knob(img) self.knob.set_plate(self.plate) #self.knob.set_shadow((-6,-4), 150, 25) knb_center = self.knob.get_rect().center self.knob = (self.knob, (self.center[0]-knb_center[0], self.center[1]-knb_center[1])) # also stores knob.rect at blit time self.center = self.screen.get_rect().center #"back" back_img = pygame.image.load(self.path + 'back.png') back_pos = (30,30) #tuple width the image and it's position and a third element containting elements Rect. self.back = (back_img, (30,30), self.screen.blit(back_img, back_pos)) #arrow arrow_img = pygame.image.load(self.path + 'arrow.png') self.arrow = (arrow_img, (self.center[0] - arrow_img.get_width()/2, 104)) #instructions, texts instrs = ['UP', 'DOWN', 'FINE UP', 'FINE DOWN', 'PRESS ENTER TO CONFIRM'] font = pygame.font.Font(self.path + 'Actor-Regular.ttf', 10) #instructions, key images key_images = pygame.Surface((184, 69), pygame.SRCALPHA, 32) #collecting those images in a surface, for flexible positioning. key_images_cp = key_images.get_rect().center img = pygame.image.load(self.path + 'key.png') up = pygame.transform.rotozoom(img, 90, 1) key_images.blit(up, (key_images_cp[0] - up.get_size()[0]/2, 0)) #up arrow key_images.blit(font.render(instrs[0], True, BLACK), (key_images_cp[0] - font.size(instrs[0])[0]/2, 9)) #up text key_images.blit(font.render(instrs[3], True, BLACK), (0, key_images_cp[1] - font.size(instrs[3])[1]/2)) #left text left = pygame.transform.rotozoom(img, 180, 1) key_images.blit(left, (font.size(instrs[3])[0] + 5, key_images_cp[1] - left.get_size()[1]/2)) #left arrow right = img key_images.blit(right, (key_images.get_width() - font.size(instrs[3])[0] - 5 - right.get_size()[0], key_images_cp[1] - right.get_size()[1]/2)) #right arrow (reflects left) key_images.blit(font.render(instrs[2], True, BLACK), (key_images.get_width() - font.size(instrs[3])[0] + 5 - right.get_size()[0], key_images_cp[1] - font.size(instrs[2])[1]/2)) #right text key_images.blit(font.render(instrs[1], True, BLACK), (key_images_cp[0] - font.size(instrs[1])[0]/2, 44)) #down text down = pygame.transform.rotozoom(img, 270, 1) key_images.blit(down, (key_images_cp[0] - down.get_size()[0]/2, 69 - down.get_size()[1])) #up arrow #public parent container for instructions self.instructions = pygame.Surface((self.screen.get_width(), 115), pygame.SRCALPHA, 32) self.instructions.blit(key_images, (self.instructions.get_rect().center[0] - key_images_cp[0], 0)) self.instructions.blit(font.render(instrs[4], True, BLACK),(self.instructions.get_rect().center[0] - font.size(instrs[4])[0]/2, key_images.get_height() + 20)) def initAudio(self): """ Inits the two oscillators and their channels. """ #guide tone self.guide_osc = Oscillator('sine', self.guide, BUFFER_SIZE) self.guide_ch = pygame.mixer.Channel(0) self.guide_ch.set_volume(0.9/2.0) #adjustable (the knob one), starts at same freq self.osc = Oscillator('sine', self.pitch, BUFFER_SIZE) self.osc_ch = pygame.mixer.Channel(1) self.osc_ch.set_volume(0.9/2.0) def setLevel(self, level): """ inits different levels """ lowest_freq = 220 # low limit # for use in levels > 4 rand_guide = self.stepToFreq(random.randint(0, 12), 220) # 220Hz < 440Hz in perfect notes. if level == 1: self.guide = 440 self.steps = 0 self.pitch = self.stepToFreq(1, self.guide) elif level == 2: self.guide = 440 self.steps = 12 self.pitch = self.stepToFreq(11, self.guide) elif level == 3: self.guide = 440 self.steps = 7 self.pitch = self.stepToFreq(6, self.guide) elif level == 4: self.guide = rand_guide self.steps = 5 init_rand = random.randint(0, 11) self.pitch = self.stepToFreq(init_rand, self.guide) elif level == 5: self.guide = rand_guide self.steps = self.randExclude(self.prev_steps + [5], 0,12) init_rand = random.randint(0, 11) self.pitch = self.stepToFreq(11, self.guide) elif level == 6: self.guide = rand_guide self.steps = self.randExclude(self.prev_steps + [6]) init_rand = random.randint(0, 24) self.pitch = self.stepToFreq(11, self.guide) elif level >= 7: self.guide = rand_guide self.steps = random.randint(0,24) # whole range init_rand = random.randint(0, 24) self.pitch = self.stepToFreq(11, self.guide) else: return False self.prev_steps.append(self.steps) #store, for unique intervals the first 6 levels # set min/max frequencies self.max_freq = self.guide * 4 # maximum frequency self.min_freq = self.guide - 20# minimum frequency #set interval text self.setIntervalText() def setIntervalText(self): """ Text to display the wanted interval """ font = pygame.font.Font(pygame.font.get_default_font(), 18) img = font.render(self.intervals.at(self.steps), True, BLACK) #interval surface gets made every time function is called, this is done during pauses in main loop. The inefficiency should not be a problem. self.interval = pygame.Surface((self.screen.get_width(), font.get_height()), SRCALPHA, 32) self.interval.blit(img, (self.center[0] - img.get_width()/2, 0)) def draw(self): """ draw screen """ self.back = (self.back[0], self.back[1], self.screen.blit(self.back[0], self.back[1])) self.screen.blit(self.arrow[0], self.arrow[1]) self.screen.blit(self.knob[0], self.knob[1]) if not self.pause: self.screen.blit(self.interval, (0, 70)) self.screen.blit(self.instructions, (0, 285)) #practise mode? if self.practise is True: #display tuner goal = self.stepToFreq(self.steps, self.guide_osc.frequency()) cents = self.hertzToCents(goal, self.pitch) self.tuner.update(cents) self.screen.blit(self.tuner, (self.center[0]-self.tuner.center[0], 20)) self.screen.draw() def updateChannels(self): """ update audio queues """ if self.guide_ch.get_queue() == None: self.guide_ch.queue(self.guide_osc.samples()) if self.osc_ch.get_queue() == None: self.osc_ch.queue(self.osc.samples()) def set_practise(self, on=True): """ Turn practise mode on/off """ self.practise = on self.tuner = Tuner(self.path) #initiats at practise on, and stays. def message(self): """ Checks current frequency (at the adjustable oscillator) and sets a message to user """ font = pygame.font.Font(pygame.font.get_default_font(), 18) goal = self.stepToFreq(self.steps, self.guide_osc.frequency()) cents = self.hertzToCents(goal, self.pitch) self.screen.clear() if cents < 0: off = 'flat' elif cents > 0: off = 'sharp' msg = '' #ok? if cents > -self.acceptable_off and cents < self.acceptable_off: self.level += 1; self.setLevel(self.level) self.guide_osc.set_frequency(self.guide) msg = 'Well done! Just ' + str(round(cents,1)) + ' cents ' + off + '.' else: msg = str(round(cents,1)) + ' cents ' + off + '. Try again' if round(cents,1) == 0: msg = 'Amazing! Right on the spot!' #display message img = font.render(msg.upper(), True, BLACK) self.screen.blit(img, (self.center[0] - img.get_width()/2, 70)) #instruction message cont = 'PRESS ANY KEY TO CONTINUE.' font = pygame.font.Font(self.path + 'Actor-Regular.ttf', 10) self.screen.blit(font.render(cont, True, BLACK),(self.center[0] - font.size(cont)[0]/2, self.screen.get_height() - font.size(cont)[1] - 13)) self.draw() def run(self): """ main game loop. Always starts from level 1, and reinits the oscillators/audio channels """ if self.running: return False self.running = True degrees = 0 self.setLevel(1) # start from level 1 again self.initAudio() # init audio here for fresh oscillators clock = pygame.time.Clock() while self.running: if not self.pause: #start with checking each channels audio queue self.updateChannels() self.screen.clear() mx,my = pygame.mouse.get_pos() keystate = pygame.key.get_pressed() #fast increase frequency if keystate[K_UP]: if self.pitch < self.max_freq: self.pitch += 1.6#*= 1.01 #self.pitch *= 1.01 degrees += 1.3 self.knob[0].rotate(degrees) #fast decrease frequency elif keystate[K_DOWN]: if self.pitch > self.min_freq: self.pitch -= 1.6#/= 1.01 #self.pitch /= 1.01 degrees -= 1.3 self.knob[0].rotate(degrees) #slow decrease frequency elif keystate[K_LEFT]: if self.pitch > self.min_freq: self.pitch -= 0.1 degrees -= 0.2 self.knob[0].rotate(degrees) #slow increase frequency elif keystate[K_RIGHT]: if self.pitch < self.max_freq: self.pitch += 0.1 degrees += 0.2 self.knob[0].rotate(degrees) self.osc.set_frequency(self.pitch) for e in pygame.event.get(): if e.type == QUIT: self.running = False elif e.type == MOUSEBUTTONDOWN: #check back button if self.back[2].collidepoint(e.pos): self.running = False elif e.type == KEYUP: #unpause if self.pause: self.pause = False break elif e.key == K_RETURN: self.pause = True self.message() if not self.pause: #redraw screen self.draw() clock.tick(60) self.running = False return True #helpers def hertzToCents(self, a, b): try: return 1200 * math.log((b/float(a)), 2) except Exception as e: print e return 0 def posToDeg(self, pos): #not used """ Returns a positions degree from windows center """ degree = math.degrees(math.atan2(self.center[1]-pos[1], self.center[0]-pos[0])) + 180 if degree == 360.0: degree = 0 return round(degree) def randExclude(self, seq, low=0, high=24): """ returns a random integer seq: numbers to exclude (list) low: lowest int high: highest int """ rand = 0 while rand in seq: rand = random.randint(low, high) return rand def stepToFreq(self, step, frequency=False): """ returns a frequncy scale or a new frequency step: number of keys frequency: from frequency """ if not frequency: return math.pow(2, step/12.0) return frequency * math.pow(2, step/12.0) def freqToNote(self, freq): #not used """ Code for determining note name from frequency value. Code is written for equal temperament and A=440. Notes are displayed according to sharps. This can be overrided easily by changing the array definition below. Written by Firat Civaner (for mathlab) http://www.mathworks.com/matlabcentral/fileexchange/35330-frequency-to-note/content/freq2note.m return: A tuple with a string with notename + octave and frequency offset in cents """ A4 = 440 notenames = ['C' , 'C#', 'D' , 'D#' , 'E' , 'F' , 'F#', 'G' , 'G#' , 'A' , 'A#' , 'B' ] centdif = round( 1200 * math.log(freq/A4)/math.log(2)) notedif = round(centdif/100) if centdif % 100 > 50: notedif = notedif + 1 error = centdif-notedif*100 notenumber = notedif + 9 + 12*4 #count of half tones starting from C0. octavenumber = round((notenumber)/12) place = int(round(notenumber % 12 + 1)) if place < 0 or place > len(notenames)-1: print place return 'error' try: return (notenames[place]+str(octavenumber), error) except: return 'Error. Could not identify note'
def __init__(self, **kwargs): super(Otmg, self).__init__(**kwargs) self.otm = Otm("XV1") self.otm.load("Roman_Numeral_Square_Root") self.alph = self.otm.findchars() #Clock.schedule_interval(self.runstep_callback, 0.0000005) self.lastloc = 0 self.movedloc = False self.orientation = 'vertical' self.padding = 20 self.row1 = BoxLayout(size_hint=(1,0.2)) self.row1.tape = LabelB(text=self.otm.croptape(30), size_hint=(1, 1), bold=True, halign='center', valign='top', color=(0, 0, 0, 1), bcolor=(1, 1, 0.7, 1), font_name='Courier New') self.row1.add_widget(self.row1.tape) self.add_widget(self.row1) self.row15 = BoxLayout(size_hint=(1, 0.01)) self.row15.pointer = LabelB(text='^', halign='center', color=(1, 0, 0 ,1), bcolor=(1, 1, 0.9, 1), valign = 'top') self.row15.add_widget(self.row15.pointer) self.add_widget(self.row15) self.row2 = BoxLayout(orientation='horizontal') self.row2.it1 = BoxLayout(orientation='vertical') self.row2.it2 = BoxLayout(orientation='horizontal') self.row2.it3 = BoxLayout(orientation='vertical') self.row2.gear_left = Image(source='cw.zip', anim_delay=-1, size_hint=(1, 1)) self.row2.it1.add_widget(self.row2.gear_left) self.row2.desc1 = BoxLayout(orientation='horizontal') self.row2.actdesc1 = Button(text=" ", font_size=25, color=(0, 0, 0, 1), background_color=(138/255, 43/255, 226/255, 1), size_hint=(0.5, 0.5), background_normal='') self.row2.actdesc1.bind(on_press=self.write_char) self.row2.knob_left = Knob(size=(125,125), step=100/len(self.alph), knobimg_source="knob/img/knob_metal.png", marker_img="knob/img/bline.png", markeroff_color=(0.3, 0.3, 0.3, 1)) self.row2.knob_left.bind(on_touch_move=self.change_char) self.row2.desc1.add_widget(self.row2.knob_left) self.row2.desc1.add_widget(self.row2.actdesc1) self.row2.it1.add_widget(self.row2.desc1) self.row2.it2.program = LabelB(text=''.join(txtformat(self.otm.cropprog(3))), color=(0, 0, 0, 1), bold=True, halign='left', valign='top', bcolor=(1, 1, 0.8, 1), size_hint=(0.9, 1), font_name="Courier New", text_size=(200, None)) self.row2.it2.pointer = LabelB(text='->', color=(1, 0, 0, 1), halign='right', valign='middle', size_hint=(0.1, 1), bcolor=(1, 1, 0.8, 1)) self.row2.it2.add_widget(self.row2.it2.pointer) self.row2.it2.add_widget(self.row2.it2.program) self.row2.gear_right = Image(source='cw.zip', anim_delay=-1, size_hint=(1, 1)) self.row2.it3.add_widget(self.row2.gear_right) self.row2.desc2 = BoxLayout(orientation='horizontal') self.row2.actdesc2 = LabelB(text='Location -->', color=(0, 0, 0, 1), bcolor=(1, 1, 1, 1)) self.row2.knob_right = Knob(size=(125,125), knobimg_source="knob/img/knob_metal.png", marker_img="knob/img/bline.png", markeroff_color=(0.3, 0.3, 0.3, 1)) self.row2.knob_right.bind(on_touch_move=self.set_location) self.row2.desc2.add_widget(self.row2.actdesc2) self.row2.desc2.add_widget(self.row2.knob_right) self.row2.it3.add_widget(self.row2.desc2) self.row2.add_widget(self.row2.it1) self.row2.add_widget(self.row2.it2) self.row2.add_widget(self.row2.it3) self.add_widget(self.row2) self.row3 = BoxLayout(orientation='horizontal', size_hint=(1, 0.3)) self.row3.slider = OtmgSlider(min=0, max=100, value=0) self.row3.add_widget(self.row3.slider) self.add_widget(self.row3) self.row4 = BoxLayout(orientation='horizontal', size_hint=(1, 0.5)) self.row4.btn1 = ToggleButton(text='Start/Stop') self.row4.btn1.bind(on_press=self.do_startstop) self.row4.add_widget(self.row4.btn1) self.row4.btn2 = Button(text='Step') self.row4.btn2.bind(on_press=self.do_step_request) self.row4.add_widget(self.row4.btn2) self.row4.btn3 = Button(text='Restart') self.row4.add_widget(self.row4.btn3) self.row4.btn4 = Button(text='Clear') self.row4.btn4.bind(on_press=self.do_clear) self.row4.add_widget(self.row4.btn4) self.row4.btn5 = Button(text='EXIT') self.row4.btn5.bind(on_press=self.exit) self.row4.add_widget(self.row4.btn5) self.add_widget(self.row4)
class Menu: """ Main menu for PyTone """ screen = None snap = 30 options = { } #map to keep track of our menu options. dict[degree] = (option_rect, return value) def __init__(self, gradient, path): """ gradient: A gradient object to act as background path: path to media """ start = 330 stop = 60 self.screen = gradient img = pygame.image.load(path + 'switch.png') self.switch = Knob(img, self.snap, (start, stop)) snd = pygame.mixer.Sound(path + 'switch_snd.ogg') self.switch.set_sound(snd) self.switch.set_volume(0.5) self.path = path def draw(self): #clear self.screen.clear() #blit switch object pos = self.tupleSub(self.screen.get_rect().center, self.switch.get_rect().center) self.screen.blit(self.switch, pos) #draw lines line_practice = pygame.draw.aalines(self.screen, BLACK, False, ((254, 167), (257, 164), (280, 164))) line_newGame = pygame.draw.aaline(self.screen, BLACK, (264, 200), (280, 200)) line_instr = pygame.draw.aalines(self.screen, BLACK, False, ((254, 233), (257, 236), (280, 236))) line_quit = pygame.draw.aalines(self.screen, BLACK, False, ((236, 264), (243, 272), (280, 272))) #make labels #logo font = pygame.font.Font(pygame.font.get_default_font(), 21) text = font.render('PyTone', True, BLACK) text_size = font.size('PyTone') self.screen.blit(text, (50, 192)) #menu options font = pygame.font.Font(self.path + "Actor-Regular.ttf", 10) practice = font.render("PRACTICE", True, BLACK) self.options[330] = (self.screen.blit(practice, (290, 158)), PRACTICE) new = font.render("NEW GAME", True, BLACK) self.options[0] = (self.screen.blit(new, (290, 194)), NEW_GAME) instructions = font.render('INSTRUCTIONS', True, BLACK) self.options[30] = (self.screen.blit(instructions, (290, 230)), INSTRUCTIONS) quit = font.render('EXIT', True, BLACK) self.options[60] = (self.screen.blit(quit, (290, 266)), QUIT) #draw screen self.screen.draw() def run(self): while True: self.draw() for e in pygame.event.get(): if e.type == QUIT: return QUIT if e.type == KEYUP: if e.key == K_UP: self.switch.snap('CCW') elif e.key == K_DOWN: self.switch.snap('CW') elif e.key in (K_RETURN, K_SPACE): try: return self.options[self.switch.degree()][1] except: print "Error. Unknown menu option: " + str( self.switch.degree()) #check for clicks elif e.type == MOUSEBUTTONUP: for key, value in self.options.items(): if value[0].collidepoint(e.pos): sw_deg = self.switch.degree() #Two clicks on the same label confirms if int(key) == int(sw_deg): return value[1] #rotate self.switch.rotate(key) pygame.time.wait(10) #helper functions def tupleAdd(self, a, b): """ Element wise addition of two tuples Credits to @delnan http://stackoverflow.com/questions/5607284/how-to-add-with-tuples """ return tuple(x + y for x, y in izip(a, b)) def tupleSub(self, a, b): return tuple(x - y for x, y in izip(a, b))
class Game: """ The main game class. This deals with two oscillators, of which one is adjustable. The diffrence between those frequencies are measured and compared to the wanted interval. Margin of errors is given i cents. """ screen = None center = None #screen center instructions = None #instructions surface interval = None #interval surface result = None # surface for result displaying path = None #for resources #GUI elements knob = None knob_rect = None plate = None running = False #state check intevals = None #interval array guide_osc = None # guide note oscillator guide = None # guide_osc frequency osc = None # user ajustable oscillator guide_ch = None #Audio channel osc_ch = None #Audio channel pitch = None # osc frequency steps = 1 # number of musical notes. Level one starts at an octave prev_steps = [] #stores old game settings max_freq = 0 # 4 x base oscillator frequency (two octaves) min_freq = 0 # bace oscillator frequency level = 1 #level pause = False # pausing main loop practise = False tuner = None acceptable_off = 10 # how many cents off for a corrects answer? def __init__(self, gradient, path): """ gradient: A gradient object to act as background path: path to images """ self.screen = gradient self.center = self.screen.get_rect().center self.path = path # interval class self.intervals = Interval() self.instr_str = 'UP AND DOWN ARROWS COARSE TUNE. USE LEFT AND RIGHT FOR FINE ADJUSTMENT' self.conf_str = 'PRESS ENTER TO CONFIRM' self.setLevel(self.level) self.initGUI() #self.initAudio() def initGUI(self): """ Inits the graphical components """ #clear background self.screen.clear() self.screen.draw() #knob image img = pygame.image.load(self.path + 'knob.png') #plates self.plate = pygame.image.load(self.path + 'rust.png') self.knob = Knob(img) self.knob.set_plate(self.plate) #self.knob.set_shadow((-6,-4), 150, 25) knb_center = self.knob.get_rect().center self.knob = (self.knob, (self.center[0] - knb_center[0], self.center[1] - knb_center[1]) ) # also stores knob.rect at blit time self.center = self.screen.get_rect().center #"back" back_img = pygame.image.load(self.path + 'back.png') back_pos = (30, 30) #tuple width the image and it's position and a third element containting elements Rect. self.back = (back_img, (30, 30), self.screen.blit(back_img, back_pos)) #arrow arrow_img = pygame.image.load(self.path + 'arrow.png') self.arrow = (arrow_img, (self.center[0] - arrow_img.get_width() / 2, 104)) #instructions, texts instrs = [ 'UP', 'DOWN', 'FINE UP', 'FINE DOWN', 'PRESS ENTER TO CONFIRM' ] font = pygame.font.Font(self.path + 'Actor-Regular.ttf', 10) #instructions, key images key_images = pygame.Surface( (184, 69), pygame.SRCALPHA, 32 ) #collecting those images in a surface, for flexible positioning. key_images_cp = key_images.get_rect().center img = pygame.image.load(self.path + 'key.png') up = pygame.transform.rotozoom(img, 90, 1) key_images.blit( up, (key_images_cp[0] - up.get_size()[0] / 2, 0)) #up arrow key_images.blit( font.render(instrs[0], True, BLACK), (key_images_cp[0] - font.size(instrs[0])[0] / 2, 9)) #up text key_images.blit( font.render(instrs[3], True, BLACK), (0, key_images_cp[1] - font.size(instrs[3])[1] / 2)) #left text left = pygame.transform.rotozoom(img, 180, 1) key_images.blit(left, (font.size(instrs[3])[0] + 5, key_images_cp[1] - left.get_size()[1] / 2)) #left arrow right = img key_images.blit( right, (key_images.get_width() - font.size(instrs[3])[0] - 5 - right.get_size()[0], key_images_cp[1] - right.get_size()[1] / 2)) #right arrow (reflects left) key_images.blit(font.render(instrs[2], True, BLACK), (key_images.get_width() - font.size(instrs[3])[0] + 5 - right.get_size()[0], key_images_cp[1] - font.size(instrs[2])[1] / 2)) #right text key_images.blit( font.render(instrs[1], True, BLACK), (key_images_cp[0] - font.size(instrs[1])[0] / 2, 44)) #down text down = pygame.transform.rotozoom(img, 270, 1) key_images.blit(down, (key_images_cp[0] - down.get_size()[0] / 2, 69 - down.get_size()[1])) #up arrow #public parent container for instructions self.instructions = pygame.Surface((self.screen.get_width(), 115), pygame.SRCALPHA, 32) self.instructions.blit( key_images, (self.instructions.get_rect().center[0] - key_images_cp[0], 0)) self.instructions.blit( font.render(instrs[4], True, BLACK), (self.instructions.get_rect().center[0] - font.size(instrs[4])[0] / 2, key_images.get_height() + 20)) def initAudio(self): """ Inits the two oscillators and their channels. """ #guide tone self.guide_osc = Oscillator('sine', self.guide, BUFFER_SIZE) self.guide_ch = pygame.mixer.Channel(0) self.guide_ch.set_volume(0.9 / 2.0) #adjustable (the knob one), starts at same freq self.osc = Oscillator('sine', self.pitch, BUFFER_SIZE) self.osc_ch = pygame.mixer.Channel(1) self.osc_ch.set_volume(0.9 / 2.0) def setLevel(self, level): """ inits different levels """ lowest_freq = 220 # low limit # for use in levels > 4 rand_guide = self.stepToFreq(random.randint(0, 12), 220) # 220Hz < 440Hz in perfect notes. if level == 1: self.guide = 440 self.steps = 0 self.pitch = self.stepToFreq(1, self.guide) elif level == 2: self.guide = 440 self.steps = 12 self.pitch = self.stepToFreq(11, self.guide) elif level == 3: self.guide = 440 self.steps = 7 self.pitch = self.stepToFreq(6, self.guide) elif level == 4: self.guide = rand_guide self.steps = 5 init_rand = random.randint(0, 11) self.pitch = self.stepToFreq(init_rand, self.guide) elif level == 5: self.guide = rand_guide self.steps = self.randExclude(self.prev_steps + [5], 0, 12) init_rand = random.randint(0, 11) self.pitch = self.stepToFreq(11, self.guide) elif level == 6: self.guide = rand_guide self.steps = self.randExclude(self.prev_steps + [6]) init_rand = random.randint(0, 24) self.pitch = self.stepToFreq(11, self.guide) elif level >= 7: self.guide = rand_guide self.steps = random.randint(0, 24) # whole range init_rand = random.randint(0, 24) self.pitch = self.stepToFreq(11, self.guide) else: return False self.prev_steps.append( self.steps) #store, for unique intervals the first 6 levels # set min/max frequencies self.max_freq = self.guide * 4 # maximum frequency self.min_freq = self.guide - 20 # minimum frequency #set interval text self.setIntervalText() def setIntervalText(self): """ Text to display the wanted interval """ font = pygame.font.Font(pygame.font.get_default_font(), 18) img = font.render(self.intervals.at(self.steps), True, BLACK) #interval surface gets made every time function is called, this is done during pauses in main loop. The inefficiency should not be a problem. self.interval = pygame.Surface( (self.screen.get_width(), font.get_height()), SRCALPHA, 32) self.interval.blit(img, (self.center[0] - img.get_width() / 2, 0)) def draw(self): """ draw screen """ self.back = (self.back[0], self.back[1], self.screen.blit(self.back[0], self.back[1])) self.screen.blit(self.arrow[0], self.arrow[1]) self.screen.blit(self.knob[0], self.knob[1]) if not self.pause: self.screen.blit(self.interval, (0, 70)) self.screen.blit(self.instructions, (0, 285)) #practise mode? if self.practise is True: #display tuner goal = self.stepToFreq(self.steps, self.guide_osc.frequency()) cents = self.hertzToCents(goal, self.pitch) self.tuner.update(cents) self.screen.blit(self.tuner, (self.center[0] - self.tuner.center[0], 20)) self.screen.draw() def updateChannels(self): """ update audio queues """ if self.guide_ch.get_queue() == None: self.guide_ch.queue(self.guide_osc.samples()) if self.osc_ch.get_queue() == None: self.osc_ch.queue(self.osc.samples()) def set_practise(self, on=True): """ Turn practise mode on/off """ self.practise = on self.tuner = Tuner(self.path) #initiats at practise on, and stays. def message(self): """ Checks current frequency (at the adjustable oscillator) and sets a message to user """ font = pygame.font.Font(pygame.font.get_default_font(), 18) goal = self.stepToFreq(self.steps, self.guide_osc.frequency()) cents = self.hertzToCents(goal, self.pitch) self.screen.clear() if cents < 0: off = 'flat' elif cents > 0: off = 'sharp' msg = '' #ok? if cents > -self.acceptable_off and cents < self.acceptable_off: self.level += 1 self.setLevel(self.level) self.guide_osc.set_frequency(self.guide) msg = 'Well done! Just ' + str(round(cents, 1)) + ' cents ' + off + '.' else: msg = str(round(cents, 1)) + ' cents ' + off + '. Try again' if round(cents, 1) == 0: msg = 'Amazing! Right on the spot!' #display message img = font.render(msg.upper(), True, BLACK) self.screen.blit(img, (self.center[0] - img.get_width() / 2, 70)) #instruction message cont = 'PRESS ANY KEY TO CONTINUE.' font = pygame.font.Font(self.path + 'Actor-Regular.ttf', 10) self.screen.blit(font.render(cont, True, BLACK), (self.center[0] - font.size(cont)[0] / 2, self.screen.get_height() - font.size(cont)[1] - 13)) self.draw() def run(self): """ main game loop. Always starts from level 1, and reinits the oscillators/audio channels """ if self.running: return False self.running = True degrees = 0 self.setLevel(1) # start from level 1 again self.initAudio() # init audio here for fresh oscillators clock = pygame.time.Clock() while self.running: if not self.pause: #start with checking each channels audio queue self.updateChannels() self.screen.clear() mx, my = pygame.mouse.get_pos() keystate = pygame.key.get_pressed() #fast increase frequency if keystate[K_UP]: if self.pitch < self.max_freq: self.pitch += 1.6 #*= 1.01 #self.pitch *= 1.01 degrees += 1.3 self.knob[0].rotate(degrees) #fast decrease frequency elif keystate[K_DOWN]: if self.pitch > self.min_freq: self.pitch -= 1.6 #/= 1.01 #self.pitch /= 1.01 degrees -= 1.3 self.knob[0].rotate(degrees) #slow decrease frequency elif keystate[K_LEFT]: if self.pitch > self.min_freq: self.pitch -= 0.1 degrees -= 0.2 self.knob[0].rotate(degrees) #slow increase frequency elif keystate[K_RIGHT]: if self.pitch < self.max_freq: self.pitch += 0.1 degrees += 0.2 self.knob[0].rotate(degrees) self.osc.set_frequency(self.pitch) for e in pygame.event.get(): if e.type == QUIT: self.running = False elif e.type == MOUSEBUTTONDOWN: #check back button if self.back[2].collidepoint(e.pos): self.running = False elif e.type == KEYUP: #unpause if self.pause: self.pause = False break elif e.key == K_RETURN: self.pause = True self.message() if not self.pause: #redraw screen self.draw() clock.tick(60) self.running = False return True #helpers def hertzToCents(self, a, b): try: return 1200 * math.log((b / float(a)), 2) except Exception as e: print e return 0 def posToDeg(self, pos): #not used """ Returns a positions degree from windows center """ degree = math.degrees( math.atan2(self.center[1] - pos[1], self.center[0] - pos[0])) + 180 if degree == 360.0: degree = 0 return round(degree) def randExclude(self, seq, low=0, high=24): """ returns a random integer seq: numbers to exclude (list) low: lowest int high: highest int """ rand = 0 while rand in seq: rand = random.randint(low, high) return rand def stepToFreq(self, step, frequency=False): """ returns a frequncy scale or a new frequency step: number of keys frequency: from frequency """ if not frequency: return math.pow(2, step / 12.0) return frequency * math.pow(2, step / 12.0) def freqToNote(self, freq): #not used """ Code for determining note name from frequency value. Code is written for equal temperament and A=440. Notes are displayed according to sharps. This can be overrided easily by changing the array definition below. Written by Firat Civaner (for mathlab) http://www.mathworks.com/matlabcentral/fileexchange/35330-frequency-to-note/content/freq2note.m return: A tuple with a string with notename + octave and frequency offset in cents """ A4 = 440 notenames = [ 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B' ] centdif = round(1200 * math.log(freq / A4) / math.log(2)) notedif = round(centdif / 100) if centdif % 100 > 50: notedif = notedif + 1 error = centdif - notedif * 100 notenumber = notedif + 9 + 12 * 4 #count of half tones starting from C0. octavenumber = round((notenumber) / 12) place = int(round(notenumber % 12 + 1)) if place < 0 or place > len(notenames) - 1: print place return 'error' try: return (notenames[place] + str(octavenumber), error) except: return 'Error. Could not identify note'
def initGUI(self): """ Inits the graphical components """ #clear background self.screen.clear() self.screen.draw() #knob image img = pygame.image.load(self.path + 'knob.png') #plates self.plate = pygame.image.load(self.path + 'rust.png') self.knob = Knob(img) self.knob.set_plate(self.plate) #self.knob.set_shadow((-6,-4), 150, 25) knb_center = self.knob.get_rect().center self.knob = (self.knob, (self.center[0] - knb_center[0], self.center[1] - knb_center[1]) ) # also stores knob.rect at blit time self.center = self.screen.get_rect().center #"back" back_img = pygame.image.load(self.path + 'back.png') back_pos = (30, 30) #tuple width the image and it's position and a third element containting elements Rect. self.back = (back_img, (30, 30), self.screen.blit(back_img, back_pos)) #arrow arrow_img = pygame.image.load(self.path + 'arrow.png') self.arrow = (arrow_img, (self.center[0] - arrow_img.get_width() / 2, 104)) #instructions, texts instrs = [ 'UP', 'DOWN', 'FINE UP', 'FINE DOWN', 'PRESS ENTER TO CONFIRM' ] font = pygame.font.Font(self.path + 'Actor-Regular.ttf', 10) #instructions, key images key_images = pygame.Surface( (184, 69), pygame.SRCALPHA, 32 ) #collecting those images in a surface, for flexible positioning. key_images_cp = key_images.get_rect().center img = pygame.image.load(self.path + 'key.png') up = pygame.transform.rotozoom(img, 90, 1) key_images.blit( up, (key_images_cp[0] - up.get_size()[0] / 2, 0)) #up arrow key_images.blit( font.render(instrs[0], True, BLACK), (key_images_cp[0] - font.size(instrs[0])[0] / 2, 9)) #up text key_images.blit( font.render(instrs[3], True, BLACK), (0, key_images_cp[1] - font.size(instrs[3])[1] / 2)) #left text left = pygame.transform.rotozoom(img, 180, 1) key_images.blit(left, (font.size(instrs[3])[0] + 5, key_images_cp[1] - left.get_size()[1] / 2)) #left arrow right = img key_images.blit( right, (key_images.get_width() - font.size(instrs[3])[0] - 5 - right.get_size()[0], key_images_cp[1] - right.get_size()[1] / 2)) #right arrow (reflects left) key_images.blit(font.render(instrs[2], True, BLACK), (key_images.get_width() - font.size(instrs[3])[0] + 5 - right.get_size()[0], key_images_cp[1] - font.size(instrs[2])[1] / 2)) #right text key_images.blit( font.render(instrs[1], True, BLACK), (key_images_cp[0] - font.size(instrs[1])[0] / 2, 44)) #down text down = pygame.transform.rotozoom(img, 270, 1) key_images.blit(down, (key_images_cp[0] - down.get_size()[0] / 2, 69 - down.get_size()[1])) #up arrow #public parent container for instructions self.instructions = pygame.Surface((self.screen.get_width(), 115), pygame.SRCALPHA, 32) self.instructions.blit( key_images, (self.instructions.get_rect().center[0] - key_images_cp[0], 0)) self.instructions.blit( font.render(instrs[4], True, BLACK), (self.instructions.get_rect().center[0] - font.size(instrs[4])[0] / 2, key_images.get_height() + 20))
# setup trellis i2c = busio.I2C(board.SCL, board.SDA) addresses = [0x71, 0x70] if i2c is not None: print("I2C devices found: ", [hex(i) for i in i2c.scan()]) trellis = Trellis(i2c, addresses) trellis.led.fill(False) trellis.brightness = 1 # collect all the metronome's callbacks ctlButtons = ControllerButtons(midi_h) state = ButtonState() knob = Knob() # button reconciler async def button_handler(clock): # add some button chill so we don't spam notes global bounce_count if bounce_count % 3 != 0: bounce_count += 1 return bounce_count = 1 # get button state state.set_buttons(trellis)
def getUI(self): """get the ui element""" result = Knob() if self.value: result.value = self.value skin = sm.getSkin('knob', self.asset) result.size = sm.getControlSize(skin, self.asset) result.knobimg_source = os.path.join(skin['path'], skin["knob"]) result.marker_img = os.path.join(skin['path'], skin['marker']) result.min = sm.getMinimum('knob', self.value, self._typeInfo) result.max = sm.getMaximum('knob', self.value, self._typeInfo) result.step = sm.getStep('knob', self._typeInfo) result.show_label = sm.getVar(skin, self.asset, "show_label", False) result.show_marker = sm.getVar(skin, self.asset, "show_marker", False) self.uiEl = result self.prepareUiElement() if sm.getVar(skin, self.asset, "send_on_release", False): result.on_dragEnded = self.value_changed # set the callback for when drag ends (self made, so no binding) else: result.bind(value=self.value_changed) return result
class Menu: """ Main menu for PyTone """ screen = None snap = 30 options = {} #map to keep track of our menu options. dict[degree] = (option_rect, return value) def __init__(self, gradient, path): """ gradient: A gradient object to act as background path: path to media """ start = 330 stop = 60 self.screen = gradient img = pygame.image.load(path + 'switch.png') self.switch = Knob(img, self.snap, (start, stop)) snd = pygame.mixer.Sound(path + 'switch_snd.ogg') self.switch.set_sound(snd) self.switch.set_volume(0.5) self.path = path def draw(self): #clear self.screen.clear() #blit switch object pos = self.tupleSub(self.screen.get_rect().center, self.switch.get_rect().center) self.screen.blit(self.switch, pos) #draw lines line_practice = pygame.draw.aalines(self.screen, BLACK, False, ((254, 167), (257,164),(280,164))) line_newGame = pygame.draw.aaline(self.screen, BLACK, (264, 200), (280,200)) line_instr = pygame.draw.aalines(self.screen, BLACK, False, ((254, 233), (257,236),(280,236))) line_quit = pygame.draw.aalines(self.screen, BLACK, False, ((236, 264), (243,272),(280,272))) #make labels #logo font = pygame.font.Font(pygame.font.get_default_font(), 21) text = font.render('PyTone', True, BLACK) text_size = font.size('PyTone') self.screen.blit(text, (50,192)) #menu options font = pygame.font.Font(self.path + "Actor-Regular.ttf", 10) practice = font.render("PRACTICE", True, BLACK) self.options[330] = (self.screen.blit(practice,(290,158)), PRACTICE) new = font.render("NEW GAME", True, BLACK) self.options[0] = (self.screen.blit(new,(290,194)), NEW_GAME) instructions = font.render('INSTRUCTIONS', True, BLACK) self.options[30] = (self.screen.blit(instructions,(290, 230)), INSTRUCTIONS) quit = font.render('EXIT', True, BLACK) self.options[60] = (self.screen.blit(quit, (290,266)), QUIT) #draw screen self.screen.draw() def run(self): while True: self.draw() for e in pygame.event.get(): if e.type == QUIT: return QUIT if e.type == KEYUP: if e.key == K_UP: self.switch.snap('CCW') elif e.key == K_DOWN: self.switch.snap('CW') elif e.key in (K_RETURN, K_SPACE): try: return self.options[self.switch.degree()][1] except: print "Error. Unknown menu option: " + str(self.switch.degree()) #check for clicks elif e.type == MOUSEBUTTONUP: for key, value in self.options.items(): if value[0].collidepoint(e.pos): sw_deg = self.switch.degree() #Two clicks on the same label confirms if int(key) == int(sw_deg): return value[1] #rotate self.switch.rotate(key) pygame.time.wait(10) #helper functions def tupleAdd(self, a, b): """ Element wise addition of two tuples Credits to @delnan http://stackoverflow.com/questions/5607284/how-to-add-with-tuples """ return tuple(x + y for x, y in izip(a, b)) def tupleSub(self, a, b): return tuple(x - y for x, y in izip(a, b))
def __init__(self, **kwargs): super(Otmg, self).__init__(**kwargs) self.progs = os.listdir("../../otmp") self.prog = "Roman_Numeral_Square_Root" self.steps = 0 self.geardir = "CW" self.otm = Otm(" ") self.otm.load(self.prog) self.alph = self.otm.findchars() self.lasttape = self.otm.tape self.changetape = True self.lastloc = 0 self.movedloc = False self.lastleftknob = 0 self.lastrightknob = 0 self.lastinput = [" "] self.setlast = False self.orientation = 'vertical' self.padding = 20 self.row0 = BoxLayout(size_hint=(1, 0.1)) self.row0.prev = Button(text="Previous", size_hint=(0.25, 1)) self.row0.prev.bind(on_press=self.prev) self.row0.add_widget(self.row0.prev) self.row0.title = LabelB(text=self.prog.replace("_", " "), size_hint=(0.5, 1), halign='center', valign='top', color=(0, 0, 0, 1), font_size=25, bcolor=(1, 1, 1, 1)) self.row0.add_widget(self.row0.title) self.row0.nex = Button(text="Next", size_hint=(0.25, 1)) self.row0.nex.bind(on_press=self.nex) self.row0.add_widget(self.row0.nex) self.add_widget(self.row0) self.row1 = BoxLayout(size_hint=(1, 0.2)) self.row1.tape = LabelB(text=self.otm.croptape(25), size_hint=(1, 1), halign='center', valign='top', color=(0, 0, 0, 1), font_size=25, bcolor=(210 / 255.0, 105 / 255.0, 30 / 255.0, 1), font_name='Courier New Bold') self.row1.add_widget(self.row1.tape) self.add_widget(self.row1) self.row15 = BoxLayout(size_hint=(1, 0.01)) self.row15.pointer = LabelB(text='^', halign='center', color=(0, 0, 0, 1), bcolor=(210 / 255.0, 105 / 255.0, 30 / 255.0, 1), valign='top') self.row15.add_widget(self.row15.pointer) self.add_widget(self.row15) self.row2 = BoxLayout(orientation='horizontal') self.row2.it1 = BoxLayout(orientation='vertical') self.row2.it2 = BoxLayout(orientation='horizontal') self.row2.it3 = BoxLayout(orientation='vertical') self.row2.gear_left = Image(source='Clockwise/Gear0.png', size_hint=(1, 1)) self.row2.it1.add_widget(self.row2.gear_left) self.row2.desc1 = BoxLayout(orientation='horizontal') self.row2.actdesc1 = Button(text=" ", font_size=25, color=(0, 0, 0, 1), background_color=(32 / 255.0, 178 / 255.0, 170 / 255.0, 1), size_hint=(1, 1), background_normal='') self.row2.actdesc1.bind(on_press=self.write_char) self.row2.knob_left = Knob(size=(125, 125), step=100 / len(self.alph), knobimg_source="knob/img/knob_metal.png", marker_img="knob/img/bline.png", markeroff_color=(0.3, 0.3, 0.3, 1)) self.row2.knob_left.bind(on_touch_move=self.change_char) self.row2.desc1.add_widget(self.row2.knob_left) self.row2.desc1.add_widget(self.row2.actdesc1) self.row2.it1.add_widget(self.row2.desc1) self.row2.it2.program = LabelB( text=''.join(txtformat(self.otm.cropprog(3))), color=(0, 0, 0, 1), halign='left', valign='top', bcolor=(218 / 255.0, 165 / 255.0, 32 / 255.0, 1), size_hint=(0.9, 1), font_size=20, font_name="Courier New Bold", text_size=(200, None)) self.row2.it2.pointer = LabelB(text='->', color=(0, 0, 0, 1), halign='right', valign='middle', size_hint=(0.1, 1), bcolor=(218 / 255.0, 165 / 255.0, 32 / 255.0, 1)) self.row2.it2.add_widget(self.row2.it2.pointer) self.row2.it2.add_widget(self.row2.it2.program) self.row2.gear_right = Image(source='Clockwise/Gear0.png', size_hint=(1, 1)) self.row2.it3.add_widget(self.row2.gear_right) self.row2.desc2 = BoxLayout(orientation='horizontal') self.row2.actdesc2 = LabelB(text='Location -->', color=(0, 0, 0, 1), bcolor=(32 / 255.0, 178 / 255.0, 170 / 255.0, 1)) self.row2.knob_right = Knob(size=(125, 125), knobimg_source="knob/img/knob_metal.png", marker_img="knob/img/bline.png", markeroff_color=(0.3, 0.3, 0.3, 1)) self.row2.knob_right.bind(on_touch_move=self.set_location) self.row2.desc2.add_widget(self.row2.actdesc2) self.row2.desc2.add_widget(self.row2.knob_right) self.row2.it3.add_widget(self.row2.desc2) self.row2.add_widget(self.row2.it1) self.row2.add_widget(self.row2.it2) self.row2.add_widget(self.row2.it3) self.add_widget(self.row2) self.row3 = BoxLayout(orientation='horizontal', size_hint=(1, 0.3)) self.row3.slider = OtmgSlider(min=0, max=100, value=0) self.row3.add_widget(self.row3.slider) self.add_widget(self.row3) self.row4 = BoxLayout(orientation='horizontal', size_hint=(1, 0.2)) self.row4.btn1 = ToggleButton(text='Start/Stop') self.row4.btn1.bind(on_press=self.do_startstop) self.row4.add_widget(self.row4.btn1) self.row4.btn2 = Button(text='Step') self.row4.btn2.bind(on_press=self.do_step_request) self.row4.add_widget(self.row4.btn2) self.row4.btn3 = Button(text='Restart') self.row4.btn3.bind(on_press=self.do_restart) self.row4.add_widget(self.row4.btn3) self.row4.btn4 = Button(text='Clear') self.row4.btn4.bind(on_press=self.do_clear) self.row4.add_widget(self.row4.btn4) self.row4.btn5 = Button(text='EXIT') self.row4.btn5.bind(on_press=self.exit) self.row4.add_widget(self.row4.btn5) self.add_widget(self.row4)