Microphone Support for LÖVE!

Showcase your libraries, tools and other projects that help your fellow love users.
Noacos
Prole
Posts: 5
Joined: Sun Mar 22, 2015 4:51 pm

Re: Microphone Support for LÖVE!

Post by Noacos » Thu Oct 29, 2015 1:53 pm

Hello. I'm curious how could I get the microphone audio levels (sorry for my terminology) to use (for example) for a visualizer.

User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Microphone Support for LÖVE!

Post by vrld » Thu Oct 29, 2015 2:49 pm

I'm assuming that by "audio level" you mean the loudness of the sound bites. To understand how this can be computed it is worth looking into how that sound bite is represented. With math.

So: a [wiki]SoundData[/wiki] object represents a short signal that describes the vibration of the microphone membrane (which is basically all that sound is: vibration over time) at any given time. Mathematically, we have a function that maps a time to the amount of vibration: sound(time) = amount of vibration, or shorter: \(s(t) = v\). Note that v can be positive or negative, depending on whether the membrane swings up or down. A SoundData object basically stores the values of s(t) for discrete values of t (for example t=0, t=0.00002, t=0.00004, ...)

The loudness of a sound can be measured by the Amplitude, which wikipedia defines as "a measure of its change over a single period". This isn't really helpful though, and indeed there are many definitions of how the change is actually measured. In my opinion, "Peak amplitude" and "Root mean square amplitude" are the most suitable, so we will use that.

Peak amplitude is the maximum absolute value of the signal, that is: \(\text{peak amp} = \arg\max_t |s(t)|\)
In Code:

Code: Select all

function peakAmplitude(sounddata)
    local peak_amp = -math.huge
    for t = 0,sounddata:getSampleCount()-1 do
        local amp = math.abs(sounddata:getSample(t)) -- |s(t)|
        peak_amp = math.max(peak_amp, amp)
    end
    return peak_amp
end
Root mean square amplitude is "defined as the square root of the mean over time of the square of the vertical distance of the graph from the rest state." In our case, we can assume the "rest state" to be 0; then the distance is just the value of the signal. Mathematically this means: \(\text{rms} = \sqrt{\frac{1}{T}\sum_{t=1}^T {(s(t))}^2}\) - we have to sum the square of every value, divide by the number of items and then take the root:

Code: Select all

function rmsAmplitude(sounddata)
    local amp = 0
    for t = 0,sounddata:getSampleCount()-1 do
        amp = amp + sounddata:getSample(t)^2 -- (s(t))^2
    end
    return math.sqrt(amp / sounddata:getSampleCount())
end
Now, if you want to know the volume distribution across different frequency bands (as seen in equalizers), you will need to process the signal with a Fourier transform. But this is a rather complicated topic...

edit: forgot the mean part in root mean square
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine

Noacos
Prole
Posts: 5
Joined: Sun Mar 22, 2015 4:51 pm

Re: Microphone Support for LÖVE!

Post by Noacos » Sat Oct 31, 2015 7:23 am

Thank you for your quick answer. So I read your answer few times, I have done a small research and for now I just store absolute value of the first sample. I don't need an equalizer, I just want a game using similar mechanics as http://kanako.dk/clients/fun/WOOORRK!/. Do you think that this is a good approach?

Manyrio
Prole
Posts: 29
Joined: Sat Feb 06, 2016 10:12 am

Re: Microphone Support for LÖVE!

Post by Manyrio » Thu Oct 20, 2016 9:31 pm

Hey I just discovered this awesome library.
I find it very cool ! I have just one question, after playing with it during the last hours, I wanted to know how do we get the sounddata created by the library ?
(Sorry for bad english, I'm french)
function love.load() end
function love.update(dt) end
function love.draw() end

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

Re: Microphone Support for LÖVE!

Post by zorg » Thu Oct 20, 2016 11:27 pm

Hi,
as you can see from this example, for example, the callback's second parameter, data, is the SoundData.
The poll method creates them, as seen here.
Me and my stuff :3True 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.

User avatar
Dr. Peeps
Citizen
Posts: 57
Joined: Sat May 28, 2016 12:57 am
Location: British Columbia, Canada

Re: Microphone Support for LÖVE!

Post by Dr. Peeps » Wed Jan 11, 2017 9:42 pm

I'm just looking at the new RecordingDevice class implemented in 0.11 (and excited about it!). Does anyone have some simple example code? The link given doesn't seem to contain anything (http://hastebin.com/revohalixi.lua). Thanks in advance.

User avatar
raidho36
Party member
Posts: 1685
Joined: Mon Jun 17, 2013 12:00 pm

Re: Microphone Support for LÖVE!

Post by raidho36 » Wed Jan 11, 2017 9:59 pm

It used to - but it's gone. You'll notice the link redirects you to the front page, which is a blank paste.

Code: Select all

local inputs
local output

function love.load ( )
	inputs = love.audio.getRecordingDevices ( )
	print ( inputs[ 1 ]:getName ( ) )
	inputs[ 1 ]:start ( )

	output = love.audio.newQueueableSource ( inputs[ 1 ]:getSampleRate ( ), inputs[ 1 ]:getBitDepth ( ), inputs[ 1 ]:getChannels ( ) )
end

function love.update ( )
	if inputs[ 1 ]:getSampleCount ( ) > inputs[ 1 ]:getSampleRate ( ) / 20 then
		local data = inputs[ 1 ]:getData ( )
		output:queue ( data )
		print ( ( "%d samples captured" ):format ( data:getSampleCount ( ) ) )
		if output:getDuration ( "samples" ) > data:getSampleCount ( ) then
			output:play ( )
		end
	end
end

User avatar
Dr. Peeps
Citizen
Posts: 57
Joined: Sat May 28, 2016 12:57 am
Location: British Columbia, Canada

Re: Microphone Support for LÖVE!

Post by Dr. Peeps » Thu Jan 12, 2017 12:52 am

raidho36 wrote:

Code: Select all

	inputs = love.audio.getRecordingDevices ( )
	inputs[ 1 ]:start ( )
Thanks! Seems to work.

Hmm, the source lists RecordingDevice:startRecording() as a method, but that's not called in this example - just RecordingDevice:start(). :?

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

Re: Microphone Support for LÖVE!

Post by zorg » Thu Jan 12, 2017 2:44 am

It may have been renamed. Check the merged pull requests.
Me and my stuff :3True 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.

User avatar
Dr. Peeps
Citizen
Posts: 57
Joined: Sat May 28, 2016 12:57 am
Location: British Columbia, Canada

Re: Microphone Support for LÖVE!

Post by Dr. Peeps » Thu Jan 12, 2017 9:35 pm

LÖVE 0.11 wrote:getData removes currently recorded samples from input and puts them into new SoundData
This works well, but .... What is the likelihood of having a variant of getData that doesn't create a new SoundData object with every call, instead "refilling" an existing buffer with new data?

This is only in the interest of keeping object creation / garbage collection / memory fragmentation down. (In the above example I can see that data pointer climbing ever higher the longer the program runs ...) In my case, my app is constantly monitoring the microphone (not just recording it for a short period), so creating the same object over and over seems wasteful ... but I'm new to both LÖVE and Lua and perhaps don't know what I'm talking about. :ehem:

Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests