Saturday, June 29, 2013

Building a python media player: Part 3

Got the player to a fairly polished state now! Piamp is a fairly powerful media player finally. Here is the project folder, for anyone interested: LINK

Also, to demonstrate the functionality of the player, I made a short video for you:




The great thing about this player is that it should work across platform. The only windows-specific code in the program is a specification of initial directory for Tkinter's file dialog, but even if Tkinter throws an error when trying to find "F://Media//Music//" on a linux operating system, it really isn't a big deal to me to change a line of code to fix that.

We'll see how it runs across platform when I get the touchscreen in and compile the modified debian image (with touchscreen support) for the Pi early next week. Stay tuned!




Wednesday, June 26, 2013

Building a python media player: Part 2

I've been working heavily on the code for Piamp, and I'm getting closer to a stable enough point where I can go through the code step by step. There are just a few features left to implement before I can get there. In the meantime, here is an updated screenshot of the player:


The most notable difference here is clearly the volume slider, but under the hood I've rewritten just about the whole thing. Here is the current piamp code:

#---------------------------------------------------------------------
#        piamp.py
#  
#      A Python Media Player
#
#      By: Josh Archer
#---------------------------------------------------------------------

import os
import pyglet
import Tkinter, tkFileDialog

dir = pyglet.resource.get_settings_path('Piamp')
if not os.path.exists(dir):
 os.makedirs(dir)
configFileName = os.path.join(dir, 'settings.cfg')

pyglet.resource.path = ['resources']
pyglet.resource.reindex()
batch = pyglet.graphics.Batch()

