#!/usr/bin/env python3 """ make-sounds.py - sintetiza os dois efeitos sonoros do martelo do Neverwell Moor para o fredygames.com. Os dois originais (mallet_swing.ogg e mallet_whomp.ogg, atribuidos a "Etherian") nao tem licenca registrada, entao o site nao os usa. Este script gera outros, do zero, com os mesmos nomes de arquivo, que o jogo carrega sem mudanca: o balanco do martelo (um sopro de ruido filtrado que sobe e desce) e a pancada (uma batida grave com um estalo). Sao sons simples (senoides, ruido filtrado, envelopes), criados pelo FredyGames e dedicados ao dominio publico (CC0 1.0). A saida e deterministica (o ruido vem de um gerador com semente fixa). python3 -I make-sounds.py # escreve mallet_swing.wav e mallet_whomp.wav (44,1 kHz, 16 bits, estereo) O build-neverwell-moor.sh codifica cada .wav em Ogg Vorbis com o wav2ogg (qualidade 0.3). """ import math, random, struct, sys, wave, os RATE = 44100 def n(sec): return int(sec * RATE) def mix(*parts): out = [0.0] * max(len(p) for p in parts) for p in parts: for i, v in enumerate(p): out[i] += v return out def delay(sig, sec): return [0.0] * n(sec) + sig def sweep_noise(sec, seed, amp_fn, cutoff_fn): """Ruido branco por um passa-baixa de um polo cuja frequencia de corte (0..1) muda no tempo.""" rng = random.Random(seed) out, y = [], 0.0 for i in range(n(sec)): t = i / RATE y += cutoff_fn(t) * (rng.uniform(-1, 1) - y) out.append(y * amp_fn(t)) return out def thump(freq0, freq1, sec, rate, amp=1.0): ph, out = 0.0, [] for i in range(n(sec)): t = i / RATE ph += 2 * math.pi * (freq1 + (freq0 - freq1) * math.exp(-t * 25)) / RATE out.append(math.sin(ph) * amp * math.exp(-rate * t)) return out def click(seed, amp, sec): rng = random.Random(seed) out, y = [], 0.0 for i in range(n(sec)): x = rng.uniform(-1, 1) y += 0.6 * (x - y) out.append((x - y) * amp * math.exp(-i / RATE * 300)) return out def sounds(): dur = 0.32 swing = sweep_noise(dur, 21, lambda t: math.sin(math.pi * t / dur) ** 2 * 0.9, lambda t: 0.04 + 0.28 * math.sin(math.pi * t / dur)) whomp = mix(thump(150, 55, 0.45, 9, 1.0), click(22, 0.5, 0.03), sweep_noise(0.2, 23, lambda t: 0.5 * math.exp(-18 * t), lambda t: 0.15)) return {'mallet_swing': swing, 'mallet_whomp': whomp} def write(path, sig): peak = max(abs(v) for v in sig) or 1.0 scale = 0.7 / peak fade = n(0.005) frames = bytearray() for i, v in enumerate(sig): g = min(1.0, i / fade, (len(sig) - i) / fade) x = int(max(-1.0, min(1.0, v * scale * g)) * 32767) frames += struct.pack('