Page 1 of 1

A python music player

Posted: Fri Jul 13, 2007 9:23 pm
by smudge
Hello, I've been working on this for a while now. It serves no purpose other than to give me something to do and to make my knowledge of python better, but I would like to 1) Have my code reviewed and if anybody is willing 2) have a helping (and skilled) hand at finishing this.
Basically, it parses a string and converts the instructions to music that is played via the winsound module.
Keep in mind that this is by no means done yet, but here it is:

Code: Select all

""" Name/ToDo list
  Music Maker
  by smudge
  
  #Add support for repeats, something like |: ... : |x (repeat x times, if no x, 1 time)
  #Staccato & Legato (*X and ^X)?
  #Add support for dotting notes: A-8.
  #Add support for reading from files
  """

import winsound

''' Usage instructions
  A- -> G for notes
  R for rest
  - = flat
  + = sharp

  L1=whole note default
  L2/4/8/16=half/quarter/eighth/sixteenth...

  A-8 plays an A flat eighth note

  > = octave up perm
  < = octave down perm

  <X = X played down an octave
  >>X = X played up 2 octaves

  each note should be space separated
  '''
#Crazy Train test music :D
music="L8 D D >A D >B- D >A D G F E F G F E C4"
print "Playing:",music


#settings
tempo=138.
played_in=4.
noteLen=4.
octave=0.

tempo=tempo/60./1000.#beats/ms
scale="A- A B- B C D- D E- E F G- G"

#Some shortcut functions
def findNote(baseF,hsteps):
  return int(baseF * 2**(float(hsteps)/float(12)))

def playN(note,len):
  if note != 'R':
    if octave<0:
      oct=1/(abs(octave)*2.)
    elif octave==0:
      oct=1
    else:
      oct=octave*2
  else:
    oct=1
  beats=played_in/len
  winsound.Beep(int(dict[note]*oct),int(beats/tempo))



def noteChecks(n):
  global music,tempo,played_in,octave,scale,repeatLevel,repeatArr,noteLen
  if   'L' in n:#If we are defining a default note length
    #print "  Found a length definition of",n[1:],"in",n
    noteLen=int(n[1:])
  elif 'O' in n:#If we are setting the default octave
    octave=float(n[1:])
  elif 'T' in n:#if we are setting the tempo
    tempo=float(n[1:])/60./1000.
  elif '>' in n:#shifting octave up
    notNote=True
    for x in scale.split(' '):
      if n.find(x)!=-1: notNote=False
    if notNote==True:#if we are shifting up permanently
      octs=n.count('>')
      octave+=octs
    else:#or on a note to note basis
      octs=n.count('>')
      n=n[octs:]
      octave+=octs
      noteChecks(n)
      octave-=octs
      
  elif '<' in n:#shifting octave down
    notNote=True
    for x in scale.split(' '):
      if n.find(x)!=-1: notNote=False
    if notNote==True:#if we are shifting down permanently
      octs=n.count('<')
      octave-=octs
    else:#or on a note to note basis
      octs=n.count('<')
      n=n[octs:]
      octave-=octs
      noteChecks(n)
      octave+=octs
  
  else:#if we are playing a note
    if ('-' in n) or ('+' in n):#if we have a sharp or flat
      if n[2:]=='':#if no length is defined
        playN(n[0:2],noteLen)
      else:
        playN(n[0:2],int(n[2:]))    
    else:
      if n[1:]=='':#if no length is defined
        playN(n[0],noteLen)
      else:
        playN(n[0],int(n[1:]))
  

#Dictionary of notes and freqs
dict={}
i=-1
for n in scale.split(" "):
  dict[n]=findNote(440,i)
  #print "Loaded freq of",n,":",dict[n]
  i=i+1
  

#Fakes resting by playing an inaudible pitch
dict['R']=30000

#Read the music
for n in music.split(' '):
 noteChecks(n)

print "Done"
If you are willing to help me finish this, you don't have to worry about musical knowledge. That's my part :D
At the very least, please review my code and give me a few pointers. Thanks much, smudge