39 lines
1.2 KiB
Python
39 lines
1.2 KiB
Python
import io
|
|
from pathlib import Path
|
|
|
|
from pydub import AudioSegment
|
|
|
|
from backend.models import ExportRequest, SwitchType
|
|
|
|
SAMPLE_RATE = 48000
|
|
SAMPLES_DIR = Path(__file__).resolve().parent.parent / "assets" / "samples"
|
|
|
|
SWITCH_FILES: dict[SwitchType, str] = {
|
|
"cherry-mx-blue": "cherry-mx-blue.wav",
|
|
"cherry-mx-red": "cherry-mx-red.wav",
|
|
"cherry-mx-brown": "cherry-mx-brown.wav",
|
|
}
|
|
|
|
|
|
def _load_sample(switch: SwitchType) -> AudioSegment:
|
|
path = SAMPLES_DIR / SWITCH_FILES[switch]
|
|
if not path.exists():
|
|
raise FileNotFoundError(f"Sample not found: {path}")
|
|
sample = AudioSegment.from_file(path)
|
|
return sample.set_frame_rate(SAMPLE_RATE).set_channels(2)
|
|
|
|
|
|
def export_keyboard_audio(request: ExportRequest) -> bytes:
|
|
duration_ms = int(request.duration * 1000)
|
|
base = AudioSegment.silent(duration=duration_ms, frame_rate=SAMPLE_RATE)
|
|
click = _load_sample(request.switch)
|
|
|
|
for marker in sorted(request.markers, key=lambda m: m.time):
|
|
position_ms = int(marker.time * 1000)
|
|
if position_ms < duration_ms:
|
|
base = base.overlay(click, position=position_ms)
|
|
|
|
buffer = io.BytesIO()
|
|
base.export(buffer, format="wav")
|
|
return buffer.getvalue()
|