class Piamp(pyglet.window.Window):
 def __init__(self):
  super(Piamp, self).__init__()
  self.set_size(800, 480)
  #self.set_fullscreen(True)
  
  configFile = open(configFileName, 'wt')
  
  self.load_graphics()
  self.canPlay = True
  self.canMute = True
  self.mainMenuVisible = True
  self.frameCount = 0
  
  self.selectedFile = "null"
  
  self.mediaType = 'Audio'
 
  self.currentVolume = 0.5
  
  self.refresh_player()
  
 def load_graphics(self):
  #Background:
  self.img_background = pyglet.resource.image('background.png')
  self.img_background.anchor_x = self.img_background.width/2
  self.img_background.anchor_y = self.img_background.height/2
  
  #Main Menu Buttons:
  self.img_movies = pyglet.resource.image('movies.png')
  self.img_movies.anchor_x = self.img_movies.width/2
  self.img_movies.anchor_y = self.img_movies.height/2
  
  self.img_music = pyglet.resource.image('music.png')
  self.img_music.anchor_x = self.img_music.width/2
  self.img_music.anchor_y = self.img_music.height/2
  
  self.img_shutdown = pyglet.resource.image('shutdown.png')
  self.img_shutdown.anchor_x = self.img_shutdown.width/2
  self.img_shutdown.anchor_y = self.img_shutdown.height/2
  
  self.img_reboot = pyglet.resource.image('reboot.png')
  self.img_reboot.anchor_x = self.img_reboot.width/2
  self.img_reboot.anchor_y = self.img_reboot.height/2
  
  self.img_eq = pyglet.resource.image('equalizer.png')
  self.img_eq.anchor_x = self.img_eq.width/2
  self.img_eq.anchor_y = self.img_eq.height/2
  
  
  #Player Control Buttons:
  self.img_mute = pyglet.resource.image('mute.png')
  self.img_mute.anchor_x = self.img_mute.width/2
  self.img_mute.anchor_y = self.img_mute.height/2
  
  self.img_unmute = pyglet.resource.image('unmute.png')
  self.img_unmute.anchor_x = self.img_unmute.width/2
  self.img_unmute.anchor_y = self.img_unmute.height/2
  
  self.img_prev = pyglet.resource.image('previous.png')
  self.img_prev.anchor_x = self.img_prev.width/2
  self.img_prev.anchor_y = self.img_prev.height/2
  
  self.img_rewind = pyglet.resource.image('rewind.png')
  self.img_rewind.anchor_x = self.img_rewind.width/2
  self.img_rewind.anchor_y = self.img_rewind.height/2
  
  self.img_play = pyglet.resource.image('play.png')
  self.img_play.anchor_x = self.img_play.width/2
  self.img_play.anchor_y = self.img_play.height/2
  
  self.img_pause = pyglet.resource.image('pause.png')
  self.img_pause.anchor_x = self.img_pause.width/2
  self.img_pause.anchor_y = self.img_pause.height/2
  
  self.img_ff = pyglet.resource.image('ff.png')
  self.img_ff.anchor_x = self.img_ff.width/2
  self.img_ff.anchor_y = self.img_ff.height/2
  
  self.img_next = pyglet.resource.image('next.png')
  self.img_next.anchor_x = self.img_next.width/2
  self.img_next.anchor_y = self.img_next.height/2
  
  #Volume Control Graphics
  self.img_volume = pyglet.resource.image('volume.png')
  self.img_volume.anchor_y = self.img_volume.height/2
  
  self.img_volume_fill = pyglet.resource.image('volume_fill.png')
  #self.img_volume_fill.anchor_y = self.img_volume_fill.height/2
  
  #self.maxFill = self.img_volume_fill.width
  
 def update_sprites(self):
  #print("Entering update_sprites function...")
  
  self.backgroundSprite = pyglet.sprite.Sprite(self.img_background, x=400, y=240, batch=batch)
  
  if(self.mainMenuVisible == True):
   self.mainMenuSprites = [pyglet.sprite.Sprite(self.img_movies, x=280, y=315, batch=batch),
         pyglet.sprite.Sprite(self.img_music, x=525, y=315, batch=batch),
         pyglet.sprite.Sprite(self.img_shutdown, x=60, y=425, batch=batch),
         pyglet.sprite.Sprite(self.img_reboot, x=60, y=305, batch=batch),
         pyglet.sprite.Sprite(self.img_eq, x=60, y=185, batch=batch)]
         
  if(self.canPlay == True and self.canMute == True):
   self.controlSprites = [pyglet.sprite.Sprite(self.img_mute, x=50, y=108, batch=batch),
       pyglet.sprite.Sprite(self.img_prev, x=50, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_rewind, x=146, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_play, x=242, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_ff, x=338, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_next, x=434, y=35, batch=batch)]
       
  if(self.canPlay == False and self.canMute == True):
   self.controlSprites = [pyglet.sprite.Sprite(self.img_mute, x=50, y=108, batch=batch),
       pyglet.sprite.Sprite(self.img_prev, x=50, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_rewind, x=146, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_pause, x=242, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_ff, x=338, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_next, x=434, y=35, batch=batch)]
       
  if(self.canPlay == False and self.canMute == False):
   self.controlSprites = [pyglet.sprite.Sprite(self.img_unmute, x=50, y=108, batch=batch),
       pyglet.sprite.Sprite(self.img_prev, x=50, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_rewind, x=146, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_pause, x=242, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_ff, x=338, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_next, x=434, y=35, batch=batch)]
       
  if(self.canPlay == True and self.canMute == False):
   self.controlSprites = [pyglet.sprite.Sprite(self.img_unmute, x=50, y=108, batch=batch),
       pyglet.sprite.Sprite(self.img_prev, x=50, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_rewind, x=146, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_play, x=242, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_ff, x=338, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_next, x=434, y=35, batch=batch)]
       
  
  self.volumeSprites = [pyglet.sprite.Sprite(self.img_volume, x=498, y=35, batch=batch),
       pyglet.sprite.Sprite(self.currentFill, x=498, y=3, batch=batch)]
       
  
       
 def update_volume_fill(self):
  self.currentFill = self.img_volume_fill.get_region(x=0, y=0, width=int(self.img_volume_fill.width * self.currentVolume), height=64)
 
 def update_volume(self):
  self.player.volume = self.currentVolume
  
 def on_draw(self):
  self.clear()
  
  if(self.frameCount%10 == 0):
   #print("Resetting frame count")
   self.frameCount = 0
   
   self.update_volume_fill()
   
   self.update_volume()
   
   self.update_sprites()
  batch.draw()
  
  self.frameCount += 1
 
 def open_file(self):
  
  self.root = Tkinter.Tk()
  self.root.withdraw()
  
  if(self.mediaType == 'Audio'):
   f = tkFileDialog.askopenfilename(parent = self.root, title = 'Please select an audio file:', filetypes = [('MP3 Files', '.mp3'), ('WAV Files', '.wav'), ('All Files', '.*')], initialdir = 'F:\\Media\\Music\\')
   if(f):
    file = f
    self.root.destroy()
    return file
   else:
    self.root.destroy()
    return None
    
  else:
   f = tkFileDialog.askopenfilename(parent = self.root, title = 'Please select a video file:', filetypes = [('AVI Files', '.avi'), ('MPEG Files', '.mpeg'), ('MKV Files', '.mkv'), ('All Files', '.*')], initialdir = 'F:\\Media\\Video\\')
   if(f):
    file = f
    self.root.destroy()
    return file
   else:
    self.root.destroy()
    return None
  
  
 def refresh_player(self):
 
  self.player = pyglet.media.Player()
  
  @self.player.event('on_eos')
  def auto_next():
   self.next()
   
  self.player.volume = self.currentVolume
 
 def previous(self):
  #Go back to the previous file in the current directory
  
  self.player.canPlay = True
  self.player.pause()
  if(self.player.source != 'null'):
   
   #Find the index of the first / from the end of our source filepath
   sourceIndex = self.selectedFile.rfind('/')
   
   #Now we can get the name of the directory (including path)
   directory = self.selectedFile[:sourceIndex + 1]
   
   previousFile = 'null'
   if(self.mediaType == 'Audio'):
    for file in os.listdir(directory):
     if file.endswith('.MP3') or file.endswith('.mp3'):
      print('Previous Button: Checking ' + file)
      if(self.selectedFile == (directory + file)):
       print('Previous Button: Match!')
       #Found the current file, now we need to check if there is a file before this in the directory, and play that file if there is
       if(previousFile != 'null'):
        print('Previous Button: Previous file is ' + previousFile)
        
        self.refresh_player()
        
        media = pyglet.media.load(directory + previousFile)
        self.player.queue(media)
        
        self.selectedFile = directory + previousFile
        
        self.player.play()
        self.player.canPlay = False
       else:
        print('Previous Button: Current file first in directory!')
        
       return
      else:
       #Assign the current file to previousFile so that we can refer back to it if the next file is the current source
       previousFile = file
       
     if file.endswith('.WAV') or file.endswith('.wav') or file.endswith('.Wav') or file.endswith('.WAv') or file.endswith('.waV') or file.endswith('.wAV'):
      print('Previous Button: Checking ' + file)
      if(self.selectedFile == (directory + file)):
       print('Previous Button: Match!')
       #Found the current file, now we need to check if there is a file before this in the directory, and play that file if there is
       if(previousFile != 'null'):
        print('Previous Button: Previous file is ' + previousFile)
        
        self.refresh_player()
        
        media = pyglet.media.load(directory + previousFile)
        self.player.queue(media)
        
        self.selectedFile = directory + previousFile
        
        self.player.play()
        self.player.canPlay = False
       else:
        print('Previous Button: Current file first in directory!')
        
       return
      else:
       #Assign the current file to previousFile so that we can refer back to it if the next file is the current source
       previousFile = file
       
  else:
   print('Previous Button: Source is null!')
        
 def next(self):
  #Go to the next file in the current directory
  
  self.player.canPlay = True
  self.player.pause()
  if(self.player.source != 'null'):
   
   #Find the index of the first / from the end of our source filepath
   sourceIndex = self.selectedFile.rfind('/')
   
   #Now we can get the name of the directory (including path)
   directory = self.selectedFile[:sourceIndex + 1]
   
   foundCurrent = False
   isLastFile = True
   
   if(self.mediaType == 'Audio'):
    for file in os.listdir(directory):
     if file.endswith('.MP3') or file.endswith('.mp3') or file.endswith('.mP3') or file.endswith('.Mp3'):
      if(foundCurrent):
       print('Next Button: Next file is ' + file)
       
       self.refresh_player()
       
       media = pyglet.media.load(directory + file)
       self.player.queue(media)
       
       self.selectedFile = (directory + file)
       
       self.player.play()
       self.player.canPlay = False
       
       #Use this to tell program we successfully loaded the next file
       isLastFile = False
       
       return
       
      if(self.selectedFile == (directory + file)):
      
       #Found the current file, so change foundCurrent to True
       foundCurrent = True
       
     if file.endswith('.WAV') or file.endswith('.wav') or file.endswith('.Wav') or file.endswith('.WAv') or file.endswith('.waV') or file.endswith('.wAV'):
      if(foundCurrent):
       print('Next Button: Next file is ' + file)
       
       self.refresh_player()
       
       media = pyglet.media.load(directory + file)
       self.player.queue(media)
       
       self.selectedFile = (directory + file)
       
       self.player.play()
       self.player.canPlay = False
       
       #Use this to tell program we successfully loaded the next file
       isLastFile = False
       
       return
       
      if(self.selectedFile == (directory + file)):
      
       #Found the current file, so change foundCurrent to True
       foundCurrent = True
        
   if(isLastFile):
    print('Next Button: Current file is last in the directory!')
      
   
 def check_for_button(self, x, y):
  #Check all button coordinates against x and y, return True if a button was hit or False if not
  
  if( (525 - (self.img_music.width / 2)) < x < (525 + (self.img_music.width / 2)) and ( (315 - (self.img_music.height / 2)) < y < (315 + (self.img_music.height / 2)) ) ):
   #coordinate lies inside the music button
   if(self.player.playing):
    self.player.canPlay = True
    self.player.pause()
    wasPlaying = True
   else:
    wasPlaying = False
   
   self.mediaType = 'Audio'
   filename = self.open_file()
   
   if(filename):
    self.selectedFile = filename
    print('Opening ' + self.selectedFile + ' ...')
    
    #Drop the current queue so we can build a new one by overwriting our player with a fresh one
    self.refresh_player()
    
    media = pyglet.media.load(filename)
    self.player.queue(media)
    
  
    #Start playback from the selected file
    self.canPlay = False
    self.player.play()
   else:
    print('Dialog cancelled')
    
    if(wasPlaying):
     self.player.play()
   
  if( (280 - (self.img_movies.width / 2)) < x < (280 + (self.img_movies.width / 2)) and ( (315 - (self.img_movies.height /2)) < y < (315 + (self.img_movies.height /2)) ) ):
   #coordinate lies inside the movies button
   if(self.player.playing):
    self.player.canPlay = True
    self.player.pause()
    wasPlaying = True
   else:
    wasPlaying = False
   
   self.mediaType = 'Video'
   filename = self.open_file()
   
   if(filename):
    self.selectedFile = filename
    print('Opening ' + self.selectedFile + ' ...')
    
    #Drop the current queue so we can build a new one by overwriting our player with a fresh one
    self.refresh_player()
    
    media = pyglet.media.load(filename)
    self.player.queue(media)
  
    
    #Start playback from the selected file
    self.canPlay = False
    self.player.play()
   else:
    print('Dialog cancelled')
    
    if(wasPlaying):
     self.player.play()
    
  if( (242 - (self.img_play.width / 2)) < x < (242 + (self.img_play.width / 2)) and ( (35 - (self.img_play.height / 2)) < y < (35 + (self.img_play.height / 2)) ) ):
   #coordinate lies inside the play/pause button
   if(self.canPlay):
    print('Play Button: Playing ' + self.selectedFile)
    self.player.play()
    
    self.canPlay = False
   else:    
    print('Pause Button: Pausing ' + self.selectedFile)
    self.player.pause()
    
    self.canPlay = True
   
  if( (434 - (self.img_next.width / 2)) < x < (434 + (self.img_next.width / 2)) and ( (35 - (self.img_next.height / 2)) < y < (35 + (self.img_next.height / 2)) ) ):
   #coordinate lies inside the next button
   print('Clicked next button...')
   
   self.next()
   
  if( (50 - (self.img_prev.width / 2)) < x < (50 + (self.img_prev.width / 2)) and ( (35 - (self.img_prev.height / 2)) < y < (35 + (self.img_prev.height / 2)) ) ):
   #coordinate lies inside the previous button
   print('Clicked previous button...')
   
   self.previous()
   
  if( (50 - (self.img_mute.width / 2)) < x < (50 + (self.img_mute.width / 2)) and ( (108 - (self.img_mute.height / 2)) < y < (108 + (self.img_mute.height / 2)) ) ):
   #coordinate lies inside the mute/unmute button
   if(self.canMute):
    print('Mute Button: Audio Muted!')
    self.player.volume = 0
    self.canMute = False
   else:
    print('Mute Button: Audio Unmuted!')
    self.player.volume = self.currentVolume
    self.canMute = True
    
  if( (146 - (self.img_rewind.width / 2)) < x < (146 + (self.img_rewind.width / 2)) and ( (35 - (self.img_rewind.height / 2)) < y < (35 + (self.img_rewind.height / 2)) ) ):
   #coordinate lies inside the rewind button
   if(self.player.playing or self.canPlay):
    print('Rewind Button: Seeking backwards 10 seconds.')
    newPosition = self.player.time - 10.0
    
    if(newPosition < 0.0):
     print('Rewind Button: New time is negative, set to 0 instead.')
     newPosition = 0.0
     
    self.player.seek(newPosition)
    
    if(self.canPlay):
     pass
    else:
     self.player.play()
    
  if( (338 - (self.img_ff.width / 2)) < x < (338 + (self.img_ff.width / 2)) and ( (35 - (self.img_ff.height / 2)) < y < (35 + (self.img_ff.height / 2)) ) ):
   #coordinate lies inside the fast forward button
   if(self.player.playing or self.canPlay):
    print('FF Button: Seeking forwards 10 seconds.')
    newPosition = self.player.time + 10.0
    
    #Note: We don't need to check if the time is past the end of the track because the Player() class will automatically clamp this to the end of the source
    
    self.player.seek(newPosition)
    if(self.canPlay):
     pass
    else:
     self.player.play()
     
     
  self.volumeSprites = [pyglet.sprite.Sprite(self.img_volume, x=498, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_volume_fill, x=498, y=35, batch=batch)]
       
  if( (498 < x < (498 + self.img_volume.width)) and ( (35 - (self.img_volume.height / 2)) < y < (35 + (self.img_volume.height / 2)) ) ):
   #coordinate lies inside the volume control
   
   #First, we need to convert the image's width to a percentage scale
   ratio = 100.0 / self.img_volume.width / 100.0
   
   #To make more sense of this, here is an example:
   #100 / 256 = 0.390625
   #If our touch/mouse location was 128 (right in the middle of the image), we want to set our volume to 50%, or 0.5
   #Since 128 * 0.390625 = 50, we still need to divide that by 100 to get the percentage (or 0 to 1 decimal) that we want to use.
   #Therefore, instead of 100 / 256 = 0.390625, we need a ratio of 100 / 256 / 100 = 0.00390625
   
   #Now we need to find our x position in relation to the image, instead of the screen like it currently is
   local_x = x - 498
   
   
   #Let's use our new conversion factor to set the volume appropriately
   self.currentVolume = local_x * ratio
   
   
   
 
 def on_mouse_press(self, x, y, button, modifiers):
  self.check_for_button(x, y)
  
  
