Effets de bus

Un pluck généré routé de Voice vers FX puis Master, avec réverbe et distorsion que vous activez et le niveau crête de chaque bus à l'écran.

L'éditeur ci-dessus fait tourner ce projet. Changez une ligne et il se recharge.

Classes Godot utilisées

AudioServerAudioEffectReverbAudioEffectDistortion

Le code

scripts/main.gd
extends Node

const MIX_RATE: float = 22050.0
const PANEL: Vector2 = Vector2(210.0, 150.0)
const GAP: float = 120.0
const PLUCK_SECONDS: float = 0.55
const DECAY: float = 0.99975
const NOTES: Array = [261.63, 329.63, 392.00, 523.25]

var player: AudioStreamPlayer
var playback: AudioStreamGeneratorPlayback
var buses: Array[int] = []
var meters: Array[ColorRect] = []
var readouts: Array[Label] = []
var dots: Array[Polygon2D] = []
var wires: Array[Vector2] = []
var effect_labels: Array[Label] = []
var start_button: Button
var phase: float = 0.0
var level: float = 0.0
var note: int = 0
var elapsed: float = 0.0
var flow: float = 0.0


func _ready() -> void:
	_add_background()

	var view: Vector2 = get_viewport().get_visible_rect().size
	var width: float = PANEL.x * 3.0 + GAP * 2.0
	var left: float = (view.x - width) * 0.5
	var top: float = view.y * 0.3

	_add_label('Bus effects', Vector2(left, view.y * 0.09), 26, Color('#ffffff'))
	_add_label('one generated pluck routed Voice into FX into Master, with the peak of every bus below its name', Vector2(left, view.y * 0.15), 15, Color('#999999'))

	_wire_buses()

	for i in 3:
		_add_panel(['Voice', 'FX', 'Master'][i], Vector2(left + i * (PANEL.x + GAP), top))

	for i in 2:
		var from: float = left + i * (PANEL.x + GAP) + PANEL.x
		wires.append(Vector2(from, from + GAP))
		_add_wire(Vector2(from, top + PANEL.y * 0.5))

	_add_effect_labels(Vector2(left + PANEL.x + GAP + 16.0, top + 54.0))
	_add_controls(Vector2(left, top + PANEL.y + 70.0))
	_add_player()

	print('routing is live, press Start sound and toggle the two effects on the FX bus')


func _process(delta: float) -> void:
	flow = fmod(flow + delta * 0.6, 1.0)

	for i in dots.size():
		var at: float = fmod(flow + i * 0.5, 1.0)
		dots[i].position.x = lerpf(wires[i].x, wires[i].y, at)
		dots[i].modulate.a = (1.0 if playback != null else 0.55) * maxf(sin(at * PI), 0.35)

	for i in buses.size():
		var db: float = AudioServer.get_bus_peak_volume_left_db(buses[i], 0)
		var target: float = clampf((db + 60.0) / 60.0, 0.0, 1.0)

		meters[i].size.x = maxf(target * (PANEL.x - 32.0), 3.0)
		readouts[i].text = '%.0f dB' % maxf(db, -60.0)

	if playback == null:
		return

	elapsed += delta

	if elapsed >= PLUCK_SECONDS:
		elapsed -= PLUCK_SECONDS
		note = (note + 1) % NOTES.size()
		level = 0.5

	_fill_buffer()


func _fill_buffer() -> void:
	var hz: float = NOTES[note]

	for i in playback.get_frames_available():
		phase = fmod(phase + hz / MIX_RATE, 1.0)
		level *= DECAY
		var sample: float = (sin(phase * TAU) + sin(phase * TAU * 3.0) * 0.25) * level
		playback.push_frame(Vector2(sample, sample))


func _wire_buses() -> void:
	# a bus can only send to a lower index, so the downstream bus has to be created first
	var fx: int = _find_bus('FX', 'Master')
	var voice: int = _find_bus('Voice', 'FX')

	if AudioServer.get_bus_effect_count(fx) == 0:
		var reverb: AudioEffectReverb = AudioEffectReverb.new()
		reverb.room_size = 0.85
		reverb.wet = 0.6
		AudioServer.add_bus_effect(fx, reverb)

		var distortion: AudioEffectDistortion = AudioEffectDistortion.new()
		distortion.drive = 0.5
		distortion.pre_gain = 8.0
		distortion.post_gain = -14.0
		AudioServer.add_bus_effect(fx, distortion)

	AudioServer.set_bus_effect_enabled(fx, 0, false)
	AudioServer.set_bus_effect_enabled(fx, 1, false)

	buses.append(voice)
	buses.append(fx)
	buses.append(AudioServer.get_bus_index('Master'))


