def build_from_intervals(self, root, octave, intervals, scale_name="major"): """Given chord specs return a MidiChord object of said chord. usage: chord = ChordBuilder().build_from_intervals('c', 6, ["1", "3", "5", "b7", "#9"]) :param root: string of the note. :param octave: an integer between 0 and 8 (or 9 or something) :param intervals: a list of note intervals relative to the root. Use 'b' for flat and '#' for sharp. :param scale_name: the scale from which to select notes :return: a Chord object """ named_scale = scale.NAMED_SCALES[scale_name] my_scale = Scale(Note((root.upper(), octave)), named_scale) num_notes_in_scale = len(my_scale) # TODO: is this the correct way to calculate the scale_start_num? scale_start_num = octave * num_notes_in_scale intervals = [ self._deal_with_pitch_accidentals(interval) for interval in intervals ] notes = [ my_scale.get(scale_start_num + interval[0] - 1).transpose( interval[1]) for interval in intervals ] chord = MidiChord([note.note + str(note.octave) for note in notes]) chord.build_chord() return chord
def build_randomly_from_scale(root, octave, scale_name="major", num_note_choices=None): """Create a MidiChord object based on a given scale. :param root: the root note of the scale :param octave: the octave to be used when creating the chord :param scale_name: the scale name to be used :param num_note_choices: a list of how integers representing the number of notes allowed to be chosen at random when constructing the chord randomly. None will default to [3, 4, 5]. :return: a MidiChord """ if num_note_choices is None: num_note_choices = [3, 4, 5] named_scale = scale.NAMED_SCALES[scale_name] my_scale = Scale(Note((root.upper(), octave)), named_scale) num_notes_in_scale = len(my_scale) scale_start_num = octave * num_notes_in_scale num_notes_in_chord = np.random.choice(num_note_choices) possible_notes = [ my_scale.get(temp_note) for temp_note in range(scale_start_num, scale_start_num + num_notes_in_scale * 2) ] notes = np.random.choice(possible_notes, size=num_notes_in_chord, replace=False) chord = MidiChord([note.note + str(note.octave) for note in notes]) chord.build_chord() return chord
class Melody: def __init__(self, root_note=None, octave=None, scale_name=None, melody_len=None, quantization=None, note_density=None, note_len_choices=None): self.root_note = root_note self.octave = octave self.scale_name = scale_name self.melody_len = melody_len self.quantization = quantization # this maybe should be at note level only self.note_density = note_density # proportion of available ticks (determined by quantization) occupied by notes self.note_len_choices = note_len_choices self.root = Note((self.root_note, self.octave)) self.named_scale = scale.NAMED_SCALES[self.scale_name] self.scale = Scale(self.root, self.named_scale) self.available_notes = [self.scale.get(x) for x in range(21, 30)] self.number_of_notes = self._compute_num_notes() self.start_ticks = self._get_start_ticks() def _compute_num_notes(self): return int(self.melody_len * self.note_density / float(self.quantization)) def _get_start_ticks(self): return np.unique( sorted([ Rhythm().find_nearest_note(random.randint(0, self.melody_len), self.quantization) for _ in range(self.number_of_notes) ])) def _create_melody_note_tuple(self, start_tick): velocity = random.randint(50, 90) cur_note = random.choice(self.available_notes) cur_note = Note.index_from_string(cur_note.note + str(cur_note.octave)) note_length = random.choice(self.note_len_choices) # ["event_type_fun", "tick", "duration", "pitch", "velocity"] return [ MidiEventStager(midi.NoteOnEvent, start_tick, note_length, cur_note, velocity), MidiEventStager(midi.NoteOffEvent, start_tick + note_length, note_length, cur_note, 0) ] def create_melody(self): melody_notes = [] for tick in self.start_ticks: melody_tuples = self._create_melody_note_tuple(tick) melody_notes.extend(melody_tuples) return melody_notes
# Define key and scale key = Note('E3') scale = Scale(key, 'harmonic minor') time = 0.0 # Keep track of currect note placement time in seconds timeline = Timeline() note = key # Semi-randomly queue notes from the scale for i in range(64): if note.index > 50 or note.index < 24: # If note goes out of comfort zone, randomly place back at base octave note = scale.get(random.randrange(4) * 2) note = note.at_octave(key.octave) else: # Transpose the note by some small random interval note = scale.transpose(note, random.choice((-2, -1, 1, 2))) length = random.choice((0.125, 0.125, 0.25)) timeline.add(time, Hit(note, length + 0.125)) time += length # Resolve note = scale.transpose(key, random.choice((-1, 1, 4))) timeline.add(time, Hit(note, 0.75)) # Tension timeline.add(time + 0.5, Hit(key, 4.0)) # Resolution print("Rendering audio...")
# Define key and scale key = Note('E3') scale = Scale(key, 'major') time = 0.0 # Keep track of currect note placement time in seconds timeline = Timeline() note = key # Semi-randomly queue notes from the scale for i in xrange(64): if note.index > 50 or note.index < 24: # If note goes out of comfort zone, randomly place back at base octave note = scale.get(random.randrange(4) * 2) note = note.at_octave(key.octave) else: # Transpose the note by some small random interval note = scale.transpose(note, random.choice((-2, -1, 1, 2))) length = random.choice((0.125, 0.125, 0.25)) timeline.add(time, Hit(note, length + 0.125)) time += length # Resolve note = scale.transpose(key, random.choice((-1, 1, 4))) timeline.add(time, Hit(note, 0.75)) # Tension timeline.add(time + 0.5, Hit(key, 4.0)) # Resolution print "Rendering audio..."