Comp107 Support Code


From time to time it will be convenient for me to provide you with some helper code that isn't already built into JES. You should copy the functions you need from the code below into your .py file.


comp107Util.py

#A set of helper functions for use in comp107
#Nathan Sprague 1/23/2009
#Updated for 0 based inexing: 3/12/2010

import os
import sys

#You'll need to change the following line if JES is installed somewhere
#else.  On a Mac it will probably be something like:
#sys.path.append('/Applications/JES-3-1-1.app/Contents/Resources/Java')

sys.path.append('C:\\Program Files\\JES\\Sources')
from media import *

# Alyce Brady's version of copyInto, with additional error-checking on the upper-left corner
# Will copy as much of the original picture into the destination picture as will fit.
# copies the Picture origPic into the Picture destPic
# starting at location (upperLeftX, upperLeftY) in destPic.
# Returns the new Picture. (destPict is unchanged.)

def copyInto(origPict, destPict, upperLeftX, upperLeftY):
  if not isinstance(origPict, Picture):
    print "copyInto(origPict, destPict, upperLeftX, upperLeftY): First parameter is not a picture"
    raise ValueError
  if not isinstance(destPict, Picture):
    print "copyInto(origPict, destPict, upperLeftX, upperLeftY): Second parameter is not a picture"
    raise ValueError
  if upperLeftX < 0 or upperLeftX >= getWidth(destPict):
    print "copyInto(origPict, destPict, upperLeftX, upperLeftY): upperLeftX must be within the destPict"
    raise ValueError
  if upperLeftY < 0 or upperLeftY >= getHeight(destPict):
    print "copyInto(origPict, destPict, upperLeftX, upperLeftY): upperLeftY must be within the destPict"
    raise ValueError
  newCanvas = duplicatePicture(destPict)
  origPict.copyInto(newCanvas, upperLeftX, upperLeftY)
  return newCanvas

#Version of copyInto that modifies the destination picture, and does not return a value.

def copyPictureInto(origPict, destPict, upperLeftX, upperLeftY):
  if not isinstance(origPict, Picture):
    print "copyInto(origPict, destPict, upperLeftX, upperLeftY): First parameter is not a picture"
    raise ValueError
  if not isinstance(destPict, Picture):
    print "copyInto(origPict, destPict, upperLeftX, upperLeftY): Second parameter is not a picture"
    raise ValueError
  if upperLeftX < 0 or upperLeftX >= getWidth(destPict):
    print "copyInto(origPict, destPict, upperLeftX, upperLeftY): upperLeftX must be within the destPict"
    raise ValueError
  if upperLeftY < 0 or upperLeftY >= getHeight(destPict):
    print "copyInto(origPict, destPict, upperLeftX, upperLeftY): upperLeftY must be within the destPict"
    raise ValueError
  origPict.copyInto(destPict, upperLeftX, upperLeftY)



# Alyce Brady/ Pam Cutter: Function that crops a picture
# returns a Picture of size (width, height) that is
# a copy of the part of Picture pict starting at
# location (upperLeftX, upperLeftY) and having size (width, height)

def cropPicture(picture, upperLeftX, upperLeftY, width, height):
  if not isinstance(picture, Picture):
    print "crop(picture, upperLeftX, upperLeftY, width, height): First parameter is not a picture"
    raise ValueError
  if upperLeftX < 0 or upperLeftX >= getWidth(picture):
    print "crop(picture, upperLeftX, upperLeftY, width, height): upperLeftX must be within the picture"
    raise ValueError
  if upperLeftY < 0 or upperLeftY >= getHeight(picture):
    print "crop(picture, upperLeftX, upperLeftY, width, height): upperLeftY must be within the picture"
    raise ValueError
  return picture.crop(upperLeftX, upperLeftY, width, height)

#Crop out a segment of sound starting at start index, numSamples long.
#if asked to crop past the end of the sound, this will return as many samples
#as possible.
def cropSound(sound,startIndex,numSamples):
  if not isinstance(sound,Sound):
      print "cropSound(sound,startIndex,numSamples): Input is not a sound"
      raise ValueError
  if startIndex >= sound.getLength():
      print "cropSound(sound,startIndex,numSamples): startIndex must be within the sound"
      raise ValueError
  newLength = min(numSamples, getNumSamples(sound) - startIndex )
  newSound = makeEmptySound(newLength, int(getSamplingRate(sound)))
  for i in range(newLength):
    v = getSampleValueAt(sound,i+startIndex)
    setSampleValueAt(newSound, i, v)
  return newSound

#copy sound into dest at startIndex.  A new sound is returned (dest is not modified).
def copySoundInto(sound, dest, startIndex):
  if not isinstance(sound, Sound):
      print "copySoundInto(sound, dest, startIndex): First parameter is not a sound"
      raise ValueError
  if not isinstance(dest, Sound):
      print "copySoundInto(sound, dest, startIndex): Second parameter is not a sound"
      raise ValueError
  newSound = duplicateSound(dest)
  sound.copySoundInto(newSound, startIndex)
  return newSound


