├── .gitattributes ├── .gitignore ├── changelog.md ├── license.txt ├── love-microphone ├── Device.lua ├── QueueableSource.lua ├── init.lua └── openal.lua ├── readme.md └── samples ├── echo-low-latency.lua └── echo.lua /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # CUSTOM BUILD 2 | main.lua 3 | conf.lua -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## 0.6.0 4 | - Added QueueableSource:setVolume() method (thanks, pgimeno) 5 | - Fixed documentation typo (thanks, tst2005) 6 | 7 | ## 0.5.0 8 | - 8-bit audio support (thanks to miko for recommendation) 9 | - Added Device:getBitDepth() method 10 | - Device:new() is now typechecked properly 11 | - Cleaned up typechecking code slightly 12 | - Cleaned up documentation 13 | 14 | ## 0.4.3 15 | - Fixed-size buffers are now larger, thanks to KittyCat@#openal for the recommendation. 16 | 17 | ## 0.4.2 18 | - bufferCount is now honored when creating QueueableSource objects. 19 | 20 | ## 0.4.1 21 | - Fixed version field being incorrect. 22 | - Added QueueableSource:getFreeBufferCount() 23 | - Added optional argument to QueueableSource constructor to specify number of buffers to use. 24 | - Removed outdated demos and todo document 25 | 26 | ## 0.4.0 27 | - "fast as possible" mode added for microphone input; uses a new variable buffer size. 28 | - Pass 0 as the third argument (sampleLength) to openDevice to enable this mode. 29 | - Removed Device:getSoundData since it doesn't work for this new mode. 30 | 31 | ## 0.3.0 32 | - QueueableSource object, created with microphone.newQueueableSource. 33 | - Updated demos to use QueueableSource and promote the microphone-specific callback method. 34 | 35 | ## 0.2.4 36 | - Functions now do typechecking on their arguments. They will return nil and an error message like usual. 37 | 38 | ## 0.2.3 39 | - Updated documentation for core functions. 40 | 41 | ## 0.2.2 42 | - Fixed data callbacks not passing the first parameter (the device) properly 43 | 44 | ## 0.2.1 45 | - Moved Device functionality to separate file, cleaned up main code considerably 46 | - Standardized file headers 47 | 48 | ## 0.2.0 49 | - Added getVersion to retrieve version 50 | - Documented all methods 51 | - Fixed latency issues; sample length is now latency 52 | - Added microphone.getDeviceList and microphone.getDefaultDeviceName 53 | - Added todo.md document for future plans 54 | - Noted in readme that linux is now tested 55 | 56 | ## 0.1.0 57 | - Initial release -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Lucien Greathouse (LPGhatguy) 2 | 3 | This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. 4 | 5 | Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 6 | 7 | 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 8 | 9 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 10 | 11 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /love-microphone/Device.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | love-microphone 3 | Device.lua 4 | 5 | Holds methods for the Device class to be used by the love-microphone core. 6 | ]] 7 | 8 | local ffi = require("ffi") 9 | local al = require("love-microphone.openal") 10 | 11 | local Device = {} 12 | local formats = { 13 | [8] = al.AL_FORMAT_MONO8, 14 | [16] = al.AL_FORMAT_MONO16 15 | } 16 | 17 | --[[ 18 | Device Device:new(string? deviceName, [int frequency, float sampleLength, uint format]) 19 | deviceName: The device to open. Specify nil to get the default device. 20 | frequency: The sample rate in Hz to open the source at; defaults to 22050 Hz. 21 | sampleLength: How long in seconds a sample should be; defaults to 0.5 s. Directly affects latency. 22 | format: How many bits per sample; defaults to 16. 23 | 24 | Creates a new Device object corresponding to the given microphone. 25 | Will not check for duplicate handles on the same device, have care. 26 | ]] 27 | function Device:new(name, frequency, sampleLength, format) 28 | if (name ~= nil and type(name) ~= "string") then 29 | return nil, "Invalid argument #1: Device name must be of type 'string' if given." 30 | end 31 | 32 | if (frequency ~= nil and (type(frequency) ~= "number" or frequency % 1 ~= 0)) then 33 | return nil, "Invalid argument #2: Frequency must of type 'number' and an integer if given." 34 | end 35 | 36 | if (sampleLength ~= nil and type(sampleLength) ~= "number") then 37 | return nil, "Invalid argument #3: Sample length must be of type 'number' if given." 38 | end 39 | 40 | if (format ~= nil and (type(format) ~= "number" or format % 1 ~= 0)) then 41 | return nil, "Invalid argument #4: Format must be of type 'number' and an integer if given." 42 | end 43 | 44 | frequency = frequency or 22050 45 | sampleLength = sampleLength or 0.5 46 | format = format or 16 47 | 48 | local fastAsPossible = false 49 | 50 | if (sampleLength == 0) then 51 | sampleLength = 0.1 52 | fastAsPossible = true 53 | end 54 | 55 | local alFormat = formats[format] 56 | 57 | if (not alFormat) then 58 | return nil, "Invalid argument #4: Format must be a valid OpenAL bit depth (8 or 16) if given." 59 | end 60 | 61 | -- Convert sampleLength to be in terms of audio samples 62 | sampleSize = math.floor(frequency * sampleLength) 63 | 64 | local alcdevice = al.alcCaptureOpenDevice(name, frequency, alFormat, sampleSize * 2) 65 | 66 | -- Create our actual microphone device object 67 | local internal = {} 68 | 69 | for key, value in pairs(Device) do 70 | if (key ~= "new") then 71 | internal[key] = value 72 | end 73 | end 74 | 75 | -- Set some private fields 76 | internal._sampleSize = sampleSize 77 | 78 | -- Samples should be read as quickly as possible! 79 | if (fastAsPossible) then 80 | internal._fastAsPossible = true 81 | internal._sampleSize = nil 82 | else 83 | -- We can only use an internal buffer if we have fixed buffer sizing. 84 | internal._buffer = love.sound.newSoundData(sampleSize, frequency, format, 1) 85 | end 86 | 87 | internal._alcdevice = alcdevice 88 | internal._format = format 89 | internal._alformat = alFormat 90 | internal._name = name 91 | internal._valid = true 92 | internal._samplesIn = ffi.new("ALCint[1]") 93 | internal._frequency = frequency 94 | internal._dataCallback = nil 95 | 96 | -- Wrap everything in a convenient userdata 97 | local wrap = newproxy(true) 98 | local meta = getmetatable(wrap) 99 | meta.__index = internal 100 | meta.__newindex = internal 101 | meta.__gc = internal.close 102 | 103 | return wrap 104 | end 105 | 106 | --[[ 107 | void Device:setDataCallback(void callback(Device device, SoundData data)?) 108 | callback: The function to receive the data 109 | 110 | Sets the function that this microphone will call when it receives a buffer full of data. 111 | Send no arguments to remove the current callback. 112 | By default, tries to call love.microphonedata. 113 | ]] 114 | function Device:setDataCallback(callback) 115 | if (callback and type(callback) ~= "function") then 116 | return nil, "Invalid argument #1: Callback must be of type 'function' if given." 117 | end 118 | 119 | self._dataCallback = callback 120 | end 121 | 122 | --[[ 123 | bool Device:start() 124 | 125 | Starts recording audio with this microphone. 126 | Returns true if successful. 127 | ]] 128 | function Device:start() 129 | if (not self._valid) then 130 | return false, "Device is closed." 131 | end 132 | 133 | al.alcCaptureStart(self._alcdevice) 134 | 135 | return true 136 | end 137 | 138 | --[[ 139 | bool Device:stop() 140 | 141 | Stops recording audio with this microphone. 142 | Returns true if successful. 143 | ]] 144 | function Device:stop() 145 | if (not self._valid) then 146 | return false, "Device is closed." 147 | end 148 | 149 | al.alcCaptureStop(self._alcdevice) 150 | 151 | return true 152 | end 153 | 154 | --[[ 155 | bool Device:close() 156 | 157 | Closes the microphone object and stops it from being used. 158 | Returns true if successful. 159 | ]] 160 | function Device:close() 161 | if (not self._valid) then 162 | return false, "Device already closed." 163 | end 164 | 165 | al.alcCaptureStop(self._alcdevice) 166 | al.alcCaptureCloseDevice(self._alcdevice) 167 | 168 | self._valid = false 169 | microphone._devices[self._name] = nil 170 | 171 | return true 172 | end 173 | 174 | --[[ 175 | void Device:poll() 176 | 177 | Polls the microphone for data, updates the buffer, and calls any registered callbacks if there is data. 178 | ]] 179 | function Device:poll() 180 | al.alcGetIntegerv(self._alcdevice, al.ALC_CAPTURE_SAMPLES, 1, self._samplesIn) 181 | 182 | -- fastAsPossible requires variable buffer sizing; we can't reuse the internal buffer. 183 | local samplesIn = self._samplesIn[0] 184 | if (self._fastAsPossible) then 185 | if (samplesIn == 0) then 186 | return 187 | end 188 | 189 | local samples = samplesIn 190 | 191 | local buffer = love.sound.newSoundData(samples, self._frequency, self._format, 1) 192 | al.alcCaptureSamples(self._alcdevice, buffer:getPointer(), samples) 193 | 194 | if (self._dataCallback) then 195 | self:_dataCallback(buffer) 196 | elseif (love.microphonedata) then 197 | love.microphonedata(self, buffer) 198 | end 199 | elseif (samplesIn >= self._sampleSize) then 200 | local samples = self._sampleSize 201 | local buffer 202 | 203 | local buffer = self._buffer 204 | al.alcCaptureSamples(self._alcdevice, buffer:getPointer(), samples) 205 | 206 | if (self._dataCallback) then 207 | self:_dataCallback(buffer) 208 | elseif (love.microphonedata) then 209 | love.microphonedata(self, buffer) 210 | end 211 | end 212 | end 213 | 214 | --[[ 215 | uint Device:getBitDepth() 216 | 217 | Returns the bit depth of the microphone. 218 | ]] 219 | function Device:getBitDepth() 220 | return self._format 221 | end 222 | 223 | return Device -------------------------------------------------------------------------------- /love-microphone/QueueableSource.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | love-microphone 3 | QueueableSource.lua 4 | 5 | Provides a QueueableSource object, pseudo-inheriting from Source. 6 | See http://love2d.org/wiki/Source for better documentation on 7 | most methods except queue and new. 8 | ]] 9 | 10 | local ffi = require("ffi") 11 | local al = require("love-microphone.openal") 12 | 13 | local QueueableSource = {} 14 | local typecheck = { 15 | Object = true, 16 | QueueableSource = true 17 | } 18 | 19 | --[[ 20 | alFormat getALFormat(SoundData data) 21 | data: The SoundData to query. 22 | 23 | Returns the correct alFormat enum value for the given SoundData. 24 | ]] 25 | local function getALFormat(data) 26 | local stereo = data:getChannels() == 2 27 | local deep = data:getBitDepth() == 16 28 | 29 | if (stereo) then 30 | if (deep) then 31 | return al.AL_FORMAT_STEREO16 32 | else 33 | return al.AL_FORMAT_STEREO8 34 | end 35 | end 36 | 37 | if (deep) then 38 | return al.AL_FORMAT_MONO16 39 | else 40 | return al.AL_FORMAT_MONO8 41 | end 42 | end 43 | 44 | --[[ 45 | QueueableSource QueueableSource:new(uint bufferCount=16) 46 | bufferCount: The number of buffers to use to hold queued sounds. 47 | 48 | Creates a new QueueableSource object. 49 | ]] 50 | function QueueableSource:new(bufferCount) 51 | if (bufferCount) then 52 | if (type(bufferCount) ~= "number" or bufferCount % 1 ~= 0 or bufferCount < 0) then 53 | return nil, "Invalid argument #1: bufferCount must be a positive integer if given." 54 | end 55 | else 56 | bufferCount = 16 57 | end 58 | 59 | local new = {} 60 | 61 | for key, value in pairs(self) do 62 | if (key ~= "new") then 63 | new[key] = value 64 | end 65 | end 66 | 67 | local pBuffers = ffi.new("ALuint[?]", bufferCount) 68 | al.alGenBuffers(bufferCount, pBuffers) 69 | 70 | local freeBuffers = {} 71 | for i = 0, bufferCount - 1 do 72 | table.insert(freeBuffers, pBuffers[i]) 73 | end 74 | 75 | local pSource = ffi.new("ALuint[1]") 76 | al.alGenSources(1, pSource) 77 | al.alSourcei(pSource[0], al.AL_LOOPING, 0) 78 | 79 | new._bufferCount = bufferCount 80 | new._pBuffers = pBuffers 81 | new._freeBuffers = freeBuffers 82 | new._source = pSource[0] 83 | new._pAvailable = ffi.new("ALint[1]") 84 | new._pBufferHolder = ffi.new("ALuint[16]") 85 | 86 | local wrapper = newproxy(true) 87 | getmetatable(wrapper).__index = new 88 | getmetatable(wrapper).__gc = function(self) 89 | al.alSourceStop(new._source) 90 | al.alSourcei(new._source, al.AL_BUFFER, 0) 91 | al.alDeleteSources(1, pSource) 92 | al.alDeleteBuffers(bufferCount, pBuffers) 93 | end 94 | 95 | return wrapper 96 | end 97 | 98 | --[[ 99 | string QueueableSource:type() 100 | 101 | Returns the string name of the class, "QueueableSource". 102 | ]] 103 | function QueueableSource:type() 104 | return "QueueableSource" 105 | end 106 | 107 | --[[ 108 | bool QueueableSource:typeOf(string type) 109 | type: The type to check against. 110 | 111 | Returns whether the object matches the given type. 112 | ]] 113 | function QueueableSource:typeOf(type) 114 | return typecheck[type] 115 | end 116 | 117 | --[[ 118 | void QueueableSource:queue(SoundData data) (Success) 119 | (void, string) QueueableSource:queue(SoundData data) (Failure) 120 | data: The SoundData to queue for playback. 121 | 122 | Queues a new SoundData to play. 123 | 124 | Will fail and return nil and an error message if no buffers were available. 125 | ]] 126 | function QueueableSource:queue(data) 127 | self:step() 128 | 129 | if (#self._freeBuffers == 0) then 130 | return nil, "No free buffers were available to playback the given audio." 131 | end 132 | 133 | local top = table.remove(self._freeBuffers, 1) 134 | 135 | al.alBufferData(top, getALFormat(data), data:getPointer(), data:getSize(), data:getSampleRate()) 136 | al.alSourceQueueBuffers(self._source, 1, ffi.new("ALuint[1]", top)) 137 | end 138 | 139 | --[[ 140 | void QueueableSource:step() 141 | 142 | Opens up queues that have been used. 143 | Called automatically by queue. 144 | ]] 145 | function QueueableSource:step() 146 | al.alGetSourcei(self._source, al.AL_BUFFERS_PROCESSED, self._pAvailable) 147 | 148 | if (self._pAvailable[0] > 0) then 149 | al.alSourceUnqueueBuffers(self._source, self._pAvailable[0], self._pBufferHolder) 150 | 151 | for i = 0, self._pAvailable[0] - 1 do 152 | table.insert(self._freeBuffers, self._pBufferHolder[i]) 153 | end 154 | end 155 | end 156 | 157 | --[[ 158 | void QueueableSource:clear() 159 | 160 | Stops playback and clears all queued data. 161 | ]] 162 | function QueueableSource:clear() 163 | self:pause() 164 | 165 | for i = 0, self._bufferCount - 1 do 166 | al.alSourceUnqueueBuffers(self._source, self._bufferCount, self._pBuffers) 167 | table.insert(self._freeBuffers, self._pBuffers[i]) 168 | end 169 | end 170 | 171 | --[[ 172 | uint QueueableSource:getFreeBufferCount() 173 | 174 | Returns the number of free buffers for queueing sounds with this QueueableSource. 175 | ]] 176 | function QueueableSource:getFreeBufferCount() 177 | return #self._freeBuffers 178 | end 179 | 180 | --[[ 181 | void QueueableSource:play() 182 | 183 | Begins playing audio. 184 | ]] 185 | function QueueableSource:play() 186 | if (not self:isPlaying()) then 187 | al.alSourcePlay(self._source) 188 | end 189 | end 190 | 191 | --[[ 192 | bool QueueableSource:isPlaying() 193 | 194 | Returns whether the source is playing audio. 195 | ]] 196 | function QueueableSource:isPlaying() 197 | local state = ffi.new("ALint[1]") 198 | 199 | al.alGetSourcei(self._source, al.AL_SOURCE_STATE, state) 200 | 201 | return (state[0] == al.AL_PLAYING) 202 | end 203 | 204 | --[[ 205 | void QueueableSource:pause() 206 | 207 | Stops playing audio. 208 | ]] 209 | function QueueableSource:pause() 210 | if (not self:isPaused()) then 211 | al.alSourcePause(self._source) 212 | end 213 | end 214 | 215 | --[[ 216 | void QueueableSource:isPaused() 217 | 218 | Returns whether the source is paused. 219 | ]] 220 | function QueueableSource:isPaused() 221 | local state = ffi.new("ALint[1]") 222 | 223 | al.alGetSourcei(self._source, al.AL_SOURCE_STATE, state) 224 | 225 | return (state[0] == al.AL_PAUSED) 226 | end 227 | 228 | --[[ 229 | void QueueableSource:SetVolume(number volume) 230 | 231 | Sets the volume of the source. 232 | ]] 233 | function QueueableSource:setVolume(volume) 234 | al.alSourcef(self._source, al.AL_GAIN, volume) 235 | end 236 | 237 | return QueueableSource -------------------------------------------------------------------------------- /love-microphone/init.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | love-microphone 3 | init.lua 4 | 5 | Main file for love-microphone, creates the microphone namespace. 6 | ]] 7 | 8 | local ffi = require("ffi") 9 | local al = require("love-microphone.openal") 10 | local Device = require("love-microphone.Device") 11 | local QueueableSource = require("love-microphone.QueueableSource") 12 | 13 | local microphone = { 14 | _devices = {} 15 | } 16 | 17 | --[[ 18 | (int major, int minor, int revision) microphone.getVersion() 19 | 20 | Returns the version of love-microphone currently running. 21 | ]] 22 | function microphone.getVersion() 23 | return 0, 6, 0 24 | end 25 | 26 | --[[ 27 | void microphone.import() 28 | 29 | Imports the module into love.microphone. Not always desired. 30 | ]] 31 | function microphone.import() 32 | love.microphone = microphone 33 | end 34 | 35 | --[[ 36 | QueueableSource microphone.newQueueableSource() 37 | 38 | Creates a new QueueableSource object to play lists of SoundData. 39 | ]] 40 | function microphone.newQueueableSource(bufferCount) 41 | return QueueableSource:new(bufferCount) 42 | end 43 | 44 | --[[ 45 | Device microphone.openDevice(string? deviceName, [int frequency, float sampleLength, uint format]) 46 | deviceName: The device to open. Specify nil to get the default device. 47 | frequency: The sample rate in Hz to open the source at; defaults to 22050 Hz. 48 | sampleLength: How long in seconds a sample should be; defaults to 0.5 s. Directly affects latency. 49 | format: Number of bits per audio sample; defaults to 16. Must be 8 or 16. 50 | 51 | Open a new microphone device or returns an existing opened device 52 | ]] 53 | function microphone.openDevice(name, frequency, sampleLength, format) 54 | if (microphone._devices[name]) then 55 | return microphone._devices[name] 56 | end 57 | 58 | local device, err = Device:new(name, frequency, sampleLength, format) 59 | 60 | if (not device) then 61 | return nil, err 62 | end 63 | 64 | microphone._devices[name or microphone.getDefaultDeviceName()] = device 65 | 66 | return device 67 | end 68 | 69 | --[[ 70 | string[] microphone.getDeviceList() 71 | 72 | Returns a list of microphones on the system. 73 | ]] 74 | function microphone.getDeviceList() 75 | local pDeviceList = al.alcGetString(nil, al.ALC_CAPTURE_DEVICE_SPECIFIER) 76 | local list = {} 77 | 78 | while (pDeviceList[0] ~= 0) do 79 | local str = ffi.string(pDeviceList) 80 | pDeviceList = pDeviceList + #str + 1 81 | 82 | table.insert(list, str) 83 | end 84 | 85 | return list 86 | end 87 | 88 | --[[ 89 | string microphone.getDefaultDeviceName() 90 | 91 | Returns the name of the default microphone. 92 | ]] 93 | function microphone.getDefaultDeviceName() 94 | return ffi.string(al.alcGetString(nil, al.ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)) 95 | end 96 | 97 | return microphone -------------------------------------------------------------------------------- /love-microphone/openal.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | love-microphone 3 | openal.lua 4 | 5 | LuaJIT FFI binding for OpenAL-soft 6 | ]] 7 | 8 | local ffi = require("ffi") 9 | -- Load OpenAL32.dll on Windows (from LOVE) or use ffi.C 10 | local openal = (ffi.os == "Windows") and ffi.load("openal32") or ffi.C 11 | 12 | --alc.h 13 | ffi.cdef([[ 14 | enum { 15 | ALC_INVALID = 0, //Deprecated 16 | 17 | ALC_VERSION_0_1 = 1, 18 | 19 | ALC_FALSE = 0, 20 | ALC_TRUE = 1, 21 | ALC_FREQUENCY = 0x1007, 22 | ALC_REFRESH = 0x1008, 23 | ALC_SYNC = 0x1009, 24 | 25 | ALC_MONO_SOURCES = 0x1010, 26 | ALC_STEREO_SOURCES = 0x1011, 27 | 28 | ALC_NO_ERROR = 0, 29 | ALC_INVALID_DEVICE = 0xA001, 30 | ALC_INVALID_CONTEXT = 0xA002, 31 | ALC_INVALID_ENUM = 0xA003, 32 | ALC_INVALID_VALUE = 0xA004, 33 | ALC_OUT_OF_MEMORY = 0xA005, 34 | 35 | ALC_MAJOR_VERSION = 0x1000, 36 | ALC_MINOR_VERSION = 0x1001, 37 | 38 | ALC_ATTRIBUTES_SIZE = 0x1002, 39 | ALC_ALL_ATTRIBUTES = 0x1003, 40 | 41 | ALC_DEFAULT_DEVICE_SPECIFIER = 0x1004, 42 | ALC_DEVICE_SPECIFIER = 0x1005, 43 | ALC_EXTENSIONS = 0x1006, 44 | 45 | ALC_EXT_CAPTURE = 1, 46 | ALC_CAPTURE_DEVICE_SPECIFIER = 0x310, 47 | ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER = 0x311, 48 | ALC_CAPTURE_SAMPLES = 0x312, 49 | 50 | ALC_DEFAULT_ALL_DEVICES_SPECIFIER = 0x1012, 51 | ALC_ALL_DEVICES_SPECIFIER = 0x1013 52 | }; 53 | 54 | typedef struct ALCdevice_struct ALCdevice; 55 | typedef struct ALCcontext_struct ALCcontext; 56 | 57 | typedef char ALCboolean; 58 | typedef char ALCchar; 59 | typedef signed char ALCbyte; 60 | typedef unsigned char ALCubyte; 61 | typedef short ALCshort; 62 | typedef unsigned short ALCushort; 63 | typedef int ALCint; 64 | typedef unsigned int ALCuint; 65 | typedef int ALCsizei; 66 | typedef int ALCenum; 67 | typedef float ALCfloat; 68 | typedef double ALCdouble; 69 | typedef void ALCvoid; 70 | 71 | ALCcontext* alcCreateContext(ALCdevice *device, const ALCint* attrlist); 72 | ALCboolean alcMakeContextCurrent(ALCcontext *context); 73 | void alcProcessContext(ALCcontext *context); 74 | void alcSuspendContext(ALCcontext *context); 75 | void alcDestroyContext(ALCcontext *context); 76 | ALCcontext* alcGetCurrentContext(void); 77 | ALCdevice* alcGetContextsDevice(ALCcontext *context); 78 | 79 | ALCdevice* alcOpenDevice(const ALCchar *devicename); 80 | ALCboolean alcCloseDevice(ALCdevice *device); 81 | 82 | ALCenum alcGetError(ALCdevice *device); 83 | ALCboolean alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname); 84 | void* alcGetProcAddress(ALCdevice *device, const ALCchar *funcname); 85 | ALCenum alcGetEnumValue(ALCdevice *device, const ALCchar *enumname); 86 | 87 | const ALCchar* alcGetString(ALCdevice *device, ALCenum param); 88 | void alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); 89 | 90 | ALCdevice* alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); 91 | ALCboolean alcCaptureCloseDevice(ALCdevice *device); 92 | void alcCaptureStart(ALCdevice *device); 93 | void alcCaptureStop(ALCdevice *device); 94 | void alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); 95 | 96 | typedef ALCcontext* (*LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist); 97 | typedef ALCboolean (*LPALCMAKECONTEXTCURRENT)(ALCcontext *context); 98 | typedef void (*LPALCPROCESSCONTEXT)(ALCcontext *context); 99 | typedef void (*LPALCSUSPENDCONTEXT)(ALCcontext *context); 100 | typedef void (*LPALCDESTROYCONTEXT)(ALCcontext *context); 101 | typedef ALCcontext* (*LPALCGETCURRENTCONTEXT)(void); 102 | typedef ALCdevice* (*LPALCGETCONTEXTSDEVICE)(ALCcontext *context); 103 | typedef ALCdevice* (*LPALCOPENDEVICE)(const ALCchar *devicename); 104 | typedef ALCboolean (*LPALCCLOSEDEVICE)(ALCdevice *device); 105 | typedef ALCenum (*LPALCGETERROR)(ALCdevice *device); 106 | typedef ALCboolean (*LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname); 107 | typedef void* (*LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname); 108 | typedef ALCenum (*LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname); 109 | typedef const ALCchar* (*LPALCGETSTRING)(ALCdevice *device, ALCenum param); 110 | typedef void (*LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); 111 | typedef ALCdevice* (*LPALCCAPTUREOPENDEVICE)(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); 112 | typedef ALCboolean (*LPALCCAPTURECLOSEDEVICE)(ALCdevice *device); 113 | typedef void (*LPALCCAPTURESTART)(ALCdevice *device); 114 | typedef void (*LPALCCAPTURESTOP)(ALCdevice *device); 115 | typedef void (*LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); 116 | ]]) 117 | 118 | --al.h 119 | ffi.cdef([[ 120 | enum { 121 | AL_NONE = 0, 122 | AL_FALSE = 0, 123 | AL_TRUE = 1, 124 | 125 | AL_SOURCE_RELATIVE = 0x202, 126 | AL_CONE_INNER_ANGLE = 0x1001, 127 | AL_CONE_OUTER_ANGLE = 0x1002, 128 | AL_PITCH = 0x1003, 129 | AL_POSITION = 0x1004, 130 | AL_DIRECTION = 0x1005, 131 | AL_VELOCITY = 0x1006, 132 | AL_LOOPING = 0x1007, 133 | AL_BUFFER = 0x1009, 134 | AL_GAIN = 0x100A, 135 | AL_MIN_GAIN = 0x100D, 136 | AL_MAX_GAIN = 0x100E, 137 | AL_ORIENTATION = 0x100F, 138 | AL_SOURCE_STATE = 0x1010, 139 | 140 | AL_INITIAL = 0x1011, 141 | AL_PLAYING = 0x1012, 142 | AL_PAUSED = 0x1013, 143 | AL_STOPPED = 0x1014, 144 | 145 | AL_BUFFERS_QUEUED = 0x1015, 146 | AL_BUFFERS_PROCESSED = 0x1016, 147 | 148 | AL_REFERENCE_DISTANCE = 0x1020, 149 | AL_ROLLOFF_FACTOR = 0x1021, 150 | AL_CONE_OUTER_GAIN = 0x1022, 151 | AL_MAX_DISTANCE = 0x1023, 152 | 153 | AL_SEC_OFFSET = 0x1024, 154 | AL_SAMPLE_OFFSET = 0x1025, 155 | AL_BYTE_OFFSET = 0x1026, 156 | 157 | AL_SOURCE_TYPE = 0x1027, 158 | 159 | AL_STATIC = 0x1028, 160 | AL_STREAMING = 0x1029, 161 | AL_UNDETERMINED = 0x1030, 162 | 163 | AL_FORMAT_MONO8 = 0x1100, 164 | AL_FORMAT_MONO16 = 0x1101, 165 | AL_FORMAT_STEREO8 = 0x1102, 166 | AL_FORMAT_STEREO16 = 0x1103, 167 | 168 | AL_FREQUENCY = 0x2001, 169 | AL_BITS = 0x2002, 170 | AL_CHANNELS = 0x2003, 171 | AL_SIZE = 0x2004, 172 | 173 | AL_UNUSED = 0x2010, 174 | AL_PENDING = 0x2011, 175 | AL_PROCESSED = 0x2012, 176 | 177 | AL_NO_ERROR = 0, 178 | AL_INVALID_NAME = 0xA001, 179 | AL_INVALID_ENUM = 0xA002, 180 | AL_INVALID_VALUE = 0xA003, 181 | AL_INVALID_OPERATION = 0xA004, 182 | AL_OUT_OF_MEMORY = 0xA005, 183 | 184 | AL_VENDOR = 0xB001, 185 | AL_VERSION = 0xB002, 186 | AL_RENDERER = 0xB003, 187 | AL_EXTENSIONS = 0xB004, 188 | 189 | AL_DOPPLER_FACTOR = 0xC000, 190 | AL_DOPPLER_VELOCITY = 0xC001, 191 | AL_SPEED_OF_SOUND = 0xC003, 192 | AL_DISTANCE_MODEL = 0xD000, 193 | 194 | AL_INVERSE_DISTANCE = 0xD001, 195 | AL_INVERSE_DISTANCE_CLAMPED = 0xD002, 196 | AL_LINEAR_DISTANCE = 0xD003, 197 | AL_LINEAR_DISTANCE_CLAMPED = 0xD004, 198 | AL_EXPONENT_DISTANCE = 0xD005, 199 | AL_EXPONENT_DISTANCE_CLAMPED = 0xD006 200 | }; 201 | 202 | typedef char ALboolean; 203 | typedef char ALchar; 204 | typedef signed char ALbyte; 205 | typedef unsigned char ALubyte; 206 | typedef short ALshort; 207 | typedef unsigned short ALushort; 208 | typedef int ALint; 209 | typedef unsigned int ALuint; 210 | typedef int ALsizei; 211 | typedef int ALenum; 212 | typedef float ALfloat; 213 | typedef double ALdouble; 214 | typedef void ALvoid; 215 | 216 | void alDopplerFactor(ALfloat value); 217 | void alDopplerVelocity(ALfloat value); 218 | void alSpeedOfSound(ALfloat value); 219 | void alDistanceModel(ALenum distanceModel); 220 | 221 | void alEnable(ALenum capability); 222 | void alDisable(ALenum capability); 223 | ALboolean alIsEnabled(ALenum capability); 224 | 225 | const ALchar* alGetString(ALenum param); 226 | void alGetBooleanv(ALenum param, ALboolean *values); 227 | void alGetIntegerv(ALenum param, ALint *values); 228 | void alGetFloatv(ALenum param, ALfloat *values); 229 | void alGetDoublev(ALenum param, ALdouble *values); 230 | ALboolean alGetBoolean(ALenum param); 231 | ALint alGetInteger(ALenum param); 232 | ALfloat alGetFloat(ALenum param); 233 | ALdouble alGetDouble(ALenum param); 234 | 235 | ALenum alGetError(void); 236 | 237 | ALboolean alIsExtensionPresent(const ALchar *extname); 238 | void* alGetProcAddress(const ALchar *fname); 239 | ALenum alGetEnumValue(const ALchar *ename); 240 | 241 | void alListenerf(ALenum param, ALfloat value); 242 | void alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); 243 | void alListenerfv(ALenum param, const ALfloat *values); 244 | void alListeneri(ALenum param, ALint value); 245 | void alListener3i(ALenum param, ALint value1, ALint value2, ALint value3); 246 | void alListeneriv(ALenum param, const ALint *values); 247 | 248 | void alGetListenerf(ALenum param, ALfloat *value); 249 | void alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); 250 | void alGetListenerfv(ALenum param, ALfloat *values); 251 | void alGetListeneri(ALenum param, ALint *value); 252 | void alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3); 253 | void alGetListeneriv(ALenum param, ALint *values); 254 | 255 | void alGenSources(ALsizei n, ALuint *sources); 256 | void alDeleteSources(ALsizei n, const ALuint *sources); 257 | ALboolean alIsSource(ALuint source); 258 | 259 | void alSourcef(ALuint source, ALenum param, ALfloat value); 260 | void alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); 261 | void alSourcefv(ALuint source, ALenum param, const ALfloat *values); 262 | void alSourcei(ALuint source, ALenum param, ALint value); 263 | void alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); 264 | void alSourceiv(ALuint source, ALenum param, const ALint *values); 265 | 266 | void alGetSourcef(ALuint source, ALenum param, ALfloat *value); 267 | void alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); 268 | void alGetSourcefv(ALuint source, ALenum param, ALfloat *values); 269 | void alGetSourcei(ALuint source, ALenum param, ALint *value); 270 | void alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); 271 | void alGetSourceiv(ALuint source, ALenum param, ALint *values); 272 | 273 | void alSourcePlayv(ALsizei n, const ALuint *sources); 274 | void alSourceStopv(ALsizei n, const ALuint *sources); 275 | void alSourceRewindv(ALsizei n, const ALuint *sources); 276 | void alSourcePausev(ALsizei n, const ALuint *sources); 277 | 278 | void alSourcePlay(ALuint source); 279 | void alSourceStop(ALuint source); 280 | void alSourceRewind(ALuint source); 281 | void alSourcePause(ALuint source); 282 | 283 | void alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers); 284 | void alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers); 285 | 286 | void alGenBuffers(ALsizei n, ALuint *buffers); 287 | void alDeleteBuffers(ALsizei n, const ALuint *buffers); 288 | ALboolean alIsBuffer(ALuint buffer); 289 | 290 | void alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); 291 | 292 | void alBufferf(ALuint buffer, ALenum param, ALfloat value); 293 | void alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); 294 | void alBufferfv(ALuint buffer, ALenum param, const ALfloat *values); 295 | void alBufferi(ALuint buffer, ALenum param, ALint value); 296 | void alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); 297 | void alBufferiv(ALuint buffer, ALenum param, const ALint *values); 298 | 299 | void alGetBufferf(ALuint buffer, ALenum param, ALfloat *value); 300 | void alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); 301 | void alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values); 302 | void alGetBufferi(ALuint buffer, ALenum param, ALint *value); 303 | void alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); 304 | void alGetBufferiv(ALuint buffer, ALenum param, ALint *values); 305 | 306 | typedef void (*LPALENABLE)(ALenum capability); 307 | typedef void (*LPALDISABLE)(ALenum capability); 308 | typedef ALboolean (*LPALISENABLED)(ALenum capability); 309 | typedef const ALchar* (*LPALGETSTRING)(ALenum param); 310 | typedef void (*LPALGETBOOLEANV)(ALenum param, ALboolean *values); 311 | typedef void (*LPALGETINTEGERV)(ALenum param, ALint *values); 312 | typedef void (*LPALGETFLOATV)(ALenum param, ALfloat *values); 313 | typedef void (*LPALGETDOUBLEV)(ALenum param, ALdouble *values); 314 | typedef ALboolean (*LPALGETBOOLEAN)(ALenum param); 315 | typedef ALint (*LPALGETINTEGER)(ALenum param); 316 | typedef ALfloat (*LPALGETFLOAT)(ALenum param); 317 | typedef ALdouble (*LPALGETDOUBLE)(ALenum param); 318 | typedef ALenum (*LPALGETERROR)(void); 319 | typedef ALboolean (*LPALISEXTENSIONPRESENT)(const ALchar *extname); 320 | typedef void* (*LPALGETPROCADDRESS)(const ALchar *fname); 321 | typedef ALenum (*LPALGETENUMVALUE)(const ALchar *ename); 322 | typedef void (*LPALLISTENERF)(ALenum param, ALfloat value); 323 | typedef void (*LPALLISTENER3F)(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); 324 | typedef void (*LPALLISTENERFV)(ALenum param, const ALfloat *values); 325 | typedef void (*LPALLISTENERI)(ALenum param, ALint value); 326 | typedef void (*LPALLISTENER3I)(ALenum param, ALint value1, ALint value2, ALint value3); 327 | typedef void (*LPALLISTENERIV)(ALenum param, const ALint *values); 328 | typedef void (*LPALGETLISTENERF)(ALenum param, ALfloat *value); 329 | typedef void (*LPALGETLISTENER3F)(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); 330 | typedef void (*LPALGETLISTENERFV)(ALenum param, ALfloat *values); 331 | typedef void (*LPALGETLISTENERI)(ALenum param, ALint *value); 332 | typedef void (*LPALGETLISTENER3I)(ALenum param, ALint *value1, ALint *value2, ALint *value3); 333 | typedef void (*LPALGETLISTENERIV)(ALenum param, ALint *values); 334 | typedef void (*LPALGENSOURCES)(ALsizei n, ALuint *sources); 335 | typedef void (*LPALDELETESOURCES)(ALsizei n, const ALuint *sources); 336 | typedef ALboolean (*LPALISSOURCE)(ALuint source); 337 | typedef void (*LPALSOURCEF)(ALuint source, ALenum param, ALfloat value); 338 | typedef void (*LPALSOURCE3F)(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); 339 | typedef void (*LPALSOURCEFV)(ALuint source, ALenum param, const ALfloat *values); 340 | typedef void (*LPALSOURCEI)(ALuint source, ALenum param, ALint value); 341 | typedef void (*LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); 342 | typedef void (*LPALSOURCEIV)(ALuint source, ALenum param, const ALint *values); 343 | typedef void (*LPALGETSOURCEF)(ALuint source, ALenum param, ALfloat *value); 344 | typedef void (*LPALGETSOURCE3F)(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); 345 | typedef void (*LPALGETSOURCEFV)(ALuint source, ALenum param, ALfloat *values); 346 | typedef void (*LPALGETSOURCEI)(ALuint source, ALenum param, ALint *value); 347 | typedef void (*LPALGETSOURCE3I)(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); 348 | typedef void (*LPALGETSOURCEIV)(ALuint source, ALenum param, ALint *values); 349 | typedef void (*LPALSOURCEPLAYV)(ALsizei n, const ALuint *sources); 350 | typedef void (*LPALSOURCESTOPV)(ALsizei n, const ALuint *sources); 351 | typedef void (*LPALSOURCEREWINDV)(ALsizei n, const ALuint *sources); 352 | typedef void (*LPALSOURCEPAUSEV)(ALsizei n, const ALuint *sources); 353 | typedef void (*LPALSOURCEPLAY)(ALuint source); 354 | typedef void (*LPALSOURCESTOP)(ALuint source); 355 | typedef void (*LPALSOURCEREWIND)(ALuint source); 356 | typedef void (*LPALSOURCEPAUSE)(ALuint source); 357 | typedef void (*LPALSOURCEQUEUEBUFFERS)(ALuint source, ALsizei nb, const ALuint *buffers); 358 | typedef void (*LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers); 359 | typedef void (*LPALGENBUFFERS)(ALsizei n, ALuint *buffers); 360 | typedef void (*LPALDELETEBUFFERS)(ALsizei n, const ALuint *buffers); 361 | typedef ALboolean (*LPALISBUFFER)(ALuint buffer); 362 | typedef void (*LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); 363 | typedef void (*LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value); 364 | typedef void (*LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); 365 | typedef void (*LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values); 366 | typedef void (*LPALBUFFERI)(ALuint buffer, ALenum param, ALint value); 367 | typedef void (*LPALBUFFER3I)(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); 368 | typedef void (*LPALBUFFERIV)(ALuint buffer, ALenum param, const ALint *values); 369 | typedef void (*LPALGETBUFFERF)(ALuint buffer, ALenum param, ALfloat *value); 370 | typedef void (*LPALGETBUFFER3F)(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); 371 | typedef void (*LPALGETBUFFERFV)(ALuint buffer, ALenum param, ALfloat *values); 372 | typedef void (*LPALGETBUFFERI)(ALuint buffer, ALenum param, ALint *value); 373 | typedef void (*LPALGETBUFFER3I)(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); 374 | typedef void (*LPALGETBUFFERIV)(ALuint buffer, ALenum param, ALint *values); 375 | typedef void (*LPALDOPPLERFACTOR)(ALfloat value); 376 | typedef void (*LPALDOPPLERVELOCITY)(ALfloat value); 377 | typedef void (*LPALSPEEDOFSOUND)(ALfloat value); 378 | typedef void (*LPALDISTANCEMODEL)(ALenum distanceModel); 379 | ]]) 380 | 381 | return openal -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # love-microphone 2 | ![Release Version](https://img.shields.io/badge/release-0.6.0-brightgreen.svg?style=flat-square) 3 | ![License](https://img.shields.io/badge/license-zlib/libpng-333333.svg?style=flat-square) 4 | 5 | LÖVE-microphone adds simple microphone functionality to LÖVE! Better yet, *all* you need is LÖVE to use love-microphone! 6 | 7 | See the samples directory for example code! 8 | 9 | ## Supported Platforms 10 | - Windows 11 | - Linux 12 | - Mac OS X 13 | - Android (untested) -------------------------------------------------------------------------------- /samples/echo-low-latency.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Records a user's microphone and echos it back to them. 3 | 4 | This variant uses "fast as possible mode" to get a lower latency audio stream. 5 | ]] 6 | 7 | -- Alias love-microphone as microphone 8 | local microphone = require("love-microphone") 9 | local device, source 10 | 11 | function love.load() 12 | -- Report the name of the microphone we're going to use 13 | print("Opening microphone:", microphone.getDefaultDeviceName()) 14 | 15 | -- Open the default microphone device with default quality and as little latency as possible. 16 | device = microphone.openDevice(nil, nil, 0) 17 | 18 | -- Create a new QueueableSource to echo our audio 19 | source = microphone.newQueueableSource() 20 | 21 | -- Register our local callback 22 | device:setDataCallback(function(device, data) 23 | source:queue(data) 24 | source:play() 25 | end) 26 | 27 | -- Start recording 28 | device:start() 29 | end 30 | 31 | -- Add microphone polling to our update loop 32 | function love.update() 33 | device:poll() 34 | end -------------------------------------------------------------------------------- /samples/echo.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Records a user's microphone and echos it back to them. 3 | 4 | This uses the included QueueableSource object, which may still have issues. 5 | ]] 6 | 7 | -- Alias love-microphone as microphone 8 | local microphone = require("love-microphone") 9 | local device, source 10 | 11 | function love.load() 12 | -- Report the name of the microphone we're going to use 13 | print("Opening microphone:", microphone.getDefaultDeviceName()) 14 | 15 | -- Open the default microphone device with default quality and 100ms of latency. 16 | device = microphone.openDevice(nil, nil, 0.1) 17 | 18 | -- Create a new QueueableSource to echo our audio 19 | source = microphone.newQueueableSource() 20 | 21 | -- Register our local callback 22 | device:setDataCallback(function(device, data) 23 | source:queue(data) 24 | source:play() 25 | end) 26 | 27 | -- Start recording 28 | device:start() 29 | end 30 | 31 | -- Add microphone polling to our update loop 32 | function love.update() 33 | device:poll() 34 | end --------------------------------------------------------------------------------