if __name__ == '__main__':
 window = Piamp()
 #window.set_mouse_visible(False)
 pyglet.app.run()


I've decided to utilize Tkinter and tkFileDialog for the file opening window, which looks like this:

This dialog will look different depending on the operating system that runs it. Tkinter works on a variety of operating systems, so it was an easy choice for this functionality.

To give you an idea on the state of the player:

Working:

  • Volume Slider
  • Previous Button
  • Rewind
  • Play/Pause
  • Fast Forward
  • Next Button
  • Mute/Unmute
  • Music Button (Open audio file)
  • Movies Button (Open video file)
Not Yet Implemented:
  • Show current selected file in text box
  • Shutdown button
  • Reboot button
  • Equalizer button
  • Video Playback - Currently player only plays audio for video files
In case you want to play around with the player (or the code) yourself, here is a zip file of the entire project:


Stay tuned - I'll be finishing up as much as possible tomorrow, and then I'm transferring all of this to the Pi and getting it installed in the car!

Saturday, June 15, 2013

Building a python media player: Part 1

After testing out several different libraries for python, I've decided upon pyglet. Getting an mp3 file to play was as simple as this:

import pyglet

player_window = pyglet.window.Window(800, 480)
player = pyglet.media.Player()

song=pyglet.media.load('thesong.mp3')
player.queue(song)
player.play()
pyglet.app.run()

