## [Solved] Is there any way to save sounddata to a file?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Intas
Prole
Posts: 5
Joined: Sun Mar 12, 2017 9:51 pm
Location: Buenos Aires, Argentina

### [Solved] Is there any way to save sounddata to a file?

Hello.

With the microphone recording thing you can get the sounddata using RecordingDevice:getData() and with that you can create a source using love.audio.newSource(). Now I'd like to know if is possible to store that sounddata into a file (.wav? .mp3?) so I can play anytime whatever the microphone have recorded.

Thanks!
Last edited by Intas on Fri Jan 04, 2019 4:54 am, edited 1 time in total.

zorg
Party member
Posts: 2700
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

### Re: Is there any way to save sounddata to a file?

Hi and welcome to the forums!

You can write out the contents sample-by-sample using love.filesystem stuff, but löve doesn't have a way, as far as i know, to encode it to a format it can load; you could write out a wav header and then the data using the correct format, which would be the simplest format to do, in my opinion.
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.

Intas
Prole
Posts: 5
Joined: Sun Mar 12, 2017 9:51 pm
Location: Buenos Aires, Argentina

### Re: Is there any way to save sounddata to a file?

zorg wrote:
Sun Dec 30, 2018 1:31 am
you could write out a wav header and then the data using the correct format, which would be the simplest format to do, in my opinion.
Could you point me in the right direction on how could I do this? Is it something I should do using ffi? I'm completely unfamiliar with it

zorg
Party member
Posts: 2700
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

### Re: Is there any way to save sounddata to a file?

Here's a site i found that's helpful, in that it shows how the (most used variation of the) format works: http://soundfile.sapp.org/doc/WaveFormat/

You don't need to use the FFI for this though, it can be implemented with just lua, tables, numbers and some string manipulation (to write out the correctly formatted numbers)

You can get the sampling rate, bit depth and channel count from the sounddata itself.
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.

Intas
Prole
Posts: 5
Joined: Sun Mar 12, 2017 9:51 pm
Location: Buenos Aires, Argentina

### Re: Is there any way to save sounddata to a file?

Okay, so I found this which seems to be what I want. It's made in pure lua so I have to change lua's IO with love.filesystem.

Code: Select all

require("wav")
-- ...
local samples = {}
local sounddata = rd:getData()
rd:stop()
local source = love.audio.newSource(sounddata)
love.audio.play(source) -- Play whatever was recorded

local w = wav.create_context("audiotest.wav", "w")

local channelCount = sounddata:getChannelCount()
local sampleRate   = sounddata:getSampleRate()
local bitDepth     = sounddata:getBitDepth() -- bits per sample

w.init(channelCount, sampleRate, bitDepth)
w.write_samples_interlaced(samples) -- ???
w.finish()

The only problem is that I don't know what "samples" should contain? According to the test file the samples are calculated like this: math.sin(i % 44100 / 44099 * freq) * 32767
Where:
• i is a number from 0 to 44100*3
• 44100 is the sample rate,
• 44099 is sample rate - 1,
• freq is math.pi * 2 * 500
• 32767 is the maximum value for a signed integer?
Those last two values are magic numbers for me because I have no idea what they mean

Guess I'll have to actually understand the wave formatting and write my own "formatter"...

zorg
Party member
Posts: 2700
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

### Re: Is there any way to save sounddata to a file?

The samples would be the audio data you want to write out, contained within the sounddata;

Since i'm guessing write_samples_interlaced wants a lua table of values, you need to fill a table with the samplepoints you can get from the sounddata with the :getSample method (indexed from 0 to sounddata:getSampleCount-1), then, since that method returns values in the range of [-1.0,1.0], you need to convert that to signed 16bit integers;

The multiplication by 32767 will work for that, although you should restrict it with math.min and math.max as well (limits are -32768 and 32767 inclusive), and you should also math.floor it at the end, to be sure.

That said, if the bit depth would be 8, it would be either signed or unsigned bytes instead, it's in the specs i linked... interlaced means the channels' samplepoints are woven together, e.g.: left1, right1, left2, right2, etc...; löve already uses this format internally if the sounddata has two channels, but it shouldn't work too differently if there's only 1 channel, since there's nothing to interleave in that case.

(And i understand what the intention of that test code is, looks like a simple sine wave generator, but i have zero idea about why it does the sampling rate division thing it does... Edit: I misread the precedence on that, it just wraps it, but the division, imo should still be with 44100 and not 44099; the frequency is 500 Hz, but they decided to include 2pi in that variable as well, probably for performance reasons; it's only needed because they're using a trigonometric function to generate the samplepoints (sine), making the cycle be [0,1] instead of [0,2*pi].)
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.

Intas
Prole
Posts: 5
Joined: Sun Mar 12, 2017 9:51 pm
Location: Buenos Aires, Argentina

### Re: Is there any way to save sounddata to a file?

zorg wrote:
Wed Jan 02, 2019 6:23 am
Since i'm guessing write_samples_interlaced wants a lua table of values, you need to fill a table with the samplepoints you can get from the sounddata with the :getSample method (indexed from 0 to sounddata:getSampleCount-1), then, since that method returns values in the range of [-1.0,1.0], you need to convert that to signed 16bit integers;
Ohhhh, right, that makes sense. I knew that :getSample existed but I didn't know how to convert those numbers to 16bit integers.

IT'S WORKING NOW! Thank you sooooooo much for your help zorg, you've been really helpful

So my code looks like this, if there's something to add/remove/modify let me know.

Code: Select all

require("wav")
-- ...
local sounddata = rd:getData()
rd:stop()
local channelCount = sounddata:getChannelCount()
local sampleRate   = sounddata:getSampleRate()
local bitDepth     = sounddata:getBitDepth()
local samples = {}
for i = 0, sounddata:getSampleCount() - 1 do
local sample = sounddata:getSample(i)
local n
local to16bit = sample * 32767
if (to16bit > 0) then
n = math.floor(math.min(to16bit, 32767))
else
n = math.floor(math.max(to16bit, -32768))
end
table.insert(samples, n)
end
local w = wav.create_context("test.wav", "w")
w.init(channelCount, sampleRate, bitDepth)
w.write_samples_interlaced(samples)
w.finish()

Now I'm going to edit wav.lua to make it löve compatible.

Again, thank you for your help (and patience all this audio stuff is new to me).

ni_lus
Prole
Posts: 2
Joined: Mon Feb 04, 2019 8:40 am