def parse_midi(path): midifile = smf.SMF(path) notes_on = [] for event in midifile.events: # if it is as "Note On" event, append the time and the pitch if event.midi_buffer[0] == 144: notes_on.append((event.time_pulses, event.midi_buffer[1])) notes_on = [(t, max(map(itemgetter(1), notes))) for t, notes in groupby(notes_on, itemgetter(0))] ticks = list(map(itemgetter(0), notes_on)) pitches = bytes(map(itemgetter(1), notes_on)) return pitches, ticks, event.time_pulses
def process_file(infile, outfile, patch): """ Process a MIDI file, using pysmf. """ import smf # create dummy engine with no inputs or outputs _setup._config_impl(backend='dummy') engine = Engine() engine.setup({_util.offset(0): patch}, None, None, None) # open input file smf_in = smf.SMF(infile) # create SMF object with same ppqn and number of tracks as input file smf_out = smf.SMF() smf_out.ppqn = smf_in.ppqn for n in range(len(smf_in.tracks)): smf_out.add_track() for smf_ev in smf_in.events: if smf_ev.midi_buffer[0] == 0xff: # event is metadata. copy to output unmodified smf_out.add_event(smf.Event(smf_ev.midi_buffer), smf_ev.track_number, pulses=smf_ev.time_pulses) else: ev = _mididings.buffer_to_midi_event(smf_ev.midi_buffer, smf_ev.track_number, smf_ev.time_pulses) # use base class version of process_event() to bypass calling # ev._finalize(), which would fail since ev is of type # _mididings.MidiEvent. for out_ev in _mididings.Engine.process_event(engine, ev): buf, track, pulses = _mididings.midi_event_to_buffer(out_ev) smf_out.add_event(smf.Event(buf), track, pulses=pulses) smf_out.save(outfile)
def peek_midi_file(context, filepath, use_some_setting): print(filepath) prefs = context.user_preferences.addons["sound_drivers"].preferences import sys sys.path.append(prefs.smf_dir) import smf pin_id = getattr(context.space_data, "pin_id", None) sp = pin_id if pin_id is not None else context.object.data sound = sp.sound f = smf.SMF(filepath) midi = {} tracks = {} for t in f.tracks: track = {} for e in t.events: #print(e.decode(), e.time_seconds) s = e.decode() #print(s.startswith("Note")) if s.startswith("Instrument"): #print("INSTRUMENT", s) track["name"] = "Track %d" % (t.track_number) track["index"] = t.track_number track["instrument"] = s.title() elif s.startswith("Time Signature"): track["time_sig"] = s elif s.startswith("Tempo"): track["tempo"] = s elif s.startswith("Key Signature"): print("KEYSIG", s) track["keysig"] = s elif s.startswith("Program Change"): #print("PROGCHA", s) # this could be instrument too idx = int(s.split(" ")[-1]) s = midi_instruments[idx] track["name"] = "Track %d" % (t.track_number) track["instrument"] = s.title() track["index"] = t.track_number elif s.startswith("Controller"): continue print("CONTROLLER", s) elif s.startswith("Pitch Wheel"): # do nothing for now continue elif s.startswith("Note"): continue elif s.startswith("End Of Track"): break else: #continue print("XXX", s) if t.track_number == 0: midi = track if track.get("name", False): tracks.setdefault(track["name"], track) sound.midifile.filepath = filepath sound.midifile.tracks.clear() for k, track in tracks.items(): t = sound.midifile.tracks.add() t.name = track["name"] t.data_dic = json.dumps(track) print("-" * 77) print(k, tracks[k]) return
def read_midi_file(context, filepath, use_some_setting): print(filepath) prefs = context.user_preferences.addons["sound_drivers"].preferences import sys sys.path.append(prefs.smf_dir) import smf pin_id = context.space_data.pin_id sp = pin_id if pin_id is not None else context.object.data channels = [ c for sp in context.scene.objects if sp.type == 'SPEAKER' for c in sp.data.channels ] midichannels = [] f = smf.SMF(filepath) tracks = [] for t in f.tracks: print("TRACK : %s" % t.track_number) a = {} #a = bpy.data.actions.new("MidiAction") print(channels) channel_name = unique_name(channels, 'AA') channels.append(channel_name) a["name"] = "%s Unknown (trk %d)" % (channel_name, t.track_number) a['wavfile'] = sp.sound.name a['start'] = 0 a['end'] = len(midi_notes) a['row_height'] = 0.4 a["Channels"] = 0 a["channel_name"] = channel_name a['MIDI'] = filepath #sp.animation_data.action = a a["keyframe_points"] = {} # list of tups (dp, frame, value) ''' for i, n in enumerate(midi_notes): channel = "%s%d" % (channel_name, i) sp[channel] = 0 sp.keyframe_insert('["%s"]' % channel, frame = 0) #sp.keyframe_insert('["%s"]' % channel, frame = 0) #sp.keyframe_insert('["%s"]' % channel, frame = 0) ''' for e in t.events: s = e.decode() print("XXXXXXXX", s, e.time_seconds) #print(s.startswith("Note")) if s.startswith("Instrument"): print("INSTRUMENT", s) a["name"] = "%s:%s (trk %d)" % (channel_name, s.title(), t.track_number) elif s.startswith("Key Signature"): print("KEYSIG", s) elif s.startswith("Program Change"): #print("PROGCHA", s) # this could be instrument too idx = int(s.split(" ")[-1]) #print(midi_instruments[idx]) a["name"] = "%s:%s (trk %d)" % (channel_name, midi_instruments[idx].title(), t.track_number) elif s.startswith("Controller"): continue print("CONTROLLER", s) elif s.startswith("Pitch Wheel"): print("PITCHWEEL", s) # do nothing for now continue elif s.startswith("Note"): v = 0 s = s.replace("Note ", "") #print("StartsWithNote", s) c = s.split(",") #print("CC", c[0]) v = int(c[3].replace(" velocity ", "")) if c[0] == "On": note = c[2].replace(" note ", "") print("ON key[%s] = %d @ %fs" % (note, v, e.time_seconds)) elif c[0] == "Off": v = 0 note = c[2].replace(" note ", "") print("OFF key[%s] = %d @ %fs" % (note, v, e.time_seconds)) if note not in midi_notes: print("WARNING: unable to use note %s %d" % notesplit(note)) continue channel = "%s%i" % (channel_name, midi_notes.index(note)) fcurve = a["keyframe_points"].setdefault(channel, []) fcurve.append((e.time_seconds * context.scene.render.fps, v)) #sp[channel] = v #a["keyframe_points"].append(('["%s"]' % channel, e.time_seconds * context.scene.render.fps, v)) else: #continue print("XXX", s) if len(a["keyframe_points"].keys()): midichannels.append(channel_name) midifile["TRACK : %s" % t.track_number] = a print(midichannels) keys = [ "name", "wavfile", "start", "end", "row_height", "Channels", "channel_name", "MIDI" ] actions = [] channels = [] action = bpy.data.actions.new("MidiAction") sp.animation_data.action = action for k, a in midifile.items(): print("-" * 77) print(midifile[k]["name"]) tracks = a["keyframe_points"] #action = bpy.data.actions.new("MidiAction") #sp.animation_data.action = action for key in keys: action[key] = a[key] channel = a["channel_name"] channels.append(channel) for t in tracks.keys(): kfps = tracks[t] print(t) #fc = action.fcurves.new('["%s"]' % t) # make the fcurves sp[t] = 0 sp.keyframe_insert('["%s"]' % t, frame=1, group=a["name"]) for kfp in kfps: f, v = kfp sp[t] = v sp.keyframe_insert('["%s"]' % t, frame=f, group=a["name"]) print("KFPS", t, len(tracks[t])) actions.append(action) # would normally load the data here vals = [] sp_rna = {} for a in actions: if len(a.fcurves) <= 1: print("NO FCURVES IN ", a.name) try: del (a["wavfile"]) a.user_clear() actions.remove(a) #bpy.data.actions.remove(a) #print("REMOVED") except: print("XCPT") continue print("WTF") continue a["Channels"] = len(a.fcurves) a["channels"] = channels channel_name = a["channel_name"] for fc in a.fcurves: for kp in fc.keyframe_points: kp.interpolation = 'CONSTANT' fc_range, points = fc.minmax cn = fc.data_path.replace('["', '').replace('"]', '') print(channel_name, cn) n = int(cn[2:]) f = pow(2, (n - 69) / 12.0) * 440 high = low = f vals.extend(list(fc_range)) rna = sp['_RNA_UI'] set_channel_idprop_rna(cn, rna, low, high, fc_range, fc_range, is_music=True) ''' vcns = ["%s%d" % (channel_name, i) for i in range(len(midi_notes))] ''' sp_rna = {k: sp['_RNA_UI'][k].to_dict() for k in sp['_RNA_UI'].keys()} # if k in vcns} a['rna'] = str(sp_rna) a['min'] = min(vals) a['max'] = max(vals) nla_drop(sp, action, 1, "%s %s" % (channel_name, channel_name)) return {'FINISHED'}
import smf # create a new SMF object f = smf.SMF() # add a track f.add_track() # add a single note (middle C with a duration of one second) f.add_event(smf.Event([0x90, 60, 127]), 0, seconds=0.0) f.add_event(smf.Event([0x80, 60, 0]), 0, seconds=1.0) # save as a new standard MIDI file f.save('test.mid')
parser.add_argument('inputfile', metavar='inputfile.mid', nargs='?', help='input midi file name') parser.add_argument('--blofeld', action='store_true', help='ignore all sysex except waldorf blofeld patches') parser.add_argument('--verbose', action='store_true', help='verbose output') args = parser.parse_args() midfile = args.inputfile syxfile = midfile.split('.')[0] + ".syx" print("opening input file '%s'..." % midfile) f = smf.SMF(midfile) t = f.tracks[0] print("opening output file '%s'" % syxfile) outfile = open(syxfile, 'wb') patchno = 0 for e in t.events: if e.midi_buffer[0] == 0xf0: patchno += 1 buflen = len(e.midi_buffer) bufhex = map(hex, e.midi_buffer) if args.blofeld: if buflen != 392:
import smf import sys filename = sys.argv[1] tracknum = int(sys.argv[2]) print("opening file '%s'..." % filename) f = smf.SMF(filename) t = f.tracks[tracknum] print("---\nlisting binary data for track %d:\n---" % tracknum) for e in t.events: print(e.midi_buffer) print("---\nlisting decoded events for track %d:\n---" % tracknum) for e in t.events: print(e.decode())