Pyglet's player class has a lot of built-in functionality that should streamline the development of this media player (which is good because I have to do it in 2 weeks!). Currently my prototype has the graphics positioned and updating. Here is a screenshot:



Here is the full code so far:

#---------------------------------------------------------------------
# piamp prototype
#---------------------------------------------------------------------

import os
import pyglet

dir = pyglet.resource.get_settings_path('Piamp')
if not os.path.exists(dir):
 os.makedirs(dir)
configFileName = os.path.join(dir, 'settings.cfg')

pyglet.resource.path = ['resources']
pyglet.resource.reindex()
batch = pyglet.graphics.Batch()

class Piamp(pyglet.window.Window):
 def __init__(self):
  super(Piamp, self).__init__()
  self.set_size(800, 480)
  
  configFile = open(configFileName, 'wt')
  
  self.load_graphics()
  self.canPlay = True
  self.canMute = True
  self.mainMenuVisible = True
  self.frameCount = 0
  
  player = pyglet.media.Player()
  player.volume = 0.5
  
 def load_graphics(self):
  #Background:
  self.img_background = pyglet.resource.image('background.png')
  self.img_background.anchor_x = self.img_background.width/2
  self.img_background.anchor_y = self.img_background.height/2
  
  #Main Menu Buttons:
  self.img_movies = pyglet.resource.image('movies.png')
  self.img_movies.anchor_x = self.img_movies.width/2
  self.img_movies.anchor_y = self.img_movies.height/2
  
  self.img_music = pyglet.resource.image('music.png')
  self.img_music.anchor_x = self.img_music.width/2
  self.img_music.anchor_y = self.img_music.height/2
  
  self.img_shutdown = pyglet.resource.image('shutdown.png')
  self.img_shutdown.anchor_x = self.img_shutdown.width/2
  self.img_shutdown.anchor_y = self.img_shutdown.height/2
  
  self.img_reboot = pyglet.resource.image('reboot.png')
  self.img_reboot.anchor_x = self.img_reboot.width/2
  self.img_reboot.anchor_y = self.img_reboot.height/2
  
  self.img_eq = pyglet.resource.image('equalizer.png')
  self.img_eq.anchor_x = self.img_eq.width/2
  self.img_eq.anchor_y = self.img_eq.height/2
  
  
  #Player Control Buttons:
  self.img_mute = pyglet.resource.image('mute.png')
  self.img_mute.anchor_x = self.img_mute.width/2
  self.img_mute.anchor_y = self.img_mute.height/2
  
  self.img_unmute = pyglet.resource.image('unmute.png')
  self.img_unmute.anchor_x = self.img_unmute.width/2
  self.img_unmute.anchor_y = self.img_unmute.height/2
  
  self.img_prev = pyglet.resource.image('previous.png')
  self.img_prev.anchor_x = self.img_prev.width/2
  self.img_prev.anchor_y = self.img_prev.height/2
  
  self.img_rewind = pyglet.resource.image('rewind.png')
  self.img_rewind.anchor_x = self.img_rewind.width/2
  self.img_rewind.anchor_y = self.img_rewind.height/2
  
  self.img_play = pyglet.resource.image('play.png')
  self.img_play.anchor_x = self.img_play.width/2
  self.img_play.anchor_y = self.img_play.height/2
  
  self.img_pause = pyglet.resource.image('pause.png')
  self.img_pause.anchor_x = self.img_pause.width/2
  self.img_pause.anchor_y = self.img_pause.height/2
  
  self.img_ff = pyglet.resource.image('ff.png')
  self.img_ff.anchor_x = self.img_ff.width/2
  self.img_ff.anchor_y = self.img_ff.height/2
  
  self.img_next = pyglet.resource.image('next.png')
  self.img_next.anchor_x = self.img_next.width/2
  self.img_next.anchor_y = self.img_next.height/2
 
 def update_sprites(self):
  #print("Entering update_sprites function...")
  
  self.backgroundSprite = pyglet.sprite.Sprite(self.img_background, x=400, y=240, batch=batch)
  
  if(self.mainMenuVisible == True):
   self.mainMenuSprites = [pyglet.sprite.Sprite(self.img_movies, x=280, y=315, batch=batch),
         pyglet.sprite.Sprite(self.img_music, x=525, y=315, batch=batch),
         pyglet.sprite.Sprite(self.img_shutdown, x=60, y=425, batch=batch),
         pyglet.sprite.Sprite(self.img_reboot, x=60, y=305, batch=batch),
         pyglet.sprite.Sprite(self.img_eq, x=60, y=185, batch=batch)]
         
  if(self.canPlay == True and self.canMute == True):
   self.controlSprites = [pyglet.sprite.Sprite(self.img_mute, x=50, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_prev, x=208, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_rewind, x=304, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_play, x=400, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_ff, x=496, y=35, batch=batch),
       pyglet.sprite.Sprite(self.img_next, x=592, y=35, batch=batch)]
       
  if(self.canPlay == False and self.canMute == True):
   self.controlSprites = [pyglet.sprite.Sprite(self.img_mute, x=50, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_prev, x=208, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_rewind, x=304, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_pause, x=400, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_ff, x=496, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_next, x=592, y=360, batch=batch)]
       
  if(self.canPlay == False and self.canMute == False):
   self.controlSprites = [pyglet.sprite.Sprite(self.img_unmute, x=50, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_prev, x=208, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_rewind, x=304, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_pause, x=400, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_ff, x=496, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_next, x=592, y=360, batch=batch)]
       
  if(self.canPlay == True and self.canMute == False):
   self.controlSprites = [pyglet.sprite.Sprite(self.img_unmute, x=50, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_prev, x=208, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_rewind, x=304, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_play, x=400, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_ff, x=496, y=360, batch=batch),
       pyglet.sprite.Sprite(self.img_next, x=592, y=360, batch=batch)]
 def on_draw(self):
  self.clear()
  
  if(self.frameCount%10 == 0):
   #print("Resetting frame count")
   self.frameCount = 0
   self.update_sprites()
  batch.draw()
  
  self.frameCount += 1
 
 def check_for_button(self, x, y):
  #Check all button coordinates against x and y, return True if a button was hit or False if not
  pass
 
 def on_mouse_press(x, y, button, modifiers):
  if (check_for_button(x, y)):
   pass
  pass
 
 def on_mouse_release(x, y, button, modifiers):
  pass
  
 def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
  pass
  
