Streaming audio from memory

General discussion about LÖVE, Lua, game development, puns, and unicorns.
foo0
Prole
Posts: 35
Joined: Sun Apr 27, 2014 10:25 am

Streaming audio from memory

Post by foo0 »

Keep in mind that, if you pass love.audio.newSource "static" as a second argument, the sound file will be expanded into memory, so if you load a 5MB compressed .ogg file that way, it would consume ~50MB RAM when fully decompressed. Consider not using "static" in such cases.
Why not load that 5MB file into memory as it is, and stream from there, instead of hard drive? Or is it doable already? That would seem like an optimal way of doing it, as opposed to "stream from disk" (disk reads in the main loop) or "uncompress to memory" (excessive memory usage).
User avatar
slime
Solid Snayke
Posts: 3144
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Streaming audio from memory

Post by slime »

That's what love.audio.newSource(filename, "stream") does right now.
foo0
Prole
Posts: 35
Joined: Sun Apr 27, 2014 10:25 am

Re: Streaming audio from memory

Post by foo0 »

Ah, my bad then for not checking it more thoroughly. The wiki is kind of misleading, it gives the impression that with "stream" parameter audio is streamed from disk, not loaded to memory and streamed from there.
User avatar
slime
Solid Snayke
Posts: 3144
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Streaming audio from memory

Post by slime »

Yeah, I guess one reason it's ambiguously defined is so that can be added in the future if it's proven to be useful, without affecting the API.
One way to guarantee that it will always be streamed from RAM rather than the disk (although the internal implementation always does this right now anyway) is to load the file as FileData first. Something like this:

Code: Select all

local filedata = love.filesystem.newFileData("myaudio.ogg") -- Loads the whole file into memory.
source = love.audio.newSource(filedata, "stream")
jjmafiae
Party member
Posts: 1331
Joined: Tue Jul 24, 2012 8:22 am

Re: Streaming audio from memory

Post by jjmafiae »

Is this for avoiding drive bottlenecking ?
foo0
Prole
Posts: 35
Joined: Sun Apr 27, 2014 10:25 am

Re: Streaming audio from memory

Post by foo0 »

@jjmafiae: In my case it's about avoiding HDD reads, analogically to why you don't usually read textures from HDD in main game loop.

Just to clarify things already said in this thread:
To play the same sound file multiple times simultaneously, each play needs its own copy of the file? E.g.:

Code: Select all

-- This will result in one time read of "myaudio.ogg" from disk, and 4 copies in memory?
local filedata = love.filesystem.newFileData("myaudio.ogg")
source1 = love.audio.newSource(filedata, "stream")
source2 = love.audio.newSource(filedata, "stream")
source3 = love.audio.newSource(filedata, "stream")

-- This will result in 3 times read of "myaudio.ogg" from disk, and 3 copies in memory?
source1 = love.audio.newSource("myaudio.ogg", "stream")
source2 = love.audio.newSource("myaudio.ogg", "stream")
source3 = love.audio.newSource("myaudio.ogg", "stream")

-- Example use:
love.audio.play(source1)
-- wait 1 sec
love.audio.play(source2)
-- wait 1 sec
love.audio.play(source3)
User avatar
slime
Solid Snayke
Posts: 3144
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Streaming audio from memory

Post by slime »

If you do this, you will have 3 copies of the mp3 data loaded in RAM, 3 decoders (which only reference the mp3 data and allocate a small buffer of their own when streaming), and 3 unique Sources:

Code: Select all

source1 = love.audio.newSource("myaudio.ogg", "stream")
source2 = love.audio.newSource("myaudio.ogg", "stream")
source3 = love.audio.newSource("myaudio.ogg", "stream")
If you do this, you will have 1 copy of the mp3 data loaded in RAM, 3 decoders (which all reference the same un-decoded mp3 data), and 3 unique sources:

Code: Select all

local filedata = love.filesystem.newFileData("myaudio.ogg")
source1 = love.audio.newSource(filedata, "stream")
source2 = love.audio.newSource(filedata, "stream")
source3 = love.audio.newSource(filedata, "stream")
In general there aren't a lot of reasons to have multiple copies of the same streaming source. If you have a short sound file that will be played many times, you should create a static source. Static sources only decode the audio once per source (when it's initially loaded), whereas streaming sources will decode the same thing every time, if you play it back several times.

As of LÖVE 0.9.1, you can use [wiki]Source:clone[/wiki], which will be as efficient as method #2 above for streaming sources, and more efficient than that for static sources - it won't create a separate copy of the decoded (raw PCM) data with static sources, so it uses less RAM.

Code: Select all

source1 = love.audio.newSource("myaudio.ogg", "static")
source2 = source1:clone()
source3 = source1:clone()
jjmafiae
Party member
Posts: 1331
Joined: Tue Jul 24, 2012 8:22 am

Re: Streaming audio from memory

Post by jjmafiae »

can textures be streamed from memory too ?
User avatar
slime
Solid Snayke
Posts: 3144
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Streaming audio from memory

Post by slime »

You can use Image:getData to get the ImageData which was used to create the Image. If you modify that ImageData, you can use Image:refresh to apply the changes.
foo0
Prole
Posts: 35
Joined: Sun Apr 27, 2014 10:25 am

Re: Streaming audio from memory

Post by foo0 »

Thanks for detailed explanation. This clone() mechanics seems to be the way.

Is it possible to check the length (duration) of a sound source (either stream or static)?
Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests