Slide 47 de 53

Um som é uma forma

Sustentada e percutida, lado a lado
import hive.ui

type Msg { Tick }

type Car {
	seat:  Int
	x:     Float
	z:     Float
	speed: Float
	knock: Bool
}

// Um func como todo outro construtor de formas deste arquivo, e vale notar
// que um som é exatamente tão valor quanto uma box: sessenta destes são
// construídos por segundo e jogados fora, enquanto a voz do outro lado do
// nome segue rodando o tempo todo.
func noises(cars: Car[]): ui.Shape[dyn] {
	mut ui.Shape[dyn] out = []
	for each car in cars {
		// Sustentada: dura enquanto a scene continuar a nomeando, e dobra
		// com a velocidade em vez de ser reiniciada em uma nova.
		append(out, ui.sound([
			ui.at(car.x, 0.6, car.z),
			ui.voice(ui.Voice.Engine()),
			ui.pitch(0.7 + car.speed / 90.0),
			ui.volume(0.6),
		], "engine-{car.seat}"))

		// Percutida: dispara quando o nome chega e fica surda a tudo depois
		// disso. Soltar o nome e trazê-lo de volta é um segundo impacto.
		if car.knock {
			append(out, ui.sound([
				ui.at(car.x, 0.6, car.z),
				ui.voice(ui.Voice.Impact()),
				ui.pitch(1.0),
				ui.volume(0.8),
			], "hit-{car.seat}"))
		}
	}
	return out
}

func view(cars: Car[dyn]): ui.View {
	solids := [ui.ground([ui.paint(ui.Tone.HEX("#3a3f45"))], 400.0, 400.0)]
	return ui.scene([
		ui.grow(1),
		ui.eye(0.0, 1.4, 6.0),
		ui.aim(0.0, 0.0),
		ui.background(ui.Tone.HEX("#8ec5ff")),
	], solids + noises(cars))
}

proc update(cars: Car[dyn], msg: Msg, envelope: hive.syslink.Envelope): Car[dyn] {
	return cars
}

proc main(): void {
	Car[dyn] grid = [Car(1, -2.0, 0.0, 40.0, false), Car(2, 2.0, -6.0, 62.0, true)]
	ui.window("Som", view, update, grid)
}
sound(attrs, nome) é a oitava forma de uma scene, e a única que é ouvida de onde está em vez de desenhada onde está. Ela recebe at como toda outra forma e três atributos próprios: voice(Voice) é que barulho ela é, pitch(Float) quão agudo e volume(Float) quão alto. Os dois são múltiplos daquela voz em repouso, e não hertz e decibéis — como um motor soa em 1.0 é assunto do renderizador, e um programa diz duas vezes mais rápido e metade do volume, que é o que ele de fato sabe.Um som está listado ao lado dos sólidos por um motivo que vale mais do que a estranheza custa: um barulho em um mundo tem um lugar nele, e um lugar é o que todo outro membro daquele conjunto já sabe carregar. Então ele é posicionado pelo mesmo at, escrito no mesmo frame, e chega à página com a mesma câmera que precisa ouvi-lo — onde um módulo próprio seria uma segunda descrição de onde as coisas estão.A carga é um nome, e o nome é a identidade da forma entre frames. Este é o único lugar em que o áudio não pode seguir a regra que os sólidos seguem. Uma box é casada com o que estava no lugar dela no frame anterior, porque uma view construída pelo mesmo código lista as mesmas coisas na mesma ordem — e uma box reconstruída mesmo assim é uma box que ninguém percebe que foi reconstruída. Um oscilador reconstruído mesmo assim é um clique, sessenta deles por segundo, e uma posição não pode prometer o contrário, porque uma scene é livre para parar de desenhar o carro da frente e todo som depois dele subiria uma posição e viraria outro motor. Então um nome que está neste frame e estava no anterior continua, um nome que acabou de chegar começa, e um nome que sumiu se apaga.Qual dessas coisas uma voz de fato faz pertence à voz, não ao programa. Engine, Tyres, Brakes, Wind, Crowd e Music são sustentadas: duram enquanto a scene continuar as nomeando. Impact e Chime são percutidas: disparam uma vez, quando o nome chega, e ficam surdas a tudo depois disso — porque uma batida é algo que aconteceu e não algo que está acontecendo, e um mundo de valores não tem outro jeito de dizer isso. Nomear "hit-3" enquanto um carro souber que bateu é um impacto só; soltar o nome e trazê-lo de volta é um segundo.Sons são posicionados e quem escuta é o próprio eye e aim da scene, então o que se ouve à esquerda é o que está desenhado à esquerda, e um carro passa pelo seu ouvido tanto quanto pelo seu olho. Music é a exceção, por não ter onde ficar, então nunca é panoramizada. E nada é baixado para nada disso: toda voz é osciladores e ruído filtrado, pelo mesmo motivo que uma Surface é um padrão desenhado e não uma imagem — um programa Hive construído é um arquivo só. Isso compra algo além de custar algo, já que uma voz feita de frequência pode ser dobrada, e um motor que é a gravação de uma rotação tocada mais rápido é um motor que dá para ouvir dando a volta.