#!/usr/bin/env python # -*- coding: utf-8 -*- import StringIO import sys import soundfont.parser import os import audio_output #f_0 = 440 # A #f_0 = 8.1757989 # in Hz, MIDI note 0, a C. def frequency_of_note(note_half_tone_index): """ Gleichstufig temperiertes Intervall. """ i = note_half_tone_index assert(i == int(i)) #f_0 = 440 # A #return f_0 * 2**(i / 12.0) return 440 * 2**((i - 69) / 12.0) class Instrument(object): def __init__(self, contents): sample_data_points_info_list, self.sample_data_points = soundfont.parser.get_sample_data_points(contents) self.sample_data_points_info = sample_data_points_info_list[0] self.waveform_pattern = "".join([audio_output.encode_sample(item) for item in self.sample_data_points]) for i in range(8): self.waveform_pattern = self.waveform_pattern + self.waveform_pattern self.base_frequency = frequency_of_note(self.sample_data_points_info.original_pitch) #print self.sample_data_points_info.original_pitch, self.base_frequency self.cache = {} def generate_waveform(self, frequency, duration): # TODO looping etc. key_duration = duration key_frequency = frequency if frequency not in self.cache: self.cache[frequency] = {} else: if key_duration in self.cache[key_frequency]: return self.cache[frequency][key_duration] blurb = [] j = 0 #print frequency for i in range(int(22050 * duration)): j = int(i * frequency / self.base_frequency) # 523.25113060119725) # FIXME encoded_sample = self.waveform_pattern[j << 1 : (j << 1) + 2] #value = audio_output.decode_sample() #blurb.append(audio_output.encode_sample(value)) blurb.append(encoded_sample) #math.sin(2 * math.pi * frequency * i / 22050) * volume)) result = "".join(blurb) if key_duration not in self.cache[key_frequency]: self.cache[key_duration] = result return result def load_instrument(name): input_stream = file(name, "rb") contents = soundfont.parser.load(input_stream) result = Instrument(contents) input_stream.close() return result half_tones = [] for i in range(11): for note in ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]: half_tones.append("%s%d" % (note, i)) #half_tones = ["A2", "A#2", "B2", "C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A3", "A#3", "H3", "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3"] #tones = ["A2", "B2", "C2", "D2", "E2", "F2", "G2"] assert(frequency_of_note(half_tones.index("C1")) >= 16) assert(frequency_of_note(half_tones.index("C1")) < 17) Organ_B3 = load_instrument(os.path.join("soundfont", "example", "361-Organ_B3.SF2")) Pizzicato = load_instrument(os.path.join("soundfont", "example", "FaithlessPizzicato.SF2")) #Guitar = load_instrument(os.path.join("soundfont", "example", "754-Donnys_Guitar.SF2")) Guitar = load_instrument(os.path.join("soundfont", "example", "6488-Guitar_Acoustic_melo.SF2")) #1/4 pause = None sheet = [ #["G", None, "G", ], #["F", None, "F", ], (Organ_B3, [None, "G4", None, "G4", None, "F#4", None, "F#4", None, "G4", None, "G4", None, "F#4", None, "F#4", None, "G4", None, "G4", None, "F#4", None, "F#4", None, "G4", None, "F#4", "G4", None, None, (None, 8), (None, 8), (None, 8), (None, (3, 8)), None, (None, 8), (None, 8), "A4", ("A4", 8), ("D4", 8), "D4", (None, 8), ("B4", 8), ("B4", 8),("B4", 8),("B4", 8),("B4", 8),("B4", 8),("A4", 8),("G4", 8),("G4", 8), ("A4", 4), ("A4", 8), ("B4", 8), ("B4", 4), ("B4", 4), ("B4", 8), ("B4", 8), ("B4", 8), ("E5", 8), ("E5", 8), ("E5", 4), ("E5", 8), ("A4", 8), ("A4", 8), ("A4", 8), ("D5", 8), ("D5", 4), (None, 8), ("A4", 8), ("A4", 8), ("A4", 8), ("G4", 8), ("A4", 8), ("A4", 4), ("A4", 4), ("A4", 8), ("A4", 8), ("A4", 8), ("B4", 8), ("B4", 4), ("D5", 4), ("A4", 8), ("A4", 8), ("A4", 8), ("G4", 8), ("A4", 8), ("B4", (3,8)), (None, 2), (None, 8), ("A4", 8), ("B4", 4), ("A4", 4), ("G4", 8), ("E4", 8), ("E4", 4), (None, 4), (None, 2), (None, 4), (None, 8), ("B4", 8), ("B4", 8), ("B4", 8), ("B4", 8), ("E5", 8), ("E5", 2), ("A4", 8), ("A4", 4), ("D5", 8), ("D5", 4), (None, 8), ("B4", 8), ("B4", 8), ("B4", 8), ("B4", 8), ("B4", 8), ("B4", 4), ("B4", 4), ("A4", 8), ("A4", 8), ("A4", 8), ("B4", 8), ("B4", 4), (None, 8), ("B4", 8), ("B4", 4), ("B4", 8), ("E5", 8), ("E5", 8), ("G5", (3,8)), ("F#5", 4), ("D5", 8), ("B4", 8), ("B4", 4), (None, 8), ("A4", 8), ("A4", 4), ("G4", 8), ("A4", 8), ("A4", 8), ("B4", 4), ("G4", 8), ("A4", 8), ("A4", 8), ("A4", 8), ("B4", 8), ("B4", 8), ("D4", (3,8)), ]), (Organ_B3, [None, "E4", None, "E4", None, "D4", None, "D4", None, "E4", None, "E4", None, "D4", None, "D4", None, "C4", None, "C4", None, "D4", None, "D4", None, "E4", None, "D4", "E4", None, None, (None, 8), ("A4", 8), ("B4", 8), ("B4", (3, 8)), "E5", ("E5", 8), ("E5", 8), None, (None, 8), (None, 8), None, (None, 8), (None, 8), (None, 8),(None,8), (None,8), (None,8), (None,8), (None,8), (None,8), (None,8), (None, 4), (None, 8), (None, 8), (None, 4), (None, 4), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, 4), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, 4), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, 4), (None, 4), (None, 8), (None, 8), (None, 8), (None, 8), (None, 4), (None, 4), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, (3,8)), (None, 2), (None, 8), (None, 8), (None, 4), (None, 4), (None, 8), (None, 8), (None, 4), (None, 4), (None, 2), (None, 4), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, 2), (None, 8), (None, 4), (None, 8), (None, 4), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, 4), (None, 4), (None, 8), (None, 8), (None, 8), (None, 8), (None, 4), (None, 8), (None, 8), (None, 4), (None, 8), (None, 8), (None, 8), (None, (3,8)), (None, 4), (None, 8), (None, 8), (None, 4), (None, 8), (None, 8), (None, 4), (None, 8), (None, 8), (None, 8), (None, 4), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, 8), (None, (3,8)), ]), (Organ_B3, [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, (None, 2 ), (None, 2 ), ("A4", 2), (None, 2 ), ("F#3", 2 ), (None, 2 ),("A3", 2 ), (None, 2 ), ("D3", 2 ), (None, 2), ("B4", 2), (None, 2), ("F#4", 2), (None, 2), ("G4", 2), (None, 2), ("F#4", 2), (None, 2), ("E4", 2), (None, 2), ("F#4", 2), (None, 2), (None, 4), (None, 4), (None, 4), (None, 4), (None, 2), (None, 2), ("B4", 2), (None, 2), ("F#4", 2), (None, 2), ("B4", 2), (None, 2), ("F#4", 2), ("E4", 2), ("B4", 2), (None, 2), ("F#4", 2), (None, 2), ("B4", 2), ("B3", 2), ("F#4", 2), ]), (Organ_B3, ["E4", None, "E4", None, "B3", None, "B3", None, "E4", None, "E4", None, "B3", None, "B3", "A#3", "A3", None, "A3", None, "B3", None, "B3", None, "E4", None, "B3", None, "E4", None, (None, 2 ), ("E4", 2 ), ("G4", 2), ("B3", 2 ), ("D3", 2 ), ("E4", 2 ),("G3", 2 ), ("B3", 2 ), ("F#3", 2 ), ("E4", 2), ("G4", 2), ("B3", 2), ("D4", 2), ("E3", 2), ("B4", 2), ("B3", 2), ("D4", 2), ("A3", 2), ("C4", 2), ("B3", 2), ("D4", 2), ("E4", 2), ("B3", 4), ("D4", 4), ("E4", 4), (None, 4), (None, 2), ("E4", 2), ("G4", 2), ("B3", 2), ("D4", 2), ("E4", 2), ("G4", 2), ("B3", 2), ("D4", 2), (None, 2), ("G4", 2), ("B3", 2), ("D4", 2), ("E4", 2), ("G4", 2), (None, 2), ("D4", 2), ]), # ^ * * * * ^ * * * * * * ^ * * * * ] def half_tone_by_base_and_offset(base, offset): base_tone_index = half_tones.index(base) return half_tones[base_tone_index + offset] def duration_for_note_or_pause(note_or_pause): duration = 59.99 / 35.0 # TODO configurable beat. if isinstance(note_or_pause, tuple): # note, BPM_divisor note, BPM_part = note_or_pause if isinstance(BPM_part, tuple): BPM_nominator, BPM_denominator = BPM_part else: BPM_nominator = 1 BPM_denominator = BPM_part else: note = note_or_pause BPM_nominator = 1 BPM_denominator = 4 note_duration = (duration * BPM_nominator) / BPM_denominator return note_duration def wave_for_note_or_pause(instrument, note_or_pause): note_duration = duration_for_note_or_pause(note_or_pause) #print note, BPM_nominator, BPM_denominator, note_duration if isinstance(note_or_pause, tuple): # note, BPM_divisor note, BPM_part = note_or_pause else: note = note_or_pause if note is None: # pause a = audio_output.generate_silence(note_duration) else: # note a = instrument.generate_waveform(frequency_of_note(half_tones.index(note)), note_duration) return a def encode_lassus(clef, note_or_pause): # C C# D D# E F F# G G# A A# B C' C#' D' D#' E' F' F#' G' G#' A' A#' B C'' lassus_table = {4: ["%", u"\xc8%", "^", u"\u201e^", "&", "*", u"\xc2*", "(", u"\xca(", ")", u"\xc1)", "_", "+", u"\xc8+", "Q", u"\u201eQ", "W", "E", u"\xc2E", "R", u"\xcaR", "T", u"\xc1T", "Y", "U", ], # 4 # C is first. 8: ["{", u"\xc8{", "}", u"\u201e)", "|", "A", u"\xc2A", "S", u"\xcaS", "D", u"\xc1D", "F", "G", u"\xc8G", "H", u"\u201eH", "J", "K", u"\xc2K", "L", u"\xcaL", ":", u"\xc1:", '"', "Z", ], 2: ["l", u"\xc8l", ";", u"\u201e;", "'", "z", u"\xc2z", "x", u"\xcax", "c", u"\xc1c", "v", "b", u"\xc8b", "n", u"\u201en", "m", ",", u"\xc2,", ".", u"\xca.", "/", u"\xc1/", "~"], 1: ["r", u"\xc8r", "t", u"\u201et", "y", "u", u"\xc2u", "i", u"\xcai", "o", u"\xc1o", "p", "[", u"\xc8[", "]", u"\u201e]", "\\","a", u"\xc2a", "s", u"\xcas", "d", u"\xc1d", "f", "g"], 16: []} # don't exist in the font. pauses = { 1: "05", 8: "75", 4: "85", 2: "95", } #hashes = [ , , , , , u"\xcb", u"\xc8", u"\xd8"] # C is first. # TODO end-of-track: "-", long(note-like) space: "4", short space: "5", very short space: "6"=space. #sys.stderr.write("%s\n" % str(note_or_pause or "")) #sys.stderr.flush() if note_or_pause is None: note, duration = None, 4 elif isinstance(note_or_pause, tuple): note, duration = note_or_pause else: note = note_or_pause duration = 4 if duration is None: duration = 4 if duration == (3, 8): # FIXME duration = 2 if note is not None: #while len(note) > 0 and note[-1] in "0123456789": # note = note[ : -1] half_tone_index = half_tones.index(note) if clef == "bass": assert(half_tone_index >= 0) half_tone_index = (half_tone_index % 12) + 12 half_tone_index = half_tone_index - 4 else: half_tone_index = half_tone_index % 12 return lassus_table[duration][half_tone_index] else: return pauses[duration] def lassus_debug(sheet_voice, clef = "treble"): return {"treble": "`", "bass": "1"}[clef] + "".join([encode_lassus(clef, note_or_pause) for note_or_pause in sheet_voice]) def Windows_print(text): print text if __name__ == "__main__": # 140 BPM import codecs fse = sys.getfilesystemencoding() or "UTF-8" sys.stdout = codecs.getwriter(fse)(sys.stdout) voice_clefs = ["treble", "treble", "bass", "bass"] voice_tracks = [] for index, (instrument, voice) in enumerate(sheet): Windows_print(lassus_debug(voice, voice_clefs[index])) voice_track = "".join([wave_for_note_or_pause(instrument, note_or_pause) for note_or_pause in voice]) print(len(voice_track)) voice_tracks.append(voice_track) audio_output.queue_blurb(audio_output.mix(voice_tracks)) """for i in range(13): #print half_tones[i] a = generate_sine_note(frequency_of_note(i), 0.3) b = generate_sine_note(frequency_of_note(i + 4), 0.3) c = generate_sine_note(frequency_of_note(i + 7), 0.3) queue_blurb(mix([a, b, c]))""" audio_output.play_blurbs()