feat(packages): ludic.audio - world sounds with a gain, a pan and a pitch from where they are relative to a listener port, flat interface sounds, clips loaded past Audio.load's blind spot for packed assets, loops and the master volume; the one door to Audio.*
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
47ba3d9028
commit
fdf9866e88
10 changed files with 338 additions and 0 deletions
49
packages/ludic.audio/load.ludic
Normal file
49
packages/ludic.audio/load.ludic
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# load.ludic - a clip the runtime can actually open. Audio.load takes a real FILESYSTEM path (it
|
||||
# bottoms out in AVAudioPlayer), not the pack-aware file_open every other asset arrives through: in a
|
||||
# bundle every clip loads as 0 while Fs.exists, which IS pack-aware, says it is there. So try the
|
||||
# runtime's path, and on 0 lift the bytes out of the pack into the cache directory and load that.
|
||||
var tried: int = 0
|
||||
var live: int = 0
|
||||
|
||||
export function aud_load(path: string) -> int {
|
||||
tried += 1
|
||||
if not is_windowed() { return 0 }
|
||||
var h = Audio.load(path)
|
||||
if h == 0 {
|
||||
let out = aud_unpack(path, base_name(path))
|
||||
if out != null { h = Audio.load(out) }
|
||||
}
|
||||
if h != 0 { live += 1 }
|
||||
return h
|
||||
}
|
||||
|
||||
# how many clips were asked for and how many loaded: a silent game looks exactly like a working one
|
||||
# unless something says so
|
||||
export function aud_tried() -> int { return tried }
|
||||
export function aud_live() -> int { return live }
|
||||
|
||||
# One packed file out to the cache, or null. A cached copy is trusted only if it is as long as the
|
||||
# packed one: a write interrupted halfway would otherwise play truncated for ever.
|
||||
export function aud_unpack(path: string, name: string) -> string {
|
||||
let dir = AudioFiles.cache_dir()
|
||||
if len(dir) == 0 { return null }
|
||||
Fs.mkdir(dir)
|
||||
let dst = dir + "/" + name
|
||||
let f = file_open(path, "rb")
|
||||
if f == null { return null }
|
||||
file_seek(f, 0, 2)
|
||||
let n = file_tell(f)
|
||||
file_close(f)
|
||||
if n <= 0 { return null }
|
||||
if Fs.exists(dst) and Fs.size(dst) == n { return dst }
|
||||
let buf = Fs.read_bytes(path)
|
||||
if buf == null or len(buf) < n { return null }
|
||||
if not Fs.write_bytes(dst, buf, n) { return null }
|
||||
return dst
|
||||
}
|
||||
|
||||
function base_name(path: string) -> string {
|
||||
var i = len(path) - 1
|
||||
while i >= 0 and path[i] != 47 { i -= 1 }
|
||||
return path[i + 1..len(path)]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue