Microphone Plugin for Solar2D

The Microphone plugin allows you to record audio. Includes volume detection (only start recording when volume is high enough) and automatic gain control. To get access to the plugin, you need to support me on Patreon https://www.patreon.com/lerg

Supported platforms: iOS, Android.

Sample Project

https://github.com/Lerg/plugins-sample-microphone

API Overview

Functions

Events

Project Settings

To use this plugin, add an entry into the plugins table of build.settings. When added, the build server will integrate the plugin during the build phase.

You also need to add a special function at the top of the build.settings file and provide your Patreon email and an access key. The access key you get when you become a patron.

local spiralcodestudio_patreon_email = 'YOUR_EMAIL'
local spiralcodestudio_key = 'YOUR_ACCESS_KEY'

local function spiralcodestudio_plugin(name)
	local plugin = {publisherId = 'com.spiralcodestudio', supportedPlatforms = {}}
	local platforms = {'android', 'appletvos', 'appletvsimulator', 'iphone', 'iphone-sim', 'mac-sim', 'win32-sim'}
	for i = 1, #platforms do
		local platform = platforms[i]
		plugin.supportedPlatforms[platform] = {url = 'https://build.spiralcodestudio.com/' .. spiralcodestudio_patreon_email .. '/' .. spiralcodestudio_key .. '/solar2d/' .. name .. '_' .. platform .. '.tgz'}
	end
	return plugin
end

settings = {
	plugins = {
		['plugin.microphone'] = spiralcodestudio_plugin('microphone')
	}
}

Functions

microphone.enableDebug()

Enables additional output for debugging purposes. Shows when signal detector changes states.


microphone.init(params)

Initializes the plugin. This function has to be called first, before using any other methods of the plugin.

params required

Table. Contains parameters for the call — see the next section for details.

Parameter Reference

The params table includes parameters for the call.

filename required

String. Filename of the recording.

baseDir optional

Directory. Where to save the recording. Default is system.DocumentsDirectory.

sampleRate optional

Integer. Sample rate in Hz. Default is 44100.

detector optional

Table. Signal detector settings.

  • detector.on Number. Start recording when volume is larger or equal to this value.

  • detector.off Number. Trim the end if the volume of the last part is less than this value.

Example

detector = {
	on = 0.2,
	off = 0.05
}

gain optional

Table. Automatic gain control settings.

  • gain.min Number. Minimal gain. Default is 0.

  • gain.max Number. Maximum gain.

  • gain.value Number. Initial gain value. Default is 1.

  • gain.target Number. Target volume. Set 0 to disable.

  • gain.speed Number. Gain adjustment speed. Default is 0.1.

  • gain.allowClipping Boolean. If true, gain is not automatically reduced to prevent clipping.

Example

gain = {
	min = 1,
	max = 10,
	target = 0.2
}

listener required

Function. The callback function which receives init and recorded events.


microphone.getVolume()

Returns current volume as a number between 0 and 1.

Example

local volume = microphone.getVolume()
print(volume)

microphone.getGain()

Returns current gain value as a number.

Example

local gain = microphone.getGain()
print(gain)

microphone.start()

Starts the recording.

Example

microphone.start()

microphone.stop()

Stops the recording as saves it to a file.

Example

microphone.stop()

microphone.set(params)

Adjusts detector settings and automatic gain control settings even while recording. The parameters are same as for the microphone.init() function.

Example

microphone.set{
	gain = {value = 1},
	detector = {on = 0.5}
}

microphone.isRecording()

Returns true if currently recording.

Example

print(microphone.isRecording())

Events

init

Occurs when plugin is initialized

event.name

event.is_error

event.error_code

event.error_message

event.name

The string 'init'.


event.is_error

Boolean. true in case of an error.


event.error_code

Number. Unique error code, present when event.is_error is true, nil otherwise.

Possible codes: - 'already_initialized' - init() called before stopping recording. - 'init_failed' - Failed to init for various reasons. - 'missing_microphone' - No microphone. - 'missing_permission' - RECORD_AUDIO permission is missing from the manifest file. - 'denied_permission' - User denied permission. - 'permission_request_failed' - User didn’t grant permission when requested.

  • 'file_open_failed' - Failed to open the file.
  • 'file_write_failed' - Failed to write to the file.
  • 'empty_recording' - Recording didn’t trigger the detector.

event.error_message

String. Description of an error when event.is_error is true, nil otherwise.


recorded

Occurs when recording is done.

event.name

event.is_error

event.error_code

event.error_message

event.name

The string 'recorded'.


event.is_error

Boolean. true in case of an error.


event.error_code

Number. Unique error code, present when event.is_error is true, nil otherwise.

Possible codes: - ‘file_open_failed’ - Failed to open the file. - ‘file_write_failed’ - Failed to write to the file. - ‘empty_recording’ - Recording didn’t trigger the detector.


event.error_message

String. Description of an error when event.is_error is true, nil otherwise.


Example

local json = require('json')
local microphone = require('plugin.microphone')

-- Random filename prevents audio caching by Solar2D.
local filename = 'recording_' .. tostring(math.random()):sub(3, 10) .. '.wav'

local function microphone_listener(event)
	print(json.encode(event))
	if not event.isError then
		if event.name == 'init' then
			-- Start recording.
			timer.performWithDelay(1000, function()
				microphone.start()
			end)

			-- Stop recording.
			timer.performWithDelay(5000, function()
				microphone.stop()
			end)
		elseif event.name == 'recorded' then
			-- Play recording.
			local audio_file = audio.loadSound(filename, system.DocumentsDirectory)
			audio.play(audio_file)
		end
	end
end

microphone.init{
	filename = filename,
	detector = {
		on = 0.2
		off = 0.05
	},
	gain = {
		max = 10,
		target = 0.1,
		allowClipping = true
	},
	listener = microphone_listener
}