20. November 2024
Sampler für lange Samples
Auf der Suche nach einem Sampler / Sampleplayer bzw. Rompler, der lange Samples abspielen kann musste ich überrascht feststellen: Es gibt kaum ein Gerät, das diese Anforderungen erfüllt.
Gesucht habe ich ein Gerät, das mit Hilfe eines MIDI-Keyboards gesteuert werden kann und mehrere Audiofiles – idealerweise mp3s – gleichzeitig abspielen kann. Dabei sollte es keine Rolle spielen, ob die Sounds 3 Sekunden oder 10 Minuten lang sind. Eines der wenigen Geräte, das mit langen Audiofiles umgehen kann, scheint die „1010music Blackbox“ zu sein. Die ist allerdings mit 650€ nicht gerade ein Schnäppchen.
Bei meiner weiteren Suche bin auf ein spannendes Projekt namens „SamplerBox“ gestoßen.
„SamplerBox“ ist eine Software, die auf einem Raspberry Pi installiert werden kann. Samples können direkt von einem USB-Stick aus abgespielt werden. Hierfür müssen Sie lediglich durchnummeriert werden. Das C3 hat z.B. die MIDI-Note-Nr. 48 – also lautet der Dateiname 48.wav.
Eigentlich genau das, was ich gesucht habe – auch wenn SamplerBox eher als „Instrument“ gedacht ist und die Samples im Sinne des Entwicklers nur aus einem einzigen Ton bestehen. Problem ist hierbei – zumindest in meinem Fall -, dass die Samples nur so lange gespielt werden, wie die Taste gehalten wird.
Also: Selber machen! 🙂
Mit Hilfe von ChatGPT habe ich ein Python-Skript entwickelt, das schon ziemlich genau meinen Anforderungen entspricht:
- Samples können als mp3 geladen werden
- auch lange Samples können abgespielt werden
- Steuerung erfolgt über ein MIDI-Keyboard
- Samples sind nach Notennamen benannt (z.B. C3.mp3)
- Samples können gestoppt werden (Doppelklick)
Auf dem Mac funktioniert das Skript bislang ganz gut. Geplant ist, das Skript auf einem Raspberry Pi laufen zu lassen. Sobald ich das gemacht habe, werde ich die Erfahrungen hier teilen.
So kannst du das Skript auf dem Mac nutzen:
Öffne das Terminal und installiere „pygame“.
pip3 install pygame
Speichere das untenstehende Skript als sampler.py. Kopiere die Samples in das gleiche Verzeichnis wie „sampler.py“. Navigiere im Terminal in das Verzeichnis. z.B.:
cd musik/dev
Starte das Skript mit dem Befehl
python3 sampler.py
Code-Sprache: CSS (css)
Wenn ein MIDI-Keyboard angeschlossen ist, kannst du damit jetzt Samples abspielen.
import pygame.midi
import pygame.mixer
import os
import time
DOUBLE_CLICK_THRESHOLD = 0.3
note_channels = {}
note_last_press_time = {}
loaded_sounds = {}
def initialize_midi():
pygame.midi.init()
midi_device_id = None
for i in range(pygame.midi.get_count()):
info = pygame.midi.get_device_info(i)
if info[2] == 1: # Überprüfen, ob das Gerät ein Eingabegerät ist
midi_device_id = i
print(f"MIDI-Gerät gefunden: {info[1].decode()} (ID: {i})")
break
if midi_device_id is None:
raise Exception("Kein MIDI-Eingabegerät gefunden.")
return pygame.midi.Input(midi_device_id)
def initialize_audio(buffer_size=1024):
pygame.mixer.pre_init(44100, -16, 2, buffer_size) # Erhöht die Puffergröße
pygame.mixer.init()
pygame.mixer.set_num_channels(64) # Mehr Kanäle erlauben
print("Audio-System initialisiert.")
def preload_samples():
for file in os.listdir():
if file.endswith(".mp3"):
note_name = os.path.splitext(file)[0]
loaded_sounds[note_name] = pygame.mixer.Sound(file)
print(f"Geladen: {file}")
def play_or_stop_sample(note_name, note):
current_time = time.time()
if note in note_last_press_time:
elapsed_time = current_time - note_last_press_time[note]
if elapsed_time <= DOUBLE_CLICK_THRESHOLD:
# Doppelklick erkannt -> Stoppe das zugehörige Sample
if note in note_channels:
channel = note_channels[note]
channel.stop()
print(f"Doppelklick erkannt: Stoppe {note_name}.")
del note_channels[note] # Entferne die Zuordnung der Note
note_last_press_time.pop(note, None)
return
if note_name in loaded_sounds:
sound = loaded_sounds[note_name]
if note in note_channels:
channel = note_channels[note]
channel.stop()
channel = sound.play()
note_channels[note] = channel # Speichere den neuen Kanal
print(f"Spiele Datei: {note_name}.mp3")
else:
print(f"MP3-Datei nicht gefunden: {note_name}.mp3")
note_last_press_time[note] = current_time
def midi_note_to_name(note):
octave = (note // 12) - 1
note_names = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
name = note_names[note % 12]
return f"{name}{octave}"
def main():
try:
midi_input = initialize_midi()
initialize_audio()
preload_samples()
print("Drücke eine Taste auf dem MIDI-Keyboard (Strg+C zum Beenden).")
while True:
if midi_input.poll():
midi_events = midi_input.read(10)
for event in midi_events:
data = event[0]
status, note, velocity, _ = data
if status == 144 and velocity > 0: # Note On
note_name = midi_note_to_name(note)
play_or_stop_sample(note_name, note)
except KeyboardInterrupt:
print("\nProgramm beendet.")
finally:
pygame.midi.quit()
pygame.mixer.quit()
if __name__ == "__main__":
main()
Code-Sprache: PHP (php)