Files
PNGTuber-Plus/autoload/global.gd
Max Litruv Boonzaayer 8ba361f3c2 Integrate microphone improvements from k0ffinz repository
- Add experimental microphone loudness detection feature
- Remove microphone restart interval for better stability
- Improve microphone initialization and error handling
- Fix audio delay issues by setting channel_disable_time=0.0
- Update settings UI to include experimental mic loudness toggle
- Add credits to k0ffinz/Ralsi for microphone improvements

These changes improve audio responsiveness and fix various
microphone-related issues including WASAPI errors and growing
audio delay problems.
2025-07-19 22:00:53 +10:00

352 lines
7.7 KiB
GDScript

extends Node
#Global Node Reference
var main = null
var spriteEdit = null
var fail = null
var mouse = null
var spriteList = null
var chain = null
var animationTick = 0
var filtering = false
#Object Selection
var heldSprite = null
var lastArray = []
var i = 0
var reparentMode = false
var scrollSelection = 0
var backgroundColor = Color(0.0,0.0,0.0,0.0)
#Blink
var blinkSpeed = 1.0
var blinkChance = 200
var blink = false
var blinkTick = 0
#Audio Listener
var playa:AudioStreamPlayer
var speaking = false
var spectrum
var volume = 0
var volumeSensitivity = 0.0
var experimentalMicLoudness = false
var volumeLimit = 0.0
var senseLimit = 0.0
#Speak Signals
signal startSpeaking
signal stopSpeaking
var updatePusherNode = null
var rand = RandomNumberGenerator.new()
func _ready():
spectrum = AudioServer.get_bus_effect_instance(1, 1)
if !Saving.settings.has("useStreamDeck"):
Saving.settings["useStreamDeck"] = false
if Saving.settings.has("experimentalMicLoudness"):
Global.experimentalMicLoudness = Saving.settings["experimentalMicLoudness"]
else:
Saving.settings["experimentalMicLoudness"] = false
createMicrophone()
func createMicrophone():
if playa != null:
remove_child(playa)
playa.free()
playa = AudioStreamPlayer.new()
playa.bus = "MIC"
playa.stream = AudioStreamMicrophone.new()
add_child(playa)
await get_tree().create_timer(0.25).timeout # apparently it works to fix WASAPI "Initialize failed with error 0xffffffff88890002" and "init_input_device" errors
playa.play()
func deleteAllMics():
for child in get_children():
child.queue_free()
func _process(delta):
animationTick += 1
volume = (AudioServer.get_bus_peak_volume_left_db(1, 0) + AudioServer.get_bus_peak_volume_right_db(1, 0)) / 1600.0 + 0.25 if experimentalMicLoudness else spectrum.get_magnitude_for_frequency_range(20, 20000).length()
if playa != null:
volumeSensitivity = lerp(volumeSensitivity,0.0,delta*2)
if volume>volumeLimit:
volumeSensitivity = 1.0
var prev = speaking
speaking = volumeSensitivity > senseLimit
if prev != speaking:
if speaking:
emit_signal("startSpeaking")
else:
emit_signal("stopSpeaking")
if main != null and heldSprite != null:
if Input.is_action_just_pressed("zDown"):
heldSprite.z -= 1
heldSprite.setZIndex()
pushUpdate("Moved sprite layer.")
if Input.is_action_just_pressed("zUp"):
heldSprite.z += 1
heldSprite.setZIndex()
pushUpdate("Moved sprite layer.")
if main.editMode:
if Input.is_action_just_pressed("reparent"):
reparentMode = !reparentMode
Global.chain.enable(reparentMode)
else:
reparentMode = false
Global.chain.enable(reparentMode)
if main.editMode:
if reparentMode:
RenderingServer.set_default_clear_color(Color.POWDER_BLUE)
else:
RenderingServer.set_default_clear_color(Color.GRAY)
blinking()
scrollSprites()
if !main.fileSystemOpen:
if Input.is_action_just_pressed("refresh"):
refresh()
if Input.is_action_just_pressed("unlink"):
unlinkSprite()
if Input.is_action_pressed("control"):
if Input.is_action_just_pressed("saveImages"):
saveImagesFromData()
func select(areas):
if main.fileSystemOpen:
return
for area in areas:
if area.is_in_group("penis"):
return
var prevSpr = heldSprite
if areas.size() <= 0:
heldSprite = null
i = 0
lastArray = []
return
if areas != lastArray:
heldSprite = areas[0].get_parent().get_parent().get_parent()
i = 0
else:
i += 1
if i >= areas.size():
i = 0
heldSprite = areas[i].get_parent().get_parent().get_parent()
var count = heldSprite.path.get_slice_count("/") - 1
var i1 = heldSprite.path.get_slice("/",count)
pushUpdate("Selected sprite \"" + i1 + "\"" + ".")
heldSprite.set_physics_process(true)
if reparentMode:
if prevSpr == heldSprite:
reparentMode = false
return
if heldSprite.parentId == prevSpr.id:
return
linkSprite(prevSpr,heldSprite)
Global.chain.enable(reparentMode)
lastArray = areas.duplicate()
spriteEdit.setImage()
func linkSprite(sprite,newParent):
if sprite == newParent:
reparentMode = false
return
if newParent.parentId == sprite.id:
reparentMode = false
return
if sprite.is_ancestor_of(newParent):
pushUpdate("Can't link to own child sprite!")
reparentMode = false
return
sprite.reparent(newParent.sprite,true)
sprite.parentId = newParent.id
sprite.parentSprite = newParent
reparentMode = false
Global.spriteList.updateData()
var count = sprite.path.get_slice_count("/") - 1
var i1 = sprite.path.get_slice("/",count)
count = newParent.path.get_slice_count("/") - 1
var i2 = newParent.path.get_slice("/",count)
pushUpdate("Linked sprite \"" + i1 + "\" to sprite \"" + i2 + "\".")
newParent.set_physics_process(true)
func scrollSprites():
if Input.is_action_pressed("control"):
return
if !main.editMode:
return
if main.fileSystemOpen:
return
for area in mouse.area.get_overlapping_areas():
if area.is_in_group("penis"):
return
var scroll = 0
if heldSprite == null:
scrollSelection = 0
if Input.is_action_just_pressed("scrollUp"):
scroll-=1
if Input.is_action_just_pressed("scrollDown"):
scroll+=1
if scroll == 0:
return
var obj = get_tree().get_nodes_in_group("saved")
if obj.size() <= 0:
return
scrollSelection += scroll
if scrollSelection >= obj.size():
scrollSelection = 0
elif scrollSelection < 0:
scrollSelection = obj.size() - 1
heldSprite = obj[scrollSelection]
var count = heldSprite.path.get_slice_count("/") - 1
var i1 = heldSprite.path.get_slice("/",count)
pushUpdate("Selected sprite \"" + i1 + "\"" + ".")
heldSprite.set_physics_process(true)
spriteEdit.setImage()
func blinking():
blinkTick += 1
if blinkTick == 0:
blink = false
if rand.randf_range(-1.0,1.0) > 0.5:
blinkTick = (420 * blinkSpeed) + 1
if blinkTick > 420 * blinkSpeed:
if rand.randi() % int(blinkChance) == 0:
blink = true
blinkTick = -12
func epicFail(err):
print(fail)
if fail == null:
return
fail.get_node("type").text = ""
match err:
ERR_FILE_CORRUPT:
fail.get_node("type").text = "FILE CORRUPT"
ERR_FILE_NOT_FOUND:
fail.get_node("type").text = "FILE NOT FOUND"
ERR_FILE_CANT_OPEN:
fail.get_node("type").text = "FILE CANT OPEN"
ERR_FILE_ALREADY_IN_USE:
fail.get_node("type").text = "FILE IN USE"
ERR_FILE_NO_PERMISSION:
fail.get_node("type").text = "MISSING PERMISSION"
ERR_INVALID_DATA:
fail.get_node("type").text = "DATA INVALID"
ERR_FILE_CANT_READ:
fail.get_node("type").text = "CANT READ FILE"
fail.visible = true
await get_tree().create_timer(2.5).timeout
fail.visible = false
func refresh():
var objs = get_tree().get_nodes_in_group("saved")
for object in objs:
object.replaceSprite(object.path)
object.sprite.frame = 0
object.remadePolygon = false
pushUpdate("Refreshed all sprites.")
func unlinkSprite():
if heldSprite == null:
return
if heldSprite.parentId == null:
return
var glob = heldSprite.global_position
glob = Vector2(int(glob.x),int(glob.y))
heldSprite.get_parent().remove_child(heldSprite)
main.origin.add_child(heldSprite)
heldSprite.set_owner(main.origin)
heldSprite.parentId = null
heldSprite.parentSprite = null
heldSprite.position = glob - main.origin.position
Global.spriteList.updateData()
pushUpdate("Unlinked sprite.")
func saveImagesFromData():
var sprites = get_tree().get_nodes_in_group("saved")
if sprites.size() <= 0:
return
for sprite in sprites:
var img = sprite.imageData
var array = sprite.path.split("/",false)
var length = sprite.path.length() - array[array.size()-1].length()
DirAccess.make_dir_recursive_absolute(sprite.path.left(length-1))
img.save_png(sprite.path)
pushUpdate("Saved all avatar images to computer.")
func pushUpdate(text):
if is_instance_valid(updatePusherNode):
updatePusherNode.pushUpdate(text)