1
0
mirror of https://gitlab.com/80486DX2-66/gists synced 2025-04-08 15:59:05 +05:30
gists/python-programming/binary_to_midi.py

88 lines
2.0 KiB
Python

#!/usr/bin/env python3
# binary_to_midi.py
#
# Author: Intel A80486DX2-66
# License: Creative Commons Zero 1.0 Universal or Unlicense
# SPDX-License-Identifier: CC0-1.0 OR Unlicense
from decimal import Decimal
from midiutil import MIDIFile
from os import stat
from sys import argv
NOTE_TABLE = {i: 52 + i for i in range(8 * 2)}
is_prime = lambda n: n > 1 and all(n % i for i in range(2, n))
TEMPO = 110
TIME_SIGNATURE = (4, 4)
INSTRUMENT_SELECTED = 1
STEP_SIZE = 1
DURATION_CONSTANT = 32
def binary_to_midi(input_file, output_file):
print("Reading file")
with open(input_file, "rb") as f:
byte_data = f.read()
print("Initialization")
pattern = MIDIFile(1, TIME_SIGNATURE, TEMPO)
pattern.addTempo(0, 0, TEMPO)
track = 0
channel = 0
time = 0
chords = []
current_chord = []
previous_note = NOTE_TABLE[0]
byte_step = (len(byte_data) // 2**6) + 1
print("Converting")
taking_chord = False
for i, byte in enumerate(byte_data[::STEP_SIZE]):
is_rest = False
note = NOTE_TABLE[byte % len(NOTE_TABLE)]
is_previous_note = i > 0 and note == previous_note
if byte % 51 == 25:
is_rest = True
elif byte % 12 == 0:
current_chord = [note]
chords.append(current_chord)
taking_chord = True
elif taking_chord:
current_chord.append(note)
taking_chord = False
duration = (Decimal('0.25') if is_prime(byte) or byte % 11 < 6 else \
Decimal('0.015')) * DURATION_CONSTANT
if abs(previous_note - note) > 3 and not is_previous_note:
current_chord.append(0)
previous_note = note
pattern.addProgramChange(0, 0, 0, INSTRUMENT_SELECTED)
for chord in chords:
for note in chord:
if is_rest:
pattern.addNote(track, channel, 0, time, duration, 0)
else:
pattern.addNote(track, channel, note, time, duration, 100)
time += duration
print("Writing out")
with open(output_file, "wb") as file:
pattern.writeFile(file)
print(f"Saved, {stat(output_file).st_size} bytes")
if __name__ == "__main__":
if len(argv) < 2:
print("Fatal error: No file specified as argument.")
exit(1)
binary_to_midi(argv[1], "output.mid")