Python Sound Generator The following example demonstrates how to generate a simple sound. Each sound should have its own Python file in which the sound is defined (Section 1). Afterwards, the files are converted into a playable WAV file using create.py (Section 2). The goal was to generate sounds using simple Python code.
import numpy as np

SAMPLE_RATE = 44100

def sound():

    duration = 2

    t = np.linspace(
        0,
        duration,
        int(SAMPLE_RATE * duration),
        False
    )

    freq = 440

    signal = (
        1.0 * np.sin(2 * np.pi * freq * t)
        + 0.8 * np.sin(2 * np.pi * freq * 2 * t)
        + 0.6 * np.sin(2 * np.pi * freq * 3 * t)
        + 0.4 * np.sin(2 * np.pi * freq * 4 * t)
        + 0.2 * np.sin(2 * np.pi * freq * 5 * t)
    )

    env = np.ones(len(signal))

    fade_in = int(0.02 * SAMPLE_RATE)
    fade_out = int(0.20 * SAMPLE_RATE)

    env[:fade_in] = np.linspace(
        0,
        1,
        fade_in
    )

    env[-fade_out:] = np.linspace(
        1,
        0,
        fade_out
    )

    signal *= env

    signal /= np.max(np.abs(signal))

    return signal * 0.3

1. Sample Rate

SAMPLE_RATE = 44100

Explanation

The sample rate determines how many samples are calculated per second. A sample rate of 44,100 Hz corresponds to CD-quality audio. For a two-second sound, a total of 88,200 samples are generated.


2. Duration

duration = 2

Explanation

This defines that the generated sound should last for two seconds.


3. Time Axis

t = np.linspace(
    0,
    duration,
    int(SAMPLE_RATE * duration),
    False
)

Explanation

np.linspace() creates the time axis. A timestamp is generated for every individual sample. These values are later used by the sine functions.


4. Frequency

freq = 440

Explanation

440 Hz corresponds to the musical note A4 (concert pitch). The waveform repeats 440 times per second.


5. Sine Waves

signal = (
    ...
)

Explanation

Five sine waves are added together:

Different amplitudes of the harmonics create a richer and more natural sounding tone than a single sine wave.


6. Envelope

env = np.ones(len(signal))

Explanation

The envelope controls the volume over time. Initially, every sample has the value 1, so the signal remains unchanged.


7. Fade In and Fade Out

fade_in = int(0.02 * SAMPLE_RATE)
fade_out = int(0.20 * SAMPLE_RATE)

Explanation

The sound fades in over 20 ms and fades out over 200 ms, preventing audible clicks.


8. Apply Envelope

signal *= env

Explanation

Every sample is multiplied by the corresponding envelope value, changing the volume over time.


9. Normalization

signal /= np.max(np.abs(signal))

Explanation

Adding multiple sine waves can produce values greater than 1. Normalization scales the signal so that the maximum amplitude becomes exactly 1, preventing clipping.


10. Volume

return signal * 0.3

Explanation

Finally, the overall volume is reduced to 30 %. The waveform itself remains unchanged; only the loudness is reduced.

WAV Creator

This program automatically creates WAV files from Python sound files. All Python files inside the sounds directory are detected automatically and can be selected through a graphical user interface.

import os
import tkinter as tk
from tkinter import ttk, messagebox
import importlib
import numpy as np
from scipy.io.wavfile import write

SAMPLE_RATE = 44100


def create_wav():

    sound_name = combo.get()

    if not sound_name:
        messagebox.showwarning(
            "Hinweis",
            "Bitte einen Sound auswählen."
        )
        return

    sound_module = importlib.import_module(
        f"sounds.{sound_name}"
    )

    sound = sound_module.sound()

    sound /= np.max(np.abs(sound))

    audio = (sound * 32767).astype(np.int16)

    # Ordner "wav" erstellen, falls er nicht existiert
    os.makedirs("wav", exist_ok=True)

    base_name = sound_name

    output_file = os.path.join(
        "wav",
        f"{base_name}.wav"
    )

    counter = 1

    while os.path.exists(output_file):
        output_file = os.path.join(
            "wav",
            f"{base_name} ({counter}).wav"
        )
        counter += 1

    # WAV-Datei speichern
    write(
        output_file,
        SAMPLE_RATE,
        audio
    )

    messagebox.showinfo(
        "Fertig",
        f"{output_file} wurde erstellt."
    )


files = sorted([
    f[:-3]
    for f in os.listdir("sounds")
    if f.endswith(".py") and not f.startswith("__")
])

root = tk.Tk()
root.title("WAV Creator")
root.geometry("350x160")

ttk.Label(
    root,
    text="Sound auswählen:"
).pack(pady=(15,5))

combo = ttk.Combobox(
    root,
    values=files,
    state="readonly"
)
combo.pack(fill="x", padx=20)

if files:
    combo.current(0)

ttk.Button(
    root,
    text="WAV erstellen",
    command=create_wav
).pack(pady=20)

root.mainloop()