2 sekmeden oluşan uygulamam size hem müzik çalmanızı hem de resim çizmenizi sağlıyor. Bu uygulama bi html dosyası üzerinden size ya programlanmış ses dizisi verir ya da programlanmış resim matrisi.
Uygulamayı kendi bilgisayarınızda çalıştırmak için ilk önce bir Spigot / Bukkit sunucunuz olması gerekir. (https://www.spigotmc.org/) bu siteden gerekli makaleleri okuyarak kendinize bir tane edinebilirsiniz. Bu sunucu lokalde de çalışabilir, globalde de sizin ihtiyacınız olan RCON kullanıcı adı ve şifresidir. RCON Spigot / Bukkit sunucularında bulunan özel bir komut gönderme protokolüdür. RCON kullanarak 3. taraf uygulamalarla sunucuya komut göndermeyi mümkün kılar. İşte tam da bu anda bu dönüştürücü/gönderici scriptleri devreye giriyor. Dönüştürücü web uygulaması sizin MIDI dosyanızdan veya resim dosyanızdan elde edilen bilgilerle dizi oluştururlar. Bu dizileri python scriptine girdiğinizde MCRCON (https://pypi.org/project/mcrcon/) kütüphanesi sunucuya uygun komutları gönderek müziğinizin ve resminizin oluşmasını sağlar.
MIDI çalarken python scripti ile aynı dizinde 'music.txt' diye bir dosya oluşturup müzik dizinizi içine yapıştırmanız gerekmektedir.
(Scriptte RCON Sunucu IP'sini ve şifresini değiştirebilirsiniz. Kendi sunucunuzun RCON ip ve şifrenizi 'server.properties' dosyasından öğrenip, değiştirebilirsiniz. Mevcut scriptte default olarak 127.0.0.1 ve 12345 kullanıldı.)
Daha önceki yazılarımda bu uygulamanın sadece resimle çalışan halini yapmıştım. O uygulama sadece tek Minecraft sürümüne bağlıyken bu uygulama daha dinamik bir yapı sunmakta. RCON sunucusu açılabilen her sürümde çalışmaktadır.
pip install mcrcon
from mcrcon import MCRcon
import time
import ast
import os
import threading
from collections import defaultdict
sunucuIP = "127.0.0.1"
sunucuPASS = "12345"
blok = 'minecraft:redstone_block'
# RCON bağlantısı için thread lock
rcon_lock = threading.Lock()
# Her enstrüman için farklı Y koordinatları
INSTRUMENT_Y = {
'harp': 57, # Herhangi bir blok
'bass': 60, # Oak planks
'bell': 63, # Gold block
'flute': 66, # Clay
'chime': 69, # Packed ice
'guitar': 72, # White wool
'xylophone': 75 # Bone block
}
# Her enstrüman için nota koordinatları
NOTA_Z_KOORDS = {
'harp': {
'fad1': 1, 'sol1': 2, 'sold1': 3, 'la1': 4, 'lad1': 5, 'si1': 6,
'do2': 7, 'dod2': 8, 're2': 9, 'red2': 10, 'mi2': 11, 'fa2': 12,
'fad2': 13, 'sol2': 14, 'sold2': 15, 'la2': 16, 'lad2': 17, 'si2': 18,
'do3': 19, 'dod3': 20, 're3': 21, 'red3': 22, 'mi3': 23, 'fa3': 24, 'fad3': 25
},
'bass': {
'fad0': 1, 'sol0': 2, 'sold0': 3, 'la0': 4, 'lad0': 5, 'si0': 6,
'do1': 7, 'dod1': 8, 're1': 9, 'red1': 10, 'mi1': 11, 'fa1': 12,
'fad1': 13, 'sol1': 14, 'sold1': 15, 'la1': 16, 'lad1': 17, 'si1': 18,
'do2': 19, 'dod2': 20, 're2': 21, 'red2': 22, 'mi2': 23, 'fa2': 24, 'fad2': 25
},
'bell': {
'fad3': 1, 'sol3': 2, 'sold3': 3, 'la3': 4, 'lad3': 5, 'si3': 6,
'do4': 7, 'dod4': 8, 're4': 9, 'red4': 10, 'mi4': 11, 'fa4': 12,
'fad4': 13, 'sol4': 14, 'sold4': 15, 'la4': 16, 'lad4': 17, 'si4': 18,
'do5': 19, 'dod5': 20, 're5': 21, 'red5': 22, 'mi5': 23, 'fa5': 24, 'fad5': 25
},
'flute': {
'fad2': 1, 'sol2': 2, 'sold2': 3, 'la2': 4, 'lad2': 5, 'si2': 6,
'do3': 7, 'dod3': 8, 're3': 9, 'red3': 10, 'mi3': 11, 'fa3': 12,
'fad3': 13, 'sol3': 14, 'sold3': 15, 'la3': 16, 'lad3': 17, 'si3': 18,
'do4': 19, 'dod4': 20, 're4': 21, 'red4': 22, 'mi4': 23, 'fa4': 24, 'fad4': 25
},
'chime': {
'fad3': 1, 'sol3': 2, 'sold3': 3, 'la3': 4, 'lad3': 5, 'si3': 6,
'do4': 7, 'dod4': 8, 're4': 9, 'red4': 10, 'mi4': 11, 'fa4': 12,
'fad4': 13, 'sol4': 14, 'sold4': 15, 'la4': 16, 'lad4': 17, 'si4': 18,
'do5': 19, 'dod5': 20, 're5': 21, 'red5': 22, 'mi5': 23, 'fa5': 24, 'fad5': 25
},
'guitar': {
'fad1': 1, 'sol1': 2, 'sold1': 3, 'la1': 4, 'lad1': 5, 'si1': 6,
'do2': 7, 'dod2': 8, 're2': 9, 'red2': 10, 'mi2': 11, 'fa2': 12,
'fad2': 13, 'sol2': 14, 'sold2': 15, 'la2': 16, 'lad2': 17, 'si2': 18,
'do3': 19, 'dod3': 20, 're3': 21, 'red3': 22, 'mi3': 23, 'fa3': 24, 'fad3': 25
},
'xylophone': {
'fad3': 1, 'sol3': 2, 'sold3': 3, 'la3': 4, 'lad3': 5, 'si3': 6,
'do4': 7, 'dod4': 8, 're4': 9, 'red4': 10, 'mi4': 11, 'fa4': 12,
'fad4': 13, 'sol4': 14, 'sold4': 15, 'la4': 16, 'lad4': 17, 'si4': 18,
'do5': 19, 'dod5': 20, 're5': 21, 'red5': 22, 'mi5': 23, 'fa5': 24, 'fad5': 25
}
}
def muzik_yukle(dosya_adi='music.txt'):
"""music.txt dosyasından müzik dizisini yükle"""
try:
script_dir = os.path.dirname(os.path.abspath(__file__))
dosya_yolu = os.path.join(script_dir, dosya_adi)
if not os.path.exists(dosya_yolu):
print(f"❌ Hata: {dosya_adi} dosyası bulunamadı!")
print(f"📁 Aranan konum: {dosya_yolu}")
print(f"💡 Çözüm: music.txt dosyasını şu konuma kaydedin: {script_dir}")
try:
dosyalar = os.listdir(script_dir)
print(f"\n📂 Mevcut dizindeki dosyalar:")
for d in dosyalar:
print(f" - {d}")
except:
pass
return []
with open(dosya_yolu, 'r', encoding='utf-8') as f:
icerik = f.read()
# "music = [" ile başlıyorsa, sadece liste kısmını al
if 'music = [' in icerik:
baslangic = icerik.find('[')
bitis = icerik.rfind(']') + 1
liste_str = icerik[baslangic:bitis]
else:
liste_str = icerik
# String'i Python listesine çevir
music = ast.literal_eval(liste_str)
# Format kontrolü - yeni format (zaman, nota, enstruman)
if music and len(music[0]) == 3 and isinstance(music[0][0], (int, float)):
print(f"✅ {len(music)} nota yüklendi (mutlak zamanlama)")
else:
print(f"❌ Hata: Geçersiz müzik formatı!")
print(f"💡 Format: (zaman_saniye, nota, enstruman)")
return []
return music
except FileNotFoundError:
print(f"❌ Hata: {dosya_adi} dosyası bulunamadı!")
return []
except Exception as e:
print(f"❌ Müzik dosyası okunurken hata: {e}")
return []
def nota_cal(note_name, instrument, mcr):
"""Belirtilen enstrüman ve notayı çal"""
y_coord = INSTRUMENT_Y.get(instrument)
z_coord = NOTA_Z_KOORDS.get(instrument, {}).get(note_name)
if y_coord is None or z_coord is None:
return
try:
with rcon_lock:
cmd = f'setblock 0 {y_coord} {z_coord} {blok}'
mcr.command(cmd)
time.sleep(0.05)
cmd = f'setblock 0 {y_coord} {z_coord} air'
mcr.command(cmd)
except Exception as e:
print(f"Hata ({note_name}/{instrument}): {e}")
def muzik_cal(melody, mcr):
"""Müziği polifonik olarak çalar - mutlak zamanlama ile"""
if not melody:
return
# Zamanı aynı olan notaları grupla (20ms tolerans)
nota_gruplari = defaultdict(list)
for zaman, note, instrument in melody:
zaman_anahtari = round(zaman * 50) / 50 # 20ms hassasiyet
nota_gruplari[zaman_anahtari].append((note, instrument))
# Sıralı zamanları al
zamanlar = sorted(nota_gruplari.keys())
baslangic = time.time()
for hedef_zaman in zamanlar:
# Hedef zamana kadar bekle
simdiki_zaman = time.time() - baslangic
bekleme = hedef_zaman - simdiki_zaman
if bekleme > 0:
time.sleep(bekleme)
# Bu zamandaki tüm notaları paralel çal
notalar = nota_gruplari[hedef_zaman]
if len(notalar) > 1:
# Birden fazla nota varsa thread'lerle paralel çal
threads = []
for note, instrument in notalar:
t = threading.Thread(target=nota_cal, args=(note, instrument, mcr))
t.start()
threads.append(t)
# Tüm notaların çalmasını bekle
for t in threads:
t.join()
else:
# Tek nota
note, instrument = notalar[0]
nota_cal(note, instrument, mcr)
# Ana program
if __name__ == "__main__":
music = muzik_yukle('music.txt')
if not music:
print("Müzik yüklenemedi, program sonlandırılıyor...")
exit()
try:
with MCRcon(sunucuIP, sunucuPASS) as mcr:
print("🎵 Müzik çalıyor... (Durdurmak için Ctrl+C)")
time.sleep(2)
muzik_cal(music, mcr)
print("Müzik bitti.")
except KeyboardInterrupt:
print("\n⏹️ Müzik durduruldu!")
except Exception as e:
print(f"❌ Bağlantı hatası: {e}")
from mcrcon import MCRcon
import time
sunucuIP = "127.0.0.1"
sunucuPASS = "12345"
resim_matrisi = [] # Matrisi buraya yapıştıracaksınız.
# Buradaki blokları kendi istediğiniz gibi deeğiştirebilirsiniz.
# Ancak web uygulama buradaki sıralamaya göre renkler üretecektir. Buna dikkat edin.
RENKLI_BLOKLAR = {
1: "minecraft:white_concrete_powder",
2: "minecraft:light_gray_concrete_powder",
3: "minecraft:gray_concrete_powder",
4: "minecraft:black_concrete_powder",
5: "minecraft:brown_concrete_powder",
6: "minecraft:red_concrete_powder",
7: "minecraft:orange_concrete_powder",
8: "minecraft:yellow_concrete_powder",
9: "minecraft:lime_concrete_powder",
10: "minecraft:green_concrete_powder",
11: "minecraft:cyan_concrete_powder",
12: "minecraft:light_blue_concrete_powder",
13: "minecraft:blue_concrete_powder",
14: "minecraft:purple_concrete_powder",
15: "minecraft:magenta_concrete_powder",
16: "minecraft:pink_concrete_powder",
}
with MCRcon(sunucuIP, sunucuPASS) as mcr:
cmd = f'fill -20 57 32 -20 88 1 air'
mcr.command(cmd)
cmd = f'fill -20 56 32 -20 56 1 minecraft:stone'
mcr.command(cmd)
x = 32
y = 57
z = 0
for i in range(0, 32):
for i in range (0, 32):
blok_sirasi = resim_matrisi[z]
blok = RENKLI_BLOKLAR.get(blok_sirasi)
cmd = f'setblock -20 {y} {x} {blok}'
mcr.command(cmd)
x -= 1
z += 1
time.sleep(0.001)
x = 32
y += 1
time.sleep(0.01)