diff --git a/README.md b/README.md index c6f894bd..c8ff1914 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,17 @@ Features -Example -======= -mini_al will request and deliver audio data through callbacks. +Simple Playback Example +======================= ```c mal_uint32 on_send_frames_to_device(mal_device* pDevice, mal_uint32 frameCount, void* pSamples) { - drwav* pWav = (drwav*)pDevice->pUserData; + drwav* pWav = (drwav*)pDevice->pUserData; + if (pWav == NULL) { + return 0; + } + return (mal_uint32)drwav_read_f32(pWav, frameCount * pDevice->channels, (float*)pSamples) / pDevice->channels; } @@ -42,20 +45,23 @@ int main(int argc, char** argv) } // In this example we use the default playback device with a default buffer size and period count. + mal_device_config config; + config.format = mal_format_f32; + config.channels = wav.channels; + config.sampleRate = wav.sampleRate; + config.bufferSizeInFrames = 0; // Use default. + config.periods = 0; // Use default. + config.onRecvCallback = NULL; // Not used for playback. + config.onSendCallback = on_send_frames_to_device; + config.onStopCallback = NULL; + config.onLogCallback = NULL; + mal_device device; - if (mal_device_init(&device, mal_device_type_playback, NULL, mal_format_f32, wav.channels, wav.sampleRate, 0, 0, NULL) != MAL_SUCCESS) { + if (mal_device_init(&device, mal_device_type_playback, NULL, &config, &wav) != MAL_SUCCESS) { printf("Failed to open playback device."); drwav_uninit(&wav); return -3; } - - // The pUserData member of mal_device is reserved for you. - device.pUserData = &wav; - - // This is the callback for sending data to a playback device when it needs more. Make sure - // it's set before playing the device otherwise you'll end up with silence for the first - // bunch of frames. - mal_device_set_send_callback(&device, on_send_frames_to_device); mal_device_start(&device); printf("Press Enter to quit..."); diff --git a/examples/simple_capture.c b/examples/simple_capture.c index 58f14f5c..a923e004 100644 --- a/examples/simple_capture.c +++ b/examples/simple_capture.c @@ -53,14 +53,17 @@ int main() config.sampleRate = 48000; config.bufferSizeInFrames = 0; // Use default. config.periods = 0; // Use default. + config.onRecvCallback = on_recv_frames; + config.onSendCallback = on_send_frames; + config.onStopCallback = NULL; + config.onLogCallback = NULL; printf("Recording...\n"); mal_device captureDevice; - if (mal_device_init(&captureDevice, mal_device_type_capture, NULL, &config, NULL, NULL)) { + if (mal_device_init(&captureDevice, mal_device_type_capture, NULL, &config, NULL)) { printf("Failed to initialize capture device.\n"); return -2; } - mal_device_set_recv_callback(&captureDevice, on_recv_frames); mal_device_start(&captureDevice); printf("Press Enter to stop recording...\n"); @@ -71,11 +74,10 @@ int main() printf("Playing...\n"); mal_device playbackDevice; - if (mal_device_init(&playbackDevice, mal_device_type_playback, NULL, &config, NULL, NULL)) { + if (mal_device_init(&playbackDevice, mal_device_type_playback, NULL, &config, NULL)) { printf("Failed to initialize playback device.\n"); return -3; } - mal_device_set_send_callback(&playbackDevice, on_send_frames); mal_device_start(&playbackDevice); printf("Press Enter to quit...\n"); diff --git a/examples/simple_playback.c b/examples/simple_playback.c index 79e38ec3..9f50e5a3 100644 --- a/examples/simple_playback.c +++ b/examples/simple_playback.c @@ -37,21 +37,17 @@ int main(int argc, char** argv) config.sampleRate = wav.sampleRate; config.bufferSizeInFrames = 0; // Use default. config.periods = 0; // Use default. + config.onRecvCallback = NULL; // Not used for playback. + config.onSendCallback = on_send_frames_to_device; + config.onStopCallback = NULL; + config.onLogCallback = NULL; mal_device device; - if (mal_device_init(&device, mal_device_type_playback, NULL, &config, NULL, NULL) != MAL_SUCCESS) { + if (mal_device_init(&device, mal_device_type_playback, NULL, &config, &wav) != MAL_SUCCESS) { printf("Failed to open playback device."); drwav_uninit(&wav); return -3; } - - // The pUserData member of mal_device is reserved for you. - device.pUserData = &wav; - - // This is the callback for sending data to a playback device when it needs more. Make sure - // it's set before playing the device otherwise you'll end up with silence for the first - // bunch of frames. - mal_device_set_send_callback(&device, on_send_frames_to_device); mal_device_start(&device); printf("Press Enter to quit..."); diff --git a/mini_al.h b/mini_al.h index 0bf2d2a8..ff267a1f 100644 --- a/mini_al.h +++ b/mini_al.h @@ -75,14 +75,17 @@ // config.sampleRate = wav.sampleRate; // config.bufferSizeInFrames = 0; // Use default. // config.periods = 0; // Use default. +// config.onSendCallback = on_send_samples; +// config.onRecvCallback = NULL; // Not used for playback devices. +// config.onStopCallback = NULL; // We don't care about knowing when the device has stopped... +// config.onLogCallback = NULL; // ... nor do we care about logging (but you really should in a real-world application). // // mal_device device; -// mal_result result = mal_device_init(&device, mal_device_type_playback, NULL, &config, NULL, pMyData); +// mal_result result = mal_device_init(&device, mal_device_type_playback, NULL, &config, pMyData); // if (result != MAL_SUCCESS) { // return -1; // } // -// mal_device_set_send_callback(&device, on_send_samples); // mal_device_start(&device); // The device is sleeping by default so you'll need to start it manually. // // ... @@ -293,11 +296,11 @@ typedef enum { // I like to keep these explicitly defined because they're used as a key into a lookup table. When items are // added to this, make sure there are no gaps and that they're added to the lookup table in mal_get_sample_size_in_bytes(). - mal_format_u8 = 0, - mal_format_s16 = 1, // Seems to be the most widely supported format. - mal_format_s24 = 2, // Tightly packed. 3 bytes per sample. - mal_format_s32 = 3, - mal_format_f32 = 4, + mal_format_u8 = 0, + mal_format_s16 = 1, // Seems to be the most widely supported format. + mal_format_s24 = 2, // Tightly packed. 3 bytes per sample. + mal_format_s32 = 3, + mal_format_f32 = 4, } mal_format; typedef union @@ -325,6 +328,10 @@ typedef struct mal_uint32 sampleRate; mal_uint32 bufferSizeInFrames; mal_uint32 periods; + mal_recv_proc onRecvCallback; + mal_send_proc onSendCallback; + mal_stop_proc onStopCallback; + mal_log_proc onLogCallback; } mal_device_config; struct mal_device @@ -337,7 +344,6 @@ struct mal_device mal_uint32 bufferSizeInFrames; mal_uint32 periods; mal_uint32 state; - mal_uint32 flags; // MAL_DEVICE_FLAG_* mal_recv_proc onRecv; mal_send_proc onSend; mal_stop_proc onStop; @@ -349,6 +355,7 @@ struct mal_device mal_event stopEvent; mal_thread thread; mal_result workResult; // This is set by the worker thread after it's finished doing a job. + mal_uint32 flags; // MAL_DEVICE_FLAG_* union { @@ -467,7 +474,7 @@ mal_result mal_enumerate_devices(mal_device_type type, mal_uint32* pCount, mal_d // Efficiency: LOW // This API will dynamically link to backend DLLs/SOs like dsound.dll, and is otherwise just slow // 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_device_config* pConfig, mal_log_proc onLog, void* pUserData); +mal_result mal_device_init(mal_device* pDevice, mal_device_type type, mal_device_id* pDeviceID, mal_device_config* pConfig, void* pUserData); // Uninitializes a device. // @@ -3468,14 +3475,17 @@ mal_result mal_enumerate_devices(mal_device_type type, mal_uint32* pCount, mal_d return result; } -mal_result mal_device_init(mal_device* pDevice, mal_device_type type, mal_device_id* pDeviceID, mal_device_config* pConfig, mal_log_proc onLog, void* pUserData) +mal_result mal_device_init(mal_device* pDevice, mal_device_type type, mal_device_id* pDeviceID, mal_device_config* pConfig, void* pUserData) { if (pDevice == NULL) return mal_post_error(pDevice, "mal_device_init() called with invalid arguments.", MAL_INVALID_ARGS); mal_zero_object(pDevice); // Set the user data and log callback ASAP to ensure it is available for the entire initialization process. pDevice->pUserData = pUserData; - pDevice->onLog = onLog; + pDevice->onLog = pConfig->onLogCallback; + pDevice->onStop = pConfig->onStopCallback; + pDevice->onSend = pConfig->onSendCallback; + pDevice->onRecv = pConfig->onRecvCallback; if (((mal_uint64)pDevice % sizeof(pDevice)) != 0) { if (pDevice->onLog) {