#-------------------------------
#convertSamplingRate - convert a sound file to a new sampling rate
#Inputs:   sound -   the sound to convert
#          newRate - the new sampling rate
#Returns:  a copy of sound with the new sampling rate.
#-------------------------------
def convertSamplingRate(sound, newRate):
  oldRate = getSamplingRate(sound)
  numSamplesNew = int(getNumSamples(sound) * newRate / float(oldRate))
  newSound = makeEmptySound(numSamplesNew, newRate)
  for index in range(numSamplesNew):
    oldIndex = index * float(oldRate)/newRate
    val = getSampleValueAt(sound, int(oldIndex))
    setSampleValueAt(newSound, index, val)
  return newSound

#----------------------------------------------------------------------
#expFade (exponential Fade)
#sound   - The sound to fade
#factor  - The factor that the sound should be reduced by.
#returns - A new sound that is gradually reduced in volume
#          by the desired factor
#----------------------------------------------------------------------
def expFade(sound, factor):
  ns = getNumSamples(sound)
  newSound = duplicateSound(sound)
  for i in range(ns):
    val = getSampleValueAt(sound, i)
    newVal = val * pow(exp(1), -(float(i)/ns * log(factor)))
    setSampleValueAt(newSound, i, newVal)
  return newSound

#----------------------------------------------------------------------
#returnTone
#freq - frequency in hertz
#dur - duration in milliseconds
#vol - volume from 0-127
#sampleRate - the sampling rate of the returned sound
#returns - a sine wave sound of the desired frequency.
#----------------------------------------------------------------------
def returnTone(freq, dur, vol, sampleRate = 22050):
  numSamples = int(dur/1000.0 * sampleRate)
  sound = makeEmptySound(numSamples, sampleRate)
  volFactor = vol / 127.0 * 32767
  for i in range(numSamples):
    val = sin(2 * pi * freq * i * 1.0/sampleRate)
    setSampleValueAt(sound, i, val * volFactor)
  return sound

#----------------------------------------------------------------------
#returnSquareTone
#freq - frequency in hertz
#dur - duration in milliseconds
#vol - volume from 0-127
#sampleRate - the sampling rate of the returned sound
#returns - a square wave sound of the desired frequency
#----------------------------------------------------------------------
def returnSquareTone(freq, dur, vol, sampleRate = 22050):
  numSamples = int(dur/1000.0 * sampleRate)
  sound = makeEmptySound(numSamples, sampleRate)
  period = 1.0/freq * sampleRate
  volFactor = vol / 127.0 * 32767
  for i in range(numSamples):
    if (i % period) < (.5 * period):
      val = -1 * volFactor
    else:
      val = 1 * volFactor
    setSampleValueAt(sound, i, val)
  return sound


#----------------------------------------------------------------------
#returnNote
#note - Note in MIDI encoding
#dur - duration in milliseconds
#vol - volume from 0-127
#returns - The desired note as a sine wave.
#----------------------------------------------------------------------
def returnNote(note, dur, vol, sampleRate = 22050):
  f = 8.1758 * 2**(note / 12.0)  # midi to frequency conversion
  return expFade(returnTone(f, dur, vol, sampleRate), 10)

#----------------------------------------------------------------------
#returnSquareNote
#note - Note in MIDI encoding
#dur - duration in milliseconds
#vol - volume from 0-127
#returns - The desired note as a square wave.
#----------------------------------------------------------------------
def returnSquareNote(note, dur, vol):
  f = 8.1758 * 2**(note / 12.0)  # midi to frequency conversion
  return expFade(returnSquareTone(f, dur, vol), 10)

#----------------------------------------------------------------------
#returnNotes - Return a series of musical notes at a given volume.
#notes - an array of integers: [note#1, dur#1, note#2, dur#2...]
#volume - a volume from 1-127
#returns - a single sound containing all of the requested notes
#----------------------------------------------------------------------
def returnNotes(notes, vol):
  newSound = makeEmptySound(1)
  for noteNum in range(0, len(notes), 2):
    n = returnNote(notes[noteNum],notes[noteNum+1], vol)
    newSound = appendSound(newSound, n)
  return newSound

#----------------------------------------------------------------------
#returnSquareNotes - Return a series of musical notes at a given volume.
#notes - An array of integers: [note#1, dur#1, note#2, dur#2...]
#volume - A volume from 1-127
#returns - A single sound containing all of the requested notes
#----------------------------------------------------------------------
def returnSquareNotes(notes, vol):
  newSound = makeEmptySound(1)
  for noteNum in range(0, len(notes), 2):
    n = returnSquareNote(notes[noteNum],notes[noteNum+1], vol)
    newSound = appendSound(newSound, n)
  return newSound

#----------------------------------------------------------------------
#appendSound
#s1, s2 - sounds
#returns - A new sound: s2 appended to the end of s1.
#----------------------------------------------------------------------
def appendSound(s1, s2):
  s1NumSamples = getNumSamples(s1)
  s2NumSamples = getNumSamples(s2)
  newSound = makeEmptySound(s1NumSamples+s2NumSamples, int(getSamplingRate(s1)))
  s1.copySoundInto(newSound, 0)
  s2.copySoundInto(newSound, s1NumSamples)
  return newSound


#----------------------------------------------------------------------
#appendSounds
#sounds - a list of sounds
#returns - A single sound created by appending all
#          of the individual sounds in order.
#----------------------------------------------------------------------
def appendSounds(sounds):
  newSound = makeEmptySound(1, int(getSamplingRate(sounds[0])))
  for s in sounds:
    newSound = appendSound(newSound, s)
  return newSound