The Wave (2.0)

Showcase your libraries, tools and other projects that help your fellow love users.
Post Reply
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

The Wave (2.0)

Post by Nixola »

Hi! I wrote a utility to save PCM .wav files some time ago, but it was kinda buggy, it only worked properly with 16-bit files and only saved SoundDatas. I tried to rewrite it and it seems it works better (also, it's now 0.9.2 compatible), but I'm not completely sure about that. Here's how it works:

Code: Select all

local wave = require "wave"
local sData = love.sound.newSoundData "Example.ogg"
wave.save{ filename = "Example.wav", sound = sData, overwrite = true, callback = function() love.graphics.setColor(255, 0, 0) end}
This is the simplest it gets. You require the lib, call wave.save giving it a SoundData, a filename, an optional callback which is called when the file is saved) and an optional "force" parameter (if true, The Wave will overwrite the file if it already exists). When saving SoundDatas, this is pretty much all you have to worry about. It automatically gets the parameters (bitrate, bit depth, channels number) from the SoundData and is fast enough you probably don't have to worry about a callback: if you don't like it being asynchronous, you can pass "false" (the value, not the string) as callback and it'll wait until the thread's done. The callback is only called if you call wave.update in your love.update though.

There is also a more complex way to use it:

Code: Select all

local t = {}

t.bitDepth = 16
t.channels = 1
t.sampleRate = 48000

local BIRATEPI = t.sampleRate/math.pi/2

local sine = function(s, v, a) return a*math.sin(s*v/BIRATEPI) end

for i = 1, t.sampleRate*15 do
    t[i] = sine(i, 220, 2)
end

local sin = wave.save{ sound = t, filename = "Sine.wav", callback = function() love.system.openURL(love.filesystem.getSaveDirectory()) end, overwrite = true, exceptionMode = "normalize" }

love.update = function(dt)
    wave.update(dt)
end

love.draw = function()
    love.graphics.print("This is not a fancy demo. If everything is red, the .ogg file was saved as a wav file.\nWhen the following's done, a folder will automagically be opened.", 0, 0)
    local p = sin:getPercent()
    if p then
        love.graphics.print(p .. "%", 0, 32)
    end
    local s = sin:getStatus()
    if s then
        love.graphics.print(s, 0, 48)
    end
    if sin:getError() then
        love.graphics.print(sin:getError(), 0, 64)
    end
end
wave.save also return a handy handler (hey! pun there! laugh!) that allows you to query Wave for the saving status (it can return "analyzing", "saving", "done" or "error"), how much it saved (only if you save a table though; it will be nil if you're saving a SoundData) and, if the thread errors, the error message. An error might be caused if you pass an invalid table or an invalid userdata (pretty much anything but SoundData). A table is only valid if it has an array part and that array only contains numbers, and if it has the fields bitDepth (which also has to be either 8 or 16), channel (which must be a positive number) and sampleRate (which must be a positive number). It can also error if the file exists and the 4th argument isn't true-ish, or if it can't write to the file.

wave.save can receive normal arguments (filename, soundData or table, callback, overwrite, exceptionMode) or a table {filename = string, sound = soundData or table, callback = func/false, overwrite = true, exceptionMode = string}.
The filename is, of course, the name/path the file will end up into in the save directory.
Sound is either a SoundData or the aforementioned table.
Callback is a function that will be called if the file is succesfully saved or if the thread encountered an error. It gets one argument, a boolean which is true if the thread's done and false if it errored. If the callback itself is false (not nil!), wave.save will behave synchronously and block everything till it's done. The function itself will return true if the file got saved correctly or nil, error if the thread encountered an error.
Overwrite is a boolean that tells Wave wether to overwrite a file, if it already exists.
ExceptionMode is the one single reason the API got changed a few hours after first release. It only makes sense if you're saving a table and it can have three values:
  • "error": if any single sample is greater than 1 or lesser than -1, the thread will halt and Wave won't even try to save. Default if unspecified.
  • "clip": if any sample is greater than 1 or lesser than -1, it becomes 1 or -1 respectively. Standard clipping.
  • "normalize": normalizes the whole table, dividing every sample by the absolute value of the biggest one (thus making it 1 or -1 and every other one smaller)
I'm sure I forgot something. If you've got any questions, feel free to ask! The .love is down here.

EDIT: A point has been brought up on IRC. Poll!
EDIT2: Poll's over. 0 results, but a good talk on IRC brought a solution. Thanks, z0rg and DesertRock!
Attachments
wave.love
Third version. Dammit.
(104.32 KiB) Downloaded 112 times
Last edited by Nixola on Mon Oct 05, 2015 2:05 pm, edited 1 time in total.
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
boobeebah13
Prole
Posts: 7
Joined: Sun Sep 20, 2015 12:16 am

Re: The Wave (2.0)

Post by boobeebah13 »

lol syntax error in the .love file
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: The Wave (2.0)

Post by Nixola »

I should test things more often. Thanks! .love updated.
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 4 guests