MEMBUAT APPLIKASI PARTITUR NOTASI ANGKA KE AUDIO (Part-2)
Kenapa pada output_text atau partitur tidak ada semacam highlight atau garis lurus tegak yang menandakan baris nada sedang dibaca dan di "run" pada sebuah nada di mana penanda tersebut berada
Untuk menampilkan highlight atau garis tegak yang menandakan baris nada sedang dibaca (misalnya, seperti cursor atau indikator pemutaran audio), Anda memerlukan cara untuk secara visual menghubungkan posisi nada yang sedang dimainkan dengan teks atau notasi partitur di antarmuka Anda.
Langkah-langkah berikut dapat membantu menambahkan fitur ini:
1. Sinkronisasi Waktu dengan Audio
Ketika audio diputar, Anda harus menghitung durasi setiap nada berdasarkan panjang audionya. Dengan mengetahui durasi tiap nada, Anda bisa memperkirakan kapan highlight atau garis harus berpindah ke nada berikutnya.
Jika Anda menggunakan tkinter untuk GUI, gunakan fungsi seperti after() untuk memperbarui tampilan berdasarkan waktu pemutaran.
2. Menambahkan Highlight ke Teks di tkinter
Misalnya, jika Anda menggunakan tkinter Text widget untuk menampilkan teks partitur, Anda bisa menggunakan fitur tag untuk menyorot atau menandai teks tertentu sebagai "highlight". Berikut adalah contoh dasar tentang bagaimana Anda bisa menerapkannya:
import tkinter as tk
from tkinter import Text
def highlight_nada(posisi_awal, posisi_akhir):
# Hapus highlight sebelumnya
text_area.tag_remove("highlight", "1.0", "end")
# Tambahkan highlight baru
text_area.tag_add("highlight", posisi_awal, posisi_akhir)
text_area.tag_config("highlight", background="yellow")
# Fungsi yang mensimulasikan pemutaran nada
def play_nada():
nada_list = ['1', '2', '3', '4', '5', '6', '7']
for i, nada in enumerate(nada_list):
# Highlight satu per satu
posisi_awal = f"1.{i * 2}"
posisi_akhir = f"1.{i * 2 + 1}"
highlight_nada(posisi_awal, posisi_akhir)
# Tunggu sejenak sebelum lanjut ke nada berikutnya
root.after(1000 * i)
root = tk.Tk()
text_area = Text(root)
text_area.pack()
# Isi text area dengan partitur sederhana
text_area.insert("1.0", "1 2 3 4 5 6 7")
# Panggil fungsi untuk memainkan nada dengan highlight
root.after(1000, play_nada)
root.mainloop()
3. Menggerakkan Garis Vertikal
Jika Anda lebih suka garis vertikal (misalnya di layar yang menandai posisi pemutaran), Anda bisa membuatnya dengan tkinter menggunakan Canvas widget atau Label. Garis tersebut bisa dipindahkan setiap kali nada berpindah.
4. Menggunakan Event Loop
Jika nada dimainkan menggunakan Pydub, Anda dapat menggunakan loop event yang sinkron dengan durasi masing-masing nada, kemudian memperbarui GUI untuk menunjukkan bahwa nada tertentu sedang dimainkan.
Berikut adalah langkah dasar yang bisa diterapkan untuk menandakan posisi pemutaran. Apakah Anda menggunakan tkinter atau GUI lain, implementasinya bisa disesuaikan.
Apakah kode isi file simbol_dan_partitur.py berikut sudah benar atau masih salah:
import tkinter as tk
from tkinter import Menu, filedialog, simpledialog, messagebox, Frame, Label, Entry, Button
from tkinter import Text
import os
import time
from pydub import AudioSegment
from pydub.playback import play
from peta_nada import petakan_notasi_ke_audio
def highlight_nada(posisi_awal, posisi_akhir):
# Hapus highlight sebelumnya
text_area.tag_remove("highlight", "1.0", "end")
# Tambahkan highlight baru
text_area.tag_add("highlight", posisi_awal, posisi_akhir)
text_area.tag_config("highlight", background="yellow")
# Fungsi yang mensimulasikan pemutaran nada
def play_nada():
nada_list = output_text.get("1.0", tk.END).strip().split()
for i, nada in enumerate(nada_list):
# Highlight satu per satu
posisi_awal = f"1.{i * 2}"
posisi_akhir = f"1.{i * 2 + 1}"
highlight_nada(posisi_awal, posisi_akhir)
# Tunggu sejenak sebelum lanjut ke nada berikutnya
root.after(1000 * i)
# Setup UI
root = tk.Tk()
root.geometry("690x1390")
root.title("Partitur Notasi Angka Ke Audio")
# Membuat canvas untuk konten partitur
output_text_canvas = tk.Canvas(root, width=800, height=600)
output_text_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Membuat frame untuk konten di dalam canvas
output_frame = tk.Frame(output_text_canvas)
output_text_canvas.create_window((0, 0), window=output_frame, anchor="nw")
# Pastikan output_text_canvas didefinisikan sebelum diakses
output_text_canvas = tk.Canvas(output_frame)
partitur_frame = Frame(root)
partitur_frame.pack(padx=10, pady=10, fill="both", expand=True)
# Fungsi untuk memasukkan simbol notasi yang dipilih ke partitur
def insert_symbol(symbol):
output_text.insert(tk.INSERT, symbol)
# Simbol notasi yang akan digunakan (tambahkan nada panjang satu, dua, dan tiga ketuk)
symbol_options = [
"\u135E", "\u135F", "\u135D", "\u1A18", "\u0324", "\u1CDF",
"•", "••", "•••", "\u007C", "\u20E6", ":||", "/", "\\", "'",
"0", "♯", "♭", "\u2323", "\u0305", "\u0818", "\u07EB", "\u266D", "\u203F", "\u3022", "\u2503", "\u2595", "\u0821", "\u2191", "\u2193" # Nada panjang satu, dua, dan tiga ketuk
]
# Membuat kotak untuk tombol simbol notasi
symbol_frame = tk.Frame(output_frame)
symbol_frame.grid(row=0, column=0, pady=5, sticky= "w")
# Label instruksi simbol
symbol_label = tk.Label(symbol_frame, text="Simbol Notasi Angka:")
symbol_label.grid(row=0, column=0, columnspan=6, pady=(0, 5))
# Loop untuk membuat tombol untuk setiap simbol
for i, symbol in enumerate(symbol_options):
button = tk.Button(symbol_frame, text=symbol, width=2, command=lambda s=symbol: insert_symbol(s))
button.grid(row=1 + i // 10, column=i % 10, padx=5, pady=5)
# Label instruksi di atas output_text
instruksi_label = tk.Label(output_frame, fg="tomato", text="Partitur Notasi Angka (Edit di bawah sini):")
instruksi_label.grid(row=1, column=0, padx=5, pady=5)
# Membuat Text Widget untuk output
output_text = tk.Text(output_frame, wrap=tk.WORD, undo=True, width=80, height=18, font=("Courier", 10))
output_text.grid(row=4, column=0, columnspan=3, padx=10, pady=10)
text_area = output_text
# Isi text area dengan partitur sederhana
text_area.insert("1.0", "")
# Panggil fungsi untuk memainkan nada dengan highlight
root.after(1000, play_nada)
# Menambahkan tombol untuk notasi angka biasa (tanpa garis di atas)
button_1 = tk.Button(symbol_frame, text="1", width=3, command=lambda: insert_symbol("1"))
button_1.grid(row=5, column=0, padx=5, pady=5)
button_2 = tk.Button(symbol_frame, text="2", width=3, command=lambda: insert_symbol("2"))
button_2.grid(row=5, column=1, padx=5, pady=5)
button_3 = tk.Button(symbol_frame, text="3", width=3, command=lambda: insert_symbol("3"))
button_3.grid(row=5, column=2, padx=5, pady=5)
button_4 = tk.Button(symbol_frame, text="4", width=3, command=lambda: insert_symbol("4"))
button_4.grid(row=5, column=3, padx=5, pady=5)
button_5 = tk.Button(symbol_frame, text="5", width=3, command=lambda: insert_symbol("5"))
button_5.grid(row=5, column=4, padx=5, pady=5)
button_6 = tk.Button(symbol_frame, text="6", width=3, command=lambda: insert_symbol("6"))
button_6.grid(row=5, column=5, padx=5, pady=5)
button_7 = tk.Button(symbol_frame, text="7", width=3, command=lambda: insert_symbol("7"))
button_7.grid(row=5, column=6, padx=5, pady=5)
# Menambahkan tombol simbol untuk notasi angka dengan garis di atas (1/2 ketuk)
button_1_garis_atas = tk.Button(symbol_frame, text="1\u0305", width=3, command=lambda: insert_symbol("1\u0305"))
button_1_garis_atas.grid(row=6, column=0, padx=5, pady=5)
button_2_garis_atas = tk.Button(symbol_frame, text="2\u0305", width=3, command=lambda: insert_symbol("2\u0305"))
button_2_garis_atas.grid(row=6, column=1, padx=5, pady=5)
button_3_garis_atas = tk.Button(symbol_frame, text="3\u0305", width=3, command=lambda: insert_symbol("3\u0305"))
button_3_garis_atas.grid(row=6, column=2, padx=5, pady=5)
button_4_garis_atas = tk.Button(symbol_frame, text="4\u0305", width=3, command=lambda: insert_symbol("4\u0305"))
button_4_garis_atas.grid(row=6, column=3, padx=5, pady=5)
button_5_garis_atas = tk.Button(symbol_frame, text="5\u0305", width=3, command=lambda: insert_symbol("5\u0305"))
button_5_garis_atas.grid(row=6, column=4, padx=5, pady=5)
button_6_garis_atas = tk.Button(symbol_frame, text="6\u0305", width=3, command=lambda: insert_symbol("6\u0305"))
button_6_garis_atas.grid(row=6, column=5, padx=5, pady=5)
button_7_garis_atas = tk.Button(symbol_frame, text="7\u0305", width=3, command=lambda: insert_symbol("7\u0305"))
button_7_garis_atas.grid(row=6, column=6, padx=5, pady=5)
# Fungsi untuk memainkan audio berdasarkan notasi di output_text
def mainkan_audio():
# Mengambil teks dari output_text dan membaginya menjadi daftar simbol
notasi = output_text.get("1.0", tk.END).strip().split()
if notasi:
try:
# Memetakan notasi ke audio dan menggabungkannya
hasil_audio = petakan_notasi_ke_audio(notasi)
# Memainkan audio hasil gabungan
play(hasil_audio)
except Exception as e:
messagebox.showerror("Error", f"Terjadi kesalahan saat memproses audio: {e}")
else:
messagebox.showwarning("Peringatan", "Tidak ada notasi yang dimasukkan.")
# Fungsi untuk menyimpan partitur ke file teks
def simpan_partitur():
file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
if file_path:
with open(file_path, 'w') as f:
f.write(output_text.get("1.0", tk.END))
messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")
# Fungsi untuk memuat partitur dari file teks
def muat_partitur():
file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])
if file_path:
with open(file_path, 'r') as f:
partitur = f.read()
output_text.delete("1.0", tk.END)
output_text.insert(tk.INSERT, partitur)
# Atur frame untuk tombol di baris yang sama
button_frame = tk.Frame(output_frame)
button_frame.grid(row=2, column=0, sticky="w", columnspan=2, pady=(10, 0)) # Di atas partitur dan gunakan columnspan agar tombol berada di tengah
# Tambahkan tombol-tombol ke dalam frame
mainkan_button = tk.Button(button_frame, text="Mainkan", bg="purple", fg="white", command= mainkan_audio)
mainkan_button.grid(row=0, column=0, padx=5)
simpan_button = tk.Button(button_frame, text="Simpan", bg="purple", fg="white", command= simpan_partitur)
simpan_button.grid(row=0, column=1, padx=5)
muat_button = tk.Button(button_frame, text="Buka", bg="purple", fg="white", command= muat_partitur)
muat_button.grid(row=0, column=2, padx=5)
# Menjalankan UI
root.mainloop()
Melihat kode yang kamu berikan, secara umum, struktur program sudah benar dan sudah memadai untuk menampilkan partitur dan simbol serta mengelola highlight nada saat diputar. Namun, terdapat beberapa masalah yang dapat diperbaiki untuk memastikan highlight bekerja dengan benar dan beberapa bagian lain berfungsi seperti yang diharapkan:
1. Masalah Highlight:
Di bagian highlight_nada, posisi_awal dan posisi_akhir dihitung berdasarkan jumlah karakter. Kamu menghitung posisi berdasarkan index i * 2 dan i * 2 + 1, yang mungkin tidak sesuai dengan posisi sebenarnya dalam teks. Sebaiknya gunakan cara yang lebih tepat untuk menghitung posisi highlight berdasarkan posisi simbol dalam teks.
Untuk memperbaiki ini, kamu bisa menggunakan metode text.search() untuk menemukan simbol yang akan di-highlight, bukan menghitung posisi berdasarkan urutan.
Misalnya:
posisi_awal = text_area.search(nada, "1.0", tk.END)
if posisi_awal:
posisi_akhir = f"{posisi_awal}+{len(nada)}c"
highlight_nada(posisi_awal, posisi_akhir)
2. Logika Pemutaran Nada (Delay):
Fungsi play_nada hanya melakukan highlight secara bertahap dengan jeda waktu, namun sebaiknya ditambahkan pengulangan root.after() pada setiap nada, bukan mengalikan waktu berdasarkan index i seperti yang ada saat ini. Sebaiknya panggil fungsi secara berulang menggunakan root.after() dalam loop yang lebih terorganisir untuk setiap nada.
Misalnya:
def play_nada(i=0):
nada_list = output_text.get("1.0", tk.END).strip().split()
if i < len(nada_list):
nada = nada_list[i]
posisi_awal = text_area.search(nada, "1.0", tk.END)
if posisi_awal:
posisi_akhir = f"{posisi_awal}+{len(nada)}c"
highlight_nada(posisi_awal, posisi_akhir)
# Pemutaran suara (opsional)
root.after(1000, play_nada, i + 1) # Delay 1 detik per nada
3. Ukuran Window output_text_canvas:
Di awal kode, output_text_canvas didefinisikan dua kali, ini dapat dihapus untuk menghindari kebingungan. Hanya gunakan satu definisi output_text_canvas.
4. Pemutaran Audio:
Pastikan file peta_nada.py sudah diatur dengan benar untuk memetakan notasi ke audio. Kamu mungkin ingin memastikan bahwa pemetaan ini sesuai dengan simbol yang digunakan.
5. Tampilan Simbol:
Kamu sudah menggunakan beberapa simbol unicode untuk notasi. Jika simbol-simbol ini tidak ditampilkan dengan benar di Text widget, coba pastikan bahwa font yang digunakan mendukung unicode tersebut. Kamu bisa menggunakan font yang lebih sesuai seperti "Arial Unicode MS" untuk memastikan kompatibilitas simbol.
Jika semua hal ini diperbaiki, highlight dan pemutaran notasi akan berjalan dengan lebih baik dan sesuai harapan.
Tolong perbaiki kode isi file peta_nada.py berikut:
import tkinter as tk
from tkinter import Menu, filedialog, simpledialog, messagebox, Frame, Label, Entry, Button
import os
import time
from pydub import AudioSegment
from pydub.playback import play
from pydub import AudioSegment
AudioSegment.ffmpeg = "/storage/emulated/0/proyekku/PanotanKeAudio/ffmpeg-7.1/"
# Folder tempat file sampel nada berada
folder_nada = '/storage/emulated/0/proyekku/PanotanKeAudio/sampel_nada/'
def petakan_notasi_ke_audio(notasi):
audio_segments = []
for simbol in notasi:
if simbol == '6\u0324' or simbol == '6-2':
file_nada = 'piano_A2.wav'
elif simbol == '7\u0324' or simbol == '7-2':
file_nada = 'piano_B2.wav'
elif simbol == '1\u1A18' or simbol == '1-1':
file_nada = 'piano_C3.wav' # Nada C3 (1 rendah satu oktaf)
elif simbol == '2\u1A18' or simbol == '2-1':
file_nada = 'piano_D3.wav'
elif simbol == '3\u1A18' or simbol == '3-1':
file_nada = 'piano_E3.wav'
elif simbol == '4\u1A18' or simbol == '4-1':
file_nada = 'piano_F3.wav'
elif simbol == '5\u1A18' or simbol == '5-1':
file_nada = 'piano_G3.wav'
elif simbol == '6\u1A18' or simbol == '6-1':
file_nada = 'piano_A3.wav' # Nada A3 (6 rendah satu oktaf)
elif simbol == '7\u1A18' or simbol == '7-1':
file_nada = 'piano_B3.wav'
elif simbol == '1' or simbol == '10':
file_nada = 'piano_C4.wav' # Nada C4 (1 di oktaf tengah)
elif simbol == '2' or simbol == '20':
file_nada = 'piano_D4.wav'
elif simbol == '3' or simbol == '30':
file_nada = 'piano_E4.wav'
elif simbol == '4' or simbol == '40':
file_nada = 'piano_F4.wav'
elif simbol == '5' or simbol == '50':
file_nada = 'piano_G4.wav'
elif simbol == '6' or simbol == '60':
file_nada = 'piano_A4.wav' # Nada A4 (6 di oktaf tengah)
elif simbol == '7' or simbol == '70':
file_nada = 'piano_B4.wav'
elif simbol == '1\u135E' or simbol == '11':
file_nada = 'piano_C5.wav' # Nada C5 (1 tinggi satu oktaf)
elif simbol == '2\u135E' or simbol == '21':
file_nada = 'piano_D5.wav'
elif simbol == '3\u135E' or simbol == '31':
file_nada = 'piano_E5.wav'
elif simbol == '4\u135E' or simbol == '41':
file_nada = 'piano_F5.wav'
elif simbol == '5\u135E' or simbol == '51':
file_nada = 'piano_G5.wav'
elif simbol == '6\u135E' or simbol == '61':
file_nada = 'piano_A5.wav' # Nada A5 (6 tinggi satu oktaf)
elif simbol == '7\u135E' or simbol == '71':
file_nada = 'piano_B5.wav'
elif simbol == '1\u135F' or simbol == '12':
file_nada = 'piano_C6.wav'
elif simbol == '2\u135F' or simbol == '22':
file_nada = 'piano_D6.wav'
elif simbol == '3\u135F' or simbol == '32':
file_nada = 'piano_E6.wav'
elif simbol == '4\u135F' or simbol == '42':
file_nada = 'piano_F6.wav'
elif simbol == '5\u135F' or simbol == '52':
file_nada = 'piano_G6.wav'
elif simbol == '6\u135F' or simbol == '62':
file_nada = 'piano_A6.wav'
elif simbol == '7\u135F' or simbol == '72':
file_nada = 'piano_B6.wav'
elif simbol == '1\u135D' or simbol == '13':
file_nada = 'piano_C7.wav'
elif simbol == '1#':
file_nada = 'piano_C4_sharp.wav',
elif simbol == '2b':
file_nada = 'piano_D4_flat.wav'
elif simbol == 'r': 'rest.wav'
audio_segments.append(file_nada)
return audio_segments # Mengembalikan daftar file audio yang terpetakan
# Objek AudioSegment untuk gabungan audio
hasil_audio = AudioSegment.silent(duration=0)
# Loop untuk setiap simbol
for simbol in simbol_list:
file_nada = None
if simbol.endswith('#'):
file_nada = peta_nada.get(simbol[0] + '#') # Tangani sharp
elif simbol.endswith('b'):
file_nada = peta_nada.get(simbol[0] + 'b') # Tangani flat
elif simbol == 'r':
hasil_audio += AudioSegment.silent(duration=500) # Jeda 500ms
continue
else:
file_nada = peta_nada.get(simbol)
if not file_nada:
messagebox.showerror("Notasi Error", f"Simbol '{simbol}' tidak dikenali.")
return None
file_path = os.path.join(folder_nada, file_nada)
try:
audio_segment = AudioSegment.from_wav(file_path)
hasil_audio += audio_segment
except Exception as e:
messagebox.showerror("File Error", f"Terjadi kesalahan saat memuat file '{file_nada}': {str(e)}")
return None
# Ekspor hasil gabungan audio ke file WAV
hasil_audio.export("output_audio.wav", format="wav")
return hasil_audio
Ada beberapa hal yang bisa diperbaiki dalam kode tersebut agar lebih baik dalam logika dan penanganan error. Beberapa perbaikan yang dilakukan adalah:
1. Memastikan simbol rest berfungsi dengan benar.
2. Penambahan penggabungan audio setelah daftar file audio terbentuk.
3. Memperbaiki pengelolaan file audio agar tidak terjadi kesalahan penanganan path.
4. Perbaikan beberapa kesalahan logika pada pengisian file_nada.
Berikut adalah versi perbaikan dari kode tersebut:
import tkinter as tk
from tkinter import Menu, filedialog, simpledialog, messagebox, Frame, Label, Entry, Button
import os
import time
from pydub import AudioSegment
from pydub.playback import play
AudioSegment.ffmpeg = "/storage/emulated/0/proyekku/PanotanKeAudio/ffmpeg-7.1/"
# Folder tempat file sampel nada berada
folder_nada = '/storage/emulated/0/proyekku/PanotanKeAudio/sampel_nada/'
def petakan_notasi_ke_audio(notasi):
audio_segments = []
for simbol in notasi:
if simbol == '6\u0324' or simbol == '6-2':
file_nada = 'piano_A2.wav'
elif simbol == '7\u0324' or simbol == '7-2':
file_nada = 'piano_B2.wav'
elif simbol == '1\u1A18' or simbol == '1-1':
file_nada = 'piano_C3.wav' # Nada C3 (1 rendah satu oktaf)
elif simbol == '2\u1A18' or simbol == '2-1':
file_nada = 'piano_D3.wav'
elif simbol == '3\u1A18' or simbol == '3-1':
file_nada = 'piano_E3.wav'
elif simbol == '4\u1A18' or simbol == '4-1':
file_nada = 'piano_F3.wav'
elif simbol == '5\u1A18' or simbol == '5-1':
file_nada = 'piano_G3.wav'
elif simbol == '6\u1A18' or simbol == '6-1':
file_nada = 'piano_A3.wav' # Nada A3 (6 rendah satu oktaf)
elif simbol == '7\u1A18' or simbol == '7-1':
file_nada = 'piano_B3.wav'
elif simbol == '1' or simbol == '10':
file_nada = 'piano_C4.wav' # Nada C4 (1 di oktaf tengah)
elif simbol == '2' or simbol == '20':
file_nada = 'piano_D4.wav'
elif simbol == '3' or simbol == '30':
file_nada = 'piano_E4.wav'
elif simbol == '4' or simbol == '40':
file_nada = 'piano_F4.wav'
elif simbol == '5' or simbol == '50':
file_nada = 'piano_G4.wav'
elif simbol == '6' or simbol == '60':
file_nada = 'piano_A4.wav' # Nada A4 (6 di oktaf tengah)
elif simbol == '7' or simbol == '70':
file_nada = 'piano_B4.wav'
elif simbol == '1\u135E' or simbol == '11':
file_nada = 'piano_C5.wav' # Nada C5 (1 tinggi satu oktaf)
elif simbol == '2\u135E' or simbol == '21':
file_nada = 'piano_D5.wav'
elif simbol == '3\u135E' or simbol == '31':
file_nada = 'piano_E5.wav'
elif simbol == '4\u135E' or simbol == '41':
file_nada = 'piano_F5.wav'
elif simbol == '5\u135E' or simbol == '51':
file_nada = 'piano_G5.wav'
elif simbol == '6\u135E' or simbol == '61':
file_nada = 'piano_A5.wav' # Nada A5 (6 tinggi satu oktaf)
elif simbol == '7\u135E' or simbol == '71':
file_nada = 'piano_B5.wav'
elif simbol == '1\u135F' or simbol == '12':
file_nada = 'piano_C6.wav'
elif simbol == '2\u135F' or simbol == '22':
file_nada = 'piano_D6.wav'
elif simbol == '3\u135F' or simbol == '32':
file_nada = 'piano_E6.wav'
elif simbol == '4\u135F' or simbol == '42':
file_nada = 'piano_F6.wav'
elif simbol == '5\u135F' or simbol == '52':
file_nada = 'piano_G6.wav'
elif simbol == '6\u135F' or simbol == '62':
file_nada = 'piano_A6.wav'
elif simbol == '7\u135F' or simbol == '72':
file_nada = 'piano_B6.wav'
elif simbol == '1\u135D' or simbol == '13':
file_nada = 'piano_C7.wav'
elif simbol == '1#':
file_nada = 'piano_C4_sharp.wav'
elif simbol == '2b':
file_nada = 'piano_D4_flat.wav'
elif simbol == 'r': # Simbol istirahat (rest)
audio_segments.append(AudioSegment.silent(duration=500)) # Jeda 500ms
continue # Lewati penambahan file untuk simbol 'r'
# Menambahkan file audio yang dipetakan ke daftar
file_path = os.path.join(folder_nada, file_nada)
try:
audio_segment = AudioSegment.from_wav(file_path)
audio_segments.append(audio_segment)
except Exception as e:
messagebox.showerror("File Error", f"Terjadi kesalahan saat memuat file '{file_nada}': {str(e)}")
return None
# Menggabungkan segmen audio menjadi satu file
hasil_audio = sum(audio_segments)
# Ekspor hasil gabungan audio ke file WAV
output_file = os.path.join(folder_nada, "output_audio.wav")
hasil_audio.export(output_file, format="wav")
return hasil_audio
Penjelasan perubahan:
1. Simbol rest (r): Sekarang simbol == 'r' menangani jeda 500ms tanpa mencoba memetakan file nada untuk simbol tersebut.
2. Penggabungan audio: Menggunakan sum(audio_segments) untuk menggabungkan semua segmen audio yang berhasil dimuat.
3. Pengelolaan file audio: file_path diatur dengan benar untuk setiap segmen berdasarkan folder dan nama file yang sesuai.
4. Penanganan error: Jika terjadi kesalahan saat memuat file WAV, pesan kesalahan akan muncul melalui messagebox dan fungsi akan dihentikan.
Coba jalankan kembali kode ini, dan pastikan file WAV yang disebutkan ada di lokasi yang tepat untuk pengujian hasilnya.
Tolong hasilkan audionya menggunakan pygame dengan kode isi file simbol_dan_partitur.py berikut:
import tkinter as tk
from tkinter import messagebox
import pygame
from peta_nada import petakan_notasi_ke_audio
# Setup UI
root = tk.Tk()
root.geometry("800x600")
root.title("Partitur Notasi Angka Ke Audio")
# Fungsi untuk memasukkan simbol notasi yang dipilih ke partitur
def insert_symbol(symbol):
output_text.insert(tk.INSERT, symbol + " ")
# Membuat canvas untuk konten partitur
output_text_canvas = tk.Canvas(root, width=800, height=600)
output_text_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Membuat frame untuk konten di dalam canvas
output_frame = tk.Frame(output_text_canvas)
output_text_canvas.create_window((0, 0), window=output_frame, anchor="nw")
# Membuat Text Widget untuk output
output_text = tk.Text(output_frame, wrap=tk.WORD, undo=True, width=80, height=23, font=("Courier", 8))
output_text.grid(row=3, column=0, columnspan=3, padx=10, pady=10)
# Membuat frame untuk simbol notasi
symbol_frame = tk.Frame(output_frame)
symbol_frame.grid(row=0, column=0, pady=5, sticky="w")
# Label instruksi simbol
symbol_label = tk.Label(symbol_frame, text="Simbol Notasi Angka:")
symbol_label.grid(row=0, column=0, columnspan=6, pady=(0, 5))
# Simbol notasi yang akan digunakan
symbol_options = [
"\u135E", "\u135F", "\u135D", "\u1A18", "\u0324", "\u1CDF",
"•", "••", "•••", "\u007C", "\u20E6", ":||", "/", "\\", "'",
"0", "♯", "♭", "\u2323", "\u0305", "\u0818", "\u07EB", "\u266D", "\u203F", "\u3022",
"\u2503", "\u2595", "\u0821", "\u2191", "\u2193"
]
# Loop untuk membuat tombol untuk setiap simbol
for i, symbol in enumerate(symbol_options):
button = tk.Button(symbol_frame, text=symbol, width=2, command=lambda s=symbol: insert_symbol(s))
button.grid(row=1 + i // 10, column=i % 10, padx=5, pady=5)
# Label instruksi di atas output_text
instruksi_label = tk.Label(output_frame, fg="tomato", text="Partitur Notasi Angka (Edit di bawah sini):")
instruksi_label.grid(row=1, column=0, padx=5, pady=5)
# Fungsi untuk memainkan audio berdasarkan notasi di output_text
def play_nada():
# Mengambil teks dari output_text dan membaginya menjadi daftar simbol
notasi = output_text.get("1.0", tk.END).strip().split()
if not notasi:
messagebox.showwarning("Kosong", "Silakan masukkan notasi untuk diputar.")
return
try:
# Memetakan notasi ke audio dan menggabungkannya
hasil_audio = petakan_notasi_ke_audio(notasi)
if hasil_audio is not None:
hasil_audio.export("output_audio_temp.wav", format="wav")
# Inisialisasi pygame mixer
pygame.mixer.init()
# Memuat dan memutar audio
pygame.mixer.music.load("output_audio_temp.wav")
pygame.mixer.music.play()
# Tunggu hingga audio selesai diputar
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
except Exception as e:
messagebox.showerror("Error", f"Terjadi kesalahan saat memproses audio: \n{e}")
# Tombol untuk mulai memainkan nada
play_button = tk.Button(output_frame, text="Mainkan", command=play_nada)
play_button.grid(row=2, column=0, columnspan=3, padx=10, pady=10)
root.mainloop()
Berikut adalah perbaikan kode untuk memainkan audio menggunakan pygame dalam file simbol_dan_partitur.py. Saya juga memastikan agar audio dihasilkan dan diputar menggunakan pygame dengan benar.
import tkinter as tk
from tkinter import messagebox
import pygame
from peta_nada import petakan_notasi_ke_audio
# Setup UI
root = tk.Tk()
root.geometry("800x600")
root.title("Partitur Notasi Angka Ke Audio")
# Fungsi untuk memasukkan simbol notasi yang dipilih ke partitur
def insert_symbol(symbol):
output_text.insert(tk.INSERT, symbol + " ")
# Membuat canvas untuk konten partitur
output_text_canvas = tk.Canvas(root, width=800, height=600)
output_text_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Membuat frame untuk konten di dalam canvas
output_frame = tk.Frame(output_text_canvas)
output_text_canvas.create_window((0, 0), window=output_frame, anchor="nw")
# Membuat Text Widget untuk output
output_text = tk.Text(output_frame, wrap=tk.WORD, undo=True, width=80, height=23, font=("Courier", 8))
output_text.grid(row=3, column=0, columnspan=3, padx=10, pady=10)
# Membuat frame untuk simbol notasi
symbol_frame = tk.Frame(output_frame)
symbol_frame.grid(row=0, column=0, pady=5, sticky="w")
# Label instruksi simbol
symbol_label = tk.Label(symbol_frame, text="Simbol Notasi Angka:")
symbol_label.grid(row=0, column=0, columnspan=6, pady=(0, 5))
# Simbol notasi yang akan digunakan
symbol_options = [
"\u135E", "\u135F", "\u135D", "\u1A18", "\u0324", "\u1CDF",
"•", "••", "•••", "\u007C", "\u20E6", ":||", "/", "\\", "'",
"0", "♯", "♭", "\u2323", "\u0305", "\u0818", "\u07EB", "\u266D", "\u203F", "\u3022",
"\u2503", "\u2595", "\u0821", "\u2191", "\u2193"
]
# Loop untuk membuat tombol untuk setiap simbol
for i, symbol in enumerate(symbol_options):
button = tk.Button(symbol_frame, text=symbol, width=2, command=lambda s=symbol: insert_symbol(s))
button.grid(row=1 + i // 10, column=i % 10, padx=5, pady=5)
# Label instruksi di atas output_text
instruksi_label = tk.Label(output_frame, fg="tomato", text="Partitur Notasi Angka (Edit di bawah sini):")
instruksi_label.grid(row=1, column=0, padx=5, pady=5)
# Fungsi untuk memainkan audio berdasarkan notasi di output_text
def play_nada():
# Mengambil teks dari output_text dan membaginya menjadi daftar simbol
notasi = output_text.get("1.0", tk.END).strip().split()
if not notasi:
messagebox.showwarning("Kosong", "Silakan masukkan notasi untuk diputar.")
return
try:
# Memetakan notasi ke audio dan menggabungkannya
hasil_audio = petakan_notasi_ke_audio(notasi)
if hasil_audio is not None:
# Simpan audio yang digabungkan sementara
temp_audio_file = "output_audio_temp.wav"
hasil_audio.export(temp_audio_file, format="wav")
# Inisialisasi pygame mixer
pygame.mixer.init()
# Memuat dan memutar audio
pygame.mixer.music.load(temp_audio_file)
pygame.mixer.music.play()
# Tunggu hingga audio selesai diputar
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
except Exception as e:
messagebox.showerror("Error", f"Terjadi kesalahan saat memproses audio: \n{e}")
# Tombol untuk mulai memainkan nada
play_button = tk.Button(output_frame, text="Mainkan", command=play_nada)
play_button.grid(row=2, column=0, columnspan=3, padx=10, pady=10)
root.mainloop()
Perbaikan utama:
1. Memastikan proses ekspor audio sementara ke file .wav sebelum diputar menggunakan pygame.
2. Menggunakan pygame.mixer.music untuk memutar audio dan mengontrol loop sampai audio selesai dimainkan.
Silakan coba menjalankan kode ini di lingkungan yang mendukung pygame dan pydub.
Dua kode isi file berikut, peta_nada.py:
import tkinter as tk
from tkinter import Menu, filedialog, simpledialog, messagebox, Frame, Label, Entry, Button
import os
import time
from pydub import AudioSegment
from pydub.playback import play
# Folder tempat file sampel nada berada
folder_nada = '/storage/emulated/0/proyekku/PanotanKeAudio/sampel_nada/'
def petakan_notasi_ke_audio(notasi):
audio_segments = []
for simbol in notasi:
if simbol == '6\u0324' or simbol == '6-2':
file_nada = 'piano_A2.wav'
elif simbol == '7\u0324' or simbol == '7-2':
file_nada = 'piano_B2.wav'
elif simbol == '1\u1A18' or simbol == '1-1':
file_nada = 'piano_C3.wav' # Nada C3 (1 rendah satu oktaf)
elif simbol == '2\u1A18' or simbol == '2-1':
file_nada = 'piano_D3.wav'
elif simbol == '3\u1A18' or simbol == '3-1':
file_nada = 'piano_E3.wav'
elif simbol == '4\u1A18' or simbol == '4-1':
file_nada = 'piano_F3.wav'
elif simbol == '5\u1A18' or simbol == '5-1':
file_nada = 'piano_G3.wav'
elif simbol == '6\u1A18' or simbol == '6-1':
file_nada = 'piano_A3.wav' # Nada A3 (6 rendah satu oktaf)
elif simbol == '7\u1A18' or simbol == '7-1':
file_nada = 'piano_B3.wav'
elif simbol == '1' or simbol == '10':
file_nada = 'piano_C4.wav' # Nada C4 (1 di oktaf tengah)
elif simbol == '2' or simbol == '20':
file_nada = 'piano_D4.wav'
elif simbol == '3' or simbol == '30':
file_nada = 'piano_E4.wav'
elif simbol == '4' or simbol == '40':
file_nada = 'piano_F4.wav'
elif simbol == '5' or simbol == '50':
file_nada = 'piano_G4.wav'
elif simbol == '6' or simbol == '60':
file_nada = 'piano_A4.wav' # Nada A4 (6 di oktaf tengah)
elif simbol == '7' or simbol == '70':
file_nada = 'piano_B4.wav'
elif simbol == '1\u135E' or simbol == '11':
file_nada = 'piano_C5.wav' # Nada C5 (1 tinggi satu oktaf)
elif simbol == '2\u135E' or simbol == '21':
file_nada = 'piano_D5.wav'
elif simbol == '3\u135E' or simbol == '31':
file_nada = 'piano_E5.wav'
elif simbol == '4\u135E' or simbol == '41':
file_nada = 'piano_F5.wav'
elif simbol == '5\u135E' or simbol == '51':
file_nada = 'piano_G5.wav'
elif simbol == '6\u135E' or simbol == '61':
file_nada = 'piano_A5.wav' # Nada A5 (6 tinggi satu oktaf)
elif simbol == '7\u135E' or simbol == '71':
file_nada = 'piano_B5.wav'
elif simbol == '1\u135F' or simbol == '12':
file_nada = 'piano_C6.wav'
elif simbol == '2\u135F' or simbol == '22':
file_nada = 'piano_D6.wav'
elif simbol == '3\u135F' or simbol == '32':
file_nada = 'piano_E6.wav'
elif simbol == '4\u135F' or simbol == '42':
file_nada = 'piano_F6.wav'
elif simbol == '5\u135F' or simbol == '52':
file_nada = 'piano_G6.wav'
elif simbol == '6\u135F' or simbol == '62':
file_nada = 'piano_A6.wav'
elif simbol == '7\u135F' or simbol == '72':
file_nada = 'piano_B6.wav'
elif simbol == '1\u135D' or simbol == '13':
file_nada = 'piano_C7.wav'
elif simbol == '1#':
file_nada = 'piano_C4_sharp.wav'
elif simbol == '2b':
file_nada = 'piano_D4_flat.wav'
elif simbol == 'r': # Simbol istirahat (rest)
audio_segments.append(AudioSegment.silent(duration=500)) # Jeda 500ms
continue # Lewati penambahan file untuk simbol 'r'
# Menambahkan file audio yang dipetakan ke daftar
file_path = os.path.join(folder_nada, file_nada)
try:
audio_segment = AudioSegment.from_wav(file_path)
audio_segments.append(audio_segment)
except Exception as e:
messagebox.showerror("File Error", f"Terjadi kesalahan saat memuat file '{file_nada}': {str(e)}")
return None
# Menggabungkan segmen audio menjadi satu file
hasil_audio = sum(audio_segments)
# Ekspor hasil gabungan audio ke file WAV
output_file = os.path.join(folder_nada, "output_audio.wav")
hasil_audio.export(output_file, format="wav")
return hasil_audio
Dan kode isi file simbol_dan_partitur.py:
import tkinter as tk
from tkinter import Menu, filedialog, simpledialog, messagebox, Frame, Label, Entry, Button
import pygame
from peta_nada import petakan_notasi_ke_audio
import os
# Setup UI
root = tk.Tk()
root.geometry("800x600")
root.title("Partitur Notasi Angka Ke Audio")
# Fungsi untuk memasukkan simbol notasi yang dipilih ke partitur
def insert_symbol(symbol):
output_text.insert(tk.INSERT, symbol + " ")
# Membuat canvas untuk konten partitur
output_text_canvas = tk.Canvas(root, width=800, height=600)
output_text_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Membuat frame untuk konten di dalam canvas
output_frame = tk.Frame(output_text_canvas)
output_text_canvas.create_window((0, 0), window=output_frame, anchor="nw")
# Membuat Text Widget untuk output
output_text = tk.Text(output_frame, wrap=tk.WORD, undo=True, width=80, height=23, font=("Courier", 8))
output_text.grid(row=5, column=0, columnspan=3, padx=10, pady=10)
# Membuat frame untuk simbol notasi
symbol_frame = tk.Frame(output_frame)
symbol_frame.grid(row=0, column=0, pady=5, sticky="w")
# Label instruksi simbol
symbol_label = tk.Label(symbol_frame, text="Simbol Notasi Angka:")
symbol_label.grid(row=0, column=0, columnspan=6, pady=(0, 5))
# Simbol notasi yang akan digunakan
symbol_options = [
"\u135E", "\u135F", "\u135D", "\u1A18", "\u0324", "\u1CDF",
"•", "••", "•••", "\u007C", "\u20E6", ":||", "/", "\\", "'",
"0", "♯", "♭", "\u2323", "\u0305", "\u0818", "\u07EB", "\u266D", "\u203F", "\u3022",
"\u2503", "\u2595", "\u0821", "\u2191", "\u2193"
]
# Loop untuk membuat tombol untuk setiap simbol
for i, symbol in enumerate(symbol_options):
button = tk.Button(symbol_frame, text=symbol, width=2, command=lambda s=symbol: insert_symbol(s))
button.grid(row=1 + i // 10, column=i % 10, padx=5, pady=5)
# Label instruksi di atas output_text
instruksi_label = tk.Label(output_frame, fg="tomato", text="Partitur Notasi Angka (Edit di bawah sini):")
instruksi_label.grid(row=1, column=0, padx=5, pady=5)
# Fungsi untuk menyimpan partitur ke file teks
def simpan_partitur():
file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
if file_path:
with open(file_path, 'w') as f:
f.write(output_text.get("1.0", tk.END))
messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")
# Fungsi untuk memuat partitur dari file teks
def muat_partitur():
file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])
if file_path:
with open(file_path, 'r') as f:
partitur = f.read()
output_text.delete("1.0", tk.END)
output_text.insert(tk.INSERT, partitur)
# Fungsi untuk memainkan audio berdasarkan notasi di output_text
def play_nada():
# Mengambil teks dari output_text dan membaginya menjadi daftar simbol
notasi = output_text.get("1.0", tk.END).strip().split()
if not notasi:
messagebox.showwarning("Kosong", "Silakan masukkan notasi untuk diputar.")
return
try:
# Memetakan notasi ke audio dan menggabungkannya
hasil_audio = petakan_notasi_ke_audio(notasi)
if hasil_audio is not None:
# Simpan audio yang digabungkan sementara
temp_audio_file = "output_audio_temp.wav"
hasil_audio.export(temp_audio_file, format="wav")
# Inisialisasi pygame mixer dengan pengecekan error
try:
pygame.mixer.init()
except pygame.error as e:
messagebox.showerror("Pygame Error", f"Gagal menginisialisasi mixer: {e}")
return
# Memuat dan memutar audio
try:
if os.path.exists(temp_audio_file):
pygame.mixer.music.load(temp_audio_file)
pygame.mixer.music.play()
# Tunggu hingga audio selesai diputar
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
else:
messagebox.showerror("File Error", "File audio tidak ditemukan.")
except pygame.error as e:
messagebox.showerror("Pygame Error", f"Kesalahan saat memuat atau memainkan audio: {e}")
finally:
# Membersihkan file audio sementara
if os.path.exists(temp_audio_file):
os.remove(temp_audio_file)
except Exception as e:
messagebox.showerror("Error", f"Terjadi kesalahan saat memproses audio: \n{e}")
# Tombol untuk mulai memainkan nada
play_button = tk.Button(output_frame, text="Mainkan", bg="purple", fg="white", command=play_nada)
play_button.grid(row=2, column=0, columnspan=3, padx=10, pady=10, sticky="w")
simpan_button = tk.Button(output_frame, text="Simpan", bg="purple", fg="white", command= simpan_partitur)
simpan_button.grid(row=3, column=0, columnspan=3, padx=10, pady=10, sticky="w")
muat_button = tk.Button(output_frame, text="Buka", bg="purple", fg="white", command= muat_partitur)
muat_button.grid(row=4, column=0, columnspan=3, padx=10, pady=10, sticky="w")
root.mainloop()
Sudah bisa menghasilkan output audio berformat wav dengan nama filenya output_audio_temp.wav yang menghasilkan suara atau bunyi dari mada nada yang diketikksn pada output_text. Tetapi ketika kode dieksekusi dari simbol_dan_partitur.py maka applikasi mengalami crash (applikasi tiba tiba menutup). Tolong perbaiki kode agar supaya applikasi tidak crash
Potongan kode yang Anda bagikan cukup lengkap untuk dua file, yaitu peta_nada.py dan simbol_dan_partitur.py. Berikut adalah ikhtisar ringkas dari fungsi utama masing-masing file:
File peta_nada.py
Kode ini memiliki fungsi utama petakan_notasi_ke_audio() yang:
1. Memetakan setiap simbol notasi musik ke file audio WAV berdasarkan simbol nada.
2. Mengambil file audio dari folder yang telah ditentukan (folder_nada) dan membuat daftar audio berdasarkan notasi.
3. Menggabungkan daftar file audio menjadi satu audio utuh menggunakan pydub.
4. Menyimpan hasil gabungan audio ke dalam file output_audio.wav di lokasi folder yang sama.
Anda bisa menambahkan berbagai simbol dan mapping file WAV lainnya, sesuai kebutuhan notasi Anda.
File simbol_dan_partitur.py
Kode ini mencakup antarmuka pengguna (UI) berbasis tkinter dengan tujuan:
1. UI Partitur Notasi: Pengguna dapat memasukkan simbol-simbol notasi ke dalam teks partitur.
2. Penyimpanan Partitur: Fungsi untuk menyimpan dan memuat partitur dalam file teks.
3. Pemutaran Audio: Menggunakan fungsi petakan_notasi_ke_audio() dari file peta_nada.py untuk mengonversi notasi menjadi audio. Kode ini memanfaatkan pygame untuk memutar file audio yang sudah dipetakan.
Kode ini telah cukup lengkap dan fungsional untuk aplikasi partitur notasi angka ke audio berbasis notasi musik. Silakan lanjutkan dengan menyesuaikan sesuai kebutuhan Anda atau menambahkan fitur tambahan jika diperlukan.
Saya bisa bantu dengan mengecek kode Anda pada file simbol_dan_partitur.py untuk melihat sumber masalah yang mungkin menyebabkan aplikasi crash. Biasanya, crash disebabkan oleh beberapa kemungkinan, seperti kesalahan pada inisialisasi variabel atau objek, ketidakcocokan tipe data, atau error yang tidak ter-handle dengan baik.
Untuk mendiagnosis dan memperbaiki masalahnya, ada beberapa langkah awal yang bisa dilakukan:
1. Tambah Blok Try-Except: Bungkus bagian-bagian kode yang rentan terhadap error dalam blok try-except untuk menangkap dan mencetak pesan errornya. Ini akan membantu mengidentifikasi baris mana yang memicu error.
2. Cek Dependency Library: Pastikan semua pustaka yang diperlukan sudah diimpor dan diinisialisasi dengan benar, terutama jika menggunakan tkinter atau pustaka database.
3. Periksa Logika pada Fungsi-fungsi Kunci: Kadang, fungsi yang salah dalam mengambil atau mengubah data bisa memicu error yang tak terduga.
4. Tambahkan Logging: Jika aplikasi cukup besar, bisa dipertimbangkan untuk menambahkan log di berbagai bagian kode. Ini berguna untuk melacak urutan eksekusi dan melihat di mana program berhenti sebelum crash.
Aplikasi pada simbol_dan_partitur.py bisa mengalami crash karena beberapa alasan potensial, termasuk masalah pada pustaka pygame, akses file, atau pembacaan dan penulisan notasi. Berikut adalah beberapa perbaikan dan langkah diagnostik untuk mengatasi kemungkinan masalah ini:
1. Tambahkan Penanganan Error di play_nada()
Untuk memastikan tidak ada crash saat audio diputar, tambahkan penanganan error lebih detail di bagian play_nada() yang menginisialisasi dan memainkan audio.
def play_nada():
# Mengambil teks dari output_text dan membaginya menjadi daftar simbol
notasi = output_text.get("1.0", tk.END).strip().split()
if not notasi:
messagebox.showwarning("Kosong", "Silakan masukkan notasi untuk diputar.")
return
try:
# Memetakan notasi ke audio dan menggabungkannya
hasil_audio = petakan_notasi_ke_audio(notasi)
if hasil_audio is not None:
# Simpan audio yang digabungkan sementara
temp_audio_file = "output_audio_temp.wav"
hasil_audio.export(temp_audio_file, format="wav")
# Inisialisasi pygame mixer dengan pengecekan error
try:
pygame.mixer.init()
except pygame.error as e:
messagebox.showerror("Pygame Error", f"Gagal menginisialisasi mixer: {e}")
return
# Memuat dan memutar audio
try:
if os.path.exists(temp_audio_file):
pygame.mixer.music.load(temp_audio_file)
pygame.mixer.music.play()
# Tunggu hingga audio selesai diputar
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
else:
messagebox.showerror("File Error", "File audio tidak ditemukan.")
except pygame.error as e:
messagebox.showerror("Pygame Error", f"Kesalahan saat memuat atau memainkan audio: {e}")
finally:
# Membersihkan file audio sementara
if os.path.exists(temp_audio_file):
os.remove(temp_audio_file)
except Exception as e:
messagebox.showerror("Error", f"Terjadi kesalahan saat memproses audio: \n{e}")
2. Validasi pada Modul petakan_notasi_ke_audio
Karena petakan_notasi_ke_audio berasal dari modul peta_nada, perlu dipastikan modul tersebut mengembalikan data yang benar. Jika petakan_notasi_ke_audio tidak mengembalikan file audio yang valid, tambahkan kode berikut untuk memastikan pengecekan output:
if hasil_audio is None:
messagebox.showerror("Error", "Tidak ada hasil audio yang dihasilkan. Periksa format notasi atau fungsi petakan_notasi_ke_audio.")
return
3. Pengecekan pygame.mixer sebelum Inisialisasi Ulang
Menambahkan pengecekan sebelum menginisialisasi pygame.mixer.init() bisa menghindari crash karena duplikasi inisialisasi:
if not pygame.mixer.get_init():
try:
pygame.mixer.init()
except pygame.error as e:
messagebox.showerror("Pygame Error", f"Gagal menginisialisasi mixer: {e}")
return
4. Periksa Ketergantungan pygame dan File Audio Sementara
Pastikan pygame terinstal dengan benar dan file sementara output_audio_temp.wav benar-benar ada dan dapat diakses oleh aplikasi. Gunakan berikut ini untuk debug:
if os.path.exists(temp_audio_file):
pygame.mixer.music.load(temp_audio_file)
else:
messagebox.showerror("File Error", "File audio sementara tidak ditemukan atau tidak dapat diakses.")
return
5. Tambahkan try-except di root.mainloop()
Untuk menangkap crash yang tidak terduga dan mencegah aplikasi menutup sepenuhnya, bungkus root.mainloop() dalam blok try-except utama:
try:
root.mainloop()
except Exception as e:
messagebox.showerror("Fatal Error", f"Aplikasi mengalami kesalahan fatal: {e}")
6. Menggunakan Log untuk Debugging
Tambahkan print atau logging untuk membantu menemukan lokasi crash saat kode dijalankan:
import logging
logging.basicConfig(level=logging.INFO)
logging.info("Aplikasi mulai berjalan.")
# Misalnya di play_nada:
logging.info("Memulai play_nada.")
...
logging.info("Selesai play_nada.")
Setelah melakukan perubahan di atas, jalankan kembali aplikasi dan perhatikan setiap pesan error yang muncul. Langkah-langkah ini harus membantu mengurangi kemungkinan crash dan memberi lebih banyak informasi jika terjadi error.
Jika file txt dibuka misalnya file KJ No 33.txt yaitu file berupa partitur lagu dalam format notasi angka. Lalu menekan tombol play_button, maka muncul messagebox pesan error:
cannot access local variable 'file_nada' whe ....
Pesan error cannot access local variable 'file_nada' biasanya muncul ketika variabel file_nada dideklarasikan di dalam blok try atau kondisi tertentu, tetapi kemudian tidak tersedia saat ingin diakses karena kondisinya tidak terpenuhi atau ada error lain yang terjadi lebih awal.
Untuk memperbaiki error ini, kita bisa memastikan bahwa variabel file_nada selalu dideklarasikan sebelum dipakai. Berikut beberapa langkah yang bisa membantu menyelesaikan masalah ini:
1. Deklarasikan file_nada di Awal Fungsi
Inisialisasikan file_nada di awal fungsi play_nada() agar variabel ini selalu didefinisikan meskipun terjadi error di dalam blok berikutnya. Tambahkan kode berikut di awal fungsi play_nada:
def play_nada():
file_nada = None # Inisialisasi variabel file_nada
2. Pastikan file_nada Mendapatkan Nilai Sebelum Diakses
Jika file_nada baru mendapatkan nilai setelah proses petakan_notasi_ke_audio, tambahkan kondisi yang memeriksa apakah file_nada telah didefinisikan sebelum digunakan, atau tampilkan pesan jika file_nada tidak tersedia. Contoh:
try:
hasil_audio = petakan_notasi_ke_audio(notasi)
if hasil_audio:
file_nada = "output_audio_temp.wav"
hasil_audio.export(file_nada, format="wav")
else:
messagebox.showerror("Error", "Tidak ada hasil audio yang dihasilkan.")
return
# Lakukan sesuatu dengan file_nada
if os.path.exists(file_nada):
pygame.mixer.music.load(file_nada)
pygame.mixer.music.play()
else:
messagebox.showerror("File Error", "File audio tidak ditemukan atau gagal dibuat.")
3. Tambahkan finally untuk Membersihkan File Sementara
Jika file_nada digunakan sebagai file sementara, sebaiknya tambahkan blok finally untuk memastikan file ini dihapus bahkan jika ada error, tanpa menyebabkan crash jika file_nada belum terbentuk:
try:
# Proses konversi notasi ke audio
hasil_audio = petakan_notasi_ke_audio(notasi)
if hasil_audio:
file_nada = "output_audio_temp.wav"
hasil_audio.export(file_nada, format="wav")
else:
messagebox.showerror("Error", "Tidak ada hasil audio yang dihasilkan.")
return
# Memutar file audio
if os.path.exists(file_nada):
pygame.mixer.music.load(file_nada)
pygame.mixer.music.play()
else:
messagebox.showerror("File Error", "File audio tidak ditemukan atau gagal dibuat.")
finally:
if file_nada and os.path.exists(file_nada):
os.remove(file_nada)
4. Tambahkan Debugging untuk Melacak file_nada
Untuk memastikan apakah file_nada berhasil dibuat, tambahkan log atau pesan debugging di mana variabel file_nada diset dan sebelum diputar:
print("file_nada path:", file_nada) # Debug: Cek apakah file_nada berhasil dibuat
Dengan mengikuti langkah-langkah ini, error cannot access local variable 'file_nada' seharusnya dapat diatasi. Jika masih ada
pesan error lainnya, beri tahu saya agar kita dapat melakukan pengecekan lebih lanjut.
Error cannot access local variable 'file_nada' timbul karena masih banyak simbol musik yang belum dimasukkan pada fungsi petakan_notasi_ke_audio. Misalnya simbol legato, garis aatu si atas nada, dan simbol-simbol lainnya. Untuk itu bagaimana caranya membuat:
if simbol == '\u0818' :
file_nada = ''
Maka file_nada di sini berisikan apa agar dapat dibaca dan diartikan oleh applikasi
Jika simbol musik seperti legato atau simbol garis tertentu (\u0818 dalam kasus ini) belum dipetakan ke file audio, kita perlu mempertimbangkan dua pendekatan utama agar aplikasi dapat berjalan lancar saat simbol-simbol ini muncul di partitur:
1. Buat Representasi Kosong untuk Simbol: Jika simbol seperti legato atau garis hanya berfungsi sebagai penanda musik tanpa menghasilkan suara, kita bisa mengabaikan pemrosesan audio untuk simbol ini dengan cara memberikan representasi audio kosong atau skip. Contohnya, saat simbol legato ditemukan, kita dapat menggunakan silence (kesunyian) dalam audio sebagai pengganti suara. Dengan ini, aplikasi akan tetap mengalir tanpa kesalahan.
2. Definisikan Suara Khusus atau Efek Placeholder untuk Simbol: Alternatifnya, kita bisa memberikan efek suara sederhana, seperti suara penanda, yang menggambarkan simbol tersebut dalam audio. Misalnya, jika legato memiliki makna musik tertentu, kita bisa menggunakan suara yang mengisyaratkan transisi antar nada.
Berikut adalah contoh kode untuk kedua pendekatan tersebut yang dapat disesuaikan di dalam petakan_notasi_ke_audio:
Contoh Penerapan dalam petakan_notasi_ke_audio
Asumsikan file_nada adalah hasil audio atau jalur file sementara dari hasil pemrosesan petakan_notasi_ke_audio:
from pydub import AudioSegment # Pastikan modul ini telah diimpor jika menggunakan pydub
def petakan_notasi_ke_audio(notasi):
audio_hasil = AudioSegment.silent(duration=0) # Mulai dengan audio kosong
for simbol in notasi:
if simbol == '\u0818': # Legato
# Opsi 1: Masukkan jeda/silence sebagai placeholder
jeda = AudioSegment.silent(duration=300) # 300 ms jeda untuk legato
audio_hasil += jeda
elif simbol == '•': # Contoh simbol notasi lainnya
# Masukkan audio atau suara untuk notasi ini
nada_do = AudioSegment.from_file("path_ke_audio/nada_do.wav")
audio_hasil += nada_do
# Tambahkan elif lainnya untuk simbol-simbol tambahan
else:
# Jika simbol belum didefinisikan, tambahkan placeholder untuk menghindari error
placeholder_suara = AudioSegment.silent(duration=500)
audio_hasil += placeholder_suara
return audio_hasil
Penjelasan Kode
1. Legato sebagai Placeholder: Simbol legato (atau simbol lainnya) diberikan jeda menggunakan AudioSegment.silent(duration=300). Durasi jeda bisa disesuaikan.
2. Penanganan Simbol Tambahan: Tambahkan simbol-simbol yang diperlukan dengan cara yang sama, menggunakan elif untuk setiap simbol dan memberikan suara atau jeda sesuai kebutuhan.
3. Placeholder untuk Simbol Tak Dikenal: Pada bagian else, kita menggunakan placeholder berupa jeda jika simbol belum memiliki representasi khusus.
Menggunakan File Audio Kosong Sebagai file_nada
Jika simbol tidak memiliki audio yang relevan, file_nada bisa mengarah ke file audio kosong. Contoh membuat file kosong:
if simbol == '\u0818':
file_nada = AudioSegment.silent(duration=300) # 300 ms placeholder silence untuk legato
Pendekatan ini membantu memastikan aplikasi berjalan lancar meskipun ada simbol yang belum terdefinisi. Pastikan semua simbol yang relevan diberikan representasi dalam bentuk audio atau jeda agar tidak terjadi error.
Bagaimana me-representasikan simbol garis satu di atas nada (\u0818) yang menandakan nada tersebut bernilai 1/2 ketuk.
Untuk merepresentasikan simbol garis satu di atas nada (\u0818) sebagai nada dengan nilai setengah ketuk, kita dapat mengatur durasi suara yang lebih pendek dibandingkan dengan ketukan penuh.
Misalnya, jika satu ketuk memiliki durasi standar (misalnya 500 ms untuk tempo tertentu), maka simbol \u0818 ini akan dimainkan dengan durasi setengah dari ketukan tersebut (250 ms).
Implementasi dalam petakan_notasi_ke_audio
Mari kita tambahkan logika dalam petakan_notasi_ke_audio untuk menangani simbol \u0818.
Berikut ini adalah cara mengatur file_nada agar nada dengan simbol \u0818 dimainkan dengan durasi 1/2 ketuk:
from pydub import AudioSegment # Pastikan pydub telah diimpor
def petakan_notasi_ke_audio(notasi):
audio_hasil = AudioSegment.silent(duration=0) # Mulai dengan audio kosong
# Durasi dasar untuk satu ketuk (misalnya 500 ms)
ketukan_penuh_durasi = 500
for simbol in notasi:
if simbol == '\u0818': # Simbol garis satu di atas nada (1/2 ketuk)
# Mengatur nada yang lebih pendek, misalnya nada "Do" dengan setengah ketuk
nada_dasar = AudioSegment.from_file("path_ke_audio/nada_do.wav")
nada_setengah_ketuk = nada_dasar[:ketukan_penuh_durasi // 2] # Potong durasi menjadi setengah
audio_hasil += nada_setengah_ketuk
elif simbol == '•': # Contoh simbol notasi lainnya
# Masukkan audio untuk notasi ini dengan durasi penuh
nada_do = AudioSegment.from_file("path_ke_audio/nada_do.wav")
audio_hasil += nada_do[:ketukan_penuh_durasi]
# Tambahkan elif untuk simbol-simbol tambahan sesuai kebutuhan
else:
# Placeholder untuk simbol yang tidak dikenal
placeholder_suara = AudioSegment.silent(duration=ketukan_penuh_durasi)
audio_hasil += placeholder_suara
return audio_hasil
Penjelasan Kode
1. ketukan_penuh_durasi: Variabel ini menetapkan durasi standar satu ketuk (dalam contoh ini, 500 ms). Sesuaikan nilai ini berdasarkan tempo lagu.
2. Representasi Simbol \u0818: Ketika simbol \u0818 ditemukan, kita mengambil nada dasar (misalnya, suara Do) dan memotongnya menjadi setengah ketuk dengan nada_dasar[:ketukan_penuh_durasi // 2].
3. Penerapan Simbol Lainnya: Anda bisa menambahkan simbol-simbol lain dengan durasi penuh atau durasi lainnya sesuai kebutuhan.
Dengan pendekatan ini, simbol \u0818 akan mewakili nada dengan durasi setengah ketuk, memastikan ketukan dalam musik terdengar sesuai.
Tolong perbaiki dua kode berikut agar supaya ketika nada nada di partitur dimainkan dan indikator highlight berjalan, maka hasil audio tidak hanya menghasilkan output_audio_temp.wav tetapi juga seharusnya mengeluarkan bunyi nada (suara) yang terdengar dari spraker HP Android. Berikut kode isi file peta_nada.py:
import tkinter as tk
from tkinter import Menu, filedialog, simpledialog, messagebox, Frame, Label, Entry, Button
import os
import time
from pydub import AudioSegment
from pydub.playback import play
# Folder tempat file sampel nada berada
folder_nada = '/storage/emulated/0/proyekku/PanotanKeAudio/sampel_nada/'
def petakan_notasi_ke_audio(notasi):
audio_hasil = AudioSegment.silent(duration=0) # Mulai dengan audio kosong
audio_segments = []
for simbol in notasi:
if simbol == '6\u0324' or simbol == '6-2':
file_nada = 'piano_A2.wav'
elif simbol == '7\u0324' or simbol == '7-2':
file_nada = 'piano_B2.wav'
elif simbol == '1\u1A18' or simbol == '1-1':
file_nada = 'piano_C3.wav' # Nada C3 (1 rendah satu oktaf)
elif simbol == '2\u1A18' or simbol == '2-1':
file_nada = 'piano_D3.wav'
elif simbol == '3\u1A18' or simbol == '3-1':
file_nada = 'piano_E3.wav'
elif simbol == '4\u1A18' or simbol == '4-1':
file_nada = 'piano_F3.wav'
elif simbol == '5\u1A18' or simbol == '5-1':
file_nada = 'piano_G3.wav'
elif simbol == '6\u1A18' or simbol == '6-1':
file_nada = 'piano_A3.wav' # Nada A3 (6 rendah satu oktaf)
elif simbol == '7\u1A18' or simbol == '7-1':
file_nada = 'piano_B3.wav'
elif simbol == '1' or simbol == '10':
file_nada = 'piano_C4.wav' # Nada C4 (1 di oktaf tengah)
elif simbol == '2' or simbol == '20':
file_nada = 'piano_D4.wav'
elif simbol == '3' or simbol == '30':
file_nada = 'piano_E4.wav'
elif simbol == '4' or simbol == '40':
file_nada = 'piano_F4.wav'
elif simbol == '5' or simbol == '50':
file_nada = 'piano_G4.wav'
elif simbol == '6' or simbol == '60':
file_nada = 'piano_A4.wav' # Nada A4 (6 di oktaf tengah)
elif simbol == '7' or simbol == '70':
file_nada = 'piano_B4.wav'
elif simbol == '1\u135E' or simbol == '11':
file_nada = 'piano_C5.wav' # Nada C5 (1 tinggi satu oktaf)
elif simbol == '2\u135E' or simbol == '21':
file_nada = 'piano_D5.wav'
elif simbol == '3\u135E' or simbol == '31':
file_nada = 'piano_E5.wav'
elif simbol == '4\u135E' or simbol == '41':
file_nada = 'piano_F5.wav'
elif simbol == '5\u135E' or simbol == '51':
file_nada = 'piano_G5.wav'
elif simbol == '6\u135E' or simbol == '61':
file_nada = 'piano_A5.wav' # Nada A5 (6 tinggi satu oktaf)
elif simbol == '7\u135E' or simbol == '71':
file_nada = 'piano_B5.wav'
elif simbol == '1\u135F' or simbol == '12':
file_nada = 'piano_C6.wav'
elif simbol == '2\u135F' or simbol == '22':
file_nada = 'piano_D6.wav'
elif simbol == '3\u135F' or simbol == '32':
file_nada = 'piano_E6.wav'
elif simbol == '4\u135F' or simbol == '42':
file_nada = 'piano_F6.wav'
elif simbol == '5\u135F' or simbol == '52':
file_nada = 'piano_G6.wav'
elif simbol == '6\u135F' or simbol == '62':
file_nada = 'piano_A6.wav'
elif simbol == '7\u135F' or simbol == '72':
file_nada = 'piano_B6.wav'
elif simbol == '1\u135D' or simbol == '13':
file_nada = 'piano_C7.wav'
elif simbol == '1#':
file_nada = 'piano_C4_sharp.wav'
elif simbol == '2b':
file_nada = 'piano_D4_flat.wav'
elif simbol == 'r': # Simbol istirahat (rest)
audio_segments.append(AudioSegment.silent(duration=500)) # Jeda 500ms
continue # Lewati penambahan file untuk simbol 'r'
elif simbol == '\u203F': # Legato
# Opsi 1: Masukkan jeda/silence sebagai placeholder
jeda = AudioSegment.silent(duration=300) # 300 ms jeda untuk legato
audio_hasil += jeda
# Tambahkan elif lainnya untuk simbol-simbol tambahan
else:
# Jika simbol belum didefinisikan, tambahkan placeholder untuk menghindari error
placeholder_suara = AudioSegment.silent(duration=500)
audio_hasil += placeholder_suara
# Menambahkan file audio yang dipetakan ke daftar
file_path = os.path.join(folder_nada, file_nada)
print("file_nada path:", file_nada) # Debug: Cek apakah file_nada berhasil dibuat
try:
audio_segment = AudioSegment.from_wav(file_path)
audio_segments.append(audio_segment)
except Exception as e:
messagebox.showerror("File Error", f"Terjadi kesalahan saat memuat file '{file_nada}': {str(e)}")
return None
# Menggabungkan segmen audio menjadi satu file
hasil_audio = sum(audio_segments)
# Ekspor hasil gabungan audio ke file WAV
output_file = os.path.join(folder_nada, "output_audio.wav")
hasil_audio.export(output_file, format="wav")
return hasil_audio
Dan kode isi file simbol_dan_partitur.py:
import tkinter as tk
from tkinter import Menu, filedialog, simpledialog, messagebox, Frame, Label, Entry, Button
import pygame
from peta_nada import petakan_notasi_ke_audio
import os
import time
from tkinter import Text
from tkinter import PhotoImage
import logging
logging.basicConfig(level=logging.INFO)
logging.info("Aplikasi mulai berjalan.")
# Setup UI
root = tk.Tk()
root.geometry("685x1385")
root.title("Partitur Notasi Angka Ke Audio")
# Fungsi untuk highlight teks yang sedang dimainkan
def highlight_nada(posisi_awal, posisi_akhir):
# Hapus highlight sebelumnya
text_area.tag_remove("highlight", "1.0", "end")
# Tambahkan highlight baru
text_area.tag_add("highlight", posisi_awal, posisi_akhir)
text_area.tag_config("highlight", background="yellow")
# Fungsi untuk memasukkan simbol notasi yang dipilih ke partitur
def insert_symbol(symbol):
output_text.insert(tk.INSERT, symbol + " ")
# Membuat canvas untuk konten partitur
output_text_canvas = tk.Canvas(root, width=800, height=600)
output_text_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Membuat frame untuk konten di dalam canvas
output_frame = tk.Frame(output_text_canvas)
output_text_canvas.create_window((0, 0), window=output_frame, anchor="nw")
# Membuat Text Widget untuk output
output_text = tk.Text(output_frame, wrap=tk.WORD, undo=True, width=80, height=50, font=("Courier", 8))
output_text.grid(row=5, column=0, columnspan=3, padx=10, pady=10)
# Referensi untuk text_area
text_area = output_text
# Isi text area dengan partitur sederhana
text_area.insert("1.0", "")
# Membuat frame untuk simbol notasi
symbol_frame = tk.Frame(output_frame)
symbol_frame.grid(row=0, column=0, pady=5, sticky="w")
# Label instruksi simbol
symbol_label = tk.Label(symbol_frame, text="Simbol Notasi Angka:")
symbol_label.grid(row=0, column=0, columnspan=6, pady=(0, 5))
# Simbol notasi yang akan digunakan
symbol_options = [
"\u135E", "\u135F", "\u135D", "\u1A18", "\u0324", "\u1CDF",
"•", "••", "•••", "\u007C", "\u20E6", ":||", "/", "\\", "'",
"0", "♯", "♭", "\u2323", "\u0305", "\u0818", "\u07EB", "\u266D", "\u203F", "\u3022",
"\u2503", "\u2595", "\u0821", "\u2191", "\u2193"
]
# Loop untuk membuat tombol untuk setiap simbol
for i, symbol in enumerate(symbol_options):
button = tk.Button(symbol_frame, text=symbol, width=2, command=lambda s=symbol: insert_symbol(s))
button.grid(row=1 + i // 10, column=i % 10, padx=5, pady=5)
# Label instruksi di atas output_text
instruksi_label = tk.Label(output_frame, fg="tomato", text="Partitur Notasi Angka (Edit di bawah sini):")
instruksi_label.grid(row=1, column=0, padx=5, pady=5)
# Fungsi untuk menyimpan partitur ke file teks
def simpan_partitur():
file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
if file_path:
with open(file_path, 'w') as f:
f.write(output_text.get("1.0", tk.END))
messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")
# Fungsi untuk memuat partitur dari file teks
def muat_partitur():
file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])
if file_path:
with open(file_path, 'r') as f:
partitur = f.read()
output_text.delete("1.0", tk.END)
output_text.insert(tk.INSERT, partitur)
# Misalnya di play_nada:
logging.info("Memulai play_nada.")
# Fungsi untuk memainkan audio berdasarkan notasi di output_text
def play_nada(i=0):
nada_list = output_text.get("1.0", tk.END).strip().split()
if i < len(nada_list):
nada = nada_list[i]
posisi_awal = text_area.search(nada, "1.0", tk.END)
if posisi_awal:
posisi_akhir = f"{posisi_awal}+{len(nada)}c"
highlight_nada(posisi_awal, posisi_akhir)
root.after(1000, play_nada, i + 1) # Delay 1 detik per nada
file_nada = None # Inisialisasi variabel file_nada
# Mengambil teks dari output_text dan membaginya menjadi daftar simbol
notasi = output_text.get("1.0", tk.END).strip().split()
if not notasi:
messagebox.showwarning("Kosong", "Silakan masukkan notasi untuk diputar.")
return
try:
# Memetakan notasi ke audio dan menggabungkannya
hasil_audio = petakan_notasi_ke_audio(notasi)
if hasil_audio is None:
messagebox.showerror("Error", "Tidak ada hasil audio yang dihasilkan. Periksa format notasi atau fungsi petakan_notasi_ke_audio.")
if hasil_audio is not None:
# Simpan audio yang digabungkan sementara
temp_audio_file = "output_audio_temp.wav"
hasil_audio.export(temp_audio_file, format="wav")
return
# Inisialisasi pygame mixer dengan pengecekan error
if not pygame.mixer.get_init():
try:
pygame.mixer.init()
except pygame.error as e:
messagebox.showerror("Pygame Error", f"Gagal menginisialisasi mixer: {e}")
return
# Memuat dan memutar audio
try:
if os.path.exists(temp_audio_file):
pygame.mixer.music.load(temp_audio_file)
pygame.mixer.music.play()
# Tunggu hingga audio selesai diputar
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
else:
messagebox.showerror("File Error", "File audio tidak ditemukan.")
except pygame.error as e:
messagebox.showerror("Pygame Error", f"Kesalahan saat memuat atau memainkan audio: {e}")
finally:
# Membersihkan file audio sementara
if os.path.exists(temp_audio_file):
pygame.mixer.music.load(temp_audio_file)
else:
messagebox.showerror("File Error", "File audio sementara tidak ditemukan atau tidak dapat diakses.")
except Exception as e:
messagebox.showerror("Error", f"Terjadi kesalahan saat memproses audio: \n{e}")
try:
# Proses konversi notasi ke audio
hasil_audio = petakan_notasi_ke_audio(notasi)
if hasil_audio:
file_nada = "output_audio_temp.wav"
hasil_audio.export(file_nada, format="wav")
else:
messagebox.showerror("Error", "Tidak ada hasil audio yang dihasilkan.")
return
finally:
if file_nada and os.path.exists(file_nada):
os.remove(file_nada)
logging.info("Selesai play_nada.")
# Atur frame untuk tombol di baris yang sama
button_frame = tk.Frame(output_frame)
button_frame.grid(row=2, column=0, sticky="w", columnspan=2, pady=(10, 0)) # Di atas partitur dan gunakan columnspan agar tombol berada di tengah
# Tambahkan tombol-tombol ke dalam frame
mainkan_button = tk.Button(button_frame, text="Mainkan", bg="purple", fg="white", command= play_nada)
mainkan_button.grid(row=0, column=0, padx=5)
simpan_button = tk.Button(button_frame, text="Simpan", bg="purple", fg="white", command= simpan_partitur)
simpan_button.grid(row=0, column=1, padx=5)
muat_button = tk.Button(button_frame, text="Buka", bg="purple", fg="white", command= muat_partitur)
muat_button.grid(row=0, column=2, padx=5)
# Fungsi untuk memasukkan simbol custom ke dalam teks partitur
def insert_custom_symbol():
output_text.image_create(tk.END, image=symbol_image)
button_8_font_custom = tk.Button(symbol_frame, text="7\u0305", width=3, command= insert_custom_symbol)
button_8_font_custom.grid(row=7, column=0, padx=5, pady=5)
# Simbol custom (gunakan gambar yang sudah kamu buat)
symbol_image = PhotoImage(file="garis_dua_atas.jpg") # Gambar untuk simbol '1 dengan titik di atas'
# Menambahkan tombol untuk notasi angka biasa (tanpa garis di atas)
button_1 = tk.Button(symbol_frame, text="1", width=3, command=lambda: insert_symbol("1"))
button_1.grid(row=5, column=0, padx=5, pady=5)
button_2 = tk.Button(symbol_frame, text="2", width=3, command=lambda: insert_symbol("2"))
button_2.grid(row=5, column=1, padx=5, pady=5)
button_3 = tk.Button(symbol_frame, text="3", width=3, command=lambda: insert_symbol("3"))
button_3.grid(row=5, column=2, padx=5, pady=5)
button_4 = tk.Button(symbol_frame, text="4", width=3, command=lambda: insert_symbol("4"))
button_4.grid(row=5, column=3, padx=5, pady=5)
button_5 = tk.Button(symbol_frame, text="5", width=3, command=lambda: insert_symbol("5"))
button_5.grid(row=5, column=4, padx=5, pady=5)
button_6 = tk.Button(symbol_frame, text="6", width=3, command=lambda: insert_symbol("6"))
button_6.grid(row=5, column=5, padx=5, pady=5)
button_7 = tk.Button(symbol_frame, text="7", width=3, command=lambda: insert_symbol("7"))
button_7.grid(row=5, column=6, padx=5, pady=5)
try:
root.mainloop()
except Exception as e:
messagebox.showerror("Fatal Error", f"Aplikasi mengalami kesalahan fatal: {e}")
Untuk memastikan agar kode yang dibuat dapat memutar nada langsung melalui speaker Android saat partitur dimainkan, kita bisa menggunakan pygame.mixer untuk memainkan audio di Android langsung dari memori tanpa mengekspor terlebih dahulu ke file .wav. Selain itu, pydub tetap akan kita gunakan untuk pengolahan audio.
Berikut adalah beberapa langkah perbaikan untuk mencapai hal ini:
1. Gunakan pygame.mixer untuk memainkan nada langsung: Dengan menggunakan pygame.mixer.Sound, audio yang dihasilkan oleh pydub dapat dimainkan langsung tanpa harus disimpan dalam file .wav.
2. Memodifikasi fungsi petakan_notasi_ke_audio untuk output langsung: Alih-alih mengekspor dan menyimpan audio sebagai file output_audio_temp.wav, kita akan langsung memutarnya dengan pygame.
Berikut adalah versi perbaikan dari kedua kode tersebut:
File peta_nada.py
Tambahkan pygame.init() di awal, lalu ubah fungsi petakan_notasi_ke_audio agar dapat langsung memutar audio dengan pygame.
import tkinter as tk
from tkinter import messagebox
import os
from pydub import AudioSegment
from pygame import mixer
# Folder tempat file sampel nada berada
folder_nada = '/storage/emulated/0/proyekku/PanotanKeAudio/sampel_nada/'
# Inisialisasi pygame mixer untuk memainkan audio
mixer.init()
def petakan_notasi_ke_audio(notasi):
audio_segments = []
for simbol in notasi:
if simbol == '6\u0324' or simbol == '6-2':
file_nada = 'piano_A2.wav'
elif simbol == '7\u0324' or simbol == '7-2':
file_nada = 'piano_B2.wav'
elif simbol == '1\u1A18' or simbol == '1-1':
file_nada = 'piano_C3.wav'
elif simbol == '2\u1A18' or simbol == '2-1':
file_nada = 'piano_D3.wav'
# (Tambahkan simbol lain sesuai kebutuhan)
elif simbol == 'r': # Istirahat (rest)
audio_segments.append(AudioSegment.silent(duration=500)) # Jeda 500ms
continue
else:
# Placeholder untuk simbol yang tidak dikenali
audio_segments.append(AudioSegment.silent(duration=500))
continue
# Mendapatkan path file audio
file_path = os.path.join(folder_nada, file_nada)
try:
audio_segment = AudioSegment.from_wav(file_path)
audio_segments.append(audio_segment)
except Exception as e:
messagebox.showerror("File Error", f"Terjadi kesalahan saat memuat file '{file_nada}': {str(e)}")
return None
# Menggabungkan segmen audio menjadi satu file audio akhir
hasil_audio = sum(audio_segments)
# Memainkan hasil_audio menggunakan pygame.mixer
temp_file = os.path.join(folder_nada, "temp_audio.wav")
hasil_audio.export(temp_file, format="wav")
mixer.music.load(temp_file)
mixer.music.play()
return hasil_audio
File simbol_dan_partitur.py
Tambahkan panggilan ke petakan_notasi_ke_audio ketika partitur mulai dimainkan agar langsung memutar nada, serta tambahkan fungsi untuk menghentikan pemutaran.
import tkinter as tk
from tkinter import filedialog, messagebox
from peta_nada import petakan_notasi_ke_audio
from pygame import mixer
import logging
logging.basicConfig(level=logging.INFO)
logging.info("Aplikasi mulai berjalan.")
# Setup UI
root = tk.Tk()
root.geometry("685x1385")
root.title("Partitur Notasi Angka Ke Audio")
# Fungsi untuk highlight teks yang sedang dimainkan
def highlight_nada(posisi_awal, posisi_akhir):
text_area.tag_remove("highlight", "1.0", "end")
text_area.tag_add("highlight", posisi_awal, posisi_akhir)
text_area.tag_config("highlight", background="yellow")
# Fungsi untuk memulai pemutaran partitur
def mulai_putar_partitur():
notasi = text_area.get("1.0", tk.END).split() # Mengambil teks partitur dan memisahkannya menjadi simbol
petakan_notasi_ke_audio(notasi) # Memutar partitur sebagai audio
highlight_nada("1.0", "1.end") # Highlight simbol pertama
# Fungsi untuk menghentikan pemutaran
def hentikan_pemutaran():
mixer.music.stop()
text_area.tag_remove("highlight", "1.0", "end")
# Tombol untuk mulai dan menghentikan pemutaran
mulai_button = tk.Button(root, text="Mulai Putar", command=mulai_putar_partitur)
mulai_button.pack(pady=5)
stop_button = tk.Button(root, text="Hentikan", command=hentikan_pemutaran)
stop_button.pack(pady=5)
# Membuat Text Widget untuk output
output_text = tk.Text(root, wrap=tk.WORD, undo=True, width=80, height=50, font=("Courier", 8))
output_text.pack(fill=tk.BOTH, expand=True)
text_area = output_text # Referensi untuk text_area
Dengan perbaikan ini:
Nada dapat langsung dimainkan dari speaker Android menggunakan pygame.
Fungsi mulai_putar_partitur akan mengambil notasi dari text_area, meneruskannya ke petakan_notasi_ke_audio, dan memulai pemutaran.
Fungsi hentikan_pemutaran menggunakan mixer.music.stop() untuk menghentikan nada.
Pada kode berikut, ketika nada nada dimainkn, kenapa nada pertama dibunyikan berkali kali sebanyak nada yang ada.
Kode:
import tkinter as tk
from tkinter import Menu, filedialog, simpledialog, messagebox, Frame, Label, Entry, Button
import pygame
from peta_nada import petakan_notasi_ke_audio
from pygame import mixer
import os
import time
from tkinter import Text
from tkinter import PhotoImage
import logging
logging.basicConfig(level=logging.INFO)
logging.info("Aplikasi mulai berjalan.")
# Setup UI
root = tk.Tk()
root.geometry("685x1385")
root.title("Partitur Notasi Angka Ke Audio")
# Inisialisasi pygame mixer
pygame.mixer.init()
# Fungsi untuk highlight teks yang sedang dimainkan
def highlight_nada(posisi_awal, posisi_akhir):
# Hapus highlight sebelumnya
text_area.tag_remove("highlight", "1.0", "end")
# Tambahkan highlight baru
text_area.tag_add("highlight", posisi_awal, posisi_akhir)
text_area.tag_config("highlight", background="yellow")
# Fungsi untuk memasukkan simbol notasi yang dipilih ke partitur
def insert_symbol(symbol):
output_text.insert(tk.INSERT, symbol + " ")
# Membuat canvas untuk konten partitur
output_text_canvas = tk.Canvas(root, width=800, height=600)
output_text_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Membuat frame untuk konten di dalam canvas
output_frame = tk.Frame(output_text_canvas)
output_text_canvas.create_window((0, 0), window=output_frame, anchor="nw")
# Membuat Text Widget untuk output
output_text = tk.Text(output_frame, wrap=tk.WORD, undo=True, width=80, height=50, font=("Courier", 8))
output_text.grid(row=5, column=0, columnspan=3, padx=10, pady=10)
# Referensi untuk text_area
text_area = output_text
# Membuat frame untuk simbol notasi
symbol_frame = tk.Frame(output_frame)
symbol_frame.grid(row=0, column=0, pady=5, sticky="w")
# Label instruksi simbol
symbol_label = tk.Label(symbol_frame, text="Simbol Notasi Angka:")
symbol_label.grid(row=0, column=0, columnspan=6, pady=(0, 5))
# Simbol notasi yang akan digunakan
symbol_options = [
"\u135E", "\u135F", "\u135D", "\u1A18", "\u0324", "\u1CDF",
"•", "••", "•••", "\u007C", "\u20E6", ":||", "/", "\\", "'",
"0", "♯", "♭", "\u2323", "\u0305", "\u0818", "\u07EB", "\u266D", "\u203F", "\u3022",
"\u2503", "\u2595", "\u0821", "\u2191", "\u2193"
]
# Loop untuk membuat tombol untuk setiap simbol
for i, symbol in enumerate(symbol_options):
button = tk.Button(symbol_frame, text=symbol, width=2, command=lambda s=symbol: insert_symbol(s))
button.grid(row=1 + i // 10, column=i % 10, padx=5, pady=5)
# Label instruksi di atas output_text
instruksi_label = tk.Label(output_frame, fg="tomato", text="Partitur Notasi Angka (Edit di bawah sini):")
instruksi_label.grid(row=1, column=0, padx=5, pady=5)
# Fungsi untuk menyimpan partitur ke file teks
def simpan_partitur():
file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
if file_path:
with open(file_path, 'w') as f:
f.write(output_text.get("1.0", tk.END))
messagebox.showinfo("Sukses", "Partitur berhasil disimpan.")
# Fungsi untuk memuat partitur dari file teks
def muat_partitur():
file_path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])
if file_path:
with open(file_path, 'r') as f:
partitur = f.read()
output_text.delete("1.0", tk.END)
output_text.insert(tk.INSERT, partitur)
# Misalnya di play_nada:
logging.info("Memulai play_nada.")
# Fungsi untuk memainkan audio berdasarkan notasi di output_text
def play_nada(i=0):
file_nada = None # Inisialisasi variabel file_nada
notasi = output_text.get("1.0", tk.END).strip().split() # Mengambil teks dari output_text dan membaginya menjadi daftar simbol
if i < len(notasi):
nada = notasi[i]
posisi_awal = text_area.search(nada, "1.0", tk.END)
if posisi_awal:
posisi_akhir = f"{posisi_awal}+{len(nada)}c"
highlight_nada(posisi_awal, posisi_akhir)
root.after(1000, play_nada, i + 1) # Delay 1 detik per nada
if not notasi:
messagebox.showwarning("Kosong", "Silakan masukkan notasi untuk diputar.")
return
try:
# Memetakan notasi ke audio dan menggabungkannya
hasil_audio = petakan_notasi_ke_audio(notasi)
if hasil_audio is None:
messagebox.showerror("Error", "Tidak ada hasil audio yang dihasilkan. Periksa format notasi atau fungsi petakan_notasi_ke_audio.")
if hasil_audio is not None:
# Simpan audio yang digabungkan sementara
temp_audio_file = "output_audio_temp.wav"
hasil_audio.export(temp_audio_file, format="wav")
else:
messagebox.showerror("Error", "Tidak ada hasil audio yang dihasilkan.")
return
# Inisialisasi pygame mixer dengan pengecekan error
if not pygame.mixer.get_init():
try:
pygame.mixer.init()
except pygame.error as e:
messagebox.showerror("Pygame Error", f"Gagal menginisialisasi mixer: {e}")
return
# Memuat dan memutar audio
try:
if os.path.exists(temp_audio_file):
pygame.mixer.music.load(temp_audio_file)
pygame.mixer.music.play()
# Tunggu hingga audio selesai diputar
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
else:
messagebox.showerror("File Error", "File audio tidak ditemukan.")
except pygame.error as e:
messagebox.showerror("Pygame Error", f"Kesalahan saat memuat atau memainkan audio: {e}")
finally:
# Membersihkan file audio sementara
if os.path.exists(temp_audio_file):
pygame.mixer.music.load(temp_audio_file)
else:
messagebox.showerror("File Error", "File audio sementara tidak ditemukan atau tidak dapat diakses.")
except Exception as e:
messagebox.showerror("Error", f"Terjadi kesalahan saat memproses audio: \n{e}")
finally:
if file_nada and os.path.exists(file_nada):
os.remove(file_nada)
logging.info("Selesai play_nada.")
# Atur frame untuk tombol di baris yang sama
button_frame = tk.Frame(output_frame)
button_frame.grid(row=2, column=0, sticky="w", columnspan=2, pady=(10, 0)) # Di atas partitur dan gunakan columnspan agar tombol berada di tengah
# Tambahkan tombol-tombol ke dalam frame
mainkan_button = tk.Button(button_frame, text="Mainkan", bg="purple", fg="white", command= play_nada)
mainkan_button.grid(row=0, column=0, padx=5)
simpan_button = tk.Button(button_frame, text="Simpan", bg="purple", fg="white", command= simpan_partitur)
simpan_button.grid(row=0, column=1, padx=5)
muat_button = tk.Button(button_frame, text="Buka", bg="purple", fg="white", command= muat_partitur)
muat_button.grid(row=0, column=2, padx=5)
# Fungsi untuk memasukkan simbol custom ke dalam teks partitur
def insert_custom_symbol():
output_text.image_create(tk.END, image=symbol_image)
button_8_font_custom = tk.Button(symbol_frame, text="7\u0305", width=3, command= insert_custom_symbol)
button_8_font_custom.grid(row=7, column=0, padx=5, pady=5)
# Simbol custom (gunakan gambar yang sudah kamu buat)
symbol_image = PhotoImage(file="garis_dua_atas.jpg") # Gambar untuk simbol '1 dengan titik di atas'
# Menambahkan tombol untuk notasi angka biasa (tanpa garis di atas)
button_1 = tk.Button(symbol_frame, text="1", width=3, command=lambda: insert_symbol("1"))
button_1.grid(row=5, column=0, padx=5, pady=5)
button_2 = tk.Button(symbol_frame, text="2", width=3, command=lambda: insert_symbol("2"))
button_2.grid(row=5, column=1, padx=5, pady=5)
button_3 = tk.Button(symbol_frame, text="3", width=3, command=lambda: insert_symbol("3"))
button_3.grid(row=5, column=2, padx=5, pady=5)
button_4 = tk.Button(symbol_frame, text="4", width=3, command=lambda: insert_symbol("4"))
button_4.grid(row=5, column=3, padx=5, pady=5)
button_5 = tk.Button(symbol_frame, text="5", width=3, command=lambda: insert_symbol("5"))
button_5.grid(row=5, column=4, padx=5, pady=5)
button_6 = tk.Button(symbol_frame, text="6", width=3, command=lambda: insert_symbol("6"))
button_6.grid(row=5, column=5, padx=5, pady=5)
button_7 = tk.Button(symbol_frame, text="7", width=3, command=lambda: insert_symbol("7"))
button_7.grid(row=5, column=6, padx=5, pady=5)
# Fungsi untuk menghentikan pemutaran
def hentikan_pemutaran():
mixer.music.stop()
text_area.tag_remove("highlight", "1.0", "end")
# Tombol untuk menghentikan pemutaran
stop_button = tk.Button(button_frame, text="Hentikan", bg="red", fg="white", command=hentikan_pemutaran)
stop_button.grid(row=1, column=1, padx=5)
try:
root.mainloop()
except Exception as e:
messagebox.showerror("Fatal Error", f"Aplikasi mengalami kesalahan fatal: {e}")
Masalah yang kamu hadapi, di mana nada pertama diputar berulang kali, kemungkinan disebabkan oleh beberapa faktor dalam fungsi play_nada. Pada fungsi ini, alur pemutaran nada mungkin salah urutannya atau terjadi penundaan (delay) yang tidak tepat. Mari kita periksa dan perbaiki beberapa hal yang penting:
1. Looping dan Alur Pemutaran Nada: Kode ini kemungkinan mengulang nada pertama karena alur play_nada tidak secara eksplisit menghentikan pemutaran atau menunggu dengan benar hingga audio selesai. Dengan root.after, seharusnya pemutaran dilanjutkan ke nada berikutnya setelah satu nada selesai, tapi ada beberapa logika yang bisa diperbaiki.
2. Kode highlight_nada: Fungsi ini sepertinya berfungsi baik, tetapi perlu dipastikan bahwa pemutaran audio sinkron dengan highlight teks.
Berikut perbaikan yang dapat dilakukan:
Memisahkan Logika Pemutaran dan Pengulangan Nada: Pastikan setiap nada hanya diputar sekali, lalu lanjutkan ke nada berikutnya. Kita bisa memodifikasi sedikit kode play_nada agar secara eksplisit memuat dan memutar satu per satu notasi, lalu menghentikan pemutaran untuk setiap nada sebelum lanjut ke nada berikutnya.
Mari kita modifikasi fungsi play_nada seperti berikut ini:
# Fungsi untuk memainkan audio berdasarkan notasi di output_text
def play_nada(i=0):
# Ambil semua notasi dari output_text
notasi = output_text.get("1.0", tk.END).strip().split()
# Pastikan ada notasi yang bisa dimainkan
if not notasi:
messagebox.showwarning("Kosong", "Silakan masukkan notasi untuk diputar.")
return
# Periksa apakah kita sudah selesai memainkan semua notasi
if i >= len(notasi):
return # Keluarkan dari fungsi saat sudah selesai
# Ambil nada saat ini dan posisinya di text_area
nada = notasi[i]
posisi_awal = text_area.search(nada, "1.0", tk.END)
if posisi_awal:
posisi_akhir = f"{posisi_awal}+{len(nada)}c"
highlight_nada(posisi_awal, posisi_akhir)
# Proses pemetaan notasi ke file audio untuk nada saat ini saja
hasil_audio = petakan_notasi_ke_audio([nada]) # hanya proses satu nada
# Simpan hasil audio sementara jika ada hasilnya
temp_audio_file = "output_audio_temp.wav"
if hasil_audio:
hasil_audio.export(temp_audio_file, format="wav")
# Mainkan file audio sementara
if os.path.exists(temp_audio_file):
pygame.mixer.music.load(temp_audio_file)
pygame.mixer.music.play()
# Tunda hingga audio selesai diputar, lalu lanjutkan ke nada berikutnya
while pygame.mixer.music.get_busy():
root.update() # Pastikan GUI tetap responsif
# Bersihkan file audio sementara setelah diputar
if os.path.exists(temp_audio_file):
os.remove(temp_audio_file)
# Lanjutkan ke nada berikutnya setelah 1 detik
root.after(1000, play_nada, i + 1)
Penjelasan Perubahan
1. Petakan Per Nada: Memanggil petakan_notasi_ke_audio([nada]) hanya untuk satu nada saja, bukan seluruh daftar notasi.
2. Looping yang Jelas dengan root.after: Setelah pemutaran selesai, gunakan root.after untuk memastikan kelanjutan ke nada berikutnya dengan jeda yang sama.
3. Membersihkan File Audio Sementara: Setelah setiap nada selesai diputar, file sementara dihapus sehingga tidak terjadi pengulangan nada yang sama.
Coba jalankan modifikasi ini, dan pastikan semua dependensi (seperti petakan_notasi_ke_audio) berfungsi sebagaimana mestinya.
Komentar
Posting Komentar
This Message