2 * OpenAL cross platform audio library
3 * Copyright (C) 2011 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
23 #define _WIN32_IE 0x501
25 #define _WIN32_IE 0x400
42 #ifndef AL_NO_UID_DEFS
43 #if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
52 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71);
53 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
, 0x00000003, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71);
55 DEFINE_GUID(IID_IDirectSoundNotify
, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16);
57 DEFINE_GUID(CLSID_MMDeviceEnumerator
, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e);
58 DEFINE_GUID(IID_IMMDeviceEnumerator
, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6);
59 DEFINE_GUID(IID_IAudioClient
, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2);
60 DEFINE_GUID(IID_IAudioRenderClient
, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2);
61 DEFINE_GUID(IID_IAudioCaptureClient
, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17);
64 #include <devpropdef.h>
65 #include <propkeydef.h>
66 DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName
, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
67 DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor
, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0);
70 #endif /* AL_NO_UID_DEFS */
81 #ifdef HAVE_SYS_SYSCONF_H
82 #include <sys/sysconf.h>
93 #elif defined(_WIN32_IE)
102 #include "alstring.h"
107 extern inline ALuint
NextPowerOf2(ALuint value
);
108 extern inline ALint
fastf2i(ALfloat f
);
109 extern inline ALuint
fastf2u(ALfloat f
);
112 ALuint CPUCapFlags
= 0;
115 void FillCPUCaps(ALuint capfilter
)
119 /* FIXME: We really should get this for all available CPUs in case different
120 * CPUs have different caps (is that possible on one machine?). */
121 #if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \
122 defined(_M_IX86) || defined(_M_X64))
124 unsigned int regs
[4];
125 char str
[sizeof(unsigned int[4])];
128 if(!__get_cpuid(0, &cpuinf
[0].regs
[0], &cpuinf
[0].regs
[1], &cpuinf
[0].regs
[2], &cpuinf
[0].regs
[3]))
129 ERR("Failed to get CPUID\n");
132 unsigned int maxfunc
= cpuinf
[0].regs
[0];
133 unsigned int maxextfunc
= 0;
135 if(__get_cpuid(0x80000000, &cpuinf
[0].regs
[0], &cpuinf
[0].regs
[1], &cpuinf
[0].regs
[2], &cpuinf
[0].regs
[3]))
136 maxextfunc
= cpuinf
[0].regs
[0];
137 TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc
, maxextfunc
);
139 TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf
[0].str
+4, cpuinf
[0].str
+12, cpuinf
[0].str
+8);
140 if(maxextfunc
>= 0x80000004 &&
141 __get_cpuid(0x80000002, &cpuinf
[0].regs
[0], &cpuinf
[0].regs
[1], &cpuinf
[0].regs
[2], &cpuinf
[0].regs
[3]) &&
142 __get_cpuid(0x80000003, &cpuinf
[1].regs
[0], &cpuinf
[1].regs
[1], &cpuinf
[1].regs
[2], &cpuinf
[1].regs
[3]) &&
143 __get_cpuid(0x80000004, &cpuinf
[2].regs
[0], &cpuinf
[2].regs
[1], &cpuinf
[2].regs
[2], &cpuinf
[2].regs
[3]))
144 TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf
[0].str
, cpuinf
[1].str
, cpuinf
[2].str
);
147 __get_cpuid(1, &cpuinf
[0].regs
[0], &cpuinf
[0].regs
[1], &cpuinf
[0].regs
[2], &cpuinf
[0].regs
[3]))
149 if((cpuinf
[0].regs
[3]&(1<<25)))
152 if((cpuinf
[0].regs
[3]&(1<<26)))
154 caps
|= CPU_CAP_SSE2
;
155 if((cpuinf
[0].regs
[2]&(1<<0)))
157 caps
|= CPU_CAP_SSE3
;
158 if((cpuinf
[0].regs
[2]&(1<<19)))
159 caps
|= CPU_CAP_SSE4_1
;
165 #elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \
166 defined(_M_IX86) || defined(_M_X64))
169 char str
[sizeof(int[4])];
172 (__cpuid
)(cpuinf
[0].regs
, 0);
173 if(cpuinf
[0].regs
[0] == 0)
174 ERR("Failed to get CPUID\n");
177 unsigned int maxfunc
= cpuinf
[0].regs
[0];
178 unsigned int maxextfunc
;
180 (__cpuid
)(cpuinf
[0].regs
, 0x80000000);
181 maxextfunc
= cpuinf
[0].regs
[0];
183 TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc
, maxextfunc
);
185 TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf
[0].str
+4, cpuinf
[0].str
+12, cpuinf
[0].str
+8);
186 if(maxextfunc
>= 0x80000004)
188 (__cpuid
)(cpuinf
[0].regs
, 0x80000002);
189 (__cpuid
)(cpuinf
[1].regs
, 0x80000003);
190 (__cpuid
)(cpuinf
[2].regs
, 0x80000004);
191 TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf
[0].str
, cpuinf
[1].str
, cpuinf
[2].str
);
196 (__cpuid
)(cpuinf
[0].regs
, 1);
197 if((cpuinf
[0].regs
[3]&(1<<25)))
200 if((cpuinf
[0].regs
[3]&(1<<26)))
202 caps
|= CPU_CAP_SSE2
;
203 if((cpuinf
[0].regs
[2]&(1<<0)))
205 caps
|= CPU_CAP_SSE3
;
206 if((cpuinf
[0].regs
[2]&(1<<19)))
207 caps
|= CPU_CAP_SSE4_1
;
214 /* Assume support for whatever's supported if we can't check for it */
215 #if defined(HAVE_SSE4_1)
216 #warning "Assuming SSE 4.1 run-time support!"
217 caps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
| CPU_CAP_SSE4_1
;
218 #elif defined(HAVE_SSE3)
219 #warning "Assuming SSE 3 run-time support!"
220 caps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
| CPU_CAP_SSE3
;
221 #elif defined(HAVE_SSE2)
222 #warning "Assuming SSE 2 run-time support!"
223 caps
|= CPU_CAP_SSE
| CPU_CAP_SSE2
;
224 #elif defined(HAVE_SSE)
225 #warning "Assuming SSE run-time support!"
230 /* Assume Neon support if compiled with it */
231 caps
|= CPU_CAP_NEON
;
234 TRACE("Extensions:%s%s%s%s%s%s\n",
235 ((capfilter
&CPU_CAP_SSE
) ? ((caps
&CPU_CAP_SSE
) ? " +SSE" : " -SSE") : ""),
236 ((capfilter
&CPU_CAP_SSE2
) ? ((caps
&CPU_CAP_SSE2
) ? " +SSE2" : " -SSE2") : ""),
237 ((capfilter
&CPU_CAP_SSE3
) ? ((caps
&CPU_CAP_SSE3
) ? " +SSE3" : " -SSE3") : ""),
238 ((capfilter
&CPU_CAP_SSE4_1
) ? ((caps
&CPU_CAP_SSE4_1
) ? " +SSE4.1" : " -SSE4.1") : ""),
239 ((capfilter
&CPU_CAP_NEON
) ? ((caps
&CPU_CAP_NEON
) ? " +Neon" : " -Neon") : ""),
240 ((!capfilter
) ? " -none-" : "")
242 CPUCapFlags
= caps
& capfilter
;
246 void SetMixerFPUMode(FPUCtl
*ctl
)
249 fegetenv(STATIC_CAST(fenv_t
, ctl
));
250 #if defined(__GNUC__) && defined(HAVE_SSE)
251 /* FIXME: Some fegetenv implementations can get the SSE environment too?
252 * How to tell when it does? */
253 if((CPUCapFlags
&CPU_CAP_SSE
))
254 __asm__
__volatile__("stmxcsr %0" : "=m" (*&ctl
->sse_state
));
258 fesetround(FE_TOWARDZERO
);
260 #if defined(__GNUC__) && defined(HAVE_SSE)
261 if((CPUCapFlags
&CPU_CAP_SSE
))
263 int sseState
= ctl
->sse_state
;
264 sseState
|= 0x6000; /* set round-to-zero */
265 sseState
|= 0x8000; /* set flush-to-zero */
266 if((CPUCapFlags
&CPU_CAP_SSE2
))
267 sseState
|= 0x0040; /* set denormals-are-zero */
268 __asm__
__volatile__("ldmxcsr %0" : : "m" (*&sseState
));
272 #elif defined(HAVE___CONTROL87_2)
275 __control87_2(0, 0, &ctl
->state
, NULL
);
276 __control87_2(_RC_CHOP
, _MCW_RC
, &mode
, NULL
);
278 if((CPUCapFlags
&CPU_CAP_SSE
))
280 __control87_2(0, 0, NULL
, &ctl
->sse_state
);
281 __control87_2(_RC_CHOP
|_DN_FLUSH
, _MCW_RC
|_MCW_DN
, NULL
, &mode
);
285 #elif defined(HAVE__CONTROLFP)
287 ctl
->state
= _controlfp(0, 0);
288 (void)_controlfp(_RC_CHOP
, _MCW_RC
);
292 void RestoreFPUMode(const FPUCtl
*ctl
)
295 fesetenv(STATIC_CAST(fenv_t
, ctl
));
296 #if defined(__GNUC__) && defined(HAVE_SSE)
297 if((CPUCapFlags
&CPU_CAP_SSE
))
298 __asm__
__volatile__("ldmxcsr %0" : : "m" (*&ctl
->sse_state
));
301 #elif defined(HAVE___CONTROL87_2)
304 __control87_2(ctl
->state
, _MCW_RC
, &mode
, NULL
);
306 if((CPUCapFlags
&CPU_CAP_SSE
))
307 __control87_2(ctl
->sse_state
, _MCW_RC
|_MCW_DN
, NULL
, &mode
);
310 #elif defined(HAVE__CONTROLFP)
312 _controlfp(ctl
->state
, _MCW_RC
);
317 static int StringSortCompare(const void *str1
, const void *str2
)
319 return al_string_cmp(*(const_al_string
*)str1
, *(const_al_string
*)str2
);
324 static WCHAR
*FromUTF8(const char *str
)
329 if((len
=MultiByteToWideChar(CP_UTF8
, 0, str
, -1, NULL
, 0)) > 0)
331 out
= calloc(sizeof(WCHAR
), len
);
332 MultiByteToWideChar(CP_UTF8
, 0, str
, -1, out
, len
);
338 void *LoadLib(const char *name
)
343 wname
= FromUTF8(name
);
345 ERR("Failed to convert UTF-8 filename: \"%s\"\n", name
);
348 hdl
= LoadLibraryW(wname
);
353 void CloseLib(void *handle
)
354 { FreeLibrary((HANDLE
)handle
); }
355 void *GetSymbol(void *handle
, const char *name
)
359 ret
= (void*)GetProcAddress((HANDLE
)handle
, name
);
361 ERR("Failed to load %s\n", name
);
365 WCHAR
*strdupW(const WCHAR
*str
)
375 ret
= calloc(sizeof(WCHAR
), len
+1);
377 memcpy(ret
, str
, sizeof(WCHAR
)*len
);
381 FILE *al_fopen(const char *fname
, const char *mode
)
383 WCHAR
*wname
=NULL
, *wmode
=NULL
;
386 wname
= FromUTF8(fname
);
387 wmode
= FromUTF8(mode
);
389 ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname
);
391 ERR("Failed to convert UTF-8 mode: \"%s\"\n", mode
);
393 file
= _wfopen(wname
, wmode
);
402 void al_print(const char *type
, const char *func
, const char *fmt
, ...)
409 vsnprintf(str
, sizeof(str
), fmt
, ap
);
412 str
[sizeof(str
)-1] = 0;
413 wstr
= FromUTF8(str
);
415 fprintf(LogFile
, "AL lib: %s %s: <UTF-8 error> %s", type
, func
, str
);
418 fprintf(LogFile
, "AL lib: %s %s: %ls", type
, func
, wstr
);
426 static inline int is_slash(int c
)
427 { return (c
== '\\' || c
== '/'); }
429 static void DirectorySearch(const char *path
, const char *ext
, vector_al_string
*results
)
431 al_string pathstr
= AL_STRING_INIT_STATIC();
432 WIN32_FIND_DATAW fdata
;
436 al_string_copy_cstr(&pathstr
, path
);
437 al_string_append_cstr(&pathstr
, "\\*");
438 al_string_append_cstr(&pathstr
, ext
);
440 TRACE("Searching %s\n", al_string_get_cstr(pathstr
));
442 wpath
= FromUTF8(al_string_get_cstr(pathstr
));
444 hdl
= FindFirstFileW(wpath
, &fdata
);
445 if(hdl
!= INVALID_HANDLE_VALUE
)
447 size_t base
= VECTOR_SIZE(*results
);
449 al_string str
= AL_STRING_INIT_STATIC();
450 al_string_copy_cstr(&str
, path
);
451 al_string_append_char(&str
, '\\');
452 al_string_append_wcstr(&str
, fdata
.cFileName
);
453 TRACE("Got result %s\n", al_string_get_cstr(str
));
454 VECTOR_PUSH_BACK(*results
, str
);
455 } while(FindNextFileW(hdl
, &fdata
));
458 if(VECTOR_SIZE(*results
) > base
)
459 qsort(VECTOR_BEGIN(*results
)+base
, VECTOR_SIZE(*results
)-base
,
460 sizeof(VECTOR_FRONT(*results
)), StringSortCompare
);
464 al_string_deinit(&pathstr
);
467 vector_al_string
SearchDataFiles(const char *ext
, const char *subdir
)
469 static const int ids
[2] = { CSIDL_APPDATA
, CSIDL_COMMON_APPDATA
};
470 static RefCount search_lock
;
471 vector_al_string results
= VECTOR_INIT_STATIC();
474 while(ATOMIC_EXCHANGE(uint
, &search_lock
, 1) == 1)
477 /* If the path is absolute, use it directly. */
478 if(isalpha(subdir
[0]) && subdir
[1] == ':' && is_slash(subdir
[2]))
480 al_string path
= AL_STRING_INIT_STATIC();
481 al_string_copy_cstr(&path
, subdir
);
482 #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
483 VECTOR_FOR_EACH(char, path
, FIX_SLASH
);
486 DirectorySearch(al_string_get_cstr(path
), ext
, &results
);
488 al_string_deinit(&path
);
490 else if(subdir
[0] == '\\' && subdir
[1] == '\\' && subdir
[2] == '?' && subdir
[3] == '\\')
491 DirectorySearch(subdir
, ext
, &results
);
494 al_string path
= AL_STRING_INIT_STATIC();
497 /* Search the app-local directory. */
498 if((cwdbuf
=_wgetenv(L
"ALSOFT_LOCAL_PATH")) && *cwdbuf
!= '\0')
500 al_string_copy_wcstr(&path
, cwdbuf
);
501 if(is_slash(VECTOR_BACK(path
)))
503 VECTOR_POP_BACK(path
);
504 *VECTOR_END(path
) = 0;
507 else if(!(cwdbuf
=_wgetcwd(NULL
, 0)))
508 al_string_copy_cstr(&path
, ".");
511 al_string_copy_wcstr(&path
, cwdbuf
);
512 if(is_slash(VECTOR_BACK(path
)))
514 VECTOR_POP_BACK(path
);
515 *VECTOR_END(path
) = 0;
519 #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
520 VECTOR_FOR_EACH(char, path
, FIX_SLASH
);
522 DirectorySearch(al_string_get_cstr(path
), ext
, &results
);
524 /* Search the local and global data dirs. */
525 for(i
= 0;i
< COUNTOF(ids
);i
++)
527 WCHAR buffer
[PATH_MAX
];
528 if(SHGetSpecialFolderPathW(NULL
, buffer
, ids
[i
], FALSE
) != FALSE
)
530 al_string_copy_wcstr(&path
, buffer
);
531 if(!is_slash(VECTOR_BACK(path
)))
532 al_string_append_char(&path
, '\\');
533 al_string_append_cstr(&path
, subdir
);
534 #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
535 VECTOR_FOR_EACH(char, path
, FIX_SLASH
);
538 DirectorySearch(al_string_get_cstr(path
), ext
, &results
);
542 al_string_deinit(&path
);
545 ATOMIC_STORE(&search_lock
, 0);
554 void *LoadLib(const char *name
)
560 handle
= dlopen(name
, RTLD_NOW
);
561 if((err
=dlerror()) != NULL
)
565 void CloseLib(void *handle
)
567 void *GetSymbol(void *handle
, const char *name
)
573 sym
= dlsym(handle
, name
);
574 if((err
=dlerror()) != NULL
)
576 WARN("Failed to load %s: %s\n", name
, err
);
582 #endif /* HAVE_DLFCN_H */
584 void al_print(const char *type
, const char *func
, const char *fmt
, ...)
589 fprintf(LogFile
, "AL lib: %s %s: ", type
, func
);
590 vfprintf(LogFile
, fmt
, ap
);
597 static void DirectorySearch(const char *path
, const char *ext
, vector_al_string
*results
)
599 size_t extlen
= strlen(ext
);
602 TRACE("Searching %s for *%s\n", path
, ext
);
606 size_t base
= VECTOR_SIZE(*results
);
607 struct dirent
*dirent
;
608 while((dirent
=readdir(dir
)) != NULL
)
612 if(strcmp(dirent
->d_name
, ".") == 0 || strcmp(dirent
->d_name
, "..") == 0)
615 len
= strlen(dirent
->d_name
);
618 if(strcasecmp(dirent
->d_name
+len
-extlen
, ext
) != 0)
622 al_string_copy_cstr(&str
, path
);
623 if(VECTOR_BACK(str
) != '/')
624 al_string_append_char(&str
, '/');
625 al_string_append_cstr(&str
, dirent
->d_name
);
626 TRACE("Got result %s\n", al_string_get_cstr(str
));
627 VECTOR_PUSH_BACK(*results
, str
);
631 if(VECTOR_SIZE(*results
) > base
)
632 qsort(VECTOR_BEGIN(*results
)+base
, VECTOR_SIZE(*results
)-base
,
633 sizeof(VECTOR_FRONT(*results
)), StringSortCompare
);
637 vector_al_string
SearchDataFiles(const char *ext
, const char *subdir
)
639 static RefCount search_lock
;
640 vector_al_string results
= VECTOR_INIT_STATIC();
642 while(ATOMIC_EXCHANGE(uint
, &search_lock
, 1) == 1)
646 DirectorySearch(subdir
, ext
, &results
);
649 al_string path
= AL_STRING_INIT_STATIC();
650 const char *str
, *next
;
651 char cwdbuf
[PATH_MAX
];
653 /* Search the app-local directory. */
654 if((str
=getenv("ALSOFT_LOCAL_PATH")) && *str
!= '\0')
655 DirectorySearch(str
, ext
, &results
);
656 else if(getcwd(cwdbuf
, sizeof(cwdbuf
)))
657 DirectorySearch(cwdbuf
, ext
, &results
);
659 DirectorySearch(".", ext
, &results
);
661 // Search local data dir
662 if((str
=getenv("XDG_DATA_HOME")) != NULL
&& str
[0] != '\0')
664 al_string_copy_cstr(&path
, str
);
665 if(VECTOR_BACK(path
) != '/')
666 al_string_append_char(&path
, '/');
667 al_string_append_cstr(&path
, subdir
);
668 DirectorySearch(al_string_get_cstr(path
), ext
, &results
);
670 else if((str
=getenv("HOME")) != NULL
&& str
[0] != '\0')
672 al_string_copy_cstr(&path
, str
);
673 if(VECTOR_BACK(path
) == '/')
675 VECTOR_POP_BACK(path
);
676 *VECTOR_END(path
) = 0;
678 al_string_append_cstr(&path
, "/.local/share/");
679 al_string_append_cstr(&path
, subdir
);
680 DirectorySearch(al_string_get_cstr(path
), ext
, &results
);
683 // Search global data dirs
684 if((str
=getenv("XDG_DATA_DIRS")) == NULL
|| str
[0] == '\0')
685 str
= "/usr/local/share/:/usr/share/";
688 while((str
=next
) != NULL
&& str
[0] != '\0')
690 next
= strchr(str
, ':');
692 al_string_copy_cstr(&path
, str
);
695 al_string_copy_range(&path
, str
, next
);
698 if(!al_string_empty(path
))
700 if(VECTOR_BACK(path
) != '/')
701 al_string_append_char(&path
, '/');
702 al_string_append_cstr(&path
, subdir
);
704 DirectorySearch(al_string_get_cstr(path
), ext
, &results
);
708 al_string_deinit(&path
);
711 ATOMIC_STORE(&search_lock
, 0);
719 void SetRTPriority(void)
721 ALboolean failed
= AL_FALSE
;
725 failed
= !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
);
726 #elif defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__)
729 struct sched_param param
;
730 /* Use the minimum real-time priority possible for now (on Linux this
731 * should be 1 for SCHED_RR) */
732 param
.sched_priority
= sched_get_priority_min(SCHED_RR
);
733 failed
= !!pthread_setschedparam(pthread_self(), SCHED_RR
, ¶m
);
736 /* Real-time priority not available */
737 failed
= (RTPrioLevel
>0);
740 ERR("Failed to set priority level for thread\n");
744 ALboolean
vector_reserve(char *ptr
, size_t base_size
, size_t obj_size
, size_t obj_count
, ALboolean exact
)
746 vector_
*vecptr
= (vector_
*)ptr
;
747 if((*vecptr
? (*vecptr
)->Capacity
: 0) < obj_count
)
749 size_t old_size
= (*vecptr
? (*vecptr
)->Size
: 0);
752 /* Use the next power-of-2 size if we don't need to allocate the exact
753 * amount. This is preferred when regularly increasing the vector since
754 * it means fewer reallocations. Though it means it also wastes some
756 if(exact
== AL_FALSE
&& obj_count
< INT_MAX
)
757 obj_count
= NextPowerOf2((ALuint
)obj_count
);
759 /* Need to be explicit with the caller type's base size, because it
760 * could have extra padding before the start of the array (that is,
761 * sizeof(*vector_) may not equal base_size). */
762 temp
= realloc(*vecptr
, base_size
+ obj_size
*obj_count
);
763 if(temp
== NULL
) return AL_FALSE
;
766 (*vecptr
)->Capacity
= obj_count
;
767 (*vecptr
)->Size
= old_size
;
772 ALboolean
vector_resize(char *ptr
, size_t base_size
, size_t obj_size
, size_t obj_count
)
774 vector_
*vecptr
= (vector_
*)ptr
;
775 if(*vecptr
|| obj_count
> 0)
777 if(!vector_reserve((char*)vecptr
, base_size
, obj_size
, obj_count
, AL_TRUE
))
779 (*vecptr
)->Size
= obj_count
;
784 ALboolean
vector_insert(char *ptr
, size_t base_size
, size_t obj_size
, void *ins_pos
, const void *datstart
, const void *datend
)
786 vector_
*vecptr
= (vector_
*)ptr
;
787 if(datstart
!= datend
)
789 ptrdiff_t ins_elem
= (*vecptr
? ((char*)ins_pos
- ((char*)(*vecptr
) + base_size
)) :
790 ((char*)ins_pos
- (char*)NULL
)) /
792 ptrdiff_t numins
= ((const char*)datend
- (const char*)datstart
) / obj_size
;
795 if((size_t)numins
+ VECTOR_SIZE(*vecptr
) < (size_t)numins
||
796 !vector_reserve((char*)vecptr
, base_size
, obj_size
, VECTOR_SIZE(*vecptr
)+numins
, AL_TRUE
))
799 /* NOTE: ins_pos may have been invalidated if *vecptr moved. Use ins_elem instead. */
800 if((size_t)ins_elem
< (*vecptr
)->Size
)
802 memmove((char*)(*vecptr
) + base_size
+ ((ins_elem
+numins
)*obj_size
),
803 (char*)(*vecptr
) + base_size
+ ((ins_elem
)*obj_size
),
804 ((*vecptr
)->Size
-ins_elem
)*obj_size
);
806 memcpy((char*)(*vecptr
) + base_size
+ (ins_elem
*obj_size
),
807 datstart
, numins
*obj_size
);
808 (*vecptr
)->Size
+= numins
;
814 extern inline void al_string_deinit(al_string
*str
);
815 extern inline size_t al_string_length(const_al_string str
);
816 extern inline ALboolean
al_string_empty(const_al_string str
);
817 extern inline const al_string_char_type
*al_string_get_cstr(const_al_string str
);
819 void al_string_clear(al_string
*str
)
821 if(!al_string_empty(*str
))
823 /* Reserve one more character than the total size of the string. This
824 * is to ensure we have space to add a null terminator in the string
825 * data so it can be used as a C-style string.
827 VECTOR_RESERVE(*str
, 1);
828 VECTOR_RESIZE(*str
, 0);
829 *VECTOR_END(*str
) = 0;
833 static inline int al_string_compare(const al_string_char_type
*str1
, size_t str1len
,
834 const al_string_char_type
*str2
, size_t str2len
)
836 size_t complen
= (str1len
< str2len
) ? str1len
: str2len
;
837 int ret
= memcmp(str1
, str2
, complen
);
840 if(str1len
> str2len
) return 1;
841 if(str1len
< str2len
) return -1;
845 int al_string_cmp(const_al_string str1
, const_al_string str2
)
847 return al_string_compare(&VECTOR_FRONT(str1
), al_string_length(str1
),
848 &VECTOR_FRONT(str2
), al_string_length(str2
));
850 int al_string_cmp_cstr(const_al_string str1
, const al_string_char_type
*str2
)
852 return al_string_compare(&VECTOR_FRONT(str1
), al_string_length(str1
),
856 void al_string_copy(al_string
*str
, const_al_string from
)
858 size_t len
= al_string_length(from
);
859 VECTOR_RESERVE(*str
, len
+1);
860 VECTOR_RESIZE(*str
, 0);
861 VECTOR_INSERT(*str
, VECTOR_END(*str
), VECTOR_BEGIN(from
), VECTOR_BEGIN(from
)+len
);
862 *VECTOR_END(*str
) = 0;
865 void al_string_copy_cstr(al_string
*str
, const al_string_char_type
*from
)
867 size_t len
= strlen(from
);
868 VECTOR_RESERVE(*str
, len
+1);
869 VECTOR_RESIZE(*str
, 0);
870 VECTOR_INSERT(*str
, VECTOR_END(*str
), from
, from
+len
);
871 *VECTOR_END(*str
) = 0;
874 void al_string_copy_range(al_string
*str
, const al_string_char_type
*from
, const al_string_char_type
*to
)
876 size_t len
= to
- from
;
877 VECTOR_RESERVE(*str
, len
+1);
878 VECTOR_RESIZE(*str
, 0);
879 VECTOR_INSERT(*str
, VECTOR_END(*str
), from
, to
);
880 *VECTOR_END(*str
) = 0;
883 void al_string_append_char(al_string
*str
, const al_string_char_type c
)
885 VECTOR_RESERVE(*str
, al_string_length(*str
)+2);
886 VECTOR_PUSH_BACK(*str
, c
);
887 *VECTOR_END(*str
) = 0;
890 void al_string_append_cstr(al_string
*str
, const al_string_char_type
*from
)
892 size_t len
= strlen(from
);
895 VECTOR_RESERVE(*str
, al_string_length(*str
)+len
+1);
896 VECTOR_INSERT(*str
, VECTOR_END(*str
), from
, from
+len
);
897 *VECTOR_END(*str
) = 0;
901 void al_string_append_range(al_string
*str
, const al_string_char_type
*from
, const al_string_char_type
*to
)
905 VECTOR_RESERVE(*str
, al_string_length(*str
)+(to
-from
)+1);
906 VECTOR_INSERT(*str
, VECTOR_END(*str
), from
, to
);
907 *VECTOR_END(*str
) = 0;
912 void al_string_copy_wcstr(al_string
*str
, const wchar_t *from
)
915 if((len
=WideCharToMultiByte(CP_UTF8
, 0, from
, -1, NULL
, 0, NULL
, NULL
)) > 0)
917 VECTOR_RESERVE(*str
, len
);
918 VECTOR_RESIZE(*str
, len
-1);
919 WideCharToMultiByte(CP_UTF8
, 0, from
, -1, &VECTOR_FRONT(*str
), len
, NULL
, NULL
);
920 *VECTOR_END(*str
) = 0;
924 void al_string_append_wcstr(al_string
*str
, const wchar_t *from
)
927 if((len
=WideCharToMultiByte(CP_UTF8
, 0, from
, -1, NULL
, 0, NULL
, NULL
)) > 0)
929 size_t strlen
= al_string_length(*str
);
930 VECTOR_RESERVE(*str
, strlen
+len
);
931 VECTOR_RESIZE(*str
, strlen
+len
-1);
932 WideCharToMultiByte(CP_UTF8
, 0, from
, -1, &VECTOR_FRONT(*str
) + strlen
, len
, NULL
, NULL
);
933 *VECTOR_END(*str
) = 0;
937 void al_string_append_wrange(al_string
*str
, const wchar_t *from
, const wchar_t *to
)
940 if((len
=WideCharToMultiByte(CP_UTF8
, 0, from
, (int)(to
-from
), NULL
, 0, NULL
, NULL
)) > 0)
942 size_t strlen
= al_string_length(*str
);
943 VECTOR_RESERVE(*str
, strlen
+len
+1);
944 VECTOR_RESIZE(*str
, strlen
+len
);
945 WideCharToMultiByte(CP_UTF8
, 0, from
, (int)(to
-from
), &VECTOR_FRONT(*str
) + strlen
, len
+1, NULL
, NULL
);
946 *VECTOR_END(*str
) = 0;