77#include <audioclient.h>
88#include <fcntl.h>
99#include <io.h>
10+ #include <stdbool.h>
11+ #include <stddef.h>
12+ #include <stdint.h>
1013#include <stdio.h>
1114#include <stdlib.h>
1215#include <windows.h>
1518
1619#include "common.h"
1720
21+ static void make_stereo_waveformatex (const WAVEFORMATEX * orig , WAVEFORMATEX * stereo ) {
22+ * stereo = * orig ;
23+ stereo -> wFormatTag = WAVE_FORMAT_PCM ;
24+ stereo -> nChannels = 2 ;
25+ stereo -> wBitsPerSample = 16 ;
26+ stereo -> nBlockAlign = stereo -> nChannels * (stereo -> wBitsPerSample / 8 );
27+ stereo -> nAvgBytesPerSec = stereo -> nSamplesPerSec * stereo -> nBlockAlign ;
28+ stereo -> cbSize = 0 ;
29+ }
30+
31+ // Downmix interleaved 16-bit PCM to stereo
32+ static void downmix_to_stereo_s16 (const int16_t * src , int16_t * dst , size_t frames , int channels ) {
33+ size_t i ;
34+ for (i = 0 ; i < frames ; ++ i ) {
35+ int left = 0 , right = 0 ;
36+ if (channels >= 2 ) {
37+ left += src [i * channels + 0 ];
38+ right += src [i * channels + 1 ];
39+ }
40+ if (channels >= 3 ) {
41+ left += (int )(src [i * channels + 2 ] * 0.7f );
42+ right += (int )(src [i * channels + 2 ] * 0.7f );
43+ }
44+ if (channels >= 5 ) {
45+ left += (int )(src [i * channels + 4 ] * 0.7f );
46+ right += (int )(src [i * channels + 5 ] * 0.7f );
47+ }
48+ if (channels >= 7 ) {
49+ left += (int )(src [i * channels + 6 ] * 0.7f );
50+ right += (int )(src [i * channels + 7 ] * 0.7f );
51+ }
52+ if (left > 32767 )
53+ left = 32767 ;
54+ if (left < -32768 )
55+ left = -32768 ;
56+ if (right > 32767 )
57+ right = 32767 ;
58+ if (right < -32768 )
59+ right = -32768 ;
60+ dst [i * 2 + 0 ] = (int16_t )left ;
61+ dst [i * 2 + 1 ] = (int16_t )right ;
62+ }
63+ }
64+
65+ // Helper to convert 3 bytes (little-endian) to signed 32-bit int
66+ static inline int32_t s24_to_s32 (const uint8_t * p ) {
67+ int32_t val = p [0 ] | (p [1 ] << 8 ) | (p [2 ] << 16 );
68+ // Sign-extend if negative
69+ if (val & 0x800000 )
70+ val |= ~0xFFFFFF ;
71+ return val ;
72+ }
73+
74+ // Downmix interleaved 24-bit PCM to stereo
75+ static void downmix_to_stereo_s24 (const uint8_t * src , int16_t * dst , size_t frames , int channels ) {
76+ size_t i ;
77+ for (i = 0 ; i < frames ; ++ i ) {
78+ int left = 0 , right = 0 ;
79+
80+ const uint8_t * frame = src + i * channels * 3 ;
81+ if (channels >= 2 ) {
82+ left += s24_to_s32 (frame + 0 * 3 ) >> 8 ;
83+ right += s24_to_s32 (frame + 1 * 3 ) >> 8 ;
84+ }
85+ if (channels >= 3 ) {
86+ int32_t c = s24_to_s32 (frame + 2 * 3 ) >> 8 ;
87+ left += (int )(c * 0.7f );
88+ right += (int )(c * 0.7f );
89+ }
90+ if (channels >= 5 ) {
91+ int32_t c4 = s24_to_s32 (frame + 4 * 3 ) >> 8 ;
92+ int32_t c5 = s24_to_s32 (frame + 5 * 3 ) >> 8 ;
93+ left += (int )(c4 * 0.7f );
94+ right += (int )(c5 * 0.7f );
95+ }
96+ if (channels >= 7 ) {
97+ int32_t c6 = s24_to_s32 (frame + 6 * 3 ) >> 8 ;
98+ int32_t c7 = s24_to_s32 (frame + 7 * 3 ) >> 8 ;
99+ left += (int )(c6 * 0.7f );
100+ right += (int )(c7 * 0.7f );
101+ }
102+ // Clip to int16_t
103+ if (left > 32767 )
104+ left = 32767 ;
105+ if (left < -32768 )
106+ left = -32768 ;
107+ if (right > 32767 )
108+ right = 32767 ;
109+ if (right < -32768 )
110+ right = -32768 ;
111+ dst [i * 2 + 0 ] = (int16_t )left ;
112+ dst [i * 2 + 1 ] = (int16_t )right ;
113+ }
114+ }
115+
116+ // Downmix interleaved 32-bit PCM to stereo
117+ static void downmix_to_stereo_s32 (const int32_t * src , int16_t * dst , size_t frames , int channels ) {
118+ size_t i ;
119+ for (i = 0 ; i < frames ; ++ i ) {
120+ int64_t left = 0 , right = 0 ;
121+ if (channels >= 2 ) {
122+ left += src [i * channels + 0 ];
123+ right += src [i * channels + 1 ];
124+ }
125+ if (channels >= 3 ) {
126+ left += (int64_t )(src [i * channels + 2 ] * 0.7f );
127+ right += (int64_t )(src [i * channels + 2 ] * 0.7f );
128+ }
129+ if (channels >= 5 ) {
130+ left += (int64_t )(src [i * channels + 4 ] * 0.7f );
131+ right += (int64_t )(src [i * channels + 5 ] * 0.7f );
132+ }
133+ if (channels >= 7 ) {
134+ left += (int64_t )(src [i * channels + 6 ] * 0.7f );
135+ right += (int64_t )(src [i * channels + 7 ] * 0.7f );
136+ }
137+ // Convert from 32-bit to 16-bit with clipping
138+ left >>= 16 ;
139+ right >>= 16 ;
140+ if (left > 32767 )
141+ left = 32767 ;
142+ if (left < -32768 )
143+ left = -32768 ;
144+ if (right > 32767 )
145+ right = 32767 ;
146+ if (right < -32768 )
147+ right = -32768 ;
148+ dst [i * 2 + 0 ] = (int16_t )left ;
149+ dst [i * 2 + 1 ] = (int16_t )right ;
150+ }
151+ }
152+
153+ // Downmix interleaved 32-bit float to stereo
154+ static void downmix_to_stereo_f32 (const float * src , int16_t * dst , size_t frames , int channels ) {
155+ size_t i ;
156+ for (i = 0 ; i < frames ; ++ i ) {
157+ float left = 0.0f , right = 0.0f ;
158+ if (channels >= 2 ) {
159+ left += src [i * channels + 0 ];
160+ right += src [i * channels + 1 ];
161+ }
162+ if (channels >= 3 ) {
163+ left += src [i * channels + 2 ] * 0.7f ;
164+ right += src [i * channels + 2 ] * 0.7f ;
165+ }
166+ if (channels >= 5 ) {
167+ left += src [i * channels + 4 ] * 0.7f ;
168+ right += src [i * channels + 5 ] * 0.7f ;
169+ }
170+ if (channels >= 7 ) {
171+ left += src [i * channels + 6 ] * 0.7f ;
172+ right += src [i * channels + 7 ] * 0.7f ;
173+ }
174+ // Convert from float [-1.0, 1.0] to int16_t
175+ int l = (int )(left * 32767.0f );
176+ int r = (int )(right * 32767.0f );
177+ if (l > 32767 )
178+ l = 32767 ;
179+ if (l < -32768 )
180+ l = -32768 ;
181+ if (r > 32767 )
182+ r = 32767 ;
183+ if (r < -32768 )
184+ r = -32768 ;
185+ dst [i * 2 + 0 ] = (int16_t )l ;
186+ dst [i * 2 + 1 ] = (int16_t )r ;
187+ }
188+ }
189+
18190// IID_IMMNotificationClient definition for linking
19191
20192#if !defined(__MINGW32__ ) && !defined(__MINGW64__ )
@@ -132,6 +304,45 @@ struct {
132304 {AUDCLNT_E_UNSUPPORTED_FORMAT , L"Requested sound format unsupported" },
133305};
134306
307+ void write_silent_frame (struct audio_data * audio , IAudioCaptureClient * pCapture ,
308+ UINT32 numFramesAvailable , UINT32 packetLength ) {
309+ // Send one silent frame to the spectrometer
310+ int silent_channels = audio -> channels ;
311+ int silent_bytes = silent_channels * sizeof (int16_t ); // 16-bit PCM
312+ int16_t silence [2 ] = {0 };
313+
314+ write_to_cava_input_buffers (silent_channels , (unsigned char * )silence , audio );
315+ pCapture -> lpVtbl -> ReleaseBuffer (pCapture , numFramesAvailable );
316+ pCapture -> lpVtbl -> GetNextPacketSize (pCapture , & packetLength );
317+ }
318+
319+ void process_multichannel (UINT32 numFramesAvailable , const WAVEFORMATEX format , const void * pData ,
320+ struct audio_data * audio , IAudioCaptureClient * pCapture ,
321+ UINT32 packetLength , WAVEFORMATEX stereo_format ) {
322+
323+ int16_t * stereo_buffer = (int16_t * )malloc (numFramesAvailable * 2 * sizeof (int16_t ));
324+ if (format .wFormatTag == WAVE_FORMAT_IEEE_FLOAT && format .wBitsPerSample == 32 ) {
325+ downmix_to_stereo_f32 ((const float * )pData , stereo_buffer , numFramesAvailable ,
326+ format .nChannels );
327+ } else if (format .wBitsPerSample == 32 ) {
328+ downmix_to_stereo_s32 ((const int32_t * )pData , stereo_buffer , numFramesAvailable ,
329+ format .nChannels );
330+ } else if (format .wBitsPerSample == 24 ) {
331+ downmix_to_stereo_s24 ((const uint8_t * )pData , stereo_buffer , numFramesAvailable ,
332+ format .nChannels );
333+ } else if (format .wBitsPerSample == 16 ) {
334+ downmix_to_stereo_s16 ((const int16_t * )pData , stereo_buffer , numFramesAvailable ,
335+ format .nChannels );
336+ } else {
337+ // Unsupported format, handle error
338+ write_silent_frame (audio , pCapture , numFramesAvailable , packetLength );
339+ return ;
340+ }
341+ write_to_cava_input_buffers (numFramesAvailable * stereo_format .nChannels ,
342+ (unsigned char * )stereo_buffer , audio );
343+ free (stereo_buffer );
344+ }
345+
135346void input_winscap (void * data ) {
136347
137348 static const GUID CLSID_MMDeviceEnumerator = {0xBCDE0395 , 0xE52F , 0x467C , 0x8E , 0x3D , 0xC4 ,
@@ -145,13 +356,25 @@ void input_winscap(void *data) {
145356
146357 struct audio_data * audio = (struct audio_data * )data ;
147358 pthread_mutex_lock (& audio -> lock );
148- CoInitialize (0 );
359+
360+ HRESULT hr = CoInitialize (0 );
361+ if (FAILED (hr )) {
362+ fwprintf (stderr , L"CoInitialize failed: 0x%08lx\n" , hr );
363+ pthread_mutex_unlock (& audio -> lock );
364+ return ;
365+ }
149366
150367 WAVEFORMATEX * wfx = NULL ;
151368 WAVEFORMATEXTENSIBLE * wfx_ext = NULL ;
152369 IMMDeviceEnumerator * pEnumerator = NULL ;
153- HRESULT hr = CoCreateInstance (& CLSID_MMDeviceEnumerator , NULL , CLSCTX_ALL ,
154- & IID_IMMDeviceEnumerator , (void * * )& pEnumerator );
370+ hr = CoCreateInstance (& CLSID_MMDeviceEnumerator , NULL , CLSCTX_ALL , & IID_IMMDeviceEnumerator ,
371+ (void * * )& pEnumerator );
372+ if (FAILED (hr )) {
373+ fwprintf (stderr , L"Failed to create device enumerator: 0x%08lx\n" , hr );
374+ CoUninitialize ();
375+ pthread_mutex_unlock (& audio -> lock );
376+ return ;
377+ }
155378
156379 HANDLE hEvent = CreateEvent (NULL , TRUE, FALSE, NULL );
157380
@@ -172,9 +395,16 @@ void input_winscap(void *data) {
172395
173396 hr = pClient -> lpVtbl -> GetMixFormat (pClient , & wfx );
174397
398+ if (FAILED (hr ) || wfx == NULL ) {
399+ fwprintf (stderr , L"Failed to GetMixFormat for client\n" );
400+ continue ;
401+ }
402+
175403 HRESULT hrInit = pClient -> lpVtbl -> Initialize (pClient , AUDCLNT_SHAREMODE_SHARED ,
176- AUDCLNT_STREAMFLAGS_LOOPBACK ,
404+ AUDCLNT_STREAMFLAGS_LOOPBACK |
405+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK ,
177406 16 * REFTIMES_PER_MILLISEC , 0 , wfx , 0 );
407+
178408 if (FAILED (hrInit )) {
179409 //_com_error err(hrInit);
180410
@@ -192,7 +422,19 @@ void input_winscap(void *data) {
192422 pClient -> lpVtbl -> Release (pClient );
193423 if (pDevice )
194424 pDevice -> lpVtbl -> Release (pDevice );
195- WaitForSingleObject (hEvent , INFINITE );
425+ WaitForSingleObject (hEvent , INFINITE ); // may freeze, need to test on spacial device
426+ continue ;
427+ }
428+
429+ // use event handling instead of polling
430+ HRESULT hrEvent = pClient -> lpVtbl -> SetEventHandle (pClient , hEvent );
431+ if (FAILED (hrEvent )) {
432+ fwprintf (stderr , L"SetEventHandle failed: 0x%08lx\n" , hrEvent );
433+ // Clean up resources as needed
434+ if (pClient )
435+ pClient -> lpVtbl -> Release (pClient );
436+ if (pDevice )
437+ pDevice -> lpVtbl -> Release (pDevice );
196438 continue ;
197439 }
198440
@@ -205,25 +447,33 @@ void input_winscap(void *data) {
205447
206448 WAVEFORMATEX format = * wfx ;
207449
208- DWORD dwDelay =
209- (DWORD )(((double )REFTIMES_PER_SEC * bufferFrameCount / format .nSamplesPerSec ) /
210- REFTIMES_PER_MILLISEC / 2 );
211-
212- LPBYTE pSilence = (LPBYTE )malloc (bufferFrameCount * format .nBlockAlign );
213-
214- ZeroMemory (pSilence , bufferFrameCount * format .nBlockAlign );
215-
216450 pClient -> lpVtbl -> Start (pClient );
217451
218- audio -> channels = format .nChannels ;
219- audio -> rate = format .nSamplesPerSec ;
220- audio -> format = format .wBitsPerSample ;
221- if (format .wBitsPerSample == 32 )
222- audio -> IEEE_FLOAT = 1 ;
452+ WAVEFORMATEX stereo_format ;
453+ make_stereo_waveformatex (& format , & stereo_format );
454+
455+ if (format .nChannels > 2 ) {
456+ audio -> channels = 2 ;
457+ audio -> rate = stereo_format .nSamplesPerSec ;
458+ audio -> format = stereo_format .wBitsPerSample ;
459+ audio -> IEEE_FLOAT = 0 ;
460+ } else {
461+ audio -> channels = format .nChannels ;
462+ audio -> rate = format .nSamplesPerSec ;
463+ audio -> format = format .wBitsPerSample ;
464+ if (format .wBitsPerSample == 32 )
465+ audio -> IEEE_FLOAT = 1 ;
466+ }
467+
223468 pthread_mutex_unlock (& audio -> lock );
469+
224470 // deviceChanged
225471 while (!audio -> terminate ) {
226- Sleep (dwDelay );
472+ DWORD waitResult = WaitForSingleObject (hEvent , INFINITE );
473+ if (waitResult != WAIT_OBJECT_0 ) {
474+ // Handle error or termination
475+ continue ;
476+ }
227477
228478 UINT32 packetLength ;
229479 HRESULT hrNext = pCapture -> lpVtbl -> GetNextPacketSize (pCapture , & packetLength );
@@ -250,19 +500,25 @@ void input_winscap(void *data) {
250500
251501 pCapture -> lpVtbl -> GetBuffer (pCapture , & pData , & numFramesAvailable , & flags , 0 , 0 );
252502
253- if (flags & AUDCLNT_BUFFERFLAGS_SILENT )
254- pData = pSilence ;
503+ if (flags & AUDCLNT_BUFFERFLAGS_SILENT ) {
504+ write_silent_frame (audio , pCapture , numFramesAvailable , packetLength );
505+ continue ;
506+ }
255507
256- write_to_cava_input_buffers (numFramesAvailable * format .nChannels ,
257- (unsigned char * )pData , audio );
508+ if (format .nChannels > 2 ) {
509+ process_multichannel (numFramesAvailable , format , pData , audio , pCapture ,
510+ packetLength , stereo_format );
511+ } else {
512+ write_to_cava_input_buffers (numFramesAvailable * format .nChannels ,
513+ (unsigned char * )pData , audio );
514+ }
258515
259516 pCapture -> lpVtbl -> ReleaseBuffer (pCapture , numFramesAvailable );
260517 pCapture -> lpVtbl -> GetNextPacketSize (pCapture , & packetLength );
261518 }
262519 }
263520 deviceChanged = FALSE;
264521 pClient -> lpVtbl -> Stop (pClient );
265- free (pSilence );
266522 if (pCapture )
267523 pCapture -> lpVtbl -> Release (pCapture );
268524 if (pClient )
0 commit comments