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:
- Fundamental frequency: 440 Hz
- 2nd harmonic: 880 Hz
- 3rd harmonic: 1320 Hz
- 4th harmonic: 1760 Hz
- 5th harmonic: 2200 Hz
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()