Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
miniaudio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
miniaudio
Commits
58989ea1
Commit
58989ea1
authored
Oct 15, 2016
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update documentation.
parent
a752a49c
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
122 additions
and
30 deletions
+122
-30
README.md
README.md
+5
-3
mini_al.h
mini_al.h
+117
-27
No files found.
README.md
View file @
58989ea1
...
...
@@ -10,8 +10,10 @@ C/C++, single file, public domain.
Features
========
-
A very simple API.
-
Both synchronous and asynchronous APIs.
-
Public domain
-
Single file
-
A very simple API
...
...
@@ -36,7 +38,7 @@ int main()
mal_uint32 fragmentCount = 2;
mal_device playbackDevice;
if (mal_device_init
_async
(&playbackDevice, mal_device_type_playback, NULL, mal_format_f32, channels, sampleRate, fragmentSizeInFrames, fragmentCount) != MAL_SUCCESS) {
if (mal_device_init(&playbackDevice, mal_device_type_playback, NULL, mal_format_f32, channels, sampleRate, fragmentSizeInFrames, fragmentCount) != MAL_SUCCESS) {
return -1;
}
...
...
mini_al.h
View file @
58989ea1
...
...
@@ -3,10 +3,27 @@
//
// David Reid - mackron@gmail.com
//
USAGE
//
ABOUT
// =====
// mini_al is a small library for making it easy to do audio playback and recording. It's focused on
// simplicity and being light-weight so don't expect all the bells and whistles.
//
// mini_al's uses an asynchronous API. Every device is created with it's own thread, with audio data
// being either delivered to the application from the device (in the case of recording/capture) or
// delivered from the application to the device in the case of playback. Synchronous APIs are not
// supported in the interest of keeping the library as small and lightweight as possible.
//
// Supported backends:
// - DirectSound (Windows Only)
// - ALSA (Linux Only)
// - ... and many more in the future.
//
// (WRITE ME)
//
// USAGE
// =====
// mini_al is a single-file library. To use it, do something like the following in one .c file.
// #define MAL_IMPLEMENTATION
// #include "mini_al.h"
//
//
// NOTES
...
...
@@ -17,6 +34,8 @@
// boundary (4 bytes on 32-bit, 8 bytes on 64-bit), it will _not_ be thread-safe. The reason for this
// is that it depends on members of mal_device being correctly aligned for atomic assignments and bit
// manipulation.
// - Sample data is always little-endian and interleaved. For example, mal_format_s16 means signed 16-bit
// integer samples, interleaved. Let me know if you need non-interleaved and I'll look into it.
//
//
// BACKEND NUANCES
...
...
@@ -86,11 +105,8 @@ typedef void* mal_ptr;
#ifdef MAL_WIN32
typedef
mal_handle
mal_thread
;
typedef
mal_handle
mal_event
;
typedef
mal_handle
mal_semaphore
;
#else
typedef
pthread_t
mal_thread
;
typedef
sem_t
mal_semaphore
;
typedef
struct
{
pthread_mutex_t
mutex
;
...
...
@@ -120,6 +136,7 @@ typedef int mal_result;
#define MAL_FAILED_TO_READ_DATA_FROM_CLIENT -23
#define MAL_FAILED_TO_START_BACKEND_DEVICE -24
#define MAL_FAILED_TO_STOP_BACKEND_DEVICE -25
#define MAL_FAILED_TO_MAP_DEVICE_BUFFER -26
typedef
struct
mal_device
mal_device
;
...
...
@@ -223,6 +240,13 @@ struct mal_device
// Enumerates over each device of the given type (playback or capture).
//
// Return Value:
// - MAL_SUCCESS if successful.
// - MAL_INVALID_ARGS
// One or more of the input arguments is invalid.
// - MAL_NO_BACKEND
// There is no supported backend, or there was an error loading it (such as a missing dll/so).
//
// Thread Safety: SAFE, SEE NOTES.
// This API uses an application-defined buffer for output. This is thread-safe so long as the
// application ensures mutal exclusion to the output buffer at their level.
...
...
@@ -238,23 +262,46 @@ mal_result mal_enumerate_devices(mal_device_type type, mal_uint32* pCount, mal_d
// information.
//
// This will try it's hardest to create a valid device, even if it means adjusting input arguments.
//
Use
pDevice->channels, pDevice->sampleRate, etc. to determine the actual properties after
//
Look at
pDevice->channels, pDevice->sampleRate, etc. to determine the actual properties after
// initialization.
//
// Return Value:
// - MAL_SUCCESS if successful.
// - MAL_INVALID_ARGS
// One or more of the input arguments is invalid.
// - MAL_NO_BACKEND
// There is no supported backend, or there was an error loading it (such as a missing dll/so).
// - MAL_OUT_OF_MEMORY
// A necessary memory allocation failed, likely due to running out of memory. The only backend
// that performs a memory allocation is ALSA when mmap mode is not supported.
// - MAL_FORMAT_NOT_SUPPORTED
// The specified format is not supported by the backend. mini_al does not currently do any
// software format conversions which means initialization must fail if the backend device does
// not natively support it.
// - MAL_FAILED_TO_INIT_BACKEND
// There was a backend-specific error during initialization.
//
// Thread Safety: SAFE
// This API is thread safe so long as the application does not try to use the device object before
// this call has returned.
//
// Efficiency: LOW
// This API will dynamically link to backend DLLs/SOs like dsound.dll, and is otherwise just slow
// due to the
fact that it's
an initialization API.
mal_result
mal_device_init
_async
(
mal_device
*
pDevice
,
mal_device_type
type
,
mal_device_id
*
pDeviceID
,
mal_format
format
,
mal_uint32
channels
,
mal_uint32
sampleRate
,
mal_uint32
fragmentSizeInFrames
,
mal_uint32
fragmentCount
);
// due to the
nature of it being
an initialization API.
mal_result
mal_device_init
(
mal_device
*
pDevice
,
mal_device_type
type
,
mal_device_id
*
pDeviceID
,
mal_format
format
,
mal_uint32
channels
,
mal_uint32
sampleRate
,
mal_uint32
fragmentSizeInFrames
,
mal_uint32
fragmentCount
);
// Uninitializes a device.
//
// This will explicitly stop the device. You do not need to call mal_device_stop() beforehand, but it's
// harmless if you do.
//
// Return Value:
// - MAL_SUCCESS if successful.
// - MAL_INVALID_ARGS
// pDevice is NULL.
// - MAL_DEVICE_NOT_INITIALIZED
// The device is not currently or was never initialized.
//
// Thread Safety: UNSAFE
// This API shouldn't crash in a multi-threaded environment, but results are undefined if an application
// attempts to do something with the device at the same time as uninitializing.
...
...
@@ -290,18 +337,19 @@ void mal_device_set_send_callback(mal_device* pDevice, mal_send_proc proc);
// to be done _before_ the device starts playing back audio.
//
// Return Value:
// MAL_SUCCESS if successful.
//
// MAL_DEVICE_BUSY
// - MAL_SUCCESS if successful.
// - MAL_INVALID_ARGS
// One or more of the input arguments is invalid.
// - MAL_DEVICE_NOT_INITIALIZED
// The device is not currently or was never initialized.
// - MAL_DEVICE_BUSY
// The device is in the process of stopping. This will only happen if mal_device_start() and
// mal_device_stop() is called simultaneous on separate threads. This will never be returned in
// single-threaded applications.
//
// MAL_DEVICE_ALREADY_STARTING
// - MAL_DEVICE_ALREADY_STARTING
// The device is already in the process of starting. This will never be returned in single-threaded
// applications.
//
// MAL_DEVICE_ALREADY_STARTED
// - MAL_DEVICE_ALREADY_STARTED
// The device is already started.
//
// Thread Safety: SAFE
...
...
@@ -312,6 +360,22 @@ mal_result mal_device_start(mal_device* pDevice);
// Puts the device to sleep, but does not uninitialize it. Use mal_device_start() to start it up again.
//
// Return Value:
// - MAL_SUCCESS if successful.
// - MAL_INVALID_ARGS
// One or more of the input arguments is invalid.
// - MAL_DEVICE_NOT_INITIALIZED
// The device is not currently or was never initialized.
// - MAL_DEVICE_BUSY
// The device is in the process of starting. This will only happen if mal_device_start() and
// mal_device_stop() is called simultaneous on separate threads. This will never be returned in
// single-threaded applications.
// - MAL_DEVICE_ALREADY_STOPPING
// The device is already in the process of stopping. This will never be returned in single-threaded
// applications.
// - MAL_DEVICE_ALREADY_STOPPED
// The device is already stopped.
//
// Thread Safety: SAFE
//
// Efficiency: LOW
...
...
@@ -320,6 +384,9 @@ mal_result mal_device_stop(mal_device* pDevice);
// Determines whether or not the device is started.
//
// Return Value:
// True if the device is started, false otherwise.
//
// Thread Safety: SAFE
// If another thread calls mal_device_start() or mal_device_stop() at this same time as this function
// is called, there's a very small chance the return value will out of sync.
...
...
@@ -559,6 +626,11 @@ void mal_thread_wait__win32(mal_thread* pThread)
WaitForSingleObject
(
*
pThread
,
INFINITE
);
}
void
mal_sleep__win32
(
mal_uint32
milliseconds
)
{
Sleep
((
DWORD
)
milliseconds
);
}
mal_bool32
mal_event_create__win32
(
mal_event
*
pEvent
)
{
...
...
@@ -598,6 +670,11 @@ void mal_thread_wait__posix(mal_thread* pThread)
pthread_join
(
*
pThread
,
NULL
);
}
void
mal_sleep__posix
(
mal_uint32
milliseconds
)
{
usleep
(
milliseconds
*
1000
);
// <-- usleep is in microseconds.
}
mal_bool32
mal_event_create__posix
(
mal_event
*
pEvent
)
{
...
...
@@ -673,6 +750,17 @@ void mal_thread_wait(mal_thread* pThread)
#endif
}
void
mal_sleep
(
mal_uint32
milliseconds
)
{
#ifdef MAL_WIN32
mal_sleep__win32
(
milliseconds
);
#endif
#ifdef MAL_POSIX
mal_sleep__posix
(
milliseconds
);
#endif
}
mal_bool32
mal_event_create
(
mal_event
*
pEvent
)
{
...
...
@@ -1283,7 +1371,7 @@ static mal_result mal_device__read_fragment_from_client__dsound(mal_device* pDev
void
*
pLockPtr
;
DWORD
lockSize
;
if
(
FAILED
(
IDirectSoundBuffer_Lock
((
LPDIRECTSOUNDBUFFER
)
pDevice
->
dsound
.
pPlaybackBuffer
,
offset
,
fragmentSizeInBytes
,
&
pLockPtr
,
&
lockSize
,
NULL
,
NULL
,
0
)))
{
return
MAL_
ERRO
R
;
return
MAL_
FAILED_TO_MAP_DEVICE_BUFFE
R
;
}
mal_device__read_samples_from_client
(
pDevice
,
pDevice
->
fragmentSizeInFrames
*
pDevice
->
channels
,
pLockPtr
);
...
...
@@ -1302,7 +1390,7 @@ static mal_result mal_device__send_fragment_to_client__dsound(mal_device* pDevic
void
*
pLockPtr
;
DWORD
lockSize
;
if
(
FAILED
(
IDirectSoundCaptureBuffer_Lock
((
LPDIRECTSOUNDCAPTUREBUFFER8
)
pDevice
->
dsound
.
pCaptureBuffer
,
offset
,
fragmentSizeInBytes
,
&
pLockPtr
,
&
lockSize
,
NULL
,
NULL
,
0
)))
{
return
MAL_
ERRO
R
;
return
MAL_
FAILED_TO_MAP_DEVICE_BUFFE
R
;
}
mal_device__send_samples_to_client
(
pDevice
,
pDevice
->
fragmentSizeInFrames
*
pDevice
->
channels
,
pLockPtr
);
...
...
@@ -1630,7 +1718,7 @@ mal_result mal_enumerate_devices__alsa(mal_device_type type, mal_uint32* pCount,
char
**
ppDeviceHints
;
if
(
snd_device_name_hint
(
-
1
,
"pcm"
,
(
void
***
)
&
ppDeviceHints
)
<
0
)
{
return
MAL_
ERROR
;
return
MAL_
SUCCESS
;
// <-- This is unintuitive, but it just emulates the case where there are no devices.
}
char
**
ppNextDeviceHint
=
ppDeviceHints
;
...
...
@@ -1730,7 +1818,7 @@ mal_result mal_device_init__alsa(mal_device* pDevice, mal_device_type type, mal_
if
(
snd_pcm_hw_params_set_format
((
snd_pcm_t
*
)
pDevice
->
alsa
.
pPCM
,
pHWParams
,
formatALSA
)
<
0
)
{
snd_pcm_hw_params_free
(
pHWParams
);
mal_device_uninit__alsa
(
pDevice
);
return
MAL_F
AILED_TO_INIT_BACKEN
D
;
return
MAL_F
ORMAT_NOT_SUPPORTE
D
;
}
if
(
snd_pcm_hw_params_set_rate_near
((
snd_pcm_t
*
)
pDevice
->
alsa
.
pPCM
,
pHWParams
,
&
sampleRate
,
0
)
<
0
)
{
...
...
@@ -2154,7 +2242,9 @@ void mal_device_uninit(mal_device* pDevice)
// Make sure the device is stopped first. The backends will probably handle this naturally,
// but I like to do it explicitly for my own sanity.
mal_device_stop
(
pDevice
);
while
(
mal_device_stop
(
pDevice
)
==
MAL_DEVICE_BUSY
)
{
mal_sleep
(
10
);
}
// Putting the device into an uninitialized state will make the worker thread return.
mal_device__set_state
(
pDevice
,
MAL_STATE_UNINITIALIZED
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment