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

Popular posts from this blog

PERBEDAAN CARA, TEKNIK, DAN JARAK ANTAR LUBANG DALAM PEMBUATAN SERULING BAMBU PADA MUSIK SISTEM 8-TET (8 NADA PER OKTAF) DENGAN MUSIK SISTEM 12-TET (12 NADA PER OKTAF)

KONSEP DAN METODOLOGI MUSIK 12 NADA DALAM 1 OKTAF

Grup Komunitas Pendukung Musik Sistem 12 TET (20 Nada per Oktaf)