Compare commits

...

2912 Commits

Author SHA1 Message Date
Ivan Epifanov 27239f7844 Bump cmake version 2026-01-28 19:45:50 +03:00
Ivan Epifanov 75e5b00ef7 Allow setting thread affinity/priority and bump cmake version 2026-01-28 15:46:16 +03:00
Ivan Epifanov 430467664c Update openal 2021-02-28 23:04:23 +03:00
Ivan Epifanov ef45405eed Samplerate fixes 2021-01-28 23:36:19 +03:00
Ivan Epifanov 425e5b5615 Fixes 2021-01-27 18:48:35 +03:00
Ivan Epifanov cd9f8bd49d Building 2021-01-27 18:18:42 +03:00
Ivan Epifanov d9f5668968 Master is for patchsets 2021-01-27 18:16:01 +03:00
Chris Robinson 5ff5fd8ecc Use a standard bitset for bitfield flags 2021-01-22 00:00:10 -08:00
Chris Robinson 5729e1004d Make the endian test more C++-like 2021-01-21 23:21:18 -08:00
Chris Robinson 87dbeed853 Update apt before installing dependencies 2021-01-21 09:15:18 -08:00
Chris Robinson fb6585cf18 Fix handling paused devices with the wave writer backend 2021-01-21 06:51:29 -08:00
Chris Robinson 19adb622ef Simplify a division
The division opcode typically also generates the remainder, making the result
of x%y free with x/y.
2021-01-21 06:27:11 -08:00
Chris Robinson db4de2b56a Avoid declaring some variables multiple times 2021-01-21 06:25:50 -08:00
Chris Robinson 20f5e7c1fa Avoid global constexpr arrays 2021-01-21 04:03:30 -08:00
Chris Robinson 92c653e5f0 Update ChangeLog 2021-01-20 17:47:36 -08:00
Chris Robinson 1c649943f7 Revert "Print the build results after CI"
This reverts commit e1e0809253.
2021-01-20 06:33:11 -08:00
Chris Robinson e1e0809253 Print the build results after CI 2021-01-20 04:16:06 -08:00
Chris Robinson 32e0d92c51 Avoid extra copies/work when reading HRTF data 2021-01-20 01:26:55 -08:00
Chris Robinson 13698362f1 Avoid explicitly searching for the WindowsSDK
It's causing problems with various setups. So instead we'll have to assume some
things for Windows (namely that winmm exists, and if dsound isn't in DXSDK_DIR,
it needs to be in the compiler's default paths to be usable).
2021-01-19 17:19:44 -08:00
Chris Robinson c3380d4201 Remove constexpr from a function
Various versions of GCC have a problem with it, and it doesn't really add much
benefit anyway.
2021-01-17 23:39:33 -08:00
Chris Robinson 8ebf146c72 First try at using GitHub Actions 2021-01-17 23:09:42 -08:00
Chris Robinson 229bf45e24 Avoid calling readAdvance in a loop 2021-01-17 03:17:46 -08:00
Chris Robinson 855a8c0cd9 Don't assume the ring buffer's read vector is the next writable space
This is untrue since the ring buffer leaves one element unwritten, so there's
one extra element to be written once a readable element is read.
2021-01-15 18:18:07 -08:00
Chris Robinson 8c4adfd752 Use a span instead of passing a vector by reference 2021-01-11 17:39:57 -08:00
Chris Robinson 1f01311ee3 Make sure proper names are used for querying PulseAudio info 2021-01-10 13:34:05 -08:00
kcat 3348d3ce15 Merge pull request #515 from ilya-fedin/pulse-nullptr-default
Pass nullptr to pulse for default device
2021-01-10 11:25:05 -08:00
Ilya Fedin a30d3ad803 Pass nullptr to pulse for default device 2021-01-10 16:23:08 +04:00
Chris Robinson b99adb623d Remove the invalid noexcept specification 2021-01-08 19:23:17 -08:00
Chris Robinson 89906453ea Quickly fade out samples of a stopping voice
Rather than linearly fading out the mix over the mixing update, logarithmically
fade out the post-resampled samples by approx -60dB per millisecond.
2021-01-08 18:54:46 -08:00
Chris Robinson 537fd6d0a1 Avoid dereferencing the end iterator 2021-01-08 18:51:25 -08:00
Chris Robinson 1f24f5caa1 Ensure the endian test is constexpr 2021-01-06 18:04:04 -08:00
Chris Robinson 948ae3bc7e Avoid duplicating an inline template function 2021-01-06 17:52:50 -08:00
Chris Robinson a9ac165c39 Properly trace the new HRTF delay for the B-Format decoder 2021-01-06 17:19:10 -08:00
Chris Robinson 292de73c75 Use a template to read integers with endian awareness 2021-01-06 17:10:03 -08:00
Chris Robinson 04cd0bc576 Return non-const from the resampler function 2021-01-02 17:37:09 -08:00
Chris Robinson 1f51de9983 Make optional trivially destructible if the stored type is 2021-01-02 14:24:53 -08:00
Chris Robinson d6495b35df Fix comment typo 2021-01-01 15:35:46 -08:00
Chris Robinson 1327aca9d7 Don't use templates unnecessarily 2021-01-01 15:35:14 -08:00
Chris Robinson 87a862199d Make FPUCtl methods noexcept 2020-12-31 18:23:59 -08:00
Chris Robinson 20ef8bf390 Move cpu_caps and fpu_ctrl to core 2020-12-31 16:47:12 -08:00
Chris Robinson 002c506296 Remove an unnecessary include 2020-12-31 13:15:38 -08:00
Chris Robinson f2b7a063ef Add NEON-enhanced FIR loops for convolution and UHJ 2020-12-31 13:01:17 -08:00
Chris Robinson 9d354f721c Assume run-time NEON support if detected by cmake 2020-12-31 11:42:02 -08:00
Chris Robinson 78f3d8fcd8 Check for SSE and NEON earlier 2020-12-31 11:16:44 -08:00
Chris Robinson ec7e7c9174 Avoid ugly reinterpret_casts with offsetof 2020-12-29 09:57:08 -08:00
Chris Robinson 96942d7968 Combine multiple functions into one 2020-12-28 08:37:49 -08:00
Chris Robinson aae115c35a Return an intrusive_ptr from EffectStateFactory::create 2020-12-28 08:04:23 -08:00
Chris Robinson 15e05fcef8 Workaround a GCC 5 constexpr function bug 2020-12-28 03:36:26 -08:00
Chris Robinson 7fe9d8d20c Remove extraneous semicolor 2020-12-28 02:50:15 -08:00
Chris Robinson 62fa6a2277 Avoid including voice.h in alcontext.h 2020-12-27 16:14:11 -08:00
Chris Robinson ffa7d1b1a7 Reduce a few lines 2020-12-27 14:37:43 -08:00
Chris Robinson 43d053cb32 Reorder some device fields 2020-12-27 12:23:35 -08:00
Chris Robinson 04358890d9 Use a unique_ptr to hold DistanceComp data 2020-12-27 11:30:45 -08:00
Chris Robinson adb5467720 Use smaller types for enums 2020-12-27 10:28:59 -08:00
Chris Robinson 4c0f77c13e Remove some unnecessary constructors 2020-12-27 06:43:59 -08:00
Chris Robinson 7833cfa8de Make FlexArray trivially destructible when possible 2020-12-27 04:29:54 -08:00
Chris Robinson cf7f201c92 Reorder some context properties 2020-12-27 03:11:01 -08:00
Chris Robinson cd2ebb9c3a Use a uint for a bitfield 2020-12-27 01:05:16 -08:00
Chris Robinson e20143fcc4 Move the WetBuffer reference to EffectSlot 2020-12-27 00:14:58 -08:00
Chris Robinson 507cbfa027 Combine EffectState::deviceUpdate with setBuffer 2020-12-26 12:33:00 -08:00
Chris Robinson 54719de132 Avoid AL enums for the EffectSlot type 2020-12-26 09:21:30 -08:00
Chris Robinson 8850a3f730 Combine variable terms separate from the scaling weights 2020-12-26 06:27:49 -08:00
Chris Robinson 8a86ec8ac5 Add a crossover frequency field for the device
Used when upsampling low-order ambisonic signals to higher order. Rather than a
hardcoded 400hz, it ensures a consistent crossover point when an ambdec
configuration is used. It can also allow for an alsoft config option.
2020-12-26 05:23:08 -08:00
Chris Robinson 5f233a2c24 Use more constexpr variables instead of macros 2020-12-25 20:52:18 -08:00
Chris Robinson 223f93e13d Increase direct HRTF delay to 256
This should improve the error from the all-pass on the partial input.
2020-12-25 13:02:22 -08:00
Chris Robinson f6e29ce5bb Return an optional for an error 2020-12-25 09:26:24 -08:00
Chris Robinson 78f73a4277 Avoid dynamic vectors in AmbDecConf
Also add a bit more sanity checking
2020-12-25 08:31:02 -08:00
Chris Robinson eaf209d2f1 Update a comment and type used in the convolution effect 2020-12-25 07:00:57 -08:00
Chris Robinson 204f7d8811 Rename From2D to FromACN2D 2020-12-25 06:40:13 -08:00
Chris Robinson 20820fd01b Move the ambdec loader to core 2020-12-25 06:30:47 -08:00
Chris Robinson fe9ec157fd Use an import target for linking OpenSL 2020-12-24 22:49:55 -08:00
Chris Robinson 4bc686d89b Remove unnecessary includes 2020-12-24 22:49:55 -08:00
Chris Robinson 0d3b041aa2 Avoid AL types and enums in the effect processors 2020-12-24 22:49:55 -08:00
Chris Robinson eedc42890f Move alexcpt to core 2020-12-24 22:49:55 -08:00
Chris Robinson 63ea62bea1 Avoid some more AL types 2020-12-24 22:49:55 -08:00
David CARLIER 8c4c14ea73 fast_roundf implementations in asm for ARM64. (#511) 2020-12-24 22:48:57 -08:00
Chris Robinson 6ae0115bf7 Avoid AL/ALC types in the backends 2020-12-17 23:21:45 -08:00
Chris Robinson 5edd5a11fc Don't use ALC error enums for the backend error code 2020-12-17 21:07:53 -08:00
Chris Robinson 7d2e21334c Move the AL error enum out of base_exception 2020-12-17 16:46:21 -08:00
Chris Robinson 4d1ac95ae2 Don't return an enum from captureSamples
It's always no_error
2020-12-17 03:06:52 -08:00
Chris Robinson d578bc6cb1 Move logging to core 2020-12-17 02:47:03 -08:00
Chris Robinson f0fe57dc5a Don't link DistanceModel enums to AL values 2020-12-16 14:58:55 -08:00
Chris Robinson efc9c146c3 Move AsyncEvent to a separate header 2020-12-16 13:58:51 -08:00
Chris Robinson 9710a859fa Add missing include 2020-12-16 03:02:49 -08:00
Chris Robinson 41594a07bc Update changelog 2020-12-16 02:17:18 -08:00
Chris Robinson 02be0149f1 Send stop events when stopping paused voices 2020-12-16 02:12:18 -08:00
Chris Robinson c96b50fb65 Use a separate enum for the VoiceChange state 2020-12-16 01:40:15 -08:00
Chris Robinson 5ad28f8cba Move VoiceChange to a separate header 2020-12-16 00:50:50 -08:00
Chris Robinson f38919eecc Avoid using a hidden unnamed template parameter 2020-12-15 23:47:47 -08:00
Chris Robinson 5b51a58ff2 Fix some includes 2020-12-15 23:39:17 -08:00
Chris Robinson 304ab8d890 Avoid a generic event struct 2020-12-15 21:32:01 -08:00
Chris Robinson a08f68f213 Avoid some AL types 2020-12-15 20:48:21 -08:00
Chris Robinson daf9d46478 Use a separate structure for the context/listener params 2020-12-15 18:41:50 -08:00
Chris Robinson 03358a0d80 Avoid changing the global CPU flags in FillCPUCaps 2020-12-15 12:33:57 -08:00
Chris Robinson 9435641c0d Remove unneeded includes 2020-12-15 01:31:09 -08:00
Chris Robinson 56af137ba0 Move fmt_traits to core 2020-12-13 21:12:03 -08:00
Chris Robinson 783904e414 Avoid compiling different sources for different targets
Simplifies configuration and fixes a potential problem with inline functions.
Inline functions that fail to inline will have a callable body generated. If
such a body is generated with the SSE4 source, for example, it can generate
SSE4 instructions. Calls for that function in other sources can then end up
calling the SSE4-generated body outside of any CPU capability check.
2020-12-13 16:49:46 -08:00
Chris Robinson 225d42538d Be more consistent with size_t 2020-12-12 23:41:38 -08:00
Chris Robinson bb597546e1 Make sure to stop ALSA playback when the backend stops 2020-12-12 15:10:25 -08:00
Chris Robinson e179bf0a12 Move the mixer functions to core 2020-12-12 14:58:09 -08:00
Chris Robinson 14df534114 Use a separate list for core objects 2020-12-12 14:45:41 -08:00
Chris Robinson f57801102a Remove an unnecessary include and forward declaration 2020-12-12 14:21:45 -08:00
Chris Robinson 1ad944555c Move some HRTF definitions to a separate header 2020-12-12 14:15:17 -08:00
Chris Robinson 176bc8a835 Avoid passing DirectHrtfState to MixDirectHrtf 2020-12-12 13:52:14 -08:00
Chris Robinson 191fe888b4 Move ambidefs.h to core 2020-12-12 10:38:24 -08:00
Chris Robinson 1bb7f575f0 Don't modify the IR size of loaded HRTFs 2020-12-11 15:08:50 -08:00
Chris Robinson bd08b9a5b5 Use constexpr variables instead of macros 2020-12-06 08:49:20 -08:00
Chris Robinson 4ee95dc296 Use a smaller FFT for convolution 2020-12-05 14:18:19 -08:00
Chris Robinson 2fc10a2bc0 Avoid returning an array for initialization 2020-12-05 07:27:54 -08:00
Chris Robinson 1679ab937e Reorder definitions to keep them near each other 2020-12-05 06:40:06 -08:00
Chris Robinson 16c7d1816d Remove some unnecessary inlines and includes 2020-12-05 06:30:13 -08:00
Chris Robinson 7485e402c1 Avoid a REQUIRES macro for SFINAE 2020-12-05 05:57:18 -08:00
Chris Robinson 8a352d25f9 Move the ringbuffer to common 2020-12-05 03:28:19 -08:00
Chris Robinson 2b919eac78 Use an alias for the DevFmtType type 2020-12-05 02:44:19 -08:00
Chris Robinson 16ec07275f Remove an unneeded include 2020-12-04 14:45:55 -08:00
Chris Robinson 50e33ce8f4 Change some macros into constexpr variables 2020-12-04 13:53:56 -08:00
Chris Robinson c4132b80ed Move a couple more things to core 2020-12-04 13:13:52 -08:00
Chris Robinson 3a3094c887 Fix some tabs and missing cast 2020-12-04 11:19:59 -08:00
Chris Robinson 69d55d7e03 Move the filters to core 2020-12-04 11:15:50 -08:00
Chris Robinson 84d47f7d4c Move the bsinc tables to core 2020-12-04 11:15:50 -08:00
Chris Robinson 36c1589c11 Move mastering.cpp/h to core 2020-12-04 11:15:50 -08:00
Chris Robinson aa05feec4a Avoid a global MAX_PITCH macro 2020-12-04 11:15:50 -08:00
Chris Robinson b1c2671e9d Move the resampler declarations to a more appropriate header 2020-12-04 11:15:50 -08:00
Chris Robinson 75f469fa71 Remove some unnecessary includes 2020-12-04 11:15:50 -08:00
Chris Robinson 630a3b8cbd Move lerp/cubic to alnumeric.h 2020-12-04 11:15:50 -08:00
Eliot Miranda e3179aa058 Add a gain argument to altonegen (#502)
* Fix a speeling rorre in an error message.
Add a gain command-line argument to altonegen.c

* Fix some formatting issues and a copy/paste error.
2020-12-04 11:15:27 -08:00
Chris Robinson 8750810f5c Change a couple macros into constexpr variables 2020-11-28 03:38:20 -08:00
Chris Robinson eb9b9fb4e5 Avoid AL types in mastering.cpp/h 2020-11-28 02:06:56 -08:00
Chris Robinson dbfdd35545 Move some declarations to more appropriate headers 2020-11-27 22:27:45 -08:00
Chris Robinson 7e798df7b8 Avoid AL types in the converter 2020-11-27 21:40:02 -08:00
Chris Robinson b0919240ab Move some sources to a separate directory
To begin separating the ALC interfaces from internal ones.
2020-11-27 19:18:17 -08:00
Chris Robinson d86046d522 Update ChangeLog 2020-11-25 16:31:52 -08:00
Chris Robinson 32b9a46b39 Move AL EffectProp handling to separate sources 2020-11-25 13:55:29 -08:00
Chris Robinson 3970252da9 Don't limit the available converted sample count to BUFFERSIZE 2020-11-25 04:20:16 -08:00
Chris Robinson 28278a9c15 Fix a UInt32 variable type 2020-11-24 16:43:38 -08:00
Chris Robinson f16692ecf8 Fill all buffers for CoreAudio playback 2020-11-24 14:47:04 -08:00
Chris Robinson ba39c622ef Disable buffer allocation with CoreAudio capture 2020-11-24 14:44:13 -08:00
Chris Robinson a913aa6ba8 Make sure batched source updates are with the proper voice 2020-11-24 10:49:53 -08:00
Chris Robinson 7632dfb51a Use a type alias instead of decltype 2020-11-23 12:20:33 -08:00
Chris Robinson d08d6b18c4 Ceil the scaled buffer size instead of round
The result has to be large enough to get the original requested size from it.
2020-11-23 10:55:13 -08:00
Chris Robinson d062c16629 Fix buffer offset for the second conversion 2020-11-23 10:43:20 -08:00
Chris Robinson 31c7eb5c55 Fix capture buffer size scaling in CoreAudio 2020-11-23 10:40:20 -08:00
Chris Robinson 5d82058da7 Use kAudioUnitScope_Global to get the maximum frame size 2020-11-23 10:11:28 -08:00
Chris Robinson 534c487f14 Avoid AL types in hrtf.cpp/h 2020-11-22 17:27:22 -08:00
Chris Robinson 822224312d Use optionals for some attribute parameters 2020-11-22 04:31:02 -08:00
Chris Robinson 21174047df Make ALbuffer inherit from BufferStorage 2020-11-21 00:54:25 -08:00
Chris Robinson 54afcbe113 Use clearer variable names 2020-11-20 22:02:20 -08:00
Chris Robinson 2cb2ffef72 Disassociate internal buffer enums from AL enum values 2020-11-20 04:27:10 -08:00
Chris Robinson c3cb09aa0c Avoid AL types in the mixer 2020-11-20 03:59:14 -08:00
Chris Robinson f85e76285f Disassociate internal voice enums from AL enums 2020-11-20 01:37:19 -08:00
Chris Robinson bee9917598 Disassociate internal format enums from ALC enums 2020-11-20 00:55:51 -08:00
Chris Robinson 0024ea229b Don't try to override the CoreAudio maximum capture slice 2020-11-19 17:49:25 -08:00
Chris Robinson 03f9700071 Use BufferStorage for the buffer queue 2020-11-19 04:18:25 -08:00
Chris Robinson 537510afc8 Put the loop start/end in BufferStorage 2020-11-19 03:23:46 -08:00
Chris Robinson ee9f0fe306 Recognize ARM64 as a VS platform 2020-11-18 04:20:10 -08:00
Chris Robinson 645d354ffa Add a close method to the win32 ifstream 2020-11-16 14:51:50 -08:00
Chris Robinson 88cb398a83 Avoid direct initialization of float32x4_t 2020-11-16 13:42:20 -08:00
Chris Robinson 1869dc14d4 Use WinAPI functions to check for NEON support 2020-11-16 12:42:33 -08:00
Chris Robinson a494a89c5a Add some missing custom device config descriptions 2020-11-15 15:54:09 -08:00
Chris Robinson e64c52ce8c Use doubles to calculate the listener matrix translation
To help stablize sources near the listener, when away from origin. Also clean
up some related methods and move them to more appropriate places.
2020-11-13 23:33:40 -08:00
Chris Robinson 417d8da6f4 Avoid a deprecated function 2020-11-13 21:47:48 -08:00
Chris Robinson 1a05dda8db Avoid testing a bool against AL_FALSE 2020-11-12 12:46:15 -08:00
Chris Robinson 7e76770278 Avoid an unnecessary multiplier 2020-11-09 12:33:07 -08:00
Chris Robinson 3a58bac7bd Fix pitch shifter bin count 2020-11-09 08:10:43 -08:00
Chris Robinson 54e4346f50 Simplify some pitch shifter scaling calculations 2020-11-08 07:59:14 -08:00
Chris Robinson db6d6d68b4 Avoid bitshifts for loop counting 2020-11-08 07:46:10 -08:00
Chris Robinson 0498ca200d Use an array of auxslot pointers instead of IDs to lookup 2020-11-07 12:58:19 -08:00
Chris Robinson 4e760bbecc Use a separate structure for the active effect slot properties 2020-11-07 08:36:49 -08:00
Chris Robinson 120776bec5 Use a range-for loop instead of for_each 2020-11-06 15:44:49 -08:00
Chris Robinson 26b03f534c Use more efficient sorting for effect slots 2020-11-05 15:35:09 -08:00
Chris Robinson aeb7170a8b Add missing include for the CoreAudio backend 2020-11-05 05:42:02 -08:00
Chris Robinson 4e50ce9d30 Avoid declaring standard types 2020-11-05 04:57:50 -08:00
Chris Robinson 40c92c4643 Simplify the [u]int64_t typedef header check
And include the correct header
2020-11-05 04:41:17 -08:00
Chris Robinson c0cbe602ce Release 1.21.0 2020-11-04 02:00:35 -08:00
Chris Robinson ce52ecaa87 Update changelog 2020-11-02 18:06:10 -08:00
Chris Robinson 03389f390c Avoid a full wipe and reallocation of wet buffers 2020-11-02 05:19:17 -08:00
Chris Robinson 52d58a4023 Store the wet buffers in the context
This is rather ugly, but we need the wet buffers to remain allocated after its
effect slot is deleted, because a voice can still use it for its final fade-out
mix.
2020-11-02 04:24:36 -08:00
Chris Robinson 6e05adf955 Fix a typo in the changelog 2020-10-27 00:26:16 -07:00
Chris Robinson 267d9caac4 Check for the right extension string in alffplay 2020-10-26 12:21:42 -07:00
Chris Robinson dfb6d70902 Update Changelog 2020-10-26 11:18:08 -07:00
Chris Robinson be0798b56d Finalize AL_SOFT_events 2020-10-26 10:57:48 -07:00
Chris Robinson 9e7c816498 Fix copy-paste error 2020-10-26 10:47:31 -07:00
Chris Robinson 36ecea458a Clear /W3 on MSVC since we use /W4 2020-10-25 14:53:44 -07:00
Chris Robinson 0311f6431c Add a comment about building for static linking 2020-10-25 00:08:54 -07:00
Chris Robinson 88b9eb1560 Silence a couple more MSVC warnings 2020-10-23 21:03:13 -07:00
Chris Robinson 6de861a75c Remove a constexpr that needs C++17 2020-10-23 20:00:09 -07:00
Chris Robinson 966c4498d4 Don't use a template parameter as a variable
And try to silence an MSVC warning about a constant overflow.
2020-10-23 19:53:07 -07:00
Chris Robinson 556321f18d Some cleanup in alspan.h 2020-10-23 19:03:37 -07:00
Chris Robinson 7cb1cc8ab5 Add some constexpr 2020-10-23 18:40:54 -07:00
Chris Robinson 7bb37deb51 Replace the mixer fraction macros with constexpr variables 2020-10-21 17:16:27 -07:00
Chris Robinson 3e62600ecc Replace some more macros with constexpr variables 2020-10-21 16:39:21 -07:00
Chris Robinson b8f5e1f424 Change some more macros into constexpr variables 2020-10-21 10:39:00 -07:00
Chris Robinson a3ea46f773 Add some missing constexpr attributes 2020-10-20 11:40:27 -07:00
kcat 1acfd11635 Merge pull request #483 from jhasse/silence-nodiscard
Silence warning about unused return values
2020-10-20 11:31:32 -07:00
Jan Niklas Hasse bd9d5d7bf0 Silence warning about unused return values
warning C4834: discarding return value of function with 'nodiscard'
attribute
2020-10-20 18:33:53 +02:00
Chris Robinson 95ea5951b1 Try again to work around a GCC 5 issue 2020-10-19 08:29:50 -07:00
Chris Robinson a3903b84f9 Revert "Workaround a GCC 5 issue"
This reverts commit ada92b058a.

It didn't fix the problem.
2020-10-19 08:24:19 -07:00
Chris Robinson ada92b058a Workaround a GCC 5 issue 2020-10-19 08:01:38 -07:00
Chris Robinson cdc15a4783 Use constexpr variables in place of some macros 2020-10-19 07:55:25 -07:00
Chris Robinson d6686bceb0 Avoid an extra function to generate BSincHeaders 2020-10-18 16:49:36 -07:00
Chris Robinson 20cc3882b4 Do in-place initialization for the bsinc filters
Requires less dynamic allocations and less troublesome return values of large
arrays. Also reduces repetition with specified parameters.
2020-10-18 05:34:27 -07:00
Chris Robinson 24c7ddbac2 Update Changelog 2020-10-18 05:32:48 -07:00
Chris Robinson 3728f74e10 Utilize C++11's [u]int64_t in alext.h 2020-10-16 11:13:20 -07:00
Chris Robinson f8af992b2b Quick update to ALC_BFORMAT3D_SOFT's value 2020-10-16 07:49:59 -07:00
Chris Robinson 17e88bdef3 Add a missing enum to the enum list 2020-10-16 06:39:42 -07:00
Chris Robinson 8e09ae8ee6 Finalize AL_SOFT_effect_target 2020-10-16 06:36:43 -07:00
Chris Robinson 2beb095eb1 Finalize ALC_SOFT_loopback_bformat 2020-10-16 06:35:23 -07:00
Chris Robinson 5f8fe0e5bb Enable standard stdio methods with MinGW
This unfortunately doesn't fix the %z warnings for whatever reason, but it
should help guarantee correct function behavior by not relying on msvcrt's
stdio functions.
2020-10-13 05:59:35 -07:00
Chris Robinson 7b43cb8266 Declare variables closer to where they're used 2020-10-13 05:54:05 -07:00
Chris Robinson b0e025946e Don't check for the app path if one was already retrieved 2020-10-13 01:57:53 -07:00
Chris Robinson 303ca3af72 Use inline functions for popcnt and ctz instead of macros 2020-10-13 01:21:44 -07:00
Chris Robinson 45ff10fb4d Use a span instead of a pointer and count parameters 2020-10-12 23:58:54 -07:00
Chris Robinson 0dc9ae0998 Update event enum values
To keep them less spread out from other OpenAL Soft extensions.
2020-10-07 20:13:52 -07:00
Chris Robinson af9c990277 Print the number of used measurements in sofa-info 2020-10-07 01:04:42 -07:00
Chris Robinson 5fbd02e60e Update ChangeLog 2020-10-06 00:38:37 -07:00
Chris Robinson 7fb6d64ca8 Be more robust with to-mono channel conversions 2020-10-05 22:30:23 -07:00
Chris Robinson e7a44d3b70 Cast the ringbuffer size to the correct type 2020-10-05 00:43:06 -07:00
Chris Robinson 7361e108a3 Fix a variable name 2020-10-05 00:17:13 -07:00
Chris Robinson e0097c18b8 Simplify some DSound capture math 2020-10-03 16:17:34 -07:00
Chris Robinson b5eccf424b Remove the unused Ref logging level 2020-09-28 16:14:20 -07:00
Chris Robinson f02bc1354d Rework logging a little
Use OutputDebugStringW on Windows in addition to the log file

Avoid duplicate formatter parsing with Android
2020-09-28 11:34:24 -07:00
Chris Robinson da29489ead Use an enum class for the log level 2020-09-28 00:40:30 -07:00
Chris Robinson 39f4ea61c5 Add missing linear resampler to the option setting list 2020-09-24 14:21:57 -07:00
Chris Robinson cef82153b6 Use a smaller buffer for the phase-shift filter 2020-09-24 13:26:01 -07:00
Chris Robinson 04fd50bcdf Support B-Format sounds in the examples 2020-09-22 11:36:43 -07:00
Chris Robinson d2970443dd Recognize B-Format format names in the examples 2020-09-22 10:43:27 -07:00
Chris Robinson c993ade9bf Support B-Format amb file IRs in alconvolve
Be aware this requires proper header data (a WAVE_FORMAT_EXTENSIBLE format with
the proper integer or float B-Format sub-format GUID). A normal 4-channel wave
file will not be recognized, since it's indistinguishable from quadrophonic.
2020-09-22 10:18:43 -07:00
Chris Robinson 844e6c881b Add an alconvolve option to silence the dry signal 2020-09-22 08:30:04 -07:00
Chris Robinson d912b92a60 Support all buffer layouts for convolution 2020-09-22 08:09:42 -07:00
Chris Robinson 191150d9a8 Remove deprecated, performance, and error event types
These would be better served with a proper debug API, rather than a general
audio event API.
2020-09-20 04:11:52 -07:00
Chris Robinson 8ef242bce0 Don't use direct channels with convolution
It may come back as an effect property, but it's probably better to not try
forcing it by default.
2020-09-18 10:12:58 -07:00
Chris Robinson 07989a34dc Allow higher-order B-Format buffers for convolution
Only the first-order channels will be used, but higher-order buffers will be
allowed.
2020-09-18 00:06:10 -07:00
Chris Robinson e7d8e7eb3f Avoid extraneous buffers and buffer clears 2020-09-17 21:34:26 -07:00
Chris Robinson d86d882d8b Fix an invalid unicode character in a comment 2020-09-14 02:52:16 -07:00
Chris Robinson 0974b6b47c Use inline wrappers to clarify forward/inverse FFTs 2020-09-13 04:18:40 -07:00
Chris Robinson 9a883f5046 Partly simplify FFT bit-reversal
This can almost certainly be improved further, as less than half of the indices
really need their reversed bit-pattern calculated and elements swapped (any
symetrical bit pattern would just swap with itself, and indices whose reversed
bit-pattern has already been traversed is already swapped).

It may also prove beneficial to provide the base-2 log of the fft buffer size
(number of bits to represent the indices), as that could help make the reversal
more efficient with a known bit/loop count.
2020-09-13 03:33:52 -07:00
Chris Robinson 1d4b355622 Use standard sin and sqrt 2020-09-12 19:06:06 -07:00
Chris Robinson bb90bfd9b3 Accumulate delays as samples before calculating nanoseconds 2020-09-12 01:52:45 -07:00
Chris Robinson cf298075b5 Round (and clamp) the reftime instead of ceiling it 2020-09-12 00:47:04 -07:00
Chris Robinson 33d91ceeec Avoid repeating string literals 2020-09-11 01:40:36 -07:00
Chris Robinson a4bfba4cb5 Recognize GUID name strings with the DSound backend 2020-09-10 22:05:25 -07:00
Chris Robinson 21162cf5fc Allow JACK to enumerate custom devices
Each device being associated with a port name pattern it'll try connecting to.
2020-09-10 21:09:06 -07:00
Chris Robinson bb63d5aab3 Simplify clearing an array 2020-09-09 23:21:46 -07:00
Chris Robinson ce0a45cbc7 Don't assume iterators are pointers 2020-09-09 14:02:02 -07:00
Chris Robinson 68a099ba35 Apply the first convolution segment in the time domain
This avoids an inherent delay from the effect, at the cost of higher CPU use.
Having a customizable user-specified delay (with said user ensuring a properly
trimmed impulse response) could help alleviate the cost since once the delay
exceeds the segment size, the initial FIR filter could be skipped.
2020-09-09 02:23:38 -07:00
Chris Robinson f4a55cc8c2 Don't leave the negative frequencies as 0 for inverse FFT 2020-09-08 23:20:06 -07:00
Chris Robinson 29566b995c Avoid an extraneous ConvolutionFilter sub-object 2020-09-06 00:16:50 -07:00
Chris Robinson 7eb5dfb3f8 Allow querying the new enums and functions 2020-09-05 23:53:53 -07:00
Chris Robinson f5163ca988 Print the name and format for alconvole's impulse response 2020-09-05 23:48:19 -07:00
Chris Robinson 800e2b6125 Cleanup and fix alAuxiliaryEffectSlotPlayv/StopvSOFT 2020-09-05 21:39:31 -07:00
Chris Robinson 13710b474e Ensure effect slot properties are updated when playing 2020-09-05 21:04:41 -07:00
Chris Robinson c52bf8c401 Rework effect slot buffer setting
Rather than creating an effect-specific buffer that gets passed along as a
property, the buffer is set the effect state when the effect state is created,
the device is updated, or the buffer is changed. The buffer can only be set
while the effect slot isn't playing, so it won't be changed or updated while
the mixer is processing the effect state.
2020-09-05 20:48:56 -07:00
Chris Robinson 9975aeb37f Add methods to start and stop effect slot processing
A newly-created effect slot is in an AL_INITIAL state, in which processing is
stopped but will automatically become AL_PLAYING after successfully setting an
AL_EFFECTSLOT_EFFECT value (including AL_EFFECT_NULL or 0). Calling Play[v] or
Stop[v] will set the effect slot to AL_PLAYING or AL_STOPPED respectively.
While stopped, the effect won't produce audio and will not be processed.
2020-09-05 19:11:57 -07:00
Chris Robinson 7851f7d4ce Don't add effect slots to the active list until an effect is set 2020-09-05 18:13:08 -07:00
Chris Robinson c1ad5d6055 Avoid confusing */*...*/ syntax
MSVC warns about */ being outside of a comment.
2020-09-05 14:28:08 -07:00
Chris Robinson 7e3fed42ed Use a recursive_mutex for the router enumeration lock 2020-09-05 12:41:28 -07:00
Chris Robinson 73f5331305 Use an RAII wrapper to manage COM object references 2020-09-05 12:32:41 -07:00
Chris Robinson 88f7617807 Avoid duplicate WASAPI devices by matching GUIDs 2020-09-04 18:32:06 -07:00
Chris Robinson afdd1c67ad Update changelog 2020-09-03 13:25:51 -07:00
Chris Robinson 9e862900fe Update some UHJ comments 2020-09-02 15:50:11 -07:00
Chris Robinson fe329c2af2 Avoid class templates for the POPCNT64/CTZ64 macros 2020-09-01 15:55:48 -07:00
Chris Robinson 1968136c98 Add an in-progress extension string for convolution reverb 2020-09-01 07:37:07 -07:00
Chris Robinson eeba1a385c Don't use config.h to define RESTRICT 2020-09-01 06:22:50 -07:00
Chris Robinson a6aefeccd8 Use enum class for a couple enums 2020-09-01 05:46:19 -07:00
Chris Robinson 02e51c0525 Avoid using a deprecated function 2020-08-31 17:48:26 -07:00
Chris Robinson af97a92952 Move more processing to the ConvolutionFilter struct 2020-08-31 06:43:42 -07:00
Chris Robinson 88425becb2 Remove a couple unnecessary pointers 2020-08-30 04:41:19 -07:00
Chris Robinson 82873486b7 Dynamically allocate the convolution channel mixing data 2020-08-30 04:28:01 -07:00
Chris Robinson ebe0765ce3 Reorganize some convolution fields 2020-08-30 03:42:44 -07:00
Chris Robinson 8724c1ce4b Remove extraneous parenthesis 2020-08-28 23:28:20 -07:00
Chris Robinson 3fdee6c814 Calculate the correct number of convolution segments 2020-08-28 23:08:44 -07:00
Chris Robinson ecfb0d4f5b Limit convolution processing to the output ambisonic order 2020-08-28 06:47:21 -07:00
Chris Robinson 7266cd8b6c Don't dereference a null convolution filter 2020-08-28 06:44:05 -07:00
Chris Robinson 52531d8b72 Support B-Format impulse responses for convolution 2020-08-28 05:48:26 -07:00
Chris Robinson 986a58d5b4 Pass a BufferStorage to EffectState::createBuffer 2020-08-28 00:44:55 -07:00
Chris Robinson 1f486f820e Use a separate structure for buffer storage 2020-08-28 00:09:46 -07:00
Chris Robinson ecf30de36f Rename buffer_formats to buffer_storage 2020-08-27 23:02:17 -07:00
Chris Robinson a9ebcdcb7f Handle 0-length convolution buffers 2020-08-27 21:32:25 -07:00
Chris Robinson 0ad7bb577a Don't allow callback buffers for effect slots 2020-08-27 21:10:00 -07:00
Chris Robinson 3c09f17421 Blend panned B-Format source directivity given its radius 2020-08-27 08:44:29 -07:00
Chris Robinson 2a01940041 De-duplicate LoadSampleArray and FmtTypeTraits 2020-08-26 21:29:16 -07:00
Chris Robinson 97ecf5810f Base the convolution example on the simpler stream example 2020-08-26 17:23:50 -07:00
Chris Robinson 577a8234f2 Recognize float32 format names for the example healpers 2020-08-26 17:15:30 -07:00
Chris Robinson 9dab2db33b Avoid copying the convolution filter history to shift it
Instead, the current/head/newest segment is tracked, and decremented with each
process to overwrite the oldest.
2020-08-25 15:43:48 -07:00
Chris Robinson 309be1c6f6 Add an example using convolution reverb 2020-08-25 04:59:04 -07:00
Chris Robinson 801c7a9226 Initial implementation of the convolution effect
Currently limited to mono and stereo impulse responses, and stereo IRs try to
use direct/real output rather than panning.
2020-08-25 04:21:10 -07:00
Chris Robinson e98a058595 Fix handling doubles 2020-08-25 02:38:44 -07:00
Chris Robinson a6bd53c4e1 Store a reference to the effect buffer as an active property 2020-08-24 20:40:24 -07:00
Chris Robinson 1a9fbc1b2f Stub out a convolution effect state 2020-08-24 20:04:16 -07:00
Chris Robinson b955479e18 Recognize a convolution reverb effect type 2020-08-24 20:00:58 -07:00
Chris Robinson 9e5a388dfe Add a method for effects to create persistent buffer data 2020-08-24 19:13:46 -07:00
Chris Robinson 9d61484e4b Move storable buffer format info to a separate source 2020-08-24 17:59:07 -07:00
Chris Robinson 73ab9d46c8 Use an intrusive_ptr to hold the unapplied effect state 2020-08-24 16:34:53 -07:00
Chris Robinson f9d6aa2f48 Allow setting a buffer on an effect slot 2020-08-24 16:08:09 -07:00
Chris Robinson 54a0972bfe Clean up some comments 2020-08-24 14:26:47 -07:00
Chris Robinson ff5c9d1c15 Use an intrusive_ptr for ALeffectslotProps::State 2020-08-24 14:09:26 -07:00
Chris Robinson 01f76f2b67 Allow intrusive_ptr::reset to take a new pointer 2020-08-24 14:09:26 -07:00
HALX99 de060ce09a macOS osx/ios dynamic framework support (#466)
* OSX bundle support

* Disable framework by default, and fix domain name typo

* Remove info.plist, add efx.h for framework public header

* Fix osx/ios framework PUBLIC_HEADER doesn't work

* Refine comment message

* Auto set CFBundleShortVersionString by var LIB_VERSION

* Set CFBundleVersion from git commit count

* Use space to separate elements in a list

* Specific framework name to variable 'IMPL_TARGET'

* Solve cmake try_compile failed with code sign, and disable framework code sign

* Make ios travis to build dynamic framework bundle by default

* Update ios.toolchain.cmake

Since we solve code sign issue for cmake to generate dynamic framework xcode project, enable strict try_compile by default

* Remove MAKE_CXX_EXTENSIONS from travis-ci

* Combined flat lib armv7;arm64 support

* Remvoe ios.toolchain.cmake since we don't need
[skip appveyor] [skip travis]

* Sets framework name to soft_oal,
avoid ambiguous with system OpenAL.framework

* Fix missing BUNDLE, FRAMEWORK's DESTINATION
Build osx/ios dynamic framework required them.

* Use @rpath instead fullPath to mac local disk
see also:
https://github.com/libjpeg-turbo/libjpeg-turbo/commit/c80ddef7a4ce21ace9e3ca0fd190d320cc8cdaeb

* CMake, use TRUE for bool value

* Don't disable examples, utils, install

* Make ALSOFT_OSX_FRAMEWORK for APPLE spec

* Remove unused flag and more clearly comment

* More clearly comment for solve armv7 target issue

Co-authored-by: deal <deal@dealdeMac.local>
Co-authored-by: bel <bel@beldeMac.local>
2020-08-24 14:09:02 -07:00
Chris Robinson 4eba5c34e9 Use CMAKE_DLLTOOL instead of looking for dlltool manually 2020-08-20 16:46:51 -07:00
Chris Robinson 34b29a48a4 Ensure enough space is allocated for structs with a FlexArray 2020-08-15 23:53:43 -07:00
Chris Robinson 23259b48dd Avoid a zero-length array for the FlexArray definition
Newer GCCs are warning about FlexArray being used at the end of another struct.
Though not the most ideal to always allocate space for at least 1 element,
actual 0-sized uses are rare and for smaller element types.
2020-08-15 23:22:10 -07:00
Chris Robinson 2fa842a04c Avoid allocating for each HRIR reconstruction 2020-08-14 18:22:20 -07:00
Chris Robinson 3796e407b5 Rename ALSOFT_INSTALL_HRTF_DEFS to ALSOFT_INSTALL_HRTF_DATA 2020-08-13 18:04:09 -07:00
Chris Robinson aafcb1f6fc Simplify StrSubst in makemhr 2020-08-13 16:02:13 -07:00
Chris Robinson 8e7199cbb6 Avoid a cmake check for determining the size of long 2020-08-13 14:04:29 -07:00
Chris Robinson fd52c828a9 Improve handling main() with UTF-8 args on Windows 2020-08-12 17:40:00 -07:00
Chris Robinson 476e9d7522 Cleanup some warnings with ffmpeg/alffplay 2020-08-12 17:39:08 -07:00
Chris Robinson b12cd77d32 Use a wait predicate instead of a while loop 2020-08-12 10:00:43 -07:00
Chris Robinson ed1135f7ae Fix configure-time ffmpeg version detection 2020-08-12 09:48:17 -07:00
Chris Robinson 57d6df29b4 Update .gitignore for QtCreator files 2020-08-11 10:11:20 -07:00
Chris Robinson 529049dc59 Remove an unused variable 2020-08-11 10:06:12 -07:00
Chris Robinson 475ed0f039 Use a FlexArray instead of a vector for distance compensation 2020-08-11 05:59:20 -07:00
Chris Robinson c549797af0 Make osme things constexpr 2020-08-10 15:11:52 -07:00
Chris Robinson e8b3e82f96 Change a couple functions into member functions 2020-08-07 06:22:39 -07:00
Chris Robinson 84354c792e Cleanup OSS enumeration and fix duplicate names 2020-08-07 00:11:29 -07:00
Chris Robinson 02f8419663 Fix DIAGNOSTIC_POP for GCC and Clang 2020-08-06 23:20:20 -07:00
Chris Robinson 58a2a5e2e3 Add a comment about 32-bit GCC stack aligning with SSE codegen 2020-08-05 17:43:51 -07:00
Chris Robinson 816510fee7 Update changelog 2020-08-05 07:18:13 -07:00
Luis Cáceres 064710cdf7 Force stack alignment on 32-bit gcc for proper SSE use (#462)
Fixes crashes due to misaligned stack variables in SSE instructions (#460).
2020-08-05 07:16:56 -07:00
Chris Robinson 7ddd49e16a Add the jack/connect-ports option to alsoft-config 2020-08-05 00:43:08 -07:00
Chris Robinson f138369808 Add an option to auto-connect JACK ports 2020-08-05 00:27:12 -07:00
Chris Robinson 516de157d8 Use std::array instead of some C-style arrays 2020-08-05 00:10:10 -07:00
Chris Robinson 2e1645f32a Print the error from pthread_setschedparam 2020-08-04 12:46:27 -07:00
HALX99 7cac5304c8 Add ios build for travis (#452)
* Add ios build for travis

* fix cmake command and set osx_image: xcode11

* print cmake version

* print cmake version before config

* [iOS] By default use iphoneos for sysroot

* Use ios.toolchain.cmake to build ios

* By default, don't require gnu extension

* Update CMakeLists.txt

Co-authored-by: deal <deal@dealdeMac.local>
2020-08-01 02:52:36 -07:00
Chris Robinson 76c57990be Cleanup and fix a typo in the changelog 2020-07-23 19:20:55 -07:00
Chris Robinson 39a2f0626a Use a predicate instead of a while loop 2020-07-23 09:03:47 -07:00
Chris Robinson ac1fc1b60a Don't include headers in a namespace definition 2020-07-23 09:03:47 -07:00
Chris Robinson 91df03f7eb Simplify mixer buffer size saturation handling 2020-07-23 09:03:47 -07:00
kcat 4817d82185 Merge pull request #453 from devnexen/haiku_support_completion
GetProcBinary implementation for Haiku.
2020-07-21 10:27:43 -07:00
David Carlier d3ffaeb8d7 GetProcBinary implementation for Haiku. 2020-07-21 17:22:38 +00:00
Chris Robinson f409cb4039 Revert "Don't call find_package(WindowsSDK) if the platform ver is already set"
This reverts commit c1383e3a48.
2020-07-09 00:07:33 -07:00
Chris Robinson c1383e3a48 Don't call find_package(WindowsSDK) if the platform ver is already set 2020-07-08 23:32:24 -07:00
Chris Robinson da25557ed6 Remove dead code 2020-06-30 16:44:14 -07:00
Chris Robinson b0e72266b6 Don't round up the dst size when the src size was saturated 2020-06-29 19:41:08 -07:00
Chris Robinson 775187788a Fix SrcBufferSize calculation when downsampling 2020-06-29 12:34:12 -07:00
Chris Robinson 88ad84edf6 Reduce the MAX_PITCH to 10
255 is insanely overkill. The bsinc resamplers fade to silence after a few
octaves, and the others would be a mess.
2020-06-29 11:32:15 -07:00
Chris Robinson f81558c948 Avoid including windows.h in threads.h 2020-06-28 12:55:55 -07:00
Chris Robinson 31791c9997 Workaround a MinGW quirk
Sometimes MinGW defines strncasecmp to _strnicmp in string.h, which can cause
problems with al::strncasecmp if it's not consistently replaced.
2020-06-26 05:39:26 -07:00
Chris Robinson c4cf84c549 Update default HRTF 2020-06-21 19:41:07 -07:00
Chris Robinson a0eb532100 Apply simulated HRIR occlusion in the frequency domain 2020-06-21 19:28:37 -07:00
Chris Robinson 967ea42359 Update the default HRTF 2020-06-21 05:01:35 -07:00
Chris Robinson 24393ab192 Synthesize missing elevations in the frequency domain
This should help avoid destructive phase interference. The occlusion low-pass
filter is still applied in the time domain due to no clear topology (cutoff
frequency, slope, bandwidth, etc).
2020-06-21 00:29:57 -07:00
Chris Robinson a01dbeb09f Use multiple threads for magnitude calculations
Also allow user-declarable thread count.
2020-06-19 16:43:09 -07:00
Chris Robinson bc91e4d302 Update the default HRTF 2020-06-19 15:44:20 -07:00
Chris Robinson 8780976979 Avoid blending multiple IRs for the -90 elevation IR 2020-06-19 15:28:22 -07:00
Chris Robinson 4cd0e333c8 Calculate the HRIR onsets and magnitudes separately from loading
This should help improve memory use a bit since the SOFA file can be unloaded
before allocating some temp buffers for onset detection and FFT calculation.
2020-06-17 17:15:26 -07:00
Chris Robinson 3f26ce4a82 Add a makemhr option to use the farthest field only
All fields are used for equalization, but only the farthest field is resampled,
reconstructed, normalized, and written to the mhr.
2020-06-17 16:25:40 -07:00
Chris Robinson beba71a6f9 Resample HRIRs after equalization 2020-06-17 13:03:26 -07:00
Chris Robinson 4cfd63a1c7 Avoid reinitializing the resampler with each HRIR 2020-06-17 01:50:11 -07:00
Chris Robinson cd6bb65d49 Resample HRTFs in the frequency domain in makemhr
This should produce far better results given it works directly on the frequency
response magnitudes prior to phase reconstruction, as it doesn't deal with a
linear phase filter on a truncated time-domain response (with the result also
getting truncated in both direction).

The in-library on-load HRTF resampler still uses the linear filter due to its
relative performance and simplicity benefits. It's good enough as a backup,
though users with custom HRTFs would benefit from resampling when creating the
mhr (adjusting its window size as appropriate/desired).
2020-06-17 01:15:01 -07:00
Chris Robinson 8ea7d5183b Print the synthesized elevations' azimuth counts 2020-06-16 17:33:26 -07:00
Chris Robinson b0b720c609 Avoid an unnecessary local variable 2020-06-16 14:01:39 -07:00
Chris Robinson bd0144065a Set channel labels from WFX channel masks 2020-06-15 20:21:54 -07:00
Chris Robinson c142b49981 Print the name of unhandled PulseAudio channels 2020-06-15 14:07:21 -07:00
Chris Robinson 6db6d1510a Remove the Lower channel labels and rename the Upper labels 2020-06-15 13:49:45 -07:00
Chris Robinson 401a9bacd1 Don't bother with otherwise unused Aux channels 2020-06-15 02:27:29 -07:00
Chris Robinson 540315b07c Handle the front stablizer with the B-Format decoder 2020-06-15 02:13:14 -07:00
Chris Robinson c951190d3a Fix a typo 2020-06-12 12:54:05 -07:00
Chris Robinson 6ce9bf6c94 Move a couple related functions to the backend base 2020-06-12 12:53:47 -07:00
Chris Robinson 26eccd159f Link with the CoreFoundation framework on iOS 2020-06-11 08:55:52 -07:00
Chris Robinson ad9fc31bfd More capitalization fixes 2020-06-11 08:55:24 -07:00
Chris Robinson df1bdc7bc4 Fix some capitalization 2020-06-11 07:56:45 -07:00
kcat 8fee1da426 Merge pull request #439 from halx99/patch-1
Enable to detect Windows SDK v2004
2020-06-11 07:55:53 -07:00
HALX99 3702dcb1d3 Enable to detect Windows SDK v2004 2020-06-11 22:39:47 +08:00
Chris Robinson 15437e3140 Don't export functions when static linking 2020-06-10 21:03:04 -07:00
Chris Robinson c50250c978 Use a range-for loop instead of for_each 2020-06-09 21:28:09 -07:00
Chris Robinson b2b3ad570b Use better types for array lengths 2020-06-09 11:52:48 -07:00
Chris Robinson 46eb353b84 Update changelog 2020-06-07 18:59:49 -07:00
Chris Robinson b7b52ec28b Simplify the aligned over-allocation strategy 2020-06-07 15:40:04 -07:00
Chris Robinson 9322c86e2f Avoid explicit checks for _BitScanForward[64] 2020-06-07 14:15:48 -07:00
Chris Robinson ab3ccb513a Check the returned sample endianess with sndio 2020-06-07 11:50:16 -07:00
Chris Robinson 2a324d34be Fix a return value 2020-06-07 11:47:39 -07:00
Chris Robinson b4a52321c4 Use a safer layout if sndio changes the channel count 2020-06-07 11:45:06 -07:00
Chris Robinson c8f67cffc5 Use a more appropriate size value for copying 2020-06-07 11:00:19 -07:00
Chris Robinson 03eb6a01b9 Use a better type for array access 2020-06-07 11:00:19 -07:00
kcat 4acfbfc37a Merge pull request #435 from DanielGibson/sndio-more-channels
sndio: Support more than 2 channels
2020-06-07 10:59:54 -07:00
Daniel Gibson 5cffe7e50a sndio: Support more than 2 channels
So far the sndio backend only supports Mono and Stereo, but sndio
supports up to 16 channels (64 in their current git code).
This adds support for all the openal-soft formats (DevFmt*).
I tested this on Linux with 5.1 surround speakers.
2020-06-07 17:22:51 +02:00
Chris Robinson 70d345bbf2 Avoid convolving an always-0 sample 2020-05-30 16:29:23 -07:00
Chris Robinson 7a95a870be Clarify some changelog entries 2020-05-27 15:46:25 -07:00
Chris Robinson f1612ce228 Use dual-biquad processing for the equalizer effect 2020-05-26 18:08:57 -07:00
Chris Robinson 9b63e2460c Update the Changelog 2020-05-26 14:13:02 -07:00
Chris Robinson 7b642330c5 Simplify UHJ delay handling 2020-05-26 12:19:19 -07:00
Chris Robinson 8d77c59da4 Fade over more of the update with HRTF 2020-05-25 16:57:38 -07:00
Chris Robinson 4e82feffef Only apply non-silent inputs for blended HRIR 2020-05-25 16:37:31 -07:00
Chris Robinson 5eb1ae5a14 Simplify the HRTF blending fade out gain scaling 2020-05-25 13:18:10 -07:00
Chris Robinson 4d9d406966 Clarify an error message 2020-05-25 02:02:50 -07:00
kcat 070ed0d5ac Merge pull request #429 from jbeich/ci
Add FreeBSD to CI
2020-05-24 11:31:06 -07:00
Jan Beich c262d0146e CI: add FreeBSD job 2020-05-24 13:12:18 +00:00
Chris Robinson 1a287f434a Round the pitch shifter frequency bin targets 2020-05-22 16:36:41 -07:00
Chris Robinson 978f32acf7 Round the scaled HRTF delays 2020-05-21 17:59:15 -07:00
Chris Robinson 109875942c Slightly increase the HRTF direct delay
To help improve the phase-corrected HF scaler.
2020-05-21 15:25:03 -07:00
Chris Robinson 94105409f8 Print why a sofa file couldn't be opened 2020-05-21 13:51:48 -07:00
Chris Robinson da3dfa2fb0 Simplify handling the stablizer side channel delay 2020-05-21 13:48:50 -07:00
Chris Robinson e98017b475 Avoid a log10 constant call 2020-05-21 09:46:39 -07:00
Chris Robinson 5bbbe8341e Use an enum class for SpatializeMode 2020-05-21 09:10:32 -07:00
Chris Robinson e880c04f32 Clarify a comment about the band-splitter 2020-05-20 11:22:53 -07:00
Chris Robinson 200c164d78 Improve HRTF delay handling
Ensures source-level HRTF, the dry mix, and direct output all align properly,
and simplifies adding the delay in the direct mix output.
2020-05-20 11:13:06 -07:00
Chris Robinson f38b813ba8 Fix some comments 2020-05-19 18:22:38 -07:00
Chris Robinson 19baf646d2 Rename applyHfScale to processHfScale 2020-05-19 13:58:55 -07:00
Chris Robinson c5e90ed6c7 Use an enum for FamCount 2020-05-19 12:15:57 -07:00
Chris Robinson 825206bfa2 Apply the ambisonic HF scaling in real-time with HRTF
Rather than applying the HF scale to the IRs necessitating them to be truncated
along with increasing the IR size, it can be applied to the input signal for
the same results. Consequently, the IR size can be notably shortened while
avoiding the extra truncation. In its place, the delayed reversed all-pass
technique can still be used on the input for maintaining phase when applying
the bandsplit/hfscalar filter to the input signal.
2020-05-19 10:27:52 -07:00
Chris Robinson a512eae7bb Move BUFFERSIZE and FloatBufferLine to a separate header 2020-05-19 10:21:19 -07:00
Chris Robinson 463591663c Check that aligned_alloc is available with cmake
Some compilers support C++17 even on targets that lack required functions.
Projects that want to force C++17 will then run into a problem with
std::aligned_alloc not existing on those targets, so it needs to be explicitly
checked for. The alternative is to simply never use it even when it would be
available.
2020-05-19 08:13:13 -07:00
Chris Robinson 400a108ead Also search for asimd for Neon 2020-05-17 16:23:24 -07:00
Chris Robinson c75c96ce2d Assume Neon support if cpu_caps.cpp is compiled with it 2020-05-17 14:14:29 -07:00
Chris Robinson 36aebbb6ae Include the existing direct signal in the UHJ delay
So any direct_channels sources and normal panned sources remain aligned, and
the reported latency is accurate.
2020-05-16 11:35:55 -07:00
Chris Robinson 0f81fafc62 Fix some standard calls 2020-05-16 01:21:09 -07:00
Chris Robinson d086e78a38 Fix the all-pass's shuffle order 2020-05-14 21:16:21 -07:00
Chris Robinson 91b8387c0a Give names to parameter value constants 2020-05-13 00:57:03 -07:00
Chris Robinson f5bf7dc76e Do two samples at once with the SSE UHJ all-pass 2020-05-12 05:51:48 -07:00
Chris Robinson ad95cb6312 Clear the whole buffer 2020-05-12 04:46:15 -07:00
Chris Robinson 2f8f829772 Properly count the last number of samples to mix 2020-05-12 04:45:25 -07:00
Chris Robinson 3ce8a9914c Fix applying the UHJ phase-shift filter 2020-05-11 23:49:39 -07:00
Chris Robinson 2574b98f8a Move the bsinc tables out of common 2020-05-11 02:24:08 -07:00
Chris Robinson 0406e3bef7 Change a couple functions into member functions 2020-05-10 20:16:43 -07:00
Chris Robinson 2fb4ac1621 Revert "Fix the FFT half point for the shifter effects"
This reverts commit 12bb5a47cd.
2020-05-09 16:44:29 -07:00
Chris Robinson 52a5dc23a3 Fix the UHJ filter generator
The half point needs to be included in the frequency response.
2020-05-09 16:42:43 -07:00
Chris Robinson 73569dfeca Avoid a reference on a constexpr variable 2020-05-08 20:11:30 -07:00
Chris Robinson 1c320c3532 Use a FIR filter for the UHJ all-pass 2020-05-08 15:38:14 -07:00
Chris Robinson 12bb5a47cd Fix the FFT half point for the shifter effects 2020-05-08 01:39:48 -07:00
Chris Robinson 48fbad9836 Slightly improve the Hann windows
There's no need to include the 0 terms on the ends since they'll never
contribute a sample. So extend the width to have the 0 terms just outside the
window where it wouldn't contribute anyway.
2020-05-08 01:25:32 -07:00
Chris Robinson 301f8f5db5 Use std::arrays for the UHJ filters 2020-05-08 01:24:14 -07:00
Chris Robinson 0cfb8fee44 Combine multiple UHJ encoder all-pass loops 2020-05-07 21:01:37 -07:00
Chris Robinson 7ed37a8282 Use dual-band for the internal quad and 7.1 decoders 2020-05-07 03:15:46 -07:00
Chris Robinson faec0c78eb Allow declaring internal dual-band decoders 2020-05-07 02:13:11 -07:00
Chris Robinson 4630a535b2 Re-add an option for installing the main lib 2020-05-07 00:02:23 -07:00
Chris Robinson ca851298ad Update the quad and 7.1 decoders 2020-05-06 22:36:29 -07:00
Chris Robinson bef25361f1 Make the built-in decoders more flexible 2020-05-06 19:31:31 -07:00
Chris Robinson f82fca2c6a Fix the dual-band decoder 2020-05-05 16:56:25 -07:00
Chris Robinson ee82db3966 Use a flexible array for the front stablizer delay buffers 2020-05-05 01:34:14 -07:00
Chris Robinson deac36a1eb Improve the front stablizer
Apply the all-pass+band-split only once, after generating the mid and side
signals separately.
2020-05-05 01:05:38 -07:00
Chris Robinson fcec76663f Move some sin/cos constants out of a loop 2020-05-04 16:16:55 -07:00
Chris Robinson 58d953f6aa Clear buffers right before use 2020-05-03 19:13:20 -07:00
Chris Robinson 15fd3da870 Don't put the LFO on the stack 2020-05-03 19:04:43 -07:00
Chris Robinson fe7a74b09a Use a helper to set an identity ambisonic pan 2020-05-03 18:47:49 -07:00
Chris Robinson b52fde7c0e Simplify SIMD linear resampler loop count 2020-05-02 20:27:05 -07:00
Chris Robinson b051f2e33d Use a matching type given the initializer 2020-05-02 19:24:21 -07:00
Chris Robinson 6823fa2de2 Improve the leftover and realignment mixing loops
Using a mask helps the compiler recognize that the leftover (any remaining non-
multiple-of-4) and realignment loops will only have 3 iterations at most, which
it can unroll or otherwise make more meaningful optimizations for. Previously
it would try to vectorize and partially unroll the loops, which is wasteful
when there would never be enough to vectorize.
2020-05-02 16:42:24 -07:00
Chris Robinson 3898b77dd6 Avoid iterators for the main mixer 2020-05-01 21:14:41 -07:00
Chris Robinson 8acf16fc82 Make BuildBFormatHrtf a member of DirectHrtfState 2020-05-01 10:28:16 -07:00
Chris Robinson ae09e1f60c Don't truncate odd IR sizes with SSE 2020-04-30 20:33:35 -07:00
Chris Robinson 6bc3ae178e Use a more efficient type for holding the IrSize 2020-04-30 17:03:56 -07:00
Chris Robinson 972869f76f Dump the ffmpeg file info on the main thread 2020-04-29 21:32:09 -07:00
Chris Robinson 054071998c Correctly handle unicode paths on Windows for ALSOFT_LOGFILE 2020-04-29 15:41:11 -07:00
Chris Robinson a25dea6cd9 Rename effect_chain to effect_target 2020-04-29 14:39:28 -07:00
Chris Robinson 047f1666d5 Fix subspan extent calculation 2020-04-28 19:58:17 -07:00
Chris Robinson 4094135ed7 Don't return a bool from the backend start method 2020-04-28 19:25:58 -07:00
Chris Robinson 065775d814 Limit the maximum settable sample rate 2020-04-28 16:30:11 -07:00
Chris Robinson 45cb3e4956 Remove a couple redundant comments 2020-04-28 14:59:45 -07:00
Chris Robinson cf64dc1103 Fix up some more uses of [AL[C]]void 2020-04-28 14:48:12 -07:00
Chris Robinson 2520d492a5 Clean up al.h a bit 2020-04-28 14:27:52 -07:00
Chris Robinson c47f4822dc Move standard ALC function's annotations to the header 2020-04-28 13:36:43 -07:00
Chris Robinson 1120f52556 Clean up some function comments 2020-04-28 08:29:42 -07:00
Chris Robinson b828cf81a9 Shorten the name of format types 2020-04-28 07:56:36 -07:00
Chris Robinson 5441fba419 Don't maintain a global backend list end 2020-04-28 07:28:22 -07:00
Chris Robinson 187477db03 Properly return on error 2020-04-28 07:01:30 -07:00
Chris Robinson b4435cd053 Avoid using some extraneous ALC types 2020-04-28 06:51:21 -07:00
Chris Robinson 0a69adf845 Avoid unnecessary PATH_SUFFIXES 2020-04-26 07:59:08 -07:00
Chris Robinson 950e4f3cc4 Avoid duplicate env var declarations 2020-04-26 07:36:50 -07:00
Chris Robinson ff1562c916 Don't delete non-existent files in AppVeyor 2020-04-26 07:19:27 -07:00
Chris Robinson e3f6afafde Remove some hopefully unneeded macros 2020-04-25 02:12:43 -07:00
Chris Robinson be476c7935 Use global placement new for AsyncEvent 2020-04-24 07:04:32 -07:00
Chris Robinson f49238c792 Minor cleanup of reverb code 2020-04-24 02:51:23 -07:00
Chris Robinson 8739833770 Add a method to process two biquads at once 2020-04-23 22:13:52 -07:00
Chris Robinson e89978195f Clean up some scaling math 2020-04-23 06:18:54 -07:00
Chris Robinson aff410fa6d Avoid using some more AL types 2020-04-23 04:57:04 -07:00
Chris Robinson 2deb5e47d1 Avoid an unnecessary out parameter 2020-04-21 23:58:53 -07:00
Chris Robinson a97e6e6a12 Fix the source ID for a source voice stopped from deletion 2020-04-21 01:01:18 -07:00
Chris Robinson 552d2b1918 Set the device name in the Oboe backend 2020-04-20 04:39:36 -07:00
Chris Robinson 947826af1c Get rid of an unnecessary variable 2020-04-20 04:30:14 -07:00
Chris Robinson b692440725 Trace the opened Oboe stream properties 2020-04-19 15:19:28 -07:00
Chris Robinson 3ef6f22760 More gracefully relax the Oboe format request 2020-04-19 15:10:22 -07:00
Chris Robinson 61cf6d3bb6 Simplify some install statements 2020-04-19 04:38:44 -07:00
Chris Robinson 9b9a65a0bf Use an import target for libsndfile 2020-04-19 04:00:01 -07:00
Chris Robinson 3902337e01 Fix some message formatting 2020-04-19 03:37:32 -07:00
Chris Robinson 07726ad63a Make sure HAVE_OBOE is cleared before checking 2020-04-19 03:35:31 -07:00
Chris Robinson 1ca7f22145 Correctly test for SSE switches 2020-04-19 02:47:11 -07:00
Chris Robinson 0a0478f670 Rename install options for consistency 2020-04-19 00:58:01 -07:00
Chris Robinson 12d71a0ad1 Don't explicitly link libpthread
Compiling and linking with -pthread is apparently enough.
2020-04-19 00:37:03 -07:00
Chris Robinson 253773b316 Build Oboe with hidden visibility 2020-04-18 23:03:50 -07:00
Chris Robinson 643b192fd5 Try to be more robust with the Oboe format 2020-04-18 22:43:20 -07:00
Chris Robinson a387a610f8 Add missing backslash 2020-04-18 20:46:20 -07:00
Chris Robinson 0390828de0 Initial implementation for Oboe-based playback 2020-04-18 19:21:13 -07:00
Chris Robinson bd9eae8edd Attempt to build with Oboe on Android with Travis 2020-04-18 19:20:38 -07:00
Chris Robinson 67e54a2669 Add an Oboe backend stub 2020-04-18 15:17:53 -07:00
Chris Robinson a1e5f4eb83 Use cmake --build with Travis to build
Instead of assuming makefiles
2020-04-17 23:33:09 -07:00
Chris Robinson cd87b9c66b Update Travis to use Android NDK r21, API 16 2020-04-17 23:21:04 -07:00
Chris Robinson 93e677edb3 Precalculate some values
MSVC isn't as willing to precompute sqrt and log10 results from known input
values.
2020-04-16 23:17:07 -07:00
Chris Robinson 3824b92704 Simplify some reverb update code 2020-04-16 20:52:20 -07:00
Chris Robinson 27ac637a66 Remove another unnecessary return value 2020-04-16 17:29:32 -07:00
Chris Robinson cf4a848fd0 Remove an always-true return value 2020-04-16 16:00:26 -07:00
Chris Robinson 3cb12da765 Move a type to where it's used 2020-04-16 02:05:07 -07:00
Chris Robinson dc41f276d8 Get rid of the specialized MixRow_ methods 2020-04-16 01:47:33 -07:00
Chris Robinson 5214a7210a Combine multiple target installs 2020-04-15 00:21:36 -07:00
Chris Robinson 3a5a9e90d0 Fix installing alsoft-config 2020-04-15 00:09:45 -07:00
Chris Robinson 8ef8b5e215 Combine utility target installs 2020-04-14 23:37:48 -07:00
Chris Robinson cd6908fd19 Always define install targets for the main library
Examples and utilities now have separate install options.
2020-04-14 23:25:47 -07:00
Chris Robinson 930cda39cd Simplify some indentation 2020-04-14 22:02:59 -07:00
Chris Robinson ac54ab8a3e Remove some unnecessary cmake checks 2020-04-14 18:25:22 -07:00
Chris Robinson 78e789bf7b Silence a type conversion warning with GCC 2020-04-14 12:05:54 -07:00
Chris Robinson 6ac5816354 Avoid inlining some potentially costly calls 2020-04-14 11:50:59 -07:00
Chris Robinson 7f81eec1a6 Avoid a function call to get the frame step 2020-04-13 23:36:05 -07:00
Chris Robinson 02d7fbfa0c Use standard attribute declarations 2020-04-13 23:27:56 -07:00
Chris Robinson 1d8ac4d61f Throw exceptions for errors in the effect getters/setters 2020-04-10 20:23:20 -07:00
Chris Robinson 13153bab60 Add an effect_exception for handling effect properties 2020-04-10 18:26:08 -07:00
Chris Robinson f7380a44d4 Use a common base for a couple exceptions 2020-04-10 15:12:57 -07:00
Chris Robinson 611a0155cd Ignore "attribute '...' is not recognized" MSVC warning 2020-04-10 15:12:57 -07:00
kcat fc140db781 Merge pull request #414 from ArthurSonzogni/master
Add missing <cstdarg>
2020-04-10 15:01:38 -07:00
ArthurSonzogni 7548c235bd Add missing <cstdarg>
OpenAL-Soft fails to compile on some GCC version:
https://travis-ci.com/github/ArthurSonzogni/smk/jobs/318304162

It has regressed likely after:
https://github.com/kcat/openal-soft/commit/c83609277bed4be4ef40ed306bf2c57fefa19519

va_start is defined in:
- <stdarg.h>
- <cstdarg>

The repository is using it from:
- al/error.cpp
- al/filter.cpp
- alc/alu.cpp
- alc/helpers.cpp
- common/alexcpt.cpp
- utils/makemhr/loaddef.cpp
- utils/openal-info.c

This patch is adding its definition in the files missing it:
- common/alexcpt.cpp
- utils/makemhr/loaddef.cpp
- utils/openal-info.c

Bug: https://travis-ci.com/github/ArthurSonzogni/smk/jobs/318304162
2020-04-10 23:36:19 +02:00
Chris Robinson e123fa0ec3 Apply some alloc and alignment attributes 2020-04-10 11:05:25 -07:00
Chris Robinson 8bddf3e6ab Report invalid filter values 2020-04-10 09:16:08 -07:00
Chris Robinson 8713bb8afb Add missing include 2020-04-10 09:04:40 -07:00
Chris Robinson ae173ba863 Remove an unused cmake variable 2020-04-10 08:59:22 -07:00
Chris Robinson 0dc9b0392d Apply static-link flags directly to the target 2020-04-10 08:43:59 -07:00
Chris Robinson 35a2b0e5f8 Simplify generating chorus delays a bit 2020-04-09 21:00:37 -07:00
Chris Robinson c83609277b Use exceptions for filter errors 2020-04-09 19:36:37 -07:00
Chris Robinson 97c11577cd Make a default/empty constructor noexcept 2020-04-09 19:32:02 -07:00
Chris Robinson d67cba99bd Clean up some more unnecessary uses of AL types 2020-04-08 10:15:43 -07:00
Chris Robinson 8a5153ce0d Avoid ALfloat and ALint in the effects 2020-04-08 07:28:07 -07:00
Chris Robinson 55539787fb Avoid ALfloat in some places 2020-04-08 06:17:04 -07:00
Chris Robinson 024112a53a Use acquire-release semantics for changing deferred updates 2020-04-07 12:46:35 -07:00
Chris Robinson 0077a01667 Don't yield the CPU when waiting for updates to finish 2020-04-07 12:36:44 -07:00
Chris Robinson f628ab2151 Use better values for a couple in-progress enums 2020-04-07 12:24:20 -07:00
Chris Robinson efed431237 Use a unique_ptr for constructing the bsinc table coefficients 2020-04-07 08:30:37 -07:00
Chris Robinson 2fcc3f3887 Dynamically allocate the temporary bsinc filter table 2020-04-06 17:12:39 -07:00
Chris Robinson 7a324231a3 Combine the late reverb feedback and modulator delay lines 2020-04-06 16:14:13 -07:00
Chris Robinson 6ff5339112 Include the average modulation delay for the late reverb feedback 2020-04-06 15:46:14 -07:00
Chris Robinson baf14aad2a Pass the BSincHeader by reference instead of value 2020-04-05 23:08:02 -07:00
Chris Robinson ab6afd6fa0 Reimplement the modulation stage for reverb
This seems to be quite close recordings from real hardware, so it's probably
good enough.
2020-04-05 12:00:45 -07:00
Chris Robinson 192b1a1f65 Require Qt5 for alsoft-config 2020-04-05 01:41:36 -07:00
kcat de2599b70b Merge pull request #167 from aaronmjacobs/build-version-option
Add option to disable "build_version" cmake target
2020-04-05 00:02:54 -07:00
Chris Robinson 25464b2210 Avoid storing the bsinc coefficient deltas before output
This cuts the majority of stack use when generating the coefficients.
2020-04-04 22:04:59 -07:00
Chris Robinson 8084d08cf9 Get rid of the Android cross-compile toolchain
It has problems, and the Android NDK provides one that works fine.
2020-04-04 10:58:43 -07:00
Chris Robinson 9b11029af9 Remove the now-unused native tools 2020-04-04 08:58:06 -07:00
Chris Robinson 431d01cc7f Use a cmake script to convert a binary file to a header file 2020-04-04 08:46:18 -07:00
Chris Robinson a0b7638d63 Add an extension to change a buffer's unpack ambisonic order 2020-04-04 03:10:01 -07:00
Chris Robinson fc906c97f5 Track a buffer's ambisonic order 2020-04-04 01:52:29 -07:00
Chris Robinson 902f5a0dd2 Add an ambisonic order parameter to the buffer channel count 2020-04-03 21:43:57 -07:00
Chris Robinson bd50601f15 Remove a couple outdated comments 2020-04-03 10:07:43 -07:00
Chris Robinson 8f47013e43 Some more ALfloat->float cleanup 2020-04-03 08:49:15 -07:00
Chris Robinson 1130597562 Use structs for the mixer and resampler tags 2020-04-03 03:52:23 -07:00
Chris Robinson d9225083b4 Avoid using ALfloat in the mixer functions 2020-04-03 03:11:32 -07:00
Chris Robinson 236564b54a Another small cleanup 2020-04-03 02:57:51 -07:00
Chris Robinson 8adbde90f5 Jump to the target gain if the fade amount is small 2020-04-03 02:48:35 -07:00
Chris Robinson 367d4af07c Avoid unnecessary duplication in the resamplers 2020-04-03 02:39:23 -07:00
Chris Robinson ebe30fb0bd Remove the now-unused bsincgen 2020-04-02 04:34:28 -07:00
Chris Robinson ee89ca1bdd Fix bsinc filter alignment and offsets 2020-04-02 02:13:18 -07:00
Chris Robinson 57109902cd Avoid std::abs in a constexpr function 2020-04-02 01:52:07 -07:00
Chris Robinson 8853519d89 Generate the bsinc tables using constexpr methods
All the methods used should be compliant with C++14 constexpr rules. However,
the number of scales and phases cause GenerateBSincCoeffs to reach the allowed
step limit, preventing full compile-time generation. It's not a terribly big
deal, it'll generate them very quickly when loading, but it does prevent using
shared read-only memory pages.
2020-04-02 00:49:19 -07:00
Chris Robinson 6fb59f1182 Avoid using M_PI 2020-04-01 22:22:50 -07:00
Chris Robinson bf48dcd375 Report better latency when PulseAudio has no timing info 2020-03-30 20:06:24 -07:00
Chris Robinson b9f19c6ca2 Inline a small helper method 2020-03-30 16:06:34 -07:00
Chris Robinson 662d77159b Get rid of a redundant enum 2020-03-30 16:00:02 -07:00
Chris Robinson f2ddf971df Return the enumerated device names from the backend
Rather than using an out parameter.
2020-03-30 15:37:41 -07:00
Chris Robinson 167bdce48d Hold the ListLock while opening a device
Since it may rely on the enumerated device list that could be updated
asynchronously.
2020-03-30 13:50:50 -07:00
Chris Robinson 75479b58e3 Remove use of unnecessary type aliases 2020-03-30 13:43:49 -07:00
Chris Robinson cc009b8aa0 Move the FrontStablizer definition to its own header 2020-03-30 01:16:15 -07:00
Chris Robinson f8a5ea2d74 Inline a couple BackendBase methods 2020-03-30 00:07:35 -07:00
Chris Robinson 9b237790b2 Remove the mutex from the backend base 2020-03-29 23:57:37 -07:00
Chris Robinson d70912c034 Remove the QSA backend
It's been broken for who knows how long, and could really do with a rewrite for
the new interface anyway.
2020-03-29 20:37:58 -07:00
Chris Robinson fed80e0c10 Reset real-time priority on fork 2020-03-29 19:39:00 -07:00
Chris Robinson fb433cd918 Protect the call to pa_mainloop_quit with the mutex 2020-03-29 03:44:34 -07:00
Chris Robinson 5dfa24d5e2 Stop updating effects when one fails 2020-03-29 03:10:35 -07:00
Chris Robinson a5b8167280 Make some functions private methods 2020-03-28 18:15:05 -07:00
Chris Robinson 963d9b761b Rename ALvoice and related structs to Voice 2020-03-28 18:15:05 -07:00
Chris Robinson fb07612545 Get rid of MAX_INPUT_CHANNELS 2020-03-28 18:15:05 -07:00
Chris Robinson f1f9a14172 Avoid AL[C]boolean for internal use 2020-03-28 18:15:05 -07:00
Chris Robinson 504745abec Use a standard bool instead of ALboolean 2020-03-28 18:15:05 -07:00
Chris Robinson e78cb9b77f Avoid using more unnecessary type aliases 2020-03-28 18:15:04 -07:00
kcat 3fce1c4217 Merge pull request #405 from aaronmjacobs/cmake-fixes
Fix find_package_handle_standard_args name mismatch warnings
2020-03-28 18:14:34 -07:00
Aaron Jacobs a3a2305d7a Fix find_package_handle_standard_args name mismatch warnings 2020-03-28 17:43:17 -07:00
kcat 6cfb4ec462 Merge pull request #404 from jhasse/cmake-no-cxx-compiler
Don't require a C++ compiler for native-tools
2020-03-27 12:35:23 -07:00
Jan Niklas Hasse 2a3c7ccd81 Don't require a C++ compiler for native-tools
"By default C and CXX are enabled if no language options are given."
https://cmake.org/cmake/help/v3.17/command/project.html
2020-03-27 20:14:25 +01:00
Chris Robinson 8731accd3f Make sure prebuf is filled when starting pulseaudio playback 2020-03-27 01:03:01 -07:00
Chris Robinson e73c0979a1 Use "zero-copy" writes with pulseaudio playback 2020-03-26 22:50:54 -07:00
Chris Robinson d344c5a228 Avoid some extraneous uses of AL type aliases 2020-03-25 22:39:45 -07:00
Chris Robinson e8149ec509 Move some setup to a more logical place 2020-03-25 22:24:09 -07:00
Chris Robinson a27096dd63 Dynamically allocate voice channel data
Rather than allocating for a full 8 channels for each voice, when the vast
majority will only need 1 or 2. The voice channel data is relatively big since
it needs to hold HRTF coefficients and history, and this will allow increasing
the maximum number of buffer channels without an obscene memory increase.
2020-03-25 21:06:24 -07:00
Chris Robinson cae78e79e8 Convert the examples from SDL_sound to libsndfile 2020-03-24 15:46:47 -07:00
Chris Robinson 586bc94d51 Use libsndfile for the alplay example 2020-03-24 13:36:49 -07:00
Chris Robinson c24d127229 Avoid non-namespace template specialization 2020-03-24 12:03:07 -07:00
Chris Robinson cc27bbb680 Clear the WASAPI device list when enumerating 2020-03-24 11:48:25 -07:00
Chris Robinson 62f17d8763 Don't send close messages for unopened WASAPI devices 2020-03-24 11:40:34 -07:00
Chris Robinson eed8407599 Remove some unused functions 2020-03-23 17:18:11 -07:00
Chris Robinson 7effad45c2 Clean up ALfilter some
Use inline methods instead of macros
Fix indentation
Add some consts
2020-03-23 16:31:08 -07:00
Chris Robinson 6a3b3b180b Add a macro to disable class-specific new/delete 2020-03-23 16:00:50 -07:00
Chris Robinson b53294e291 Use inline initialization more for sources 2020-03-23 15:04:26 -07:00
Chris Robinson 5d0f90fed0 Avoid ## in a macro
Cppcheck thinks it's an invalid use of it
2020-03-23 14:26:00 -07:00
Chris Robinson 41b4c06697 Simplify clamping the voice mix size 2020-03-23 11:35:08 -07:00
Chris Robinson 132a69c03d Use more appropriate types for bitfields 2020-03-22 21:34:50 -07:00
Chris Robinson 46234171d1 Clean up some C++11-isms 2020-03-22 21:15:12 -07:00
Chris Robinson dc8ccc06ce More cleanup for the pitch shifter 2020-03-22 20:48:02 -07:00
Chris Robinson 813d4ed566 Use make_unique instead of new'ing into a unique_ptr 2020-03-22 18:48:33 -07:00
Chris Robinson 49b2d703e7 Properly define the new[] and delete[] operators 2020-03-22 13:28:45 -07:00
Chris Robinson 3c631149e3 Update AppVeyor to VS 2017 for 32-bit 2020-03-22 11:41:57 -07:00
Chris Robinson be1584ab47 Avoid assigning in a conditional expression 2020-03-22 11:35:08 -07:00
Chris Robinson ef663f13c0 Properly allocate voices 2020-03-22 11:34:37 -07:00
Chris Robinson 3d09898d40 Use the correct include for al::fstream 2020-03-22 11:09:19 -07:00
Chris Robinson 2acdcba8d1 Silence a potential type truncation warning 2020-03-22 10:41:23 -07:00
Chris Robinson f3ff28fb2a Some type cleanup 2020-03-22 10:41:02 -07:00
Chris Robinson d30d9a2c9f Clean up the pitch and frequency shifter some 2020-03-22 10:06:23 -07:00
Chris Robinson 002d0eb6a0 Fix the frequency shifter channel panning 2020-03-22 08:51:59 -07:00
Chris Robinson 9ce182228d Avoid some pre-C++14 workarounds 2020-03-22 08:51:06 -07:00
Chris Robinson 040309b9f4 Add missing semicolon 2020-03-22 08:22:25 -07:00
Chris Robinson f6a0b004e0 Update to C++14 2020-03-22 08:05:22 -07:00
Chris Robinson adf28d87aa Remove the check for stat()
It's POSIX-2001 standard
2020-03-21 08:39:45 -07:00
Chris Robinson 12775513ae Cleanup some helper code 2020-03-20 15:48:27 -07:00
Chris Robinson 0d11de3e8d Move CPUCapFlags and FillCPUCaps to their own source 2020-03-20 15:30:41 -07:00
Chris Robinson f56ef433d8 Move the FPUCtl methods to its own source 2020-03-20 15:01:45 -07:00
Chris Robinson ad98895876 Avoid a function call to get the channel count 2020-03-18 04:08:26 -07:00
Chris Robinson 7805179313 Rename a method to be clearer 2020-03-18 03:17:14 -07:00
Chris Robinson 54e2eafcc9 Make the pulseaudio enumeration functions class methods 2020-03-18 03:07:54 -07:00
Chris Robinson 9f077d5f41 Remove a couple unused methods 2020-03-18 02:35:31 -07:00
Chris Robinson bf50f227b9 Use a busy-wait when synchronizing against the mixer
The mixer should have higher priority than any thread that can make AL calls,
so even on single-core systems, it shouldn't stall the mix. It will, however,
return back to the caller as soon as it can, while yielding will give up the
timeslice if there's any other thread waiting to process even if the mix is
almost done.
2020-03-16 01:05:14 -07:00
Chris Robinson 78251fd7e6 Fix voices being forced to update without valid properties
When starting a voice, the source ID was set before its first update struct was
provided, creating a small window where a listener or effect slot update could
force a voice to update without it having any valid properties to update with.
Supplying the update struct first would create a different race, where the
mixer could see a voice without a source but with an update struct, causing the
update struct to be 'freed' without being applied.

The fix here is to provide the update struct before setting the source ID, and
change the mixer to ignore update structs for voices without a source ID. This
can pseudo-orphan the updates that get set on a voice just as it stops, leaving
the struct unusable until the voice is used again, or the voice gets deleted
which will clear it. But it allows the update struct to stay in place and get
applied once the voice gets a source ID.
2020-03-04 23:18:05 -08:00
Chris Robinson 48b9b541ec Avoid redundantly setting voice members 2020-03-04 13:40:21 -08:00
Chris Robinson 971862a80c Don't change flags after InitVoice 2020-03-04 11:01:35 -08:00
Chris Robinson e7405f7801 Use a new voice state to indicate a pending source offset change 2020-03-04 10:16:59 -08:00
Chris Robinson 08dc831e0e Avoid unnecessarily reclearing some variables 2020-03-03 20:44:19 -08:00
Chris Robinson accc1ec1c8 Add a helper to wait for the device mix 2020-03-03 20:32:44 -08:00
Chris Robinson 3e1a2c0f77 Use an intrusive_ptr for the device's HrtfStore 2020-03-01 17:16:09 -08:00
Chris Robinson a01617904c Simplify getting a voice for a new source offset 2020-02-28 20:07:43 -08:00
Chris Robinson b42d241da5 Use real-time priority by default 2020-02-26 09:53:06 -08:00
Chris Robinson eb49290dab Remove unnecessary locks now that the mixer doesn't require one 2020-02-26 04:58:02 -08:00
Chris Robinson 4555b74bd7 Use a VoiceChange object to change the offset of a playing source 2020-02-26 03:52:40 -08:00
Chris Robinson 872096958b Rename the voice's PendingStop to PendingChange 2020-02-26 01:48:59 -08:00
Chris Robinson 814f80ec59 Move voice initialization to a separate function 2020-02-26 01:39:30 -08:00
Chris Robinson 8618571866 Avoid storing the source offset when it's just read and reset 2020-02-26 01:03:23 -08:00
Chris Robinson 795c4fcecc Make the source's send array static instead of dynamic 2020-02-25 06:39:03 -08:00
Chris Robinson 9ddfcd6a1b Update an comment about the default HRTF filters 2020-02-25 05:00:26 -08:00
Chris Robinson af6584b8fc Reduce the maximum number of source sends to 6 2020-02-25 04:52:39 -08:00
Chris Robinson 7144cf405a Handle playing voices after disconnection 2020-02-24 22:21:44 -08:00
Chris Robinson fd0ed9f33f Improve searching for the next voice when playing multiple sources
Instead of searching from the beginning of the voice list for each source, just
continue searching from the last source's voice.
2020-02-24 21:40:54 -08:00
Chris Robinson 52d86ad51f Ignore VoiceChange objects while disconnected
And try to improve ALvoice/VoiceChange handling when attempting to recover a
lost device.
2020-02-24 11:01:45 -08:00
Chris Robinson 90d45984dc Simplify replaying a source 2020-02-23 21:40:54 -08:00
Chris Robinson 8554e6cde2 Remove AL_SOFT_map_buffer from alffplay and add AL_SOFT_callback_buffer
The former doesn't really help too much since buffers still need to be
(re)filled and (de)queued individually. A callback buffer, on the other hand,
allows for greater efficiency since it just needs to write into a ring buffer
that the mixer will directly read from.
2020-02-23 06:28:39 -08:00
Chris Robinson a37932a0d0 Fix voice allocation increase amount 2020-02-22 18:01:34 -08:00
Chris Robinson 6044e0d7ca Remove a couple unnecessary type aliases 2020-02-22 00:08:55 -08:00
Chris Robinson 4660819f6a Avoid a single function call in a loop 2020-02-21 22:17:29 -08:00
Chris Robinson a8162a77c2 Use an array of ALvoice pointers for the active voices
This allows growing the array atomically with the mixer since the ALvoice
objects themselves don't move, and a new larger array of them can be swapped in
without blocking the mixer.
2020-02-21 20:14:28 -08:00
Chris Robinson 6e6a30679e Set the voice's property update after the source ID
Otherwise the mixer has a chance to throw it out before realizing it's needed.
2020-02-21 04:55:04 -08:00
Chris Robinson 0694df9014 Handle playing and pausing with VoiceChanges 2020-02-21 04:29:32 -08:00
Chris Robinson 9887c6971d Prepare VoiceChange objects one at a time 2020-02-21 03:23:22 -08:00
Chris Robinson 9b801227d5 Don't unnecessarily count all voices when playing sources 2020-02-21 00:54:05 -08:00
Chris Robinson 9b43327f56 Asynchronously stop and rewind voices 2020-02-20 23:53:56 -08:00
Chris Robinson bdb8ef22b0 Asynchronously stop voices if its source is being deleted 2020-02-20 22:50:37 -08:00
Chris Robinson acf7f6f74e Add a voice flag to indicate a voice has a pending stop
Pending/asynchronous stops to be implemented soon.
2020-02-20 19:18:07 -08:00
Chris Robinson 642ef4edc9 Add a streaming example using a callback buffer 2020-02-20 17:53:09 -08:00
Chris Robinson 3aad01d3ba Add AL_SOFTX_callback_buffer to the extension list 2020-02-19 17:32:32 -08:00
Chris Robinson 4277c05b0c Workaround a 32-bit GCC/MinGW TLS bug 2020-02-18 18:14:59 -08:00
Chris Robinson d4e01a1818 Flag the voice as callback-based when given a callback buffer 2020-02-17 17:34:17 -08:00
Chris Robinson 04e5b23286 Don't bother looping the calculated source offset
The offset shouldn't be in a non-wrapped state when playing, and when not
playing it's always 0 anyway.
2020-02-17 17:30:47 -08:00
Chris Robinson d6e49b503b Don't allow setting a source offset for a callback 2020-02-17 17:20:01 -08:00
Chris Robinson 3122c3b4a1 Handle running the buffer callback in the voice 2020-02-17 17:13:25 -08:00
Chris Robinson c8dfd24818 Add a callback flag for voices 2020-02-17 04:50:00 -08:00
Chris Robinson a221f8671e Prevent queueing a callback buffer
Also prevent setting it on multiple sources
2020-02-17 00:32:22 -08:00
Chris Robinson ccc6da0a5b Set and retrieve a buffer's callback 2020-02-17 00:22:51 -08:00
Chris Robinson 3156b17057 Stub out an interface for a callback-driven buffer 2020-02-16 23:49:29 -08:00
Chris Robinson 8665f404a5 Always start streaming sources from the start of the queue
For sources that don't start with an offset, at least. This is necessary so the
completed buffer event will give the correct count if it starts with null or
empty buffers that become processed.
2020-02-15 22:37:19 -08:00
Chris Robinson be89684f3c Update the makemhr utility and default HRTF 2020-02-11 01:01:10 -08:00
Chris Robinson 1d91e282c8 Update the MHR format
This update removes the 16/24-bit sample type enum, now always being 24-bit
(other than a very small size saving, there's no practical benefit to storing
16-bit samples). This also reverses the field storage, so no on-load fixup is
needed, and stores the IR delays with 2 bits of sub-sample precision, allowing
for slightly better timing (after resampling, blending, etc).
2020-02-11 00:37:21 -08:00
Chris Robinson 3acc667c28 Scale delays when exceeding the max for generated mhr files 2020-02-10 22:25:07 -08:00
Chris Robinson 6ebdf3ab62 Use a triplet struct array instead of separate arrays 2020-02-09 14:25:20 -08:00
Chris Robinson f2bc24f761 Consistently use distant wavefronts for 0 distance 2020-02-08 22:39:32 -08:00
Chris Robinson 85395b23a4 Clear voice target gains earlier 2020-02-08 18:10:59 -08:00
Chris Robinson 3ee0906c81 Use std::array and span for the HRTF delays 2020-02-08 15:00:58 -08:00
kcat e72a02c5e2 Merge pull request #393 from Etwus/patch-1
Fix unreachable code warning
2020-02-08 15:00:26 -08:00
Aleš Gajdacz 7e319ad99b Fix unreachable code warning 2020-02-08 23:34:09 +01:00
Chris Robinson ebb1aaa06d Make sure stereo angles are kept in-range. 2020-01-31 11:11:06 -08:00
Chris Robinson e960276a47 Try harder to find the closest HRIR for the B-Format decoder 2020-01-26 01:23:39 -08:00
Chris Robinson bd7937e5b5 Update the default HRTF 2020-01-25 16:59:07 -08:00
Chris Robinson f63880c2ff Use the peak IR magnitude to get the onset
While maybe not technically correct, we actually only care about the difference
between onsets (any base constant is removed). This should work better since it
determines when the IR is most audible, whereas previously it used a variable
threshold of when it reached 15% of the max amplitude.

An even better method may be to check where the IR amplitude exceeds a fixed
threshold (i.e. the same threshold applied to all IRs), but that would need
tweaking to find a level that doesn't catch random noise and doesn't
potentially miss the more occluded IRs.
2020-01-25 16:59:07 -08:00
kcat 3cd4af1b8e Merge pull request #385 from sergeyext/fix_msvc_runtime
Set static MSVC runtime for cpp files when FORCE_STATIC_VCRT is ON.
2020-01-25 15:44:30 -08:00
Sergey Karchevsky 3001d56d4b Set static MSVC runtim for cpp files when FORCE_STATIC_VCRT is ON.
Fixes #384
2020-01-26 05:38:37 +07:00
Chris Robinson f5e0eef34d Release 1.20.1 2020-01-23 23:28:45 -08:00
Chris Robinson 43780913cd Fix the output channel count for the B-Format decoder 2020-01-19 13:40:39 -08:00
Chris Robinson 3904289af7 Only sort active effect slots as needed 2020-01-18 18:53:58 -08:00
Chris Robinson 8a9eef70af Use struct methods to get a buffer's format info 2020-01-18 13:23:59 -08:00
Chris Robinson 32c9dbd7ff Avoid an extraneous index map 2020-01-15 10:45:08 -08:00
Chris Robinson 6a8c6eae6f Make a couple helper methods to create BFormatDec 2020-01-15 10:33:56 -08:00
Chris Robinson fcfcb88b28 Repack B-Format decoder fields
This should better provide sequential access.
2020-01-15 10:09:41 -08:00
Chris Robinson c112acadaf Transpose BFormatDec's matrices
This allows the band-split and output mix to happen together, rather than
splitting all input channels first and then mixing them to output.
2020-01-14 23:08:04 -08:00
Chris Robinson 030d428aec Clean up some formating 2020-01-14 13:10:01 -08:00
Chris Robinson 75a58ae333 Simplify appending delayed samples 2020-01-14 12:13:00 -08:00
Chris Robinson 5324bdb908 Signal the event handler only once per update 2020-01-14 10:39:41 -08:00
Chris Robinson 400c768e2f Inline a couple ring buffer methods 2020-01-14 10:17:57 -08:00
Chris Robinson e889282131 Get rid of an unnecessary struct 2020-01-13 19:45:13 -08:00
Chris Robinson a1a107f576 Return immediately on error when loading HRTFs 2020-01-13 18:13:05 -08:00
Chris Robinson aca1d02024 Get the audio sync once per update in alffplay 2020-01-13 17:31:35 -08:00
Chris Robinson a56a6116c0 Make a separate function for duplicate code 2020-01-13 15:55:31 -08:00
Chris Robinson 174e48fe8f Use the Field and Elevation structs directly when loading 2020-01-13 14:23:11 -08:00
Chris Robinson bc946b004e Don't assume the total length of certain arrays 2020-01-13 10:59:15 -08:00
Chris Robinson 7551242143 Use a span for a fixed-size array reference 2020-01-13 08:55:10 -08:00
Chris Robinson a866aece46 Add missing include 2020-01-12 19:28:12 -08:00
Chris Robinson 2f1a2ce242 Scale the resampled HRTF delays if they exceed the max 2020-01-12 14:49:11 -08:00
Chris Robinson 00d80497d8 Warn when resampled HRIR delays get clamped 2020-01-12 11:24:30 -08:00
Chris Robinson c182a3376a Blend the whole IR for the interpolated HRIR
The SIMD mixers may use a few more elements beyond the irSize, so not limiting
the blend to that size can slightly improve the quality for resampled HRIRs.
2020-01-12 11:08:05 -08:00
Chris Robinson 711c05613e Update changelog 2020-01-12 10:52:55 -08:00
Chris Robinson af08f68448 Fix JACK process callback handling
The callback apparently can't be set after activation, but we can't allocate
the ring buffer until after activation when the callback is already getting
called. An ugly flag it is, then, I guess.
2020-01-12 07:48:11 -08:00
Chris Robinson 6f1c853397 Don't allocate the ring buffer for JACK before activation
It seems the JACK server can send buffer size change events during device reset
and wait on it, which causes a failure since the change event can't be
processed during a reset. It's otherwise impossible to safely disable the
change event callback during a reset since the lock is already held and the
callback can be waiting to acquire it. The only guarantee we seem to have is
the event callback won't be invoked after jack_activate succeeds.

So instead, the buffer size can be queried after jack_activate and the ring
buffer allocated then, instead of using an event callback. This does mean the
buffer size can change with a start() call, but it's better than a failure to
start.
2020-01-11 15:10:54 -08:00
Chris Robinson e6e2f509f8 Make CreateRingBuffer a static RingBuffer method 2020-01-10 07:56:43 -08:00
Chris Robinson b31886ad73 Fix blending for the right IR delay 2020-01-08 17:00:48 -08:00
Chris Robinson 82720a4b11 Update changelog 2020-01-08 09:10:06 -08:00
Chris Robinson 6608e5dd9f Make sure unassociated voices give back their update structs 2020-01-08 07:31:01 -08:00
Chris Robinson 45e82379a4 Make sure an unmixable source is properly stopped 2020-01-08 06:40:58 -08:00
Chris Robinson 84f65c1883 Avoid auto-releasing containers for the global device list
If any are left open at process shutdown, it may try to clean them up, and
subsequently close the device. This is dangerous to do at process exit, so
don't. The app should have closed the device(s) prior to exiting anyway
2020-01-07 03:12:49 -08:00
Chris Robinson 1a2438b09c Don't blend the B-Format decoder HRIRs
Though fine in theory, an issue arises with extra phase interference since the
frequency phases aren't aligned for each response. It would be better to do the
blending before minimum phase reconstruction, where it can blend just the
frequency magnitudes, essentially allowing makemhr to increase the resolution
of the dataset.
2020-01-07 00:40:38 -08:00
Chris Robinson 819763a6c2 Fix some 'ambiguous' calls for newer MSVC 2020-01-06 01:40:21 -08:00
Chris Robinson e9ee6dd239 Ensure a pointer is provided for a templated iterator type 2020-01-05 23:17:26 -08:00
Chris Robinson 8338d9e197 Use a loop instead of a series of lambda calls 2020-01-05 18:25:50 -08:00
Chris Robinson 54b49594e6 Simplify post-mix HRTF gain storage 2020-01-05 17:12:48 -08:00
Chris Robinson 05abcbc600 Update changelog wording 2020-01-05 15:44:50 -08:00
Chris Robinson ae780e22c1 Update the changelog 2020-01-05 04:02:18 -08:00
Chris Robinson 6ed8061cbf Finalize AL_SOFT_bformat_ex 2020-01-05 03:45:35 -08:00
Chris Robinson 0d0ea586b6 Use temporaries for repeated values 2020-01-05 03:38:19 -08:00
Chris Robinson cc9fa266e7 Avoid more duplicate arrays 2020-01-04 16:50:35 -08:00
Chris Robinson cdd24c7d01 Combine identical arrays 2020-01-04 00:59:49 -08:00
Chris Robinson 462bcd4ab7 Use a span instead of an array+size 2020-01-04 00:37:59 -08:00
Chris Robinson a42a586f0f Avoid a duplicate array 2020-01-04 00:04:55 -08:00
Chris Robinson 8b3a1ed9e4 Use an array type for the HRIR delay pair 2019-12-30 21:04:10 -08:00
Chris Robinson cfc8a82951 Load the HRIRs directly into HrirArrays 2019-12-30 20:49:19 -08:00
Chris Robinson d9e3f0edf6 Avoid declaring a variable early 2019-12-30 19:17:33 -08:00
Chris Robinson 28d2294b07 Workaround for MSVC 2015 2019-12-29 21:49:29 -08:00
Chris Robinson 9fc2f8541b Don't hardcode the system paths for searching frameworks 2019-12-29 21:03:28 -08:00
Chris Robinson c1cf10f508 Handle downmixing for mono output 2019-12-29 20:35:47 -08:00
Chris Robinson 9ac8f25a05 Ignore direct channels for mono and B-Format buffers 2019-12-29 19:17:29 -08:00
Chris Robinson 137394c2cf Make the new direct channel remix extension public 2019-12-28 16:40:10 -08:00
Chris Robinson 701d43b41e Start a new extension for a new direct_channels state
So existing behavior remains consistent for anything that needs it, and new
behavior is opt-in.
2019-12-28 11:33:19 -08:00
Chris Robinson 3b3d3d3a03 Use a span for the band-splitter input 2019-12-25 21:48:58 -08:00
Chris Robinson 06b7c63cef Fix reverse iterators for spans 2019-12-25 21:48:40 -08:00
Chris Robinson f153def941 Pass a span for the biquad filter input 2019-12-25 18:39:22 -08:00
Chris Robinson 36c745a514 Fix parameter order 2019-12-25 18:32:53 -08:00
Chris Robinson 0897927419 Make a couple more functions private 2019-12-25 17:09:14 -08:00
Chris Robinson de2c64c06f Pass a span to the NFC filters 2019-12-24 23:41:26 -08:00
Chris Robinson 04b8f2a042 Reorganize some function parameters 2019-12-24 23:36:08 -08:00
Chris Robinson 28e68d03d3 Fix a shadowed parameter warning 2019-12-23 23:13:45 -08:00
Chris Robinson bff6696814 Avoid reading a struct field twice 2019-12-23 23:00:59 -08:00
Chris Robinson 16220be86e Make a duration type to handle WASAPI reference times 2019-12-22 22:05:47 -08:00
Chris Robinson 8807d373b0 Print the unhandled subformat 2019-12-22 16:38:52 -08:00
Chris Robinson a671c02b0b Try harder to find a matching WASAPI configuration
As long as the lowest channel bits match the enabled bits for a given
configuration, higher bits from any extra channels can be ignored since they
can be skipped.
2019-12-22 02:52:50 -08:00
Chris Robinson 2e6a55a87c Handle padding between device sample frames
The padding must be constant and sample type aligned (e.g. some fixed multiple
of two bytes between the start of two consecutive frames for 16-bit output).
The intent is to always have the ability for stereo output with WASAPI even if
the device has some other unsupported configuration, as long as front-left and
front-right exist.
2019-12-21 20:43:46 -08:00
Chris Robinson c2ca617ed6 Use size_t for the compressor channel count
And general cleanup of the compressor
2019-12-21 03:21:13 -08:00
Chris Robinson 54e7f48df9 Use unique setters for biquad filter parameters
One for whether a slope parameter is used, and one for bandwidth.
2019-12-21 02:02:57 -08:00
Chris Robinson 274fd36edd Improve gain/hf/lf packing when processing voice updates 2019-12-21 00:48:58 -08:00
Chris Robinson 22bbb14a65 Use a standard bool type 2019-12-19 05:16:56 -08:00
Chris Robinson 4634002104 Remix missing channels with direct channels enabled
Instead of dropping them.
2019-12-19 04:38:34 -08:00
Chris Robinson 6480c2c854 Don't apply direct channels with mono output 2019-12-18 23:29:52 -08:00
Chris Robinson 5e35f73cad Don't process direct channel sources with attenuation 2019-12-17 22:40:49 -08:00
Chris Robinson a8de1570e9 Update a comment since B-Format input isn't always FuMa 2019-12-17 22:25:00 -08:00
Chris Robinson 466c6faeb5 Correctly scale spatialized B-Format sources 2019-12-17 22:20:38 -08:00
Chris Robinson 0a65ed2190 Use normal panning for B-Format output
It can never work since it only uses auxiliary channel labels.
2019-12-17 22:12:47 -08:00
Chris Robinson 2215a4072c Don't apply stereo panning with direct channels enabled 2019-12-17 21:49:58 -08:00
Chris Robinson ad9584acc3 Avoid sscanf for parsing config lines 2019-12-14 17:26:58 -08:00
Chris Robinson ac7a5dcbfa Use size_t for array indices 2019-12-11 02:44:05 -08:00
Chris Robinson 053de62398 Don't force the HRIR length to a rounded value
The coefficient and accumulation buffers are guaranteed large enough for the
full size, and the SIMD handlers will behave the same either way.
2019-12-11 02:24:44 -08:00
Chris Robinson 7d0c01050a Fix MHR limits 2019-12-11 01:20:00 -08:00
Chris Robinson 4867f93a34 Move duplicate SOFA-related functions to a reusable library 2019-12-11 00:49:57 -08:00
Chris Robinson ae916929c9 Simplify a status-checking loop 2019-12-10 20:11:11 -08:00
Chris Robinson 47f416efaf Simplify a couple assignments 2019-12-09 23:11:16 -08:00
Chris Robinson d6bc56d7c1 Use proper array types instead of C-style arrays 2019-12-09 20:55:54 -08:00
Chris Robinson a1de05fed7 Avoid global macros for format-secific types 2019-12-09 20:45:11 -08:00
Chris Robinson e43c2bba61 Don't re-sort the enumerated HRTF list 2019-12-08 22:09:21 -08:00
Chris Robinson 0afb5a2ab9 Update the default HRTF 2019-12-08 19:29:50 -08:00
Chris Robinson f4b3c3b4da Simplify a check 2019-12-08 19:23:16 -08:00
Chris Robinson 7ded42cb94 Load SOFA HRIRs in a background thread 2019-12-08 19:17:58 -08:00
Chris Robinson 5942974d47 Report the non-uniform elevations in sofa-info 2019-12-08 17:56:56 -08:00
Chris Robinson 8076fd8aa9 Report the number of IRs used from SOFA files 2019-12-08 17:01:34 -08:00
Chris Robinson a280373dc1 Improve blended IR delay precision for the B-Format decoder 2019-12-08 16:46:11 -08:00
Chris Robinson 8cb0e0a58b Simplify some parameters 2019-12-08 13:37:42 -08:00
Chris Robinson 1dc26f305a Improve detection of compatible layouts in SOFA files 2019-12-08 03:36:27 -08:00
Chris Robinson 3f559e7e60 Rename a couple structs for clarity 2019-12-06 23:11:26 -08:00
Chris Robinson c9a6527121 Use doubles for blending the B-Format decoder HRIRs 2019-12-06 22:31:30 -08:00
Chris Robinson 200b07b288 Fully reset the voice when updating the device 2019-12-05 00:18:59 -08:00
Chris Robinson 863171efc9 Check the voice's ambisonic order when starting 2019-12-05 00:18:01 -08:00
Chris Robinson bbe1c4c64e Test the B-Format buffer extension in alffplay 2019-12-02 13:04:44 -08:00
Chris Robinson 38037e29ba Handle the buffer's ambisonic properties 2019-12-02 12:50:18 -08:00
Chris Robinson 799c60f3bb Add an interface to set a B-Format buffer's layout and scaling 2019-12-02 11:51:27 -08:00
Chris Robinson 58e4d643d3 Make B-Format rotation more robust
This should now handle higher orders, and can be easily extended to non-FuMa
layouts and scalings.
2019-12-01 22:33:41 -08:00
Chris Robinson 1a51e3a9d1 Add an index map for 2D FuMa channels 2019-12-01 17:52:36 -08:00
Chris Robinson b79aa32308 Store the ambisonic order for the voice
Currently only first-order B-Format is possible for a buffer/source, but this
will begin to allow for higher orders with an appropriate extension.
2019-12-01 15:36:25 -08:00
Chris Robinson 9559f7bfc2 Update the second-order decoder for HRTF
This uses fewer virtual speakers to help with clarity. The fewer speakers used
for the response, the less destructive phase interference there should be.
2019-11-30 18:42:04 -08:00
Chris Robinson fcf03705e6 Clear the resampler after use 2019-11-29 18:19:01 -08:00
Chris Robinson 1a4a3764d1 Update built-in HRTF name for alsoft-config 2019-11-29 14:54:29 -08:00
Chris Robinson a8d06c0731 Store HRTF delays with some fractional precision
Since the delays get bilinearly filtered before use, maintaining a bit of extra
precision can help accuracy even if it ultimately gets rounded to the nearest
integer before use. This should help with resampled HRTFs, which need to scale
the delays that are already rounded, and can also be leveraged by an updated
MHR format.
2019-11-29 14:01:39 -08:00
Chris Robinson 2453f4ec14 Avoid a shadow declaration warning 2019-11-29 08:41:20 -08:00
Chris Robinson 7ff165b095 Use unsigned for array indices 2019-11-29 08:33:46 -08:00
Chris Robinson 34edd3a914 Fix sorting of loaded HRTFs 2019-11-29 06:19:06 -08:00
Chris Robinson 7b3f88c430 Avoid extraneous looping 2019-11-29 05:52:33 -08:00
Chris Robinson e80256e394 Remove an unnecessary alias 2019-11-28 16:17:00 -08:00
Chris Robinson b310e09f59 Rename the default HRTF 2019-11-28 15:48:07 -08:00
Chris Robinson 6069eef94d Also scale the HRTF delays for different rates 2019-11-28 14:53:13 -08:00
Chris Robinson 846a997956 Add an option to limit the HRTF's IR size 2019-11-28 14:51:45 -08:00
Chris Robinson 4eb9a0b835 Don't keep a resampled default HRTF 2019-11-28 12:57:42 -08:00
Chris Robinson f6105cbff0 Resample HRIRs when loading 2019-11-28 12:33:26 -08:00
Chris Robinson c093728ced Move the polyphase resampler to the common lib 2019-11-28 10:54:47 -08:00
Chris Robinson 576adf06b1 Store HRIR coefficients using HrirArray 2019-11-28 09:46:16 -08:00
Chris Robinson 925e6e979c Rework HRTF enuemration so the loaded HRTFs are separate 2019-11-28 08:24:29 -08:00
Chris Robinson 1e93fba6d0 Rename HrtfEntry to HrtfStore 2019-11-28 06:10:36 -08:00
Chris Robinson c0cf323e1d Release 1.20.0 2019-11-28 00:45:08 -08:00
Chris Robinson 39e3484dbe Update ChangeLog 2019-11-22 22:47:36 -08:00
Chris Robinson eb8922596a Apply the full HRIR length for the B-Format decoder 2019-11-21 23:55:10 -08:00
Chris Robinson 2fd8c619b3 Rename a couple struct fields 2019-11-21 02:58:35 -08:00
Chris Robinson 7bc4a27900 Allocate storage for full HRTF coefficient lengths 2019-11-21 02:43:34 -08:00
Chris Robinson f2eab3e919 Properly get the AppData path on Windows in alsoft-config 2019-11-20 14:22:04 -08:00
Chris Robinson 6159b837cf Add a first-order ambisonic decoder for HRTF 2019-11-18 00:32:01 -08:00
Chris Robinson c86a28af5c Simplify some pi statements 2019-11-16 14:33:09 -08:00
Chris Robinson 6ad252efda Use wrappers to distinguish elevation and azimuth values 2019-11-16 14:07:31 -08:00
Chris Robinson d120e1464f Improve precision of the HRTF ambisonic decoder matrix 2019-11-13 08:39:27 -08:00
Chris Robinson 0ad512dd51 Clear the whole response HRIR before blending 2019-11-10 21:56:19 -08:00
Chris Robinson 74cbba511d Limit HRTF ambisonic decoding to second-order
The generated third-order matrix has incorrect first-order coefficients,
indicating a wonky decoder. The generated second-order matrix looks more
stable.
2019-11-09 13:04:44 -08:00
kcat 89938b95cf Merge pull request #356 from Raulshc/modulator_fix
EFX: Modulator fix
2019-11-09 06:58:29 -08:00
Raulshc c5f88ab59f EFX: Add explicit cast to a square function
MSVC 2015 and above returns the expression according to its datatype.
In this case, returns 4294967295 instead of -1.
2019-11-09 12:12:53 +01:00
Chris Robinson d2608e4bde Avoid holding HRTF accumulation samples per-source
It notably simplifies things to mix HRTF sources into an accumulation buffer
together, which the Dry buffer's Ambisonic-to-HRTF decode is then added to,
before being mixed to the Real output.
2019-11-03 00:30:33 -07:00
Chris Robinson 2741a94e58 Use rotate to reorder the default list entry 2019-10-28 23:47:30 -07:00
Chris Robinson d37a294d4c Add a config option for custom ALSA capture devices 2019-10-27 19:20:26 -07:00
Chris Robinson 205ff0080e Adjust padding in alsoft-config and remove an invalid signal 2019-10-27 18:02:25 -07:00
Chris Robinson 101afb1ee4 Convert HRTF field distances to meters when creating storage 2019-10-27 15:50:59 -07:00
Chris Robinson 697da8724f Avoid an extraneous macro and use a simplified type alias 2019-10-27 00:47:33 -07:00
Chris Robinson cac4072781 Change a few more really small gain values to 0 2019-10-26 19:57:17 -07:00
Chris Robinson 0cba99ed1b Avoid static constexpr for arrays iterated over at run-time 2019-10-25 01:43:23 -07:00
Chris Robinson 5ac1f19241 Don't dereference the end iterator 2019-10-24 21:58:35 -07:00
Chris Robinson 48347f62b5 Don't trace twice for a new HRTF data file 2019-10-24 15:28:28 -07:00
Chris Robinson f0977e5cc9 Print the found file entries after sorting 2019-10-24 15:10:37 -07:00
Chris Robinson 7bed2fe7cc Report the real ambisonic order set for HRTF rendering 2019-10-24 14:33:43 -07:00
Chris Robinson f40e69f9e3 Use a 26-point Lebedev grid for the HRTF ambisonic decode 2019-10-23 23:36:02 -07:00
Chris Robinson 0dfdebdf6d Limit the number of azimuths and elevations used in SOFA files 2019-10-22 16:30:07 -07:00
Chris Robinson 4733fc6f1e Fix azimuth limit 2019-10-22 15:23:17 -07:00
Chris Robinson a8a3acb6f6 More consistently use doubles in makemhr and loadsofa 2019-10-22 15:22:37 -07:00
Chris Robinson fcde56e1fc Increase the max elevation and azimuth count for HRTFs 2019-10-21 11:30:39 -07:00
Chris Robinson f58167e72d More sanely handle the voice state when mixing 2019-10-14 20:45:23 -07:00
Chris Robinson 33fd1f9efd Use better types for some specific sizes 2019-10-13 09:37:07 -07:00
Chris Robinson e70f98c95a Wrap the cycle amount when passing to sin() 2019-10-12 16:41:13 -07:00
Chris Robinson 630d4d573d Gracefully drain the OpenSL capture buffer on disconnect 2019-10-10 13:33:27 -07:00
Chris Robinson d2053e6784 Use one PulseAudio mainloop per device
To help avoid devices blocking on each other when handling asynchronous
messages.
2019-10-09 23:25:56 -07:00
Chris Robinson 8bf3da0cd2 Remove a useless prebuf check with PulseAudio 2019-10-09 09:45:02 -07:00
Chris Robinson 57cdac3368 Create the initial PulseAudio stream corked 2019-10-09 09:42:35 -07:00
Chris Robinson 404f3e2d08 Don't track the PulseAudio context state in devices 2019-10-09 05:01:30 -07:00
Chris Robinson b687e952ef Make C callbacks noexcept
No telling what would happen if exceptions managed to get back into presumably
C-based callers.
2019-10-09 03:29:25 -07:00
Chris Robinson a7c1245360 Use smart pointers for ALSA param handles
And simplify some related error handling
2019-10-09 02:16:08 -07:00
Chris Robinson 2842df5a02 Catch exceptions from backend start calls 2019-10-09 00:11:19 -07:00
Chris Robinson 963580c2d5 Never return null from CreateRingBuffer
Allocation failure would already throw a bad_alloc anyway, now a size overflow
throws an exception too.
2019-10-08 21:55:03 -07:00
Chris Robinson 7726a06d26 Clean up some exception messages and avoid duplicate log messages 2019-10-08 05:44:38 -07:00
Chris Robinson 360330b2ad Define some simple wrapper methods inline 2019-10-08 03:41:49 -07:00
Chris Robinson f4bc3d7ab2 Improve logging for Windows 2019-10-08 00:21:21 -07:00
Chris Robinson 52a003e9bb Avoid raw lock/unlock calls 2019-10-07 23:22:06 -07:00
Chris Robinson f0fa6c6baf Fix BackendVase typo 2019-10-07 22:42:54 -07:00
Chris Robinson 9b411cfcbe Reduce some indentation 2019-10-07 22:25:45 -07:00
Chris Robinson 02d80cd74d Use exceptions for backend open failures 2019-10-07 21:37:56 -07:00
Chris Robinson f8ff4e269b Put the pragma defines in a separate header 2019-10-07 15:26:35 -07:00
Chris Robinson f52eed0607 Update some wording in the changelog 2019-10-07 05:01:05 -07:00
Chris Robinson acb6baad90 Use std::array instead of plain arrays in a couple places 2019-10-05 21:23:31 -07:00
Chris Robinson eb89faf963 Use a span instead of a reference-to-array 2019-10-05 20:00:22 -07:00
Chris Robinson 267b79f337 Avoid duplicate structs 2019-10-05 16:11:38 -07:00
Chris Robinson 1bb93f4fc2 Avoid direct function template and alias types
It's somewhat ambiguous what they mean. Sometimes acting as a pointer, other
times having weird behavior. Pointer-to-function types are explicitly defined
as such, whereas uses of these tend to be as references (never null and not
changeable).
2019-10-03 04:22:39 -07:00
Chris Robinson b350ae3766 Remove the Offset parameter from ApplyCoeffs 2019-10-02 22:38:19 -07:00
Chris Robinson bce6889173 Remove an unnecessary struct specifier 2019-10-02 22:20:34 -07:00
Chris Robinson 324fb8d0b7 Fix a comment 2019-10-02 19:22:14 -07:00
Chris Robinson 58085f1c7b Clean up some unnecessary includes 2019-10-02 19:13:07 -07:00
Chris Robinson 50198ee30c Clean up some ALfloat -> float 2019-10-02 17:07:23 -07:00
Chris Robinson 64e2c377d8 Move ALvoice from alu.h to a separate header 2019-10-02 16:53:23 -07:00
Chris Robinson d639935e19 Move a couple types to the source they're used in 2019-10-02 15:37:33 -07:00
Chris Robinson a35cac7ce0 Rename mixvoice.cpp to voice.cpp 2019-10-02 15:29:01 -07:00
Chris Robinson 4620912f0f Don't inline the utf8 converters 2019-10-01 23:33:00 -07:00
Chris Robinson 2980adb8c0 Make sure the temporary HRIRs are properly aligned 2019-10-01 22:50:28 -07:00
Chris Robinson 69eb685dbc Check for librt earlier 2019-10-01 22:35:33 -07:00
Chris Robinson accac7950c Silence some warnings from GCC in the router 2019-10-01 22:22:46 -07:00
Chris Robinson 28d54efe72 Use al::getenv to get the router env vars 2019-10-01 22:15:40 -07:00
Chris Robinson a0a55d300f Remove an unnecessary function 2019-10-01 21:45:44 -07:00
Chris Robinson e2c1602ede Link the examples with librt if it exists 2019-10-01 19:56:39 -07:00
Chris Robinson 0063f4bfac Add some allocator fields GCC 6.3 seems to want 2019-10-01 01:49:21 -07:00
Chris Robinson 8f6fafd19a Update the changelog 2019-09-30 22:23:14 -07:00
Chris Robinson 5d7a1fa6da Clear the HRTF state values on allocation 2019-09-30 19:29:01 -07:00
Chris Robinson 4d127a2f98 Avoid infs/nans in the crest detector
It needs to be investigated why the rendered mix sometimes has such large
sample values when starting, but the compressor/limiter shouldn't generate NaNs
because of it.
2019-09-30 17:29:04 -07:00
Chris Robinson cf617760b6 Separate a couple assignments from conditionals 2019-09-30 03:03:27 -07:00
Chris Robinson 0139d8a04f Remove noexcept from a function that explicitly throws 2019-09-30 02:57:19 -07:00
Chris Robinson c833af9ecd Repack the bsinc resamplers coefficients
This puts the base coefficients and the phase deltas next to each other. This
improves caching, as the base and phase deltas are always used together while
the scales are only used for the non-fast versions.
2019-09-29 23:39:04 -07:00
Chris Robinson fb56b02041 Modify the bsinc resampler
Readjusted the bsinc12 cutoff back to -60dB. Also increased the filter's phase
count.
2019-09-29 22:43:46 -07:00
Chris Robinson 94ff2daafc Use using to avoid extraneous template instantiations 2019-09-29 16:02:25 -07:00
Chris Robinson fabb9add9b Silence an MSVC warning 2019-09-28 23:31:49 -07:00
Chris Robinson 00250042c8 Check MAX_RESAMPLER_PADDING properly to ensure it's large enough 2019-09-28 19:14:27 -07:00
Chris Robinson 7783fa738c Make the BSincTables constexpr in an anonymous namespace 2019-09-28 16:40:38 -07:00
Chris Robinson 4b746b8d37 Make MAX_RESAMPLER_PADDING specify the total padding 2019-09-28 14:35:42 -07:00
Chris Robinson 31ffb0887c Don't let a function end without a return 2019-09-28 13:56:51 -07:00
Chris Robinson 2d2e5539c0 Use FastBSinc24 for WASAPI and CoreAudio capture
Given a fixed rate, there's no downside to the fast version.
2019-09-28 03:44:13 -07:00
Chris Robinson cbc00bcffe Combine two function calls into one 2019-09-28 03:42:17 -07:00
Chris Robinson f7b574c8f2 Redo resampler strings to be safer
Now the name is guaranteed to match the type, and to be ordered as the enum
declares.
2019-09-28 03:15:48 -07:00
Chris Robinson 882b4acae8 Add "fast" variants for the bsinc resamplers
This simply omits the scale factor from the filter, similar to how up-sampling
does. The consequence of this is less smooth transitions when ramping the
pitch while down-sampling, but otherwise behaves fine.
2019-09-28 01:58:29 -07:00
Chris Robinson 00d5356b96 Remove the unnecessary FRACTIONONE from bsincgen 2019-09-28 00:01:21 -07:00
Chris Robinson 9b64e5e0db Implement a "fast" bsinc path
This takes advantage of the fact than when increment <= 1 (when not down-
sampling), the scale factor is always 0. As a result, the scale and scale-phase
deltas never contribute to the filtered output. Removing those multiply+add
operations cuts half of the work done by the inner loop.

Sounds that do need to down-sample (when played with a high pitch, or is 48khz
on 44.1khz output, for example), still go through the normal bsinc process.
2019-09-26 19:24:29 -07:00
Chris Robinson d50ca464cd Use a span for holding the source handles 2019-09-25 03:01:58 -07:00
Chris Robinson f009219523 Avoid extraneous parameters 2019-09-25 02:11:37 -07:00
Chris Robinson 5bb91b858f Use blended HRIRs for the B-Format decode 2019-09-24 22:27:12 -07:00
Chris Robinson 16a715a2b5 Fix unsigned 8-bit buffers 2019-09-24 21:49:12 -07:00
Chris Robinson 6963712d46 Use an array to match the HRTF rendering method 2019-09-24 13:51:40 -07:00
Chris Robinson 96865d6b99 Only build ex-common as needed 2019-09-24 01:16:57 -07:00
Chris Robinson bf31ce688a Add a missing header for Android 2019-09-23 19:23:33 -07:00
Chris Robinson e01b32f8e0 Use istream for makemhr input 2019-09-23 18:37:36 -07:00
Chris Robinson 34a0fad6cd Use a unique_ptr to auto-free MYSOFA_HRTF 2019-09-23 17:38:43 -07:00
Chris Robinson 4a111f7671 Update changelog 2019-09-22 21:27:59 -07:00
Chris Robinson 61ffa23e44 Fix a couple more conversion warnings 2019-09-22 21:27:10 -07:00
Chris Robinson 24db8a3f4b Make the resampler type an enum class 2019-09-22 21:19:19 -07:00
Chris Robinson 95996effaf Move the ifstream wrapper to common 2019-09-22 12:23:41 -07:00
Chris Robinson 9c95f62e95 Remove large file macros
Large file offsets aren't being utilized, and C++ seems to use to 64-bit
offsets anyway.
2019-09-22 11:17:31 -07:00
Chris Robinson 5f6a35c960 Avoid storing an integer in a pointer
C++ does not guarantee that, given an int of sufficient size, converting
int->ptr->int will result in the original value. A pointer may have more than
one integer representation. Only ptr->int->ptr round trips are well-defined.
2019-09-21 23:35:24 -07:00
Chris Robinson 9325f1d507 Split some code into separate functions 2019-09-21 21:14:11 -07:00
Chris Robinson 9993ea818c Restructure the changelog updates 2019-09-21 19:46:19 -07:00
Chris Robinson 564c953e94 Make the buffer frequency unsigned 2019-09-21 16:47:33 -07:00
Chris Robinson 146afcbd70 Explicitly mark a couple functions as inline 2019-09-21 16:12:48 -07:00
Chris Robinson c83055ff53 Initial update for the changelog 2019-09-21 15:49:18 -07:00
Chris Robinson 28e62456ac Use an array and loop instead of individual tests 2019-09-21 12:08:45 -07:00
Chris Robinson 8907a4fb04 Cleanup some router warnings 2019-09-20 15:45:59 -07:00
Chris Robinson a0a8af47ae Include VS2017 in AppVeyor builds 2019-09-20 14:56:21 -07:00
Chris Robinson 2ae1f8b8b6 Revert "Silence some unreachable code warnings on MSVC"
This reverts commit 2ab4883439.

It apparently didn't work at silencing anything.
2019-09-20 14:40:12 -07:00
Chris Robinson 2ab4883439 Silence some unreachable code warnings on MSVC 2019-09-20 14:25:06 -07:00
Chris Robinson 65eb0987e2 Remove and simplify some functions 2019-09-20 13:35:29 -07:00
Chris Robinson 79a621ac47 Simplify some REQUIRES uses 2019-09-20 10:59:12 -07:00
Chris Robinson b9daffe159 Don't clean up more than necessary on destruction 2019-09-20 10:58:29 -07:00
Chris Robinson 057b253adb Use an anonymous namespace instead of static 2019-09-19 21:01:10 -07:00
Chris Robinson c0678816fc Remove deprecated CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS 2019-09-19 18:50:45 -07:00
Chris Robinson ffb5623ead Fix a couple more annoying conversion warnings 2019-09-18 20:13:58 -07:00
Chris Robinson a092624ed3 Fix some Windows warnings 2019-09-18 18:20:11 -07:00
Chris Robinson 9a0a5c79d8 Avoid hiding a class member function 2019-09-18 17:02:33 -07:00
Chris Robinson 24a1058952 Work around MSVC's lack of standard _Pragma support 2019-09-18 13:58:04 -07:00
Chris Robinson b8f64155e9 Silence a couple specific warning instances 2019-09-18 13:24:16 -07:00
Chris Robinson 66565ca7a3 Enable and fix some more warnings 2019-09-18 10:09:04 -07:00
Chris Robinson da80a7c2b2 Disable warnings 4268 and 4324 on MSVC
warning C4268: 'const' static/global data initialized with compiler generated
default constructor fills the object with zeros

warning C4324: structure was padded due to alignment specifier
2019-09-18 09:31:32 -07:00
Chris Robinson ab87e56b22 Enable some more MSVC warnings 2019-09-18 09:01:46 -07:00
Chris Robinson dffb874478 Some cleanup for CMakeLists.txt 2019-09-18 08:58:36 -07:00
Chris Robinson aca9f4e095 Make the bsinc l and m coefficients unsigned 2019-09-17 18:38:46 -07:00
Chris Robinson 1da7512628 Avoid an unnecessary multiply 2019-09-16 21:49:06 -07:00
Chris Robinson 62972babea Remove unnecessary long long checks 2019-09-16 18:10:01 -07:00
Chris Robinson 6398bd8373 Add preprocessor defines for the common lib 2019-09-16 15:57:05 -07:00
Chris Robinson b00128411f Add a missing include directory for the common lib 2019-09-16 15:45:20 -07:00
Chris Robinson 899a414591 Remove the last uses of the system's str[n]casecmp 2019-09-16 15:10:36 -07:00
Chris Robinson 6d93b2ba81 Use our case-insensitive compare functions in makemhr 2019-09-16 14:55:52 -07:00
Chris Robinson 7a9463f863 Make the common code a separate static library 2019-09-16 14:46:41 -07:00
Chris Robinson 10a841cd7e Avoid an unused variable 2019-09-16 14:10:48 -07:00
Chris Robinson 2c5c5a5397 Add and use custom string types and functions 2019-09-16 13:45:14 -07:00
Chris Robinson 650764775f Fix typo 2019-09-16 07:50:39 -07:00
Chris Robinson fcf850c1dd Clean up some more conversion warnings 2019-09-16 07:32:13 -07:00
Chris Robinson bf2c865d39 Clean up some more shadowing warnings 2019-09-16 07:16:31 -07:00
Chris Robinson e16e2269b6 Add a fallback if SLAndroidDataFormat_PCM_EX isn't available 2019-09-15 20:46:37 -07:00
Chris Robinson 35129d66b7 Clean up the spaghetti mess in alcCaptureSamples 2019-09-15 13:42:56 -07:00
Chris Robinson a999df8ce5 Rename ALautowah* for consistency 2019-09-15 12:58:58 -07:00
Chris Robinson 47f0d301dc Make the BackendFactory base destructor protected 2019-09-15 10:22:56 -07:00
Chris Robinson c5a3c52822 Return and pass more appropriate types for backends 2019-09-15 09:50:28 -07:00
Chris Robinson e4cc77ea23 Fix a few warnings from MSVC 2019-09-14 20:19:59 -07:00
Chris Robinson 4b8f78a8d6 Fix a few more GCC warnings 2019-09-14 19:42:54 -07:00
Chris Robinson e82c43fb38 Fix a copy-paste error 2019-09-14 19:07:30 -07:00
Chris Robinson b43cd047ba Build with -Wunused 2019-09-14 18:54:16 -07:00
Chris Robinson b212ab9ea2 Add a note about clearing complex_hilbert's imaginary input 2019-09-14 18:37:00 -07:00
Chris Robinson 807d3b64ca Enable and fix more warnings 2019-09-14 18:35:23 -07:00
Chris Robinson 2cc0600476 Avoid recalculations in the formant filter process 2019-09-14 18:35:23 -07:00
Chris Robinson d75de6ee4d Don't hold the pulse lock while not necessary 2019-09-14 18:35:23 -07:00
Chris Robinson 2c348cecb6 Fix some more implicit conversions noted by GCC 2019-09-14 18:35:23 -07:00
kcat 1c45b1791b Merge pull request #344 from Lopuska/patch-3
removed unnecessary loop
2019-09-14 18:34:53 -07:00
kcat 6644a660e8 Merge pull request #342 from Lopuska/patch-1
pass proper effects slot number to AddActiveEffectSlots
2019-09-14 18:29:48 -07:00
Lopuska 925894fb8b removed unnecessary loop
the caller in fshifter is already doing the same job by putting 0 for the imaginary part
2019-09-15 02:58:53 +02:00
Lopuska 0023614da5 pass proper effects slot number to AddActiveEffectSlots
It resolves wrong logic when creating more than 1 aux slot at time in a batch
2019-09-15 02:09:05 +02:00
Chris Robinson 4e8caea97e Enable -Wconversion warnings
This is now clean with Clang 7, let's see what other compilers give.
2019-09-14 12:50:44 -07:00
Chris Robinson 532197a650 Clean up (most) implicit conversions in the backends 2019-09-14 12:44:35 -07:00
Chris Robinson fa64b1fd6d Fix implicit conversions in the effects 2019-09-14 12:16:51 -07:00
Chris Robinson 3675dfcfef Use an unsigned index value 2019-09-14 08:50:07 -07:00
Chris Robinson 88364dcbc7 Fix more implicit conversions 2019-09-14 08:29:02 -07:00
Chris Robinson 2646f509ee Store the ambisonic order as unsigned 2019-09-13 20:04:22 -07:00
Chris Robinson 42ae95b8fa Remove a couple no-op statements 2019-09-13 14:44:52 -07:00
Chris Robinson a250b6a986 Return unsigned values from the FromDevFmt functions 2019-09-13 14:29:25 -07:00
Chris Robinson fcd3bed0c0 Clean up more implicit conversions 2019-09-13 12:51:16 -07:00
Chris Robinson f09734b707 Pass IrSize to the HRTF mixers as unsigned 2019-09-13 11:19:11 -07:00
Chris Robinson 4254888576 Make IrSize unsigned 2019-09-13 09:38:35 -07:00
Chris Robinson df306b5524 Make NumAuxSends unsigned 2019-09-13 04:15:05 -07:00
Chris Robinson 5b763e1437 Clean up implicit conversions in alu.cpp 2019-09-13 03:47:23 -07:00
Chris Robinson c1690178ec Make the resampler increment unsigned 2019-09-13 03:25:13 -07:00
Chris Robinson 5f862a5b49 Clean up sample converter implicit conversions 2019-09-12 17:45:06 -07:00
Chris Robinson 5ca8796d6a Clean up some lambda definitions 2019-09-12 17:10:33 -07:00
Chris Robinson 70b58d79fe Fix source limit check 2019-09-12 12:19:07 -07:00
Chris Robinson 6ca8fadd58 Fix counting free objects 2019-09-12 12:14:23 -07:00
Chris Robinson ac48569c69 Avoid a macro call and mark unlikely paths as unlikely 2019-09-12 11:59:36 -07:00
Chris Robinson 2e010d29cb Clean up implicit conversions in source.cpp 2019-09-12 11:33:04 -07:00
Chris Robinson c0ce03d8b9 Get rid of more implicit conversions 2019-09-12 06:29:32 -07:00
Chris Robinson b71eb4dafd Don't use [[nodiscard]] in C++11
To silence some warnings in older compilers, and fix an error with newer MSVC.
2019-09-12 04:30:52 -07:00
Chris Robinson 6699f3cf1c Use unsigned channel indices 2019-09-12 04:17:21 -07:00
Chris Robinson 4c76f32dda Avoid implicit conversions with the examples and utils 2019-09-12 03:22:34 -07:00
Chris Robinson 474d478854 Only pass -Wold-style-cast for C++ 2019-09-11 15:55:37 -07:00
Chris Robinson 07e2aa3bc0 Clean up some more implicit conversions 2019-09-11 14:33:26 -07:00
Chris Robinson 681c78d348 Allocate buffer batches separately from buffers 2019-09-11 12:28:33 -07:00
Chris Robinson 1a9f1e0869 Fix a few more C-style casts 2019-09-11 08:08:23 -07:00
Chris Robinson 14c76ca244 Fix allocator comparison operators 2019-09-11 07:32:14 -07:00
Chris Robinson a895709b6f Fix function declaration 2019-09-11 06:58:27 -07:00
Chris Robinson be0442c620 Avoid C-style casts in C++ 2019-09-11 06:47:56 -07:00
Chris Robinson 388928f3aa Fix some more implicit casts 2019-09-11 05:53:10 -07:00
Chris Robinson e4b15aeefc Fix some implicit casts 2019-09-11 04:55:54 -07:00
Chris Robinson 5b37e2339b Simplify flexible array member usage 2019-09-11 03:59:53 -07:00
Chris Robinson c6c5048416 Don't inherit for the allocator 2019-09-11 03:22:10 -07:00
Chris Robinson 65374dc5d0 Avoid dynamically allocating ChannelConverter 2019-09-10 23:01:33 -07:00
Chris Robinson 19e1cd7430 Make hq-mode the default and update ambisonics.txt 2019-09-08 01:38:20 -07:00
Chris Robinson 449c09bf03 Remove mention of an unsupported env var 2019-09-08 00:59:56 -07:00
Chris Robinson ec8b56ef3b Remove unneeded TRACEREF logging 2019-09-08 00:59:10 -07:00
Chris Robinson fcb496bb5c Avoid unnecessary explicit copy methods 2019-09-08 00:31:55 -07:00
Chris Robinson 987fd13796 Use a new voice when restarting a playing source 2019-09-06 21:20:20 -07:00
Chris Robinson e5c9643dd5 Combine two functions into one 2019-09-05 15:08:22 -07:00
Chris Robinson 97c043da07 Don't set voice properties in ApplyOffset 2019-09-05 04:00:49 -07:00
Chris Robinson ef2769af03 Use a normal vector for the voices array 2019-09-04 23:04:55 -07:00
Chris Robinson c47a6d2279 Increment the mix count during disconnect
So attempts to get the current playback offset behave correctly while
disconnecting.
2019-09-04 20:31:55 -07:00
Chris Robinson e873165019 Only ASSUME values where a variable is used 2019-09-04 19:31:30 -07:00
Chris Robinson 8940bbd034 Only use one accumulation buffer for B-Format HRTF mixing
It's all getting added together anyway and all channels are continuous inputs,
so this is fewer passes over various buffers.
2019-09-03 23:19:24 -07:00
Chris Robinson e1ee1bcde9 Clean up some formatting 2019-09-03 21:34:58 -07:00
Chris Robinson 3d7ce5a860 Use global placement new for AL object batches 2019-09-01 18:07:16 -07:00
Chris Robinson bb35e24c9b Avoid unnecessary placement new definitions 2019-09-01 17:54:17 -07:00
Chris Robinson 727217ce0a Ensure AL_STOPPED state change events are sent
With explicit calls to alSourceStop on a playing or paused source
2019-09-01 15:28:33 -07:00
Chris Robinson d15950f383 Avoid accumulating a temporary 2019-09-01 15:03:22 -07:00
Chris Robinson aee10ef606 Hold the source lock in UpdateAllSourceProps 2019-09-01 00:29:26 -07:00
Chris Robinson a15f25b07a Return a QString from GetVersionString 2019-08-31 22:28:26 -07:00
Chris Robinson 5becf4bb73 Don't include version.h in mainwindow.cpp
Should help with post-commit compile times
2019-08-31 21:47:58 -07:00
Chris Robinson 96af306b3c Update the language for travis 2019-08-31 20:24:34 -07:00
Chris Robinson 3973334a64 Store the voice fraction offset as unsigned 2019-08-31 15:49:34 -07:00
Chris Robinson a546343148 Make MixVoice a member function 2019-08-31 14:53:28 -07:00
Chris Robinson 5b6772440a Remove a couple unnecessary variables 2019-08-27 12:31:19 -07:00
Chris Robinson 3223b6a906 Update mainwindow.cpp
Use the less-error-prone pointer-to-member syntax for connect calls, and use
uniform initialization more often.
2019-08-26 19:13:31 -07:00
Chris Robinson b5a6dcc14f Remove some unnecessary local spans 2019-08-26 11:02:09 -07:00
Chris Robinson 7dbf69afa2 Use a span for effect state input 2019-08-26 09:16:20 -07:00
Chris Robinson 12e6dc0cce Fix a function's sample count type 2019-08-25 21:30:32 -07:00
Chris Robinson 4e72d7b3ec Use al::byte for a couple more buffers 2019-08-25 18:09:14 -07:00
Chris Robinson 164626a7be Pass unsigned sample count to aluMixData 2019-08-25 17:54:36 -07:00
Chris Robinson b93098f7df Use unsigned sample counts for the compressor/limiter 2019-08-25 17:24:53 -07:00
Chris Robinson 88a8bf903b Use size_t for the post-process sample length 2019-08-25 15:36:40 -07:00
Chris Robinson e165cae3cd Fade reverb over the whole update
Since the early and late panning gains fade over the course of the update, it
should match the fading done by the feedback loops to avoid percussive "blasts"
when transitioning to a long-decay low-gain environment from a short-decay
high-gain environment.
2019-08-24 16:25:56 -07:00
Chris Robinson 02d38091c8 Make a couple functions into member functions 2019-08-23 15:34:45 -07:00
Chris Robinson b7ab8b6896 Fix a variable declaration 2019-08-22 18:53:09 -07:00
Chris Robinson 7ad2ed965c Avoid reading from pointers to __m128 values 2019-08-21 07:43:28 -07:00
Chris Robinson 024d5d900a Dereference the correct buffer when destructing a source 2019-08-21 03:00:19 -07:00
Chris Robinson bb46cec0b1 Pass samplesToDo as size_t to effects 2019-08-20 14:30:04 -07:00
Chris Robinson 3e499e70fd Try to improve non-dynamic-extent span construction 2019-08-20 12:31:46 -07:00
Chris Robinson 3a6676b61e Fix NEON store call 2019-08-20 12:19:38 -07:00
Chris Robinson 80710c146a Use size_t for the mixers' fade counter and outpos 2019-08-20 12:00:24 -07:00
Chris Robinson 3fa83547e9 Use size_t for HrtfMixer functions' buffer size 2019-08-20 11:39:39 -07:00
Chris Robinson a19f65f2c8 Use size_t for reverb offsets and masks 2019-08-20 11:13:19 -07:00
Chris Robinson 9e326846f6 Simplify passing some span parameters 2019-08-20 10:36:17 -07:00
Chris Robinson a3a295f6dc Try to fix span construction for MSVC 2019-08-20 09:31:08 -07:00
Chris Robinson a7f078927d Fix MixRow definition for NEON 2019-08-20 09:20:18 -07:00
Chris Robinson 0961f4eb00 Pass a span to the Resample function 2019-08-20 08:46:12 -07:00
Chris Robinson ce76cc1441 Use unsigned for the sample and channel converters 2019-08-20 07:57:37 -07:00
Chris Robinson 2ab52968f4 Track the MixVoice sample count and fade counter as unsigned 2019-08-20 06:03:31 -07:00
Chris Robinson 7a8f81259c Use size_t for the NFC and biquad filters' sample count 2019-08-20 05:26:51 -07:00
Chris Robinson 102ef6cb33 Pass a span for the Mix function's input 2019-08-20 04:16:44 -07:00
Chris Robinson 4883091f5d Rename the Mix function input for clarity 2019-08-20 01:24:02 -07:00
Chris Robinson 8fd90334a1 Pass the MixRow buffer size as a span 2019-08-20 00:27:28 -07:00
Chris Robinson 34a61122f6 Change NUM_LINES to a size_t for MSVC 2019-08-19 09:49:01 -07:00
Chris Robinson 34331c0dfa Fix for GCC5 decaying an array to a pointer 2019-08-19 09:14:54 -07:00
Chris Robinson c0cd43d100 More logically separate temp reverb buffers 2019-08-19 08:46:57 -07:00
Chris Robinson 2d0568c048 Allow using a variable channel stride for MixRowSamples 2019-08-19 08:02:08 -07:00
Chris Robinson a9223ae601 Improve subspan default template argument 2019-08-18 23:26:49 -07:00
Chris Robinson 2bbdd329cd Use the appropriate type 2019-08-18 15:37:39 -07:00
Chris Robinson 6629b65ab9 Formatting cleanup 2019-08-18 15:25:18 -07:00
Chris Robinson 4f4ef3a410 Don't require MixRow's output to be a FloatBufferLine 2019-08-18 15:15:56 -07:00
kcat 6750907bdd Merge pull request #329 from Raulshc/fshifter
EFX: Update Frequency shifter
2019-08-18 15:15:19 -07:00
kcat 71ddb86047 Merge pull request #328 from Raulshc/double2int
Move double2int function
2019-08-18 15:15:09 -07:00
kcat c89fb550b6 Merge pull request #327 from Raulshc/alsoft_config_vmorpher
Alsoft-config: Add vocal morpher effect
2019-08-18 15:15:01 -07:00
Raulshc eaaa194163 EFX: Update Frequency shifter
Add f. shifter processing for L and R channels.
2019-08-18 19:28:00 +02:00
Raulshc 550f1dce1f Move double2int function
Move inline double2int function to alnumeric.h from pshifter.cpp
2019-08-18 19:12:38 +02:00
Raulshc 42602b9ede Alsoft-config: Add vocal morpher effect 2019-08-18 18:49:52 +02:00
Chris Robinson ff66061091 Reduce the size of reverb's temporary buffer storage
The size of ReverbState is now almost half of what it was.
2019-08-18 03:19:19 -07:00
Chris Robinson 16886bd259 Avoid an out parameter for VectorPartialScatter 2019-08-17 23:00:46 -07:00
Chris Robinson ddf7e0f07c Use a std::array for the reverb sample buffer 2019-08-17 21:23:30 -07:00
Chris Robinson 351ccf2e11 Use new/delete for context and effectslot properties 2019-08-13 22:25:59 -07:00
Chris Robinson ecab99bce9 Move update pointers to the containers they update 2019-08-13 22:06:14 -07:00
Chris Robinson 0806a003e2 Use new/delete for listener properties 2019-08-13 20:33:44 -07:00
Chris Robinson 91ff01d1ad Don't explicitly inline a particular function 2019-08-13 20:33:26 -07:00
Chris Robinson bc9f39b5ac Environment variables should override config settings 2019-08-12 17:10:04 -07:00
Chris Robinson 38a565bdf8 Move UID definitions to a separate source 2019-08-12 14:56:17 -07:00
Chris Robinson dff906c13b Remove always-true assumption 2019-08-12 14:32:04 -07:00
Chris Robinson 81d17bb80f Fix some return types 2019-08-12 14:30:47 -07:00
Chris Robinson 1aaf65abfe Add methods to get env vars as an optional 2019-08-12 03:59:52 -07:00
Chris Robinson 50d16d2422 Don't use INT_MAX for unknown span lengths
32-bit doesn't like it, for some reason. Use the largest possible length it
could be.
2019-08-11 22:48:18 -07:00
Chris Robinson f290bf2751 Move vector.h to common 2019-08-11 20:54:21 -07:00
Chris Robinson e200569cd3 Move the wstr converters to a separate header 2019-08-11 18:50:07 -07:00
Chris Robinson 7118733458 Remove multiple buffers per queue item
And simplify related code
2019-08-11 14:01:57 -07:00
Chris Robinson 70058a8a84 Move the dynload decls and defs to common 2019-08-10 21:54:30 -07:00
Chris Robinson dca2365051 Fix array access index 2019-08-10 20:31:08 -07:00
Chris Robinson e3f5bd37e6 Avoid __popcnt[64] on MSVC
It requires SSE4, and provides no fallback mechanism for CPU targets lacking
the opcode it maps to.
2019-08-10 16:35:29 -07:00
Chris Robinson 98029d64b9 Fix and clarify the peaking biquad filter 2019-08-10 14:41:55 -07:00
kcat 8f93656f53 Merge pull request #323 from Raulshc/vmorpher_decls
Add parameter DECLs for vocal morpher
2019-08-10 14:41:25 -07:00
Raulshc c4f1c95a45 Add parameter DECLs for vocal morpher 2019-08-10 18:42:02 +02:00
kcat 926b515edf Merge pull request #322 from gongminmin/SDK1903
Enable to detect Windows SDK v1903
2019-08-10 03:18:01 -07:00
Minmin Gong becd1cf1bd Enable to detect Windows SDK v1903 2019-08-09 23:04:37 -07:00
Chris Robinson f900efa7f2 Simplify and fix vocal morpher pitch calculations 2019-08-08 15:22:22 -07:00
Chris Robinson fb1fde9fb0 Simplify the weighted decay time calculation 2019-08-08 12:44:53 -07:00
Chris Robinson a4391a213d Turn a couple methods into member functions 2019-08-08 12:40:34 -07:00
Chris Robinson e22dc27218 Improve log formatting for file searches 2019-08-07 15:56:38 -07:00
Chris Robinson 0eb5e80f67 Don't store options that are set to blank/default 2019-08-07 15:43:37 -07:00
Chris Robinson 5b33b4aa97 Make the post-process methods member functions 2019-08-07 11:43:53 -07:00
Chris Robinson 7c069e29ee Update some more includes 2019-08-06 23:13:05 -07:00
kcat 50c59dab8f Merge pull request #321 from Frozen-Tofu/master
no AudioObjectPropertyAddress  on iOS
2019-08-06 23:11:55 -07:00
Li Keqing ad059fb62e no AudioObjectPropertyAddress on iOS 2019-08-07 13:29:26 +08:00
Chris Robinson 80a85febcf Update some includes 2019-08-05 18:36:39 -07:00
Chris Robinson d06afa7ca1 Move a struct definition to where it's used 2019-08-05 15:11:47 -07:00
Chris Robinson e286ec8d09 Move some declarations out of alcmain.h 2019-08-05 15:03:18 -07:00
Chris Robinson d24401c3f3 Move the meters per unit property to the listener 2019-08-05 12:15:14 -07:00
Chris Robinson 3154a915b1 Remove the ReverbSpeedOfSound hack
No other effect depends on context or listener properties, so reverb being the
only exception for speed of sound and meters per unit was putting extra work on
the effect engine for no real reason. Especially since the reverb decay time
should be the time actual time to decay irrespective of other settings.
2019-08-05 11:37:05 -07:00
Chris Robinson 3bc9490fd2 Move some structs to where they're used 2019-08-04 17:45:46 -07:00
Chris Robinson 082622951d Don't allow numeric values for the resampler option 2019-08-04 17:29:55 -07:00
Chris Robinson 2fa2c35bdc Modify LIKELY and UNLIKELY to not need extra parenthesis 2019-08-04 11:59:14 -07:00
Chris Robinson 7897de31d0 Pass spans to the source get-property methods 2019-08-03 19:36:19 -07:00
Chris Robinson 7baa07e3ad Pass spans to the source set-property methods
This avoids an extra property check to get the size since the number of values
can be checked when accessed.
2019-08-03 18:57:38 -07:00
Chris Robinson 559d1666b8 Add a Create method to FlexArray for "raw" arrays 2019-08-03 14:59:01 -07:00
Chris Robinson 13222d719d Make a couple counts size_t 2019-08-03 13:05:42 -07:00
Chris Robinson 3417436804 Avoid manually incrementing a reference count 2019-08-03 12:14:50 -07:00
Chris Robinson a7a9c00275 Turn a couple more functions into methods 2019-08-02 18:30:22 -07:00
Chris Robinson 9f223898f2 Use an unsigned voice index 2019-08-02 12:38:20 -07:00
Chris Robinson ce7c86b217 Avoid reloading the voices array when processing 2019-08-02 11:07:48 -07:00
Chris Robinson 61bb079036 Add operator* to intrusive_ptr 2019-08-01 20:15:47 -07:00
Chris Robinson 33bcced82a Use a smart pointer for holding the context's device 2019-08-01 19:44:09 -07:00
Chris Robinson 4917024c94 Reduce the AsyncEvent struct size
The "user" message length is significantly reduced to fit the struct in 256
bytes, rather than 1KB.
2019-08-01 15:54:17 -07:00
Chris Robinson 0be823320d Add and use an intrusive_ptr type 2019-08-01 15:19:37 -07:00
Chris Robinson 57e7fff6f6 Remove an unnecessary variable 2019-08-01 14:29:02 -07:00
Chris Robinson 65f7fc610e Add a common base for auto-deleting ref-counted objects
Which will also work as the basis for a future intrusive_ptr
2019-08-01 13:43:32 -07:00
Chris Robinson 380f3dc11d Cleanup alcontext.h includes 2019-08-01 09:21:56 -07:00
Chris Robinson 62534f424a Use float2 where appropriate 2019-07-31 11:05:53 -07:00
Chris Robinson 151ff51e7d Don't templatize HrirArray 2019-07-31 10:46:33 -07:00
Chris Robinson d1f72624a7 Fix a couple ASSUME statements 2019-07-31 10:28:04 -07:00
Chris Robinson 471f905fbd Use enums for the resampler and mixer template tags 2019-07-31 10:09:43 -07:00
Chris Robinson a0aa5bc80a Add iterators to ALbufferlistitem
And change some types to ALuint
2019-07-31 09:20:53 -07:00
Chris Robinson 4cd7eee01c Remove improper include 2019-07-30 21:50:47 -07:00
Chris Robinson f286c3fa38 Move another function to a ALCcontext method 2019-07-30 21:32:05 -07:00
Chris Robinson ac554de67d Turn some functions into methods 2019-07-30 14:13:05 -07:00
Chris Robinson ea76e003e7 Properly prefix ALCcontext members 2019-07-30 09:05:54 -07:00
Chris Robinson 488d1de944 More include cleanup 2019-07-29 19:59:48 -07:00
Chris Robinson 06e5454eb9 Use Transposed Direct Form II for the BS2B filters 2019-07-29 19:40:03 -07:00
Chris Robinson 4c9e18c5a0 Rename al/* sources to avoid camel-case 2019-07-29 17:54:07 -07:00
Chris Robinson c2de0782cf Minor formatting fixes 2019-07-29 16:49:56 -07:00
Chris Robinson 76d87330ec Move the event declarations to a separate header 2019-07-29 15:58:26 -07:00
Chris Robinson 0a26bab14e Rename the OpenAL32 directory to al 2019-07-29 15:40:17 -07:00
Chris Robinson 8ccb7604d3 Remove some unnecessary cmake checks 2019-07-29 13:46:25 -07:00
Chris Robinson f0408809d6 Cleanup common sources' includes 2019-07-29 09:29:35 -07:00
Chris Robinson 40e937c63a Cleanup the examples' includes 2019-07-29 08:21:38 -07:00
Chris Robinson d38d255364 More include cleanups 2019-07-28 21:29:59 -07:00
Chris Robinson 83432a7e5c Move some headers out of the Include subdirectory 2019-07-28 19:09:07 -07:00
Chris Robinson cb3e96e756 Rename Alc to alc 2019-07-28 18:56:04 -07:00
Chris Robinson 93e60919c8 Rename alMain.h to alcmain.h
And move it and alu.h to Alc/.
2019-07-28 18:33:29 -07:00
Chris Robinson bb0062625f Move the ADPCM decoders to alBuffer.cpp 2019-07-28 17:22:00 -07:00
Chris Robinson b4d56d3fdf Remove the UNUSED macro 2019-07-28 17:15:34 -07:00
Chris Robinson c8bbd75bf9 Remove a couple more cmake checks 2019-07-28 15:37:12 -07:00
Chris Robinson 12e179d539 Remove some unnecessary header checks 2019-07-28 15:22:58 -07:00
Chris Robinson 585d965c92 Remove a couple unnecessary includes 2019-07-28 15:16:13 -07:00
Chris Robinson e0a795d9d2 Clean up some more headers 2019-07-28 14:55:02 -07:00
Chris Robinson 5428d6acc3 Clean up includes a bit
Trying out the IWYU tool to only include what's necessary in a given file.
Seems to work decently (it'll miss some headers, suggest unnecessary ones, and
make nonsense suggestions for some things, but overall gives a good starting
point), and helps clean out some headers.
2019-07-28 11:28:36 -07:00
Chris Robinson 659b6d4245 Use more proper cmake to set the C/C++ standard version 2019-07-27 18:58:19 -07:00
Chris Robinson 7cfb353334 Don't explicitly check for standard functions 2019-07-26 14:02:14 -07:00
Chris Robinson b22ecc45c9 Increase the video picture queue size to 24 2019-07-26 03:44:46 -07:00
Chris Robinson 18f1139de8 Only redraw the image when necessary 2019-07-23 12:51:14 -07:00
Chris Robinson b8ac4b79e4 Only send packets as needed 2019-07-23 02:38:07 -07:00
Chris Robinson 8a9434c623 Use a local variable to track the decoded pts 2019-07-20 18:46:43 -07:00
Chris Robinson f0ed35d3d0 Set the initial clock time closer to starting playback 2019-07-20 01:10:14 -07:00
Chris Robinson 9959d661a0 Restructure codec send/receive calls
In particular, after an initial fill of the codec's internal buffer, each
receive_frame call is followed by one or more send_packet calls. For
asynchronous codecs, this has the effect of letting the codec work while the
handler thread is waiting for an AVFrame structure to become available or
waiting for more decoded data to be needed. For synchronous codecs, this
makes the send_packet calls use up time that would be spent waiting.
2019-07-19 22:55:20 -07:00
Chris Robinson 29cf87f34d Combine duplicate code into a function 2019-07-18 16:04:45 -07:00
kcat ec855215db Merge pull request #318 from Lopuska/pitchshift_for_vmorpher
pitch shift for formant filters
2019-07-18 15:42:45 -07:00
Anis 31055f48d6 pitch shift for formant filters 2019-07-18 21:42:59 +02:00
Chris Robinson 2b21a08f89 Receive video frames in a loop 2019-07-16 20:20:25 -07:00
Chris Robinson 101e641288 Fix an unused parameter warning 2019-07-16 16:19:51 -07:00
Chris Robinson ffc7258cbc Remove an unused lambda capture 2019-07-16 16:04:56 -07:00
kcat 8a9e72109e Merge pull request #317 from Lopuska/vocal_morpher_improvements
misc fixes and improvements for Vocal Morpher
2019-07-16 16:04:27 -07:00
Anis ee013521ee misc fixes and improvements for Vocal Morpher 2019-07-16 17:40:18 +02:00
Philip Muzzall 28f07d2d5e Misc fixes (#315)
* Added rc scripts for dll

* Reverted numbering scheme in CMakeLists

* Misc fixes
2019-07-14 17:39:45 -07:00
Chris Robinson b728cf7bd6 Properly include getopt.h 2019-07-14 04:05:08 -07:00
Chris Robinson 4ff7bfd2d8 Use atomics for the picture queue 2019-07-14 03:59:57 -07:00
Chris Robinson ac7eeeae79 Don't use the same mutex for the video clock 2019-07-14 03:59:57 -07:00
Chris Robinson 93c53e33f0 Receive frames directly into the picture's AVFrame 2019-07-14 03:59:57 -07:00
Chris Robinson e7e734f8b9 Don't use one texture per picture in alffplay 2019-07-14 03:59:56 -07:00
kcat d2f71ae42a Merge pull request #314 from PenguinDOOM/pr-master
Fixed makemhr and sofa-info errors
2019-07-14 03:58:38 -07:00
Penguin 4027664fc2 Fixed MSVC error. 2019-07-14 18:03:49 +09:00
Penguin 313549c76d Add missing header. 2019-07-14 18:03:32 +09:00
Chris Robinson 363e2fb73a MSVC doesn't like parenthesized type initialization 2019-07-13 16:51:19 -07:00
Chris Robinson f99474c913 Handle alffplay video using continuous rendering 2019-07-12 23:34:21 -07:00
Chris Robinson 79d572cf72 Properly comment out the sample config's options 2019-07-12 22:13:19 -07:00
Chris Robinson 2e6c7808b0 Try to improve alffplay timing again 2019-07-11 03:54:26 -07:00
Chris Robinson 99b55bc230 Add the Windows SDK for the winmm library path 2019-07-10 20:06:50 -07:00
Chris Robinson 93d0c8993d Fix OpenSL library name 2019-07-10 19:55:14 -07:00
Chris Robinson e2f2b74d6a Get rid of the custom CHECK_SHARED_FUNCTION_EXISTS function 2019-07-10 19:32:26 -07:00
Chris Robinson ac28b7d0f2 Use a find module for OpenSL 2019-07-10 18:54:43 -07:00
Chris Robinson 426c4587cc Some clean up to use uniform initialization 2019-07-10 02:13:28 -07:00
Chris Robinson 159024acc9 Improve alffplay video clock timing 2019-07-09 22:15:05 -07:00
Lopuska 4a33bbb14d vocal morpher implementation (#312)
* vocal morpher implementation

* compile fix for GCC
2019-07-09 22:14:31 -07:00
Chris Robinson 3ffb6867a3 Rework packet handling in alffplay
Turns out avcodec_send_packet is what can invoke the decode for serialized
codecs, so don't call that in the parse handler thread. The packet queue is
used to get the compressed data from the parse handler to the audio/video
threads.

Additionally, don't serialize the video frame preparation with the decode
thread.
2019-07-08 13:18:10 -07:00
Chris Robinson 2783b4c04b Somewhat simplify alffplay playback timing 2019-07-06 22:18:52 -07:00
Chris Robinson c230554851 Clamp NFC reference distance between 0.1m and 10m 2019-07-06 19:09:26 -07:00
Chris Robinson b95bf8d7c1 Update a comment about the speaker distance 2019-07-06 18:39:26 -07:00
Chris Robinson c9f6f9652a Avoid looking up source IDs multiple times 2019-07-06 14:59:26 -07:00
Chris Robinson 47246e5205 Don't stop the device before going over the attributes 2019-07-06 13:20:21 -07:00
Chris Robinson aeb7fe52f1 Use unsigned more consistently for source counts 2019-07-06 00:19:48 -07:00
Chris Robinson fa032368ae Rename HRTF Quality title to HRTF Render Method 2019-07-05 12:27:58 -07:00
Chris Robinson 3edbeefdb7 Add a setting for hrtf-mode to alsoft-config 2019-07-04 22:59:12 -07:00
Chris Robinson 474073955b Pass a span to ApplyStablizer 2019-07-04 17:00:01 -07:00
Chris Robinson 3fe5ef272f Use a span for MixParams 2019-07-04 15:02:12 -07:00
Chris Robinson 729ffe02d6 Reorder some methods for better placement 2019-07-04 14:03:27 -07:00
Chris Robinson 949507c891 Use a span for RealMixParams 2019-07-03 23:26:33 -07:00
Chris Robinson 9a51ca0a78 Pass a span to BFormatDec::process 2019-07-03 22:59:29 -07:00
Chris Robinson 0a0704071a Allocate device buffer when setting the channel counts 2019-07-03 22:32:39 -07:00
Chris Robinson 61ba455edd Don't warn about non-multiple-of-4 update sizes
It's not always possible to do anything about it, especially for backends that
aren't restricted to the period size, and it's not really a problem anyway
(still getting SIMD benefits for the vast majority of samples).
2019-07-02 01:56:59 -07:00
Minmin Gong cee8100f19 Remove noexcept from sampler functions to match the signature of SamplerT (#309)
This change fixes compilation problems on gcc 9.1 with -std=c++17.
2019-07-01 22:42:20 -07:00
Chris Robinson bc1d058d2d Add a helper to construct the optional value 2019-07-01 17:55:56 -07:00
Chris Robinson 6bb0edf0a5 Create and use a make_optional method 2019-07-01 17:25:58 -07:00
Chris Robinson 53c13de5ce Simplify some optional usage 2019-07-01 16:28:51 -07:00
Chris Robinson eb70171433 Add a few more constructor and assignment operators for optional 2019-07-01 16:27:49 -07:00
Chris Robinson 143ad16051 Use uninitialized_copy/move for optionals 2019-07-01 12:34:24 -07:00
Chris Robinson c9ffa9d466 Add C++17-like uninitialized_move methods 2019-07-01 12:33:39 -07:00
Chris Robinson e9b41d9b90 Don't unnecessarily force the output limiter on 2019-07-01 11:13:23 -07:00
Chris Robinson 871257b69e Some cleanup for optional 2019-07-01 10:44:55 -07:00
Chris Robinson 0066ac26f0 Add a missing return 2019-07-01 10:44:55 -07:00
kcat 22311169d8 Merge pull request #307 from Lopuska/patch-2
Corrected old naming
2019-07-01 10:41:20 -07:00
Lopuska a5197177be Corrected old naming 2019-07-01 14:58:32 +02:00
Chris Robinson 0c2edd10dd Remove BOM markers and set UTF-8 codepage for rc files 2019-07-01 00:28:06 -07:00
Chris Robinson 90b1bc7b7a Make sure a variable is set before use 2019-06-30 23:32:09 -07:00
Chris Robinson 01300d9735 Convert rc files to UTF-8
MinGW chokes on them being UTF-16
2019-06-30 22:29:21 -07:00
Chris Robinson 0aeaf06173 Properly set DisableVideo to true 2019-06-30 22:02:40 -07:00
Philip Muzzall 7affe3d78d Added rc scripts for dll (#306)
* Added rc scripts for dll

* Reverted numbering scheme in CMakeLists
2019-06-30 22:01:04 -07:00
Chris Robinson e9bf7e4b15 Add an option to disable video in alffplay 2019-06-30 18:17:23 -07:00
Chris Robinson c21b7e2461 Use explicit storage types for some enums 2019-06-30 17:41:43 -07:00
Chris Robinson f458642237 Use optionals where methods may not return a valid value 2019-06-30 16:57:10 -07:00
Chris Robinson 49ceae681b Return optionals from the remaining ConfigValue* methods 2019-06-30 16:40:08 -07:00
Chris Robinson 3658dafdcb Use an optional for ConfigValueStr 2019-06-30 16:40:08 -07:00
Chris Robinson db026454f2 Fix Y channel offset for the UHJ encoder 2019-06-30 16:40:08 -07:00
Chris Robinson 0fc30151f2 Use an optional for ConfigValueUInt 2019-06-30 16:40:08 -07:00
Chris Robinson 51f53afe12 Use an optional for ConfigValueInt 2019-06-30 16:40:08 -07:00
Chris Robinson 689f70ce6d Add a simple optional<> implementation 2019-06-30 16:40:08 -07:00
kcat 15ac839054 Merge pull request #305 from Lopuska/patch-1
avoid extra local member declaration
2019-06-30 16:39:36 -07:00
Lopuska 541a9383a7 avoid extra local member declaration 2019-06-30 23:17:13 +02:00
Chris Robinson ada86d2fcf Hold references in the global device and context lists 2019-06-29 22:38:38 -07:00
Chris Robinson 7303e22d89 Use a FlexArray for a device's contexts 2019-06-29 21:32:36 -07:00
Chris Robinson cbcee69ed1 Add an empty() method to FlexArray 2019-06-29 18:53:20 -07:00
Chris Robinson c7797fa10f Declare variables closer to their use 2019-06-29 15:04:20 -07:00
Chris Robinson 811d0738fa Put some static functions in an anonymous namespace 2019-06-29 12:16:38 -07:00
Chris Robinson b905a224ee Avoid a generic function for specialized behavior 2019-06-29 11:45:55 -07:00
Chris Robinson 6790a9b44f Use a bool for the TrapALError flag 2019-06-29 11:22:29 -07:00
Chris Robinson 12911cc533 Use a range-for loop to concatenate available backends 2019-06-29 10:23:29 -07:00
Chris Robinson 3ede66ae45 Don't keep retrieving the backend factories 2019-06-28 18:54:31 -07:00
kcat c238619a8b Merge pull request #301 from gongminmin/FixGcc9
Fix the error "a reinterpret_cast is not a constant expression" in GCC 9
2019-06-27 23:29:48 -07:00
Minmin Gong 9326b98e2d Fix the error "a reinterpret_cast is not a constant expression" on GCC 9 2019-06-27 22:29:42 -07:00
Chris Robinson 2598ee6f0a Properly set extra fields in MakeExtensible 2019-06-27 09:47:31 -07:00
Chris Robinson 341c68c9a1 Trace the requested and required formats for WASAPI 2019-06-27 09:41:52 -07:00
Chris Robinson 360869f23b Use a span for some post-mixing processing 2019-06-27 08:49:04 -07:00
Chris Robinson 48191cbf0a Use a span instead of explicit current and end pointers 2019-06-25 17:10:46 -07:00
Chris Robinson edd75b3b4e Don't return a blank span when offset==size() 2019-06-25 14:40:25 -07:00
Chris Robinson ab3c2ea777 Don't bother with a passthru filter method
There's not really a case where it'll process less than 2 samples, and it was
wrong anyway.
2019-06-24 21:18:25 -07:00
Chris Robinson f5cb6ac20e Use a reference instead of the same array index 2019-06-24 13:33:09 -07:00
Chris Robinson eb5ff42d15 Correctly index the send params 2019-06-24 13:21:06 -07:00
Chris Robinson e8cef0cdae Clean up all unused HRTFs when going through them 2019-06-24 12:55:36 -07:00
Chris Robinson b46fc572f5 Use spans to handle pulseaudio capture buffers 2019-06-23 17:08:52 -07:00
Chris Robinson ee983bda75 Document the hrtf-mode config option 2019-06-21 12:43:33 -07:00
kcat 281e61e4cc Merge pull request #298 from TeamHypersomnia/master
Fix ambiguous calls to destroy_at
2019-06-21 12:42:55 -07:00
geneotech 499aa65a4b Fix ambiguous calls to destroy_at 2019-06-21 18:25:09 +02:00
Chris Robinson 723ab7f15a Don't inline ifstream destructor 2019-06-18 23:04:24 -07:00
Chris Robinson 0fa984027c Simplify al_print 2019-06-18 22:57:48 -07:00
Chris Robinson 706df72d18 Rename HrtfParams to HrtfFilter 2019-06-18 06:20:35 -07:00
Chris Robinson 2b19c53ece Use al::byte instead of ALbyte for raw bytes 2019-06-17 20:26:00 -07:00
Chris Robinson 55785c0a16 Use al::make_unique for ChannelConverter 2019-06-17 20:15:37 -07:00
Chris Robinson 5a884572f0 Use a span instead of pointer+size parameters 2019-06-17 20:05:38 -07:00
Chris Robinson 21b8571f50 Avoid an implied else if check 2019-06-16 22:45:07 -07:00
Chris Robinson a009b9502a Avoid manually looping to destroy orphaned async events 2019-06-16 18:58:56 -07:00
Chris Robinson 0a532729ba Reorganize how some device fields are set and reset 2019-06-15 23:10:11 -07:00
Chris Robinson 8670fca3dc Fix BS2B output 2019-06-12 22:51:09 -07:00
Chris Robinson a2ba230e05 Combine two macros into one 2019-06-11 22:29:39 -07:00
Chris Robinson a478fd4b25 Fix unsigned short/int sample converters
And add const/noexcept in some places
2019-06-11 14:59:06 -07:00
Chris Robinson 97d56dd424 Use C++ I/O to check for NEON support 2019-06-10 22:29:58 -07:00
Chris Robinson 1a14946306 Get rid of an unnecessary constructor 2019-06-10 21:56:09 -07:00
Chris Robinson c22d537d93 Remove some extern "C" blocks 2019-06-10 21:45:33 -07:00
Chris Robinson 8bb42c2f98 Don't inline some file IO methods 2019-06-10 01:51:14 -07:00
Chris Robinson ec6fdff0c6 Make the voice count unsigned 2019-06-09 19:27:15 -07:00
Chris Robinson bc8f206ee1 Use a FlexArray for the context's voices 2019-06-09 18:13:54 -07:00
Chris Robinson 90d25e5187 Make sure the bitfield indices are constants 2019-06-09 02:20:30 -07:00
Chris Robinson 2e154069c6 Use a bitfield for the device flags 2019-06-08 23:49:15 -07:00
Chris Robinson c9ba7ba193 Add a bitfield class for indexed, auto-sized flags 2019-06-08 23:33:59 -07:00
Chris Robinson b6ce793f84 Use a span for the complex_fft/hilbert functions 2019-06-08 16:05:18 -07:00
Chris Robinson 1569b79c5d Fix for GCC 5.4 2019-06-08 02:17:08 -07:00
Chris Robinson 91b7e8142c Simplify DistanceComp somewhat 2019-06-08 01:39:28 -07:00
Chris Robinson 7988bc6e91 Add and use proper types for FlexArray 2019-06-07 23:42:31 -07:00
Chris Robinson 7537bb3492 Don't warn about standard functions with MSVC 2019-06-06 15:57:15 -07:00
Chris Robinson 87ccdf02a7 Avoid strcpy 2019-06-06 04:39:30 -07:00
Chris Robinson 56faf66887 Disable MSVC warning 4200 again 2019-06-06 03:32:28 -07:00
Chris Robinson 39c2b18cd4 Remove a couple unused functions 2019-06-06 00:42:59 -07:00
Chris Robinson 585b0cf3be Remove the DEF_ALIGN macro 2019-06-06 00:37:00 -07:00
Chris Robinson a7be531049 Remove the unused ALIGN macro 2019-06-06 00:24:13 -07:00
Chris Robinson d9d9e70ed8 Don't disable some MSVC warnings 2019-06-06 00:18:25 -07:00
Chris Robinson 5acae56ecd Use a FlexArray for ringbuffer storage 2019-06-05 23:29:13 -07:00
Chris Robinson 24df52c042 Remove the per-voice ChannelsPerOrder field 2019-06-05 23:00:28 -07:00
Chris Robinson f9da06fc6a Use a span for the effect state's output target 2019-06-05 19:58:58 -07:00
Chris Robinson 1ce310c6d1 Make some more channel counts unsigned 2019-06-05 19:26:54 -07:00
Chris Robinson 410a5ca621 Make RealMixParams channel count unsigned 2019-06-05 18:54:17 -07:00
Chris Robinson 5f26205f8f Properly destroy other objects 2019-06-05 17:25:08 -07:00
Chris Robinson f27e73989c Properly destroy the limiter's extra fields 2019-06-05 17:09:15 -07:00
Chris Robinson 142721df17 Add methods to construct and destruct objects in-place 2019-06-05 16:38:53 -07:00
Chris Robinson b2735331c0 Use a 16-sample base delay for the B-Format decoder IRs 2019-06-04 20:27:32 -07:00
Chris Robinson 9d861406c0 Avoid a separate struct for the bandsplitter all-pass 2019-06-04 17:50:36 -07:00
Chris Robinson 4522a51ea2 Don't log the function or prefix
It's ultimately unnecessary since the message is an indicator about where it
was logged from. The message itself is generally more important than where it
was from, too.
2019-06-04 01:37:36 -07:00
Chris Robinson f0bc9d8a9b Improve alignment handling for the alignment allocator 2019-06-03 22:58:56 -07:00
Chris Robinson c76fb714cc Restructure voice data members
This should improve access patters by packing each buffer channel's data
together, which is more inline with its use.
2019-06-03 22:24:26 -07:00
Chris Robinson 53e1415a67 Allow selecting the ambisonic order for basic HRTF rendering 2019-06-02 20:38:43 -07:00
Chris Robinson 8c4a9a5a32 Properly search for prebuilt native-tools 2019-06-01 11:21:43 -07:00
Chris Robinson 20ce461096 Make sure the T60 filter gains are properly clamped 2019-05-31 11:58:48 -07:00
Chris Robinson 6ee49cad52 Once more for MSVC 2019-05-30 18:55:24 -07:00
Chris Robinson 4bae4cbafb Another attempt to fix MSVC 2015 2019-05-30 18:39:51 -07:00
Chris Robinson a123c87ba5 Avoid some MSVC workarounds that didn't seem to work 2019-05-30 14:38:06 -07:00
Chris Robinson 1c8dfb55d8 Improve span constructor requirements
Particularly, properly account for the const-ness of the data returned by it.
2019-05-30 11:46:48 -07:00
Chris Robinson 76e7c8b244 Try to work around some MSVC short-comings 2019-05-30 10:52:28 -07:00
Chris Robinson 1961828d0b Avoid potentially ambiguous span copy constructor 2019-05-30 10:06:12 -07:00
Chris Robinson 153f133435 Try to fix "ambiguous" initializations with older compilers 2019-05-29 23:41:09 -07:00
Chris Robinson dbdf516dbf Use a span for the voice's buffer references 2019-05-29 23:06:24 -07:00
Chris Robinson 2909f263fd Use span<FloatBufferLine> for EffectState::process output 2019-05-29 22:31:36 -07:00
Chris Robinson 893ffe9a84 Use span<FloatBufferLine> for MixSamples 2019-05-29 21:58:37 -07:00
Chris Robinson 8af7b4c6e0 Use FloatBufferLine and span<> for MixRowSamples 2019-05-29 20:45:33 -07:00
Chris Robinson 7e6b6d7ad9 Use FloatBufferLine and span<> in the reverb effect 2019-05-29 19:36:06 -07:00
Chris Robinson ba449d2b08 Pass a span to MixDirectHrtf instead of a pointer+size 2019-05-29 17:32:16 -07:00
Chris Robinson d0f0a5fdca Separate two HRTF passes into two loops 2019-05-29 11:13:35 -07:00
Chris Robinson ec3a6f8cde Use FloatBufferLine for the effect process method 2019-05-29 09:37:25 -07:00
Chris Robinson b923eb1879 Use FloatBufferLine with the HRTF mixer functions 2019-05-28 22:44:50 -07:00
Chris Robinson 838e2bae80 Improve a couple algorithms 2019-05-28 17:18:22 -07:00
Chris Robinson c80ee5b701 Use std::array for most mixing buffer arrays 2019-05-28 16:22:36 -07:00
Chris Robinson 7ce2b632f5 Simplify template type requirement checking 2019-05-28 08:49:53 -07:00
Chris Robinson aa4b6afad6 Small cleanup for is_span and is_std_array 2019-05-27 22:01:59 -07:00
Chris Robinson bac52e9537 Fix default constructor for static-sized spans 2019-05-27 17:48:19 -07:00
Chris Robinson 28fbb5178a Remove unnecessary assignment operators 2019-05-27 15:56:50 -07:00
Chris Robinson aad49d666a Implement static-sized spans, and handle overload requirements
Note that span is specialized such that a static-sized span only has a single
data member, making it a suitable replacement for  Type (&arg)[Size]  style
variables/parameters.
2019-05-27 15:36:10 -07:00
Chris Robinson f57fedec7f Get rid of the COUNTOF macro 2019-05-26 21:28:51 -07:00
Chris Robinson f6f220025b Fix subspan 2019-05-26 21:00:17 -07:00
Chris Robinson 3007fbf5e5 Use a span for loading source samples 2019-05-26 20:05:12 -07:00
Chris Robinson b0e12ccf71 Ensure a couple calls are constexpr 2019-05-26 15:57:17 -07:00
Chris Robinson 01f717ae59 Use SL_ANDROID_DATAFORMAT_PCM_EX for extended PCM info 2019-05-26 14:45:53 -07:00
Chris Robinson 20e3c78aef Use al::byte instead of char for generic data storage 2019-05-26 12:54:54 -07:00
Chris Robinson 63a130204c Add a few more methods to the span class 2019-05-26 12:05:43 -07:00
Chris Robinson 7cbf82afe4 Avoid a few more NUM_LINES assumptions 2019-05-26 11:34:17 -07:00
Chris Robinson 8ca97a7d9a Move a couple functions into its related class 2019-05-25 11:54:51 -07:00
Chris Robinson 5b5dee07b4 Remove a couple unused functions 2019-05-25 11:36:13 -07:00
Chris Robinson ebf33b7c6b Avoid some uses of RESTRICT 2019-05-25 08:17:37 -07:00
Chris Robinson 219f818b16 Use al::byte for ADPCM decoders 2019-05-24 13:32:20 -07:00
Chris Robinson b4fbc271d2 Add byte ops that take an integer-based rhs parameter 2019-05-24 13:30:40 -07:00
Chris Robinson 674ca3cf24 Move a couple table definitions to where they're used 2019-05-24 12:06:52 -07:00
Chris Robinson 1f45cc051a Fix some truncation warnings with MSVC 2019-05-24 06:47:24 -07:00
Chris Robinson e90a6beaa2 Remove an unnecessary struct member 2019-05-24 06:25:18 -07:00
Chris Robinson 9c63bbd6ce Use raw bytes for the buffer data 2019-05-24 06:12:20 -07:00
Chris Robinson 1945b50834 Add a unique byte type for dealing with raw bytes 2019-05-24 06:11:21 -07:00
Chris Robinson 857473b6b0 Store the span extents as a pair of pointers 2019-05-24 04:55:38 -07:00
Chris Robinson 3a9caec72f Use a span for referencing the channel map to initialize 2019-05-23 13:30:16 -07:00
Chris Robinson 517b8158a7 Add a missing include 2019-05-23 08:30:02 -07:00
Chris Robinson b46eca97a6 Use a span for resource data 2019-05-23 08:17:05 -07:00
Chris Robinson a4af617532 Add a span class to act as a view to contiguous data 2019-05-23 08:15:02 -07:00
Chris Robinson e3d6f3d988 Use a function to mark a source for updating 2019-05-23 05:06:26 -07:00
Chris Robinson 6708504026 Properly reverse the HRTF field order when loading it
And combine a couple arrays into an array structure
2019-05-22 11:07:12 -07:00
Chris Robinson b48bab3394 Allow initializing splitter filters with constructors 2019-05-22 03:03:24 -07:00
Chris Robinson 657978c732 Don't change the format tag in MakeExtensible 2019-05-21 09:01:51 -07:00
Chris Robinson d502397b37 Simplify the echo feedback loop 2019-05-20 22:07:41 -07:00
Chris Robinson 55845f316d Don't use coverage spread for the echo spread 2019-05-20 21:30:56 -07:00
Chris Robinson 6dbd488d13 Avoid unnecessary use of CalcAngleCoeffs 2019-05-20 21:16:13 -07:00
Chris Robinson 136caf0cb0 Don't attenuate the repeated sample
The mixing gain stepping will handle it
2019-05-19 00:53:39 -07:00
Chris Robinson 515a201e30 Restructure some voice fields 2019-05-17 20:39:28 -07:00
Chris Robinson 5ac19673db Fix a couple type truncation warnings with MSVC 2019-05-12 19:41:34 -07:00
Chris Robinson 8d437a5135 Use available buffer samples when pausing a source 2019-05-05 01:51:46 -07:00
Chris Robinson 0759ed7213 Properly mark a likely branch 2019-05-05 00:05:41 -07:00
Chris Robinson 0c09c8378b Set the device channel order from PulseAudio's channel map 2019-05-04 23:45:27 -07:00
Chris Robinson 42dfefbb0e Fix when PulseAudio channel configuration changes 2019-05-04 22:11:29 -07:00
Chris Robinson 1b11ca48dc Avoid unnecessary parsing for channel maps 2019-05-04 20:54:49 -07:00
Chris Robinson 31c29f1ea8 Use exceptions when opening and reseting the PulseAudio backend 2019-05-04 20:35:24 -07:00
Chris Robinson 95d19be36b Catch exceptions from backend reset 2019-05-04 20:34:33 -07:00
Chris Robinson b9592bddbc Add the printf format attribute to backend_exception's constructor 2019-05-04 18:25:59 -07:00
Chris Robinson 5ff8d5ae32 Add an exception class to cover backend creation and opening 2019-05-04 18:03:25 -07:00
Chris Robinson 1607f9c525 Report the threshold limit for the output limiter 2019-05-04 13:53:11 -07:00
Chris Robinson 9eea2e4c73 Use BUFFERSIZE for the reverb loop limit
At 44/48khz, the main delay line comes out to 20k to 22k samples, which gets
rounded up to 32k as the next power of two. This leaves plenty of room for the
full 1k BUFFERSIZE without having to increase the delay line beyond what it
already is.
2019-05-03 12:59:04 -07:00
Chris Robinson 2f2ec2b6e3 Add some assumes and consts 2019-05-03 00:50:47 -07:00
Chris Robinson a72c47164c Avoid a few more array length assumptions 2019-05-01 11:15:17 -07:00
Chris Robinson 6281f6e85a Avoid masking offsets in the inner reverb loops 2019-04-30 23:28:57 -07:00
Chris Robinson 85439cbd87 Add some missing include directories 2019-04-29 20:03:51 -07:00
Chris Robinson fb52413a6e Make a number of settings tristate 2019-04-29 19:47:14 -07:00
Chris Robinson cef7eebed6 Disable NFC by default 2019-04-29 19:47:14 -07:00
Chris Robinson b42694ea31 Allow NFC filters without HQ decoding
It still requires a proper custom decoder configuration for speakers, so that
proper distances can be specified. Ambisonic output still relies on the
nfc-ref-delay option, and HRTF uses the dataset's distance.
2019-04-29 19:47:14 -07:00
kcat 1ab783c7ac Merge pull request #285 from ArthurSonzogni/master
Update CMakeLists.txt. Simplify examples build and export PUBLIC headers.
2019-04-29 19:46:39 -07:00
ArthurSonzogni 2eb657f2df CMAKE: export PUBLIC headers of OpenAL.
Remove the cmake function:
  INCLUDE_DIRECTORIES(..)
Replace it by:
  TARGET_INCLUDE_DIRECTORIES(...)

It gives us the opportunity to define whether or not OpenAL dependencies
should be exported or not (using PUBLIC or PRIVATE keywoard).

[user visible changes]
The OpenAL PUBLIC headers are exported. When a target depends on OpenAL,
it will have access to its public headers.

Some small refactor along the way.
2019-04-30 04:17:43 +02:00
Chris Robinson c7e388873c Increase the period size slider and don't use steps of 64 2019-04-28 22:21:23 -07:00
Chris Robinson 8ca849655f Properly replace sinc4 with cubic in alsoft-config 2019-04-28 21:51:47 -07:00
Chris Robinson ace7481b8e Only enable NFC with HRTF when hq-mode is enabled 2019-04-28 21:49:10 -07:00
Chris Robinson 9d6619efdc Combine some reverb processing loops
Specifically, the A2B and output mixing, as well as applying the band-pass with
B2A mixing (the latter of which hiding a bug that was overwriting the early
buffer storage).
2019-04-28 08:56:41 -07:00
Chris Robinson ec869234f7 Remove restrict from in+out parameters 2019-04-28 08:51:50 -07:00
Chris Robinson 014936ceff Be more robust with PulseAudio capture
Particularly, handle "holes" in the record stream and premature end-of-buffer.
Also don't bail out when capturing while disconnected (the extension says it
should provide anything it previously reported available, going to silence for
anything no longer readable).
2019-04-27 21:25:42 -07:00
Chris Robinson 0577028b65 Add missing function pointers 2019-04-27 18:01:26 -07:00
Chris Robinson c135629eae Remove some ancient PulseAudio KDE/Phonon/Qt hacks
Unfortuantely, the relevant KDE bug still seems to exist (streams are forced to
KDE's default device after opening, even when they're created with a specific
device at user request). I do not know why KDE thinks this is in any way good
behavior (the user doesn't get their desired device, nor does the stream get
the appropriate format for the device its ultimately put on), but making
streams non-movable as a workaround has been a thorn in the side of non-KDE
users for too long. C'mon KDE, it's been nearly (if not more than) 7 years now.
2019-04-27 14:13:07 -07:00
Chris Robinson 150dc92f68 Remove unused pa_threaded* functions 2019-04-27 13:06:39 -07:00
Chris Robinson f9f34def82 Use a custom PulseAudio mainloop
This allows using RT priority again with the mixer. It also consolidates all
mainloop instances into one.
2019-04-27 12:25:49 -07:00
Chris Robinson c724798c85 Don't round WASAPI updates to the update size 2019-04-27 08:48:14 -07:00
Chris Robinson dd2c43be42 Update the period size placeholder text 2019-04-26 19:02:18 -07:00
Chris Robinson b502bbaf5c Change the default period size to 20ms 2019-04-26 18:56:54 -07:00
Chris Robinson 9e4ee500b6 Scale the update size with sample rate changes 2019-04-26 18:04:22 -07:00
Chris Robinson b29be3b39e Set the ALSA period size first 2019-04-26 16:20:27 -07:00
Chris Robinson f23ff0394d Specify the buffer size as itself instead of the period count
Certain backends don't need a buffer size to be a strict multiple of the period
count, which allows a little more flexibility. The period/update size simply
acts as the minimum request, which helps control CPU load by determining how
often parameter and other pre-mixing updates are processed.
2019-04-26 15:58:25 -07:00
Chris Robinson 348e01dc4b Work around a 32-bit GCC compiler bug 2019-04-26 07:11:09 -07:00
Chris Robinson 725ceb128e Open the playback device earlier
So we actually have a device name to get the initial settings for. Be aware
that some backends set a format when opening instead of on reset, so such
devices will only set the default format (it can't get a desired format without
the device name, but the format will already be set once that's known). The
affected backends are WinMM, SDL2, and PortAudio (none of which are generally
used). This could be fixed by reopening the device during reset, but it would
need to be done carefully.
2019-04-20 19:29:33 -07:00
Chris Robinson 87e279082f Don't round the PulseAudio write size to the period multiple 2019-04-17 05:51:40 -07:00
Chris Robinson 09dbc4c2da Fix PulseAudio backend initialization 2019-04-16 17:23:28 -07:00
Chris Robinson 61f7e7716c Remove the backend factory deinit method
It was never actually called anywhere, and there's no safe place where it can
be called. It's probably better to let the individual backends worry about
cleaning themselves up anyway.
2019-04-14 04:05:07 -07:00
Chris Robinson 7f52678099 Use a custom message queue for the WASAPI backend 2019-04-14 01:03:36 -07:00
Chris Robinson 629cfa04a3 Fix some integer truncation warnings in MSVC 2019-04-12 19:19:24 -07:00
Chris Robinson 6761fe137f Load buffer data using the current and end pointer 2019-04-12 16:24:11 -07:00
Chris Robinson 4b95d310ae Remove the SZFMT macro
C++11 mandates the %zu/d formatter
2019-04-11 16:01:11 -07:00
Chris Robinson 8215251571 Simplify sorting and initializing the backends 2019-04-11 02:49:13 -07:00
Chris Robinson abcca1acd1 Add exception protection to the last of the API functions 2019-04-10 17:47:13 -07:00
Chris Robinson 1d214dba1e Add exception protection to effect, filter, and buffer functions 2019-04-10 17:33:21 -07:00
Chris Robinson b4a8615ea9 Add exception protection to the listener functions 2019-04-10 14:16:15 -07:00
Chris Robinson 5ad50e4f8e Add exception protection to context state functions 2019-04-10 13:44:46 -07:00
Chris Robinson f39d4598b7 Add exception protection to some AL functions 2019-04-10 13:05:21 -07:00
Chris Robinson d6f72b777a Fix usage of the voice's HRTF accumulation buffer when blending 2019-04-09 22:42:45 -07:00
Chris Robinson 55a3f38405 Don't use a fixed size buffer for printed messages 2019-04-09 22:13:21 -07:00
Chris Robinson 460a01443c Add macros to stop exceptions from leaving API functions
Effectively makes the functions act as noexcept, since there's no meaningful
reason to propogate exceptions from "C" functions. Currently only applied to
ALC functions, but can incrementally be applied to AL functions too. In the
future, this could also handle ALC and AL errors with unique exception types
(functions that utilize this behavior would need to ensure proper cleanup).
2019-04-09 20:48:01 -07:00
Chris Robinson e6daab51e8 Make sure the all-pass filter is cleared before use 2019-04-04 22:57:29 -07:00
Chris Robinson dc5759f80c Fix MSVC error about parenthesized explicit type conversion 2019-04-03 10:32:48 -07:00
Chris Robinson e66632b301 Avoid directly using CalcAmbiCoeffs 2019-04-02 20:23:19 -07:00
Chris Robinson d04f9326c9 Change RealMixParams::ChannelName to better reflect its use 2019-04-02 16:06:45 -07:00
Chris Robinson 9ac3524521 Spread out the ALC extensions like the AL extensions 2019-04-01 21:41:11 -07:00
Chris Robinson 86683264c9 Avoid multiple using statements for the same things 2019-04-01 21:35:52 -07:00
Chris Robinson 8781a32df5 Copy the voice's ambisonic upsampler state when reallocating 2019-04-01 17:27:31 -07:00
Chris Robinson da8494dd8a Use the existing function to get the ambisonic channel count 2019-03-31 22:50:30 -07:00
Chris Robinson 0e0e85af72 Don't bother with a separate reset method for BFormatDec 2019-03-31 22:27:56 -07:00
Chris Robinson 423333c594 Fix use of reverse_copy 2019-03-31 19:09:21 -07:00
Chris Robinson c88b09170c Use phase correction for the front stablizer 2019-03-31 18:54:43 -07:00
Chris Robinson d8c76ba0c0 Remove a couple unused member variables 2019-03-30 23:41:47 -07:00
Chris Robinson 89210cddb7 Don't stop the backend if it's not running 2019-03-30 23:30:15 -07:00
Chris Robinson cc91490b61 Use a temporary buffer for HRTF filter accumulation
Similar to the history buffer, to avoid using the state buffer as a ring
buffer.
2019-03-29 11:33:04 -07:00
Chris Robinson fe7918465e Use a function reference for a template parameter 2019-03-28 10:00:35 -07:00
Chris Robinson dfb81ff42d Avoid using the HRTF history buffer as a ring buffer
The HRTF mixers now get a full input buffer with the history prepended, so the
delay offsets just need to account for the start point and read forward for
each sample.
2019-03-28 09:34:31 -07:00
Chris Robinson e7bfe1ebd0 Simplify applying the field magnitude factor 2019-03-27 11:52:35 -07:00
Chris Robinson 095a0b9beb Set the EARLY_REQUESTS flag for PulseAudio when possible 2019-03-26 17:03:31 -07:00
Chris Robinson 608e4e916e Avoid recreating temporary buffers all the time 2019-03-26 17:01:45 -07:00
Chris Robinson 2960d729ef Fix a return type for accumulation 2019-03-26 13:47:24 -07:00
Chris Robinson 8b0c9fcf30 Require IR dimensions from a SOFA file 2019-03-26 13:45:25 -07:00
Chris Robinson 2446ee0cca Avoid some explicit loops 2019-03-26 12:37:52 -07:00
Chris Robinson a5b442b1a4 Add a missing include for varargs 2019-03-26 11:37:28 -07:00
Chris Robinson bcbe7c493c Remove another unnecessary distance check 2019-03-26 11:04:52 -07:00
Chris Robinson 525b5e65b2 Remove a couple unnecessary duration_casts 2019-03-26 10:20:32 -07:00
Chris Robinson 2c37d4fae1 Move an enum to a more appropriate header 2019-03-26 10:08:26 -07:00
Chris Robinson 4c32e55ac2 Don't mention which rendering methods aren't used 2019-03-25 23:17:34 -07:00
Chris Robinson a57116f788 Scale floats directly to 32-bit integer values
Rather than scaling to a 25-bit integer and shifting for the extra 7 bits. This
should improve precision for values closer to 0.
2019-03-25 22:52:15 -07:00
Chris Robinson 0a4d1c858e Support loading SOFA files directly with makemhr
This extracts the definition info it can from the SOFA, and uses the same logic
as sofa-info to automatically detect an appropriate layout. There is a bit of
code duplication from loaddef.cpp and sofa-info.cpp, though there are slight
modifications.
2019-03-25 20:16:02 -07:00
Chris Robinson cb02bb00be Detect SOFA files for makemhr input 2019-03-25 13:01:44 -07:00
Chris Robinson a3687db015 Use only a single function to load the HrirDataT 2019-03-25 00:21:45 -07:00
Chris Robinson 78aeca10c9 Add a command-line option to force mono input with makemhr 2019-03-24 22:43:43 -07:00
Chris Robinson 6edfa6e6e0 Cleanup some unnecessary parameters 2019-03-24 22:06:01 -07:00
Chris Robinson f392d9c138 Move makemhr's .def loading code to a separate source 2019-03-24 19:00:58 -07:00
Chris Robinson 5e6e738681 Change references of makehrtf to makemhr 2019-03-24 17:35:32 -07:00
Chris Robinson 7c16b1e02f Rename makehrtf to makemhr and move it to a subdirectory 2019-03-24 17:31:10 -07:00
Chris Robinson c8e8ac42ab Use false instead of 0 for a boolean 2019-03-24 14:02:06 -07:00
Chris Robinson f7ab7b45f7 Mark the device and context deletes as unlikely 2019-03-24 13:54:49 -07:00
Chris Robinson 12d4953a5f Remove a couple redundant distance checks 2019-03-23 13:55:07 -07:00
Chris Robinson 6df673e01c Don't redundantly set the voice's direct output buffer 2019-03-23 13:30:15 -07:00
Chris Robinson 819ec8a653 Rename and move ALeffectProps 2019-03-22 22:48:12 -07:00
Chris Robinson 3a6e741e90 Use MixParams for the wet buffers 2019-03-22 19:25:55 -07:00
Chris Robinson 92adfaebce Fix a comment typo 2019-03-22 18:37:47 -07:00
Chris Robinson edc32b40a5 Slightly improve casting in the modulator effect 2019-03-22 17:47:19 -07:00
Chris Robinson ea8b02dead Pass ALeffectProps directly to the get/setParam* methods 2019-03-22 16:04:13 -07:00
Chris Robinson e7e585f65c Use the effect state factory to set the default effect props 2019-03-22 15:00:37 -07:00
Chris Robinson f951f4a66b Implement getDefaultProps for effect state factories 2019-03-22 12:58:24 -07:00
Chris Robinson 935f386982 Use a separate EffectStateFactory for standard reverb 2019-03-22 11:57:32 -07:00
Chris Robinson 9790135127 Add a new EffectStateFactory method to get the default properties 2019-03-22 11:52:55 -07:00
Chris Robinson 8a1b1f4204 Make sure the file is rewound before writing the wave header 2019-03-19 22:10:49 -07:00
Chris Robinson 7880540407 Use a sorted vector for looking up contexts
Note that the device still holds and uses a linked list of its contexts. The
sorted vector is used to verify handles given by callers.
2019-03-19 18:53:32 -07:00
Chris Robinson 90465e9124 Use a sorted vector for devices instead of a linked list 2019-03-19 15:56:30 -07:00
Chris Robinson cf6545ebb2 Avoid AL types in the common alnumeric.h header 2019-03-19 14:34:44 -07:00
Chris Robinson 813976e58d Add some enum casts for the WASAPI backend 2019-03-19 01:33:36 -07:00
Chris Robinson 9695952c8d Rename DevProbe enum names 2019-03-19 00:24:54 -07:00
Chris Robinson d31514f8be Move some inline functions from alMain.h to alnumeric.h 2019-03-18 22:06:01 -07:00
Chris Robinson 3e816de4fb Use SSE intrinsics in a few more places 2019-03-18 20:58:48 -07:00
Chris Robinson 73a43fb19c Don't bother trying _controlfp or __control87_2 2019-03-18 20:27:25 -07:00
Chris Robinson 2de1d17bc6 Use SSE intrinsics to set FTZ and DAZ 2019-03-18 20:14:40 -07:00
Chris Robinson 6a0b2ed0ca Check compile-time support for SSE intrinsics 2019-03-18 20:05:15 -07:00
Chris Robinson 821c7565cf Don't bother checking for SSE1 alone
SSE2 support is now the minimum required for SSE. Run-time can still disable
SSE2-specific functions separately from SSE1, but build-time support can't be
separated.
2019-03-18 17:38:02 -07:00
Chris Robinson e61cec8f17 Don't bother checking for C99 inline semantics
Should be unneeded with C++
2019-03-18 14:31:12 -07:00
Chris Robinson d802a5785e Fix indexing for basic B-Format decoding 2019-03-17 14:03:21 -07:00
Chris Robinson f96c37120b Always reset all voices on disconnect 2019-03-16 17:01:04 -07:00
Chris Robinson 339a37b034 Include std::placeholders once in an anonymouse namespace 2019-03-16 15:15:59 -07:00
Chris Robinson 12999f9efe Simplify calculating azimuth and elevation indices for HRTF 2019-03-14 22:26:19 -07:00
Chris Robinson 9f5a7a7a50 Fix wrapping for the upper HRIR index 2019-03-14 13:17:07 -07:00
Chris Robinson 3a19b94503 Mirror a couple HRIR elevations from the top for the bottom
Because the ears are offset from center, linear interpolation from the lowest
defined elevation to the -90 degree bottom misses this slight deviation.
Mirroring one or two more elevations from the top helps catch it, and bilinear
interpolation is used to transition back to the lowest known measurements.
2019-03-13 12:27:44 -07:00
Chris Robinson 3a39a2c790 Set the correct target gain after a fade-out HRTF mix 2019-03-12 16:45:34 -07:00
Chris Robinson 24ae12f58e Check a value where its used 2019-03-12 09:56:02 -07:00
Chris Robinson 098c7ca6ea Fix not looping when the source offset is beyond the loop end 2019-03-11 22:09:30 -07:00
Chris Robinson 24b43fe852 Remove a couple redundant local variables 2019-03-11 22:00:28 -07:00
Chris Robinson 30a7c6d86f Pass the voice state as a parameter instead of reloading it 2019-03-11 20:00:14 -07:00
Chris Robinson e0daad6a16 Update comment for SynthesizeOnsets 2019-03-11 14:28:13 -07:00
Chris Robinson d2b4099024 Process minimum phase reconstruction in parallel 2019-03-11 13:41:26 -07:00
Chris Robinson 0689333da8 Mirror the +90 degree elevation delays for -90 degrees 2019-03-10 21:47:05 -07:00
Chris Robinson 2c67ab0d2c Rename ALvoice fields for consistency 2019-03-10 16:29:06 -07:00
Chris Robinson 030b24a40d Improve handling of voice's AmbiScales for upsampling 2019-03-10 15:46:46 -07:00
Chris Robinson 663a6ce4e7 Use the correct value for MAX_AMBI2D_CHANNELS 2019-03-10 15:39:31 -07:00
Chris Robinson d99d2a400a Don't copy old coeffs in MixHrtfBlendBase 2019-03-10 14:31:46 -07:00
Chris Robinson 80e55b87ed Avoid an extra level of indentation 2019-03-10 12:50:38 -07:00
Chris Robinson 0d295cf811 Don't directly use a buffer for updating source parameters 2019-03-10 11:52:39 -07:00
Chris Robinson e5651c15dd Avoid excessive transformations of the source position 2019-03-10 11:33:08 -07:00
Chris Robinson 12721f94a7 Add a method to apply an HF scale without band-splitting 2019-03-10 10:30:33 -07:00
Chris Robinson 6a95189ef6 Fix for MSVC decaying arrays to pointers with ?: 2019-03-09 21:54:15 -08:00
Chris Robinson 106671d451 Fade out voices that end normally
Sometimes a sound may end with non-0 amplitude, particularly if a buffer queue
underruns. This helps avoid clicks and pops for sources that don't already end
in silence.
2019-03-09 21:32:14 -08:00
Chris Robinson 87479b4b32 Play dummy samples and force a fade out on stopping voices 2019-03-09 18:34:00 -08:00
Chris Robinson ef0f335132 Add a Stopping state for voices
This currently doesn't do much, except have the mixer progress it to Stopped.
It's valid to have without a source or buffers, and in the future will allow
fading out when a source is paused or stopped.
2019-03-09 16:48:07 -08:00
Chris Robinson cde4500e24 Increment the active voice count ahead of playing the sources 2019-03-09 15:04:51 -08:00
Chris Robinson d39cfcc7bb Clear the voice's buffer when detaching from source 2019-03-09 13:20:10 -08:00
Chris Robinson 972a5c0f1d Exclude far-ear IRs for the synthesized -90 degree elevation 2019-03-09 13:00:08 -08:00
Chris Robinson 0e4402b2e1 Avoid some explicit loops 2019-03-05 06:21:09 -08:00
Chris Robinson da9ec374d8 Normalize HRIRs using their maximum RMS 2019-03-04 08:00:04 -08:00
Chris Robinson 90d1e1212b Pass a reference to function for a template parameter 2019-03-03 00:24:33 -08:00
Chris Robinson 2d14de3fb0 Use more specific names for temp buffer storage 2019-03-02 23:41:26 -08:00
Chris Robinson 0aa0f24dd7 Use a proper flag to indicate audio is prepared in alffplay 2019-03-01 22:46:56 -08:00
Chris Robinson e4b76d2627 Reverse the HRTF field array
Most often a sound's distance will be beyond the farthest field measurement, so
It's more efficient to have the farthest field first and avoid looping through
the whole field array for them.
2019-02-27 23:13:40 -08:00
Chris Robinson 86926f0998 Combine the reverb output mixes into a single call 2019-02-25 05:52:37 -08:00
Chris Robinson 8a34bd59b0 Unlock the audio decoder mutex before disabling events in alffplay
The callback may be waiting on the mutex, but disabling the callback needs any
current invocation to finish first.
2019-02-25 02:03:43 -08:00
Chris Robinson 81aa5af3b9 Make sure the reverb fading completes
The processing loop doesn't depend on being aligned anymore, so it won't get
stuck when only less than 4 samples can be done in a non-final update.
2019-02-25 01:08:11 -08:00
Chris Robinson 4d6b66163c Convert the device frequency to float just once 2019-02-24 19:07:21 -08:00
Chris Robinson d6fb4d5f52 Make sure the voice's direct buffer is always set 2019-02-24 19:02:49 -08:00
Chris Robinson d2664e2192 Remove a duplicate index array 2019-02-24 18:00:49 -08:00
Chris Robinson cadff0f6c1 Reduce BUFFERSIZE to match the default period size
Also adds a bit more space to the temp source data buffer, to avoid needing to
loop on matching sample rates.
2019-02-24 16:13:51 -08:00
Chris Robinson a2ba550ebf Rework reverb A/B-Format conversion mixing
This should help improve performance using the optimized mixers, and fewer
passes on the transforms, though at the cost of more memory.
2019-02-24 15:43:56 -08:00
Chris Robinson 4ec0aed286 Change some functions to proper methods 2019-02-23 03:18:12 -08:00
Chris Robinson 42934b09e5 Avoid multiple int-to-float conversions 2019-02-23 01:43:55 -08:00
Chris Robinson 3683e31662 Constify some parameters and remove an explicit loop 2019-02-23 00:01:38 -08:00
Chris Robinson 317206e8f3 Remove the FOAOut mixing buffer and associated post-processes 2019-02-22 22:35:37 -08:00
Chris Robinson 45378fe687 Remove the unused FOAOut EffectTarget 2019-02-22 22:03:04 -08:00
Chris Robinson 5b35e60a98 Apply ambisonic upsampling on reverb output as needed
This isn't the greatest thing since it splits the A-to-B-Format transform from
the panning transform. The A-to-B and HF scale mixes are also not as optimal as
they could be, since they can't use the main mixer functions (wrong buffer line
length).

It does, however, get rid of the final use of the FOAOut buffer, so the
upsampling post-process is no longer needed.
2019-02-22 21:53:45 -08:00
Chris Robinson 6a3c10d850 Ensure reverb fading doesn't end with less than 4 samples 2019-02-22 02:15:22 -08:00
Chris Robinson 6a2cf96448 Avoid some unnecessary local variables 2019-02-22 01:00:57 -08:00
Chris Robinson 01ac6e2e56 Combine reverb transform matrices one column at a time 2019-02-21 19:05:20 -08:00
Chris Robinson 7a9d67934f Mix B-Format sources directly to the dry buffer
Now the only thing that utilizes FOAOut is reverb output.
2019-02-21 17:48:08 -08:00
Chris Robinson 1eea3cb2d1 Remove RESTRICT from the bandsplitter process method
The compiler can see there's no aliasing with the local variables, and the
input/output buffers are handled sequentially one element at a time anyway.
2019-02-21 17:37:02 -08:00
Chris Robinson 169a11dffc Add some preliminary fields for mix-time ambisonic upsampling 2019-02-21 04:57:56 -08:00
Chris Robinson 8ac2d34706 Allow processing some effects in higher order ambisonics
Reverb notably is still only first-order (any higher order channels are
dropped, and it writes to FOAOut). But others, like the equalizer, work on all
available channels.
2019-02-21 04:23:01 -08:00
Chris Robinson a964890537 Add helpers to get the channel count from an ambisonic order 2019-02-21 04:05:49 -08:00
Chris Robinson a35255291f Fix unused parameter warning 2019-02-21 03:54:12 -08:00
Chris Robinson 8d2d7c63da Get rid of the MAX_EFFECT_CHANNELS macro 2019-02-21 03:52:54 -08:00
Chris Robinson 462e320847 Make sure the B2A matrix has enough values for the input count 2019-02-21 03:31:24 -08:00
Chris Robinson d95e144c48 Remove some now-unnecessary ReverbState fields 2019-02-21 03:07:36 -08:00
Chris Robinson 4b4041319d Pass the number of input channels to EffectState::process 2019-02-21 02:57:39 -08:00
Chris Robinson 7e00f646d9 Add a method to get the row of an ambisonic identity transform 2019-02-21 02:13:30 -08:00
Chris Robinson 615446d6d5 Ensure the device's mAmbiOrder is always set appropriately
The Dry target is always ambisonic, so set its order correctly.
2019-02-21 01:23:11 -08:00
Chris Robinson 3966665ca3 Store effect slots in groups of 64
Now that their wet buffers are allocated dynamically, the ALeffectslot object
itself is rather small.
2019-02-20 22:00:26 -08:00
Chris Robinson c43381d811 Allocate the effect slot wet buffer dynamically 2019-02-20 21:01:08 -08:00
Chris Robinson 77ba61ecb3 Partially handle non-periphonic reverb input 2019-02-19 22:55:43 -08:00
Chris Robinson 87902fa3b2 Use the right macro for the number of reverb panning gains 2019-02-19 20:51:10 -08:00
Chris Robinson 194fcb6bb7 Rename MAX_AMBI_COEFFS and MAX_AMBI2D_COEFFS 2019-02-19 15:39:33 -08:00
Chris Robinson a75bc26173 Reduce some indenting 2019-02-19 02:30:01 -08:00
Chris Robinson 2c04095d22 Apply the upsampler's all-pass when mixing the band-split samples 2019-02-19 02:05:35 -08:00
Chris Robinson d713f5f828 Clean up some AmbiUpsampler initialization 2019-02-19 01:59:30 -08:00
Chris Robinson 69ab36cc14 Avoid a temp buffer for the distance compensation delay 2019-02-17 00:43:10 -08:00
Chris Robinson c95d6a5d8c Apply phase correction to the ambisonic decoder HRIRs
This preserves the original phase of the HRIR frequencies for decoding the
ambisonic signal. This should help prevent extra coloration from the band-
splitter used to scale the HF response.
2019-02-16 22:57:38 -08:00
Chris Robinson 69f6f56160 Avoid using internal AL[u]int64 types 2019-02-11 12:16:58 -08:00
Chris Robinson 2fc8461c14 Don't check for __int64 2019-02-11 11:44:35 -08:00
Chris Robinson dac609b29a Move some more functions to alnumeric.h 2019-02-11 11:31:31 -08:00
Chris Robinson 21aaa18c50 Get rid of the FAM_SIZE macro 2019-02-11 11:14:34 -08:00
Chris Robinson 995c9649cb Move some number-related stuff to a separate header 2019-02-11 11:07:06 -08:00
Chris Robinson 69d8c6546d Use std::arrays for HRIR coeffs and values 2019-02-07 08:38:49 -08:00
Chris Robinson b371862fb2 Simply setting a couple indices 2019-02-04 22:17:28 -08:00
Chris Robinson 05cdc2cb30 Use relaxed memory ordering for initializing atomic_flags 2019-02-04 21:28:37 -08:00
Chris Robinson e104f580b3 Use a unique_ptr to store the loaded HrtfEntry 2019-02-04 21:22:43 -08:00
Chris Robinson b7b4cfae2b Fixed alffplay underrun recovery timing 2019-02-04 21:22:43 -08:00
kcat 367191cbfb Merge pull request #269 from gongminmin/FixForVS2019
Fix compiling problems on VS2019 with vc142 toolset
2019-02-04 21:22:16 -08:00
Minmin Gong 41b9d473a2 Fix compiling problems on VS2019 with vc142 toolset
Msvc142 in VS2019 preview 2 doesn't allow std::atomic_flag to be initialized by a bool. Call test_and_set in the constructors instead.
2019-02-04 20:03:18 -08:00
Chris Robinson c25433986a Add missing include 2019-01-29 14:14:52 -08:00
Chris Robinson 613145e900 Calculate the correct evidx for the HRTF B-Format decoder 2019-01-29 03:52:28 -08:00
Chris Robinson 44d72942fb Load and use all available HRTF fields 2019-01-29 00:42:18 -08:00
Chris Robinson 4c740636c2 Pass the distance to GetHrtfCoeffs 2019-01-28 22:22:34 -08:00
Chris Robinson 2d93a9cdb1 Collect HRTF field info into a struct 2019-01-28 20:43:34 -08:00
Chris Robinson df5d238e3d Clean up calculating HRIR indices to blend 2019-01-28 19:39:45 -08:00
Chris Robinson b3fe540c49 Don't normalize HRIRs per-field 2019-01-27 15:50:02 -08:00
Chris Robinson e55f9b42e9 Partially handle ambisonics in alffplay
This is currently really only applicable to Opus-encoded files. It assumes
AmbiX (SN3D normalization, ACN ordering) and only comes into play when the
channel layout is blank. FFmpeg/libavcodec doesn't have a way to detect
B-Format input or what normalization and ordering it uses. Note in particular
.amb files do not play correctly (libavcodec seems to apply a default channel
layout for 4-channel wav-type files, regardless of its channel mask value).
2019-01-27 14:53:46 -08:00
Chris Robinson d7af17ab87 Round the calculated field distance in makehrtf 2019-01-27 14:35:58 -08:00
Chris Robinson f98a24fb8a Don't try to clean up the async ringbuffer if it isn't allocated 2019-01-26 19:29:26 -08:00
Chris Robinson f5e17bafea Fix applied scalars for B-Format source mixing 2019-01-26 17:33:57 -08:00
Chris Robinson 8eab75f312 Update a function comment 2019-01-24 17:05:13 -08:00
Chris Robinson b5569d8455 Slight cleanup for NfcFilterCreate4 2019-01-24 10:22:38 -08:00
Chris Robinson 98be1d1bf5 Make IncRef and DecRef member functions 2019-01-24 10:05:37 -08:00
Chris Robinson 7757789590 Clean up the NFC filters a bit 2019-01-23 16:32:53 -08:00
Chris Robinson ebb46cf4cf Rename a header
To workaround an apparent MSVC error
2019-01-23 15:09:11 -08:00
Chris Robinson 1ec8686407 Add missing includes 2019-01-23 13:46:43 -08:00
Chris Robinson ce3acf4d1b Make hrtf_inc.cpp a proper header 2019-01-23 12:33:18 -08:00
Chris Robinson 8429770c3f Use template declarations for the HRTF mixers 2019-01-23 12:23:05 -08:00
Chris Robinson d3842a632d Use template declarations for the normal mixing functions 2019-01-23 11:21:03 -08:00
Chris Robinson 23179d0bcd Use a template declaration for the resampler functions 2019-01-23 11:11:41 -08:00
Chris Robinson e332ac8528 Use the farthest of multi-field HRTFs 2019-01-22 21:36:40 -08:00
Chris Robinson 3ab4bc5186 Don't install utilities that aren't built 2019-01-22 17:34:45 -08:00
Chris Robinson 5c0dcd1f24 Fix building makehrtf and sofa-info on Windows 2019-01-22 13:17:21 -08:00
Chris Robinson ecafa19bcf Support loading sofa files in makehrtf
The makehrtf utility now requires libmysofa to build. This isn't necessay for
the OpenAL Soft library itself.
2019-01-22 11:24:57 -08:00
Chris Robinson b4a2532ffc Partially allow loading of multi-field HRTFs
Only the first field actually gets used, but all the data is processed when
loading.
2019-01-22 10:27:04 -08:00
Chris Robinson 1565d7e276 Add a sofa-info utility to check sofa files 2019-01-21 10:23:17 -08:00
Chris Robinson c239ae44f8 Add a FindMySOFA cmake module 2019-01-21 10:21:13 -08:00
Chris Robinson d1a8607515 Handle a missing default WASAPI device ID 2019-01-18 17:23:46 -08:00
Chris Robinson 40c6f74bb7 Add front and back methods to FlexArray 2019-01-17 02:23:57 -08:00
Chris Robinson 101be788e1 Replace a couple more C math calls 2019-01-14 22:30:18 -08:00
Chris Robinson 867161d55f Constify some parameters 2019-01-12 21:08:34 -08:00
Chris Robinson 5b382a69b6 Avoid implicit conversions from signed to unsigned 2019-01-12 18:08:43 -08:00
Chris Robinson d64eaba322 Use a flexible array for DirectHrtfState and ALvoice 2019-01-12 01:25:33 -08:00
Chris Robinson ab16671466 Use a flexible array for HrtfHandle and SampleConverter 2019-01-11 22:09:57 -08:00
Chris Robinson f8c2e54b47 Make the min/max/clamp functions constexpr 2019-01-11 21:04:50 -08:00
Chris Robinson 77447fcd54 Add placement operator delete 2019-01-11 20:06:23 -08:00
Chris Robinson 852c5005ab Add a missing include 2019-01-11 08:07:25 -08:00
Chris Robinson 81e7222633 Use a flexible array for the active effect slots 2019-01-11 07:28:44 -08:00
Chris Robinson 8aedaea5fb Add a flexible array template container 2019-01-11 06:00:41 -08:00
Chris Robinson e7d77f5caa Use a vector for ALeffectslotArray 2019-01-09 18:29:22 -08:00
kcat 30184613a5 Merge pull request #264 from ShFil119/impr/cleanup
Cleanup continuation
2019-01-09 17:16:28 -08:00
Filip Gawin f7fe15e1ce Use = default to define trivial dtor/ctor 2019-01-09 19:57:35 +01:00
Filip Gawin 6ddb2c36fc Remove redundant void argument list in function def 2019-01-09 19:43:54 +01:00
Filip Gawin 4169c6f37d Use c++ headers 2019-01-09 19:42:40 +01:00
Chris Robinson 8f35f464a1 Change a true/false ALenum atomic into a bool 2019-01-09 01:06:19 -08:00
Chris Robinson b49c45d3a4 Add prefixes for ALCdevice and ALCcontext 2019-01-09 00:31:57 -08:00
Chris Robinson 673983dc5d Make Create methods for structs with flexible array members ...
... that are used with unique_ptr.
2019-01-08 23:44:08 -08:00
Chris Robinson bc1eeb5df0 Avoid calling unique_ptr::reset with a raw pointer 2019-01-08 23:15:58 -08:00
Chris Robinson 173c97c2db Remove an unused macro 2019-01-08 21:51:56 -08:00
Chris Robinson a46f1f810d Rename ALC_SOFT_loopback2 and renumber its enums 2019-01-08 20:02:36 -08:00
Chris Robinson d7eee03272 Replace a couple more C-style casts 2019-01-08 19:08:03 -08:00
Chris Robinson 0763dfa954 Apply the all-pass separately from the upsampling mix 2019-01-08 18:34:45 -08:00
Chris Robinson edba7da8ab Avoid macros for indexing HF and LF fequency bands 2019-01-08 17:21:22 -08:00
Chris Robinson 0c3662d8b2 Fix some comments and reduce indentation 2019-01-08 17:21:22 -08:00
kcat 009d738c1e Merge pull request #261 from ShFil119/avoid_old_style_casts
Avoid using old style casts
2019-01-08 17:19:15 -08:00
Filip Gawin 0d3a0635d9 Avoid using old style casts
To think about:
examples/alffplay.cpp:600
OpenAL32/Include/alMain.h:295
2019-01-08 19:42:44 +01:00
kcat 2a7f27ca58 Merge pull request #260 from ShFil119/impr/nullptr
Use nullptr in cpp files
2019-01-07 04:36:50 -08:00
Chris Robinson 4d047e2bc1 Use user-defined literals for 64-bit literals 2019-01-07 04:06:40 -08:00
Filip Gawin 0537414baf Use nullptr in cpp files 2019-01-07 12:37:13 +01:00
Chris Robinson 67c9cf8174 Define logging calls to be unlikely 2019-01-07 01:13:06 -08:00
Chris Robinson 648b76ed65 Move some macros to a common header 2019-01-07 01:12:09 -08:00
Chris Robinson 20a5306bdf Clean up some initializers and use of C methods 2019-01-06 21:16:08 -08:00
Chris Robinson fababe76c4 Don't use the dual-band upsampler for basic ambisonic decoding 2019-01-06 17:45:44 -08:00
Chris Robinson f5b6d761ff Apply an all-pass on the existing output when upsampling ambisonics 2019-01-06 06:50:58 -08:00
Chris Robinson 13056b45b0 Revert back to using a band-splitter to increase the HF response
Unfortunately the shelf filter causes issues due to the shelf gain magnitude
creating a varying phase offset. The splitter also creates phase offsets, but
it's consistent regardless of gain.
2019-01-06 05:15:11 -08:00
Chris Robinson d2e34e509b Make the band-splitter and splitter-allpass filters templated
With float and double explicit instantiations
2019-01-06 04:45:35 -08:00
Chris Robinson da3a916042 Replace macros with constexpr inline functions 2019-01-06 04:16:51 -08:00
Chris Robinson 98f3e6a162 Remove an unnecessary undef 2019-01-06 02:49:24 -08:00
Chris Robinson e645d25b62 Use double-precision biquads for the HRTF shelf filters 2019-01-06 00:54:39 -08:00
Chris Robinson 607e778344 Make BiquadFilter a templated class
With explicit instantiations for float and double
2019-01-06 00:53:02 -08:00
Chris Robinson 03aeb7edf6 Use a shelf filter for the HRTF B-Format decoder HF scale 2019-01-06 00:23:15 -08:00
Chris Robinson 3b91010e21 Pass the normalized crossover frequency to the reset method 2019-01-05 22:31:13 -08:00
Chris Robinson aa29bf5933 Remove unnecessary structs and buffers 2019-01-05 22:24:38 -08:00
Chris Robinson 3f35fcc4b5 Simplify MixParams and AmbiUpsampler
Since the dry buffer is always an ambisonic target now
2019-01-05 21:59:04 -08:00
Chris Robinson cff20c2fe8 Use BFormatDec for custom and built-in ambisonic decoding 2019-01-05 19:21:25 -08:00
Chris Robinson 641bbf075d Enable simplified upsampling for AmbiUpsampler 2019-01-05 00:23:06 -08:00
Chris Robinson 6d7e8cf8b0 Simplify the BFormatDec upsampler
Since the only difference applied is a scalar on the high-frequency response, a
B-Format-to-B-Format transcode can be accomplished with a high-shelf filter. A
similar thing can be done with AmbiUpsampler, but only when outputing to
periphonic B-Format.
2019-01-04 22:17:30 -08:00
Chris Robinson 0a6748156d Make sure the OpenSL capture buffer queue has the correct size
The ring buffer size may round up and have more queueable elements than OpenSL
was allocated with, leading to errors when queueing those extra elements. Now
OpenSL allocates the same number of elements that can be written to the ring
buffer.
2019-01-03 18:16:46 -08:00
Chris Robinson 21a17620e3 Fix the ringbuffer write limit
Previously it just limited the returned write space, irrespective of how much
had already been written. The buffer could still be filled up by doing multiple
writes. Now the size is limited by adjusting the read pointer by the real vs
limited difference when calculating the writable space.
2019-01-03 15:54:18 -08:00
Chris Robinson 88c2f11dcf Use DeviceRef and ContextRef when creating a new device and context 2019-01-01 22:44:46 -08:00
Chris Robinson 399dfca1e3 Rename ALCdevice_struct and ALCcontext_struct
A (possibly contentious?) change in the public headers. Those names were never
part of any specification, and I don't know why the struct names differed from
the actual type name. But with C++, which takes the original struct declaration
as the original name, it was affecting the type's internal symbols.

This shouldn't affect user code since ALCdevice_struct and ALCcontext_struct
were never part of the spec. If issues arise from this change, it should be
reported.
2019-01-01 18:13:33 -08:00
Chris Robinson 1630a33567 Use standard unique_lock and lock_guard for the backend lock 2019-01-01 16:42:54 -08:00
Chris Robinson 2f1566e0b4 Add and use a make_unique function 2019-01-01 14:33:01 -08:00
Chris Robinson c36798fd07 Avoid unnecessary extra buffers for filter chains 2019-01-01 02:41:27 -08:00
Chris Robinson e930c70eaa Don't make BiquadFilter's src and dst restrict
There's no technical reason they can't be the same since IIR filters can't be
auto-vectorized anyway.
2019-01-01 00:04:46 -08:00
Chris Robinson a9e71c2668 Handle all input channels in MixDirectHrtf 2018-12-31 23:33:04 -08:00
Chris Robinson 0452c9201d Add a missing include 2018-12-31 20:51:51 -08:00
Chris Robinson 87143b6645 Remove some C-isms from makehrtf
Remove unnecessary typedefs, use C++11 stamndard types and values, avoid
explicit allocations.
2018-12-31 19:54:34 -08:00
Chris Robinson 4c4572ae8a Compile makehrtf as C++ 2018-12-31 18:23:30 -08:00
Chris Robinson d8eecc89e0 Pass a reference to an array instead of a pointer 2018-12-31 18:07:00 -08:00
Chris Robinson 5a9a1c8d7d Further improve HRTF methods to avoid masking in the inner loops 2018-12-31 04:12:20 -08:00
Chris Robinson 5e03941701 Use an atomic bool on things that only take true or false 2018-12-30 21:58:14 -08:00
Chris Robinson 9f5c9a2260 Rename BackendLock to StateLock 2018-12-30 21:38:42 -08:00
Chris Robinson 3df1d185f8 Don't make the backend's lock/unlock methods noexcept 2018-12-29 17:29:52 -08:00
Chris Robinson 24e763f2a1 Get rid of ALCdevice_Lock/Unlock 2018-12-29 14:00:34 -08:00
Chris Robinson bdf7c16cfb Clean up a member name 2018-12-29 13:21:47 -08:00
Chris Robinson 8a84e7b662 Use member functions for the sample and channel converters 2018-12-29 12:26:45 -08:00
Chris Robinson 9b0b722d72 Add missing includes for mem_fn 2018-12-29 03:11:06 -08:00
Chris Robinson 63fc74beaa Don't bother with an explicit Loopback backend type 2018-12-29 02:21:53 -08:00
Chris Robinson 71a4d6db6f Return a unique_ptr for the backend 2018-12-29 02:16:16 -08:00
Chris Robinson 3c637d5fd7 Make the backend type an enum class 2018-12-29 01:38:26 -08:00
Chris Robinson 8fd4477215 Get CoreAudio capture samples in one call 2018-12-28 23:19:49 -08:00
Chris Robinson 3d92e8c4df Convert the backends to use proper inheritence 2018-12-28 22:56:20 -08:00
Chris Robinson 67b874328d Use static_cast instead of reinterpret_cast where possible 2018-12-28 16:13:28 -08:00
Chris Robinson 01ed98c99b Finish turning ancillary backend methods into member functions 2018-12-28 15:09:51 -08:00
Chris Robinson b7f5166d59 Turn even more methods into member functions 2018-12-28 14:06:15 -08:00
Chris Robinson 200e267b81 Turn some more methods into member functions 2018-12-28 12:58:01 -08:00
Chris Robinson 983904bbdc Add a method to prefix logged function names 2018-12-28 12:29:05 -08:00
Chris Robinson aff58265cb Make more methods into member functions 2018-12-27 23:37:24 -08:00
Chris Robinson 28308226e7 Turn more methods into member functions 2018-12-27 21:50:54 -08:00
Chris Robinson 885f68268f Turn more methods into member functions 2018-12-27 20:24:35 -08:00
Chris Robinson 015a4b060b Make some ancillary methods into member functions 2018-12-27 19:38:02 -08:00
Chris Robinson 0f36459028 Use vectors instead of malloc'd buffers 2018-12-27 18:33:49 -08:00
Chris Robinson 465ab11748 Finish renaming backend struct fields 2018-12-27 17:48:02 -08:00
Chris Robinson e48b8c4cda Rename some more struct members for consistency 2018-12-27 17:09:14 -08:00
Chris Robinson 515edc3dee Fix ring buffer vector methods 2018-12-27 15:05:12 -08:00
Chris Robinson f2c2b7c538 Get rid of the unnecessary STATIC_(UP)CAST macros 2018-12-27 14:27:35 -08:00
Chris Robinson 4782d6107d Use a proper constructor/destructor for the ALCbackend base 2018-12-27 13:40:43 -08:00
Chris Robinson 7880f27054 Rename DSound class members for consistency 2018-12-27 13:07:14 -08:00
Chris Robinson 1a4387d137 Return unique_ptrs instead of raw pointers
For the ring buffer, channel converter, and sample converter.
2018-12-27 12:55:43 -08:00
Chris Robinson 323cf58f02 Simplify resampling with CoreAudio capture
The ringbuffer holds the samples from the device, and we use our own converter
for resampling, calling it on demand with data from the ring buffer.
2018-12-27 12:04:18 -08:00
Chris Robinson 4dca2f2ee5 Use a unique_ptr for the AsyncEvents ringbuffer 2018-12-27 10:44:02 -08:00
Chris Robinson be85ab6f82 Rename some ALSA class members for consistency 2018-12-27 10:34:22 -08:00
Chris Robinson c3f370fa41 Constify and reorder a couple device fields 2018-12-27 10:25:09 -08:00
Chris Robinson 7d821551ac Recognize ambix as an alias for acn+sn3d 2018-12-27 01:18:10 -08:00
Chris Robinson d367093c06 Use std::array for appropriate source and listener properties 2018-12-26 22:27:34 -08:00
Chris Robinson a4ac43b602 Avoid a lambda to find a not-null entry in an array 2018-12-26 21:55:39 -08:00
Chris Robinson 8a0295503d Clean up the ring buffer struct and use member functions 2018-12-26 21:22:17 -08:00
Chris Robinson 4f253a935a Handle HRTF coefficients and values by reference where possible 2018-12-26 15:35:05 -08:00
Chris Robinson c5be03b51e Avoid masking in ApplyCoeffs's inner loop
This unfortunately does not apply to NEON, which would need a bit more
reworking of its method.
2018-12-26 14:59:21 -08:00
Chris Robinson 5c449de73f Improve UHJ2 encoding 2018-12-26 13:20:59 -08:00
Chris Robinson 3b9defa4af Improve some post-process handlers 2018-12-26 12:46:01 -08:00
Chris Robinson 5cc545f157 More aggressively try to decrement an effect's refcount in-place 2018-12-26 12:25:34 -08:00
Chris Robinson 38537a35cc Avoid using a local for a temporary 2018-12-25 22:32:30 -08:00
Chris Robinson b2665a503f Do some pre-mixing fading checks once before preparing to mix 2018-12-25 19:54:14 -08:00
Chris Robinson a7c58decfb Add a couple more ASSUMEs for number of channels and sends 2018-12-25 18:49:12 -08:00
Chris Robinson 497226f11e Add an adjust-latency config option for PulseAudio 2018-12-25 17:04:54 -08:00
Chris Robinson 6a8c791e3c Rework the pulseaudio backend to avoid an explicit mixer thread 2018-12-25 16:31:31 -08:00
Chris Robinson 0314370eb5 Cache the process binary path and name 2018-12-25 11:27:22 -08:00
Chris Robinson 208ea76922 Cleanup some includes 2018-12-25 11:09:41 -08:00
Chris Robinson 8336de6653 Rename a couple filter files for consistency 2018-12-25 10:28:02 -08:00
Chris Robinson 9e19acd9e1 Avoid making static local copies of constexpr values 2018-12-25 10:06:17 -08:00
Chris Robinson 63df7cd537 Construct AsyncEvent objects directly in the ringbuffer 2018-12-25 09:32:38 -08:00
Chris Robinson 3b7f668b28 Avoid an intermediate mixing buffer 2018-12-24 20:44:55 -08:00
Chris Robinson fbae41020d Remove extraneous typedef, struct, and enum keywords 2018-12-24 19:29:01 -08:00
Chris Robinson 194e7ff815 Add an in-progress extension to set the effect slot target 2018-12-24 15:52:37 -08:00
Chris Robinson bbf9e6931c Propagate an effectslot target property 2018-12-24 15:17:38 -08:00
Chris Robinson ae86aef4db Provide effect target parameters through a common struct 2018-12-24 13:29:36 -08:00
Chris Robinson cd213fe6b7 Avoid using select() 2018-12-24 09:58:48 -08:00
Chris Robinson 95631aa358 Make the Compressor more class-like 2018-12-24 09:17:00 -08:00
Chris Robinson d49eeb576c Only check ambisonic attributes with B-Format output 2018-12-24 07:33:38 -08:00
Chris Robinson 68352d3188 Apply the limiter before distance compensation 2018-12-24 07:30:01 -08:00
Chris Robinson ef10152361 Assume alignment for some buffers 2018-12-23 20:56:27 -08:00
Chris Robinson 1f966c11ef Add some more ASSUMEs 2018-12-23 17:56:01 -08:00
Chris Robinson 11d815cfd3 Repack some AmbiUpsampler fields for better access patterns 2018-12-23 15:55:12 -08:00
Chris Robinson ba9aba699d Properly rebalance the HF scale with ambisonic upsampling 2018-12-23 10:37:07 -08:00
Chris Robinson 3fe38fed7c Mix effect slot output to the effect target if it's set 2018-12-23 08:51:28 -08:00
Chris Robinson e218999b4f Dynamically sort the effect slots when mixing
This is to be able to support effects that output to other effects. When an
effect outputs to another effect, the former needs to process first, so the
former mixes to the latter's buffer before the latter is processed.

This sorting needs to happen in the mixer because the effect slot's "Target"
property changes asynchronously.
2018-12-22 22:31:26 -08:00
Chris Robinson ebfe818d2e Fix narrowing conversion from double to float 2018-12-22 20:32:00 -08:00
Chris Robinson bfa98be48a Cleanup definitions and declarations in reverb.cpp 2018-12-22 19:31:12 -08:00
Chris Robinson 86caf2683e Constify a parameter 2018-12-22 18:43:34 -08:00
Chris Robinson 334b3a905a Clean up some math stuff 2018-12-22 16:01:14 -08:00
Chris Robinson d4d98e2fe9 Fix for C++11 compatibility
std::array::operator[] isn't constexpr until C++14.
2018-12-22 11:41:03 -08:00
Chris Robinson 10ce121dbd Use a normal delete instead of ll_ringbuffer_free
And use RingBufferPtr in more places
2018-12-22 11:38:38 -08:00
Chris Robinson b955c5cf5d A bit of cleanup for CalcPanningAndFilters 2018-12-22 10:00:06 -08:00
Chris Robinson 87724db6e3 Rename a couple HRTF structs 2018-12-22 09:20:50 -08:00
Chris Robinson 985d03d13d Try to help GetHrtfCoeffs vectorize 2018-12-21 21:07:42 -08:00
Chris Robinson 5e4378f30a Small cleanup for BuildBFormatHrtf 2018-12-21 18:17:59 -08:00
Chris Robinson 3553ce1f67 Don't convert the HRTF decoder virtual speaker positions to radians 2018-12-21 08:55:22 -08:00
Chris Robinson b785d80526 Use a dodecahedron for the ambisonic HRTF decode
Also uses full second-order for "basic" HRTF rendering. Note that the supplied
matrix is full third-order, but only the first- and second-order coefficients
are used. The base matrices are the identical, only differing by the high-
frequency scalars.
2018-12-21 06:32:18 -08:00
Chris Robinson 7744e4ff72 Pass RealMixParams by reference instead of pointer 2018-12-20 13:26:39 -08:00
Chris Robinson 9fde260df9 Fix the type used for another subtraction 2018-12-20 12:29:46 -08:00
Chris Robinson 768ed3cfbb Silence some MSVC warnings 2018-12-20 12:04:34 -08:00
Chris Robinson 837881eb79 Fix the type used for subtraction 2018-12-20 12:03:32 -08:00
Chris Robinson 7dc553350b Clean up most of the compressor loops 2018-12-20 11:46:57 -08:00
Chris Robinson 08b79b9bbf Add an assume_aligned helper 2018-12-20 11:46:40 -08:00
Chris Robinson 10f87c5d26 Use std::accumulate to get the max composited buffer length loaded 2018-12-20 07:10:09 -08:00
Chris Robinson 49ac268334 Add index maps from 2D and 3D 2018-12-20 04:19:35 -08:00
Chris Robinson 8d3f7651c9 Use std::array in place of some C-style arrays 2018-12-20 03:26:46 -08:00
Chris Robinson d18140391a Rename some conversion arrays 2018-12-20 02:46:59 -08:00
Chris Robinson 0214a11024 Use inline methods for the device format sizes 2018-12-19 05:57:36 -08:00
Chris Robinson b49e8985a4 Don't hardcode the channel count from the device ambisonic order 2018-12-19 03:13:15 -08:00
Chris Robinson fbd47961d5 Don't allow FuMa ordering or normalization above third-order 2018-12-19 02:55:21 -08:00
Chris Robinson e2896dc839 Combine handling of attribute processing 2018-12-18 09:27:00 -08:00
Chris Robinson 5243516149 Use the AmbiUpsampler with higher order basic and custom panning
Also allocate the BFormatDec and AmbiUpsampler where they're (re)set.
2018-12-17 07:29:55 -08:00
Chris Robinson 59013b5cb5 Avoid hard-coded scale factors in BFormatDec's upsampler 2018-12-17 07:12:37 -08:00
Chris Robinson a359cb85e6 Mix each frequency band individually for ambisonic upsampling 2018-12-16 22:37:29 -08:00
Chris Robinson 3b0fd20bee Always use the transcode method with the AmbiUpsampler 2018-12-16 21:03:24 -08:00
Chris Robinson 064f4f500a Avoid extraneous alignment requirements 2018-12-16 01:27:52 -08:00
Chris Robinson 741861eaa6 Put the ACN index map in a header
Also put it and the Ambisonic scales in a more appropriate header.
2018-12-15 23:28:49 -08:00
Chris Robinson a6a5634adb Reorder some math terms to help optimizations
Because floating-point math is not associative ((a*b)*c does not necessarily
give the same result as a*(b*c)), the ordering of terms can inhibit reuse of
temporary values. For example, both

coeffs[9]  =  2.091650066f * y * (3.0f*x*x - y*y);
and
coeffs[15] =  2.091650066f * x * (x*x - 3.0f*y*y);

contain x*x and y*y terms that could be calculated once, stored in temporary
registers, and reused to multiply with 3. But since 3.0f*(x*x) would produce
different results, the compiler is not allowed to make that optimization. If,
however, the multiply with 3 is moved to the right side:

coeffs[9]  =  2.091650066f * y * (x*x*3.0f - y*y);
and
coeffs[15] =  2.091650066f * x * (x*x - y*y*3.0f);

in both cases x*x and y*y are calculated first in their respective groups,
guaranteeing the same results for both instances prior to the multiply with 3
and allowing the compiler to reuse those intermediate values.
2018-12-15 20:28:52 -08:00
Chris Robinson dea077cbae Add encoding calculations for fourth-order ambisonics 2018-12-15 19:23:42 -08:00
Chris Robinson e0f635b20d Move some ambisonic-related macros to a separate header 2018-12-15 03:30:47 -08:00
Chris Robinson 0dd13a9dfe Make the AmbDec speaker and matrix arrays dynamic 2018-12-15 02:56:19 -08:00
Chris Robinson 640c06c292 Avoid some explicit loop counts 2018-12-15 01:48:54 -08:00
Chris Robinson 4d36730baa Clean up panning.cpp a bit 2018-12-15 00:38:38 -08:00
Chris Robinson 2d13e0af29 Add macros for the ambisonic order masks 2018-12-14 23:26:44 -08:00
Chris Robinson 0882728dec Cleanup bformatdec.cpp a bit 2018-12-13 22:48:02 -08:00
Chris Robinson d18ae81e9c Add POPCNT32 and CTZ32 macros 2018-12-13 22:05:47 -08:00
Chris Robinson 0d73b13f59 Add more casts for MSVC 2018-12-12 21:58:41 -08:00
Chris Robinson b779ebb512 Fix some MSVC conversion warnings 2018-12-12 21:18:31 -08:00
Chris Robinson b37bc9f8b7 Fix an MSVC warning 2018-12-12 19:24:06 -08:00
Chris Robinson 43f6a7c626 Remove an unused source 2018-12-12 04:34:09 -08:00
Chris Robinson 5a283c66ee Use proper classes for Vector and Matrix types 2018-12-12 04:22:11 -08:00
Chris Robinson 19c5c41c70 Cleanup alu.cpp some 2018-12-12 01:09:04 -08:00
Chris Robinson 0d36ba0fbb Use helpers to get the Ambisonic scales and layout maps 2018-12-10 22:35:32 -08:00
Chris Robinson e87eb07db4 A bit more cleanup 2018-12-10 21:30:22 -08:00
Chris Robinson ed18fd76c5 Clean up a few more loops 2018-12-10 14:49:57 -08:00
Chris Robinson d91ada2e02 Add missing header 2018-12-10 02:13:57 -08:00
Chris Robinson 9bb7ed0129 Put static methods into an anonymous namespace 2018-12-10 02:08:54 -08:00
Chris Robinson 0d56c59f14 Avoid some more explicit loops 2018-12-10 00:01:13 -08:00
Chris Robinson 0a805727db Use std::accumulate to find the max channel count 2018-12-09 18:16:00 -08:00
Chris Robinson b1beb7dfdc Avoid some more explicit loops 2018-12-09 17:24:00 -08:00
Chris Robinson efb8e076c7 Pass a reference to an array for a function parameter 2018-12-09 15:21:24 -08:00
Chris Robinson 6c8f45b5f6 Rename a couple global variables
Avoid clashing with an enum name
2018-12-09 15:07:44 -08:00
Chris Robinson d7d9870839 Add default construction to HrtfEntry 2018-12-09 13:36:13 -08:00
Chris Robinson 621f0dfe73 Use a vector for LoadedHrtfs 2018-12-09 03:04:18 -08:00
Chris Robinson e5db9b2378 Avoid static global initialization functions 2018-12-08 21:58:44 -08:00
Chris Robinson a4009c47e7 Add a cmake option to specify prebuilt native tools
This should only be used with automated build systems that guarantee the native
tools' binaries are up-to-date. Otherwise it's best to leave it alone so it can
automatically rebuild them as needed.
2018-12-08 17:22:10 -08:00
Chris Robinson 30a3a19574 Rename a member variable and inline a function 2018-12-08 16:30:19 -08:00
Chris Robinson c9f5617f06 Avoid several uses of memset 2018-12-08 14:22:20 -08:00
Chris Robinson fc8da0c16b Add missing include 2018-12-08 13:06:31 -08:00
Chris Robinson 5a9a2cb1ed Increase GAIN_MIX_MAX 2018-12-08 04:10:59 -08:00
Chris Robinson 9e9b771e8a A bit more cleanup 2018-12-08 04:10:45 -08:00
Chris Robinson 5ea3c8fb60 Use member functions for BFormatDec and AmbiUpsampler 2018-12-08 02:50:34 -08:00
Chris Robinson 7695afe0cb Clean up some more loops 2018-12-08 02:15:00 -08:00
Chris Robinson a603cc906f Inline a simple method 2018-12-08 00:08:39 -08:00
Chris Robinson ab5a11d5f3 Avoid using the deprecated mem_fun_ref method 2018-12-07 21:46:22 -08:00
Chris Robinson 6e4c856257 Add fourth-order methods to the NFC filter
Unused, but it finishes out the currently possible implementations.
2018-12-07 18:38:56 -08:00
Chris Robinson 0f24139b57 Use a constructor instead of a macro to initialize AsyncEvent 2018-12-06 22:24:20 -08:00
Chris Robinson 42d26472eb Remove some more explicit loops 2018-12-05 17:11:33 -08:00
Chris Robinson e60d0886d0 Use class methods for BandSplitter and SplitterAllpass filters 2018-12-05 15:38:05 -08:00
Chris Robinson 10b39d57d5 Use class methods for the NFC filters 2018-12-05 15:20:52 -08:00
Chris Robinson 164a86a381 Use class methods for the biquad filter 2018-12-04 22:31:08 -08:00
Chris Robinson 36a8b615c8 Avoid using AL types with the filters 2018-12-04 20:55:10 -08:00
Chris Robinson 2a30ae3807 Avoid some more explicit loops in the filters 2018-12-04 20:35:23 -08:00
Chris Robinson 3866c9f941 Avoid more explicit loops 2018-12-04 19:45:11 -08:00
Chris Robinson a94bfd3ec9 Increase the async event queue size 2018-12-04 16:38:22 -08:00
Chris Robinson 6409910543 Handle EventType_BufferCompleted uniquely 2018-12-04 16:33:26 -08:00
Chris Robinson f79b0e24d4 Avoid a few more explicit loops 2018-12-04 15:30:39 -08:00
Chris Robinson a0967967de Read atomic variables in the reverse order they're set 2018-12-04 14:48:08 -08:00
Chris Robinson 31b54eb86a Avoid a few more explicit loops 2018-12-03 01:41:52 -08:00
Chris Robinson 85e83bbdff Use a std::string for the source state change message 2018-12-02 19:34:09 -08:00
Chris Robinson 45b65366bb Improve some checks for compiler analysis 2018-12-02 15:29:26 -08:00
Chris Robinson 60254488e9 Add a couple missing source lock guards 2018-12-02 14:36:53 -08:00
Chris Robinson 4e17ad3ec0 Avoid a few more explicit loops 2018-12-02 13:35:07 -08:00
Chris Robinson 607fb3e632 Use a lambda to apply the NFC mixes 2018-12-01 23:25:34 -08:00
Chris Robinson e1af866a3d Rework source sample counting for mixing a bit 2018-12-01 13:47:56 -08:00
Chris Robinson 255c07def9 Try to pacify MSVC's missing a suitable default constructor 2018-12-01 11:28:11 -08:00
Chris Robinson cc161fe7c1 Add a missing include 2018-12-01 01:12:05 -08:00
Chris Robinson 7b1548af3c Handle source state changed events uniquely in the event loop
To avoid the need of constructing the string in the mixer thread, which is
commonly formatted anyway.
2018-11-30 21:39:59 -08:00
Chris Robinson 1e6e84374b Use std::array for the voice's PrevSamples 2018-11-30 21:23:43 -08:00
Chris Robinson c7569c31ad Improve construction and destruction of ALvoices 2018-11-30 19:04:38 -08:00
Chris Robinson 4b7ac4a6ed Don't bother making ALvoiceProps dynamically sized 2018-11-30 16:56:23 -08:00
Chris Robinson 364850e8f9 Move a variable declaration to a more appropriate place 2018-11-30 10:08:18 -08:00
Chris Robinson b582f1346a Avoid hard-coding a couple sizes 2018-11-29 22:56:33 -08:00
Chris Robinson 8ca8da30bd Store the source ID with the voice instead of the source pointer 2018-11-29 22:49:01 -08:00
Chris Robinson 0d2bbe17f2 Rename a function for consistency 2018-11-29 13:34:06 -08:00
Chris Robinson c5d5d574e6 Reorganize some device members 2018-11-29 13:10:46 -08:00
Chris Robinson 57bb467072 Pass the desired resampler to CreateSampleConverter 2018-11-28 23:19:25 -08:00
Chris Robinson e017d9e40f Clean up the converter a bit 2018-11-28 22:42:46 -08:00
Chris Robinson 5df89c504e Remove an improper Connected check 2018-11-28 19:29:20 -08:00
Chris Robinson 38f4a0cf2c Avoid the update size going to 0 with a relatively large device period 2018-11-28 18:45:35 -08:00
Chris Robinson c3c0a5022a Don't bother with (really) old pulseaudio headers 2018-11-28 15:09:19 -08:00
Chris Robinson 14d746e7c2 Don't sever a paused source from its voice on disconnect 2018-11-28 14:38:26 -08:00
Chris Robinson 598851fed7 Attempt to reconnect lost devices with alcResetDeviceSOFT
Be aware there's currently possible race conditions with PulseAudio's callbacks
(the state callbacks need to be cleared while not playing).

Also paused sources will assert/crash if attempted to play again without being
explicitly stopped or rewound first.

Both of these will eventually be fixed (though a paused source's offset will be
lost regardless).
2018-11-28 12:24:12 -08:00
Chris Robinson 16aa3ab196 Reduce some indentation 2018-11-28 11:55:43 -08:00
Chris Robinson ed2e456dfb Avoid some explicit loops 2018-11-28 11:30:44 -08:00
Chris Robinson 8d95b6a0f2 Avoid an unnecessary lambda 2018-11-28 08:42:30 -08:00
Chris Robinson ec2927cd32 Small cleanup for ~ALCcontext_struct 2018-11-27 21:19:30 -08:00
Chris Robinson ff8c694957 Clean up the JACK backend 2018-11-27 20:29:54 -08:00
Chris Robinson 0116e763ea Add a unique_ptr alias for the ringbuffer 2018-11-27 19:49:45 -08:00
Chris Robinson 2179388430 Remove unneeded mutex checks 2018-11-27 15:23:18 -08:00
Chris Robinson c2da83dea8 Avoid alsem* wrappers for al::semaphore 2018-11-27 14:52:04 -08:00
Chris Robinson 89abbe8d94 Replace last uses of alsem_t with al::semaphore 2018-11-27 14:05:56 -08:00
Chris Robinson f26083e9ed Make and use a semaphore class 2018-11-27 13:41:30 -08:00
Chris Robinson 3f745be1dc Return a signed integer from altime_get 2018-11-27 12:11:11 -08:00
Chris Robinson ff6dda06ad Add the appropriate include for the _POSIX_TIMERS macro 2018-11-27 10:35:00 -08:00
Chris Robinson 07670ed36a Swap context references in the move assignment 2018-11-27 10:08:25 -08:00
Chris Robinson ee2d756d94 Disable MSVC warning C4065
"switch statement contains 'default' but no 'case' labels"
2018-11-27 00:04:55 -08:00
Chris Robinson 9b2b83f99c Fix use of clock_gettime 2018-11-27 00:02:31 -08:00
Chris Robinson 2530370ff2 Avoid relying on struct timespec 2018-11-26 23:45:04 -08:00
Chris Robinson d7d99adc91 Avoid including threads.h in the example helpers 2018-11-26 23:18:51 -08:00
Chris Robinson d06f76957c Remove althrd_yield 2018-11-26 23:06:49 -08:00
Chris Robinson 4c1fc3ae00 Remove unused almtx stuff 2018-11-26 22:36:55 -08:00
Chris Robinson 2d45ec8dc3 Use a standard mutex for the remaining locks 2018-11-26 22:06:53 -08:00
Chris Robinson 68eef6abb4 Use a standard mutex for the source and effect slot locks 2018-11-26 21:50:48 -08:00
Chris Robinson 2e73c2ca92 Use a standard mutex for the proplock 2018-11-26 21:39:31 -08:00
Chris Robinson d8b9230ee4 Use a standard mutex for the backend lock 2018-11-26 21:39:31 -08:00
Chris Robinson b108d0acfd Remove the last remaining uses of althrd_t 2018-11-26 21:39:31 -08:00
kcat 7860a11ae2 Merge pull request #249 from wangwenx190/patch-win10-sdk
Support build with latest Win10 SDK
2018-11-26 21:39:05 -08:00
wangwenx190 00ad4a2f5d Update FindWindowsSDK.cmake 2018-11-27 13:20:04 +08:00
wangwenx190 9070426ece Update FindWindowsSDK.cmake
Support latest Win10 SDK.
2018-11-27 13:18:30 +08:00
Chris Robinson 9ac76c0a7f Simplify some binary search lookups 2018-11-26 20:55:00 -08:00
Chris Robinson bf9db1fe3d Remove althrd_t from Windows 2018-11-26 20:34:16 -08:00
Chris Robinson ecab90802a Replace some uses of althrd_t with std::thread 2018-11-26 20:06:22 -08:00
Chris Robinson 05390fa827 Add a missing std::begin 2018-11-26 19:01:14 -08:00
Chris Robinson 75b39cafc8 Get rid of some unnecessary functions 2018-11-26 18:25:29 -08:00
Chris Robinson df3dcc879f Get rid of the last ATOMIC macro uses 2018-11-26 18:19:58 -08:00
Chris Robinson 461ef4196e Avoid using ATOMIC_LOAD on ALCdevice::Connected 2018-11-26 18:07:52 -08:00
Chris Robinson 1a9edd4e35 Use a unique_ptr for the QSA backend data 2018-11-26 17:53:56 -08:00
Chris Robinson 04c2802a82 Rename some struct members 2018-11-26 17:31:04 -08:00
Chris Robinson 04cbdbd569 Remove some unused macros 2018-11-26 14:53:20 -08:00
Chris Robinson 053599b243 Avoid using the ATOMIC() macro 2018-11-26 14:48:26 -08:00
Chris Robinson a6923790fa Avoid using ATOMIC_INIT 2018-11-26 14:31:54 -08:00
Chris Robinson 5b2b96b245 Don't explicitly clear vector objects in the destructor 2018-11-25 17:51:39 -08:00
Chris Robinson 127ec026e7 Automatically clean up filters and effects with their sublists 2018-11-25 16:16:40 -08:00
Chris Robinson 8ae07ad1ae Automatically clean up buffers with ther sublist 2018-11-25 15:30:32 -08:00
Chris Robinson 05845b53e8 Clean up MixSource 2018-11-25 13:20:26 -08:00
Chris Robinson ad2639248a Avoid another DECL_TEMPLATE macro 2018-11-25 10:52:17 -08:00
Chris Robinson adcdb8ce64 Fix an incorrect function call 2018-11-25 09:27:50 -08:00
Chris Robinson ec97360352 Avoid a separate function to clean up effect slots 2018-11-25 09:23:01 -08:00
Chris Robinson bf4518fe5c Atuomatically clean up sources with its sublist's destruction 2018-11-25 08:42:43 -08:00
Chris Robinson 7c0605f09e Properly initialize the sublists' freemask 2018-11-25 07:40:15 -08:00
Chris Robinson f5f2cdaaf3 Add a POPCNT64 macro
To count the number of 1/on bits in a 64-bit value
2018-11-24 21:16:53 -08:00
Chris Robinson 71660df5e5 Move bs2b.h to a more appropriate place 2018-11-24 19:54:30 -08:00
Chris Robinson 377325e794 Use C++ methods a bit more 2018-11-24 19:16:21 -08:00
Chris Robinson 9e10f632c7 Replace remaining uses of std::vector with al::vector
Which uses a custom allocator that uses our allocation functions.
2018-11-24 16:58:49 -08:00
Chris Robinson 16a60dc371 Avoid an extraneous boolean 2018-11-24 15:30:28 -08:00
Chris Robinson bd8db0d27b Make GetContextRef return a ContextRef 2018-11-24 14:07:32 -08:00
Chris Robinson 62d38b1187 Use RAII in alEffect.cpp 2018-11-24 13:23:27 -08:00
Chris Robinson 6a84a2ca61 Fix a couple comments 2018-11-24 12:09:37 -08:00
Chris Robinson d83cff02e5 Ensure an enum is the appropriate size/type 2018-11-24 11:41:50 -08:00
Chris Robinson b508a760c8 Use a normal vector to store buffer data 2018-11-24 10:07:48 -08:00
Chris Robinson 505e535655 Use RAII more with alFilter.cpp 2018-11-24 09:40:13 -08:00
Chris Robinson 48154c94d7 Use a unique_ptr while opening a device 2018-11-23 20:16:34 -08:00
Chris Robinson a7c556f814 Use RAII for device references 2018-11-23 17:54:12 -08:00
Chris Robinson df057d4118 Make the context VoiceCount atomic 2018-11-23 16:16:31 -08:00
Chris Robinson 73528c9f55 Fix an incorrect check 2018-11-23 14:42:02 -08:00
Chris Robinson fb94cdcfd3 Restructure and clean up alu.cpp a bit 2018-11-23 13:12:48 -08:00
Chris Robinson 438e626993 Avoid a couple explicit loops 2018-11-22 22:53:22 -08:00
Chris Robinson 976e49711b Add noexcept to a bunch of inline functions 2018-11-22 19:47:41 -08:00
Chris Robinson 30ee6e1b3f Make a DirectHrtfState constructor to try appeasing MSVC 2018-11-22 14:36:37 -08:00
Chris Robinson d26b5d9467 Use proper time types for the device clock time and latency 2018-11-22 14:32:48 -08:00
Chris Robinson 84f0f74d07 Use standard types for the device clock times 2018-11-22 12:53:16 -08:00
Chris Robinson bb9d8db73c Clean up alSource.cpp some 2018-11-22 12:02:02 -08:00
Chris Robinson cc938c34b2 Clean up the Chorus a little 2018-11-22 08:08:46 -08:00
Chris Robinson 9c155a57fb Use unique_ptr for DirectHrtfState 2018-11-22 07:54:29 -08:00
Chris Robinson ba8c865513 Add and use a macro to define placement-new-only allocators
This is for structs that utilize over-allocation, either flexible array
members, or which store optional additional objects in the same allocation
block.
2018-11-22 07:06:42 -08:00
Chris Robinson ab6db9a589 Clean up some unnecessary specifiers 2018-11-22 06:59:32 -08:00
Chris Robinson 9d73e03aaa Use unique_ptr for bs2b 2018-11-22 06:49:37 -08:00
Chris Robinson b3b4220182 Use unique_ptr for BFormatDec and AmbiUpsampler 2018-11-22 05:37:35 -08:00
Chris Robinson 671ed1abf8 Use a unique_ptr for the FrontStablizer 2018-11-22 04:53:29 -08:00
Chris Robinson cc3e2a838f Use a unique_ptr for the Compressor 2018-11-21 16:46:52 -08:00
Chris Robinson eefc379a23 Use a unique_ptr for Uhj2Encoder 2018-11-21 15:31:32 -08:00
Chris Robinson dfcc98afbf Fix deleting the same buffer ID multiple times in one call 2018-11-21 11:51:34 -08:00
Chris Robinson d20522166e Use RAII more in alSource.cpp 2018-11-21 11:11:25 -08:00
Chris Robinson 9f2a77f788 Use RAII when handling the mixer's FPU state 2018-11-21 09:07:02 -08:00
Chris Robinson 8f43f737ba Avoid using ATOMIC macros 2018-11-21 07:52:17 -08:00
Chris Robinson de4bb7aca1 Replace a couple more almtx_lock/unlock calls 2018-11-21 06:41:49 -08:00
Chris Robinson 75213ee6f9 Always use RAII with EffectSlotLock 2018-11-21 05:35:47 -08:00
Chris Robinson 757c42c74b Use a normal vector for the distance buffer storage 2018-11-21 05:06:31 -08:00
Chris Robinson 4c64fa1e4e Make VerifyContext return a context reference 2018-11-21 02:02:53 -08:00
Chris Robinson 8ec25da12e Rename a method to be clearer about its behavior 2018-11-21 00:40:41 -08:00
Chris Robinson ed06169569 Use RAII locks with the BackendLock 2018-11-20 23:42:21 -08:00
Chris Robinson d64d64d4a5 Use an enum class for AmbiLayout/Norm settings 2018-11-20 22:47:24 -08:00
Chris Robinson dc8ef8264a Try to improve alffplay underrun device time adjustment 2018-11-20 12:32:42 -08:00
Chris Robinson f3e01ae9d4 Use a normal vector for the source send properties 2018-11-20 12:25:15 -08:00
Chris Robinson a111254c26 Use C++ more in alListener.cpp 2018-11-20 11:17:54 -08:00
Chris Robinson f9e969a339 Use a standard mutex for the event callback lock 2018-11-20 10:55:57 -08:00
Chris Robinson 191ea90de3 Use atomic_flags and atomic<bools>s where appropriate 2018-11-20 10:45:01 -08:00
Chris Robinson 1e31ac469e Store effect slots as unique_ptrs 2018-11-20 10:01:20 -08:00
Chris Robinson 29558c091b Use C++ more in alAuxEffectSlot.cpp 2018-11-20 09:47:49 -08:00
Chris Robinson 1df42c4a0f Use a unique_ptr for the default effect slot 2018-11-20 05:01:08 -08:00
Chris Robinson 66fdd027d0 Use more C++ templates instead of DECL_TEMPLATE tricks 2018-11-20 03:35:41 -08:00
Chris Robinson c7472f8642 Use C++ templates instead of macro definitions more 2018-11-20 02:59:02 -08:00
Chris Robinson 16d0e79db7 Add compile-time traits for FmtType enum values 2018-11-20 02:42:49 -08:00
Chris Robinson 457d484872 Use C++ templates instead of macro-defined variations 2018-11-20 02:12:04 -08:00
Chris Robinson 5881cd2183 Add compile-time traits for DevFmtType enum values 2018-11-20 02:01:03 -08:00
Chris Robinson eb2937de84 Avoid another case of a variable named the same as a type 2018-11-19 23:48:45 -08:00
Chris Robinson 288dbbe886 Use default initialization for the reverb effect state 2018-11-19 22:48:56 -08:00
Chris Robinson 8995306203 Use proper templating for the modulator's Modulate function 2018-11-19 22:43:28 -08:00
Chris Robinson 8472a9d916 Use proper inheritence for the effect state objects 2018-11-19 22:34:26 -08:00
Chris Robinson 6ac84c7a5f Clean up the remaining effect struct member names 2018-11-19 21:04:50 -08:00
Chris Robinson 67da3850cb Use a normal vector for the echo buffer 2018-11-19 20:15:40 -08:00
Chris Robinson a346380e2b Clean up more effects' struct members 2018-11-19 19:57:30 -08:00
Chris Robinson 7f3584ec4c Fix the reverb buffer size calculation 2018-11-19 19:13:44 -08:00
Chris Robinson 4810def613 Use a normal vector for the chorus sample buffer 2018-11-19 19:08:30 -08:00
Chris Robinson ba33f6a7a4 Clean up the chorus/flanger struct members 2018-11-19 18:51:01 -08:00
Chris Robinson 3ae1c78d1a Use std::isfinite instead of isfinite 2018-11-19 09:51:29 -08:00
Chris Robinson ddfed7187f Use a regular vector for the reverb sample buffer 2018-11-19 09:36:59 -08:00
Chris Robinson 55637ff1fc Rename reverb struct members 2018-11-19 09:29:22 -08:00
Chris Robinson 387a34ca00 Clean up the biquad filter a bit 2018-11-19 09:10:36 -08:00
Chris Robinson 07386e79de Fix up the struct member names in the autowah effect 2018-11-19 09:06:17 -08:00
Chris Robinson f51f6703d8 Add a missing include 2018-11-19 06:50:37 -08:00
Chris Robinson c5c537cc5f Use proper inheritence for EffectStateFactory 2018-11-19 06:43:37 -08:00
Chris Robinson f0cc34a60e Use a vector to handle mixing buffer storage 2018-11-19 06:22:09 -08:00
Chris Robinson f766437569 Fix a couple incorrect uses of ringbuffer pointer data 2018-11-19 05:07:09 -08:00
Chris Robinson ac2a420351 Remove the ATOMIC_THREAD_FENCE macro 2018-11-19 05:04:17 -08:00
Chris Robinson ad5f9d9b22 Return the ringbuffer data pointers as a pair 2018-11-19 04:46:49 -08:00
Chris Robinson a14f39ea06 Make ll_ringbuffer_write/read take void*/const void* 2018-11-19 04:11:21 -08:00
Chris Robinson c01743fe5d Remove the CONST_CAST hack 2018-11-19 03:53:31 -08:00
Chris Robinson e6c2c1f3b6 Remove unnecessary using statements 2018-11-19 03:32:16 -08:00
Chris Robinson e24435ef58 Remove the atomic exchange macros 2018-11-19 03:21:58 -08:00
Chris Robinson c5142530d6 Simplify the RefCount type 2018-11-19 02:17:06 -08:00
Chris Robinson 6e114a7a70 Replace ATOMIC_REPLACE_HEAD with an inline function 2018-11-19 01:20:03 -08:00
Chris Robinson 190de1452e Remove the unused vector macros 2018-11-18 23:37:56 -08:00
Chris Robinson dbf2381a3b Use a normal vector in the QSA backend 2018-11-18 23:23:12 -08:00
Chris Robinson e0d0faaa63 Use a normal vector for filter sublists 2018-11-18 23:02:31 -08:00
Chris Robinson 362979cefb Use a normal vector for effect sublists 2018-11-18 22:50:04 -08:00
Chris Robinson 81aed2ea01 Use a normal vector for buffer sublists 2018-11-18 22:31:51 -08:00
Chris Robinson becbaab2dc Remove some unnecessary static specifiers 2018-11-18 22:14:44 -08:00
Chris Robinson e23796aabe Use a standard string for the enumerated HRTF names 2018-11-18 21:18:19 -08:00
Chris Robinson 140c139852 Use a standard string for the device's HRTF name 2018-11-18 19:28:01 -08:00
Chris Robinson 2c06ec7093 Use a regular vector for the enumerated HRTF list 2018-11-18 19:19:35 -08:00
Chris Robinson bafcba7194 Use a std::string for the device name 2018-11-18 18:45:45 -08:00
Chris Robinson b10e7d08c3 Use a std::thread for the event thread 2018-11-18 18:04:27 -08:00
Chris Robinson ef7995cfd0 Fix the initial device refcount 2018-11-18 08:14:23 -08:00
Chris Robinson aef52be432 Fix a float constant type 2018-11-18 08:03:22 -08:00
Chris Robinson 8b8f01e25d Avoid more cases of an enum variable and type name clash 2018-11-18 08:01:50 -08:00
Chris Robinson 336b7b7799 Use constructors/destructors with ALCdevice
As with ALCcontext, this is really ALCdevice_struct because of the way it's
declared in the public header.
2018-11-18 07:33:42 -08:00
Chris Robinson 1bc88ed751 Avoid a fixed-size string buffer 2018-11-18 07:00:43 -08:00
Chris Robinson 5bbddff2f3 Separate class and variable definitions 2018-11-18 06:46:50 -08:00
Chris Robinson e194d896de Use constructors/destructors for ALeffectslot 2018-11-18 06:35:45 -08:00
Chris Robinson ad82a70a65 Use cleaner constructor/destructor calls for ALCcontext
Note that the actual type name is ALCcontext_struct, because of how it's
defined in AL/alc.h (ALCcontext is just an alias to struct ALCcontext_struct).
2018-11-18 05:40:00 -08:00
Chris Robinson de13f30e28 Improve audio underrun recordery in alffplay
Now it has a better idea to skip samples during refill instead of after
restarting.
2018-11-18 05:38:03 -08:00
Chris Robinson 0851dc12b4 Remove an unused typedef 2018-11-18 04:26:28 -08:00
Chris Robinson f48be9d73b Remove the pointer-specific atomic exchange macros 2018-11-18 03:59:39 -08:00
Chris Robinson 7433cb5f4c Avoid naming a struct member the same as an enum type 2018-11-18 03:39:32 -08:00
Chris Robinson bf30eb0391 Use std::isfinite instead of the global isfinite 2018-11-18 03:25:32 -08:00
Chris Robinson 310770c531 Add and use new/delete operators to ALeffectslot 2018-11-18 02:52:46 -08:00
Chris Robinson 3eededf5d6 Use a normal vector for auxiliary effect slots 2018-11-18 02:39:27 -08:00
Chris Robinson 7b95712f38 Use a proper vector for the source sublists 2018-11-18 02:15:31 -08:00
Chris Robinson 4dc8f44d00 Move the alignment-aware allocator and vector to headers 2018-11-18 01:33:26 -08:00
Chris Robinson d7cc9b912b Use new/delete for ALCcontext objects 2018-11-18 00:38:31 -08:00
Chris Robinson 38d6df9c1d Store the listener directly in the context 2018-11-17 23:41:11 -08:00
Chris Robinson e79d9bdd1a Move the vector and matrix declarations to a separate header 2018-11-17 23:21:37 -08:00
Chris Robinson fa3c34268d Move the ALCcontext definition to its own header 2018-11-17 23:02:27 -08:00
Chris Robinson 8f6e0f97ec Try to clear up an MSVC warning 2018-11-17 21:48:54 -08:00
Chris Robinson 20e62aa959 Avoid an explicit static_cast to bool 2018-11-17 20:39:45 -08:00
Chris Robinson d10301c209 Remove unused headers and checks 2018-11-17 19:52:54 -08:00
Chris Robinson 1ac41d3ea0 Convert almalloc.c to C++ 2018-11-17 19:01:10 -08:00
Chris Robinson 8c69fb046c Always use C++11 atomics 2018-11-17 18:56:00 -08:00
Chris Robinson 1468dee831 Convert bs2b.c to C++ 2018-11-17 18:54:10 -08:00
Chris Robinson 9992cef915 Remove now unneeded inldefs.c
All code using inline functions is now C++, so will generate callable functions
as-needed.
2018-11-17 17:52:23 -08:00
Chris Robinson 7f69dbb517 Convert the mixers to C++ 2018-11-17 17:49:55 -08:00
Chris Robinson 2d4ff77410 Remove ASSUME_ALIGNED
It's become a liability with C++ since it returns void* instead of the input
pointer type, and it doesn't seem to help optimizations anyway (auto-
vectorization still produces unaligned loads and stores).
2018-11-17 17:35:52 -08:00
Chris Robinson e5442db803 Convert the filters to C++ 2018-11-17 17:22:32 -08:00
Chris Robinson ed5d222eed Remove the old unused bsincgen.c 2018-11-17 07:50:46 -08:00
Chris Robinson 057b1411f9 Convert ringbuffer.c to C++ 2018-11-17 07:45:10 -08:00
Chris Robinson ff4219e54e Convert mastering.c to C++ 2018-11-17 07:40:10 -08:00
Chris Robinson 6e6a024058 Convert converter.c to C++ 2018-11-17 07:35:11 -08:00
Chris Robinson 13478126cb Convert the remaining effects to C++ 2018-11-17 07:08:41 -08:00
Chris Robinson 93d96ced9c Convert the dedicated, distortion, echo, and equalizer to C++ 2018-11-17 06:53:20 -08:00
Chris Robinson ad34855a2b Add a couple missing includes 2018-11-17 06:11:55 -08:00
Chris Robinson 7b537c795b Don't pass the current thread to althrd_setname 2018-11-17 06:07:04 -08:00
Chris Robinson 1fae8c16a8 Convert threads.c to C++
Also vastly simplify and remove related code.
2018-11-17 05:31:29 -08:00
Chris Robinson ccdaca80c9 Use standard complex types instead of custom 2018-11-17 04:14:57 -08:00
Chris Robinson 09943683b5 Remove some more unused stuff 2018-11-17 02:41:21 -08:00
Chris Robinson b485cbe53a Make the Hann windows const 2018-11-17 02:30:41 -08:00
Chris Robinson b69b3bd89f Convert fshifter.c to C++ 2018-11-17 01:58:38 -08:00
Chris Robinson aa66ed0ea5 Convert modulator.c to C++ 2018-11-17 01:53:39 -08:00
Chris Robinson a7d3c24b51 Convert null.c to C++ 2018-11-17 01:49:26 -08:00
Chris Robinson 557048afa2 Convert pshifter.c to C++ 2018-11-17 01:36:47 -08:00
Chris Robinson f1731af282 Remove unneeded declarations and definitions 2018-11-17 01:29:35 -08:00
Chris Robinson 3bbfd0c099 Fix compilation with MSVC 2018-11-16 23:01:40 -08:00
Chris Robinson 1bd40d9434 Put a lambda in the call_once call
This optimizes better and avoids a visible symbol (templating to an anonymous
lambda type will generate a unique anonymous instantiation, making inlining
more likely, whereas passing a general function pointer/reference type will
likely use or generate a publically available instance).
2018-11-16 22:41:04 -08:00
Chris Robinson de8d8b5216 Remove unused altss types and methods 2018-11-16 22:12:35 -08:00
Chris Robinson ee8e6733e1 Avoid using C-style TLS 2018-11-16 21:55:11 -08:00
Chris Robinson 8410e71a34 Convert the reverb effect to C++ 2018-11-16 21:31:52 -08:00
Chris Robinson a68d0b68d7 Convert mixvoice.c to C++ 2018-11-16 20:46:50 -08:00
Chris Robinson 53373a43b8 Convert ALu.c to C++
Required changes to bsincgen to generate C++-friendly structures.
2018-11-16 20:32:19 -08:00
Chris Robinson 317acd6ae2 Convert alEffect.c and alFilter.c to C++ 2018-11-16 18:44:43 -08:00
Chris Robinson a15a678da6 Convert alListener.c to C++ 2018-11-16 18:37:55 -08:00
Chris Robinson 0e0fe15b98 Convert alAuxEffectSlot.c to C++ 2018-11-16 18:28:39 -08:00
Chris Robinson ce370be52b Remove some unneeded includes 2018-11-16 08:09:56 -08:00
Chris Robinson 50f36d39f7 Use lock_guard instead of manual lock/unlock calls 2018-11-16 07:11:27 -08:00
Chris Robinson 165c162d01 Convert alState.c to C++ 2018-11-16 06:48:33 -08:00
Chris Robinson 436db28a3f Convert alError.c to C++ 2018-11-16 06:24:24 -08:00
Chris Robinson 8be45fe8a5 Convert alExtension.c to C++ 2018-11-16 06:08:25 -08:00
Chris Robinson fedd5ebbea Convert event.c to C++ 2018-11-16 06:00:28 -08:00
Chris Robinson 5cdd28c736 Convert sample_cvt.c to C++ 2018-11-16 05:24:15 -08:00
Chris Robinson 02eae1123f Use iterators instead of indexed loops 2018-11-16 05:23:42 -08:00
Chris Robinson fc8191012a Cleanup some syntax in alc.cpp 2018-11-16 00:06:54 -08:00
Chris Robinson 7a06a54af7 Simplify a couple checks 2018-11-15 23:58:34 -08:00
Chris Robinson a727978eb9 Remove unused declarations and definitions 2018-11-15 23:55:23 -08:00
Chris Robinson 7ef7477a13 Convert the PortAudio backend factory 2018-11-15 23:50:15 -08:00
Chris Robinson 78eb68a89f Convert the WinMM backend factory 2018-11-15 23:41:09 -08:00
Chris Robinson 2ca6119e0e Convert the DSound backend factory 2018-11-15 23:32:28 -08:00
Chris Robinson 5dc1956e18 Convert the QSA backend factory 2018-11-15 23:10:06 -08:00
Chris Robinson c78b42fb4e Convert the OSS backend factory 2018-11-15 23:02:26 -08:00
Chris Robinson 7884cec02b Convert the SndIO backend factory 2018-11-15 22:36:49 -08:00
Chris Robinson 271cfcf8e3 Convert the Solaris backend factory 2018-11-15 22:23:29 -08:00
Chris Robinson d73d01548d Convert the SDL2 backend factory 2018-11-15 22:15:10 -08:00
Chris Robinson 2a839e5762 Convert the JACK backend factory 2018-11-15 22:03:20 -08:00
Chris Robinson d4928d4e7d Convert the Wave Writer backend factory 2018-11-15 21:53:14 -08:00
Chris Robinson cc113ce6ab Convert the OpenSL backend factory 2018-11-15 21:42:17 -08:00
Chris Robinson 9d43b548cc Convert the ALSA backend factory 2018-11-15 21:33:44 -08:00
Chris Robinson ead830814b Convert the CoreAudio backend factory 2018-11-15 21:24:09 -08:00
Chris Robinson b1fb2e9e14 Convert the WASAPI backend factory 2018-11-15 21:14:20 -08:00
Chris Robinson e716c7b988 Convert the PulseAudio backend factory 2018-11-15 19:57:21 -08:00
Chris Robinson 4311c609e4 Update the loopback backend 2018-11-15 19:42:13 -08:00
Chris Robinson 49d8ac2537 Start a new backend factory API
Using proper class inheritance. Be aware this breaks all backends except null
(and loopback). They will be restored individually in due time.
2018-11-15 19:15:14 -08:00
Chris Robinson 7c93308771 Remove checks for functions that always exist
They're part of C++11 and available on the testing systems. If some system has
trouble, switching to proper C++ calls should fix it.
2018-11-15 17:53:05 -08:00
Chris Robinson dc622b3182 Use std::isfinite from the cmath header 2018-11-15 06:48:52 -08:00
Chris Robinson a3b644374b Add a missing cast for MSVC 2018-11-15 06:48:00 -08:00
Chris Robinson 245b7ff0b4 Remove the unused al_string API 2018-11-15 06:32:01 -08:00
Chris Robinson 7b3a2085aa Use a regular char* for the device's name 2018-11-15 06:23:01 -08:00
Chris Robinson ab9f8162b8 Pass a normal const char* to EnumerateHrtf 2018-11-15 05:38:27 -08:00
Chris Robinson 9d9d626d99 Avoid some more uses of al_string 2018-11-15 05:33:02 -08:00
Chris Robinson 08bee7cb58 Search the right list for WASAPI name duplicates 2018-11-15 04:35:35 -08:00
Chris Robinson 17161131e5 Remove an unused extern inline 2018-11-15 04:28:47 -08:00
Chris Robinson 1971d0f5c6 Use std::string instead of al_string for enumerating 2018-11-15 04:24:33 -08:00
Chris Robinson d4f64b9e29 Use a C++ mutex with the device backend base 2018-11-15 03:49:59 -08:00
Chris Robinson b7daddb564 Try to clean up compat.h's macro block spaghetti a bit 2018-11-15 03:29:56 -08:00
Chris Robinson 8f771a0387 Convert alSource.c to C++ 2018-11-15 03:13:54 -08:00
Chris Robinson 27e7168ad4 Only declare the device backend stuff with C++ 2018-11-15 02:36:05 -08:00
Chris Robinson 1d2cc90175 Use C++ more in the OSS backend 2018-11-14 20:49:08 -08:00
Chris Robinson 83dec6b975 Use a C++ vector for enumerated OSS devices 2018-11-14 19:16:50 -08:00
Chris Robinson 3b1b029a75 Remove some now-unused function checks 2018-11-14 17:08:14 -08:00
Chris Robinson c4d3444a6d Use std::pow and std::log2 2018-11-14 17:03:04 -08:00
Chris Robinson 46301a087c Use C++ a bit more with alc.cpp 2018-11-14 06:17:47 -08:00
Chris Robinson 3021a426c0 Convert ALc.c to C++ 2018-11-14 04:15:44 -08:00
Chris Robinson dfcb6d3e6d More clearly check if the buffer is not empty 2018-11-14 02:41:21 -08:00
Chris Robinson b15dcea4bb Move extern inline declarations to their own C source 2018-11-14 00:07:50 -08:00
Chris Robinson 6ae217d005 Fix some comment indentation 2018-11-13 23:26:42 -08:00
Chris Robinson c3ee206129 Use an anonymous namespace in the OSS backend 2018-11-13 23:23:46 -08:00
Chris Robinson 6510a44dba Use C++ more with the ALSA backend 2018-11-13 23:07:23 -08:00
Chris Robinson a5f68c2121 Avoid using ATOMIC_FLAG
Although it cant potentially be better than a regular atomic, it presents
compatibility issues when non-C11 atomics are mixed with C++
2018-11-13 20:26:32 -08:00
Chris Robinson 5867c7b8c2 Don't bother inlining some functions 2018-11-13 19:45:26 -08:00
Chris Robinson 7088f4e34a Avoid calling through the vtable in the backends 2018-11-13 18:41:24 -08:00
Chris Robinson 0dfb805fa2 Use utf8_to_wstr to convert UTF-8 to wstring 2018-11-13 06:29:02 -08:00
Chris Robinson 6f635d3b1a Make ReadALConfig noexcept in C++ 2018-11-13 02:15:10 -08:00
Chris Robinson 2445bfd578 Convert the CoreAudio backend to C++ 2018-11-13 02:09:21 -08:00
Chris Robinson 0ff349a714 Convert the QSA backend to C++
This may very well not work, since there's no testing and my IDE is not able to
show real problems over the incompatibilities with ALSA headers.
2018-11-13 01:56:34 -08:00
Chris Robinson 09ea1d58f6 Convert the backend base to C++ 2018-11-13 01:39:42 -08:00
Chris Robinson 74d1337cc7 Convert the ALSA backend to C++ 2018-11-13 01:36:17 -08:00
Chris Robinson 1f34af4718 Convert the JACK backend to C++ 2018-11-13 01:20:15 -08:00
Chris Robinson 51a1310902 Convert the OpenSL backend to C++ 2018-11-13 00:33:25 -08:00
Chris Robinson c93b7ca0da Convert the OSS backend to C++ 2018-11-12 23:49:11 -08:00
Chris Robinson d9a47ab63c Convert the PortAudio backend to C++ 2018-11-12 23:32:11 -08:00
Chris Robinson dd9ccde055 Convert the SoundIO backend to C++ 2018-11-12 23:17:27 -08:00
Chris Robinson efae7bfb72 Convert the Solaris backend to C++ 2018-11-12 23:06:31 -08:00
Chris Robinson e7ab5053e4 Convert the SDL2 backend to C++ 2018-11-12 22:57:39 -08:00
Chris Robinson a6d780574d Make the enumerated HRTF entry name a char*
Would ideally be a std::string with the HRTF name itself, but they're still
seen in C code.
2018-11-12 22:26:12 -08:00
Chris Robinson d4d0b1fdd4 Use a regular char* for the HRTF string name 2018-11-12 19:02:38 -08:00
Chris Robinson c0f2858f3d Split Windows-specific SetRTPriority 2018-11-12 18:05:16 -08:00
Chris Robinson 4def2a60f2 Clean up helpers.cpp some 2018-11-11 23:13:11 -08:00
Chris Robinson c66db3cdf6 Use the correct type for __control87_2 2018-11-11 22:27:37 -08:00
Chris Robinson c23ea494ea Fix getting the process binary for FreeBSD or macOS 2018-11-11 22:19:32 -08:00
Chris Robinson 5848dab92d Make AmbDecConf::load noexcept
To ease the ovewrhead of destructors that call C (non-noexcept) functions.
2018-11-11 20:40:37 -08:00
Chris Robinson f8bda31c72 Remove unused wstr functions 2018-11-11 20:40:02 -08:00
Chris Robinson 51ed335833 Use C++ more with helpers.cpp 2018-11-11 19:17:40 -08:00
Chris Robinson 4793e5c4ae Use C++ for GetProcBinary 2018-11-11 16:09:24 -08:00
Chris Robinson 58a71a1a00 Convert helpers.c to C++ 2018-11-11 14:56:25 -08:00
Chris Robinson d3c4bab7bb Use a vector in the wave backend 2018-11-11 03:29:43 -08:00
Chris Robinson 2db82bea6f Define the examples' common library earlier 2018-11-11 00:47:57 -08:00
Chris Robinson f99b16daa9 Use C++ threads in the null and wave backends 2018-11-11 00:33:04 -08:00
Chris Robinson 5bc2918e16 Remove the unused condition variable APIs 2018-11-10 22:53:03 -08:00
Chris Robinson f3ce7bc7dc Move altimespec_get and al_nssleep to examples' common code 2018-11-10 21:09:54 -08:00
Chris Robinson 2f42f74418 Ensure ambdec parsing stops at unexpected EOF 2018-11-10 19:38:52 -08:00
Chris Robinson 3939878cc0 Use standard timing methods for the null and wave backends 2018-11-10 19:31:23 -08:00
Chris Robinson dc31969b04 Get rid of the last few al_fopen calls 2018-11-10 04:27:10 -08:00
Chris Robinson 58eb0e754d Load config files using C++
Specifically, avoid al_fopen
2018-11-10 03:42:18 -08:00
Chris Robinson 5ec644f859 Convert alconfig to C++ 2018-11-10 00:13:35 -08:00
Chris Robinson 981205de36 Remove unused strdupW 2018-11-10 00:01:34 -08:00
Chris Robinson 68bcf81756 Remove the unused file mapping calls 2018-11-09 23:51:29 -08:00
Chris Robinson d8163a416a Use C++ more in hrtf.cpp 2018-11-09 23:47:42 -08:00
Chris Robinson add776ddbb Handle the open mode in al::ifstream 2018-11-09 21:56:05 -08:00
Chris Robinson db56fd5e3d Convert hrtf.c to C++ 2018-11-09 18:08:42 -08:00
Chris Robinson e8679e7214 Convert the null backend to C++ 2018-11-09 03:46:30 -08:00
Chris Robinson 781ca7c58b Convert the loopback backend to C++ 2018-11-09 03:15:57 -08:00
Chris Robinson b327a50a15 Add missing consttructor and destructor calls for the wave backend 2018-11-09 02:55:28 -08:00
Chris Robinson b2cdfe58eb Convert the wave backend to C++ 2018-11-09 01:55:54 -08:00
Chris Robinson 55c860deec Use C++ with the winmm backend 2018-11-09 01:34:59 -08:00
Chris Robinson 75eeb6ba4b Convert the WinMM backend to C++ 2018-11-08 20:32:31 -08:00
Chris Robinson 34c836c490 Disambiguate operation order 2018-11-08 14:25:05 -08:00
Chris Robinson d71e50f7f7 Avoid using out parameters 2018-11-08 14:09:13 -08:00
Chris Robinson b27ccb8aa6 Fix a macro typo 2018-11-08 12:21:25 -08:00
Chris Robinson 29435ad966 Prevent MSVC's dumb min/max macros 2018-11-08 04:15:16 -08:00
kcat 22c8330200 Merge pull request #246 from john-preston/fix_macro
Fix Resample_bsinc_SSE pointer casts.
2018-11-08 03:50:37 -08:00
Chris Robinson 4eed3e9236 Move static functions to an anonymous namespace 2018-11-08 03:31:42 -08:00
John Preston c354ba2d2e Fix Resample_bsinc_SSE pointer casts.
Regression was introduced in 5ec11a017c.
2018-11-08 14:18:34 +04:00
Chris Robinson 41aa9845c4 Hide function pointer wrapper macros for IDE parsing 2018-11-07 18:26:33 -08:00
Chris Robinson 5e5e2f654e Disable MSVC warning C4200
"nonstandard extension used: zero-sized array in struct/union"
2018-11-06 21:45:40 -08:00
Chris Robinson 3cb0999a23 Use the proper enum values for atomic ops 2018-11-06 21:33:08 -08:00
Chris Robinson aeb3849904 Also extract the Android support includes 2018-11-06 20:04:28 -08:00
Chris Robinson 620ae6491b Handle CMake policy CMP0075 2018-11-06 19:43:14 -08:00
Chris Robinson 8954d3a438 Fix Android extraction paths 2018-11-06 19:34:19 -08:00
Chris Robinson 9d4af941b9 Update Travis build images
GCC 4.x is too problematic with C++11. Ubuntu Xenial has GCC 5 which has more
complete C++11 conformance. For Android, NDK r16 includes libc++ as an
alternative to the deprecated GCC 4.9's libstdc++.
2018-11-06 19:23:00 -08:00
Chris Robinson bf63c3d3d8 Don't set _FILE_OFFSET_BITS on Android 2018-11-06 19:15:09 -08:00
Chris Robinson 27fbccfb23 Don't directly declare standard function names 2018-11-06 19:14:17 -08:00
Chris Robinson d76e9800da Use a more appropriate type for the result of tellg 2018-11-06 18:55:00 -08:00
Chris Robinson 3b664041ba Convert the DSound backend to C++ 2018-11-06 02:17:20 -08:00
Chris Robinson 9fa31fcd07 Avoid moving istringstreams
Doesn't work with GCC 4.x. Hopefully swapping does.
2018-11-04 19:11:07 -08:00
Chris Robinson 4dafb7dab1 Use C++ to read and parse ambdec files 2018-11-04 15:24:24 -08:00
Chris Robinson 26f7007507 Allocate the appropriate amount in the aligned allocator 2018-11-04 15:21:03 -08:00
Chris Robinson 087fdd3ca9 Properly mark arrays constexpr and/or static 2018-11-04 15:19:48 -08:00
Chris Robinson 96819237d6 Convert ambdec.c to C++ 2018-11-03 19:51:23 -07:00
Chris Robinson 4bfaa173c4 Convert panning.c to C++ 2018-11-03 19:05:23 -07:00
Chris Robinson ba5ec8b074 Be more C++-friendly with the B-Format decoder 2018-11-03 18:00:05 -07:00
Chris Robinson 67f9efdad4 Convert the BFormat decoder to C++ 2018-11-03 15:32:09 -07:00
Chris Robinson 12d5b638f2 Convert the band-split filter to C++ 2018-11-03 15:23:15 -07:00
Chris Robinson 18e1d10338 Convert the UHJ encoder to C++ 2018-11-03 14:40:40 -07:00
Chris Robinson e9d17c5191 Move wstr_to_utf8 to compat.h 2018-11-03 12:55:02 -07:00
Chris Robinson 5482efc921 Make the polymorphic allocators allocate cleared memory 2018-11-02 18:48:08 -07:00
Chris Robinson a7dcc1c6d1 Expand the anonymous namespaces 2018-11-02 14:56:10 -07:00
Chris Robinson b54c4b02c7 Add a wrapper to manage PROPVARIANT objects 2018-11-02 13:32:42 -07:00
Chris Robinson 9e8e3c146f Workaround lack of roundf with early MSVC 2018-11-02 09:39:57 -07:00
Chris Robinson e20d2cdbce Use HUGE_VALF instead of INFINITY
Older MSVC lacks INFINITY, and we define a HUGE_VALF fallback when needed.
2018-11-02 09:25:19 -07:00
Chris Robinson 4ec757c1de Specify the correct array size for casting 2018-11-02 09:22:12 -07:00
Chris Robinson aaa31d987f Check the correct propvariant object 2018-11-02 00:42:50 -07:00
Chris Robinson d66664122a Try another fix to declare GUIDs in C++ 2018-11-02 00:13:07 -07:00
Chris Robinson 66df771d96 Make the polymorphism macros less hacky in C++
In particular, it relies on derived structs using C++-style inheritence. Any
implementation's source that's converted to C++ will consequently need to make
that change.
2018-11-01 23:52:53 -07:00
Chris Robinson 7307c2d5aa Workaround some issue with DEFINE_GUID in C++ 2018-11-01 21:42:26 -07:00
Chris Robinson a90b17113a Use more C++ types where possible 2018-11-01 21:39:34 -07:00
Chris Robinson 434582b8e3 Use an anonymous namespace instead of static for some things 2018-11-01 20:18:51 -07:00
Chris Robinson 1ca4e268f6 Preliminary conversion of the WASAPI backend to C++
A very sparse conversion. Will clean up more later after seeing what MSVC does.
2018-11-01 16:26:42 -07:00
Chris Robinson dee2905f4a Remove unused CXX_FLAGS variable
The Visual Studio generators apparently don't like the $<COMPILE_LANGUAGE:...>
expression. Since it's not actually used for anything at the moment, remove it.
2018-11-01 16:10:46 -07:00
Chris Robinson c0ce71a175 Fix a macro check 2018-11-01 16:00:38 -07:00
Chris Robinson 11967dc2da Use a wrapper function to simplify a check 2018-11-01 16:00:16 -07:00
Chris Robinson 69162cf9c6 Use perfect forwarding to initialize DevMap entries 2018-11-01 13:12:42 -07:00
Chris Robinson cd68530ab4 Simplify a couple loops 2018-11-01 11:44:11 -07:00
Chris Robinson 5d092a1c58 Use the appropriate enums for standard atomics 2018-11-01 08:43:31 -07:00
Chris Robinson d28c0eb556 Avoid uniform initialization with references
Also doesn't work with GCC 4.x
2018-11-01 08:41:23 -07:00
Chris Robinson 48f877e859 Remove unused header 2018-11-01 08:19:51 -07:00
Chris Robinson ccf356a03d Include a missing header for atomic 2018-11-01 08:17:23 -07:00
Chris Robinson 95966c4d92 Fix another use of auto uniform initialization 2018-11-01 08:15:47 -07:00
Chris Robinson 759c3a996c Avoid all uniform initialization with auto
Because of early C++11 (GCC 4.x) deficiencies, it's not interpreted correctly.
Either declare the type name explicitly with uniform initization, or use auto
with = initialization. It'll be fine when updating to GCC 5 or Clang 3.6.
2018-11-01 08:04:21 -07:00
Chris Robinson 353bb1ed17 Avoid uniform initialization on auto for integer types
To work around a deficiency with early C++11 compilers (GCC 4.x).
2018-10-31 22:10:26 -07:00
Chris Robinson d41fbd5c2d Convert the PulseAudio backend to C++ 2018-10-31 20:09:14 -07:00
Chris Robinson de275408fa Make a const array constexpr 2018-10-31 13:31:14 -07:00
Chris Robinson 0e7986eaa8 Move some extern inline declarations to C 2018-10-31 13:21:05 -07:00
Chris Robinson 9dba90fa20 Avoid assigning in an if statement 2018-10-31 13:00:08 -07:00
Chris Robinson 77bac8eeaa Add a missing <array> include 2018-10-31 12:01:07 -07:00
Chris Robinson 4d422dfb24 Fix some backup atomic macros 2018-10-31 12:00:02 -07:00
Chris Robinson 624bc1c839 Convert alBuffer.c to C++
A test to ensure everything works.
2018-10-31 10:37:16 -07:00
Chris Robinson 4b7af24ed5 Add specializations for lock_guard and unique_lock to take almtx_t 2018-10-31 10:35:12 -07:00
Chris Robinson 1e8c6df7b9 Add a C++ ContextRef helper to manage a ALCcontext reference 2018-10-31 10:05:15 -07:00
Chris Robinson da150572f9 Clean up the DriverIface in its destructor 2018-10-30 17:03:21 -07:00
Chris Robinson 615c025b67 Add a missing include for array 2018-10-30 16:35:14 -07:00
Chris Robinson 08aa9d898b Remove an unnecessary include 2018-10-30 16:32:25 -07:00
Chris Robinson 6a8f5e5950 Build the router with AppVeyor 2018-10-30 15:38:11 -07:00
Chris Robinson f747ac8882 Clean up the router's PtrIntMap 2018-10-30 14:28:19 -07:00
Chris Robinson 44f91760b5 Use std::array instead of raw arrays 2018-10-30 10:01:49 -07:00
Chris Robinson e2a1dd4503 Use std::wstring in place of some fixed WCHAR arrays 2018-10-30 09:31:52 -07:00
Chris Robinson ce212c911c Add a cmake option to static-link winpthread 2018-10-30 09:24:39 -07:00
Chris Robinson c17e59f63a Use std::vector instead of custom dynamic arrays 2018-10-30 08:33:40 -07:00
Chris Robinson e75e0a342e Use C++ atomics and mutexes in the router 2018-10-30 07:30:46 -07:00
Chris Robinson a0d03e50e8 Convert the router to C++ 2018-10-30 07:06:03 -07:00
Chris Robinson f17b930638 Add extern "C" for router.h 2018-10-30 06:45:44 -07:00
Chris Robinson 71303b73a4 Add a cmake option to static-link libstdc++ 2018-10-29 20:55:45 -07:00
Chris Robinson 3deb7c6ed5 Workaround C++ compatiility issues for atomic.h
This isn't wholly correct since neither C11 or C++11 guarantee compatibility
between atomic implementations. It's desired behavior and mostly works, see:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0943r1.html

Alignment issues can be fixed with manual alignas() specifications, should the
need arise.
2018-10-29 20:50:57 -07:00
Chris Robinson 5fea511cce Fix some more headers for C++ 2018-10-29 11:51:41 -07:00
Chris Robinson 662e1c5cc2 Fix some uses of RESTRICT 2018-10-29 11:50:41 -07:00
Chris Robinson ea3789d985 Update version for AppVeyor 2018-10-29 11:35:43 -07:00
Chris Robinson 903d878460 Replace restrict with RESTRICT 2018-10-29 11:32:50 -07:00
Chris Robinson 184241f2ef Simplify a couple more checks 2018-10-29 10:17:30 -07:00
Chris Robinson e876b50113 Remove unnecessary uses of IN_IDE_PARSER 2018-10-29 10:10:37 -07:00
Chris Robinson 7d5a288e83 Add a couple casts for compiling with C++
Also avoid using __builtin_types_compatible_p, which seems broken with C++?
2018-10-29 10:10:37 -07:00
Chris Robinson 1d7b0f54be Add another missing extern "C" 2018-10-29 10:10:37 -07:00
Chris Robinson 8a8ab68f1c Add a more C++-friendly VECTOR_RESIZE 2018-10-29 10:10:37 -07:00
Chris Robinson fd1361c198 Add a RESTRICT macro to help with C++ compatibility 2018-10-29 10:10:37 -07:00
Chris Robinson 5148a73a7b Add missing extern "C" 2018-10-29 10:10:37 -07:00
Chris Robinson f1058c635f Handle C++-only compile flags in cmake 2018-10-29 10:10:37 -07:00
Chris Robinson 7f8ef092aa Fix a couple internal headers to compile with C++ 2018-10-29 10:10:37 -07:00
kcat 44a4602508 Merge pull request #240 from ShFil119/impr/simplify_statements
Simplify some statements
2018-10-29 10:10:06 -07:00
Filip Gawin 08226bc6b0 Simplify some statements 2018-10-29 13:38:58 +01:00
kcat 56b8b97642 Merge pull request #236 from alexey-lysiuk/macos_semaphore
Use GCD semaphore on macOS
2018-10-15 14:16:49 -07:00
alexey.lysiuk c8d866a25a Use GCD semaphore on macOS
Unnamed POSIX semaphore doesn't work on macOS
2018-10-15 19:41:22 +03:00
Chris Robinson 6761218e51 Release 1.19.1 2018-10-11 15:05:31 -07:00
Chris Robinson 31b9c50721 Use the common init/close functions for alffplay 2018-10-10 16:16:00 -07:00
Chris Robinson f589244fb6 Allow building alffplay without experimental extensions 2018-10-08 15:03:49 -07:00
Chris Robinson 7a79f09a31 Add a comment about waiting to kill the event thread 2018-10-07 17:18:50 -07:00
Chris Robinson db65113c5f Use a 24-bit dither depth limit 2018-10-03 13:51:21 -07:00
Chris Robinson f3f94e478b Don't limit output for ALC_DONT_CARE_SOFT and float samples 2018-10-03 13:48:04 -07:00
Chris Robinson c39eeb9638 Don't try to get the JNIEnv on Android
It's currently not used. More stuff is needed anyway which may need a different
approach.
2018-10-02 12:40:26 -07:00
Chris Robinson 493c8bbc83 Add back an inadvertently removed static 2018-10-02 12:25:26 -07:00
Chris Robinson 052fdd67cd Use < instead of != for some loop checks 2018-10-01 15:59:05 -07:00
Chris Robinson ed8f44d102 Don't scale the reverb fade counter so much 2018-09-30 16:34:00 -07:00
Chris Robinson 1d1acc0c34 Ensure BUFFERSIZE is a power of 2 2018-09-30 12:12:27 -07:00
Chris Robinson 1860b2ec8a Make the Compressor struct opaque 2018-09-30 12:08:01 -07:00
Chris Robinson 7ad4f753a4 Fix some length ranges 2018-09-29 19:39:49 -07:00
Chris Robinson d5a78f0843 Improve a couple loops
Avoid masking the index with each iteration, and instead do up to when the mask
would apply. This allows for better optimizations, in particular fewer
instructions and better chances for vectorization.
2018-09-29 18:48:28 -07:00
Chris Robinson 32494e72a5 Don't use a ringbuffer design for the limiter's side chain
Rather than continuously wrapping when used, each update uses it from the front
and copies the tail to the front at the end. This allows for more effficient
accesses in loops.
2018-09-29 11:54:45 -07:00
Chris Robinson 0396c0ecd2 Add some assumes for the limiter 2018-09-29 09:47:05 -07:00
Chris Robinson 51a447852f Simplify a lower-bound clamp 2018-09-28 18:34:21 -07:00
Chris Robinson 1684b2cc5f Constify a couple more variables 2018-09-28 16:42:22 -07:00
Chris Robinson 1dee902a5f Update changelog 2018-09-26 08:23:48 -07:00
Chris Robinson 79314c4461 Include the limiter's lookAhead delay in the device latency 2018-09-25 23:05:27 -07:00
Chris Robinson 2d6309d6fc Don't hardcode the limiter threshold
It's now calculated from the output sample type and dither depth.
2018-09-25 10:33:20 -07:00
Chris Robinson c69338bc0d Update the output limiter/compressor
This provides better characteristics for an amplitude limiter. In particular,
it utilizes the peak amplitude instead of the RMS, and the used parameters
basically guarantee no output samples exceed the given threshold... almost, due
to floating-point errors as the threshold is converted from dB to log-e for the
envelope, then is negated and converted to linear amplitude to apply to the
signal. It's quite possible for some rounding errors to creep in and not
perfectly saturate the result.
2018-09-25 10:04:14 -07:00
Chris Robinson 39c3314d00 Only compare the reverb params that induce a need for fading
The offsets and coefficients are controlled by a relatively small set of input
parameters, just with different base constants or different calculations. This
lead to numerous redundant checks since if one value didn't change, others that
use the same inputs wouldn't have either.
2018-09-23 22:59:16 -07:00
Chris Robinson db6905bf57 Clear reverb gain coefficients when doing a device update 2018-09-23 02:22:23 -07:00
Chris Robinson 800326d37a Rename ALreverbState to ReverbState 2018-09-23 01:11:58 -07:00
Chris Robinson c708f871ec Update changelog 2018-09-22 20:13:31 -07:00
Chris Robinson 77a53594ba Improve the gain stepping difference check
Given the more stable stepping now in use, check that the total difference is
enough for perceptible transition, instead of the step itself.
2018-09-22 08:26:52 -07:00
Chris Robinson 36a6b9d42a Adjust comment spacing 2018-09-21 06:06:29 -07:00
Chris Robinson b6d0ff02c2 Use an internal event to more timely release old effect states 2018-09-21 04:14:15 -07:00
Chris Robinson f21e2df4cf Remove an unnecessary mutex 2018-09-20 22:53:16 -07:00
Chris Robinson 84a90b7cc3 Stop the event thread when releasing the context
To ensure no user callback gets called after alcDestroyContext.
2018-09-20 22:44:58 -07:00
Chris Robinson ebbbeb0d66 Put user events in a union structure 2018-09-20 21:59:38 -07:00
Chris Robinson cb8545346d Always start the event thread with the context 2018-09-20 19:58:01 -07:00
Chris Robinson 5c6b8eda4f Remove another duplicate function 2018-09-19 22:18:46 -07:00
Chris Robinson ea95a8adef Combine nearly-duplicate structures 2018-09-19 21:31:46 -07:00
Chris Robinson 6eb980d1b2 Remove a couple duplicate functions 2018-09-19 21:09:19 -07:00
Chris Robinson 48b7745a49 Add macros for commonly used square roots 2018-09-19 19:53:25 -07:00
Chris Robinson 9ef4dd4247 Use ALsizei for the source resample position 2018-09-18 19:08:13 -07:00
Chris Robinson 952ff84b99 Properly queue buffers for OpenSL capture 2018-09-17 23:43:23 -07:00
Chris Robinson b77e6096b8 Fix some potential race conditions with OpenSL
For playback, increment the ring buffer's write pointer before queueing audio,
to handle cases where the callback is invoked, advancing the read pointer,
before the write pointer is advanced.

For capture, limit the number of re-queued chunks to the number of fully read
chunks.
2018-09-17 22:49:52 -07:00
Chris Robinson 7f4441ffbe Handle the bsinc C resampler like the others 2018-09-17 04:07:56 -07:00
Chris Robinson 8bacb5dfb8 Fix buffer queue mixing logic
In particular, the source sample position was reduced by the size of the
next buffer list item when one is completed, rather than the size of the
one it just completed.
2018-09-16 17:38:55 -07:00
Chris Robinson a6734c7a91 Check the effect slot list size only when there's no free entries
The list can contain (reuable) NULL entries, so the max - current_size doesn't
indicate how many can be allocated.
2018-09-14 14:53:35 -07:00
Chris Robinson db452a19da The last reverb loop update doesn't need an aligned count. 2018-09-11 19:05:49 -07:00
Chris Robinson 99737469e2 Ensure the max reverb update size is a multiple of 4
It's not an issue for the final mix, but if one loop has an unaligned count,
the next loop will have unaligned input and output buffer targets which can
crash the SSE mixers.
2018-09-11 18:39:50 -07:00
Chris Robinson b13396cce2 Separate the delay line feeding from reading
Since it feeds a different line than it reads, the feeding could overwrite
what's subsequently read.
2018-09-10 13:30:20 -07:00
Chris Robinson d1f8b78dd4 Avoid a couple line count assumptions 2018-09-10 03:19:41 -07:00
Chris Robinson 4bdab0051f Combine identical loops into a separate function 2018-09-10 03:17:14 -07:00
Chris Robinson 634b13a630 Handle the early reflection delay separate from late refeed 2018-09-10 02:10:35 -07:00
Chris Robinson 275658b6db Some suggested changes for iOS 2018-09-07 23:01:17 -07:00
Chris Robinson 9054f41434 PATH_MAX not MAX_PATH 2018-09-07 22:52:34 -07:00
Chris Robinson fa7993fe3e Load .alsoftrc from the app bundle root on macOS
Not sure what priority this should have. Currently it loads after system-level
configs, and before user-level configs.
2018-09-07 22:32:48 -07:00
Chris Robinson 46cfedb117 Pass the device name list to the backend probe method 2018-09-07 22:02:37 -07:00
Chris Robinson 212cb8e298 Implement capture support for SoundIO 2018-09-07 20:08:24 -07:00
Chris Robinson 7394dd512d Rename ALCsndioBackend 2018-09-07 18:45:24 -07:00
Chris Robinson 96aacac10c Release 1.19.0 2018-09-06 14:35:18 -07:00
Chris Robinson 4c32a0aba7 Update changelog about 32-bit using SSE2 by default 2018-09-03 21:09:31 -07:00
Chris Robinson 0f243b927c Slightly restructure some loops 2018-09-03 17:07:43 -07:00
Chris Robinson fce86815f4 Extract SIMD values right before using them 2018-09-03 12:42:31 -07:00
Chris Robinson 3b4f28d173 Avoid double-resizing when appending a char to a string 2018-09-02 21:15:21 -07:00
Chris Robinson b854f4037f Read the whole Features string for neon support 2018-09-02 18:15:56 -07:00
Chris Robinson 30bd84a935 Fix a typo in the changelog 2018-08-31 17:45:59 -07:00
Chris Robinson 0a8398dd99 Update a comment 2018-08-31 17:36:50 -07:00
Chris Robinson 01cc0cd787 Pass the appropriate /arch switch for x86 MSVC 2018-08-31 13:22:21 -07:00
Chris Robinson 0d4b68239a Include the mid-band decay with the density gain 2018-08-31 08:30:57 -07:00
Chris Robinson 68a8c42176 Calcualte and use the maximum reverb update size
Instead of requiring it to be at least as big as MAX_UPDATE_SAMPLES, which may
not be true in some situations.
2018-08-31 07:20:46 -07:00
Chris Robinson 8b733728af Apply the decay gain when reading from the late line 2018-08-31 06:31:58 -07:00
Chris Robinson 1fa464ec3e Don't modify the late reverb density with the echo parameters 2018-08-30 18:40:53 -07:00
Chris Robinson 3368bd75c7 Enable HRTF data set embedding by default 2018-08-29 15:31:04 -07:00
Chris Robinson 827c66f4f6 Widen the plain stereo width
Now full right and left is +-60 degrees instead of +-30. This should help
create a smoother panning for a sound moving in front for plain stereo output
(surround sound and HRTF are not changed).

Multi-channel sources are also not affected by this change. The stereo channel
defaults of +-pi/6 (30 degrees) still correspond to full left/right panning.
This is an unfortuante discrepancy, but is necessary for AL_EXT_STEREO_ANGLES
to work.
2018-08-29 07:13:54 -07:00
Chris Robinson 21dc2c761d Check for and use copysignf 2018-08-29 03:53:09 -07:00
Chris Robinson 529f387695 Use a separate method to warp the azimuth for plain stereo output 2018-08-29 01:45:27 -07:00
Chris Robinson dacd08dc5d Use shuffle+cvt to extract SIMD values instead of storing to memory 2018-08-26 22:36:30 -07:00
Chris Robinson 072ca731e2 Avoid making extraneous calls 2018-08-26 19:14:17 -07:00
Chris Robinson a3010f50be Pack two arrays into one 2018-08-26 19:08:50 -07:00
Chris Robinson 4be6584850 Further limit the upper frequency range for autowah 2018-08-26 19:04:49 -07:00
Chris Robinson 24b646dec0 Append the OpenSL capture device to the appropriate list 2018-08-23 18:20:09 -07:00
Chris Robinson 7d76cbddd6 Use second-order biquad filters for the reverb's T60 decay 2018-08-12 18:02:39 -07:00
Chris Robinson 90ca9b9ff4 Store the reverb state offset locally while processing 2018-08-11 01:29:15 -07:00
Chris Robinson 2b9c213f89 Correctly apply reverb coefficient fading over the entire fade length 2018-08-09 21:10:17 -07:00
Chris Robinson adfbe0d6cd Crossfade the early reflections delay coefficients 2018-08-08 22:47:07 -07:00
Chris Robinson 125ac166d1 Apply late reverb density gain on late reverb input
This also uses gain stepping for changes in density or decay, so that the
late reverb tap fades smoothly between delay offsets and density gain levels
simultaneously. Now with these changes, it's preferrable to apply density gain
adjustments on late reverb input instead of output so that samples currently in
the feedback loop won't see a sudden increase or decrease in amplitude.

A similar change can probably be made for the early reflection delays to
further smooth out delay changes.
2018-08-08 19:30:58 -07:00
Chris Robinson 1e33c4a922 Specify both scale values to FadedDelayLineOut 2018-08-08 06:24:12 -07:00
Chris Robinson a8250db2bb Use the correct input channel for the compressor effect 2018-08-08 04:05:07 -07:00
Chris Robinson 04921dd727 Properly set early reflection all-pass coefficient 2018-08-06 23:45:32 -07:00
Chris Robinson 06da60c555 Make the all-pass coefficient part of the all-pass structure 2018-08-06 21:57:08 -07:00
Chris Robinson 32edc7f33f Prevent the autowah filter frequency from reaching nyquist 2018-08-06 14:14:31 -07:00
Chris Robinson 4f92bd5938 Apply the vector all-pass separate on uninterleaved samples
With the vector all-pass applied in a self-contained function, the individual
steps of the early and late reverb stages can be better optimized with tighter
loops. That allows for more data to be held local, resulting in less thrashing
from reloading the same values multiple times.

There is room for further improvement, depending on the length of the early
delay lines and all-pass delay lines allowing for bulk reads.
2018-08-05 20:29:03 -07:00
Chris Robinson 4aa029183b Apply the reverb's T60 filter in groups of samples
The late reverb line lengths are long enough to ensure a single process loop
won't rely on reading samples it wrote in the same call. So we can safely read
in all samples we need from the feedback buffer up front, then more efficiently
filter them.
2018-08-05 00:45:13 -07:00
Chris Robinson 3f165040e2 Mix reverb samples right after generating them
Instead of generating both the early and late reverb samples first, then mixing
them both to output, this now generates and mixes the early reflections then
generates and mixes the late reverb. There's no reason to hold both at the same
time so this reduces the amount of temporary storage needed.
2018-08-04 22:52:36 -07:00
Chris Robinson 754a32fa16 Scale the reverb decay weights to cover up to 20khz
Otherwise, using the device's maximum frequency will cause the weighting
factors to shift for different sample rates, irrespective of the content being
processed. 20khz is the maximum allowed reference frequency, and also acts as
the upper limit of human hearing.
2018-08-03 20:04:08 -07:00
Chris Robinson 57b860d8ca Trace the NFC reference distance when set 2018-08-03 00:07:08 -07:00
Chris Robinson 0c67429a38 Apply late reverb density gain adjustment on output
Because density/late line length changes start affecting late reverb output
right away, with samples that are still going through feedback decay and not
just new input samples, it makes more sense to correct for it on output instead
of input. This has the additional benefit of working with the output mixer's
gain fading, avoiding discontinuities from significant density gain changes.
2018-08-01 16:08:27 -07:00
Chris Robinson aa58a5d208 Fix late reverb density gain blend weights
Now it only accounts for the representable frequency range (0.5 normalized, or
 0...pi radians instead of tau). Previously, the bulk of the weighting factors
was given to the HF decay (nearly 90%, given a 44.1khz sample rate and the
default 5khz reference), with low- and mid-frequency decays splitting the
remaining 10%. Now it's closer to 75%, matching the range of representable
frequencies above the reference.

This could probably be improved further due to human hearing being less
sensitive to higher frequencies, but that is much more complicated.
2018-08-01 02:48:31 -07:00
Chris Robinson 3894c580bf Use just the omnidirectional response for the compressor effect
This is not the output compressor/limiter, but the EFX effect. Consequently, it
simply compresses the dynamic range around 1.0 (boosting samples below it by up
to double, reducing samples above it by as much as half). This is not intended
to prevent clipping on the output, but to instead reduce the range between
quiet sounds and loud sounds.
2018-07-29 00:18:46 -07:00
Chris Robinson f1bf932a84 Update ChangeLog 2018-07-28 14:11:12 -07:00
Chris Robinson 8ab448b119 Inline the autowah peaking filter processing 2018-07-28 14:03:28 -07:00
Chris Robinson 39a5d0cb94 Mark a couple parameters as unused 2018-07-25 13:15:47 -07:00
Raulshc 7d68eeac88 EFX: Enable 3D processing
Use channel 0 envelope for calculate the frequency in all channels.
2018-07-25 12:51:09 -07:00
Raulshc 92fd59fe6a EFX: Add 3D processing for autowah
Add 3D processing code. It can be activated at compilation time.
2018-07-25 12:51:09 -07:00
Raulshc f79683d459 Alsoft-config: Add autowah effect 2018-07-25 12:51:09 -07:00
Raulshc 83dba26ea6 EFX: Autowah implementation
Add autowah effect using biquad peaking filter and envelope follower
2018-07-25 12:51:09 -07:00
Chris Robinson 809f709ba6 Limit the normalized filter frequency to under half
Nearing half, weird things can start happening with the filters' generated sine
and cosine values.
2018-07-21 14:22:52 -07:00
Chris Robinson 6fe1ffa3bb Improve handling of 0hz ring modulator frequency 2018-07-21 14:21:00 -07:00
Chris Robinson d117a5209f On 32-bit targets with SSE, enable SSE/SSE2 codegen by default
Two new CMake options are available for 32-bit targets that accept -msse:
ALSOFT_ENABLE_SSE_CODEGEN and ALSOFT_ENABLE_SSE2_CODEGEN, which default to
TRUE. This should not affect MSVC, which already defaults to SSE2 codegen.
2018-07-16 08:41:56 -07:00
Chris Robinson ed1f1d2bf3 Start an extension to allow source filter gains greater than 1 2018-07-15 21:01:26 -07:00
kcat fd3f52ea36 Merge pull request #210 from qwertychouskie/patch-1
Fix COPYING
2018-07-02 18:38:57 -07:00
QwertyChouskie 4c61103e34 Fix COPYING
Remove bad chars, remove section that shouldn't be there.
2018-07-02 17:09:53 -07:00
kcat dc3fa3e51f Merge pull request #207 from t6/patch-sndio-oss
Prefer sndio backend over OSS when both are enabled
2018-06-22 11:49:00 -07:00
Tobias Kortkamp e2d7c5dfb3 Prefer sndio over OSS when both are enabled
Signed-off-by: Tobias Kortkamp <tobik@FreeBSD.org>
2018-06-22 14:36:33 +02:00
kcat 7e2cac5292 Merge pull request #204 from jhasse/android-byte-order
Correctly check byte order for newer Android compiler, fix #203
2018-06-20 12:53:22 -07:00
Jan Niklas Hasse a80ab01227 Correctly check byte order for newer Android compiler, fix #203 2018-06-20 21:36:33 +02:00
Chris Robinson 73e08e51ba Properly get the full executable and pathname on FreeBSD 2018-06-08 19:49:13 -07:00
Chris Robinson fd1458ce1b Always prepare the ALSA PCM handle before starting capture
Draining the ALSA device via stopping puts it into a setup state, which
requires re-preparing before playback can start again. Preparing it prior to
the first start seems to cause no harm, so just always do it before starting.
2018-06-08 05:02:47 -07:00
kcat 9c643f0356 Merge pull request #200 from kdhp/fix-199
Stop capture devices while closing
2018-06-07 19:30:34 -07:00
kdhp 35b78d55a4 Stop capture devices while closing
In 'alcCaptureCloseDevice', check if the capture device is
running and stop it if necessary.
This fixes the case where the device data is deallocated while
a background thread is still running (Issue #199)
2018-06-08 01:42:13 +00:00
Chris Robinson bd9c6989c2 Clear the TLS pointer after running its destructor callback 2018-06-06 23:10:37 -07:00
Chris Robinson 72e4b60374 Clamp the maximum normalized reference frequency too 2018-06-03 01:52:05 -07:00
Chris Robinson 48b265e136 Use a higher normalized frequency limit for the ring modulator 2018-06-02 00:02:14 -07:00
Chris Robinson 7865ebb6d5 Use the biquad high-pass in the ring modulator 2018-05-31 22:21:00 -07:00
Chris Robinson f765099503 Slightly simplify the modulator square wave generator 2018-05-31 19:43:02 -07:00
kcat d5dd4937eb Merge pull request #197 from Raulshc/Modulator
EFX: Modulator fixes
2018-05-31 19:38:42 -07:00
Raulshc 1bba276aaf EFX: Ring modulator fixes
Change from unipolar to bipolar carrier signal in the Ring modulator effect.
2018-05-31 15:47:47 +02:00
Raulshc 5233c4aa21 Merge from kcat/master
Update git repository
2018-05-31 14:17:20 +02:00
Chris Robinson 0b7f35b289 Avoid extra sample copies and storage in the modulator effect 2018-05-29 22:55:21 -07:00
Chris Robinson 46c59f382f Use fastf2i instead of manual rounding in another place 2018-05-29 22:49:45 -07:00
Chris Robinson 8854720e8a Avoid separate in/out parameters when they're always the same 2018-05-29 22:15:49 -07:00
kcat 42d3235a66 Merge pull request #196 from rindeal/cmake-sse2-typo-fix
CMake: fix SSE3 typo
2018-05-29 16:24:42 -07:00
Jan Chren (rindeal) 5cba81cf35 CMake: fix SSE3 typo
Closes: https://github.com/kcat/openal-soft/issues/195
2018-05-29 18:32:30 +02:00
Chris Robinson a5edf487dd Use a macro to handle common case formatting 2018-05-27 01:03:18 -07:00
Chris Robinson 728dd5a4e0 Avoid setting unnecessary variables 2018-05-26 20:43:05 -07:00
Chris Robinson ac4061b9d2 Better sort the effect list in alsoft-config 2018-05-26 18:17:17 -07:00
Chris Robinson ec84a107a4 Don't hardcode the max channels for HRTF B-Format decoding 2018-05-26 00:26:11 -07:00
Chris Robinson 803d331711 Improve formatting of the hilbert function 2018-05-24 00:16:50 -07:00
Chris Robinson 422cf429e6 Clamp the dither depth between 2 and 20 bits 2018-05-23 19:49:49 -07:00
Chris Robinson 93de5350b9 Add some LIKELY and ASSUME statements 2018-05-23 19:22:21 -07:00
Chris Robinson 9bf3ee722c Fix a function comment about a return value 2018-05-23 06:10:09 -07:00
Chris Robinson 1782208fde Remove unused function 2018-05-23 05:58:06 -07:00
Chris Robinson 84a94a6109 Update ChangeLog 2018-05-23 01:04:52 -07:00
Chris Robinson c2a4a35c2e Use a tighter loop to handle the frequency shifter's fifo 2018-05-22 07:28:53 -07:00
Chris Robinson f3d4220cab Use fixed point for the frequency shifter's phase 2018-05-22 07:02:14 -07:00
Chris Robinson 8219bb374d Fix a couple property variable names 2018-05-22 06:19:59 -07:00
Chris Robinson 80df89d0db Improve the frequency shifter output accum handling 2018-05-22 06:12:55 -07:00
Chris Robinson ecdc58c1c9 Fix formatting and line endings 2018-05-22 05:59:03 -07:00
kcat da63b4a596 Merge pull request #193 from Raulshc/Frequency-shifter
EFX: Frequency shifter
2018-05-22 04:44:50 -07:00
Chris Robinson 4e315353c8 Add a method to queue multiple buffer layers onto a source 2018-05-21 23:25:56 -07:00
Chris Robinson 720ec2beea Use the __BYTE_ORDER__ macro when available 2018-05-21 17:51:57 -07:00
Chris Robinson a235259b5e Further clarify a comment about float precision 2018-05-21 06:16:03 -07:00
Raulshc 97c165b951 Add correct cast 2018-05-20 18:44:24 +02:00
Raulshc da6f32a1c0 Alsoft-config: Add frequency shifter effect 2018-05-20 17:27:37 +02:00
Raulshc d3a81f4f28 EFX: Frequency Shifter implementation
Add frequency shifter effect using discrete Hilbert transform. Only mono signal processing by now (LEFT_DIRECTION).
2018-05-20 17:23:03 +02:00
Raulshc dd51ba396b Common: Implement discrete Hilbert transform 2018-05-20 17:21:50 +02:00
Chris Robinson 7501c8b483 Simplify counting for the bsinc FIR loop 2018-05-19 08:18:08 -07:00
Chris Robinson 5e7513d0a0 Accumulate ambisonic upsampler gains using double-precision 2018-05-18 18:59:27 -07:00
Chris Robinson cd2fd126c4 Add an alffplay option to play stereo streams with wide angles 2018-05-17 03:54:32 -07:00
Chris Robinson 0cd375f03c Add a function to calculate coefficients from X, Y, Z components 2018-05-17 03:52:40 -07:00
Chris Robinson 588a6bcb4f Simplify counting for SIMD MixRow functions 2018-05-15 23:14:23 -07:00
Chris Robinson 72e39ba1c9 Fix a function comment 2018-05-15 22:11:10 -07:00
Chris Robinson 6534aa0c27 Undefine the correct macros 2018-05-15 21:46:22 -07:00
Chris Robinson e42489b3e9 Include math_defs.h to ensure M_PI is defined 2018-05-15 18:50:32 -07:00
Chris Robinson 2b9064cb6e Move the ALcomplex and FFT functions to a separate file 2018-05-15 18:31:41 -07:00
Chris Robinson 197e88cdcc Avoid using unsigned values for signed 2018-05-15 01:20:39 -07:00
Chris Robinson 4ac4889912 Avoid unnecessary function-like macros 2018-05-15 00:53:12 -07:00
Chris Robinson 4ee04cd444 Use a step counter for gain stepping
This should provide more stable stepping, preventing floating-point errors from
accumulating on each step/sample.
2018-05-14 23:41:29 -07:00
Chris Robinson 43dccc8807 Add a faster double-to-int converter for x87 builds 2018-05-14 18:00:43 -07:00
Chris Robinson df9faba689 Use more accurate elevations for virtual HRTF speaker positions 2018-05-14 05:28:06 -07:00
Chris Robinson 5272caf7f4 More accurately convert between degrees and radians 2018-05-14 00:20:31 -07:00
Chris Robinson 1e04c4c689 Make a faster float2int method for x87 targets 2018-05-12 22:34:15 -07:00
Chris Robinson dd055fc858 Use fastf2i instead of manually rounding with float2int 2018-05-12 21:36:23 -07:00
Chris Robinson 5c0673049c Fix MSVC 2018-05-12 03:31:58 -07:00
Chris Robinson f240952bcc Fix non-SEE (32-bit) GCC builds 2018-05-12 00:58:27 -07:00
Chris Robinson e787a241c0 Add and use a method for fast float rounding
Unlike fastf2i, this keeps the result as a float instead of converting to
integer.
2018-05-12 00:52:09 -07:00
Chris Robinson 3867cad94d Simplify calculating the HRTF B-Format IR length 2018-05-04 06:48:20 -07:00
Chris Robinson be30e6bf8f Don't assume the FPU is round-to-zero in the pitch shifter 2018-05-04 04:53:50 -07:00
Chris Robinson 1fb6428ffa Another fix attempt for 32-bit MSVC 2018-05-04 04:02:57 -07:00
Chris Robinson b31a54e972 Try to fix 32-bit MSVC builds 2018-05-04 02:56:01 -07:00
Chris Robinson 75e2cb97f7 Don't assume round-to-zero for fastf2i 2018-05-04 02:09:32 -07:00
Chris Robinson ac8dbd7a56 Add a specific function for truncating float-to-int conversions 2018-05-03 22:02:32 -07:00
Chris Robinson d8a659c6f2 Avoid fastf2i in the converter init 2018-05-03 17:27:30 -07:00
Chris Robinson af90d89b6b Use a fixed-point scale for the pitch shifter frequency index 2018-05-03 17:06:55 -07:00
Chris Robinson a19296e3cf Avoid excessive if block depths 2018-05-02 21:06:57 -07:00
Chris Robinson 85c03925fb Avoid duplication for getting the cpuid 2018-05-02 20:59:53 -07:00
Chris Robinson 22413b82ca Pass in the number of channels per order to InitNearFieldCtrl 2018-05-01 20:21:24 -07:00
Chris Robinson e8aaa9cb13 An output device buffer is likely 2018-04-29 18:03:33 -07:00
Chris Robinson 2385ab700c Avoid potentially calling log10f(0) 2018-04-29 14:02:33 -07:00
Chris Robinson 242ed45f65 Rename some struct members for clarity 2018-04-28 22:10:22 -07:00
Chris Robinson e420752e82 Fix a comment about a float's mantissa 2018-04-28 18:52:40 -07:00
Chris Robinson 54109043b8 Remove some unnecessary floor calls 2018-04-28 01:14:17 -07:00
Chris Robinson ddd4751f87 Increase the band-split IR for decoding ambisonics to HRTF 2018-04-27 18:42:26 -07:00
Chris Robinson 492c75cb7b Rename some variables for clarity 2018-04-27 00:41:02 -07:00
Chris Robinson 1e0728af64 Transpose the band-splitter all-pass section 2018-04-26 23:26:11 -07:00
Chris Robinson 1cc6983b96 Use doubles for the pitch shifter's FFTs and processing 2018-04-24 21:40:41 -07:00
Chris Robinson 8311b57ca6 Update ChangeLog 2018-04-24 00:18:02 -07:00
Chris Robinson 510efae066 Don't specialize biquad processing for a single sample 2018-04-24 00:17:07 -07:00
Chris Robinson b3ba90f5fa Use transposed direct form 2 for the UHJ all-pass filters
This has one extra multiply, but avoids two moves and uses almost half as much
memory for the encoder state.
2018-04-22 03:34:29 -07:00
Chris Robinson e10595df31 Pre-calculate the squares of the UHJ filter coefficients 2018-04-22 02:39:14 -07:00
Chris Robinson b51d30f84d Change some if checks to asserts since they must be true 2018-04-22 02:38:09 -07:00
Chris Robinson ea8b52ee2c Include header files in CMake's source lists 2018-04-21 23:42:04 -07:00
Chris Robinson 9575eebac4 Move the bnad-splitter filters to a separate source 2018-04-21 23:23:46 -07:00
Chris Robinson ace8e64850 Only use fast float-to-int workarounds for x87
At least SSE and ARM have opcodes that handle float-to-int conversions well
enough. Also, Clang doesn't inline lrintf, incurring function call overhead for
what should be a single opcode.
2018-04-21 21:07:20 -07:00
Chris Robinson 4ee26f4ca3 Add some more ASSUME statements 2018-04-21 02:44:01 -07:00
Chris Robinson a55c93e1f5 Improve ASSUME for Clang
For some reason, the { if(!x)__builtin_unreachable(); } construct does not
provide the same optimization opportunity for Clang (even though the condition
being false would trigger undefined behavior by reaching unreachable code, it
still performs checks and such for the condition potentially being false).
Using __builtin_assume seems to work better.
2018-04-21 01:54:43 -07:00
Chris Robinson 400ab8766c Adjust the stereo panning front gain
This gives it a (more) precise -4.5dB gain drop for front-center panned sounds.
2018-04-19 21:55:20 -07:00
Chris Robinson 90b8d639f1 Remove unnecessary undefs 2018-04-19 18:24:27 -07:00
Chris Robinson 525b6fe168 Clear ALSA's PCM handle after closing it 2018-04-19 12:22:39 -07:00
Chris Robinson f96a8fe369 Add some ASSUME statements that ensure mixing at least 1 sample 2018-04-18 20:39:52 -07:00
Chris Robinson 150586d7fe Add an ASSUME macro that requires a true condition 2018-04-17 22:50:50 -07:00
Chris Robinson 09194fd488 Accumulate the B-Format HRTF responses using doubles
The final result is still truncated to single-precision float, but this should
keep the responses more stable as it accumulates the various inputs.
2018-04-17 21:27:47 -07:00
Chris Robinson e619b64175 Don't minimize the HRTF per-response delay
The reverts both fa9ab9af7c and
79604c3c0e. As helpful as it was for the high
frequencies, the overall response's gain suffered.
2018-04-16 18:54:41 -07:00
Chris Robinson 795ed65797 Preliminary ChangeLog update 2018-04-15 19:01:38 -07:00
Chris Robinson 5b82dd8733 Update .gitignore 2018-04-14 13:02:21 -07:00
Chris Robinson 9c5307a48a Rename BiquadState to BiquadFilter 2018-04-04 18:07:46 -07:00
Chris Robinson b1fe405861 Improve ordering of channel processing in makehrtf 2018-04-03 11:21:15 -07:00
Chris Robinson 869637af2e Apply biquad and T60 filters using transposed direct form II 2018-04-03 10:15:35 -07:00
Chris Robinson 414b56edec Initialize COM using the multithreaded apartment
I honestly have no idea which is the correct (or better) mode to use given the
confusing mess COM is, but CoInitialize uses single-threaded apartments which
seems to be a problem for with at least a couple games in the STALKER series
(the call fails, which causes us to drop back to the DSound backend).
2018-04-01 16:39:20 -07:00
Chris Robinson 334bc4f551 Limit the near-field control distance to 10m. 2018-03-31 23:11:48 -07:00
Chris Robinson e288c3b44a Fix HRTF HOA coefficients
ACN8 was accidentally put on ACN7. However, rather than adding the missing
channel of silence, set up the coefficient map to only use the ambisonic
channels that can contribute to output.
2018-03-31 20:44:14 -07:00
Chris Robinson 91900b0599 Fix misspellings of quadraphonic
AL_LOKI_quadriphonic is left alone since that is what the extension is called
and what code expects. All other instances have been fixed for consistency.
2018-03-30 09:18:17 -07:00
Chris Robinson 29ae74d4bb Fix lower elevation synthesis for stereo HRTFs 2018-03-29 20:44:44 -07:00
Chris Robinson a2c24ff946 Specify Libs.private for the pkg-config file
Only used when building the static lib for its dependencies, since the shared
lib automatically handles its own dependencies.
2018-03-29 18:57:48 -07:00
Chris Robinson 61de399806 Don't cache SDL2_LIBRARY_TEMP with CMake
Otherwise it keeps prepending and appending the same extra libs and flags with
each invocation.
2018-03-29 18:10:58 -07:00
Chris Robinson f48a1e3a31 Add simple descriptions to some extension formats in alext.h 2018-03-29 17:18:24 -07:00
Chris Robinson 4a8c3b50b6 Apply the initial decay and air absorption after gain clamping 2018-03-29 16:11:46 -07:00
Chris Robinson 852ad41176 Pass the azimuth and elevation to CalcPanningAndFilters 2018-03-29 16:11:46 -07:00
Chris Robinson 880d555060 Combine two loops 2018-03-29 16:11:46 -07:00
kcat 5523913a81 Merge pull request #184 from hhyyrylainen/master
Added missing string include to alffplay
2018-03-29 16:11:13 -07:00
Henri Hyyryläinen a7da29804d Added missing string include to alffplay 2018-03-30 01:53:55 +03:00
Chris Robinson cae4b1a062 Don't specify macros as arguments to CHECK_INCLUDE_FILE(S) 2018-03-28 14:34:58 -07:00
Chris Robinson 2b16ff3ca8 Check all buffers to update a source with 2018-03-28 06:28:46 -07:00
Chris Robinson 5aecce5a0d Store the ALbufferlistitem's composited/max sample length 2018-03-27 18:09:28 -07:00
Chris Robinson d85ddf8aae Rename NfcFilterUpdate* to NfcFilterProcess* for consistency 2018-03-27 05:58:58 -07:00
Chris Robinson 788f5398b0 Slightly relax the memory order for ref counters 2018-03-26 10:14:27 -07:00
Chris Robinson 964723691a Condense an if check 2018-03-26 06:04:11 -07:00
Chris Robinson 2475d4652c Clear mixing target parameters before setting them 2018-03-25 18:02:07 -07:00
Chris Robinson 79eb2ea26e Reduce the gain of front-panned sounds with plain stereo
Now front-center sounds are attenuated by roughly -4.5dB instead of -3dB. This
will help keep rear-panned sounds from attenuating too much while not making
front-panned also attenuate too much.
2018-03-25 12:24:43 -07:00
Chris Robinson f3672ab26b Annotate the B-Format rotation/conversion matrix 2018-03-25 08:24:53 -07:00
Chris Robinson f757fbce4d Fix Hanning -> Hann window name 2018-03-24 14:18:29 -07:00
Chris Robinson e5e3b05015 Fix capture device closing in the CoreAudio backend 2018-03-24 09:25:49 -07:00
kcat eccf679ca9 Merge pull request #181 from jhasse/sdl2-include
Also add SDL2's include path
2018-03-24 09:25:13 -07:00
Jan Niklas Hasse 3fc9d3a1be Also add SDL2's include path 2018-03-24 16:45:13 +01:00
Chris Robinson 3f071a90a4 Use proc_pidpath to get the process path on macOS when available 2018-03-24 08:25:58 -07:00
Chris Robinson 413d55aaa5 Fix a couple comments about coordinate handedness 2018-03-24 07:02:27 -07:00
Raulshc 6d8062a2a7 EFX: Align some arrays used in intrinsics (#180) 2018-03-24 05:43:56 -07:00
Chris Robinson 6990478369 Rename ALfilterState/Type to BiquadState/Type 2018-03-23 14:52:59 -07:00
Chris Robinson e37634e908 Remove an unused struct and move some functions to where they're used 2018-03-23 11:58:11 -07:00
Chris Robinson 63c9d95b84 Combine multiple allocations into one 2018-03-23 11:39:07 -07:00
Chris Robinson 63c35248be Some formatting cleanup 2018-03-22 11:32:23 -07:00
Chris Robinson 6685e0a078 Don't use an ALsizei for a potentially negative value 2018-03-22 11:11:45 -07:00
Chris Robinson 7789cc8e32 Define the Hanning window globally once for the pitch shifter 2018-03-22 09:55:15 -07:00
Chris Robinson 1d6622aa2b Fix a delta phase offset calculation in the pitch shifter
tmp can be negative, and &1 is not the same as %2 in that case.
2018-03-22 08:56:48 -07:00
Chris Robinson eeff730034 Hold some immediate values on the stack 2018-03-22 08:49:35 -07:00
Chris Robinson 23fd7451d0 Avoid some memset calls in the pitch shifter process loop 2018-03-22 08:49:22 -07:00
Chris Robinson bc3a96308e Use appropriately-sized buffers for the pitch shifter 2018-03-22 08:05:48 -07:00
Chris Robinson 8e976a92f7 Move NFC filters to the filter directory 2018-03-22 07:17:48 -07:00
Chris Robinson 7a23330ffe Move the filter implementation to a separate directory 2018-03-22 07:05:40 -07:00
Chris Robinson 6ea3b5445f Rename mixer_inc.c to hrtf_inc.c 2018-03-22 05:41:42 -07:00
Chris Robinson 091e676db3 Move mixer sources into a sub-directory 2018-03-22 05:06:15 -07:00
Chris Robinson 6ad171781a Use the global MixSamples for the pitch shifter output 2018-03-22 03:13:09 -07:00
Chris Robinson d157d66678 Change a parameter type to float since that's what it's used as 2018-03-22 02:13:40 -07:00
Chris Robinson 4da6364fc2 Slightly restructure the pitch-shifter process loop 2018-03-22 02:10:51 -07:00
Chris Robinson 7b95753cf7 Fix typo (Substraction -> Subtraction) and rename related function 2018-03-21 23:10:12 -07:00
Chris Robinson 8f3d496541 Avoid duplicate path searches in the router
And avoid inadvertently increasing the priority of the system path over the
executable's path, or either of them over the current working directory.
2018-03-21 20:39:04 -07:00
Chris Robinson 0a6c17c544 Don't auto-attenuate the pitch shifter output 2018-03-21 09:32:04 -07:00
Chris Robinson f11d7eeadf Don't use mutable fields for constant values 2018-03-21 09:23:58 -07:00
Chris Robinson 22a7bcd5ad Avoid placing a 2K sample buffer on the stack 2018-03-21 09:01:32 -07:00
Chris Robinson ecc51c8c55 Clean up some code formatting in the pitch shifter source
Clean up excessive newlines and extra-long comments, move static inline
definitions to their declarations.
2018-03-21 08:56:26 -07:00
Chris Robinson 55a73b8df9 Fix for older MSVC lacking strtof 2018-03-21 08:35:37 -07:00
kcat c40b4ce3f2 Merge pull request #177 from Raulshc/Pitch-shifter
EFX:Pitch shifter
2018-03-21 08:35:09 -07:00
Chris Robinson 47260fc70b Update the multi-reverb example with improved transitions
This better calculates the environment coverage by correctly calculating the
portal's extents, improves the panning direction when close to the portal, and
applies attenuation based on contribution. Movement has changed to make the
listener move back and forth between environments with a stationary source,
rather than continually looping environments with a position-relative source.
2018-03-20 23:58:32 -07:00
Raulshc c38854fe3d EFX:Own size for pitch shifter buffers 2018-03-19 16:48:00 +01:00
Chris Robinson df6e4617e4 Fix the reverb panning behavior to better fit the spec
Previously it would attenuate the response from direction opposite to the
vector, whereas the property descriptions say it should simply move all
reflections toward the given direction.
2018-03-19 06:41:38 -07:00
Raulshc 56423b9ef1 Alsoft-config: Add pitch shifter effect 2018-03-18 17:53:07 +01:00
Raulshc 6fd23f0984 EFX:Pitch Shifter implementation
Add pitch shifter effect using standard phase vocoder, based on work of Stephan Bernsee. Only mono signal processing by now.
2018-03-18 17:47:17 +01:00
Chris Robinson 325fca5215 Change the presets for the multireverb example 2018-03-16 05:01:00 -07:00
Chris Robinson 3fde27d890 Use a macro template to define similar functions 2018-03-15 00:28:49 -07:00
Chris Robinson 445f63f350 Remove an extraneous + 2018-03-14 23:59:20 -07:00
Chris Robinson 603e3e23ac Remove an outdated comment 2018-03-14 23:51:13 -07:00
Chris Robinson 2011421e18 Release the PulseAudio mainloop lock sooner 2018-03-14 23:48:46 -07:00
Chris Robinson 7c0e68a33e Store the filter history in local variables
Despite being marked as restrict (and const for src) to mark the pointers as
being non-aliased, it seems the compiler optimizes better this way.
2018-03-14 17:27:41 -07:00
Chris Robinson f65e83c349 Avoid using pa_stream_begin_write with PulseAudio
It seems to actually have a negative performance impact when the system is
under load. Without having actual measurements for any potential benefits,
simply go with the recommended (and previous fallback) method of allocating
space for the write and passing the free method.

Ideally some kind of ring buffer could be used, so rather than constantly
allocating and freeing blocks of memory, it uses the same memory over again
with the callback marking each one as reusable. Unfortunately the callback
isn't given much information to work with, and the update size (minreq) can
potentially change during playback, which complicates things.
2018-03-14 03:21:26 -07:00
Chris Robinson 942abab8f9 Move a loop into a function 2018-03-13 03:45:24 -07:00
Chris Robinson 8eb7a94e1c Apply a distance decay on the source send for the reverb's DecayLFRatio 2018-03-11 22:40:08 -07:00
Chris Robinson 6b35a4534f Comment and clarify some code 2018-03-11 22:18:11 -07:00
Chris Robinson dac9379449 Add methods to clean up althrd and altss data 2018-03-10 12:10:58 -08:00
Chris Robinson a6ddeaf5f1 Rename the mmdevapi backend to wasapi 2018-03-09 18:56:24 -08:00
Chris Robinson 30821e978b Add extern "C" to some headers 2018-03-09 17:24:03 -08:00
Chris Robinson c0e7a5b8b0 Prefix SDL2 device names on Windows 2018-03-09 11:41:28 -08:00
Chris Robinson 8b24255557 Request the device's sample type for SDL2 2018-03-09 10:53:03 -08:00
Chris Robinson 46e7e96eb3 Store the frame size for the SDL2 backend 2018-03-08 22:23:36 -08:00
Chris Robinson 41cc82e84b Print the unsupported values from SDL2 2018-03-08 22:09:30 -08:00
Chris Robinson 2866c6cf28 Init and quit the SDL2 audio subsystem with the factory 2018-03-08 18:59:22 -08:00
Chris Robinson 0c7fa1b955 Avoid deinitializing backends that never initialized 2018-03-08 18:53:49 -08:00
Chris Robinson aa7df8183f Also save the update size with SDL2 2018-03-08 18:22:03 -08:00
Chris Robinson 58760e6184 Use the audio device lock for the SDL2 backend 2018-03-08 18:16:10 -08:00
Chris Robinson 52ca70d98e Properly close the SDL2 audio device 2018-03-08 18:12:14 -08:00
Chris Robinson d4fc87fc9c Avoid calling SDL_GetNumAudioDevices multiple times 2018-03-08 18:07:49 -08:00
Chris Robinson 2187316bce Use function-like macros to call filter and effect vtable methods 2018-03-08 17:48:22 -08:00
Chris Robinson 52dee31270 Only calculate the modulation samples once for all 4 channels 2018-03-08 17:48:22 -08:00
Chris Robinson 22d3e3b563 Simplify modulator effect index updating 2018-03-08 17:48:21 -08:00
Chris Robinson 4e613c5d4b Rename UpdateContextSources for clarity 2018-03-08 17:48:21 -08:00
Chris Robinson 07c8857558 Fix struct forward declaration typo 2018-03-08 17:48:21 -08:00
Chris Robinson 9bd1678299 Fix adding to and removing from the active effect slots
It wasn't properly removing all duplicates on insertion, and didn't remove the
first effect slot when removing them.
2018-03-08 17:48:21 -08:00
Chris Robinson 19281868dc Properly limit the max number of effect slots to 2^31 - 1 2018-03-08 17:48:21 -08:00
kcat 5133fe5115 Merge pull request #175 from jhasse/sdl2-backend
Add SDL2 backend for playback, fix #173
2018-03-08 17:47:32 -08:00
Jan Niklas Hasse 2eb29d538b SDL2 backend: Reset device parameters 2018-03-08 20:42:47 +01:00
Jan Niklas Hasse 0af075b5ff SDL2 backend: Allow changes to channels and format 2018-03-08 20:27:02 +01:00
Jan Niklas Hasse ef2b813776 SDL2 backend: Allow frequency changes 2018-03-08 10:17:02 +01:00
Jan Niklas Hasse a6f93a501a Handle passing NULL to SDL_OpenAudioDevice as a special device
https://discourse.libsdl.org/t/changing-audio-output-when-the-default-audio-playback-device-changes/22399/2
2018-03-08 10:07:22 +01:00
Jan Niklas Hasse 767807cd22 SDL2 backend: Use callback instead of a timing loop
The system clock and audio clock aren't necessarily synchronized.
2018-03-08 09:51:44 +01:00
Jan Niklas Hasse 86319127e3 Add SDL2 backend for playback, fix #173 2018-03-07 20:57:53 +01:00
Chris Robinson 179e1c4dbc Don't check for space in the ringbuffer before trying to write
The write method already checks and returns how much it managed to fit in.
2018-03-03 21:57:42 -08:00
Chris Robinson 945d74cbc9 Avoid some code duplication 2018-03-03 14:04:10 -08:00
Chris Robinson b8636a3dbf Add some missing locks to protect reading state 2018-03-03 13:54:21 -08:00
Chris Robinson 4e6c758daf Use a plain mutex for the property lock 2018-03-03 13:42:37 -08:00
Chris Robinson 4bd02eada6 Init more stuff in InitDevice 2018-03-03 09:00:14 -08:00
Chris Robinson bd32a682f7 Use atomic variables instead of volatile 2018-03-02 19:16:55 -08:00
Chris Robinson 03274a5b95 Ensure at least the specified ringbuffer size is writable
Previously, all but one of the specified size could be written (so for a size
of n, only n-1 was guaranteed writable). All users pretty much compensated for
this, but it makes more sense to fix it at the source.
2018-03-02 13:01:11 -08:00
Chris Robinson 6f62fed65c Add an option to limit the write size of the ringbuffer 2018-03-01 21:23:13 -08:00
Chris Robinson cba37819d1 Add missing include 2018-03-01 21:19:49 -08:00
Chris Robinson 4b85104c4f Apply the limiter, distance comp, and others even with no output buffer 2018-03-01 16:16:37 -08:00
Chris Robinson 0d91d63cf3 Fix use of argv[0] as the program name after incrementing 2018-02-28 21:04:45 -08:00
Chris Robinson abc6e37e6e Apply distance attenuation to reverb zones in almultireverb 2018-02-28 20:59:41 -08:00
Chris Robinson 812cb62617 Fix a comment regarding the effect slot channel scaling 2018-02-28 20:39:53 -08:00
Chris Robinson a211c2f5e4 Avoid AL prefix on internal effect state factory types
Also avoid using the generic V/V0 macros for them
2018-02-28 19:37:12 -08:00
Chris Robinson d25398d2c7 Avoid using static inline in headers 2018-02-25 13:14:14 -08:00
Chris Robinson 654a45833a Only send one buffer completed event per update
The 'param' callback parameter indicates the number of buffers that were
completed.
2018-02-25 10:05:25 -08:00
Chris Robinson 455763aa9a Count all buffers in a list item for processed and queued 2018-02-25 09:51:07 -08:00
Chris Robinson c7456affd5 Don't make the source state atomic 2018-02-24 09:44:52 -08:00
Chris Robinson a1ef5e38b6 Handle source state change events 2018-02-24 09:24:18 -08:00
Chris Robinson 14bdc6c2ef Use separate functions to add and remove active effect slots 2018-02-23 23:02:31 -08:00
Chris Robinson bf886444d2 Avoid multiple GetChannelIdxByName calls 2018-02-21 19:53:18 -08:00
Chris Robinson 9fc2dbe063 Update the multi-zone reverb example for clarity 2018-02-20 08:08:18 -08:00
Chris Robinson 51c6d13c0f Add almultireverb to the install target 2018-02-20 08:08:18 -08:00
kcat e7ac63be4d Merge pull request #171 from digitalist/patch-1
fix building on freebsd (clang), maybe osx too
2018-02-20 07:46:38 -08:00
Alexey Elymanov d7d043a5ef fix building on freebsd (clang)
fixes error: 'pow' is not a member of 'std'
2018-02-20 11:53:55 +03:00
Chris Robinson 1002bc36e0 Add an example for multi-zone reverb 2018-02-18 23:56:51 -08:00
Chris Robinson 6ff50558a0 Use a proper struct for specifying angular points 2018-02-18 23:56:51 -08:00
Chris Robinson fa9ab9af7c Minimize each response delay for the ambisonic HRTF decode 2018-02-18 23:56:51 -08:00
Chris Robinson b5aa0c0759 Remove the unnecessary ComputeAmbientGains 2018-02-18 23:56:51 -08:00
Chris Robinson 79604c3c0e Preserve RMS for the high-frequency HRTF ambisonic coefficients 2018-02-18 23:56:51 -08:00
Chris Robinson 7a974b2460 Combine the vector reverse and partial scatter where they're together 2018-02-18 23:56:51 -08:00
Chris Robinson 7f3d69fdbc Remove an unnecessary comment about if meters_per_unit is > 0 2018-02-18 23:56:51 -08:00
Chris Robinson 7dafac0c34 Avoid duplicating some scale tables 2018-02-18 23:56:51 -08:00
kcat c24aea712b Merge pull request #170 from digitalist/patch-1
freebsd fix: typo
2018-02-18 23:56:02 -08:00
Alexey Elymanov 063ad490a2 freebsd fix: typo
Alc/helpers.c:738:30: error: use of undeclared identifier 'KERN_PROCARGS'
    int mib[4] = { CTL_KERN, KERN_PROCARGS, getpid() };

/usr/include/sys/sysctl.h:
`#define	KERN_PROC_ARGS		7	/* get/set arguments/proctitle */`
there's no KERN_PROCARGS
2018-02-18 20:55:31 +03:00
Chris Robinson 59768674f1 Use an alternate ambisonic HRTF decode layout
Similar to the previous, but includes the top and bottom HRTF responses. The
higher-order decode (for the "basic" HRTF output) also now uses 2H1P mixed-
order instead of 2H1V, which seems more stable.
2018-02-13 03:03:26 -08:00
Chris Robinson 2cb49e51a0 Fix NULL pointer dereference 2018-02-12 22:20:43 -08:00
Chris Robinson 6b76eddbe3 Supply HF coefficient scales with a single-band ambisonic matrix 2018-02-12 21:24:58 -08:00
Chris Robinson 59934b47de Avoid using an enum for array indices 2018-02-12 20:58:39 -08:00
Chris Robinson 4d417f3dd4 Make bformatdec_free and ambiup_free clear the freed pointer 2018-02-12 20:48:28 -08:00
Chris Robinson dce497fbca Use a bitfield for enabled bformatdec channels 2018-02-12 20:33:31 -08:00
Chris Robinson e63e0ee596 Combine multiple functions called sequentially 2018-02-11 22:23:03 -08:00
Chris Robinson 494e9fd61d Don't asynchronously modify the source on disconnect 2018-02-11 16:58:34 -08:00
Chris Robinson b11e31fbfd Clear stale 'post's on the event semphaphore 2018-02-11 06:14:18 -08:00
Chris Robinson 1e93122470 Remove unused reverb modulation code
Still unsure how to handle reverb modulation without some kind of reference
output, so remove the related functions to not waste CPU time. It'll remain in
the Git history should it ever need to be resurrected.
2018-02-10 19:50:42 -08:00
Chris Robinson 5b11129eaa Use a function pointer for applying the dry mix post-process 2018-02-10 15:50:05 -08:00
Chris Robinson ee3d53a673 Use an alternate virtual layout for Ambisonic HRTF decoding
This uses 16 channels, an 8-channel octagon + 8-channel cube, which should
improve horizontal resolution without affecting vertical too much.
2018-02-10 05:16:28 -08:00
Chris Robinson c346baff5b Clarify some macro names using ambisonic mixed-mode notation 2018-02-09 18:43:34 -08:00
Chris Robinson 20bee69955 Attempt to improve the reverb panning vectors
This should now retain the original orientation of the soundfield and merely
focus on the panning vector direction, as intended.
2018-02-08 01:18:40 -08:00
Chris Robinson 4cd04f192d Alter tha curve of the density-related delay scale
The delay scale is roughly linear with respect to room size, however the
density is not linear with room size. The density is calculated by taking the
room size cubed, then normalized by some factor. Unnormalizing the density and
taking the cube root restores the original room size to use as a delay scale.

The patch also alters the delay and all-pass line lengths to be based on a 1
meter room size, so the the room size recovered from the density acts as a
direct multiple for the desired target length.

Note that the room scale range is unchanged (5m to 50m), so the minimum and
maximum delays are the same. It should also be noted that 50m may not be the
correct room size for a density value of 1. A density value of 1 corresponds to
an environment size of roughly 2.52m when converted from EAX (DENSITY_SCALE
should be 16 rather than 125000), but sizes that low result in undesirable
resonance in the feedback, indicating other changes are necessary for that to
work.
2018-02-08 00:05:29 -08:00
Chris Robinson f5f996c14a Check for a cbrtf function 2018-02-06 02:35:08 -08:00
Chris Robinson da1ee3baba Revert "Don't fade the all-pass delay changes"
This reverts commit 799dfb732b.
2018-02-04 19:57:22 -08:00
Chris Robinson 1d7a5dbede Remove unsupported source queries 2018-02-04 15:01:04 -08:00
Chris Robinson 9b878c64f9 Make the Connected state atomic
Also don't send the Disconnected event more than once.
2018-02-04 00:01:12 -08:00
Chris Robinson 1f61472e77 Avoid potentially writing partial samples 2018-02-03 14:02:47 -08:00
Chris Robinson b99e64a0e3 Provide more descriptive messages to disconnection events 2018-02-03 13:54:42 -08:00
Chris Robinson e49607078e Handle disconnected events in alffplay 2018-02-03 11:27:03 -08:00
Chris Robinson 4ef60d7214 Add a couple missing lock calls 2018-02-03 01:26:04 -08:00
Chris Robinson 40bda4d93f Add a disconnected event type 2018-02-03 01:07:06 -08:00
Chris Robinson 8f4c078fb5 Add missing header for UINT_MAX 2018-02-02 23:08:29 -08:00
Chris Robinson 80cc32d77b Remove the unused thunk code 2018-02-02 22:59:06 -08:00
Chris Robinson 28fa82378b Remove the individual source queue and buffer locks
They're inherently protected by the mutex for their respective lists. Should
those mutexes be replaced by rwlocks the individual locks should also be
reinstated, but they're unlikely to be unless a lot of contention starts
happening in the read-only case.
2018-02-02 22:24:33 -08:00
Chris Robinson 6a4a88f8f5 Store an index to a given source's voice
For more efficient voice lookups when needed.
2018-02-01 23:56:35 -08:00
Chris Robinson a114d6cbb5 Remove unused _timed methods
They're not reliably implemented anyway, as some systems will just flat out
fail when trying to use them.
2018-02-01 22:24:17 -08:00
Chris Robinson 3acd2a55ad Don't generate Buffer Completed events for static sources 2018-02-01 21:07:55 -08:00
Chris Robinson 3a90fd5751 Avoid an unnecessary temp variable 2018-02-01 19:11:23 -08:00
Chris Robinson ec14c98f2d Use an atomic instead of volatile to tell a thread to quit 2018-02-01 18:59:32 -08:00
Chris Robinson 975c682ec3 Use semaphores to signal for more samples with JACK and OpenSL 2018-02-01 18:54:13 -08:00
Chris Robinson e240351d81 Use a semaphore to signal the event handler
Semaphores allow for semi-persistent signals, compared to a condition variable
which requires a mutex for proper detection. A semaphore can be 'post'ed after
writing some data on one thread, and another thread will be able to recognize
it quickly even if the post occured in between checking for data and waiting.

This more correctly fixes a race condition with events since the mixer
shouldn't be using mutexes, and arbitrary wake-ups just to make sure an event
wasn't missed was quite inefficient.
2018-02-01 18:20:14 -08:00
Chris Robinson 4ec31291c0 Add semaphore functions to the thread API wrapper 2018-02-01 17:37:31 -08:00
Chris Robinson 7a538141c9 Signal a condition variable when a buffer completes in alffplay 2018-02-01 02:24:44 -08:00
Chris Robinson bcdc399029 Send buffer completed events when enabled 2018-02-01 01:36:03 -08:00
Chris Robinson 8652ae046b Fix check for matching event type 2018-02-01 00:50:06 -08:00
Chris Robinson 833eface38 Don't print buffer completed events in alffplay 2018-01-31 20:27:14 -08:00
Chris Robinson 7256bc92fa Add a thread to marshal events from the mixer
To avoid having unknown user code running in the mixer thread that could
significantly delay the mixed output, a lockless ringbuffer is used for the
mixer to provide events that a secondary thread will pop off and process.
2018-01-31 20:21:54 -08:00
Chris Robinson 0394d5a44f Rename EventLock to make it more clear it's protecting the callback 2018-01-30 12:34:25 -08:00
Chris Robinson e7217760f3 Don't bother with an explicit stop backend method 2018-01-29 01:00:53 -08:00
Chris Robinson a042dbf305 Call the backend close method in the destructor 2018-01-28 23:32:28 -08:00
Chris Robinson 328fd7329d Combine common initialization code into a function 2018-01-28 18:03:54 -08:00
Chris Robinson a24a22c39a Fix the effect slot limit check 2018-01-28 17:56:47 -08:00
Chris Robinson c2710ffe87 Make EnabledEvts atomic 2018-01-28 16:58:41 -08:00
Chris Robinson 782eb650c7 Use std::array instead of a plain array in alffplay 2018-01-28 13:18:33 -08:00
Chris Robinson 38a3ba74d4 Report the problem value for global state errors 2018-01-28 13:13:40 -08:00
Chris Robinson d1da9f1f67 Remove some now-unused NoLock function variants 2018-01-28 00:53:21 -08:00
Chris Robinson dcc5a10c7b Use a fixed array for the effect state factory list 2018-01-28 00:10:12 -08:00
Aaron Jacobs 79bce84900 Add option to disable "build_version" cmake target 2018-01-28 00:03:02 -08:00
Chris Robinson 0051ebace0 Don't bother with a return value that's never used 2018-01-27 23:50:04 -08:00
Chris Robinson 0cd61fd197 Don't allocate more effect slots than allowed 2018-01-27 23:07:29 -08:00
Chris Robinson f16ece6048 Move some inline functions into a header instead of copying them
Unfortunately does not include the Lookup* functions, which need the full type
declaration to offset the pointer.
2018-01-27 21:16:24 -08:00
Chris Robinson e12059a311 Fix error reporting for resource generation 2018-01-27 20:04:21 -08:00
Chris Robinson cb9fb31214 Store filters in an array of lists 2018-01-27 19:40:47 -08:00
Chris Robinson e8c268ef09 Store effects in an array of lists 2018-01-27 19:04:32 -08:00
Chris Robinson 6a839600b9 Use a vector to store the effect slot pointers
And make the ID a simple index into it (1-base, to avoid ID 0).
2018-01-27 19:04:32 -08:00
Chris Robinson 4d1795e90b Remove an unused function 2018-01-27 19:04:32 -08:00
kcat 277127829a Merge pull request #166 from Ybalrid/betterReadme
Better readme
2018-01-27 19:03:50 -08:00
Arthur Brainville 58fd9d70d2 Additional corrections as mentionned in the PR 2018-01-28 03:26:02 +01:00
Arthur Brainville d2cf61c99a Added AppVeyor badge 2018-01-28 02:29:54 +01:00
Arthur Brainville 6562a939ea Add project overview and travis build badge
Signed-off-by: Arthur Brainville (Ybalrid) <ybalrid@ybalrid.info>
2018-01-28 01:37:00 +01:00
Chris Robinson 031cf24880 Use an array lookup for source IDs
This is now similar to buffers, being stored in groups of 64 in a vector with
the ID providing the array indices.
2018-01-27 14:34:05 -08:00
Chris Robinson 38261a0f2a Make some more functions static where they're used 2018-01-27 14:34:05 -08:00
Chris Robinson c4a76af397 Add some casts to pacify MSVC 2018-01-27 14:34:05 -08:00
Chris Robinson f76ab02bd4 Add a ctz64 fallback using _BitScanForward when available 2018-01-27 14:34:05 -08:00
kcat 4d392a8b87 Merge pull request #165 from Ybalrid/Ybalrid-readme-patch
Reformat README for a nicer display on github
2018-01-27 14:33:38 -08:00
Arthur Brainville c969dad6c2 Reformat README for a nicer display on github 2018-01-27 23:16:36 +01:00
Chris Robinson 9718502e5d Check for _BitScanForward64 before using it 2018-01-27 11:11:39 -08:00
Chris Robinson 9613b4bfe2 Use a different method for storing and looking up buffers
Rather than each buffer being individually allocated with a generated 'thunk'
ID that's used with a uint:ptr map, buffers are allocated in arrays of 64
within a vector. Each group of 64 has an associated 64-bit mask indicating
which are free to use, and the buffer ID is comprised of the two array indices
which directly locate the buffer (no searching, binary or otherwise).

Currently no buffers are actually deallocated after being allocated, though
they are reused. So an app that creates a ton of buffers once, then deletes
them all and uses only a couple from then on, will have a bit of waste, while
an app that's more consistent with the number of used buffers won't be a
problem. This can be improved by removing elements of the containing vector
that contain all-free buffers while there are plenty of other free buffers.

Also, this method can easily be applied to other resources, like sources.
2018-01-27 01:51:01 -08:00
Chris Robinson 5d2196c119 Don't rely on alMain.h in alBuffer.h 2018-01-26 21:32:43 -08:00
Chris Robinson a885fd6d0e Make some functions static that are only used in one source 2018-01-26 21:11:12 -08:00
Chris Robinson 3ba4746ff8 Allow preserving converted samples 2018-01-26 16:41:14 -08:00
Chris Robinson e1e1c73ae6 Read the buffer unpack alignment under the buffer lock 2018-01-26 15:58:38 -08:00
Chris Robinson fbafbe6272 Improve error reporting for buffers 2018-01-26 00:13:03 -08:00
Chris Robinson 6ae7fc5df1 Add the printf-format attribute to alSetError 2018-01-25 23:52:09 -08:00
Chris Robinson 99f0377ae3 Construct error messages using parameterized values 2018-01-25 15:59:59 -08:00
Chris Robinson 932939c5a8 Enable events in alffplay 2018-01-24 20:04:57 -08:00
Chris Robinson 0c9c846522 Report AL_SOFTX_events as an in-progress extension 2018-01-24 19:59:22 -08:00
Chris Robinson f5236ab186 Use more appropriate enum values for events 2018-01-24 19:25:15 -08:00
Chris Robinson 2a7f5aa569 Add a deprecated event type for alDopplerVelocity 2018-01-24 18:47:19 -08:00
Chris Robinson 1d86aea61c Fix ordering of alGetPointervSOFT 2018-01-24 18:30:32 -08:00
Chris Robinson 2ded5547ba Provide messages for the remaining AL errors 2018-01-24 17:07:01 -08:00
Chris Robinson 395278fcdb Set the buffer load error in LoadData 2018-01-24 12:45:56 -08:00
Chris Robinson 786a05876e Call the event callback when an error is generated
Most errors don't yet provide correct object IDs or text messages for the AL
error.
2018-01-24 12:10:48 -08:00
Chris Robinson caa3b4f7f8 Handle event properties
This just implements the event methods insofar as tracked state. No events are
generated/reported yet.
2018-01-23 18:25:59 -08:00
Chris Robinson 2266a9e01e Declare the beginnings of an event extension 2018-01-23 17:42:39 -08:00
Chris Robinson def2547e40 Fix some 'may be used initialized' warnings 2018-01-23 16:03:06 -08:00
Chris Robinson 2ac0adaebb Use a new proper buffer function with a flags parameter
Rather than hackily combining bit flags with the format, to increase the number
of potential flags. alBufferData now behaves as if calling alBufferStorageSOFT
with a flags value of 0.
2018-01-23 14:33:30 -08:00
Chris Robinson 4ebb97bf73 Test mapped buffers in alffplay 2018-01-23 11:15:25 -08:00
Chris Robinson b05592b0ab Ensure read or write flags are specified with persistent mappings 2018-01-23 10:59:51 -08:00
Chris Robinson 9ee58fd454 Track the buffer's mapped section 2018-01-23 10:51:23 -08:00
Chris Robinson 4f9a0460c4 Add a flag for persistent mapping
And a function to "flush" a mapped buffer
2018-01-23 10:38:27 -08:00
Chris Robinson ad61392318 Slightly simplify alBufferSubDataSOFT 2018-01-22 16:17:45 -08:00
Chris Robinson a852ecf8ce Ensure proper alignment when preserving data too 2018-01-22 15:52:53 -08:00
Chris Robinson d6d6ec03f1 Don't bother allocating cleared memory for buffer storage 2018-01-22 15:46:46 -08:00
Chris Robinson fce72610bb Add a flag for alBufferData to non-destructively resize the data
Requires having the same format as the last call to alBufferData. Also only
makes sense when given a NULL data pointer, as otherwise the internal data will
be overwritten anyway.
2018-01-22 11:34:16 -08:00
Chris Robinson 4a368ab905 Fix the return type of the al_fwrite wrapper 2018-01-22 10:48:55 -08:00
Chris Robinson f1f7fba3b9 Don't convert/copy samples with a NULL dest buffer
Only happens with a 0 size, so there's nothing to copy or convert anyway.
2018-01-22 00:31:27 -08:00
Chris Robinson ca07e210a7 Remove now-unused alloca and VLA checks 2018-01-21 23:50:47 -08:00
Chris Robinson 5f3ae527c9 More cleanup for buffer loading
Don't bother with unnecessary and unused converters, and remove some
unsupported queries.
2018-01-21 23:35:28 -08:00
Chris Robinson db13af1935 Handle double-precision buffers in the mixer 2018-01-21 18:34:03 -08:00
Chris Robinson efd11f32a2 Remove support for (signed) byte and ushort sample storage
Also not used without buffer_samples
2018-01-21 18:16:27 -08:00
Chris Robinson 6489fb586b Remove (u)int32 sample storage conversion
Unused without the buffer_samples extension
2018-01-21 17:55:35 -08:00
Chris Robinson 427212705f Remove the old buffer_samples functions
The symbols are still there and exported to retain ABI compatibility, but they
no longer do anything except set an AL_INVALID_OPERATION error. They're also
removed from the function and enum tables, since they're not part of any
supported extension.
2018-01-21 17:19:57 -08:00
Chris Robinson f6276164f3 Fix the return type of the LPALUNMAPBUFFERSOFT typedef 2018-01-21 16:32:37 -08:00
Chris Robinson dcb934fc2e Avoid repeating some code 2018-01-21 10:32:48 -08:00
Chris Robinson c2c3846930 Expose a preliminary AL_SOFT_map_buffer extension for testing 2018-01-20 13:37:43 -08:00
Chris Robinson 03d4e4acc4 Add methods to "map" a buffer's storage
Requires the MAP_READ_BIT or MAP_WRITE_BIT flags to be OR'd with the format
upon a call to alBufferData, to enable mappable storage for the given access
types. This will fail if the format requires internal conversion and doesn't
resemble the original input data, so the app can be guaranteed the size, type,
and layout of the original data is the same as what's in storage.

Then alMapBufferSOFT may be called with appropriate bit flags to get a readable
and/or writable pointer to the buffer's sample storage. alUnmapBufferSOFT must
be called when access is finished. It is currently invalid to map a buffer that
is attached to a source, or to attach a buffer to a source that is currently
mapped. This restriction may be eased in the future, at least to allow read-
only access while in use (perhaps also to allow writing, if coherency can be
achieved).

Currently the access flags occupy the upper 8 bits of a 32-bit bitfield to
avoid clashing with format enum values, which don't use more than 16 or 17
bits. This means any future formats are limited to 24-bit enum values, and also
means only 8 flags are possible when declaring storage. The alternative would
be to add a new function (alBufferStorage?) with a separate flags parameter.
2018-01-20 11:49:01 -08:00
Chris Robinson 4e647bda07 Return the effective alignment from SanitizeAlignment 2018-01-19 21:00:53 -08:00
Chris Robinson ab2295b68f Store 8-bit sample types directly as unsigned byte 2018-01-19 20:10:31 -08:00
Chris Robinson 940c6146e8 Remove unnecessary private AL_SOFT_buffer_samples2 definitions 2018-01-19 19:28:23 -08:00
Chris Robinson b56673bbce Make a function static that's only used in one source file 2018-01-17 18:43:23 -08:00
Chris Robinson 2102625021 Reformat the format array 2018-01-17 18:03:31 -08:00
Chris Robinson 884fe40fd1 Store mulaw and alaw samples directly in the buffer
They're now decompressed on the fly in the mixer. This is not a significant
performance issue given that it only needs a 512-byte lookup table, and the
buffer stores half as much data (it may actually be faster, requiring less
overall memory).
2018-01-17 08:49:49 -08:00
Chris Robinson 3baf9d0e81 Add a method to get the system's page size 2018-01-16 19:28:10 -08:00
Chris Robinson 248832b266 Use a voice flag to indicate it being static 2018-01-16 18:07:59 -08:00
Chris Robinson bf8c889631 Define DECL_VLA where it's used 2018-01-16 12:57:06 -08:00
Chris Robinson 273dca2fa0 Avoid using alloca in the CoreAudio backend 2018-01-16 12:54:20 -08:00
Chris Robinson e80b016cbe Use a global RowMixerFunc 2018-01-16 12:18:59 -08:00
Chris Robinson 8c19497340 Properly cast some parameters for MSVC 2018-01-16 09:40:34 -08:00
Chris Robinson 5deb1df8db Add min/max/clamp functions for size_t 2018-01-16 09:39:28 -08:00
Chris Robinson 14a0df03e8 Do more samples at once with the distortion effect 2018-01-16 08:49:15 -08:00
Chris Robinson bc44efb91d Use ALsizei for some count/length variables 2018-01-15 18:31:43 -08:00
Chris Robinson 799dfb732b Don't fade the all-pass delay changes 2018-01-15 18:02:11 -08:00
Chris Robinson 813b06a3a4 Fix a comment regarding the T60 filter coefficients 2018-01-15 09:22:28 -08:00
Chris Robinson 47c9b0a17e Simplify preparing the T60 filters 2018-01-15 09:17:15 -08:00
Chris Robinson 44795b8614 Assign the HRTF storage pointers separately 2018-01-15 08:38:25 -08:00
Chris Robinson 5acb2e5165 Remove alffplay's duplicate ALC_SOFT_device_clock declarations 2018-01-15 07:14:35 -08:00
Chris Robinson 682205a3d4 Finalize ALC_SOFT_device_clock 2018-01-15 06:45:53 -08:00
Chris Robinson 7441311e3d Use separate input and outputs for the T60 and allpass processing 2018-01-15 05:37:00 -08:00
Chris Robinson 6f48dac4cc Use a proper type for the T60 decay filter 2018-01-15 05:23:35 -08:00
Chris Robinson bc078e5158 Separate some anonymous structs into defined structs 2018-01-14 15:42:25 -08:00
Chris Robinson 63416bf28f Avoid unnecessarily using type aliases 2018-01-14 09:02:59 -08:00
Chris Robinson 0152bc0d10 Remove the SAFE_CONST macro
Seems compilers are now allowing a pointer-to-type-array to implicitly convert
to pointer-to-const-type-array.
2018-01-14 08:51:03 -08:00
Chris Robinson 7e491ef2b2 Remove a redundant lower value clamp 2018-01-14 08:25:36 -08:00
Chris Robinson 6f532fa0e5 Don't check the modulation depth for changes multiple times 2018-01-14 07:33:53 -08:00
Chris Robinson 25b3ed3532 Use separate arrays for the T60 filter states 2018-01-14 07:29:18 -08:00
Chris Robinson 7a77a20a67 Use a macro for the number of reverb lines 2018-01-14 07:25:02 -08:00
Chris Robinson 2957d85924 Only pass the needed parameters to LateT60Filter 2018-01-14 05:24:23 -08:00
Chris Robinson 2b968766b9 Pre-apply the T60 filter midgain to the HF filter coeffs 2018-01-13 09:58:47 -08:00
Chris Robinson 78cb70a5f9 Replace some freq_mult variable names with f0norm
The latter is a bit more descriptive as f0 is often used to denote the
reference frequency of a filter, so f0norm indicates the normalized reference
frequency (ref_freq / sample_rate).
2018-01-13 09:14:46 -08:00
Chris Robinson 16e4e0fa7c Use a more normal vtable setup for filter methods 2018-01-13 08:07:03 -08:00
Chris Robinson c031b3cc6a Avoid fixed-PATH_MAX-size buffers
Windows still needs to use MAX_PATH in a couple places, but that macro's
guaranteed there.
2018-01-13 04:40:20 -08:00
Chris Robinson bbc4ebecab Use GetProcBinary to get the executable name for PulseAudio 2018-01-13 03:41:56 -08:00
Chris Robinson 71ad3b1715 Use KERN_PROCARGS to get the process path+filename on FreeBSD 2018-01-13 03:38:10 -08:00
Chris Robinson af8bbefcab Support procfs on *BSD to get the process binary 2018-01-13 03:22:41 -08:00
Chris Robinson 26043269e4 Allow GetProcPath to return the filename also 2018-01-13 02:59:21 -08:00
Chris Robinson c9edf7cf78 Add a string function to copy a wide-char range 2018-01-13 02:03:13 -08:00
Chris Robinson 77910afe57 Make NumAttrsForDevice do similar type checks as alcGetIntegerv 2018-01-12 11:34:23 -08:00
Chris Robinson 4db1328bc5 Move the FORCE_ALIGN macro to threads.h 2018-01-12 03:55:33 -08:00
Chris Robinson e634564b26 Make a couple functions inline 2018-01-12 02:37:48 -08:00
Chris Robinson dae5faedb0 Use atomic variables in place of volatile 2018-01-11 23:28:15 -08:00
Chris Robinson 1f236d8f20 Define a function where it's used 2018-01-11 22:42:25 -08:00
Chris Robinson 370817ba60 Move logging declarations to a separate header 2018-01-11 20:17:02 -08:00
Chris Robinson 2873abcbc0 Fix up some types for MSVC 2018-01-11 10:55:35 -08:00
Chris Robinson e89c183231 Avoid including alMain.h in ringbuffer.c 2018-01-11 10:03:26 -08:00
Chris Robinson ca9e6a4f94 Ensure NextPowerOf2 is being used correctly 2018-01-11 09:53:52 -08:00
Chris Robinson b11131ce0c Move a forward declaration to the others 2018-01-11 09:43:45 -08:00
Chris Robinson 2d2ca1d791 Remove SET_VTABLE1 2018-01-11 09:39:52 -08:00
Chris Robinson 85a8f965e5 Clean up the EffectList members and make the list size known 2018-01-11 09:34:01 -08:00
Chris Robinson 88545ccae5 Move the EffectList array to alEffect.c/h 2018-01-11 09:25:17 -08:00
Chris Robinson 3832b25f30 Move the ringbuffer declarations to a separate header
And rename alcRing.c to ringbuffer.c for consistency.
2018-01-11 09:16:28 -08:00
Chris Robinson 15ad5245bf Move the FPU mode declarations to a separate header
Also don't use inheritance with FPUCtl.
2018-01-11 08:44:52 -08:00
Chris Robinson 8aa9e35f8c Move the config function declarations to their own header
And rename alcConfig.c to alconfig.c for consistency.
2018-01-11 07:56:54 -08:00
Chris Robinson 81b13f78ea Move the CPU capability flags to a separate header 2018-01-11 07:19:19 -08:00
Chris Robinson 9b9ec2c21a Move the compressor/limiter declarations to their own header 2018-01-11 06:50:53 -08:00
Chris Robinson f3c9bc114c Move the polymorphic/inheritance macros to a separate header 2018-01-11 06:32:45 -08:00
Chris Robinson ff231b42ff Reorder some loops in the equalizer and use MixSamples 2018-01-11 05:03:00 -08:00
Chris Robinson 9c33f4aea8 Use MixSamples for the dedicated and ring modulator effect output 2018-01-11 04:48:18 -08:00
Chris Robinson f55583330b Apply the distortion gain to the mixing gains 2018-01-11 04:34:51 -08:00
Chris Robinson 2c8e4467c3 Move some HRTF structures to hrtf.h 2018-01-11 03:53:25 -08:00
Chris Robinson 15f9d15ba0 Avoid using macros to access anonymous structures 2018-01-11 03:45:23 -08:00
Chris Robinson 279799ad70 Don't return whether the bsinc filter cuts or not 2018-01-10 19:20:58 -08:00
Chris Robinson ea6b384980 Make a function pointer static 2018-01-10 19:13:41 -08:00
Chris Robinson ef63ec3fe9 Use one macro to handle both resample padding sizes 2018-01-09 23:55:59 -08:00
Chris Robinson de8c5b1824 Combine the chorus and flanger processing functions
Given that they're nearly identical, it should be relatively simple to use the
same effect state to process either of them, similar to the reverbs. The big
differences seem to be the delay range (much shorter with flanger) and the
defaults.
2018-01-09 23:21:16 -08:00
Chris Robinson 9e2eb5dc23 Rename the device's temp buffer storage to be more generic 2018-01-09 22:01:46 -08:00
Chris Robinson 5d1207104a Remove standard reverb specific processing functions 2018-01-07 22:48:03 -08:00
Chris Robinson d547f52d8f Move the UNEXPECTED macro to the main header and rename it 2018-01-07 22:20:08 -08:00
Chris Robinson 56e9cb69d3 Ensure the chorus delay and depth leave enough padding for resampling
Also use cubic resampling for the modulated tap. Applies to flanger too.
2018-01-07 21:15:18 -08:00
Chris Robinson 70973035de Use a separate function to get the cubic value 2018-01-07 17:24:29 -08:00
Chris Robinson c8a30592e8 Only print the time in alffplay when it changes 2018-01-07 17:23:51 -08:00
Chris Robinson d8258984b4 Use a -40dB drop for bsinc12
This improves the transition width at the cost of slightly more audible high-
frequency noise (nothing compared to linear or cubic, but still some). The
previous transition band caused a noticeable loss in higher frequencies, making
lower sample rate sources sound exceptionally dull or muffled.
2018-01-07 06:43:35 -08:00
Chris Robinson c423b6c8b7 Remove the sinc4 table 2018-01-07 05:58:52 -08:00
Chris Robinson 4cc1c64646 Replace the sinc4 resampler with cubic
Turns out the C version of the cubic resampler is just slightly faster than
even the SSE3 version of the FIR4 resampler. This is likely due to not using a
64KB random-access lookup table along with unaligned loads, both offseting the
gains from SSE.
2018-01-07 05:32:07 -08:00
Chris Robinson 0e1fd34c89 Fix a temp buffer leak in alffplay 2018-01-05 20:41:55 -08:00
Chris Robinson 10f2531b6c Handle the audio clock diff as nanoseconds in alffplay 2018-01-05 05:41:57 -08:00
Chris Robinson ecd327e5e1 Test the correct offset for the loop start range 2018-01-04 21:21:48 -08:00
Chris Robinson 510bccb6ac Use the correct start point when looping 2018-01-04 20:21:46 -08:00
Chris Robinson 32330c5eef Use separate outputs for the vector reverse and scatter functions 2018-01-04 20:04:39 -08:00
Chris Robinson e00ef16893 Avoid the modulated output tap for late reverb
And fix the output filtering. The modulation code is still there since it's
(probably) technically correct, but the interaction with the feedback loop and
filtering on the output caused improper behavior which needs to be sorted out.
2018-01-04 19:17:16 -08:00
Chris Robinson fd8143fea0 Use a non-recursive mutex for alffplay's source lock 2018-01-03 19:05:25 -08:00
Chris Robinson 08a4840298 Don't offset the reverb modulation sinus 2018-01-02 19:52:57 -08:00
Chris Robinson a16f933e3a Use a float literal for float math 2018-01-02 19:44:31 -08:00
Chris Robinson 9d61f429a5 Use ALC_SOFT_device_clock in alffplay 2018-01-02 19:32:28 -08:00
Chris Robinson b8de63d608 Reset CompLen when loading loop repeats in the mixer 2018-01-02 19:29:58 -08:00
Chris Robinson dcc0f6e25d Improve starting synchronization in alffplay
It waits until the internal buffers are filled before starting playback, then
triggering the audio and video to start as close together as possible.
2018-01-02 03:31:12 -08:00
Chris Robinson 21684fac69 Inline and simplify some code 2018-01-01 22:28:28 -08:00
Chris Robinson 329333ca8b Don't leak the AVIOContext 2018-01-01 19:16:05 -08:00
Chris Robinson 91e20dc12e Fix a couple alffplay comments still referencing Alure 2018-01-01 18:54:15 -08:00
Chris Robinson aecfa0b426 Make smart pointer wrappers for some ffmpeg types 2018-01-01 18:47:48 -08:00
Chris Robinson 9675068706 Print the running time and duration in alffplay 2018-01-01 16:15:32 -08:00
Chris Robinson cbd55ad31e Use aliases to simplify some time type names 2018-01-01 02:26:39 -08:00
Chris Robinson 5eb1753d31 Wrap av_gettime to ensure it's interpreted as microseconds 2018-01-01 01:39:28 -08:00
Chris Robinson e277f5e268 Rename the do_direct_out variable 2018-01-01 01:14:53 -08:00
Chris Robinson 145bf52b7a Use a less-intense memory order to check for quitting 2018-01-01 01:13:32 -08:00
Chris Robinson fe7bdc93eb Check for AL_SOFT_direct_channels once when initializing 2018-01-01 01:07:29 -08:00
Chris Robinson d889435334 Declare the total buffer time instead of buffer count 2018-01-01 01:04:47 -08:00
Chris Robinson dad17a7d91 Use a std::array for the buffers in alffplay 2018-01-01 00:32:27 -08:00
Chris Robinson 830adf6ae8 Use inline member initialization where possible 2018-01-01 00:17:40 -08:00
Chris Robinson babfa70cab Make more values global const 2018-01-01 00:02:51 -08:00
Chris Robinson 258eadd003 Use a global to specify alffplay's audio sync threshold 2017-12-31 23:44:33 -08:00
Chris Robinson 6dd1643a70 Avoid dereferencing a NULL pointer
Even though it's taking the address of a member, it's still technically a
derefernce and thus undefined behavior. sizeof doesn't "execute" the
expression, so derefering in it instead is fine.
2017-12-31 23:19:41 -08:00
Chris Robinson 48916ebd76 Clear the buffer queue when underrun 2017-12-31 16:29:52 -08:00
Chris Robinson 506d316f55 Wake up the packet send loop when more frames are needed 2017-12-31 16:11:00 -08:00
Chris Robinson 490b71378e Readd AL_SOFT_source_latency support to alffplay 2017-12-30 23:12:19 -08:00
Chris Robinson 0e8b0c520e Use standard duration types for stream clocks 2017-12-30 22:46:09 -08:00
Chris Robinson 0136df1e62 Improve the alffplay queue for FFmpeg's send/receive API
The packet handling thread now calls avcodec_send_packet to give compressed
data to libavcodec, while the audio/video threads call avcodec_receive_frame to
handle decoded frames. The packet thread still maintains local queues for each
stream to avoid starving an A/V thread when the other doesn't want another
frame yet.
2017-12-30 20:34:33 -08:00
Chris Robinson 98731bb574 Update resampler padding checks 2017-12-29 16:28:49 -08:00
Chris Robinson 27dfb7fd11 Fix up a comment 2017-12-24 20:41:20 -08:00
Chris Robinson 6457df54bb Don't make a pass-through macro for FadedDelayLineOut 2017-12-24 20:41:20 -08:00
Chris Robinson 07f3ed0419 Use linear interpolation for reverb modulation
The core LateReverb_* functions are explicitly written out now, since the
tapping and blending done by the Faded version is a bit more complex and it's
not so easy to ensure proper optimizing on the Unfaded version.
2017-12-24 20:40:53 -08:00
Chris Robinson dabb99de8d Don't offset the chorus/flanger delay and LFO
The delay being added to the scaled LFO will ensure a proper positive result
regardless.
2017-12-24 20:40:33 -08:00
Chris Robinson 254ebe5f96 Fade between depths in the reverb modulator 2017-12-24 16:23:30 -08:00
Chris Robinson b32a366137 Use a separate unmodulated feedback tap for reverb 2017-12-24 14:21:13 -08:00
Chris Robinson 3633b65e04 Only link to the common lib when building as shared 2017-12-23 21:23:32 -08:00
Chris Robinson ce74098b40 Clarify some reverb values 2017-12-23 21:13:57 -08:00
Chris Robinson 5769efe48e Reorder some global variables 2017-12-23 18:50:38 -08:00
Chris Robinson 02051ab51a Cleanup reverb modulation scaling 2017-12-23 14:18:14 -08:00
Chris Robinson 02c0620141 Add missing integer queries 2017-12-21 11:46:01 -08:00
Chris Robinson d7895db166 Fix the lfo_offset for a 0-rate flanger 2017-12-19 19:15:34 -08:00
Chris Robinson 0f84e32520 Use MixSamples for the echo output 2017-12-19 15:13:11 -08:00
Chris Robinson 1a911be617 Update the chorus and flanger state struct less often 2017-12-19 15:12:06 -08:00
Chris Robinson a0565dc9bb Make the echo effect only apply feedback to repeated samples 2017-12-19 14:11:37 -08:00
Chris Robinson 52569ef562 Fade gains in the chorus and flanger output 2017-12-19 13:52:05 -08:00
Chris Robinson 661bd054aa Use a single delay line for chorus feedback on a fixed tap
The outputs themselves use a variale-delay tap, but using a separate fixed-
delay tap on the feedback helps improve the perceived "wobble" with sustained
notes. This also applies to the flanger effect.
2017-12-18 13:41:12 -08:00
Chris Robinson eee4aca40b Apply chorus and flanger feedback on the tapped re-feed 2017-12-17 22:14:20 -08:00
Chris Robinson 04cf832fe6 Use the selected mixer for chorus and flanger output 2017-12-17 22:10:58 -08:00
Chris Robinson 2346426b6e Make MixSamples non-static global 2017-12-17 21:48:07 -08:00
Chris Robinson 8253014fe9 Fix some types to make MSVC happy 2017-12-17 15:56:30 -08:00
Chris Robinson 57e516720e Avoid a potential calloc of 0 2017-12-17 14:30:51 -08:00
Chris Robinson d229afb83d Build common code once 2017-12-16 15:53:24 -08:00
Chris Robinson 3cd1f30577 Use the right path for android's cmake toolchain 2017-12-16 15:15:11 -08:00
Chris Robinson 94347d4e64 Update travis for android-ndk-r15, required for its newer cmake 2017-12-16 15:10:20 -08:00
Chris Robinson 6fe6c370c2 Include the fpu=neon switch when testing for arm_neon.h 2017-12-16 15:01:05 -08:00
Chris Robinson 42acafcbc3 Don't cache the Android NDK in Travis 2017-12-16 14:05:13 -08:00
Chris Robinson ebd42ab619 Mix multiple buffers in each buffer list item
Basically now this just relies on being able to specify composited buffers.
2017-12-16 11:34:52 -08:00
Chris Robinson b10780f119 Pre-clear the source temp buffer and accumulate into it 2017-12-16 09:41:27 -08:00
Chris Robinson d657c51be8 Rename SrcDataSize to be less confusing 2017-12-16 08:58:46 -08:00
Chris Robinson 30007263e5 Allow storing multiple buffers in a ALbufferlistitem
This will be to allow buffer layering, multiple buffers of the same format and
sample rate that are mixed together prior to resampling, filtering, and
panning. This will allow composing sounds from individual components that can
be swapped around on different invocations (e.g. layer SoundA and SoundB on one
instance and SoundA and SoundC on a different instance for a slightly different
sound, then just SoundA for a third instance, and so on). The longest buffer
within the list item determines the length of the list item.

More work needs to be done to fully support it, namely the ability to specity
multiple buffers to layer for static and streaming sources. Also the behavior
of loop points for layered static sources should be worked out. Should also
consider allowing each layer to have a sample offset.
2017-12-15 22:59:51 -08:00
Chris Robinson ff3d31e17f Update flanger with the same changes as chorus 2017-12-15 17:35:46 -08:00
Chris Robinson d281b25723 Use a separate LFO offset in the chorus effect
Given that the LFO range is not a power-of-two, it won't correctly wrap on
overflow.
2017-12-15 17:26:03 -08:00
Chris Robinson 2a3b5ab9e9 Use linear interpolation for the chorus delay output 2017-12-15 16:50:06 -08:00
Chris Robinson d9f57c099b Use the correct functions set to the compiler switches 2017-12-15 12:25:50 -08:00
Chris Robinson 32f72c7471 Add queries to get the source offset with the device clock 2017-12-03 14:45:19 -08:00
Chris Robinson 5993ef0baa It's getFactory that may be NULL, not its return value... 2017-11-26 09:59:55 -08:00
Chris Robinson d96be76875 Don't probe a NULL backend factory 2017-11-26 09:53:26 -08:00
Chris Robinson 0e2e9e9a29 Add a simple non-streaming play example 2017-11-07 23:12:12 -08:00
Chris Robinson 7c88e4a16b Properly initialize with the default distance model 2017-10-29 18:25:04 -07:00
Chris Robinson eac0539ea0 Enable NFC filters for HRTF
Only applies to the Ambisonic mix (basic HRTF rendering, or B-Format buffers).
2017-10-23 13:30:01 -07:00
Chris Robinson b82d2cf055 Store the HRTF distance in the Hrtf handle 2017-10-23 13:26:35 -07:00
Chris Robinson 7d4028b2df Update default HRTFs for 24-bit samples
This is still using the (mono) KEMAR set, although perhaps the IRCAM 1005 set
could be made the default (stereo and smaller).
2017-10-22 15:45:30 -07:00
Chris Robinson 0349bcc500 Update mhr format for 24-bit, multi-field, stereo measurements
Currently only single field HRTFs are supported, but the format now allows up
to 16.
2017-10-22 15:36:42 -07:00
Chris Robinson 2f5b86dd38 Add an "un-exposed" method to get the library version
This reports the same ALSOFT version as alGetString(AL_VERSION), but doesn't
require a current context (which requires a ALCdevice) to call. Do *NOT* use
this version to determine feature support, use the standard interfaces. If you
think you need to use this, you probably don't, and shouldn't.
2017-10-16 05:47:12 -07:00
Chris Robinson 5ec11a017c Add casts for assigning the SSE bsinc filter pointers 2017-10-07 15:28:35 -07:00
Chris Robinson b3f7df6f5b Use a typedef to declare extern atomic variables
Some systems use anonymous structs for atomic storage, and extern declarations
need to have the same type as their non-extern definition.
2017-10-07 14:58:35 -07:00
Chris Robinson d57eca57a9 Use _wfopen_s to silence MSVC security warnings 2017-10-07 14:48:07 -07:00
Chris Robinson 71ce90d083 Don't hide the log2 macro behind an Android-only macro 2017-10-07 14:39:41 -07:00
Chris Robinson 296abf03de Avoid a separate function to query ambisonic mode support
Now FuMa and ACN channel orders are required, as are FuMa, SN3D, and N3D
normalization schemes. An integer query (alcGetIntegerv) is added for the
maximum ambisonic order.
2017-09-27 11:58:36 -07:00
Chris Robinson 1ab8902621 Re-update effect slots when context properties change
Also keep all free property update structs together in the context instead of
per-object.
2017-09-27 11:13:18 -07:00
Chris Robinson fd70b0bca6 Don't update context and listener props unnecessarily 2017-09-27 09:36:34 -07:00
Chris Robinson 101d284a18 Update the context state properties separately
The context state properties are less likely to change compared to the listener
state, and future changes may prefer more infrequent updates to the context
state.

Note that this puts the MetersPerUnit in as a context state, even though it's
handled through the listener functions. Considering the infrequency that it's
updated at (generally set just once for the context's lifetime), it makes more
sense to put it there than with the more frequently updated listener
properties. The aforementioned future changes would also prefer MetersPerUnit
to not be updated unnecessarily.
2017-09-27 08:55:42 -07:00
Chris Robinson 2f66139053 Update version for 1.18.2 release
Note the real release is in the v1.18 branch! This is just for numbering
consistency.
2017-09-24 07:06:50 -07:00
Chris Robinson 8e64adb2d3 Update ChangeLog with JACK fix 2017-09-23 15:11:07 -07:00
Chris Robinson c5a917b401 Restore the original JACK message callback when possible 2017-09-23 03:56:45 -07:00
Chris Robinson 27ab921e5b Update ChangeLog 2017-09-22 05:52:27 -07:00
Chris Robinson 369f52a0d7 Add an option to ignore the app's speed of sound for reverb decay 2017-09-22 05:42:04 -07:00
kcat 9007b77355 Merge pull request #149 from dscharrer/master
Fix build on Gentoo FreeBSD with freebsd-lib 9.1
2017-09-21 10:28:04 -07:00
Chris Robinson fc9cb2fbd8 Use the app-specified speed of sound for reverb decay
Specifically, the initial reverb decay as determined by the source distance,
and the reverb decayhf limit from air absorption.
2017-09-21 10:20:59 -07:00
Daniel Scharrer 46b9efc5a2 Fix build on Gentoo FreeBSD with freebsd-lib 9.1 2017-09-21 17:37:10 +02:00
Chris Robinson 90cedbea49 Pass the context to the auxiliary effect update method 2017-09-21 05:42:35 -07:00
Chris Robinson 0b243f1aaf Update ChangeLog 2017-09-19 10:47:22 -07:00
Chris Robinson bc386af5c5 Manually save and restore the FPU rounding mode on Windows
Apparently there is a bug with at least MinGW-W64 where fegetenv and fesetenv
do not properly save and restore the FPU rounding mode, resulting in the
rounding mode remaining as round-to-zero after certain function calls. I do not
know if this also affects MSVC, but better safe than sorry for now.
2017-09-19 03:42:00 -07:00
Chris Robinson 4ca8b4080a Always link to ossaudio when found 2017-09-15 22:40:51 -07:00
Chris Robinson c7273ada8e Handle libossaudio as an optional OSS library 2017-09-15 22:22:45 -07:00
Chris Robinson 724d6267c8 Add a check for pthread_setname_np with three parameters
As found in NetBSD.
2017-09-15 22:09:37 -07:00
Chris Robinson 653edd4b02 Don't hide -msse and -mfpu=neon checks behind a not-msvc check
Apparently Clang gets reported as being MSVC on Windows, but still needs the
GCC switches to enable SSE code generation.
2017-08-30 19:14:59 -07:00
Chris Robinson 0b0ae75ccf I guess -1 isn't allowed for the output 2017-08-30 18:04:04 -07:00
Chris Robinson 226efffd21 Free the args returned by CommandLineToArgvW 2017-08-30 17:08:38 -07:00
Chris Robinson 88d76bf069 Depend on native-tools sources using IMPLICIT_DEPENDS 2017-08-30 16:38:07 -07:00
Chris Robinson 67f183f206 Avoid using wmain on Windows 2017-08-30 16:33:44 -07:00
Chris Robinson 0408f9b7df Pass the current cmake generator to the native-tools build 2017-08-30 14:47:13 -07:00
Chris Robinson e3d99412a2 Include limits.h where INT_MAX is used 2017-08-30 12:01:49 -07:00
Chris Robinson cd15b1775e Avoid some extraneous load calls
This likely doesn't change anything given a working optimizer, but it cleans up
the code some.
2017-08-30 11:30:19 -07:00
Chris Robinson 2916efee21 Automatically generate the bsinc table when building
This makes bsincgen a native tool like bin2h, so it can run automatically when
compiling.
2017-08-28 10:31:23 -07:00
Chris Robinson 6c367cad6e Ensure some macros have the correct size 2017-08-28 05:56:57 -07:00
Chris Robinson fde02abc35 Rename resampler labels 2017-08-27 10:47:04 -07:00
Chris Robinson fdce192aab Add bsinc24 to alsoft-config 2017-08-27 10:38:33 -07:00
Chris Robinson a4d357de06 Add a higher quality bsinc resampler using 24 sample points
This improves the transition width, allowing more of the higher frequencies
remain audible. It would be preferrable to have an upper limit of 32 points
instead of 48, to reduce the overall table size and the CPU cost for down-
sampling.
2017-08-27 10:16:36 -07:00
Chris Robinson 773d4664ff Properly open the output file for writing 2017-08-27 06:40:39 -07:00
Chris Robinson 72e3398baf Avoid including AL headers in makehrtf 2017-08-27 06:23:31 -07:00
Chris Robinson f1bbf2e48a Use a common header for Unicode-awareness on Windows 2017-08-27 06:01:31 -07:00
Chris Robinson bfcde9ae8a Allow specifying the output filename with bsincgen 2017-08-26 04:43:16 -07:00
Chris Robinson b1ff2a05af Always declare a native-tools build target 2017-08-26 02:21:50 -07:00
Chris Robinson 561e95528f Rename the bsinc resampler to bsinc12 2017-08-25 05:52:19 -07:00
Chris Robinson 9ea32713b5 Constify some pointers 2017-08-23 23:01:11 -07:00
Chris Robinson 3d76e1c514 Parameterize the filter order and rejection in bsincgen 2017-08-23 03:32:47 -07:00
Chris Robinson 61097d467c Parameterize the bsinc table name 2017-08-22 00:52:17 -07:00
Chris Robinson 46f18ba114 Install the itu5.1-nocenter.ambdec preset 2017-08-21 06:03:49 -07:00
Chris Robinson ef7ce82828 Properly postfix the filter order number 2017-08-21 04:54:49 -07:00
Chris Robinson 921a820867 Meters per unit can't be 0 2017-08-21 00:30:14 -07:00
Chris Robinson e7c4681e9a 0 meters per unit is invalid 2017-08-21 00:27:52 -07:00
Chris Robinson 877ecda14d Properly check if a pointer is different when cleaning it up 2017-08-20 21:23:25 -07:00
Chris Robinson 079e4b1edb Fix -l switch 2017-08-20 18:39:26 -07:00
Chris Robinson 65bcbe0dc8 Clarify argument errors in makehrtf 2017-08-20 18:38:22 -07:00
Chris Robinson bbabc9705e Ensure the arglist is properly terminated 2017-08-20 18:16:52 -07:00
Chris Robinson 520938da57 Print the input and output filenames in makehrtf 2017-08-20 18:00:52 -07:00
Chris Robinson 97d09b4cee Remove the -m command from makehrtf
It only ever outputs mhr files, so there's no need to have a command for it. If
another output format is ever made, it can be a normal option flag.
2017-08-20 16:54:08 -07:00
Chris Robinson 0a147693e8 Properly add getopt.c to makehrtf 2017-08-20 04:46:45 -07:00
Chris Robinson 55643d6370 Use getopt to handle options in makehrtf 2017-08-20 04:30:53 -07:00
Chris Robinson 051828344e Improve unicode handling for makehrtf
Command line parameters and filenames are now unicode-aware (the .def files
should be UTF-8 encoded, if they contain any non-ASCII-7 characters). Unicode
characters might not display correctly in the console, but it should process
them correctly.
2017-08-20 01:50:27 -07:00
Chris Robinson 3e56e7f562 Properly clear the extra ChannelsPerOrder entries 2017-08-19 23:52:24 -07:00
Chris Robinson e8e1a05f38 Add a function to multiply a complex with a scalar 2017-08-18 20:58:58 -07:00
Chris Robinson 5f50d085ad Pass the filter entry to apply to resample_fir4 2017-08-18 19:20:30 -07:00
Chris Robinson f75020da5a Show progress when processing HRTFs 2017-08-18 19:00:42 -07:00
Chris Robinson 75bf45376c Use a proper complex number types in makehrtf 2017-08-18 04:32:55 -07:00
Chris Robinson d2e485cc6d Simplify bsincgen's Kaiser function 2017-08-18 03:09:36 -07:00
Chris Robinson fdd5070c3b "Unfix" the filter length calculation
Partially reverts 3f3a3ac4f1. The l*2 + 1 is
correct when you want an odd number of sample points, which avoids an
unnecessary phase offset in the fitler. However, the rounding is still needed
to calculating the left offset (l), or else the transition width can increase
with an odd-numbered order.
2017-08-18 02:48:32 -07:00
Chris Robinson 5048956ff0 Keep bsinc filter quality more consistent between scales
This generates the filters using the proper size and scale. The 'a' divisor
should represent the +/- sample range (and thus be a whole number), with the
number of sample points being double that. Increasing the filter size to a
multiple of 4 (for SIMD) can be done by padding in 0s afterward.
2017-08-17 23:21:41 -07:00
Chris Robinson 080c076643 Workaround Android not having log2 2017-08-17 15:51:42 -07:00
Chris Robinson 3f3a3ac4f1 Properly calculate the filter size 2017-08-17 05:53:16 -07:00
Chris Robinson 9fd3e5f529 Correct the bsinc filter order
Despite the claim that it was an 11th order filter, the transition width was
generated by specifying 12th order. A 12th order filter would need 14 sample
points rather than the 12 it had.
2017-08-17 05:51:18 -07:00
Chris Robinson e0408d8edf Make the sinc4 table static 2017-08-16 18:19:04 -07:00
Chris Robinson 5008024e73 Store the sinc4 table in the filter state
Also rename the resampler functions to remove the unnecessary '32' token.
2017-08-16 18:09:53 -07:00
Chris Robinson f9c09cc845 Simplify bsinc filter storage in the filter state
Rather than storing individual pointers to filter, scale delta, phase delta,
and scale  phase delta entries, per phase index, the new table layout makes it
trivial to access the per-phase filter and delta entries given the base offset
and coefficient count.
2017-08-16 02:45:25 -07:00
Chris Robinson 520dd5c779 Make the bsinc table layout more efficient
The old layout separated filters, scale deltas, phase deltas, and scale phase
deltas into separate segments that each contained a numbers of scale and phase
entries, Since processing a sample needed a filter and one of each delta entry
relating to a particular scale and phase, the memory needed would be spread
across the whole table. And since subsequent samples would use a different
phase, it would jump around the table a whole lot as well.

The new layout packs the data in a way more consistent with its use. The
filters, scale deltas, phase deltas, and scale phase deltas are interleaved,
such that for a particular scale and phase, the filter and delta entries used
are contiguous. And the phase entries for a particular scale are kept together,
so the ~500 to ~1000 samples processed per source update stay within the same
3KB to 6KB area of the 70+KB table, which is much more cache friendly.
2017-08-16 02:05:10 -07:00
Chris Robinson 4dd53ab942 Keep bsinc info together in a struct 2017-08-15 04:15:50 -07:00
Chris Robinson 0604b00360 Check the source type once when mixing 2017-08-14 22:58:24 -07:00
Chris Robinson a931314d3f Add restrict to a few more parameters 2017-08-10 00:14:55 -07:00
Chris Robinson 2987c87645 Check the right size for the in-progress mhr update 2017-08-09 20:42:22 -07:00
Chris Robinson 649bf575e2 Declare that a couple arrays are aligned 2017-08-09 14:57:01 -07:00
Chris Robinson ad3c4b81e2 Add experimental support for 24-bit, dual-ear HRTFs
Currently makehrtf only handles 24-bit output, not dual-ear, and only when
given the --experimental switch. Files produced this way will not be guaranteed
future compatibility. When the mhr format is also updated with multi-distance
measurements, the experimental switch can go away.
2017-08-08 20:30:26 -07:00
Chris Robinson 530002e168 Avoid re-selecting the direct HRTF mix function 2017-08-07 01:38:26 -07:00
Chris Robinson 6eadccc99d Replace makehrtf's dither
This uses a custom RNG instead of relying on the system-dependent rand(). It
also removes the high-pass/noise-shaping, to flatten the noise floor.
2017-08-01 23:43:25 -07:00
Chris Robinson 8a735d0ba9 Add a front-stablizer config option for surround sound modes
This improves a stereo (front-left + front-right) sound "image" by generating a
front-center channel signal. Done correctly, it helps reduce the comb effects
and phase errors associated with using only two speakers to simulate center
sounds.

Note that it shouldn't be used if the front-center channel is already included
in the positional audio mix (the dialog effect is okay). In general, it may
actually be better to exclude the front-center channel from the positional
audio mix and use this to generate front-center output.
2017-07-31 23:49:48 -07:00
Chris Robinson 88c0d22e7c Don't bother returning the IR length for B-Format decoding 2017-07-31 01:20:42 -07:00
Chris Robinson e5431bbef7 Print an error if the input channel isn't in the device
Rather than the other way around, if a device channel isn't in the channel map.
2017-07-31 01:11:36 -07:00
Chris Robinson de51ba088e Update default 5.1 and 6.1 coefficients to exclude front-center
Not all speaker kits have a front-center speaker capable of outputing full-
range content. It's best to err on the side of caution and not include front-
center for normal positional sound by default, leaving it instead for the
dedicated dialog effect.
2017-07-30 23:39:06 -07:00
179 changed files with 1575 additions and 80346 deletions
+7 -5
View File
@@ -1,7 +1,9 @@
build
build*/
winbuild
win64build
include/SLES
include/sndio.h
include/sys
openal-soft.kdev4
## kdevelop
*.kdev4
## qt-creator
CMakeLists.txt.user*
-70
View File
@@ -1,70 +0,0 @@
language: c
matrix:
include:
- os: linux
dist: trusty
- os: linux
dist: trusty
env:
- BUILD_ANDROID=true
- os: osx
sudo: required
cache:
directories:
- $HOME/android-ndk-r14
install:
- >
if [[ "${TRAVIS_OS_NAME}" == "linux" && -z "${BUILD_ANDROID}" ]]; then
# Install pulseaudio, portaudio, ALSA, JACK dependencies for
# corresponding backends.
# Install Qt5 dependency for alsoft-config.
sudo apt-get install -qq \
libpulse-dev \
portaudio19-dev \
libasound2-dev \
libjack-dev \
qtbase5-dev
fi
- >
if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then
if [[ ! -d ~/android-ndk-r14 || -z "$(ls -A ~/android-ndk-r14)" ]]; then
curl -o ~/android-ndk.zip https://dl.google.com/android/repository/android-ndk-r14-linux-x86_64.zip
unzip -q ~/android-ndk.zip -d ~ \
'android-ndk-r14/build/cmake/*' \
'android-ndk-r14/platforms/android-9/arch-arm/*' \
'android-ndk-r14/source.properties' \
'android-ndk-r14/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/*' \
'android-ndk-r14/sysroot/*' \
'android-ndk-r14/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/*' \
'android-ndk-r14/toolchains/llvm/prebuilt/linux-x86_64/*'
sed -i -e 's/VERSION 3.6.0/VERSION 3.2/' ~/android-ndk-r14/build/cmake/android.toolchain.cmake
fi
fi
script:
- >
if [[ "${TRAVIS_OS_NAME}" == "linux" && -z "${BUILD_ANDROID}" ]]; then
cmake \
-DALSOFT_REQUIRE_ALSA=ON \
-DALSOFT_REQUIRE_OSS=ON \
-DALSOFT_REQUIRE_PORTAUDIO=ON \
-DALSOFT_REQUIRE_PULSEAUDIO=ON \
-DALSOFT_REQUIRE_JACK=ON \
-DALSOFT_EMBED_HRTF_DATA=YES \
.
fi
- >
if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then
cmake \
-DCMAKE_TOOLCHAIN_FILE=~/android-ndk-r14/build/cmake/android.toolchain.cmake \
-DALSOFT_REQUIRE_OPENSL=ON \
-DALSOFT_EMBED_HRTF_DATA=YES \
.
fi
- >
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
cmake \
-DALSOFT_REQUIRE_COREAUDIO=ON \
-DALSOFT_EMBED_HRTF_DATA=YES \
.
fi
- make -j2
-4649
View File
File diff suppressed because it is too large Load Diff
-1830
View File
File diff suppressed because it is too large Load Diff
-652
View File
@@ -1,652 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#ifdef _WIN32
#ifdef __MINGW32__
#define _WIN32_IE 0x501
#else
#define _WIN32_IE 0x400
#endif
#endif
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#ifdef _WIN32_IE
#include <windows.h>
#include <shlobj.h>
#endif
#include "alMain.h"
#include "compat.h"
#include "bool.h"
typedef struct ConfigEntry {
char *key;
char *value;
} ConfigEntry;
typedef struct ConfigBlock {
ConfigEntry *entries;
unsigned int entryCount;
} ConfigBlock;
static ConfigBlock cfgBlock;
static char *lstrip(char *line)
{
while(isspace(line[0]))
line++;
return line;
}
static char *rstrip(char *line)
{
size_t len = strlen(line);
while(len > 0 && isspace(line[len-1]))
len--;
line[len] = 0;
return line;
}
static int readline(FILE *f, char **output, size_t *maxlen)
{
size_t len = 0;
int c;
while((c=fgetc(f)) != EOF && (c == '\r' || c == '\n'))
;
if(c == EOF)
return 0;
do {
if(len+1 >= *maxlen)
{
void *temp = NULL;
size_t newmax;
newmax = (*maxlen ? (*maxlen)<<1 : 32);
if(newmax > *maxlen)
temp = realloc(*output, newmax);
if(!temp)
{
ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, *maxlen);
return 0;
}
*output = temp;
*maxlen = newmax;
}
(*output)[len++] = c;
(*output)[len] = '\0';
} while((c=fgetc(f)) != EOF && c != '\r' && c != '\n');
return 1;
}
static char *expdup(const char *str)
{
char *output = NULL;
size_t maxlen = 0;
size_t len = 0;
while(*str != '\0')
{
const char *addstr;
size_t addstrlen;
size_t i;
if(str[0] != '$')
{
const char *next = strchr(str, '$');
addstr = str;
addstrlen = next ? (size_t)(next-str) : strlen(str);
str += addstrlen;
}
else
{
str++;
if(*str == '$')
{
const char *next = strchr(str+1, '$');
addstr = str;
addstrlen = next ? (size_t)(next-str) : strlen(str);
str += addstrlen;
}
else
{
bool hasbraces;
char envname[1024];
size_t k = 0;
hasbraces = (*str == '{');
if(hasbraces) str++;
while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1)
envname[k++] = *(str++);
envname[k++] = '\0';
if(hasbraces && *str != '}')
continue;
if(hasbraces) str++;
if((addstr=getenv(envname)) == NULL)
continue;
addstrlen = strlen(addstr);
}
}
if(addstrlen == 0)
continue;
if(addstrlen >= maxlen-len)
{
void *temp = NULL;
size_t newmax;
newmax = len+addstrlen+1;
if(newmax > maxlen)
temp = realloc(output, newmax);
if(!temp)
{
ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, maxlen);
return output;
}
output = temp;
maxlen = newmax;
}
for(i = 0;i < addstrlen;i++)
output[len++] = addstr[i];
output[len] = '\0';
}
return output ? output : calloc(1, 1);
}
static void LoadConfigFromFile(FILE *f)
{
char curSection[128] = "";
char *buffer = NULL;
size_t maxlen = 0;
ConfigEntry *ent;
while(readline(f, &buffer, &maxlen))
{
char *line, *comment;
char key[256] = "";
char value[256] = "";
line = rstrip(lstrip(buffer));
if(!line[0]) continue;
if(line[0] == '[')
{
char *section = line+1;
char *endsection;
endsection = strchr(section, ']');
if(!endsection || section == endsection)
{
ERR("config parse error: bad line \"%s\"\n", line);
continue;
}
if(endsection[1] != 0)
{
char *end = endsection+1;
while(isspace(*end))
++end;
if(*end != 0 && *end != '#')
{
ERR("config parse error: bad line \"%s\"\n", line);
continue;
}
}
*endsection = 0;
if(strcasecmp(section, "general") == 0)
curSection[0] = 0;
else
{
size_t len, p = 0;
do {
char *nextp = strchr(section, '%');
if(!nextp)
{
strncpy(curSection+p, section, sizeof(curSection)-1-p);
break;
}
len = nextp - section;
if(len > sizeof(curSection)-1-p)
len = sizeof(curSection)-1-p;
strncpy(curSection+p, section, len);
p += len;
section = nextp;
if(((section[1] >= '0' && section[1] <= '9') ||
(section[1] >= 'a' && section[1] <= 'f') ||
(section[1] >= 'A' && section[1] <= 'F')) &&
((section[2] >= '0' && section[2] <= '9') ||
(section[2] >= 'a' && section[2] <= 'f') ||
(section[2] >= 'A' && section[2] <= 'F')))
{
unsigned char b = 0;
if(section[1] >= '0' && section[1] <= '9')
b = (section[1]-'0') << 4;
else if(section[1] >= 'a' && section[1] <= 'f')
b = (section[1]-'a'+0xa) << 4;
else if(section[1] >= 'A' && section[1] <= 'F')
b = (section[1]-'A'+0x0a) << 4;
if(section[2] >= '0' && section[2] <= '9')
b |= (section[2]-'0');
else if(section[2] >= 'a' && section[2] <= 'f')
b |= (section[2]-'a'+0xa);
else if(section[2] >= 'A' && section[2] <= 'F')
b |= (section[2]-'A'+0x0a);
if(p < sizeof(curSection)-1)
curSection[p++] = b;
section += 3;
}
else if(section[1] == '%')
{
if(p < sizeof(curSection)-1)
curSection[p++] = '%';
section += 2;
}
else
{
if(p < sizeof(curSection)-1)
curSection[p++] = '%';
section += 1;
}
if(p < sizeof(curSection)-1)
curSection[p] = 0;
} while(p < sizeof(curSection)-1 && *section != 0);
curSection[sizeof(curSection)-1] = 0;
}
continue;
}
comment = strchr(line, '#');
if(comment) *(comment++) = 0;
if(!line[0]) continue;
if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 ||
sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 ||
sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2)
{
/* sscanf doesn't handle '' or "" as empty values, so clip it
* manually. */
if(strcmp(value, "\"\"") == 0 || strcmp(value, "''") == 0)
value[0] = 0;
}
else if(sscanf(line, "%255[^=] %255[=]", key, value) == 2)
{
/* Special case for 'key =' */
value[0] = 0;
}
else
{
ERR("config parse error: malformed option line: \"%s\"\n\n", line);
continue;
}
rstrip(key);
if(curSection[0] != 0)
{
size_t len = strlen(curSection);
memmove(&key[len+1], key, sizeof(key)-1-len);
key[len] = '/';
memcpy(key, curSection, len);
}
/* Check if we already have this option set */
ent = cfgBlock.entries;
while((unsigned int)(ent-cfgBlock.entries) < cfgBlock.entryCount)
{
if(strcasecmp(ent->key, key) == 0)
break;
ent++;
}
if((unsigned int)(ent-cfgBlock.entries) >= cfgBlock.entryCount)
{
/* Allocate a new option entry */
ent = realloc(cfgBlock.entries, (cfgBlock.entryCount+1)*sizeof(ConfigEntry));
if(!ent)
{
ERR("config parse error: error reallocating config entries\n");
continue;
}
cfgBlock.entries = ent;
ent = cfgBlock.entries + cfgBlock.entryCount;
cfgBlock.entryCount++;
ent->key = strdup(key);
ent->value = NULL;
}
free(ent->value);
ent->value = expdup(value);
TRACE("found '%s' = '%s'\n", ent->key, ent->value);
}
free(buffer);
}
#ifdef _WIN32
void ReadALConfig(void)
{
WCHAR buffer[PATH_MAX];
const WCHAR *str;
al_string ppath;
FILE *f;
if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
{
al_string filepath = AL_STRING_INIT_STATIC();
alstr_copy_wcstr(&filepath, buffer);
alstr_append_cstr(&filepath, "\\alsoft.ini");
TRACE("Loading config %s...\n", alstr_get_cstr(filepath));
f = al_fopen(alstr_get_cstr(filepath), "rt");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
alstr_reset(&filepath);
}
ppath = GetProcPath();
if(!alstr_empty(ppath))
{
alstr_append_cstr(&ppath, "\\alsoft.ini");
TRACE("Loading config %s...\n", alstr_get_cstr(ppath));
f = al_fopen(alstr_get_cstr(ppath), "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str)
{
al_string filepath = AL_STRING_INIT_STATIC();
alstr_copy_wcstr(&filepath, str);
TRACE("Loading config %s...\n", alstr_get_cstr(filepath));
f = al_fopen(alstr_get_cstr(filepath), "rt");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
alstr_reset(&filepath);
}
alstr_reset(&ppath);
}
#else
void ReadALConfig(void)
{
char buffer[PATH_MAX];
const char *str;
al_string ppath;
FILE *f;
str = "/etc/openal/alsoft.conf";
TRACE("Loading config %s...\n", str);
f = al_fopen(str, "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0)
str = "/etc/xdg";
strncpy(buffer, str, sizeof(buffer)-1);
buffer[sizeof(buffer)-1] = 0;
/* Go through the list in reverse, since "the order of base directories
* denotes their importance; the first directory listed is the most
* important". Ergo, we need to load the settings from the later dirs
* first so that the settings in the earlier dirs override them.
*/
while(1)
{
char *next = strrchr(buffer, ':');
if(next) *(next++) = 0;
else next = buffer;
if(next[0] != '/')
WARN("Ignoring XDG config dir: %s\n", next);
else
{
size_t len = strlen(next);
strncpy(next+len, "/alsoft.conf", buffer+sizeof(buffer)-next-len);
buffer[sizeof(buffer)-1] = 0;
TRACE("Loading config %s...\n", next);
f = al_fopen(next, "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
if(next == buffer)
break;
}
if((str=getenv("HOME")) != NULL && *str)
{
snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", str);
TRACE("Loading config %s...\n", buffer);
f = al_fopen(buffer, "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
if((str=getenv("XDG_CONFIG_HOME")) != NULL && str[0] != 0)
snprintf(buffer, sizeof(buffer), "%s/%s", str, "alsoft.conf");
else
{
buffer[0] = 0;
if((str=getenv("HOME")) != NULL && str[0] != 0)
snprintf(buffer, sizeof(buffer), "%s/.config/%s", str, "alsoft.conf");
}
if(buffer[0] != 0)
{
TRACE("Loading config %s...\n", buffer);
f = al_fopen(buffer, "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
ppath = GetProcPath();
if(!alstr_empty(ppath))
{
alstr_append_cstr(&ppath, "/alsoft.conf");
TRACE("Loading config %s...\n", alstr_get_cstr(ppath));
f = al_fopen(alstr_get_cstr(ppath), "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
if((str=getenv("ALSOFT_CONF")) != NULL && *str)
{
TRACE("Loading config %s...\n", str);
f = al_fopen(str, "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
alstr_reset(&ppath);
}
#endif
void FreeALConfig(void)
{
unsigned int i;
for(i = 0;i < cfgBlock.entryCount;i++)
{
free(cfgBlock.entries[i].key);
free(cfgBlock.entries[i].value);
}
free(cfgBlock.entries);
}
const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def)
{
unsigned int i;
char key[256];
if(!keyName)
return def;
if(blockName && strcasecmp(blockName, "general") != 0)
{
if(devName)
snprintf(key, sizeof(key), "%s/%s/%s", blockName, devName, keyName);
else
snprintf(key, sizeof(key), "%s/%s", blockName, keyName);
}
else
{
if(devName)
snprintf(key, sizeof(key), "%s/%s", devName, keyName);
else
{
strncpy(key, keyName, sizeof(key)-1);
key[sizeof(key)-1] = 0;
}
}
for(i = 0;i < cfgBlock.entryCount;i++)
{
if(strcmp(cfgBlock.entries[i].key, key) == 0)
{
TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value);
if(cfgBlock.entries[i].value[0])
return cfgBlock.entries[i].value;
return def;
}
}
if(!devName)
{
TRACE("Key %s not found\n", key);
return def;
}
return GetConfigValue(NULL, blockName, keyName, def);
}
int ConfigValueExists(const char *devName, const char *blockName, const char *keyName)
{
const char *val = GetConfigValue(devName, blockName, keyName, "");
return !!val[0];
}
int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret)
{
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = val;
return 1;
}
int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret)
{
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = strtol(val, NULL, 0);
return 1;
}
int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret)
{
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = strtoul(val, NULL, 0);
return 1;
}
int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret)
{
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
#ifdef HAVE_STRTOF
*ret = strtof(val, NULL);
#else
*ret = (float)strtod(val, NULL);
#endif
return 1;
}
int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret)
{
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||
strcasecmp(val, "on") == 0 || atoi(val) != 0);
return 1;
}
int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def)
{
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return !!def;
return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||
strcasecmp(val, "on") == 0 || atoi(val) != 0);
}
-317
View File
@@ -1,317 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include "alMain.h"
#include "threads.h"
#include "almalloc.h"
#include "compat.h"
/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended
* to include an element size. Consequently, parameters and return values for a
* size or count is in 'elements', not bytes. Additionally, it only supports
* single-consumer/single-provider operation. */
struct ll_ringbuffer {
ATOMIC(size_t) write_ptr;
ATOMIC(size_t) read_ptr;
size_t size;
size_t size_mask;
size_t elem_size;
int mlocked;
alignas(16) char buf[];
};
/* Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes.
* The number of elements is rounded up to the next power of two. */
ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz)
{
ll_ringbuffer_t *rb;
ALuint power_of_two;
power_of_two = NextPowerOf2(sz);
if(power_of_two < sz)
return NULL;
rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz);
if(!rb) return NULL;
ATOMIC_INIT(&rb->write_ptr, 0);
ATOMIC_INIT(&rb->read_ptr, 0);
rb->size = power_of_two;
rb->size_mask = rb->size - 1;
rb->elem_size = elem_sz;
rb->mlocked = 0;
return rb;
}
/* Free all data associated with the ringbuffer `rb'. */
void ll_ringbuffer_free(ll_ringbuffer_t *rb)
{
if(rb)
{
#ifdef USE_MLOCK
if(rb->mlocked)
munlock(rb, sizeof(*rb) + rb->size*rb->elem_size);
#endif /* USE_MLOCK */
al_free(rb);
}
}
/* Lock the data block of `rb' using the system call 'mlock'. */
int ll_ringbuffer_mlock(ll_ringbuffer_t *rb)
{
#ifdef USE_MLOCK
if(!rb->mlocked && mlock(rb, sizeof(*rb) + rb->size*rb->elem_size))
return -1;
#endif /* USE_MLOCK */
rb->mlocked = 1;
return 0;
}
/* Reset the read and write pointers to zero. This is not thread safe. */
void ll_ringbuffer_reset(ll_ringbuffer_t *rb)
{
ATOMIC_STORE(&rb->write_ptr, 0, almemory_order_release);
ATOMIC_STORE(&rb->read_ptr, 0, almemory_order_release);
memset(rb->buf, 0, rb->size*rb->elem_size);
}
/* Return the number of elements available for reading. This is the number of
* elements in front of the read pointer and behind the write pointer. */
size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb)
{
size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire);
size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire);
return (w-r) & rb->size_mask;
}
/* Return the number of elements available for writing. This is the number of
* elements in front of the write pointer and behind the read pointer. */
size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb)
{
size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire);
size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire);
return (r-w-1) & rb->size_mask;
}
/* The copying data reader. Copy at most `cnt' elements from `rb' to `dest'.
* Returns the actual number of elements copied. */
size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt)
{
size_t read_ptr;
size_t free_cnt;
size_t cnt2;
size_t to_read;
size_t n1, n2;
free_cnt = ll_ringbuffer_read_space(rb);
if(free_cnt == 0) return 0;
to_read = (cnt > free_cnt) ? free_cnt : cnt;
read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask;
cnt2 = read_ptr + to_read;
if(cnt2 > rb->size)
{
n1 = rb->size - read_ptr;
n2 = cnt2 & rb->size_mask;
}
else
{
n1 = to_read;
n2 = 0;
}
memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size);
read_ptr += n1;
if(n2)
{
memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size],
n2*rb->elem_size);
read_ptr += n2;
}
ATOMIC_STORE(&rb->read_ptr, read_ptr, almemory_order_release);
return to_read;
}
/* The copying data reader w/o read pointer advance. Copy at most `cnt'
* elements from `rb' to `dest'. Returns the actual number of elements copied.
*/
size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt)
{
size_t free_cnt;
size_t cnt2;
size_t to_read;
size_t n1, n2;
size_t read_ptr;
free_cnt = ll_ringbuffer_read_space(rb);
if(free_cnt == 0) return 0;
to_read = (cnt > free_cnt) ? free_cnt : cnt;
read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask;
cnt2 = read_ptr + to_read;
if(cnt2 > rb->size)
{
n1 = rb->size - read_ptr;
n2 = cnt2 & rb->size_mask;
}
else
{
n1 = to_read;
n2 = 0;
}
memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size);
if(n2)
{
read_ptr += n1;
memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size],
n2*rb->elem_size);
}
return to_read;
}
/* The copying data writer. Copy at most `cnt' elements to `rb' from `src'.
* Returns the actual number of elements copied. */
size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt)
{
size_t write_ptr;
size_t free_cnt;
size_t cnt2;
size_t to_write;
size_t n1, n2;
free_cnt = ll_ringbuffer_write_space(rb);
if(free_cnt == 0) return 0;
to_write = (cnt > free_cnt) ? free_cnt : cnt;
write_ptr = ATOMIC_LOAD(&rb->write_ptr, almemory_order_relaxed) & rb->size_mask;
cnt2 = write_ptr + to_write;
if(cnt2 > rb->size)
{
n1 = rb->size - write_ptr;
n2 = cnt2 & rb->size_mask;
}
else
{
n1 = to_write;
n2 = 0;
}
memcpy(&rb->buf[write_ptr*rb->elem_size], src, n1*rb->elem_size);
write_ptr += n1;
if(n2)
{
memcpy(&rb->buf[(write_ptr&rb->size_mask)*rb->elem_size], src + n1*rb->elem_size,
n2*rb->elem_size);
write_ptr += n2;
}
ATOMIC_STORE(&rb->write_ptr, write_ptr, almemory_order_release);
return to_write;
}
/* Advance the read pointer `cnt' places. */
void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt)
{
ATOMIC_ADD(&rb->read_ptr, cnt, almemory_order_acq_rel);
}
/* Advance the write pointer `cnt' places. */
void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt)
{
ATOMIC_ADD(&rb->write_ptr, cnt, almemory_order_acq_rel);
}
/* The non-copying data reader. `vec' is an array of two places. Set the values
* at `vec' to hold the current readable data at `rb'. If the readable data is
* in one segment the second segment has zero length. */
void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t * vec)
{
size_t free_cnt;
size_t cnt2;
size_t w, r;
w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire);
r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire);
w &= rb->size_mask;
r &= rb->size_mask;
free_cnt = (w-r) & rb->size_mask;
cnt2 = r + free_cnt;
if(cnt2 > rb->size)
{
/* Two part vector: the rest of the buffer after the current write ptr,
* plus some from the start of the buffer. */
vec[0].buf = (char*)&rb->buf[r*rb->elem_size];
vec[0].len = rb->size - r;
vec[1].buf = (char*)rb->buf;
vec[1].len = cnt2 & rb->size_mask;
}
else
{
/* Single part vector: just the rest of the buffer */
vec[0].buf = (char*)&rb->buf[r*rb->elem_size];
vec[0].len = free_cnt;
vec[1].buf = NULL;
vec[1].len = 0;
}
}
/* The non-copying data writer. `vec' is an array of two places. Set the values
* at `vec' to hold the current writeable data at `rb'. If the writeable data
* is in one segment the second segment has zero length. */
void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec)
{
size_t free_cnt;
size_t cnt2;
size_t w, r;
w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire);
r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire);
w &= rb->size_mask;
r &= rb->size_mask;
free_cnt = (r-w-1) & rb->size_mask;
cnt2 = w + free_cnt;
if(cnt2 > rb->size)
{
/* Two part vector: the rest of the buffer after the current write ptr,
* plus some from the start of the buffer. */
vec[0].buf = (char*)&rb->buf[w*rb->elem_size];
vec[0].len = rb->size - w;
vec[1].buf = (char*)rb->buf;
vec[1].len = cnt2 & rb->size_mask;
}
else
{
vec[0].buf = (char*)&rb->buf[w*rb->elem_size];
vec[0].len = free_cnt;
vec[1].buf = NULL;
vec[1].len = 0;
}
}
-49
View File
@@ -1,49 +0,0 @@
#ifndef ALSTRING_H
#define ALSTRING_H
#include <string.h>
#include "vector.h"
typedef char al_string_char_type;
TYPEDEF_VECTOR(al_string_char_type, al_string)
TYPEDEF_VECTOR(al_string, vector_al_string)
inline void alstr_reset(al_string *str)
{ VECTOR_DEINIT(*str); }
#define AL_STRING_INIT(_x) do { (_x) = (al_string)NULL; } while(0)
#define AL_STRING_INIT_STATIC() ((al_string)NULL)
#define AL_STRING_DEINIT(_x) alstr_reset(&(_x))
inline size_t alstr_length(const_al_string str)
{ return VECTOR_SIZE(str); }
inline ALboolean alstr_empty(const_al_string str)
{ return alstr_length(str) == 0; }
inline const al_string_char_type *alstr_get_cstr(const_al_string str)
{ return str ? &VECTOR_FRONT(str) : ""; }
void alstr_clear(al_string *str);
int alstr_cmp(const_al_string str1, const_al_string str2);
int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2);
void alstr_copy(al_string *str, const_al_string from);
void alstr_copy_cstr(al_string *str, const al_string_char_type *from);
void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to);
void alstr_append_char(al_string *str, const al_string_char_type c);
void alstr_append_cstr(al_string *str, const al_string_char_type *from);
void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to);
#ifdef _WIN32
#include <wchar.h>
/* Windows-only methods to deal with WideChar strings. */
void alstr_copy_wcstr(al_string *str, const wchar_t *from);
void alstr_append_wcstr(al_string *str, const wchar_t *from);
void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to);
#endif
#endif /* ALSTRING_H */
-566
View File
@@ -1,566 +0,0 @@
#include "config.h"
#include "ambdec.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "compat.h"
static char *lstrip(char *line)
{
while(isspace(line[0]))
line++;
return line;
}
static char *rstrip(char *line)
{
size_t len = strlen(line);
while(len > 0 && isspace(line[len-1]))
len--;
line[len] = 0;
return line;
}
static int readline(FILE *f, char **output, size_t *maxlen)
{
size_t len = 0;
int c;
while((c=fgetc(f)) != EOF && (c == '\r' || c == '\n'))
;
if(c == EOF)
return 0;
do {
if(len+1 >= *maxlen)
{
void *temp = NULL;
size_t newmax;
newmax = (*maxlen ? (*maxlen)<<1 : 32);
if(newmax > *maxlen)
temp = realloc(*output, newmax);
if(!temp)
{
ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, *maxlen);
return 0;
}
*output = temp;
*maxlen = newmax;
}
(*output)[len++] = c;
(*output)[len] = '\0';
} while((c=fgetc(f)) != EOF && c != '\r' && c != '\n');
return 1;
}
/* Custom strtok_r, since we can't rely on it existing. */
static char *my_strtok_r(char *str, const char *delim, char **saveptr)
{
/* Sanity check and update internal pointer. */
if(!saveptr || !delim) return NULL;
if(str) *saveptr = str;
str = *saveptr;
/* Nothing more to do with this string. */
if(!str) return NULL;
/* Find the first non-delimiter character. */
while(*str != '\0' && strchr(delim, *str) != NULL)
str++;
if(*str == '\0')
{
/* End of string. */
*saveptr = NULL;
return NULL;
}
/* Find the next delimiter character. */
*saveptr = strpbrk(str, delim);
if(*saveptr) *((*saveptr)++) = '\0';
return str;
}
static char *read_int(ALint *num, const char *line, int base)
{
char *end;
*num = strtol(line, &end, base);
if(end && *end != '\0')
end = lstrip(end);
return end;
}
static char *read_uint(ALuint *num, const char *line, int base)
{
char *end;
*num = strtoul(line, &end, base);
if(end && *end != '\0')
end = lstrip(end);
return end;
}
static char *read_float(ALfloat *num, const char *line)
{
char *end;
#ifdef HAVE_STRTOF
*num = strtof(line, &end);
#else
*num = (ALfloat)strtod(line, &end);
#endif
if(end && *end != '\0')
end = lstrip(end);
return end;
}
char *read_clipped_line(FILE *f, char **buffer, size_t *maxlen)
{
while(readline(f, buffer, maxlen))
{
char *line, *comment;
line = lstrip(*buffer);
comment = strchr(line, '#');
if(comment) *(comment++) = 0;
line = rstrip(line);
if(line[0]) return line;
}
return NULL;
}
static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxlen, char **saveptr)
{
ALsizei cur = 0;
while(cur < conf->NumSpeakers)
{
const char *cmd = my_strtok_r(NULL, " \t", saveptr);
if(!cmd)
{
char *line = read_clipped_line(f, buffer, maxlen);
if(!line)
{
ERR("Unexpected end of file\n");
return 0;
}
cmd = my_strtok_r(line, " \t", saveptr);
}
if(strcmp(cmd, "add_spkr") == 0)
{
const char *name = my_strtok_r(NULL, " \t", saveptr);
const char *dist = my_strtok_r(NULL, " \t", saveptr);
const char *az = my_strtok_r(NULL, " \t", saveptr);
const char *elev = my_strtok_r(NULL, " \t", saveptr);
const char *conn = my_strtok_r(NULL, " \t", saveptr);
if(!name) WARN("Name not specified for speaker %u\n", cur+1);
else alstr_copy_cstr(&conf->Speakers[cur].Name, name);
if(!dist) WARN("Distance not specified for speaker %u\n", cur+1);
else read_float(&conf->Speakers[cur].Distance, dist);
if(!az) WARN("Azimuth not specified for speaker %u\n", cur+1);
else read_float(&conf->Speakers[cur].Azimuth, az);
if(!elev) WARN("Elevation not specified for speaker %u\n", cur+1);
else read_float(&conf->Speakers[cur].Elevation, elev);
if(!conn) TRACE("Connection not specified for speaker %u\n", cur+1);
else alstr_copy_cstr(&conf->Speakers[cur].Connection, conn);
cur++;
}
else
{
ERR("Unexpected speakers command: %s\n", cmd);
return 0;
}
cmd = my_strtok_r(NULL, " \t", saveptr);
if(cmd)
{
ERR("Unexpected junk on line: %s\n", cmd);
return 0;
}
}
return 1;
}
static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, FILE *f, char **buffer, size_t *maxlen, char **saveptr)
{
int gotgains = 0;
ALsizei cur = 0;
while(cur < maxrow)
{
const char *cmd = my_strtok_r(NULL, " \t", saveptr);
if(!cmd)
{
char *line = read_clipped_line(f, buffer, maxlen);
if(!line)
{
ERR("Unexpected end of file\n");
return 0;
}
cmd = my_strtok_r(line, " \t", saveptr);
}
if(strcmp(cmd, "order_gain") == 0)
{
ALuint curgain = 0;
char *line;
while((line=my_strtok_r(NULL, " \t", saveptr)) != NULL)
{
ALfloat value;
line = read_float(&value, line);
if(line && *line != '\0')
{
ERR("Extra junk on gain %u: %s\n", curgain+1, line);
return 0;
}
if(curgain < MAX_AMBI_ORDER+1)
gains[curgain] = value;
curgain++;
}
while(curgain < MAX_AMBI_ORDER+1)
gains[curgain++] = 0.0f;
gotgains = 1;
}
else if(strcmp(cmd, "add_row") == 0)
{
ALuint curidx = 0;
char *line;
while((line=my_strtok_r(NULL, " \t", saveptr)) != NULL)
{
ALfloat value;
line = read_float(&value, line);
if(line && *line != '\0')
{
ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx, line);
return 0;
}
if(curidx < MAX_AMBI_COEFFS)
matrix[cur][curidx] = value;
curidx++;
}
while(curidx < MAX_AMBI_COEFFS)
matrix[cur][curidx++] = 0.0f;
cur++;
}
else
{
ERR("Unexpected speakers command: %s\n", cmd);
return 0;
}
cmd = my_strtok_r(NULL, " \t", saveptr);
if(cmd)
{
ERR("Unexpected junk on line: %s\n", cmd);
return 0;
}
}
if(!gotgains)
{
ERR("Matrix order_gain not specified\n");
return 0;
}
return 1;
}
void ambdec_init(AmbDecConf *conf)
{
ALsizei i;
memset(conf, 0, sizeof(*conf));
AL_STRING_INIT(conf->Description);
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
{
AL_STRING_INIT(conf->Speakers[i].Name);
AL_STRING_INIT(conf->Speakers[i].Connection);
}
}
void ambdec_deinit(AmbDecConf *conf)
{
ALsizei i;
alstr_reset(&conf->Description);
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
{
alstr_reset(&conf->Speakers[i].Name);
alstr_reset(&conf->Speakers[i].Connection);
}
memset(conf, 0, sizeof(*conf));
}
int ambdec_load(AmbDecConf *conf, const char *fname)
{
char *buffer = NULL;
size_t maxlen = 0;
char *line;
FILE *f;
f = al_fopen(fname, "r");
if(!f)
{
ERR("Failed to open: %s\n", fname);
return 0;
}
while((line=read_clipped_line(f, &buffer, &maxlen)) != NULL)
{
char *saveptr;
char *command;
command = my_strtok_r(line, "/ \t", &saveptr);
if(!command)
{
ERR("Malformed line: %s\n", line);
goto fail;
}
if(strcmp(command, "description") == 0)
{
char *value = my_strtok_r(NULL, "", &saveptr);
alstr_copy_cstr(&conf->Description, lstrip(value));
}
else if(strcmp(command, "version") == 0)
{
line = my_strtok_r(NULL, "", &saveptr);
line = read_uint(&conf->Version, line, 10);
if(line && *line != '\0')
{
ERR("Extra junk after version: %s\n", line);
goto fail;
}
if(conf->Version != 3)
{
ERR("Unsupported version: %u\n", conf->Version);
goto fail;
}
}
else if(strcmp(command, "dec") == 0)
{
const char *dec = my_strtok_r(NULL, "/ \t", &saveptr);
if(strcmp(dec, "chan_mask") == 0)
{
line = my_strtok_r(NULL, "", &saveptr);
line = read_uint(&conf->ChanMask, line, 16);
if(line && *line != '\0')
{
ERR("Extra junk after mask: %s\n", line);
goto fail;
}
}
else if(strcmp(dec, "freq_bands") == 0)
{
line = my_strtok_r(NULL, "", &saveptr);
line = read_uint(&conf->FreqBands, line, 10);
if(line && *line != '\0')
{
ERR("Extra junk after freq_bands: %s\n", line);
goto fail;
}
if(conf->FreqBands != 1 && conf->FreqBands != 2)
{
ERR("Invalid freq_bands value: %u\n", conf->FreqBands);
goto fail;
}
}
else if(strcmp(dec, "speakers") == 0)
{
line = my_strtok_r(NULL, "", &saveptr);
line = read_int(&conf->NumSpeakers, line, 10);
if(line && *line != '\0')
{
ERR("Extra junk after speakers: %s\n", line);
goto fail;
}
if(conf->NumSpeakers > MAX_OUTPUT_CHANNELS)
{
ERR("Unsupported speaker count: %u\n", conf->NumSpeakers);
goto fail;
}
}
else if(strcmp(dec, "coeff_scale") == 0)
{
line = my_strtok_r(NULL, " \t", &saveptr);
if(strcmp(line, "n3d") == 0)
conf->CoeffScale = ADS_N3D;
else if(strcmp(line, "sn3d") == 0)
conf->CoeffScale = ADS_SN3D;
else if(strcmp(line, "fuma") == 0)
conf->CoeffScale = ADS_FuMa;
else
{
ERR("Unsupported coeff scale: %s\n", line);
goto fail;
}
}
else
{
ERR("Unexpected /dec option: %s\n", dec);
goto fail;
}
}
else if(strcmp(command, "opt") == 0)
{
const char *opt = my_strtok_r(NULL, "/ \t", &saveptr);
if(strcmp(opt, "xover_freq") == 0)
{
line = my_strtok_r(NULL, "", &saveptr);
line = read_float(&conf->XOverFreq, line);
if(line && *line != '\0')
{
ERR("Extra junk after xover_freq: %s\n", line);
goto fail;
}
}
else if(strcmp(opt, "xover_ratio") == 0)
{
line = my_strtok_r(NULL, "", &saveptr);
line = read_float(&conf->XOverRatio, line);
if(line && *line != '\0')
{
ERR("Extra junk after xover_ratio: %s\n", line);
goto fail;
}
}
else if(strcmp(opt, "input_scale") == 0 || strcmp(opt, "nfeff_comp") == 0 ||
strcmp(opt, "delay_comp") == 0 || strcmp(opt, "level_comp") == 0)
{
/* Unused */
my_strtok_r(NULL, " \t", &saveptr);
}
else
{
ERR("Unexpected /opt option: %s\n", opt);
goto fail;
}
}
else if(strcmp(command, "speakers") == 0)
{
const char *value = my_strtok_r(NULL, "/ \t", &saveptr);
if(strcmp(value, "{") != 0)
{
ERR("Expected { after %s command, got %s\n", command, value);
goto fail;
}
if(!load_ambdec_speakers(conf, f, &buffer, &maxlen, &saveptr))
goto fail;
value = my_strtok_r(NULL, "/ \t", &saveptr);
if(!value)
{
line = read_clipped_line(f, &buffer, &maxlen);
if(!line)
{
ERR("Unexpected end of file\n");
goto fail;
}
value = my_strtok_r(line, "/ \t", &saveptr);
}
if(strcmp(value, "}") != 0)
{
ERR("Expected } after speaker definitions, got %s\n", value);
goto fail;
}
}
else if(strcmp(command, "lfmatrix") == 0 || strcmp(command, "hfmatrix") == 0 ||
strcmp(command, "matrix") == 0)
{
const char *value = my_strtok_r(NULL, "/ \t", &saveptr);
if(strcmp(value, "{") != 0)
{
ERR("Expected { after %s command, got %s\n", command, value);
goto fail;
}
if(conf->FreqBands == 1)
{
if(strcmp(command, "matrix") != 0)
{
ERR("Unexpected \"%s\" type for a single-band decoder\n", command);
goto fail;
}
if(!load_ambdec_matrix(conf->HFOrderGain, conf->HFMatrix, conf->NumSpeakers,
f, &buffer, &maxlen, &saveptr))
goto fail;
}
else
{
if(strcmp(command, "lfmatrix") == 0)
{
if(!load_ambdec_matrix(conf->LFOrderGain, conf->LFMatrix, conf->NumSpeakers,
f, &buffer, &maxlen, &saveptr))
goto fail;
}
else if(strcmp(command, "hfmatrix") == 0)
{
if(!load_ambdec_matrix(conf->HFOrderGain, conf->HFMatrix, conf->NumSpeakers,
f, &buffer, &maxlen, &saveptr))
goto fail;
}
else
{
ERR("Unexpected \"%s\" type for a dual-band decoder\n", command);
goto fail;
}
}
value = my_strtok_r(NULL, "/ \t", &saveptr);
if(!value)
{
line = read_clipped_line(f, &buffer, &maxlen);
if(!line)
{
ERR("Unexpected end of file\n");
goto fail;
}
value = my_strtok_r(line, "/ \t", &saveptr);
}
if(strcmp(value, "}") != 0)
{
ERR("Expected } after matrix definitions, got %s\n", value);
goto fail;
}
}
else if(strcmp(command, "end") == 0)
{
line = my_strtok_r(NULL, "/ \t", &saveptr);
if(line)
{
ERR("Unexpected junk on end: %s\n", line);
goto fail;
}
fclose(f);
free(buffer);
return 1;
}
else
{
ERR("Unexpected command: %s\n", command);
goto fail;
}
line = my_strtok_r(NULL, "/ \t", &saveptr);
if(line)
{
ERR("Unexpected junk on line: %s\n", line);
goto fail;
}
}
ERR("Unexpected end of file\n");
fail:
fclose(f);
free(buffer);
return 0;
}
-46
View File
@@ -1,46 +0,0 @@
#ifndef AMBDEC_H
#define AMBDEC_H
#include "alstring.h"
#include "alMain.h"
/* Helpers to read .ambdec configuration files. */
enum AmbDecScaleType {
ADS_N3D,
ADS_SN3D,
ADS_FuMa,
};
typedef struct AmbDecConf {
al_string Description;
ALuint Version; /* Must be 3 */
ALuint ChanMask;
ALuint FreqBands; /* Must be 1 or 2 */
ALsizei NumSpeakers;
enum AmbDecScaleType CoeffScale;
ALfloat XOverFreq;
ALfloat XOverRatio;
struct {
al_string Name;
ALfloat Distance;
ALfloat Azimuth;
ALfloat Elevation;
al_string Connection;
} Speakers[MAX_OUTPUT_CHANNELS];
/* Unused when FreqBands == 1 */
ALfloat LFOrderGain[MAX_AMBI_ORDER+1];
ALfloat LFMatrix[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
ALfloat HFOrderGain[MAX_AMBI_ORDER+1];
ALfloat HFMatrix[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
} AmbDecConf;
void ambdec_init(AmbDecConf *conf);
void ambdec_deinit(AmbDecConf *conf);
int ambdec_load(AmbDecConf *conf, const char *fname);
#endif /* AMBDEC_H */
-1437
View File
File diff suppressed because it is too large Load Diff
-81
View File
@@ -1,81 +0,0 @@
#include "config.h"
#include <stdlib.h>
#include "alMain.h"
#include "alu.h"
#include "backends/base.h"
extern inline ALuint64 GetDeviceClockTime(ALCdevice *device);
/* Base ALCbackend method implementations. */
void ALCbackend_Construct(ALCbackend *self, ALCdevice *device)
{
int ret = almtx_init(&self->mMutex, almtx_recursive);
assert(ret == althrd_success);
self->mDevice = device;
}
void ALCbackend_Destruct(ALCbackend *self)
{
almtx_destroy(&self->mMutex);
}
ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self))
{
return ALC_FALSE;
}
ALCenum ALCbackend_captureSamples(ALCbackend* UNUSED(self), void* UNUSED(buffer), ALCuint UNUSED(samples))
{
return ALC_INVALID_DEVICE;
}
ALCuint ALCbackend_availableSamples(ALCbackend* UNUSED(self))
{
return 0;
}
ClockLatency ALCbackend_getClockLatency(ALCbackend *self)
{
ALCdevice *device = self->mDevice;
ALuint refcount;
ClockLatency ret;
do {
while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
althrd_yield();
ret.ClockTime = GetDeviceClockTime(device);
ATOMIC_THREAD_FENCE(almemory_order_acquire);
} while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
/* NOTE: The device will generally have about all but one periods filled at
* any given time during playback. Without a more accurate measurement from
* the output, this is an okay approximation.
*/
ret.Latency = device->UpdateSize * DEVICE_CLOCK_RES / device->Frequency *
maxu(device->NumUpdates-1, 1);
return ret;
}
void ALCbackend_lock(ALCbackend *self)
{
int ret = almtx_lock(&self->mMutex);
assert(ret == althrd_success);
}
void ALCbackend_unlock(ALCbackend *self)
{
int ret = almtx_unlock(&self->mMutex);
assert(ret == althrd_success);
}
/* Base ALCbackendFactory method implementations. */
void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self))
{
}
-155
View File
@@ -1,155 +0,0 @@
#ifndef AL_BACKENDS_BASE_H
#define AL_BACKENDS_BASE_H
#include "alMain.h"
#include "threads.h"
typedef struct ClockLatency {
ALint64 ClockTime;
ALint64 Latency;
} ClockLatency;
/* Helper to get the current clock time from the device's ClockBase, and
* SamplesDone converted from the sample rate.
*/
inline ALuint64 GetDeviceClockTime(ALCdevice *device)
{
return device->ClockBase + (device->SamplesDone * DEVICE_CLOCK_RES /
device->Frequency);
}
struct ALCbackendVtable;
typedef struct ALCbackend {
const struct ALCbackendVtable *vtbl;
ALCdevice *mDevice;
almtx_t mMutex;
} ALCbackend;
void ALCbackend_Construct(ALCbackend *self, ALCdevice *device);
void ALCbackend_Destruct(ALCbackend *self);
ALCboolean ALCbackend_reset(ALCbackend *self);
ALCenum ALCbackend_captureSamples(ALCbackend *self, void *buffer, ALCuint samples);
ALCuint ALCbackend_availableSamples(ALCbackend *self);
ClockLatency ALCbackend_getClockLatency(ALCbackend *self);
void ALCbackend_lock(ALCbackend *self);
void ALCbackend_unlock(ALCbackend *self);
struct ALCbackendVtable {
void (*const Destruct)(ALCbackend*);
ALCenum (*const open)(ALCbackend*, const ALCchar*);
void (*const close)(ALCbackend*);
ALCboolean (*const reset)(ALCbackend*);
ALCboolean (*const start)(ALCbackend*);
void (*const stop)(ALCbackend*);
ALCenum (*const captureSamples)(ALCbackend*, void*, ALCuint);
ALCuint (*const availableSamples)(ALCbackend*);
ClockLatency (*const getClockLatency)(ALCbackend*);
void (*const lock)(ALCbackend*);
void (*const unlock)(ALCbackend*);
void (*const Delete)(void*);
};
#define DEFINE_ALCBACKEND_VTABLE(T) \
DECLARE_THUNK(T, ALCbackend, void, Destruct) \
DECLARE_THUNK1(T, ALCbackend, ALCenum, open, const ALCchar*) \
DECLARE_THUNK(T, ALCbackend, void, close) \
DECLARE_THUNK(T, ALCbackend, ALCboolean, reset) \
DECLARE_THUNK(T, ALCbackend, ALCboolean, start) \
DECLARE_THUNK(T, ALCbackend, void, stop) \
DECLARE_THUNK2(T, ALCbackend, ALCenum, captureSamples, void*, ALCuint) \
DECLARE_THUNK(T, ALCbackend, ALCuint, availableSamples) \
DECLARE_THUNK(T, ALCbackend, ClockLatency, getClockLatency) \
DECLARE_THUNK(T, ALCbackend, void, lock) \
DECLARE_THUNK(T, ALCbackend, void, unlock) \
static void T##_ALCbackend_Delete(void *ptr) \
{ T##_Delete(STATIC_UPCAST(T, ALCbackend, (ALCbackend*)ptr)); } \
\
static const struct ALCbackendVtable T##_ALCbackend_vtable = { \
T##_ALCbackend_Destruct, \
\
T##_ALCbackend_open, \
T##_ALCbackend_close, \
T##_ALCbackend_reset, \
T##_ALCbackend_start, \
T##_ALCbackend_stop, \
T##_ALCbackend_captureSamples, \
T##_ALCbackend_availableSamples, \
T##_ALCbackend_getClockLatency, \
T##_ALCbackend_lock, \
T##_ALCbackend_unlock, \
\
T##_ALCbackend_Delete, \
}
typedef enum ALCbackend_Type {
ALCbackend_Playback,
ALCbackend_Capture,
ALCbackend_Loopback
} ALCbackend_Type;
struct ALCbackendFactoryVtable;
typedef struct ALCbackendFactory {
const struct ALCbackendFactoryVtable *vtbl;
} ALCbackendFactory;
void ALCbackendFactory_deinit(ALCbackendFactory *self);
struct ALCbackendFactoryVtable {
ALCboolean (*const init)(ALCbackendFactory *self);
void (*const deinit)(ALCbackendFactory *self);
ALCboolean (*const querySupport)(ALCbackendFactory *self, ALCbackend_Type type);
void (*const probe)(ALCbackendFactory *self, enum DevProbe type);
ALCbackend* (*const createBackend)(ALCbackendFactory *self, ALCdevice *device, ALCbackend_Type type);
};
#define DEFINE_ALCBACKENDFACTORY_VTABLE(T) \
DECLARE_THUNK(T, ALCbackendFactory, ALCboolean, init) \
DECLARE_THUNK(T, ALCbackendFactory, void, deinit) \
DECLARE_THUNK1(T, ALCbackendFactory, ALCboolean, querySupport, ALCbackend_Type) \
DECLARE_THUNK1(T, ALCbackendFactory, void, probe, enum DevProbe) \
DECLARE_THUNK2(T, ALCbackendFactory, ALCbackend*, createBackend, ALCdevice*, ALCbackend_Type) \
\
static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \
T##_ALCbackendFactory_init, \
T##_ALCbackendFactory_deinit, \
T##_ALCbackendFactory_querySupport, \
T##_ALCbackendFactory_probe, \
T##_ALCbackendFactory_createBackend, \
}
ALCbackendFactory *ALCpulseBackendFactory_getFactory(void);
ALCbackendFactory *ALCalsaBackendFactory_getFactory(void);
ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void);
ALCbackendFactory *ALCossBackendFactory_getFactory(void);
ALCbackendFactory *ALCjackBackendFactory_getFactory(void);
ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
ALCbackendFactory *ALCsndioBackendFactory_getFactory(void);
ALCbackendFactory *ALCqsaBackendFactory_getFactory(void);
ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void);
ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void);
ALCbackendFactory *ALCportBackendFactory_getFactory(void);
ALCbackendFactory *ALCopenslBackendFactory_getFactory(void);
ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
ALCbackendFactory *ALCloopbackFactory_getFactory(void);
#endif /* AL_BACKENDS_BASE_H */
-828
View File
@@ -1,828 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloca.h>
#include "alMain.h"
#include "alu.h"
#include <CoreServices/CoreServices.h>
#include <unistd.h>
#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioToolbox.h>
#include "backends/base.h"
typedef struct {
AudioUnit audioUnit;
ALuint frameSize;
ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate
AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD
AudioConverterRef audioConverter; // Sample rate converter if needed
AudioBufferList *bufferList; // Buffer for data coming from the input device
ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling
ll_ringbuffer_t *ring;
} ca_data;
static const ALCchar ca_device[] = "CoreAudio Default";
static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize)
{
AudioBufferList *list;
list = calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer));
if(list)
{
list->mNumberBuffers = 1;
list->mBuffers[0].mNumberChannels = channelCount;
list->mBuffers[0].mDataByteSize = byteSize;
list->mBuffers[0].mData = malloc(byteSize);
if(list->mBuffers[0].mData == NULL)
{
free(list);
list = NULL;
}
}
return list;
}
static void destroy_buffer_list(AudioBufferList* list)
{
if(list)
{
UInt32 i;
for(i = 0;i < list->mNumberBuffers;i++)
free(list->mBuffers[i].mData);
free(list);
}
}
typedef struct ALCcoreAudioPlayback {
DERIVE_FROM_TYPE(ALCbackend);
AudioUnit audioUnit;
ALuint frameSize;
AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD
} ALCcoreAudioPlayback;
static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device);
static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self);
static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name);
static void ALCcoreAudioPlayback_close(ALCcoreAudioPlayback *self);
static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self);
static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self);
static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self);
static DECLARE_FORWARD2(ALCcoreAudioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback)
DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback);
static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self);
self->frameSize = 0;
memset(&self->format, 0, sizeof(self->format));
}
static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self)
{
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon,
AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp),
UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData)
{
ALCcoreAudioPlayback *self = inRefCon;
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
ALCdevice_Lock(device);
aluMixData(device, ioData->mBuffers[0].mData,
ioData->mBuffers[0].mDataByteSize / self->frameSize);
ALCdevice_Unlock(device);
return noErr;
}
static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
AudioComponentDescription desc;
AudioComponent comp;
OSStatus err;
if(!name)
name = ca_device;
else if(strcmp(name, ca_device) != 0)
return ALC_INVALID_VALUE;
/* open the default output unit */
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
comp = AudioComponentFindNext(NULL, &desc);
if(comp == NULL)
{
ERR("AudioComponentFindNext failed\n");
return ALC_INVALID_VALUE;
}
err = AudioComponentInstanceNew(comp, &self->audioUnit);
if(err != noErr)
{
ERR("AudioComponentInstanceNew failed\n");
return ALC_INVALID_VALUE;
}
/* init and start the default audio unit... */
err = AudioUnitInitialize(self->audioUnit);
if(err != noErr)
{
ERR("AudioUnitInitialize failed\n");
AudioComponentInstanceDispose(self->audioUnit);
return ALC_INVALID_VALUE;
}
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCcoreAudioPlayback_close(ALCcoreAudioPlayback *self)
{
AudioUnitUninitialize(self->audioUnit);
AudioComponentInstanceDispose(self->audioUnit);
}
static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
AudioStreamBasicDescription streamFormat;
AURenderCallbackStruct input;
OSStatus err;
UInt32 size;
err = AudioUnitUninitialize(self->audioUnit);
if(err != noErr)
ERR("-- AudioUnitUninitialize failed.\n");
/* retrieve default output unit's properties (output side) */
size = sizeof(AudioStreamBasicDescription);
err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size);
if(err != noErr || size != sizeof(AudioStreamBasicDescription))
{
ERR("AudioUnitGetProperty failed\n");
return ALC_FALSE;
}
#if 0
TRACE("Output streamFormat of default output unit -\n");
TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket);
TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame);
TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel);
TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket);
TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame);
TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate);
#endif
/* set default output unit's input side to match output side */
err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size);
if(err != noErr)
{
ERR("AudioUnitSetProperty failed\n");
return ALC_FALSE;
}
if(device->Frequency != streamFormat.mSampleRate)
{
device->NumUpdates = (ALuint)((ALuint64)device->NumUpdates *
streamFormat.mSampleRate /
device->Frequency);
device->Frequency = streamFormat.mSampleRate;
}
/* FIXME: How to tell what channels are what in the output device, and how
* to specify what we're giving? eg, 6.0 vs 5.1 */
switch(streamFormat.mChannelsPerFrame)
{
case 1:
device->FmtChans = DevFmtMono;
break;
case 2:
device->FmtChans = DevFmtStereo;
break;
case 4:
device->FmtChans = DevFmtQuad;
break;
case 6:
device->FmtChans = DevFmtX51;
break;
case 7:
device->FmtChans = DevFmtX61;
break;
case 8:
device->FmtChans = DevFmtX71;
break;
default:
ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame);
device->FmtChans = DevFmtStereo;
streamFormat.mChannelsPerFrame = 2;
break;
}
SetDefaultWFXChannelOrder(device);
/* use channel count and sample rate from the default output unit's current
* parameters, but reset everything else */
streamFormat.mFramesPerPacket = 1;
streamFormat.mFormatFlags = 0;
switch(device->FmtType)
{
case DevFmtUByte:
device->FmtType = DevFmtByte;
/* fall-through */
case DevFmtByte:
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
streamFormat.mBitsPerChannel = 8;
break;
case DevFmtUShort:
device->FmtType = DevFmtShort;
/* fall-through */
case DevFmtShort:
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
streamFormat.mBitsPerChannel = 16;
break;
case DevFmtUInt:
device->FmtType = DevFmtInt;
/* fall-through */
case DevFmtInt:
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
streamFormat.mBitsPerChannel = 32;
break;
case DevFmtFloat:
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
streamFormat.mBitsPerChannel = 32;
break;
}
streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame *
streamFormat.mBitsPerChannel / 8;
streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame;
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian |
kLinearPCMFormatFlagIsPacked;
err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription));
if(err != noErr)
{
ERR("AudioUnitSetProperty failed\n");
return ALC_FALSE;
}
/* setup callback */
self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
input.inputProc = ALCcoreAudioPlayback_MixerProc;
input.inputProcRefCon = self;
err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct));
if(err != noErr)
{
ERR("AudioUnitSetProperty failed\n");
return ALC_FALSE;
}
/* init the default audio unit... */
err = AudioUnitInitialize(self->audioUnit);
if(err != noErr)
{
ERR("AudioUnitInitialize failed\n");
return ALC_FALSE;
}
return ALC_TRUE;
}
static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self)
{
OSStatus err = AudioOutputUnitStart(self->audioUnit);
if(err != noErr)
{
ERR("AudioOutputUnitStart failed\n");
return ALC_FALSE;
}
return ALC_TRUE;
}
static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self)
{
OSStatus err = AudioOutputUnitStop(self->audioUnit);
if(err != noErr)
ERR("AudioOutputUnitStop failed\n");
}
typedef struct ALCcoreAudioCapture {
DERIVE_FROM_TYPE(ALCbackend);
AudioUnit audioUnit;
ALuint frameSize;
ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate
AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD
AudioConverterRef audioConverter; // Sample rate converter if needed
AudioBufferList *bufferList; // Buffer for data coming from the input device
ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling
ll_ringbuffer_t *ring;
} ALCcoreAudioCapture;
static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device);
static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self);
static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name);
static void ALCcoreAudioCapture_close(ALCcoreAudioCapture *self);
static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset)
static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self);
static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self);
static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self);
static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture)
DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture);
static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self);
}
static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self)
{
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon,
AudioUnitRenderActionFlags* UNUSED(ioActionFlags),
const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber),
UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData))
{
ALCcoreAudioCapture *self = inRefCon;
AudioUnitRenderActionFlags flags = 0;
OSStatus err;
// fill the bufferList with data from the input device
err = AudioUnitRender(self->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->bufferList);
if(err != noErr)
{
ERR("AudioUnitRender error: %d\n", err);
return err;
}
ll_ringbuffer_write(self->ring, self->bufferList->mBuffers[0].mData, inNumberFrames);
return noErr;
}
static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inAudioConverter),
UInt32 *ioNumberDataPackets, AudioBufferList *ioData,
AudioStreamPacketDescription** UNUSED(outDataPacketDescription),
void *inUserData)
{
ALCcoreAudioCapture *self = inUserData;
// Read from the ring buffer and store temporarily in a large buffer
ll_ringbuffer_read(self->ring, self->resampleBuffer, *ioNumberDataPackets);
// Set the input data
ioData->mNumberBuffers = 1;
ioData->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame;
ioData->mBuffers[0].mData = self->resampleBuffer;
ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->format.mBytesPerFrame;
return noErr;
}
static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
AudioStreamBasicDescription requestedFormat; // The application requested format
AudioStreamBasicDescription hardwareFormat; // The hardware format
AudioStreamBasicDescription outputFormat; // The AudioUnit output format
AURenderCallbackStruct input;
AudioComponentDescription desc;
AudioDeviceID inputDevice;
UInt32 outputFrameCount;
UInt32 propertySize;
AudioObjectPropertyAddress propertyAddress;
UInt32 enableIO;
AudioComponent comp;
OSStatus err;
if(!name)
name = ca_device;
else if(strcmp(name, ca_device) != 0)
return ALC_INVALID_VALUE;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
// Search for component with given description
comp = AudioComponentFindNext(NULL, &desc);
if(comp == NULL)
{
ERR("AudioComponentFindNext failed\n");
return ALC_INVALID_VALUE;
}
// Open the component
err = AudioComponentInstanceNew(comp, &self->audioUnit);
if(err != noErr)
{
ERR("AudioComponentInstanceNew failed\n");
goto error;
}
// Turn off AudioUnit output
enableIO = 0;
err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint));
if(err != noErr)
{
ERR("AudioUnitSetProperty failed\n");
goto error;
}
// Turn on AudioUnit input
enableIO = 1;
err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint));
if(err != noErr)
{
ERR("AudioUnitSetProperty failed\n");
goto error;
}
// Get the default input device
propertySize = sizeof(AudioDeviceID);
propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = kAudioObjectPropertyElementMaster;
err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice);
if(err != noErr)
{
ERR("AudioObjectGetPropertyData failed\n");
goto error;
}
if(inputDevice == kAudioDeviceUnknown)
{
ERR("No input device found\n");
goto error;
}
// Track the input device
err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID));
if(err != noErr)
{
ERR("AudioUnitSetProperty failed\n");
goto error;
}
// set capture callback
input.inputProc = ALCcoreAudioCapture_RecordProc;
input.inputProcRefCon = self;
err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct));
if(err != noErr)
{
ERR("AudioUnitSetProperty failed\n");
goto error;
}
// Initialize the device
err = AudioUnitInitialize(self->audioUnit);
if(err != noErr)
{
ERR("AudioUnitInitialize failed\n");
goto error;
}
// Get the hardware format
propertySize = sizeof(AudioStreamBasicDescription);
err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize);
if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription))
{
ERR("AudioUnitGetProperty failed\n");
goto error;
}
// Set up the requested format description
switch(device->FmtType)
{
case DevFmtUByte:
requestedFormat.mBitsPerChannel = 8;
requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
break;
case DevFmtShort:
requestedFormat.mBitsPerChannel = 16;
requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
break;
case DevFmtInt:
requestedFormat.mBitsPerChannel = 32;
requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
break;
case DevFmtFloat:
requestedFormat.mBitsPerChannel = 32;
requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
break;
case DevFmtByte:
case DevFmtUShort:
case DevFmtUInt:
ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
goto error;
}
switch(device->FmtChans)
{
case DevFmtMono:
requestedFormat.mChannelsPerFrame = 1;
break;
case DevFmtStereo:
requestedFormat.mChannelsPerFrame = 2;
break;
case DevFmtQuad:
case DevFmtX51:
case DevFmtX51Rear:
case DevFmtX61:
case DevFmtX71:
case DevFmtAmbi3D:
ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
goto error;
}
requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8;
requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame;
requestedFormat.mSampleRate = device->Frequency;
requestedFormat.mFormatID = kAudioFormatLinearPCM;
requestedFormat.mReserved = 0;
requestedFormat.mFramesPerPacket = 1;
// save requested format description for later use
self->format = requestedFormat;
self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
// Use intermediate format for sample rate conversion (outputFormat)
// Set sample rate to the same as hardware for resampling later
outputFormat = requestedFormat;
outputFormat.mSampleRate = hardwareFormat.mSampleRate;
// Determine sample rate ratio for resampling
self->sampleRateRatio = outputFormat.mSampleRate / device->Frequency;
// The output format should be the requested format, but using the hardware sample rate
// This is because the AudioUnit will automatically scale other properties, except for sample rate
err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat));
if(err != noErr)
{
ERR("AudioUnitSetProperty failed\n");
goto error;
}
// Set the AudioUnit output format frame count
outputFrameCount = device->UpdateSize * self->sampleRateRatio;
err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount));
if(err != noErr)
{
ERR("AudioUnitSetProperty failed: %d\n", err);
goto error;
}
// Set up sample converter
err = AudioConverterNew(&outputFormat, &requestedFormat, &self->audioConverter);
if(err != noErr)
{
ERR("AudioConverterNew failed: %d\n", err);
goto error;
}
// Create a buffer for use in the resample callback
self->resampleBuffer = malloc(device->UpdateSize * self->frameSize * self->sampleRateRatio);
// Allocate buffer for the AudioUnit output
self->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * self->frameSize * self->sampleRateRatio);
if(self->bufferList == NULL)
goto error;
self->ring = ll_ringbuffer_create(
device->UpdateSize*self->sampleRateRatio*device->NumUpdates + 1,
self->frameSize
);
if(!self->ring) goto error;
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
error:
ll_ringbuffer_free(self->ring);
self->ring = NULL;
free(self->resampleBuffer);
destroy_buffer_list(self->bufferList);
if(self->audioConverter)
AudioConverterDispose(self->audioConverter);
if(self->audioUnit)
AudioComponentInstanceDispose(self->audioUnit);
return ALC_INVALID_VALUE;
}
static void ALCcoreAudioCapture_close(ALCcoreAudioCapture *self)
{
ll_ringbuffer_free(self->ring);
self->ring = NULL;
free(self->resampleBuffer);
destroy_buffer_list(self->bufferList);
AudioConverterDispose(self->audioConverter);
AudioComponentInstanceDispose(self->audioUnit);
}
static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self)
{
OSStatus err = AudioOutputUnitStart(self->audioUnit);
if(err != noErr)
{
ERR("AudioOutputUnitStart failed\n");
return ALC_FALSE;
}
return ALC_TRUE;
}
static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self)
{
OSStatus err = AudioOutputUnitStop(self->audioUnit);
if(err != noErr)
ERR("AudioOutputUnitStop failed\n");
}
static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples)
{
AudioBufferList *list;
UInt32 frameCount;
OSStatus err;
// If no samples are requested, just return
if(samples == 0)
return ALC_NO_ERROR;
// Allocate a temporary AudioBufferList to use as the return resamples data
list = alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer));
// Point the resampling buffer to the capture buffer
list->mNumberBuffers = 1;
list->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame;
list->mBuffers[0].mDataByteSize = samples * self->frameSize;
list->mBuffers[0].mData = buffer;
// Resample into another AudioBufferList
frameCount = samples;
err = AudioConverterFillComplexBuffer(self->audioConverter,
ALCcoreAudioCapture_ConvertCallback, self, &frameCount, list, NULL
);
if(err != noErr)
{
ERR("AudioConverterFillComplexBuffer error: %d\n", err);
return ALC_INVALID_VALUE;
}
return ALC_NO_ERROR;
}
static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self)
{
return ll_ringbuffer_read_space(self->ring) / self->sampleRateRatio;
}
typedef struct ALCcoreAudioBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCcoreAudioBackendFactory;
#define ALCCOREAUDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCcoreAudioBackendFactory, ALCbackendFactory) } }
ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void);
static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self);
static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit)
static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type);
static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory);
ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void)
{
static ALCcoreAudioBackendFactory factory = ALCCOREAUDIOBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory* UNUSED(self))
{
return ALC_TRUE;
}
static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback || ALCbackend_Capture)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(ca_device);
break;
case CAPTURE_DEVICE_PROBE:
AppendCaptureDeviceList(ca_device);
break;
}
}
static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCcoreAudioPlayback *backend;
NEW_OBJ(backend, ALCcoreAudioPlayback)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCcoreAudioCapture *backend;
NEW_OBJ(backend, ALCcoreAudioCapture)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
File diff suppressed because it is too large Load Diff
-632
View File
@@ -1,632 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "compat.h"
#include "backends/base.h"
#include <jack/jack.h>
#include <jack/ringbuffer.h>
static const ALCchar jackDevice[] = "JACK Default";
#ifdef HAVE_DYNLOAD
#define JACK_FUNCS(MAGIC) \
MAGIC(jack_client_open); \
MAGIC(jack_client_close); \
MAGIC(jack_client_name_size); \
MAGIC(jack_get_client_name); \
MAGIC(jack_connect); \
MAGIC(jack_activate); \
MAGIC(jack_deactivate); \
MAGIC(jack_port_register); \
MAGIC(jack_port_unregister); \
MAGIC(jack_port_get_buffer); \
MAGIC(jack_port_name); \
MAGIC(jack_get_ports); \
MAGIC(jack_free); \
MAGIC(jack_get_sample_rate); \
MAGIC(jack_set_error_function); \
MAGIC(jack_set_process_callback); \
MAGIC(jack_set_buffer_size_callback); \
MAGIC(jack_set_buffer_size); \
MAGIC(jack_get_buffer_size);
static void *jack_handle;
#define MAKE_FUNC(f) static __typeof(f) * p##f
JACK_FUNCS(MAKE_FUNC);
#undef MAKE_FUNC
#define jack_client_open pjack_client_open
#define jack_client_close pjack_client_close
#define jack_client_name_size pjack_client_name_size
#define jack_get_client_name pjack_get_client_name
#define jack_connect pjack_connect
#define jack_activate pjack_activate
#define jack_deactivate pjack_deactivate
#define jack_port_register pjack_port_register
#define jack_port_unregister pjack_port_unregister
#define jack_port_get_buffer pjack_port_get_buffer
#define jack_port_name pjack_port_name
#define jack_get_ports pjack_get_ports
#define jack_free pjack_free
#define jack_get_sample_rate pjack_get_sample_rate
#define jack_set_error_function pjack_set_error_function
#define jack_set_process_callback pjack_set_process_callback
#define jack_set_buffer_size_callback pjack_set_buffer_size_callback
#define jack_set_buffer_size pjack_set_buffer_size
#define jack_get_buffer_size pjack_get_buffer_size
#endif
static jack_options_t ClientOptions = JackNullOption;
static ALCboolean jack_load(void)
{
ALCboolean error = ALC_FALSE;
#ifdef HAVE_DYNLOAD
if(!jack_handle)
{
al_string missing_funcs = AL_STRING_INIT_STATIC();
#ifdef _WIN32
#define JACKLIB "libjack.dll"
#else
#define JACKLIB "libjack.so.0"
#endif
jack_handle = LoadLib(JACKLIB);
if(!jack_handle)
{
WARN("Failed to load %s\n", JACKLIB);
return ALC_FALSE;
}
error = ALC_FALSE;
#define LOAD_FUNC(f) do { \
p##f = GetSymbol(jack_handle, #f); \
if(p##f == NULL) { \
error = ALC_TRUE; \
alstr_append_cstr(&missing_funcs, "\n" #f); \
} \
} while(0)
JACK_FUNCS(LOAD_FUNC);
#undef LOAD_FUNC
if(error)
{
WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs));
CloseLib(jack_handle);
jack_handle = NULL;
}
alstr_reset(&missing_funcs);
}
#endif
return !error;
}
typedef struct ALCjackPlayback {
DERIVE_FROM_TYPE(ALCbackend);
jack_client_t *Client;
jack_port_t *Port[MAX_OUTPUT_CHANNELS];
ll_ringbuffer_t *Ring;
alcnd_t Cond;
volatile int killNow;
althrd_t thread;
} ALCjackPlayback;
static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg);
static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg);
static int ALCjackPlayback_mixerProc(void *arg);
static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device);
static void ALCjackPlayback_Destruct(ALCjackPlayback *self);
static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name);
static void ALCjackPlayback_close(ALCjackPlayback *self);
static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self);
static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self);
static void ALCjackPlayback_stop(ALCjackPlayback *self);
static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples)
static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self);
static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback)
DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback);
static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device)
{
ALuint i;
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCjackPlayback, ALCbackend, self);
alcnd_init(&self->Cond);
self->Client = NULL;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
self->Port[i] = NULL;
self->Ring = NULL;
self->killNow = 1;
}
static void ALCjackPlayback_Destruct(ALCjackPlayback *self)
{
ALuint i;
if(self->Client)
{
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
{
if(self->Port[i])
jack_port_unregister(self->Client, self->Port[i]);
self->Port[i] = NULL;
}
jack_client_close(self->Client);
self->Client = NULL;
}
alcnd_destroy(&self->Cond);
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg)
{
ALCjackPlayback *self = arg;
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
ALuint bufsize;
ALCjackPlayback_lock(self);
device->UpdateSize = numframes;
device->NumUpdates = 2;
bufsize = device->UpdateSize;
if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize))
bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize);
bufsize += device->UpdateSize;
device->NumUpdates = bufsize / device->UpdateSize;
TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates);
ll_ringbuffer_free(self->Ring);
self->Ring = ll_ringbuffer_create(bufsize,
FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)
);
if(!self->Ring)
{
ERR("Failed to reallocate ringbuffer\n");
aluHandleDisconnect(device);
}
ALCjackPlayback_unlock(self);
return 0;
}
static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg)
{
ALCjackPlayback *self = arg;
jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS];
ll_ringbuffer_data_t data[2];
jack_nframes_t total = 0;
jack_nframes_t todo;
ALsizei i, c, numchans;
ll_ringbuffer_get_read_vector(self->Ring, data);
for(c = 0;c < MAX_OUTPUT_CHANNELS && self->Port[c];c++)
out[c] = jack_port_get_buffer(self->Port[c], numframes);
numchans = c;
todo = minu(numframes, data[0].len);
for(c = 0;c < numchans;c++)
{
const ALfloat *restrict in = ((ALfloat*)data[0].buf) + c;
for(i = 0;(jack_nframes_t)i < todo;i++)
out[c][i] = in[i*numchans];
out[c] += todo;
}
total += todo;
todo = minu(numframes-total, data[1].len);
if(todo > 0)
{
for(c = 0;c < numchans;c++)
{
const ALfloat *restrict in = ((ALfloat*)data[1].buf) + c;
for(i = 0;(jack_nframes_t)i < todo;i++)
out[c][i] = in[i*numchans];
out[c] += todo;
}
total += todo;
}
ll_ringbuffer_read_advance(self->Ring, total);
alcnd_signal(&self->Cond);
if(numframes > total)
{
todo = numframes-total;
for(c = 0;c < numchans;c++)
{
for(i = 0;(jack_nframes_t)i < todo;i++)
out[c][i] = 0.0f;
}
}
return 0;
}
static int ALCjackPlayback_mixerProc(void *arg)
{
ALCjackPlayback *self = arg;
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
ll_ringbuffer_data_t data[2];
SetRTPriority();
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
ALCjackPlayback_lock(self);
while(!self->killNow && device->Connected)
{
ALuint todo, len1, len2;
/* NOTE: Unfortunately, there is an unavoidable race condition here.
* It's possible for the process() method to run, updating the read
* pointer and signaling the condition variable, in between the mixer
* loop checking the write size and waiting for the condition variable.
* This will cause the mixer loop to wait until the *next* process()
* invocation, most likely writing silence for it.
*
* However, this should only happen if the mixer is running behind
* anyway (as ideally we'll be asleep in alcnd_wait by the time the
* process() method is invoked), so this behavior is not unwarranted.
* It's unfortunate since it'll be wasting time sleeping that could be
* used to catch up, but there's no way around it without blocking in
* the process() method.
*/
if(ll_ringbuffer_write_space(self->Ring) < device->UpdateSize)
{
alcnd_wait(&self->Cond, &STATIC_CAST(ALCbackend,self)->mMutex);
continue;
}
ll_ringbuffer_get_write_vector(self->Ring, data);
todo = data[0].len + data[1].len;
todo -= todo%device->UpdateSize;
len1 = minu(data[0].len, todo);
len2 = minu(data[1].len, todo-len1);
aluMixData(device, data[0].buf, len1);
if(len2 > 0)
aluMixData(device, data[1].buf, len2);
ll_ringbuffer_write_advance(self->Ring, todo);
}
ALCjackPlayback_unlock(self);
return 0;
}
static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
const char *client_name = "alsoft";
jack_status_t status;
if(!name)
name = jackDevice;
else if(strcmp(name, jackDevice) != 0)
return ALC_INVALID_VALUE;
self->Client = jack_client_open(client_name, ClientOptions, &status, NULL);
if(self->Client == NULL)
{
ERR("jack_client_open() failed, status = 0x%02x\n", status);
return ALC_INVALID_VALUE;
}
if((status&JackServerStarted))
TRACE("JACK server started\n");
if((status&JackNameNotUnique))
{
client_name = jack_get_client_name(self->Client);
TRACE("Client name not unique, got `%s' instead\n", client_name);
}
jack_set_process_callback(self->Client, ALCjackPlayback_process, self);
jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self);
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCjackPlayback_close(ALCjackPlayback *self)
{
ALuint i;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
{
if(self->Port[i])
jack_port_unregister(self->Client, self->Port[i]);
self->Port[i] = NULL;
}
jack_client_close(self->Client);
self->Client = NULL;
}
static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALsizei numchans, i;
ALuint bufsize;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
{
if(self->Port[i])
jack_port_unregister(self->Client, self->Port[i]);
self->Port[i] = NULL;
}
/* Ignore the requested buffer metrics and just keep one JACK-sized buffer
* ready for when requested. Note that one period's worth of audio in the
* ring buffer will always be left unfilled because one element of the ring
* buffer will not be writeable, and we only write in period-sized chunks.
*/
device->Frequency = jack_get_sample_rate(self->Client);
device->UpdateSize = jack_get_buffer_size(self->Client);
device->NumUpdates = 2;
bufsize = device->UpdateSize;
if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize))
bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize);
bufsize += device->UpdateSize;
device->NumUpdates = bufsize / device->UpdateSize;
/* Force 32-bit float output. */
device->FmtType = DevFmtFloat;
numchans = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
for(i = 0;i < numchans;i++)
{
char name[64];
snprintf(name, sizeof(name), "channel_%d", i+1);
self->Port[i] = jack_port_register(self->Client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
if(self->Port[i] == NULL)
{
ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device->FmtChans));
if(i == 0) return ALC_FALSE;
break;
}
}
if(i < numchans)
{
if(i == 1)
device->FmtChans = DevFmtMono;
else
{
for(--i;i >= 2;i--)
{
jack_port_unregister(self->Client, self->Port[i]);
self->Port[i] = NULL;
}
device->FmtChans = DevFmtStereo;
}
}
ll_ringbuffer_free(self->Ring);
self->Ring = ll_ringbuffer_create(bufsize,
FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)
);
if(!self->Ring)
{
ERR("Failed to allocate ringbuffer\n");
return ALC_FALSE;
}
SetDefaultChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self)
{
const char **ports;
ALsizei i;
if(jack_activate(self->Client))
{
ERR("Failed to activate client\n");
return ALC_FALSE;
}
ports = jack_get_ports(self->Client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
if(ports == NULL)
{
ERR("No physical playback ports found\n");
jack_deactivate(self->Client);
return ALC_FALSE;
}
for(i = 0;i < MAX_OUTPUT_CHANNELS && self->Port[i];i++)
{
if(!ports[i])
{
ERR("No physical playback port for \"%s\"\n", jack_port_name(self->Port[i]));
break;
}
if(jack_connect(self->Client, jack_port_name(self->Port[i]), ports[i]))
ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(self->Port[i]), ports[i]);
}
jack_free(ports);
self->killNow = 0;
if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success)
{
jack_deactivate(self->Client);
return ALC_FALSE;
}
return ALC_TRUE;
}
static void ALCjackPlayback_stop(ALCjackPlayback *self)
{
int res;
if(self->killNow)
return;
self->killNow = 1;
/* Lock the backend to ensure we don't flag the mixer to die and signal the
* mixer to wake up in between it checking the flag and going to sleep and
* wait for a wakeup (potentially leading to it never waking back up to see
* the flag). */
ALCjackPlayback_lock(self);
ALCjackPlayback_unlock(self);
alcnd_signal(&self->Cond);
althrd_join(self->thread, &res);
jack_deactivate(self->Client);
}
static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ClockLatency ret;
ALCjackPlayback_lock(self);
ret.ClockTime = GetDeviceClockTime(device);
ret.Latency = ll_ringbuffer_read_space(self->Ring) * DEVICE_CLOCK_RES /
device->Frequency;
ALCjackPlayback_unlock(self);
return ret;
}
static void jack_msg_handler(const char *message)
{
WARN("%s\n", message);
}
typedef struct ALCjackBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCjackBackendFactory;
#define ALCJACKBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCjackBackendFactory, ALCbackendFactory) } }
static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self))
{
jack_client_t *client;
jack_status_t status;
if(!jack_load())
return ALC_FALSE;
if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0))
ClientOptions |= JackNoStartServer;
jack_set_error_function(jack_msg_handler);
client = jack_client_open("alsoft", ClientOptions, &status, NULL);
jack_set_error_function(NULL);
if(client == NULL)
{
WARN("jack_client_open() failed, 0x%02x\n", status);
if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer))
ERR("Unable to connect to JACK server\n");
return ALC_FALSE;
}
jack_client_close(client);
return ALC_TRUE;
}
static void ALCjackBackendFactory_deinit(ALCjackBackendFactory* UNUSED(self))
{
#ifdef HAVE_DYNLOAD
if(jack_handle)
CloseLib(jack_handle);
jack_handle = NULL;
#endif
}
static ALCboolean ALCjackBackendFactory_querySupport(ALCjackBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(jackDevice);
break;
case CAPTURE_DEVICE_PROBE:
break;
}
}
static ALCbackend* ALCjackBackendFactory_createBackend(ALCjackBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCjackPlayback *backend;
NEW_OBJ(backend, ALCjackPlayback)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCjackBackendFactory);
ALCbackendFactory *ALCjackBackendFactory_getFactory(void)
{
static ALCjackBackendFactory factory = ALCJACKBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
-133
View File
@@ -1,133 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2011 by Chris Robinson
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include "alMain.h"
#include "alu.h"
#include "backends/base.h"
typedef struct ALCloopback {
DERIVE_FROM_TYPE(ALCbackend);
} ALCloopback;
static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device);
static DECLARE_FORWARD(ALCloopback, ALCbackend, void, Destruct)
static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name);
static void ALCloopback_close(ALCloopback *self);
static ALCboolean ALCloopback_reset(ALCloopback *self);
static ALCboolean ALCloopback_start(ALCloopback *self);
static void ALCloopback_stop(ALCloopback *self);
static DECLARE_FORWARD2(ALCloopback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCloopback, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCloopback, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCloopback)
DEFINE_ALCBACKEND_VTABLE(ALCloopback);
static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCloopback, ALCbackend, self);
}
static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCloopback_close(ALCloopback* UNUSED(self))
{
}
static ALCboolean ALCloopback_reset(ALCloopback *self)
{
SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice);
return ALC_TRUE;
}
static ALCboolean ALCloopback_start(ALCloopback* UNUSED(self))
{
return ALC_TRUE;
}
static void ALCloopback_stop(ALCloopback* UNUSED(self))
{
}
typedef struct ALCloopbackFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCloopbackFactory;
#define ALCNULLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCloopbackFactory, ALCbackendFactory) } }
ALCbackendFactory *ALCloopbackFactory_getFactory(void);
static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory *self);
static DECLARE_FORWARD(ALCloopbackFactory, ALCbackendFactory, void, deinit)
static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory *self, ALCbackend_Type type);
static void ALCloopbackFactory_probe(ALCloopbackFactory *self, enum DevProbe type);
static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCloopbackFactory);
ALCbackendFactory *ALCloopbackFactory_getFactory(void)
{
static ALCloopbackFactory factory = ALCNULLBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory* UNUSED(self))
{
return ALC_TRUE;
}
static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Loopback)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type))
{
}
static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Loopback)
{
ALCloopback *backend;
NEW_OBJ(backend, ALCloopback)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
File diff suppressed because it is too large Load Diff
-225
View File
@@ -1,225 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2010 by Chris Robinson
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "compat.h"
#include "backends/base.h"
typedef struct ALCnullBackend {
DERIVE_FROM_TYPE(ALCbackend);
volatile int killNow;
althrd_t thread;
} ALCnullBackend;
static int ALCnullBackend_mixerProc(void *ptr);
static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device);
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, Destruct)
static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name);
static void ALCnullBackend_close(ALCnullBackend *self);
static ALCboolean ALCnullBackend_reset(ALCnullBackend *self);
static ALCboolean ALCnullBackend_start(ALCnullBackend *self);
static void ALCnullBackend_stop(ALCnullBackend *self);
static DECLARE_FORWARD2(ALCnullBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCnullBackend)
DEFINE_ALCBACKEND_VTABLE(ALCnullBackend);
static const ALCchar nullDevice[] = "No Output";
static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCnullBackend, ALCbackend, self);
}
static int ALCnullBackend_mixerProc(void *ptr)
{
ALCnullBackend *self = (ALCnullBackend*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
struct timespec now, start;
ALuint64 avail, done;
const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 /
device->Frequency / 2);
SetRTPriority();
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
done = 0;
if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC)
{
ERR("Failed to get starting time\n");
return 1;
}
while(!self->killNow && device->Connected)
{
if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
{
ERR("Failed to get current time\n");
return 1;
}
avail = (now.tv_sec - start.tv_sec) * device->Frequency;
avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000;
if(avail < done)
{
/* Oops, time skipped backwards. Reset the number of samples done
* with one update available since we (likely) just came back from
* sleeping. */
done = avail - device->UpdateSize;
}
if(avail-done < device->UpdateSize)
al_nssleep(restTime);
else while(avail-done >= device->UpdateSize)
{
ALCnullBackend_lock(self);
aluMixData(device, NULL, device->UpdateSize);
ALCnullBackend_unlock(self);
done += device->UpdateSize;
}
}
return 0;
}
static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name)
{
ALCdevice *device;
if(!name)
name = nullDevice;
else if(strcmp(name, nullDevice) != 0)
return ALC_INVALID_VALUE;
device = STATIC_CAST(ALCbackend, self)->mDevice;
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCnullBackend_close(ALCnullBackend* UNUSED(self))
{
}
static ALCboolean ALCnullBackend_reset(ALCnullBackend *self)
{
SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice);
return ALC_TRUE;
}
static ALCboolean ALCnullBackend_start(ALCnullBackend *self)
{
self->killNow = 0;
if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
}
static void ALCnullBackend_stop(ALCnullBackend *self)
{
int res;
if(self->killNow)
return;
self->killNow = 1;
althrd_join(self->thread, &res);
}
typedef struct ALCnullBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCnullBackendFactory;
#define ALCNULLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCnullBackendFactory, ALCbackendFactory) } }
ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory *self);
static DECLARE_FORWARD(ALCnullBackendFactory, ALCbackendFactory, void, deinit)
static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory *self, ALCbackend_Type type);
static void ALCnullBackendFactory_probe(ALCnullBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCnullBackendFactory);
ALCbackendFactory *ALCnullBackendFactory_getFactory(void)
{
static ALCnullBackendFactory factory = ALCNULLBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory* UNUSED(self))
{
return ALC_TRUE;
}
static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(nullDevice);
break;
case CAPTURE_DEVICE_PROBE:
break;
}
}
static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCnullBackend *backend;
NEW_OBJ(backend, ALCnullBackend)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
File diff suppressed because it is too large Load Diff
-868
View File
@@ -1,868 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <unistd.h>
#include <errno.h>
#include <math.h>
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "compat.h"
#include "backends/base.h"
#include <sys/soundcard.h>
/*
* The OSS documentation talks about SOUND_MIXER_READ, but the header
* only contains MIXER_READ. Play safe. Same for WRITE.
*/
#ifndef SOUND_MIXER_READ
#define SOUND_MIXER_READ MIXER_READ
#endif
#ifndef SOUND_MIXER_WRITE
#define SOUND_MIXER_WRITE MIXER_WRITE
#endif
#if defined(SOUND_VERSION) && (SOUND_VERSION < 0x040000)
#define ALC_OSS_COMPAT
#endif
#ifndef SNDCTL_AUDIOINFO
#define ALC_OSS_COMPAT
#endif
/*
* FreeBSD strongly discourages the use of specific devices,
* such as those returned in oss_audioinfo.devnode
*/
#ifdef __FreeBSD__
#define ALC_OSS_DEVNODE_TRUC
#endif
struct oss_device {
const ALCchar *handle;
const char *path;
struct oss_device *next;
};
static struct oss_device oss_playback = {
"OSS Default",
"/dev/dsp",
NULL
};
static struct oss_device oss_capture = {
"OSS Default",
"/dev/dsp",
NULL
};
#ifdef ALC_OSS_COMPAT
#define DSP_CAP_OUTPUT 0x00020000
#define DSP_CAP_INPUT 0x00010000
static void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag))
{
}
#else
#ifndef HAVE_STRNLEN
static size_t strnlen(const char *str, size_t maxlen)
{
const char *end = memchr(str, 0, maxlen);
if(!end) return maxlen;
return end - str;
}
#endif
static void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, const char *path, size_t plen)
{
struct oss_device *next;
struct oss_device *last;
size_t i;
/* skip the first item "OSS Default" */
last = list;
next = list->next;
#ifdef ALC_OSS_DEVNODE_TRUC
for(i = 0;i < plen;i++)
{
if(path[i] == '.')
{
if(strncmp(path + i, handle + hlen + i - plen, plen - i) == 0)
hlen = hlen + i - plen;
plen = i;
}
}
#else
(void)i;
#endif
if(handle[0] == '\0')
{
handle = path;
hlen = plen;
}
while(next != NULL)
{
if(strncmp(next->path, path, plen) == 0)
return;
last = next;
next = next->next;
}
next = (struct oss_device*)malloc(sizeof(struct oss_device) + hlen + plen + 2);
next->handle = (char*)(next + 1);
next->path = next->handle + hlen + 1;
next->next = NULL;
last->next = next;
strncpy((char*)next->handle, handle, hlen);
((char*)next->handle)[hlen] = '\0';
strncpy((char*)next->path, path, plen);
((char*)next->path)[plen] = '\0';
TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path);
}
static void ALCossListPopulate(struct oss_device *devlist, int type_flag)
{
struct oss_sysinfo si;
struct oss_audioinfo ai;
int fd, i;
if((fd=open("/dev/mixer", O_RDONLY)) < 0)
{
TRACE("Could not open /dev/mixer: %s\n", strerror(errno));
return;
}
if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1)
{
TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno));
goto done;
}
for(i = 0;i < si.numaudios;i++)
{
const char *handle;
size_t len;
ai.dev = i;
if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1)
{
ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno));
continue;
}
if(ai.devnode[0] == '\0')
continue;
if(ai.handle[0] != '\0')
{
len = strnlen(ai.handle, sizeof(ai.handle));
handle = ai.handle;
}
else
{
len = strnlen(ai.name, sizeof(ai.name));
handle = ai.name;
}
if((ai.caps&type_flag))
ALCossListAppend(devlist, handle, len, ai.devnode,
strnlen(ai.devnode, sizeof(ai.devnode)));
}
done:
close(fd);
}
#endif
static void ALCossListFree(struct oss_device *list)
{
struct oss_device *cur;
if(list == NULL)
return;
/* skip the first item "OSS Default" */
cur = list->next;
list->next = NULL;
while(cur != NULL)
{
struct oss_device *next = cur->next;
free(cur);
cur = next;
}
}
static int log2i(ALCuint x)
{
int y = 0;
while (x > 1)
{
x >>= 1;
y++;
}
return y;
}
typedef struct ALCplaybackOSS {
DERIVE_FROM_TYPE(ALCbackend);
int fd;
ALubyte *mix_data;
int data_size;
ATOMIC(ALenum) killNow;
althrd_t thread;
} ALCplaybackOSS;
static int ALCplaybackOSS_mixerProc(void *ptr);
static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device);
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, Destruct)
static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name);
static void ALCplaybackOSS_close(ALCplaybackOSS *self);
static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self);
static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self);
static void ALCplaybackOSS_stop(ALCplaybackOSS *self);
static DECLARE_FORWARD2(ALCplaybackOSS, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS)
DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS);
static int ALCplaybackOSS_mixerProc(void *ptr)
{
ALCplaybackOSS *self = (ALCplaybackOSS*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
struct timeval timeout;
ALubyte *write_ptr;
ALint frame_size;
ALint to_write;
ssize_t wrote;
fd_set wfds;
int sret;
SetRTPriority();
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
ALCplaybackOSS_lock(self);
while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected)
{
FD_ZERO(&wfds);
FD_SET(self->fd, &wfds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
ALCplaybackOSS_unlock(self);
sret = select(self->fd+1, NULL, &wfds, NULL, &timeout);
ALCplaybackOSS_lock(self);
if(sret < 0)
{
if(errno == EINTR)
continue;
ERR("select failed: %s\n", strerror(errno));
aluHandleDisconnect(device);
break;
}
else if(sret == 0)
{
WARN("select timeout\n");
continue;
}
write_ptr = self->mix_data;
to_write = self->data_size;
aluMixData(device, write_ptr, to_write/frame_size);
while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow))
{
wrote = write(self->fd, write_ptr, to_write);
if(wrote < 0)
{
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
continue;
ERR("write failed: %s\n", strerror(errno));
aluHandleDisconnect(device);
break;
}
to_write -= wrote;
write_ptr += wrote;
}
}
ALCplaybackOSS_unlock(self);
return 0;
}
static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCplaybackOSS, ALCbackend, self);
ATOMIC_INIT(&self->killNow, AL_FALSE);
}
static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
{
struct oss_device *dev = &oss_playback;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
if(!name || strcmp(name, dev->handle) == 0)
name = dev->handle;
else
{
if(!dev->next)
{
ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT);
dev = &oss_playback;
}
while(dev != NULL)
{
if (strcmp(dev->handle, name) == 0)
break;
dev = dev->next;
}
if(dev == NULL)
{
WARN("Could not find \"%s\" in device list\n", name);
return ALC_INVALID_VALUE;
}
}
self->fd = open(dev->path, O_WRONLY);
if(self->fd == -1)
{
ERR("Could not open %s: %s\n", dev->path, strerror(errno));
return ALC_INVALID_VALUE;
}
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCplaybackOSS_close(ALCplaybackOSS *self)
{
close(self->fd);
self->fd = -1;
}
static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
int numFragmentsLogSize;
int log2FragmentSize;
unsigned int periods;
audio_buf_info info;
ALuint frameSize;
int numChannels;
int ossFormat;
int ossSpeed;
char *err;
switch(device->FmtType)
{
case DevFmtByte:
ossFormat = AFMT_S8;
break;
case DevFmtUByte:
ossFormat = AFMT_U8;
break;
case DevFmtUShort:
case DevFmtInt:
case DevFmtUInt:
case DevFmtFloat:
device->FmtType = DevFmtShort;
/* fall-through */
case DevFmtShort:
ossFormat = AFMT_S16_NE;
break;
}
periods = device->NumUpdates;
numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
ossSpeed = device->Frequency;
frameSize = numChannels * BytesFromDevFmt(device->FmtType);
/* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */
log2FragmentSize = maxi(log2i(device->UpdateSize*frameSize), 4);
numFragmentsLogSize = (periods << 16) | log2FragmentSize;
#define CHECKERR(func) if((func) < 0) { \
err = #func; \
goto err; \
}
/* Don't fail if SETFRAGMENT fails. We can handle just about anything
* that's reported back via GETOSPACE */
ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat));
CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels));
CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed));
CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &info));
if(0)
{
err:
ERR("%s failed: %s\n", err, strerror(errno));
return ALC_FALSE;
}
#undef CHECKERR
if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels)
{
ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
return ALC_FALSE;
}
if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
(ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
(ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
{
ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
return ALC_FALSE;
}
device->Frequency = ossSpeed;
device->UpdateSize = info.fragsize / frameSize;
device->NumUpdates = info.fragments;
SetDefaultChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
self->data_size = device->UpdateSize * FrameSizeFromDevFmt(
device->FmtChans, device->FmtType, device->AmbiOrder
);
self->mix_data = calloc(1, self->data_size);
ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE);
if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success)
{
free(self->mix_data);
self->mix_data = NULL;
return ALC_FALSE;
}
return ALC_TRUE;
}
static void ALCplaybackOSS_stop(ALCplaybackOSS *self)
{
int res;
if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE))
return;
althrd_join(self->thread, &res);
if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
ERR("Error resetting device: %s\n", strerror(errno));
free(self->mix_data);
self->mix_data = NULL;
}
typedef struct ALCcaptureOSS {
DERIVE_FROM_TYPE(ALCbackend);
int fd;
ll_ringbuffer_t *ring;
ATOMIC(ALenum) killNow;
althrd_t thread;
} ALCcaptureOSS;
static int ALCcaptureOSS_recordProc(void *ptr);
static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device);
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, Destruct)
static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name);
static void ALCcaptureOSS_close(ALCcaptureOSS *self);
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset)
static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self);
static void ALCcaptureOSS_stop(ALCcaptureOSS *self);
static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self);
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS)
DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS);
static int ALCcaptureOSS_recordProc(void *ptr)
{
ALCcaptureOSS *self = (ALCcaptureOSS*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
struct timeval timeout;
int frame_size;
fd_set rfds;
ssize_t amt;
int sret;
SetRTPriority();
althrd_setname(althrd_current(), RECORD_THREAD_NAME);
frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
while(!ATOMIC_LOAD_SEQ(&self->killNow))
{
ll_ringbuffer_data_t vec[2];
FD_ZERO(&rfds);
FD_SET(self->fd, &rfds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
sret = select(self->fd+1, &rfds, NULL, NULL, &timeout);
if(sret < 0)
{
if(errno == EINTR)
continue;
ERR("select failed: %s\n", strerror(errno));
aluHandleDisconnect(device);
break;
}
else if(sret == 0)
{
WARN("select timeout\n");
continue;
}
ll_ringbuffer_get_write_vector(self->ring, vec);
if(vec[0].len > 0)
{
amt = read(self->fd, vec[0].buf, vec[0].len*frame_size);
if(amt < 0)
{
ERR("read failed: %s\n", strerror(errno));
ALCcaptureOSS_lock(self);
aluHandleDisconnect(device);
ALCcaptureOSS_unlock(self);
break;
}
ll_ringbuffer_write_advance(self->ring, amt/frame_size);
}
}
return 0;
}
static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCcaptureOSS, ALCbackend, self);
ATOMIC_INIT(&self->killNow, AL_FALSE);
}
static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
struct oss_device *dev = &oss_capture;
int numFragmentsLogSize;
int log2FragmentSize;
unsigned int periods;
audio_buf_info info;
ALuint frameSize;
int numChannels;
int ossFormat;
int ossSpeed;
char *err;
if(!name || strcmp(name, dev->handle) == 0)
name = dev->handle;
else
{
if(!dev->next)
{
ALCossListPopulate(&oss_capture, DSP_CAP_INPUT);
dev = &oss_capture;
}
while(dev != NULL)
{
if (strcmp(dev->handle, name) == 0)
break;
dev = dev->next;
}
if(dev == NULL)
{
WARN("Could not find \"%s\" in device list\n", name);
return ALC_INVALID_VALUE;
}
}
self->fd = open(dev->path, O_RDONLY);
if(self->fd == -1)
{
ERR("Could not open %s: %s\n", dev->path, strerror(errno));
return ALC_INVALID_VALUE;
}
switch(device->FmtType)
{
case DevFmtByte:
ossFormat = AFMT_S8;
break;
case DevFmtUByte:
ossFormat = AFMT_U8;
break;
case DevFmtShort:
ossFormat = AFMT_S16_NE;
break;
case DevFmtUShort:
case DevFmtInt:
case DevFmtUInt:
case DevFmtFloat:
ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
return ALC_INVALID_VALUE;
}
periods = 4;
numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
frameSize = numChannels * BytesFromDevFmt(device->FmtType);
ossSpeed = device->Frequency;
log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
frameSize / periods);
/* according to the OSS spec, 16 bytes are the minimum */
if (log2FragmentSize < 4)
log2FragmentSize = 4;
numFragmentsLogSize = (periods << 16) | log2FragmentSize;
#define CHECKERR(func) if((func) < 0) { \
err = #func; \
goto err; \
}
CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat));
CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels));
CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed));
CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETISPACE, &info));
if(0)
{
err:
ERR("%s failed: %s\n", err, strerror(errno));
close(self->fd);
self->fd = -1;
return ALC_INVALID_VALUE;
}
#undef CHECKERR
if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels)
{
ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
close(self->fd);
self->fd = -1;
return ALC_INVALID_VALUE;
}
if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
(ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
(ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
{
ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
close(self->fd);
self->fd = -1;
return ALC_INVALID_VALUE;
}
self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, frameSize);
if(!self->ring)
{
ERR("Ring buffer create failed\n");
close(self->fd);
self->fd = -1;
return ALC_OUT_OF_MEMORY;
}
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCcaptureOSS_close(ALCcaptureOSS *self)
{
close(self->fd);
self->fd = -1;
ll_ringbuffer_free(self->ring);
self->ring = NULL;
}
static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self)
{
ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE);
if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
}
static void ALCcaptureOSS_stop(ALCcaptureOSS *self)
{
int res;
if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE))
return;
althrd_join(self->thread, &res);
if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
ERR("Error resetting device: %s\n", strerror(errno));
}
static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples)
{
ll_ringbuffer_read(self->ring, buffer, samples);
return ALC_NO_ERROR;
}
static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self)
{
return ll_ringbuffer_read_space(self->ring);
}
typedef struct ALCossBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCossBackendFactory;
#define ALCOSSBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCossBackendFactory, ALCbackendFactory) } }
ALCbackendFactory *ALCossBackendFactory_getFactory(void);
static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self);
static void ALCossBackendFactory_deinit(ALCossBackendFactory *self);
static ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory *self, ALCbackend_Type type);
static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory);
ALCbackendFactory *ALCossBackendFactory_getFactory(void)
{
static ALCossBackendFactory factory = ALCOSSBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self))
{
ConfigValueStr(NULL, "oss", "device", &oss_playback.path);
ConfigValueStr(NULL, "oss", "capture", &oss_capture.path);
return ALC_TRUE;
}
void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self))
{
ALCossListFree(&oss_playback);
ALCossListFree(&oss_capture);
}
ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback || type == ALCbackend_Capture)
return ALC_TRUE;
return ALC_FALSE;
}
void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type)
{
struct oss_device *cur;
switch(type)
{
case ALL_DEVICE_PROBE:
ALCossListFree(&oss_playback);
ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT);
cur = &oss_playback;
while(cur != NULL)
{
#ifdef HAVE_STAT
struct stat buf;
if(stat(cur->path, &buf) == 0)
#endif
AppendAllDevicesList(cur->handle);
cur = cur->next;
}
break;
case CAPTURE_DEVICE_PROBE:
ALCossListFree(&oss_capture);
ALCossListPopulate(&oss_capture, DSP_CAP_INPUT);
cur = &oss_capture;
while(cur != NULL)
{
#ifdef HAVE_STAT
struct stat buf;
if(stat(cur->path, &buf) == 0)
#endif
AppendCaptureDeviceList(cur->handle);
cur = cur->next;
}
break;
}
}
ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCplaybackOSS *backend;
NEW_OBJ(backend, ALCplaybackOSS)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCcaptureOSS *backend;
NEW_OBJ(backend, ALCcaptureOSS)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
-575
View File
@@ -1,575 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "alMain.h"
#include "alu.h"
#include "compat.h"
#include "backends/base.h"
#include <portaudio.h>
static const ALCchar pa_device[] = "PortAudio Default";
#ifdef HAVE_DYNLOAD
static void *pa_handle;
#define MAKE_FUNC(x) static __typeof(x) * p##x
MAKE_FUNC(Pa_Initialize);
MAKE_FUNC(Pa_Terminate);
MAKE_FUNC(Pa_GetErrorText);
MAKE_FUNC(Pa_StartStream);
MAKE_FUNC(Pa_StopStream);
MAKE_FUNC(Pa_OpenStream);
MAKE_FUNC(Pa_CloseStream);
MAKE_FUNC(Pa_GetDefaultOutputDevice);
MAKE_FUNC(Pa_GetDefaultInputDevice);
MAKE_FUNC(Pa_GetStreamInfo);
#undef MAKE_FUNC
#define Pa_Initialize pPa_Initialize
#define Pa_Terminate pPa_Terminate
#define Pa_GetErrorText pPa_GetErrorText
#define Pa_StartStream pPa_StartStream
#define Pa_StopStream pPa_StopStream
#define Pa_OpenStream pPa_OpenStream
#define Pa_CloseStream pPa_CloseStream
#define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice
#define Pa_GetDefaultInputDevice pPa_GetDefaultInputDevice
#define Pa_GetStreamInfo pPa_GetStreamInfo
#endif
static ALCboolean pa_load(void)
{
PaError err;
#ifdef HAVE_DYNLOAD
if(!pa_handle)
{
#ifdef _WIN32
# define PALIB "portaudio.dll"
#elif defined(__APPLE__) && defined(__MACH__)
# define PALIB "libportaudio.2.dylib"
#elif defined(__OpenBSD__)
# define PALIB "libportaudio.so"
#else
# define PALIB "libportaudio.so.2"
#endif
pa_handle = LoadLib(PALIB);
if(!pa_handle)
return ALC_FALSE;
#define LOAD_FUNC(f) do { \
p##f = GetSymbol(pa_handle, #f); \
if(p##f == NULL) \
{ \
CloseLib(pa_handle); \
pa_handle = NULL; \
return ALC_FALSE; \
} \
} while(0)
LOAD_FUNC(Pa_Initialize);
LOAD_FUNC(Pa_Terminate);
LOAD_FUNC(Pa_GetErrorText);
LOAD_FUNC(Pa_StartStream);
LOAD_FUNC(Pa_StopStream);
LOAD_FUNC(Pa_OpenStream);
LOAD_FUNC(Pa_CloseStream);
LOAD_FUNC(Pa_GetDefaultOutputDevice);
LOAD_FUNC(Pa_GetDefaultInputDevice);
LOAD_FUNC(Pa_GetStreamInfo);
#undef LOAD_FUNC
if((err=Pa_Initialize()) != paNoError)
{
ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err));
CloseLib(pa_handle);
pa_handle = NULL;
return ALC_FALSE;
}
}
#else
if((err=Pa_Initialize()) != paNoError)
{
ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err));
return ALC_FALSE;
}
#endif
return ALC_TRUE;
}
typedef struct ALCportPlayback {
DERIVE_FROM_TYPE(ALCbackend);
PaStream *stream;
PaStreamParameters params;
ALuint update_size;
} ALCportPlayback;
static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
const PaStreamCallbackFlags statusFlags, void *userData);
static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device);
static void ALCportPlayback_Destruct(ALCportPlayback *self);
static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name);
static void ALCportPlayback_close(ALCportPlayback *self);
static ALCboolean ALCportPlayback_reset(ALCportPlayback *self);
static ALCboolean ALCportPlayback_start(ALCportPlayback *self);
static void ALCportPlayback_stop(ALCportPlayback *self);
static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback)
DEFINE_ALCBACKEND_VTABLE(ALCportPlayback);
static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCportPlayback, ALCbackend, self);
self->stream = NULL;
}
static void ALCportPlayback_Destruct(ALCportPlayback *self)
{
if(self->stream)
Pa_CloseStream(self->stream);
self->stream = NULL;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{
ALCportPlayback *self = userData;
ALCportPlayback_lock(self);
aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer);
ALCportPlayback_unlock(self);
return 0;
}
static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
PaError err;
if(!name)
name = pa_device;
else if(strcmp(name, pa_device) != 0)
return ALC_INVALID_VALUE;
self->update_size = device->UpdateSize;
self->params.device = -1;
if(!ConfigValueInt(NULL, "port", "device", &self->params.device) ||
self->params.device < 0)
self->params.device = Pa_GetDefaultOutputDevice();
self->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
(float)device->Frequency;
self->params.hostApiSpecificStreamInfo = NULL;
self->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
switch(device->FmtType)
{
case DevFmtByte:
self->params.sampleFormat = paInt8;
break;
case DevFmtUByte:
self->params.sampleFormat = paUInt8;
break;
case DevFmtUShort:
/* fall-through */
case DevFmtShort:
self->params.sampleFormat = paInt16;
break;
case DevFmtUInt:
/* fall-through */
case DevFmtInt:
self->params.sampleFormat = paInt32;
break;
case DevFmtFloat:
self->params.sampleFormat = paFloat32;
break;
}
retry_open:
err = Pa_OpenStream(&self->stream, NULL, &self->params,
device->Frequency, device->UpdateSize, paNoFlag,
ALCportPlayback_WriteCallback, self
);
if(err != paNoError)
{
if(self->params.sampleFormat == paFloat32)
{
self->params.sampleFormat = paInt16;
goto retry_open;
}
ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
return ALC_INVALID_VALUE;
}
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCportPlayback_close(ALCportPlayback *self)
{
PaError err = Pa_CloseStream(self->stream);
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
self->stream = NULL;
}
static ALCboolean ALCportPlayback_reset(ALCportPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
const PaStreamInfo *streamInfo;
streamInfo = Pa_GetStreamInfo(self->stream);
device->Frequency = streamInfo->sampleRate;
device->UpdateSize = self->update_size;
if(self->params.sampleFormat == paInt8)
device->FmtType = DevFmtByte;
else if(self->params.sampleFormat == paUInt8)
device->FmtType = DevFmtUByte;
else if(self->params.sampleFormat == paInt16)
device->FmtType = DevFmtShort;
else if(self->params.sampleFormat == paInt32)
device->FmtType = DevFmtInt;
else if(self->params.sampleFormat == paFloat32)
device->FmtType = DevFmtFloat;
else
{
ERR("Unexpected sample format: 0x%lx\n", self->params.sampleFormat);
return ALC_FALSE;
}
if(self->params.channelCount == 2)
device->FmtChans = DevFmtStereo;
else if(self->params.channelCount == 1)
device->FmtChans = DevFmtMono;
else
{
ERR("Unexpected channel count: %u\n", self->params.channelCount);
return ALC_FALSE;
}
SetDefaultChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean ALCportPlayback_start(ALCportPlayback *self)
{
PaError err;
err = Pa_StartStream(self->stream);
if(err != paNoError)
{
ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err));
return ALC_FALSE;
}
return ALC_TRUE;
}
static void ALCportPlayback_stop(ALCportPlayback *self)
{
PaError err = Pa_StopStream(self->stream);
if(err != paNoError)
ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
}
typedef struct ALCportCapture {
DERIVE_FROM_TYPE(ALCbackend);
PaStream *stream;
PaStreamParameters params;
ll_ringbuffer_t *ring;
} ALCportCapture;
static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
const PaStreamCallbackFlags statusFlags, void *userData);
static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device);
static void ALCportCapture_Destruct(ALCportCapture *self);
static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name);
static void ALCportCapture_close(ALCportCapture *self);
static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset)
static ALCboolean ALCportCapture_start(ALCportCapture *self);
static void ALCportCapture_stop(ALCportCapture *self);
static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCportCapture_availableSamples(ALCportCapture *self);
static DECLARE_FORWARD(ALCportCapture, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCportCapture)
DEFINE_ALCBACKEND_VTABLE(ALCportCapture);
static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCportCapture, ALCbackend, self);
self->stream = NULL;
}
static void ALCportCapture_Destruct(ALCportCapture *self)
{
if(self->stream)
Pa_CloseStream(self->stream);
self->stream = NULL;
if(self->ring)
ll_ringbuffer_free(self->ring);
self->ring = NULL;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer),
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{
ALCportCapture *self = userData;
size_t writable = ll_ringbuffer_write_space(self->ring);
if(framesPerBuffer > writable)
framesPerBuffer = writable;
ll_ringbuffer_write(self->ring, inputBuffer, framesPerBuffer);
return 0;
}
static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALuint samples, frame_size;
PaError err;
if(!name)
name = pa_device;
else if(strcmp(name, pa_device) != 0)
return ALC_INVALID_VALUE;
samples = device->UpdateSize * device->NumUpdates;
samples = maxu(samples, 100 * device->Frequency / 1000);
frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
self->ring = ll_ringbuffer_create(samples, frame_size);
if(self->ring == NULL) return ALC_INVALID_VALUE;
self->params.device = -1;
if(!ConfigValueInt(NULL, "port", "capture", &self->params.device) ||
self->params.device < 0)
self->params.device = Pa_GetDefaultInputDevice();
self->params.suggestedLatency = 0.0f;
self->params.hostApiSpecificStreamInfo = NULL;
switch(device->FmtType)
{
case DevFmtByte:
self->params.sampleFormat = paInt8;
break;
case DevFmtUByte:
self->params.sampleFormat = paUInt8;
break;
case DevFmtShort:
self->params.sampleFormat = paInt16;
break;
case DevFmtInt:
self->params.sampleFormat = paInt32;
break;
case DevFmtFloat:
self->params.sampleFormat = paFloat32;
break;
case DevFmtUInt:
case DevFmtUShort:
ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
return ALC_INVALID_VALUE;
}
self->params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
err = Pa_OpenStream(&self->stream, &self->params, NULL,
device->Frequency, paFramesPerBufferUnspecified, paNoFlag,
ALCportCapture_ReadCallback, self
);
if(err != paNoError)
{
ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
return ALC_INVALID_VALUE;
}
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCportCapture_close(ALCportCapture *self)
{
PaError err = Pa_CloseStream(self->stream);
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
self->stream = NULL;
ll_ringbuffer_free(self->ring);
self->ring = NULL;
}
static ALCboolean ALCportCapture_start(ALCportCapture *self)
{
PaError err = Pa_StartStream(self->stream);
if(err != paNoError)
{
ERR("Error starting stream: %s\n", Pa_GetErrorText(err));
return ALC_FALSE;
}
return ALC_TRUE;
}
static void ALCportCapture_stop(ALCportCapture *self)
{
PaError err = Pa_StopStream(self->stream);
if(err != paNoError)
ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
}
static ALCuint ALCportCapture_availableSamples(ALCportCapture *self)
{
return ll_ringbuffer_read_space(self->ring);
}
static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples)
{
ll_ringbuffer_read(self->ring, buffer, samples);
return ALC_NO_ERROR;
}
typedef struct ALCportBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCportBackendFactory;
#define ALCPORTBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory) } }
static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self);
static void ALCportBackendFactory_deinit(ALCportBackendFactory *self);
static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type);
static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory);
static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory* UNUSED(self))
{
if(!pa_load())
return ALC_FALSE;
return ALC_TRUE;
}
static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self))
{
#ifdef HAVE_DYNLOAD
if(pa_handle)
{
Pa_Terminate();
CloseLib(pa_handle);
pa_handle = NULL;
}
#else
Pa_Terminate();
#endif
}
static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback || type == ALCbackend_Capture)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(pa_device);
break;
case CAPTURE_DEVICE_PROBE:
AppendCaptureDeviceList(pa_device);
break;
}
}
static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCportPlayback *backend;
NEW_OBJ(backend, ALCportPlayback)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCportCapture *backend;
NEW_OBJ(backend, ALCportCapture)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
ALCbackendFactory *ALCportBackendFactory_getFactory(void)
{
static ALCportBackendFactory factory = ALCPORTBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
File diff suppressed because it is too large Load Diff
-1069
View File
File diff suppressed because it is too large Load Diff
-346
View File
@@ -1,346 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "backends/base.h"
#include <sndio.h>
typedef struct ALCsndioBackend {
DERIVE_FROM_TYPE(ALCbackend);
struct sio_hdl *sndHandle;
ALvoid *mix_data;
ALsizei data_size;
volatile int killNow;
althrd_t thread;
} ALCsndioBackend;
static int ALCsndioBackend_mixerProc(void *ptr);
static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device);
static void ALCsndioBackend_Destruct(ALCsndioBackend *self);
static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name);
static void ALCsndioBackend_close(ALCsndioBackend *self);
static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self);
static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self);
static void ALCsndioBackend_stop(ALCsndioBackend *self);
static DECLARE_FORWARD2(ALCsndioBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCsndioBackend)
DEFINE_ALCBACKEND_VTABLE(ALCsndioBackend);
static const ALCchar sndio_device[] = "SndIO Default";
static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCsndioBackend, ALCbackend, self);
}
static void ALCsndioBackend_Destruct(ALCsndioBackend *self)
{
if(self->sndHandle)
sio_close(self->sndHandle);
self->sndHandle = NULL;
al_free(self->mix_data);
self->mix_data = NULL;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCsndioBackend_mixerProc(void *ptr)
{
ALCsndioBackend *self = (ALCsndioBackend*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALsizei frameSize;
size_t wrote;
SetRTPriority();
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
while(!self->killNow && device->Connected)
{
ALsizei len = self->data_size;
ALubyte *WritePtr = self->mix_data;
ALCsndioBackend_lock(self);
aluMixData(device, WritePtr, len/frameSize);
ALCsndioBackend_unlock(self);
while(len > 0 && !self->killNow)
{
wrote = sio_write(self->sndHandle, WritePtr, len);
if(wrote == 0)
{
ERR("sio_write failed\n");
ALCdevice_Lock(device);
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
break;
}
len -= wrote;
WritePtr += wrote;
}
}
return 0;
}
static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
if(!name)
name = sndio_device;
else if(strcmp(name, sndio_device) != 0)
return ALC_INVALID_VALUE;
self->sndHandle = sio_open(NULL, SIO_PLAY, 0);
if(self->sndHandle == NULL)
{
ERR("Could not open device\n");
return ALC_INVALID_VALUE;
}
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCsndioBackend_close(ALCsndioBackend *self)
{
sio_close(self->sndHandle);
self->sndHandle = NULL;
}
static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
struct sio_par par;
sio_initpar(&par);
par.rate = device->Frequency;
par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1);
switch(device->FmtType)
{
case DevFmtByte:
par.bits = 8;
par.sig = 1;
break;
case DevFmtUByte:
par.bits = 8;
par.sig = 0;
break;
case DevFmtFloat:
case DevFmtShort:
par.bits = 16;
par.sig = 1;
break;
case DevFmtUShort:
par.bits = 16;
par.sig = 0;
break;
case DevFmtInt:
par.bits = 32;
par.sig = 1;
break;
case DevFmtUInt:
par.bits = 32;
par.sig = 0;
break;
}
par.le = SIO_LE_NATIVE;
par.round = device->UpdateSize;
par.appbufsz = device->UpdateSize * (device->NumUpdates-1);
if(!par.appbufsz) par.appbufsz = device->UpdateSize;
if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par))
{
ERR("Failed to set device parameters\n");
return ALC_FALSE;
}
if(par.bits != par.bps*8)
{
ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8);
return ALC_FALSE;
}
device->Frequency = par.rate;
device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo);
if(par.bits == 8 && par.sig == 1)
device->FmtType = DevFmtByte;
else if(par.bits == 8 && par.sig == 0)
device->FmtType = DevFmtUByte;
else if(par.bits == 16 && par.sig == 1)
device->FmtType = DevFmtShort;
else if(par.bits == 16 && par.sig == 0)
device->FmtType = DevFmtUShort;
else if(par.bits == 32 && par.sig == 1)
device->FmtType = DevFmtInt;
else if(par.bits == 32 && par.sig == 0)
device->FmtType = DevFmtUInt;
else
{
ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits);
return ALC_FALSE;
}
device->UpdateSize = par.round;
device->NumUpdates = (par.bufsz/par.round) + 1;
SetDefaultChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
self->data_size = device->UpdateSize * FrameSizeFromDevFmt(
device->FmtChans, device->FmtType, device->AmbiOrder
);
al_free(self->mix_data);
self->mix_data = al_calloc(16, self->data_size);
if(!sio_start(self->sndHandle))
{
ERR("Error starting playback\n");
return ALC_FALSE;
}
self->killNow = 0;
if(althrd_create(&self->thread, ALCsndioBackend_mixerProc, self) != althrd_success)
{
sio_stop(self->sndHandle);
return ALC_FALSE;
}
return ALC_TRUE;
}
static void ALCsndioBackend_stop(ALCsndioBackend *self)
{
int res;
if(self->killNow)
return;
self->killNow = 1;
althrd_join(self->thread, &res);
if(!sio_stop(self->sndHandle))
ERR("Error stopping device\n");
al_free(self->mix_data);
self->mix_data = NULL;
}
typedef struct ALCsndioBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCsndioBackendFactory;
#define ALCSNDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsndioBackendFactory, ALCbackendFactory) } }
ALCbackendFactory *ALCsndioBackendFactory_getFactory(void);
static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory *self);
static DECLARE_FORWARD(ALCsndioBackendFactory, ALCbackendFactory, void, deinit)
static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory *self, ALCbackend_Type type);
static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsndioBackendFactory);
ALCbackendFactory *ALCsndioBackendFactory_getFactory(void)
{
static ALCsndioBackendFactory factory = ALCSNDIOBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory* UNUSED(self))
{
/* No dynamic loading */
return ALC_TRUE;
}
static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(sndio_device);
break;
case CAPTURE_DEVICE_PROBE:
break;
}
}
static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCsndioBackend *backend;
NEW_OBJ(backend, ALCsndioBackend)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
-363
View File
@@ -1,363 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <unistd.h>
#include <errno.h>
#include <math.h>
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "compat.h"
#include "backends/base.h"
#include <sys/audioio.h>
typedef struct ALCsolarisBackend {
DERIVE_FROM_TYPE(ALCbackend);
int fd;
ALubyte *mix_data;
int data_size;
ATOMIC(ALenum) killNow;
althrd_t thread;
} ALCsolarisBackend;
static int ALCsolarisBackend_mixerProc(void *ptr);
static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device);
static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self);
static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name);
static void ALCsolarisBackend_close(ALCsolarisBackend *self);
static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self);
static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self);
static void ALCsolarisBackend_stop(ALCsolarisBackend *self);
static DECLARE_FORWARD2(ALCsolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCsolarisBackend)
DEFINE_ALCBACKEND_VTABLE(ALCsolarisBackend);
static const ALCchar solaris_device[] = "Solaris Default";
static const char *solaris_driver = "/dev/audio";
static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCsolarisBackend, ALCbackend, self);
self->fd = -1;
ATOMIC_INIT(&self->killNow, AL_FALSE);
}
static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self)
{
if(self->fd != -1)
close(self->fd);
self->fd = -1;
free(self->mix_data);
self->mix_data = NULL;
self->data_size = 0;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCsolarisBackend_mixerProc(void *ptr)
{
ALCsolarisBackend *self = ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
struct timeval timeout;
ALubyte *write_ptr;
ALint frame_size;
ALint to_write;
ssize_t wrote;
fd_set wfds;
int sret;
SetRTPriority();
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
ALCsolarisBackend_lock(self);
while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected)
{
FD_ZERO(&wfds);
FD_SET(self->fd, &wfds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
ALCsolarisBackend_unlock(self);
sret = select(self->fd+1, NULL, &wfds, NULL, &timeout);
ALCsolarisBackend_lock(self);
if(sret < 0)
{
if(errno == EINTR)
continue;
ERR("select failed: %s\n", strerror(errno));
aluHandleDisconnect(device);
break;
}
else if(sret == 0)
{
WARN("select timeout\n");
continue;
}
write_ptr = self->mix_data;
to_write = self->data_size;
aluMixData(device, write_ptr, to_write/frame_size);
while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow))
{
wrote = write(self->fd, write_ptr, to_write);
if(wrote < 0)
{
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
continue;
ERR("write failed: %s\n", strerror(errno));
aluHandleDisconnect(device);
break;
}
to_write -= wrote;
write_ptr += wrote;
}
}
ALCsolarisBackend_unlock(self);
return 0;
}
static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name)
{
ALCdevice *device;
if(!name)
name = solaris_device;
else if(strcmp(name, solaris_device) != 0)
return ALC_INVALID_VALUE;
self->fd = open(solaris_driver, O_WRONLY);
if(self->fd == -1)
{
ERR("Could not open %s: %s\n", solaris_driver, strerror(errno));
return ALC_INVALID_VALUE;
}
device = STATIC_CAST(ALCbackend,self)->mDevice;
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCsolarisBackend_close(ALCsolarisBackend *self)
{
close(self->fd);
self->fd = -1;
}
static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
audio_info_t info;
ALsizei frameSize;
ALsizei numChannels;
AUDIO_INITINFO(&info);
info.play.sample_rate = device->Frequency;
if(device->FmtChans != DevFmtMono)
device->FmtChans = DevFmtStereo;
numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
info.play.channels = numChannels;
switch(device->FmtType)
{
case DevFmtByte:
info.play.precision = 8;
info.play.encoding = AUDIO_ENCODING_LINEAR;
break;
case DevFmtUByte:
info.play.precision = 8;
info.play.encoding = AUDIO_ENCODING_LINEAR8;
break;
case DevFmtUShort:
case DevFmtInt:
case DevFmtUInt:
case DevFmtFloat:
device->FmtType = DevFmtShort;
/* fall-through */
case DevFmtShort:
info.play.precision = 16;
info.play.encoding = AUDIO_ENCODING_LINEAR;
break;
}
frameSize = numChannels * BytesFromDevFmt(device->FmtType);
info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize;
if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0)
{
ERR("ioctl failed: %s\n", strerror(errno));
return ALC_FALSE;
}
if(ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)info.play.channels)
{
ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), info.play.channels);
return ALC_FALSE;
}
if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && device->FmtType == DevFmtUByte) ||
(info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtByte) ||
(info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtShort) ||
(info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtInt)))
{
ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(device->FmtType),
info.play.precision, info.play.encoding);
return ALC_FALSE;
}
device->Frequency = info.play.sample_rate;
device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1;
SetDefaultChannelOrder(device);
free(self->mix_data);
self->data_size = device->UpdateSize * FrameSizeFromDevFmt(
device->FmtChans, device->FmtType, device->AmbiOrder
);
self->mix_data = calloc(1, self->data_size);
return ALC_TRUE;
}
static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self)
{
ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE);
if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
}
static void ALCsolarisBackend_stop(ALCsolarisBackend *self)
{
int res;
if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE))
return;
althrd_join(self->thread, &res);
if(ioctl(self->fd, AUDIO_DRAIN) < 0)
ERR("Error draining device: %s\n", strerror(errno));
}
typedef struct ALCsolarisBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCsolarisBackendFactory;
#define ALCSOLARISBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsolarisBackendFactory, ALCbackendFactory) } }
ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory *self);
static DECLARE_FORWARD(ALCsolarisBackendFactory, ALCbackendFactory, void, deinit)
static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory *self, ALCbackend_Type type);
static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory);
ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void)
{
static ALCsolarisBackendFactory factory = ALCSOLARISBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory* UNUSED(self))
{
ConfigValueStr(NULL, "solaris", "device", &solaris_driver);
return ALC_TRUE;
}
static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
{
#ifdef HAVE_STAT
struct stat buf;
if(stat(solaris_driver, &buf) == 0)
#endif
AppendAllDevicesList(solaris_device);
}
break;
case CAPTURE_DEVICE_PROBE:
break;
}
}
ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCsolarisBackend *backend;
NEW_OBJ(backend, ALCsolarisBackend)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
-453
View File
@@ -1,453 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "compat.h"
#include "backends/base.h"
static const ALCchar waveDevice[] = "Wave File Writer";
static const ALubyte SUBTYPE_PCM[] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
0x00, 0x38, 0x9b, 0x71
};
static const ALubyte SUBTYPE_FLOAT[] = {
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
0x00, 0x38, 0x9b, 0x71
};
static const ALubyte SUBTYPE_BFORMAT_PCM[] = {
0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
0xca, 0x00, 0x00, 0x00
};
static const ALubyte SUBTYPE_BFORMAT_FLOAT[] = {
0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
0xca, 0x00, 0x00, 0x00
};
static void fwrite16le(ALushort val, FILE *f)
{
ALubyte data[2] = { val&0xff, (val>>8)&0xff };
fwrite(data, 1, 2, f);
}
static void fwrite32le(ALuint val, FILE *f)
{
ALubyte data[4] = { val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff };
fwrite(data, 1, 4, f);
}
typedef struct ALCwaveBackend {
DERIVE_FROM_TYPE(ALCbackend);
FILE *mFile;
long mDataStart;
ALvoid *mBuffer;
ALuint mSize;
volatile int killNow;
althrd_t thread;
} ALCwaveBackend;
static int ALCwaveBackend_mixerProc(void *ptr);
static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device);
static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, Destruct)
static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name);
static void ALCwaveBackend_close(ALCwaveBackend *self);
static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self);
static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self);
static void ALCwaveBackend_stop(ALCwaveBackend *self);
static DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend)
DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend);
static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCwaveBackend, ALCbackend, self);
self->mFile = NULL;
self->mDataStart = -1;
self->mBuffer = NULL;
self->mSize = 0;
self->killNow = 1;
}
static int ALCwaveBackend_mixerProc(void *ptr)
{
ALCwaveBackend *self = (ALCwaveBackend*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
struct timespec now, start;
ALint64 avail, done;
ALuint frameSize;
size_t fs;
const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 /
device->Frequency / 2);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
done = 0;
if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC)
{
ERR("Failed to get starting time\n");
return 1;
}
while(!self->killNow && device->Connected)
{
if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
{
ERR("Failed to get current time\n");
return 1;
}
avail = (now.tv_sec - start.tv_sec) * device->Frequency;
avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000;
if(avail < done)
{
/* Oops, time skipped backwards. Reset the number of samples done
* with one update available since we (likely) just came back from
* sleeping. */
done = avail - device->UpdateSize;
}
if(avail-done < device->UpdateSize)
al_nssleep(restTime);
else while(avail-done >= device->UpdateSize)
{
ALCwaveBackend_lock(self);
aluMixData(device, self->mBuffer, device->UpdateSize);
ALCwaveBackend_unlock(self);
done += device->UpdateSize;
if(!IS_LITTLE_ENDIAN)
{
ALuint bytesize = BytesFromDevFmt(device->FmtType);
ALuint i;
if(bytesize == 2)
{
ALushort *samples = self->mBuffer;
ALuint len = self->mSize / 2;
for(i = 0;i < len;i++)
{
ALushort samp = samples[i];
samples[i] = (samp>>8) | (samp<<8);
}
}
else if(bytesize == 4)
{
ALuint *samples = self->mBuffer;
ALuint len = self->mSize / 4;
for(i = 0;i < len;i++)
{
ALuint samp = samples[i];
samples[i] = (samp>>24) | ((samp>>8)&0x0000ff00) |
((samp<<8)&0x00ff0000) | (samp<<24);
}
}
}
fs = fwrite(self->mBuffer, frameSize, device->UpdateSize, self->mFile);
(void)fs;
if(ferror(self->mFile))
{
ERR("Error writing to file\n");
ALCdevice_Lock(device);
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
break;
}
}
}
return 0;
}
static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name)
{
ALCdevice *device;
const char *fname;
fname = GetConfigValue(NULL, "wave", "file", "");
if(!fname[0]) return ALC_INVALID_VALUE;
if(!name)
name = waveDevice;
else if(strcmp(name, waveDevice) != 0)
return ALC_INVALID_VALUE;
self->mFile = al_fopen(fname, "wb");
if(!self->mFile)
{
ERR("Could not open file '%s': %s\n", fname, strerror(errno));
return ALC_INVALID_VALUE;
}
device = STATIC_CAST(ALCbackend, self)->mDevice;
alstr_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCwaveBackend_close(ALCwaveBackend *self)
{
if(self->mFile)
fclose(self->mFile);
self->mFile = NULL;
}
static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALuint channels=0, bits=0, chanmask=0;
int isbformat = 0;
size_t val;
fseek(self->mFile, 0, SEEK_SET);
clearerr(self->mFile);
if(GetConfigValueBool(NULL, "wave", "bformat", 0))
{
device->FmtChans = DevFmtAmbi3D;
device->AmbiOrder = 1;
}
switch(device->FmtType)
{
case DevFmtByte:
device->FmtType = DevFmtUByte;
break;
case DevFmtUShort:
device->FmtType = DevFmtShort;
break;
case DevFmtUInt:
device->FmtType = DevFmtInt;
break;
case DevFmtUByte:
case DevFmtShort:
case DevFmtInt:
case DevFmtFloat:
break;
}
switch(device->FmtChans)
{
case DevFmtMono: chanmask = 0x04; break;
case DevFmtStereo: chanmask = 0x01 | 0x02; break;
case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break;
case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break;
case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break;
case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break;
case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
case DevFmtAmbi3D:
/* .amb output requires FuMa */
device->AmbiLayout = AmbiLayout_FuMa;
device->AmbiScale = AmbiNorm_FuMa;
isbformat = 1;
chanmask = 0;
break;
}
bits = BytesFromDevFmt(device->FmtType) * 8;
channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
fputs("RIFF", self->mFile);
fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close
fputs("WAVE", self->mFile);
fputs("fmt ", self->mFile);
fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE
// 16-bit val, format type id (extensible: 0xFFFE)
fwrite16le(0xFFFE, self->mFile);
// 16-bit val, channel count
fwrite16le(channels, self->mFile);
// 32-bit val, frequency
fwrite32le(device->Frequency, self->mFile);
// 32-bit val, bytes per second
fwrite32le(device->Frequency * channels * bits / 8, self->mFile);
// 16-bit val, frame size
fwrite16le(channels * bits / 8, self->mFile);
// 16-bit val, bits per sample
fwrite16le(bits, self->mFile);
// 16-bit val, extra byte count
fwrite16le(22, self->mFile);
// 16-bit val, valid bits per sample
fwrite16le(bits, self->mFile);
// 32-bit val, channel mask
fwrite32le(chanmask, self->mFile);
// 16 byte GUID, sub-type format
val = fwrite((device->FmtType == DevFmtFloat) ?
(isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
(isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, self->mFile);
(void)val;
fputs("data", self->mFile);
fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close
if(ferror(self->mFile))
{
ERR("Error writing header: %s\n", strerror(errno));
return ALC_FALSE;
}
self->mDataStart = ftell(self->mFile);
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
self->mSize = device->UpdateSize * FrameSizeFromDevFmt(
device->FmtChans, device->FmtType, device->AmbiOrder
);
self->mBuffer = malloc(self->mSize);
if(!self->mBuffer)
{
ERR("Buffer malloc failed\n");
return ALC_FALSE;
}
self->killNow = 0;
if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success)
{
free(self->mBuffer);
self->mBuffer = NULL;
self->mSize = 0;
return ALC_FALSE;
}
return ALC_TRUE;
}
static void ALCwaveBackend_stop(ALCwaveBackend *self)
{
ALuint dataLen;
long size;
int res;
if(self->killNow)
return;
self->killNow = 1;
althrd_join(self->thread, &res);
free(self->mBuffer);
self->mBuffer = NULL;
size = ftell(self->mFile);
if(size > 0)
{
dataLen = size - self->mDataStart;
if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0)
fwrite32le(dataLen, self->mFile); // 'data' header len
if(fseek(self->mFile, 4, SEEK_SET) == 0)
fwrite32le(size-8, self->mFile); // 'WAVE' header len
}
}
typedef struct ALCwaveBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCwaveBackendFactory;
#define ALCWAVEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) } }
ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self);
static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit)
static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type);
static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory);
ALCbackendFactory *ALCwaveBackendFactory_getFactory(void)
{
static ALCwaveBackendFactory factory = ALCWAVEBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory* UNUSED(self))
{
return ALC_TRUE;
}
static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
return !!ConfigValueExists(NULL, "wave", "file");
return ALC_FALSE;
}
static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(waveDevice);
break;
case CAPTURE_DEVICE_PROBE:
break;
}
}
static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCwaveBackend *backend;
NEW_OBJ(backend, ALCwaveBackend)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
-803
View File
@@ -1,803 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <windows.h>
#include <mmsystem.h>
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "backends/base.h"
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif
#define DEVNAME_HEAD "OpenAL Soft on "
static vector_al_string PlaybackDevices;
static vector_al_string CaptureDevices;
static void clear_devlist(vector_al_string *list)
{
VECTOR_FOR_EACH(al_string, *list, alstr_reset);
VECTOR_RESIZE(*list, 0, 0);
}
static void ProbePlaybackDevices(void)
{
ALuint numdevs;
ALuint i;
clear_devlist(&PlaybackDevices);
numdevs = waveOutGetNumDevs();
VECTOR_RESIZE(PlaybackDevices, 0, numdevs);
for(i = 0;i < numdevs;i++)
{
WAVEOUTCAPSW WaveCaps;
const al_string *iter;
al_string dname;
AL_STRING_INIT(dname);
if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
{
ALuint count = 0;
while(1)
{
alstr_copy_cstr(&dname, DEVNAME_HEAD);
alstr_append_wcstr(&dname, WaveCaps.szPname);
if(count != 0)
{
char str[64];
snprintf(str, sizeof(str), " #%d", count+1);
alstr_append_cstr(&dname, str);
}
count++;
#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0)
VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_ENTRY);
if(iter == VECTOR_END(PlaybackDevices)) break;
#undef MATCH_ENTRY
}
TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i);
}
VECTOR_PUSH_BACK(PlaybackDevices, dname);
}
}
static void ProbeCaptureDevices(void)
{
ALuint numdevs;
ALuint i;
clear_devlist(&CaptureDevices);
numdevs = waveInGetNumDevs();
VECTOR_RESIZE(CaptureDevices, 0, numdevs);
for(i = 0;i < numdevs;i++)
{
WAVEINCAPSW WaveCaps;
const al_string *iter;
al_string dname;
AL_STRING_INIT(dname);
if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
{
ALuint count = 0;
while(1)
{
alstr_copy_cstr(&dname, DEVNAME_HEAD);
alstr_append_wcstr(&dname, WaveCaps.szPname);
if(count != 0)
{
char str[64];
snprintf(str, sizeof(str), " #%d", count+1);
alstr_append_cstr(&dname, str);
}
count++;
#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0)
VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY);
if(iter == VECTOR_END(CaptureDevices)) break;
#undef MATCH_ENTRY
}
TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i);
}
VECTOR_PUSH_BACK(CaptureDevices, dname);
}
}
typedef struct ALCwinmmPlayback {
DERIVE_FROM_TYPE(ALCbackend);
RefCount WaveBuffersCommitted;
WAVEHDR WaveBuffer[4];
HWAVEOUT OutHdl;
WAVEFORMATEX Format;
volatile ALboolean killNow;
althrd_t thread;
} ALCwinmmPlayback;
static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device);
static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self);
static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2);
static int ALCwinmmPlayback_mixerProc(void *arg);
static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name);
static void ALCwinmmPlayback_close(ALCwinmmPlayback *self);
static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self);
static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self);
static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self);
static DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback)
DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback);
static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self);
InitRef(&self->WaveBuffersCommitted, 0);
self->OutHdl = NULL;
self->killNow = AL_TRUE;
}
static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self)
{
if(self->OutHdl)
waveOutClose(self->OutHdl);
self->OutHdl = 0;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
/* ALCwinmmPlayback_waveOutProc
*
* Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer
* is completed and returns to the application (for more data)
*/
static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
{
ALCwinmmPlayback *self = (ALCwinmmPlayback*)instance;
if(msg != WOM_DONE)
return;
DecrementRef(&self->WaveBuffersCommitted);
PostThreadMessage(self->thread, msg, 0, param1);
}
FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg)
{
ALCwinmmPlayback *self = arg;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
WAVEHDR *WaveHdr;
MSG msg;
SetRTPriority();
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
while(GetMessage(&msg, NULL, 0, 0))
{
if(msg.message != WOM_DONE)
continue;
if(self->killNow)
{
if(ReadRef(&self->WaveBuffersCommitted) == 0)
break;
continue;
}
WaveHdr = ((WAVEHDR*)msg.lParam);
ALCwinmmPlayback_lock(self);
aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength /
self->Format.nBlockAlign);
ALCwinmmPlayback_unlock(self);
// Send buffer back to play more data
waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR));
IncrementRef(&self->WaveBuffersCommitted);
}
return 0;
}
static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
const al_string *iter;
UINT DeviceID;
MMRESULT res;
if(VECTOR_SIZE(PlaybackDevices) == 0)
ProbePlaybackDevices();
// Find the Device ID matching the deviceName if valid
#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && \
(!deviceName || alstr_cmp_cstr(*(iter), deviceName) == 0))
VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME);
if(iter == VECTOR_END(PlaybackDevices))
return ALC_INVALID_VALUE;
#undef MATCH_DEVNAME
DeviceID = (UINT)(iter - VECTOR_BEGIN(PlaybackDevices));
retry_open:
memset(&self->Format, 0, sizeof(WAVEFORMATEX));
if(device->FmtType == DevFmtFloat)
{
self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
self->Format.wBitsPerSample = 32;
}
else
{
self->Format.wFormatTag = WAVE_FORMAT_PCM;
if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte)
self->Format.wBitsPerSample = 8;
else
self->Format.wBitsPerSample = 16;
}
self->Format.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2);
self->Format.nBlockAlign = self->Format.wBitsPerSample *
self->Format.nChannels / 8;
self->Format.nSamplesPerSec = device->Frequency;
self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec *
self->Format.nBlockAlign;
self->Format.cbSize = 0;
if((res=waveOutOpen(&self->OutHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
{
if(device->FmtType == DevFmtFloat)
{
device->FmtType = DevFmtShort;
goto retry_open;
}
ERR("waveOutOpen failed: %u\n", res);
goto failure;
}
alstr_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID));
return ALC_NO_ERROR;
failure:
if(self->OutHdl)
waveOutClose(self->OutHdl);
self->OutHdl = NULL;
return ALC_INVALID_VALUE;
}
static void ALCwinmmPlayback_close(ALCwinmmPlayback* UNUSED(self))
{ }
static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
self->Format.nSamplesPerSec /
device->Frequency);
device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4;
device->NumUpdates = 4;
device->Frequency = self->Format.nSamplesPerSec;
if(self->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
{
if(self->Format.wBitsPerSample == 32)
device->FmtType = DevFmtFloat;
else
{
ERR("Unhandled IEEE float sample depth: %d\n", self->Format.wBitsPerSample);
return ALC_FALSE;
}
}
else if(self->Format.wFormatTag == WAVE_FORMAT_PCM)
{
if(self->Format.wBitsPerSample == 16)
device->FmtType = DevFmtShort;
else if(self->Format.wBitsPerSample == 8)
device->FmtType = DevFmtUByte;
else
{
ERR("Unhandled PCM sample depth: %d\n", self->Format.wBitsPerSample);
return ALC_FALSE;
}
}
else
{
ERR("Unhandled format tag: 0x%04x\n", self->Format.wFormatTag);
return ALC_FALSE;
}
if(self->Format.nChannels == 2)
device->FmtChans = DevFmtStereo;
else if(self->Format.nChannels == 1)
device->FmtChans = DevFmtMono;
else
{
ERR("Unhandled channel count: %d\n", self->Format.nChannels);
return ALC_FALSE;
}
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALbyte *BufferData;
ALint BufferSize;
ALuint i;
self->killNow = AL_FALSE;
if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success)
return ALC_FALSE;
InitRef(&self->WaveBuffersCommitted, 0);
// Create 4 Buffers
BufferSize = device->UpdateSize*device->NumUpdates / 4;
BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
BufferData = calloc(4, BufferSize);
for(i = 0;i < 4;i++)
{
memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR));
self->WaveBuffer[i].dwBufferLength = BufferSize;
self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
(self->WaveBuffer[i-1].lpData +
self->WaveBuffer[i-1].dwBufferLength));
waveOutPrepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
waveOutWrite(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
IncrementRef(&self->WaveBuffersCommitted);
}
return ALC_TRUE;
}
static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self)
{
void *buffer = NULL;
int i;
if(self->killNow)
return;
// Set flag to stop processing headers
self->killNow = AL_TRUE;
althrd_join(self->thread, &i);
// Release the wave buffers
for(i = 0;i < 4;i++)
{
waveOutUnprepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
if(i == 0) buffer = self->WaveBuffer[i].lpData;
self->WaveBuffer[i].lpData = NULL;
}
free(buffer);
}
typedef struct ALCwinmmCapture {
DERIVE_FROM_TYPE(ALCbackend);
RefCount WaveBuffersCommitted;
WAVEHDR WaveBuffer[4];
HWAVEIN InHdl;
ll_ringbuffer_t *Ring;
WAVEFORMATEX Format;
volatile ALboolean killNow;
althrd_t thread;
} ALCwinmmCapture;
static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device);
static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self);
static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2);
static int ALCwinmmCapture_captureProc(void *arg);
static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name);
static void ALCwinmmCapture_close(ALCwinmmCapture *self);
static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset)
static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self);
static void ALCwinmmCapture_stop(ALCwinmmCapture *self);
static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self);
static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ClockLatency, getClockLatency)
static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture)
DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture);
static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCwinmmCapture, ALCbackend, self);
InitRef(&self->WaveBuffersCommitted, 0);
self->InHdl = NULL;
self->killNow = AL_TRUE;
}
static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self)
{
if(self->InHdl)
waveInClose(self->InHdl);
self->InHdl = 0;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
/* ALCwinmmCapture_waveInProc
*
* Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer
* is completed and returns to the application (with more data).
*/
static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
{
ALCwinmmCapture *self = (ALCwinmmCapture*)instance;
if(msg != WIM_DATA)
return;
DecrementRef(&self->WaveBuffersCommitted);
PostThreadMessage(self->thread, msg, 0, param1);
}
static int ALCwinmmCapture_captureProc(void *arg)
{
ALCwinmmCapture *self = arg;
WAVEHDR *WaveHdr;
MSG msg;
althrd_setname(althrd_current(), RECORD_THREAD_NAME);
while(GetMessage(&msg, NULL, 0, 0))
{
if(msg.message != WIM_DATA)
continue;
/* Don't wait for other buffers to finish before quitting. We're
* closing so we don't need them. */
if(self->killNow)
break;
WaveHdr = ((WAVEHDR*)msg.lParam);
ll_ringbuffer_write(self->Ring, WaveHdr->lpData,
WaveHdr->dwBytesRecorded / self->Format.nBlockAlign
);
// Send buffer back to capture more data
waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR));
IncrementRef(&self->WaveBuffersCommitted);
}
return 0;
}
static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
const al_string *iter;
ALbyte *BufferData = NULL;
DWORD CapturedDataSize;
ALint BufferSize;
UINT DeviceID;
MMRESULT res;
ALuint i;
if(VECTOR_SIZE(CaptureDevices) == 0)
ProbeCaptureDevices();
// Find the Device ID matching the deviceName if valid
#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && (!name || alstr_cmp_cstr(*iter, name) == 0))
VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME);
if(iter == VECTOR_END(CaptureDevices))
return ALC_INVALID_VALUE;
#undef MATCH_DEVNAME
DeviceID = (UINT)(iter - VECTOR_BEGIN(CaptureDevices));
switch(device->FmtChans)
{
case DevFmtMono:
case DevFmtStereo:
break;
case DevFmtQuad:
case DevFmtX51:
case DevFmtX51Rear:
case DevFmtX61:
case DevFmtX71:
case DevFmtAmbi3D:
return ALC_INVALID_ENUM;
}
switch(device->FmtType)
{
case DevFmtUByte:
case DevFmtShort:
case DevFmtInt:
case DevFmtFloat:
break;
case DevFmtByte:
case DevFmtUShort:
case DevFmtUInt:
return ALC_INVALID_ENUM;
}
memset(&self->Format, 0, sizeof(WAVEFORMATEX));
self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ?
WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
self->Format.nBlockAlign = self->Format.wBitsPerSample *
self->Format.nChannels / 8;
self->Format.nSamplesPerSec = device->Frequency;
self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec *
self->Format.nBlockAlign;
self->Format.cbSize = 0;
if((res=waveInOpen(&self->InHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
{
ERR("waveInOpen failed: %u\n", res);
goto failure;
}
// Allocate circular memory buffer for the captured audio
CapturedDataSize = device->UpdateSize*device->NumUpdates;
// Make sure circular buffer is at least 100ms in size
if(CapturedDataSize < (self->Format.nSamplesPerSec / 10))
CapturedDataSize = self->Format.nSamplesPerSec / 10;
self->Ring = ll_ringbuffer_create(CapturedDataSize+1, self->Format.nBlockAlign);
if(!self->Ring) goto failure;
InitRef(&self->WaveBuffersCommitted, 0);
// Create 4 Buffers of 50ms each
BufferSize = self->Format.nAvgBytesPerSec / 20;
BufferSize -= (BufferSize % self->Format.nBlockAlign);
BufferData = calloc(4, BufferSize);
if(!BufferData) goto failure;
for(i = 0;i < 4;i++)
{
memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR));
self->WaveBuffer[i].dwBufferLength = BufferSize;
self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
(self->WaveBuffer[i-1].lpData +
self->WaveBuffer[i-1].dwBufferLength));
self->WaveBuffer[i].dwFlags = 0;
self->WaveBuffer[i].dwLoops = 0;
waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
IncrementRef(&self->WaveBuffersCommitted);
}
self->killNow = AL_FALSE;
if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success)
goto failure;
alstr_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID));
return ALC_NO_ERROR;
failure:
if(BufferData)
{
for(i = 0;i < 4;i++)
waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
free(BufferData);
}
ll_ringbuffer_free(self->Ring);
self->Ring = NULL;
if(self->InHdl)
waveInClose(self->InHdl);
self->InHdl = NULL;
return ALC_INVALID_VALUE;
}
static void ALCwinmmCapture_close(ALCwinmmCapture *self)
{
void *buffer = NULL;
int i;
/* Tell the processing thread to quit and wait for it to do so. */
self->killNow = AL_TRUE;
PostThreadMessage(self->thread, WM_QUIT, 0, 0);
althrd_join(self->thread, &i);
/* Make sure capture is stopped and all pending buffers are flushed. */
waveInReset(self->InHdl);
// Release the wave buffers
for(i = 0;i < 4;i++)
{
waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
if(i == 0) buffer = self->WaveBuffer[i].lpData;
self->WaveBuffer[i].lpData = NULL;
}
free(buffer);
ll_ringbuffer_free(self->Ring);
self->Ring = NULL;
// Close the Wave device
waveInClose(self->InHdl);
self->InHdl = NULL;
}
static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self)
{
waveInStart(self->InHdl);
return ALC_TRUE;
}
static void ALCwinmmCapture_stop(ALCwinmmCapture *self)
{
waveInStop(self->InHdl);
}
static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples)
{
ll_ringbuffer_read(self->Ring, buffer, samples);
return ALC_NO_ERROR;
}
static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self)
{
return ll_ringbuffer_read_space(self->Ring);
}
static inline void AppendAllDevicesList2(const al_string *name)
{
if(!alstr_empty(*name))
AppendAllDevicesList(alstr_get_cstr(*name));
}
static inline void AppendCaptureDeviceList2(const al_string *name)
{
if(!alstr_empty(*name))
AppendCaptureDeviceList(alstr_get_cstr(*name));
}
typedef struct ALCwinmmBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCwinmmBackendFactory;
#define ALCWINMMBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) } }
static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory *self);
static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory *self);
static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory *self, ALCbackend_Type type);
static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory);
static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory* UNUSED(self))
{
VECTOR_INIT(PlaybackDevices);
VECTOR_INIT(CaptureDevices);
return ALC_TRUE;
}
static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory* UNUSED(self))
{
clear_devlist(&PlaybackDevices);
VECTOR_DEINIT(PlaybackDevices);
clear_devlist(&CaptureDevices);
VECTOR_DEINIT(CaptureDevices);
}
static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback || type == ALCbackend_Capture)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
ProbePlaybackDevices();
VECTOR_FOR_EACH(const al_string, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
ProbeCaptureDevices();
VECTOR_FOR_EACH(const al_string, CaptureDevices, AppendCaptureDeviceList2);
break;
}
}
static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCwinmmPlayback *backend;
NEW_OBJ(backend, ALCwinmmPlayback)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCwinmmCapture *backend;
NEW_OBJ(backend, ALCwinmmCapture)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void)
{
static ALCwinmmBackendFactory factory = ALCWINMMBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
-612
View File
@@ -1,612 +0,0 @@
#include "config.h"
#include "bformatdec.h"
#include "ambdec.h"
#include "mixer_defs.h"
#include "alu.h"
#include "bool.h"
#include "threads.h"
#include "almalloc.h"
void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult)
{
ALfloat w = freq_mult * F_TAU;
ALfloat cw = cosf(w);
if(cw > FLT_EPSILON)
splitter->coeff = (sinf(w) - 1.0f) / cw;
else
splitter->coeff = cw * -0.5f;
splitter->lp_z1 = 0.0f;
splitter->lp_z2 = 0.0f;
splitter->hp_z1 = 0.0f;
}
void bandsplit_clear(BandSplitter *splitter)
{
splitter->lp_z1 = 0.0f;
splitter->lp_z2 = 0.0f;
splitter->hp_z1 = 0.0f;
}
void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout,
const ALfloat *input, ALsizei count)
{
ALfloat coeff, d, x;
ALfloat z1, z2;
ALsizei i;
coeff = splitter->coeff*0.5f + 0.5f;
z1 = splitter->lp_z1;
z2 = splitter->lp_z2;
for(i = 0;i < count;i++)
{
x = input[i];
d = (x - z1) * coeff;
x = z1 + d;
z1 = x + d;
d = (x - z2) * coeff;
x = z2 + d;
z2 = x + d;
lpout[i] = x;
}
splitter->lp_z1 = z1;
splitter->lp_z2 = z2;
coeff = splitter->coeff;
z1 = splitter->hp_z1;
for(i = 0;i < count;i++)
{
x = input[i];
d = x - coeff*z1;
x = z1 + coeff*d;
z1 = d;
hpout[i] = x - lpout[i];
}
splitter->hp_z1 = z1;
}
void splitterap_init(SplitterAllpass *splitter, ALfloat freq_mult)
{
ALfloat w = freq_mult * F_TAU;
ALfloat cw = cosf(w);
if(cw > FLT_EPSILON)
splitter->coeff = (sinf(w) - 1.0f) / cw;
else
splitter->coeff = cw * -0.5f;
splitter->z1 = 0.0f;
}
void splitterap_clear(SplitterAllpass *splitter)
{
splitter->z1 = 0.0f;
}
void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count)
{
ALfloat coeff, d, x;
ALfloat z1;
ALsizei i;
coeff = splitter->coeff;
z1 = splitter->z1;
for(i = 0;i < count;i++)
{
x = samples[i];
d = x - coeff*z1;
x = z1 + coeff*d;
z1 = d;
samples[i] = x;
}
splitter->z1 = z1;
}
static const ALfloat UnitScale[MAX_AMBI_COEFFS] = {
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
};
static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
1.000000000f, /* ACN 0 (W), sqrt(1) */
1.732050808f, /* ACN 1 (Y), sqrt(3) */
1.732050808f, /* ACN 2 (Z), sqrt(3) */
1.732050808f, /* ACN 3 (X), sqrt(3) */
2.236067978f, /* ACN 4 (V), sqrt(5) */
2.236067978f, /* ACN 5 (T), sqrt(5) */
2.236067978f, /* ACN 6 (R), sqrt(5) */
2.236067978f, /* ACN 7 (S), sqrt(5) */
2.236067978f, /* ACN 8 (U), sqrt(5) */
2.645751311f, /* ACN 9 (Q), sqrt(7) */
2.645751311f, /* ACN 10 (O), sqrt(7) */
2.645751311f, /* ACN 11 (M), sqrt(7) */
2.645751311f, /* ACN 12 (K), sqrt(7) */
2.645751311f, /* ACN 13 (L), sqrt(7) */
2.645751311f, /* ACN 14 (N), sqrt(7) */
2.645751311f, /* ACN 15 (P), sqrt(7) */
};
static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
1.414213562f, /* ACN 0 (W), sqrt(2) */
1.732050808f, /* ACN 1 (Y), sqrt(3) */
1.732050808f, /* ACN 2 (Z), sqrt(3) */
1.732050808f, /* ACN 3 (X), sqrt(3) */
1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
2.236067978f, /* ACN 6 (R), sqrt(5) */
1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
2.231093404f, /* ACN 11 (M), sqrt(224/45) */
2.645751311f, /* ACN 12 (K), sqrt(7) */
2.231093404f, /* ACN 13 (L), sqrt(224/45) */
1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
2.091650066f, /* ACN 15 (P), sqrt(35/8) */
};
enum FreqBand {
FB_HighFreq,
FB_LowFreq,
FB_Max
};
/* These points are in AL coordinates! */
static const ALfloat Ambi3DPoints[8][3] = {
{ -0.577350269f, 0.577350269f, -0.577350269f },
{ 0.577350269f, 0.577350269f, -0.577350269f },
{ -0.577350269f, 0.577350269f, 0.577350269f },
{ 0.577350269f, 0.577350269f, 0.577350269f },
{ -0.577350269f, -0.577350269f, -0.577350269f },
{ 0.577350269f, -0.577350269f, -0.577350269f },
{ -0.577350269f, -0.577350269f, 0.577350269f },
{ 0.577350269f, -0.577350269f, 0.577350269f },
};
static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = {
{ { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } },
{ { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } },
{ { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } },
{ { 0.25f, -0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, 0.125f, -0.125f } },
{ { 0.25f, 0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, -0.125f, 0.125f } },
{ { 0.25f, -0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, -0.125f, 0.125f } },
{ { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } },
{ { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } },
};
static RowMixerFunc MixMatrixRow = MixRow_C;
static alonce_flag bformatdec_inited = AL_ONCE_FLAG_INIT;
static void init_bformatdec(void)
{
MixMatrixRow = SelectRowMixer();
}
/* NOTE: BandSplitter filters are unused with single-band decoding */
typedef struct BFormatDec {
ALboolean Enabled[MAX_OUTPUT_CHANNELS];
union {
alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][FB_Max][MAX_AMBI_COEFFS];
alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
} Matrix;
BandSplitter XOver[MAX_AMBI_COEFFS];
ALfloat (*Samples)[BUFFERSIZE];
/* These two alias into Samples */
ALfloat (*SamplesHF)[BUFFERSIZE];
ALfloat (*SamplesLF)[BUFFERSIZE];
alignas(16) ALfloat ChannelMix[BUFFERSIZE];
struct {
BandSplitter XOver;
ALfloat Gains[FB_Max];
} UpSampler[4];
ALsizei NumChannels;
ALboolean DualBand;
} BFormatDec;
BFormatDec *bformatdec_alloc()
{
alcall_once(&bformatdec_inited, init_bformatdec);
return al_calloc(16, sizeof(BFormatDec));
}
void bformatdec_free(BFormatDec *dec)
{
if(dec)
{
al_free(dec->Samples);
dec->Samples = NULL;
dec->SamplesHF = NULL;
dec->SamplesLF = NULL;
memset(dec, 0, sizeof(*dec));
al_free(dec);
}
}
void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS])
{
static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = {
0, 1, 3, 4, 8, 9, 15
};
const ALfloat *coeff_scale = UnitScale;
bool periphonic;
ALfloat ratio;
ALsizei i;
al_free(dec->Samples);
dec->Samples = NULL;
dec->SamplesHF = NULL;
dec->SamplesLF = NULL;
dec->NumChannels = chancount;
dec->Samples = al_calloc(16, dec->NumChannels*2 * sizeof(dec->Samples[0]));
dec->SamplesHF = dec->Samples;
dec->SamplesLF = dec->SamplesHF + dec->NumChannels;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
dec->Enabled[i] = AL_FALSE;
for(i = 0;i < conf->NumSpeakers;i++)
dec->Enabled[chanmap[i]] = AL_TRUE;
if(conf->CoeffScale == ADS_SN3D)
coeff_scale = SN3D2N3DScale;
else if(conf->CoeffScale == ADS_FuMa)
coeff_scale = FuMa2N3DScale;
memset(dec->UpSampler, 0, sizeof(dec->UpSampler));
ratio = 400.0f / (ALfloat)srate;
for(i = 0;i < 4;i++)
bandsplit_init(&dec->UpSampler[i].XOver, ratio);
if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
{
periphonic = true;
dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? W_SCALE3D_THIRD :
(dec->NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f;
dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f;
for(i = 1;i < 4;i++)
{
dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? XYZ_SCALE3D_THIRD :
(dec->NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f;
dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f;
}
}
else
{
periphonic = false;
dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? W_SCALE2D_THIRD :
(dec->NumChannels > 3) ? W_SCALE2D_SECOND : 1.0f;
dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f;
for(i = 1;i < 3;i++)
{
dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? XYZ_SCALE2D_THIRD :
(dec->NumChannels > 3) ? XYZ_SCALE2D_SECOND : 1.0f;
dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f;
}
dec->UpSampler[3].Gains[FB_HighFreq] = 0.0f;
dec->UpSampler[3].Gains[FB_LowFreq] = 0.0f;
}
memset(&dec->Matrix, 0, sizeof(dec->Matrix));
if(conf->FreqBands == 1)
{
dec->DualBand = AL_FALSE;
for(i = 0;i < conf->NumSpeakers;i++)
{
ALsizei chan = chanmap[i];
ALfloat gain;
ALsizei j, k;
if(!periphonic)
{
for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
{
ALsizei l = map2DTo3D[j];
if(j == 0) gain = conf->HFOrderGain[0];
else if(j == 1) gain = conf->HFOrderGain[1];
else if(j == 3) gain = conf->HFOrderGain[2];
else if(j == 5) gain = conf->HFOrderGain[3];
if((conf->ChanMask&(1<<l)))
dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
gain;
}
}
else
{
for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
{
if(j == 0) gain = conf->HFOrderGain[0];
else if(j == 1) gain = conf->HFOrderGain[1];
else if(j == 4) gain = conf->HFOrderGain[2];
else if(j == 9) gain = conf->HFOrderGain[3];
if((conf->ChanMask&(1<<j)))
dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
gain;
}
}
}
}
else
{
dec->DualBand = AL_TRUE;
ratio = conf->XOverFreq / (ALfloat)srate;
for(i = 0;i < MAX_AMBI_COEFFS;i++)
bandsplit_init(&dec->XOver[i], ratio);
ratio = powf(10.0f, conf->XOverRatio / 40.0f);
for(i = 0;i < conf->NumSpeakers;i++)
{
ALsizei chan = chanmap[i];
ALfloat gain;
ALsizei j, k;
if(!periphonic)
{
for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
{
ALsizei l = map2DTo3D[j];
if(j == 0) gain = conf->HFOrderGain[0] * ratio;
else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
if((conf->ChanMask&(1<<l)))
dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
coeff_scale[l] * gain;
}
for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
{
ALsizei l = map2DTo3D[j];
if(j == 0) gain = conf->LFOrderGain[0] / ratio;
else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
if((conf->ChanMask&(1<<l)))
dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
coeff_scale[l] * gain;
}
}
else
{
for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
{
if(j == 0) gain = conf->HFOrderGain[0] * ratio;
else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
if((conf->ChanMask&(1<<j)))
dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
coeff_scale[j] * gain;
}
for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
{
if(j == 0) gain = conf->LFOrderGain[0] / ratio;
else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
if((conf->ChanMask&(1<<j)))
dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
coeff_scale[j] * gain;
}
}
}
}
}
void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
{
ALsizei chan, i;
OutBuffer = ASSUME_ALIGNED(OutBuffer, 16);
if(dec->DualBand)
{
for(i = 0;i < dec->NumChannels;i++)
bandsplit_process(&dec->XOver[i], dec->SamplesHF[i], dec->SamplesLF[i],
InSamples[i], SamplesToDo);
for(chan = 0;chan < OutChannels;chan++)
{
if(!dec->Enabled[chan])
continue;
memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq],
SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesHF), dec->NumChannels, 0,
SamplesToDo
);
MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq],
SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesLF), dec->NumChannels, 0,
SamplesToDo
);
for(i = 0;i < SamplesToDo;i++)
OutBuffer[chan][i] += dec->ChannelMix[i];
}
}
else
{
for(chan = 0;chan < OutChannels;chan++)
{
if(!dec->Enabled[chan])
continue;
memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
MixMatrixRow(dec->ChannelMix, dec->Matrix.Single[chan], InSamples,
dec->NumChannels, 0, SamplesToDo);
for(i = 0;i < SamplesToDo;i++)
OutBuffer[chan][i] += dec->ChannelMix[i];
}
}
}
void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo)
{
ALsizei i;
/* This up-sampler leverages the differences observed in dual-band second-
* and third-order decoder matrices compared to first-order. For the same
* output channel configuration, the low-frequency matrix has identical
* coefficients in the shared input channels, while the high-frequency
* matrix has extra scalars applied to the W channel and X/Y/Z channels.
* Mixing the first-order content into the higher-order stream with the
* appropriate counter-scales applied to the HF response results in the
* subsequent higher-order decode generating the same response as a first-
* order decode.
*/
for(i = 0;i < InChannels;i++)
{
/* First, split the first-order components into low and high frequency
* bands.
*/
bandsplit_process(&dec->UpSampler[i].XOver,
dec->Samples[FB_HighFreq], dec->Samples[FB_LowFreq],
InSamples[i], SamplesToDo
);
/* Now write each band to the output. */
MixMatrixRow(OutBuffer[i], dec->UpSampler[i].Gains,
SAFE_CONST(ALfloatBUFFERSIZE*,dec->Samples), FB_Max, 0,
SamplesToDo
);
}
}
#define INVALID_UPSAMPLE_INDEX INT_MAX
static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn)
{
ALsizei i;
for(i = 0;i < numchans;i++)
{
if(chans[i].Index == acn)
return i;
}
return INVALID_UPSAMPLE_INDEX;
}
#define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
typedef struct AmbiUpsampler {
alignas(16) ALfloat Samples[FB_Max][BUFFERSIZE];
BandSplitter XOver[4];
ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max];
} AmbiUpsampler;
AmbiUpsampler *ambiup_alloc()
{
alcall_once(&bformatdec_inited, init_bformatdec);
return al_calloc(16, sizeof(AmbiUpsampler));
}
void ambiup_free(struct AmbiUpsampler *ambiup)
{
al_free(ambiup);
}
void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device)
{
ALfloat ratio;
size_t i;
ratio = 400.0f / (ALfloat)device->Frequency;
for(i = 0;i < 4;i++)
bandsplit_init(&ambiup->XOver[i], ratio);
memset(ambiup->Gains, 0, sizeof(ambiup->Gains));
if(device->Dry.CoeffCount > 0)
{
ALfloat encgains[8][MAX_OUTPUT_CHANNELS];
ALsizei j;
size_t k;
for(i = 0;i < COUNTOF(Ambi3DPoints);i++)
{
ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f };
CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, coeffs);
ComputePanningGains(device->Dry, coeffs, 1.0f, encgains[i]);
}
/* Combine the matrices that do the in->virt and virt->out conversions
* so we get a single in->out conversion. NOTE: the Encoder matrix
* (encgains) and output are transposed, so the input channels line up
* with the rows and the output channels line up with the columns.
*/
for(i = 0;i < 4;i++)
{
for(j = 0;j < device->Dry.NumChannels;j++)
{
ALfloat hfgain=0.0f, lfgain=0.0f;
for(k = 0;k < COUNTOF(Ambi3DDecoder);k++)
{
hfgain += Ambi3DDecoder[k][FB_HighFreq][i]*encgains[k][j];
lfgain += Ambi3DDecoder[k][FB_LowFreq][i]*encgains[k][j];
}
ambiup->Gains[i][j][FB_HighFreq] = hfgain;
ambiup->Gains[i][j][FB_LowFreq] = lfgain;
}
}
}
else
{
/* Assumes full 3D/periphonic on the input and output mixes! */
ALfloat w_scale = (device->Dry.NumChannels > 9) ? W_SCALE3D_THIRD :
(device->Dry.NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f;
ALfloat xyz_scale = (device->Dry.NumChannels > 9) ? XYZ_SCALE3D_THIRD :
(device->Dry.NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f;
for(i = 0;i < 4;i++)
{
ALsizei index = GetChannelForACN(device->Dry, i);
if(index != INVALID_UPSAMPLE_INDEX)
{
ALfloat scale = device->Dry.Ambi.Map[index].Scale;
ambiup->Gains[i][index][FB_HighFreq] = scale * ((i==0) ? w_scale : xyz_scale);
ambiup->Gains[i][index][FB_LowFreq] = scale;
}
}
}
}
void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
{
ALsizei i, j;
for(i = 0;i < 4;i++)
{
bandsplit_process(&ambiup->XOver[i],
ambiup->Samples[FB_HighFreq], ambiup->Samples[FB_LowFreq],
InSamples[i], SamplesToDo
);
for(j = 0;j < OutChannels;j++)
MixMatrixRow(OutBuffer[j], ambiup->Gains[i][j],
SAFE_CONST(ALfloatBUFFERSIZE*,ambiup->Samples), FB_Max, 0,
SamplesToDo
);
}
}
-75
View File
@@ -1,75 +0,0 @@
#ifndef BFORMATDEC_H
#define BFORMATDEC_H
#include "alMain.h"
/* These are the necessary scales for first-order HF responses to play over
* higher-order 2D (non-periphonic) decoders.
*/
#define W_SCALE2D_SECOND 1.224744871f /* sqrt(1.5) */
#define XYZ_SCALE2D_SECOND 1.0f
#define W_SCALE2D_THIRD 1.414213562f /* sqrt(2) */
#define XYZ_SCALE2D_THIRD 1.082392196f
/* These are the necessary scales for first-order HF responses to play over
* higher-order 3D (periphonic) decoders.
*/
#define W_SCALE3D_SECOND 1.341640787f /* sqrt(1.8) */
#define XYZ_SCALE3D_SECOND 1.0f
#define W_SCALE3D_THIRD 1.695486018f
#define XYZ_SCALE3D_THIRD 1.136697713f
struct AmbDecConf;
struct BFormatDec;
struct AmbiUpsampler;
struct BFormatDec *bformatdec_alloc();
void bformatdec_free(struct BFormatDec *dec);
void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]);
/* Decodes the ambisonic input to the given output channels. */
void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo);
/* Up-samples a first-order input to the decoder's configuration. */
void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo);
/* Stand-alone first-order upsampler. Kept here because it shares some stuff
* with bformatdec.
*/
struct AmbiUpsampler *ambiup_alloc();
void ambiup_free(struct AmbiUpsampler *ambiup);
void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device);
void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo);
/* Band splitter. Splits a signal into two phase-matching frequency bands. */
typedef struct BandSplitter {
ALfloat coeff;
ALfloat lp_z1;
ALfloat lp_z2;
ALfloat hp_z1;
} BandSplitter;
void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult);
void bandsplit_clear(BandSplitter *splitter);
void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout,
const ALfloat *input, ALsizei count);
/* The all-pass portion of the band splitter. Applies the same phase shift
* without splitting the signal.
*/
typedef struct SplitterAllpass {
ALfloat coeff;
ALfloat z1;
} SplitterAllpass;
void splitterap_init(SplitterAllpass *splitter, ALfloat freq_mult);
void splitterap_clear(SplitterAllpass *splitter);
void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count);
#endif /* BFORMATDEC_H */
-187
View File
@@ -1,187 +0,0 @@
/*-
* Copyright (c) 2005 Boris Mikhaylov
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <math.h>
#include <string.h>
#include "bs2b.h"
#include "alu.h"
/* Set up all data. */
static void init(struct bs2b *bs2b)
{
float Fc_lo, Fc_hi;
float G_lo, G_hi;
float x, g;
switch(bs2b->level)
{
case BS2B_LOW_CLEVEL: /* Low crossfeed level */
Fc_lo = 360.0f;
Fc_hi = 501.0f;
G_lo = 0.398107170553497f;
G_hi = 0.205671765275719f;
break;
case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */
Fc_lo = 500.0f;
Fc_hi = 711.0f;
G_lo = 0.459726988530872f;
G_hi = 0.228208484414988f;
break;
case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */
Fc_lo = 700.0f;
Fc_hi = 1021.0f;
G_lo = 0.530884444230988f;
G_hi = 0.250105790667544f;
break;
case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */
Fc_lo = 360.0f;
Fc_hi = 494.0f;
G_lo = 0.316227766016838f;
G_hi = 0.168236228897329f;
break;
case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */
Fc_lo = 500.0f;
Fc_hi = 689.0f;
G_lo = 0.354813389233575f;
G_hi = 0.187169483835901f;
break;
default: /* High easy crossfeed level */
bs2b->level = BS2B_HIGH_ECLEVEL;
Fc_lo = 700.0f;
Fc_hi = 975.0f;
G_lo = 0.398107170553497f;
G_hi = 0.205671765275719f;
break;
} /* switch */
g = 1.0f / (1.0f - G_hi + G_lo);
/* $fc = $Fc / $s;
* $d = 1 / 2 / pi / $fc;
* $x = exp(-1 / $d);
*/
x = expf(-2.0f * F_PI * Fc_lo / bs2b->srate);
bs2b->b1_lo = x;
bs2b->a0_lo = G_lo * (1.0f - x) * g;
x = expf(-2.0f * F_PI * Fc_hi / bs2b->srate);
bs2b->b1_hi = x;
bs2b->a0_hi = (1.0f - G_hi * (1.0f - x)) * g;
bs2b->a1_hi = -x * g;
} /* init */
/* Exported functions.
* See descriptions in "bs2b.h"
*/
void bs2b_set_params(struct bs2b *bs2b, int level, int srate)
{
if(srate <= 0) srate = 1;
bs2b->level = level;
bs2b->srate = srate;
init(bs2b);
} /* bs2b_set_params */
int bs2b_get_level(struct bs2b *bs2b)
{
return bs2b->level;
} /* bs2b_get_level */
int bs2b_get_srate(struct bs2b *bs2b)
{
return bs2b->srate;
} /* bs2b_get_srate */
void bs2b_clear(struct bs2b *bs2b)
{
memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample));
} /* bs2b_clear */
void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, int SamplesToDo)
{
float lsamples[128][2];
float rsamples[128][2];
int base;
for(base = 0;base < SamplesToDo;)
{
int todo = mini(128, SamplesToDo-base);
int i;
/* Process left input */
lsamples[0][0] = bs2b->a0_lo*Left[0] +
bs2b->b1_lo*bs2b->last_sample[0].lo;
lsamples[0][1] = bs2b->a0_hi*Left[0] +
bs2b->a1_hi*bs2b->last_sample[0].asis +
bs2b->b1_hi*bs2b->last_sample[0].hi;
for(i = 1;i < todo;i++)
{
lsamples[i][0] = bs2b->a0_lo*Left[i] +
bs2b->b1_lo*lsamples[i-1][0];
lsamples[i][1] = bs2b->a0_hi*Left[i] +
bs2b->a1_hi*Left[i-1] +
bs2b->b1_hi*lsamples[i-1][1];
}
bs2b->last_sample[0].asis = Left[i-1];
bs2b->last_sample[0].lo = lsamples[i-1][0];
bs2b->last_sample[0].hi = lsamples[i-1][1];
/* Process right input */
rsamples[0][0] = bs2b->a0_lo*Right[0] +
bs2b->b1_lo*bs2b->last_sample[1].lo;
rsamples[0][1] = bs2b->a0_hi*Right[0] +
bs2b->a1_hi*bs2b->last_sample[1].asis +
bs2b->b1_hi*bs2b->last_sample[1].hi;
for(i = 1;i < todo;i++)
{
rsamples[i][0] = bs2b->a0_lo*Right[i] +
bs2b->b1_lo*rsamples[i-1][0];
rsamples[i][1] = bs2b->a0_hi*Right[i] +
bs2b->a1_hi*Right[i-1] +
bs2b->b1_hi*rsamples[i-1][1];
}
bs2b->last_sample[1].asis = Right[i-1];
bs2b->last_sample[1].lo = rsamples[i-1][0];
bs2b->last_sample[1].hi = rsamples[i-1][1];
/* Crossfeed */
for(i = 0;i < todo;i++)
*(Left++) = lsamples[i][1] + rsamples[i][0];
for(i = 0;i < todo;i++)
*(Right++) = rsamples[i][1] + lsamples[i][0];
base += todo;
}
} /* bs2b_cross_feed */
-5081
View File
File diff suppressed because it is too large Load Diff
-57
View File
@@ -1,57 +0,0 @@
#ifndef AL_COMPAT_H
#define AL_COMPAT_H
#include "alstring.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
WCHAR *strdupW(const WCHAR *str);
/* Opens a file with standard I/O. The filename is expected to be UTF-8. */
FILE *al_fopen(const char *fname, const char *mode);
#define HAVE_DYNLOAD 1
#else
#define al_fopen fopen
#if defined(HAVE_DLFCN_H) && !defined(IN_IDE_PARSER)
#define HAVE_DYNLOAD 1
#endif
#endif
struct FileMapping {
#ifdef _WIN32
HANDLE file;
HANDLE fmap;
#else
int fd;
#endif
void *ptr;
size_t len;
};
struct FileMapping MapFileToMem(const char *fname);
void UnmapFileMem(const struct FileMapping *mapping);
al_string GetProcPath(void);
#ifdef HAVE_DYNLOAD
void *LoadLib(const char *name);
void CloseLib(void *handle);
void *GetSymbol(void *handle, const char *name);
#endif
#ifdef __ANDROID__
#define JCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
#define JCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
/** Returns a JNIEnv*. */
void *Android_GetJNIEnv(void);
#endif
#endif /* AL_COMPAT_H */
-466
View File
@@ -1,466 +0,0 @@
#include "config.h"
#include "converter.h"
#include "mixer_defs.h"
SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate)
{
SampleConverter *converter;
ALsizei step;
if(numchans <= 0 || srcRate <= 0 || dstRate <= 0)
return NULL;
converter = al_calloc(16, FAM_SIZE(SampleConverter, Chan, numchans));
converter->mSrcType = srcType;
converter->mDstType = dstType;
converter->mNumChannels = numchans;
converter->mSrcTypeSize = BytesFromDevFmt(srcType);
converter->mDstTypeSize = BytesFromDevFmt(dstType);
converter->mSrcPrepCount = 0;
converter->mFracOffset = 0;
/* Have to set the mixer FPU mode since that's what the resampler code expects. */
START_MIXER_MODE();
step = fastf2i(minf((ALdouble)srcRate / dstRate, MAX_PITCH)*FRACTIONONE + 0.5f);
converter->mIncrement = maxi(step, 1);
if(converter->mIncrement == FRACTIONONE)
converter->mResample = Resample_copy32_C;
else
{
/* TODO: Allow other resamplers. */
BsincPrepare(converter->mIncrement, &converter->mState.bsinc);
converter->mResample = SelectResampler(BSincResampler);
}
END_MIXER_MODE();
return converter;
}
void DestroySampleConverter(SampleConverter **converter)
{
if(converter)
{
al_free(*converter);
*converter = NULL;
}
}
static inline ALfloat Sample_ALbyte(ALbyte val)
{ return val * (1.0f/128.0f); }
static inline ALfloat Sample_ALubyte(ALubyte val)
{ return Sample_ALbyte((ALint)val - 128); }
static inline ALfloat Sample_ALshort(ALshort val)
{ return val * (1.0f/32768.0f); }
static inline ALfloat Sample_ALushort(ALushort val)
{ return Sample_ALshort((ALint)val - 32768); }
static inline ALfloat Sample_ALint(ALint val)
{ return (val>>7) * (1.0f/16777216.0f); }
static inline ALfloat Sample_ALuint(ALuint val)
{ return Sample_ALint(val - INT_MAX - 1); }
static inline ALfloat Sample_ALfloat(ALfloat val)
{ return val; }
#define DECL_TEMPLATE(T) \
static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \
ALint srcstep, ALsizei samples) \
{ \
ALsizei i; \
for(i = 0;i < samples;i++) \
dst[i] = Sample_##T(src[i*srcstep]); \
}
DECL_TEMPLATE(ALbyte)
DECL_TEMPLATE(ALubyte)
DECL_TEMPLATE(ALshort)
DECL_TEMPLATE(ALushort)
DECL_TEMPLATE(ALint)
DECL_TEMPLATE(ALuint)
DECL_TEMPLATE(ALfloat)
#undef DECL_TEMPLATE
static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum DevFmtType srctype, ALsizei samples)
{
switch(srctype)
{
case DevFmtByte:
Load_ALbyte(dst, src, srcstep, samples);
break;
case DevFmtUByte:
Load_ALubyte(dst, src, srcstep, samples);
break;
case DevFmtShort:
Load_ALshort(dst, src, srcstep, samples);
break;
case DevFmtUShort:
Load_ALushort(dst, src, srcstep, samples);
break;
case DevFmtInt:
Load_ALint(dst, src, srcstep, samples);
break;
case DevFmtUInt:
Load_ALuint(dst, src, srcstep, samples);
break;
case DevFmtFloat:
Load_ALfloat(dst, src, srcstep, samples);
break;
}
}
static inline ALbyte ALbyte_Sample(ALfloat val)
{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); }
static inline ALubyte ALubyte_Sample(ALfloat val)
{ return ALbyte_Sample(val)+128; }
static inline ALshort ALshort_Sample(ALfloat val)
{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); }
static inline ALushort ALushort_Sample(ALfloat val)
{ return ALshort_Sample(val)+32768; }
static inline ALint ALint_Sample(ALfloat val)
{ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f)) << 7; }
static inline ALuint ALuint_Sample(ALfloat val)
{ return ALint_Sample(val)+INT_MAX+1; }
static inline ALfloat ALfloat_Sample(ALfloat val)
{ return val; }
#define DECL_TEMPLATE(T) \
static inline void Store_##T(T *restrict dst, const ALfloat *restrict src, \
ALint dststep, ALsizei samples) \
{ \
ALsizei i; \
for(i = 0;i < samples;i++) \
dst[i*dststep] = T##_Sample(src[i]); \
}
DECL_TEMPLATE(ALbyte)
DECL_TEMPLATE(ALubyte)
DECL_TEMPLATE(ALshort)
DECL_TEMPLATE(ALushort)
DECL_TEMPLATE(ALint)
DECL_TEMPLATE(ALuint)
DECL_TEMPLATE(ALfloat)
#undef DECL_TEMPLATE
static void StoreSamples(ALvoid *dst, const ALfloat *src, ALint dststep, enum DevFmtType dsttype, ALsizei samples)
{
switch(dsttype)
{
case DevFmtByte:
Store_ALbyte(dst, src, dststep, samples);
break;
case DevFmtUByte:
Store_ALubyte(dst, src, dststep, samples);
break;
case DevFmtShort:
Store_ALshort(dst, src, dststep, samples);
break;
case DevFmtUShort:
Store_ALushort(dst, src, dststep, samples);
break;
case DevFmtInt:
Store_ALint(dst, src, dststep, samples);
break;
case DevFmtUInt:
Store_ALuint(dst, src, dststep, samples);
break;
case DevFmtFloat:
Store_ALfloat(dst, src, dststep, samples);
break;
}
}
ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes)
{
ALint prepcount = converter->mSrcPrepCount;
ALsizei increment = converter->mIncrement;
ALsizei DataPosFrac = converter->mFracOffset;
ALuint64 DataSize64;
if(prepcount < 0)
{
/* Negative prepcount means we need to skip that many input samples. */
if(-prepcount >= srcframes)
return 0;
srcframes += prepcount;
prepcount = 0;
}
if(srcframes < 1)
{
/* No output samples if there's no input samples. */
return 0;
}
if(prepcount < MAX_POST_SAMPLES+MAX_PRE_SAMPLES &&
MAX_POST_SAMPLES+MAX_PRE_SAMPLES-prepcount >= srcframes)
{
/* Not enough input samples to generate an output sample. */
return 0;
}
DataSize64 = prepcount;
DataSize64 += srcframes;
DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
DataSize64 <<= FRACTIONBITS;
DataSize64 -= DataPosFrac;
/* If we have a full prep, we can generate at least one sample. */
return (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE);
}
ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes)
{
const ALsizei SrcFrameSize = converter->mNumChannels * converter->mSrcTypeSize;
const ALsizei DstFrameSize = converter->mNumChannels * converter->mDstTypeSize;
const ALsizei increment = converter->mIncrement;
ALsizei pos = 0;
START_MIXER_MODE();
while(pos < dstframes && *srcframes > 0)
{
ALfloat *restrict SrcData = ASSUME_ALIGNED(converter->mSrcSamples, 16);
ALfloat *restrict DstData = ASSUME_ALIGNED(converter->mDstSamples, 16);
ALint prepcount = converter->mSrcPrepCount;
ALsizei DataPosFrac = converter->mFracOffset;
ALuint64 DataSize64;
ALsizei DstSize;
ALint toread;
ALsizei chan;
if(prepcount < 0)
{
/* Negative prepcount means we need to skip that many input samples. */
if(-prepcount >= *srcframes)
{
converter->mSrcPrepCount = prepcount + *srcframes;
*srcframes = 0;
break;
}
*src = (const ALbyte*)*src + SrcFrameSize*-prepcount;
*srcframes += prepcount;
converter->mSrcPrepCount = 0;
continue;
}
toread = mini(*srcframes, BUFFERSIZE-(MAX_POST_SAMPLES+MAX_PRE_SAMPLES));
if(prepcount < MAX_POST_SAMPLES+MAX_PRE_SAMPLES &&
MAX_POST_SAMPLES+MAX_PRE_SAMPLES-prepcount >= toread)
{
/* Not enough input samples to generate an output sample. Store
* what we're given for later.
*/
for(chan = 0;chan < converter->mNumChannels;chan++)
LoadSamples(&converter->Chan[chan].mPrevSamples[prepcount],
(const ALbyte*)*src + converter->mSrcTypeSize*chan,
converter->mNumChannels, converter->mSrcType, toread
);
converter->mSrcPrepCount = prepcount + toread;
*srcframes = 0;
break;
}
DataSize64 = prepcount;
DataSize64 += toread;
DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
DataSize64 <<= FRACTIONBITS;
DataSize64 -= DataPosFrac;
/* If we have a full prep, we can generate at least one sample. */
DstSize = (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE);
DstSize = mini(DstSize, dstframes-pos);
for(chan = 0;chan < converter->mNumChannels;chan++)
{
const ALbyte *SrcSamples = (const ALbyte*)*src + converter->mSrcTypeSize*chan;
ALbyte *DstSamples = (ALbyte*)dst + converter->mDstTypeSize*chan;
const ALfloat *ResampledData;
ALsizei SrcDataEnd;
/* Load the previous samples into the source data first, then the
* new samples from the input buffer.
*/
memcpy(SrcData, converter->Chan[chan].mPrevSamples,
prepcount*sizeof(ALfloat));
LoadSamples(SrcData + prepcount, SrcSamples,
converter->mNumChannels, converter->mSrcType, toread
);
/* Store as many prep samples for next time as possible, given the
* number of output samples being generated.
*/
SrcDataEnd = (DataPosFrac + increment*DstSize)>>FRACTIONBITS;
if(SrcDataEnd >= prepcount+toread)
memset(converter->Chan[chan].mPrevSamples, 0,
sizeof(converter->Chan[chan].mPrevSamples));
else
{
size_t len = mini(MAX_PRE_SAMPLES+MAX_POST_SAMPLES, prepcount+toread-SrcDataEnd);
memcpy(converter->Chan[chan].mPrevSamples, &SrcData[SrcDataEnd],
len*sizeof(ALfloat));
memset(converter->Chan[chan].mPrevSamples+len, 0,
sizeof(converter->Chan[chan].mPrevSamples) - len*sizeof(ALfloat));
}
/* Now resample, and store the result in the output buffer. */
ResampledData = converter->mResample(&converter->mState,
SrcData+MAX_PRE_SAMPLES, DataPosFrac, increment,
DstData, DstSize
);
StoreSamples(DstSamples, ResampledData, converter->mNumChannels,
converter->mDstType, DstSize);
}
/* Update the number of prep samples still available, as well as the
* fractional offset.
*/
DataPosFrac += increment*DstSize;
converter->mSrcPrepCount = mini(MAX_PRE_SAMPLES+MAX_POST_SAMPLES,
prepcount+toread-(DataPosFrac>>FRACTIONBITS));
converter->mFracOffset = DataPosFrac & FRACTIONMASK;
/* Update the src and dst pointers in case there's still more to do. */
*src = (const ALbyte*)*src + SrcFrameSize*(DataPosFrac>>FRACTIONBITS);
*srcframes -= mini(*srcframes, (DataPosFrac>>FRACTIONBITS));
dst = (ALbyte*)dst + DstFrameSize*DstSize;
pos += DstSize;
}
END_MIXER_MODE();
return pos;
}
ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans)
{
ChannelConverter *converter;
if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) ||
(srcChans == DevFmtStereo && dstChans == DevFmtMono)))
return NULL;
converter = al_calloc(DEF_ALIGN, sizeof(*converter));
converter->mSrcType = srcType;
converter->mSrcChans = srcChans;
converter->mDstChans = dstChans;
return converter;
}
void DestroyChannelConverter(ChannelConverter **converter)
{
if(converter)
{
al_free(*converter);
*converter = NULL;
}
}
#define DECL_TEMPLATE(T) \
static void Mono2Stereo##T(ALfloat *restrict dst, const T *src, ALsizei frames)\
{ \
ALsizei i; \
for(i = 0;i < frames;i++) \
dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(src[i]) * 0.707106781187f; \
} \
\
static void Stereo2Mono##T(ALfloat *restrict dst, const T *src, ALsizei frames)\
{ \
ALsizei i; \
for(i = 0;i < frames;i++) \
dst[i] = (Sample_##T(src[i*2 + 0])+Sample_##T(src[i*2 + 1])) * \
0.707106781187f; \
}
DECL_TEMPLATE(ALbyte)
DECL_TEMPLATE(ALubyte)
DECL_TEMPLATE(ALshort)
DECL_TEMPLATE(ALushort)
DECL_TEMPLATE(ALint)
DECL_TEMPLATE(ALuint)
DECL_TEMPLATE(ALfloat)
#undef DECL_TEMPLATE
void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames)
{
if(converter->mSrcChans == converter->mDstChans)
{
LoadSamples(dst, src, 1, converter->mSrcType,
frames*ChannelsFromDevFmt(converter->mSrcChans, 0));
return;
}
if(converter->mSrcChans == DevFmtStereo && converter->mDstChans == DevFmtMono)
{
switch(converter->mSrcType)
{
case DevFmtByte:
Stereo2MonoALbyte(dst, src, frames);
break;
case DevFmtUByte:
Stereo2MonoALubyte(dst, src, frames);
break;
case DevFmtShort:
Stereo2MonoALshort(dst, src, frames);
break;
case DevFmtUShort:
Stereo2MonoALushort(dst, src, frames);
break;
case DevFmtInt:
Stereo2MonoALint(dst, src, frames);
break;
case DevFmtUInt:
Stereo2MonoALuint(dst, src, frames);
break;
case DevFmtFloat:
Stereo2MonoALfloat(dst, src, frames);
break;
}
}
else /*if(converter->mSrcChans == DevFmtMono && converter->mDstChans == DevFmtStereo)*/
{
switch(converter->mSrcType)
{
case DevFmtByte:
Mono2StereoALbyte(dst, src, frames);
break;
case DevFmtUByte:
Mono2StereoALubyte(dst, src, frames);
break;
case DevFmtShort:
Mono2StereoALshort(dst, src, frames);
break;
case DevFmtUShort:
Mono2StereoALushort(dst, src, frames);
break;
case DevFmtInt:
Mono2StereoALint(dst, src, frames);
break;
case DevFmtUInt:
Mono2StereoALuint(dst, src, frames);
break;
case DevFmtFloat:
Mono2StereoALfloat(dst, src, frames);
break;
}
}
}
-55
View File
@@ -1,55 +0,0 @@
#ifndef CONVERTER_H
#define CONVERTER_H
#include "alMain.h"
#include "alu.h"
#ifdef __cpluspluc
extern "C" {
#endif
typedef struct SampleConverter {
enum DevFmtType mSrcType;
enum DevFmtType mDstType;
ALsizei mNumChannels;
ALsizei mSrcTypeSize;
ALsizei mDstTypeSize;
ALint mSrcPrepCount;
ALsizei mFracOffset;
ALsizei mIncrement;
InterpState mState;
ResamplerFunc mResample;
alignas(16) ALfloat mSrcSamples[BUFFERSIZE];
alignas(16) ALfloat mDstSamples[BUFFERSIZE];
struct {
alignas(16) ALfloat mPrevSamples[MAX_PRE_SAMPLES+MAX_POST_SAMPLES];
} Chan[];
} SampleConverter;
SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate);
void DestroySampleConverter(SampleConverter **converter);
ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes);
ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes);
typedef struct ChannelConverter {
enum DevFmtType mSrcType;
enum DevFmtChannels mSrcChans;
enum DevFmtChannels mDstChans;
} ChannelConverter;
ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans);
void DestroyChannelConverter(ChannelConverter **converter);
void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames);
#ifdef __cpluspluc
}
#endif
#endif /* CONVERTER_H */
-410
View File
@@ -1,410 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2013 by Mike Gorchak
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
enum ChorusWaveForm {
CWF_Triangle = AL_CHORUS_WAVEFORM_TRIANGLE,
CWF_Sinusoid = AL_CHORUS_WAVEFORM_SINUSOID
};
typedef struct ALchorusState {
DERIVE_FROM_TYPE(ALeffectState);
ALfloat *SampleBuffer[2];
ALsizei BufferLength;
ALsizei offset;
ALsizei lfo_range;
ALfloat lfo_scale;
ALint lfo_disp;
/* Gains for left and right sides */
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
/* effect parameters */
enum ChorusWaveForm waveform;
ALint delay;
ALfloat depth;
ALfloat feedback;
} ALchorusState;
static ALvoid ALchorusState_Destruct(ALchorusState *state);
static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device);
static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALchorusState)
DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState);
static void ALchorusState_Construct(ALchorusState *state)
{
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALchorusState, ALeffectState, state);
state->BufferLength = 0;
state->SampleBuffer[0] = NULL;
state->SampleBuffer[1] = NULL;
state->offset = 0;
state->lfo_range = 1;
state->waveform = CWF_Triangle;
}
static ALvoid ALchorusState_Destruct(ALchorusState *state)
{
al_free(state->SampleBuffer[0]);
state->SampleBuffer[0] = NULL;
state->SampleBuffer[1] = NULL;
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device)
{
ALsizei maxlen;
ALsizei it;
maxlen = fastf2i(AL_CHORUS_MAX_DELAY * 2.0f * Device->Frequency) + 1;
maxlen = NextPowerOf2(maxlen);
if(maxlen != state->BufferLength)
{
void *temp = al_calloc(16, maxlen * sizeof(ALfloat) * 2);
if(!temp) return AL_FALSE;
al_free(state->SampleBuffer[0]);
state->SampleBuffer[0] = temp;
state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
state->BufferLength = maxlen;
}
for(it = 0;it < state->BufferLength;it++)
{
state->SampleBuffer[0][it] = 0.0f;
state->SampleBuffer[1][it] = 0.0f;
}
return AL_TRUE;
}
static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
{
ALfloat frequency = (ALfloat)Device->Frequency;
ALfloat coeffs[MAX_AMBI_COEFFS];
ALfloat rate;
ALint phase;
switch(props->Chorus.Waveform)
{
case AL_CHORUS_WAVEFORM_TRIANGLE:
state->waveform = CWF_Triangle;
break;
case AL_CHORUS_WAVEFORM_SINUSOID:
state->waveform = CWF_Sinusoid;
break;
}
state->feedback = props->Chorus.Feedback;
state->delay = fastf2i(props->Chorus.Delay * frequency);
/* The LFO depth is scaled to be relative to the sample delay. */
state->depth = props->Chorus.Depth * state->delay;
/* Gains for left and right sides */
CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
phase = props->Chorus.Phase;
rate = props->Chorus.Rate;
if(!(rate > 0.0f))
{
state->lfo_scale = 0.0f;
state->lfo_range = 1;
state->lfo_disp = 0;
}
else
{
/* Calculate LFO coefficient */
state->lfo_range = fastf2i(frequency/rate + 0.5f);
switch(state->waveform)
{
case CWF_Triangle:
state->lfo_scale = 4.0f / state->lfo_range;
break;
case CWF_Sinusoid:
state->lfo_scale = F_TAU / state->lfo_range;
break;
}
/* Calculate lfo phase displacement */
if(phase >= 0)
state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
else
state->lfo_disp = fastf2i(state->lfo_range * ((360+phase)/360.0f));
}
}
static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
const ALsizei todo)
{
ALsizei i;
for(i = 0;i < todo;i++)
{
delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay;
offset = (offset+1)%lfo_range;
}
}
static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
const ALsizei todo)
{
ALsizei i;
for(i = 0;i < todo;i++)
{
delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay;
offset = (offset+1)%lfo_range;
}
}
static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
ALfloat *restrict leftbuf = state->SampleBuffer[0];
ALfloat *restrict rightbuf = state->SampleBuffer[1];
const ALsizei bufmask = state->BufferLength-1;
const ALfloat feedback = state->feedback;
ALsizei offset = state->offset;
ALsizei i, c;
ALsizei base;
for(base = 0;base < SamplesToDo;)
{
const ALsizei todo = mini(128, SamplesToDo-base);
ALfloat temps[128][2];
ALint moddelays[2][128];
switch(state->waveform)
{
case CWF_Triangle:
GetTriangleDelays(moddelays[0], offset%state->lfo_range, state->lfo_range,
state->lfo_scale, state->depth, state->delay, todo);
GetTriangleDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range,
state->lfo_range, state->lfo_scale, state->depth, state->delay,
todo);
break;
case CWF_Sinusoid:
GetSinusoidDelays(moddelays[0], offset%state->lfo_range, state->lfo_range,
state->lfo_scale, state->depth, state->delay, todo);
GetSinusoidDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range,
state->lfo_range, state->lfo_scale, state->depth, state->delay,
todo);
break;
}
for(i = 0;i < todo;i++)
{
leftbuf[offset&bufmask] = SamplesIn[0][base+i];
temps[i][0] = leftbuf[(offset-moddelays[0][i])&bufmask] * feedback;
leftbuf[offset&bufmask] += temps[i][0];
rightbuf[offset&bufmask] = SamplesIn[0][base+i];
temps[i][1] = rightbuf[(offset-moddelays[1][i])&bufmask] * feedback;
rightbuf[offset&bufmask] += temps[i][1];
offset++;
}
for(c = 0;c < NumChannels;c++)
{
ALfloat gain = state->Gain[0][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < todo;i++)
SamplesOut[c][i+base] += temps[i][0] * gain;
}
gain = state->Gain[1][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < todo;i++)
SamplesOut[c][i+base] += temps[i][1] * gain;
}
}
base += todo;
}
state->offset = offset;
}
typedef struct ALchorusStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALchorusStateFactory;
static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(factory))
{
ALchorusState *state;
NEW_OBJ0(state, ALchorusState)();
if(!state) return NULL;
return STATIC_CAST(ALeffectState, state);
}
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALchorusStateFactory);
ALeffectStateFactory *ALchorusStateFactory_getFactory(void)
{
static ALchorusStateFactory ChorusFactory = { { GET_VTABLE2(ALchorusStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(ALeffectStateFactory, &ChorusFactory);
}
void ALchorus_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_CHORUS_WAVEFORM:
if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Waveform = val;
break;
case AL_CHORUS_PHASE:
if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Phase = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALchorus_setParami(effect, context, param, vals[0]);
}
void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_CHORUS_RATE:
if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Rate = val;
break;
case AL_CHORUS_DEPTH:
if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Depth = val;
break;
case AL_CHORUS_FEEDBACK:
if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Feedback = val;
break;
case AL_CHORUS_DELAY:
if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Delay = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{
ALchorus_setParamf(effect, context, param, vals[0]);
}
void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_CHORUS_WAVEFORM:
*val = props->Chorus.Waveform;
break;
case AL_CHORUS_PHASE:
*val = props->Chorus.Phase;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALchorus_getParami(effect, context, param, vals);
}
void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_CHORUS_RATE:
*val = props->Chorus.Rate;
break;
case AL_CHORUS_DEPTH:
*val = props->Chorus.Depth;
break;
case AL_CHORUS_FEEDBACK:
*val = props->Chorus.Feedback;
break;
case AL_CHORUS_DELAY:
*val = props->Chorus.Delay;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{
ALchorus_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALchorus);
-254
View File
@@ -1,254 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2013 by Anis A. Hireche
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include <stdlib.h>
#include "config.h"
#include "alError.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alu.h"
typedef struct ALcompressorState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALboolean Enabled;
ALfloat AttackRate;
ALfloat ReleaseRate;
ALfloat GainCtrl;
} ALcompressorState;
static ALvoid ALcompressorState_Destruct(ALcompressorState *state);
static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device);
static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALcompressorState)
DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState);
static void ALcompressorState_Construct(ALcompressorState *state)
{
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALcompressorState, ALeffectState, state);
state->Enabled = AL_TRUE;
state->AttackRate = 0.0f;
state->ReleaseRate = 0.0f;
state->GainCtrl = 1.0f;
}
static ALvoid ALcompressorState_Destruct(ALcompressorState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device)
{
const ALfloat attackTime = device->Frequency * 0.2f; /* 200ms Attack */
const ALfloat releaseTime = device->Frequency * 0.4f; /* 400ms Release */
state->AttackRate = 1.0f / attackTime;
state->ReleaseRate = 1.0f / releaseTime;
return AL_TRUE;
}
static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props)
{
ALuint i;
state->Enabled = props->Compressor.OnOff;
STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
for(i = 0;i < 4;i++)
ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i],
slot->Params.Gain, state->Gain[i]);
}
static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
ALsizei i, j, k;
ALsizei base;
for(base = 0;base < SamplesToDo;)
{
ALfloat temps[64][4];
ALsizei td = mini(64, SamplesToDo-base);
/* Load samples into the temp buffer first. */
for(j = 0;j < 4;j++)
{
for(i = 0;i < td;i++)
temps[i][j] = SamplesIn[j][i+base];
}
if(state->Enabled)
{
ALfloat gain = state->GainCtrl;
ALfloat output, amplitude;
for(i = 0;i < td;i++)
{
/* Roughly calculate the maximum amplitude from the 4-channel
* signal, and attack or release the gain control to reach it.
*/
amplitude = fabsf(temps[i][0]);
amplitude = maxf(amplitude + fabsf(temps[i][1]),
maxf(amplitude + fabsf(temps[i][2]),
amplitude + fabsf(temps[i][3])));
if(amplitude > gain)
gain = minf(gain+state->AttackRate, amplitude);
else if(amplitude < gain)
gain = maxf(gain-state->ReleaseRate, amplitude);
/* Apply the inverse of the gain control to normalize/compress
* the volume. */
output = 1.0f / clampf(gain, 0.5f, 2.0f);
for(j = 0;j < 4;j++)
temps[i][j] *= output;
}
state->GainCtrl = gain;
}
else
{
ALfloat gain = state->GainCtrl;
ALfloat output, amplitude;
for(i = 0;i < td;i++)
{
/* Same as above, except the amplitude is forced to 1. This
* helps ensure smooth gain changes when the compressor is
* turned on and off.
*/
amplitude = 1.0f;
if(amplitude > gain)
gain = minf(gain+state->AttackRate, amplitude);
else if(amplitude < gain)
gain = maxf(gain-state->ReleaseRate, amplitude);
output = 1.0f / clampf(gain, 0.5f, 2.0f);
for(j = 0;j < 4;j++)
temps[i][j] *= output;
}
state->GainCtrl = gain;
}
/* Now mix to the output. */
for(j = 0;j < 4;j++)
{
for(k = 0;k < NumChannels;k++)
{
ALfloat gain = state->Gain[j][k];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(i = 0;i < td;i++)
SamplesOut[k][base+i] += gain * temps[i][j];
}
}
base += td;
}
}
typedef struct ALcompressorStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALcompressorStateFactory;
static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *UNUSED(factory))
{
ALcompressorState *state;
NEW_OBJ0(state, ALcompressorState)();
if(!state) return NULL;
return STATIC_CAST(ALeffectState, state);
}
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALcompressorStateFactory);
ALeffectStateFactory *ALcompressorStateFactory_getFactory(void)
{
static ALcompressorStateFactory CompressorFactory = { { GET_VTABLE2(ALcompressorStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(ALeffectStateFactory, &CompressorFactory);
}
void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_COMPRESSOR_ONOFF:
if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Compressor.OnOff = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALcompressor_setParami(effect, context, param, vals[0]);
}
void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALcompressor_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{
ALcompressor_setParamf(effect, context, param, vals[0]);
}
void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_COMPRESSOR_ONOFF:
*val = props->Compressor.OnOff;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALcompressor_getParami(effect, context, param, vals);
}
void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALcompressor_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{
ALcompressor_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALcompressor);
-203
View File
@@ -1,203 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2011 by Chris Robinson.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
typedef struct ALdedicatedState {
DERIVE_FROM_TYPE(ALeffectState);
ALfloat gains[MAX_OUTPUT_CHANNELS];
} ALdedicatedState;
static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state);
static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device);
static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState)
DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState);
static void ALdedicatedState_Construct(ALdedicatedState *state)
{
ALsizei s;
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALdedicatedState, ALeffectState, state);
for(s = 0;s < MAX_OUTPUT_CHANNELS;s++)
state->gains[s] = 0.0f;
}
static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), ALCdevice *UNUSED(device))
{
return AL_TRUE;
}
static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props)
{
ALfloat Gain;
ALuint i;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
state->gains[i] = 0.0f;
Gain = Slot->Params.Gain * props->Dedicated.Gain;
if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
{
int idx;
if((idx=GetChannelIdxByName(device->RealOut, LFE)) != -1)
{
STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer;
STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels;
state->gains[idx] = Gain;
}
}
else if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
{
int idx;
/* Dialog goes to the front-center speaker if it exists, otherwise it
* plays from the front-center location. */
if((idx=GetChannelIdxByName(device->RealOut, FrontCenter)) != -1)
{
STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer;
STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels;
state->gains[idx] = Gain;
}
else
{
ALfloat coeffs[MAX_AMBI_COEFFS];
CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer;
STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels;
ComputePanningGains(device->Dry, coeffs, Gain, state->gains);
}
}
}
static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
ALsizei i, c;
SamplesIn = ASSUME_ALIGNED(SamplesIn, 16);
SamplesOut = ASSUME_ALIGNED(SamplesOut, 16);
for(c = 0;c < NumChannels;c++)
{
const ALfloat gain = state->gains[c];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(i = 0;i < SamplesToDo;i++)
SamplesOut[c][i] += SamplesIn[0][i] * gain;
}
}
typedef struct ALdedicatedStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALdedicatedStateFactory;
ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(factory))
{
ALdedicatedState *state;
NEW_OBJ0(state, ALdedicatedState)();
if(!state) return NULL;
return STATIC_CAST(ALeffectState, state);
}
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdedicatedStateFactory);
ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void)
{
static ALdedicatedStateFactory DedicatedFactory = { { GET_VTABLE2(ALdedicatedStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(ALeffectStateFactory, &DedicatedFactory);
}
void ALdedicated_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALdedicated_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALdedicated_setParami(effect, context, param, vals[0]);
}
void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_DEDICATED_GAIN:
if(!(val >= 0.0f && isfinite(val)))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Dedicated.Gain = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALdedicated_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{
ALdedicated_setParamf(effect, context, param, vals[0]);
}
void ALdedicated_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALdedicated_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALdedicated_getParami(effect, context, param, vals);
}
void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_DEDICATED_GAIN:
*val = props->Dedicated.Gain;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALdedicated_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{
ALdedicated_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALdedicated);
-297
View File
@@ -1,297 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2013 by Mike Gorchak
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
typedef struct ALdistortionState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
ALfloat Gain[MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALfilterState lowpass;
ALfilterState bandpass;
ALfloat attenuation;
ALfloat edge_coeff;
} ALdistortionState;
static ALvoid ALdistortionState_Destruct(ALdistortionState *state);
static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device);
static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALdistortionState)
DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState);
static void ALdistortionState_Construct(ALdistortionState *state)
{
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALdistortionState, ALeffectState, state);
ALfilterState_clear(&state->lowpass);
ALfilterState_clear(&state->bandpass);
}
static ALvoid ALdistortionState_Destruct(ALdistortionState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state), ALCdevice *UNUSED(device))
{
return AL_TRUE;
}
static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
{
ALfloat frequency = (ALfloat)Device->Frequency;
ALfloat bandwidth;
ALfloat cutoff;
ALfloat edge;
/* Store distorted signal attenuation settings. */
state->attenuation = props->Distortion.Gain;
/* Store waveshaper edge settings. */
edge = sinf(props->Distortion.Edge * (F_PI_2));
edge = minf(edge, 0.99f);
state->edge_coeff = 2.0f * edge / (1.0f-edge);
cutoff = props->Distortion.LowpassCutoff;
/* Bandwidth value is constant in octaves. */
bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
/* Multiply sampling frequency by the amount of oversampling done during
* processing.
*/
ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f,
cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
);
cutoff = props->Distortion.EQCenter;
/* Convert bandwidth in Hz to octaves. */
bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f);
ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f,
cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
);
ComputeAmbientGains(Device->Dry, Slot->Params.Gain, state->Gain);
}
static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
const ALfloat fc = state->edge_coeff;
ALsizei it, kt;
ALsizei base;
for(base = 0;base < SamplesToDo;)
{
float buffer[2][64 * 4];
ALsizei td = mini(64, SamplesToDo-base);
/* Perform 4x oversampling to avoid aliasing. Oversampling greatly
* improves distortion quality and allows to implement lowpass and
* bandpass filters using high frequencies, at which classic IIR
* filters became unstable.
*/
/* Fill oversample buffer using zero stuffing. */
for(it = 0;it < td;it++)
{
/* Multiply the sample by the amount of oversampling to maintain
* the signal's power.
*/
buffer[0][it*4 + 0] = SamplesIn[0][it+base] * 4.0f;
buffer[0][it*4 + 1] = 0.0f;
buffer[0][it*4 + 2] = 0.0f;
buffer[0][it*4 + 3] = 0.0f;
}
/* First step, do lowpass filtering of original signal. Additionally
* perform buffer interpolation and lowpass cutoff for oversampling
* (which is fortunately first step of distortion). So combine three
* operations into the one.
*/
ALfilterState_process(&state->lowpass, buffer[1], buffer[0], td*4);
/* Second step, do distortion using waveshaper function to emulate
* signal processing during tube overdriving. Three steps of
* waveshaping are intended to modify waveform without boost/clipping/
* attenuation process.
*/
for(it = 0;it < td*4;it++)
{
ALfloat smp = buffer[1][it];
smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f;
smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
buffer[0][it] = smp;
}
/* Third step, do bandpass filtering of distorted signal. */
ALfilterState_process(&state->bandpass, buffer[1], buffer[0], td*4);
for(kt = 0;kt < NumChannels;kt++)
{
/* Fourth step, final, do attenuation and perform decimation,
* store only one sample out of 4.
*/
ALfloat gain = state->Gain[kt] * state->attenuation;
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(it = 0;it < td;it++)
SamplesOut[kt][base+it] += gain * buffer[1][it*4];
}
base += td;
}
}
typedef struct ALdistortionStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALdistortionStateFactory;
static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory *UNUSED(factory))
{
ALdistortionState *state;
NEW_OBJ0(state, ALdistortionState)();
if(!state) return NULL;
return STATIC_CAST(ALeffectState, state);
}
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdistortionStateFactory);
ALeffectStateFactory *ALdistortionStateFactory_getFactory(void)
{
static ALdistortionStateFactory DistortionFactory = { { GET_VTABLE2(ALdistortionStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(ALeffectStateFactory, &DistortionFactory);
}
void ALdistortion_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALdistortion_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALdistortion_setParami(effect, context, param, vals[0]);
}
void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_DISTORTION_EDGE:
if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Distortion.Edge = val;
break;
case AL_DISTORTION_GAIN:
if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Distortion.Gain = val;
break;
case AL_DISTORTION_LOWPASS_CUTOFF:
if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Distortion.LowpassCutoff = val;
break;
case AL_DISTORTION_EQCENTER:
if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Distortion.EQCenter = val;
break;
case AL_DISTORTION_EQBANDWIDTH:
if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Distortion.EQBandwidth = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{
ALdistortion_setParamf(effect, context, param, vals[0]);
}
void ALdistortion_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALdistortion_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALdistortion_getParami(effect, context, param, vals);
}
void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_DISTORTION_EDGE:
*val = props->Distortion.Edge;
break;
case AL_DISTORTION_GAIN:
*val = props->Distortion.Gain;
break;
case AL_DISTORTION_LOWPASS_CUTOFF:
*val = props->Distortion.LowpassCutoff;
break;
case AL_DISTORTION_EQCENTER:
*val = props->Distortion.EQCenter;
break;
case AL_DISTORTION_EQBANDWIDTH:
*val = props->Distortion.EQBandwidth;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{
ALdistortion_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALdistortion);
-326
View File
@@ -1,326 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2009 by Chris Robinson.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
typedef struct ALechoState {
DERIVE_FROM_TYPE(ALeffectState);
ALfloat *SampleBuffer;
ALsizei BufferLength;
// The echo is two tap. The delay is the number of samples from before the
// current offset
struct {
ALsizei delay;
} Tap[2];
ALsizei Offset;
/* The panning gains for the two taps */
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
ALfloat FeedGain;
ALfilterState Filter;
} ALechoState;
static ALvoid ALechoState_Destruct(ALechoState *state);
static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device);
static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALechoState)
DEFINE_ALEFFECTSTATE_VTABLE(ALechoState);
static void ALechoState_Construct(ALechoState *state)
{
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALechoState, ALeffectState, state);
state->BufferLength = 0;
state->SampleBuffer = NULL;
state->Tap[0].delay = 0;
state->Tap[1].delay = 0;
state->Offset = 0;
ALfilterState_clear(&state->Filter);
}
static ALvoid ALechoState_Destruct(ALechoState *state)
{
al_free(state->SampleBuffer);
state->SampleBuffer = NULL;
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
{
ALsizei maxlen, i;
// Use the next power of 2 for the buffer length, so the tap offsets can be
// wrapped using a mask instead of a modulo
maxlen = fastf2i(AL_ECHO_MAX_DELAY * Device->Frequency) + 1;
maxlen += fastf2i(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1;
maxlen = NextPowerOf2(maxlen);
if(maxlen != state->BufferLength)
{
void *temp = al_calloc(16, maxlen * sizeof(ALfloat));
if(!temp) return AL_FALSE;
al_free(state->SampleBuffer);
state->SampleBuffer = temp;
state->BufferLength = maxlen;
}
for(i = 0;i < state->BufferLength;i++)
state->SampleBuffer[i] = 0.0f;
return AL_TRUE;
}
static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
{
ALuint frequency = Device->Frequency;
ALfloat coeffs[MAX_AMBI_COEFFS];
ALfloat gain, lrpan, spread;
state->Tap[0].delay = fastf2i(props->Echo.Delay * frequency) + 1;
state->Tap[1].delay = fastf2i(props->Echo.LRDelay * frequency);
state->Tap[1].delay += state->Tap[0].delay;
spread = props->Echo.Spread;
if(spread < 0.0f) lrpan = -1.0f;
else lrpan = 1.0f;
/* Convert echo spread (where 0 = omni, +/-1 = directional) to coverage
* spread (where 0 = point, tau = omni).
*/
spread = asinf(1.0f - fabsf(spread))*4.0f;
state->FeedGain = props->Echo.Feedback;
gain = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */
ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf,
gain, LOWPASSFREQREF/frequency,
calc_rcpQ_from_slope(gain, 1.0f));
gain = Slot->Params.Gain;
/* First tap panning */
CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs);
ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[0]);
/* Second tap panning */
CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs);
ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[1]);
}
static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
const ALsizei mask = state->BufferLength-1;
const ALsizei tap1 = state->Tap[0].delay;
const ALsizei tap2 = state->Tap[1].delay;
ALsizei offset = state->Offset;
ALfloat x[2], y[2], in, out;
ALsizei base, k;
ALsizei i;
x[0] = state->Filter.x[0];
x[1] = state->Filter.x[1];
y[0] = state->Filter.y[0];
y[1] = state->Filter.y[1];
for(base = 0;base < SamplesToDo;)
{
ALfloat temps[128][2];
ALsizei td = mini(128, SamplesToDo-base);
for(i = 0;i < td;i++)
{
/* First tap */
temps[i][0] = state->SampleBuffer[(offset-tap1) & mask];
/* Second tap */
temps[i][1] = state->SampleBuffer[(offset-tap2) & mask];
// Apply damping and feedback gain to the second tap, and mix in the
// new sample
in = temps[i][1] + SamplesIn[0][i+base];
out = in*state->Filter.b0 +
x[0]*state->Filter.b1 + x[1]*state->Filter.b2 -
y[0]*state->Filter.a1 - y[1]*state->Filter.a2;
x[1] = x[0]; x[0] = in;
y[1] = y[0]; y[0] = out;
state->SampleBuffer[offset&mask] = out * state->FeedGain;
offset++;
}
for(k = 0;k < NumChannels;k++)
{
ALfloat gain = state->Gain[0][k];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < td;i++)
SamplesOut[k][i+base] += temps[i][0] * gain;
}
gain = state->Gain[1][k];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < td;i++)
SamplesOut[k][i+base] += temps[i][1] * gain;
}
}
base += td;
}
state->Filter.x[0] = x[0];
state->Filter.x[1] = x[1];
state->Filter.y[0] = y[0];
state->Filter.y[1] = y[1];
state->Offset = offset;
}
typedef struct ALechoStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALechoStateFactory;
ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory))
{
ALechoState *state;
NEW_OBJ0(state, ALechoState)();
if(!state) return NULL;
return STATIC_CAST(ALeffectState, state);
}
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALechoStateFactory);
ALeffectStateFactory *ALechoStateFactory_getFactory(void)
{
static ALechoStateFactory EchoFactory = { { GET_VTABLE2(ALechoStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(ALeffectStateFactory, &EchoFactory);
}
void ALecho_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALecho_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALecho_setParami(effect, context, param, vals[0]);
}
void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_ECHO_DELAY:
if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Echo.Delay = val;
break;
case AL_ECHO_LRDELAY:
if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Echo.LRDelay = val;
break;
case AL_ECHO_DAMPING:
if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Echo.Damping = val;
break;
case AL_ECHO_FEEDBACK:
if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Echo.Feedback = val;
break;
case AL_ECHO_SPREAD:
if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Echo.Spread = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALecho_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{
ALecho_setParamf(effect, context, param, vals[0]);
}
void ALecho_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALecho_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALecho_getParami(effect, context, param, vals);
}
void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_ECHO_DELAY:
*val = props->Echo.Delay;
break;
case AL_ECHO_LRDELAY:
*val = props->Echo.LRDelay;
break;
case AL_ECHO_DAMPING:
*val = props->Echo.Damping;
break;
case AL_ECHO_FEEDBACK:
*val = props->Echo.Feedback;
break;
case AL_ECHO_SPREAD:
*val = props->Echo.Spread;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALecho_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{
ALecho_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALecho);
-380
View File
@@ -1,380 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2013 by Mike Gorchak
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
/* The document "Effects Extension Guide.pdf" says that low and high *
* frequencies are cutoff frequencies. This is not fully correct, they *
* are corner frequencies for low and high shelf filters. If they were *
* just cutoff frequencies, there would be no need in cutoff frequency *
* gains, which are present. Documentation for "Creative Proteus X2" *
* software describes 4-band equalizer functionality in a much better *
* way. This equalizer seems to be a predecessor of OpenAL 4-band *
* equalizer. With low and high shelf filters we are able to cutoff *
* frequencies below and/or above corner frequencies using attenuation *
* gains (below 1.0) and amplify all low and/or high frequencies using *
* gains above 1.0. *
* *
* Low-shelf Low Mid Band High Mid Band High-shelf *
* corner center center corner *
* frequency frequency frequency frequency *
* 50Hz..800Hz 200Hz..3000Hz 1000Hz..8000Hz 4000Hz..16000Hz *
* *
* | | | | *
* | | | | *
* B -----+ /--+--\ /--+--\ +----- *
* O |\ | | | | | | /| *
* O | \ - | - - | - / | *
* S + | \ | | | | | | / | *
* T | | | | | | | | | | *
* ---------+---------------+------------------+---------------+-------- *
* C | | | | | | | | | | *
* U - | / | | | | | | \ | *
* T | / - | - - | - \ | *
* O |/ | | | | | | \| *
* F -----+ \--+--/ \--+--/ +----- *
* F | | | | *
* | | | | *
* *
* Gains vary from 0.126 up to 7.943, which means from -18dB attenuation *
* up to +18dB amplification. Band width varies from 0.01 up to 1.0 in *
* octaves for two mid bands. *
* *
* Implementation is based on the "Cookbook formulae for audio EQ biquad *
* filter coefficients" by Robert Bristow-Johnson *
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */
/* The maximum number of sample frames per update. */
#define MAX_UPDATE_SAMPLES 256
typedef struct ALequalizerState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALfilterState filter[4][MAX_EFFECT_CHANNELS];
ALfloat SampleBuffer[4][MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES];
} ALequalizerState;
static ALvoid ALequalizerState_Destruct(ALequalizerState *state);
static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device);
static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALequalizerState)
DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState);
static void ALequalizerState_Construct(ALequalizerState *state)
{
int it, ft;
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALequalizerState, ALeffectState, state);
/* Initialize sample history only on filter creation to avoid */
/* sound clicks if filter settings were changed in runtime. */
for(it = 0; it < 4; it++)
{
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
ALfilterState_clear(&state->filter[it][ft]);
}
}
static ALvoid ALequalizerState_Destruct(ALequalizerState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), ALCdevice *UNUSED(device))
{
return AL_TRUE;
}
static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props)
{
ALfloat frequency = (ALfloat)device->Frequency;
ALfloat gain, freq_mult;
ALuint i;
STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i],
slot->Params.Gain, state->Gain[i]);
/* Calculate coefficients for the each type of filter. Note that the shelf
* filters' gain is for the reference frequency, which is the centerpoint
* of the transition band.
*/
gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */
freq_mult = props->Equalizer.LowCutoff/frequency;
ALfilterState_setParams(&state->filter[0][0], ALfilterType_LowShelf,
gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
);
/* Copy the filter coefficients for the other input channels. */
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
ALfilterState_copyParams(&state->filter[0][i], &state->filter[0][0]);
gain = maxf(props->Equalizer.Mid1Gain, 0.0625f);
freq_mult = props->Equalizer.Mid1Center/frequency;
ALfilterState_setParams(&state->filter[1][0], ALfilterType_Peaking,
gain, freq_mult, calc_rcpQ_from_bandwidth(
freq_mult, props->Equalizer.Mid1Width
)
);
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
ALfilterState_copyParams(&state->filter[1][i], &state->filter[1][0]);
gain = maxf(props->Equalizer.Mid2Gain, 0.0625f);
freq_mult = props->Equalizer.Mid2Center/frequency;
ALfilterState_setParams(&state->filter[2][0], ALfilterType_Peaking,
gain, freq_mult, calc_rcpQ_from_bandwidth(
freq_mult, props->Equalizer.Mid2Width
)
);
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
ALfilterState_copyParams(&state->filter[2][i], &state->filter[2][0]);
gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f);
freq_mult = props->Equalizer.HighCutoff/frequency;
ALfilterState_setParams(&state->filter[3][0], ALfilterType_HighShelf,
gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
);
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
ALfilterState_copyParams(&state->filter[3][i], &state->filter[3][0]);
}
static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
ALfloat (*Samples)[MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES] = state->SampleBuffer;
ALsizei it, kt, ft;
ALsizei base;
for(base = 0;base < SamplesToDo;)
{
ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base);
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
ALfilterState_process(&state->filter[0][ft], Samples[0][ft], &SamplesIn[ft][base], td);
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
ALfilterState_process(&state->filter[1][ft], Samples[1][ft], Samples[0][ft], td);
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
ALfilterState_process(&state->filter[2][ft], Samples[2][ft], Samples[1][ft], td);
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
ALfilterState_process(&state->filter[3][ft], Samples[3][ft], Samples[2][ft], td);
for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
{
for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[ft][kt];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(it = 0;it < td;it++)
SamplesOut[kt][base+it] += gain * Samples[3][ft][it];
}
}
base += td;
}
}
typedef struct ALequalizerStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALequalizerStateFactory;
ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(factory))
{
ALequalizerState *state;
NEW_OBJ0(state, ALequalizerState)();
if(!state) return NULL;
return STATIC_CAST(ALeffectState, state);
}
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALequalizerStateFactory);
ALeffectStateFactory *ALequalizerStateFactory_getFactory(void)
{
static ALequalizerStateFactory EqualizerFactory = { { GET_VTABLE2(ALequalizerStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(ALeffectStateFactory, &EqualizerFactory);
}
void ALequalizer_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALequalizer_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALequalizer_setParami(effect, context, param, vals[0]);
}
void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_EQUALIZER_LOW_GAIN:
if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.LowGain = val;
break;
case AL_EQUALIZER_LOW_CUTOFF:
if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.LowCutoff = val;
break;
case AL_EQUALIZER_MID1_GAIN:
if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid1Gain = val;
break;
case AL_EQUALIZER_MID1_CENTER:
if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid1Center = val;
break;
case AL_EQUALIZER_MID1_WIDTH:
if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid1Width = val;
break;
case AL_EQUALIZER_MID2_GAIN:
if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid2Gain = val;
break;
case AL_EQUALIZER_MID2_CENTER:
if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid2Center = val;
break;
case AL_EQUALIZER_MID2_WIDTH:
if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid2Width = val;
break;
case AL_EQUALIZER_HIGH_GAIN:
if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.HighGain = val;
break;
case AL_EQUALIZER_HIGH_CUTOFF:
if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.HighCutoff = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALequalizer_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{
ALequalizer_setParamf(effect, context, param, vals[0]);
}
void ALequalizer_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALequalizer_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALequalizer_getParami(effect, context, param, vals);
}
void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_EQUALIZER_LOW_GAIN:
*val = props->Equalizer.LowGain;
break;
case AL_EQUALIZER_LOW_CUTOFF:
*val = props->Equalizer.LowCutoff;
break;
case AL_EQUALIZER_MID1_GAIN:
*val = props->Equalizer.Mid1Gain;
break;
case AL_EQUALIZER_MID1_CENTER:
*val = props->Equalizer.Mid1Center;
break;
case AL_EQUALIZER_MID1_WIDTH:
*val = props->Equalizer.Mid1Width;
break;
case AL_EQUALIZER_MID2_GAIN:
*val = props->Equalizer.Mid2Gain;
break;
case AL_EQUALIZER_MID2_CENTER:
*val = props->Equalizer.Mid2Center;
break;
case AL_EQUALIZER_MID2_WIDTH:
*val = props->Equalizer.Mid2Width;
break;
case AL_EQUALIZER_HIGH_GAIN:
*val = props->Equalizer.HighGain;
break;
case AL_EQUALIZER_HIGH_CUTOFF:
*val = props->Equalizer.HighCutoff;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALequalizer_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{
ALequalizer_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALequalizer);
-408
View File
@@ -1,408 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2013 by Mike Gorchak
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
enum FlangerWaveForm {
FWF_Triangle = AL_FLANGER_WAVEFORM_TRIANGLE,
FWF_Sinusoid = AL_FLANGER_WAVEFORM_SINUSOID
};
typedef struct ALflangerState {
DERIVE_FROM_TYPE(ALeffectState);
ALfloat *SampleBuffer[2];
ALsizei BufferLength;
ALsizei offset;
ALsizei lfo_range;
ALfloat lfo_scale;
ALint lfo_disp;
/* Gains for left and right sides */
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
/* effect parameters */
enum FlangerWaveForm waveform;
ALint delay;
ALfloat depth;
ALfloat feedback;
} ALflangerState;
static ALvoid ALflangerState_Destruct(ALflangerState *state);
static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device);
static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALflangerState)
DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState);
static void ALflangerState_Construct(ALflangerState *state)
{
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALflangerState, ALeffectState, state);
state->BufferLength = 0;
state->SampleBuffer[0] = NULL;
state->SampleBuffer[1] = NULL;
state->offset = 0;
state->lfo_range = 1;
state->waveform = FWF_Triangle;
}
static ALvoid ALflangerState_Destruct(ALflangerState *state)
{
al_free(state->SampleBuffer[0]);
state->SampleBuffer[0] = NULL;
state->SampleBuffer[1] = NULL;
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device)
{
ALsizei maxlen;
ALsizei it;
maxlen = fastf2i(AL_FLANGER_MAX_DELAY * 2.0f * Device->Frequency) + 1;
maxlen = NextPowerOf2(maxlen);
if(maxlen != state->BufferLength)
{
void *temp = al_calloc(16, maxlen * sizeof(ALfloat) * 2);
if(!temp) return AL_FALSE;
al_free(state->SampleBuffer[0]);
state->SampleBuffer[0] = temp;
state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
state->BufferLength = maxlen;
}
for(it = 0;it < state->BufferLength;it++)
{
state->SampleBuffer[0][it] = 0.0f;
state->SampleBuffer[1][it] = 0.0f;
}
return AL_TRUE;
}
static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
{
ALfloat frequency = (ALfloat)Device->Frequency;
ALfloat coeffs[MAX_AMBI_COEFFS];
ALfloat rate;
ALint phase;
switch(props->Flanger.Waveform)
{
case AL_FLANGER_WAVEFORM_TRIANGLE:
state->waveform = FWF_Triangle;
break;
case AL_FLANGER_WAVEFORM_SINUSOID:
state->waveform = FWF_Sinusoid;
break;
}
state->feedback = props->Flanger.Feedback;
state->delay = fastf2i(props->Flanger.Delay * frequency);
/* The LFO depth is scaled to be relative to the sample delay. */
state->depth = props->Flanger.Depth * state->delay;
/* Gains for left and right sides */
CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
phase = props->Flanger.Phase;
rate = props->Flanger.Rate;
if(!(rate > 0.0f))
{
state->lfo_scale = 0.0f;
state->lfo_range = 1;
state->lfo_disp = 0;
}
else
{
/* Calculate LFO coefficient */
state->lfo_range = fastf2i(frequency/rate + 0.5f);
switch(state->waveform)
{
case FWF_Triangle:
state->lfo_scale = 4.0f / state->lfo_range;
break;
case FWF_Sinusoid:
state->lfo_scale = F_TAU / state->lfo_range;
break;
}
/* Calculate lfo phase displacement */
if(phase >= 0)
state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
else
state->lfo_disp = fastf2i(state->lfo_range * ((360+phase)/360.0f));
}
}
static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
const ALsizei todo)
{
ALsizei i;
for(i = 0;i < todo;i++)
{
delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay;
offset = (offset+1)%lfo_range;
}
}
static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
const ALsizei todo)
{
ALsizei i;
for(i = 0;i < todo;i++)
{
delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay;
offset = (offset+1)%lfo_range;
}
}
static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
ALfloat *restrict leftbuf = state->SampleBuffer[0];
ALfloat *restrict rightbuf = state->SampleBuffer[1];
const ALsizei bufmask = state->BufferLength-1;
const ALfloat feedback = state->feedback;
ALsizei offset = state->offset;
ALsizei i, c;
ALsizei base;
for(base = 0;base < SamplesToDo;)
{
const ALsizei todo = mini(128, SamplesToDo-base);
ALfloat temps[128][2];
ALint moddelays[2][128];
switch(state->waveform)
{
case FWF_Triangle:
GetTriangleDelays(moddelays[0], offset%state->lfo_range, state->lfo_range,
state->lfo_scale, state->depth, state->delay, todo);
GetTriangleDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range,
state->lfo_range, state->lfo_scale, state->depth, state->delay,
todo);
break;
case FWF_Sinusoid:
GetSinusoidDelays(moddelays[0], offset%state->lfo_range, state->lfo_range,
state->lfo_scale, state->depth, state->delay, todo);
GetSinusoidDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range,
state->lfo_range, state->lfo_scale, state->depth, state->delay,
todo);
break;
}
for(i = 0;i < todo;i++)
{
leftbuf[offset&bufmask] = SamplesIn[0][base+i];
temps[i][0] = leftbuf[(offset-moddelays[0][i])&bufmask] * feedback;
leftbuf[offset&bufmask] += temps[i][0];
rightbuf[offset&bufmask] = SamplesIn[0][base+i];
temps[i][1] = rightbuf[(offset-moddelays[1][i])&bufmask] * feedback;
rightbuf[offset&bufmask] += temps[i][1];
offset++;
}
for(c = 0;c < NumChannels;c++)
{
ALfloat gain = state->Gain[0][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < todo;i++)
SamplesOut[c][i+base] += temps[i][0] * gain;
}
gain = state->Gain[1][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < todo;i++)
SamplesOut[c][i+base] += temps[i][1] * gain;
}
}
base += todo;
}
state->offset = offset;
}
typedef struct ALflangerStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALflangerStateFactory;
ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory))
{
ALflangerState *state;
NEW_OBJ0(state, ALflangerState)();
if(!state) return NULL;
return STATIC_CAST(ALeffectState, state);
}
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory);
ALeffectStateFactory *ALflangerStateFactory_getFactory(void)
{
static ALflangerStateFactory FlangerFactory = { { GET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(ALeffectStateFactory, &FlangerFactory);
}
void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_FLANGER_WAVEFORM:
if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Flanger.Waveform = val;
break;
case AL_FLANGER_PHASE:
if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Flanger.Phase = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALflanger_setParami(effect, context, param, vals[0]);
}
void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_FLANGER_RATE:
if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Flanger.Rate = val;
break;
case AL_FLANGER_DEPTH:
if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Flanger.Depth = val;
break;
case AL_FLANGER_FEEDBACK:
if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Flanger.Feedback = val;
break;
case AL_FLANGER_DELAY:
if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Flanger.Delay = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{
ALflanger_setParamf(effect, context, param, vals[0]);
}
void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_FLANGER_WAVEFORM:
*val = props->Flanger.Waveform;
break;
case AL_FLANGER_PHASE:
*val = props->Flanger.Phase;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALflanger_getParami(effect, context, param, vals);
}
void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_FLANGER_RATE:
*val = props->Flanger.Rate;
break;
case AL_FLANGER_DEPTH:
*val = props->Flanger.Depth;
break;
case AL_FLANGER_FEEDBACK:
*val = props->Flanger.Feedback;
break;
case AL_FLANGER_DELAY:
*val = props->Flanger.Delay;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{
ALflanger_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALflanger);
-311
View File
@@ -1,311 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2009 by Chris Robinson.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
typedef struct ALmodulatorState {
DERIVE_FROM_TYPE(ALeffectState);
void (*Process)(ALfloat*, const ALfloat*, ALsizei, const ALsizei, ALsizei);
ALsizei index;
ALsizei step;
ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
ALfilterState Filter[MAX_EFFECT_CHANNELS];
} ALmodulatorState;
static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state);
static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device);
static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState)
DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState);
#define WAVEFORM_FRACBITS 24
#define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
#define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
static inline ALfloat Sin(ALsizei index)
{
return sinf(index*(F_TAU/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f;
}
static inline ALfloat Saw(ALsizei index)
{
return (ALfloat)index / WAVEFORM_FRACONE;
}
static inline ALfloat Square(ALsizei index)
{
return (ALfloat)((index >> (WAVEFORM_FRACBITS - 1)) & 1);
}
#define DECL_TEMPLATE(func) \
static void Modulate##func(ALfloat *restrict dst, const ALfloat *restrict src,\
ALsizei index, const ALsizei step, ALsizei todo) \
{ \
ALsizei i; \
for(i = 0;i < todo;i++) \
{ \
index += step; \
index &= WAVEFORM_FRACMASK; \
dst[i] = src[i] * func(index); \
} \
}
DECL_TEMPLATE(Sin)
DECL_TEMPLATE(Saw)
DECL_TEMPLATE(Square)
#undef DECL_TEMPLATE
static void ALmodulatorState_Construct(ALmodulatorState *state)
{
ALuint i;
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALmodulatorState, ALeffectState, state);
state->index = 0;
state->step = 1;
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
ALfilterState_clear(&state->Filter[i]);
}
static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), ALCdevice *UNUSED(device))
{
return AL_TRUE;
}
static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
{
ALfloat cw, a;
ALsizei i;
if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
state->Process = ModulateSin;
else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
state->Process = ModulateSaw;
else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
state->Process = ModulateSquare;
state->step = fastf2i(props->Modulator.Frequency*WAVEFORM_FRACONE /
Device->Frequency);
if(state->step == 0) state->step = 1;
/* Custom filter coeffs, which match the old version instead of a low-shelf. */
cw = cosf(F_TAU * props->Modulator.HighPassCutoff / Device->Frequency);
a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f);
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
{
state->Filter[i].b0 = a;
state->Filter[i].b1 = -a;
state->Filter[i].b2 = 0.0f;
state->Filter[i].a1 = -a;
state->Filter[i].a2 = 0.0f;
}
STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer;
STATIC_CAST(ALeffectState,state)->OutChannels = Device->FOAOut.NumChannels;
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
ComputeFirstOrderGains(Device->FOAOut, IdentityMatrixf.m[i],
Slot->Params.Gain, state->Gain[i]);
}
static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
const ALsizei step = state->step;
ALsizei index = state->index;
ALsizei base;
for(base = 0;base < SamplesToDo;)
{
ALfloat temps[2][128];
ALsizei td = mini(128, SamplesToDo-base);
ALsizei i, j, k;
for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
{
ALfilterState_process(&state->Filter[j], temps[0], &SamplesIn[j][base], td);
state->Process(temps[1], temps[0], index, step, td);
for(k = 0;k < NumChannels;k++)
{
ALfloat gain = state->Gain[j][k];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(i = 0;i < td;i++)
SamplesOut[k][base+i] += gain * temps[1][i];
}
}
for(i = 0;i < td;i++)
{
index += step;
index &= WAVEFORM_FRACMASK;
}
base += td;
}
state->index = index;
}
typedef struct ALmodulatorStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALmodulatorStateFactory;
static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UNUSED(factory))
{
ALmodulatorState *state;
NEW_OBJ0(state, ALmodulatorState)();
if(!state) return NULL;
return STATIC_CAST(ALeffectState, state);
}
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALmodulatorStateFactory);
ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void)
{
static ALmodulatorStateFactory ModulatorFactory = { { GET_VTABLE2(ALmodulatorStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(ALeffectStateFactory, &ModulatorFactory);
}
void ALmodulator_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_RING_MODULATOR_FREQUENCY:
if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Modulator.Frequency = val;
break;
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Modulator.HighPassCutoff = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALmodulator_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{
ALmodulator_setParamf(effect, context, param, vals[0]);
}
void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
{
ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_RING_MODULATOR_FREQUENCY:
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
ALmodulator_setParamf(effect, context, param, (ALfloat)val);
break;
case AL_RING_MODULATOR_WAVEFORM:
if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Modulator.Waveform = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALmodulator_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALmodulator_setParami(effect, context, param, vals[0]);
}
void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_RING_MODULATOR_FREQUENCY:
*val = (ALint)props->Modulator.Frequency;
break;
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
*val = (ALint)props->Modulator.HighPassCutoff;
break;
case AL_RING_MODULATOR_WAVEFORM:
*val = props->Modulator.Waveform;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALmodulator_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALmodulator_getParami(effect, context, param, vals);
}
void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
switch(param)
{
case AL_RING_MODULATOR_FREQUENCY:
*val = props->Modulator.Frequency;
break;
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
*val = props->Modulator.HighPassCutoff;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALmodulator_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{
ALmodulator_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALmodulator);
-179
View File
@@ -1,179 +0,0 @@
#include "config.h"
#include <stdlib.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
typedef struct ALnullState {
DERIVE_FROM_TYPE(ALeffectState);
} ALnullState;
/* Forward-declare "virtual" functions to define the vtable with. */
static ALvoid ALnullState_Destruct(ALnullState *state);
static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device);
static ALvoid ALnullState_update(ALnullState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloatBUFFERSIZE*restrict samplesIn, ALfloatBUFFERSIZE*restrict samplesOut, ALsizei NumChannels);
static void *ALnullState_New(size_t size);
static void ALnullState_Delete(void *ptr);
/* Define the ALeffectState vtable for this type. */
DEFINE_ALEFFECTSTATE_VTABLE(ALnullState);
/* This constructs the effect state. It's called when the object is first
* created. Make sure to call the parent Construct function first, and set the
* vtable!
*/
static void ALnullState_Construct(ALnullState *state)
{
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALnullState, ALeffectState, state);
}
/* This destructs (not free!) the effect state. It's called only when the
* effect slot is no longer used. Make sure to call the parent Destruct
* function before returning!
*/
static ALvoid ALnullState_Destruct(ALnullState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
/* This updates the device-dependant effect state. This is called on
* initialization and any time the device parameters (eg. playback frequency,
* format) have been changed.
*/
static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice* UNUSED(device))
{
return AL_TRUE;
}
/* This updates the effect state. This is called any time the effect is
* (re)loaded into a slot.
*/
static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCdevice* UNUSED(device), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props))
{
}
/* This processes the effect state, for the given number of samples from the
* input to the output buffer. The result should be added to the output buffer,
* not replace it.
*/
static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALsizei UNUSED(NumChannels))
{
}
/* This allocates memory to store the object, before it gets constructed.
* DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method.
*/
static void *ALnullState_New(size_t size)
{
return al_malloc(16, size);
}
/* This frees the memory used by the object, after it has been destructed.
* DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method.
*/
static void ALnullState_Delete(void *ptr)
{
al_free(ptr);
}
typedef struct ALnullStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALnullStateFactory;
/* Creates ALeffectState objects of the appropriate type. */
ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory))
{
ALnullState *state;
NEW_OBJ0(state, ALnullState)();
if(!state) return NULL;
return STATIC_CAST(ALeffectState, state);
}
/* Define the ALeffectStateFactory vtable for this type. */
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALnullStateFactory);
ALeffectStateFactory *ALnullStateFactory_getFactory(void)
{
static ALnullStateFactory NullFactory = { { GET_VTABLE2(ALnullStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(ALeffectStateFactory, &NullFactory);
}
void ALnull_setParami(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
{
switch(param)
{
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_setParamiv(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, const ALint* UNUSED(vals))
{
switch(param)
{
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_setParamf(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val))
{
switch(param)
{
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_setParamfv(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals))
{
switch(param)
{
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_getParami(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(val))
{
switch(param)
{
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_getParamiv(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(vals))
{
switch(param)
{
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_getParamf(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(val))
{
switch(param)
{
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_getParamfv(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(vals))
{
switch(param)
{
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
DEFINE_ALEFFECT_VTABLE(ALnull);
-2407
View File
File diff suppressed because it is too large Load Diff
-1154
View File
File diff suppressed because it is too large Load Diff
-1154
View File
File diff suppressed because it is too large Load Diff
-52
View File
@@ -1,52 +0,0 @@
#ifndef ALC_HRTF_H
#define ALC_HRTF_H
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alstring.h"
#include "atomic.h"
/* The maximum number of virtual speakers used to generate HRTF coefficients
* for decoding B-Format.
*/
#define HRTF_AMBI_MAX_CHANNELS 16
struct HrtfEntry;
struct Hrtf {
RefCount ref;
ALuint sampleRate;
ALsizei irSize;
ALubyte evCount;
const ALubyte *azCount;
const ALushort *evOffset;
const ALfloat (*coeffs)[2];
const ALubyte (*delays)[2];
};
void FreeHrtfs(void);
vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname);
void FreeHrtfList(vector_EnumeratedHrtf *list);
struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry);
void Hrtf_IncRef(struct Hrtf *hrtf);
void Hrtf_DecRef(struct Hrtf *hrtf);
void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays);
/**
* Produces HRTF filter coefficients for decoding B-Format, given a set of
* virtual speaker positions and HF/LF matrices for decoding to them. The
* returned coefficients are ordered and scaled according to the matrices.
* Returns the maximum impulse-response length of the generated coefficients.
*/
ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[2][MAX_AMBI_COEFFS], ALsizei AmbiCount);
#endif /* ALC_HRTF_H */
-255
View File
@@ -1,255 +0,0 @@
#include "config.h"
#include <math.h>
#include "alu.h"
#include "almalloc.h"
#define RMS_WINDOW_SIZE (1<<7)
#define RMS_WINDOW_MASK (RMS_WINDOW_SIZE-1)
#define RMS_VALUE_MAX (1<<24)
#define LOOKAHEAD_SIZE (1<<13)
#define LOOKAHEAD_MASK (LOOKAHEAD_SIZE-1)
static_assert(RMS_VALUE_MAX < (UINT_MAX / RMS_WINDOW_SIZE), "RMS_VALUE_MAX is too big");
typedef struct Compressor {
ALfloat PreGain;
ALfloat PostGain;
ALboolean SummedLink;
ALfloat AttackMin;
ALfloat AttackMax;
ALfloat ReleaseMin;
ALfloat ReleaseMax;
ALfloat Ratio;
ALfloat Threshold;
ALfloat Knee;
ALuint SampleRate;
ALuint RmsSum;
ALuint *RmsWindow;
ALsizei RmsIndex;
ALfloat Envelope[BUFFERSIZE];
ALfloat EnvLast;
} Compressor;
/* Multichannel compression is linked via one of two modes:
*
* Summed - Absolute sum of all channels.
* Maxed - Absolute maximum of any channel.
*/
static void SumChannels(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
ALfloat (*restrict OutBuffer)[BUFFERSIZE])
{
ALsizei c, i;
for(i = 0;i < SamplesToDo;i++)
Comp->Envelope[i] = 0.0f;
for(c = 0;c < NumChans;c++)
{
for(i = 0;i < SamplesToDo;i++)
Comp->Envelope[i] += OutBuffer[c][i];
}
for(i = 0;i < SamplesToDo;i++)
Comp->Envelope[i] = fabsf(Comp->Envelope[i]);
}
static void MaxChannels(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
ALfloat (*restrict OutBuffer)[BUFFERSIZE])
{
ALsizei c, i;
for(i = 0;i < SamplesToDo;i++)
Comp->Envelope[i] = 0.0f;
for(c = 0;c < NumChans;c++)
{
for(i = 0;i < SamplesToDo;i++)
Comp->Envelope[i] = maxf(Comp->Envelope[i], fabsf(OutBuffer[c][i]));
}
}
/* Envelope detection/sensing can be done via:
*
* RMS - Rectangular windowed root mean square of linking stage.
* Peak - Implicit output from linking stage.
*/
static void RmsDetection(Compressor *Comp, const ALsizei SamplesToDo)
{
ALuint sum = Comp->RmsSum;
ALuint *window = Comp->RmsWindow;
ALsizei index = Comp->RmsIndex;
ALsizei i;
for(i = 0;i < SamplesToDo;i++)
{
ALfloat sig = Comp->Envelope[i];
sum -= window[index];
window[index] = fastf2i(minf(sig * sig * 65536.0f, RMS_VALUE_MAX));
sum += window[index];
index = (index + 1) & RMS_WINDOW_MASK;
Comp->Envelope[i] = sqrtf(sum / 65536.0f / RMS_WINDOW_SIZE);
}
Comp->RmsSum = sum;
Comp->RmsIndex = index;
}
/* This isn't a very sophisticated envelope follower, but it gets the job
* done. First, it operates at logarithmic scales to keep transitions
* appropriate for human hearing. Second, it can apply adaptive (automated)
* attack/release adjustments based on the signal.
*/
static void FollowEnvelope(Compressor *Comp, const ALsizei SamplesToDo)
{
ALfloat attackMin = Comp->AttackMin;
ALfloat attackMax = Comp->AttackMax;
ALfloat releaseMin = Comp->ReleaseMin;
ALfloat releaseMax = Comp->ReleaseMax;
ALfloat last = Comp->EnvLast;
ALsizei i;
for(i = 0;i < SamplesToDo;i++)
{
ALfloat env = maxf(-6.0f, log10f(Comp->Envelope[i]));
ALfloat slope = minf(1.0f, fabsf(env - last) / 4.5f);
if(env > last)
last = minf(env, last + lerp(attackMin, attackMax, 1.0f - (slope * slope)));
else
last = maxf(env, last + lerp(releaseMin, releaseMax, 1.0f - (slope * slope)));
Comp->Envelope[i] = last;
}
Comp->EnvLast = last;
}
/* The envelope is converted to control gain with an optional soft knee. */
static void EnvelopeGain(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat Slope)
{
const ALfloat threshold = Comp->Threshold;
const ALfloat knee = Comp->Knee;
ALsizei i;
if(!(knee > 0.0f))
{
for(i = 0;i < SamplesToDo;i++)
{
ALfloat gain = Slope * (threshold - Comp->Envelope[i]);
Comp->Envelope[i] = powf(10.0f, minf(0.0f, gain));
}
}
else
{
const ALfloat lower = threshold - (0.5f * knee);
const ALfloat upper = threshold + (0.5f * knee);
const ALfloat m = 0.5f * Slope / knee;
for(i = 0;i < SamplesToDo;i++)
{
ALfloat env = Comp->Envelope[i];
ALfloat gain;
if(env > lower && env < upper)
gain = m * (env - lower) * (lower - env);
else
gain = Slope * (threshold - env);
Comp->Envelope[i] = powf(10.0f, minf(0.0f, gain));
}
}
}
Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb,
const ALboolean SummedLink, const ALboolean RmsSensing,
const ALfloat AttackTimeMin, const ALfloat AttackTimeMax,
const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax,
const ALfloat Ratio, const ALfloat ThresholdDb,
const ALfloat KneeDb, const ALuint SampleRate)
{
Compressor *Comp;
size_t size;
ALsizei i;
size = sizeof(*Comp);
if(RmsSensing)
size += sizeof(Comp->RmsWindow[0]) * RMS_WINDOW_SIZE;
Comp = al_calloc(16, size);
Comp->PreGain = powf(10.0f, PreGainDb / 20.0f);
Comp->PostGain = powf(10.0f, PostGainDb / 20.0f);
Comp->SummedLink = SummedLink;
Comp->AttackMin = 1.0f / maxf(0.000001f, AttackTimeMin * SampleRate * logf(10.0f));
Comp->AttackMax = 1.0f / maxf(0.000001f, AttackTimeMax * SampleRate * logf(10.0f));
Comp->ReleaseMin = -1.0f / maxf(0.000001f, ReleaseTimeMin * SampleRate * logf(10.0f));
Comp->ReleaseMax = -1.0f / maxf(0.000001f, ReleaseTimeMax * SampleRate * logf(10.0f));
Comp->Ratio = Ratio;
Comp->Threshold = ThresholdDb / 20.0f;
Comp->Knee = maxf(0.0f, KneeDb / 20.0f);
Comp->SampleRate = SampleRate;
Comp->RmsSum = 0;
if(RmsSensing)
Comp->RmsWindow = (ALuint*)(Comp+1);
else
Comp->RmsWindow = NULL;
Comp->RmsIndex = 0;
for(i = 0;i < BUFFERSIZE;i++)
Comp->Envelope[i] = 0.0f;
Comp->EnvLast = -6.0f;
return Comp;
}
ALuint GetCompressorSampleRate(const Compressor *Comp)
{
return Comp->SampleRate;
}
void ApplyCompression(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
ALfloat (*restrict OutBuffer)[BUFFERSIZE])
{
ALsizei c, i;
if(Comp->PreGain != 1.0f)
{
for(c = 0;c < NumChans;c++)
{
for(i = 0;i < SamplesToDo;i++)
OutBuffer[c][i] *= Comp->PreGain;
}
}
if(Comp->SummedLink)
SumChannels(Comp, NumChans, SamplesToDo, OutBuffer);
else
MaxChannels(Comp, NumChans, SamplesToDo, OutBuffer);
if(Comp->RmsWindow)
RmsDetection(Comp, SamplesToDo);
FollowEnvelope(Comp, SamplesToDo);
if(Comp->Ratio > 0.0f)
EnvelopeGain(Comp, SamplesToDo, 1.0f - (1.0f / Comp->Ratio));
else
EnvelopeGain(Comp, SamplesToDo, 1.0f);
if(Comp->PostGain != 1.0f)
{
for(i = 0;i < SamplesToDo;i++)
Comp->Envelope[i] *= Comp->PostGain;
}
for(c = 0;c < NumChans;c++)
{
for(i = 0;i < SamplesToDo;i++)
OutBuffer[c][i] *= Comp->Envelope[i];
}
}
-671
View File
@@ -1,671 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
#include "alSource.h"
#include "alBuffer.h"
#include "alListener.h"
#include "alAuxEffectSlot.h"
#include "alu.h"
#include "mixer_defs.h"
static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE,
"MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size);
/* BSinc requires up to 11 extra samples before the current position, and 12 after. */
static_assert(MAX_PRE_SAMPLES >= 11, "MAX_PRE_SAMPLES must be at least 11!");
static_assert(MAX_POST_SAMPLES >= 12, "MAX_POST_SAMPLES must be at least 12!");
enum Resampler ResamplerDefault = LinearResampler;
static MixerFunc MixSamples = Mix_C;
static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C;
MixerFunc SelectMixer(void)
{
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return Mix_Neon;
#endif
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
return Mix_SSE;
#endif
return Mix_C;
}
RowMixerFunc SelectRowMixer(void)
{
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return MixRow_Neon;
#endif
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
return MixRow_SSE;
#endif
return MixRow_C;
}
static inline HrtfMixerFunc SelectHrtfMixer(void)
{
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return MixHrtf_Neon;
#endif
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
return MixHrtf_SSE;
#endif
return MixHrtf_C;
}
static inline HrtfMixerBlendFunc SelectHrtfBlendMixer(void)
{
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return MixHrtfBlend_Neon;
#endif
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
return MixHrtfBlend_SSE;
#endif
return MixHrtfBlend_C;
}
ResamplerFunc SelectResampler(enum Resampler resampler)
{
switch(resampler)
{
case PointResampler:
return Resample_point32_C;
case LinearResampler:
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return Resample_lerp32_Neon;
#endif
#ifdef HAVE_SSE4_1
if((CPUCapFlags&CPU_CAP_SSE4_1))
return Resample_lerp32_SSE41;
#endif
#ifdef HAVE_SSE2
if((CPUCapFlags&CPU_CAP_SSE2))
return Resample_lerp32_SSE2;
#endif
return Resample_lerp32_C;
case FIR4Resampler:
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return Resample_fir4_32_Neon;
#endif
#ifdef HAVE_SSE4_1
if((CPUCapFlags&CPU_CAP_SSE4_1))
return Resample_fir4_32_SSE41;
#endif
#ifdef HAVE_SSE3
if((CPUCapFlags&CPU_CAP_SSE3))
return Resample_fir4_32_SSE3;
#endif
return Resample_fir4_32_C;
case BSincResampler:
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return Resample_bsinc32_Neon;
#endif
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
return Resample_bsinc32_SSE;
#endif
return Resample_bsinc32_C;
}
return Resample_point32_C;
}
void aluInitMixer(void)
{
const char *str;
if(ConfigValueStr(NULL, NULL, "resampler", &str))
{
if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0)
ResamplerDefault = PointResampler;
else if(strcasecmp(str, "linear") == 0)
ResamplerDefault = LinearResampler;
else if(strcasecmp(str, "sinc4") == 0)
ResamplerDefault = FIR4Resampler;
else if(strcasecmp(str, "bsinc") == 0)
ResamplerDefault = BSincResampler;
else if(strcasecmp(str, "cubic") == 0 || strcasecmp(str, "sinc8") == 0)
{
WARN("Resampler option \"%s\" is deprecated, using sinc4\n", str);
ResamplerDefault = FIR4Resampler;
}
else
{
char *end;
long n = strtol(str, &end, 0);
if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler))
ResamplerDefault = n;
else
WARN("Invalid resampler: %s\n", str);
}
}
MixHrtfBlendSamples = SelectHrtfBlendMixer();
MixHrtfSamples = SelectHrtfMixer();
MixSamples = SelectMixer();
}
static inline ALfloat Sample_ALbyte(ALbyte val)
{ return val * (1.0f/128.0f); }
static inline ALfloat Sample_ALshort(ALshort val)
{ return val * (1.0f/32768.0f); }
static inline ALfloat Sample_ALfloat(ALfloat val)
{ return val; }
#define DECL_TEMPLATE(T) \
static inline void Load_##T(ALfloat *dst, const T *src, ALint srcstep, ALsizei samples)\
{ \
ALsizei i; \
for(i = 0;i < samples;i++) \
dst[i] = Sample_##T(src[i*srcstep]); \
}
DECL_TEMPLATE(ALbyte)
DECL_TEMPLATE(ALshort)
DECL_TEMPLATE(ALfloat)
#undef DECL_TEMPLATE
static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum FmtType srctype, ALsizei samples)
{
switch(srctype)
{
case FmtByte:
Load_ALbyte(dst, src, srcstep, samples);
break;
case FmtShort:
Load_ALshort(dst, src, srcstep, samples);
break;
case FmtFloat:
Load_ALfloat(dst, src, srcstep, samples);
break;
}
}
static inline void SilenceSamples(ALfloat *dst, ALsizei samples)
{
ALsizei i;
for(i = 0;i < samples;i++)
dst[i] = 0.0f;
}
static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
ALfloat *restrict dst, const ALfloat *restrict src,
ALsizei numsamples, enum ActiveFilters type)
{
ALsizei i;
switch(type)
{
case AF_None:
ALfilterState_processPassthru(lpfilter, src, numsamples);
ALfilterState_processPassthru(hpfilter, src, numsamples);
break;
case AF_LowPass:
ALfilterState_process(lpfilter, dst, src, numsamples);
ALfilterState_processPassthru(hpfilter, dst, numsamples);
return dst;
case AF_HighPass:
ALfilterState_processPassthru(lpfilter, src, numsamples);
ALfilterState_process(hpfilter, dst, src, numsamples);
return dst;
case AF_BandPass:
for(i = 0;i < numsamples;)
{
ALfloat temp[256];
ALsizei todo = mini(256, numsamples-i);
ALfilterState_process(lpfilter, temp, src+i, todo);
ALfilterState_process(hpfilter, dst+i, temp, todo);
i += todo;
}
return dst;
}
return src;
}
ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo)
{
ALbufferlistitem *BufferListItem;
ALbufferlistitem *BufferLoopItem;
ALsizei NumChannels, SampleSize;
ResamplerFunc Resample;
ALsizei DataPosInt;
ALsizei DataPosFrac;
ALint64 DataSize64;
ALint increment;
ALsizei Counter;
ALsizei OutPos;
ALsizei IrSize;
bool isplaying;
bool firstpass;
ALsizei chan;
ALsizei send;
/* Get source info */
isplaying = true; /* Will only be called while playing. */
DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire);
DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
BufferLoopItem = ATOMIC_LOAD(&voice->loop_buffer, almemory_order_relaxed);
NumChannels = voice->NumChannels;
SampleSize = voice->SampleSize;
increment = voice->Step;
IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0);
Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
Resample_copy32_C : voice->Resampler);
Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0;
firstpass = true;
OutPos = 0;
do {
ALsizei SrcBufferSize, DstBufferSize;
/* Figure out how many buffer samples will be needed */
DataSize64 = SamplesToDo-OutPos;
DataSize64 *= increment;
DataSize64 += DataPosFrac+FRACTIONMASK;
DataSize64 >>= FRACTIONBITS;
DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE);
/* Figure out how many samples we can actually mix from this. */
DataSize64 = SrcBufferSize;
DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
DataSize64 <<= FRACTIONBITS;
DataSize64 -= DataPosFrac;
DstBufferSize = (ALsizei)((DataSize64+(increment-1)) / increment);
DstBufferSize = mini(DstBufferSize, (SamplesToDo-OutPos));
/* Some mixers like having a multiple of 4, so try to give that unless
* this is the last update. */
if(OutPos+DstBufferSize < SamplesToDo)
DstBufferSize &= ~3;
for(chan = 0;chan < NumChannels;chan++)
{
const ALfloat *ResampledData;
ALfloat *SrcData = Device->SourceData;
ALsizei SrcDataSize;
/* Load the previous samples into the source data first. */
memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat));
SrcDataSize = MAX_PRE_SAMPLES;
if(Source->SourceType == AL_STATIC)
{
const ALbuffer *ALBuffer = BufferListItem->buffer;
const ALubyte *Data = ALBuffer->data;
ALsizei DataSize;
/* Offset buffer data to current channel */
Data += chan*SampleSize;
/* If current pos is beyond the loop range, do not loop */
if(!BufferLoopItem || DataPosInt >= ALBuffer->LoopEnd)
{
BufferLoopItem = NULL;
/* Load what's left to play from the source buffer, and
* clear the rest of the temp buffer */
DataSize = minu(SrcBufferSize - SrcDataSize,
ALBuffer->SampleLen - DataPosInt);
LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
SrcDataSize += SrcBufferSize - SrcDataSize;
}
else
{
ALsizei LoopStart = ALBuffer->LoopStart;
ALsizei LoopEnd = ALBuffer->LoopEnd;
/* Load what's left of this loop iteration, then load
* repeats of the loop section */
DataSize = minu(SrcBufferSize - SrcDataSize, LoopEnd - DataPosInt);
LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
DataSize = LoopEnd-LoopStart;
while(SrcBufferSize > SrcDataSize)
{
DataSize = mini(SrcBufferSize - SrcDataSize, DataSize);
LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
}
}
}
else
{
/* Crawl the buffer queue to fill in the temp buffer */
ALbufferlistitem *tmpiter = BufferListItem;
ALsizei pos = DataPosInt;
while(tmpiter && SrcBufferSize > SrcDataSize)
{
const ALbuffer *ALBuffer;
if((ALBuffer=tmpiter->buffer) != NULL)
{
const ALubyte *Data = ALBuffer->data;
ALsizei DataSize = ALBuffer->SampleLen;
/* Skip the data already played */
if(DataSize <= pos)
pos -= DataSize;
else
{
Data += (pos*NumChannels + chan)*SampleSize;
DataSize -= pos;
pos -= pos;
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
LoadSamples(&SrcData[SrcDataSize], Data, NumChannels,
ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
}
}
tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire);
if(!tmpiter && BufferLoopItem)
tmpiter = BufferLoopItem;
else if(!tmpiter)
{
SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
SrcDataSize += SrcBufferSize - SrcDataSize;
}
}
}
/* Store the last source samples used for next time. */
memcpy(voice->PrevSamples[chan],
&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
MAX_PRE_SAMPLES*sizeof(ALfloat)
);
/* Now resample, then filter and mix to the appropriate outputs. */
ResampledData = Resample(&voice->ResampleState,
&SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment,
Device->ResampledData, DstBufferSize
);
{
DirectParams *parms = &voice->Direct.Params[chan];
const ALfloat *samples;
samples = DoFilters(
&parms->LowPass, &parms->HighPass, Device->FilteredData,
ResampledData, DstBufferSize, voice->Direct.FilterType
);
if(!(voice->Flags&VOICE_HAS_HRTF))
{
if(!Counter)
memcpy(parms->Gains.Current, parms->Gains.Target,
sizeof(parms->Gains.Current));
if(!(voice->Flags&VOICE_HAS_NFC))
MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer,
parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
DstBufferSize
);
else
{
ALfloat *nfcsamples = Device->NFCtrlData;
ALsizei chanoffset = 0;
MixSamples(samples,
voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer,
parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
DstBufferSize
);
chanoffset += voice->Direct.ChannelsPerOrder[0];
#define APPLY_NFC_MIX(order) \
if(voice->Direct.ChannelsPerOrder[order] > 0) \
{ \
NfcFilterUpdate##order(&parms->NFCtrlFilter[order-1], nfcsamples, \
samples, DstBufferSize); \
MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \
voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \
parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \
); \
chanoffset += voice->Direct.ChannelsPerOrder[order]; \
}
APPLY_NFC_MIX(1)
APPLY_NFC_MIX(2)
APPLY_NFC_MIX(3)
#undef APPLY_NFC_MIX
}
}
else
{
MixHrtfParams hrtfparams;
ALsizei fademix = 0;
int lidx, ridx;
lidx = GetChannelIdxByName(Device->RealOut, FrontLeft);
ridx = GetChannelIdxByName(Device->RealOut, FrontRight);
assert(lidx != -1 && ridx != -1);
if(!Counter)
{
/* No fading, just overwrite the old HRTF params. */
parms->Hrtf.Old = parms->Hrtf.Target;
}
else if(!(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD))
{
/* The old HRTF params are silent, so overwrite the old
* coefficients with the new, and reset the old gain to
* 0. The future mix will then fade from silence.
*/
parms->Hrtf.Old = parms->Hrtf.Target;
parms->Hrtf.Old.Gain = 0.0f;
}
else if(firstpass)
{
ALfloat gain;
/* Fade between the coefficients over 128 samples. */
fademix = mini(DstBufferSize, 128);
/* The new coefficients need to fade in completely
* since they're replacing the old ones. To keep the
* gain fading consistent, interpolate between the old
* and new target gains given how much of the fade time
* this mix handles.
*/
gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain,
minf(1.0f, (ALfloat)fademix/Counter));
hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs);
hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0];
hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1];
hrtfparams.Gain = 0.0f;
hrtfparams.GainStep = gain / (ALfloat)fademix;
MixHrtfBlendSamples(
voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx],
samples, voice->Offset, OutPos, IrSize, &parms->Hrtf.Old,
&hrtfparams, &parms->Hrtf.State, fademix
);
/* Update the old parameters with the result. */
parms->Hrtf.Old = parms->Hrtf.Target;
if(fademix < Counter)
parms->Hrtf.Old.Gain = hrtfparams.Gain;
}
if(fademix < DstBufferSize)
{
ALsizei todo = DstBufferSize - fademix;
ALfloat gain = parms->Hrtf.Target.Gain;
/* Interpolate the target gain if the gain fading lasts
* longer than this mix.
*/
if(Counter > DstBufferSize)
gain = lerp(parms->Hrtf.Old.Gain, gain,
(ALfloat)todo/(Counter-fademix));
hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs);
hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0];
hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1];
hrtfparams.Gain = parms->Hrtf.Old.Gain;
hrtfparams.GainStep = (gain - parms->Hrtf.Old.Gain) / (ALfloat)todo;
MixHrtfSamples(
voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx],
samples+fademix, voice->Offset+fademix, OutPos+fademix, IrSize,
&hrtfparams, &parms->Hrtf.State, todo
);
/* Store the interpolated gain or the final target gain
* depending if the fade is done.
*/
if(DstBufferSize < Counter)
parms->Hrtf.Old.Gain = gain;
else
parms->Hrtf.Old.Gain = parms->Hrtf.Target.Gain;
}
}
}
for(send = 0;send < Device->NumAuxSends;send++)
{
SendParams *parms = &voice->Send[send].Params[chan];
const ALfloat *samples;
if(!voice->Send[send].Buffer)
continue;
samples = DoFilters(
&parms->LowPass, &parms->HighPass, Device->FilteredData,
ResampledData, DstBufferSize, voice->Send[send].FilterType
);
if(!Counter)
memcpy(parms->Gains.Current, parms->Gains.Target,
sizeof(parms->Gains.Current));
MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer,
parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize
);
}
}
/* Update positions */
DataPosFrac += increment*DstBufferSize;
DataPosInt += DataPosFrac>>FRACTIONBITS;
DataPosFrac &= FRACTIONMASK;
OutPos += DstBufferSize;
voice->Offset += DstBufferSize;
Counter = maxi(DstBufferSize, Counter) - DstBufferSize;
firstpass = false;
/* Handle looping sources */
while(1)
{
const ALbuffer *ALBuffer;
ALsizei DataSize = 0;
ALsizei LoopStart = 0;
ALsizei LoopEnd = 0;
if((ALBuffer=BufferListItem->buffer) != NULL)
{
DataSize = ALBuffer->SampleLen;
LoopStart = ALBuffer->LoopStart;
LoopEnd = ALBuffer->LoopEnd;
if(LoopEnd > DataPosInt)
break;
}
if(BufferLoopItem && Source->SourceType == AL_STATIC)
{
assert(LoopEnd > LoopStart);
DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
break;
}
if(DataSize > DataPosInt)
break;
BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire);
if(!BufferListItem)
{
BufferListItem = BufferLoopItem;
if(!BufferListItem)
{
isplaying = false;
DataPosInt = 0;
DataPosFrac = 0;
break;
}
}
DataPosInt -= DataSize;
}
} while(isplaying && OutPos < SamplesToDo);
voice->Flags |= VOICE_IS_FADING;
/* Update source info */
ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed);
ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed);
ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release);
return isplaying;
}
-208
View File
@@ -1,208 +0,0 @@
#include "config.h"
#include <assert.h>
#include "alMain.h"
#include "alu.h"
#include "alSource.h"
#include "alAuxEffectSlot.h"
static inline ALfloat point32(const ALfloat *restrict vals, ALsizei UNUSED(frac))
{ return vals[0]; }
static inline ALfloat lerp32(const ALfloat *restrict vals, ALsizei frac)
{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); }
static inline ALfloat fir4_32(const ALfloat *restrict vals, ALsizei frac)
{ return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); }
const ALfloat *Resample_copy32_C(const InterpState* UNUSED(state),
const ALfloat *restrict src, ALsizei UNUSED(frac), ALint UNUSED(increment),
ALfloat *restrict dst, ALsizei numsamples)
{
#if defined(HAVE_SSE) || defined(HAVE_NEON)
/* Avoid copying the source data if it's aligned like the destination. */
if((((intptr_t)src)&15) == (((intptr_t)dst)&15))
return src;
#endif
memcpy(dst, src, numsamples*sizeof(ALfloat));
return dst;
}
#define DECL_TEMPLATE(Sampler) \
const ALfloat *Resample_##Sampler##_C(const InterpState* UNUSED(state), \
const ALfloat *restrict src, ALsizei frac, ALint increment, \
ALfloat *restrict dst, ALsizei numsamples) \
{ \
ALsizei i; \
for(i = 0;i < numsamples;i++) \
{ \
dst[i] = Sampler(src, frac); \
\
frac += increment; \
src += frac>>FRACTIONBITS; \
frac &= FRACTIONMASK; \
} \
return dst; \
}
DECL_TEMPLATE(point32)
DECL_TEMPLATE(lerp32)
DECL_TEMPLATE(fir4_32)
#undef DECL_TEMPLATE
const ALfloat *Resample_bsinc32_C(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei dstlen)
{
const ALfloat *fil, *scd, *phd, *spd;
const ALfloat sf = state->bsinc.sf;
const ALsizei m = state->bsinc.m;
ALsizei j_f, pi, i;
ALfloat pf, r;
src += state->bsinc.l;
for(i = 0;i < dstlen;i++)
{
// Calculate the phase index and factor.
#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
pi = frac >> FRAC_PHASE_BITDIFF;
pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
#undef FRAC_PHASE_BITDIFF
fil = ASSUME_ALIGNED(state->bsinc.coeffs[pi].filter, 16);
scd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].scDelta, 16);
phd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].phDelta, 16);
spd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].spDelta, 16);
// Apply the scale and phase interpolated filter.
r = 0.0f;
for(j_f = 0;j_f < m;j_f++)
r += (fil[j_f] + sf*scd[j_f] + pf*(phd[j_f] + sf*spd[j_f])) * src[j_f];
dst[i] = r;
frac += increment;
src += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples)
{
ALsizei i;
if(numsamples > 1)
{
dst[0] = filter->b0 * src[0] +
filter->b1 * filter->x[0] +
filter->b2 * filter->x[1] -
filter->a1 * filter->y[0] -
filter->a2 * filter->y[1];
dst[1] = filter->b0 * src[1] +
filter->b1 * src[0] +
filter->b2 * filter->x[0] -
filter->a1 * dst[0] -
filter->a2 * filter->y[0];
for(i = 2;i < numsamples;i++)
dst[i] = filter->b0 * src[i] +
filter->b1 * src[i-1] +
filter->b2 * src[i-2] -
filter->a1 * dst[i-1] -
filter->a2 * dst[i-2];
filter->x[0] = src[i-1];
filter->x[1] = src[i-2];
filter->y[0] = dst[i-1];
filter->y[1] = dst[i-2];
}
else if(numsamples == 1)
{
dst[0] = filter->b0 * src[0] +
filter->b1 * filter->x[0] +
filter->b2 * filter->x[1] -
filter->a1 * filter->y[0] -
filter->a2 * filter->y[1];
filter->x[1] = filter->x[0];
filter->x[0] = src[0];
filter->y[1] = filter->y[0];
filter->y[0] = dst[0];
}
}
static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
const ALsizei IrSize,
const ALfloat (*restrict Coeffs)[2],
ALfloat left, ALfloat right)
{
ALsizei c;
for(c = 0;c < IrSize;c++)
{
const ALsizei off = (Offset+c)&HRIR_MASK;
Values[off][0] += Coeffs[c][0] * left;
Values[off][1] += Coeffs[c][1] * right;
}
}
#define MixHrtf MixHrtf_C
#define MixHrtfBlend MixHrtfBlend_C
#define MixDirectHrtf MixDirectHrtf_C
#include "mixer_inc.c"
#undef MixHrtf
void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
ALsizei BufferSize)
{
ALfloat gain, delta, step;
ALsizei c;
delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
for(c = 0;c < OutChans;c++)
{
ALsizei pos = 0;
gain = CurrentGains[c];
step = (TargetGains[c] - gain) * delta;
if(fabsf(step) > FLT_EPSILON)
{
ALsizei minsize = mini(BufferSize, Counter);
for(;pos < minsize;pos++)
{
OutBuffer[c][OutPos+pos] += data[pos]*gain;
gain += step;
}
if(pos == Counter)
gain = TargetGains[c];
CurrentGains[c] = gain;
}
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
}
/* Basically the inverse of the above. Rather than one input going to multiple
* outputs (each with its own gain), it's multiple inputs (each with its own
* gain) going to one output. This applies one row (vs one column) of a matrix
* transform. And as the matrices are more or less static once set up, no
* stepping is necessary.
*/
void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize)
{
ALsizei c, i;
for(c = 0;c < InChans;c++)
{
ALfloat gain = Gains[c];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(i = 0;i < BufferSize;i++)
OutBuffer[i] += data[c][InPos+i] * gain;
}
}
-129
View File
@@ -1,129 +0,0 @@
#ifndef MIXER_DEFS_H
#define MIXER_DEFS_H
#include "AL/alc.h"
#include "AL/al.h"
#include "alMain.h"
#include "alu.h"
struct MixGains;
struct MixHrtfParams;
struct HrtfState;
/* C resamplers */
const ALfloat *Resample_copy32_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen);
const ALfloat *Resample_point32_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen);
const ALfloat *Resample_lerp32_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen);
const ALfloat *Resample_fir4_32_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen);
const ALfloat *Resample_bsinc32_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen);
/* C mixers */
void MixHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, struct MixHrtfParams *hrtfparams,
struct HrtfState *hrtfstate, ALsizei BufferSize);
void MixHrtfBlend_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, const HrtfParams *oldparams,
MixHrtfParams *newparams, HrtfState *hrtfstate,
ALsizei BufferSize);
void MixDirectHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
ALsizei BufferSize);
void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
ALsizei BufferSize);
void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains,
const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans,
ALsizei InPos, ALsizei BufferSize);
/* SSE mixers */
void MixHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, struct MixHrtfParams *hrtfparams,
struct HrtfState *hrtfstate, ALsizei BufferSize);
void MixHrtfBlend_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, const HrtfParams *oldparams,
MixHrtfParams *newparams, HrtfState *hrtfstate,
ALsizei BufferSize);
void MixDirectHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
ALsizei BufferSize);
void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
ALsizei BufferSize);
void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains,
const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans,
ALsizei InPos, ALsizei BufferSize);
/* SSE resamplers */
inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size)
{
ALsizei i;
pos_arr[0] = 0;
frac_arr[0] = frac;
for(i = 1;i < size;i++)
{
ALint frac_tmp = frac_arr[i-1] + increment;
pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS);
frac_arr[i] = frac_tmp&FRACTIONMASK;
}
}
const ALfloat *Resample_lerp32_SSE2(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_lerp32_SSE41(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_fir4_32_SSE3(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_fir4_32_SSE41(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_bsinc32_SSE(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei dstlen);
/* Neon mixers */
void MixHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, struct MixHrtfParams *hrtfparams,
struct HrtfState *hrtfstate, ALsizei BufferSize);
void MixHrtfBlend_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, const HrtfParams *oldparams,
MixHrtfParams *newparams, HrtfState *hrtfstate,
ALsizei BufferSize);
void MixDirectHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
ALsizei BufferSize);
void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
ALsizei BufferSize);
void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains,
const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans,
ALsizei InPos, ALsizei BufferSize);
/* Neon resamplers */
const ALfloat *Resample_lerp32_Neon(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_fir4_32_Neon(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_bsinc32_Neon(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei dstlen);
#endif /* MIXER_DEFS_H */
-114
View File
@@ -1,114 +0,0 @@
#include "config.h"
#include "alMain.h"
#include "alSource.h"
#include "hrtf.h"
#include "mixer_defs.h"
#include "align.h"
#include "alu.h"
static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
const ALsizei irSize,
const ALfloat (*restrict Coeffs)[2],
ALfloat left, ALfloat right);
void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate,
ALsizei BufferSize)
{
const ALfloat (*Coeffs)[2] = ASSUME_ALIGNED(hrtfparams->Coeffs, 16);
const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] };
ALfloat gainstep = hrtfparams->GainStep;
ALfloat gain = hrtfparams->Gain;
ALfloat left, right;
ALsizei i;
LeftOut += OutPos;
RightOut += OutPos;
for(i = 0;i < BufferSize;i++)
{
hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++);
left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*gain;
right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*gain;
hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f;
hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f;
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right);
*(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0];
*(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1];
gain += gainstep;
Offset++;
}
hrtfparams->Gain = gain;
}
void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, const HrtfParams *oldparams,
MixHrtfParams *newparams, HrtfState *hrtfstate,
ALsizei BufferSize)
{
const ALfloat (*OldCoeffs)[2] = ASSUME_ALIGNED(oldparams->Coeffs, 16);
const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] };
ALfloat oldGain = oldparams->Gain;
ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize;
const ALfloat (*NewCoeffs)[2] = ASSUME_ALIGNED(newparams->Coeffs, 16);
const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] };
ALfloat newGain = newparams->Gain;
ALfloat newGainStep = newparams->GainStep;
ALfloat left, right;
ALsizei i;
LeftOut += OutPos;
RightOut += OutPos;
for(i = 0;i < BufferSize;i++)
{
hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f;
hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f;
hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++);
left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*oldGain;
right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*oldGain;
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right);
left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*newGain;
right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*newGain;
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right);
*(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0];
*(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1];
oldGain += oldGainStep;
newGain += newGainStep;
Offset++;
}
newparams->Gain = newGain;
}
void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
ALsizei BufferSize)
{
ALfloat insample;
ALsizei i;
for(i = 0;i < BufferSize;i++)
{
Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
Offset++;
insample = *(data++);
ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample);
*(LeftOut++) += Values[Offset&HRIR_MASK][0];
*(RightOut++) += Values[Offset&HRIR_MASK][1];
}
}
-331
View File
@@ -1,331 +0,0 @@
#include "config.h"
#include <arm_neon.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alu.h"
#include "hrtf.h"
#include "mixer_defs.h"
const ALfloat *Resample_lerp32_Neon(const InterpState* UNUSED(state),
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei numsamples)
{
const int32x4_t increment4 = vdupq_n_s32(increment*4);
const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE);
const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK);
alignas(16) ALint pos_[4];
alignas(16) ALsizei frac_[4];
int32x4_t pos4;
int32x4_t frac4;
ALsizei i;
InitiatePositionArrays(frac, increment, frac_, pos_, 4);
frac4 = vld1q_s32(frac_);
pos4 = vld1q_s32(pos_);
for(i = 0;numsamples-i > 3;i += 4)
{
const float32x4_t val1 = (float32x4_t){src[pos_[0]], src[pos_[1]], src[pos_[2]], src[pos_[3]]};
const float32x4_t val2 = (float32x4_t){src[pos_[0]+1], src[pos_[1]+1], src[pos_[2]+1], src[pos_[3]+1]};
/* val1 + (val2-val1)*mu */
const float32x4_t r0 = vsubq_f32(val2, val1);
const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4);
const float32x4_t out = vmlaq_f32(val1, mu, r0);
vst1q_f32(&dst[i], out);
frac4 = vaddq_s32(frac4, increment4);
pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS));
frac4 = vandq_s32(frac4, fracMask4);
vst1q_s32(pos_, pos4);
}
if(i < numsamples)
{
/* NOTE: These four elements represent the position *after* the last
* four samples, so the lowest element is the next position to
* resample.
*/
ALint pos = pos_[0];
frac = vgetq_lane_s32(frac4, 0);
do {
dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
} while(++i < numsamples);
}
return dst;
}
const ALfloat *Resample_fir4_32_Neon(const InterpState* UNUSED(state),
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei numsamples)
{
const int32x4_t increment4 = vdupq_n_s32(increment*4);
const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK);
alignas(16) ALint pos_[4];
alignas(16) ALsizei frac_[4];
int32x4_t pos4;
int32x4_t frac4;
ALsizei i;
InitiatePositionArrays(frac, increment, frac_, pos_, 4);
frac4 = vld1q_s32(frac_);
pos4 = vld1q_s32(pos_);
--src;
for(i = 0;numsamples-i > 3;i += 4)
{
const float32x4_t val0 = vld1q_f32(&src[pos_[0]]);
const float32x4_t val1 = vld1q_f32(&src[pos_[1]]);
const float32x4_t val2 = vld1q_f32(&src[pos_[2]]);
const float32x4_t val3 = vld1q_f32(&src[pos_[3]]);
float32x4_t k0 = vld1q_f32(sinc4Tab[frac_[0]]);
float32x4_t k1 = vld1q_f32(sinc4Tab[frac_[1]]);
float32x4_t k2 = vld1q_f32(sinc4Tab[frac_[2]]);
float32x4_t k3 = vld1q_f32(sinc4Tab[frac_[3]]);
float32x4_t out;
k0 = vmulq_f32(k0, val0);
k1 = vmulq_f32(k1, val1);
k2 = vmulq_f32(k2, val2);
k3 = vmulq_f32(k3, val3);
k0 = vcombine_f32(vpadd_f32(vget_low_f32(k0), vget_high_f32(k0)),
vpadd_f32(vget_low_f32(k1), vget_high_f32(k1)));
k2 = vcombine_f32(vpadd_f32(vget_low_f32(k2), vget_high_f32(k2)),
vpadd_f32(vget_low_f32(k3), vget_high_f32(k3)));
out = vcombine_f32(vpadd_f32(vget_low_f32(k0), vget_high_f32(k0)),
vpadd_f32(vget_low_f32(k2), vget_high_f32(k2)));
vst1q_f32(&dst[i], out);
frac4 = vaddq_s32(frac4, increment4);
pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS));
frac4 = vandq_s32(frac4, fracMask4);
vst1q_s32(pos_, pos4);
vst1q_s32(frac_, frac4);
}
if(i < numsamples)
{
/* NOTE: These four elements represent the position *after* the last
* four samples, so the lowest element is the next position to
* resample.
*/
ALint pos = pos_[0];
frac = frac_[0];
do {
dst[i] = resample_fir4(src[pos], src[pos+1], src[pos+2], src[pos+3], frac);
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
} while(++i < numsamples);
}
return dst;
}
const ALfloat *Resample_bsinc32_Neon(const InterpState *state,
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei dstlen)
{
const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf);
const ALsizei m = state->bsinc.m;
const ALfloat *fil, *scd, *phd, *spd;
ALsizei pi, i, j;
float32x4_t r4;
ALfloat pf;
src += state->bsinc.l;
for(i = 0;i < dstlen;i++)
{
// Calculate the phase index and factor.
#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
pi = frac >> FRAC_PHASE_BITDIFF;
pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
#undef FRAC_PHASE_BITDIFF
fil = ASSUME_ALIGNED(state->bsinc.coeffs[pi].filter, 16);
scd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].scDelta, 16);
phd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].phDelta, 16);
spd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].spDelta, 16);
// Apply the scale and phase interpolated filter.
r4 = vdupq_n_f32(0.0f);
{
const float32x4_t pf4 = vdupq_n_f32(pf);
for(j = 0;j < m;j+=4)
{
/* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */
const float32x4_t f4 = vmlaq_f32(vmlaq_f32(vld1q_f32(&fil[j]),
sf4, vld1q_f32(&scd[j])),
pf4, vmlaq_f32(vld1q_f32(&phd[j]),
sf4, vld1q_f32(&spd[j])
)
);
/* r += f*src */
r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j]));
}
}
r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)),
vrev64_f32(vget_low_f32(r4))));
dst[i] = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0);
frac += increment;
src += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
const ALsizei IrSize,
const ALfloat (*restrict Coeffs)[2],
ALfloat left, ALfloat right)
{
ALsizei c;
float32x4_t leftright4;
{
float32x2_t leftright2 = vdup_n_f32(0.0);
leftright2 = vset_lane_f32(left, leftright2, 0);
leftright2 = vset_lane_f32(right, leftright2, 1);
leftright4 = vcombine_f32(leftright2, leftright2);
}
Values = ASSUME_ALIGNED(Values, 16);
Coeffs = ASSUME_ALIGNED(Coeffs, 16);
for(c = 0;c < IrSize;c += 2)
{
const ALsizei o0 = (Offset+c)&HRIR_MASK;
const ALsizei o1 = (o0+1)&HRIR_MASK;
float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]),
vld1_f32((float32_t*)&Values[o1][0]));
float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]);
vals = vmlaq_f32(vals, coefs, leftright4);
vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals));
vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals));
}
}
#define MixHrtf MixHrtf_Neon
#define MixHrtfBlend MixHrtfBlend_Neon
#define MixDirectHrtf MixDirectHrtf_Neon
#include "mixer_inc.c"
#undef MixHrtf
void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
ALsizei BufferSize)
{
ALfloat gain, delta, step;
float32x4_t gain4;
ALsizei c;
data = ASSUME_ALIGNED(data, 16);
OutBuffer = ASSUME_ALIGNED(OutBuffer, 16);
delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
for(c = 0;c < OutChans;c++)
{
ALsizei pos = 0;
gain = CurrentGains[c];
step = (TargetGains[c] - gain) * delta;
if(fabsf(step) > FLT_EPSILON)
{
ALsizei minsize = mini(BufferSize, Counter);
/* Mix with applying gain steps in aligned multiples of 4. */
if(minsize-pos > 3)
{
float32x4_t step4;
gain4 = vsetq_lane_f32(gain, gain4, 0);
gain4 = vsetq_lane_f32(gain + step, gain4, 1);
gain4 = vsetq_lane_f32(gain + step + step, gain4, 2);
gain4 = vsetq_lane_f32(gain + step + step + step, gain4, 3);
step4 = vdupq_n_f32(step + step + step + step);
do {
const float32x4_t val4 = vld1q_f32(&data[pos]);
float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]);
dry4 = vmlaq_f32(dry4, val4, gain4);
gain4 = vaddq_f32(gain4, step4);
vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
pos += 4;
} while(minsize-pos > 3);
/* NOTE: gain4 now represents the next four gains after the
* last four mixed samples, so the lowest element represents
* the next gain to apply.
*/
gain = vgetq_lane_f32(gain4, 0);
}
/* Mix with applying left over gain steps that aren't aligned multiples of 4. */
for(;pos < minsize;pos++)
{
OutBuffer[c][OutPos+pos] += data[pos]*gain;
gain += step;
}
if(pos == Counter)
gain = TargetGains[c];
CurrentGains[c] = gain;
/* Mix until pos is aligned with 4 or the mix is done. */
minsize = mini(BufferSize, (pos+3)&~3);
for(;pos < minsize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
gain4 = vdupq_n_f32(gain);
for(;BufferSize-pos > 3;pos += 4)
{
const float32x4_t val4 = vld1q_f32(&data[pos]);
float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]);
dry4 = vmlaq_f32(dry4, val4, gain4);
vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
}
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
}
void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize)
{
float32x4_t gain4;
ALsizei c;
data = ASSUME_ALIGNED(data, 16);
OutBuffer = ASSUME_ALIGNED(OutBuffer, 16);
for(c = 0;c < InChans;c++)
{
ALsizei pos = 0;
ALfloat gain = Gains[c];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
gain4 = vdupq_n_f32(gain);
for(;BufferSize-pos > 3;pos += 4)
{
const float32x4_t val4 = vld1q_f32(&data[c][InPos+pos]);
float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]);
dry4 = vmlaq_f32(dry4, val4, gain4);
vst1q_f32(&OutBuffer[pos], dry4);
}
for(;pos < BufferSize;pos++)
OutBuffer[pos] += data[c][InPos+pos]*gain;
}
}
-230
View File
@@ -1,230 +0,0 @@
#include "config.h"
#include <xmmintrin.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alu.h"
#include "alSource.h"
#include "alAuxEffectSlot.h"
#include "mixer_defs.h"
const ALfloat *Resample_bsinc32_SSE(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei dstlen)
{
const __m128 sf4 = _mm_set1_ps(state->bsinc.sf);
const ALsizei m = state->bsinc.m;
const ALfloat *fil, *scd, *phd, *spd;
ALsizei pi, i, j;
ALfloat pf;
__m128 r4;
src += state->bsinc.l;
for(i = 0;i < dstlen;i++)
{
// Calculate the phase index and factor.
#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
pi = frac >> FRAC_PHASE_BITDIFF;
pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
#undef FRAC_PHASE_BITDIFF
fil = ASSUME_ALIGNED(state->bsinc.coeffs[pi].filter, 16);
scd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].scDelta, 16);
phd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].phDelta, 16);
spd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].spDelta, 16);
// Apply the scale and phase interpolated filter.
r4 = _mm_setzero_ps();
{
const __m128 pf4 = _mm_set1_ps(pf);
#define LD4(x) _mm_load_ps(x)
#define ULD4(x) _mm_loadu_ps(x)
#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z))
for(j = 0;j < m;j+=4)
{
/* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */
const __m128 f4 = MLA4(MLA4(LD4(&fil[j]), sf4, LD4(&scd[j])),
pf4, MLA4(LD4(&phd[j]), sf4, LD4(&spd[j]))
);
/* r += f*src */
r4 = MLA4(r4, f4, ULD4(&src[j]));
}
#undef MLA4
#undef ULD4
#undef LD4
}
r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3)));
r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4));
dst[i] = _mm_cvtss_f32(r4);
frac += increment;
src += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
const ALsizei IrSize,
const ALfloat (*restrict Coeffs)[2],
ALfloat left, ALfloat right)
{
const __m128 lrlr = _mm_setr_ps(left, right, left, right);
__m128 vals = _mm_setzero_ps();
__m128 coeffs;
ALsizei i;
Values = ASSUME_ALIGNED(Values, 16);
Coeffs = ASSUME_ALIGNED(Coeffs, 16);
if((Offset&1))
{
const ALsizei o0 = Offset&HRIR_MASK;
const ALsizei o1 = (Offset+IrSize-1)&HRIR_MASK;
__m128 imp0, imp1;
coeffs = _mm_load_ps(&Coeffs[0][0]);
vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]);
imp0 = _mm_mul_ps(lrlr, coeffs);
vals = _mm_add_ps(imp0, vals);
_mm_storel_pi((__m64*)&Values[o0][0], vals);
for(i = 1;i < IrSize-1;i += 2)
{
const ALsizei o2 = (Offset+i)&HRIR_MASK;
coeffs = _mm_load_ps(&Coeffs[i+1][0]);
vals = _mm_load_ps(&Values[o2][0]);
imp1 = _mm_mul_ps(lrlr, coeffs);
imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2));
vals = _mm_add_ps(imp0, vals);
_mm_store_ps(&Values[o2][0], vals);
imp0 = imp1;
}
vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]);
imp0 = _mm_movehl_ps(imp0, imp0);
vals = _mm_add_ps(imp0, vals);
_mm_storel_pi((__m64*)&Values[o1][0], vals);
}
else
{
for(i = 0;i < IrSize;i += 2)
{
const ALsizei o = (Offset + i)&HRIR_MASK;
coeffs = _mm_load_ps(&Coeffs[i][0]);
vals = _mm_load_ps(&Values[o][0]);
vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs));
_mm_store_ps(&Values[o][0], vals);
}
}
}
#define MixHrtf MixHrtf_SSE
#define MixHrtfBlend MixHrtfBlend_SSE
#define MixDirectHrtf MixDirectHrtf_SSE
#include "mixer_inc.c"
#undef MixHrtf
void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
ALsizei BufferSize)
{
ALfloat gain, delta, step;
__m128 gain4;
ALsizei c;
delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
for(c = 0;c < OutChans;c++)
{
ALsizei pos = 0;
gain = CurrentGains[c];
step = (TargetGains[c] - gain) * delta;
if(fabsf(step) > FLT_EPSILON)
{
ALsizei minsize = mini(BufferSize, Counter);
/* Mix with applying gain steps in aligned multiples of 4. */
if(minsize-pos > 3)
{
__m128 step4;
gain4 = _mm_setr_ps(
gain,
gain + step,
gain + step + step,
gain + step + step + step
);
step4 = _mm_set1_ps(step + step + step + step);
do {
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4));
gain4 = _mm_add_ps(gain4, step4);
_mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
pos += 4;
} while(minsize-pos > 3);
/* NOTE: gain4 now represents the next four gains after the
* last four mixed samples, so the lowest element represents
* the next gain to apply.
*/
gain = _mm_cvtss_f32(gain4);
}
/* Mix with applying left over gain steps that aren't aligned multiples of 4. */
for(;pos < minsize;pos++)
{
OutBuffer[c][OutPos+pos] += data[pos]*gain;
gain += step;
}
if(pos == Counter)
gain = TargetGains[c];
CurrentGains[c] = gain;
/* Mix until pos is aligned with 4 or the mix is done. */
minsize = mini(BufferSize, (pos+3)&~3);
for(;pos < minsize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
gain4 = _mm_set1_ps(gain);
for(;BufferSize-pos > 3;pos += 4)
{
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4));
_mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
}
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
}
void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize)
{
__m128 gain4;
ALsizei c;
for(c = 0;c < InChans;c++)
{
ALsizei pos = 0;
ALfloat gain = Gains[c];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
gain4 = _mm_set1_ps(gain);
for(;BufferSize-pos > 3;pos += 4)
{
const __m128 val4 = _mm_load_ps(&data[c][InPos+pos]);
__m128 dry4 = _mm_load_ps(&OutBuffer[pos]);
dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4));
_mm_store_ps(&OutBuffer[pos], dry4);
}
for(;pos < BufferSize;pos++)
OutBuffer[pos] += data[c][InPos+pos]*gain;
}
}
-82
View File
@@ -1,82 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2014 by Timothy Arceri <t_arceri@yahoo.com.au>.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <xmmintrin.h>
#include <emmintrin.h>
#include "alu.h"
#include "mixer_defs.h"
const ALfloat *Resample_lerp32_SSE2(const InterpState* UNUSED(state),
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
union { alignas(16) ALint i[4]; float f[4]; } pos_;
union { alignas(16) ALsizei i[4]; float f[4]; } frac_;
__m128i frac4, pos4;
ALint pos;
ALsizei i;
InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
for(i = 0;numsamples-i > 3;i += 4)
{
const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]);
const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]);
/* val1 + (val2-val1)*mu */
const __m128 r0 = _mm_sub_ps(val2, val1);
const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4);
const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0));
_mm_store_ps(&dst[i], out);
frac4 = _mm_add_epi32(frac4, increment4);
pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
frac4 = _mm_and_si128(frac4, fracMask4);
_mm_store_ps(pos_.f, _mm_castsi128_ps(pos4));
}
/* NOTE: These four elements represent the position *after* the last four
* samples, so the lowest element is the next position to resample.
*/
pos = pos_.i[0];
frac = _mm_cvtsi128_si32(frac4);
for(;i < numsamples;i++)
{
dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
-97
View File
@@ -1,97 +0,0 @@
/**
* OpenAL cross platform audio library, SSE3 mixer functions
*
* Copyright (C) 2014 by Timothy Arceri <t_arceri@yahoo.com.au>.
* Copyright (C) 2015 by Chris Robinson <chris.kcat@gmail.com>.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <xmmintrin.h>
#include <emmintrin.h>
#include <pmmintrin.h>
#include "alu.h"
#include "mixer_defs.h"
const ALfloat *Resample_fir4_32_SSE3(const InterpState* UNUSED(state),
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
union { alignas(16) ALint i[4]; float f[4]; } pos_;
union { alignas(16) ALsizei i[4]; float f[4]; } frac_;
__m128i frac4, pos4;
ALint pos;
ALsizei i;
InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
--src;
for(i = 0;numsamples-i > 3;i += 4)
{
const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]]);
const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]);
const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]);
const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]);
__m128 k0 = _mm_load_ps(sinc4Tab[frac_.i[0]]);
__m128 k1 = _mm_load_ps(sinc4Tab[frac_.i[1]]);
__m128 k2 = _mm_load_ps(sinc4Tab[frac_.i[2]]);
__m128 k3 = _mm_load_ps(sinc4Tab[frac_.i[3]]);
__m128 out;
k0 = _mm_mul_ps(k0, val0);
k1 = _mm_mul_ps(k1, val1);
k2 = _mm_mul_ps(k2, val2);
k3 = _mm_mul_ps(k3, val3);
k0 = _mm_hadd_ps(k0, k1);
k2 = _mm_hadd_ps(k2, k3);
out = _mm_hadd_ps(k0, k2);
_mm_store_ps(&dst[i], out);
frac4 = _mm_add_epi32(frac4, increment4);
pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
frac4 = _mm_and_si128(frac4, fracMask4);
_mm_store_ps(pos_.f, _mm_castsi128_ps(pos4));
_mm_store_ps(frac_.f, _mm_castsi128_ps(frac4));
}
/* NOTE: These four elements represent the position *after* the last four
* samples, so the lowest element is the next position to resample.
*/
pos = pos_.i[0];
frac = frac_.i[0];
for(;i < numsamples;i++)
{
dst[i] = resample_fir4(src[pos], src[pos+1], src[pos+2], src[pos+3], frac);
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
-154
View File
@@ -1,154 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2014 by Timothy Arceri <t_arceri@yahoo.com.au>.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <xmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#include "alu.h"
#include "mixer_defs.h"
const ALfloat *Resample_lerp32_SSE41(const InterpState* UNUSED(state),
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
union { alignas(16) ALint i[4]; float f[4]; } pos_;
union { alignas(16) ALsizei i[4]; float f[4]; } frac_;
__m128i frac4, pos4;
ALint pos;
ALsizei i;
InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
for(i = 0;numsamples-i > 3;i += 4)
{
const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]);
const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]);
/* val1 + (val2-val1)*mu */
const __m128 r0 = _mm_sub_ps(val2, val1);
const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4);
const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0));
_mm_store_ps(&dst[i], out);
frac4 = _mm_add_epi32(frac4, increment4);
pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
frac4 = _mm_and_si128(frac4, fracMask4);
pos_.i[0] = _mm_extract_epi32(pos4, 0);
pos_.i[1] = _mm_extract_epi32(pos4, 1);
pos_.i[2] = _mm_extract_epi32(pos4, 2);
pos_.i[3] = _mm_extract_epi32(pos4, 3);
}
/* NOTE: These four elements represent the position *after* the last four
* samples, so the lowest element is the next position to resample.
*/
pos = pos_.i[0];
frac = _mm_cvtsi128_si32(frac4);
for(;i < numsamples;i++)
{
dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
const ALfloat *Resample_fir4_32_SSE41(const InterpState* UNUSED(state),
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
union { alignas(16) ALint i[4]; float f[4]; } pos_;
union { alignas(16) ALsizei i[4]; float f[4]; } frac_;
__m128i frac4, pos4;
ALint pos;
ALsizei i;
InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
--src;
for(i = 0;numsamples-i > 3;i += 4)
{
const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]]);
const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]);
const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]);
const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]);
__m128 k0 = _mm_load_ps(sinc4Tab[frac_.i[0]]);
__m128 k1 = _mm_load_ps(sinc4Tab[frac_.i[1]]);
__m128 k2 = _mm_load_ps(sinc4Tab[frac_.i[2]]);
__m128 k3 = _mm_load_ps(sinc4Tab[frac_.i[3]]);
__m128 out;
k0 = _mm_mul_ps(k0, val0);
k1 = _mm_mul_ps(k1, val1);
k2 = _mm_mul_ps(k2, val2);
k3 = _mm_mul_ps(k3, val3);
k0 = _mm_hadd_ps(k0, k1);
k2 = _mm_hadd_ps(k2, k3);
out = _mm_hadd_ps(k0, k2);
_mm_store_ps(&dst[i], out);
frac4 = _mm_add_epi32(frac4, increment4);
pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
frac4 = _mm_and_si128(frac4, fracMask4);
pos_.i[0] = _mm_extract_epi32(pos4, 0);
pos_.i[1] = _mm_extract_epi32(pos4, 1);
pos_.i[2] = _mm_extract_epi32(pos4, 2);
pos_.i[3] = _mm_extract_epi32(pos4, 3);
frac_.i[0] = _mm_extract_epi32(frac4, 0);
frac_.i[1] = _mm_extract_epi32(frac4, 1);
frac_.i[2] = _mm_extract_epi32(frac4, 2);
frac_.i[3] = _mm_extract_epi32(frac4, 3);
}
pos = pos_.i[0];
frac = frac_.i[0];
for(;i < numsamples;i++)
{
dst[i] = resample_fir4(src[pos], src[pos+1], src[pos+2], src[pos+3], frac);
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
-418
View File
@@ -1,418 +0,0 @@
#include "config.h"
#include "nfcfilter.h"
#include "alu.h"
/* Near-field control filters are the basis for handling the near-field effect.
* The near-field effect is a bass-boost present in the directional components
* of a recorded signal, created as a result of the wavefront curvature (itself
* a function of sound distance). Proper reproduction dictates this be
* compensated for using a bass-cut given the playback speaker distance, to
* avoid excessive bass in the playback.
*
* For real-time rendered audio, emulating the near-field effect based on the
* sound source's distance, and subsequently compensating for it at output
* based on the speaker distances, can create a more realistic perception of
* sound distance beyond a simple 1/r attenuation.
*
* These filters do just that. Each one applies a low-shelf filter, created as
* the combination of a bass-boost for a given sound source distance (near-
* field emulation) along with a bass-cut for a given control/speaker distance
* (near-field compensation).
*
* Note that it is necessary to apply a cut along with the boost, since the
* boost alone is unstable in higher-order ambisonics as it causes an infinite
* DC gain (even first-order ambisonics requires there to be no DC offset for
* the boost to work). Consequently, ambisonics requires a control parameter to
* be used to avoid an unstable boost-only filter. NFC-HOA defines this control
* as a reference delay, calculated with:
*
* reference_delay = control_distance / speed_of_sound
*
* This means w0 (for input) or w1 (for output) should be set to:
*
* wN = 1 / (reference_delay * sample_rate)
*
* when dealing with NFC-HOA content. For FOA input content, which does not
* specify a reference_delay variable, w0 should be set to 0 to apply only
* near-field compensation for output. It's important that w1 be a finite,
* positive, non-0 value or else the bass-boost will become unstable again.
* Also, w0 should not be too large compared to w1, to avoid excessively loud
* low frequencies.
*/
static const float B[4][3] = {
{ 0.0f },
{ 1.0f },
{ 3.0f, 3.0f },
{ 3.6778f, 6.4595f, 2.3222f },
/*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/
};
void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1)
{
float b_00, g_0;
float r;
memset(nfc, 0, sizeof(*nfc));
nfc->g = 1.0f;
nfc->coeffs[0] = 1.0f;
/* Calculate bass-boost coefficients. */
r = 0.5f * w0;
b_00 = B[1][0] * r;
g_0 = 1.0f + b_00;
nfc->coeffs[0] *= g_0;
nfc->coeffs[1] = (2.0f * b_00) / g_0;
/* Calculate bass-cut coefficients. */
r = 0.5f * w1;
b_00 = B[1][0] * r;
g_0 = 1.0f + b_00;
nfc->g /= g_0;
nfc->coeffs[0] /= g_0;
nfc->coeffs[1+1] = (2.0f * b_00) / g_0;
}
void NfcFilterAdjust1(NfcFilter *nfc, const float w0)
{
float b_00, g_0;
float r;
r = 0.5f * w0;
b_00 = B[1][0] * r;
g_0 = 1.0f + b_00;
nfc->coeffs[0] = nfc->g * g_0;
nfc->coeffs[1] = (2.0f * b_00) / g_0;
}
void NfcFilterUpdate1(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count)
{
const float b0 = nfc->coeffs[0];
const float a0 = nfc->coeffs[1];
const float a1 = nfc->coeffs[2];
float z1 = nfc->history[0];
int i;
for(i = 0;i < count;i++)
{
float out = src[i] * b0;
float y;
y = out - (a1*z1);
out = y + (a0*z1);
z1 += y;
dst[i] = out;
}
nfc->history[0] = z1;
}
void NfcFilterCreate2(NfcFilter *nfc, const float w0, const float w1)
{
float b_10, b_11, g_1;
float r;
memset(nfc, 0, sizeof(*nfc));
nfc->g = 1.0f;
nfc->coeffs[0] = 1.0f;
/* Calculate bass-boost coefficients. */
r = 0.5f * w0;
b_10 = B[2][0] * r;
b_11 = B[2][1] * r * r;
g_1 = 1.0f + b_10 + b_11;
nfc->coeffs[0] *= g_1;
nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
nfc->coeffs[2] = (4.0f * b_11) / g_1;
/* Calculate bass-cut coefficients. */
r = 0.5f * w1;
b_10 = B[2][0] * r;
b_11 = B[2][1] * r * r;
g_1 = 1.0f + b_10 + b_11;
nfc->g /= g_1;
nfc->coeffs[0] /= g_1;
nfc->coeffs[2+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
nfc->coeffs[2+2] = (4.0f * b_11) / g_1;
}
void NfcFilterAdjust2(NfcFilter *nfc, const float w0)
{
float b_10, b_11, g_1;
float r;
r = 0.5f * w0;
b_10 = B[2][0] * r;
b_11 = B[2][1] * r * r;
g_1 = 1.0f + b_10 + b_11;
nfc->coeffs[0] = nfc->g * g_1;
nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
nfc->coeffs[2] = (4.0f * b_11) / g_1;
}
void NfcFilterUpdate2(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count)
{
const float b0 = nfc->coeffs[0];
const float a00 = nfc->coeffs[1];
const float a01 = nfc->coeffs[2];
const float a10 = nfc->coeffs[3];
const float a11 = nfc->coeffs[4];
float z1 = nfc->history[0];
float z2 = nfc->history[1];
int i;
for(i = 0;i < count;i++)
{
float out = src[i] * b0;
float y;
y = out - (a10*z1) - (a11*z2);
out = y + (a00*z1) + (a01*z2);
z2 += z1;
z1 += y;
dst[i] = out;
}
nfc->history[0] = z1;
nfc->history[1] = z2;
}
void NfcFilterCreate3(NfcFilter *nfc, const float w0, const float w1)
{
float b_10, b_11, g_1;
float b_00, g_0;
float r;
memset(nfc, 0, sizeof(*nfc));
nfc->g = 1.0f;
nfc->coeffs[0] = 1.0f;
/* Calculate bass-boost coefficients. */
r = 0.5f * w0;
b_10 = B[3][0] * r;
b_11 = B[3][1] * r * r;
g_1 = 1.0f + b_10 + b_11;
nfc->coeffs[0] *= g_1;
nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
nfc->coeffs[2] = (4.0f * b_11) / g_1;
b_00 = B[3][2] * r;
g_0 = 1.0f + b_00;
nfc->coeffs[0] *= g_0;
nfc->coeffs[2+1] = (2.0f * b_00) / g_0;
/* Calculate bass-cut coefficients. */
r = 0.5f * w1;
b_10 = B[3][0] * r;
b_11 = B[3][1] * r * r;
g_1 = 1.0f + b_10 + b_11;
nfc->g /= g_1;
nfc->coeffs[0] /= g_1;
nfc->coeffs[3+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
nfc->coeffs[3+2] = (4.0f * b_11) / g_1;
b_00 = B[3][2] * r;
g_0 = 1.0f + b_00;
nfc->g /= g_0;
nfc->coeffs[0] /= g_0;
nfc->coeffs[3+2+1] = (2.0f * b_00) / g_0;
}
void NfcFilterAdjust3(NfcFilter *nfc, const float w0)
{
float b_10, b_11, g_1;
float b_00, g_0;
float r;
r = 0.5f * w0;
b_10 = B[3][0] * r;
b_11 = B[3][1] * r * r;
g_1 = 1.0f + b_10 + b_11;
nfc->coeffs[0] = nfc->g * g_1;
nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
nfc->coeffs[2] = (4.0f * b_11) / g_1;
b_00 = B[3][2] * r;
g_0 = 1.0f + b_00;
nfc->coeffs[0] *= g_0;
nfc->coeffs[2+1] = (2.0f * b_00) / g_0;
}
void NfcFilterUpdate3(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count)
{
const float b0 = nfc->coeffs[0];
const float a00 = nfc->coeffs[1];
const float a01 = nfc->coeffs[2];
const float a02 = nfc->coeffs[3];
const float a10 = nfc->coeffs[4];
const float a11 = nfc->coeffs[5];
const float a12 = nfc->coeffs[6];
float z1 = nfc->history[0];
float z2 = nfc->history[1];
float z3 = nfc->history[2];
int i;
for(i = 0;i < count;i++)
{
float out = src[i] * b0;
float y;
y = out - (a10*z1) - (a11*z2);
out = y + (a00*z1) + (a01*z2);
z2 += z1;
z1 += y;
y = out - (a12*z3);
out = y + (a02*z3);
z3 += y;
dst[i] = out;
}
nfc->history[0] = z1;
nfc->history[1] = z2;
nfc->history[2] = z3;
}
#if 0 /* Original methods the above are derived from. */
static void NfcFilterCreate(NfcFilter *nfc, const ALsizei order, const float src_dist, const float ctl_dist, const float rate)
{
static const float B[4][5] = {
{ },
{ 1.0f },
{ 3.0f, 3.0f },
{ 3.6778f, 6.4595f, 2.3222f },
{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }
};
float w0 = SPEEDOFSOUNDMETRESPERSEC / (src_dist * rate);
float w1 = SPEEDOFSOUNDMETRESPERSEC / (ctl_dist * rate);
ALsizei i;
float r;
nfc->g = 1.0f;
nfc->coeffs[0] = 1.0f;
/* NOTE: Slight adjustment from the literature to raise the center
* frequency a bit (0.5 -> 1.0).
*/
r = 1.0f * w0;
for(i = 0; i < (order-1);i += 2)
{
float b_10 = B[order][i ] * r;
float b_11 = B[order][i+1] * r * r;
float g_1 = 1.0f + b_10 + b_11;
nfc->b[i] = b_10;
nfc->b[i + 1] = b_11;
nfc->coeffs[0] *= g_1;
nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
nfc->coeffs[i+2] = (4.0f * b_11) / g_1;
}
if(i < order)
{
float b_00 = B[order][i] * r;
float g_0 = 1.0f + b_00;
nfc->b[i] = b_00;
nfc->coeffs[0] *= g_0;
nfc->coeffs[i+1] = (2.0f * b_00) / g_0;
}
r = 1.0f * w1;
for(i = 0;i < (order-1);i += 2)
{
float b_10 = B[order][i ] * r;
float b_11 = B[order][i+1] * r * r;
float g_1 = 1.0f + b_10 + b_11;
nfc->g /= g_1;
nfc->coeffs[0] /= g_1;
nfc->coeffs[order+i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
nfc->coeffs[order+i+2] = (4.0f * b_11) / g_1;
}
if(i < order)
{
float b_00 = B[order][i] * r;
float g_0 = 1.0f + b_00;
nfc->g /= g_0;
nfc->coeffs[0] /= g_0;
nfc->coeffs[order+i+1] = (2.0f * b_00) / g_0;
}
for(i = 0; i < MAX_AMBI_ORDER; i++)
nfc->history[i] = 0.0f;
}
static void NfcFilterAdjust(NfcFilter *nfc, const float distance)
{
int i;
nfc->coeffs[0] = nfc->g;
for(i = 0;i < (nfc->order-1);i += 2)
{
float b_10 = nfc->b[i] / distance;
float b_11 = nfc->b[i+1] / (distance * distance);
float g_1 = 1.0f + b_10 + b_11;
nfc->coeffs[0] *= g_1;
nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
nfc->coeffs[i+2] = (4.0f * b_11) / g_1;
}
if(i < nfc->order)
{
float b_00 = nfc->b[i] / distance;
float g_0 = 1.0f + b_00;
nfc->coeffs[0] *= g_0;
nfc->coeffs[i+1] = (2.0f * b_00) / g_0;
}
}
static float NfcFilterUpdate(const float in, NfcFilter *nfc)
{
int i;
float out = in * nfc->coeffs[0];
for(i = 0;i < (nfc->order-1);i += 2)
{
float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) -
(nfc->coeffs[nfc->order+i+2] * nfc->history[i+1]) + 1.0e-30f;
out = y + (nfc->coeffs[i+1]*nfc->history[i]) + (nfc->coeffs[i+2]*nfc->history[i+1]);
nfc->history[i+1] += nfc->history[i];
nfc->history[i] += y;
}
if(i < nfc->order)
{
float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) + 1.0e-30f;
out = y + (nfc->coeffs[i+1] * nfc->history[i]);
nfc->history[i] += y;
}
return out;
}
#endif
-37
View File
@@ -1,37 +0,0 @@
#ifndef NFCFILTER_H
#define NFCFILTER_H
#include "alMain.h"
typedef struct NfcFilter {
float g;
float coeffs[MAX_AMBI_ORDER*2 + 1];
float history[MAX_AMBI_ORDER];
} NfcFilter;
/* NOTE:
* w0 = speed_of_sound / (source_distance * sample_rate);
* w1 = speed_of_sound / (control_distance * sample_rate);
*
* Generally speaking, the control distance should be approximately the average
* speaker distance, or based on the reference delay if outputing NFC-HOA. It
* must not be negative, 0, or infinite. The source distance should not be too
* small relative to the control distance.
*/
/* Near-field control filter for first-order ambisonic channels (1-3). */
void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1);
void NfcFilterAdjust1(NfcFilter *nfc, const float w0);
void NfcFilterUpdate1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count);
/* Near-field control filter for second-order ambisonic channels (4-8). */
void NfcFilterCreate2(NfcFilter *nfc, const float w0, const float w1);
void NfcFilterAdjust2(NfcFilter *nfc, const float w0);
void NfcFilterUpdate2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count);
/* Near-field control filter for third-order ambisonic channels (9-15). */
void NfcFilterCreate3(NfcFilter *nfc, const float w0, const float w1);
void NfcFilterAdjust3(NfcFilter *nfc, const float w0);
void NfcFilterUpdate3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count);
#endif /* NFCFILTER_H */
-1271
View File
File diff suppressed because it is too large Load Diff
-134
View File
@@ -1,134 +0,0 @@
#include "config.h"
#include "alu.h"
#include "uhjfilter.h"
/* This is the maximum number of samples processed for each inner loop
* iteration. */
#define MAX_UPDATE_SAMPLES 128
static const ALfloat Filter1Coeff[4] = {
0.6923878f, 0.9360654322959f, 0.9882295226860f, 0.9987488452737f
};
static const ALfloat Filter2Coeff[4] = {
0.4021921162426f, 0.8561710882420f, 0.9722909545651f, 0.9952884791278f
};
static void allpass_process(AllPassState *state, ALfloat *restrict dst, const ALfloat *restrict src, const ALfloat aa, ALsizei todo)
{
ALsizei i;
if(todo > 1)
{
dst[0] = aa*(src[0] + state->y[1]) - state->x[1];
dst[1] = aa*(src[1] + state->y[0]) - state->x[0];
for(i = 2;i < todo;i++)
dst[i] = aa*(src[i] + dst[i-2]) - src[i-2];
state->x[1] = src[i-2];
state->x[0] = src[i-1];
state->y[1] = dst[i-2];
state->y[0] = dst[i-1];
}
else if(todo == 1)
{
dst[0] = aa*(src[0] + state->y[1]) - state->x[1];
state->x[1] = state->x[0];
state->x[0] = src[0];
state->y[1] = state->y[0];
state->y[0] = dst[0];
}
}
/* NOTE: There seems to be a bit of an inconsistency in how this encoding is
* supposed to work. Some references, such as
*
* http://members.tripod.com/martin_leese/Ambisonic/UHJ_file_format.html
*
* specify a pre-scaling of sqrt(2) on the W channel input, while other
* references, such as
*
* https://en.wikipedia.org/wiki/Ambisonic_UHJ_format#Encoding.5B1.5D
* and
* https://wiki.xiph.org/Ambisonics#UHJ_format
*
* do not. The sqrt(2) scaling is in line with B-Format decoder coefficients
* which include such a scaling for the W channel input, however the original
* source for this equation is a 1985 paper by Michael Gerzon, which does not
* apparently include the scaling. Applying the extra scaling creates a louder
* result with a narrower stereo image compared to not scaling, and I don't
* know which is the intended result.
*/
void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
{
ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES];
ALfloat temp[2][MAX_UPDATE_SAMPLES];
ALsizei base, i;
for(base = 0;base < SamplesToDo;)
{
ALsizei todo = mini(SamplesToDo - base, MAX_UPDATE_SAMPLES);
/* D = 0.6554516*Y */
for(i = 0;i < todo;i++)
temp[0][i] = 0.6554516f*InSamples[2][base+i];
allpass_process(&enc->Filter1_Y[0], temp[1], temp[0],
Filter1Coeff[0]*Filter1Coeff[0], todo);
allpass_process(&enc->Filter1_Y[1], temp[0], temp[1],
Filter1Coeff[1]*Filter1Coeff[1], todo);
allpass_process(&enc->Filter1_Y[2], temp[1], temp[0],
Filter1Coeff[2]*Filter1Coeff[2], todo);
/* NOTE: Filter1 requires a 1 sample delay for the final output, so
* take the last processed sample from the previous run as the first
* output sample.
*/
D[0] = enc->Filter1_Y[3].y[0];
allpass_process(&enc->Filter1_Y[3], temp[0], temp[1],
Filter1Coeff[3]*Filter1Coeff[3], todo);
for(i = 1;i < todo;i++)
D[i] = temp[0][i-1];
/* D += j(-0.3420201*W + 0.5098604*X) */
for(i = 0;i < todo;i++)
temp[0][i] = -0.3420201f*InSamples[0][base+i] +
0.5098604f*InSamples[1][base+i];
allpass_process(&enc->Filter2_WX[0], temp[1], temp[0],
Filter2Coeff[0]*Filter2Coeff[0], todo);
allpass_process(&enc->Filter2_WX[1], temp[0], temp[1],
Filter2Coeff[1]*Filter2Coeff[1], todo);
allpass_process(&enc->Filter2_WX[2], temp[1], temp[0],
Filter2Coeff[2]*Filter2Coeff[2], todo);
allpass_process(&enc->Filter2_WX[3], temp[0], temp[1],
Filter2Coeff[3]*Filter2Coeff[3], todo);
for(i = 0;i < todo;i++)
D[i] += temp[0][i];
/* S = 0.9396926*W + 0.1855740*X */
for(i = 0;i < todo;i++)
temp[0][i] = 0.9396926f*InSamples[0][base+i] +
0.1855740f*InSamples[1][base+i];
allpass_process(&enc->Filter1_WX[0], temp[1], temp[0],
Filter1Coeff[0]*Filter1Coeff[0], todo);
allpass_process(&enc->Filter1_WX[1], temp[0], temp[1],
Filter1Coeff[1]*Filter1Coeff[1], todo);
allpass_process(&enc->Filter1_WX[2], temp[1], temp[0],
Filter1Coeff[2]*Filter1Coeff[2], todo);
S[0] = enc->Filter1_WX[3].y[0];
allpass_process(&enc->Filter1_WX[3], temp[0], temp[1],
Filter1Coeff[3]*Filter1Coeff[3], todo);
for(i = 1;i < todo;i++)
S[i] = temp[0][i-1];
/* Left = (S + D)/2.0 */
for(i = 0;i < todo;i++)
*(LeftOut++) += (S[i] + D[i]) * 0.5f;
/* Right = (S - D)/2.0 */
for(i = 0;i < todo;i++)
*(RightOut++) += (S[i] - D[i]) * 0.5f;
base += todo;
}
}
-49
View File
@@ -1,49 +0,0 @@
#ifndef UHJFILTER_H
#define UHJFILTER_H
#include "AL/al.h"
#include "alMain.h"
typedef struct AllPassState {
ALfloat x[2]; /* Last two input samples */
ALfloat y[2]; /* Last two output samples */
} AllPassState;
/* Encoding 2-channel UHJ from B-Format is done as:
*
* S = 0.9396926*W + 0.1855740*X
* D = j(-0.3420201*W + 0.5098604*X) + 0.6554516*Y
*
* Left = (S + D)/2.0
* Right = (S - D)/2.0
*
* where j is a wide-band +90 degree phase shift.
*
* The phase shift is done using a Hilbert transform, described here:
* https://web.archive.org/web/20060708031958/http://www.biochem.oulu.fi/~oniemita/dsp/hilbert/
* It works using 2 sets of 4 chained filters. The first filter chain produces
* a phase shift of varying magnitude over a wide range of frequencies, while
* the second filter chain produces a phase shift 90 degrees ahead of the
* first over the same range.
*
* Combining these two stages requires the use of three filter chains. S-
* channel output uses a Filter1 chain on the W and X channel mix, while the D-
* channel output uses a Filter1 chain on the Y channel plus a Filter2 chain on
* the W and X channel mix. This results in the W and X input mix on the D-
* channel output having the required +90 degree phase shift relative to the
* other inputs.
*/
typedef struct Uhj2Encoder {
AllPassState Filter1_WX[4];
AllPassState Filter1_Y[4];
AllPassState Filter2_WX[4];
} Uhj2Encoder;
/* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input
* signal. The input must use FuMa channel ordering and scaling.
*/
void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo);
#endif /* UHJFILTER_H */
-93
View File
@@ -1,93 +0,0 @@
#ifndef AL_VECTOR_H
#define AL_VECTOR_H
#include <stdlib.h>
#include <AL/al.h>
#include "almalloc.h"
#define TYPEDEF_VECTOR(T, N) typedef struct { \
size_t Capacity; \
size_t Size; \
T Data[]; \
} _##N; \
typedef _##N* N; \
typedef const _##N* const_##N;
#define VECTOR(T) struct { \
size_t Capacity; \
size_t Size; \
T Data[]; \
}*
#define VECTOR_INIT(_x) do { (_x) = NULL; } while(0)
#define VECTOR_INIT_STATIC() NULL
#define VECTOR_DEINIT(_x) do { al_free((_x)); (_x) = NULL; } while(0)
#define VECTOR_RESIZE(_x, _s, _c) do { \
size_t _size = (_s); \
size_t _cap = (_c); \
if(_size > _cap) \
_cap = _size; \
\
if(!(_x) && _cap == 0) \
break; \
\
if(((_x) ? (_x)->Capacity : 0) < _cap) \
{ \
ptrdiff_t data_offset = (char*)((_x)->Data) - (char*)(_x); \
size_t old_size = ((_x) ? (_x)->Size : 0); \
void *temp; \
\
temp = al_calloc(16, data_offset + sizeof((_x)->Data[0])*_cap); \
assert(temp != NULL); \
if((_x)) \
memcpy(((char*)temp)+data_offset, (_x)->Data, \
sizeof((_x)->Data[0])*old_size); \
\
al_free((_x)); \
(_x) = temp; \
(_x)->Capacity = _cap; \
} \
(_x)->Size = _size; \
} while(0) \
#define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0)
#define VECTOR_SIZE(_x) ((_x) ? (_x)->Size : 0)
#define VECTOR_BEGIN(_x) ((_x) ? (_x)->Data + 0 : NULL)
#define VECTOR_END(_x) ((_x) ? (_x)->Data + (_x)->Size : NULL)
#define VECTOR_PUSH_BACK(_x, _obj) do { \
size_t _pbsize = VECTOR_SIZE(_x)+1; \
VECTOR_RESIZE(_x, _pbsize, _pbsize); \
(_x)->Data[(_x)->Size-1] = (_obj); \
} while(0)
#define VECTOR_POP_BACK(_x) ((void)((_x)->Size--))
#define VECTOR_BACK(_x) ((_x)->Data[(_x)->Size-1])
#define VECTOR_FRONT(_x) ((_x)->Data[0])
#define VECTOR_ELEM(_x, _o) ((_x)->Data[(_o)])
#define VECTOR_FOR_EACH(_t, _x, _f) do { \
_t *_iter = VECTOR_BEGIN((_x)); \
_t *_end = VECTOR_END((_x)); \
for(;_iter != _end;++_iter) \
_f(_iter); \
} while(0)
#define VECTOR_FIND_IF(_i, _t, _x, _f) do { \
_t *_iter = VECTOR_BEGIN((_x)); \
_t *_end = VECTOR_END((_x)); \
for(;_iter != _end;++_iter) \
{ \
if(_f(_iter)) \
break; \
} \
(_i) = _iter; \
} while(0)
#endif /* AL_VECTOR_H */
-1552
View File
File diff suppressed because it is too large Load Diff
-481
View File
@@ -1,481 +0,0 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
-290
View File
@@ -1,290 +0,0 @@
openal-soft-1.18.1:
Fixed an issue where resuming a source might not restart playing it.
Fixed PulseAudio playback when the configured stream length is much less
than the requested length.
Fixed MMDevAPI capture with sample rates not matching the backing device.
Fixed int32 output for the Wave Writer.
Fixed enumeration of OSS devices that are missing device files.
Added correct retrieval of the executable's path on FreeBSD.
Added a config option to specify the dithering depth.
Added a 5.1 decoder preset that excludes front-center output.
openal-soft-1.18.0:
Implemented the AL_EXT_STEREO_ANGLES and AL_EXT_SOURCE_RADIUS extensions.
Implemented the AL_SOFT_gain_clamp_ex, AL_SOFT_source_resampler,
AL_SOFT_source_spatialize, and ALC_SOFT_output_limiter extensions.
Implemented 3D processing for some effects. Currently implemented for
Reverb, Compressor, Equalizer, and Ring Modulator.
Implemented 2-channel UHJ output encoding. This needs to be enabled with a
config option to be used.
Implemented dual-band processing for high-quality ambisonic decoding.
Implemented distance-compensation for surround sound output.
Implemented near-field emulation and compensation with ambisonic rendering.
Currently only applies when using the high-quality ambisonic decoder or
ambisonic output, with appropriate config options.
Implemented an output limiter to reduce the amount of distortion from
clipping.
Implemented dithering for 8-bit and 16-bit output.
Implemented a config option to select a preferred HRTF.
Implemented a run-time check for NEON extensions using /proc/cpuinfo.
Implemented experimental capture support for the OpenSL backend.
Fixed building on compilers with NEON support but don't default to having
NEON enabled.
Fixed support for JACK on Windows.
Fixed starting a source while alcSuspendContext is in effect.
Fixed detection of headsets as headphones, with MMDevAPI.
Added support for AmbDec config files, for custom ambisonic decoder
configurations. Version 3 files only.
Added backend-specific options to alsoft-config.
Added first-, second-, and third-order ambisonic output formats. Currently
only works with backends that don't rely on channel labels, like JACK,
ALSA, and OSS.
Added a build option to embed the default HRTFs into the lib.
Added AmbDec presets to enable high-quality ambisonic decoding.
Added an AmbDec preset for 3D7.1 speaker setups.
Added documentation regarding Ambisonics, 3D7.1, AmbDec config files, and
the provided ambdec presets.
Added the ability for MMDevAPI to open devices given a Device ID or GUID
string.
Added an option to the example apps to open a specific device.
Increased the maximum auxiliary send limit to 16 (up from 4). Requires
requesting them with the ALC_MAX_AUXILIARY_SENDS context creation
attribute.
Increased the default auxiliary effect slot count to 64 (up from 4).
Reduced the default period count to 3 (down from 4).
Slightly improved automatic naming for enumerated HRTFs.
Improved B-Format decoding with HRTF output.
Improved internal property handling for better batching behavior.
Improved performance of certain filter uses.
Removed support for the AL_SOFT_buffer_samples and AL_SOFT_buffer_sub_data
extensions. Due to conflicts with AL_EXT_SOURCE_RADIUS.
openal-soft-1.17.2:
Implemented device enumeration for OSSv4.
Fixed building on OSX.
Fixed building on non-Windows systems without POSIX-2008.
Fixed Dedicated Dialog and Dedicated LFE effect output.
Added a build option to override the share install dir.
Added a build option to static-link libgcc for MinGW.
openal-soft-1.17.1:
Fixed building with JACK and without PulseAudio.
Fixed building on FreeBSD.
Fixed the ALSA backend's allow-resampler option.
Fixed handling of inexact ALSA period counts.
Altered device naming scheme on Windows backends to better match other
drivers.
Updated the CoreAudio backend to use the AudioComponent API. This clears up
deprecation warnings for OSX 10.11, although requires OSX 10.6 or newer.
openal-soft-1.17.0:
Implemented a JACK playback backend.
Implemented the AL_EXT_BFORMAT and AL_EXT_MULAW_BFORMAT extensions.
Implemented the ALC_SOFT_HRTF extension.
Implemented C, SSE3, and SSE4.1 based 4- and 8-point Sinc resamplers.
Implemented a C and SSE based band-limited Sinc resampler. This does 12- to
24-point Sinc resampling, and performs anti-aliasing.
Implemented B-Format output support for the wave file writer. This creates
FuMa-style first-order Ambisonics wave files (AMB format).
Implemented a stereo-mode config option for treating stereo modes as either
speakers or headphones.
Implemented per-device configuration options.
Fixed handling of PulseAudio and MMDevAPI devices that have identical
descriptions.
Fixed a potential lockup when stopping playback of suspended PulseAudio devices.
Fixed logging of Unicode characters on Windows.
Fixed 5.1 surround sound channels. By default it will now use the side
channels for the surround output. A configuration using rear channels is
still available.
Fixed the QSA backend potentially altering the capture format.
Fixed detecting MMDevAPI's default device.
Fixed returning the default capture device name.
Fixed mixing property calculations when deferring context updates.
Altered the behavior of alcSuspendContext and alcProcessContext to better
match certain Windows drivers.
Altered the panning algorithm, utilizing Ambisonics for better side and
back positioning cues with surround sound output.
Improved support for certain older Windows apps.
Improved the alffplay example to support surround sound streams.
Improved support for building as a sub-project.
Added an HRTF playback example.
Added a tone generator output test.
Added a toolchain to help with cross-compiling to Android.
openal-soft-1.16.0:
Implemented EFX Chorus, Flanger, Distortion, Equalizer, and Compressor
effects.
Implemented high-pass and band-pass EFX filters.
Implemented the high-pass filter for the EAXReverb effect.
Implemented SSE2 and SSE4.1 linear resamplers.
Implemented Neon-enhanced non-HRTF mixers.
Implemented a QSA backend, for QNX.
Implemented the ALC_SOFT_pause_device, AL_SOFT_deferred_updates,
AL_SOFT_block_alignment, AL_SOFT_MSADPCM, and AL_SOFT_source_length
extensions.
Fixed resetting mmdevapi backend devices.
Fixed clamping when converting 32-bit float samples to integer.
Fixed modulation range in the Modulator effect.
Several fixes for the OpenSL playback backend.
Fixed device specifier names that have Unicode characters on Windows.
Added support for filenames and paths with Unicode (UTF-8) characters on
Windows.
Added support for alsoft.conf config files found in XDG Base Directory
Specification locations (XDG_CONFIG_DIRS and XDG_CONFIG_HOME, or their
defaults) on non-Windows systems.
Added a GUI configuration utility (requires Qt 4.8).
Added support for environment variable expansion in config options (not
keys or section names).
Added an example that uses SDL2 and ffmpeg.
Modified examples to use SDL_sound.
Modified CMake config option names for better sorting.
HRTF data sets specified in the hrtf_tables config option may now be
relative or absolute filenames.
Made the default HRTF data set an external file, and added a data set for
48khz playback in addition to 44.1khz.
Added support for C11 atomic methods.
Improved support for some non-GNU build systems.
openal-soft-1.15.1:
Fixed a regression with retrieving the source's AL_GAIN property.
openal-soft-1.15:
Fixed device enumeration with the OSS backend.
Reorganized internal mixing logic, so unneeded steps can potentially be
skipped for better performance.
Removed the lookup table for calculating the mixing pans. The panning is
now calculated directly for better precision.
Improved the panning of stereo source channels when using stereo output.
Improved source filter quality on send paths.
Added a config option to allow PulseAudio to move streams between devices.
The PulseAudio backend will now attempt to spawn a server by default.
Added a workaround for a DirectSound bug relating to float32 output.
Added SSE-based mixers, for HRTF and non-HRTF mixing.
Added support for the new AL_SOFT_source_latency extension.
Improved ALSA capture by avoiding an extra buffer when using sizes
supported by the underlying device.
Improved the makehrtf utility to support new options and input formats.
Modified the CFLAGS declared in the pkg-config file so the "AL/" portion of
the header includes can optionally be omitted.
Added a couple example code programs to show how to apply reverb, and
retrieve latency.
The configuration sample is now installed into the share/openal/ directory
instead of /etc/openal.
The configuration sample now gets installed by default.
-190
View File
@@ -1,190 +0,0 @@
#ifndef _AL_AUXEFFECTSLOT_H_
#define _AL_AUXEFFECTSLOT_H_
#include "alMain.h"
#include "alEffect.h"
#include "atomic.h"
#include "align.h"
#ifdef __cplusplus
extern "C" {
#endif
struct ALeffectStateVtable;
struct ALeffectslot;
typedef struct ALeffectState {
RefCount Ref;
const struct ALeffectStateVtable *vtbl;
ALfloat (*OutBuffer)[BUFFERSIZE];
ALsizei OutChannels;
} ALeffectState;
void ALeffectState_Construct(ALeffectState *state);
void ALeffectState_Destruct(ALeffectState *state);
struct ALeffectStateVtable {
void (*const Destruct)(ALeffectState *state);
ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
void (*const update)(ALeffectState *state, const ALCdevice *device, const struct ALeffectslot *slot, const union ALeffectProps *props);
void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei numChannels);
void (*const Delete)(void *ptr);
};
#define DEFINE_ALEFFECTSTATE_VTABLE(T) \
DECLARE_THUNK(T, ALeffectState, void, Destruct) \
DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \
DECLARE_THUNK3(T, ALeffectState, void, update, const ALCdevice*, const ALeffectslot*, const ALeffectProps*) \
DECLARE_THUNK4(T, ALeffectState, void, process, ALsizei, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALsizei) \
static void T##_ALeffectState_Delete(void *ptr) \
{ return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \
\
static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \
T##_ALeffectState_Destruct, \
\
T##_ALeffectState_deviceUpdate, \
T##_ALeffectState_update, \
T##_ALeffectState_process, \
\
T##_ALeffectState_Delete, \
}
struct ALeffectStateFactoryVtable;
typedef struct ALeffectStateFactory {
const struct ALeffectStateFactoryVtable *vtbl;
} ALeffectStateFactory;
struct ALeffectStateFactoryVtable {
ALeffectState *(*const create)(ALeffectStateFactory *factory);
};
#define DEFINE_ALEFFECTSTATEFACTORY_VTABLE(T) \
DECLARE_THUNK(T, ALeffectStateFactory, ALeffectState*, create) \
\
static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = { \
T##_ALeffectStateFactory_create, \
}
#define MAX_EFFECT_CHANNELS (4)
struct ALeffectslotArray {
ALsizei count;
struct ALeffectslot *slot[];
};
struct ALeffectslotProps {
ALfloat Gain;
ALboolean AuxSendAuto;
ALenum Type;
ALeffectProps Props;
ALeffectState *State;
ATOMIC(struct ALeffectslotProps*) next;
};
typedef struct ALeffectslot {
ALfloat Gain;
ALboolean AuxSendAuto;
struct {
ALenum Type;
ALeffectProps Props;
ALeffectState *State;
} Effect;
ATOMIC_FLAG PropsClean;
RefCount ref;
ATOMIC(struct ALeffectslotProps*) Update;
ATOMIC(struct ALeffectslotProps*) FreeList;
struct {
ALfloat Gain;
ALboolean AuxSendAuto;
ALenum EffectType;
ALeffectState *EffectState;
ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */
ALfloat DecayTime;
ALfloat DecayHFRatio;
ALboolean DecayHFLimit;
ALfloat AirAbsorptionGainHF;
} Params;
/* Self ID */
ALuint id;
ALsizei NumChannels;
BFChannelConfig ChanMap[MAX_EFFECT_CHANNELS];
/* Wet buffer configuration is ACN channel order with N3D scaling:
* * Channel 0 is the unattenuated mono signal.
* * Channel 1 is OpenAL -X
* * Channel 2 is OpenAL Y
* * Channel 3 is OpenAL -Z
* Consequently, effects that only want to work with mono input can use
* channel 0 by itself. Effects that want multichannel can process the
* ambisonics signal and make a B-Format pan (ComputeFirstOrderGains) for
* first-order device output (FOAOut).
*/
alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE];
} ALeffectslot;
inline void LockEffectSlotsRead(ALCcontext *context)
{ LockUIntMapRead(&context->EffectSlotMap); }
inline void UnlockEffectSlotsRead(ALCcontext *context)
{ UnlockUIntMapRead(&context->EffectSlotMap); }
inline void LockEffectSlotsWrite(ALCcontext *context)
{ LockUIntMapWrite(&context->EffectSlotMap); }
inline void UnlockEffectSlotsWrite(ALCcontext *context)
{ UnlockUIntMapWrite(&context->EffectSlotMap); }
inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
{ return (struct ALeffectslot*)LookupUIntMapKeyNoLock(&context->EffectSlotMap, id); }
inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id)
{ return (struct ALeffectslot*)RemoveUIntMapKeyNoLock(&context->EffectSlotMap, id); }
ALenum InitEffectSlot(ALeffectslot *slot);
void DeinitEffectSlot(ALeffectslot *slot);
void UpdateEffectSlotProps(ALeffectslot *slot);
void UpdateAllEffectSlotProps(ALCcontext *context);
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
ALeffectStateFactory *ALnullStateFactory_getFactory(void);
ALeffectStateFactory *ALreverbStateFactory_getFactory(void);
ALeffectStateFactory *ALchorusStateFactory_getFactory(void);
ALeffectStateFactory *ALcompressorStateFactory_getFactory(void);
ALeffectStateFactory *ALdistortionStateFactory_getFactory(void);
ALeffectStateFactory *ALechoStateFactory_getFactory(void);
ALeffectStateFactory *ALequalizerStateFactory_getFactory(void);
ALeffectStateFactory *ALflangerStateFactory_getFactory(void);
ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void);
ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void);
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect);
void InitEffectFactoryMap(void);
void DeinitEffectFactoryMap(void);
#ifdef __cplusplus
}
#endif
#endif
-128
View File
@@ -1,128 +0,0 @@
#ifndef _AL_BUFFER_H_
#define _AL_BUFFER_H_
#include "alMain.h"
#ifdef __cplusplus
extern "C" {
#endif
/* User formats */
enum UserFmtType {
UserFmtByte = AL_BYTE_SOFT,
UserFmtUByte = AL_UNSIGNED_BYTE_SOFT,
UserFmtShort = AL_SHORT_SOFT,
UserFmtUShort = AL_UNSIGNED_SHORT_SOFT,
UserFmtInt = AL_INT_SOFT,
UserFmtUInt = AL_UNSIGNED_INT_SOFT,
UserFmtFloat = AL_FLOAT_SOFT,
UserFmtDouble = AL_DOUBLE_SOFT,
UserFmtMulaw = AL_MULAW_SOFT,
UserFmtAlaw = 0x10000000,
UserFmtIMA4,
UserFmtMSADPCM,
};
enum UserFmtChannels {
UserFmtMono = AL_MONO_SOFT,
UserFmtStereo = AL_STEREO_SOFT,
UserFmtRear = AL_REAR_SOFT,
UserFmtQuad = AL_QUAD_SOFT,
UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */
UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */
UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */
UserFmtBFormat2D = AL_BFORMAT2D_SOFT, /* WXY */
UserFmtBFormat3D = AL_BFORMAT3D_SOFT, /* WXYZ */
};
ALsizei BytesFromUserFmt(enum UserFmtType type);
ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans);
inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type)
{
return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type);
}
/* Storable formats */
enum FmtType {
FmtByte = UserFmtByte,
FmtShort = UserFmtShort,
FmtFloat = UserFmtFloat,
};
enum FmtChannels {
FmtMono = UserFmtMono,
FmtStereo = UserFmtStereo,
FmtRear = UserFmtRear,
FmtQuad = UserFmtQuad,
FmtX51 = UserFmtX51,
FmtX61 = UserFmtX61,
FmtX71 = UserFmtX71,
FmtBFormat2D = UserFmtBFormat2D,
FmtBFormat3D = UserFmtBFormat3D,
};
#define MAX_INPUT_CHANNELS (8)
ALsizei BytesFromFmt(enum FmtType type);
ALsizei ChannelsFromFmt(enum FmtChannels chans);
inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
{
return ChannelsFromFmt(chans) * BytesFromFmt(type);
}
typedef struct ALbuffer {
ALvoid *data;
ALsizei Frequency;
ALenum Format;
ALsizei SampleLen;
enum FmtChannels FmtChannels;
enum FmtType FmtType;
ALuint BytesAlloc;
enum UserFmtChannels OriginalChannels;
enum UserFmtType OriginalType;
ALsizei OriginalSize;
ALsizei OriginalAlign;
ALsizei LoopStart;
ALsizei LoopEnd;
ATOMIC(ALsizei) UnpackAlign;
ATOMIC(ALsizei) PackAlign;
/* Number of times buffer was attached to a source (deletion can only occur when 0) */
RefCount ref;
RWLock lock;
/* Self ID */
ALuint id;
} ALbuffer;
ALbuffer *NewBuffer(ALCcontext *context);
void DeleteBuffer(ALCdevice *device, ALbuffer *buffer);
ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc);
inline void LockBuffersRead(ALCdevice *device)
{ LockUIntMapRead(&device->BufferMap); }
inline void UnlockBuffersRead(ALCdevice *device)
{ UnlockUIntMapRead(&device->BufferMap); }
inline void LockBuffersWrite(ALCdevice *device)
{ LockUIntMapWrite(&device->BufferMap); }
inline void UnlockBuffersWrite(ALCdevice *device)
{ UnlockUIntMapWrite(&device->BufferMap); }
inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
{ return (struct ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); }
inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id)
{ return (struct ALbuffer*)RemoveUIntMapKeyNoLock(&device->BufferMap, id); }
ALvoid ReleaseALBuffers(ALCdevice *device);
#ifdef __cplusplus
}
#endif
#endif
-196
View File
@@ -1,196 +0,0 @@
#ifndef _AL_EFFECT_H_
#define _AL_EFFECT_H_
#include "alMain.h"
#ifdef __cplusplus
extern "C" {
#endif
struct ALeffect;
enum {
AL__EAXREVERB = 0,
AL__REVERB,
AL__CHORUS,
AL__COMPRESSOR,
AL__DISTORTION,
AL__ECHO,
AL__EQUALIZER,
AL__FLANGER,
AL__MODULATOR,
AL__DEDICATED,
MAX_EFFECTS
};
extern ALboolean DisabledEffects[MAX_EFFECTS];
extern ALfloat ReverbBoost;
extern ALboolean EmulateEAXReverb;
struct ALeffectVtable {
void (*const setParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val);
void (*const setParamiv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals);
void (*const setParamf)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val);
void (*const setParamfv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals);
void (*const getParami)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALint *val);
void (*const getParamiv)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals);
void (*const getParamf)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val);
void (*const getParamfv)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals);
};
#define DEFINE_ALEFFECT_VTABLE(T) \
const struct ALeffectVtable T##_vtable = { \
T##_setParami, T##_setParamiv, \
T##_setParamf, T##_setParamfv, \
T##_getParami, T##_getParamiv, \
T##_getParamf, T##_getParamfv, \
}
extern const struct ALeffectVtable ALeaxreverb_vtable;
extern const struct ALeffectVtable ALreverb_vtable;
extern const struct ALeffectVtable ALchorus_vtable;
extern const struct ALeffectVtable ALcompressor_vtable;
extern const struct ALeffectVtable ALdistortion_vtable;
extern const struct ALeffectVtable ALecho_vtable;
extern const struct ALeffectVtable ALequalizer_vtable;
extern const struct ALeffectVtable ALflanger_vtable;
extern const struct ALeffectVtable ALmodulator_vtable;
extern const struct ALeffectVtable ALnull_vtable;
extern const struct ALeffectVtable ALdedicated_vtable;
typedef union ALeffectProps {
struct {
// Shared Reverb Properties
ALfloat Density;
ALfloat Diffusion;
ALfloat Gain;
ALfloat GainHF;
ALfloat DecayTime;
ALfloat DecayHFRatio;
ALfloat ReflectionsGain;
ALfloat ReflectionsDelay;
ALfloat LateReverbGain;
ALfloat LateReverbDelay;
ALfloat AirAbsorptionGainHF;
ALfloat RoomRolloffFactor;
ALboolean DecayHFLimit;
// Additional EAX Reverb Properties
ALfloat GainLF;
ALfloat DecayLFRatio;
ALfloat ReflectionsPan[3];
ALfloat LateReverbPan[3];
ALfloat EchoTime;
ALfloat EchoDepth;
ALfloat ModulationTime;
ALfloat ModulationDepth;
ALfloat HFReference;
ALfloat LFReference;
} Reverb;
struct {
ALint Waveform;
ALint Phase;
ALfloat Rate;
ALfloat Depth;
ALfloat Feedback;
ALfloat Delay;
} Chorus;
struct {
ALboolean OnOff;
} Compressor;
struct {
ALfloat Edge;
ALfloat Gain;
ALfloat LowpassCutoff;
ALfloat EQCenter;
ALfloat EQBandwidth;
} Distortion;
struct {
ALfloat Delay;
ALfloat LRDelay;
ALfloat Damping;
ALfloat Feedback;
ALfloat Spread;
} Echo;
struct {
ALfloat LowCutoff;
ALfloat LowGain;
ALfloat Mid1Center;
ALfloat Mid1Gain;
ALfloat Mid1Width;
ALfloat Mid2Center;
ALfloat Mid2Gain;
ALfloat Mid2Width;
ALfloat HighCutoff;
ALfloat HighGain;
} Equalizer;
struct {
ALint Waveform;
ALint Phase;
ALfloat Rate;
ALfloat Depth;
ALfloat Feedback;
ALfloat Delay;
} Flanger;
struct {
ALfloat Frequency;
ALfloat HighPassCutoff;
ALint Waveform;
} Modulator;
struct {
ALfloat Gain;
} Dedicated;
} ALeffectProps;
typedef struct ALeffect {
// Effect type (AL_EFFECT_NULL, ...)
ALenum type;
ALeffectProps Props;
const struct ALeffectVtable *vtbl;
/* Self ID */
ALuint id;
} ALeffect;
inline void LockEffectsRead(ALCdevice *device)
{ LockUIntMapRead(&device->EffectMap); }
inline void UnlockEffectsRead(ALCdevice *device)
{ UnlockUIntMapRead(&device->EffectMap); }
inline void LockEffectsWrite(ALCdevice *device)
{ LockUIntMapWrite(&device->EffectMap); }
inline void UnlockEffectsWrite(ALCdevice *device)
{ UnlockUIntMapWrite(&device->EffectMap); }
inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id)
{ return (struct ALeffect*)LookupUIntMapKeyNoLock(&device->EffectMap, id); }
inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id)
{ return (struct ALeffect*)RemoveUIntMapKeyNoLock(&device->EffectMap, id); }
inline ALboolean IsReverbEffect(ALenum type)
{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; }
ALenum InitEffect(ALeffect *effect);
ALvoid ReleaseALEffects(ALCdevice *device);
ALvoid LoadReverbPreset(const char *name, ALeffect *effect);
#ifdef __cplusplus
}
#endif
#endif
-33
View File
@@ -1,33 +0,0 @@
#ifndef _AL_ERROR_H_
#define _AL_ERROR_H_
#include "alMain.h"
#ifdef __cplusplus
extern "C" {
#endif
extern ALboolean TrapALError;
ALvoid alSetError(ALCcontext *Context, ALenum errorCode);
#define SET_ERROR_AND_RETURN(ctx, err) do { \
alSetError((ctx), (err)); \
return; \
} while(0)
#define SET_ERROR_AND_RETURN_VALUE(ctx, err, val) do { \
alSetError((ctx), (err)); \
return (val); \
} while(0)
#define SET_ERROR_AND_GOTO(ctx, err, lbl) do { \
alSetError((ctx), (err)); \
goto lbl; \
} while(0)
#ifdef __cplusplus
}
#endif
#endif
-164
View File
@@ -1,164 +0,0 @@
#ifndef _AL_FILTER_H_
#define _AL_FILTER_H_
#include "alMain.h"
#include "math_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LOWPASSFREQREF (5000.0f)
#define HIGHPASSFREQREF (250.0f)
/* Filters implementation is based on the "Cookbook formulae for audio
* EQ biquad filter coefficients" by Robert Bristow-Johnson
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
*/
/* Implementation note: For the shelf filters, the specified gain is for the
* reference frequency, which is the centerpoint of the transition band. This
* better matches EFX filter design. To set the gain for the shelf itself, use
* the square root of the desired linear gain (or halve the dB gain).
*/
typedef enum ALfilterType {
/** EFX-style low-pass filter, specifying a gain and reference frequency. */
ALfilterType_HighShelf,
/** EFX-style high-pass filter, specifying a gain and reference frequency. */
ALfilterType_LowShelf,
/** Peaking filter, specifying a gain and reference frequency. */
ALfilterType_Peaking,
/** Low-pass cut-off filter, specifying a cut-off frequency. */
ALfilterType_LowPass,
/** High-pass cut-off filter, specifying a cut-off frequency. */
ALfilterType_HighPass,
/** Band-pass filter, specifying a center frequency. */
ALfilterType_BandPass,
} ALfilterType;
typedef struct ALfilterState {
ALfloat x[2]; /* History of two last input samples */
ALfloat y[2]; /* History of two last output samples */
ALfloat b0, b1, b2; /* Transfer function coefficients "b" */
ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */
} ALfilterState;
/* Currently only a C-based filter process method is implemented. */
#define ALfilterState_process ALfilterState_processC
/* Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the
* reference gain and shelf slope parameter.
* 0 < gain
* 0 < slope <= 1
*/
inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope)
{
return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f);
}
/* Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the frequency
* multiple (i.e. ref_freq / sampling_freq) and bandwidth.
* 0 < freq_mult < 0.5.
*/
inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth)
{
ALfloat w0 = F_TAU * freq_mult;
return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0));
}
inline void ALfilterState_clear(ALfilterState *filter)
{
filter->x[0] = 0.0f;
filter->x[1] = 0.0f;
filter->y[0] = 0.0f;
filter->y[1] = 0.0f;
}
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ);
inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src)
{
dst->b0 = src->b0;
dst->b1 = src->b1;
dst->b2 = src->b2;
dst->a1 = src->a1;
dst->a2 = src->a2;
}
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples);
inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples)
{
if(numsamples >= 2)
{
filter->x[1] = src[numsamples-2];
filter->x[0] = src[numsamples-1];
filter->y[1] = src[numsamples-2];
filter->y[0] = src[numsamples-1];
}
else if(numsamples == 1)
{
filter->x[1] = filter->x[0];
filter->x[0] = src[0];
filter->y[1] = filter->y[0];
filter->y[0] = src[0];
}
}
typedef struct ALfilter {
// Filter type (AL_FILTER_NULL, ...)
ALenum type;
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
void (*SetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val);
void (*SetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals);
void (*SetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val);
void (*SetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals);
void (*GetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val);
void (*GetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals);
void (*GetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val);
void (*GetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals);
/* Self ID */
ALuint id;
} ALfilter;
#define ALfilter_SetParami(x, c, p, v) ((x)->SetParami((x),(c),(p),(v)))
#define ALfilter_SetParamiv(x, c, p, v) ((x)->SetParamiv((x),(c),(p),(v)))
#define ALfilter_SetParamf(x, c, p, v) ((x)->SetParamf((x),(c),(p),(v)))
#define ALfilter_SetParamfv(x, c, p, v) ((x)->SetParamfv((x),(c),(p),(v)))
#define ALfilter_GetParami(x, c, p, v) ((x)->GetParami((x),(c),(p),(v)))
#define ALfilter_GetParamiv(x, c, p, v) ((x)->GetParamiv((x),(c),(p),(v)))
#define ALfilter_GetParamf(x, c, p, v) ((x)->GetParamf((x),(c),(p),(v)))
#define ALfilter_GetParamfv(x, c, p, v) ((x)->GetParamfv((x),(c),(p),(v)))
inline void LockFiltersRead(ALCdevice *device)
{ LockUIntMapRead(&device->FilterMap); }
inline void UnlockFiltersRead(ALCdevice *device)
{ UnlockUIntMapRead(&device->FilterMap); }
inline void LockFiltersWrite(ALCdevice *device)
{ LockUIntMapWrite(&device->FilterMap); }
inline void UnlockFiltersWrite(ALCdevice *device)
{ UnlockUIntMapWrite(&device->FilterMap); }
inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id)
{ return (struct ALfilter*)LookupUIntMapKeyNoLock(&device->FilterMap, id); }
inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id)
{ return (struct ALfilter*)RemoveUIntMapKeyNoLock(&device->FilterMap, id); }
ALvoid ReleaseALFilters(ALCdevice *device);
#ifdef __cplusplus
}
#endif
#endif
-66
View File
@@ -1,66 +0,0 @@
#ifndef _AL_LISTENER_H_
#define _AL_LISTENER_H_
#include "alMain.h"
#include "alu.h"
#ifdef __cplusplus
extern "C" {
#endif
struct ALlistenerProps {
ALfloat Position[3];
ALfloat Velocity[3];
ALfloat Forward[3];
ALfloat Up[3];
ALfloat Gain;
ALfloat MetersPerUnit;
ALfloat DopplerFactor;
ALfloat DopplerVelocity;
ALfloat SpeedOfSound;
ALboolean SourceDistanceModel;
enum DistanceModel DistanceModel;
ATOMIC(struct ALlistenerProps*) next;
};
typedef struct ALlistener {
alignas(16) ALfloat Position[3];
ALfloat Velocity[3];
ALfloat Forward[3];
ALfloat Up[3];
ALfloat Gain;
ALfloat MetersPerUnit;
/* Pointer to the most recent property values that are awaiting an update.
*/
ATOMIC(struct ALlistenerProps*) Update;
/* A linked list of unused property containers, free to use for future
* updates.
*/
ATOMIC(struct ALlistenerProps*) FreeList;
struct {
aluMatrixf Matrix;
aluVector Velocity;
ALfloat Gain;
ALfloat MetersPerUnit;
ALfloat DopplerFactor;
ALfloat SpeedOfSound;
ALboolean SourceDistanceModel;
enum DistanceModel DistanceModel;
} Params;
} ALlistener;
void UpdateListenerProps(ALCcontext *context);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
-128
View File
@@ -1,128 +0,0 @@
#ifndef _AL_SOURCE_H_
#define _AL_SOURCE_H_
#include "bool.h"
#include "alMain.h"
#include "alu.h"
#include "hrtf.h"
#include "atomic.h"
#define MAX_SENDS 16
#define DEFAULT_SENDS 2
#ifdef __cplusplus
extern "C" {
#endif
struct ALbuffer;
struct ALsource;
typedef struct ALbufferlistitem {
struct ALbuffer *buffer;
ATOMIC(struct ALbufferlistitem*) next;
} ALbufferlistitem;
typedef struct ALsource {
/** Source properties. */
ALfloat Pitch;
ALfloat Gain;
ALfloat OuterGain;
ALfloat MinGain;
ALfloat MaxGain;
ALfloat InnerAngle;
ALfloat OuterAngle;
ALfloat RefDistance;
ALfloat MaxDistance;
ALfloat RolloffFactor;
ALfloat Position[3];
ALfloat Velocity[3];
ALfloat Direction[3];
ALfloat Orientation[2][3];
ALboolean HeadRelative;
ALboolean Looping;
enum DistanceModel DistanceModel;
enum Resampler Resampler;
ALboolean DirectChannels;
enum SpatializeMode Spatialize;
ALboolean DryGainHFAuto;
ALboolean WetGainAuto;
ALboolean WetGainHFAuto;
ALfloat OuterGainHF;
ALfloat AirAbsorptionFactor;
ALfloat RoomRolloffFactor;
ALfloat DopplerFactor;
/* NOTE: Stereo pan angles are specified in radians, counter-clockwise
* rather than clockwise.
*/
ALfloat StereoPan[2];
ALfloat Radius;
/** Direct filter and auxiliary send info. */
struct {
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Direct;
struct {
struct ALeffectslot *Slot;
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} *Send;
/**
* Last user-specified offset, and the offset type (bytes, samples, or
* seconds).
*/
ALdouble Offset;
ALenum OffsetType;
/** Source type (static, streaming, or undetermined) */
ALint SourceType;
/** Source state (initial, playing, paused, or stopped) */
ATOMIC(ALenum) state;
/** Source Buffer Queue head. */
RWLock queue_lock;
ALbufferlistitem *queue;
ATOMIC_FLAG PropsClean;
/** Self ID */
ALuint id;
} ALsource;
inline void LockSourcesRead(ALCcontext *context)
{ LockUIntMapRead(&context->SourceMap); }
inline void UnlockSourcesRead(ALCcontext *context)
{ UnlockUIntMapRead(&context->SourceMap); }
inline void LockSourcesWrite(ALCcontext *context)
{ LockUIntMapWrite(&context->SourceMap); }
inline void UnlockSourcesWrite(ALCcontext *context)
{ UnlockUIntMapWrite(&context->SourceMap); }
inline struct ALsource *LookupSource(ALCcontext *context, ALuint id)
{ return (struct ALsource*)LookupUIntMapKeyNoLock(&context->SourceMap, id); }
inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id)
{ return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); }
void UpdateAllSourceProps(ALCcontext *context);
ALvoid ReleaseALSources(ALCcontext *Context);
#ifdef __cplusplus
}
#endif
#endif
-20
View File
@@ -1,20 +0,0 @@
#ifndef ALTHUNK_H
#define ALTHUNK_H
#include "alMain.h"
#ifdef __cplusplus
extern "C" {
#endif
void ThunkInit(void);
void ThunkExit(void);
ALenum NewThunkEntry(ALuint *index);
void FreeThunkEntry(ALuint index);
#ifdef __cplusplus
}
#endif
#endif //ALTHUNK_H
-516
View File
@@ -1,516 +0,0 @@
#ifndef _ALU_H_
#define _ALU_H_
#include <limits.h>
#include <math.h>
#ifdef HAVE_FLOAT_H
#include <float.h>
#endif
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif
#include "alMain.h"
#include "alBuffer.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "hrtf.h"
#include "align.h"
#include "nfcfilter.h"
#include "math_defs.h"
#define MAX_PITCH (255)
/* Maximum number of buffer samples before the current pos needed for resampling. */
#define MAX_PRE_SAMPLES 12
/* Maximum number of buffer samples after the current pos needed for resampling. */
#define MAX_POST_SAMPLES 12
#ifdef __cplusplus
extern "C" {
#endif
struct ALsource;
struct ALbufferlistitem;
struct ALvoice;
struct ALeffectslot;
#define DITHER_RNG_SEED 22222
enum SpatializeMode {
SpatializeOff = AL_FALSE,
SpatializeOn = AL_TRUE,
SpatializeAuto = AL_AUTO_SOFT
};
enum Resampler {
PointResampler,
LinearResampler,
FIR4Resampler,
BSincResampler,
ResamplerMax = BSincResampler
};
extern enum Resampler ResamplerDefault;
/* The number of distinct scale and phase intervals within the filter table. */
#define BSINC_SCALE_BITS 4
#define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
#define BSINC_PHASE_BITS 4
#define BSINC_PHASE_COUNT (1<<BSINC_PHASE_BITS)
/* Interpolator state. Kind of a misnomer since the interpolator itself is
* stateless. This just keeps it from having to recompute scale-related
* mappings for every sample.
*/
typedef struct BsincState {
ALfloat sf; /* Scale interpolation factor. */
ALuint m; /* Coefficient count. */
ALint l; /* Left coefficient offset. */
struct {
const ALfloat *filter; /* Filter coefficients. */
const ALfloat *scDelta; /* Scale deltas. */
const ALfloat *phDelta; /* Phase deltas. */
const ALfloat *spDelta; /* Scale-phase deltas. */
} coeffs[BSINC_PHASE_COUNT];
} BsincState;
typedef union InterpState {
BsincState bsinc;
} InterpState;
ALboolean BsincPrepare(const ALuint increment, BsincState *state);
typedef const ALfloat* (*ResamplerFunc)(const InterpState *state,
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei dstlen
);
typedef union aluVector {
alignas(16) ALfloat v[4];
} aluVector;
inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w)
{
vector->v[0] = x;
vector->v[1] = y;
vector->v[2] = z;
vector->v[3] = w;
}
typedef union aluMatrixf {
alignas(16) ALfloat m[4][4];
} aluMatrixf;
extern const aluMatrixf IdentityMatrixf;
inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row,
ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3)
{
matrix->m[row][0] = m0;
matrix->m[row][1] = m1;
matrix->m[row][2] = m2;
matrix->m[row][3] = m3;
}
inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03,
ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13,
ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23,
ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33)
{
aluMatrixfSetRow(matrix, 0, m00, m01, m02, m03);
aluMatrixfSetRow(matrix, 1, m10, m11, m12, m13);
aluMatrixfSetRow(matrix, 2, m20, m21, m22, m23);
aluMatrixfSetRow(matrix, 3, m30, m31, m32, m33);
}
enum ActiveFilters {
AF_None = 0,
AF_LowPass = 1,
AF_HighPass = 2,
AF_BandPass = AF_LowPass | AF_HighPass
};
typedef struct MixHrtfParams {
const ALfloat (*Coeffs)[2];
ALsizei Delay[2];
ALfloat Gain;
ALfloat GainStep;
} MixHrtfParams;
typedef struct DirectParams {
ALfilterState LowPass;
ALfilterState HighPass;
NfcFilter NFCtrlFilter[MAX_AMBI_ORDER];
struct {
HrtfParams Old;
HrtfParams Target;
HrtfState State;
} Hrtf;
struct {
ALfloat Current[MAX_OUTPUT_CHANNELS];
ALfloat Target[MAX_OUTPUT_CHANNELS];
} Gains;
} DirectParams;
typedef struct SendParams {
ALfilterState LowPass;
ALfilterState HighPass;
struct {
ALfloat Current[MAX_OUTPUT_CHANNELS];
ALfloat Target[MAX_OUTPUT_CHANNELS];
} Gains;
} SendParams;
struct ALvoiceProps {
ATOMIC(struct ALvoiceProps*) next;
ALfloat Pitch;
ALfloat Gain;
ALfloat OuterGain;
ALfloat MinGain;
ALfloat MaxGain;
ALfloat InnerAngle;
ALfloat OuterAngle;
ALfloat RefDistance;
ALfloat MaxDistance;
ALfloat RolloffFactor;
ALfloat Position[3];
ALfloat Velocity[3];
ALfloat Direction[3];
ALfloat Orientation[2][3];
ALboolean HeadRelative;
enum DistanceModel DistanceModel;
enum Resampler Resampler;
ALboolean DirectChannels;
enum SpatializeMode SpatializeMode;
ALboolean DryGainHFAuto;
ALboolean WetGainAuto;
ALboolean WetGainHFAuto;
ALfloat OuterGainHF;
ALfloat AirAbsorptionFactor;
ALfloat RoomRolloffFactor;
ALfloat DopplerFactor;
ALfloat StereoPan[2];
ALfloat Radius;
/** Direct filter and auxiliary send info. */
struct {
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Direct;
struct {
struct ALeffectslot *Slot;
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Send[];
};
/* If not 'fading', gain targets are used directly without fading. */
#define VOICE_IS_FADING (1<<0)
#define VOICE_HAS_HRTF (1<<1)
#define VOICE_HAS_NFC (1<<2)
typedef struct ALvoice {
struct ALvoiceProps *Props;
ATOMIC(struct ALvoiceProps*) Update;
ATOMIC(struct ALvoiceProps*) FreeList;
ATOMIC(struct ALsource*) Source;
ATOMIC(bool) Playing;
/**
* Source offset in samples, relative to the currently playing buffer, NOT
* the whole queue, and the fractional (fixed-point) offset to the next
* sample.
*/
ATOMIC(ALuint) position;
ATOMIC(ALsizei) position_fraction;
/* Current buffer queue item being played. */
ATOMIC(struct ALbufferlistitem*) current_buffer;
/* Buffer queue item to loop to at end of queue (will be NULL for non-
* looping voices).
*/
ATOMIC(struct ALbufferlistitem*) loop_buffer;
/**
* Number of channels and bytes-per-sample for the attached source's
* buffer(s).
*/
ALsizei NumChannels;
ALsizei SampleSize;
/** Current target parameters used for mixing. */
ALint Step;
ResamplerFunc Resampler;
ALuint Flags;
ALuint Offset; /* Number of output samples mixed since starting. */
alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES];
InterpState ResampleState;
struct {
enum ActiveFilters FilterType;
DirectParams Params[MAX_INPUT_CHANNELS];
ALfloat (*Buffer)[BUFFERSIZE];
ALsizei Channels;
ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1];
} Direct;
struct {
enum ActiveFilters FilterType;
SendParams Params[MAX_INPUT_CHANNELS];
ALfloat (*Buffer)[BUFFERSIZE];
ALsizei Channels;
} Send[];
} ALvoice;
void DeinitVoice(ALvoice *voice);
typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans,
ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains,
const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
ALsizei BufferSize);
typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains,
const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans,
ALsizei InPos, ALsizei BufferSize);
typedef void (*HrtfMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, MixHrtfParams *hrtfparams,
HrtfState *hrtfstate, ALsizei BufferSize);
typedef void (*HrtfMixerBlendFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALsizei IrSize, const HrtfParams *oldparams,
MixHrtfParams *newparams, HrtfState *hrtfstate,
ALsizei BufferSize);
typedef void (*HrtfDirectMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
const ALfloat (*restrict Coeffs)[2],
ALfloat (*restrict Values)[2], ALsizei BufferSize);
#define GAIN_MIX_MAX (16.0f) /* +24dB */
#define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */
/* Target gain for the reverb decay feedback reaching the decay time. */
#define REVERB_DECAY_GAIN (0.001f) /* -60 dB */
#define FRACTIONBITS (12)
#define FRACTIONONE (1<<FRACTIONBITS)
#define FRACTIONMASK (FRACTIONONE-1)
inline ALfloat minf(ALfloat a, ALfloat b)
{ return ((a > b) ? b : a); }
inline ALfloat maxf(ALfloat a, ALfloat b)
{ return ((a > b) ? a : b); }
inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max)
{ return minf(max, maxf(min, val)); }
inline ALdouble mind(ALdouble a, ALdouble b)
{ return ((a > b) ? b : a); }
inline ALdouble maxd(ALdouble a, ALdouble b)
{ return ((a > b) ? a : b); }
inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max)
{ return mind(max, maxd(min, val)); }
inline ALuint minu(ALuint a, ALuint b)
{ return ((a > b) ? b : a); }
inline ALuint maxu(ALuint a, ALuint b)
{ return ((a > b) ? a : b); }
inline ALuint clampu(ALuint val, ALuint min, ALuint max)
{ return minu(max, maxu(min, val)); }
inline ALint mini(ALint a, ALint b)
{ return ((a > b) ? b : a); }
inline ALint maxi(ALint a, ALint b)
{ return ((a > b) ? a : b); }
inline ALint clampi(ALint val, ALint min, ALint max)
{ return mini(max, maxi(min, val)); }
inline ALint64 mini64(ALint64 a, ALint64 b)
{ return ((a > b) ? b : a); }
inline ALint64 maxi64(ALint64 a, ALint64 b)
{ return ((a > b) ? a : b); }
inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max)
{ return mini64(max, maxi64(min, val)); }
inline ALuint64 minu64(ALuint64 a, ALuint64 b)
{ return ((a > b) ? b : a); }
inline ALuint64 maxu64(ALuint64 a, ALuint64 b)
{ return ((a > b) ? a : b); }
inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
{ return minu64(max, maxu64(min, val)); }
extern alignas(16) const ALfloat bsincTab[18840];
extern alignas(16) const ALfloat sinc4Tab[FRACTIONONE][4];
inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
{
return val1 + (val2-val1)*mu;
}
inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALsizei frac)
{
return sinc4Tab[frac][0]*val0 + sinc4Tab[frac][1]*val1 +
sinc4Tab[frac][2]*val2 + sinc4Tab[frac][3]*val3;
}
enum HrtfRequestMode {
Hrtf_Default = 0,
Hrtf_Enable = 1,
Hrtf_Disable = 2,
};
void aluInitMixer(void);
MixerFunc SelectMixer(void);
RowMixerFunc SelectRowMixer(void);
ResamplerFunc SelectResampler(enum Resampler resampler);
/* aluInitRenderer
*
* Set up the appropriate panning method and mixing method given the device
* properties.
*/
void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq);
void aluInitEffectPanning(struct ALeffectslot *slot);
/**
* CalcDirectionCoeffs
*
* Calculates ambisonic coefficients based on a direction vector. The vector
* must be normalized (unit length), and the spread is the angular width of the
* sound (0...tau).
*/
void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
/**
* CalcAngleCoeffs
*
* Calculates ambisonic coefficients based on azimuth and elevation. The
* azimuth and elevation parameters are in radians, going right and up
* respectively.
*/
inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
{
ALfloat dir[3] = {
sinf(azimuth) * cosf(elevation),
sinf(elevation),
-cosf(azimuth) * cosf(elevation)
};
CalcDirectionCoeffs(dir, spread, coeffs);
}
/**
* CalcAnglePairwiseCoeffs
*
* Calculates ambisonic coefficients based on azimuth and elevation. The
* azimuth and elevation parameters are in radians, going right and up
* respectively. This pairwise variant warps the result such that +30 azimuth
* is full right, and -30 azimuth is full left.
*/
void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
/**
* ComputeAmbientGains
*
* Computes channel gains for ambient, omni-directional sounds.
*/
#define ComputeAmbientGains(b, g, o) do { \
if((b).CoeffCount > 0) \
ComputeAmbientGainsMC((b).Ambi.Coeffs, (b).NumChannels, g, o); \
else \
ComputeAmbientGainsBF((b).Ambi.Map, (b).NumChannels, g, o); \
} while (0)
void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
/**
* ComputePanningGains
*
* Computes panning gains using the given channel decoder coefficients and the
* pre-calculated direction or angle coefficients.
*/
#define ComputePanningGains(b, c, g, o) do { \
if((b).CoeffCount > 0) \
ComputePanningGainsMC((b).Ambi.Coeffs, (b).NumChannels, (b).CoeffCount, c, g, o);\
else \
ComputePanningGainsBF((b).Ambi.Map, (b).NumChannels, c, g, o); \
} while (0)
void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
/**
* ComputeFirstOrderGains
*
* Sets channel gains for a first-order ambisonics input channel. The matrix is
* a 1x4 'slice' of a transform matrix for the input channel, used to scale and
* orient the sound samples.
*/
#define ComputeFirstOrderGains(b, m, g, o) do { \
if((b).CoeffCount > 0) \
ComputeFirstOrderGainsMC((b).Ambi.Coeffs, (b).NumChannels, m, g, o); \
else \
ComputeFirstOrderGainsBF((b).Ambi.Map, (b).NumChannels, m, g, o); \
} while (0)
void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
ALboolean MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo);
void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples);
/* Caller must lock the device. */
void aluHandleDisconnect(ALCdevice *device);
extern ALfloat ConeScale;
extern ALfloat ZScale;
#ifdef __cplusplus
}
#endif
#endif
-94
View File
@@ -1,94 +0,0 @@
/*-
* Copyright (c) 2005 Boris Mikhaylov
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef BS2B_H
#define BS2B_H
/* Number of crossfeed levels */
#define BS2B_CLEVELS 3
/* Normal crossfeed levels */
#define BS2B_HIGH_CLEVEL 3
#define BS2B_MIDDLE_CLEVEL 2
#define BS2B_LOW_CLEVEL 1
/* Easy crossfeed levels */
#define BS2B_HIGH_ECLEVEL BS2B_HIGH_CLEVEL + BS2B_CLEVELS
#define BS2B_MIDDLE_ECLEVEL BS2B_MIDDLE_CLEVEL + BS2B_CLEVELS
#define BS2B_LOW_ECLEVEL BS2B_LOW_CLEVEL + BS2B_CLEVELS
/* Default crossfeed levels */
#define BS2B_DEFAULT_CLEVEL BS2B_HIGH_ECLEVEL
/* Default sample rate (Hz) */
#define BS2B_DEFAULT_SRATE 44100
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct bs2b {
int level; /* Crossfeed level */
int srate; /* Sample rate (Hz) */
/* Lowpass IIR filter coefficients */
float a0_lo;
float b1_lo;
/* Highboost IIR filter coefficients */
float a0_hi;
float a1_hi;
float b1_hi;
/* Buffer of last filtered sample.
* [0] - first channel, [1] - second channel
*/
struct t_last_sample {
float asis;
float lo;
float hi;
} last_sample[2];
};
/* Clear buffers and set new coefficients with new crossfeed level and sample
* rate values.
* level - crossfeed level of *LEVEL values.
* srate - sample rate by Hz.
*/
void bs2b_set_params(struct bs2b *bs2b, int level, int srate);
/* Return current crossfeed level value */
int bs2b_get_level(struct bs2b *bs2b);
/* Return current sample rate value */
int bs2b_get_srate(struct bs2b *bs2b);
/* Clear buffer */
void bs2b_clear(struct bs2b *bs2b);
void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, int SamplesToDo);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* BS2B_H */
-9
View File
@@ -1,9 +0,0 @@
#ifndef SAMPLE_CVT_H
#define SAMPLE_CVT_H
#include "AL/al.h"
#include "alBuffer.h"
void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align);
#endif /* SAMPLE_CVT_H */
-727
View File
@@ -1,727 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include <math.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alThunk.h"
#include "alError.h"
#include "alListener.h"
#include "alSource.h"
#include "almalloc.h"
extern inline void LockEffectSlotsRead(ALCcontext *context);
extern inline void UnlockEffectSlotsRead(ALCcontext *context);
extern inline void LockEffectSlotsWrite(ALCcontext *context);
extern inline void UnlockEffectSlotsWrite(ALCcontext *context);
extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id);
extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id);
static UIntMap EffectStateFactoryMap;
static inline ALeffectStateFactory *getFactoryByType(ALenum type)
{
ALeffectStateFactory* (*getFactory)(void) = LookupUIntMapKey(&EffectStateFactoryMap, type);
if(getFactory != NULL)
return getFactory();
return NULL;
}
static void ALeffectState_IncRef(ALeffectState *state);
static void ALeffectState_DecRef(ALeffectState *state);
#define DO_UPDATEPROPS() do { \
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
UpdateEffectSlotProps(slot); \
else \
ATOMIC_FLAG_CLEAR(&slot->PropsClean, almemory_order_release); \
} while(0)
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCcontext *context;
ALeffectslot **tmpslots = NULL;
ALsizei cur;
ALenum err;
context = GetContextRef();
if(!context) return;
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
tmpslots = al_malloc(DEF_ALIGN, sizeof(ALeffectslot*)*n);
LockEffectSlotsWrite(context);
for(cur = 0;cur < n;cur++)
{
ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
err = AL_OUT_OF_MEMORY;
if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
{
al_free(slot);
UnlockEffectSlotsWrite(context);
alDeleteAuxiliaryEffectSlots(cur, effectslots);
SET_ERROR_AND_GOTO(context, err, done);
}
err = NewThunkEntry(&slot->id);
if(err == AL_NO_ERROR)
err = InsertUIntMapEntryNoLock(&context->EffectSlotMap, slot->id, slot);
if(err != AL_NO_ERROR)
{
FreeThunkEntry(slot->id);
ALeffectState_DecRef(slot->Effect.State);
if(slot->Params.EffectState)
ALeffectState_DecRef(slot->Params.EffectState);
al_free(slot);
UnlockEffectSlotsWrite(context);
alDeleteAuxiliaryEffectSlots(cur, effectslots);
SET_ERROR_AND_GOTO(context, err, done);
}
aluInitEffectPanning(slot);
tmpslots[cur] = slot;
effectslots[cur] = slot->id;
}
if(n > 0)
{
struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire);
struct ALeffectslotArray *newarray = NULL;
ALsizei newcount = curarray->count + n;
ALCdevice *device;
newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount));
newarray->count = newcount;
memcpy(newarray->slot, tmpslots, sizeof(ALeffectslot*)*n);
if(curarray)
memcpy(newarray->slot+n, curarray->slot, sizeof(ALeffectslot*)*curarray->count);
newarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray,
almemory_order_acq_rel);
device = context->Device;
while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
althrd_yield();
al_free(newarray);
}
UnlockEffectSlotsWrite(context);
done:
al_free(tmpslots);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots)
{
ALCcontext *context;
ALeffectslot *slot;
ALsizei i;
context = GetContextRef();
if(!context) return;
LockEffectSlotsWrite(context);
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
for(i = 0;i < n;i++)
{
if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(ReadRef(&slot->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
}
// All effectslots are valid
if(n > 0)
{
struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire);
struct ALeffectslotArray *newarray = NULL;
ALsizei newcount = curarray->count - n;
ALCdevice *device;
ALsizei j, k;
assert(newcount >= 0);
newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount));
newarray->count = newcount;
for(i = j = 0;i < newarray->count;)
{
slot = curarray->slot[j++];
for(k = 0;k < n;k++)
{
if(slot->id == effectslots[k])
break;
}
if(k == n)
newarray->slot[i++] = slot;
}
newarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray,
almemory_order_acq_rel);
device = context->Device;
while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
althrd_yield();
al_free(newarray);
}
for(i = 0;i < n;i++)
{
if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
continue;
FreeThunkEntry(slot->id);
DeinitEffectSlot(slot);
memset(slot, 0, sizeof(*slot));
al_free(slot);
}
done:
UnlockEffectSlotsWrite(context);
ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
{
ALCcontext *context;
ALboolean ret;
context = GetContextRef();
if(!context) return AL_FALSE;
LockEffectSlotsRead(context);
ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
return ret;
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value)
{
ALCdevice *device;
ALCcontext *context;
ALeffectslot *slot;
ALeffect *effect = NULL;
ALenum err;
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
LockEffectSlotsRead(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
case AL_EFFECTSLOT_EFFECT:
device = context->Device;
LockEffectsRead(device);
effect = (value ? LookupEffect(device, value) : NULL);
if(!(value == 0 || effect != NULL))
{
UnlockEffectsRead(device);
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
}
err = InitializeEffect(device, slot, effect);
UnlockEffectsRead(device);
if(err != AL_NO_ERROR)
SET_ERROR_AND_GOTO(context, err, done);
break;
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
if(!(value == AL_TRUE || value == AL_FALSE))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
slot->AuxSendAuto = value;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
DO_UPDATEPROPS();
done:
UnlockEffectSlotsRead(context);
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values)
{
ALCcontext *context;
switch(param)
{
case AL_EFFECTSLOT_EFFECT:
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
alAuxiliaryEffectSloti(effectslot, param, values[0]);
return;
}
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value)
{
ALCcontext *context;
ALeffectslot *slot;
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
LockEffectSlotsRead(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
case AL_EFFECTSLOT_GAIN:
if(!(value >= 0.0f && value <= 1.0f))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
slot->Gain = value;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
DO_UPDATEPROPS();
done:
UnlockEffectSlotsRead(context);
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values)
{
ALCcontext *context;
switch(param)
{
case AL_EFFECTSLOT_GAIN:
alAuxiliaryEffectSlotf(effectslot, param, values[0]);
return;
}
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value)
{
ALCcontext *context;
ALeffectslot *slot;
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
*value = slot->AuxSendAuto;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values)
{
ALCcontext *context;
switch(param)
{
case AL_EFFECTSLOT_EFFECT:
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
alGetAuxiliaryEffectSloti(effectslot, param, values);
return;
}
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value)
{
ALCcontext *context;
ALeffectslot *slot;
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
case AL_EFFECTSLOT_GAIN:
*value = slot->Gain;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values)
{
ALCcontext *context;
switch(param)
{
case AL_EFFECTSLOT_GAIN:
alGetAuxiliaryEffectSlotf(effectslot, param, values);
return;
}
context = GetContextRef();
if(!context) return;
LockEffectSlotsRead(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
void InitEffectFactoryMap(void)
{
InitUIntMap(&EffectStateFactoryMap, INT_MAX);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_NULL, ALnullStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_REVERB, ALreverbStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_CHORUS, ALchorusStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_COMPRESSOR, ALcompressorStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DISTORTION, ALdistortionStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_ECHO, ALechoStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EQUALIZER, ALequalizerStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_FLANGER, ALflangerStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_RING_MODULATOR, ALmodulatorStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_DIALOGUE, ALdedicatedStateFactory_getFactory);
InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, ALdedicatedStateFactory_getFactory);
}
void DeinitEffectFactoryMap(void)
{
ResetUIntMap(&EffectStateFactoryMap);
}
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
{
ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
struct ALeffectslotProps *props;
ALeffectState *State;
if(newtype != EffectSlot->Effect.Type)
{
ALeffectStateFactory *factory;
factory = getFactoryByType(newtype);
if(!factory)
{
ERR("Failed to find factory for effect type 0x%04x\n", newtype);
return AL_INVALID_ENUM;
}
State = V0(factory,create)();
if(!State) return AL_OUT_OF_MEMORY;
START_MIXER_MODE();
almtx_lock(&Device->BackendLock);
State->OutBuffer = Device->Dry.Buffer;
State->OutChannels = Device->Dry.NumChannels;
if(V(State,deviceUpdate)(Device) == AL_FALSE)
{
almtx_unlock(&Device->BackendLock);
LEAVE_MIXER_MODE();
ALeffectState_DecRef(State);
return AL_OUT_OF_MEMORY;
}
almtx_unlock(&Device->BackendLock);
END_MIXER_MODE();
if(!effect)
{
EffectSlot->Effect.Type = AL_EFFECT_NULL;
memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props));
}
else
{
EffectSlot->Effect.Type = effect->type;
EffectSlot->Effect.Props = effect->Props;
}
ALeffectState_DecRef(EffectSlot->Effect.State);
EffectSlot->Effect.State = State;
}
else if(effect)
EffectSlot->Effect.Props = effect->Props;
/* Remove state references from old effect slot property updates. */
props = ATOMIC_LOAD_SEQ(&EffectSlot->FreeList);
while(props)
{
if(props->State)
ALeffectState_DecRef(props->State);
props->State = NULL;
props = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
}
return AL_NO_ERROR;
}
static void ALeffectState_IncRef(ALeffectState *state)
{
uint ref;
ref = IncrementRef(&state->Ref);
TRACEREF("%p increasing refcount to %u\n", state, ref);
}
static void ALeffectState_DecRef(ALeffectState *state)
{
uint ref;
ref = DecrementRef(&state->Ref);
TRACEREF("%p decreasing refcount to %u\n", state, ref);
if(ref == 0) DELETE_OBJ(state);
}
void ALeffectState_Construct(ALeffectState *state)
{
InitRef(&state->Ref, 1);
state->OutBuffer = NULL;
state->OutChannels = 0;
}
void ALeffectState_Destruct(ALeffectState *UNUSED(state))
{
}
ALenum InitEffectSlot(ALeffectslot *slot)
{
ALeffectStateFactory *factory;
slot->Effect.Type = AL_EFFECT_NULL;
factory = getFactoryByType(AL_EFFECT_NULL);
if(!(slot->Effect.State=V0(factory,create)()))
return AL_OUT_OF_MEMORY;
slot->Gain = 1.0;
slot->AuxSendAuto = AL_TRUE;
ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_relaxed);
InitRef(&slot->ref, 0);
ATOMIC_INIT(&slot->Update, NULL);
ATOMIC_INIT(&slot->FreeList, NULL);
slot->Params.Gain = 1.0f;
slot->Params.AuxSendAuto = AL_TRUE;
ALeffectState_IncRef(slot->Effect.State);
slot->Params.EffectState = slot->Effect.State;
slot->Params.RoomRolloff = 0.0f;
slot->Params.DecayTime = 0.0f;
slot->Params.DecayHFRatio = 0.0f;
slot->Params.DecayHFLimit = AL_FALSE;
slot->Params.AirAbsorptionGainHF = 1.0f;
return AL_NO_ERROR;
}
void DeinitEffectSlot(ALeffectslot *slot)
{
struct ALeffectslotProps *props;
size_t count = 0;
props = ATOMIC_LOAD_SEQ(&slot->Update);
if(props)
{
if(props->State) ALeffectState_DecRef(props->State);
TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
al_free(props);
}
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
while(props)
{
struct ALeffectslotProps *next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
if(props->State) ALeffectState_DecRef(props->State);
al_free(props);
props = next;
++count;
}
TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
ALeffectState_DecRef(slot->Effect.State);
if(slot->Params.EffectState)
ALeffectState_DecRef(slot->Params.EffectState);
}
void UpdateEffectSlotProps(ALeffectslot *slot)
{
struct ALeffectslotProps *props;
ALeffectState *oldstate;
/* Get an unused property container, or allocate a new one as needed. */
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
if(!props)
props = al_calloc(16, sizeof(*props));
else
{
struct ALeffectslotProps *next;
do {
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&slot->FreeList, &props, next,
almemory_order_seq_cst, almemory_order_acquire) == 0);
}
/* Copy in current property values. */
props->Gain = slot->Gain;
props->AuxSendAuto = slot->AuxSendAuto;
props->Type = slot->Effect.Type;
props->Props = slot->Effect.Props;
/* Swap out any stale effect state object there may be in the container, to
* delete it.
*/
ALeffectState_IncRef(slot->Effect.State);
oldstate = props->State;
props->State = slot->Effect.State;
/* Set the new container for updating internal parameters. */
props = ATOMIC_EXCHANGE_PTR(&slot->Update, props, almemory_order_acq_rel);
if(props)
{
/* If there was an unused update container, put it back in the
* freelist.
*/
ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &slot->FreeList, props);
}
if(oldstate)
ALeffectState_DecRef(oldstate);
}
void UpdateAllEffectSlotProps(ALCcontext *context)
{
struct ALeffectslotArray *auxslots;
ALsizei i;
LockEffectSlotsRead(context);
auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire);
for(i = 0;i < auxslots->count;i++)
{
ALeffectslot *slot = auxslots->slot[i];
if(!ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel))
UpdateEffectSlotProps(slot);
}
UnlockEffectSlotsRead(context);
}
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
{
ALsizei pos;
for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
{
ALeffectslot *temp = Context->EffectSlotMap.values[pos];
Context->EffectSlotMap.values[pos] = NULL;
DeinitEffectSlot(temp);
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALeffectslot));
al_free(temp);
}
}
-1409
View File
File diff suppressed because it is too large Load Diff
-716
View File
@@ -1,716 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alEffect.h"
#include "alThunk.h"
#include "alError.h"
ALboolean DisabledEffects[MAX_EFFECTS];
extern inline void LockEffectsRead(ALCdevice *device);
extern inline void UnlockEffectsRead(ALCdevice *device);
extern inline void LockEffectsWrite(ALCdevice *device);
extern inline void UnlockEffectsWrite(ALCdevice *device);
extern inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id);
extern inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id);
extern inline ALboolean IsReverbEffect(ALenum type);
static void InitEffectParams(ALeffect *effect, ALenum type);
AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
{
ALCdevice *device;
ALCcontext *context;
ALsizei cur;
context = GetContextRef();
if(!context) return;
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
device = context->Device;
for(cur = 0;cur < n;cur++)
{
ALeffect *effect = al_calloc(16, sizeof(ALeffect));
ALenum err = AL_OUT_OF_MEMORY;
if(!effect || (err=InitEffect(effect)) != AL_NO_ERROR)
{
al_free(effect);
alDeleteEffects(cur, effects);
SET_ERROR_AND_GOTO(context, err, done);
}
err = NewThunkEntry(&effect->id);
if(err == AL_NO_ERROR)
err = InsertUIntMapEntry(&device->EffectMap, effect->id, effect);
if(err != AL_NO_ERROR)
{
FreeThunkEntry(effect->id);
memset(effect, 0, sizeof(ALeffect));
al_free(effect);
alDeleteEffects(cur, effects);
SET_ERROR_AND_GOTO(context, err, done);
}
effects[cur] = effect->id;
}
done:
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
{
ALCdevice *device;
ALCcontext *context;
ALeffect *effect;
ALsizei i;
context = GetContextRef();
if(!context) return;
device = context->Device;
LockEffectsWrite(device);
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
for(i = 0;i < n;i++)
{
if(effects[i] && LookupEffect(device, effects[i]) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
}
for(i = 0;i < n;i++)
{
if((effect=RemoveEffect(device, effects[i])) == NULL)
continue;
FreeThunkEntry(effect->id);
memset(effect, 0, sizeof(*effect));
al_free(effect);
}
done:
UnlockEffectsWrite(device);
ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
{
ALCcontext *Context;
ALboolean result;
Context = GetContextRef();
if(!Context) return AL_FALSE;
LockEffectsRead(Context->Device);
result = ((!effect || LookupEffect(Context->Device, effect)) ?
AL_TRUE : AL_FALSE);
UnlockEffectsRead(Context->Device);
ALCcontext_DecRef(Context);
return result;
}
AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
{
ALCcontext *Context;
ALCdevice *Device;
ALeffect *ALEffect;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockEffectsWrite(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
if(param == AL_EFFECT_TYPE)
{
ALboolean isOk = (value == AL_EFFECT_NULL);
ALint i;
for(i = 0;!isOk && EffectList[i].val;i++)
{
if(value == EffectList[i].val &&
!DisabledEffects[EffectList[i].type])
isOk = AL_TRUE;
}
if(isOk)
InitEffectParams(ALEffect, value);
else
alSetError(Context, AL_INVALID_VALUE);
}
else
{
/* Call the appropriate handler */
V(ALEffect,setParami)(Context, param, value);
}
}
UnlockEffectsWrite(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values)
{
ALCcontext *Context;
ALCdevice *Device;
ALeffect *ALEffect;
switch(param)
{
case AL_EFFECT_TYPE:
alEffecti(effect, param, values[0]);
return;
}
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockEffectsWrite(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
V(ALEffect,setParamiv)(Context, param, values);
}
UnlockEffectsWrite(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
{
ALCcontext *Context;
ALCdevice *Device;
ALeffect *ALEffect;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockEffectsWrite(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
V(ALEffect,setParamf)(Context, param, value);
}
UnlockEffectsWrite(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values)
{
ALCcontext *Context;
ALCdevice *Device;
ALeffect *ALEffect;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockEffectsWrite(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
V(ALEffect,setParamfv)(Context, param, values);
}
UnlockEffectsWrite(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value)
{
ALCcontext *Context;
ALCdevice *Device;
ALeffect *ALEffect;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockEffectsRead(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
if(param == AL_EFFECT_TYPE)
*value = ALEffect->type;
else
{
/* Call the appropriate handler */
V(ALEffect,getParami)(Context, param, value);
}
}
UnlockEffectsRead(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values)
{
ALCcontext *Context;
ALCdevice *Device;
ALeffect *ALEffect;
switch(param)
{
case AL_EFFECT_TYPE:
alGetEffecti(effect, param, values);
return;
}
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockEffectsRead(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
V(ALEffect,getParamiv)(Context, param, values);
}
UnlockEffectsRead(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value)
{
ALCcontext *Context;
ALCdevice *Device;
ALeffect *ALEffect;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockEffectsRead(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
V(ALEffect,getParamf)(Context, param, value);
}
UnlockEffectsRead(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values)
{
ALCcontext *Context;
ALCdevice *Device;
ALeffect *ALEffect;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockEffectsRead(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
V(ALEffect,getParamfv)(Context, param, values);
}
UnlockEffectsRead(Device);
ALCcontext_DecRef(Context);
}
ALenum InitEffect(ALeffect *effect)
{
InitEffectParams(effect, AL_EFFECT_NULL);
return AL_NO_ERROR;
}
ALvoid ReleaseALEffects(ALCdevice *device)
{
ALsizei i;
for(i = 0;i < device->EffectMap.size;i++)
{
ALeffect *temp = device->EffectMap.values[i];
device->EffectMap.values[i] = NULL;
// Release effect structure
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALeffect));
al_free(temp);
}
}
static void InitEffectParams(ALeffect *effect, ALenum type)
{
switch(type)
{
case AL_EFFECT_EAXREVERB:
effect->Props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY;
effect->Props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
effect->Props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN;
effect->Props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF;
effect->Props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF;
effect->Props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
effect->Props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
effect->Props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
effect->Props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN;
effect->Props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY;
effect->Props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
effect->Props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
effect->Props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
effect->Props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN;
effect->Props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY;
effect->Props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
effect->Props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
effect->Props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
effect->Props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME;
effect->Props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH;
effect->Props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME;
effect->Props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH;
effect->Props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
effect->Props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
effect->Props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
effect->Props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
effect->Props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
SET_VTABLE1(ALeaxreverb, effect);
break;
case AL_EFFECT_REVERB:
effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY;
effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION;
effect->Props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN;
effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF;
effect->Props.Reverb.GainLF = 1.0f;
effect->Props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME;
effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO;
effect->Props.Reverb.DecayLFRatio = 1.0f;
effect->Props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN;
effect->Props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY;
effect->Props.Reverb.ReflectionsPan[0] = 0.0f;
effect->Props.Reverb.ReflectionsPan[1] = 0.0f;
effect->Props.Reverb.ReflectionsPan[2] = 0.0f;
effect->Props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN;
effect->Props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY;
effect->Props.Reverb.LateReverbPan[0] = 0.0f;
effect->Props.Reverb.LateReverbPan[1] = 0.0f;
effect->Props.Reverb.LateReverbPan[2] = 0.0f;
effect->Props.Reverb.EchoTime = 0.25f;
effect->Props.Reverb.EchoDepth = 0.0f;
effect->Props.Reverb.ModulationTime = 0.25f;
effect->Props.Reverb.ModulationDepth = 0.0f;
effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
effect->Props.Reverb.HFReference = 5000.0f;
effect->Props.Reverb.LFReference = 250.0f;
effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
SET_VTABLE1(ALreverb, effect);
break;
case AL_EFFECT_CHORUS:
effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM;
effect->Props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE;
effect->Props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE;
effect->Props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH;
effect->Props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
effect->Props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY;
SET_VTABLE1(ALchorus, effect);
break;
case AL_EFFECT_COMPRESSOR:
effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF;
SET_VTABLE1(ALcompressor, effect);
break;
case AL_EFFECT_DISTORTION:
effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE;
effect->Props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN;
effect->Props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
effect->Props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
effect->Props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
SET_VTABLE1(ALdistortion, effect);
break;
case AL_EFFECT_ECHO:
effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY;
effect->Props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
effect->Props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
effect->Props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
effect->Props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
SET_VTABLE1(ALecho, effect);
break;
case AL_EFFECT_EQUALIZER:
effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF;
effect->Props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN;
effect->Props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER;
effect->Props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN;
effect->Props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH;
effect->Props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER;
effect->Props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN;
effect->Props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH;
effect->Props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF;
effect->Props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN;
SET_VTABLE1(ALequalizer, effect);
break;
case AL_EFFECT_FLANGER:
effect->Props.Flanger.Waveform = AL_FLANGER_DEFAULT_WAVEFORM;
effect->Props.Flanger.Phase = AL_FLANGER_DEFAULT_PHASE;
effect->Props.Flanger.Rate = AL_FLANGER_DEFAULT_RATE;
effect->Props.Flanger.Depth = AL_FLANGER_DEFAULT_DEPTH;
effect->Props.Flanger.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
effect->Props.Flanger.Delay = AL_FLANGER_DEFAULT_DELAY;
SET_VTABLE1(ALflanger, effect);
break;
case AL_EFFECT_RING_MODULATOR:
effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
effect->Props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM;
SET_VTABLE1(ALmodulator, effect);
break;
case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT:
case AL_EFFECT_DEDICATED_DIALOGUE:
effect->Props.Dedicated.Gain = 1.0f;
SET_VTABLE1(ALdedicated, effect);
break;
default:
SET_VTABLE1(ALnull, effect);
break;
}
effect->type = type;
}
#include "AL/efx-presets.h"
#define DECL(x) { #x, EFX_REVERB_PRESET_##x }
static const struct {
const char name[32];
EFXEAXREVERBPROPERTIES props;
} reverblist[] = {
DECL(GENERIC),
DECL(PADDEDCELL),
DECL(ROOM),
DECL(BATHROOM),
DECL(LIVINGROOM),
DECL(STONEROOM),
DECL(AUDITORIUM),
DECL(CONCERTHALL),
DECL(CAVE),
DECL(ARENA),
DECL(HANGAR),
DECL(CARPETEDHALLWAY),
DECL(HALLWAY),
DECL(STONECORRIDOR),
DECL(ALLEY),
DECL(FOREST),
DECL(CITY),
DECL(MOUNTAINS),
DECL(QUARRY),
DECL(PLAIN),
DECL(PARKINGLOT),
DECL(SEWERPIPE),
DECL(UNDERWATER),
DECL(DRUGGED),
DECL(DIZZY),
DECL(PSYCHOTIC),
DECL(CASTLE_SMALLROOM),
DECL(CASTLE_SHORTPASSAGE),
DECL(CASTLE_MEDIUMROOM),
DECL(CASTLE_LARGEROOM),
DECL(CASTLE_LONGPASSAGE),
DECL(CASTLE_HALL),
DECL(CASTLE_CUPBOARD),
DECL(CASTLE_COURTYARD),
DECL(CASTLE_ALCOVE),
DECL(FACTORY_SMALLROOM),
DECL(FACTORY_SHORTPASSAGE),
DECL(FACTORY_MEDIUMROOM),
DECL(FACTORY_LARGEROOM),
DECL(FACTORY_LONGPASSAGE),
DECL(FACTORY_HALL),
DECL(FACTORY_CUPBOARD),
DECL(FACTORY_COURTYARD),
DECL(FACTORY_ALCOVE),
DECL(ICEPALACE_SMALLROOM),
DECL(ICEPALACE_SHORTPASSAGE),
DECL(ICEPALACE_MEDIUMROOM),
DECL(ICEPALACE_LARGEROOM),
DECL(ICEPALACE_LONGPASSAGE),
DECL(ICEPALACE_HALL),
DECL(ICEPALACE_CUPBOARD),
DECL(ICEPALACE_COURTYARD),
DECL(ICEPALACE_ALCOVE),
DECL(SPACESTATION_SMALLROOM),
DECL(SPACESTATION_SHORTPASSAGE),
DECL(SPACESTATION_MEDIUMROOM),
DECL(SPACESTATION_LARGEROOM),
DECL(SPACESTATION_LONGPASSAGE),
DECL(SPACESTATION_HALL),
DECL(SPACESTATION_CUPBOARD),
DECL(SPACESTATION_ALCOVE),
DECL(WOODEN_SMALLROOM),
DECL(WOODEN_SHORTPASSAGE),
DECL(WOODEN_MEDIUMROOM),
DECL(WOODEN_LARGEROOM),
DECL(WOODEN_LONGPASSAGE),
DECL(WOODEN_HALL),
DECL(WOODEN_CUPBOARD),
DECL(WOODEN_COURTYARD),
DECL(WOODEN_ALCOVE),
DECL(SPORT_EMPTYSTADIUM),
DECL(SPORT_SQUASHCOURT),
DECL(SPORT_SMALLSWIMMINGPOOL),
DECL(SPORT_LARGESWIMMINGPOOL),
DECL(SPORT_GYMNASIUM),
DECL(SPORT_FULLSTADIUM),
DECL(SPORT_STADIUMTANNOY),
DECL(PREFAB_WORKSHOP),
DECL(PREFAB_SCHOOLROOM),
DECL(PREFAB_PRACTISEROOM),
DECL(PREFAB_OUTHOUSE),
DECL(PREFAB_CARAVAN),
DECL(DOME_TOMB),
DECL(PIPE_SMALL),
DECL(DOME_SAINTPAULS),
DECL(PIPE_LONGTHIN),
DECL(PIPE_LARGE),
DECL(PIPE_RESONANT),
DECL(OUTDOORS_BACKYARD),
DECL(OUTDOORS_ROLLINGPLAINS),
DECL(OUTDOORS_DEEPCANYON),
DECL(OUTDOORS_CREEK),
DECL(OUTDOORS_VALLEY),
DECL(MOOD_HEAVEN),
DECL(MOOD_HELL),
DECL(MOOD_MEMORY),
DECL(DRIVING_COMMENTATOR),
DECL(DRIVING_PITGARAGE),
DECL(DRIVING_INCAR_RACER),
DECL(DRIVING_INCAR_SPORTS),
DECL(DRIVING_INCAR_LUXURY),
DECL(DRIVING_FULLGRANDSTAND),
DECL(DRIVING_EMPTYGRANDSTAND),
DECL(DRIVING_TUNNEL),
DECL(CITY_STREETS),
DECL(CITY_SUBWAY),
DECL(CITY_MUSEUM),
DECL(CITY_LIBRARY),
DECL(CITY_UNDERPASS),
DECL(CITY_ABANDONED),
DECL(DUSTYROOM),
DECL(CHAPEL),
DECL(SMALLWATERROOM),
};
#undef DECL
ALvoid LoadReverbPreset(const char *name, ALeffect *effect)
{
size_t i;
if(strcasecmp(name, "NONE") == 0)
{
InitEffectParams(effect, AL_EFFECT_NULL);
TRACE("Loading reverb '%s'\n", "NONE");
return;
}
if(!DisabledEffects[AL__EAXREVERB])
InitEffectParams(effect, AL_EFFECT_EAXREVERB);
else if(!DisabledEffects[AL__REVERB])
InitEffectParams(effect, AL_EFFECT_REVERB);
else
InitEffectParams(effect, AL_EFFECT_NULL);
for(i = 0;i < COUNTOF(reverblist);i++)
{
const EFXEAXREVERBPROPERTIES *props;
if(strcasecmp(name, reverblist[i].name) != 0)
continue;
TRACE("Loading reverb '%s'\n", reverblist[i].name);
props = &reverblist[i].props;
effect->Props.Reverb.Density = props->flDensity;
effect->Props.Reverb.Diffusion = props->flDiffusion;
effect->Props.Reverb.Gain = props->flGain;
effect->Props.Reverb.GainHF = props->flGainHF;
effect->Props.Reverb.GainLF = props->flGainLF;
effect->Props.Reverb.DecayTime = props->flDecayTime;
effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio;
effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio;
effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain;
effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay;
effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
effect->Props.Reverb.LateReverbGain = props->flLateReverbGain;
effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay;
effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
effect->Props.Reverb.EchoTime = props->flEchoTime;
effect->Props.Reverb.EchoDepth = props->flEchoDepth;
effect->Props.Reverb.ModulationTime = props->flModulationTime;
effect->Props.Reverb.ModulationDepth = props->flModulationDepth;
effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
effect->Props.Reverb.HFReference = props->flHFReference;
effect->Props.Reverb.LFReference = props->flLFReference;
effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit;
return;
}
WARN("Reverb preset '%s' not found\n", name);
}
-82
View File
@@ -1,82 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2000 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <signal.h>
#ifdef HAVE_WINDOWS_H
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include "alMain.h"
#include "AL/alc.h"
#include "alError.h"
ALboolean TrapALError = AL_FALSE;
ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
{
ALenum curerr = AL_NO_ERROR;
WARN("Error generated on context %p, code 0x%04x\n", Context, errorCode);
if(TrapALError)
{
#ifdef _WIN32
/* DebugBreak will cause an exception if there is no debugger */
if(IsDebuggerPresent())
DebugBreak();
#elif defined(SIGTRAP)
raise(SIGTRAP);
#endif
}
(void)(ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&Context->LastError, &curerr, errorCode));
}
AL_API ALenum AL_APIENTRY alGetError(void)
{
ALCcontext *Context;
ALenum errorCode;
Context = GetContextRef();
if(!Context)
{
WARN("Querying error state on null context (implicitly 0x%04x)\n",
AL_INVALID_OPERATION);
if(TrapALError)
{
#ifdef _WIN32
if(IsDebuggerPresent())
DebugBreak();
#elif defined(SIGTRAP)
raise(SIGTRAP);
#endif
}
return AL_INVALID_OPERATION;
}
errorCode = ATOMIC_EXCHANGE_SEQ(&Context->LastError, AL_NO_ERROR);
ALCcontext_DecRef(Context);
return errorCode;
}
-103
View File
@@ -1,103 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "alError.h"
#include "alMain.h"
#include "alFilter.h"
#include "alEffect.h"
#include "alAuxEffectSlot.h"
#include "alSource.h"
#include "alBuffer.h"
#include "AL/al.h"
#include "AL/alc.h"
const struct EffectList EffectList[] = {
{ "eaxreverb", AL__EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB },
{ "reverb", AL__REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB },
{ "chorus", AL__CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS },
{ "compressor", AL__COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR },
{ "distortion", AL__DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION },
{ "echo", AL__ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO },
{ "equalizer", AL__EQUALIZER, "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER },
{ "flanger", AL__FLANGER, "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER },
{ "modulator", AL__MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR },
{ "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
{ "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE },
{ NULL, 0, NULL, (ALenum)0 }
};
AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName)
{
ALboolean ret = AL_FALSE;
ALCcontext *context;
const char *ptr;
size_t len;
context = GetContextRef();
if(!context) return AL_FALSE;
if(!(extName))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
len = strlen(extName);
ptr = context->ExtensionList;
while(ptr && *ptr)
{
if(strncasecmp(ptr, extName, len) == 0 &&
(ptr[len] == '\0' || isspace(ptr[len])))
{
ret = AL_TRUE;
break;
}
if((ptr=strchr(ptr, ' ')) != NULL)
{
do {
++ptr;
} while(isspace(*ptr));
}
}
done:
ALCcontext_DecRef(context);
return ret;
}
AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName)
{
if(!funcName)
return NULL;
return alcGetProcAddress(NULL, funcName);
}
AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName)
{
if(!enumName)
return (ALenum)0;
return alcGetEnumValue(NULL, enumName);
}
-719
View File
@@ -1,719 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include "alMain.h"
#include "alu.h"
#include "alFilter.h"
#include "alThunk.h"
#include "alError.h"
extern inline void LockFiltersRead(ALCdevice *device);
extern inline void UnlockFiltersRead(ALCdevice *device);
extern inline void LockFiltersWrite(ALCdevice *device);
extern inline void UnlockFiltersWrite(ALCdevice *device);
extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id);
extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id);
extern inline void ALfilterState_clear(ALfilterState *filter);
extern inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src);
extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples);
extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope);
extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth);
static void InitFilterParams(ALfilter *filter, ALenum type);
AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
{
ALCdevice *device;
ALCcontext *context;
ALsizei cur = 0;
ALenum err;
context = GetContextRef();
if(!context) return;
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
device = context->Device;
for(cur = 0;cur < n;cur++)
{
ALfilter *filter = al_calloc(16, sizeof(ALfilter));
if(!filter)
{
alDeleteFilters(cur, filters);
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
}
InitFilterParams(filter, AL_FILTER_NULL);
err = NewThunkEntry(&filter->id);
if(err == AL_NO_ERROR)
err = InsertUIntMapEntry(&device->FilterMap, filter->id, filter);
if(err != AL_NO_ERROR)
{
FreeThunkEntry(filter->id);
memset(filter, 0, sizeof(ALfilter));
al_free(filter);
alDeleteFilters(cur, filters);
SET_ERROR_AND_GOTO(context, err, done);
}
filters[cur] = filter->id;
}
done:
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
{
ALCdevice *device;
ALCcontext *context;
ALfilter *filter;
ALsizei i;
context = GetContextRef();
if(!context) return;
device = context->Device;
LockFiltersWrite(device);
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
for(i = 0;i < n;i++)
{
if(filters[i] && LookupFilter(device, filters[i]) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
}
for(i = 0;i < n;i++)
{
if((filter=RemoveFilter(device, filters[i])) == NULL)
continue;
FreeThunkEntry(filter->id);
memset(filter, 0, sizeof(*filter));
al_free(filter);
}
done:
UnlockFiltersWrite(device);
ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
{
ALCcontext *Context;
ALboolean result;
Context = GetContextRef();
if(!Context) return AL_FALSE;
LockFiltersRead(Context->Device);
result = ((!filter || LookupFilter(Context->Device, filter)) ?
AL_TRUE : AL_FALSE);
UnlockFiltersRead(Context->Device);
ALCcontext_DecRef(Context);
return result;
}
AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
{
ALCcontext *Context;
ALCdevice *Device;
ALfilter *ALFilter;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockFiltersWrite(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
if(param == AL_FILTER_TYPE)
{
if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS ||
value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS)
InitFilterParams(ALFilter, value);
else
alSetError(Context, AL_INVALID_VALUE);
}
else
{
/* Call the appropriate handler */
ALfilter_SetParami(ALFilter, Context, param, value);
}
}
UnlockFiltersWrite(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values)
{
ALCcontext *Context;
ALCdevice *Device;
ALfilter *ALFilter;
switch(param)
{
case AL_FILTER_TYPE:
alFilteri(filter, param, values[0]);
return;
}
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockFiltersWrite(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_SetParamiv(ALFilter, Context, param, values);
}
UnlockFiltersWrite(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
{
ALCcontext *Context;
ALCdevice *Device;
ALfilter *ALFilter;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockFiltersWrite(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_SetParamf(ALFilter, Context, param, value);
}
UnlockFiltersWrite(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values)
{
ALCcontext *Context;
ALCdevice *Device;
ALfilter *ALFilter;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockFiltersWrite(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_SetParamfv(ALFilter, Context, param, values);
}
UnlockFiltersWrite(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value)
{
ALCcontext *Context;
ALCdevice *Device;
ALfilter *ALFilter;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockFiltersRead(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
if(param == AL_FILTER_TYPE)
*value = ALFilter->type;
else
{
/* Call the appropriate handler */
ALfilter_GetParami(ALFilter, Context, param, value);
}
}
UnlockFiltersRead(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values)
{
ALCcontext *Context;
ALCdevice *Device;
ALfilter *ALFilter;
switch(param)
{
case AL_FILTER_TYPE:
alGetFilteri(filter, param, values);
return;
}
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockFiltersRead(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_GetParamiv(ALFilter, Context, param, values);
}
UnlockFiltersRead(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value)
{
ALCcontext *Context;
ALCdevice *Device;
ALfilter *ALFilter;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockFiltersRead(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_GetParamf(ALFilter, Context, param, value);
}
UnlockFiltersRead(Device);
ALCcontext_DecRef(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values)
{
ALCcontext *Context;
ALCdevice *Device;
ALfilter *ALFilter;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
LockFiltersRead(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_GetParamfv(ALFilter, Context, param, values);
}
UnlockFiltersRead(Device);
ALCcontext_DecRef(Context);
}
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ)
{
ALfloat alpha, sqrtgain_alpha_2;
ALfloat w0, sin_w0, cos_w0;
ALfloat a[3] = { 1.0f, 0.0f, 0.0f };
ALfloat b[3] = { 1.0f, 0.0f, 0.0f };
// Limit gain to -100dB
assert(gain > 0.00001f);
w0 = F_TAU * freq_mult;
sin_w0 = sinf(w0);
cos_w0 = cosf(w0);
alpha = sin_w0/2.0f * rcpQ;
/* Calculate filter coefficients depending on filter type */
switch(type)
{
case ALfilterType_HighShelf:
sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 );
b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 );
a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
break;
case ALfilterType_LowShelf:
sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 );
b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 );
a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
break;
case ALfilterType_Peaking:
gain = sqrtf(gain);
b[0] = 1.0f + alpha * gain;
b[1] = -2.0f * cos_w0;
b[2] = 1.0f - alpha * gain;
a[0] = 1.0f + alpha / gain;
a[1] = -2.0f * cos_w0;
a[2] = 1.0f - alpha / gain;
break;
case ALfilterType_LowPass:
b[0] = (1.0f - cos_w0) / 2.0f;
b[1] = 1.0f - cos_w0;
b[2] = (1.0f - cos_w0) / 2.0f;
a[0] = 1.0f + alpha;
a[1] = -2.0f * cos_w0;
a[2] = 1.0f - alpha;
break;
case ALfilterType_HighPass:
b[0] = (1.0f + cos_w0) / 2.0f;
b[1] = -(1.0f + cos_w0);
b[2] = (1.0f + cos_w0) / 2.0f;
a[0] = 1.0f + alpha;
a[1] = -2.0f * cos_w0;
a[2] = 1.0f - alpha;
break;
case ALfilterType_BandPass:
b[0] = alpha;
b[1] = 0;
b[2] = -alpha;
a[0] = 1.0f + alpha;
a[1] = -2.0f * cos_w0;
a[2] = 1.0f - alpha;
break;
}
filter->a1 = a[1] / a[0];
filter->a2 = a[2] / a[0];
filter->b0 = b[0] / a[0];
filter->b1 = b[1] / a[0];
filter->b2 = b[2] / a[0];
}
static void lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_LOWPASS_GAIN:
if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->Gain = val;
break;
case AL_LOWPASS_GAINHF:
if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->GainHF = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void lp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
lp_SetParamf(filter, context, param, vals[0]);
}
static void lp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
case AL_LOWPASS_GAIN:
*val = filter->Gain;
break;
case AL_LOWPASS_GAINHF:
*val = filter->GainHF;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void lp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{
lp_GetParamf(filter, context, param, vals);
}
static void hp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_HIGHPASS_GAIN:
if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->Gain = val;
break;
case AL_HIGHPASS_GAINLF:
if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->GainLF = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void hp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
hp_SetParamf(filter, context, param, vals[0]);
}
static void hp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
case AL_HIGHPASS_GAIN:
*val = filter->Gain;
break;
case AL_HIGHPASS_GAINLF:
*val = filter->GainLF;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void hp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{
hp_GetParamf(filter, context, param, vals);
}
static void bp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_BANDPASS_GAIN:
if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->Gain = val;
break;
case AL_BANDPASS_GAINHF:
if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->GainHF = val;
break;
case AL_BANDPASS_GAINLF:
if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->GainLF = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void bp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
bp_SetParamf(filter, context, param, vals[0]);
}
static void bp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
case AL_BANDPASS_GAIN:
*val = filter->Gain;
break;
case AL_BANDPASS_GAINHF:
*val = filter->GainHF;
break;
case AL_BANDPASS_GAINLF:
*val = filter->GainLF;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void bp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{
bp_GetParamf(filter, context, param, vals);
}
static void null_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_SetParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_SetParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALfloat *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
ALvoid ReleaseALFilters(ALCdevice *device)
{
ALsizei i;
for(i = 0;i < device->FilterMap.size;i++)
{
ALfilter *temp = device->FilterMap.values[i];
device->FilterMap.values[i] = NULL;
// Release filter structure
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALfilter));
al_free(temp);
}
}
static void InitFilterParams(ALfilter *filter, ALenum type)
{
if(type == AL_FILTER_LOWPASS)
{
filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = 1.0f;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = lp_SetParami;
filter->SetParamiv = lp_SetParamiv;
filter->SetParamf = lp_SetParamf;
filter->SetParamfv = lp_SetParamfv;
filter->GetParami = lp_GetParami;
filter->GetParamiv = lp_GetParamiv;
filter->GetParamf = lp_GetParamf;
filter->GetParamfv = lp_GetParamfv;
}
else if(type == AL_FILTER_HIGHPASS)
{
filter->Gain = AL_HIGHPASS_DEFAULT_GAIN;
filter->GainHF = 1.0f;
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = hp_SetParami;
filter->SetParamiv = hp_SetParamiv;
filter->SetParamf = hp_SetParamf;
filter->SetParamfv = hp_SetParamfv;
filter->GetParami = hp_GetParami;
filter->GetParamiv = hp_GetParamiv;
filter->GetParamf = hp_GetParamf;
filter->GetParamfv = hp_GetParamfv;
}
else if(type == AL_FILTER_BANDPASS)
{
filter->Gain = AL_BANDPASS_DEFAULT_GAIN;
filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF;
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = bp_SetParami;
filter->SetParamiv = bp_SetParamiv;
filter->SetParamf = bp_SetParamf;
filter->SetParamfv = bp_SetParamfv;
filter->GetParami = bp_GetParami;
filter->GetParamiv = bp_GetParamiv;
filter->GetParamf = bp_GetParamf;
filter->GetParamfv = bp_GetParamfv;
}
else
{
filter->Gain = 1.0f;
filter->GainHF = 1.0f;
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = 1.0f;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = null_SetParami;
filter->SetParamiv = null_SetParamiv;
filter->SetParamf = null_SetParamf;
filter->SetParamfv = null_SetParamfv;
filter->GetParami = null_GetParami;
filter->GetParamiv = null_GetParamiv;
filter->GetParamf = null_GetParamf;
filter->GetParamfv = null_GetParamfv;
}
filter->type = type;
}
-510
View File
@@ -1,510 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2000 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include "alMain.h"
#include "AL/alc.h"
#include "alError.h"
#include "alListener.h"
#include "alSource.h"
AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
switch(param)
{
case AL_GAIN:
if(!(value >= 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->Gain = value;
break;
case AL_METERS_PER_UNIT:
if(!(value >= 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->MetersPerUnit = value;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
switch(param)
{
case AL_POSITION:
if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->Position[0] = value1;
context->Listener->Position[1] = value2;
context->Listener->Position[2] = value3;
break;
case AL_VELOCITY:
if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->Velocity[0] = value1;
context->Listener->Velocity[1] = value2;
context->Listener->Velocity[2] = value3;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
{
ALCcontext *context;
if(values)
{
switch(param)
{
case AL_GAIN:
case AL_METERS_PER_UNIT:
alListenerf(param, values[0]);
return;
case AL_POSITION:
case AL_VELOCITY:
alListener3f(param, values[0], values[1], values[2]);
return;
}
}
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
case AL_ORIENTATION:
if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
/* AT then UP */
context->Listener->Forward[0] = values[0];
context->Listener->Forward[1] = values[1];
context->Listener->Forward[2] = values[2];
context->Listener->Up[0] = values[3];
context->Listener->Up[1] = values[4];
context->Listener->Up[2] = values[5];
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3)
{
ALCcontext *context;
switch(param)
{
case AL_POSITION:
case AL_VELOCITY:
alListener3f(param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3);
return;
}
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
{
ALCcontext *context;
if(values)
{
ALfloat fvals[6];
switch(param)
{
case AL_POSITION:
case AL_VELOCITY:
alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]);
return;
case AL_ORIENTATION:
fvals[0] = (ALfloat)values[0];
fvals[1] = (ALfloat)values[1];
fvals[2] = (ALfloat)values[2];
fvals[3] = (ALfloat)values[3];
fvals[4] = (ALfloat)values[4];
fvals[5] = (ALfloat)values[5];
alListenerfv(param, fvals);
return;
}
}
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(value))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
case AL_GAIN:
*value = context->Listener->Gain;
break;
case AL_METERS_PER_UNIT:
*value = context->Listener->MetersPerUnit;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(value1 && value2 && value3))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
case AL_POSITION:
*value1 = context->Listener->Position[0];
*value2 = context->Listener->Position[1];
*value3 = context->Listener->Position[2];
break;
case AL_VELOCITY:
*value1 = context->Listener->Velocity[0];
*value2 = context->Listener->Velocity[1];
*value3 = context->Listener->Velocity[2];
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
{
ALCcontext *context;
switch(param)
{
case AL_GAIN:
case AL_METERS_PER_UNIT:
alGetListenerf(param, values);
return;
case AL_POSITION:
case AL_VELOCITY:
alGetListener3f(param, values+0, values+1, values+2);
return;
}
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
case AL_ORIENTATION:
// AT then UP
values[0] = context->Listener->Forward[0];
values[1] = context->Listener->Forward[1];
values[2] = context->Listener->Forward[2];
values[3] = context->Listener->Up[0];
values[4] = context->Listener->Up[1];
values[5] = context->Listener->Up[2];
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(value))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(value1 && value2 && value3))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch (param)
{
case AL_POSITION:
*value1 = (ALint)context->Listener->Position[0];
*value2 = (ALint)context->Listener->Position[1];
*value3 = (ALint)context->Listener->Position[2];
break;
case AL_VELOCITY:
*value1 = (ALint)context->Listener->Velocity[0];
*value2 = (ALint)context->Listener->Velocity[1];
*value3 = (ALint)context->Listener->Velocity[2];
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
{
ALCcontext *context;
switch(param)
{
case AL_POSITION:
case AL_VELOCITY:
alGetListener3i(param, values+0, values+1, values+2);
return;
}
context = GetContextRef();
if(!context) return;
ReadLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
case AL_ORIENTATION:
// AT then UP
values[0] = (ALint)context->Listener->Forward[0];
values[1] = (ALint)context->Listener->Forward[1];
values[2] = (ALint)context->Listener->Forward[2];
values[3] = (ALint)context->Listener->Up[0];
values[4] = (ALint)context->Listener->Up[1];
values[5] = (ALint)context->Listener->Up[2];
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
void UpdateListenerProps(ALCcontext *context)
{
ALlistener *listener = context->Listener;
struct ALlistenerProps *props;
/* Get an unused proprty container, or allocate a new one as needed. */
props = ATOMIC_LOAD(&listener->FreeList, almemory_order_acquire);
if(!props)
props = al_calloc(16, sizeof(*props));
else
{
struct ALlistenerProps *next;
do {
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&listener->FreeList, &props, next,
almemory_order_seq_cst, almemory_order_acquire) == 0);
}
/* Copy in current property values. */
props->Position[0] = listener->Position[0];
props->Position[1] = listener->Position[1];
props->Position[2] = listener->Position[2];
props->Velocity[0] = listener->Velocity[0];
props->Velocity[1] = listener->Velocity[1];
props->Velocity[2] = listener->Velocity[2];
props->Forward[0] = listener->Forward[0];
props->Forward[1] = listener->Forward[1];
props->Forward[2] = listener->Forward[2];
props->Up[0] = listener->Up[0];
props->Up[1] = listener->Up[1];
props->Up[2] = listener->Up[2];
props->Gain = listener->Gain;
props->MetersPerUnit = listener->MetersPerUnit;
props->DopplerFactor = context->DopplerFactor;
props->DopplerVelocity = context->DopplerVelocity;
props->SpeedOfSound = context->SpeedOfSound;
props->SourceDistanceModel = context->SourceDistanceModel;
props->DistanceModel = context->DistanceModel;;
/* Set the new container for updating internal parameters. */
props = ATOMIC_EXCHANGE_PTR(&listener->Update, props, almemory_order_acq_rel);
if(props)
{
/* If there was an unused update container, put it back in the
* freelist.
*/
ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &listener->FreeList, props);
}
}
-3527
View File
File diff suppressed because it is too large Load Diff
-779
View File
@@ -1,779 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2000 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include "version.h"
#include <stdlib.h>
#include "alMain.h"
#include "AL/alc.h"
#include "AL/al.h"
#include "AL/alext.h"
#include "alError.h"
#include "alListener.h"
#include "alSource.h"
#include "alAuxEffectSlot.h"
#include "backends/base.h"
static const ALchar alVendor[] = "OpenAL Community";
static const ALchar alVersion[] = "1.1 ALSOFT "ALSOFT_VERSION;
static const ALchar alRenderer[] = "OpenAL Soft";
// Error Messages
static const ALchar alNoError[] = "No Error";
static const ALchar alErrInvalidName[] = "Invalid Name";
static const ALchar alErrInvalidEnum[] = "Invalid Enum";
static const ALchar alErrInvalidValue[] = "Invalid Value";
static const ALchar alErrInvalidOp[] = "Invalid Operation";
static const ALchar alErrOutOfMemory[] = "Out of Memory";
/* Resampler strings */
static const ALchar alPointResampler[] = "Nearest";
static const ALchar alLinearResampler[] = "Linear";
static const ALchar alSinc4Resampler[] = "4-Point Sinc";
static const ALchar alBSincResampler[] = "Band-limited Sinc (12/24)";
AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
switch(capability)
{
case AL_SOURCE_DISTANCE_MODEL:
context->SourceDistanceModel = AL_TRUE;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
switch(capability)
{
case AL_SOURCE_DISTANCE_MODEL:
context->SourceDistanceModel = AL_FALSE;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
{
ALCcontext *context;
ALboolean value=AL_FALSE;
context = GetContextRef();
if(!context) return AL_FALSE;
switch(capability)
{
case AL_SOURCE_DISTANCE_MODEL:
value = context->SourceDistanceModel;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
return value;
}
AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
{
ALCcontext *context;
ALboolean value=AL_FALSE;
context = GetContextRef();
if(!context) return AL_FALSE;
switch(pname)
{
case AL_DOPPLER_FACTOR:
if(context->DopplerFactor != 0.0f)
value = AL_TRUE;
break;
case AL_DOPPLER_VELOCITY:
if(context->DopplerVelocity != 0.0f)
value = AL_TRUE;
break;
case AL_DISTANCE_MODEL:
if(context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED)
value = AL_TRUE;
break;
case AL_SPEED_OF_SOUND:
if(context->SpeedOfSound != 0.0f)
value = AL_TRUE;
break;
case AL_DEFERRED_UPDATES_SOFT:
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
value = AL_TRUE;
break;
case AL_GAIN_LIMIT_SOFT:
if(GAIN_MIX_MAX/context->GainBoost != 0.0f)
value = AL_TRUE;
break;
case AL_NUM_RESAMPLERS_SOFT:
/* Always non-0. */
value = AL_TRUE;
break;
case AL_DEFAULT_RESAMPLER_SOFT:
value = ResamplerDefault ? AL_TRUE : AL_FALSE;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
return value;
}
AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
{
ALCcontext *context;
ALdouble value = 0.0;
context = GetContextRef();
if(!context) return 0.0;
switch(pname)
{
case AL_DOPPLER_FACTOR:
value = (ALdouble)context->DopplerFactor;
break;
case AL_DOPPLER_VELOCITY:
value = (ALdouble)context->DopplerVelocity;
break;
case AL_DISTANCE_MODEL:
value = (ALdouble)context->DistanceModel;
break;
case AL_SPEED_OF_SOUND:
value = (ALdouble)context->SpeedOfSound;
break;
case AL_DEFERRED_UPDATES_SOFT:
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
value = (ALdouble)AL_TRUE;
break;
case AL_GAIN_LIMIT_SOFT:
value = (ALdouble)GAIN_MIX_MAX/context->GainBoost;
break;
case AL_NUM_RESAMPLERS_SOFT:
value = (ALdouble)(ResamplerMax + 1);
break;
case AL_DEFAULT_RESAMPLER_SOFT:
value = (ALdouble)ResamplerDefault;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
return value;
}
AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
{
ALCcontext *context;
ALfloat value = 0.0f;
context = GetContextRef();
if(!context) return 0.0f;
switch(pname)
{
case AL_DOPPLER_FACTOR:
value = context->DopplerFactor;
break;
case AL_DOPPLER_VELOCITY:
value = context->DopplerVelocity;
break;
case AL_DISTANCE_MODEL:
value = (ALfloat)context->DistanceModel;
break;
case AL_SPEED_OF_SOUND:
value = context->SpeedOfSound;
break;
case AL_DEFERRED_UPDATES_SOFT:
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
value = (ALfloat)AL_TRUE;
break;
case AL_GAIN_LIMIT_SOFT:
value = GAIN_MIX_MAX/context->GainBoost;
break;
case AL_NUM_RESAMPLERS_SOFT:
value = (ALfloat)(ResamplerMax + 1);
break;
case AL_DEFAULT_RESAMPLER_SOFT:
value = (ALfloat)ResamplerDefault;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
return value;
}
AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
{
ALCcontext *context;
ALint value = 0;
context = GetContextRef();
if(!context) return 0;
switch(pname)
{
case AL_DOPPLER_FACTOR:
value = (ALint)context->DopplerFactor;
break;
case AL_DOPPLER_VELOCITY:
value = (ALint)context->DopplerVelocity;
break;
case AL_DISTANCE_MODEL:
value = (ALint)context->DistanceModel;
break;
case AL_SPEED_OF_SOUND:
value = (ALint)context->SpeedOfSound;
break;
case AL_DEFERRED_UPDATES_SOFT:
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
value = (ALint)AL_TRUE;
break;
case AL_GAIN_LIMIT_SOFT:
value = (ALint)(GAIN_MIX_MAX/context->GainBoost);
break;
case AL_NUM_RESAMPLERS_SOFT:
value = ResamplerMax + 1;
break;
case AL_DEFAULT_RESAMPLER_SOFT:
value = ResamplerDefault;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
return value;
}
AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
{
ALCcontext *context;
ALint64SOFT value = 0;
context = GetContextRef();
if(!context) return 0;
switch(pname)
{
case AL_DOPPLER_FACTOR:
value = (ALint64SOFT)context->DopplerFactor;
break;
case AL_DOPPLER_VELOCITY:
value = (ALint64SOFT)context->DopplerVelocity;
break;
case AL_DISTANCE_MODEL:
value = (ALint64SOFT)context->DistanceModel;
break;
case AL_SPEED_OF_SOUND:
value = (ALint64SOFT)context->SpeedOfSound;
break;
case AL_DEFERRED_UPDATES_SOFT:
if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
value = (ALint64SOFT)AL_TRUE;
break;
case AL_GAIN_LIMIT_SOFT:
value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost);
break;
case AL_NUM_RESAMPLERS_SOFT:
value = (ALint64SOFT)(ResamplerMax + 1);
break;
case AL_DEFAULT_RESAMPLER_SOFT:
value = (ALint64SOFT)ResamplerDefault;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
return value;
}
AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
{
ALCcontext *context;
if(values)
{
switch(pname)
{
case AL_DOPPLER_FACTOR:
case AL_DOPPLER_VELOCITY:
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_GAIN_LIMIT_SOFT:
case AL_NUM_RESAMPLERS_SOFT:
case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetBoolean(pname);
return;
}
}
context = GetContextRef();
if(!context) return;
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(pname)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
{
ALCcontext *context;
if(values)
{
switch(pname)
{
case AL_DOPPLER_FACTOR:
case AL_DOPPLER_VELOCITY:
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_GAIN_LIMIT_SOFT:
case AL_NUM_RESAMPLERS_SOFT:
case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetDouble(pname);
return;
}
}
context = GetContextRef();
if(!context) return;
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(pname)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
{
ALCcontext *context;
if(values)
{
switch(pname)
{
case AL_DOPPLER_FACTOR:
case AL_DOPPLER_VELOCITY:
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_GAIN_LIMIT_SOFT:
case AL_NUM_RESAMPLERS_SOFT:
case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetFloat(pname);
return;
}
}
context = GetContextRef();
if(!context) return;
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(pname)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
{
ALCcontext *context;
if(values)
{
switch(pname)
{
case AL_DOPPLER_FACTOR:
case AL_DOPPLER_VELOCITY:
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_GAIN_LIMIT_SOFT:
case AL_NUM_RESAMPLERS_SOFT:
case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetInteger(pname);
return;
}
}
context = GetContextRef();
if(!context) return;
switch(pname)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
{
ALCcontext *context;
if(values)
{
switch(pname)
{
case AL_DOPPLER_FACTOR:
case AL_DOPPLER_VELOCITY:
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_GAIN_LIMIT_SOFT:
case AL_NUM_RESAMPLERS_SOFT:
case AL_DEFAULT_RESAMPLER_SOFT:
values[0] = alGetInteger64SOFT(pname);
return;
}
}
context = GetContextRef();
if(!context) return;
switch(pname)
{
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
}
AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
{
const ALchar *value = NULL;
ALCcontext *context;
context = GetContextRef();
if(!context) return NULL;
switch(pname)
{
case AL_VENDOR:
value = alVendor;
break;
case AL_VERSION:
value = alVersion;
break;
case AL_RENDERER:
value = alRenderer;
break;
case AL_EXTENSIONS:
value = context->ExtensionList;
break;
case AL_NO_ERROR:
value = alNoError;
break;
case AL_INVALID_NAME:
value = alErrInvalidName;
break;
case AL_INVALID_ENUM:
value = alErrInvalidEnum;
break;
case AL_INVALID_VALUE:
value = alErrInvalidValue;
break;
case AL_INVALID_OPERATION:
value = alErrInvalidOp;
break;
case AL_OUT_OF_MEMORY:
value = alErrOutOfMemory;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
return value;
}
AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
if(!(value >= 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
WriteLock(&context->PropLock);
context->DopplerFactor = value;
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
WriteUnlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
if(!(value >= 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
WriteLock(&context->PropLock);
context->DopplerVelocity = value;
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
WriteUnlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
if(!(value > 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
WriteLock(&context->PropLock);
context->SpeedOfSound = value;
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
WriteUnlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED ||
value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED ||
value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED ||
value == AL_NONE))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
WriteLock(&context->PropLock);
context->DistanceModel = value;
if(!context->SourceDistanceModel)
{
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
}
WriteUnlock(&context->PropLock);
done:
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
ALCcontext_DeferUpdates(context);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
{
ALCcontext *context;
context = GetContextRef();
if(!context) return;
ALCcontext_ProcessUpdates(context);
ALCcontext_DecRef(context);
}
AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
{
const char *ResamplerNames[] = {
alPointResampler, alLinearResampler,
alSinc4Resampler, alBSincResampler,
};
const ALchar *value = NULL;
ALCcontext *context;
static_assert(COUNTOF(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list");
context = GetContextRef();
if(!context) return NULL;
switch(pname)
{
case AL_RESAMPLER_NAME_SOFT:
if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
value = ResamplerNames[index];
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
ALCcontext_DecRef(context);
return value;
}
-108
View File
@@ -1,108 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include "alMain.h"
#include "alThunk.h"
#include "almalloc.h"
static ATOMIC_FLAG *ThunkArray;
static ALsizei ThunkArraySize;
static RWLock ThunkLock;
void ThunkInit(void)
{
RWLockInit(&ThunkLock);
ThunkArraySize = 1024;
ThunkArray = al_calloc(16, ThunkArraySize * sizeof(*ThunkArray));
}
void ThunkExit(void)
{
al_free(ThunkArray);
ThunkArray = NULL;
ThunkArraySize = 0;
}
ALenum NewThunkEntry(ALuint *index)
{
void *NewList;
ALsizei i;
ReadLock(&ThunkLock);
for(i = 0;i < ThunkArraySize;i++)
{
if(!ATOMIC_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_acq_rel))
{
ReadUnlock(&ThunkLock);
*index = i+1;
return AL_NO_ERROR;
}
}
ReadUnlock(&ThunkLock);
WriteLock(&ThunkLock);
/* Double-check that there's still no free entries, in case another
* invocation just came through and increased the size of the array.
*/
for(;i < ThunkArraySize;i++)
{
if(!ATOMIC_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_acq_rel))
{
WriteUnlock(&ThunkLock);
*index = i+1;
return AL_NO_ERROR;
}
}
NewList = al_calloc(16, ThunkArraySize*2 * sizeof(*ThunkArray));
if(!NewList)
{
WriteUnlock(&ThunkLock);
ERR("Realloc failed to increase to %u entries!\n", ThunkArraySize*2);
return AL_OUT_OF_MEMORY;
}
memcpy(NewList, ThunkArray, ThunkArraySize*sizeof(*ThunkArray));
al_free(ThunkArray);
ThunkArray = NewList;
ThunkArraySize *= 2;
ATOMIC_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_seq_cst);
*index = ++i;
for(;i < ThunkArraySize;i++)
ATOMIC_FLAG_CLEAR(&ThunkArray[i], almemory_order_relaxed);
WriteUnlock(&ThunkLock);
return AL_NO_ERROR;
}
void FreeThunkEntry(ALuint index)
{
ReadLock(&ThunkLock);
if(index > 0 && (ALsizei)index <= ThunkArraySize)
ATOMIC_FLAG_CLEAR(&ThunkArray[index-1], almemory_order_release);
ReadUnlock(&ThunkLock);
}
File diff suppressed because it is too large Load Diff
-55
View File
@@ -1,55 +0,0 @@
Source Install
==============
To install OpenAL Soft, use your favorite shell to go into the build/
directory, and run:
cmake ..
Assuming configuration went well, you can then build it, typically using GNU
Make (KDevelop, MSVC, and others are possible depending on your system setup
and CMake configuration).
Please Note: Double check that the appropriate backends were detected. Often,
complaints of no sound, crashing, and missing devices can be solved by making
sure the correct backends are being used. CMake's output will identify which
backends were enabled.
For most systems, you will likely want to make sure ALSA, OSS, and PulseAudio
were detected (if your target system uses them). For Windows, make sure
DirectSound was detected.
Utilities
=========
The source package comes with an informational utility, openal-info, and is
built by default. It prints out information provided by the ALC and AL sub-
systems, including discovered devices, version information, and extensions.
Configuration
=============
OpenAL Soft can be configured on a per-user and per-system basis. This allows
users and sysadmins to control information provided to applications, as well
as application-agnostic behavior of the library. See alsoftrc.sample for
available settings.
Acknowledgements
================
Special thanks go to:
Creative Labs for the original source code this is based off of.
Christopher Fitzgerald for the current reverb effect implementation, and
helping with the low-pass and HRTF filters.
Christian Borss for the 3D panning code previous versions used as a base.
Ben Davis for the idea behind a previous version of the click-removal code.
Richard Furse for helping with my understanding of Ambisonics that is used by
the various parts of the library.
+16
View File
@@ -0,0 +1,16 @@
# openal-soft-vita
This repo contains patchsets for vita [openal-soft](https://openal-soft.org/) port.
Format is openal-soft-<openal_version>-vita-<patchset_version>.patch
For full source see vita-* branches
# building
```
mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=${VITASDK}/share/vita.toolchain.cmake -DCMAKE_BUILD_TYPE=Release ..
make install
```
-39
View File
@@ -1,39 +0,0 @@
# Cross-compiling requires CMake 2.6 or newer. Example:
# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile-Android.txt -DHOST=arm-linux-androideabi
# Where 'arm-linux-androideabi' is the host prefix for the cross-compiler. If
# you already have a toolchain file setup, you may use that instead of this
# file. Make sure to set CMAKE_FIND_ROOT_PATH to where the NDK toolchain was
# installed (e.g. "$ENV{HOME}/toolchains/arm-linux-androideabi-r10c-21").
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Linux)
# which compilers to use for C and C++
SET(CMAKE_C_COMPILER "${HOST}-gcc")
SET(CMAKE_CXX_COMPILER "${HOST}-g++")
SET(CMAKE_RC_COMPILER "${HOST}-windres")
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH "SET THIS TO THE NDK TOOLCHAIN'S INSTALL PATH")
# here is where stuff gets installed to
SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# set env vars so that pkg-config will look in the appropriate directory for
# .pc files (as there seems to be no way to force using ${HOST}-pkg-config)
set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
set(ENV{PKG_CONFIG_PATH} "")
# Qt4 tools
SET(QT_QMAKE_EXECUTABLE ${HOST}-qmake)
SET(QT_MOC_EXECUTABLE ${HOST}-moc)
SET(QT_RCC_EXECUTABLE ${HOST}-rcc)
SET(QT_UIC_EXECUTABLE ${HOST}-uic)
SET(QT_LRELEASE_EXECUTABLE ${HOST}-lrelease)
-37
View File
@@ -1,37 +0,0 @@
# Cross-compiling requires CMake 2.6 or newer. Example:
# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt -DHOST=i686-w64-mingw32
# Where 'i686-w64-mingw32' is the host prefix for your cross-compiler. If you
# already have a toolchain file setup, you may use that instead of this file.
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Windows)
# which compilers to use for C and C++
SET(CMAKE_C_COMPILER "${HOST}-gcc")
SET(CMAKE_CXX_COMPILER "${HOST}-g++")
SET(CMAKE_RC_COMPILER "${HOST}-windres")
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH "/usr/${HOST}")
# here is where stuff gets installed to
SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# set env vars so that pkg-config will look in the appropriate directory for
# .pc files (as there seems to be no way to force using ${HOST}-pkg-config)
set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
set(ENV{PKG_CONFIG_PATH} "")
# Qt4 tools
SET(QT_QMAKE_EXECUTABLE ${HOST}-qmake)
SET(QT_MOC_EXECUTABLE ${HOST}-moc)
SET(QT_RCC_EXECUTABLE ${HOST}-rcc)
SET(QT_UIC_EXECUTABLE ${HOST}-uic)
SET(QT_LRELEASE_EXECUTABLE ${HOST}-lrelease)
-487
View File
@@ -1,487 +0,0 @@
# OpenAL config file.
#
# Option blocks may appear multiple times, and duplicated options will take the
# last value specified. Environment variables may be specified within option
# values, and are automatically substituted when the config file is loaded.
# Environment variable names may only contain alpha-numeric characters (a-z,
# A-Z, 0-9) and underscores (_), and are prefixed with $. For example,
# specifying "$HOME/file.ext" would typically result in something like
# "/home/user/file.ext". To specify an actual "$" character, use "$$".
#
# Device-specific values may be specified by including the device name in the
# block name, with "general" replaced by the device name. That is, general
# options for the device "Name of Device" would be in the [Name of Device]
# block, while ALSA options would be in the [alsa/Name of Device] block.
# Options marked as "(global)" are not influenced by the device.
#
# The system-wide settings can be put in /etc/openal/alsoft.conf and user-
# specific override settings in $HOME/.alsoftrc.
# For Windows, these settings should go into $AppData\alsoft.ini
#
# Option and block names are case-senstive. The supplied values are only hints
# and may not be honored (though generally it'll try to get as close as
# possible). Note: options that are left unset may default to app- or system-
# specified values. These are the current available settings:
##
## General stuff
##
[general]
## disable-cpu-exts: (global)
# Disables use of specialized methods that use specific CPU intrinsics.
# Certain methods may utilize CPU extensions for improved performance, and
# this option is useful for preventing some or all of those methods from being
# used. The available extensions are: sse, sse2, sse3, sse4.1, and neon.
# Specifying 'all' disables use of all such specialized methods.
#disable-cpu-exts =
## drivers: (global)
# Sets the backend driver list order, comma-seperated. Unknown backends and
# duplicated names are ignored. Unlisted backends won't be considered for use
# unless the list is ended with a comma (e.g. 'oss,' will try OSS first before
# other backends, while 'oss' will try OSS only). Backends prepended with -
# won't be considered for use (e.g. '-oss,' will try all available backends
# except OSS). An empty list means to try all backends.
#drivers =
## channels:
# Sets the output channel configuration. If left unspecified, one will try to
# be detected from the system, and defaulting to stereo. The available values
# are: mono, stereo, quad, surround51, surround51rear, surround61, surround71,
# ambi1, ambi2, ambi3. Note that the ambi* configurations provide ambisonic
# channels of the given order (using ACN ordering and SN3D normalization by
# default), which need to be decoded to play correctly on speakers.
#channels =
## sample-type:
# Sets the output sample type. Currently, all mixing is done with 32-bit float
# and converted to the output sample type as needed. Available values are:
# int8 - signed 8-bit int
# uint8 - unsigned 8-bit int
# int16 - signed 16-bit int
# uint16 - unsigned 16-bit int
# int32 - signed 32-bit int
# uint32 - unsigned 32-bit int
# float32 - 32-bit float
#sample-type = float32
## frequency:
# Sets the output frequency. If left unspecified it will try to detect a
# default from the system, otherwise it will default to 44100.
#frequency =
## period_size:
# Sets the update period size, in frames. This is the number of frames needed
# for each mixing update. Acceptable values range between 64 and 8192.
#period_size = 1024
## periods:
# Sets the number of update periods. Higher values create a larger mix ahead,
# which helps protect against skips when the CPU is under load, but increases
# the delay between a sound getting mixed and being heard. Acceptable values
# range between 2 and 16.
#periods = 3
## stereo-mode:
# Specifies if stereo output is treated as being headphones or speakers. With
# headphones, HRTF or crossfeed filters may be used for better audio quality.
# Valid settings are auto, speakers, and headphones.
#stereo-mode = auto
## stereo-encoding:
# Specifies the encoding method for non-HRTF stereo output. 'panpot' (default)
# uses standard amplitude panning (aka pair-wise, stereo pair, etc) between
# -30 and +30 degrees, while 'uhj' creates stereo-compatible two-channel UHJ
# output, which encodes some surround sound information into stereo output
# that can be decoded with a surround sound receiver. If crossfeed filters are
# used, UHJ is disabled.
#stereo-encoding = panpot
## ambi-format:
# Specifies the channel order and normalization for the "ambi*" set of channel
# configurations. Valid settings are: fuma, acn+sn3d, acn+n3d
#ambi-format = acn+sn3d
## hrtf:
# Controls HRTF processing. These filters provide better spatialization of
# sounds while using headphones, but do require a bit more CPU power. The
# default filters will only work with 44100hz or 48000hz stereo output. While
# HRTF is used, the cf_level option is ignored. Setting this to auto (default)
# will allow HRTF to be used when headphones are detected or the app requests
# it, while setting true or false will forcefully enable or disable HRTF
# respectively.
#hrtf = auto
## default-hrtf:
# Specifies the default HRTF to use. When multiple HRTFs are available, this
# determines the preferred one to use if none are specifically requested. Note
# that this is the enumerated HRTF name, not necessarily the filename.
#default-hrtf =
## hrtf-paths:
# Specifies a comma-separated list of paths containing HRTF data sets. The
# format of the files are described in docs/hrtf.txt. The files within the
# directories must have the .mhr file extension to be recognized. By default,
# OS-dependent data paths will be used. They will also be used if the list
# ends with a comma. On Windows this is:
# $AppData\openal\hrtf
# And on other systems, it's (in order):
# $XDG_DATA_HOME/openal/hrtf (defaults to $HOME/.local/share/openal/hrtf)
# $XDG_DATA_DIRS/openal/hrtf (defaults to /usr/local/share/openal/hrtf and
# /usr/share/openal/hrtf)
#hrtf-paths =
## cf_level:
# Sets the crossfeed level for stereo output. Valid values are:
# 0 - No crossfeed
# 1 - Low crossfeed
# 2 - Middle crossfeed
# 3 - High crossfeed (virtual speakers are closer to itself)
# 4 - Low easy crossfeed
# 5 - Middle easy crossfeed
# 6 - High easy crossfeed
# Users of headphones may want to try various settings. Has no effect on non-
# stereo modes.
#cf_level = 0
## resampler: (global)
# Selects the resampler used when mixing sources. Valid values are:
# point - nearest sample, no interpolation
# linear - extrapolates samples using a linear slope between samples
# sinc4 - extrapolates samples using a 4-point Sinc filter
# bsinc - extrapolates samples using a band-limited Sinc filter (varying
# between 12 and 24 points, with anti-aliasing)
# Specifying other values will result in using the default (linear).
#resampler = linear
## rt-prio: (global)
# Sets real-time priority for the mixing thread. Not all drivers may use this
# (eg. PortAudio) as they already control the priority of the mixing thread.
# 0 and negative values will disable it. Note that this may constitute a
# security risk since a real-time priority thread can indefinitely block
# normal-priority threads if it fails to wait. As such, the default is
# disabled.
#rt-prio = 0
## sources:
# Sets the maximum number of allocatable sources. Lower values may help for
# systems with apps that try to play more sounds than the CPU can handle.
#sources = 256
## slots:
# Sets the maximum number of Auxiliary Effect Slots an app can create. A slot
# can use a non-negligible amount of CPU time if an effect is set on it even
# if no sources are feeding it, so this may help when apps use more than the
# system can handle.
#slots = 64
## sends:
# Limits the number of auxiliary sends allowed per source. Setting this higher
# than the default has no effect.
#sends = 16
## output-limiter:
# Applies a gain limiter on the final mixed output. This reduces the volume
# when the output samples would otherwise clamp, avoiding excessive clipping
# noise.
#output-limiter = true
## dither:
# Applies dithering on the final mix, for 8- and 16-bit output by default.
# This replaces the distortion created by nearest-value quantization with low-
# level whitenoise.
#dither = true
## dither-depth:
# Quantization bit-depth for dithered output. A value of 0 (or less) will
# match the output sample depth. For int32, uint32, and float32 output, 0 will
# disable dithering because they're at or beyond the rendered precision. The
# maximum dither depth is 24.
#dither-depth = 0
## volume-adjust:
# A global volume adjustment for source output, expressed in decibels. The
# value is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will
# be a scale of 4x, etc. Similarly, -6 will be x1/2, and -12 is about x1/4. A
# value of 0 means no change.
#volume-adjust = 0
## excludefx: (global)
# Sets which effects to exclude, preventing apps from using them. This can
# help for apps that try to use effects which are too CPU intensive for the
# system to handle. Available effects are: eaxreverb,reverb,chorus,compressor,
# distortion,echo,equalizer,flanger,modulator,dedicated
#excludefx =
## default-reverb: (global)
# A reverb preset that applies by default to all sources on send 0
# (applications that set their own slots on send 0 will override this).
# Available presets are: None, Generic, PaddedCell, Room, Bathroom,
# Livingroom, Stoneroom, Auditorium, ConcertHall, Cave, Arena, Hangar,
# CarpetedHallway, Hallway, StoneCorridor, Alley, Forest, City, Moutains,
# Quarry, Plain, ParkingLot, SewerPipe, Underwater, Drugged, Dizzy, Psychotic.
#default-reverb =
## trap-alc-error: (global)
# Generates a SIGTRAP signal when an ALC device error is generated, on systems
# that support it. This helps when debugging, while trying to find the cause
# of a device error. On Windows, a breakpoint exception is generated.
#trap-alc-error = false
## trap-al-error: (global)
# Generates a SIGTRAP signal when an AL context error is generated, on systems
# that support it. This helps when debugging, while trying to find the cause
# of a context error. On Windows, a breakpoint exception is generated.
#trap-al-error = false
##
## Ambisonic decoder stuff
##
[decoder]
## hq-mode:
# Enables a high-quality ambisonic decoder. This mode is capable of frequency-
# dependent processing, creating a better reproduction of 3D sound rendering
# over surround sound speakers. Enabling this also requires specifying decoder
# configuration files for the appropriate speaker configuration you intend to
# use (see the quad, surround51, etc options below). Currently, up to third-
# order decoding is supported.
hq-mode = false
## distance-comp:
# Enables compensation for the speakers' relative distances to the listener.
# This applies the necessary delays and attenuation to make the speakers
# behave as though they are all equidistant, which is important for proper
# playback of 3D sound rendering. Requires the proper distances to be
# specified in the decoder configuration file.
distance-comp = true
## nfc:
# Enables near-field control filters. This simulates and compensates for low-
# frequency effects caused by the curvature of nearby sound-waves, which
# creates a more realistic perception of sound distance. Note that the effect
# may be stronger or weaker than intended if the application doesn't use or
# specify an appropriate unit scale, or if incorrect speaker distances are set
# in the decoder configuration file. Requires hq-mode to be enabled.
nfc = true
## nfc-ref-delay
# Specifies the reference delay value for ambisonic output. When channels is
# set to one of the ambi* formats, this option enables NFC-HOA output with the
# specified Reference Delay parameter. The specified value can then be shared
# with an appropriate NFC-HOA decoder to reproduce correct near-field effects.
# Keep in mind that despite being designed for higher-order ambisonics, this
# applies to first-order output all the same. When left unset, normal output
# is created with no near-field simulation.
nfc-ref-delay =
## quad:
# Decoder configuration file for Quadrophonic channel output. See
# docs/ambdec.txt for a description of the file format.
quad =
## surround51:
# Decoder configuration file for 5.1 Surround (Side and Rear) channel output.
# See docs/ambdec.txt for a description of the file format.
surround51 =
## surround61:
# Decoder configuration file for 6.1 Surround channel output. See
# docs/ambdec.txt for a description of the file format.
surround61 =
## surround71:
# Decoder configuration file for 7.1 Surround channel output. See
# docs/ambdec.txt for a description of the file format. Note: This can be used
# to enable 3D7.1 with the appropriate configuration and speaker placement,
# see docs/3D7.1.txt.
surround71 =
##
## Reverb effect stuff (includes EAX reverb)
##
[reverb]
## boost: (global)
# A global amplification for reverb output, expressed in decibels. The value
# is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will be a
# scale of 4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A
# value of 0 means no change.
#boost = 0
## emulate-eax: (global)
# Allows the standard reverb effect to be used in place of EAX reverb. EAX
# reverb processing is a bit more CPU intensive than standard, so this option
# allows a simpler effect to be used at the loss of some quality.
#emulate-eax = false
##
## PulseAudio backend stuff
##
[pulse]
## spawn-server: (global)
# Attempts to autospawn a PulseAudio server whenever needed (initializing the
# backend, enumerating devices, etc). Setting autospawn to false in Pulse's
# client.conf will still prevent autospawning even if this is set to true.
#spawn-server = true
## allow-moves: (global)
# Allows PulseAudio to move active streams to different devices. Note that the
# device specifier (seen by applications) will not be updated when this
# occurs, and neither will the AL device configuration (sample rate, format,
# etc).
#allow-moves = false
## fix-rate:
# Specifies whether to match the playback stream's sample rate to the device's
# sample rate. Enabling this forces OpenAL Soft to mix sources and effects
# directly to the actual output rate, avoiding a second resample pass by the
# PulseAudio server.
#fix-rate = false
##
## ALSA backend stuff
##
[alsa]
## device: (global)
# Sets the device name for the default playback device.
#device = default
## device-prefix: (global)
# Sets the prefix used by the discovered (non-default) playback devices. This
# will be appended with "CARD=c,DEV=d", where c is the card id and d is the
# device index for the requested device name.
#device-prefix = plughw:
## device-prefix-*: (global)
# Card- and device-specific prefixes may be used to override the device-prefix
# option. The option may specify the card id (eg, device-prefix-NVidia), or
# the card id and device index (eg, device-prefix-NVidia-0). The card id is
# case-sensitive.
#device-prefix- =
## capture: (global)
# Sets the device name for the default capture device.
#capture = default
## capture-prefix: (global)
# Sets the prefix used by the discovered (non-default) capture devices. This
# will be appended with "CARD=c,DEV=d", where c is the card id and d is the
# device number for the requested device name.
#capture-prefix = plughw:
## capture-prefix-*: (global)
# Card- and device-specific prefixes may be used to override the
# capture-prefix option. The option may specify the card id (eg,
# capture-prefix-NVidia), or the card id and device index (eg,
# capture-prefix-NVidia-0). The card id is case-sensitive.
#capture-prefix- =
## mmap:
# Sets whether to try using mmap mode (helps reduce latencies and CPU
# consumption). If mmap isn't available, it will automatically fall back to
# non-mmap mode. True, yes, on, and non-0 values will attempt to use mmap. 0
# and anything else will force mmap off.
#mmap = true
## allow-resampler:
# Specifies whether to allow ALSA's built-in resampler. Enabling this will
# allow the playback device to be set to a different sample rate than the
# actual output, causing ALSA to apply its own resampling pass after OpenAL
# Soft resamples and mixes the sources and effects for output.
#allow-resampler = false
##
## OSS backend stuff
##
[oss]
## device: (global)
# Sets the device name for OSS output.
#device = /dev/dsp
## capture: (global)
# Sets the device name for OSS capture.
#capture = /dev/dsp
##
## Solaris backend stuff
##
[solaris]
## device: (global)
# Sets the device name for Solaris output.
#device = /dev/audio
##
## QSA backend stuff
##
[qsa]
##
## JACK backend stuff
##
[jack]
## spawn-server: (global)
# Attempts to autospawn a JACK server whenever needed (initializing the
# backend, opening devices, etc).
#spawn-server = false
## buffer-size:
# Sets the update buffer size, in samples, that the backend will keep buffered
# to handle the server's real-time processing requests. This value must be a
# power of 2, or else it will be rounded up to the next power of 2. If it is
# less than JACK's buffer update size, it will be clamped. This option may
# be useful in case the server's update size is too small and doesn't give the
# mixer time to keep enough audio available for the processing requests.
#buffer-size = 0
##
## MMDevApi backend stuff
##
[mmdevapi]
##
## DirectSound backend stuff
##
[dsound]
##
## Windows Multimedia backend stuff
##
[winmm]
##
## PortAudio backend stuff
##
[port]
## device: (global)
# Sets the device index for output. Negative values will use the default as
# given by PortAudio itself.
#device = -1
## capture: (global)
# Sets the device index for capture. Negative values will use the default as
# given by PortAudio itself.
#capture = -1
##
## Wave File Writer stuff
##
[wave]
## file: (global)
# Sets the filename of the wave file to write to. An empty name prevents the
# backend from opening, even when explicitly requested.
# THIS WILL OVERWRITE EXISTING FILES WITHOUT QUESTION!
#file =
## bformat: (global)
# Creates AMB format files using first-order ambisonics instead of a standard
# single- or multi-channel .wav file.
#bformat = false
-19
View File
@@ -1,19 +0,0 @@
version: 1.18.1.{build}
environment:
matrix:
- GEN: "Visual Studio 14 2015"
CFG: Release
- GEN: "Visual Studio 14 2015 Win64"
CFG: Release
install:
# Remove the VS Xamarin targets to reduce AppVeyor specific noise in build
# logs. See also http://help.appveyor.com/discussions/problems/4569
- del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets"
build_script:
- cd build
- cmake -G"%GEN%" -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_MMDEVAPI=ON -DALSOFT_EMBED_HRTF_DATA=YES ..
- cmake --build . --config %CFG% --clean-first
View File
-9
View File
@@ -1,9 +0,0 @@
#include <sys/types.h>
#define KB ((off_t)(1024))
#define MB ((off_t)(KB*1024))
#define GB ((off_t)(MB*1024))
int tb[((GB+GB+GB) > GB) ? 1 : -1];
int main()
{ return 0; }
-39
View File
@@ -1,39 +0,0 @@
# - Check if the _FILE_OFFSET_BITS macro is needed for large files
# CHECK_FILE_OFFSET_BITS()
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
# Copyright (c) 2009, Chris Robinson
#
# Redistribution and use is allowed according to the terms of the LGPL license.
MACRO(CHECK_FILE_OFFSET_BITS)
IF(NOT DEFINED _FILE_OFFSET_BITS)
MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files")
TRY_COMPILE(__WITHOUT_FILE_OFFSET_BITS_64
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS})
IF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
TRY_COMPILE(__WITH_FILE_OFFSET_BITS_64
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64)
ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
IF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
SET(_FILE_OFFSET_BITS 64 CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files - 64")
ELSE(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
SET(_FILE_OFFSET_BITS "" CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files - not needed")
ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
ENDIF(NOT DEFINED _FILE_OFFSET_BITS)
ENDMACRO(CHECK_FILE_OFFSET_BITS)
-92
View File
@@ -1,92 +0,0 @@
# - Check if a symbol exists as a function, variable, or macro
# CHECK_SYMBOL_EXISTS(<symbol> <files> <variable>)
#
# Check that the <symbol> is available after including given header
# <files> and store the result in a <variable>. Specify the list
# of files in one argument as a semicolon-separated list.
#
# If the header files define the symbol as a macro it is considered
# available and assumed to work. If the header files declare the
# symbol as a function or variable then the symbol must also be
# available for linking. If the symbol is a type or enum value
# it will not be recognized (consider using CheckTypeSize or
# CheckCSourceCompiles).
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
#=============================================================================
# Copyright 2003-2011 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE)
IF(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}")
SET(CMAKE_CONFIGURABLE_FILE_CONTENT "/* */\n")
SET(MACRO_CHECK_SYMBOL_EXISTS_FLAGS ${CMAKE_REQUIRED_FLAGS})
IF(CMAKE_REQUIRED_LIBRARIES)
SET(CHECK_SYMBOL_EXISTS_LIBS
"-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES};${LIBRARY}")
ELSE(CMAKE_REQUIRED_LIBRARIES)
SET(CHECK_SYMBOL_EXISTS_LIBS
"-DLINK_LIBRARIES:STRING=${LIBRARY}")
ENDIF(CMAKE_REQUIRED_LIBRARIES)
IF(CMAKE_REQUIRED_INCLUDES)
SET(CMAKE_SYMBOL_EXISTS_INCLUDES
"-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
ELSE(CMAKE_REQUIRED_INCLUDES)
SET(CMAKE_SYMBOL_EXISTS_INCLUDES)
ENDIF(CMAKE_REQUIRED_INCLUDES)
FOREACH(FILE ${FILES})
SET(CMAKE_CONFIGURABLE_FILE_CONTENT
"${CMAKE_CONFIGURABLE_FILE_CONTENT}#include <${FILE}>\n")
ENDFOREACH(FILE)
SET(CMAKE_CONFIGURABLE_FILE_CONTENT
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\nvoid cmakeRequireSymbol(int dummy,...){(void)dummy;}\nint main()\n{\n cmakeRequireSymbol(0,&${SYMBOL});\n return 0;\n}\n")
CONFIGURE_FILE("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" @ONLY)
MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY}")
TRY_COMPILE(${VARIABLE}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
CMAKE_FLAGS
-DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS}
-DLINK_DIRECTORIES:STRING=${LOCATION}
"${CHECK_SYMBOL_EXISTS_LIBS}"
"${CMAKE_SYMBOL_EXISTS_INCLUDES}"
OUTPUT_VARIABLE OUTPUT)
IF(${VARIABLE})
MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - found")
SET(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}")
FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Determining if the ${SYMBOL} "
"exist in ${LIBRARY} passed with the following output:\n"
"${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
ELSE(${VARIABLE})
MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - not found.")
SET(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}")
FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining if the ${SYMBOL} "
"exist in ${LIBRARY} failed with the following output:\n"
"${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
ENDIF(${VARIABLE})
ENDIF(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}")
ENDMACRO(CHECK_SHARED_FUNCTION_EXISTS)
-73
View File
@@ -1,73 +0,0 @@
# - Find alsa
# Find the alsa libraries (asound)
#
# This module defines the following variables:
# ALSA_FOUND - True if ALSA_INCLUDE_DIR & ALSA_LIBRARY are found
# ALSA_LIBRARIES - Set when ALSA_LIBRARY is found
# ALSA_INCLUDE_DIRS - Set when ALSA_INCLUDE_DIR is found
#
# ALSA_INCLUDE_DIR - where to find asoundlib.h, etc.
# ALSA_LIBRARY - the asound library
# ALSA_VERSION_STRING - the version of alsa found (since CMake 2.8.8)
#
#=============================================================================
# Copyright 2009-2011 Kitware, Inc.
# Copyright 2009-2011 Philip Lowman <philip@yhbt.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * The names of Kitware, Inc., the Insight Consortium, or the names of
# any consortium members, or of any contributors, may not be used to
# endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
find_path(ALSA_INCLUDE_DIR NAMES alsa/asoundlib.h
DOC "The ALSA (asound) include directory"
)
find_library(ALSA_LIBRARY NAMES asound
DOC "The ALSA (asound) library"
)
if(ALSA_INCLUDE_DIR AND EXISTS "${ALSA_INCLUDE_DIR}/alsa/version.h")
file(STRINGS "${ALSA_INCLUDE_DIR}/alsa/version.h" alsa_version_str REGEX "^#define[\t ]+SND_LIB_VERSION_STR[\t ]+\".*\"")
string(REGEX REPLACE "^.*SND_LIB_VERSION_STR[\t ]+\"([^\"]*)\".*$" "\\1" ALSA_VERSION_STRING "${alsa_version_str}")
unset(alsa_version_str)
endif()
# handle the QUIETLY and REQUIRED arguments and set ALSA_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ALSA
REQUIRED_VARS ALSA_LIBRARY ALSA_INCLUDE_DIR
VERSION_VAR ALSA_VERSION_STRING)
if(ALSA_FOUND)
set( ALSA_LIBRARIES ${ALSA_LIBRARY} )
set( ALSA_INCLUDE_DIRS ${ALSA_INCLUDE_DIR} )
endif()
mark_as_advanced(ALSA_INCLUDE_DIR ALSA_LIBRARY)

Some files were not shown because too many files have changed in this diff Show More