# # Media Wrappers for "Introduction to Media Computation" # Started: Mark Guzdial, 2 July 2002 # # Revisions: # 18 June 2003: (ellie) # Added (blocking)play(AtRate)InRange methods to Sound class # and global sound functions # Changed getSampleValue, setSampleValue to give the appearance # of 1-based indexing # Added getLeftSampleValue and getRightSampleValue to Sound class # 14 May 2003: Fixed discrepancy between getMediaPath and setMediaFolder (AdamW) # 8 Nov: Fixed getSamplingRate (MarkG) # 1 Nov: Fixed printing pixel # 31 Oct: Fixed pickAColor (MarkG) # 30 Oct: Added raises, fixed error messages. Added repaint (MarkG) # 10 Oct: Coerced value to integer in Sound.setSampleValue (MarkR) # 2 Oct: Corrected calls in setSampleValueAt (MarkG): # 30 Aug: Made commands more consistent and add type-checking (MarkG) # 2 Aug: Changed to getSampleValueAt and setSampleValueAt (MarkG) # 31 October 2005: Converted the package to no longer use Java # 7 December Lots of new stuff # dumped wxwindows because it hates threads and really despises pygame # tkinter used as alternative this is python standard for windowing # add PIL as a requirement to allow for easy image export and save to jpeg # converted pickAFile, pickAFolder, pickAColor to TKDialog pop-ups # moved initialization out of the class init and into the main import # 14 April 2007: (NadeemAbdulHamid) # Converted Picture and Pixel classes to use PythonImagingLibrary directly, # without going through pygame. This seems to provide a noticeable # performance increase. Fixed several bugs. Color.getRGB returns a # tuple in the format (r, g, b) -- before it was returning [b, g, r]!? # Also changed the Samples object to work as an iterator, lazily building # the sequence of samples from the sound, instead of building a # complete list of Sample objects in its constructor. Fixed some type-related # bugs with the values of samples; also added check to setSampleValue to ensure # value is not set above or below limits of int. # 3 May 2007: (Nadeem) # Added in a Pixels iterator class to reduce up-front time when a # picture is first loaded and getPixels() is called. # 30 May 2007: (Nadeem) # Only using pygame for the sound stuff (pygame.mixer module). Other # parts of the pygame library cause strange things to happen with # Tkinter on Mac OS X; added getFileName, getDirectory to Picture class # 6 Jun 2007: (Nadeem) # Bug fix # 10 Jun 2007: (Nadeem) version 1.5 # Modified to use John Zelle's graphics library which runs the Tk loop # in a separate thread, making this safe to run in the normal IDLE # environment # 15 Jun 2007: # Added pickASaveFile method; makeEmptyLength in sound takes number # of samples, not seconds # import sys import os import user import traceback import time import Numeric import struct #from Tkinter import * # import cStringIO # from Queue import * from threading import * from math import sqrt import thread import Image Im = Image import ImageDraw import ImageFont import ImageTk import tkFileDialog import tkColorChooser import pygame import platform # John Zelle's graphics library... from graphics import * _tkCall = tkCall _tkExec = tkExec ver = "1.5" # only need to initialize the mixer -- other parts of pygame seem to # interfere with Tkinter on the Mac pygame.mixer.pre_init(22050, -16, False) _tkExec(pygame.mixer.init) try: if platform.system() == 'Darwin': defaultFont = ImageFont.truetype("/Library/Fonts/Times New Roman", 24) else: defaultFont = ImageFont.truetype("times.ttf", 24) except: defaultFont = ImageFont.load_default() # pygame.font.SysFont("times", 24) mediaFolder = user.home + os.sep print "Media Computation Library. Version " + str(ver) print "Started by Mark Guzdial" print "Updated by Nadeem Abdul Hamid, June 14 2007" def version(): global ver return ver #Set a path to the media for those who want to have a shortcut (5/14/03 AW) def setMediaPath(path=None): global mediaFolder if not path: path = pickAFolder() mediaFolder = path print "New media folder: "+mediaFolder def getMediaPath(filename): global mediaFolder file = mediaFolder+filename if not os.path.isfile(file): print "Note: There is no file at "+file return file def pickAFile(**options): path = _tkCall(tkFileDialog.askopenfilename) return path def pickASaveFile(**options): path = _tkCall(tkFileDialog.asksaveasfilename) return path def pickAFolder(**options): global mediaFolder folder = _tkCall(tkFileDialog.askdirectory) if folder == '': folder = mediaFolder else: folder = folder + os.sep return folder def pickAColor(**options): color = _tkCall(tkColorChooser.askcolor) newColor = Color(color[0][0], color[0][1], color[0][2]) return newColor #And for those who think of things as folders (5/14/03 AW) def setMediaFolder(path=None): global mediaFolder if not path: path = pickAFolder() mediaFolder = path print "New media folder: "+mediaFolder def getMediaFolder(filename): global mediaFolder file = mediaFolder+filename if not os.path.isfile(file) or not os.path.isdir(file): print "Note: There is no file at "+file return file def getShortPath(filename): dirs = filename.split(os.sep) if len(dirs) < 1: return "." elif len(dirs) == 1: return dirs[0] else: return (dirs[len(dirs) - 2] + os.sep + dirs[len(dirs) - 1]) class PictureFrame(tk.Toplevel): def __init__(self, picture): tk.Toplevel.__init__(self) self.pic = picture def destroy(self): _tkExec(self.__destroy_help) def __destroy_help(self): self.pic.windowInactive() tk.Toplevel.destroy(self) ## ## IMAGE CLASSES ## class Picture: def __init__(self): self.title = "Unnamed" self.dispImage = None self.winActive = 0 def windowInactive(self): self.winActive = 0 def createImage(self, width, height): self.image = Im.new("RGB", (width, height)) self.pixels = self.image.load() if not self.pixels: raise RuntimeError, 'Picture.pixels is None. Python Imaging Library 1.1.6 required.' self.filename = '' self.title = 'None' def loadImage(self,filename): global mediaFolder if not os.path.isabs(filename): filename = mediaFolder + filename self.image = Im.open(filename) self.pixels = self.image.load() if not self.pixels: raise RuntimeError, 'Picture.pixels is None. Python Imaging Library 1.1.6 required.' self.filename = filename self.title = getShortPath(filename) def __str__(self): return "Picture, filename "+self.filename+" height "+str(self.getHeight())+" width "+str(self.getWidth()) def repaint(self): _tkExec(self.__repaint_help) def __repaint_help(self): if self.winActive: self.dispImage = ImageTk.PhotoImage(self.getImage()) self.item = self.canvas.create_image(0, 0, image=self.dispImage, anchor='nw') else: self.show() def show(self): _tkExec(self.__show_help) def __show_help(self): if not self.winActive: self.frame = PictureFrame(self) self.canvas = tk.Canvas(self.frame, width=self.getWidth(), height=self.getHeight()) self.dispImage = ImageTk.PhotoImage(self.getImage()) self.item = self.canvas.create_image(0, 0, image=self.dispImage, anchor='nw') self.canvas.pack() self.winActive = 1 else: self.repaint() def setTitle(self, title): self.title = title def getTitle(self): return self.title def getFileName(self): return self.filename def getDirectory(self): return self.filename[ : self.filename.rfind(os.sep) + 1] def getImage(self): return self.image def getTkImage(self): self.dispImage = ImageTk.PhotoImage(self.getImage()) return self.dispImage def getWidth(self): return self.image.size[0] def getHeight(self): return self.image.size[1] def getPixel(self,x,y): return Pixel(self.pixels,x,y) def getPixels(self): return Pixels(self) # collect = [] # for x in xrange(1,self.getWidth()+1): # for y in xrange(1,self.getHeight()+1): # collect.append(Pixel(self.pixels,x,y)) # return collect # color should be a 3-tuple def setColorXY(self, x, y, color): self.pixels[x-1, y-1] = color # returns a 3-tuple def getColorXY(self, x, y): return self.pixels[x-1, y-1] def writeTo(self,filename): if not os.path.isabs(filename): filename = mediaFolder + filename image = self.getImage() image.save(filename, None, quality=90) self.filename = filename # draw stuff on pictures def addRectFilled(self,acolor,x,y,w,h): d = ImageDraw.Draw(self.image) d.rectangle( [ (x, y), (x+w, y+h) ], outline=acolor.getRGB(), fill=acolor.getRGB() ) def addRect(self, acolor,x,y,w,h): d = ImageDraw.Draw(self.image) d.rectangle( [ (x, y), (x+w, y+h) ], outline=acolor.getRGB() ) def addOvalFilled(self, acolor,x,y,w,h): d = ImageDraw.Draw(self.image) d.ellipse( [ (x, y), (x+w, y+h) ], outline=acolor.getRGB(), fill=acolor.getRGB() ) def addOval(self, acolor,x,y,w,h): d = ImageDraw.Draw(self.image) d.ellipse( [ (x, y), (x+w, y+h) ], outline=acolor.getRGB() ) def addArcFilled(self, acolor,x,y,w,h,start,angle): d = ImageDraw.Draw(self.image) d.chord( [ (x, y), (x+w, y+h) ], start, start+angle, outline=acolor.getRGB(), fill=acolor.getRGB() ) def addArc(self, acolor,x,y,w,h,start,angle): d = ImageDraw.Draw(self.image) d.arc( [ (x, y), (x+w, y+h) ], start, start+angle, outline=acolor.getRGB() ) def addLine(self, acolor, x1, y1, x2, y2): d = ImageDraw.Draw(self.image) d.line( [ (x1, y1), (x2, y2) ], fill=acolor.getRGB() ) def addText(self, acolor, x, y, string): global defaultFont d = ImageDraw.Draw(self.image) d.text( (x, y), string, font=defaultFont, fill=acolor.getRGB()) #def addTextWithStyle(self, acolor, x, y, string, style): # To use Picture objects with John Zelle's graphics library: ## win = GraphWin('Test', 500, 500) ## p = makePicture(pickAFile()) ## im = Image(Point(250, 250), Pixmap(p.getTkImage())) ## im.draw(win) class Pixels: def __init__(self, aPicture): self.picture = aPicture self.cur = 0 self.curx = 0 # will be incremented before first pixel is returned self.cury = 1 self.len = self.picture.getWidth() * self.picture.getHeight() def __iter__(self): return self def next(self): if self.cur >= self.len: raise StopIteration self.cur += 1 self.curx += 1 if self.curx > self.picture.getWidth(): self.curx = 1 self.cury += 1 return Pixel(self.picture.pixels, self.curx, self.cury) def __str__(self): return "Pixels, length " + str(self.len) def __rep__(self): return "Pixels, length " + str(self.len) def getPicture(self): return self.picture # # CLASS PIXEL # class Pixel: def __init__(self,pixels,x,y): self.x = x - 1 self.y = y - 1 self.pixels = pixels def __str__(self): return "Pixel, color="+str(self.getColor()) def setRed(self,r): self.pixels[self.x, self.y] = (int(r), self.getGreen(), self.getBlue()) def setGreen(self,g): self.pixels[self.x, self.y] = (self.getRed(), int(g), self.getBlue()) def setBlue(self,b): self.pixels[self.x, self.y] = (self.getRed(), self.getGreen(), int(b)) def getRed(self): return self.pixels[self.x, self.y][0] def getGreen(self): return self.pixels[self.x, self.y][1] def getBlue(self): return self.pixels[self.x, self.y][2] def getColor(self): return Color(self.getRed(),self.getGreen(), self.getBlue()) def setColor(self,color): self.pixels[self.x, self.y] = (color.getRed(), color.getGreen(), color.getBlue()) def getX(self): return self.x + 1 def getY(self): return self.y + 1 class Color: def __init__(self,r,g,b): r = int(r) if r < 0: while(r<0): r = 256 + r if r > 255: while(r>255): r = r - 256 g = int(g) if g < 0: while(g<0): g = 256 + g if g > 255: while(g>255): g = g - 256 b = int(b) if b < 0: while(b<0): b = 256 + b if b > 255: while(b>255): b = b - 256 self.r=r self.g=g self.b=b def __str__(self): return "color r="+str(self.getRed())+" g="+str(self.getGreen())+" b="+str(self.getBlue()) def distance(self,color): r = pow((self.r - color.r),2) g = pow((self.g - color.g),2) b = pow((self.b - color.b),2) return sqrt(r+g+b) def __sub__(self,color): return Color((self.r-color.r),(self.g-color.g),(self.b-color.b)) def difference(self,color): return self-color def getRGB(self): return (self.r, self.g, self.b) def rgbString(self): return color_rgb(self.r, self.g, self.b) def setRGB(self,atuple): self.r = atuple[1] self.g = atuple[2] self.b = atuple[3] def getRed(self): return int(self.r) def getGreen(self): return int(self.g) def getBlue(self): return int(self.b) def setRed(self,value): self.r=value def setGreen(self,value): self.g=value def setBlue(self,value): self.b=value def makeLighter(self): self.r = (255 - self.r) * .35 + self.r self.g = (255 - self.g) * .35 + self.g self.b = (255 - self.b) * .35 + self.b def makeDarker(self): self.r = self.r * .65 self.g = self.g * .65 self.b = self.b * .65 #Constants black = Color(0,0,0) white = Color(255,255,255) blue = Color(0,0,255) red = Color(255,0,0) green = Color(0,255,0) gray = Color(128,128,128) darkGray = Color(64,64,64) lightGray = Color(192,192,192) yellow = Color(255,255,0) orange = Color(255,200,0) pink = Color(255,175,175) magenta = Color(255,0,255) cyan = Color(0,255,255) ## ## Global picture functions ## def makePicture(filename): picture = Picture() picture.loadImage(filename) try: # ??? w = picture.getWidth() return picture except: print "Was unable to load the image in " + filename +"\nMake sure it's a valid image file." def makeEmptyPicture(width, height): picture = Picture() picture.createImage(width, height) return picture def getPixels(picture): if not picture.__class__ == Picture: print "getPixels(picture): Input is not a picture" raise ValueError return picture.getPixels() def getWidth(picture): if not picture.__class__ == Picture: print "getWidth(picture): Input is not a picture" raise ValueError return picture.getWidth() def getHeight(picture): if not picture.__class__ == Picture: print "getHeight(picture): Input is not a picture" raise ValueError return picture.getHeight() def show(picture, title=None): if not picture.__class__ == Picture: print "show(picture): Input is not a picture" raise ValueError picture.show() def repaint(picture): if not picture.__class__ == Picture: print "repaint(picture): Input is not a picture" raise ValueError picture.repaint() def addLine(picture,x1,y1,x2,y2): if not picture.__class__ == Picture: print "addLine(picture,x1,y1,x2,y2): Input is not a picture" raise ValueError picture.addLine(black,x1,y1,x2,y2) def addText(picture,x1,y1,string): if not picture.__class__ == Picture: print "addText(picture,x1,y1,string): Input is not a picture" raise ValueError picture.addText(black,x1,y1,string) def addRect(picture,x,y,w,h): if not picture.__class__ == Picture: print "addRect(picture,x,y,w,h): Input is not a picture" raise ValueError picture.addRect(black,x,y,w,h) def addRectFilled(picture,x,y,w,h,acolor): if not picture.__class__ == Picture: print "addRectFilled(picture,x,y,w,h,acolor): Input is not a picture" raise ValueError picture.addRectFilled(acolor,x,y,w,h) def addOval(picture,x,y,w,h): if not picture.__class__ == Picture: print "addOval(picture,x,y,w,h): Input is not a picture" raise ValueError picture.addOval(black,x,y,w,h) def addOvalFilled(picture,x,y,w,h,acolor): if not picture.__class__ == Picture: print "addOvalFilled(picture,x,y,w,h,acolor): Input is not a picture" raise ValueError picture.addOvalFilled(acolor,x,y,w,h) def getPixel(picture,x,y): if not picture.__class__ == Picture: print "getPixel(picture,x,y): Input is not a picture" raise ValueError return picture.getPixel(x,y) def setRed(pixel,value): if not (pixel.__class__ == Pixel or pixel.__class__ == Color): print "setRed(pixel,value): Input is not a pixel or a color" raise ValueError pixel.setRed(value) def getRed(pixel): if not (pixel.__class__ == Pixel or pixel.__class__ == Color): print "getRed(pixel): Input is not a pixel or a color" raise ValueError return pixel.getRed() def setBlue(pixel,value): if not (pixel.__class__ == Pixel or pixel.__class__ == Color): print "setBlue(pixel,value): Input is not a pixel or a color" raise ValueError pixel.setBlue(value) def getBlue(pixel): if not (pixel.__class__ == Pixel or pixel.__class__ == Color): print "getBlue(pixel): Input is not a pixel or a color" raise ValueError return pixel.getBlue() def setGreen(pixel,value): if not (pixel.__class__ == Pixel or pixel.__class__ == Color): print "setGreen(pixel,value): Input is not a pixel or a color" raise ValueError pixel.setGreen(value) def getGreen(pixel): if not (pixel.__class__ == Pixel or pixel.__class__ == Color): print "getGreen(pixel): Input is not a pixel or a color" raise ValueError return pixel.getGreen() def getColor(pixel): if not pixel.__class__ == Pixel: print "getColor(pixel): Input is not a pixel" raise ValueError return pixel.getColor() def getColorXY(pic, x, y): return pic.getColorXY(x, y) def setColorXY(pic, x, y, color): pic.setColorXY(x, y, color) def setColor(pixel,color): if not pixel.__class__ == Pixel: print "setColor(pixel,color): Input is not a pixel." raise ValueError if not color.__class__ == Color: print "setColor(pixel,color): Input is not a color." raise ValueError pixel.setColor(color) def getX(pixel): if not pixel.__class__ == Pixel: print "getX(pixel): Input is not a pixel" raise ValueError return pixel.getX() def getY(pixel): if not pixel.__class__ == Pixel: print "getY(pixel): Input is not a pixel" raise ValueError return pixel.getY() def distance(c1,c2): if not c1.__class__ == Color: print "distance(c1,c2): First input is not a color." raise ValueError if not c2.__class__ == Color: print "distance(c1,c2): Second input is not a color." raise ValueError return c1.distance(c2) def writePictureTo(pict,filename): if not pict.__class__ == Picture: print "writePictureTo(pict,filename): Input is not a picture" raise ValueError pict.writeTo(filename) #if not os.path.exists(filename): # print "writePictureTo(pict,filename): Path is not valid" # raise ValueError def makeDarker(color): if not color.__class__ == Color: print "makeDarker(color): Input is not a color." raise ValueError color.makeDarker() # return color def makeLighter(color): if not color.__class__ == Color: print "makeLighter(color): Input is not a color." raise ValueError color.makeLighter() # return color def rgbString(color): if not color.__class__ == Color: print "rgbString(color): Input is not a color." raise ValueError return color.rgbString() def makeColor(red,green,blue): return Color(red,green,blue) def newColor(red,green,bllue): return Color(red,green,blue) def quit(): sys.exit(0) def getFileName(pict): return pict.getFileName() def getDirectory(pict): return pict.getDirectory() ## ## The Sound Stuff ## # # Sound # class Sound: def __init__(self,filename=None): global mediaFolder try: self.m = pygame.mixer #self.m.init(22050, -16, False) except: print "Unable to initialize sound system." return tmp = pygame.sndarray if (filename == None): self.s = tmp.make_sound( Numeric.array([0]) ) else: if not os.path.isabs(filename): filename = mediaFolder + filename self.filename = filename try: self.s = self.m.Sound(filename) except: print "Unable to open file." self.a = tmp.samples(self.s) self.alen = len(self.a) def __str__(self): return "Sound of length "+str(self.getLength()) def __rep__(self): return "Sound of length "+str(self.getLength()) def __class__(self): return Sound def makeEmptyLength(self,size): tmp = pygame.sndarray self.s = tmp.make_sound( Numeric.zeros( size ) ) # .nah. sec * 22050 ) ) self.a = tmp.samples(self.s) self.alen = len(self.a) def play(self): try: self.s.play() except: print "Trouble accessing the sound device." def playInRange(self,start,stop): try: if start > 0 and stop <= self.getLength() and start < stop: tmp = pygame.sndarray tmpsnd = tmp.make_sound( self.a[start-1:stop-1] ) tmpsnd.play() else: print "invalid range in PlayInRange()." except: exc_type, ex_value, exc_tb = sys.exc_info() print exc_type print exc_value print traceback.extract_tb(exc_tb) print "Trouble accessing the sound device." def blockingPlay(self): try: chan = self.s.play() while chan.get_busy(): #still playing pygame.time.wait(10) except: print "Trouble accessing the sound device." def blockingPlayInRange(self,start,stop): try: if start > 0 and stop <= self.getLength() and start < stop: tmp = pygame.sndarray tmpsnd = tmp.make_sound( self.a[start-1:stop-1] ) chan = tmpsnd.play() while chan.get_busy(): #still playing time.wait(10) else: print "invalid range in blockingPlayInRange()." except: exc_type, ex_value, exc_tb = sys.exc_info() print exc_type print exc_value print traceback.extract_tb(exc_tb) print "Trouble accessing the sound device." def getSamples(self): return Samples(self) def getLength(self): return self.alen def getSampleValue(self,index): if index > 0 and index <= self.alen: # .nah. optimization -- not calling getLength() in if return int(self.a[index-1]) else: print "invalid index in getSampleValue()." return 0 def getFileName(self): return self.filename def getDirectory(self): return self.filename[ : self.filename.rfind(os.sep) + 1] def setSampleValue(self,index,value): if index > 0 and index <= self.alen: # .nah. optimization -- not calling getLength() in if self.a[index-1] = max( min(int(value), 32767), -32768 ) else: print "invalid index in setSampleValue()." def getSamplingRate(self): return 22050 def getSampleObjectAt(self,index): if index > 0 and index <= self.alen: # .nah. optimization -- not calling getLength() in if return Sample(self,index) else: print "invalid index in getSampleObjectAt()." def writeTo(self,filename): global mediaFolder if not os.path.isabs(filename): filename = mediaFolder + filename try: binfile = open(filename, 'wb') except: print "Unable to create file." return self.filename = filename # RIFF header binfile.write( struct.pack( '<4s', "RIFF" ) ) binfile.write( struct.pack( '= self.len: raise StopIteration self.cur = self.cur + 1 return Sample(self.sound, self.cur) def __str__(self): return "Samples, length "+str(self.sound.getLength()) def __rep__(self): return "Samples, length "+str(self.sound.getLength()) # .nah. Are these really needed? def __getitem__(self,item): return self.sound.getSampleValue(item) #return self.myList[item] def __setitem__(self,item,value): self.sound.setSampleValue(item,value) def getSound(self): return self.sound class Sample: def __init__(self,aSound,index): self.sound=aSound self.index=index def __str__(self): return "Sample at "+str(self.index)+" value at "+str(self.getValue()) def __rep__(self): return "Sample at "+str(self.index)+" value at "+str(self.getValue()) def setValue(self,value): self.sound.setSampleValue(self.index,int(round(value))) def getValue(self): return self.sound.getSampleValue(self.index) def getSound(self): return self.sound ## ## Global sound functions ## def makeSound(filename): global mediaFolder if not os.path.isabs(filename): filename = mediaFolder + filename if not os.path.isfile(filename): print "There is no file at "+filename raise ValueError return Sound(filename) def makeEmptySound(size): snd = Sound() snd.makeEmptyLength(size) return snd def getSamples(sound): if not sound.__class__ == Sound: print "getSamples(sound): Input is not a sound." raise ValueError return Samples(sound) def play(sound): if not sound.__class__ == Sound: print "play(sound): Input is not a sound." raise ValueError sound.play() def blockingPlay(sound): if not sound.__class__ == Sound: print "blockingPlay(sound): Input is not a sound." raise ValueError sound.blockingPlay() #20June03 new functionality in JavaSound (ellie) def playInRange(sound,start,stop): if not sound.__class__ == Sound: print "playInRange(sound,start,stop): Input is not a sound." raise ValueError sound.playInRange(start,stop) #20June03 new functionality in JavaSound (ellie) def blockingPlayInRange(sound,start,stop): if not sound.__class__ == Sound: print "blockingPlayInRange(sound,start,stop): Input is not a sound." raise ValueError sound.blockingPlayInRange(start,stop) def getSamplingRate(sound): if not sound.__class__ == Sound: print "getSamplingRate(sound): Input is not a sound." raise ValueError return sound.getSamplingRate() def setSampleValueAt(sound,index,value): if not sound.__class__ == Sound: print "setSampleValueAt(sound,index,value): Input is not a sound." raise ValueError sound.setSampleValue(index,value) def getSampleValueAt(sound,index): if not sound.__class__ == Sound: print "getSampleValueAt(sound,index): Input is not a sound." raise ValueError return sound.getSampleValue(index) def getSampleObjectAt(sound,index): if not sound.__class__ == Sound: print "getSampleObjectAt(sound,index): Input is not a sound." raise ValueError return sound.getSampleObjectAt(index) def setSample(sample,value): if not sample.__class__ == Sample: print "setSample(sample,value): Input is not a sample." raise ValueError # Need to coerce value to integer return sample.setValue(value) def getSample(sample): if not sample.__class__ == Sample: print "getSample(sample): Input is not a sample." raise ValueError return sample.getValue() def getSound(sample): if not sample.__class__ == Sample: print "getSound(sample): Input is not a sample." raise ValueError return sample.getSound() def getLength(sound): if not sound.__class__ == Sound: print "getLength(sound): Input is not a sound." raise ValueError return sound.getLength() def writeSoundTo(sound,filename): global mediaFolder if not os.path.isabs(filename): filename = mediaFolder + filename if not sound.__class__ == Sound: print "writeSoundTo(sound,filename): Input is not a sound." raise ValueError sound.writeTo(filename)