KEYBOARD DIGITAL MENGHASILKAN BUNYI NADA PIANO DENGAN AMPLOP ADSR
KEYBOARD DIGITAL MENGHASILKAN BUNYI NADA PIANO DENGAN AMPLOP ADSR
Tolong implementasikan kode berikut:
# Fungsi untuk membuat gelombang nada dengan amplop ADSR
def generate_wave_with_adsr(frequency, duration, amplitude=0.5, sample_rate=44100):
t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
wave = np.sin(2 * np.pi * frequency * t)
# Amplop ADSR
attack_time = 0.02 # Waktu attack dalam detik
decay_time = 0.1 # Waktu decay dalam detik
sustain_level = 0.7 # Level sustain relatif terhadap amplitudo maksimum
release_time = 0.1 # Waktu release dalam detik
# Indeks untuk fase amplop
attack_samples = int(sample_rate * attack_time)
decay_samples = int(sample_rate * decay_time)
sustain_samples = int(sample_rate * (duration - attack_time - decay_time - release_time))
release_samples = int(sample_rate * release_time)
# Membentuk amplop ADSR
envelope = np.zeros_like(t)
envelope[:attack_samples] = np.linspace(0, 1, attack_samples) # Attack
envelope[attack_samples:attack_samples+decay_samples] = np.linspace(1, sustain_level, decay_samples) # Decay
envelope[attack_samples+decay_samples:attack_samples+decay_samples+sustain_samples] = sustain_level # Sustain
envelope[attack_samples+decay_samples+sustain_samples:] = np.linspace(sustain_level, 0, release_samples) # Release
# Menggabungkan gelombang dengan amplop
wave = (wave * envelope * amplitude * 32767).astype(np.int16)
return wave
# Fungsi untuk memainkan nada
def play_tone(frequency, duration=0.5, amplitude=0.5, sample_rate=44100):
wave_data = generate_wave_with_adsr(frequency, duration, amplitude, sample_rate)
sound = pygame.sndarray.make_sound(wave_data)
sound.play(-1)
pygame.time.delay(int(duration * 1000))
sound.stop()
Dengan kode yang ini:
import tkinter as tk
import numpy as np
import pygame
# Inisialisasi pygame mixer
pygame.mixer.init(frequency=44100, size=-16, channels=1, buffer=512)
# Frekuensi nada
frequencies_map = {
"E3": 67.975, "E#3": 71.813, "F3": 75.866, "F#3": 80.153, "G3": 84.68, "G#3": 89.462,
"H3": 94.512, "H#3": 99.846, "I3": 105.488, "J3": 111.442, "J#3": 117.734, "K3": 124.383,
"K#3": 131.41, "A3": 138.83, "A#3": 146.67, "B3": 154.953, "B#3": 163.693, "C3": 172.933,
"C#3": 182.103, "D3": 193.028,
"E4": 203.925, "E#4": 215.439, "F4": 227.597, "F#4": 240.46, "G4": 254.041, "G#4": 268.385,
"H4": 283.536, "H#4": 299.537, "I4": 316.463, "J4": 334.327, "J#4": 353.203, "K4": 373.149,
"K#4": 394.23, "A4": 416.49, "A#4": 440.00, "B4": 464.86, "B#4": 491.08, "C4": 518.80,
"C#4": 548.108, "D4": 579.084,
"E5": 611.776, "E#5": 646.316, "F5": 682.792, "F#5": 721.38, "G5": 762.124, "G#5": 805.156,
"H5": 850.608, "H#5": 898.612, "I5": 949.388, "J5": 1002.98, "J#5": 1059.608, "K5": 1119.448,
"K#5": 1182.676, "A5": 1249.468, "A#5": 1320.00, "B5": 1394.58, "B#5": 1473.24, "C5": 1556.40,
"C#5": 1644.324, "D5": 1737.252
}
# Fungsi untuk membuat gelombang nada
def generate_wave(frequency, duration, amplitude=0.5, sample_rate=44100):
t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
wave = (amplitude * np.sin(2 * np.pi * frequency * t) * 32767).astype(np.int16)
return wave
# Fungsi untuk memainkan nada
def play_tone(frequency, duration=0.5, amplitude=0.5, sample_rate=44100):
wave_data = generate_wave(frequency, duration, amplitude, sample_rate)
sound = pygame.sndarray.make_sound(wave_data)
sound.play(-1)
pygame.time.delay(int(duration * 1000))
sound.stop()
# Class untuk Keyboard Digital
class DigitalKeyboard12TET:
def __init__(self, root):
self.root = root
self.root.title("Keyboard Digital (Mapping Nada)")
# Canvas untuk menggambar keyboard
self.canvas = tk.Canvas(root, width=1400, height=400, bg="lightgrey")
self.canvas.pack()
# Susunan nada untuk tuts putih dan hitam dalam tiga oktaf
white_notes = ['E', 'F', 'G', 'H', 'I', 'J', 'K', 'A', 'B', 'C', 'D']
black_notes = ["E#", "F#", "G#", "H#", "J#", "K#", "A#", "B#", "C#"]
octaves = [3, 4, 5]
# Menggambar tuts putih
self.white_keys = []
num_white_keys = len(white_notes) * len(octaves)
for i in range(num_white_keys):
x1 = 10 + i * 40
y1 = 50
x2 = x1 + 30
y2 = y1 + 155
octave = octaves[i // len(white_notes)]
note = f"{white_notes[i % len(white_notes)]}{octave}"
key = self.canvas.create_rectangle(x1, y1, x2, y2, fill="white", outline="black", tags=f"white_{i}")
self.white_keys.append(key)
self.canvas.create_text((x1 + x2) / 2, y2 + 10, text=note, font=("Arial", 5))
freq = frequencies_map.get(note, 0)
self.canvas.tag_bind(f"white_{i}", "<Button-1>", lambda event, f=freq: self.on_key_click(f))
# Menggambar tuts hitam
self.black_keys = []
black_positions = [0, 1, 2, 3, 5, 6, 7, 8, 9]
for i in range(num_white_keys // len(white_notes) * len(black_positions)):
octave_offset = i // len(black_positions)
position = black_positions[i % len(black_positions)] + octave_offset * len(white_notes)
if position < num_white_keys:
x1 = 35 + position * 40
y1 = 50
x2 = x1 + 20
y2 = y1 + 85
octave = octaves[octave_offset]
note = f"{black_notes[i % len(black_notes)]}{octave}"
key = self.canvas.create_rectangle(x1, y1, x2, y2, fill="black", outline="black", tags=f"black_{i}")
self.black_keys.append(key)
self.canvas.create_text((x1 + x2) / 2, y2 - 10, text=note, fill="white", font=("Arial", 3))
freq = frequencies_map.get(note, 0)
self.canvas.tag_bind(f"black_{i}", "<Button-1>", lambda event, f=freq: self.on_key_click(f))
def on_key_click(self, frequency):
play_tone(frequency)
print(f"Key pressed, frequency: {frequency} Hz")
# Jalankan aplikasi
root = tk.Tk()
keyboard = DigitalKeyboard12TET(root)
root.mainloop()
Untuk membuat nada terdengar seperti instrumen piano, kita bisa menambahkan karakteristik yang meniru suara piano dengan mengubah amplitudo gelombang menjadi bentuk amplop (envelope). Amplop ini biasanya terdiri dari empat fase: Attack, Decay, Sustain, dan Release (ADSR). Implementasi berikut ini memodifikasi fungsi generate_wave agar menggunakan amplop ADSR:
Berikut adalah implementasi kode yang menggabungkan fungsi generate_wave_with_adsr dengan play_tone ke dalam aplikasi DigitalKeyboard12TET. Hal ini memungkinkan setiap tuts menghasilkan nada dengan amplop ADSR. Berikut kode lengkapnya:
Modifikasi Kode:
import tkinter as tk
import numpy as np
import pygame
# Inisialisasi pygame mixer
pygame.mixer.init(frequency=44100, size=-16, channels=1, buffer=512)
# Frekuensi nada
frequencies_map = {
"E3": 67.975, "E#3": 71.813, "F3": 75.866, "F#3": 80.153, "G3": 84.68, "G#3": 89.462,
"H3": 94.512, "H#3": 99.846, "I3": 105.488, "J3": 111.442, "J#3": 117.734, "K3": 124.383,
"K#3": 131.41, "A3": 138.83, "A#3": 146.67, "B3": 154.953, "B#3": 163.693, "C3": 172.933,
"C#3": 182.103, "D3": 193.028,
"E4": 203.925, "E#4": 215.439, "F4": 227.597, "F#4": 240.46, "G4": 254.041, "G#4": 268.385,
"H4": 283.536, "H#4": 299.537, "I4": 316.463, "J4": 334.327, "J#4": 353.203, "K4": 373.149,
"K#4": 394.23, "A4": 416.49, "A#4": 440.00, "B4": 464.86, "B#4": 491.08, "C4": 518.80,
"C#4": 548.108, "D4": 579.084,
"E5": 611.776, "E#5": 646.316, "F5": 682.792, "F#5": 721.38, "G5": 762.124, "G#5": 805.156,
"H5": 850.608, "H#5": 898.612, "I5": 949.388, "J5": 1002.98, "J#5": 1059.608, "K5": 1119.448,
"K#5": 1182.676, "A5": 1249.468, "A#5": 1320.00, "B5": 1394.58, "B#5": 1473.24, "C5": 1556.40,
"C#5": 1644.324, "D5": 1737.252
}
# Fungsi untuk membuat gelombang nada dengan amplop ADSR
def generate_wave_with_adsr(frequency, duration, amplitude=0.5, sample_rate=44100):
t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
wave = np.sin(2 * np.pi * frequency * t)
# Amplop ADSR
attack_time = 0.02 # Waktu attack dalam detik
decay_time = 0.1 # Waktu decay dalam detik
sustain_level = 0.7 # Level sustain relatif terhadap amplitudo maksimum
release_time = 0.1 # Waktu release dalam detik
# Indeks untuk fase amplop
attack_samples = int(sample_rate * attack_time)
decay_samples = int(sample_rate * decay_time)
sustain_samples = int(sample_rate * (duration - attack_time - decay_time - release_time))
release_samples = int(sample_rate * release_time)
# Membentuk amplop ADSR
envelope = np.zeros_like(t)
envelope[:attack_samples] = np.linspace(0, 1, attack_samples) # Attack
envelope[attack_samples:attack_samples+decay_samples] = np.linspace(1, sustain_level, decay_samples) # Decay
envelope[attack_samples+decay_samples:attack_samples+decay_samples+sustain_samples] = sustain_level # Sustain
envelope[attack_samples+decay_samples+sustain_samples:] = np.linspace(sustain_level, 0, release_samples) # Release
# Menggabungkan gelombang dengan amplop
wave = (wave * envelope * amplitude * 32767).astype(np.int16)
return wave
# Fungsi untuk memainkan nada
def play_tone(frequency, duration=0.5, amplitude=0.5, sample_rate=44100):
wave_data = generate_wave_with_adsr(frequency, duration, amplitude, sample_rate)
sound = pygame.sndarray.make_sound(wave_data)
sound.play(-1)
pygame.time.delay(int(duration * 1000))
sound.stop()
# Class untuk Keyboard Digital
class DigitalKeyboard12TET:
def __init__(self, root):
self.root = root
self.root.title("Keyboard Digital (Mapping Nada)")
# Canvas untuk menggambar keyboard
self.canvas = tk.Canvas(root, width=1400, height=400, bg="lightgrey")
self.canvas.pack()
# Susunan nada untuk tuts putih dan hitam dalam tiga oktaf
white_notes = ['E', 'F', 'G', 'H', 'I', 'J', 'K', 'A', 'B', 'C', 'D']
black_notes = ["E#", "F#", "G#", "H#", "J#", "K#", "A#", "B#", "C#"]
octaves = [3, 4, 5]
# Menggambar tuts putih
self.white_keys = []
num_white_keys = len(white_notes) * len(octaves)
for i in range(num_white_keys):
x1 = 10 + i * 40
y1 = 50
x2 = x1 + 30
y2 = y1 + 155
octave = octaves[i // len(white_notes)]
note = f"{white_notes[i % len(white_notes)]}{octave}"
key = self.canvas.create_rectangle(x1, y1, x2, y2, fill="white", outline="black", tags=f"white_{i}")
self.white_keys.append(key)
self.canvas.create_text((x1 + x2) / 2, y2 + 10, text=note, font=("Arial", 5))
freq = frequencies_map.get(note, 0)
self.canvas.tag_bind(f"white_{i}", "<Button-1>", lambda event, f=freq: self.on_key_click(f))
# Menggambar tuts hitam
self.black_keys = []
black_positions = [0, 1, 2, 3, 5, 6, 7, 8, 9]
for i in range(num_white_keys // len(white_notes) * len(black_positions)):
octave_offset = i // len(black_positions)
position = black_positions[i % len(black_positions)] + octave_offset * len(white_notes)
if position < num_white_keys:
x1 = 35 + position * 40
y1 = 50
x2 = x1 + 20
y2 = y1 + 85
octave = octaves[octave_offset]
note = f"{black_notes[i % len(black_notes)]}{octave}"
key = self.canvas.create_rectangle(x1, y1, x2, y2, fill="black", outline="black", tags=f"black_{i}")
self.black_keys.append(key)
self.canvas.create_text((x1 + x2) / 2, y2 - 10, text=note, fill="white", font=("Arial", 3))
freq = frequencies_map.get(note, 0)
self.canvas.tag_bind(f"black_{i}", "<Button-1>", lambda event, f=freq: self.on_key_click(f))
def on_key_click(self, frequency):
play_tone(frequency)
print(f"Key pressed, frequency: {frequency} Hz")
# Jalankan aplikasi
root = tk.Tk()
keyboard = DigitalKeyboard12TET(root)
root.mainloop()
Penyesuaian:
1. Envelope ADSR memberikan kesan instrumen piano karena bentuk amplitudo suara piano berkurang secara alami dari serangan awal yang kuat (attack) ke nada yang lebih tenang (sustain) hingga menghilang (release).
2. Anda hanya perlu mengganti fungsi generate_wave dengan generate_wave_with_adsr.
3. Kode ini menggabungkan fungsi generate_wave_with_adsr untuk menciptakan amplop ADSR dan digunakan saat memainkan setiap nada. Anda dapat menjalankan skrip ini untuk melihat hasilnya.
Jalankan Program:
Setelah modifikasi, jalankan kode seperti sebelumnya. Suara yang dihasilkan dari setiap tuts akan memiliki karakteristik piano. Anda bisa menyesuaikan durasi setiap fase amplop (attack, decay, sustain, release) untuk mendekati suara piano yang diinginkan.
Bagaimana apakah bisa jika setiap mada dimainkan oleh instrumen gitar
Ya, setiap nada pada keyboard digital dapat dimainkan menggunakan instrumen gitar jika menggunakan sampling suara gitar atau sintesis suara gitar. Anda perlu mengganti cara nada dihasilkan pada aplikasi sehingga mendekati karakteristik suara gitar. Ada beberapa pendekatan untuk mencapainya:
1. Menggunakan Sampel Audio Gitar
- Rekam setiap nada gitar (misalnya nada "E3", "F3", "G3", dll.) dalam format .wav atau gunakan pustaka audio gitar yang sudah tersedia.
- Saat sebuah nada dimainkan di aplikasi, alih-alih menghasilkan gelombang sinus, gunakan pustaka seperti pygame.mixer.Sound untuk memutar file audio yang sesuai.
Modifikasi Kode:
- Tambahkan folder dengan sampel audio gitar (contoh: guitar_samples/).
- Mapkan setiap nada ke file audio.
- Gunakan pustaka pygame.mixer.Sound untuk memainkan file tersebut.
Contoh:
# Map frekuensi ke file audio gitar
guitar_samples_map = {
"E3": "guitar_samples/E3.wav",
"F3": "guitar_samples/F3.wav",
# Tambahkan semua nada yang dibutuhkan...
}
def play_tone(note):
sample_file = guitar_samples_map.get(note)
if sample_file:
sound = pygame.mixer.Sound(sample_file)
sound.play()
else:
print(f"No sample available for {note}")
2. Menggunakan Sintesis Suara Gitar
- Gunakan model matematis atau sintesis fisik gitar untuk menghasilkan nada.
- Algoritma seperti Karplus-Strong String Synthesis cocok untuk menciptakan suara gitar yang realistis. Algoritma ini bekerja dengan memodelkan getaran senar gitar.
Contoh Implementasi:
def karplus_strong(frequency, duration, sample_rate=44100):
N = int(sample_rate / frequency)
buffer = np.random.uniform(-1, 1, N)
samples = []
for i in range(int(sample_rate * duration)):
samples.append(buffer[0])
avg = 0.996 * (buffer[0] + buffer[1]) / 2 # Faktor redaman
buffer = np.append(buffer[1:], avg)
return np.array(samples)
def play_tone(frequency, duration=0.5):
wave_data = karplus_strong(frequency, duration) * 32767
wave_data = wave_data.astype(np.int16)
sound = pygame.sndarray.make_sound(wave_data)
sound.play(-1)
pygame.time.delay(int(duration * 1000))
sound.stop()
3. Menggunakan Pustaka Virtual Instrument
- Gunakan pustaka yang mendukung sintesis suara gitar, seperti:
- MIDI dengan Suara Gitar: mido atau pygame.midi untuk mengontrol instrumen MIDI virtual.
- Pustaka Syth atau Plugin Gitar Virtual: Gunakan pustaka seperti FluidSynth atau perangkat lunak seperti Kontakt untuk memuat suara gitar.
Langkah-Langkah Implementasi:
1. Rekam Sampel atau Unduh Suara Gitar untuk semua nada.
2. Ubah Fungsi play_tone untuk memutar suara gitar alih-alih menghasilkan gelombang sinus.
3. Integrasikan suara gitar ke dalam antarmuka keyboard digital Anda.
Apakah Anda ingin bantuan dalam mengimplementasikan salah satu metode ini?
Comments
Post a Comment