if __name__ == '__main__':
 window = Piamp()
 #window.set_mouse_visible(False)
 pyglet.app.run()

Keep in mind this code is still quite raw. After I've got the media player in a fairly stable setting, I'll walk through the entire code file step by step and explain what is going on.

Sunday, June 9, 2013

Speech issues; changing course again

Sorry it's been awhile since my last post. I've been swimming in the deep end of Linux speech recognition, and unfortunately I haven't had much luck. I was able to get CMU sphinx compiled and "working," but the accuracy of the recognition was extremely low, so I had to find an alternative. I attempted to follow the voxforge guide for setting up Julius and HTK, but I ran into a lot of trouble there as well. HTK would not compile correctly with the Pi's gcc 4.6, and after several hours of searching I was not able to find a gcc version under 4 that would work with the Pi.

Due to time constraints, I've decided to abandon speech recognition for pi-amp. Instead, I'm going to build a custom media player in python controlled by touch. For the touch aspect, I've ordered this kit from ebay that comes with a 7" monitor, a 7" touchscreen panel to fit the monitor, and a controller board that converts the touch input to usb.


Here is a rough rendition of the interface:

















The top-left button will send a "sudo halt" to the Pi (shutdown command), so that I can safely turn the Pi off in the vehicle.

The middle-left button may or may not be in the final rendition, but I decided to create it at least for the testing phases of the application. This button will reboot the Pi.

The lower-left button will open a mixer/equalizer menu to adjust bass & treble.

The music button will allow the user to browse the contents of the music library, as well as select a song to play. The primary display area will be replaced with a file browser. Once a file is selected, the user will be returned to the main interface.

The video button will allow the user to browse the contents of the video library, as well as select a video to play. The primary display area will be replaced with a file browser. Once a file is selected, the primary display area will be replaced with the chosen video.

The central info-box will display information about the currently playing file.

As to the player controls, they are fairly self explanatory. From left to right:

  • mute/unmute toggle button (will switch graphics when toggled)
  • previous
  • rewind
  • play/pause toggle button (will switch graphics when toggled)
  • stop
  • fast forward
  • next

The last button on the right is a placeholder graphic - I'm going to come up with something unique to the project. This button will call the main menu to the primary display area. If playing a video, the user can press this main menu button again to re-hide the main menu.


I still need to find a good place for a volume control, and possibly a horizontal seek slider so the user can jump to different parts of the file easier.


This next week should have several posts - I have a lot to get done. First, I'm going to get a more final draft of the interface done, and then I'll be starting work on the Python code. Stay tuned!