Advertisement
Guest User

midi2conv

a guest
Oct 6th, 2020
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.97 KB | None | 0 0
  1. import midi
  2. #Needs MIDI module, find here: https://github.com/vishnubob/python-midi
  3. import sys
  4. import re
  5.  
  6. readableMIDI = midi.read_midifile(sys.argv[1])
  7. open("MidiDataOut.txt", "w").write(str(readableMIDI))
  8.  
  9. fghsbeepOut = open(sys.argv[2], "w")
  10.  
  11. txt = open("MidiDataOut.txt", "r").read()
  12.  
  13. def regexSearch(pattern, string, start=0, end=0):
  14.     #print "Regex Start: " + str(start)
  15.     #print "Regex Pattern: " + pattern
  16.     if end == 0:
  17.         return re.compile(pattern).search(string, start)
  18.     else:
  19.         return re.compile(pattern).search(string, end)
  20.  
  21. def regexFindall(pattern, string):
  22.     return re.compile(pattern).findall(string)
  23.  
  24. def regexFirstResult(pattern, string, start=0, end=0):
  25.     if end == 0:
  26.         return re.compile(pattern).search(string, start).group(0)
  27.     else:
  28.         return re.compile(pattern).search(string, start, end).group(0)
  29.  
  30. def noteString(noteNum):
  31.     #45 = A2, 46=A#2
  32.     if noteNum == None:
  33.         return ""
  34.     if noteNum == -1:
  35.         return "0"
  36.     noteList = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",]
  37.     return noteList[noteNum%12]+str(noteNum//12-1)
  38.  
  39. def writeRow(trackNotes):
  40.  
  41.     writeNotes = [noteString(trackNotes[0]), noteString(trackNotes[1]), noteString(trackNotes[2]), noteString(trackNotes[3])]
  42.  
  43.     print "writeRow notes:"
  44.     print writeNotes
  45.  
  46.     writeNotes.reverse()
  47.     endIndex = writeNotes.index("")
  48.     writeNotes.reverse()
  49.  
  50.     print "endIndex: "+str(endIndex)
  51.  
  52.     # if endIndex <= 2:
  53.     #   fghsbeepOut.write(writeNotes[0])
  54.     #   if endIndex <= 1:
  55.     #       fghsbeepOut.write("\t\t\t\t"+writeNotes[1])
  56.     #       if endIndex <= 0:
  57.     #           fghsbeepOut.write("\t\t\t\t"+writeNotes[2])
  58.     #           if endIndex <= -1:
  59.     #               fghsbeepOut.write("\t\t\t\t"+writeNotes[3])
  60.  
  61.     writeNotes.reverse()
  62.  
  63. inputRes = int(re.compile(r"\d+").search(re.compile(r"resolution=\d+,").search(txt).
  64.     group()).group())
  65.  
  66. outputRes = input("Output resolution:")
  67. outputBPM = input("Output BPM:")
  68. includeBeginAndEnd = raw_input("Include rests before the first note? (y/n):")
  69.  
  70. firstNoteTick = int(regexFirstResult(r"\d+",regexFirstResult(r"Note(?:On|Off)Event.tick=\d+",txt)))
  71.  
  72. firstNotePos = regexSearch(r"Note(?:On|Off)Event.tick=\d+",txt).start()
  73.  
  74. skipTicks = 0
  75.  
  76. if includeBeginAndEnd == "y":
  77.     i = 0
  78.     while(i < firstNotePos):
  79.         ticks = int(regexSearch(r"tick=(\d+)",txt,i).group(1))
  80.         skipTicks = skipTicks + ticks
  81.         i = regexSearch(r"tick=(\d+)",txt,i).end()
  82.  
  83. fghsbeepOut.write(str(outputRes*outputBPM)+"\n#Beat 1\n")
  84.  
  85. beatNum = 1
  86. currentPos = firstNotePos
  87. currentTick = 0
  88. occupiedTracks = [False, False, False, False]
  89. trackNotes = [None, None, None, None]
  90. previousNotes = [None, None, None, None]
  91. writeNotes = ["", "", "", ""]
  92.  
  93. def nextNote():
  94.     return regexSearch(r"Note(?:On|Off)Event.tick=\d+, channel=\d+, data=.(\d+)", txt, currentPos)
  95. def nextNoteOnOff():
  96.     return regexSearch(r"Note(On|Off)Event", txt, currentPos).group(1)
  97. def nextTick():
  98.     return int(regexSearch(r"Note(?:On|Off)Event.tick=(\d+)", txt, currentPos).group(1))
  99.  
  100. #45 = A2, 46=A#2
  101.  
  102. #print nextNote()
  103.  
  104. while nextNote():
  105.     print "- - - - - - - - - - - - - - - - - -"
  106.     noteNum = int(nextNote().group(1))
  107.     noteTick = int(round(float(nextTick())/float(inputRes)*float(outputRes), 0))
  108.  
  109.     print "noteTick: " + str(noteTick)
  110.     print nextTick()
  111.  
  112.     if noteTick >= 1:
  113.  
  114.         for i in range(4):
  115.             if (trackNotes[i] == None) | (previousNotes[i] != None) | (previousNotes != -1):
  116.                 trackNotes[i] = -1
  117.             if (trackNotes[i] == -1) | (previousNotes[i] == -1):
  118.                 trackNotes[i] = None
  119.  
  120.         writeRow(trackNotes)
  121.  
  122.         previousNotes = trackNotes
  123.    
  124.         for i in range(noteTick):
  125.             currentTick = currentTick + 1
  126.             fghsbeepOut.write("\n")
  127.    
  128.             if currentTick%(2*outputRes) == 0: #The 2* should be removed in the end, it's only there so I can debug the .fghsbeep out with a file I know is correct
  129.                 beatNum = beatNum + 1
  130.                 fghsbeepOut.write("#Beat "+str(beatNum)+"\n")
  131.  
  132.     # print "\n"
  133.     # print nextNote().group(0)
  134.     # print currentPos
  135.     # print nextNote().end()
  136.  
  137.     if nextNoteOnOff() == "On":
  138.  
  139.         print "\nNoteOnEvent"
  140.        
  141.         if min(occupiedTracks) == True:
  142.             print "Too many notes on beat "+str(beatNum)+". Fix MIDI file and try again."
  143.             break
  144.  
  145.         trackNum = occupiedTracks.index(False)
  146.         occupiedTracks[trackNum] = True
  147.         trackNotes[trackNum] = noteNum
  148.  
  149.         print occupiedTracks
  150.         print trackNotes
  151.  
  152.     else:
  153.  
  154.         print "\nNoteOffEvent"
  155.  
  156.         trackNum = trackNotes.index(noteNum)
  157.         trackNotes[trackNum] = None
  158.         occupiedTracks[trackNum] = False
  159.  
  160.         print occupiedTracks
  161.         print trackNotes
  162.         print noteNum
  163.  
  164.     currentPos = nextNote().end()
  165.  
  166.  
  167.  
  168.  
  169. #The resolution of the MIDI files is MIDI ticks per quarter note.
  170. #The resolution should be lowered as much as possible without seriously sacrificing song quality. Think of it as a really good quanitizer. I recommend tending to your MIDI files before you run them through this program to make sure that nothing will get rounded poorly. Grace notes, for example, will pretty much always need some fine tuning.
  171. #It should pretty much always be a power of two.
  172.  
  173. #The output BPM is quarter notes per minute.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement