import struct
import random
class MIDIWriter:
def __init__(self, ticks_per_beat=480):
self.ticks_per_beat = ticks_per_beat
self.events = []
def _encode_varlen(self, val):
buf = bytearray()
buf.append(val & 0x7F)
val >>= 7
while val > 0:
buf.insert(0, (val & 0x7F) | 0x80)
val >>= 7
return bytes(buf)
def set_tempo(self, tick, bpm):
tempo_us_per_beat = int(60_000_000 / bpm)
data = bytes([0xFF, 0x51, 0x03,
(tempo_us_per_beat >> 16) & 0xFF,
(tempo_us_per_beat >> 8) & 0xFF,
tempo_us_per_beat & 0xFF])
self.events.append((tick, data))
def set_time_signature(self, tick, nn=4, dd=2, cc=24, bb=8):
data = bytes([0xFF, 0x58, 0x04, nn, dd, cc, bb])
self.events.append((tick, data))
def add_note(self, start_tick, duration_ticks, channel, note, velocity):
velocity = max(1, min(127, int(velocity)))
status_on = 0x90 | (channel & 0x0F)
self.events.append((start_tick, bytes([status_on, note & 0x7F, velocity])))
status_off = 0x80 | (channel & 0x0F)
self.events.append((start_tick + duration_ticks, bytes([status_off, note & 0x7F, 0])))
def save(self, filename):
self.events.sort(key=lambda x: (x[0], x[1][0]))
track_data = bytearray()
last_tick = 0
for tick, event_bytes in self.events:
delta = tick - last_tick
track_data.extend(self._encode_varlen(delta))
track_data.extend(event_bytes)
last_tick = tick
track_data.extend(self._encode_varlen(0))
track_data.extend(bytes([0xFF, 0x2F, 0x00]))
header = struct.pack('>4sIHHH', b'MThd', 6, 0, 1, self.ticks_per_beat)
track_header = struct.pack('>4sI', b'MTrk', len(track_data))
with open(filename, 'wb') as f:
f.write(header)
f.write(track_header)
f.write(track_data)
# Mapeo General MIDI de Batería
KICK = 36
SNARE = 38
CLOSED_HH = 42
OPEN_HH = 46
FLOOR_TOM_LOW = 41
FLOOR_TOM_HI = 43
MID_TOM_LOW = 45
MID_TOM_HI = 47
HIGH_TOM = 50
CRASH_1 = 49
CRASH_2 = 57
RIDE_1 = 51
RIDE_BELL = 53
random.seed(101)
writer = MIDIWriter(ticks_per_beat=480)
ch = 9 # Canal MIDI 10 (index 0-based)
# 76 BPM
writer.set_tempo(0, 76)
writer.set_time_signature(0, 4, 2)
PPQ = 480
BAR = 4 * PPQ
EIGHTH = PPQ // 2
SIXTEENTH = PPQ // 4
def h_time(tick):
return max(0, tick + random.randint(-6, 6))
def h_vel(vel):
return max(1, min(127, vel + random.randint(-5, 5)))
current_bar = 1
def advance(n):
global current_bar
st = current_bar
current_bar += n
return st
# 1. INTRO (8 compases)
sb = advance(8)
for b in range(sb, sb + 8):
bt = (b - 1) * BAR
if b == sb:
writer.add_note(h_time(bt), PPQ * 2, ch, CRASH_1, h_vel(80))
for i in range(16):
t = bt + i * SIXTEENTH
if i in [0, 3, 8, 11]:
writer.add_note(h_time(t), SIXTEENTH, ch, KICK, h_vel(90 if i in [0, 8] else 75))
if i in [2, 6, 10, 14]:
writer.add_note(h_time(t), SIXTEENTH, ch, FLOOR_TOM_HI, h_vel(85))
if i in [4, 12]:
writer.add_note(h_time(t), SIXTEENTH, ch, MID_TOM_LOW, h_vel(90))
if i in [7, 15]:
writer.add_note(h_time(t), SIXTEENTH, ch, SNARE, h_vel(65))
# 2. ESTROFA 1 (8 compases)
sb = advance(8)
for b in range(sb, sb + 8):
bt = (b - 1) * BAR
if b == sb:
writer.add_note(h_time(bt), PPQ * 2, ch, CRASH_1, h_vel(75))
for e in range(8):
writer.add_note(h_time(bt + e * EIGHTH), EIGHTH - 10, ch, CLOSED_HH, h_vel(70 if e % 2 == 0 else 55))
if b < sb + 7:
writer.add_note(h_time(bt + PPQ), SIXTEENTH * 3, ch, SNARE, h_vel(82))
writer.add_note(h_time(bt + 3 * PPQ), SIXTEENTH * 3, ch, SNARE, h_vel(85))
writer.add_note(h_time(bt), SIXTEENTH * 3, ch, KICK, h_vel(85))
writer.add_note(h_time(bt + 2 * PPQ + EIGHTH), SIXTEENTH * 3, ch, KICK, h_vel(80))
if b == sb + 7:
writer.add_note(h_time(bt + PPQ), SIXTEENTH * 3, ch, SNARE, h_vel(85))
t3 = bt + 2 * PPQ
for idx, n in enumerate([SNARE, HIGH_TOM, MID_TOM_HI, FLOOR_TOM_HI, FLOOR_TOM_LOW, SNARE]):
writer.add_note(h_time(t3 + idx * SIXTEENTH), SIXTEENTH, ch, n, h_vel(75 + idx * 6))
# 3. ESTROFA 2 (8 compases)
sb = advance(8)
for b in range(sb, sb + 8):
bt = (b - 1) * BAR
for e in range(8):
writer.add_note(h_time(bt + e * EIGHTH), EIGHTH - 10, ch, CLOSED_HH, h_vel(80 if e % 2 == 0 else 65))
writer.add_note(h_time(bt + PPQ), SIXTEENTH * 3, ch, SNARE, h_vel(95))
writer.add_note(h_time(bt + 3 * PPQ), SIXTEENTH * 3, ch, SNARE, h_vel(98))
writer.add_note(h_time(bt), SIXTEENTH * 3, ch, KICK, h_vel(95))
writer.add_note(h_time(bt + PPQ + EIGHTH), SIXTEENTH * 3, ch, KICK, h_vel(85))
writer.add_note(h_time(bt + 2 * PPQ + EIGHTH), SIXTEENTH * 3, ch, KICK, h_vel(90))
if b == sb + 7:
t3 = bt + 2 * PPQ
for idx, n in enumerate([HIGH_TOM, MID_TOM_HI, MID_TOM_LOW, FLOOR_TOM_HI, FLOOR_TOM_LOW, SNARE]):
writer.add_note(h_time(t3 + idx * SIXTEENTH), SIXTEENTH, ch, n, h_vel(85 + idx * 6))
# 4. CORO (8 compases)
sb = advance(8)
for b in range(sb, sb + 8):
bt = (b - 1) * BAR
if b in [sb, sb + 4]:
writer.add_note(h_time(bt), PPQ * 2, ch, CRASH_1, h_vel(115))
writer.add_note(h_time(bt), PPQ * 2, ch, CRASH_2, h_vel(100))
for e in range(8):
cym = RIDE_BELL if e in [0, 4] else RIDE_1
writer.add_note(h_time(bt + e * EIGHTH), EIGHTH, ch, cym, h_vel(105 if e % 2 == 0 else 88))
if b not in [sb + 3, sb + 7]:
writer.add_note(h_time(bt + PPQ), SIXTEENTH * 3, ch, SNARE, h_vel(112))
writer.add_note(h_time(bt + 3 * PPQ), SIXTEENTH * 3, ch, SNARE, h_vel(115))
writer.add_note(h_time(bt), SIXTEENTH * 3, ch, KICK, h_vel(110))
writer.add_note(h_time(bt + EIGHTH), SIXTEENTH * 3, ch, KICK, h_vel(95))
writer.add_note(h_time(bt + 2 * PPQ), SIXTEENTH * 3, ch, KICK, h_vel(105))
writer.add_note(h_time(bt + 2 * PPQ + EIGHTH), SIXTEENTH * 3, ch, KICK, h_vel(100))
if b in [sb + 3, sb + 7]:
t3 = bt + 2 * PPQ
for idx in range(8):
n = [SNARE, HIGH_TOM, MID_TOM_HI, MID_TOM_LOW, FLOOR_TOM_HI, FLOOR_TOM_LOW, SNARE, CRASH_1][idx]
writer.add_note(h_time(t3 + idx * SIXTEENTH), SIXTEENTH, ch, n, h_vel(95 + idx * 4))
# 5. PUENTE (8 compases)
sb = advance(8)
for b in range(sb, sb + 8):
bt = (b - 1) * BAR
writer.add_note(h_time(bt), PPQ * 2, ch, CRASH_1, h_vel(110))
for e in range(8):
writer.add_note(h_time(bt + e * EIGHTH), EIGHTH, ch, OPEN_HH, h_vel(98))
writer.add_note(h_time(bt + PPQ), SIXTEENTH * 3, ch, SNARE, h_vel(115))
writer.add_note(h_time(bt + 3 * PPQ), SIXTEENTH * 3, ch, SNARE, h_vel(118))
writer.add_note(h_time(bt), SIXTEENTH * 3, ch, KICK, h_vel(115))
writer.add_note(h_time(bt + EIGHTH), SIXTEENTH * 3, ch, KICK, h_vel(100))
writer.add_note(h_time(bt + 2 * PPQ), SIXTEENTH * 3, ch, KICK, h_vel(110))
# Acorde final
ft = (current_bar - 1) * BAR
writer.add_note(h_time(ft), PPQ * 4, ch, CRASH_1, h_vel(124))
writer.add_note(h_time(ft), PPQ * 4, ch, KICK, h_vel(120))
writer.save("Hossana_Marco_Barrientos_Bateria.mid")
print("Archivo Hossana_Marco_Barrientos_Bateria.mid generado exitosamente.")
To embed this project on your website, copy the following code and paste it into your website's HTML: