pvrecorder/src/miniaudio/examples/simple_mixing.c
Go to the documentation of this file.
1 /*
2 Demonstrates one way to load multiple files and play them all back at the same time.
3 
4 When mixing multiple sounds together, you should not create multiple devices. Instead you should create only a single
5 device and then mix your sounds together which you can do by simply summing their samples together. The simplest way to
6 do this is to use floating point samples and use miniaudio's built-in clipper to handling clipping for you. (Clipping
7 is when sample are clampled to their minimum and maximum range, which for floating point is -1..1.)
8 
9 ```
10 Usage: simple_mixing [input file 0] [input file 1] ... [input file n]
11 Example: simple_mixing file1.wav file2.flac
12 ```
13 */
14 #define MINIAUDIO_IMPLEMENTATION
15 #include "../miniaudio.h"
16 
17 #include <stdio.h>
18 
19 /*
20 For simplicity, this example requires the device to use floating point samples.
21 */
22 #define SAMPLE_FORMAT ma_format_f32
23 #define CHANNEL_COUNT 2
24 #define SAMPLE_RATE 48000
25 
29 
30 ma_event g_stopEvent; /* <-- Signaled by the audio thread, waited on by the main thread. */
31 
33 {
34  ma_uint32 iDecoder;
35  for (iDecoder = 0; iDecoder < g_decoderCount; ++iDecoder) {
36  if (g_pDecodersAtEnd[iDecoder] == MA_FALSE) {
37  return MA_FALSE;
38  }
39  }
40 
41  return MA_TRUE;
42 }
43 
44 ma_uint32 read_and_mix_pcm_frames_f32(ma_decoder* pDecoder, float* pOutputF32, ma_uint32 frameCount)
45 {
46  /*
47  The way mixing works is that we just read into a temporary buffer, then take the contents of that buffer and mix it with the
48  contents of the output buffer by simply adding the samples together. You could also clip the samples to -1..+1, but I'm not
49  doing that in this example.
50  */
51  float temp[4096];
52  ma_uint32 tempCapInFrames = ma_countof(temp) / CHANNEL_COUNT;
53  ma_uint32 totalFramesRead = 0;
54 
55  while (totalFramesRead < frameCount) {
56  ma_uint32 iSample;
57  ma_uint32 framesReadThisIteration;
58  ma_uint32 totalFramesRemaining = frameCount - totalFramesRead;
59  ma_uint32 framesToReadThisIteration = tempCapInFrames;
60  if (framesToReadThisIteration > totalFramesRemaining) {
61  framesToReadThisIteration = totalFramesRemaining;
62  }
63 
64  framesReadThisIteration = (ma_uint32)ma_decoder_read_pcm_frames(pDecoder, temp, framesToReadThisIteration);
65  if (framesReadThisIteration == 0) {
66  break;
67  }
68 
69  /* Mix the frames together. */
70  for (iSample = 0; iSample < framesReadThisIteration*CHANNEL_COUNT; ++iSample) {
71  pOutputF32[totalFramesRead*CHANNEL_COUNT + iSample] += temp[iSample];
72  }
73 
74  totalFramesRead += framesReadThisIteration;
75 
76  if (framesReadThisIteration < framesToReadThisIteration) {
77  break; /* Reached EOF. */
78  }
79  }
80 
81  return totalFramesRead;
82 }
83 
84 void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
85 {
86  float* pOutputF32 = (float*)pOutput;
87  ma_uint32 iDecoder;
88 
89  MA_ASSERT(pDevice->playback.format == SAMPLE_FORMAT); /* <-- Important for this example. */
90 
91  for (iDecoder = 0; iDecoder < g_decoderCount; ++iDecoder) {
92  if (!g_pDecodersAtEnd[iDecoder]) {
93  ma_uint32 framesRead = read_and_mix_pcm_frames_f32(&g_pDecoders[iDecoder], pOutputF32, frameCount);
94  if (framesRead < frameCount) {
95  g_pDecodersAtEnd[iDecoder] = MA_TRUE;
96  }
97  }
98  }
99 
100  /*
101  If at the end all of our decoders are at the end we need to stop. We cannot stop the device in the callback. Instead we need to
102  signal an event to indicate that it's stopped. The main thread will be waiting on the event, after which it will stop the device.
103  */
104  if (are_all_decoders_at_end()) {
106  }
107 
108  (void)pInput;
109 }
110 
111 int main(int argc, char** argv)
112 {
113  ma_result result;
114  ma_decoder_config decoderConfig;
115  ma_device_config deviceConfig;
117  ma_uint32 iDecoder;
118 
119  if (argc < 2) {
120  printf("No input files.\n");
121  return -1;
122  }
123 
124  g_decoderCount = argc-1;
125  g_pDecoders = (ma_decoder*)malloc(sizeof(*g_pDecoders) * g_decoderCount);
127 
128  /* In this example, all decoders need to have the same output format. */
130  for (iDecoder = 0; iDecoder < g_decoderCount; ++iDecoder) {
131  result = ma_decoder_init_file(argv[1+iDecoder], &decoderConfig, &g_pDecoders[iDecoder]);
132  if (result != MA_SUCCESS) {
133  ma_uint32 iDecoder2;
134  for (iDecoder2 = 0; iDecoder2 < iDecoder; ++iDecoder2) {
135  ma_decoder_uninit(&g_pDecoders[iDecoder2]);
136  }
137  free(g_pDecoders);
138  free(g_pDecodersAtEnd);
139 
140  printf("Failed to load %s.\n", argv[1+iDecoder]);
141  return -3;
142  }
143  g_pDecodersAtEnd[iDecoder] = MA_FALSE;
144  }
145 
146  /* Create only a single device. The decoders will be mixed together in the callback. In this example the data format needs to be the same as the decoders. */
148  deviceConfig.playback.format = SAMPLE_FORMAT;
149  deviceConfig.playback.channels = CHANNEL_COUNT;
150  deviceConfig.sampleRate = SAMPLE_RATE;
151  deviceConfig.dataCallback = data_callback;
152  deviceConfig.pUserData = NULL;
153 
154  if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) {
155  for (iDecoder = 0; iDecoder < g_decoderCount; ++iDecoder) {
156  ma_decoder_uninit(&g_pDecoders[iDecoder]);
157  }
158  free(g_pDecoders);
159  free(g_pDecodersAtEnd);
160 
161  printf("Failed to open playback device.\n");
162  return -3;
163  }
164 
165  /*
166  We can't stop in the audio thread so we instead need to use an event. We wait on this thread in the main thread, and signal it in the audio thread. This
167  needs to be done before starting the device. We need a context to initialize the event, which we can get from the device. Alternatively you can initialize
168  a context separately, but we don't need to do that for this example.
169  */
171 
172  /* Now we start playback and wait for the audio thread to tell us to stop. */
173  if (ma_device_start(&device) != MA_SUCCESS) {
175  for (iDecoder = 0; iDecoder < g_decoderCount; ++iDecoder) {
176  ma_decoder_uninit(&g_pDecoders[iDecoder]);
177  }
178  free(g_pDecoders);
179  free(g_pDecodersAtEnd);
180 
181  printf("Failed to start playback device.\n");
182  return -4;
183  }
184 
185  printf("Waiting for playback to complete...\n");
187 
188  /* Getting here means the audio thread has signaled that the device should be stopped. */
190 
191  for (iDecoder = 0; iDecoder < g_decoderCount; ++iDecoder) {
192  ma_decoder_uninit(&g_pDecoders[iDecoder]);
193  }
194  free(g_pDecoders);
195  free(g_pDecodersAtEnd);
196 
197  return 0;
198 }
MA_FALSE
#define MA_FALSE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1531
ma_device_uninit
void ma_device_uninit(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27425
ma_device_start
ma_result ma_device_start(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27485
NULL
#define NULL
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:92
ma_decoder_uninit
ma_result ma_decoder_uninit(ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44739
ma_decoder_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5170
ma_bool32
ma_uint32 ma_bool32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1529
ma_countof
#define ma_countof(x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:776
ma_decoder_config_init
ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:40646
g_pDecodersAtEnd
ma_bool32 * g_pDecodersAtEnd
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:28
ma_device::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3625
ma_device_type_playback
@ ma_device_type_playback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3012
ma_device_config::dataCallback
ma_device_callback_proc dataCallback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3110
device
ma_device device
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/tests/test_deviceio/ma_test_deviceio.c:57
ma_result
int ma_result
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1658
ma_event_wait
MA_API ma_result ma_event_wait(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4898
ma_event_init
MA_API ma_result ma_event_init(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4829
SAMPLE_FORMAT
#define SAMPLE_FORMAT
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:22
are_all_decoders_at_end
ma_bool32 are_all_decoders_at_end()
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:32
ma_decoder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5193
MA_ASSERT
#define MA_ASSERT(condition)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:770
g_decoderCount
ma_uint32 g_decoderCount
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:26
ma_event
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2868
ma_uint32
uint32_t ma_uint32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1503
ma_device_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3128
ma_decoder_read_pcm_frames
ma_uint64 ma_decoder_read_pcm_frames(ma_decoder *pDecoder, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44808
ma_device_config_init
ma_device_config ma_device_config_init(ma_device_type deviceType)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27034
SAMPLE_RATE
#define SAMPLE_RATE
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:24
ma_device_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3129
ma_decoder_init_file
ma_result ma_decoder_init_file(const char *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44687
python.test_porcupine.argv
argv
Definition: test_porcupine.py:158
ma_device_init
ma_result ma_device_init(ma_context *pContext, const ma_device_config *pConfig, ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27048
ma_device
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3584
ma_device_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3100
ma_device_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3103
read_and_mix_pcm_frames_f32
ma_uint32 read_and_mix_pcm_frames_f32(ma_decoder *pDecoder, float *pOutputF32, ma_uint32 frameCount)
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:44
MA_TRUE
#define MA_TRUE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1530
MA_SUCCESS
#define MA_SUCCESS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1659
data_callback
void data_callback(ma_device *pDevice, void *pOutput, const void *pInput, ma_uint32 frameCount)
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:84
CHANNEL_COUNT
#define CHANNEL_COUNT
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:23
g_pDecoders
ma_decoder * g_pDecoders
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:27
ma_device_config::playback
struct ma_device_config::@97 playback
main
int main(int argc, char **argv)
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:111
ma_device::playback
struct ma_device::@115 playback
ma_event_signal
MA_API ma_result ma_event_signal(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4913
ma_device_config::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3112
g_stopEvent
ma_event g_stopEvent
Definition: pvrecorder/src/miniaudio/examples/simple_mixing.c:30


picovoice_driver
Author(s):
autogenerated on Fri Apr 1 2022 02:14:50