func _find_bus(bus: String, send: String) -> int:
	var index: int = AudioServer.get_bus_index(bus)

	if index != -1:
		return index

	index = AudioServer.get_bus_count()
	AudioServer.add_bus(index)
	AudioServer.set_bus_name(index, bus)
	AudioServer.set_bus_send(index, send)

	return index


func _toggle_effect(on: bool, slot: int) -> void:
	AudioServer.set_bus_effect_enabled(buses[1], slot, on)
	effect_labels[slot].add_theme_color_override('font_color', Color('#8eef97') if on else Color('#999999'))


func _toggle_sound() -> void:
	if playback != null:
		player.stop()
		playback = null
		level = 0.0
		start_button.text = 'Start sound'
		return

	player.play()
	playback = player.get_stream_playback()
	level = 0.5
	start_button.text = 'Stop sound'


func _add_panel(title: String, at: Vector2) -> void:
	var panel: ColorRect = ColorRect.new()
	panel.color = Color('#2a2f3d')
	panel.position = at
	panel.size = PANEL
	add_child(panel)

	_add_label(title, at + Vector2(16.0, 14.0), 20, Color('#ffffff'))

	var track: ColorRect = ColorRect.new()
	track.color = Color('#12141a')
	track.position = at + Vector2(16.0, PANEL.y - 46.0)
	track.size = Vector2(PANEL.x - 32.0, 16.0)
	add_child(track)

	var meter: ColorRect = ColorRect.new()
	meter.color = Color('#8eef97')
	meter.position = track.position
	meter.size = Vector2(3.0, 16.0)
	add_child(meter)
	meters.append(meter)

	readouts.append(_add_label('-60 dB', at + Vector2(16.0, PANEL.y - 26.0), 14, Color('#999999')))


func _add_wire(at: Vector2) -> void:
	var wire: ColorRect = ColorRect.new()
	wire.color = Color('#8da5f3', 0.3)
	wire.position = at - Vector2(0.0, 2.0)
	wire.size = Vector2(GAP, 4.0)
	add_child(wire)

	var dot: Polygon2D = Polygon2D.new()
	dot.color = Color('#8da5f3')
	dot.position = at
	dot.polygon = PackedVector2Array([Vector2(-11, 0), Vector2(0, -11), Vector2(11, 0), Vector2(0, 11)])
	add_child(dot)
	dots.append(dot)


func _add_effect_labels(at: Vector2) -> void:
	for i in 2:
		effect_labels.append(_add_label(['reverb', 'distortion'][i], at + Vector2(0.0, i * 24.0), 16, Color('#999999')))


func _add_controls(at: Vector2) -> void:
	var row: HBoxContainer = HBoxContainer.new()
	row.add_theme_constant_override('separation', 22)
	row.position = at
	add_child(row)

	for i in 2:
		var toggle: CheckButton = CheckButton.new()
		toggle.text = ['Reverb', 'Distortion'][i]
		toggle.toggled.connect(_toggle_effect.bind(i))
		row.add_child(toggle)

	start_button = Button.new()
	start_button.text = 'Start sound'
	start_button.pressed.connect(_toggle_sound)
	row.add_child(start_button)


func _add_player() -> void:
	var generator: AudioStreamGenerator = AudioStreamGenerator.new()
	generator.mix_rate = MIX_RATE
	generator.buffer_length = 0.1

	player = AudioStreamPlayer.new()
	player.stream = generator
	player.bus = 'Voice'
	add_child(player)


func _add_background() -> void:
	var background: ColorRect = ColorRect.new()
	background.color = Color('#12141a')
	add_child(background)
	background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)


func _add_label(text: String, at: Vector2, size: int, color: Color) -> Label:
	var label: Label = Label.new()
	label.text = text
	label.position = at
	label.add_theme_font_size_override('font_size', size)
	label.add_theme_color_override('font_color', color)
	add_child(label)

	return label

Plus d'exemples de Audio