# audio_miles_test —— MilesLib SoundManager 对齐回归。 # 验证 40250 的缩放、音量曲线和角色音效限频/距离规则。 extends SceneTree const Audio = preload("res://audio.gd") var _fail := 0 func _ck(condition: bool, message: String) -> void: if not condition: _fail += 1 printerr("FAIL: " + message) func _init() -> void: var audio := Audio.new() get_root().add_child(audio) _ck(is_equal_approx(Audio.SOUND_SCALE, 200.0), "sound scale is 200") _ck(is_equal_approx(Audio.AMBIENCE_SOUND_SCALE, 1000.0), "ambience scale is 1000") _ck(is_equal_approx(Audio.ratio_to_apply_volume(0.05), 0.05), "low ratio stays linear") _ck(is_equal_approx(Audio.ratio_to_apply_volume(0.5), pow(10.0, -0.5)), "ratio volume uses ClientVS22 logarithmic curve") _ck(is_equal_approx(Audio.grade_to_apply_volume(5), 1.0), "grade 5 maps to full volume") _ck(is_equal_approx(Audio.grade_to_apply_volume(0), 0.0), "grade 0 maps to silence") audio.set_sound_scale(320.0) audio.set_ambience_sound_scale(1200.0) _ck(is_equal_approx(audio.get_sound_scale(), 320.0), "sound scale setter") _ck(is_equal_approx(audio.get_ambience_sound_scale(), 1200.0), "ambience scale setter") audio.set_listener(Vector3.ZERO, Vector3(0, 0, -1), Vector3.UP) var assets := AssetRoot.path() if DirAccess.dir_exists_absolute(assets): audio.setup(assets) var mss := assets.path_join("sound_m/sound/pc/warrior/general/run.mss") if FileAccess.file_exists(mss): var data: Array = audio.load_sound_information_piece(mss) _ck(data.size() == 3, ".mss SoundDataCount and records parse") _ck(is_equal_approx(float(data[0]["time"]), 0.759), ".mss preserves event time") _ck(String(data[0]["sound"]) == "sound/common/walk_dirt_n.wav", ".mss preserves virtual sound path") var instances: Array = audio.data_to_sound_instances(data) _ck(int(instances[0]["frame"]) == 45 and int(instances[2]["frame"]) == 11, ".mss time converts to DWORD 60 FPS frames") _ck(audio._find_sound(String(data[0]["sound"])) != "", "virtual sound/ prefix resolves inside mounted sound root") var motion := assets.path_join("PC/ymir work/pc/warrior/general/run.msa") var motion_instances: Array = audio.load_mss_for_motion(motion) _ck(motion_instances.size() == 3, "motion .msa resolves paired .mss") var ambience := [{ "key": "waterfall-test", "position": Vector3(20, 0, 0), "range_cm": 3300, "max_volume_area_percentage": 0.5, "play_type": "LOOP", "sounds": ["sound/ambience/warp_test.mp3"], }] audio.update_ambience_sources(ambience) var ambience_state: Dictionary = audio._ambience_states.get("waterfall-test", {}) var ambience_id := int(ambience_state.get("id", -1)) _ck(ambience_id >= 0 and audio._active_3d.has(ambience_id), "area ambience LOOP creates a Miles 3D instance") if ambience_id >= 0 and audio._active_3d.has(ambience_id): var ambience_player: AudioStreamPlayer3D = audio._active_3d[ambience_id] _ck(abs(ambience_player.position.x - (20.0 * 100.0 / 1200.0)) < 0.001, "ambience source uses cm -> ambience scale conversion") audio.update_ambience_sources([]) _ck(not audio._ambience_states.has("waterfall-test") and not audio._active_3d.has(ambience_id), "leaving / unloading area ambience stops its loop") _ck(audio.can_play_character_sound("step.wav", Vector3(1, 0, 0), 10.0), "near character sound is allowed") _ck(not audio.can_play_character_sound("step.wav", Vector3(1, 0, 0), 10.2), "same character sound is suppressed within 0.3 seconds") _ck(audio.can_play_character_sound("step.wav", Vector3(1, 0, 0), 10.31), "same character sound resumes after 0.3 seconds") _ck(not audio.can_play_character_sound("far.wav", Vector3(51, 0, 0), 20.0), "character sound beyond 5000cm is suppressed") audio.set_sound_volume(0.0) _ck(is_equal_approx(audio.master_sfx, 0.0), "sound volume setter accepts silence") audio.stop_all_sound_3d() audio.free() if _fail == 0: print("PASS: audio_miles_test (scale + volume curve + character sound guard)") quit(0) else: printerr("%d check(s) failed" % _fail) quit(1)