VocalEasel/mma/MMA/patWalk.py

168 lines
4.9 KiB
Python
Raw Permalink Normal View History

2006-11-10 08:07:56 +00:00
# patWalk.py
"""
2007-04-29 06:47:40 +00:00
This module is an integeral part of the program
2006-11-10 08:07:56 +00:00
MMA - Musical Midi Accompaniment.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2007-04-29 06:47:40 +00:00
Bob van der Poel <bob@mellowood.ca>
2006-11-10 08:07:56 +00:00
"""
import random
2009-05-17 22:34:44 +00:00
import MMA.harmony
import MMA.notelen
2006-11-10 08:07:56 +00:00
import gbl
from MMA.common import *
from MMA.pat import PC
class Walk(PC):
2007-04-29 06:47:40 +00:00
""" Pattern class for a walking bass track. """
vtype = 'WALK'
walkChoice = 0
def getPgroup(self, ev):
""" Get group for walking bass pattern.
Fields - start, length, volume
"""
if len(ev) != 3:
error("There must be at exactly 3 items in each group in "
"a Walking Bass definition, not <%s>" % ' '.join(ev))
a = struct()
a.offset = self.setBarOffset(ev[0])
2009-05-17 22:34:44 +00:00
a.duration = MMA.notelen.getNoteLen(ev[1])
2007-04-29 06:47:40 +00:00
a.vol = stoi(ev[2], "Type error in Walking Bass definition")
return a
def restart(self):
self.ssvoice = -1
self.walkChoice = 0
def trackBar(self, pattern, ctable):
""" Do a waling bass bar.
Called from self.bar()
"""
sc=self.seq
dir = self.direction[sc]
unify = self.unify[sc]
for p in pattern:
tb = self.getChordInPos(p.offset, ctable)
if tb.walkZ:
continue
root = tb.chord.rootNote # root note of chord
""" Create a note list from the current scale. We do
this for each beat, but it's pretty fast. The note
list is simply notes 0..6 of the scale PLUS notes
1..5 reversed. So, a Cmajor chord would result in
the note list (0,2,4,5,7,9,7,5,4,2).
Note that we deliberately skip the 7th. Too often
the chord is a Major but the melody note will be
the dom. 7th and the M7 will sound off. So, just
err on the side of caution.
If DIR is UP or DOWN we don't append the 2nd half
of the scale.
If DIR is DOWN we reverse the order as well.
"""
wNotes = list(tb.chord.scaleList[0:6])
if dir not in ('UP', 'DOWN'):
b = list(tb.chord.scaleList[1:5])
b.reverse()
wNotes += b
if dir == 'DOWN':
wNotes.reverse()
# Ensure that the offset is in range.
if self.walkChoice >= len(wNotes) or self.walkChoice < 0:
self.walkChoice = 0
""" Even with a walking bass it's nice to have the chord root on
beat 1 ... not all the time, but most. This bit of code ensures
that more that 50% of beat ones will have the root.
"""
if p.offset == 0 and random.choice((0,1)):
self.walkChoice=0
note = wNotes[self.walkChoice]
""" Adjust offset for NEXT TIME. If the direction is
up/down we just increment the pointer. If we have
direction set to RANDOM then we select either -1,
0 or 1 with equal change for moving up, down or
not-at-all. With BOTH we have a preference to move up.
"""
if dir in ('UP', 'DOWN'):
self.walkChoice += 1
elif dir == 'RANDOM':
self.walkChoice += random.choice((0,1,-1))
else: # BOTH
self.walkChoice += random.choice( (-1,0,0,2,2,1,1,1,1,1,1,1))
2011-07-26 22:49:39 +00:00
2007-04-29 06:47:40 +00:00
if not self.harmonyOnly[sc]:
self.sendNote(
p.offset,
self.getDur(p.duration),
self.adjustNote(note),
self.adjustVolume(p.vol, p.offset) )
if self.harmony[sc]:
ch = self.getChordInPos(p.offset, ctable).chord.noteList
2009-05-17 22:34:44 +00:00
h = MMA.harmony.harmonize(self.harmony[sc], note, ch)
2011-07-26 22:49:39 +00:00
strumOffset = self.getStrum(sc)
2007-04-29 06:47:40 +00:00
for n in h:
self.sendNote(
2011-07-26 22:49:39 +00:00
p.offset + strumOffset,
2007-04-29 06:47:40 +00:00
self.getDur(p.duration),
self.adjustNote(n),
self.adjustVolume(p.vol * self.harmonyVolume[sc], -1) )
2006-11-10 08:07:56 +00:00
2011-07-26 22:49:39 +00:00
strumOffset += self.getStrum(sc)
2006-11-10 08:07:56 +00:00