Compare commits

...

259 Commits

Author SHA1 Message Date
Chris Robinson f72b6fe717 Release 1.9.563 2009-09-26 01:42:21 -07:00
Chris Robinson 8d29d25d60 Condense some local variables 2009-09-24 14:51:40 -07:00
Chris Robinson af8e7ab984 Check the source start position in alSourcePlayv instead of the mixer 2009-09-24 12:24:10 -07:00
Chris Robinson 4289d5de7d Parse the attribute list and reset the device before creating the context 2009-09-24 11:31:01 -07:00
Chris Robinson 83734aff0e Slightly improve the multi-channel mixing loops 2009-09-24 08:52:51 -07:00
Chris Robinson 617b6728d3 Remove the state callbacks and watch for changes synchronously 2009-09-24 00:26:41 -07:00
Chris Robinson 7a8fd6cb20 Get rid of unnecessary messages from pulseaudio 2009-09-23 08:34:15 -07:00
Chris Robinson 55da339586 Properly clean up the pulse device 2009-09-23 08:19:00 -07:00
Chris Robinson 774eae0f2f Silence unused parameter warning 2009-09-23 07:10:23 -07:00
Chris Robinson 201b108a54 Attempt to reload backend libs when probing, if they didn't initially load 2009-09-23 01:33:58 -07:00
Chris Robinson bdbdbcea26 Update in properly-sized chunks for PulseAudio 2009-09-23 01:24:10 -07:00
Chris Robinson f6c1a21cf0 Properly flip the backend entries when sorting the device list 2009-09-22 04:42:46 -07:00
Chris Robinson c953072a15 Fix reset condition check 2009-09-22 00:16:21 -07:00
Chris Robinson 93f3e9357b (Re)allocate and clear the stereo-to-binaural filter as needed 2009-09-21 23:52:59 -07:00
Chris Robinson 8ea8b49464 Avoid locking a NULL context when a device is disconnected 2009-09-21 23:31:04 -07:00
Chris Robinson 62cef44dcb Reinitialize the stereo-to-binaural filter after resetting the device 2009-09-21 23:25:26 -07:00
Chris Robinson a2edc95207 Properly set the number of sends requested by the app 2009-09-21 23:18:39 -07:00
Chris Robinson 4cd41e3e08 Don't allow setting an invalid auxiliary send 2009-09-21 23:09:31 -07:00
Chris Robinson b641f993ac Hide the wave writer device if no output file is set 2009-09-21 05:03:40 -07:00
Chris Robinson e2905b6bc9 Properly handle forced 32-bit float output with DSound 2009-09-21 02:57:17 -07:00
Chris Robinson e11b59a80f Return imediately if trying to set an unknown format 2009-09-21 02:53:33 -07:00
Chris Robinson 0ae02e8ad4 Support floating point capture for backends that can handle it 2009-09-21 02:31:33 -07:00
Chris Robinson 2cbdffab86 Create the ALSA capture ring buffer with the proper size 2009-09-21 02:14:32 -07:00
Chris Robinson 86eefdb2a8 Mix all pending periods at once instead of one at a time 2009-09-20 00:44:39 -07:00
Chris Robinson 750399ccd7 Let verify_state restore from an ALSA underrun 2009-09-20 00:40:23 -07:00
Chris Robinson fb97ca6022 Remove left-over backend-specific period options 2009-09-16 23:29:32 -07:00
Chris Robinson cbcaa54173 Store the number of periods in the device instead of the buffer size
Also keep all the fields in sync
2009-09-16 22:58:54 -07:00
Chris Robinson 94e3fca702 Remove unnecessary parameters, and rename methods 2009-09-16 00:24:44 -07:00
Chris Robinson ffff104554 Restore the device frequency using the stream info 2009-09-16 00:08:11 -07:00
Chris Robinson 307a9dd1b2 Update the frequency with what the stream actually got set with 2009-09-15 23:14:14 -07:00
Chris Robinson 5dff8ea820 Properly terminate PortAudio when closing 2009-09-15 22:45:27 -07:00
Chris Robinson 49648fe22d Make a GetConfigValueBool function and use it 2009-09-15 22:18:13 -07:00
Chris Robinson 9f037e8980 Pass the device to aluMixData 2009-09-15 19:30:27 -07:00
Chris Robinson 12f81bcbb9 Move the stereo-to-binaural filter to the device 2009-09-15 19:06:47 -07:00
Chris Robinson 6636131d3b Pass the frame count to aluMixData 2009-09-15 18:19:00 -07:00
Chris Robinson eeea9631ce Split the source mixing loop into a separate function
Helps reduce the function size and indentation levels
2009-09-15 17:56:31 -07:00
Chris Robinson f9d228c30a Add missing context checks 2009-09-12 20:22:03 -07:00
Chris Robinson d516f8c4bd Update comment 2009-09-12 20:02:45 -07:00
Chris Robinson 5d1c3a0c63 Fix wave writer backend 2009-09-12 19:58:36 -07:00
Chris Robinson 396f2d6050 Mix the proper size for every update, and notify disconnects 2009-09-12 19:36:16 -07:00
Chris Robinson e25b01c3a2 Start Solaris playback when a context is ready 2009-09-12 18:19:52 -07:00
Chris Robinson b29a24afb0 Move the default out-of-tree build dir to build 2009-09-12 17:54:27 -07:00
Chris Robinson d6d1dba3d2 Initialize OpenAL with a constructor call instead of first-use 2009-09-12 17:49:08 -07:00
Chris Robinson 8b36a9d121 Get rid of deinit code duplication 2009-09-12 17:29:35 -07:00
Chris Robinson 59ed9338d8 Add support for the in-progress ALC_EXT_thread_local_context extension 2009-09-12 16:45:46 -07:00
Chris Robinson b444dea63b Fix compilation for Windows 2009-08-28 06:33:59 -07:00
Chris Robinson 1816c8bd37 Make a copy of the default device name for the app
The pointer to it could otherwise change if the device list is rebuilt, which
would be bad if the app has it
2009-08-27 20:13:35 -07:00
Chris Robinson c27948a7ee Don't free a NULL handle 2009-08-27 19:01:12 -07:00
Chris Robinson 832dc8a585 Remove unnecessary vars and rework device name checks 2009-08-27 18:55:18 -07:00
Chris Robinson bb121e68a6 Rebuild device lists when retrieving them 2009-08-27 06:09:33 -07:00
Chris Robinson 1ec26fd789 Dynamically allocate device lists 2009-08-27 03:55:36 -07:00
Chris Robinson 4ff4a7e3b9 Close some libs when deinitializing 2009-08-27 03:12:54 -07:00
Chris Robinson 6bb14e45ce Store a copy of the device name in the device 2009-08-27 02:53:09 -07:00
Chris Robinson 45dc804819 Store copies of the device names in the individual backends 2009-08-27 01:47:41 -07:00
Chris Robinson 81db01ebf1 Add a method to deinitialize backends 2009-08-26 23:45:00 -07:00
Chris Robinson 06c576a945 Support disconnect for OSS and Solaris 2009-08-26 21:49:38 -07:00
Chris Robinson 929b025fd6 Support disconnect for ALSA playback and capture
As a consequence for capture, mmap is no longer supported. Later on, supporting
mmap capture to write directly into the ring buffer is a possibility.
2009-08-26 21:27:10 -07:00
Chris Robinson 7976de05a5 Add base support for ALC_EXT_disconnect
Individual backends need to be updated to handle disconnection events
2009-08-26 19:15:17 -07:00
Chris Robinson 70c88879ab Add ALC_EXT_disconnect to alext.h 2009-08-26 18:29:25 -07:00
Chris Robinson 276ee63b99 Define PATH_MAX if it isn't already 2009-08-19 12:59:40 -07:00
Chris Robinson 487f0dde75 Print source and auxiliary slot debug warnings from alcDestroyContext 2009-08-16 16:11:22 -07:00
Chris Robinson c8f700930a More modifications and fixes for context checks 2009-08-16 16:02:13 -07:00
Chris Robinson decbe4df45 Modify some context checks 2009-08-16 15:09:36 -07:00
Chris Robinson 462f27c129 Use a function to retrieve the current context in an already-locked state
This should help prevent race-conditions with a context being destroyed between
breing retrieved and locked
2009-08-16 14:09:23 -07:00
Chris Robinson 2d1191697a Fix the Solaris backend 2009-08-16 13:16:41 -07:00
Chris Robinson 0b5a0d1e79 Reset the target if the databuffer being deleted is currently selected 2009-08-16 11:12:13 -07:00
Chris Robinson 0b7eb9f118 Add in-progress working extension AL_EXTX_sample_buffer_object 2009-08-16 00:54:08 -07:00
Chris Robinson dc26261065 Support 32-bit float output 2009-08-15 13:20:35 -07:00
Chris Robinson 9bea67fb1c Use a function to convert float to unsigned byte 2009-08-15 11:33:38 -07:00
Chris Robinson 8246bc3418 Use a custom function to get the requested format 2009-08-15 10:32:54 -07:00
Chris Robinson 01e32b58da Fix some size checks 2009-08-15 10:01:55 -07:00
Chris Robinson 9d05ff0468 Verify the device pointer is a valid device 2009-08-15 09:55:08 -07:00
Chris Robinson 510ccc7f17 Store the effect and filter lists in the device 2009-08-15 09:39:18 -07:00
Chris Robinson 43067ed2b8 Store the buffer list in the device 2009-08-15 09:14:08 -07:00
Chris Robinson 4e4c9aef15 Calculate the buffer size and frame size when needed 2009-08-14 13:08:25 -07:00
Chris Robinson 4031ee5ef0 Fix speaker override check 2009-08-14 07:27:19 -07:00
Chris Robinson e079291202 Remove unnecessary function parameters 2009-08-13 19:36:14 -07:00
Chris Robinson 826c641668 Hold the lock while finding a capture device to open 2009-08-13 19:19:16 -07:00
Chris Robinson 6ae845fd9e Don't let the device frequency change when PortAudio gets a new context 2009-08-13 17:13:37 -07:00
Chris Robinson a78fd58dca Create PulseAudio's playback stream when the AL context is created 2009-08-13 17:08:47 -07:00
Chris Robinson a8ae610489 Set context frequency only if it successfully starts 2009-08-13 15:35:10 -07:00
Chris Robinson b86a1e5797 Add a note about app and system defaults 2009-08-13 13:48:06 -07:00
Chris Robinson 45552a68ce Hold the lock while initializing context playback 2009-08-13 13:32:42 -07:00
Chris Robinson d46655fbb2 Support the ALC_FREQUENCY context attribute 2009-08-13 13:28:35 -07:00
Chris Robinson 87fee8c504 Start DSound playback at context creation 2009-08-13 13:11:05 -07:00
Chris Robinson 9ff0617807 Don't clamp the wave writer's update size 2009-08-13 12:35:42 -07:00
Chris Robinson 243939f94f Allow delaying playback start until context creation, and don't use UpdateSize to store the buffer size
This will make it possible to support the context attributes (frequency,
refresh, etc) for some backends
2009-08-13 12:28:46 -07:00
Chris Robinson 739385bd89 Add AL_EXT_BUFFER_DATA_STATIC to alext.h 2009-08-13 10:10:34 -07:00
Chris Robinson 32060f53cd Reset the buffer played count when the queue is removed via the AL_BUFFER property 2009-08-11 14:16:30 -07:00
Chris Robinson 4ee3972f15 Update queued buffer states when source looping is toggled 2009-08-11 07:57:18 -07:00
Chris Robinson 00a9cf4a85 Remove more unneeded variables 2009-07-07 21:11:13 -07:00
Chris Robinson 1dcd538ad9 Remove unneeded variables 2009-07-07 21:01:41 -07:00
Chris Robinson a8973514ba Don't load functions if libpulse failed to open 2009-07-07 12:51:18 -07:00
Chris Robinson 0ac9e57d28 Store the requested mono/stereo source count and sends in the device
Although the properties are set as context attributes, they are queried from
the device. If multiple contexts per device are ever supported, it would not
be straight forward about where to read the values from. This way, the
attributes can be treated as device-specific attributes that are updated when
a new context is created.
2009-07-06 03:09:01 -07:00
Chris Robinson 5460e85c40 Set the right access mode for non-mmap capture 2009-07-02 20:50:12 -07:00
Chris Robinson 432f0ba34c Specify the right format for ALSA recording 2009-07-02 20:32:19 -07:00
Chris Robinson 7e01e53445 Fix parsing of layout configuration string 2009-07-02 20:31:36 -07:00
Chris Robinson 043fe6edd2 Release 1.8.466 2009-06-07 22:30:08 -07:00
Chris Robinson ef68e5d0ff Protect ring buffer access with the lock 2009-06-07 21:34:05 -07:00
Chris Robinson c6f3a4e062 Move a couple inline functions into the header 2009-06-07 20:16:41 -07:00
Chris Robinson 87ed53c7f6 Don't read deprecated config files 2009-06-07 20:12:01 -07:00
Alam Arias 89e9437b84 add check for _WAVEFORMATEXTENSIBLE_ and define _WIN32_IE before inlcuding any header 2009-06-07 19:43:42 -07:00
Chris Robinson 1454c46b5f Use a thread-safe static inline function for printing 2009-06-07 15:42:15 -07:00
Chris Robinson 0fac1e9115 Store the max number of auxiliary slots in the device 2009-06-07 14:53:22 -07:00
Chris Robinson f3a3358e63 Fix for MSVC
MSVC won't accept zero-sized arrays at the end of structs, if that struct is
used in another struct that's not also at the end. This wastes a float for each
FILTER object
2009-06-06 23:33:53 -07:00
Chris Robinson 3c122b0bef Set an error if effect creation fails 2009-05-31 11:54:49 -07:00
Chris Robinson 7940003d06 Set an error if NaN is given for panning values 2009-05-31 11:34:07 -07:00
Chris Robinson 45b16ff456 Use the generic FILTER object for the master effect filter
Also fix a couple comments
2009-05-30 12:54:53 -07:00
Chris Robinson 9341f4f884 Fixup panning gain calculations
Clamp the panning vector magnitude to 1, and use an energy-reduction method as
the vector magnitude increases (to simulate reverb area occlusion)
2009-05-30 00:32:17 -07:00
Chris Robinson 2c20f26784 Apply slot gain on slot output, not input 2009-05-29 16:51:00 -07:00
Chris Robinson 2a21a449b4 Slot gain changes should have an immediate effect 2009-05-29 13:50:58 -07:00
Chris Robinson 74dc7090fd Don't expose effect-specific structures 2009-05-29 13:30:50 -07:00
Chris Robinson e12ac95d69 Use the MIN/MAX/DEFAULT macros for checking and setting the effect parameters 2009-05-29 12:40:08 -07:00
Chris Robinson 34ea7eba9e Add preliminary support for the EAX Reverb effect
Not all parameters are supported yet, though it is a little more fuctional than
standard reverb
2009-05-29 01:32:54 -07:00
Chris Robinson 6d3ba44f55 Don't update the devicevalues before returning success 2009-05-27 07:02:33 -07:00
Chris Robinson 5a8ad67660 Lock the context before getting the mmap region to update 2009-05-26 14:54:59 -07:00
Chris Robinson f1e442408b Set the correct data size 2009-05-26 14:51:57 -07:00
Chris Robinson a946af4463 Simplify ALSA PCM parameter retrieval 2009-05-26 10:08:27 -07:00
Chris Robinson e01cd92d56 Set avail_min so snd_pcm_wait will wait for the full update to be ready 2009-05-26 10:03:17 -07:00
Chris Robinson 923af8c3a6 Don't update the source's gains in the sample mixing loop
Update copies stored on the stack instead, then update the source after mixing
2009-05-26 09:23:49 -07:00
Chris Robinson ac04cf57fa Make sure _CRT_SECURE_NO_WARNINGS is always defined for MSVC 2009-05-26 06:02:40 -07:00
Chris Robinson 1f6c4e01db Properly fall back to non-mmap capture if the parameters fail 2009-05-25 16:06:03 -07:00
Chris Robinson 04135723a2 Get rid of the ugly ok() macro 2009-05-25 13:07:49 -07:00
Chris Robinson 93fbdb1e6c Redo OSS mixing loop 2009-05-25 12:12:37 -07:00
Chris Robinson c1de15f840 Update in descrete amounts using the update size 2009-05-25 12:01:14 -07:00
Chris Robinson 3be399c555 Do not open pulseaudio if it didn't load 2009-05-19 06:37:22 -07:00
Chris Robinson 1f5453075c Dynamically load PulseAudio 2009-05-19 06:35:12 -07:00
Chris Robinson 33a74f1594 Clear the filter history directly 2009-05-17 22:50:07 -07:00
Chris Robinson e4da1224cb Optionally install the sample configuration file 2009-05-17 22:36:45 -07:00
Chris Robinson 5c2a47620c Reformat the sample config file 2009-05-17 22:24:29 -07:00
Chris Robinson 1bfa7609d2 Make the filter functions global inline, and use it for echo 2009-05-16 23:34:26 -07:00
Chris Robinson 7e8501123a Set some common macros in alu.h 2009-05-16 23:26:39 -07:00
Chris Robinson c447eeb2c7 Use the source reference distance to specify full panning magnitude
Sources that are closer than the specified reference distance will not pan to
full magnitude, thus providing a smoother transition as it moves around near
the listener
2009-05-16 03:54:16 -07:00
Chris Robinson ad19cea6e0 Make sure DSSPEAKER_5POINT1 is defined 2009-05-14 05:24:18 -07:00
Chris Robinson 0ce29863e3 Prevent spawning PulseAudio if it's not already running 2009-05-06 00:19:35 -07:00
Chris Robinson 7a7a4844f4 Make the filter history buffer size flexible
This lets the filter history buffer be as big as needed for a given use, so
that it can have a size large enough for the more demanding cases, but not be
wasteful for lesser-demanding cases, while not incuring the overhead of an
added pointer indirection
2009-04-16 05:43:09 -07:00
Chris Robinson a2adbb1ab5 Add a PulseAudio backend 2009-04-16 05:17:42 -07:00
Chris Robinson a97fc792d8 Increase the default maximum number of sends to 2 2009-04-14 22:18:47 -07:00
Chris Robinson e9a6a1d6f5 Use a 2-pole filter for the wet path low-pass filter
This should help keep CPU use from increasing a lot when the number of sends
increases. Also changes the function names to reflect the difference
2009-04-14 22:04:18 -07:00
Chris Robinson f245f0ef87 Make the number of source sends variable
The highest value is clamped to MAX_SENDS
2009-04-13 20:33:41 -07:00
Chris Robinson a30f431b63 Reduce the number of send loops 2009-04-13 02:50:40 -07:00
Chris Robinson 58f48f20e2 Rename Standard Reverb to Reverb 2009-04-13 02:01:21 -07:00
Chris Robinson ee1b02b709 Fix comment regarding the 3rd echo tap 2009-04-12 18:54:26 -07:00
Chris Robinson 55c790c9ff Add the Echo effect 2009-04-12 16:01:10 -07:00
Chris Robinson 65b69f3308 Fix air absorption 2009-04-11 20:27:55 -07:00
Chris Robinson c67fbd72dd Pay attention to the MAX_SENDS value 2009-04-11 20:04:46 -07:00
Chris Robinson 30f57d0824 Make auxiliary effect slot count configurable 2009-04-11 18:16:05 -07:00
Chris Robinson 1c54018111 Move the WetBuffer into the effect slot object
This should make it easier to support multiple slots
2009-04-11 17:04:55 -07:00
Chris Robinson e80e1b6d9f Use LIB_SUFFIX when creating the default lib install dir
Thanks to Hanno Böck for pointing this out
2009-04-07 12:11:41 -07:00
Chris Robinson 437f00d6de Add missing comment markers 2009-04-07 11:41:41 -07:00
Chris Robinson fc6d6b1601 Use the square of the values when calculating the density gain 2009-03-21 10:42:42 -07:00
Chris Robinson 9306e36d52 Make sure M_PI is defined for reverb 2009-03-15 23:14:40 -07:00
Chris Robinson 61122a5093 Release 1.7.411 2009-03-14 22:24:59 -07:00
Chris Robinson a8a4ff8af1 Constify some parameters 2009-03-13 23:08:15 -07:00
Chris Robinson 8a857c35ee Calculate filter coefficients in aluMixData 2009-03-13 22:58:54 -07:00
Chris Robinson 89ddd7d8e5 Don't modify the device struct until playback succesfully starts 2009-03-13 22:16:01 -07:00
Chris Robinson 8d0c4ccb3b The room rolloff factor can go up to 10 2009-03-13 02:12:45 -07:00
Chris Robinson 8ee47d5573 Dynamically load dsound when possible 2009-03-10 02:46:42 -07:00
Chris Robinson 9e88011417 Add a cast for setting a dummy pointer value 2009-03-10 02:20:05 -07:00
Chris Robinson f8949ee7a1 Always add the default ALSA device even if no cards are present 2009-03-10 01:46:51 -07:00
Chris Robinson 62aa2d0ba7 Only expose the default ALSA device in standard enumeration 2009-03-10 01:28:01 -07:00
Chris Robinson ace047d625 Append the card and device indices to the ALSA device strings 2009-03-10 01:21:42 -07:00
Chris Robinson d6277db209 Fix alsoftrc configuration sample comments 2009-03-10 01:08:03 -07:00
Chris Robinson 7ebb28327f Remove the SDL backend 2009-03-10 01:03:39 -07:00
Chris Robinson 86931cbde4 Add a PortAudio backend 2009-03-10 00:55:29 -07:00
Chris Robinson 6d7be151dc Remove the unneeded path from the cross-compiler commands 2009-03-06 20:09:44 -08:00
Chris Robinson 07227b9806 Use a modified reverb model that obeys the reverb parameters better 2009-03-02 18:48:23 -08:00
Chris Robinson 8348d719cd Clamp gain of multichannel sources 2009-02-10 15:15:49 -08:00
Chris Robinson 0fcefd865b Install the pkgconfig file to the correct directory 2009-02-10 14:39:48 -08:00
Chris Robinson 57c2e9b5f8 Include assert.h for assert() 2009-02-02 11:18:33 -08:00
Chris Robinson 7d7fc39035 Use calculated distance from reference for air absorption 2009-01-30 10:56:25 -08:00
Chris Robinson 351105b3df Fix incorrect comment 2009-01-30 10:53:09 -08:00
Chris Robinson cbfc33215b Use M_PI since it is sure to be defined 2009-01-27 07:11:58 -08:00
Chris Robinson 5a93b56673 Fix ignored return value warning 2009-01-26 08:10:05 -08:00
Chris Robinson 1f4c69c17a Use a matrix for up- and down-mixing channels 2009-01-25 22:11:07 -08:00
Chris Robinson f5b19fad20 Duplicate stereo onto the side channels as well as the back 2009-01-25 19:54:50 -08:00
Chris Robinson bc60818e9a Don't read stereo layout when output is mono 2009-01-25 19:33:52 -08:00
Chris Robinson f82c88f016 Add options for user-configurable speaker arrangements 2009-01-25 19:20:47 -08:00
Chris Robinson 98e86decad 6.1 uses front- and back-center, not left- and right-back channels 2009-01-24 15:13:14 -08:00
Chris Robinson aaf2c0ebd4 Seperate mixing loops depending on source channel configuration 2009-01-24 13:57:01 -08:00
Chris Robinson 778b74cae1 Reimplement panning using lookup tables, based on a patch by Christian Borss
This allows speaker positions to be specified by discrete angles around the
listener, providing more flexibility and configurability in placement.
Additional patches to take advantage of this are forthcoming.
2009-01-24 10:38:04 -08:00
Chris Robinson 43ee1edd97 Properly capitalize the libname in Win32 2009-01-10 21:23:53 -08:00
Chris Robinson dd7e23740b Remove XCOMPILEWIN32 option in favor of CMake 2.6's cross-compiling caps 2008-12-12 11:19:38 -08:00
Chris Robinson 1acd6da745 Search for SDL.h in addition to SDL/SDL.h 2008-12-12 11:09:23 -08:00
Chris Robinson 3056f91ec5 Apply the dry filter to multi-channel sources
Unlike mono sources, they use 2 chained one-pole filters instead of 4
2008-12-10 11:54:13 -08:00
Chris Robinson ed03570e1a Fix some CMake checks 2008-12-07 02:20:17 -08:00
Chris Robinson 2ec0e48d06 Protect playback device opening with a mutex lock 2008-12-07 01:07:54 -08:00
Chris Robinson 8b54d59b8c Add an SDL backend 2008-12-07 01:05:39 -08:00
Chris Robinson f6a4dbabdd Add cast for setting a dummy pointer value 2008-12-06 12:17:29 -08:00
Chris Robinson a71c291bcb Let CMAKE_DEBUG_POSTFIX be exposed for graphical CMake front-ends 2008-12-02 02:37:51 -08:00
Chris Robinson 55b9ccc2de Implement AL_EXTX_source_distance_model
As with other EXTX extensions, this is subject to change and removal as the
spec gets worked on
2008-11-25 18:56:10 -08:00
Chris Robinson 67d67a3bf6 Release 1.6.372 2008-11-21 09:16:29 -08:00
Chris Robinson 591de1ecb4 Wait until one full fragment is empty before mixing 2008-11-21 07:52:13 -08:00
Chris Robinson 3dad17c263 Make the DSound emulated fragment count configurable 2008-11-21 07:48:03 -08:00
Chris Robinson eefc18170d Fix a comment 2008-11-20 10:09:37 -08:00
Chris Robinson 5f84c5339d Fix early reflection input 2008-11-19 09:14:40 -08:00
Chris Robinson 2d461379ef Handle ALSA capture errors a bit better 2008-11-19 09:01:03 -08:00
Chris Robinson c8123756ff Simplify in-sample low-pass filter coefficient calculation 2008-11-18 06:35:00 -08:00
Chris Robinson 76c7789ee7 Fix low-pass coefficient calculation 2008-11-18 04:31:24 -08:00
Chris Robinson 13a2e6ef1f Don't calculate reverb HF limit if air absorption is 1 2008-11-18 03:26:02 -08:00
Chris Robinson 0ecb34b850 Non-cross-compiled DLLs shouldn't have lib prefixed 2008-11-18 03:24:49 -08:00
Chris Robinson 1f86c48d95 Remove outdated comments and add copyright header 2008-11-17 09:32:25 -08:00
Chris Robinson 7e1295df9a DirectSound is not explicitly dependant on windows.h 2008-11-16 04:39:12 -08:00
Chris Robinson 482b160c8a Remove unneeded macro 2008-11-16 01:07:39 -08:00
Chris Robinson 181eb95b13 Use a better dB-to-linear gain convertion 2008-11-16 00:57:35 -08:00
Chris Robinson c0ccd31a3e Implement a new reverb effect
Code created and graciously provided by Christopher Fitzgerald
2008-11-16 00:29:49 -08:00
Chris Robinson d72b132c57 Add an option to disable specific EFX effect types 2008-11-14 07:13:59 -08:00
Chris Robinson 506912aed7 Add cross-compiling option 2008-11-13 23:13:15 -08:00
Chris Robinson 670d70d3c9 Allow specifying another config file with the ALSOFT_CONF env var 2008-11-13 07:58:39 -08:00
Chris Robinson 010f7d12f4 Don't ramp gains when starting a sound from the beginning 2008-11-13 05:48:38 -08:00
Chris Robinson da684564ea Avoid unnecessary floating-point math 2008-11-11 17:59:55 -08:00
Chris Robinson fc4c867f27 Add initial AL_EXTX_buffer_sub_data support
Note that this is an in-development extension, as noted by the EXTX moniker
instead of EXT. It's behavior is subject to change, and the extension string
will be removed (replaced with the official string once it's finalized).
Developers are discouraged from using this in production code, though feel
free to play around with it.
2008-11-11 05:57:32 -08:00
Chris Robinson 9ba30c4e20 Fix Win32 thread handle leak 2008-11-05 19:42:56 -08:00
Chris Robinson 15334e56cd Be more flexible with channel count when loading IMA4 data 2008-11-02 15:30:56 -08:00
Chris Robinson ffa42ff22c Seperate data converters into reusable functions 2008-11-02 01:24:57 -07:00
Chris Robinson a7c62dbabc More padding fixes 2008-11-01 16:37:32 -07:00
Chris Robinson eda1e41152 More buffer conversion refactoring 2008-11-01 16:35:16 -07:00
Chris Robinson af5a5b76ec Padding is not dependant on the frequency cutoff anymore 2008-10-31 23:32:28 -07:00
Chris Robinson 87f3a0dc16 Restructure buffer data conversion code a bit 2008-10-31 22:13:35 -07:00
Chris Robinson 2c80a80704 Fix typo preventing capture from opening 2008-10-27 23:37:56 -07:00
Chris Robinson 301a4c4a95 Append the driver and its version to the AL version string 2008-10-25 15:48:17 -07:00
Chris Robinson 8fc4a3b724 Make sure an appropriate error is set when opening a device fails 2008-10-24 19:58:49 -07:00
Chris Robinson cb6f040005 Use plughw for capture so ALSA can convert capture data 2008-10-14 09:50:37 -07:00
Chris Robinson b91c2e4a99 Include float.h if it exists, for _RC_CHOP and _MCW_RC 2008-10-14 09:47:32 -07:00
Chris Robinson 59a71b1454 Remove another unused source member 2008-10-10 01:31:31 -07:00
Chris Robinson 36f133a5ae Use a modulo to keep the buffer position in range for looping sources
A high pitch and low buffer size can cause a lot of unnecessary iterations
otherwise, that just decrement the position
2008-10-10 01:13:32 -07:00
Chris Robinson 74a58c0d09 Clamp source position to the buffer size when it stops 2008-10-09 23:54:31 -07:00
Chris Robinson bfa1107781 Remove unneeded source member variable 2008-10-09 23:44:48 -07:00
Chris Robinson 11397f7667 Commit missing changes 2008-10-09 20:58:12 -07:00
Chris Robinson 6e9e8239ef Only send one channel through the wet path 2008-10-09 04:02:34 -07:00
Chris Robinson af9932d28b Increase max pitch to 65536
This should be safe now
2008-10-09 02:50:00 -07:00
Chris Robinson 87ff8a65e9 Simplify the lerp function 2008-10-09 02:32:47 -07:00
Chris Robinson 7b6f207790 Don't apply the wet path for multi-channel buffers 2008-10-09 02:28:52 -07:00
Chris Robinson 8672008e43 Skip mixing if the read position is beyond the end of the buffer 2008-10-09 01:17:39 -07:00
Chris Robinson c8cd193346 The wet path should be silent if no effect is set on the slot 2008-10-09 01:07:02 -07:00
Chris Robinson be292e5f0b Don't hold the whole-number position in the fractional value
This will help prevent overflows when the max pitch is increased
2008-10-02 23:53:46 -07:00
Chris Robinson 3863dcc9cb Use a new low-pass filter, based on the I3DL2 spec
Many thanks to Christopher Fitzgerald, for helping with it
2008-10-02 22:20:42 -07:00
Chris Robinson a2568409fc Implement non-mmap ALSA capture 2008-09-29 17:24:50 -07:00
Chris Robinson 6567cdd7b5 Air absorption factor is applied to the dB value, not linear gain 2008-09-22 17:01:47 -07:00
Chris Robinson 5bbf55a401 Add a variable to override the default library type with 2008-09-16 07:43:38 -07:00
Chris Robinson 4a530e2146 Fixup some source parameter calculations 2008-09-16 07:36:48 -07:00
Chris Robinson 27ba8f7b60 Fix function pointer declarations 2008-09-16 06:19:27 -07:00
Chris Robinson 6bfdb57a5b Use a 12dB/oct rolloff instead of 24 for the lowpass filter 2008-09-13 02:46:14 -07:00
Chris Robinson 26e8ea60a5 Store pi as a static const 2008-09-13 00:44:48 -07:00
Chris Robinson f4ea188ffa Fix typo to get the proper minor ALC version 2008-09-12 18:07:12 -07:00
Chris Robinson 1266580420 Print EFX info when the extension is available 2008-09-12 18:05:23 -07:00
Chris Robinson 16d96eed7b Add a Solaris playback backend 2008-09-07 14:34:14 -07:00
Chris Robinson fa76168683 Clear the end of the buffer when at the end of the queue and not looping 2008-09-06 14:08:53 -07:00
Chris Robinson 5f3329b2c9 Don't export extension function symbols from the lib 2008-09-06 13:45:27 -07:00
Chris Robinson db541f3cfa Remove unneeded source struct member 2008-08-15 17:43:07 -07:00
Chris Robinson 3e19ba6ca8 Clear channel volumes when starting a source 2008-08-15 16:33:47 -07:00
Chris Robinson ac8c082b89 Overwrite the input wet sample with the output 2008-08-14 20:44:55 -07:00
Chris Robinson 084df2a229 Allow setting the EFX doppler factor source property 2008-08-14 16:14:16 -07:00
Chris Robinson 22557070ec Ramp channel gains to remove pops and clicks from abrupt changes
Thanks to Christopher Fitzgerald for helping me work on it
2008-08-14 05:43:52 -07:00
Chris Robinson f8ef66954c Include fenv.h if it exists for fesetround 2008-08-08 08:12:41 -07:00
Chris Robinson ef59901e7c Set FPU mode to round toward zero for mixing 2008-08-08 07:32:21 -07:00
Chris Robinson cfe620ccb5 Remove unnecessary casting 2008-08-08 00:21:25 -07:00
Chris Robinson 453b015225 Prevent a 0 or negative increment for the buffer position
Thanks to Christopher Fitzgerald for pointing these last two problems out
2008-08-05 20:51:30 -07:00
Chris Robinson c1cf9ae8f6 Pass a dummy variable to CreateThread to satisfy Win9x 2008-08-05 20:19:13 -07:00
43 changed files with 9017 additions and 4534 deletions
+1 -1
View File
@@ -1 +1 @@
CMakeConf
build
+646 -313
View File
File diff suppressed because it is too large Load Diff
+1058 -849
View File
File diff suppressed because it is too large Load Diff
+23 -17
View File
@@ -18,6 +18,10 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#ifdef _WIN32
#define _WIN32_IE 0x400
#endif
#include "config.h"
#include <stdlib.h>
@@ -27,8 +31,7 @@
#include "alMain.h"
#ifdef _WIN32
#define _WIN32_IE 0x400
#ifdef _WIN32_IE
#include <shlobj.h>
#endif
@@ -219,13 +222,6 @@ void ReadALConfig(void)
}
#else
f = fopen("/etc/openal/alsoft.conf", "r");
if(!f)
{
f = fopen("/etc/openal/config", "r");
if(f)
AL_PRINT("Reading /etc/openal/config; this file is deprecated\n"
"\tPlease rename it to /etc/openal/alsoft.conf\n");
}
if(f)
{
LoadConfigFromFile(f);
@@ -235,14 +231,6 @@ void ReadALConfig(void)
{
snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", getenv("HOME"));
f = fopen(buffer, "r");
if(!f)
{
snprintf(buffer, sizeof(buffer), "%s/.openalrc", getenv("HOME"));
f = fopen(buffer, "r");
if(f)
AL_PRINT("Reading ~/.openalrc; this file is deprecated\n"
"\tPlease rename it to ~/.alsoftrc\n");
}
if(f)
{
LoadConfigFromFile(f);
@@ -250,6 +238,15 @@ void ReadALConfig(void)
}
}
#endif
if(getenv("ALSOFT_CONF"))
{
f = fopen(getenv("ALSOFT_CONF"), "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
}
void FreeALConfig(void)
@@ -316,3 +313,12 @@ float GetConfigValueFloat(const char *blockName, const char *keyName, float def)
return (float)strtod(val, NULL);
#endif
}
int GetConfigValueBool(const char *blockName, const char *keyName, float def)
{
const char *val = GetConfigValue(blockName, keyName, "");
if(!val[0]) return !!def;
return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||
strcasecmp(val, "on") == 0 || atoi(val) != 0);
}
+201
View File
@@ -0,0 +1,201 @@
/**
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, 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 {
// Must be first in all effects!
ALeffectState state;
ALfloat *SampleBuffer;
ALuint BufferLength;
// The echo is two tap. The third tap is the offset to write the feedback
// and input sample to
struct {
ALuint offset;
} Tap[3];
// The LR gains for the first tap. The second tap uses the reverse
ALfloat GainL;
ALfloat GainR;
ALfloat FeedGain;
FILTER iirFilter;
ALfloat history[2];
} ALechoState;
// Find the next power of 2. Actually, this will return the input value if
// it is already a power of 2.
static ALuint NextPowerOf2(ALuint value)
{
ALuint powerOf2 = 1;
if(value)
{
value--;
while(value)
{
value >>= 1;
powerOf2 <<= 1;
}
}
return powerOf2;
}
ALvoid EchoDestroy(ALeffectState *effect)
{
ALechoState *state = (ALechoState*)effect;
if(state)
{
free(state->SampleBuffer);
state->SampleBuffer = NULL;
free(state);
}
}
ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, ALeffect *Effect)
{
ALechoState *state = (ALechoState*)effect;
ALuint newdelay1, newdelay2;
ALfloat lrpan, cw, a, g;
newdelay1 = (ALuint)(Effect->Echo.Delay * Context->Frequency);
newdelay2 = (ALuint)(Effect->Echo.LRDelay * Context->Frequency);
state->Tap[0].offset = (state->BufferLength - newdelay1 - 1 +
state->Tap[2].offset)%state->BufferLength;
state->Tap[1].offset = (state->BufferLength - newdelay1 - newdelay2 - 1 +
state->Tap[2].offset)%state->BufferLength;
lrpan = Effect->Echo.Spread*0.5f + 0.5f;
state->GainL = aluSqrt( lrpan);
state->GainR = aluSqrt(1.0f-lrpan);
state->FeedGain = Effect->Echo.Feedback;
cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Context->Frequency);
g = 1.0f - Effect->Echo.Damping;
a = 0.0f;
if(g < 0.9999f) // 1-epsilon
a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
state->iirFilter.coeff = a;
}
ALvoid EchoProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
{
ALechoState *state = (ALechoState*)effect;
const ALuint delay = state->BufferLength-1;
ALuint tap1off = state->Tap[0].offset;
ALuint tap2off = state->Tap[1].offset;
ALuint fboff = state->Tap[2].offset;
ALfloat gain = Slot->Gain;
ALfloat samp[2];
ALuint i;
for(i = 0;i < SamplesToDo;i++)
{
// Apply damping
samp[0] = lpFilter2P(&state->iirFilter, 0, state->SampleBuffer[tap2off]+SamplesIn[i]);
// Apply feedback gain and mix in the new sample
state->SampleBuffer[fboff] = samp[0] * state->FeedGain;
tap1off = (tap1off+1) & delay;
tap2off = (tap2off+1) & delay;
fboff = (fboff+1) & delay;
// Sample first tap
samp[0] = state->SampleBuffer[tap1off]*state->GainL;
samp[1] = state->SampleBuffer[tap1off]*state->GainR;
// Sample second tap. Reverse LR panning
samp[0] += state->SampleBuffer[tap2off]*state->GainR;
samp[1] += state->SampleBuffer[tap2off]*state->GainL;
// Apply slot gain
samp[0] *= gain;
samp[1] *= gain;
SamplesOut[i][FRONT_LEFT] += samp[0];
SamplesOut[i][FRONT_RIGHT] += samp[1];
SamplesOut[i][SIDE_LEFT] += samp[0];
SamplesOut[i][SIDE_RIGHT] += samp[1];
SamplesOut[i][BACK_LEFT] += samp[0];
SamplesOut[i][BACK_RIGHT] += samp[1];
}
state->Tap[0].offset = tap1off;
state->Tap[1].offset = tap2off;
state->Tap[2].offset = fboff;
}
ALeffectState *EchoCreate(ALCcontext *Context)
{
ALechoState *state;
ALuint i, maxlen;
state = malloc(sizeof(*state));
if(!state)
{
alSetError(AL_OUT_OF_MEMORY);
return NULL;
}
state->state.Destroy = EchoDestroy;
state->state.Update = EchoUpdate;
state->state.Process = EchoProcess;
maxlen = (ALuint)(AL_ECHO_MAX_DELAY * Context->Frequency);
maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Context->Frequency);
// Use the next power of 2 for the buffer length, so the tap offsets can be
// wrapped using a mask instead of a modulo
state->BufferLength = NextPowerOf2(maxlen+1);
state->SampleBuffer = malloc(state->BufferLength * sizeof(ALfloat));
if(!state->SampleBuffer)
{
free(state);
alSetError(AL_OUT_OF_MEMORY);
return NULL;
}
for(i = 0;i < state->BufferLength;i++)
state->SampleBuffer[i] = 0.0f;
state->Tap[0].offset = 0;
state->Tap[1].offset = 0;
state->Tap[2].offset = 0;
state->GainL = 0.0f;
state->GainR = 0.0f;
for(i = 0;i < 2;i++)
state->iirFilter.history[i] = 0.0f;
state->iirFilter.coeff = 0.0f;
return &state->state;
}
+795
View File
@@ -0,0 +1,795 @@
/**
* Reverb for the OpenAL cross platform audio library
* Copyright (C) 2008-2009 by Christopher Fitzgerald.
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alEffect.h"
#include "alError.h"
#include "alu.h"
typedef struct DelayLine
{
// The delay lines use sample lengths that are powers of 2 to allow
// bitmasking instead of modulus wrapping.
ALuint Mask;
ALfloat *Line;
} DelayLine;
typedef struct ALverbState {
// Must be first in all effects!
ALeffectState state;
// All delay lines are allocated as a single buffer to reduce memory
// fragmentation and management code.
ALfloat *SampleBuffer;
// Master effect low-pass filter (2 chained 1-pole filters).
FILTER LpFilter;
ALfloat LpHistory[2];
// Initial effect delay and decorrelation.
DelayLine Delay;
// The tap points for the initial delay. First tap goes to early
// reflections, the last four decorrelate to late reverb.
ALuint Tap[5];
struct {
// Total gain for early reflections.
ALfloat Gain;
// Early reflections are done with 4 delay lines.
ALfloat Coeff[4];
DelayLine Delay[4];
ALuint Offset[4];
// The gain for each output channel based on 3D panning.
ALfloat PanGain[OUTPUTCHANNELS];
} Early;
struct {
// Total gain for late reverb.
ALfloat Gain;
// Attenuation to compensate for modal density and decay rate.
ALfloat DensityGain;
// The feed-back and feed-forward all-pass coefficient.
ALfloat ApFeedCoeff;
// Mixing matrix coefficient.
ALfloat MixCoeff;
// Late reverb has 4 parallel all-pass filters.
ALfloat ApCoeff[4];
DelayLine ApDelay[4];
ALuint ApOffset[4];
// In addition to 4 cyclical delay lines.
ALfloat Coeff[4];
DelayLine Delay[4];
ALuint Offset[4];
// The cyclical delay lines are 1-pole low-pass filtered.
ALfloat LpCoeff[4];
ALfloat LpSample[4];
// The gain for each output channel based on 3D panning.
ALfloat PanGain[OUTPUTCHANNELS];
} Late;
// The current read offset for all delay lines.
ALuint Offset;
} ALverbState;
// All delay line lengths are specified in seconds.
// The lengths of the early delay lines.
static const ALfloat EARLY_LINE_LENGTH[4] =
{
0.0015f, 0.0045f, 0.0135f, 0.0405f
};
// The lengths of the late all-pass delay lines.
static const ALfloat ALLPASS_LINE_LENGTH[4] =
{
0.0151f, 0.0167f, 0.0183f, 0.0200f,
};
// The lengths of the late cyclical delay lines.
static const ALfloat LATE_LINE_LENGTH[4] =
{
0.0211f, 0.0311f, 0.0461f, 0.0680f
};
// The late cyclical delay lines have a variable length dependent on the
// effect's density parameter (inverted for some reason) and this multiplier.
static const ALfloat LATE_LINE_MULTIPLIER = 4.0f;
// Input into the late reverb is decorrelated between four channels. Their
// timings are dependent on a fraction and multiplier. See VerbUpdate() for
// the calculations involved.
static const ALfloat DECO_FRACTION = 1.0f / 32.0f;
static const ALfloat DECO_MULTIPLIER = 2.0f;
// The maximum length of initial delay for the master delay line (a sum of
// the maximum early reflection and late reverb delays).
static const ALfloat MASTER_LINE_LENGTH = 0.3f + 0.1f;
// Find the next power of 2. Actually, this will return the input value if
// it is already a power of 2.
static ALuint NextPowerOf2(ALuint value)
{
ALuint powerOf2 = 1;
if(value)
{
value--;
while(value)
{
value >>= 1;
powerOf2 <<= 1;
}
}
return powerOf2;
}
// Basic delay line input/output routines.
static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
{
return Delay->Line[offset&Delay->Mask];
}
static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
{
Delay->Line[offset&Delay->Mask] = in;
}
// Delay line output routine for early reflections.
static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
{
return State->Early.Coeff[index] *
DelayLineOut(&State->Early.Delay[index],
State->Offset - State->Early.Offset[index]);
}
// Given an input sample, this function produces stereo output for early
// reflections.
static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *out)
{
ALfloat d[4], v, f[4];
// Obtain the decayed results of each early delay line.
d[0] = EarlyDelayLineOut(State, 0);
d[1] = EarlyDelayLineOut(State, 1);
d[2] = EarlyDelayLineOut(State, 2);
d[3] = EarlyDelayLineOut(State, 3);
/* The following uses a lossless scattering junction from waveguide
* theory. It actually amounts to a householder mixing matrix, which
* will produce a maximally diffuse response, and means this can probably
* be considered a simple feedback delay network (FDN).
* N
* ---
* \
* v = 2/N / d_i
* ---
* i=1
*/
v = (d[0] + d[1] + d[2] + d[3]) * 0.5f;
// The junction is loaded with the input here.
v += in;
// Calculate the feed values for the delay lines.
f[0] = v - d[0];
f[1] = v - d[1];
f[2] = v - d[2];
f[3] = v - d[3];
// Refeed the delay lines.
DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]);
DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]);
DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]);
DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]);
// Output the results of the junction for all four lines.
out[0] = State->Early.Gain * f[0];
out[1] = State->Early.Gain * f[1];
out[2] = State->Early.Gain * f[2];
out[3] = State->Early.Gain * f[3];
}
// All-pass input/output routine for late reverb.
static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALfloat in)
{
ALfloat out;
out = State->Late.ApCoeff[index] *
DelayLineOut(&State->Late.ApDelay[index],
State->Offset - State->Late.ApOffset[index]);
out -= (State->Late.ApFeedCoeff * in);
DelayLineIn(&State->Late.ApDelay[index], State->Offset,
(State->Late.ApFeedCoeff * out) + in);
return out;
}
// Delay line output routine for late reverb.
static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
{
return State->Late.Coeff[index] *
DelayLineOut(&State->Late.Delay[index],
State->Offset - State->Late.Offset[index]);
}
// Low-pass filter input/output routine for late reverb.
static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in)
{
State->Late.LpSample[index] = in +
((State->Late.LpSample[index] - in) * State->Late.LpCoeff[index]);
return State->Late.LpSample[index];
}
// Given four decorrelated input samples, this function produces stereo
// output for late reverb.
static __inline ALvoid LateReverb(ALverbState *State, ALfloat *in, ALfloat *out)
{
ALfloat d[4], f[4];
// Obtain the decayed results of the cyclical delay lines, and add the
// corresponding input channels attenuated by density. Then pass the
// results through the low-pass filters.
d[0] = LateLowPassInOut(State, 0, (State->Late.DensityGain * in[0]) +
LateDelayLineOut(State, 0));
d[1] = LateLowPassInOut(State, 1, (State->Late.DensityGain * in[1]) +
LateDelayLineOut(State, 1));
d[2] = LateLowPassInOut(State, 2, (State->Late.DensityGain * in[2]) +
LateDelayLineOut(State, 2));
d[3] = LateLowPassInOut(State, 3, (State->Late.DensityGain * in[3]) +
LateDelayLineOut(State, 3));
// To help increase diffusion, run each line through an all-pass filter.
// The order of the all-pass filters is selected so that the shortest
// all-pass filter will feed the shortest delay line.
d[0] = LateAllPassInOut(State, 1, d[0]);
d[1] = LateAllPassInOut(State, 3, d[1]);
d[2] = LateAllPassInOut(State, 0, d[2]);
d[3] = LateAllPassInOut(State, 2, d[3]);
/* Late reverb is done with a modified feedback delay network (FDN)
* topology. Four input lines are each fed through their own all-pass
* filter and then into the mixing matrix. The four outputs of the
* mixing matrix are then cycled back to the inputs. Each output feeds
* a different input to form a circlular feed cycle.
*
* The mixing matrix used is a 4D skew-symmetric rotation matrix derived
* using a single unitary rotational parameter:
*
* [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
* [ -a, d, c, -b ]
* [ -b, -c, d, a ]
* [ -c, b, -a, d ]
*
* The rotation is constructed from the effect's diffusion parameter,
* yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
* with differing signs, and d is the coefficient x. The matrix is thus:
*
* [ x, y, -y, y ] x = 1 - (0.5 diffusion^3)
* [ -y, x, y, y ] y = sqrt((1 - x^2) / 3)
* [ y, -y, x, y ]
* [ -y, -y, -y, x ]
*
* To reduce the number of multiplies, the x coefficient is applied with
* the cyclical delay line coefficients. Thus only the y coefficient is
* applied when mixing, and is modified to be: y / x.
*/
f[0] = d[0] + (State->Late.MixCoeff * ( d[1] - d[2] + d[3]));
f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3]));
f[2] = d[2] + (State->Late.MixCoeff * ( d[0] - d[1] + d[3]));
f[3] = d[3] + (State->Late.MixCoeff * (-d[0] - d[1] - d[2]));
// Output the results of the matrix for all four cyclical delay lines,
// attenuated by the late reverb gain (which is attenuated by the 'x'
// mix coefficient).
out[0] = State->Late.Gain * f[0];
out[1] = State->Late.Gain * f[1];
out[2] = State->Late.Gain * f[2];
out[3] = State->Late.Gain * f[3];
// The delay lines are fed circularly in the order:
// 0 -> 1 -> 3 -> 2 -> 0 ...
DelayLineIn(&State->Late.Delay[0], State->Offset, f[2]);
DelayLineIn(&State->Late.Delay[1], State->Offset, f[0]);
DelayLineIn(&State->Late.Delay[2], State->Offset, f[3]);
DelayLineIn(&State->Late.Delay[3], State->Offset, f[1]);
}
// Process the reverb for a given input sample, resulting in separate four-
// channel output for both early reflections and late reverb.
static __inline ALvoid ReverbInOut(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
{
ALfloat taps[4];
// Low-pass filter the incoming sample.
in = lpFilter2P(&State->LpFilter, 0, in);
// Feed the initial delay line.
DelayLineIn(&State->Delay, State->Offset, in);
// Calculate the early reflection from the first delay tap.
in = DelayLineOut(&State->Delay, State->Offset - State->Tap[0]);
EarlyReflection(State, in, early);
// Calculate the late reverb from the last four delay taps.
taps[0] = DelayLineOut(&State->Delay, State->Offset - State->Tap[1]);
taps[1] = DelayLineOut(&State->Delay, State->Offset - State->Tap[2]);
taps[2] = DelayLineOut(&State->Delay, State->Offset - State->Tap[3]);
taps[3] = DelayLineOut(&State->Delay, State->Offset - State->Tap[4]);
LateReverb(State, taps, late);
// Step all delays forward one sample.
State->Offset++;
}
// This destroys the reverb state. It should be called only when the effect
// slot has a different (or no) effect loaded over the reverb effect.
ALvoid VerbDestroy(ALeffectState *effect)
{
ALverbState *State = (ALverbState*)effect;
if(State)
{
free(State->SampleBuffer);
State->SampleBuffer = NULL;
free(State);
}
}
// NOTE: Temp, remove later.
static __inline ALint aluCart2LUTpos(ALfloat re, ALfloat im)
{
ALint pos = 0;
ALfloat denom = aluFabs(re) + aluFabs(im);
if(denom > 0.0f)
pos = (ALint)(QUADRANT_NUM*aluFabs(im) / denom + 0.5);
if(re < 0.0)
pos = 2 * QUADRANT_NUM - pos;
if(im < 0.0)
pos = LUT_NUM - pos;
return pos%LUT_NUM;
}
// This updates the reverb state. This is called any time the reverb effect
// is loaded into a slot.
ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, ALeffect *Effect)
{
ALverbState *State = (ALverbState*)effect;
ALuint index;
ALfloat length, mixCoeff, cw, g, coeff;
ALfloat hfRatio = Effect->Reverb.DecayHFRatio;
// Calculate the master low-pass filter (from the master effect HF gain).
cw = cos(2.0 * M_PI * Effect->Reverb.HFReference / Context->Frequency);
g = __max(Effect->Reverb.GainHF, 0.0001f);
State->LpFilter.coeff = 0.0f;
if(g < 0.9999f) // 1-epsilon
State->LpFilter.coeff = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
// Calculate the initial delay taps.
length = Effect->Reverb.ReflectionsDelay;
State->Tap[0] = (ALuint)(length * Context->Frequency);
length += Effect->Reverb.LateReverbDelay;
/* The four inputs to the late reverb are decorrelated to smooth the
* initial reverb and reduce harsh echos. The timings are calculated as
* multiples of a fraction of the smallest cyclical delay time. This
* result is then adjusted so that the first tap occurs immediately (all
* taps are reduced by the shortest fraction).
*
* offset[index] = ((FRACTION MULTIPLIER^index) - 1) delay
*/
for(index = 0;index < 4;index++)
{
length += LATE_LINE_LENGTH[0] *
(1.0f + (Effect->Reverb.Density * LATE_LINE_MULTIPLIER)) *
(DECO_FRACTION * (pow(DECO_MULTIPLIER, (ALfloat)index) - 1.0f));
State->Tap[1 + index] = (ALuint)(length * Context->Frequency);
}
// Calculate the early reflections gain (from the master effect gain, and
// reflections gain parameters).
State->Early.Gain = Effect->Reverb.Gain * Effect->Reverb.ReflectionsGain;
// Calculate the gain (coefficient) for each early delay line.
for(index = 0;index < 4;index++)
State->Early.Coeff[index] = pow(10.0f, EARLY_LINE_LENGTH[index] /
Effect->Reverb.LateReverbDelay *
-60.0f / 20.0f);
// Calculate the first mixing matrix coefficient (x).
mixCoeff = 1.0f - (0.5f * pow(Effect->Reverb.Diffusion, 3.0f));
// Calculate the late reverb gain (from the master effect gain, and late
// reverb gain parameters). Since the output is tapped prior to the
// application of the delay line coefficients, this gain needs to be
// attenuated by the 'x' mix coefficient from above.
State->Late.Gain = Effect->Reverb.Gain * Effect->Reverb.LateReverbGain * mixCoeff;
/* To compensate for changes in modal density and decay time of the late
* reverb signal, the input is attenuated based on the maximal energy of
* the outgoing signal. This is calculated as the ratio between a
* reference value and the current approximation of energy for the output
* signal.
*
* Reverb output matches exponential decay of the form Sum(a^n), where a
* is the attenuation coefficient, and n is the sample ranging from 0 to
* infinity. The signal energy can thus be approximated using the area
* under this curve, calculated as: 1 / (1 - a).
*
* The reference energy is calculated from a signal at the lowest (effect
* at 1.0) density with a decay time of one second.
*
* The coefficient is calculated as the average length of the cyclical
* delay lines. This produces a better result than calculating the gain
* for each line individually (most likely a side effect of diffusion).
*
* The final result is the square root of the ratio bound to a maximum
* value of 1 (no amplification).
*/
length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] +
LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]);
g = length * (1.0f + LATE_LINE_MULTIPLIER) * 0.25f;
g = pow(10.0f, g * -60.0f / 20.0f);
g = 1.0f / (1.0f - (g * g));
length *= 1.0f + (Effect->Reverb.Density * LATE_LINE_MULTIPLIER) * 0.25f;
length = pow(10.0f, length / Effect->Reverb.DecayTime * -60.0f / 20.0f);
length = 1.0f / (1.0f - (length * length));
State->Late.DensityGain = __min(aluSqrt(g / length), 1.0f);
// Calculate the all-pass feed-back and feed-forward coefficient.
State->Late.ApFeedCoeff = 0.6f * pow(Effect->Reverb.Diffusion, 3.0f);
// Calculate the mixing matrix coefficient (y / x).
g = aluSqrt((1.0f - (mixCoeff * mixCoeff)) / 3.0f);
State->Late.MixCoeff = g / mixCoeff;
for(index = 0;index < 4;index++)
{
// Calculate the gain (coefficient) for each all-pass line.
State->Late.ApCoeff[index] = pow(10.0f, ALLPASS_LINE_LENGTH[index] /
Effect->Reverb.DecayTime *
-60.0f / 20.0f);
}
// If the HF limit parameter is flagged, calculate an appropriate limit
// based on the air absorption parameter.
if(Effect->Reverb.DecayHFLimit && Effect->Reverb.AirAbsorptionGainHF < 1.0f)
{
ALfloat limitRatio;
// For each of the cyclical delays, find the attenuation due to air
// absorption in dB (converting delay time to meters using the speed
// of sound). Then reversing the decay equation, solve for HF ratio.
// The delay length is cancelled out of the equation, so it can be
// calculated once for all lines.
limitRatio = 1.0f / (log10(Effect->Reverb.AirAbsorptionGainHF) *
SPEEDOFSOUNDMETRESPERSEC *
Effect->Reverb.DecayTime / -60.0f * 20.0f);
// Need to limit the result to a minimum of 0.1, just like the HF
// ratio parameter.
limitRatio = __max(limitRatio, 0.1f);
// Using the limit calculated above, apply the upper bound to the
// HF ratio.
hfRatio = __min(hfRatio, limitRatio);
}
// Calculate the low-pass filter frequency.
cw = cos(2.0f * M_PI * Effect->Reverb.HFReference / Context->Frequency);
for(index = 0;index < 4;index++)
{
// Calculate the length (in seconds) of each cyclical delay line.
length = LATE_LINE_LENGTH[index] * (1.0f + (Effect->Reverb.Density *
LATE_LINE_MULTIPLIER));
// Calculate the delay offset for the cyclical delay lines.
State->Late.Offset[index] = (ALuint)(length * Context->Frequency);
// Calculate the gain (coefficient) for each cyclical line.
State->Late.Coeff[index] = pow(10.0f, length / Effect->Reverb.DecayTime *
-60.0f / 20.0f);
// Eventually this should boost the high frequencies when the ratio
// exceeds 1.
coeff = 0.0f;
if (hfRatio < 1.0f)
{
// Calculate the decay equation for each low-pass filter.
g = pow(10.0f, length / (Effect->Reverb.DecayTime * hfRatio) *
-60.0f / 20.0f) / State->Late.Coeff[index];
g = __max(g, 0.1f);
g *= g;
// Calculate the gain (coefficient) for each low-pass filter.
if(g < 0.9999f) // 1-epsilon
coeff = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
// Very low decay times will produce minimal output, so apply an
// upper bound to the coefficient.
coeff = __min(coeff, 0.98f);
}
State->Late.LpCoeff[index] = coeff;
// Attenuate the cyclical line coefficients by the mixing coefficient
// (x).
State->Late.Coeff[index] *= mixCoeff;
}
// Calculate the 3D-panning gains for the early reflections and late
// reverb (for EAX mode).
{
ALfloat earlyPan[3] = { Effect->Reverb.ReflectionsPan[0], Effect->Reverb.ReflectionsPan[1], Effect->Reverb.ReflectionsPan[2] };
ALfloat latePan[3] = { Effect->Reverb.LateReverbPan[0], Effect->Reverb.LateReverbPan[1], Effect->Reverb.LateReverbPan[2] };
ALfloat *speakerGain, dirGain, ambientGain;
ALfloat length;
ALint pos;
length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2];
if(length > 1.0f)
{
length = 1.0f / aluSqrt(length);
earlyPan[0] *= length;
earlyPan[1] *= length;
earlyPan[2] *= length;
}
length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2];
if(length > 1.0f)
{
length = 1.0f / aluSqrt(length);
latePan[0] *= length;
latePan[1] *= length;
latePan[2] *= length;
}
// This code applies directional reverb just like the mixer applies
// directional sources. It diffuses the sound toward all speakers
// as the magnitude of the panning vector drops, which is only an
// approximation of the expansion of sound across the speakers from
// the panning direction.
pos = aluCart2LUTpos(earlyPan[2], earlyPan[0]);
speakerGain = &Context->PanningLUT[OUTPUTCHANNELS * pos];
dirGain = aluSqrt((earlyPan[0] * earlyPan[0]) + (earlyPan[2] * earlyPan[2]));
ambientGain = (1.0 - dirGain);
for(index = 0;index < OUTPUTCHANNELS;index++)
State->Early.PanGain[index] = dirGain * speakerGain[index] + ambientGain;
pos = aluCart2LUTpos(latePan[2], latePan[0]);
speakerGain = &Context->PanningLUT[OUTPUTCHANNELS * pos];
dirGain = aluSqrt((latePan[0] * latePan[0]) + (latePan[2] * latePan[2]));
ambientGain = (1.0 - dirGain);
for(index = 0;index < OUTPUTCHANNELS;index++)
State->Late.PanGain[index] = dirGain * speakerGain[index] + ambientGain;
}
}
// This processes the reverb state, given the input samples and an output
// buffer.
ALvoid VerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
{
ALverbState *State = (ALverbState*)effect;
ALuint index;
ALfloat early[4], late[4], out[4];
ALfloat gain = Slot->Gain;
for(index = 0;index < SamplesToDo;index++)
{
// Process reverb for this sample.
ReverbInOut(State, SamplesIn[index], early, late);
// Mix early reflections and late reverb.
out[0] = (early[0] + late[0]) * gain;
out[1] = (early[1] + late[1]) * gain;
out[2] = (early[2] + late[2]) * gain;
out[3] = (early[3] + late[3]) * gain;
// Output the results.
SamplesOut[index][FRONT_LEFT] += out[0];
SamplesOut[index][FRONT_RIGHT] += out[1];
SamplesOut[index][FRONT_CENTER] += out[3];
SamplesOut[index][SIDE_LEFT] += out[0];
SamplesOut[index][SIDE_RIGHT] += out[1];
SamplesOut[index][BACK_LEFT] += out[0];
SamplesOut[index][BACK_RIGHT] += out[1];
SamplesOut[index][BACK_CENTER] += out[2];
}
}
// This processes the EAX reverb state, given the input samples and an output
// buffer.
ALvoid EAXVerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
{
ALverbState *State = (ALverbState*)effect;
ALuint index;
ALfloat early[4], late[4];
ALfloat gain = Slot->Gain;
for(index = 0;index < SamplesToDo;index++)
{
// Process reverb for this sample.
ReverbInOut(State, SamplesIn[index], early, late);
// Unfortunately, while the number and configuration of gains for
// panning adjust according to OUTPUTCHANNELS, the output from the
// reverb engine is not so scalable.
SamplesOut[index][FRONT_LEFT] +=
(State->Early.PanGain[FRONT_LEFT]*early[0] +
State->Late.PanGain[FRONT_LEFT]*late[0]) * gain;
SamplesOut[index][FRONT_RIGHT] +=
(State->Early.PanGain[FRONT_RIGHT]*early[1] +
State->Late.PanGain[FRONT_RIGHT]*late[1]) * gain;
SamplesOut[index][FRONT_CENTER] +=
(State->Early.PanGain[FRONT_CENTER]*early[3] +
State->Late.PanGain[FRONT_CENTER]*late[3]) * gain;
SamplesOut[index][SIDE_LEFT] +=
(State->Early.PanGain[SIDE_LEFT]*early[0] +
State->Late.PanGain[SIDE_LEFT]*late[0]) * gain;
SamplesOut[index][SIDE_RIGHT] +=
(State->Early.PanGain[SIDE_RIGHT]*early[1] +
State->Late.PanGain[SIDE_RIGHT]*late[1]) * gain;
SamplesOut[index][BACK_LEFT] +=
(State->Early.PanGain[BACK_LEFT]*early[0] +
State->Late.PanGain[BACK_LEFT]*late[0]) * gain;
SamplesOut[index][BACK_RIGHT] +=
(State->Early.PanGain[BACK_RIGHT]*early[1] +
State->Late.PanGain[BACK_RIGHT]*late[1]) * gain;
SamplesOut[index][BACK_CENTER] +=
(State->Early.PanGain[BACK_CENTER]*early[2] +
State->Late.PanGain[BACK_CENTER]*late[2]) * gain;
}
}
// This creates the reverb state. It should be called only when the reverb
// effect is loaded into a slot that doesn't already have a reverb effect.
ALeffectState *VerbCreate(ALCcontext *Context)
{
ALverbState *State = NULL;
ALuint samples, length[13], totalLength, index;
State = malloc(sizeof(ALverbState));
if(!State)
{
alSetError(AL_OUT_OF_MEMORY);
return NULL;
}
State->state.Destroy = VerbDestroy;
State->state.Update = VerbUpdate;
State->state.Process = VerbProcess;
// All line lengths are powers of 2, calculated from their lengths, with
// an additional sample in case of rounding errors.
// See VerbUpdate() for an explanation of the additional calculation
// added to the master line length.
samples = (ALuint)
((MASTER_LINE_LENGTH +
(LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER) *
(DECO_FRACTION * ((DECO_MULTIPLIER * DECO_MULTIPLIER *
DECO_MULTIPLIER) - 1.0f)))) *
Context->Frequency) + 1;
length[0] = NextPowerOf2(samples);
totalLength = length[0];
for(index = 0;index < 4;index++)
{
samples = (ALuint)(EARLY_LINE_LENGTH[index] * Context->Frequency) + 1;
length[1 + index] = NextPowerOf2(samples);
totalLength += length[1 + index];
}
for(index = 0;index < 4;index++)
{
samples = (ALuint)(ALLPASS_LINE_LENGTH[index] * Context->Frequency) + 1;
length[5 + index] = NextPowerOf2(samples);
totalLength += length[5 + index];
}
for(index = 0;index < 4;index++)
{
samples = (ALuint)(LATE_LINE_LENGTH[index] *
(1.0f + LATE_LINE_MULTIPLIER) * Context->Frequency) + 1;
length[9 + index] = NextPowerOf2(samples);
totalLength += length[9 + index];
}
// All lines share a single sample buffer and have their masks and start
// addresses calculated once.
State->SampleBuffer = malloc(totalLength * sizeof(ALfloat));
if(!State->SampleBuffer)
{
free(State);
alSetError(AL_OUT_OF_MEMORY);
return NULL;
}
for(index = 0; index < totalLength;index++)
State->SampleBuffer[index] = 0.0f;
State->LpFilter.coeff = 0.0f;
State->LpFilter.history[0] = 0.0f;
State->LpFilter.history[1] = 0.0f;
State->Delay.Mask = length[0] - 1;
State->Delay.Line = &State->SampleBuffer[0];
totalLength = length[0];
State->Tap[0] = 0;
State->Tap[1] = 0;
State->Tap[2] = 0;
State->Tap[3] = 0;
State->Tap[4] = 0;
State->Early.Gain = 0.0f;
for(index = 0;index < 4;index++)
{
State->Early.Coeff[index] = 0.0f;
State->Early.Delay[index].Mask = length[1 + index] - 1;
State->Early.Delay[index].Line = &State->SampleBuffer[totalLength];
totalLength += length[1 + index];
// The early delay lines have their read offsets calculated once.
State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
Context->Frequency);
}
State->Late.Gain = 0.0f;
State->Late.DensityGain = 0.0f;
State->Late.ApFeedCoeff = 0.0f;
State->Late.MixCoeff = 0.0f;
for(index = 0;index < 4;index++)
{
State->Late.ApCoeff[index] = 0.0f;
State->Late.ApDelay[index].Mask = length[5 + index] - 1;
State->Late.ApDelay[index].Line = &State->SampleBuffer[totalLength];
totalLength += length[5 + index];
// The late all-pass lines have their read offsets calculated once.
State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
Context->Frequency);
}
for(index = 0;index < 4;index++)
{
State->Late.Coeff[index] = 0.0f;
State->Late.Delay[index].Mask = length[9 + index] - 1;
State->Late.Delay[index].Line = &State->SampleBuffer[totalLength];
totalLength += length[9 + index];
State->Late.Offset[index] = 0;
State->Late.LpCoeff[index] = 0.0f;
State->Late.LpSample[index] = 0.0f;
}
// Panning is applied as an independent gain for each output channel.
for(index = 0;index < OUTPUTCHANNELS;index++)
{
State->Early.PanGain[index] = 0.0f;
State->Late.PanGain[index] = 0.0f;
}
State->Offset = 0;
return &State->state;
}
ALeffectState *EAXVerbCreate(ALCcontext *Context)
{
ALeffectState *State = VerbCreate(Context);
if(State) State->Process = EAXVerbProcess;
return State;
}
+4 -2
View File
@@ -81,10 +81,11 @@ ALsizei RingBufferSize(RingBuffer *ring)
void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
{
int remain = ring->length - ring->write_pos;
int remain;
EnterCriticalSection(&ring->cs);
remain = ring->length - ring->write_pos;
if((ring->read_pos-ring->write_pos+ring->length)%ring->length < len)
ring->read_pos = (ring->write_pos+len) % ring->length;
@@ -104,10 +105,11 @@ void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
{
int remain = ring->length - ring->read_pos;
int remain;
EnterCriticalSection(&ring->cs);
remain = ring->length - ring->read_pos;
if(remain < len)
{
memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), remain*ring->frame_size);
+3 -1
View File
@@ -47,13 +47,14 @@ static DWORD CALLBACK StarterFunc(void *ptr)
ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr)
{
DWORD dummy;
ThreadInfo *inf = malloc(sizeof(ThreadInfo));
if(!inf) return 0;
inf->func = func;
inf->ptr = ptr;
inf->thread = CreateThread(NULL, 0, StarterFunc, inf, 0, NULL);
inf->thread = CreateThread(NULL, 0, StarterFunc, inf, 0, &dummy);
if(!inf->thread)
{
free(inf);
@@ -70,6 +71,7 @@ ALuint StopThread(ALvoid *thread)
WaitForSingleObject(inf->thread, INFINITE);
GetExitCodeThread(inf->thread, &ret);
CloseHandle(inf->thread);
free(inf);
+491 -348
View File
File diff suppressed because it is too large Load Diff
-2
View File
@@ -113,8 +113,6 @@ static void init(struct bs2b *bs2b)
bs2b->a1_hi = -x;
bs2b->gain = 1.0 / (1.0 - G_hi + G_lo);
bs2b_clear(bs2b);
} /* init */
/* Exported functions.
+230 -96
View File
@@ -28,19 +28,29 @@
#include <dsound.h>
#include <mmreg.h>
#ifndef _WAVEFORMATEXTENSIBLE_
#include <ks.h>
#include <ksmedia.h>
#endif
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
#ifndef DSSPEAKER_5POINT1
#define DSSPEAKER_5POINT1 6
#endif
#ifndef DSSPEAKER_7POINT1
#define DSSPEAKER_7POINT1 7
#endif
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
static void *ds_handle;
static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter);
static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext);
// Since DSound doesn't report the fragment size, just assume 4 fragments
#define DS_FRAGS 4
typedef struct {
// DirectSound Playback Device
@@ -57,36 +67,53 @@ typedef struct {
ALCchar *name;
GUID guid;
} DevMap;
static DevMap DeviceList[16];
static const ALCchar dsDevice[] = "DirectSound Software";
static DevMap *DeviceList;
static ALuint NumDevices;
static ALuint DSoundProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
DSoundData *pData = (DSoundData*)pDevice->ExtraData;
DSBCAPS DSBCaps;
DWORD LastCursor = 0;
DWORD PlayCursor;
VOID *WritePtr1, *WritePtr2;
DWORD WriteCnt1, WriteCnt2;
DWORD BufferSize;
DWORD FrameSize;
DWORD FragSize;
DWORD avail;
HRESULT err;
BufferSize = pDevice->UpdateSize * DS_FRAGS *
aluBytesFromFormat(pDevice->Format) *
aluChannelsFromFormat(pDevice->Format);
memset(&DSBCaps, 0, sizeof(DSBCaps));
DSBCaps.dwSize = sizeof(DSBCaps);
err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps);
if(FAILED(err))
{
AL_PRINT("Failed to get buffer caps: 0x%lx\n", err);
aluHandleDisconnect(pDevice);
return 1;
}
FrameSize = aluChannelsFromFormat(pDevice->Format) *
aluBytesFromFormat(pDevice->Format);
FragSize = pDevice->UpdateSize * FrameSize;
IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL);
while(!pData->killNow)
{
// Get current play and write cursors
IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
avail = (PlayCursor-LastCursor+BufferSize) % BufferSize;
avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
if(avail == 0)
if(avail < FragSize)
{
Sleep(1);
continue;
}
avail -= avail%FragSize;
// Lock output buffer
WriteCnt1 = 0;
@@ -107,10 +134,8 @@ static ALuint DSoundProc(ALvoid *ptr)
if(SUCCEEDED(err))
{
// If we have an active context, mix data directly into output buffer otherwise fill with silence
SuspendContext(NULL);
aluMixData(pDevice->Context, WritePtr1, WriteCnt1, pDevice->Format);
aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format);
ProcessContext(NULL);
aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize);
aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize);
// Unlock output buffer only when successfully locked
IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
@@ -120,7 +145,7 @@ static ALuint DSoundProc(ALvoid *ptr)
// Update old write cursor location
LastCursor += WriteCnt1+WriteCnt2;
LastCursor %= BufferSize;
LastCursor %= DSBCaps.dwBufferBytes;
}
return 0;
@@ -128,34 +153,29 @@ static ALuint DSoundProc(ALvoid *ptr)
static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
{
DSBUFFERDESC DSBDescription;
DSoundData *pData = NULL;
WAVEFORMATEXTENSIBLE OutputType;
DWORD frameSize = 0;
LPGUID guid = NULL;
DWORD speakers;
HRESULT hr;
if(deviceName)
if(ds_handle == NULL)
return ALC_FALSE;
if(!deviceName)
deviceName = dsDevice;
else if(strcmp(deviceName, dsDevice) != 0)
{
int i;
for(i = 0;DeviceList[i].name;i++)
ALuint i;
for(i = 0;i < NumDevices;i++)
{
if(strcmp(deviceName, DeviceList[i].name) == 0)
{
device->szDeviceName = DeviceList[i].name;
if(i > 0)
guid = &DeviceList[i].guid;
guid = &DeviceList[i].guid;
break;
}
}
if(!DeviceList[i].name)
if(i == NumDevices)
return ALC_FALSE;
}
else
device->szDeviceName = DeviceList[0].name;
memset(&OutputType, 0, sizeof(OutputType));
//Initialise requested device
@@ -167,28 +187,60 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
}
//DirectSound Init code
hr = DirectSoundCreate(guid, &pData->lpDS, NULL);
hr = pDirectSoundCreate(guid, &pData->lpDS, NULL);
if(SUCCEEDED(hr))
hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
if(SUCCEEDED(hr))
if(FAILED(hr))
{
if(*(GetConfigValue(NULL, "format", "")) == 0)
hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
if(pData->lpDS)
IDirectSound_Release(pData->lpDS);
free(pData);
return ALC_FALSE;
}
device->szDeviceName = strdup(deviceName);
device->ExtraData = pData;
return ALC_TRUE;
}
static void DSoundClosePlayback(ALCdevice *device)
{
DSoundData *pData = device->ExtraData;
IDirectSound_Release(pData->lpDS);
free(pData);
device->ExtraData = NULL;
}
static ALCboolean DSoundResetPlayback(ALCdevice *device)
{
DSoundData *pData = (DSoundData*)device->ExtraData;
DSBUFFERDESC DSBDescription;
WAVEFORMATEXTENSIBLE OutputType;
DWORD frameSize = 0;
ALenum format = 0;
DWORD speakers;
HRESULT hr;
memset(&OutputType, 0, sizeof(OutputType));
hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
if(SUCCEEDED(hr) && *(GetConfigValue(NULL, "format", "")) != 0)
{
if(aluChannelsFromFormat(device->Format) == 1)
speakers = DSSPEAKER_COMBINED(DSSPEAKER_MONO, 0);
else if(aluChannelsFromFormat(device->Format) == 2)
speakers = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, 0);
else if(aluChannelsFromFormat(device->Format) == 4)
speakers = DSSPEAKER_COMBINED(DSSPEAKER_QUAD, 0);
else if(aluChannelsFromFormat(device->Format) == 6)
speakers = DSSPEAKER_COMBINED(DSSPEAKER_5POINT1, 0);
else if(aluChannelsFromFormat(device->Format) == 8)
speakers = DSSPEAKER_COMBINED(DSSPEAKER_7POINT1, 0);
else
{
if(device->Format == AL_FORMAT_MONO8 || device->Format == AL_FORMAT_MONO16)
speakers = DSSPEAKER_COMBINED(DSSPEAKER_MONO, 0);
else if(device->Format == AL_FORMAT_STEREO8 || device->Format == AL_FORMAT_STEREO16)
speakers = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, 0);
else if(device->Format == AL_FORMAT_QUAD8 || device->Format == AL_FORMAT_QUAD16)
speakers = DSSPEAKER_COMBINED(DSSPEAKER_QUAD, 0);
else if(device->Format == AL_FORMAT_51CHN8 || device->Format == AL_FORMAT_51CHN16)
speakers = DSSPEAKER_COMBINED(DSSPEAKER_5POINT1, 0);
else if(device->Format == AL_FORMAT_71CHN8 || device->Format == AL_FORMAT_71CHN16)
speakers = DSSPEAKER_COMBINED(DSSPEAKER_7POINT1, 0);
else
hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
AL_PRINT("Unknown format: 0x%x\n", device->Format);
return ALC_FALSE;
}
}
if(SUCCEEDED(hr))
@@ -197,23 +249,29 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
if(speakers == DSSPEAKER_MONO)
{
if(aluBytesFromFormat(device->Format) == 1)
device->Format = AL_FORMAT_MONO8;
else
device->Format = AL_FORMAT_MONO16;
format = AL_FORMAT_MONO8;
else if(aluBytesFromFormat(device->Format) == 2)
format = AL_FORMAT_MONO16;
else if(aluBytesFromFormat(device->Format) == 4)
format = AL_FORMAT_MONO_FLOAT32;
}
else if(speakers == DSSPEAKER_STEREO)
{
if(aluBytesFromFormat(device->Format) == 1)
device->Format = AL_FORMAT_STEREO8;
else
device->Format = AL_FORMAT_STEREO16;
format = AL_FORMAT_STEREO8;
else if(aluBytesFromFormat(device->Format) == 2)
format = AL_FORMAT_STEREO16;
else if(aluBytesFromFormat(device->Format) == 4)
format = AL_FORMAT_STEREO_FLOAT32;
}
else if(speakers == DSSPEAKER_QUAD)
{
if(aluBytesFromFormat(device->Format) == 1)
device->Format = AL_FORMAT_QUAD8;
else
device->Format = AL_FORMAT_QUAD16;
format = AL_FORMAT_QUAD8;
else if(aluBytesFromFormat(device->Format) == 2)
format = AL_FORMAT_QUAD16;
else if(aluBytesFromFormat(device->Format) == 4)
format = AL_FORMAT_QUAD32;
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_BACK_LEFT |
@@ -222,9 +280,11 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
else if(speakers == DSSPEAKER_5POINT1)
{
if(aluBytesFromFormat(device->Format) == 1)
device->Format = AL_FORMAT_51CHN8;
else
device->Format = AL_FORMAT_51CHN16;
format = AL_FORMAT_51CHN8;
else if(aluBytesFromFormat(device->Format) == 2)
format = AL_FORMAT_51CHN16;
else if(aluBytesFromFormat(device->Format) == 4)
format = AL_FORMAT_51CHN32;
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
@@ -235,9 +295,11 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
else if(speakers == DSSPEAKER_7POINT1)
{
if(aluBytesFromFormat(device->Format) == 1)
device->Format = AL_FORMAT_71CHN8;
else
device->Format = AL_FORMAT_71CHN16;
format = AL_FORMAT_71CHN8;
else if(aluBytesFromFormat(device->Format) == 2)
format = AL_FORMAT_71CHN16;
else if(aluBytesFromFormat(device->Format) == 4)
format = AL_FORMAT_71CHN32;
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
@@ -247,26 +309,28 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
}
frameSize = aluBytesFromFormat(device->Format) *
aluChannelsFromFormat(device->Format);
else
format = device->Format;
frameSize = aluBytesFromFormat(format) * aluChannelsFromFormat(format);
OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
OutputType.Format.nChannels = aluChannelsFromFormat(device->Format);
OutputType.Format.wBitsPerSample = aluBytesFromFormat(device->Format) * 8;
OutputType.Format.nChannels = aluChannelsFromFormat(format);
OutputType.Format.wBitsPerSample = aluBytesFromFormat(format) * 8;
OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
OutputType.Format.nSamplesPerSec = device->Frequency;
OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
OutputType.Format.cbSize = 0;
device->UpdateSize /= DS_FRAGS;
}
if(OutputType.Format.nChannels > 2)
if(OutputType.Format.nChannels > 2 || OutputType.Format.wBitsPerSample > 16)
{
OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
OutputType.Format.cbSize = 22;
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
if(OutputType.Format.wBitsPerSample == 32)
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
else
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
}
else
{
@@ -286,7 +350,7 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
DSBDescription.dwSize=sizeof(DSBUFFERDESC);
DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
DSBDescription.dwBufferBytes=device->UpdateSize * DS_FRAGS * frameSize;
DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates * frameSize;
DSBDescription.lpwfxFormat=&OutputType.Format;
hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
}
@@ -306,42 +370,41 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
{
if (pData->DSsbuffer)
IDirectSoundBuffer_Release(pData->DSsbuffer);
pData->DSsbuffer = NULL;
if (pData->DSpbuffer)
IDirectSoundBuffer_Release(pData->DSpbuffer);
if (pData->lpDS)
IDirectSound_Release(pData->lpDS);
free(pData);
pData->DSpbuffer = NULL;
return ALC_FALSE;
}
device->Format = format;
return ALC_TRUE;
}
static void DSoundClosePlayback(ALCdevice *device)
static void DSoundStopPlayback(ALCdevice *device)
{
DSoundData *pData = device->ExtraData;
if(!pData->thread)
return;
pData->killNow = 1;
StopThread(pData->thread);
pData->thread = NULL;
IDirectSoundBuffer_Release(pData->DSsbuffer);
pData->DSsbuffer = NULL;
if (pData->DSpbuffer)
IDirectSoundBuffer_Release(pData->DSpbuffer);
IDirectSound_Release(pData->lpDS);
free(pData);
device->ExtraData = NULL;
pData->DSpbuffer = NULL;
}
static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
{
(void)pDevice;
(void)deviceName;
(void)frequency;
(void)format;
(void)SampleSize;
return ALC_FALSE;
}
@@ -377,6 +440,8 @@ static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
BackendFuncs DSoundFuncs = {
DSoundOpenPlayback,
DSoundClosePlayback,
DSoundResetPlayback,
DSoundStopPlayback,
DSoundOpenCapture,
DSoundCloseCapture,
DSoundStartCapture,
@@ -387,31 +452,100 @@ BackendFuncs DSoundFuncs = {
static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
{
size_t *iter = data;
(void)data;
(void)drvname;
if(guid)
{
char str[128];
snprintf(str, sizeof(str), "DirectSound Software on %s", desc);
DeviceList[*iter].name = AppendAllDeviceList(str);
DeviceList[*iter].guid = *guid;
(*iter)++;
void *temp;
temp = realloc(DeviceList, sizeof(DevMap) * (NumDevices+1));
if(temp)
{
DeviceList = temp;
snprintf(str, sizeof(str), "DirectSound Software on %s", desc);
AppendAllDeviceList(str);
DeviceList[NumDevices].name = strdup(str);
DeviceList[NumDevices].guid = *guid;
NumDevices++;
}
}
else
DeviceList[0].name = AppendDeviceList("DirectSound Software");
return TRUE;
}
void alcDSoundInit(BackendFuncs *FuncList)
{
size_t iter = 1;
HRESULT hr;
if(FuncList) *FuncList = DSoundFuncs;
*FuncList = DSoundFuncs;
#ifdef _WIN32
ds_handle = LoadLibraryA("dsound.dll");
if(ds_handle == NULL)
{
AL_PRINT("Failed to load dsound.dll\n");
return;
}
hr = DirectSoundEnumerate(DSoundEnumDevices, &iter);
if(FAILED(hr))
AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
#define LOAD_FUNC(f) do { \
p##f = (void*)GetProcAddress((HMODULE)ds_handle, #f); \
if(p##f == NULL) \
{ \
FreeLibrary(ds_handle); \
ds_handle = NULL; \
AL_PRINT("Could not load %s from dsound.dll\n", #f); \
return; \
} \
} while(0)
#else
ds_handle = (void*)0xDEADBEEF;
#define LOAD_FUNC(f) p##f = f
#endif
LOAD_FUNC(DirectSoundCreate);
LOAD_FUNC(DirectSoundEnumerateA);
#undef LOAD_FUNC
}
void alcDSoundDeinit(void)
{
ALuint i;
for(i = 0;i < NumDevices;++i)
free(DeviceList[i].name);
free(DeviceList);
DeviceList = NULL;
NumDevices = 0;
#ifdef _WIN32
if(ds_handle)
FreeLibrary(ds_handle);
#endif
ds_handle = NULL;
}
void alcDSoundProbe(int type)
{
if(!ds_handle) alcDSoundInit(NULL);
if(!ds_handle) return;
if(type == DEVICE_PROBE)
AppendDeviceList(dsDevice);
else if(type == ALL_DEVICE_PROBE)
{
HRESULT hr;
ALuint i;
for(i = 0;i < NumDevices;++i)
free(DeviceList[i].name);
free(DeviceList);
DeviceList = NULL;
NumDevices = 0;
hr = pDirectSoundEnumerateA(DSoundEnumDevices, NULL);
if(FAILED(hr))
AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
}
}
-458
View File
@@ -1,458 +0,0 @@
/* ----------------- file filterIIR00.c begin ----------------- */
/*
Resonant low pass filter source code.
By baltrax@hotmail.com (Zxform)
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "alMain.h"
#include "alFilter.h"
static void szxform(
double *a0, double *a1, double *a2, /* numerator coefficients */
double *b0, double *b1, double *b2, /* denominator coefficients */
double fc, /* Filter cutoff frequency */
double fs, /* sampling rate */
double *k, /* overall gain factor */
float *coef); /* pointer to 4 iir coefficients */
/*
* --------------------------------------------------------------------
*
* lpFilter - Perform IIR filtering sample by sample on floats
*
* Implements cascaded direct form II second order sections.
* Requires FILTER structure for history and coefficients.
* The size of the history array is 2*FILTER_SECTIONS.
* The size of the coefficient array is 4*FILTER_SECTIONS + 1 because
* the first coefficient is the overall scale factor for the filter.
* Returns one output sample for each input sample.
*
* float lpFilter(FILTER *iir,float input)
*
* FILTER *iir pointer to FILTER structure
* float input new float input sample
*
* Returns float value giving the current output.
* --------------------------------------------------------------------
*/
/*** moved to ALu.c ***/
/*
* --------------------------------------------------------------------
*
* InitLowPassFilter()
*
* Initialize filter coefficients.
* We create a 4th order filter (24 db/oct rolloff), consisting
* of two second order sections.
* --------------------------------------------------------------------
*/
int InitLowPassFilter(ALCcontext *Context, FILTER *iir)
{
float *coef;
double fs, fc; /* Sampling frequency, cutoff frequency */
double Q; /* Resonance > 1.0 < 1000 */
unsigned nInd;
double a0, a1, a2, b0, b1, b2;
double k; /* overall gain factor */
struct {
double a0, a1, a2; /* numerator coefficients */
double b0, b1, b2; /* denominator coefficients */
} ProtoCoef[FILTER_SECTIONS]; /* Filter prototype coefficients,
1 for each filter section */
/*
* Setup filter s-domain coefficients
*/
/* Section 1 */
ProtoCoef[0].a0 = 1.0;
ProtoCoef[0].a1 = 0;
ProtoCoef[0].a2 = 0;
ProtoCoef[0].b0 = 1.0;
ProtoCoef[0].b1 = 0.765367;
ProtoCoef[0].b2 = 1.0;
/* Section 2 */
ProtoCoef[1].a0 = 1.0;
ProtoCoef[1].a1 = 0;
ProtoCoef[1].a2 = 0;
ProtoCoef[1].b0 = 1.0;
ProtoCoef[1].b1 = 1.847759;
ProtoCoef[1].b2 = 1.0;
/* Clear the coefficient and history arrays */
memset(iir->coef, 0, sizeof(iir->coef));
memset(iir->history, 0, sizeof(iir->history));
k = 1.0; /* Set overall filter gain */
coef = iir->coef + 1; /* Skip k, or gain */
Q = 1; /* Resonance */
fc = LOWPASSFREQCUTOFF; /* Filter cutoff (Hz) */
fs = Context->Frequency; /* Sampling frequency (Hz) */
/*
* Compute z-domain coefficients for each biquad section
* for new Cutoff Frequency and Resonance
*/
for (nInd = 0; nInd < FILTER_SECTIONS; nInd++)
{
a0 = ProtoCoef[nInd].a0;
a1 = ProtoCoef[nInd].a1;
a2 = ProtoCoef[nInd].a2;
b0 = ProtoCoef[nInd].b0;
b1 = ProtoCoef[nInd].b1 / Q; /* Divide by resonance or Q */
b2 = ProtoCoef[nInd].b2;
szxform(&a0, &a1, &a2, &b0, &b1, &b2, fc, fs, &k, coef);
coef += 4; /* Point to next filter section */
}
/* Update overall filter gain in coef array */
iir->coef[0] = k;
return 0;
}
/* ----------------- file filterIIR00.c end ----------------- */
/* ----------------- file bilinear.c begin ----------------- */
/*
* ----------------------------------------------------------
* bilinear.c
*
* Perform bilinear transformation on s-domain coefficients
* of 2nd order biquad section.
* First design an analog filter and use s-domain coefficients
* as input to szxform() to convert them to z-domain.
*
* Here's the butterworth polinomials for 2nd, 4th and 6th order sections.
* When we construct a 24 db/oct filter, we take to 2nd order
* sections and compute the coefficients separately for each section.
*
* n Polinomials
* --------------------------------------------------------------------
* 2 s^2 + 1.4142s +1
* 4 (s^2 + 0.765367s + 1) (s^2 + 1.847759s + 1)
* 6 (s^2 + 0.5176387s + 1) (s^2 + 1.414214 + 1) (s^2 + 1.931852s + 1)
*
* Where n is a filter order.
* For n=4, or two second order sections, we have following equasions for each
* 2nd order stage:
*
* (1 / (s^2 + (1/Q) * 0.765367s + 1)) * (1 / (s^2 + (1/Q) * 1.847759s + 1))
*
* Where Q is filter quality factor in the range of
* 1 to 1000. The overall filter Q is a product of all
* 2nd order stages. For example, the 6th order filter
* (3 stages, or biquads) with individual Q of 2 will
* have filter Q = 2 * 2 * 2 = 8.
*
* The nominator part is just 1.
* The denominator coefficients for stage 1 of filter are:
* b2 = 1; b1 = 0.765367; b0 = 1;
* numerator is
* a2 = 0; a1 = 0; a0 = 1;
*
* The denominator coefficients for stage 1 of filter are:
* b2 = 1; b1 = 1.847759; b0 = 1;
* numerator is
* a2 = 0; a1 = 0; a0 = 1;
*
* These coefficients are used directly by the szxform()
* and bilinear() functions. For all stages the numerator
* is the same and the only thing that is different between
* different stages is 1st order coefficient. The rest of
* coefficients are the same for any stage and equal to 1.
*
* Any filter could be constructed using this approach.
*
* References:
* Van Valkenburg, "Analog Filter Design"
* Oxford University Press 1982
* ISBN 0-19-510734-9
*
* C Language Algorithms for Digital Signal Processing
* Paul Embree, Bruce Kimble
* Prentice Hall, 1991
* ISBN 0-13-133406-9
*
* Digital Filter Designer's Handbook
* With C++ Algorithms
* Britton Rorabaugh
* McGraw Hill, 1997
* ISBN 0-07-053806-9
* ----------------------------------------------------------
*/
static void prewarp(double *a0, double *a1, double *a2, double fc, double fs);
static void bilinear(
double a0, double a1, double a2, /* numerator coefficients */
double b0, double b1, double b2, /* denominator coefficients */
double *k, /* overall gain factor */
double fs, /* sampling rate */
float *coef); /* pointer to 4 iir coefficients */
/*
* ----------------------------------------------------------
* Pre-warp the coefficients of a numerator or denominator.
* Note that a0 is assumed to be 1, so there is no wrapping
* of it.
* ----------------------------------------------------------
*/
static void prewarp(
double *a0, double *a1, double *a2,
double fc, double fs)
{
double wp, pi;
pi = 4.0 * atan(1.0);
wp = 2.0 * fs * tan(pi * fc / fs);
*a2 = (*a2) / (wp * wp);
*a1 = (*a1) / wp;
(void)a0;
}
/*
* ----------------------------------------------------------
* bilinear()
*
* Transform the numerator and denominator coefficients
* of s-domain biquad section into corresponding
* z-domain coefficients.
*
* Store the 4 IIR coefficients in array pointed by coef
* in following order:
* beta1, beta2 (denominator)
* alpha1, alpha2 (numerator)
*
* Arguments:
* a0-a2 - s-domain numerator coefficients
* b0-b2 - s-domain denominator coefficients
* k - filter gain factor. initially set to 1
* and modified by each biquad section in such
* a way, as to make it the coefficient by
* which to multiply the overall filter gain
* in order to achieve a desired overall filter gain,
* specified in initial value of k.
* fs - sampling rate (Hz)
* coef - array of z-domain coefficients to be filled in.
*
* Return:
* On return, set coef z-domain coefficients
* ----------------------------------------------------------
*/
static void bilinear(
double a0, double a1, double a2, /* numerator coefficients */
double b0, double b1, double b2, /* denominator coefficients */
double *k, /* overall gain factor */
double fs, /* sampling rate */
float *coef /* pointer to 4 iir coefficients */
)
{
double ad, bd;
/* alpha (Numerator in s-domain) */
ad = 4. * a2 * fs * fs + 2. * a1 * fs + a0;
/* beta (Denominator in s-domain) */
bd = 4. * b2 * fs * fs + 2. * b1* fs + b0;
/* update gain constant for this section */
*k *= ad/bd;
/* Denominator */
*coef++ = (2.*b0 - 8.*b2*fs*fs) / bd; /* beta1 */
*coef++ = (4.*b2*fs*fs - 2.*b1*fs + b0) / bd; /* beta2 */
/* Nominator */
*coef++ = (2.*a0 - 8.*a2*fs*fs) / ad; /* alpha1 */
*coef = (4.*a2*fs*fs - 2.*a1*fs + a0) / ad; /* alpha2 */
}
/*
* ----------------------------------------------------------
* Transform from s to z domain using bilinear transform
* with prewarp.
*
* Arguments:
* For argument description look at bilinear()
*
* coef - pointer to array of floating point coefficients,
* corresponding to output of bilinear transofrm
* (z domain).
*
* Note: frequencies are in Hz.
* ----------------------------------------------------------
*/
static void szxform(
double *a0, double *a1, double *a2, /* numerator coefficients */
double *b0, double *b1, double *b2, /* denominator coefficients */
double fc, /* Filter cutoff frequency */
double fs, /* sampling rate */
double *k, /* overall gain factor */
float *coef) /* pointer to 4 iir coefficients */
{
/* Calculate a1 and a2 and overwrite the original values */
prewarp(a0, a1, a2, fc, fs);
prewarp(b0, b1, b2, fc, fs);
bilinear(*a0, *a1, *a2, *b0, *b1, *b2, k, fs, coef);
}
/* ----------------- file bilinear.c end ----------------- */
/* ----------------- file filter.txt begin -----------------
How to construct a kewl low pass resonant filter?
Lets assume we want to create a filter for analog synth.
The filter rolloff is 24 db/oct, which corresponds to 4th
order filter. Filter of first order is equivalent to RC circuit
and has max rolloff of 6 db/oct.
We will use classical Butterworth IIR filter design, as it
exactly corresponds to our requirements.
A common practice is to chain several 2nd order sections,
or biquads, as they commonly called, in order to achive a higher
order filter. Each 2nd order section is a 2nd order filter, which
has 12 db/oct roloff. So, we need 2 of those sections in series.
To compute those sections, we use standard Butterworth polinomials,
or so called s-domain representation and convert it into z-domain,
or digital domain. The reason we need to do this is because
the filter theory exists for analog filters for a long time
and there exist no theory of working in digital domain directly.
So the common practice is to take standard analog filter design
and use so called bilinear transform to convert the butterworth
equasion coefficients into z-domain.
Once we compute the z-domain coefficients, we can use them in
a very simple transfer function, such as iir_filter() in our
C source code, in order to perform the filtering function.
The filter itself is the simpliest thing in the world.
The most complicated thing is computing the coefficients
for z-domain.
Ok, lets look at butterworth polynomials, arranged as a series
of 2nd order sections:
* Note: n is filter order.
*
* n Polynomials
* --------------------------------------------------------------------
* 2 s^2 + 1.4142s +1
* 4 (s^2 + 0.765367s + 1) * (s^2 + 1.847759s + 1)
* 6 (s^2 + 0.5176387s + 1) * (s^2 + 1.414214 + 1) * (s^2 + 1.931852s + 1)
*
* For n=4 we have following equasion for the filter transfer function:
*
* 1 1
* T(s) = --------------------------- * ----------------------------
* s^2 + (1/Q) * 0.765367s + 1 s^2 + (1/Q) * 1.847759s + 1
*
The filter consists of two 2nd order secions since highest s power is 2.
Now we can take the coefficients, or the numbers by which s is multiplied
and plug them into a standard formula to be used by bilinear transform.
Our standard form for each 2nd order secion is:
a2 * s^2 + a1 * s + a0
H(s) = ----------------------
b2 * s^2 + b1 * s + b0
Note that butterworth nominator is 1 for all filter sections,
which means s^2 = 0 and s^1 = 0
Lets convert standard butterworth polinomials into this form:
0 + 0 + 1 0 + 0 + 1
-------------------------- * --------------------------
1 + ((1/Q) * 0.765367) + 1 1 + ((1/Q) * 1.847759) + 1
Section 1:
a2 = 0; a1 = 0; a0 = 1;
b2 = 1; b1 = 0.5176387; b0 = 1;
Section 2:
a2 = 0; a1 = 0; a0 = 1;
b2 = 1; b1 = 1.847759; b0 = 1;
That Q is filter quality factor or resonance, in the range of
1 to 1000. The overall filter Q is a product of all 2nd order stages.
For example, the 6th order filter (3 stages, or biquads)
with individual Q of 2 will have filter Q = 2 * 2 * 2 = 8.
These a and b coefficients are used directly by the szxform()
and bilinear() functions.
The transfer function for z-domain is:
1 + alpha1 * z^(-1) + alpha2 * z^(-2)
H(z) = -------------------------------------
1 + beta1 * z^(-1) + beta2 * z^(-2)
When you need to change the filter frequency cutoff or resonance,
or Q, you call the szxform() function with proper a and b
coefficients and the new filter cutoff frequency or resonance.
You also need to supply the sampling rate and filter gain you want
to achive. For our purposes the gain = 1.
We call szxform() function 2 times becase we have 2 filter sections.
Each call provides different coefficients.
The gain argument to szxform() is a pointer to desired filter
gain variable.
double k = 1.0; // overall gain factor
Upon return from each call, the k argument will be set to a value,
by which to multiply our actual signal in order for the gain
to be one. On second call to szxform() we provide k that was
changed by the previous section. During actual audio filtering
function iir_filter() will use this k
Summary:
Our filter is pretty close to ideal in terms of all relevant
parameters and filter stability even with extremely large values
of resonance. This filter design has been verified under all
variations of parameters and it all appears to work as advertized.
Good luck with it.
If you ever make a directX wrapper for it, post it to comp.dsp.
*
* ----------------------------------------------------------
*References:
*Van Valkenburg, "Analog Filter Design"
*Oxford University Press 1982
*ISBN 0-19-510734-9
*
*C Language Algorithms for Digital Signal Processing
*Paul Embree, Bruce Kimble
*Prentice Hall, 1991
*ISBN 0-13-133406-9
*
*Digital Filter Designer's Handbook
*With C++ Algorithms
*Britton Rorabaugh
*McGraw Hill, 1997
*ISBN 0-07-053806-9
* ----------------------------------------------------------
// ----------------- file filter.txt end ----------------- */
+118 -84
View File
@@ -47,8 +47,8 @@
#define SOUND_MIXER_WRITE MIXER_WRITE
#endif
static char *oss_device;
static char *oss_device_capture;
static const ALCchar oss_device[] = "OSS Software";
static const ALCchar oss_device_capture[] = "OSS Capture";
typedef struct {
int fd;
@@ -79,35 +79,37 @@ static ALuint OSSProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
oss_data *data = (oss_data*)pDevice->ExtraData;
int remaining = 0;
ALint frameSize;
int wrote;
while(!data->killNow)
frameSize = aluChannelsFromFormat(pDevice->Format) *
aluBytesFromFormat(pDevice->Format);
while(!data->killNow && !pDevice->Connected)
{
int len = data->data_size - remaining;
ALint len = data->data_size;
ALubyte *WritePtr = data->mix_data;
if(len > 0)
aluMixData(pDevice, WritePtr, len/frameSize);
while(len > 0 && !data->killNow)
{
SuspendContext(NULL);
aluMixData(pDevice->Context, data->mix_data+remaining, len, pDevice->Format);
ProcessContext(NULL);
}
wrote = write(data->fd, WritePtr, len);
if(wrote < 0)
{
if(errno != EAGAIN && errno != EWOULDBLOCK)
{
AL_PRINT("write failed: %s\n", strerror(errno));
aluHandleDisconnect(pDevice);
len = 0;
}
else
Sleep(1);
continue;
}
remaining += len;
wrote = write(data->fd, data->mix_data, remaining);
if(wrote < 0)
{
AL_PRINT("write failed: %s\n", strerror(errno));
remaining = 0;
len -= wrote;
WritePtr += wrote;
}
else if(wrote > 0)
{
remaining -= wrote;
if(remaining > 0)
memmove(data->mix_data, data->mix_data+wrote, remaining);
}
else
Sleep(1);
}
return 0;
@@ -129,6 +131,7 @@ static ALuint OSSCaptureProc(ALvoid *ptr)
if(amt < 0)
{
AL_PRINT("read failed: %s\n", strerror(errno));
aluHandleDisconnect(pDevice);
break;
}
if(amt == 0)
@@ -145,29 +148,15 @@ static ALuint OSSCaptureProc(ALvoid *ptr)
static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
int numFragmentsLogSize;
int log2FragmentSize;
unsigned int periods;
audio_buf_info info;
ALuint frameSize;
char driver[64];
int numChannels;
oss_data *data;
int ossFormat;
int ossSpeed;
char *err;
int i;
strncpy(driver, GetConfigValue("oss", "device", "/dev/dsp"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(deviceName)
{
if(strcmp(deviceName, oss_device))
return ALC_FALSE;
device->szDeviceName = oss_device;
}
else
device->szDeviceName = oss_device;
if(!deviceName)
deviceName = oss_device;
else if(strcmp(deviceName, oss_device) != 0)
return ALC_FALSE;
data = (oss_data*)calloc(1, sizeof(oss_data));
data->killNow = 0;
@@ -180,31 +169,71 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
return ALC_FALSE;
}
device->szDeviceName = strdup(deviceName);
device->ExtraData = data;
return ALC_TRUE;
}
static void oss_close_playback(ALCdevice *device)
{
oss_data *data = (oss_data*)device->ExtraData;
close(data->fd);
free(data);
device->ExtraData = NULL;
}
static ALCboolean oss_reset_playback(ALCdevice *device)
{
oss_data *data = (oss_data*)device->ExtraData;
int numFragmentsLogSize;
int log2FragmentSize;
unsigned int periods;
audio_buf_info info;
ALuint frameSize;
int numChannels;
int ossFormat;
int ossSpeed;
char *err;
int i;
switch(aluBytesFromFormat(device->Format))
{
case 1:
ossFormat = AFMT_U8;
break;
case 4:
switch(aluChannelsFromFormat(device->Format))
{
case 1: device->Format = AL_FORMAT_MONO16; break;
case 2: device->Format = AL_FORMAT_STEREO16; break;
case 4: device->Format = AL_FORMAT_QUAD16; break;
case 6: device->Format = AL_FORMAT_51CHN16; break;
case 7: device->Format = AL_FORMAT_61CHN16; break;
case 8: device->Format = AL_FORMAT_71CHN16; break;
}
/* fall-through */
case 2:
ossFormat = AFMT_S16_NE;
break;
default:
ossFormat = -1;
AL_PRINT("Unknown format?! %x\n", device->Format);
AL_PRINT("Unknown format: 0x%x\n", device->Format);
return ALC_FALSE;
}
periods = GetConfigValueInt("oss", "periods", 4);
if((int)periods <= 0)
periods = 4;
periods = device->NumUpdates;
numChannels = aluChannelsFromFormat(device->Format);
frameSize = numChannels * aluBytesFromFormat(device->Format);
ossSpeed = device->Frequency;
log2FragmentSize = log2i(device->UpdateSize * frameSize / periods);
log2FragmentSize = log2i(device->UpdateSize * frameSize);
/* according to the OSS spec, 16 bytes are the minimum */
if (log2FragmentSize < 4)
log2FragmentSize = 4;
/* Subtract one period since the temp mixing buffer counts as one. Still
* need at least two on the card, though. */
if(periods > 2) periods--;
numFragmentsLogSize = (periods << 16) | log2FragmentSize;
#define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1))
@@ -215,19 +244,13 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
ok(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info), "get space")))
{
AL_PRINT("%s failed: %s\n", err, strerror(errno));
close(data->fd);
free(data);
return ALC_FALSE;
}
#undef ok
device->Frequency = ossSpeed;
if((int)aluChannelsFromFormat(device->Format) != numChannels)
{
AL_PRINT("Could not set %d channels, got %d instead\n", aluChannelsFromFormat(device->Format), numChannels);
close(data->fd);
free(data);
return ALC_FALSE;
}
@@ -235,44 +258,44 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
(ossFormat == AFMT_S16_NE && aluBytesFromFormat(device->Format) == 2)))
{
AL_PRINT("Could not set %d-bit output, got format %#x\n", aluBytesFromFormat(device->Format)*8, ossFormat);
close(data->fd);
free(data);
return ALC_FALSE;
}
device->Frequency = ossSpeed;
device->UpdateSize = info.fragsize / frameSize;
device->NumUpdates = info.fragments + 1;
data->data_size = device->UpdateSize * frameSize;
data->mix_data = calloc(1, data->data_size);
device->ExtraData = data;
data->thread = StartThread(OSSProc, device);
if(data->thread == NULL)
{
device->ExtraData = NULL;
free(data->mix_data);
free(data);
data->mix_data = NULL;
return ALC_FALSE;
}
return ALC_TRUE;
}
static void oss_close_playback(ALCdevice *device)
static void oss_stop_playback(ALCdevice *device)
{
oss_data *data = (oss_data*)device->ExtraData;
if(!data->thread)
return;
data->killNow = 1;
StopThread(data->thread);
close(data->fd);
data->thread = NULL;
free(data->mix_data);
free(data);
device->ExtraData = NULL;
data->mix_data = NULL;
}
static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
{
int numFragmentsLogSize;
int log2FragmentSize;
@@ -289,14 +312,10 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName,
strncpy(driver, GetConfigValue("oss", "capture", "/dev/dsp"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(deviceName)
{
if(strcmp(deviceName, oss_device_capture))
return ALC_FALSE;
device->szDeviceName = oss_device_capture;
}
else
device->szDeviceName = oss_device_capture;
if(!deviceName)
deviceName = oss_device_capture;
else if(strcmp(deviceName, oss_device_capture) != 0)
return ALC_FALSE;
data = (oss_data*)calloc(1, sizeof(oss_data));
data->killNow = 0;
@@ -309,7 +328,7 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName,
return ALC_FALSE;
}
switch(aluBytesFromFormat(format))
switch(aluBytesFromFormat(device->Format))
{
case 1:
ossFormat = AFMT_U8;
@@ -318,15 +337,18 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName,
ossFormat = AFMT_S16_NE;
break;
default:
ossFormat = -1;
AL_PRINT("Unknown format?! %x\n", device->Format);
AL_PRINT("Unknown format: 0x%x\n", device->Format);
close(data->fd);
free(data);
return ALC_FALSE;
}
periods = 4;
numChannels = aluChannelsFromFormat(device->Format);
frameSize = numChannels * aluBytesFromFormat(device->Format);
ossSpeed = frequency;
log2FragmentSize = log2i(SampleSize * frameSize / periods);
ossSpeed = device->Frequency;
log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
frameSize / periods);
/* according to the OSS spec, 16 bytes are the minimum */
if (log2FragmentSize < 4)
@@ -364,7 +386,7 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName,
return ALC_FALSE;
}
data->ring = CreateRingBuffer(frameSize, SampleSize);
data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates);
if(!data->ring)
{
AL_PRINT("ring buffer create failed\n");
@@ -386,6 +408,7 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName,
return ALC_FALSE;
}
device->szDeviceName = strdup(deviceName);
return ALC_TRUE;
}
@@ -435,6 +458,8 @@ static ALCuint oss_available_samples(ALCdevice *pDevice)
BackendFuncs oss_funcs = {
oss_open_playback,
oss_close_playback,
oss_reset_playback,
oss_stop_playback,
oss_open_capture,
oss_close_capture,
oss_start_capture,
@@ -446,9 +471,18 @@ BackendFuncs oss_funcs = {
void alc_oss_init(BackendFuncs *func_list)
{
*func_list = oss_funcs;
oss_device = AppendDeviceList("OSS Software");
AppendAllDeviceList(oss_device);
oss_device_capture = AppendCaptureDeviceList("OSS Capture");
}
void alc_oss_deinit(void)
{
}
void alc_oss_probe(int type)
{
if(type == DEVICE_PROBE)
AppendDeviceList(oss_device);
else if(type == ALL_DEVICE_PROBE)
AppendAllDeviceList(oss_device);
else if(type == CAPTURE_DEVICE_PROBE)
AppendCaptureDeviceList(oss_device_capture);
}
+271
View File
@@ -0,0 +1,271 @@
/**
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, 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 "AL/al.h"
#include "AL/alc.h"
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#include <portaudio.h>
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_GetStreamInfo);
#undef MAKE_FUNC
static const ALCchar pa_device[] = "PortAudio Software";
typedef struct {
PaStream *stream;
} pa_data;
static int pa_callback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
const PaStreamCallbackFlags statusFlags, void *userData)
{
ALCdevice *device = (ALCdevice*)userData;
(void)inputBuffer;
(void)timeInfo;
(void)statusFlags;
aluMixData(device, outputBuffer, framesPerBuffer);
return 0;
}
static ALCboolean pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
const PaStreamInfo *streamInfo;
PaStreamParameters outParams;
pa_data *data;
PaError err;
if(pa_handle == NULL)
return ALC_FALSE;
if(!deviceName)
deviceName = pa_device;
else if(strcmp(deviceName, pa_device) != 0)
return ALC_FALSE;
data = (pa_data*)calloc(1, sizeof(pa_data));
device->ExtraData = data;
outParams.device = GetConfigValueInt("port", "device", -1);
if(outParams.device < 0)
outParams.device = pPa_GetDefaultOutputDevice();
outParams.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
(float)device->Frequency;
outParams.hostApiSpecificStreamInfo = NULL;
switch(aluBytesFromFormat(device->Format))
{
case 1:
outParams.sampleFormat = paUInt8;
break;
case 2:
outParams.sampleFormat = paInt16;
break;
case 4:
outParams.sampleFormat = paFloat32;
break;
default:
AL_PRINT("Unknown format: 0x%x\n", device->Format);
device->ExtraData = NULL;
free(data);
return ALC_FALSE;
}
outParams.channelCount = aluChannelsFromFormat(device->Format);
err = pPa_OpenStream(&data->stream, NULL, &outParams, device->Frequency,
device->UpdateSize, paNoFlag, pa_callback, device);
if(err != paNoError)
{
AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err));
device->ExtraData = NULL;
free(data);
return ALC_FALSE;
}
streamInfo = pPa_GetStreamInfo(data->stream);
err = pPa_StartStream(data->stream);
if(err != paNoError)
{
AL_PRINT("Pa_StartStream() returned an error: %s\n", pPa_GetErrorText(err));
pPa_CloseStream(data->stream);
device->ExtraData = NULL;
free(data);
return ALC_FALSE;
}
device->szDeviceName = strdup(deviceName);
device->Frequency = streamInfo->sampleRate;
return ALC_TRUE;
}
static void pa_close_playback(ALCdevice *device)
{
pa_data *data = (pa_data*)device->ExtraData;
PaError err;
err = pPa_StopStream(data->stream);
if(err != paNoError)
fprintf(stderr, "Error stopping stream: %s\n", pPa_GetErrorText(err));
err = pPa_CloseStream(data->stream);
if(err != paNoError)
fprintf(stderr, "Error closing stream: %s\n", pPa_GetErrorText(err));
free(data);
device->ExtraData = NULL;
}
static ALCboolean pa_reset_playback(ALCdevice *device)
{
pa_data *data = (pa_data*)device->ExtraData;
const PaStreamInfo *streamInfo;
streamInfo = pPa_GetStreamInfo(data->stream);
device->Frequency = streamInfo->sampleRate;
return ALC_TRUE;
}
static void pa_stop_playback(ALCdevice *device)
{
(void)device;
}
static ALCboolean pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
{
return ALC_FALSE;
(void)device;
(void)deviceName;
}
static const BackendFuncs pa_funcs = {
pa_open_playback,
pa_close_playback,
pa_reset_playback,
pa_stop_playback,
pa_open_capture,
NULL,
NULL,
NULL,
NULL,
NULL
};
void alc_pa_init(BackendFuncs *func_list)
{
const char *str;
PaError err;
if(func_list) *func_list = pa_funcs;
#ifdef HAVE_DLFCN_H
#if defined(__APPLE__) && defined(__MACH__)
# define PALIB "libportaudio.2.dylib"
#else
# define PALIB "libportaudio.so.2"
#endif
pa_handle = dlopen(PALIB, RTLD_NOW);
if(!pa_handle)
return;
dlerror();
#define LOAD_FUNC(f) do { \
p##f = (typeof(f)*)dlsym(pa_handle, #f); \
if((str=dlerror()) != NULL) \
{ \
dlclose(pa_handle); \
pa_handle = NULL; \
AL_PRINT("Could not load %s from "PALIB": %s\n", #f, str); \
return; \
} \
} while(0)
#else
str = NULL;
pa_handle = (void*)0xDEADBEEF;
#define LOAD_FUNC(f) p##f = f
#endif
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_GetStreamInfo);
#undef LOAD_FUNC
if((err=pPa_Initialize()) != paNoError)
{
AL_PRINT("Pa_Initialize() returned an error: %s\n", pPa_GetErrorText(err));
alc_pa_deinit();
return;
}
}
void alc_pa_deinit(void)
{
if(pa_handle)
{
pPa_Terminate();
#ifdef HAVE_DLFCN_H
dlclose(pa_handle);
pa_handle = NULL;
#endif
}
}
void alc_pa_probe(int type)
{
if(!pa_handle) alc_pa_init(NULL);
if(!pa_handle) return;
if(type == DEVICE_PROBE)
AppendDeviceList(pa_device);
else if(type == ALL_DEVICE_PROBE)
AppendAllDeviceList(pa_device);
}
+671
View File
@@ -0,0 +1,671 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2009 by Konstantinos Natsakis <konstantinos.natsakis@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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include "alMain.h"
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#include <pulse/pulseaudio.h>
#if PA_API_VERSION == 11
#define PA_STREAM_ADJUST_LATENCY 0x2000U
static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
{
return (x == PA_STREAM_CREATING || x == PA_STREAM_READY);
}
static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
{
return (x == PA_CONTEXT_CONNECTING || x == PA_CONTEXT_AUTHORIZING ||
x == PA_CONTEXT_SETTING_NAME || x == PA_CONTEXT_READY);
}
#define PA_STREAM_IS_GOOD PA_STREAM_IS_GOOD
#define PA_CONTEXT_IS_GOOD PA_CONTEXT_IS_GOOD
#elif PA_API_VERSION != 12
#error Invalid PulseAudio API version
#endif
static void *pa_handle;
#define MAKE_FUNC(x) static typeof(x) * p##x
MAKE_FUNC(pa_context_unref);
MAKE_FUNC(pa_sample_spec_valid);
MAKE_FUNC(pa_stream_drop);
MAKE_FUNC(pa_strerror);
MAKE_FUNC(pa_context_get_state);
MAKE_FUNC(pa_stream_get_state);
MAKE_FUNC(pa_threaded_mainloop_signal);
MAKE_FUNC(pa_stream_peek);
MAKE_FUNC(pa_threaded_mainloop_wait);
MAKE_FUNC(pa_threaded_mainloop_unlock);
MAKE_FUNC(pa_context_new);
MAKE_FUNC(pa_threaded_mainloop_stop);
MAKE_FUNC(pa_context_disconnect);
MAKE_FUNC(pa_threaded_mainloop_start);
MAKE_FUNC(pa_threaded_mainloop_get_api);
MAKE_FUNC(pa_context_set_state_callback);
MAKE_FUNC(pa_stream_write);
MAKE_FUNC(pa_xfree);
MAKE_FUNC(pa_stream_connect_record);
MAKE_FUNC(pa_stream_connect_playback);
MAKE_FUNC(pa_path_get_filename);
MAKE_FUNC(pa_get_binary_name);
MAKE_FUNC(pa_threaded_mainloop_free);
MAKE_FUNC(pa_context_errno);
MAKE_FUNC(pa_xmalloc0);
MAKE_FUNC(pa_stream_unref);
MAKE_FUNC(pa_threaded_mainloop_accept);
MAKE_FUNC(pa_stream_set_write_callback);
MAKE_FUNC(pa_threaded_mainloop_new);
MAKE_FUNC(pa_context_connect);
MAKE_FUNC(pa_stream_get_buffer_attr);
MAKE_FUNC(pa_stream_set_read_callback);
MAKE_FUNC(pa_stream_set_state_callback);
MAKE_FUNC(pa_stream_new);
MAKE_FUNC(pa_stream_disconnect);
MAKE_FUNC(pa_threaded_mainloop_lock);
#undef MAKE_FUNC
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
typedef struct {
ALCuint samples;
ALCuint frame_size;
RingBuffer *ring;
pa_buffer_attr attr;
pa_sample_spec spec;
char path_name[PATH_MAX];
const char *context_name;
const char *stream_name;
pa_threaded_mainloop *loop;
pa_stream *stream;
pa_context *context;
} pulse_data;
static const ALCchar pulse_device[] = "PulseAudio Software";
static const ALCchar pulse_capture_device[] = "PulseAudio Capture";
// PulseAudio I/O Callbacks //{{{
static void stream_write_callback(pa_stream *stream, size_t len, void *pdata) //{{{
{
ALCdevice *Device = pdata;
pulse_data *data = Device->ExtraData;
void *buf = ppa_xmalloc0(data->attr.minreq);
(void)len;
aluMixData(Device, buf, data->attr.minreq/data->frame_size);
ppa_stream_write(stream, buf, data->attr.minreq, ppa_xfree, 0,
PA_SEEK_RELATIVE);
} //}}}
static void stream_read_callback(pa_stream *stream, size_t length, void *pdata) //{{{
{
ALCdevice *Device = pdata;
pulse_data *data = Device->ExtraData;
const void *buf;
if(ppa_stream_peek(stream, &buf, &length) < 0)
{
AL_PRINT("pa_stream_peek() failed: %s\n",
ppa_strerror(ppa_context_errno(data->context)));
return;
}
assert(buf);
assert(length);
length /= data->frame_size;
if(data->samples < length)
AL_PRINT("stream_read_callback: buffer overflow!\n");
WriteRingBuffer(data->ring, buf, (length<data->samples) ? length : data->samples);
ppa_stream_drop(stream);
} //}}}
//}}}
static ALCboolean pulse_open(ALCdevice *device, const ALCchar *device_name) //{{{
{
pulse_data *data = ppa_xmalloc0(sizeof(pulse_data));
pa_context_state_t state;
if(ppa_get_binary_name(data->path_name, sizeof(data->path_name)))
data->context_name = ppa_path_get_filename(data->path_name);
else
data->context_name = "OpenAL Soft";
if(!(data->loop = ppa_threaded_mainloop_new()))
{
AL_PRINT("pa_threaded_mainloop_new() failed!\n");
goto out;
}
if(ppa_threaded_mainloop_start(data->loop) < 0)
{
AL_PRINT("pa_threaded_mainloop_start() failed\n");
goto out;
}
ppa_threaded_mainloop_lock(data->loop);
data->context = ppa_context_new(ppa_threaded_mainloop_get_api(data->loop), data->context_name);
if(!data->context)
{
AL_PRINT("pa_context_new() failed: %s\n",
ppa_strerror(ppa_context_errno(data->context)));
ppa_threaded_mainloop_unlock(data->loop);
goto out;
}
if(ppa_context_connect(data->context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0)
{
AL_PRINT("Context did not connect: %s\n",
ppa_strerror(ppa_context_errno(data->context)));
ppa_context_unref(data->context);
data->context = NULL;
ppa_threaded_mainloop_unlock(data->loop);
goto out;
}
while((state=ppa_context_get_state(data->context)) != PA_CONTEXT_READY)
{
if(!PA_CONTEXT_IS_GOOD(state))
{
AL_PRINT("Context did not get ready: %s\n",
ppa_strerror(ppa_context_errno(data->context)));
ppa_context_unref(data->context);
data->context = NULL;
ppa_threaded_mainloop_unlock(data->loop);
goto out;
}
ppa_threaded_mainloop_unlock(data->loop);
Sleep(1);
ppa_threaded_mainloop_lock(data->loop);
}
device->szDeviceName = strdup(device_name);
device->ExtraData = data;
ppa_threaded_mainloop_unlock(data->loop);
return ALC_TRUE;
out:
if(data->loop)
{
ppa_threaded_mainloop_stop(data->loop);
ppa_threaded_mainloop_free(data->loop);
}
ppa_xfree(data);
return ALC_FALSE;
} //}}}
static void pulse_close(ALCdevice *device) //{{{
{
pulse_data *data = device->ExtraData;
ppa_threaded_mainloop_lock(data->loop);
if(data->stream)
{
ppa_stream_disconnect(data->stream);
ppa_stream_unref(data->stream);
}
ppa_context_disconnect(data->context);
ppa_context_unref(data->context);
ppa_threaded_mainloop_unlock(data->loop);
ppa_threaded_mainloop_stop(data->loop);
ppa_threaded_mainloop_free(data->loop);
device->ExtraData = NULL;
free(device->szDeviceName);
device->szDeviceName = NULL;
DestroyRingBuffer(data->ring);
ppa_xfree(data);
} //}}}
//}}}
// OpenAL {{{
static ALCboolean pulse_open_playback(ALCdevice *device, const ALCchar *device_name) //{{{
{
if(!pa_handle)
return ALC_FALSE;
if(!device_name)
device_name = pulse_device;
else if(strcmp(device_name, pulse_device) != 0)
return ALC_FALSE;
return pulse_open(device, device_name);
} //}}}
static void pulse_close_playback(ALCdevice *device) //{{{
{
pulse_close(device);
} //}}}
static ALCboolean pulse_reset_playback(ALCdevice *device) //{{{
{
pulse_data *data = device->ExtraData;
pa_stream_state_t state;
ppa_threaded_mainloop_lock(data->loop);
data->frame_size = aluBytesFromFormat(device->Format) *
aluChannelsFromFormat(device->Format);
data->attr.minreq = data->frame_size * device->UpdateSize;
data->attr.prebuf = -1;
data->attr.maxlength = -1;
data->attr.fragsize = -1;
data->attr.tlength = data->attr.minreq * device->NumUpdates;
data->stream_name = "Playback Stream";
switch(aluBytesFromFormat(device->Format))
{
case 1:
data->spec.format = PA_SAMPLE_U8;
break;
case 2:
data->spec.format = PA_SAMPLE_S16NE;
break;
case 4:
data->spec.format = PA_SAMPLE_FLOAT32NE;
break;
default:
AL_PRINT("Unknown format: 0x%x\n", device->Format);
ppa_threaded_mainloop_unlock(data->loop);
return ALC_FALSE;
}
data->spec.rate = device->Frequency;
data->spec.channels = aluChannelsFromFormat(device->Format);
if(ppa_sample_spec_valid(&data->spec) == 0)
{
AL_PRINT("Invalid sample format\n");
ppa_threaded_mainloop_unlock(data->loop);
return ALC_FALSE;
}
data->stream = ppa_stream_new(data->context, data->stream_name, &data->spec, NULL);
if(!data->stream)
{
AL_PRINT("pa_stream_new() failed: %s\n",
ppa_strerror(ppa_context_errno(data->context)));
ppa_threaded_mainloop_unlock(data->loop);
return ALC_FALSE;
}
if(ppa_stream_connect_playback(data->stream, NULL, &data->attr, PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0)
{
AL_PRINT("Stream did not connect: %s\n",
ppa_strerror(ppa_context_errno(data->context)));
ppa_stream_unref(data->stream);
data->stream = NULL;
ppa_threaded_mainloop_unlock(data->loop);
return ALC_FALSE;
}
while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY)
{
if(!PA_STREAM_IS_GOOD(state))
{
AL_PRINT("Stream did not get ready: %s\n",
ppa_strerror(ppa_context_errno(data->context)));
ppa_stream_unref(data->stream);
data->stream = NULL;
ppa_threaded_mainloop_unlock(data->loop);
return ALC_FALSE;
}
ppa_threaded_mainloop_unlock(data->loop);
Sleep(1);
ppa_threaded_mainloop_lock(data->loop);
}
data->attr = *(ppa_stream_get_buffer_attr(data->stream));
if((data->attr.tlength%data->attr.minreq) != 0)
AL_PRINT("tlength (%d) is not a multiple of minreq (%d)!\n",
data->attr.tlength, data->attr.minreq);
device->UpdateSize = data->attr.minreq;
device->NumUpdates = data->attr.tlength/data->attr.minreq;
ppa_stream_set_write_callback(data->stream, stream_write_callback, device);
ppa_threaded_mainloop_unlock(data->loop);
return ALC_TRUE;
} //}}}
static void pulse_stop_playback(ALCdevice *device) //{{{
{
pulse_data *data = device->ExtraData;
if(!data->stream)
return;
ppa_threaded_mainloop_lock(data->loop);
ppa_stream_disconnect(data->stream);
ppa_stream_unref(data->stream);
data->stream = NULL;
ppa_threaded_mainloop_unlock(data->loop);
} //}}}
static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_name) //{{{
{
pulse_data *data;
pa_stream_state_t state;
if(!pa_handle)
return ALC_FALSE;
if(!device_name)
device_name = pulse_capture_device;
else if(strcmp(device_name, pulse_capture_device) != 0)
return ALC_FALSE;
if(pulse_open(device, device_name) == ALC_FALSE)
return ALC_FALSE;
data = device->ExtraData;
ppa_threaded_mainloop_lock(data->loop);
data->samples = device->UpdateSize * device->NumUpdates;
data->frame_size = aluBytesFromFormat(device->Format) *
aluChannelsFromFormat(device->Format);
if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples)))
{
ppa_threaded_mainloop_unlock(data->loop);
pulse_close(device);
return ALC_FALSE;
}
data->attr.minreq = -1;
data->attr.prebuf = -1;
data->attr.maxlength = -1;
data->attr.tlength = -1;
data->attr.fragsize = data->frame_size * data->samples / 2;
data->stream_name = "Capture Stream";
data->spec.rate = device->Frequency;
data->spec.channels = aluChannelsFromFormat(device->Format);
switch(aluBytesFromFormat(device->Format))
{
case 1:
data->spec.format = PA_SAMPLE_U8;
break;
case 2:
data->spec.format = PA_SAMPLE_S16NE;
break;
case 4:
data->spec.format = PA_SAMPLE_FLOAT32NE;
break;
default:
AL_PRINT("Unknown format: 0x%x\n", device->Format);
ppa_threaded_mainloop_unlock(data->loop);
pulse_close(device);
return ALC_FALSE;
}
if(ppa_sample_spec_valid(&data->spec) == 0)
{
AL_PRINT("Invalid sample format\n");
ppa_threaded_mainloop_unlock(data->loop);
pulse_close(device);
return ALC_FALSE;
}
data->stream = ppa_stream_new(data->context, data->stream_name, &data->spec, NULL);
if(!data->stream)
{
AL_PRINT("pa_stream_new() failed: %s\n",
ppa_strerror(ppa_context_errno(data->context)));
ppa_threaded_mainloop_unlock(data->loop);
pulse_close(device);
return ALC_FALSE;
}
if(ppa_stream_connect_record(data->stream, NULL, &data->attr, PA_STREAM_ADJUST_LATENCY) < 0)
{
AL_PRINT("Stream did not connect: %s\n",
ppa_strerror(ppa_context_errno(data->context)));
ppa_stream_unref(data->stream);
ppa_threaded_mainloop_unlock(data->loop);
data->stream = NULL;
pulse_close(device);
return ALC_FALSE;
}
while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY)
{
if(!PA_STREAM_IS_GOOD(state))
{
AL_PRINT("Stream did not get ready: %s\n",
ppa_strerror(ppa_context_errno(data->context)));
ppa_stream_unref(data->stream);
ppa_threaded_mainloop_unlock(data->loop);
data->stream = NULL;
pulse_close(device);
return ALC_FALSE;
}
ppa_threaded_mainloop_unlock(data->loop);
Sleep(1);
ppa_threaded_mainloop_lock(data->loop);
}
ppa_threaded_mainloop_unlock(data->loop);
return ALC_TRUE;
} //}}}
static void pulse_close_capture(ALCdevice *device) //{{{
{
pulse_close(device);
} //}}}
static void pulse_start_capture(ALCdevice *device) //{{{
{
pulse_data *data = device->ExtraData;
ppa_threaded_mainloop_lock(data->loop);
ppa_stream_set_read_callback(data->stream, stream_read_callback, device);
ppa_threaded_mainloop_unlock(data->loop);
} //}}}
static void pulse_stop_capture(ALCdevice *device) //{{{
{
pulse_data *data = device->ExtraData;
ppa_threaded_mainloop_lock(data->loop);
ppa_stream_set_read_callback(data->stream, NULL, NULL);
ppa_threaded_mainloop_unlock(data->loop);
} //}}}
static void pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) //{{{
{
pulse_data *data = device->ExtraData;
ALCuint available = RingBufferSize(data->ring);
if(available < samples)
SetALCError(ALC_INVALID_VALUE);
else
ReadRingBuffer(data->ring, buffer, samples);
} //}}}
static ALCuint pulse_available_samples(ALCdevice *device) //{{{
{
pulse_data *data = device->ExtraData;
return RingBufferSize(data->ring);
} //}}}
BackendFuncs pulse_funcs = { //{{{
pulse_open_playback,
pulse_close_playback,
pulse_reset_playback,
pulse_stop_playback,
pulse_open_capture,
pulse_close_capture,
pulse_start_capture,
pulse_stop_capture,
pulse_capture_samples,
pulse_available_samples
}; //}}}
void alc_pulse_init(BackendFuncs *func_list) //{{{
{
if(func_list) *func_list = pulse_funcs;
#ifdef _WIN32
pa_handle = LoadLibrary("libpulse-0.dll");
#define LOAD_FUNC(x) do { \
p##x = GetProcAddress(pa_handle, #x); \
if(!(p##x)) { \
AL_PRINT("Could not load %s from libpulse-0.dll\n", #x); \
FreeLibrary(pa_handle); \
pa_handle = NULL; \
return; \
} \
} while(0)
#elif defined (HAVE_DLFCN_H)
#if defined(__APPLE__) && defined(__MACH__)
pa_handle = dlopen("libpulse.0.dylib", RTLD_NOW);
#else
pa_handle = dlopen("libpulse.so.0", RTLD_NOW);
#endif
#define LOAD_FUNC(x) do { \
p##x = dlsym(pa_handle, #x); \
if(!(p##x)) { \
AL_PRINT("Could not load %s from libpulse\n", #x); \
dlclose(pa_handle); \
pa_handle = NULL; \
return; \
} \
} while(0)
#else
pa_handle = (void*)0xDEADBEEF;
#define LOAD_FUNC(x) p##x = (x)
#endif
if(!pa_handle)
return;
LOAD_FUNC(pa_context_unref);
LOAD_FUNC(pa_sample_spec_valid);
LOAD_FUNC(pa_stream_drop);
LOAD_FUNC(pa_strerror);
LOAD_FUNC(pa_context_get_state);
LOAD_FUNC(pa_stream_get_state);
LOAD_FUNC(pa_threaded_mainloop_signal);
LOAD_FUNC(pa_stream_peek);
LOAD_FUNC(pa_threaded_mainloop_wait);
LOAD_FUNC(pa_threaded_mainloop_unlock);
LOAD_FUNC(pa_context_new);
LOAD_FUNC(pa_threaded_mainloop_stop);
LOAD_FUNC(pa_context_disconnect);
LOAD_FUNC(pa_threaded_mainloop_start);
LOAD_FUNC(pa_threaded_mainloop_get_api);
LOAD_FUNC(pa_context_set_state_callback);
LOAD_FUNC(pa_stream_write);
LOAD_FUNC(pa_xfree);
LOAD_FUNC(pa_stream_connect_record);
LOAD_FUNC(pa_stream_connect_playback);
LOAD_FUNC(pa_path_get_filename);
LOAD_FUNC(pa_get_binary_name);
LOAD_FUNC(pa_threaded_mainloop_free);
LOAD_FUNC(pa_context_errno);
LOAD_FUNC(pa_xmalloc0);
LOAD_FUNC(pa_stream_unref);
LOAD_FUNC(pa_threaded_mainloop_accept);
LOAD_FUNC(pa_stream_set_write_callback);
LOAD_FUNC(pa_threaded_mainloop_new);
LOAD_FUNC(pa_context_connect);
LOAD_FUNC(pa_stream_get_buffer_attr);
LOAD_FUNC(pa_stream_set_read_callback);
LOAD_FUNC(pa_stream_set_state_callback);
LOAD_FUNC(pa_stream_new);
LOAD_FUNC(pa_stream_disconnect);
LOAD_FUNC(pa_threaded_mainloop_lock);
#undef LOAD_FUNC
} //}}}
void alc_pulse_deinit(void) //{{{
{
if(pa_handle)
{
#ifdef _WIN32
FreeLibrary(pa_handle);
#elif defined (HAVE_DLFCN_H)
dlclose(pa_handle);
#endif
}
pa_handle = NULL;
} //}}}
void alc_pulse_probe(int type) //{{{
{
if(!pa_handle) alc_pulse_init(NULL);
if(!pa_handle) return;
if(type == DEVICE_PROBE)
AppendDeviceList(pulse_device);
else if(type == ALL_DEVICE_PROBE)
AppendAllDeviceList(pulse_device);
else if(type == CAPTURE_DEVICE_PROBE)
AppendCaptureDeviceList(pulse_capture_device);
} //}}}
//}}}
+292
View File
@@ -0,0 +1,292 @@
/**
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <sys/ioctl.h>
#include <sys/types.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 "AL/al.h"
#include "AL/alc.h"
#include <sys/audioio.h>
static const ALCchar solaris_device[] = "Solaris Software";
typedef struct {
int fd;
volatile int killNow;
ALvoid *thread;
ALubyte *mix_data;
int data_size;
} solaris_data;
static ALuint SolarisProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
solaris_data *data = (solaris_data*)pDevice->ExtraData;
int remaining = 0;
ALint frameSize;
int wrote;
frameSize = aluChannelsFromFormat(pDevice->Format) *
aluBytesFromFormat(pDevice->Format);
while(!data->killNow && !pDevice->Connected)
{
ALint len = data->data_size;
ALubyte *WritePtr = data->mix_data;
aluMixData(pDevice, WritePtr, len/frameSize);
while(len > 0 && !data->killNow)
{
wrote = write(data->fd, WritePtr, len);
if(wrote < 0)
{
if(errno != EAGAIN && errno != EWOULDBLOCK)
{
AL_PRINT("write failed: %s\n", strerror(errno));
aluHandleDisconnect(pDevice);
len = 0;
}
else
Sleep(1);
continue;
}
len -= wrote;
WritePtr += wrote;
}
}
return 0;
}
static ALCboolean solaris_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
char driver[64];
solaris_data *data;
strncpy(driver, GetConfigValue("solaris", "device", "/dev/audio"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(!deviceName)
deviceName = solaris_device;
else if(strcmp(deviceName, solaris_device) != 0)
return ALC_FALSE;
data = (solaris_data*)calloc(1, sizeof(solaris_data));
data->killNow = 0;
data->fd = open(driver, O_WRONLY);
if(data->fd == -1)
{
free(data);
AL_PRINT("Could not open %s: %s\n", driver, strerror(errno));
return ALC_FALSE;
}
device->szDeviceName = strdup(deviceName);
device->ExtraData = data;
return ALC_TRUE;
}
static void solaris_close_playback(ALCdevice *device)
{
solaris_data *data = (solaris_data*)device->ExtraData;
close(data->fd);
free(data);
device->ExtraData = NULL;
}
static ALCboolean solaris_reset_playback(ALCdevice *device)
{
solaris_data *data = (solaris_data*)device->ExtraData;
audio_info_t info;
ALuint frameSize;
int numChannels;
AUDIO_INITINFO(&info);
switch(aluBytesFromFormat(device->Format))
{
case 1:
info.play.precision = 8;
info.play.encoding = AUDIO_ENCODING_LINEAR8;
break;
case 4:
switch(numChannels)
{
case 1: device->Format = AL_FORMAT_MONO16; break;
case 2: device->Format = AL_FORMAT_STEREO16; break;
case 4: device->Format = AL_FORMAT_QUAD16; break;
case 6: device->Format = AL_FORMAT_51CHN16; break;
case 7: device->Format = AL_FORMAT_61CHN16; break;
case 8: device->Format = AL_FORMAT_71CHN16; break;
}
/* fall-through */
case 2:
info.play.precision = 16;
info.play.encoding = AUDIO_ENCODING_LINEAR;
break;
default:
AL_PRINT("Unknown format: 0x%x\n", device->Format);
return ALC_FALSE;
}
numChannels = aluChannelsFromFormat(device->Format);
info.play.sample_rate = device->Frequency;
info.play.channels = numChannels;
frameSize = numChannels * aluBytesFromFormat(device->Format);
info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize;
if(ioctl(data->fd, AUDIO_SETINFO, &info) < 0)
{
AL_PRINT("ioctl failed: %s\n", strerror(errno));
return ALC_FALSE;
}
if(aluChannelsFromFormat(device->Format) != info.play.channels)
{
AL_PRINT("Could not set %d channels, got %d instead\n", aluChannelsFromFormat(device->Format), info.play.channels);
return ALC_FALSE;
}
if(!((info.play.precision == 8 && aluBytesFromFormat(device->Format) == 1) ||
(info.play.precision == 16 && aluBytesFromFormat(device->Format) == 2)))
{
AL_PRINT("Could not set %d-bit output, got %d\n", aluBytesFromFormat(device->Format)*8, info.play.precision);
return ALC_FALSE;
}
device->Frequency = info.play.sample_rate;
device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1;
data->data_size = device->UpdateSize * frameSize;
data->mix_data = calloc(1, data->data_size);
data->thread = StartThread(SolarisProc, device);
if(data->thread == NULL)
{
free(data->mix_data);
data->mix_data = NULL;
return ALC_FALSE;
}
return ALC_TRUE;
}
static void solaris_stop_playback(ALCdevice *device)
{
solaris_data *data = (solaris_data*)device->ExtraData;
if(!data->thread)
return;
data->killNow = 1;
StopThread(data->thread);
data->thread = NULL;
free(data->mix_data);
data->mix_data = NULL;
}
static ALCboolean solaris_open_capture(ALCdevice *device, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
{
(void)device;
(void)deviceName;
(void)frequency;
(void)format;
(void)SampleSize;
return ALC_FALSE;
}
static void solaris_close_capture(ALCdevice *device)
{
(void)device;
}
static void solaris_start_capture(ALCdevice *pDevice)
{
(void)pDevice;
}
static void solaris_stop_capture(ALCdevice *pDevice)
{
(void)pDevice;
}
static void solaris_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
{
(void)pDevice;
(void)pBuffer;
(void)lSamples;
}
static ALCuint solaris_available_samples(ALCdevice *pDevice)
{
(void)pDevice;
return 0;
}
BackendFuncs solaris_funcs = {
solaris_open_playback,
solaris_close_playback,
solaris_reset_playback,
solaris_stop_playback,
solaris_open_capture,
solaris_close_capture,
solaris_start_capture,
solaris_stop_capture,
solaris_capture_samples,
solaris_available_samples
};
void alc_solaris_init(BackendFuncs *func_list)
{
*func_list = solaris_funcs;
}
void alc_solaris_deinit(void)
{
}
void alc_solaris_probe(ALCboolean capture)
{
if(type == DEVICE_PROBE)
AppendDeviceList(solaris_device);
else if(type == ALL_DEVICE_PROBE)
AppendAllDeviceList(solaris_device);
}
+67 -54
View File
@@ -40,7 +40,7 @@ typedef struct {
} wave_data;
static ALCchar *waveDevice;
static const ALCchar waveDevice[] = "Wave File Writer";
static ALuint WaveProc(ALvoid *ptr)
@@ -49,7 +49,7 @@ static ALuint WaveProc(ALvoid *ptr)
wave_data *data = (wave_data*)pDevice->ExtraData;
ALuint frameSize;
ALuint now, last;
size_t WriteCnt;
size_t fs;
ALuint avail;
union {
short s;
@@ -61,43 +61,40 @@ static ALuint WaveProc(ALvoid *ptr)
aluChannelsFromFormat(pDevice->Format);
last = timeGetTime();
while(!data->killNow)
while(!data->killNow && pDevice->Connected)
{
now = timeGetTime();
avail = (now-last) * pDevice->Frequency / 1000;
if(avail < pDevice->UpdateSize/4)
if(avail < pDevice->UpdateSize)
{
Sleep(1);
continue;
}
while(avail > 0)
while(avail >= pDevice->UpdateSize)
{
SuspendContext(NULL);
WriteCnt = min(data->size, avail);
aluMixData(pDevice->Context, data->buffer, WriteCnt * frameSize,
pDevice->Format);
ProcessContext(NULL);
aluMixData(pDevice, data->buffer, pDevice->UpdateSize);
if(uSB.b[0] != 1 && aluBytesFromFormat(pDevice->Format) > 1)
{
ALubyte *bytes = data->buffer;
ALuint i;
for(i = 0;i < WriteCnt*frameSize;i++)
for(i = 0;i < data->size;i++)
fputc(bytes[i^1], data->f);
}
else
fwrite(data->buffer, frameSize, WriteCnt, data->f);
fs = fwrite(data->buffer, frameSize, pDevice->UpdateSize,
data->f);
if(ferror(data->f))
{
AL_PRINT("Error writing to file\n");
data->killNow = 1;
aluHandleDisconnect(pDevice);
break;
}
avail -= WriteCnt;
avail -= pDevice->UpdateSize;
}
last = now;
}
@@ -108,23 +105,16 @@ static ALuint WaveProc(ALvoid *ptr)
static ALCboolean wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
wave_data *data;
ALuint channels;
ALuint bits;
const char *fname;
int i;
fname = GetConfigValue("wave", "file", "");
if(!fname[0])
return ALC_FALSE;
if(deviceName)
{
if(strcmp(deviceName, waveDevice) != 0)
return ALC_FALSE;
device->szDeviceName = waveDevice;
}
else
device->szDeviceName = waveDevice;
if(!deviceName)
deviceName = waveDevice;
else if(strcmp(deviceName, waveDevice) != 0)
return ALC_FALSE;
data = (wave_data*)calloc(1, sizeof(wave_data));
@@ -136,25 +126,44 @@ static ALCboolean wave_open_playback(ALCdevice *device, const ALCchar *deviceNam
return ALC_FALSE;
}
device->szDeviceName = strdup(deviceName);
device->ExtraData = data;
return ALC_TRUE;
}
static void wave_close_playback(ALCdevice *device)
{
wave_data *data = (wave_data*)device->ExtraData;
fclose(data->f);
free(data);
device->ExtraData = NULL;
}
static ALCboolean wave_reset_playback(ALCdevice *device)
{
wave_data *data = (wave_data*)device->ExtraData;
ALuint channels, bits, i;
fseek(data->f, 0, SEEK_SET);
clearerr(data->f);
bits = aluBytesFromFormat(device->Format) * 8;
channels = aluChannelsFromFormat(device->Format);
switch(bits)
{
case 8:
case 16:
case 32:
if(channels == 0)
{
AL_PRINT("Unknown format?! %x\n", device->Format);
fclose(data->f);
free(data);
return ALC_FALSE;
}
break;
default:
AL_PRINT("Unknown format?! %x\n", device->Format);
fclose(data->f);
free(data);
return ALC_FALSE;
}
@@ -205,47 +214,45 @@ static ALCboolean wave_open_playback(ALCdevice *device, const ALCchar *deviceNam
if(ferror(data->f))
{
AL_PRINT("Error writing header: %s\n", strerror(errno));
fclose(data->f);
free(data);
return ALC_FALSE;
}
data->DataStart = ftell(data->f);
device->UpdateSize = max(device->UpdateSize, 2048);
data->size = device->UpdateSize;
data->buffer = malloc(data->size * channels * bits / 8);
data->size = device->UpdateSize * channels * bits / 8;
data->buffer = malloc(data->size);
if(!data->buffer)
{
AL_PRINT("buffer malloc failed\n");
fclose(data->f);
free(data);
return ALC_FALSE;
}
device->ExtraData = data;
data->thread = StartThread(WaveProc, device);
if(data->thread == NULL)
{
device->ExtraData = NULL;
fclose(data->f);
free(data->buffer);
free(data);
data->buffer = NULL;
return ALC_FALSE;
}
return ALC_TRUE;
}
static void wave_close_playback(ALCdevice *device)
static void wave_stop_playback(ALCdevice *device)
{
wave_data *data = (wave_data*)device->ExtraData;
ALuint dataLen;
long size;
if(!data->thread)
return;
data->killNow = 1;
StopThread(data->thread);
data->thread = NULL;
free(data->buffer);
data->buffer = NULL;
size = ftell(data->f);
if(size > 0)
@@ -267,21 +274,13 @@ static void wave_close_playback(ALCdevice *device)
fputc((size>>24)&0xff, data->f);
}
}
fclose(data->f);
free(data->buffer);
free(data);
device->ExtraData = NULL;
}
static ALCboolean wave_open_capture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
static ALCboolean wave_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
{
(void)pDevice;
(void)deviceName;
(void)frequency;
(void)format;
(void)SampleSize;
return ALC_FALSE;
}
@@ -317,6 +316,8 @@ static ALCuint wave_available_samples(ALCdevice *pDevice)
BackendFuncs wave_funcs = {
wave_open_playback,
wave_close_playback,
wave_reset_playback,
wave_stop_playback,
wave_open_capture,
wave_close_capture,
wave_start_capture,
@@ -328,7 +329,19 @@ BackendFuncs wave_funcs = {
void alc_wave_init(BackendFuncs *func_list)
{
*func_list = wave_funcs;
waveDevice = AppendDeviceList("Wave File Writer");
AppendAllDeviceList(waveDevice);
}
void alc_wave_deinit(void)
{
}
void alc_wave_probe(int type)
{
if(*(GetConfigValue("wave", "file", "")) == 0)
return;
if(type == DEVICE_PROBE)
AppendDeviceList(waveDevice);
else if(type == ALL_DEVICE_PROBE)
AppendAllDeviceList(waveDevice);
}
+44 -16
View File
@@ -50,7 +50,8 @@ typedef struct {
} WinMMData;
static ALCchar *CaptureDeviceList[16];
static ALCchar **CaptureDeviceList;
static ALuint NumCaptureDevices;
/*
WaveInProc
@@ -175,20 +176,18 @@ static void WinMMClosePlayback(ALCdevice *device)
}
static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
{
WAVEFORMATEX wfexCaptureFormat;
WinMMData *pData = NULL;
ALint lDeviceID = 0;
ALint lBufferSize;
ALint i;
(void)format;
ALuint i;
// Find the Device ID matching the deviceName if valid
if (deviceName)
{
for(i = 0;CaptureDeviceList[i];i++)
for(i = 0;i < NumCaptureDevices;i++)
{
if (!strcmp(deviceName, CaptureDeviceList[i]))
{
@@ -196,10 +195,9 @@ static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName
break;
}
}
if(!CaptureDeviceList[i])
if(i == NumCaptureDevices)
return ALC_FALSE;
}
pDevice->szDeviceName = CaptureDeviceList[lDeviceID];
pData = calloc(1, sizeof(*pData));
if(!pData)
@@ -214,7 +212,7 @@ static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName
wfexCaptureFormat.wBitsPerSample = aluBytesFromFormat(pDevice->Format) * 8;
wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *
wfexCaptureFormat.nChannels / 8;
wfexCaptureFormat.nSamplesPerSec = frequency;
wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency;
wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *
wfexCaptureFormat.nBlockAlign;
wfexCaptureFormat.cbSize = 0;
@@ -231,7 +229,8 @@ static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName
goto failure;
// Allocate circular memory buffer for the captured audio
pData->ulCapturedDataSize = SampleSize * wfexCaptureFormat.nBlockAlign;
pData->ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates *
wfexCaptureFormat.nBlockAlign;
// Make sure circular buffer is at least 100ms in size (and an exact multiple of
// the block alignment
@@ -269,6 +268,7 @@ static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName
if (pData->hWaveInThread == NULL)
goto failure;
pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]);
return ALC_TRUE;
failure:
@@ -292,6 +292,7 @@ failure:
CloseHandle(pData->hWaveInThreadEvent);
free(pData);
pDevice->ExtraData = NULL;
return ALC_FALSE;
}
@@ -413,6 +414,8 @@ static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
BackendFuncs WinMMFuncs = {
WinMMOpenPlayback,
WinMMClosePlayback,
NULL,
NULL,
WinMMOpenCapture,
WinMMCloseCapture,
WinMMStartCapture,
@@ -423,20 +426,45 @@ BackendFuncs WinMMFuncs = {
void alcWinMMInit(BackendFuncs *FuncList)
{
ALint lNumDevs;
ALint lLoop;
*FuncList = WinMMFuncs;
}
lNumDevs = waveInGetNumDevs();
for (lLoop = 0; lLoop < lNumDevs; lLoop++)
void alcWinMMDeinit()
{
ALuint lLoop;
for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
free(CaptureDeviceList[lLoop]);
free(CaptureDeviceList);
CaptureDeviceList = NULL;
NumCaptureDevices = 0;
}
void alcWinMMProbe(int type)
{
ALuint lLoop;
if(type != CAPTURE_DEVICE_PROBE)
return;
for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
free(CaptureDeviceList[lLoop]);
NumCaptureDevices = waveInGetNumDevs();
CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices);
for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
{
WAVEINCAPS WaveInCaps;
if(waveInGetDevCaps(lLoop, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
{
char name[128];
snprintf(name, sizeof(name), "WaveIn on %s", WaveInCaps.szPname);
CaptureDeviceList[lLoop] = AppendCaptureDeviceList(name);
AppendCaptureDeviceList(name);
CaptureDeviceList[lLoop] = strdup(name);
}
else
CaptureDeviceList[lLoop] = strdup("");
}
}
+130 -26
View File
@@ -10,6 +10,7 @@ INCLUDE(CheckFunctionExists)
INCLUDE(CheckLibraryExists)
INCLUDE(CheckIncludeFile)
INCLUDE(CheckIncludeFiles)
INCLUDE(CheckSymbolExists)
INCLUDE(CheckCCompilerFlag)
INCLUDE(CheckCSourceCompiles)
INCLUDE(CheckTypeSize)
@@ -23,8 +24,11 @@ SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE)
OPTION(ALSA "Check for ALSA backend" ON)
OPTION(OSS "Check for OSS backend" ON)
OPTION(SOLARIS "Check for Solaris backend" ON)
OPTION(DSOUND "Check for DirectSound backend" ON)
OPTION(WINMM "Check for Windows Multimedia backend" ON)
OPTION(PORTAUDIO "Check for PortAudio backend" ON)
OPTION(PULSEAUDIO "Check for PulseAudio backend" ON)
OPTION(DLOPEN "Check for the dlopen API for loading optional libs" ON)
@@ -32,19 +36,22 @@ OPTION(WERROR "Treat compile warnings as errors" OFF)
OPTION(EXAMPLES "Build example programs" ON)
OPTION(ALSOFT_CONFIG "Install alsoft.conf configuration file" OFF)
IF(WIN32)
SET(LIBNAME openal32)
SET(LIBNAME OpenAL32)
ADD_DEFINITIONS("-D_WIN32")
ELSE()
SET(LIBNAME openal)
ENDIF()
SET(LIB_MAJOR_VERSION "1")
SET(LIB_MINOR_VERSION "5")
SET(LIB_BUILD_VERSION "304")
SET(LIB_MINOR_VERSION "9")
SET(LIB_BUILD_VERSION "563")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_BUILD_VERSION}")
IF(NOT DEFINED LIB_INSTALL_DIR)
SET(LIB_INSTALL_DIR "lib")
SET(LIB_INSTALL_DIR "lib${LIB_SUFFIX}")
ENDIF(NOT DEFINED LIB_INSTALL_DIR)
@@ -62,6 +69,11 @@ IF(NOT CMAKE_BUILD_TYPE)
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE)
ENDIF()
IF(NOT CMAKE_DEBUG_POSTFIX)
SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING
"Library postfix for debug builds. Normally left blank."
FORCE)
ENDIF()
IF(MSVC)
# ???
@@ -69,10 +81,11 @@ IF(MSVC)
SET(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -DNDEBUG")
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
ELSE()
ADD_DEFINITIONS(-Wall)
CHECK_C_COMPILER_FLAG(-Wextra HAVE_W_EXTRA)
IF("${HAVE_W_EXTRA}")
IF(HAVE_W_EXTRA)
ADD_DEFINITIONS(-Wextra)
ENDIF()
@@ -99,23 +112,31 @@ ELSE()
int main() {return 0;}" HAVE_GCC_DESTRUCTOR)
CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_SWITCH)
IF("${HAVE_VISIBILITY_SWITCH}")
IF(HAVE_VISIBILITY_SWITCH)
CHECK_C_SOURCE_COMPILES("int foo() __attribute__((visibility(\"default\")));
int main() {return 0;}" HAVE_GCC_VISIBILITY)
IF("${HAVE_GCC_VISIBILITY}")
IF(HAVE_GCC_VISIBILITY)
ADD_DEFINITIONS(-fvisibility=hidden -DHAVE_GCC_VISIBILITY)
ENDIF()
ENDIF()
ENDIF()
ENDIF()
CHECK_INCLUDE_FILE(fenv.h HAVE_FENV_H)
CHECK_INCLUDE_FILE(float.h HAVE_FLOAT_H)
CHECK_LIBRARY_EXISTS(m sqrtf "" HAVE_SQRTF)
CHECK_LIBRARY_EXISTS(m acosf "" HAVE_ACOSF)
IF(HAVE_SQRTF OR HAVE_ACOSF)
CHECK_LIBRARY_EXISTS(m atanf "" HAVE_ATANF)
CHECK_LIBRARY_EXISTS(m fabsf "" HAVE_FABSF)
IF(HAVE_FENV_H)
CHECK_LIBRARY_EXISTS(m fesetround "" HAVE_FESETROUND)
ENDIF()
IF(HAVE_SQRTF OR HAVE_ACOSF OR HAVE_ATANF OR HAVE_FABSF OR HAVE_FESETROUND)
SET(EXTRA_LIBS m ${EXTRA_LIBS})
ENDIF()
CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF)
CHECK_FUNCTION_EXISTS(_controlfp HAVE__CONTROLFP)
CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP)
IF(NOT HAVE_STRCASECMP)
@@ -147,6 +168,27 @@ IF(NOT HAVE_SNPRINTF)
ADD_DEFINITIONS(-Dsnprintf=_snprintf)
ENDIF()
CHECK_FUNCTION_EXISTS(vsnprintf HAVE_VSNPRINTF)
IF(NOT HAVE_VSNPRINTF)
CHECK_FUNCTION_EXISTS(_vsnprintf HAVE__VSNPRINTF)
IF(NOT HAVE__VSNPRINTF)
MESSAGE(FATAL_ERROR "No vsnprintf function found, please report!")
ENDIF()
ADD_DEFINITIONS(-Dvsnprintf=_vsnprintf)
ENDIF()
CHECK_SYMBOL_EXISTS(isnan math.h HAVE_ISNAN)
IF(NOT HAVE_ISNAN)
CHECK_FUNCTION_EXISTS(_isnan HAVE__ISNAN)
IF(NOT HAVE__ISNAN)
MESSAGE(FATAL_ERROR "No isnan function found, please report!")
ENDIF()
ADD_DEFINITIONS(-Disnan=_isnan)
ENDIF()
# Check for the dlopen API (for dynamicly loading backend libs)
IF(DLOPEN)
CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H)
@@ -210,6 +252,7 @@ ENDIF()
SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c
OpenAL32/alBuffer.c
OpenAL32/alDatabuffer.c
OpenAL32/alEffect.c
OpenAL32/alError.c
OpenAL32/alExtension.c
@@ -222,10 +265,11 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c
SET(ALC_OBJS Alc/ALc.c
Alc/ALu.c
Alc/alcConfig.c
Alc/alcEcho.c
Alc/alcReverb.c
Alc/alcRing.c
Alc/alcThread.c
Alc/bs2b.c
Alc/lpfilter.c
Alc/wave.c
)
@@ -259,24 +303,35 @@ IF(OSS)
ENDIF()
ENDIF()
# Check Solaris backend
IF(SOLARIS)
CHECK_INCLUDE_FILE(sys/audioio.h HAVE_SYS_AUDIOIO_H)
IF(HAVE_SYS_AUDIOIO_H)
SET(HAVE_SOLARIS 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/solaris.c)
SET(BACKENDS "${BACKENDS} Solaris,")
ENDIF()
ENDIF()
# Check DSound/MMSystem backend
IF(HAVE_WINDOWS_H)
IF(DSOUND)
CHECK_INCLUDE_FILE(dsound.h HAVE_DSOUND_H)
IF(HAVE_DSOUND_H)
IF(DSOUND)
CHECK_INCLUDE_FILE(dsound.h HAVE_DSOUND_H)
IF(HAVE_DSOUND_H)
CHECK_LIBRARY_EXISTS(dsound DirectSoundCreate "" HAVE_LIBDSOUND)
IF(HAVE_LIBDSOUND OR WIN32)
SET(HAVE_DSOUND 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/dsound.c)
SET(BACKENDS "${BACKENDS} DirectSound,")
SET(CMAKE_REQUIRED_LIBRARIES dsound)
CHECK_C_SOURCE_COMPILES("int main() {return 0;}" HAVE_LIBDSOUND)
SET(CMAKE_REQUIRED_LIBRARIES "")
# CHECK_LIBRARY_EXISTS(dsound DirectSoundCreate "" HAVE_LIBDSOUND)
IF(HAVE_LIBDSOUND)
IF(WIN32)
SET(BACKENDS "${BACKENDS} DirectSound,")
ELSE()
SET(BACKENDS "${BACKENDS} DirectSound \(linked\),")
SET(EXTRA_LIBS dsound ${EXTRA_LIBS})
ENDIF()
ENDIF()
ENDIF()
ENDIF()
IF(HAVE_WINDOWS_H)
IF(WINMM)
CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0500)
IF(HAVE_MMSYSTEM_H)
@@ -295,6 +350,42 @@ IF(HAVE_WINDOWS_H)
ENDIF()
ENDIF()
# Check PortAudio backend
IF(PORTAUDIO)
CHECK_INCLUDE_FILE(portaudio.h HAVE_PORTAUDIO_H)
IF(HAVE_PORTAUDIO_H)
CHECK_LIBRARY_EXISTS(portaudio Pa_Initialize "" HAVE_LIBPORTAUDIO)
IF(HAVE_LIBPORTAUDIO)
SET(HAVE_PORTAUDIO 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/portaudio.c)
IF(HAVE_DLFCN_H)
SET(BACKENDS "${BACKENDS} PortAudio,")
ELSE()
SET(BACKENDS "${BACKENDS} PortAudio \(linked\),")
SET(EXTRA_LIBS portaudio ${EXTRA_LIBS})
ENDIF()
ENDIF()
ENDIF()
ENDIF()
# Check PortAudio backend
IF(PULSEAUDIO)
CHECK_INCLUDE_FILE(pulse/pulseaudio.h HAVE_PULSE_PULSEAUDIO_H)
IF(HAVE_PULSE_PULSEAUDIO_H)
CHECK_LIBRARY_EXISTS(pulse pa_context_new "" HAVE_LIBPULSE)
IF(HAVE_LIBPULSE)
SET(HAVE_PULSEAUDIO 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/pulseaudio.c)
IF(HAVE_DLFCN_H)
SET(BACKENDS "${BACKENDS} PulseAudio,")
ELSE()
SET(BACKENDS "${BACKENDS} PulseAudio \(linked\),")
SET(EXTRA_LIBS pulse ${EXTRA_LIBS})
ENDIF()
ENDIF()
ENDIF()
ENDIF()
# This is always available
SET(BACKENDS "${BACKENDS} WaveFile")
@@ -317,8 +408,11 @@ CONFIGURE_FILE(
ADD_DEFINITIONS(-DAL_BUILD_LIBRARY)
# Build a shared library
ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALC_OBJS})
# Build a library
IF(NOT LIBTYPE)
SET(LIBTYPE SHARED)
ENDIF()
ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION}
SOVERSION ${LIB_MAJOR_VERSION})
IF(WIN32)
@@ -339,7 +433,15 @@ INSTALL(FILES include/AL/al.h
DESTINATION include/AL
)
INSTALL(FILES "${OpenAL_BINARY_DIR}/admin/pkgconfig/openal.pc"
DESTINATION lib/pkgconfig)
DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
# Install alsoft.conf configuration file
IF(ALSOFT_CONFIG)
INSTALL(FILES alsoftrc.sample
DESTINATION /etc/openal
RENAME alsoft.conf
)
ENDIF()
IF(EXAMPLES)
ADD_EXECUTABLE(openal-info examples/openal-info.c)
@@ -356,8 +458,10 @@ MESSAGE(STATUS "Building OpenAL with support for the following backends:")
MESSAGE(STATUS " ${BACKENDS}")
MESSAGE(STATUS "")
IF(WIN32 AND NOT HAVE_DSOUND)
MESSAGE(STATUS "WARNING: Building the Windows version without DirectSound output")
MESSAGE(STATUS " This is probably NOT what you want!")
MESSAGE(STATUS "")
IF(WIN32)
IF(NOT HAVE_DSOUND)
MESSAGE(STATUS "WARNING: Building the Windows version without DirectSound output")
MESSAGE(STATUS " This is probably NOT what you want!")
MESSAGE(STATUS "")
ENDIF()
ENDIF()
+31 -19
View File
@@ -15,6 +15,8 @@ extern "C" {
#define AL_EFFECTSLOT_NULL 0x0000
typedef struct ALeffectState ALeffectState;
typedef struct ALeffectslot
{
ALeffect effect;
@@ -22,15 +24,9 @@ typedef struct ALeffectslot
ALfloat Gain;
ALboolean AuxSendAuto;
ALfloat *ReverbBuffer;
// in frames!
ALuint ReverbLength;
ALuint ReverbPos;
ALuint ReverbReflectPos;
ALuint ReverbLatePos;
ALfloat ReverbDecayGain;
ALeffectState *EffectState;
FILTER iirFilter;
ALfloat WetBuffer[BUFFERSIZE];
ALuint refcount;
@@ -40,22 +36,38 @@ typedef struct ALeffectslot
struct ALeffectslot *next;
} ALeffectslot;
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
struct ALeffectState {
ALvoid (*Destroy)(ALeffectState *State);
ALvoid (*Update)(ALeffectState *State, ALCcontext *Context, ALeffect *Effect);
ALvoid (*Process)(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]);
};
ALeffectState *EAXVerbCreate(ALCcontext *Context);
ALeffectState *VerbCreate(ALCcontext *Context);
ALeffectState *EchoCreate(ALCcontext *Context);
#define ALEffect_Destroy(a) ((a)->Destroy((a)))
#define ALEffect_Update(a,b,c) ((a)->Update((a),(b),(c)))
#define ALEffect_Process(a,b,c,d,e) ((a)->Process((a),(b),(c),(d),(e)))
#ifdef __cplusplus
}
#endif
+5 -3
View File
@@ -11,7 +11,7 @@ extern "C" {
#define PENDING 1
#define PROCESSED 2
typedef struct ALbuffer_struct
typedef struct ALbuffer
{
ALenum format;
ALenum eOriginalFormat;
@@ -21,10 +21,12 @@ typedef struct ALbuffer_struct
ALsizei padding;
ALenum state;
ALuint refcount; // Number of sources using this buffer (deletion can only occur when this is 0)
struct ALbuffer_struct *next;
struct ALbuffer *next;
} ALbuffer;
ALvoid ReleaseALBuffers(ALvoid);
ALvoid ALAPIENTRY alBufferSubDataEXT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length);
ALvoid ReleaseALBuffers(ALCdevice *device);
#ifdef __cplusplus
}
+55
View File
@@ -0,0 +1,55 @@
#ifndef _AL_DATABUFFER_H_
#define _AL_DATABUFFER_H_
#include "AL/al.h"
#ifdef __cplusplus
extern "C" {
#endif
#define UNMAPPED 0
#define MAPPED 1
typedef struct ALdatabuffer
{
ALubyte *data;
ALuint size;
ALenum state;
ALenum usage;
/* Index to self */
ALuint databuffer;
struct ALdatabuffer *next;
} ALdatabuffer;
ALvoid ALAPIENTRY alGenDatabuffersEXT(ALsizei n,ALuint *puiBuffers);
ALvoid ALAPIENTRY alDeleteDatabuffersEXT(ALsizei n, const ALuint *puiBuffers);
ALboolean ALAPIENTRY alIsDatabufferEXT(ALuint uiBuffer);
ALvoid ALAPIENTRY alDatabufferDataEXT(ALuint buffer,const ALvoid *data,ALsizei size,ALenum usage);
ALvoid ALAPIENTRY alDatabufferSubDataEXT(ALuint buffer, ALuint start, ALsizei length, const ALvoid *data);
ALvoid ALAPIENTRY alGetDatabufferSubDataEXT(ALuint buffer, ALuint start, ALsizei length, ALvoid *data);
ALvoid ALAPIENTRY alDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat flValue);
ALvoid ALAPIENTRY alDatabufferfvEXT(ALuint buffer, ALenum eParam, const ALfloat* flValues);
ALvoid ALAPIENTRY alDatabufferiEXT(ALuint buffer, ALenum eParam, ALint lValue);
ALvoid ALAPIENTRY alDatabufferivEXT(ALuint buffer, ALenum eParam, const ALint* plValues);
ALvoid ALAPIENTRY alGetDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat *pflValue);
ALvoid ALAPIENTRY alGetDatabufferfvEXT(ALuint buffer, ALenum eParam, ALfloat* pflValues);
ALvoid ALAPIENTRY alGetDatabufferiEXT(ALuint buffer, ALenum eParam, ALint *plValue);
ALvoid ALAPIENTRY alGetDatabufferivEXT(ALuint buffer, ALenum eParam, ALint* plValues);
ALvoid ALAPIENTRY alSelectDatabufferEXT(ALenum target, ALuint uiBuffer);
ALvoid* ALAPIENTRY alMapDatabufferEXT(ALuint uiBuffer, ALuint start, ALsizei length, ALenum access);
ALvoid ALAPIENTRY alUnmapDatabufferEXT(ALuint uiBuffer);
ALvoid ReleaseALDatabuffers(ALCdevice *device);
#ifdef __cplusplus
}
#endif
#endif
+200 -15
View File
@@ -1,3 +1,5 @@
// NOTE: The effect structure is getting too large, it may be a good idea to
// start using a union or another form of unified storage.
#ifndef _AL_EFFECT_H_
#define _AL_EFFECT_H_
@@ -22,6 +24,7 @@ extern "C" {
#define AL_EFFECT_AUTOWAH 0x000A
#define AL_EFFECT_COMPRESSOR 0x000B
#define AL_EFFECT_EQUALIZER 0x000C
#define AL_EFFECT_EAXREVERB 0x8000
#define AL_REVERB_DENSITY 0x0001
#define AL_REVERB_DIFFUSION 0x0002
@@ -37,16 +40,176 @@ extern "C" {
#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C
#define AL_REVERB_DECAY_HFLIMIT 0x000D
#define AL_REVERB_MIN_DENSITY (0.0f)
#define AL_REVERB_MAX_DENSITY (1.0f)
#define AL_REVERB_DEFAULT_DENSITY (1.0f)
#define AL_REVERB_MIN_DIFFUSION (0.0f)
#define AL_REVERB_MAX_DIFFUSION (1.0f)
#define AL_REVERB_DEFAULT_DIFFUSION (1.0f)
#define AL_REVERB_MIN_GAIN (0.0f)
#define AL_REVERB_MAX_GAIN (1.0f)
#define AL_REVERB_DEFAULT_GAIN (0.32f)
#define AL_REVERB_MIN_GAINHF (0.0f)
#define AL_REVERB_MAX_GAINHF (1.0f)
#define AL_REVERB_DEFAULT_GAINHF (0.89f)
#define AL_REVERB_MIN_DECAY_TIME (0.1f)
#define AL_REVERB_MAX_DECAY_TIME (20.0f)
#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f)
#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f)
#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f)
#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f)
#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f)
#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f)
#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f)
#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f)
#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f)
#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f)
#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f)
#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f)
#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_REVERB_MIN_DECAY_HFLIMIT (AL_FALSE)
#define AL_REVERB_MAX_DECAY_HFLIMIT (AL_TRUE)
#define AL_REVERB_DEFAULT_DECAY_HFLIMIT (AL_TRUE)
typedef struct ALeffect_struct
#define AL_ECHO_DELAY 0x0001
#define AL_ECHO_LRDELAY 0x0002
#define AL_ECHO_DAMPING 0x0003
#define AL_ECHO_FEEDBACK 0x0004
#define AL_ECHO_SPREAD 0x0005
#define AL_ECHO_MIN_DELAY (0.0f)
#define AL_ECHO_MAX_DELAY (0.207f)
#define AL_ECHO_DEFAULT_DELAY (0.1f)
#define AL_ECHO_MIN_LRDELAY (0.0f)
#define AL_ECHO_MAX_LRDELAY (0.404f)
#define AL_ECHO_DEFAULT_LRDELAY (0.1f)
#define AL_ECHO_MIN_DAMPING (0.0f)
#define AL_ECHO_MAX_DAMPING (0.99f)
#define AL_ECHO_DEFAULT_DAMPING (0.5f)
#define AL_ECHO_MIN_FEEDBACK (0.0f)
#define AL_ECHO_MAX_FEEDBACK (1.0f)
#define AL_ECHO_DEFAULT_FEEDBACK (0.5f)
#define AL_ECHO_MIN_SPREAD (-1.0f)
#define AL_ECHO_MAX_SPREAD (1.0f)
#define AL_ECHO_DEFAULT_SPREAD (-1.0f)
#define AL_EAXREVERB_DENSITY 0x0001
#define AL_EAXREVERB_DIFFUSION 0x0002
#define AL_EAXREVERB_GAIN 0x0003
#define AL_EAXREVERB_GAINHF 0x0004
#define AL_EAXREVERB_GAINLF 0x0005
#define AL_EAXREVERB_DECAY_TIME 0x0006
#define AL_EAXREVERB_DECAY_HFRATIO 0x0007
#define AL_EAXREVERB_DECAY_LFRATIO 0x0008
#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009
#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A
#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B
#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C
#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D
#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E
#define AL_EAXREVERB_ECHO_TIME 0x000F
#define AL_EAXREVERB_ECHO_DEPTH 0x0010
#define AL_EAXREVERB_MODULATION_TIME 0x0011
#define AL_EAXREVERB_MODULATION_DEPTH 0x0012
#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013
#define AL_EAXREVERB_HFREFERENCE 0x0014
#define AL_EAXREVERB_LFREFERENCE 0x0015
#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016
#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017
#define AL_EAXREVERB_MIN_DENSITY (0.0f)
#define AL_EAXREVERB_MAX_DENSITY (1.0f)
#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f)
#define AL_EAXREVERB_MIN_DIFFUSION (0.0f)
#define AL_EAXREVERB_MAX_DIFFUSION (1.0f)
#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f)
#define AL_EAXREVERB_MIN_GAIN (0.0f)
#define AL_EAXREVERB_MAX_GAIN (1.0f)
#define AL_EAXREVERB_DEFAULT_GAIN (0.32f)
#define AL_EAXREVERB_MIN_GAINHF (0.0f)
#define AL_EAXREVERB_MAX_GAINHF (1.0f)
#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f)
#define AL_EAXREVERB_MIN_GAINLF (0.0f)
#define AL_EAXREVERB_MAX_GAINLF (1.0f)
#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f)
#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f)
#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f)
#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f)
#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f)
#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f)
#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f)
#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f)
#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f)
#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f)
#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f)
#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f)
#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f)
#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f)
#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f)
#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f)
#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f)
#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f)
#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f)
#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f)
#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f)
#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f)
#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f)
#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f)
#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f)
#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f)
#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f)
#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f)
#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f)
#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f)
#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f)
#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f)
#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f)
#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f)
#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f)
#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f)
#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f)
#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f)
#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
#define AL_EAXREVERB_MIN_DECAY_HFLIMIT (AL_FALSE)
#define AL_EAXREVERB_MAX_DECAY_HFLIMIT (AL_TRUE)
#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT (AL_TRUE)
enum {
EAXREVERB = 0,
REVERB,
ECHO,
MAX_EFFECTS
};
extern ALboolean DisabledEffects[MAX_EFFECTS];
typedef struct ALeffect
{
// Effect type (AL_EFFECT_NULL, ...)
ALenum type;
struct {
// Shared Reverb Properties
ALfloat Density;
ALfloat Diffusion;
ALfloat Gain;
ALfloat GainHF;
ALfloat DecayTime;
@@ -58,29 +221,51 @@ typedef struct ALeffect_struct
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 {
ALfloat Delay;
ALfloat LRDelay;
ALfloat Damping;
ALfloat Feedback;
ALfloat Spread;
} Echo;
// Index to itself
ALuint effect;
struct ALeffect_struct *next;
struct ALeffect *next;
} ALeffect;
AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects);
AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect);
ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects);
ALboolean AL_APIENTRY alIsEffect(ALuint effect);
AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
ALvoid ReleaseALEffects(ALvoid);
ALvoid ReleaseALEffects(ALCdevice *device);
#ifdef __cplusplus
}
+54 -20
View File
@@ -2,18 +2,54 @@
#define _AL_FILTER_H_
#include "AL/al.h"
#include "alu.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FILTER_SECTIONS 2 /* 2 filter sections for 24 db/oct filter */
typedef struct {
float history[2*FILTER_SECTIONS]; /* history in filter */
float coef[4*FILTER_SECTIONS + 1]; /* coefficients of filter */
ALfloat coeff;
#ifndef _MSC_VER
ALfloat history[0];
#else
ALfloat history[1];
#endif
} FILTER;
static __inline ALfloat lpFilter4P(FILTER *iir, ALuint offset, ALfloat input)
{
ALfloat *history = &iir->history[offset];
ALfloat a = iir->coeff;
ALfloat output = input;
output = output + (history[0]-output)*a;
history[0] = output;
output = output + (history[1]-output)*a;
history[1] = output;
output = output + (history[2]-output)*a;
history[2] = output;
output = output + (history[3]-output)*a;
history[3] = output;
return output;
}
static __inline ALfloat lpFilter2P(FILTER *iir, ALuint offset, ALfloat input)
{
ALfloat *history = &iir->history[offset];
ALfloat a = iir->coeff;
ALfloat output = input;
output = output + (history[0]-output)*a;
history[0] = output;
output = output + (history[1]-output)*a;
history[1] = output;
return output;
}
#define AL_FILTER_TYPE 0x8001
#define AL_FILTER_NULL 0x0000
@@ -25,7 +61,7 @@ typedef struct {
#define AL_LOWPASS_GAINHF 0x0002
typedef struct ALfilter_struct
typedef struct ALfilter
{
// Filter type (AL_FILTER_NULL, ...)
ALenum type;
@@ -36,26 +72,24 @@ typedef struct ALfilter_struct
// Index to itself
ALuint filter;
struct ALfilter_struct *next;
struct ALfilter *next;
} ALfilter;
AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters);
AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter);
ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters);
ALboolean AL_APIENTRY alIsFilter(ALuint filter);
AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
ALvoid ReleaseALFilters(ALvoid);
int InitLowPassFilter(ALCcontext *Context, FILTER *iir);
ALvoid ReleaseALFilters(ALCdevice *device);
#ifdef __cplusplus
}
+123 -26
View File
@@ -3,8 +3,15 @@
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include "alu.h"
#ifdef HAVE_FENV_H
#include <fenv.h>
#endif
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#ifdef _WIN32
@@ -13,6 +20,12 @@
#endif
#include <windows.h>
typedef DWORD tls_type;
#define tls_create(x) (*(x) = TlsAlloc())
#define tls_delete(x) TlsFree((x))
#define tls_get(x) TlsGetValue((x))
#define tls_set(x, a) TlsSetValue((x), (a))
#else
#include <assert.h>
@@ -26,6 +39,12 @@
#define IsBadWritePtr(a,b) (0)
typedef pthread_key_t tls_type;
#define tls_create(x) pthread_key_create((x), NULL)
#define tls_delete(x) pthread_key_delete((x))
#define tls_get(x) pthread_getspecific((x))
#define tls_set(x, a) pthread_setspecific((x), (a))
typedef pthread_mutex_t CRITICAL_SECTION;
static inline void EnterCriticalSection(CRITICAL_SECTION *cs)
{
@@ -94,43 +113,57 @@ static inline void Sleep(ALuint t)
#define max(x,y) (((x)>(y))?(x):(y))
#endif
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "alListener.h"
#include "alu.h"
#ifdef __cplusplus
extern "C" {
#endif
extern char _alDebug[256];
static __inline void al_print(const char *fname, unsigned int line, const char *fmt, ...)
{
const char *fn;
char str[256];
int i;
#define AL_PRINT(...) do { \
int _al_print_i; \
const char *_al_print_fn = strrchr(__FILE__, '/'); \
if(!_al_print_fn) _al_print_fn = __FILE__; \
else _al_print_fn += 1; \
_al_print_i = snprintf(_alDebug, sizeof(_alDebug), "AL lib: %s:%d: ", _al_print_fn, __LINE__); \
if(_al_print_i < (int)sizeof(_alDebug) && _al_print_i > 0) \
snprintf(_alDebug+_al_print_i, sizeof(_alDebug)-_al_print_i, __VA_ARGS__); \
_alDebug[sizeof(_alDebug)-1] = 0; \
fprintf(stderr, "%s", _alDebug); \
} while(0)
fn = strrchr(fname, '/');
if(!fn) fn = strrchr(fname, '\\');;
if(!fn) fn = fname;
else fn += 1;
i = snprintf(str, sizeof(str), "AL lib: %s:%d: ", fn, line);
if(i < (int)sizeof(str) && i > 0)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(str+i, sizeof(str)-i, fmt, ap);
va_end(ap);
}
str[sizeof(str)-1] = 0;
fprintf(stderr, "%s", str);
}
#define AL_PRINT(...) al_print(__FILE__, __LINE__, __VA_ARGS__)
#define SWMIXER_OUTPUT_RATE 44100
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINHF (0.994f)
#define AIRABSORBGAINDBHF (-0.05f)
#define LOWPASSFREQCUTOFF (5000)
#define QUADRANT_NUM 128
#define LUT_NUM (4 * QUADRANT_NUM)
typedef struct {
ALCboolean (*OpenPlayback)(ALCdevice*, const ALCchar*);
void (*ClosePlayback)(ALCdevice*);
ALCboolean (*ResetPlayback)(ALCdevice*);
void (*StopPlayback)(ALCdevice*);
ALCboolean (*OpenCapture)(ALCdevice*, const ALCchar*, ALCuint, ALCenum, ALCsizei);
ALCboolean (*OpenCapture)(ALCdevice*, const ALCchar*);
void (*CloseCapture)(ALCdevice*);
void (*StartCapture)(ALCdevice*);
void (*StopCapture)(ALCdevice*);
@@ -138,25 +171,78 @@ typedef struct {
ALCuint (*AvailableSamples)(ALCdevice*);
} BackendFuncs;
enum {
DEVICE_PROBE,
ALL_DEVICE_PROBE,
CAPTURE_DEVICE_PROBE
};
void alc_alsa_init(BackendFuncs *func_list);
void alc_alsa_deinit(void);
void alc_alsa_probe(int type);
void alc_oss_init(BackendFuncs *func_list);
void alc_oss_deinit(void);
void alc_oss_probe(int type);
void alc_solaris_init(BackendFuncs *func_list);
void alc_solaris_deinit(void);
void alc_solarise_probe(int type);
void alcDSoundInit(BackendFuncs *func_list);
void alcDSoundDeinit(void);
void alcDSoundProbe(int type);
void alcWinMMInit(BackendFuncs *FuncList);
void alcWinMMDeinit(void);
void alcWinMMProbe(int type);
void alc_pa_init(BackendFuncs *func_list);
void alc_pa_deinit(void);
void alc_pa_probe(int type);
void alc_wave_init(BackendFuncs *func_list);
void alc_wave_deinit(void);
void alc_wave_probe(int type);
void alc_pulse_init(BackendFuncs *func_list);
void alc_pulse_deinit(void);
void alc_pulse_probe(int type);
struct ALCdevice_struct
{
ALCboolean Connected;
ALboolean IsCaptureDevice;
ALuint Frequency;
ALuint UpdateSize;
ALuint NumUpdates;
ALenum Format;
ALCchar *szDeviceName;
// Maximum number of sources that can be created
ALuint MaxNoOfSources;
// Maximum number of slots that can be created
ALuint AuxiliaryEffectSlotMax;
ALint lNumMonoSources;
ALint lNumStereoSources;
ALuint NumAuxSends;
// Linked List of Buffers for this device
struct ALbuffer *Buffers;
ALuint BufferCount;
// Linked List of Effects for this device
struct ALeffect *EffectList;
ALuint EffectCount;
// Linked List of Filters for this device
struct ALfilter *FilterList;
ALuint FilterCount;
// Linked List of Databuffers for this device
struct ALdatabuffer *Databuffers;
ALuint DatabufferCount;
// Stereo-to-binaural filter
struct bs2b *Bs2b;
ALCint Bs2bLevel;
// Context created on this device
ALCcontext *Context;
@@ -169,7 +255,9 @@ struct ALCdevice_struct
#define ALCdevice_OpenPlayback(a,b) ((a)->Funcs->OpenPlayback((a), (b)))
#define ALCdevice_ClosePlayback(a) ((a)->Funcs->ClosePlayback((a)))
#define ALCdevice_OpenCapture(a,b,c,d,e) ((a)->Funcs->OpenCapture((a), (b), (c), (d), (e)))
#define ALCdevice_ResetPlayback(a) ((a)->Funcs->ResetPlayback((a)))
#define ALCdevice_StopPlayback(a) ((a)->Funcs->StopPlayback((a)))
#define ALCdevice_OpenCapture(a,b) ((a)->Funcs->OpenCapture((a), (b)))
#define ALCdevice_CloseCapture(a) ((a)->Funcs->CloseCapture((a)))
#define ALCdevice_StartCapture(a) ((a)->Funcs->StartCapture((a)))
#define ALCdevice_StopCapture(a) ((a)->Funcs->StopCapture((a)))
@@ -186,6 +274,9 @@ struct ALCcontext_struct
struct ALeffectslot *AuxiliaryEffectSlot;
ALuint AuxiliaryEffectSlotCount;
struct ALdatabuffer *SampleSource;
struct ALdatabuffer *SampleSink;
ALenum LastError;
ALboolean InUse;
@@ -197,22 +288,22 @@ struct ALCcontext_struct
ALfloat DopplerVelocity;
ALfloat flSpeedOfSound;
ALint lNumMonoSources;
ALint lNumStereoSources;
ALfloat PanningLUT[OUTPUTCHANNELS * LUT_NUM];
ALint NumChan;
ALfloat ChannelMatrix[OUTPUTCHANNELS][OUTPUTCHANNELS];
ALCdevice *Device;
const ALCchar *ExtensionList;
struct bs2b *bs2b;
ALCcontext *next;
};
ALCvoid ReleaseALC(ALCvoid);
ALCchar *AppendDeviceList(char *name);
ALCchar *AppendAllDeviceList(char *name);
ALCchar *AppendCaptureDeviceList(char *name);
void AppendDeviceList(const ALCchar *name);
void AppendAllDeviceList(const ALCchar *name);
void AppendCaptureDeviceList(const ALCchar *name);
ALCvoid SetALCError(ALenum errorCode);
@@ -222,6 +313,8 @@ ALCvoid ProcessContext(ALCcontext *context);
ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr);
ALuint StopThread(ALvoid *thread);
ALCcontext *GetContextSuspended(void);
typedef struct RingBuffer RingBuffer;
RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length);
void DestroyRingBuffer(RingBuffer *ring);
@@ -234,6 +327,10 @@ void FreeALConfig(void);
const char *GetConfigValue(const char *blockName, const char *keyName, const char *def);
int GetConfigValueInt(const char *blockName, const char *keyName, int def);
float GetConfigValueFloat(const char *blockName, const char *keyName, float def);
int GetConfigValueBool(const char *blockName, const char *keyName, float def);
ALCboolean ALCAPIENTRY alcMakeCurrent(ALCcontext *context);
ALCcontext* ALCAPIENTRY alcGetThreadContext(void);
#ifdef __cplusplus
}
+13 -9
View File
@@ -3,10 +3,10 @@
#define AL_NUM_SOURCE_PARAMS 128
/* This cannot be changed without working on the code! */
#define MAX_SENDS 1
#define MAX_SENDS 2
#include "alFilter.h"
#include "alu.h"
#include "AL/al.h"
#define AL_DIRECT_FILTER 0x20005
@@ -47,6 +47,7 @@ typedef struct ALsource
ALfloat vOrientation[3];
ALboolean bHeadRelative;
ALboolean bLooping;
ALenum DistanceModel;
ALuint ulBufferID;
@@ -55,19 +56,18 @@ typedef struct ALsource
ALenum state;
ALuint position;
ALuint position_fraction;
struct ALbufferlistitem *queue; // Linked list of buffers in queue
ALuint BuffersInQueue; // Number of buffers in queue
ALuint BuffersProcessed; // Number of buffers already processed (played)
ALuint TotalBufferDataSize; // Total amount of data contained in the buffers queued for this source
ALuint BuffersPlayed; // Number of buffers played on this loop
ALuint BufferPosition; // Read position in audio data of current buffer
ALuint BuffersPlayed; // Number of buffers played on this loop
ALfilter DirectFilter;
struct {
struct ALeffectslot *Slot;
ALfilter WetFilter;
FILTER iirFilter;
ALfloat history[2];
} Send[MAX_SENDS];
ALboolean DryGainHFAuto;
@@ -76,6 +76,7 @@ typedef struct ALsource
ALfloat OuterGainHF;
FILTER iirFilter;
ALfloat history[OUTPUTCHANNELS*2];
ALfloat AirAbsorptionFactor;
@@ -86,14 +87,17 @@ typedef struct ALsource
// Index to itself
ALuint source;
ALint lBytesPlayed;
ALint lOffset;
ALint lOffsetType;
// Source Type (Static, Streaming, or Undetermined)
ALint lSourceType;
// Current gains, which are ramped while mixed
ALfloat DryGains[OUTPUTCHANNELS];
ALfloat WetGains[MAX_SENDS];
ALboolean FirstStart;
struct ALsource *next;
} ALsource;
+138 -3
View File
@@ -3,16 +3,151 @@
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#ifdef HAVE_FLOAT_H
#include <float.h>
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
#define M_PI_2 1.57079632679489661923 /* pi/2 */
#endif
#ifdef HAVE_SQRTF
#define aluSqrt(x) ((ALfloat)sqrtf((float)(x)))
#else
#define aluSqrt(x) ((ALfloat)sqrt((double)(x)))
#endif
#ifdef HAVE_ACOSF
#define aluAcos(x) ((ALfloat)acosf((float)(x)))
#else
#define aluAcos(x) ((ALfloat)acos((double)(x)))
#endif
#ifdef HAVE_ATANF
#define aluAtan(x) ((ALfloat)atanf((float)(x)))
#else
#define aluAtan(x) ((ALfloat)atan((double)(x)))
#endif
#ifdef HAVE_FABSF
#define aluFabs(x) ((ALfloat)fabsf((float)(x)))
#else
#define aluFabs(x) ((ALfloat)fabs((double)(x)))
#endif
// fixes for mingw32.
#if defined(max) && !defined(__max)
#define __max max
#endif
#if defined(min) && !defined(__min)
#define __min min
#endif
#ifdef __cplusplus
extern "C" {
#endif
enum {
FRONT_LEFT = 0,
FRONT_RIGHT,
FRONT_CENTER,
SIDE_LEFT,
SIDE_RIGHT,
BACK_LEFT,
BACK_RIGHT,
BACK_CENTER,
LFE,
OUTPUTCHANNELS
};
#define BUFFERSIZE 24000
extern ALboolean DuplicateStereo;
__inline ALuint aluBytesFromFormat(ALenum format);
__inline ALuint aluChannelsFromFormat(ALenum format);
ALvoid aluMixData(ALCcontext *context,ALvoid *buffer,ALsizei size,ALenum format);
/* NOTE: The AL_FORMAT_REAR* enums aren't handled here be cause they're
* converted to AL_FORMAT_QUAD* when loaded */
static __inline ALuint aluBytesFromFormat(ALenum format)
{
switch(format)
{
case AL_FORMAT_MONO8:
case AL_FORMAT_STEREO8:
case AL_FORMAT_QUAD8_LOKI:
case AL_FORMAT_QUAD8:
case AL_FORMAT_51CHN8:
case AL_FORMAT_61CHN8:
case AL_FORMAT_71CHN8:
return 1;
case AL_FORMAT_MONO16:
case AL_FORMAT_STEREO16:
case AL_FORMAT_QUAD16_LOKI:
case AL_FORMAT_QUAD16:
case AL_FORMAT_51CHN16:
case AL_FORMAT_61CHN16:
case AL_FORMAT_71CHN16:
return 2;
case AL_FORMAT_MONO_FLOAT32:
case AL_FORMAT_STEREO_FLOAT32:
case AL_FORMAT_QUAD32:
case AL_FORMAT_51CHN32:
case AL_FORMAT_61CHN32:
case AL_FORMAT_71CHN32:
return 4;
default:
return 0;
}
}
static __inline ALuint aluChannelsFromFormat(ALenum format)
{
switch(format)
{
case AL_FORMAT_MONO8:
case AL_FORMAT_MONO16:
case AL_FORMAT_MONO_FLOAT32:
return 1;
case AL_FORMAT_STEREO8:
case AL_FORMAT_STEREO16:
case AL_FORMAT_STEREO_FLOAT32:
return 2;
case AL_FORMAT_QUAD8_LOKI:
case AL_FORMAT_QUAD16_LOKI:
case AL_FORMAT_QUAD8:
case AL_FORMAT_QUAD16:
case AL_FORMAT_QUAD32:
return 4;
case AL_FORMAT_51CHN8:
case AL_FORMAT_51CHN16:
case AL_FORMAT_51CHN32:
return 6;
case AL_FORMAT_61CHN8:
case AL_FORMAT_61CHN16:
case AL_FORMAT_61CHN32:
return 7;
case AL_FORMAT_71CHN8:
case AL_FORMAT_71CHN16:
case AL_FORMAT_71CHN32:
return 8;
default:
return 0;
}
}
ALvoid aluInitPanning(ALCcontext *Context);
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
ALvoid aluHandleDisconnect(ALCdevice *device);
#ifdef __cplusplus
}
+64 -143
View File
@@ -34,23 +34,19 @@
static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect);
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCcontext *Context;
ALsizei i;
ALsizei i, j;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (n > 0)
{
/* NOTE: We only support one slot currently */
if(n == 1 && Context->AuxiliaryEffectSlotCount == 0)
ALCdevice *Device = Context->Device;
if(Context->AuxiliaryEffectSlotCount+n <= Device->AuxiliaryEffectSlotMax)
{
// Check that enough memory has been allocted in the 'effectslots' array for n Effect Slots
if (!IsBadWritePtr((void*)effectslots, n * sizeof(ALuint)))
@@ -71,10 +67,10 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
break;
}
InitLowPassFilter(Context, &(*list)->iirFilter);
(*list)->Gain = 1.0;
(*list)->AuxSendAuto = AL_TRUE;
for(j = 0;j < BUFFERSIZE;j++)
(*list)->WetBuffer[j] = 0.0f;
(*list)->refcount = 0;
effectslots[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
@@ -94,19 +90,14 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCcontext *Context;
ALeffectslot *ALAuxiliaryEffectSlot;
ALsizei i;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (n >= 0)
{
@@ -150,7 +141,8 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effect
*list = (*list)->next;
ALTHUNK_REMOVEENTRY(ALAuxiliaryEffectSlot->effectslot);
free(ALAuxiliaryEffectSlot->ReverbBuffer);
if(ALAuxiliaryEffectSlot->EffectState)
ALEffect_Destroy(ALAuxiliaryEffectSlot->EffectState);
memset(ALAuxiliaryEffectSlot, 0, sizeof(ALeffectslot));
free(ALAuxiliaryEffectSlot);
@@ -166,18 +158,13 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effect
ProcessContext(Context);
}
AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
{
ALCcontext *Context;
ALeffectslot **list;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return AL_FALSE;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return AL_FALSE;
list = &Context->AuxiliaryEffectSlot;
while(*list && (*list)->effectslot != effectslot)
@@ -188,17 +175,12 @@ AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
return (*list ? AL_TRUE : AL_FALSE);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (alIsAuxiliaryEffectSlot(effectslot))
{
@@ -234,17 +216,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (alIsAuxiliaryEffectSlot(effectslot))
{
@@ -266,17 +243,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (alIsAuxiliaryEffectSlot(effectslot))
{
@@ -302,17 +274,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (alIsAuxiliaryEffectSlot(effectslot))
{
@@ -333,17 +300,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (alIsAuxiliaryEffectSlot(effectslot))
{
@@ -370,17 +332,12 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (alIsAuxiliaryEffectSlot(effectslot))
{
@@ -402,17 +359,12 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (alIsAuxiliaryEffectSlot(effectslot))
{
@@ -435,17 +387,12 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (alIsAuxiliaryEffectSlot(effectslot))
{
@@ -469,71 +416,45 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p
static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect)
{
ALfloat *ptr = NULL;
if((!effect) || (effect->type != ALEffectSlot->effect.type))
{
ALeffectState *NewState = NULL;
if(effect)
{
if(effect->type == AL_EFFECT_EAXREVERB)
NewState = EAXVerbCreate(Context);
else if(effect->type == AL_EFFECT_REVERB)
NewState = VerbCreate(Context);
else if(effect->type == AL_EFFECT_ECHO)
NewState = EchoCreate(Context);
/* No new state? An error occured.. */
if(!NewState)
return;
}
if(ALEffectSlot->EffectState)
ALEffect_Destroy(ALEffectSlot->EffectState);
ALEffectSlot->EffectState = NewState;
}
if(!effect)
{
memset(&ALEffectSlot->effect, 0, sizeof(ALEffectSlot->effect));
goto done;
return;
}
if(effect->type == AL_EFFECT_REVERB)
{
ALuint size;
ALfloat reverbwait;
reverbwait = (1.0f-effect->Reverb.Density)*(0.1f-0.075f) + 0.075f;
size = (ALuint)((ALfloat)Context->Frequency *
(effect->Reverb.ReflectionsDelay +
effect->Reverb.LateReverbDelay +
reverbwait)) + 1;
ptr = calloc(size, sizeof(ALfloat));
if(!ptr)
{
alSetError(AL_OUT_OF_MEMORY);
return;
}
if(ALEffectSlot->ReverbBuffer)
memcpy(ptr, ALEffectSlot->ReverbBuffer, min(size, ALEffectSlot->ReverbLength)*sizeof(ALfloat));
ALEffectSlot->ReverbLength = size;
ALEffectSlot->ReverbPos %= size;
ALEffectSlot->ReverbReflectPos = (ALuint)(ALEffectSlot->ReverbLength -
((ALfloat)Context->Frequency *
effect->Reverb.ReflectionsDelay) +
ALEffectSlot->ReverbPos) %
ALEffectSlot->ReverbLength;
ALEffectSlot->ReverbLatePos = (ALuint)(ALEffectSlot->ReverbLength -
((ALfloat)Context->Frequency *
(effect->Reverb.LateReverbDelay +
effect->Reverb.ReflectionsDelay)) +
ALEffectSlot->ReverbPos) %
ALEffectSlot->ReverbLength;
ALEffectSlot->ReverbDecayGain = pow(1.0/32768.0, 1.0/(effect->Reverb.DecayTime/reverbwait));
}
memcpy(&ALEffectSlot->effect, effect, sizeof(*effect));
done:
free(ALEffectSlot->ReverbBuffer);
ALEffectSlot->ReverbBuffer = ptr;
ALEffect_Update(ALEffectSlot->EffectState, Context, effect);
}
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
{
#ifdef _DEBUG
if(Context->AuxiliaryEffectSlotCount > 0)
AL_PRINT("alcDestroyContext(): deleting %d AuxiliaryEffectSlot(s)\n", Context->AuxiliaryEffectSlotCount);
#endif
while(Context->AuxiliaryEffectSlot)
{
ALeffectslot *temp = Context->AuxiliaryEffectSlot;
Context->AuxiliaryEffectSlot = Context->AuxiliaryEffectSlot->next;
// Release effectslot structure
free(temp->ReverbBuffer);
if(temp->EffectState)
ALEffect_Destroy(temp->EffectState);
ALTHUNK_REMOVEENTRY(temp->effectslot);
memset(temp, 0, sizeof(ALeffectslot));
+367 -379
View File
@@ -18,8 +18,6 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#define _CRT_SECURE_NO_DEPRECATE // get rid of sprintf security warnings on VS2005
#include "config.h"
#include <stdlib.h>
@@ -30,10 +28,14 @@
#include "AL/alc.h"
#include "alError.h"
#include "alBuffer.h"
#include "alDatabuffer.h"
#include "alThunk.h"
static void LoadData(ALbuffer *ALBuf, const ALubyte *data, ALsizei size, ALuint freq, ALenum OrigFormat, ALenum NewFormat);
static void ConvertData(ALshort *dst, const ALvoid *src, ALint origBytes, ALsizei len);
static void ConvertDataRear(ALshort *dst, const ALvoid *src, ALint origBytes, ALsizei len);
static void ConvertDataIMA4(ALshort *dst, const ALvoid *src, ALint origChans, ALsizei len);
/*
* AL Buffer Functions
@@ -48,9 +50,6 @@ static void LoadData(ALbuffer *ALBuf, const ALubyte *data, ALsizei size, ALuint
* Global Variables
*/
static ALbuffer *g_pBuffers = NULL; // Linked List of Buffers
static ALuint g_uiBufferCount = 0; // Buffer Count
static const long g_IMAStep_size[89]={ // IMA ADPCM Stepsize table
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143,
@@ -80,16 +79,18 @@ ALAPI ALvoid ALAPIENTRY alGenBuffers(ALsizei n,ALuint *puiBuffers)
ALCcontext *Context;
ALsizei i=0;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
// Check that we are actually generation some Buffers
if (n > 0)
{
ALCdevice *device = Context->Device;
// Check the pointer is valid (and points to enough memory to store Buffer Names)
if (!IsBadWritePtr((void*)puiBuffers, n * sizeof(ALuint)))
{
ALbuffer **list = &g_pBuffers;
ALbuffer **list = &device->Buffers;
while(*list)
list = &(*list)->next;
@@ -106,7 +107,7 @@ ALAPI ALvoid ALAPIENTRY alGenBuffers(ALsizei n,ALuint *puiBuffers)
puiBuffers[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
(*list)->state = UNUSED;
g_uiBufferCount++;
device->BufferCount++;
i++;
list = &(*list)->next;
@@ -136,12 +137,14 @@ ALAPI ALvoid ALAPIENTRY alDeleteBuffers(ALsizei n, const ALuint *puiBuffers)
ALsizei i;
ALboolean bFailed = AL_FALSE;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
// Check we are actually Deleting some Buffers
if (n >= 0)
{
ALCdevice *device = Context->Device;
// Check that all the buffers are valid and can actually be deleted
for (i = 0; i < n; i++)
{
@@ -175,7 +178,7 @@ ALAPI ALvoid ALAPIENTRY alDeleteBuffers(ALsizei n, const ALuint *puiBuffers)
{
if (puiBuffers[i] && alIsBuffer(puiBuffers[i]))
{
ALbuffer **list = &g_pBuffers;
ALbuffer **list = &device->Buffers;
ALBuf=((ALbuffer *)ALTHUNK_LOOKUPENTRY(puiBuffers[i]));
while(*list && *list != ALBuf)
@@ -190,7 +193,7 @@ ALAPI ALvoid ALAPIENTRY alDeleteBuffers(ALsizei n, const ALuint *puiBuffers)
// Release buffer structure
ALTHUNK_REMOVEENTRY(puiBuffers[i]);
memset(ALBuf, 0, sizeof(ALbuffer));
g_uiBufferCount--;
device->BufferCount--;
free(ALBuf);
}
}
@@ -217,15 +220,17 @@ ALAPI ALboolean ALAPIENTRY alIsBuffer(ALuint uiBuffer)
ALbuffer *ALBuf;
ALbuffer *TgtALBuf;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return AL_FALSE;
if (uiBuffer)
{
ALCdevice *device = Context->Device;
TgtALBuf = (ALbuffer *)ALTHUNK_LOOKUPENTRY(uiBuffer);
// Check through list of generated buffers for uiBuffer
ALBuf = g_pBuffers;
ALBuf = device->Buffers;
while (ALBuf)
{
if (ALBuf == TgtALBuf)
@@ -255,23 +260,33 @@ ALAPI ALboolean ALAPIENTRY alIsBuffer(ALuint uiBuffer)
*/
ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *data,ALsizei size,ALsizei freq)
{
ALuint *IMAData,IMACode;
ALCcontext *Context;
ALint Sample,Index;
ALint LeftSample,LeftIndex;
ALint RightSample,RightIndex;
ALuint LeftIMACode,RightIMACode;
ALsizei padding = 2;
ALbuffer *ALBuf;
ALsizei padding;
ALsizei i,j,k;
ALvoid *temp;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (alIsBuffer(buffer) && (buffer != 0))
{
ALBuf=((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer));
if(Context->SampleSource)
{
ALuint offset;
if(Context->SampleSource->state == MAPPED)
{
alSetError(AL_INVALID_OPERATION);
ProcessContext(Context);
return;
}
offset = (ALuint)data;
data = Context->SampleSource->data + offset;
}
if ((ALBuf->refcount==0)&&(data))
{
switch(format)
@@ -296,113 +311,35 @@ ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *d
ALuint OrigBytes = ((format==AL_FORMAT_REAR8) ? 1 :
((format==AL_FORMAT_REAR16) ? 2 :
4));
ALsizei i;
assert(aluBytesFromFormat(NewFormat) == 2);
if ((size%(OrigBytes*2)) != 0)
if((size%(OrigBytes*2)) != 0)
{
alSetError(AL_INVALID_VALUE);
break;
}
padding = freq / LOWPASSFREQCUTOFF;
if(padding < 1) padding = 1;
size /= OrigBytes;
size *= 2;
switch(OrigBytes)
// Samples are converted to 16 bit here
temp = realloc(ALBuf->data, (padding*NewChannels + size) * sizeof(ALshort));
if(temp)
{
case 1:
size /= sizeof(ALubyte);
size *= 2;
ALBuf->data = temp;
ConvertDataRear(ALBuf->data, data, OrigBytes, size);
// 8bit Samples are converted to 16 bit here
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
for (i = 0;i < size;i+=4)
{
ALBuf->data[i+0] = 0;
ALBuf->data[i+1] = 0;
ALBuf->data[i+2] = (ALshort)((((ALubyte*)data)[i/2+0]-128) << 8);
ALBuf->data[i+3] = (ALshort)((((ALubyte*)data)[i/2+1]-128) << 8);
}
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
memset(&(ALBuf->data[size]), 0, padding*NewChannels*sizeof(ALshort));
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
case 2:
size /= sizeof(ALshort);
size *= 2;
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
for (i = 0;i < size;i+=4)
{
ALBuf->data[i+0] = 0;
ALBuf->data[i+1] = 0;
ALBuf->data[i+2] = ((ALshort*)data)[i/2+0];
ALBuf->data[i+3] = ((ALshort*)data)[i/2+1];
}
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
case 4:
size /= sizeof(ALfloat);
size *= 2;
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALint smp;
ALBuf->data = temp;
for (i = 0;i < size;i+=4)
{
ALBuf->data[i+0] = 0;
ALBuf->data[i+1] = 0;
smp = (((ALfloat*)data)[i/2+0] * 32767.5f - 0.5);
smp = min(smp, 32767);
smp = max(smp, -32768);
ALBuf->data[i+2] = (ALshort)smp;
smp = (((ALfloat*)data)[i/2+1] * 32767.5f - 0.5);
smp = min(smp, 32767);
smp = max(smp, -32768);
ALBuf->data[i+3] = (ALshort)smp;
}
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
default:
assert(0);
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
} break;
case AL_FORMAT_QUAD8_LOKI:
@@ -432,167 +369,39 @@ ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *d
break;
case AL_FORMAT_MONO_IMA4:
padding = freq / LOWPASSFREQCUTOFF;
if(padding < 1) padding = 1;
case AL_FORMAT_STEREO_IMA4: {
int OrigChans = ((format==AL_FORMAT_MONO_IMA4) ? 1 : 2);
// Here is where things vary:
// nVidia and Apple use 64+1 samples per block => block_size=36 bytes
// Most PC sound software uses 2040+1 samples per block -> block_size=1024 bytes
if ((size%36) == 0)
// nVidia and Apple use 64+1 samples per channel per block => block_size=36*chans bytes
// Most PC sound software uses 2040+1 samples per channel per block -> block_size=1024*chans bytes
if((size%(36*OrigChans)) != 0)
{
// Allocate extra padding samples
temp=realloc(ALBuf->data,padding*2+(size/36)*(65*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
ALBuf->format = AL_FORMAT_MONO16;
ALBuf->eOriginalFormat = AL_FORMAT_MONO_IMA4;
IMAData=(ALuint *)data;
for (i=0;i<size/36;i++)
{
Sample=((ALshort *)IMAData)[0];
Index=((ALshort *)IMAData)[1];
Index=Index<0?0:Index;
Index=Index>88?88:Index;
ALBuf->data[i*65]=(short)Sample;
IMAData++;
for (j=1;j<65;j+=8)
{
IMACode=*IMAData;
for (k=0;k<8;k+=2)
{
Sample+=((g_IMAStep_size[Index]*g_IMACodeword_4[IMACode&15])/8);
Index+=g_IMAIndex_adjust_4[IMACode&15];
if (Sample<-32768) Sample=-32768;
else if (Sample>32767) Sample=32767;
if (Index<0) Index=0;
else if (Index>88) Index=88;
ALBuf->data[i*65+j+k]=(short)Sample;
IMACode>>=4;
Sample+=((g_IMAStep_size[Index]*g_IMACodeword_4[IMACode&15])/8);
Index+=g_IMAIndex_adjust_4[IMACode&15];
if (Sample<-32768) Sample=-32768;
else if (Sample>32767) Sample=32767;
if (Index<0) Index=0;
else if (Index>88) Index=88;
ALBuf->data[i*65+j+k+1]=(short)Sample;
IMACode>>=4;
}
IMAData++;
}
}
memset(&(ALBuf->data[(size/36*65)]), 0, padding*2);
ALBuf->size=size/36*65*sizeof(ALshort);
ALBuf->frequency=freq;
ALBuf->padding=padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
else
alSetError(AL_INVALID_VALUE);
break;
case AL_FORMAT_STEREO_IMA4:
padding = freq / LOWPASSFREQCUTOFF;
if(padding < 1) padding = 1;
// Here is where things vary:
// nVidia and Apple use 64+1 samples per channel per block => block_size=72 bytes
// Most PC sound software uses 2040+1 samples per channel per block -> block_size=2048 bytes
if ((size%72) == 0)
{
// Allocate extra padding samples
temp=realloc(ALBuf->data,padding*2*2+(size/72)*(2*65*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
ALBuf->format = AL_FORMAT_STEREO16;
ALBuf->eOriginalFormat = AL_FORMAT_STEREO_IMA4;
IMAData=(ALuint *)data;
for (i=0;i<size/72;i++)
{
LeftSample=((ALshort *)IMAData)[0];
LeftIndex=((ALshort *)IMAData)[1];
LeftIndex=LeftIndex<0?0:LeftIndex;
LeftIndex=LeftIndex>88?88:LeftIndex;
ALBuf->data[i*2*65]=(short)LeftSample;
IMAData++;
RightSample=((ALshort *)IMAData)[0];
RightIndex=((ALshort *)IMAData)[1];
RightIndex=RightIndex<0?0:RightIndex;
RightIndex=RightIndex>88?88:RightIndex;
ALBuf->data[i*2*65+1]=(short)RightSample;
IMAData++;
for (j=2;j<130;j+=16)
{
LeftIMACode=IMAData[0];
RightIMACode=IMAData[1];
for (k=0;k<16;k+=4)
{
LeftSample+=((g_IMAStep_size[LeftIndex]*g_IMACodeword_4[LeftIMACode&15])/8);
LeftIndex+=g_IMAIndex_adjust_4[LeftIMACode&15];
if (LeftSample<-32768) LeftSample=-32768;
else if (LeftSample>32767) LeftSample=32767;
if (LeftIndex<0) LeftIndex=0;
else if (LeftIndex>88) LeftIndex=88;
ALBuf->data[i*2*65+j+k]=(short)LeftSample;
LeftIMACode>>=4;
RightSample+=((g_IMAStep_size[RightIndex]*g_IMACodeword_4[RightIMACode&15])/8);
RightIndex+=g_IMAIndex_adjust_4[RightIMACode&15];
if (RightSample<-32768) RightSample=-32768;
else if (RightSample>32767) RightSample=32767;
if (RightIndex<0) RightIndex=0;
else if (RightIndex>88) RightIndex=88;
ALBuf->data[i*2*65+j+k+1]=(short)RightSample;
RightIMACode>>=4;
LeftSample+=((g_IMAStep_size[LeftIndex]*g_IMACodeword_4[LeftIMACode&15])/8);
LeftIndex+=g_IMAIndex_adjust_4[LeftIMACode&15];
if (LeftSample<-32768) LeftSample=-32768;
else if (LeftSample>32767) LeftSample=32767;
if (LeftIndex<0) LeftIndex=0;
else if (LeftIndex>88) LeftIndex=88;
ALBuf->data[i*2*65+j+k+2]=(short)LeftSample;
LeftIMACode>>=4;
RightSample+=((g_IMAStep_size[RightIndex]*g_IMACodeword_4[RightIMACode&15])/8);
RightIndex+=g_IMAIndex_adjust_4[RightIMACode&15];
if (RightSample<-32768) RightSample=-32768;
else if (RightSample>32767) RightSample=32767;
if (RightIndex<0) RightIndex=0;
else if (RightIndex>88) RightIndex=88;
ALBuf->data[i*2*65+j+k+3]=(short)RightSample;
RightIMACode>>=4;
}
IMAData+=2;
}
}
memset(&(ALBuf->data[(size/72*2*65)]), 0, padding*2*2);
ALBuf->size=size/72*2*65*sizeof(ALshort);
ALBuf->frequency=freq;
ALBuf->padding=padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
else
alSetError(AL_INVALID_VALUE);
break;
break;
}
size /= 36;
size *= 65;
// Allocate extra padding samples
temp = realloc(ALBuf->data, (padding*OrigChans + size)*sizeof(ALshort));
if(temp)
{
ALBuf->data = temp;
ConvertDataIMA4(ALBuf->data, data, OrigChans, size/65);
memset(&(ALBuf->data[size]), 0, padding*sizeof(ALshort)*OrigChans);
ALBuf->format = ((OrigChans==1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16);
ALBuf->eOriginalFormat = format;
ALBuf->size = size*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
} break;
default:
alSetError(AL_INVALID_ENUM);
@@ -614,6 +423,126 @@ ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *d
ProcessContext(Context);
}
/*
* alBufferSubDataEXT(ALuint buffer,ALenum format,ALvoid *data,ALsizei offset,ALsizei length)
*
* Fill buffer with audio data
*/
ALvoid ALAPIENTRY alBufferSubDataEXT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length)
{
ALCcontext *Context;
ALbuffer *ALBuf;
Context = GetContextSuspended();
if(!Context) return;
if(alIsBuffer(buffer) && buffer != 0)
{
ALBuf = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffer);
if(Context->SampleSource)
{
ALuint offset;
if(Context->SampleSource->state == MAPPED)
{
alSetError(AL_INVALID_OPERATION);
ProcessContext(Context);
return;
}
offset = (ALuint)data;
data = Context->SampleSource->data + offset;
}
if(ALBuf->data == NULL)
{
// buffer does not have any data
alSetError(AL_INVALID_NAME);
}
else if(length < 0 || offset < 0 || (length > 0 && data == NULL))
{
// data is NULL or offset/length is negative
alSetError(AL_INVALID_VALUE);
}
else
{
switch(format)
{
case AL_FORMAT_REAR8:
case AL_FORMAT_REAR16:
case AL_FORMAT_REAR32: {
ALuint OrigBytes = ((format==AL_FORMAT_REAR8) ? 1 :
((format==AL_FORMAT_REAR16) ? 2 :
4));
if(ALBuf->eOriginalFormat != AL_FORMAT_REAR8 &&
ALBuf->eOriginalFormat != AL_FORMAT_REAR16 &&
ALBuf->eOriginalFormat != AL_FORMAT_REAR32)
{
alSetError(AL_INVALID_ENUM);
break;
}
if(ALBuf->size/4/sizeof(ALshort) < (ALuint)offset+length)
{
alSetError(AL_INVALID_VALUE);
break;
}
ConvertDataRear(&ALBuf->data[offset*4], data, OrigBytes, length*2);
} break;
case AL_FORMAT_MONO_IMA4:
case AL_FORMAT_STEREO_IMA4: {
int Channels = aluChannelsFromFormat(ALBuf->format);
if(ALBuf->eOriginalFormat != format)
{
alSetError(AL_INVALID_ENUM);
break;
}
if((offset%65) != 0 || (length%65) != 0 ||
ALBuf->size/Channels/sizeof(ALshort) < (ALuint)offset+length)
{
alSetError(AL_INVALID_VALUE);
break;
}
ConvertDataIMA4(&ALBuf->data[offset*Channels], data, Channels, length/65*Channels);
} break;
default: {
ALuint Channels = aluChannelsFromFormat(format);
ALuint Bytes = aluBytesFromFormat(format);
if(Channels != aluChannelsFromFormat(ALBuf->format))
{
alSetError(AL_INVALID_ENUM);
break;
}
if(ALBuf->size/Channels/sizeof(ALshort) < (ALuint)offset+length)
{
alSetError(AL_INVALID_VALUE);
break;
}
ConvertData(&ALBuf->data[offset*Channels], data, Bytes, length*Channels);
} break;
}
}
}
else
{
// Invalid Buffer Name
alSetError(AL_INVALID_NAME);
}
ProcessContext(Context);
}
ALAPI void ALAPIENTRY alBufferf(ALuint buffer, ALenum eParam, ALfloat flValue)
{
@@ -621,8 +550,8 @@ ALAPI void ALAPIENTRY alBufferf(ALuint buffer, ALenum eParam, ALfloat flValue)
(void)flValue;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (alIsBuffer(buffer) && (buffer != 0))
{
@@ -650,8 +579,8 @@ ALAPI void ALAPIENTRY alBuffer3f(ALuint buffer, ALenum eParam, ALfloat flValue1,
(void)flValue2;
(void)flValue3;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (alIsBuffer(buffer) && (buffer != 0))
{
@@ -677,8 +606,8 @@ ALAPI void ALAPIENTRY alBufferfv(ALuint buffer, ALenum eParam, const ALfloat* fl
(void)flValues;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (alIsBuffer(buffer) && (buffer != 0))
{
@@ -704,8 +633,8 @@ ALAPI void ALAPIENTRY alBufferi(ALuint buffer, ALenum eParam, ALint lValue)
(void)lValue;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (alIsBuffer(buffer) && (buffer != 0))
{
@@ -733,8 +662,8 @@ ALAPI void ALAPIENTRY alBuffer3i( ALuint buffer, ALenum eParam, ALint lValue1, A
(void)lValue2;
(void)lValue3;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (alIsBuffer(buffer) && (buffer != 0))
{
@@ -760,8 +689,8 @@ ALAPI void ALAPIENTRY alBufferiv(ALuint buffer, ALenum eParam, const ALint* plVa
(void)plValues;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (alIsBuffer(buffer) && (buffer != 0))
{
@@ -785,8 +714,8 @@ ALAPI ALvoid ALAPIENTRY alGetBufferf(ALuint buffer, ALenum eParam, ALfloat *pflV
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (pflValue)
{
@@ -817,8 +746,8 @@ ALAPI void ALAPIENTRY alGetBuffer3f(ALuint buffer, ALenum eParam, ALfloat* pflVa
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if ((pflValue1) && (pflValue2) && (pflValue3))
{
@@ -849,8 +778,8 @@ ALAPI void ALAPIENTRY alGetBufferfv(ALuint buffer, ALenum eParam, ALfloat* pflVa
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (pflValues)
{
@@ -882,8 +811,8 @@ ALAPI ALvoid ALAPIENTRY alGetBufferi(ALuint buffer, ALenum eParam, ALint *plValu
ALCcontext *pContext;
ALbuffer *pBuffer;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (plValue)
{
@@ -932,8 +861,8 @@ ALAPI void ALAPIENTRY alGetBuffer3i(ALuint buffer, ALenum eParam, ALint* plValue
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if ((plValue1) && (plValue2) && (plValue3))
{
@@ -964,8 +893,8 @@ ALAPI void ALAPIENTRY alGetBufferiv(ALuint buffer, ALenum eParam, ALint* plValue
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (plValues)
{
@@ -1011,9 +940,8 @@ static void LoadData(ALbuffer *ALBuf, const ALubyte *data, ALsizei size, ALuint
ALuint NewChannels = aluChannelsFromFormat(NewFormat);
ALuint OrigBytes = aluBytesFromFormat(OrigFormat);
ALuint OrigChannels = aluChannelsFromFormat(OrigFormat);
ALsizei padding = freq / LOWPASSFREQCUTOFF;
ALsizei padding = 2;
ALvoid *temp;
ALsizei i;
assert(aluBytesFromFormat(NewFormat) == 2);
assert(NewChannels == OrigChannels);
@@ -1024,105 +952,165 @@ static void LoadData(ALbuffer *ALBuf, const ALubyte *data, ALsizei size, ALuint
return;
}
/* Ensure at least one padding byte for the bilinear filter */
if(padding < 1)
padding = 1;
switch(OrigBytes)
// Samples are converted to 16 bit here
size /= OrigBytes;
temp = realloc(ALBuf->data, (padding*NewChannels + size) * sizeof(ALshort));
if(temp)
{
case 1:
size /= sizeof(ALubyte);
ALBuf->data = temp;
ConvertData(ALBuf->data, data, OrigBytes, size);
// 8bit Samples are converted to 16 bit here
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
for (i = 0;i < size;i++)
ALBuf->data[i] = (ALshort)((data[i]-128) << 8);
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
memset(&(ALBuf->data[size]), 0, padding*NewChannels*sizeof(ALshort));
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
case 2:
size /= sizeof(ALshort);
static void ConvertData(ALshort *dst, const ALvoid *src, ALint origBytes, ALsizei len)
{
ALsizei i;
switch(origBytes)
{
case 1:
for(i = 0;i < len;i++)
dst[i] = ((ALshort)((ALubyte*)src)[i] - 128) << 8;
break;
// Allocate 8 extra samples
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
memcpy(ALBuf->data, data, size*1*sizeof(ALshort));
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
case 2:
memcpy(dst, src, len*sizeof(ALshort));
break;
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
case 4:
size /= sizeof(ALfloat);
// Allocate 8 extra samples
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALint smp;
ALBuf->data = temp;
for (i = 0;i < size;i++)
case 4:
for(i = 0;i < len;i++)
{
smp = (((ALfloat*)data)[i] * 32767.5f - 0.5f);
ALint smp;
smp = (((ALfloat*)src)[i] * 32767.5f - 0.5f);
smp = min(smp, 32767);
smp = max(smp, -32768);
ALBuf->data[i] = (ALshort)smp;
dst[i] = (ALshort)smp;
}
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
break;
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
default:
assert(0);
default:
assert(0);
}
}
static void ConvertDataRear(ALshort *dst, const ALvoid *src, ALint origBytes, ALsizei len)
{
ALsizei i;
switch(origBytes)
{
case 1:
for(i = 0;i < len;i+=4)
{
dst[i+0] = 0;
dst[i+1] = 0;
dst[i+2] = ((ALshort)((ALubyte*)src)[i/2+0] - 128) << 8;
dst[i+3] = ((ALshort)((ALubyte*)src)[i/2+1] - 128) << 8;
}
break;
case 2:
for(i = 0;i < len;i+=4)
{
dst[i+0] = 0;
dst[i+1] = 0;
dst[i+2] = ((ALshort*)src)[i/2+0];
dst[i+3] = ((ALshort*)src)[i/2+1];
}
break;
case 4:
for(i = 0;i < len;i+=4)
{
ALint smp;
dst[i+0] = 0;
dst[i+1] = 0;
smp = (((ALfloat*)src)[i/2+0] * 32767.5f - 0.5);
smp = min(smp, 32767);
smp = max(smp, -32768);
dst[i+2] = (ALshort)smp;
smp = (((ALfloat*)src)[i/2+1] * 32767.5f - 0.5);
smp = min(smp, 32767);
smp = max(smp, -32768);
dst[i+3] = (ALshort)smp;
}
break;
default:
assert(0);
}
}
static void ConvertDataIMA4(ALshort *dst, const ALvoid *src, ALint origChans, ALsizei len)
{
const ALuint *IMAData;
ALint Sample[2],Index[2];
ALuint IMACode[2];
ALsizei i,j,k,c;
assert(origChans <= 2);
IMAData = src;
for(i = 0;i < len/origChans;i++)
{
for(c = 0;c < origChans;c++)
{
Sample[c] = ((ALshort*)IMAData)[0];
Index[c] = ((ALshort*)IMAData)[1];
Index[c] = ((Index[c]<0) ? 0 : Index[c]);
Index[c] = ((Index[c]>88) ? 88 : Index[c]);
dst[i*65*origChans + c] = (ALshort)Sample[c];
IMAData++;
}
for(j = 1;j < 65;j += 8)
{
for(c = 0;c < origChans;c++)
IMACode[c] = *(IMAData++);
for(k = 0;k < 8;k++)
{
for(c = 0;c < origChans;c++)
{
Sample[c] += ((g_IMAStep_size[Index[c]]*g_IMACodeword_4[IMACode[c]&15])/8);
Index[c] += g_IMAIndex_adjust_4[IMACode[c]&15];
if(Sample[c] < -32768) Sample[c] = -32768;
else if(Sample[c] > 32767) Sample[c] = 32767;
if(Index[c]<0) Index[c] = 0;
else if(Index[c]>88) Index[c] = 88;
dst[(i*65+j+k)*origChans + c] = (ALshort)Sample[c];
IMACode[c] >>= 4;
}
}
}
}
}
/*
* ReleaseALBuffers()
*
* INTERNAL FN : Called by DLLMain on exit to destroy any buffers that still exist
*/
ALvoid ReleaseALBuffers(ALvoid)
ALvoid ReleaseALBuffers(ALCdevice *device)
{
ALbuffer *ALBuffer;
ALbuffer *ALBufferTemp;
#ifdef _DEBUG
if(g_uiBufferCount > 0)
AL_PRINT("exit(): deleting %d Buffer(s)\n", g_uiBufferCount);
#endif
ALBuffer = g_pBuffers;
ALBuffer = device->Buffers;
while(ALBuffer)
{
// Release sample data
@@ -1134,6 +1122,6 @@ ALvoid ReleaseALBuffers(ALvoid)
memset(ALBufferTemp, 0, sizeof(ALbuffer));
free(ALBufferTemp);
}
g_pBuffers = NULL;
g_uiBufferCount = 0;
device->Buffers = NULL;
device->BufferCount = 0;
}
+639
View File
@@ -0,0 +1,639 @@
/**
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "alError.h"
#include "alDatabuffer.h"
#include "alThunk.h"
/*
* alGenDatabuffersEXT(ALsizei n, ALuint *puiBuffers)
*
* Generates n AL Databuffers, and stores the Databuffers Names in the array pointed to by puiBuffers
*/
ALvoid ALAPIENTRY alGenDatabuffersEXT(ALsizei n,ALuint *puiBuffers)
{
ALCcontext *Context;
ALsizei i=0;
Context = GetContextSuspended();
if(!Context) return;
/* Check that we are actually generation some Databuffers */
if(n > 0)
{
ALCdevice *device = Context->Device;
/* Check the pointer is valid (and points to enough memory to store
* Databuffer Names) */
if(!IsBadWritePtr((void*)puiBuffers, n * sizeof(ALuint)))
{
ALdatabuffer **list = &device->Databuffers;
while(*list)
list = &(*list)->next;
/* Create all the new Databuffers */
while(i < n)
{
*list = calloc(1, sizeof(ALdatabuffer));
if(!(*list))
{
alDeleteDatabuffersEXT(i, puiBuffers);
alSetError(AL_OUT_OF_MEMORY);
break;
}
puiBuffers[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
(*list)->databuffer = puiBuffers[i];
(*list)->state = UNMAPPED;
device->DatabufferCount++;
i++;
list = &(*list)->next;
}
}
else
alSetError(AL_INVALID_VALUE);
}
ProcessContext(Context);
}
/*
* alDatabeleteBuffersEXT(ALsizei n, ALuint *puiBuffers)
*
* Deletes the n AL Databuffers pointed to by puiBuffers
*/
ALvoid ALAPIENTRY alDeleteDatabuffersEXT(ALsizei n, const ALuint *puiBuffers)
{
ALCcontext *Context;
ALdatabuffer *ALBuf;
ALsizei i;
ALboolean bFailed = AL_FALSE;
Context = GetContextSuspended();
if(!Context) return;
/* Check we are actually Deleting some Databuffers */
if(n >= 0)
{
ALCdevice *device = Context->Device;
/* Check that all the databuffers are valid and can actually be
* deleted */
for(i = 0;i < n;i++)
{
/* Check for valid Buffer ID (can be NULL buffer) */
if(alIsDatabufferEXT(puiBuffers[i]))
{
/* If not the NULL buffer, check that it's unmapped */
ALBuf = ((ALdatabuffer *)ALTHUNK_LOOKUPENTRY(puiBuffers[i]));
if(ALBuf)
{
if(ALBuf->state != UNMAPPED)
{
/* Databuffer still in use, cannot be deleted */
alSetError(AL_INVALID_OPERATION);
bFailed = AL_TRUE;
}
}
}
else
{
/* Invalid Databuffer */
alSetError(AL_INVALID_NAME);
bFailed = AL_TRUE;
}
}
/* If all the Databuffers were valid (and unmapped), then we can
* delete them */
if(!bFailed)
{
for(i = 0;i < n;i++)
{
if(puiBuffers[i] && alIsDatabufferEXT(puiBuffers[i]))
{
ALdatabuffer **list = &device->Databuffers;
ALBuf = (ALdatabuffer*)ALTHUNK_LOOKUPENTRY(puiBuffers[i]);
while(*list && *list != ALBuf)
list = &(*list)->next;
if(*list)
*list = (*list)->next;
if(ALBuf == Context->SampleSource)
Context->SampleSource = NULL;
if(ALBuf == Context->SampleSink)
Context->SampleSink = NULL;
// Release the memory used to store audio data
free(ALBuf->data);
// Release buffer structure
ALTHUNK_REMOVEENTRY(puiBuffers[i]);
memset(ALBuf, 0, sizeof(ALdatabuffer));
device->DatabufferCount--;
free(ALBuf);
}
}
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(Context);
return;
}
/*
* alIsDatabufferEXT(ALuint uiBuffer)
*
* Checks if ulBuffer is a valid Databuffer Name
*/
ALboolean ALAPIENTRY alIsDatabufferEXT(ALuint uiBuffer)
{
ALCcontext *Context;
ALdatabuffer *ALBuf;
Context = GetContextSuspended();
if(!Context) return AL_FALSE;
/* Check through list of generated databuffers for uiBuffer */
ALBuf = Context->Device->Databuffers;
while(ALBuf && ALBuf->databuffer != uiBuffer)
ALBuf = ALBuf->next;
ProcessContext(Context);
return ((ALBuf || !uiBuffer) ? AL_TRUE : AL_FALSE);
}
/*
* alDatabufferDataEXT(ALuint buffer,ALvoid *data,ALsizei size,ALenum usage)
*
* Fill databuffer with data
*/
ALvoid ALAPIENTRY alDatabufferDataEXT(ALuint buffer,const ALvoid *data,ALsizei size,ALenum usage)
{
ALCcontext *Context;
ALdatabuffer *ALBuf;
ALvoid *temp;
Context = GetContextSuspended();
if(!Context) return;
if(alIsDatabufferEXT(buffer) && buffer != 0)
{
ALBuf = (ALdatabuffer*)ALTHUNK_LOOKUPENTRY(buffer);
if(ALBuf->state == UNMAPPED)
{
if(usage == AL_STREAM_WRITE_EXT || usage == AL_STREAM_READ_EXT ||
usage == AL_STREAM_COPY_EXT || usage == AL_STATIC_WRITE_EXT ||
usage == AL_STATIC_READ_EXT || usage == AL_STATIC_COPY_EXT ||
usage == AL_DYNAMIC_WRITE_EXT || usage == AL_DYNAMIC_READ_EXT ||
usage == AL_DYNAMIC_COPY_EXT)
{
/* (Re)allocate data */
temp = realloc(ALBuf->data, size);
if(temp)
{
ALBuf->data = temp;
ALBuf->size = size;
ALBuf->usage = usage;
if(data)
memcpy(ALBuf->data, data, size);
}
else
alSetError(AL_OUT_OF_MEMORY);
}
else
alSetError(AL_INVALID_ENUM);
}
else
alSetError(AL_INVALID_OPERATION);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid ALAPIENTRY alDatabufferSubDataEXT(ALuint uiBuffer, ALuint start, ALsizei length, const ALvoid *data)
{
ALCcontext *pContext;
ALdatabuffer *pBuffer;
pContext = GetContextSuspended();
if(!pContext) return;
if(alIsDatabufferEXT(uiBuffer) && uiBuffer != 0)
{
pBuffer = (ALdatabuffer*)ALTHUNK_LOOKUPENTRY(uiBuffer);
if(length >= 0 && start+length <= pBuffer->size)
{
if(pBuffer->state == UNMAPPED)
memcpy(pBuffer->data+start, data, length);
else
alSetError(AL_INVALID_OPERATION);
}
else
alSetError(AL_INVALID_VALUE);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(pContext);
}
ALvoid ALAPIENTRY alGetDatabufferSubDataEXT(ALuint uiBuffer, ALuint start, ALsizei length, ALvoid *data)
{
ALCcontext *pContext;
ALdatabuffer *pBuffer;
pContext = GetContextSuspended();
if(!pContext) return;
if(alIsDatabufferEXT(uiBuffer) && uiBuffer != 0)
{
pBuffer = (ALdatabuffer*)ALTHUNK_LOOKUPENTRY(uiBuffer);
if(length >= 0 && start+length <= pBuffer->size)
{
if(pBuffer->state == UNMAPPED)
memcpy(data, pBuffer->data+start, length);
else
alSetError(AL_INVALID_OPERATION);
}
else
alSetError(AL_INVALID_VALUE);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(pContext);
}
ALvoid ALAPIENTRY alDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat flValue)
{
ALCcontext *pContext;
(void)flValue;
pContext = GetContextSuspended();
if(!pContext) return;
if(alIsDatabufferEXT(buffer) && buffer != 0)
{
switch(eParam)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(pContext);
}
ALvoid ALAPIENTRY alDatabufferfvEXT(ALuint buffer, ALenum eParam, const ALfloat* flValues)
{
ALCcontext *pContext;
(void)flValues;
pContext = GetContextSuspended();
if(!pContext) return;
if(alIsDatabufferEXT(buffer) && buffer != 0)
{
switch(eParam)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(pContext);
}
ALvoid ALAPIENTRY alDatabufferiEXT(ALuint buffer, ALenum eParam, ALint lValue)
{
ALCcontext *pContext;
(void)lValue;
pContext = GetContextSuspended();
if(!pContext) return;
if(alIsDatabufferEXT(buffer) && buffer != 0)
{
switch(eParam)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(pContext);
}
ALvoid ALAPIENTRY alDatabufferivEXT(ALuint buffer, ALenum eParam, const ALint* plValues)
{
ALCcontext *pContext;
(void)plValues;
pContext = GetContextSuspended();
if(!pContext) return;
if(alIsDatabufferEXT(buffer) && buffer != 0)
{
switch(eParam)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(pContext);
}
ALvoid ALAPIENTRY alGetDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat *pflValue)
{
ALCcontext *pContext;
pContext = GetContextSuspended();
if(!pContext) return;
if(pflValue)
{
if(alIsDatabufferEXT(buffer) && buffer != 0)
{
switch(eParam)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
ALvoid ALAPIENTRY alGetDatabufferfvEXT(ALuint buffer, ALenum eParam, ALfloat* pflValues)
{
ALCcontext *pContext;
pContext = GetContextSuspended();
if(!pContext) return;
if(pflValues)
{
if(alIsDatabufferEXT(buffer) && buffer != 0)
{
switch(eParam)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
ALvoid ALAPIENTRY alGetDatabufferiEXT(ALuint buffer, ALenum eParam, ALint *plValue)
{
ALCcontext *pContext;
ALdatabuffer *pBuffer;
pContext = GetContextSuspended();
if(!pContext) return;
if(plValue)
{
if(alIsDatabufferEXT(buffer) && buffer != 0)
{
pBuffer = (ALdatabuffer*)ALTHUNK_LOOKUPENTRY(buffer);
switch(eParam)
{
case AL_SIZE:
*plValue = pBuffer->size;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
ALvoid ALAPIENTRY alGetDatabufferivEXT(ALuint buffer, ALenum eParam, ALint* plValues)
{
ALCcontext *pContext;
pContext = GetContextSuspended();
if(!pContext) return;
if(plValues)
{
if(alIsDatabufferEXT(buffer) && buffer != 0)
{
switch (eParam)
{
case AL_SIZE:
alGetBufferi(buffer, eParam, plValues);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
ALvoid ALAPIENTRY alSelectDatabufferEXT(ALenum target, ALuint uiBuffer)
{
ALCcontext *pContext;
ALdatabuffer *pBuffer;
pContext = GetContextSuspended();
if(!pContext) return;
if(alIsDatabufferEXT(uiBuffer))
{
pBuffer = (ALdatabuffer*)(uiBuffer ? ALTHUNK_LOOKUPENTRY(uiBuffer) : NULL);
if(target == AL_SAMPLE_SOURCE_EXT)
pContext->SampleSource = pBuffer;
else if(target == AL_SAMPLE_SINK_EXT)
pContext->SampleSink = pBuffer;
else
alSetError(AL_INVALID_VALUE);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(pContext);
}
ALvoid* ALAPIENTRY alMapDatabufferEXT(ALuint uiBuffer, ALuint start, ALsizei length, ALenum access)
{
ALCcontext *pContext;
ALdatabuffer *pBuffer;
ALvoid *ret = NULL;
pContext = GetContextSuspended();
if(!pContext) return NULL;
if(alIsDatabufferEXT(uiBuffer) && uiBuffer != 0)
{
pBuffer = (ALdatabuffer*)ALTHUNK_LOOKUPENTRY(uiBuffer);
if(length >= 0 && start+length <= pBuffer->size)
{
if(access == AL_READ_ONLY_EXT || access == AL_WRITE_ONLY_EXT ||
access == AL_READ_WRITE_EXT)
{
if(pBuffer->state == UNMAPPED)
{
ret = pBuffer->data + start;
pBuffer->state = MAPPED;
}
else
alSetError(AL_INVALID_OPERATION);
}
else
alSetError(AL_INVALID_ENUM);
}
else
alSetError(AL_INVALID_VALUE);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(pContext);
return ret;
}
ALvoid ALAPIENTRY alUnmapDatabufferEXT(ALuint uiBuffer)
{
ALCcontext *pContext;
ALdatabuffer *pBuffer;
pContext = GetContextSuspended();
if(!pContext) return;
if(alIsDatabufferEXT(uiBuffer) && uiBuffer != 0)
{
pBuffer = (ALdatabuffer*)ALTHUNK_LOOKUPENTRY(uiBuffer);
if(pBuffer->state == MAPPED)
pBuffer->state = UNMAPPED;
else
alSetError(AL_INVALID_OPERATION);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(pContext);
}
/*
* ReleaseALDatabuffers()
*
* INTERNAL FN : Called by DLLMain on exit to destroy any buffers that still exist
*/
ALvoid ReleaseALDatabuffers(ALCdevice *device)
{
ALdatabuffer *ALBuffer;
ALdatabuffer *ALBufferTemp;
ALBuffer = device->Databuffers;
while(ALBuffer)
{
// Release sample data
free(ALBuffer->data);
// Release Buffer structure
ALBufferTemp = ALBuffer;
ALBuffer = ALBuffer->next;
memset(ALBufferTemp, 0, sizeof(ALdatabuffer));
free(ALBufferTemp);
}
device->Databuffers = NULL;
device->DatabufferCount = 0;
}
+710 -112
View File
File diff suppressed because it is too large Load Diff
+16 -21
View File
@@ -26,34 +26,29 @@
ALAPI ALenum ALAPIENTRY alGetError(ALvoid)
{
ALCcontext *Context;
ALenum errorCode;
ALCcontext *Context;
ALenum errorCode;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return AL_INVALID_OPERATION;
if (Context)
{
errorCode = Context->LastError;
Context->LastError = AL_NO_ERROR;
}
else
errorCode = AL_INVALID_OPERATION;
errorCode = Context->LastError;
Context->LastError = AL_NO_ERROR;
ProcessContext(Context);
ProcessContext(Context);
return errorCode;
return errorCode;
}
ALvoid alSetError(ALenum errorCode)
{
ALCcontext *Context;
ALCcontext *Context;
Context=alcGetCurrentContext();
SuspendContext(Context);
if (Context && Context->LastError == AL_NO_ERROR)
Context->LastError = errorCode;
ProcessContext(Context);
Context = GetContextSuspended();
if(Context)
{
if(Context->LastError == AL_NO_ERROR)
Context->LastError = errorCode;
ProcessContext(Context);
}
}
+24 -8
View File
@@ -29,7 +29,9 @@
#include "alFilter.h"
#include "alEffect.h"
#include "alAuxEffectSlot.h"
#include "alDatabuffer.h"
#include "alSource.h"
#include "alBuffer.h"
#include "AL/al.h"
#include "AL/alc.h"
@@ -144,6 +146,26 @@ static ALfunction function[]= {
{ "alGetAuxiliaryEffectSlotf", (ALvoid *) alGetAuxiliaryEffectSlotf },
{ "alGetAuxiliaryEffectSlotfv", (ALvoid *) alGetAuxiliaryEffectSlotfv},
{ "alBufferSubDataEXT", (ALvoid *) alBufferSubDataEXT },
{ "alGenDatabuffersEXT", (ALvoid *) alGenDatabuffersEXT },
{ "alDeleteDatabuffersEXT", (ALvoid *) alDeleteDatabuffersEXT },
{ "alIsDatabufferEXT", (ALvoid *) alIsDatabufferEXT },
{ "alDatabufferDataEXT", (ALvoid *) alDatabufferDataEXT },
{ "alDatabufferSubDataEXT", (ALvoid *) alDatabufferSubDataEXT },
{ "alGetDatabufferSubDataEXT", (ALvoid *) alGetDatabufferSubDataEXT },
{ "alDatabufferfEXT", (ALvoid *) alDatabufferfEXT },
{ "alDatabufferfvEXT", (ALvoid *) alDatabufferfvEXT },
{ "alDatabufferiEXT", (ALvoid *) alDatabufferiEXT },
{ "alDatabufferivEXT", (ALvoid *) alDatabufferivEXT },
{ "alGetDatabufferfEXT", (ALvoid *) alGetDatabufferfEXT },
{ "alGetDatabufferfvEXT", (ALvoid *) alGetDatabufferfvEXT },
{ "alGetDatabufferiEXT", (ALvoid *) alGetDatabufferiEXT },
{ "alGetDatabufferivEXT", (ALvoid *) alGetDatabufferivEXT },
{ "alSelectDatabufferEXT", (ALvoid *) alSelectDatabufferEXT },
{ "alMapDatabufferEXT", (ALvoid *) alMapDatabufferEXT },
{ "alUnmapDatabufferEXT", (ALvoid *) alUnmapDatabufferEXT },
{ NULL, (ALvoid *) NULL } };
static ALenums enumeration[]={
@@ -330,14 +352,8 @@ ALAPI ALboolean ALAPIENTRY alIsExtensionPresent(const ALchar *extName)
return AL_FALSE;
}
pContext = alcGetCurrentContext();
if(!pContext)
{
alSetError(AL_INVALID_OPERATION);
return AL_FALSE;
}
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return AL_FALSE;
len = strlen(extName);
ptr = pContext->ExtensionList;
+53 -54
View File
@@ -29,26 +29,26 @@
#include "alThunk.h"
#include "alError.h"
static ALfilter *g_FilterList;
static ALuint g_FilterCount;
static void InitFilterParams(ALfilter *filter, ALenum type);
AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
{
ALCcontext *Context;
ALsizei i;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (n > 0)
{
ALCdevice *device = Context->Device;
// Check that enough memory has been allocted in the 'filters' array for n Filters
if (!IsBadWritePtr((void*)filters, n * sizeof(ALuint)))
{
ALfilter **list = &g_FilterList;
ALfilter **list = &device->FilterList;
while(*list)
list = &(*list)->next;
@@ -68,7 +68,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
(*list)->filter = filters[i];
InitFilterParams(*list, AL_FILTER_NULL);
g_FilterCount++;
device->FilterCount++;
i++;
list = &(*list)->next;
@@ -79,17 +79,19 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
{
ALCcontext *Context;
ALfilter *ALFilter;
ALsizei i;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (n >= 0)
{
ALCdevice *device = Context->Device;
// Check that all filters are valid
for (i = 0; i < n; i++)
{
@@ -113,7 +115,7 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
ALFilter = ((ALfilter*)ALTHUNK_LOOKUPENTRY(filters[i]));
// Remove Source from list of Sources
list = &g_FilterList;
list = &device->FilterList;
while(*list && *list != ALFilter)
list = &(*list)->next;
@@ -124,7 +126,7 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
memset(ALFilter, 0, sizeof(ALfilter));
free(ALFilter);
g_FilterCount--;
device->FilterCount--;
}
}
}
@@ -135,29 +137,29 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
ProcessContext(Context);
}
AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
ALboolean AL_APIENTRY alIsFilter(ALuint filter)
{
ALCcontext *Context;
ALfilter **list;
ALfilter *list;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return AL_FALSE;
list = &g_FilterList;
while(*list && (*list)->filter != filter)
list = &(*list)->next;
list = Context->Device->FilterList;
while(list && list->filter != filter)
list = list->next;
ProcessContext(Context);
return ((*list || !filter) ? AL_TRUE : AL_FALSE);
return ((list || !filter) ? AL_TRUE : AL_FALSE);
}
AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue)
ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (filter && alIsFilter(filter))
{
@@ -184,12 +186,12 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue)
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues)
ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (filter && alIsFilter(filter))
{
@@ -210,12 +212,12 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValue
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue)
ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (filter && alIsFilter(filter))
{
@@ -257,12 +259,12 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (filter && alIsFilter(filter))
{
@@ -279,12 +281,12 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflVa
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue)
ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (filter && alIsFilter(filter))
{
@@ -307,12 +309,12 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piVal
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues)
ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (filter && alIsFilter(filter))
{
@@ -333,12 +335,12 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piVa
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue)
ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (filter && alIsFilter(filter))
{
@@ -374,12 +376,12 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pfl
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (filter && alIsFilter(filter))
{
@@ -397,23 +399,20 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pf
}
ALvoid ReleaseALFilters(ALvoid)
ALvoid ReleaseALFilters(ALCdevice *device)
{
#ifdef _DEBUG
if(g_FilterCount > 0)
AL_PRINT("exit(): deleting %d Filter(s)\n", g_FilterCount);
#endif
while(g_FilterList)
ALfilter *list = device->FilterList;
while(list)
{
ALfilter *temp = g_FilterList;
g_FilterList = g_FilterList->next;
ALfilter *temp = list;
list = list->next;
// Release filter structure
memset(temp, 0, sizeof(ALfilter));
free(temp);
}
g_FilterCount = 0;
device->FilterList = NULL;
device->FilterCount = 0;
}
+80 -164
View File
@@ -29,22 +29,20 @@ ALAPI ALvoid ALAPIENTRY alListenerf(ALenum eParam, ALfloat flValue)
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
switch (eParam)
{
switch(eParam)
{
case AL_GAIN:
if (flValue >= 0.0f)
if(flValue >= 0.0f)
pContext->Listener.Gain = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_METERS_PER_UNIT:
if (flValue > 0.0f)
if(flValue > 0.0f)
pContext->Listener.MetersPerUnit = flValue;
else
alSetError(AL_INVALID_VALUE);
@@ -53,14 +51,9 @@ ALAPI ALvoid ALAPIENTRY alListenerf(ALenum eParam, ALfloat flValue)
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
return;
ProcessContext(pContext);
}
@@ -68,13 +61,11 @@ ALAPI ALvoid ALAPIENTRY alListener3f(ALenum eParam, ALfloat flValue1, ALfloat fl
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
switch(eParam)
{
switch(eParam)
{
case AL_POSITION:
pContext->Listener.Position[0] = flValue1;
pContext->Listener.Position[1] = flValue2;
@@ -90,14 +81,9 @@ ALAPI ALvoid ALAPIENTRY alListener3f(ALenum eParam, ALfloat flValue1, ALfloat fl
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
return;
ProcessContext(pContext);
}
@@ -105,24 +91,22 @@ ALAPI ALvoid ALAPIENTRY alListenerfv(ALenum eParam, const ALfloat *pflValues)
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (pflValues)
if(pflValues)
{
switch(eParam)
{
switch (eParam)
{
case AL_GAIN:
if (pflValues[0] >= 0.0f)
if(pflValues[0] >= 0.0f)
pContext->Listener.Gain = pflValues[0];
else
alSetError(AL_INVALID_VALUE);
break;
case AL_METERS_PER_UNIT:
if (pflValues[0] > 0.0f)
if(pflValues[0] > 0.0f)
pContext->Listener.MetersPerUnit = pflValues[0];
else
alSetError(AL_INVALID_VALUE);
@@ -153,17 +137,12 @@ ALAPI ALvoid ALAPIENTRY alListenerfv(ALenum eParam, const ALfloat *pflValues)
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(pContext);
}
@@ -173,24 +152,17 @@ ALAPI ALvoid ALAPIENTRY alListeneri(ALenum eParam, ALint lValue)
(void)lValue;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
switch (eParam)
{
switch(eParam)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
return;
ProcessContext(pContext);
}
@@ -198,13 +170,11 @@ ALAPI void ALAPIENTRY alListener3i(ALenum eParam, ALint lValue1, ALint lValue2,
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
switch(eParam)
{
switch(eParam)
{
case AL_POSITION:
case AL_VELOCITY:
alListener3f(eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
@@ -213,14 +183,9 @@ ALAPI void ALAPIENTRY alListener3i(ALenum eParam, ALint lValue1, ALint lValue2,
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
return;
ProcessContext(pContext);
}
@@ -229,15 +194,13 @@ ALAPI void ALAPIENTRY alListeneriv( ALenum eParam, const ALint* plValues )
ALCcontext *pContext;
ALfloat flValues[6];
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (plValues)
if(plValues)
{
switch(eParam)
{
switch (eParam)
{
case AL_POSITION:
case AL_VELOCITY:
flValues[0] = (ALfloat)plValues[0];
@@ -259,17 +222,12 @@ ALAPI void ALAPIENTRY alListeneriv( ALenum eParam, const ALint* plValues )
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(pContext);
}
@@ -277,15 +235,13 @@ ALAPI ALvoid ALAPIENTRY alGetListenerf(ALenum eParam, ALfloat *pflValue)
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (pflValue)
if(pflValue)
{
switch(eParam)
{
switch (eParam)
{
case AL_GAIN:
*pflValue = pContext->Listener.Gain;
break;
@@ -297,17 +253,12 @@ ALAPI ALvoid ALAPIENTRY alGetListenerf(ALenum eParam, ALfloat *pflValue)
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(pContext);
}
@@ -315,15 +266,13 @@ ALAPI ALvoid ALAPIENTRY alGetListener3f(ALenum eParam, ALfloat *pflValue1, ALflo
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if ((pflValue1) && (pflValue2) && (pflValue3))
if(pflValue1 && pflValue2 && pflValue3)
{
switch(eParam)
{
switch (eParam)
{
case AL_POSITION:
*pflValue1 = pContext->Listener.Position[0];
*pflValue2 = pContext->Listener.Position[1];
@@ -339,17 +288,12 @@ ALAPI ALvoid ALAPIENTRY alGetListener3f(ALenum eParam, ALfloat *pflValue1, ALflo
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(pContext);
}
@@ -357,15 +301,13 @@ ALAPI ALvoid ALAPIENTRY alGetListenerfv(ALenum eParam, ALfloat *pflValues)
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (pflValues)
if(pflValues)
{
switch(eParam)
{
switch (eParam)
{
case AL_GAIN:
pflValues[0] = pContext->Listener.Gain;
break;
@@ -399,17 +341,12 @@ ALAPI ALvoid ALAPIENTRY alGetListenerfv(ALenum eParam, ALfloat *pflValues)
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(pContext);
}
@@ -417,29 +354,22 @@ ALAPI ALvoid ALAPIENTRY alGetListeneri(ALenum eParam, ALint *plValue)
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (plValue)
if(plValue)
{
switch(eParam)
{
switch (eParam)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(pContext);
}
@@ -447,15 +377,13 @@ ALAPI void ALAPIENTRY alGetListener3i(ALenum eParam, ALint *plValue1, ALint *plV
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if ((plValue1) && (plValue2) && (plValue3))
if(plValue1 && plValue2 && plValue3)
{
switch (eParam)
{
switch (eParam)
{
case AL_POSITION:
*plValue1 = (ALint)pContext->Listener.Position[0];
*plValue2 = (ALint)pContext->Listener.Position[1];
@@ -471,17 +399,12 @@ ALAPI void ALAPIENTRY alGetListener3i(ALenum eParam, ALint *plValue1, ALint *plV
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(pContext);
}
@@ -489,15 +412,13 @@ ALAPI void ALAPIENTRY alGetListeneriv(ALenum eParam, ALint* plValues)
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (plValues)
if(plValues)
{
switch(eParam)
{
switch (eParam)
{
case AL_POSITION:
plValues[0] = (ALint)pContext->Listener.Position[0];
plValues[1] = (ALint)pContext->Listener.Position[1];
@@ -523,15 +444,10 @@ ALAPI void ALAPIENTRY alGetListeneriv(ALenum eParam, ALint* plValues)
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
else
alSetError(AL_INVALID_OPERATION);
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(pContext);
}
+704 -841
View File
File diff suppressed because it is too large Load Diff
+274 -381
View File
@@ -23,11 +23,14 @@
#include <stdlib.h>
#include "alMain.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "alError.h"
#include "alSource.h"
#include "alState.h"
#include "alDatabuffer.h"
static const ALchar alVendor[] = "OpenAL Community";
static const ALchar alVersion[] = "1.1";
static const ALchar alVersion[] = "1.1 ALSOFT "ALSOFT_VERSION;
static const ALchar alRenderer[] = "OpenAL Soft";
// Error Messages
@@ -42,50 +45,34 @@ ALAPI ALvoid ALAPIENTRY alEnable(ALenum capability)
{
ALCcontext *Context;
Context=alcGetCurrentContext();
if (Context)
{
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
switch (capability)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
}
else
switch(capability)
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
}
ALAPI ALvoid ALAPIENTRY alDisable(ALenum capability)
{
ALCcontext *Context;
Context=alcGetCurrentContext();
if (Context)
{
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
switch (capability)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
}
else
switch(capability)
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
}
ALAPI ALboolean ALAPIENTRY alIsEnabled(ALenum capability)
@@ -93,26 +80,18 @@ ALAPI ALboolean ALAPIENTRY alIsEnabled(ALenum capability)
ALCcontext *Context;
ALboolean value=AL_FALSE;
Context=alcGetCurrentContext();
if (Context)
{
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return AL_FALSE;
switch (capability)
{
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
}
else
switch(capability)
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
return value;
}
@@ -121,46 +100,38 @@ ALAPI ALboolean ALAPIENTRY alGetBoolean(ALenum pname)
ALCcontext *Context;
ALboolean value=AL_FALSE;
Context=alcGetCurrentContext();
if (Context)
Context = GetContextSuspended();
if(!Context) return AL_FALSE;
switch(pname)
{
SuspendContext(Context);
case AL_DOPPLER_FACTOR:
if(Context->DopplerFactor != 0.0f)
value = AL_TRUE;
break;
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_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_DISTANCE_MODEL:
if (Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED)
value = AL_TRUE;
break;
case AL_SPEED_OF_SOUND:
if(Context->flSpeedOfSound != 0.0f)
value = AL_TRUE;
break;
case AL_SPEED_OF_SOUND:
if (Context->flSpeedOfSound != 0.0f)
value = AL_TRUE;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
}
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
return value;
}
@@ -169,42 +140,34 @@ ALAPI ALdouble ALAPIENTRY alGetDouble(ALenum pname)
ALCcontext *Context;
ALdouble value = 0.0;
Context=alcGetCurrentContext();
if (Context)
Context = GetContextSuspended();
if(!Context) return 0.0;
switch(pname)
{
SuspendContext(Context);
case AL_DOPPLER_FACTOR:
value = (double)Context->DopplerFactor;
break;
switch (pname)
{
case AL_DOPPLER_FACTOR:
value = (double)Context->DopplerFactor;
break;
case AL_DOPPLER_VELOCITY:
value = (double)Context->DopplerVelocity;
break;
case AL_DOPPLER_VELOCITY:
value = (double)Context->DopplerVelocity;
break;
case AL_DISTANCE_MODEL:
value = (double)Context->DistanceModel;
break;
case AL_DISTANCE_MODEL:
value = (double)Context->DistanceModel;
break;
case AL_SPEED_OF_SOUND:
value = (double)Context->flSpeedOfSound;
break;
case AL_SPEED_OF_SOUND:
value = (double)Context->flSpeedOfSound;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
}
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
return value;
}
@@ -213,42 +176,34 @@ ALAPI ALfloat ALAPIENTRY alGetFloat(ALenum pname)
ALCcontext *Context;
ALfloat value = 0.0f;
Context=alcGetCurrentContext();
if (Context)
Context = GetContextSuspended();
if(!Context) return 0.0f;
switch(pname)
{
SuspendContext(Context);
case AL_DOPPLER_FACTOR:
value = Context->DopplerFactor;
break;
switch (pname)
{
case AL_DOPPLER_FACTOR:
value = Context->DopplerFactor;
break;
case AL_DOPPLER_VELOCITY:
value = Context->DopplerVelocity;
break;
case AL_DOPPLER_VELOCITY:
value = Context->DopplerVelocity;
break;
case AL_DISTANCE_MODEL:
value = (float)Context->DistanceModel;
break;
case AL_DISTANCE_MODEL:
value = (float)Context->DistanceModel;
break;
case AL_SPEED_OF_SOUND:
value = Context->flSpeedOfSound;
break;
case AL_SPEED_OF_SOUND:
value = Context->flSpeedOfSound;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
}
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
return value;
}
@@ -257,42 +212,48 @@ ALAPI ALint ALAPIENTRY alGetInteger(ALenum pname)
ALCcontext *Context;
ALint value = 0;
Context=alcGetCurrentContext();
if (Context)
Context = GetContextSuspended();
if(!Context) return 0;
switch(pname)
{
SuspendContext(Context);
case AL_DOPPLER_FACTOR:
value = (ALint)Context->DopplerFactor;
break;
switch (pname)
{
case AL_DOPPLER_FACTOR:
value = (ALint)Context->DopplerFactor;
break;
case AL_DOPPLER_VELOCITY:
value = (ALint)Context->DopplerVelocity;
break;
case AL_DOPPLER_VELOCITY:
value = (ALint)Context->DopplerVelocity;
break;
case AL_DISTANCE_MODEL:
value = (ALint)Context->DistanceModel;
break;
case AL_DISTANCE_MODEL:
value = (ALint)Context->DistanceModel;
break;
case AL_SPEED_OF_SOUND:
value = (ALint)Context->flSpeedOfSound;
break;
case AL_SPEED_OF_SOUND:
value = (ALint)Context->flSpeedOfSound;
break;
case AL_SAMPLE_SOURCE_EXT:
if(Context->SampleSource)
value = (ALint)Context->SampleSource->databuffer;
else
value = 0;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
case AL_SAMPLE_SINK_EXT:
if(Context->SampleSink)
value = (ALint)Context->SampleSink->databuffer;
else
value = 0;
break;
ProcessContext(Context);
}
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
default:
alSetError(AL_INVALID_ENUM);
break;
}
ProcessContext(Context);
return value;
}
@@ -300,204 +261,178 @@ ALAPI ALvoid ALAPIENTRY alGetBooleanv(ALenum pname,ALboolean *data)
{
ALCcontext *Context;
Context=alcGetCurrentContext();
if (Context)
Context = GetContextSuspended();
if(!Context) return;
if(data)
{
SuspendContext(Context);
if (data)
switch(pname)
{
switch (pname)
{
case AL_DOPPLER_FACTOR:
*data = (ALboolean)((Context->DopplerFactor != 0.0f) ? AL_TRUE : AL_FALSE);
break;
case AL_DOPPLER_FACTOR:
*data = (ALboolean)((Context->DopplerFactor != 0.0f) ? AL_TRUE : AL_FALSE);
break;
case AL_DOPPLER_VELOCITY:
*data = (ALboolean)((Context->DopplerVelocity != 0.0f) ? AL_TRUE : AL_FALSE);
break;
case AL_DOPPLER_VELOCITY:
*data = (ALboolean)((Context->DopplerVelocity != 0.0f) ? AL_TRUE : AL_FALSE);
break;
case AL_DISTANCE_MODEL:
*data = (ALboolean)((Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) ? AL_TRUE : AL_FALSE);
break;
case AL_DISTANCE_MODEL:
*data = (ALboolean)((Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) ? AL_TRUE : AL_FALSE);
break;
case AL_SPEED_OF_SOUND:
*data = (ALboolean)((Context->flSpeedOfSound != 0.0f) ? AL_TRUE : AL_FALSE);
break;
case AL_SPEED_OF_SOUND:
*data = (ALboolean)((Context->flSpeedOfSound != 0.0f) ? AL_TRUE : AL_FALSE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
default:
alSetError(AL_INVALID_ENUM);
break;
}
else
{
// data is a NULL pointer
alSetError(AL_INVALID_VALUE);
}
ProcessContext(Context);
}
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
// data is a NULL pointer
alSetError(AL_INVALID_VALUE);
}
return;
ProcessContext(Context);
}
ALAPI ALvoid ALAPIENTRY alGetDoublev(ALenum pname,ALdouble *data)
{
ALCcontext *Context;
Context=alcGetCurrentContext();
if (Context)
Context = GetContextSuspended();
if(!Context) return;
if(data)
{
SuspendContext(Context);
if (data)
switch(pname)
{
switch (pname)
{
case AL_DOPPLER_FACTOR:
*data = (double)Context->DopplerFactor;
break;
case AL_DOPPLER_FACTOR:
*data = (double)Context->DopplerFactor;
break;
case AL_DOPPLER_VELOCITY:
*data = (double)Context->DopplerVelocity;
break;
case AL_DOPPLER_VELOCITY:
*data = (double)Context->DopplerVelocity;
break;
case AL_DISTANCE_MODEL:
*data = (double)Context->DistanceModel;
break;
case AL_DISTANCE_MODEL:
*data = (double)Context->DistanceModel;
break;
case AL_SPEED_OF_SOUND:
*data = (double)Context->flSpeedOfSound;
break;
case AL_SPEED_OF_SOUND:
*data = (double)Context->flSpeedOfSound;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
default:
alSetError(AL_INVALID_ENUM);
break;
}
else
{
// data is a NULL pointer
alSetError(AL_INVALID_VALUE);
}
ProcessContext(Context);
}
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
// data is a NULL pointer
alSetError(AL_INVALID_VALUE);
}
return;
ProcessContext(Context);
}
ALAPI ALvoid ALAPIENTRY alGetFloatv(ALenum pname,ALfloat *data)
{
ALCcontext *Context;
Context=alcGetCurrentContext();
if (Context)
Context = GetContextSuspended();
if(!Context) return;
if(data)
{
SuspendContext(Context);
if (data)
switch(pname)
{
switch (pname)
{
case AL_DOPPLER_FACTOR:
*data = Context->DopplerFactor;
break;
case AL_DOPPLER_FACTOR:
*data = Context->DopplerFactor;
break;
case AL_DOPPLER_VELOCITY:
*data = Context->DopplerVelocity;
break;
case AL_DOPPLER_VELOCITY:
*data = Context->DopplerVelocity;
break;
case AL_DISTANCE_MODEL:
*data = (float)Context->DistanceModel;
break;
case AL_DISTANCE_MODEL:
*data = (float)Context->DistanceModel;
break;
case AL_SPEED_OF_SOUND:
*data = Context->flSpeedOfSound;
break;
case AL_SPEED_OF_SOUND:
*data = Context->flSpeedOfSound;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
default:
alSetError(AL_INVALID_ENUM);
break;
}
else
{
// data is a NULL pointer
alSetError(AL_INVALID_VALUE);
}
ProcessContext(Context);
}
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
// data is a NULL pointer
alSetError(AL_INVALID_VALUE);
}
return;
ProcessContext(Context);
}
ALAPI ALvoid ALAPIENTRY alGetIntegerv(ALenum pname,ALint *data)
{
ALCcontext *Context;
Context=alcGetCurrentContext();
if (Context)
Context = GetContextSuspended();
if(!Context) return;
if(data)
{
SuspendContext(Context);
if (data)
switch(pname)
{
switch (pname)
{
case AL_DOPPLER_FACTOR:
*data = (ALint)Context->DopplerFactor;
break;
case AL_DOPPLER_FACTOR:
*data = (ALint)Context->DopplerFactor;
break;
case AL_DOPPLER_VELOCITY:
*data = (ALint)Context->DopplerVelocity;
break;
case AL_DOPPLER_VELOCITY:
*data = (ALint)Context->DopplerVelocity;
break;
case AL_DISTANCE_MODEL:
*data = (ALint)Context->DistanceModel;
break;
case AL_DISTANCE_MODEL:
*data = (ALint)Context->DistanceModel;
break;
case AL_SPEED_OF_SOUND:
*data = (ALint)Context->flSpeedOfSound;
break;
case AL_SPEED_OF_SOUND:
*data = (ALint)Context->flSpeedOfSound;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
case AL_SAMPLE_SOURCE_EXT:
if(Context->SampleSource)
*data = (ALint)Context->SampleSource->databuffer;
else
*data = 0;
break;
case AL_SAMPLE_SINK_EXT:
if(Context->SampleSink)
*data = (ALint)Context->SampleSink->databuffer;
else
*data = 0;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
else
{
// data is a NULL pointer
alSetError(AL_INVALID_VALUE);
}
ProcessContext(Context);
}
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
// data is a NULL pointer
alSetError(AL_INVALID_VALUE);
}
return;
ProcessContext(Context);
}
ALAPI const ALchar* ALAPIENTRY alGetString(ALenum pname)
@@ -505,14 +440,8 @@ ALAPI const ALchar* ALAPIENTRY alGetString(ALenum pname)
const ALchar *value;
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if(!pContext)
{
alSetError(AL_INVALID_OPERATION);
return NULL;
}
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return NULL;
switch(pname)
{
@@ -571,109 +500,73 @@ ALAPI ALvoid ALAPIENTRY alDopplerFactor(ALfloat value)
{
ALCcontext *Context;
Context=alcGetCurrentContext();
if (Context)
{
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (value>=0.0f)
Context->DopplerFactor = value;
else
alSetError(AL_INVALID_VALUE);
ProcessContext(Context);
}
if(value >= 0.0f)
Context->DopplerFactor = value;
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
}
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(Context);
}
ALAPI ALvoid ALAPIENTRY alDopplerVelocity(ALfloat value)
{
ALCcontext *Context;
Context=alcGetCurrentContext();
if (Context)
{
SuspendContext(Context);
Context = GetContextSuspended();
if(!Context) return;
if (value>0.0f)
Context->DopplerVelocity=value;
else
alSetError(AL_INVALID_VALUE);
ProcessContext(Context);
}
if(value > 0.0f)
Context->DopplerVelocity=value;
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
}
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(Context);
}
ALAPI ALvoid ALAPIENTRY alSpeedOfSound(ALfloat flSpeedOfSound)
{
ALCcontext *pContext;
pContext = alcGetCurrentContext();
if (pContext)
{
SuspendContext(pContext);
pContext = GetContextSuspended();
if(!pContext) return;
if (flSpeedOfSound > 0.0f)
pContext->flSpeedOfSound = flSpeedOfSound;
else
alSetError(AL_INVALID_VALUE);
ProcessContext(pContext);
}
if(flSpeedOfSound > 0.0f)
pContext->flSpeedOfSound = flSpeedOfSound;
else
{
alSetError(AL_INVALID_OPERATION);
}
alSetError(AL_INVALID_VALUE);
return;
ProcessContext(pContext);
}
ALAPI ALvoid ALAPIENTRY alDistanceModel(ALenum value)
{
ALCcontext *Context;
ALsource *Source;
Context=alcGetCurrentContext();
if (Context)
Context = GetContextSuspended();
if(!Context) return;
switch(value)
{
SuspendContext(Context);
case AL_NONE:
case AL_INVERSE_DISTANCE:
case AL_INVERSE_DISTANCE_CLAMPED:
case AL_LINEAR_DISTANCE:
case AL_LINEAR_DISTANCE_CLAMPED:
case AL_EXPONENT_DISTANCE:
case AL_EXPONENT_DISTANCE_CLAMPED:
Context->DistanceModel = value;
for(Source = Context->Source;Source != NULL;Source = Source->next)
Source->DistanceModel = value;
break;
switch (value)
{
case AL_NONE:
case AL_INVERSE_DISTANCE:
case AL_INVERSE_DISTANCE_CLAMPED:
case AL_LINEAR_DISTANCE:
case AL_LINEAR_DISTANCE_CLAMPED:
case AL_EXPONENT_DISTANCE:
case AL_EXPONENT_DISTANCE_CLAMPED:
Context->DistanceModel = value;
break;
default:
alSetError(AL_INVALID_VALUE);
break;
}
ProcessContext(Context);
}
else
{
// Invalid Context
alSetError(AL_INVALID_OPERATION);
default:
alSetError(AL_INVALID_VALUE);
break;
}
return;
ProcessContext(Context);
}
+23
View File
@@ -0,0 +1,23 @@
# Cross-compiling requires CMake 2.6 or newer. To cross-compile, first modify
# this file to set the proper settings and paths. Then use it from build/ like:
# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt \
# -DCMAKE_INSTALL_PREFIX=/usr/mingw32/mingw
# 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 mingw32-gcc)
SET(CMAKE_CXX_COMPILER mingw32-g++)
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/mingw32/mingw)
# 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)
+186 -68
View File
@@ -5,91 +5,209 @@
# The system-wide settings can be put in /etc/openal/alsoft.conf and user-
# specific override settings in ~/.alsoftrc.
# For Windows, these settings should go into %AppData%\alsoft.ini
# The environment variable ALSOFT_CONF can be used to specify another config
# override
# Option and block names are case-insenstive. The supplied values are only
# hints and may not be honored (though generally it'll try to get as close as
# possible). These are the current available settings:
# possible). Note: options that are left unset may default to app- or system-
# specified values. These are the current available settings:
format = AL_FORMAT_STEREO16 # Sets the output format. Can be one of:
# AL_FORMAT_MONO8 (8-bit mono)
# AL_FORMAT_STEREO8 (8-bit stereo)
# AL_FORMAT_QUAD8 (8-bit 4-channel)
# AL_FORMAT_51CHN8 (8-bit 5.1 output)
# AL_FORMAT_61CHN8 (8-bit 6.1 output)
# AL_FORMAT_71CHN8 (8-bit 7.1 output)
# AL_FORMAT_MONO16 (16-bit mono)
# AL_FORMAT_STEREO16 (16-bit stereo)
# AL_FORMAT_QUAD16 (16-bit 4-channel)
# AL_FORMAT_51CHN16 (16-bit 5.1 output)
# AL_FORMAT_61CHN16 (16-bit 6.1 output)
# AL_FORMAT_71CHN16 (16-bit 7.1 output)
# Default is AL_FORMAT_STEREO16
## format:
# Sets the output format. Can be one of:
# AL_FORMAT_MONO8 (8-bit mono)
# AL_FORMAT_STEREO8 (8-bit stereo)
# AL_FORMAT_QUAD8 (8-bit 4-channel)
# AL_FORMAT_51CHN8 (8-bit 5.1 output)
# AL_FORMAT_61CHN8 (8-bit 6.1 output)
# AL_FORMAT_71CHN8 (8-bit 7.1 output)
# AL_FORMAT_MONO16 (16-bit mono)
# AL_FORMAT_STEREO16 (16-bit stereo)
# AL_FORMAT_QUAD16 (16-bit 4-channel)
# AL_FORMAT_51CHN16 (16-bit 5.1 output)
# AL_FORMAT_61CHN16 (16-bit 6.1 output)
# AL_FORMAT_71CHN16 (16-bit 7.1 output)
# AL_FORMAT_MONO32 (32-bit float mono)
# AL_FORMAT_STEREO32 (32-bit float stereo)
# AL_FORMAT_QUAD32 (32-bit float 4-channel)
# AL_FORMAT_51CHN32 (32-bit float 5.1 output)
# AL_FORMAT_61CHN32 (32-bit float 6.1 output)
# AL_FORMAT_71CHN32 (32-bit float 7.1 output)
#format = AL_FORMAT_STEREO16
cf_level = 0 # 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
# Default is 0. Users of headphones may want to try various
# settings. Has no effect on non-stereo modes.
## 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
frequency = 44100 # Sets the output frequency. Default is 44100
## frequency:
# Sets the output frequency.
#frequency = 44100
refresh = 4096 # Sets the buffer size, in frames. Default is 4096. Note that
# the actual granularity may or may not be less than this.
## period_size:
# Sets the update period size, in frames. This is the number of frames needed
# for each mixing update. If the deprecated 'refresh' option is specified and
# this isn't, the value will be calculated as size = refresh/periods.
#period_size = 1024
sources = 256 # 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. Default is 256
## 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.
#periods = 4
stereodup = # Sets whether to duplicate stereo sounds on the rear speakers for
# 4+ channel output. This can make stereo sources substantially
# louder than mono or even 4+ channel sources, but provides a
# "fuller" playback quality. True, yes, on, and non-0 values will
# duplicate stereo sources. 0 and anything else will cause stereo
# sounds to only play out the front speakers.
# Default is false
## 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
drivers = # Sets the backend driver list order, comma-seperated. Unknown
# backends and duplicated names are ignored, and unlisted backends
# won't be considered for use. An empty list means the default.
# Default is:
# alsa,oss,dsound,winmm,wave
## stereodup:
# Sets whether to duplicate stereo sounds on the rear and side speakers for 4+
# channel output. This can make stereo sources substantially louder than mono
# or even 4+ channel sources, but provides a "fuller" playback quality. True,
# yes, on, and non-0 values will duplicate stereo sources. 0 and anything else
# will cause stereo sounds to only play out the front speakers.
#stereodup = false
[alsa] # ALSA backend stuff
device = default # Sets the device name for the default playback device.
# Default is default
## drivers:
# Sets the backend driver list order, comma-seperated. Unknown backends and
# duplicated names are ignored, and unlisted backends won't be considered for
# use. An empty list means the default.
#drivers = alsa,oss,solaris,dsound,winmm,port,pulse,wave
periods = 0 # Sets the number of update buffers for playback. A value of 0
# means auto-select. Default is 0
## excludefx:
# 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,echo
#excludefx =
capture = default # Sets the device name for the default capture device.
# Default is default
## 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 = 4
mmap = true # 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.
# Default is true.
## sends:
# Sets the maximum number of auxiliary sends per source. The total number of
# sends possible is defined at compile time and thus can not be increased
# beyond the default (2).
#sends = 2
[oss] # OSS backend stuff
device = /dev/dsp # Sets the device name for OSS output. Default is /dev/dsp
## layout_STEREO:
# Sets the speaker layout when using stereo output. Values are specified in
# degrees, where 0 is straight in front, negative goes left, and positive goes
# right. The values must define a circular pattern, starting with the back-
# left at the most negative, around the front to back-center. Unspecified
# speakers will remain at their default position. Available speakers are
# front-left(fl) and front-right(fr).
#layout_STEREO = fl=-90, fr=90
periods = 4 # Sets the number of update buffers. Default is 4
## laytout_QUAD:
# Sets the speaker layout when using quadriphonic output. Available speakers
# are back-left(bl), front-left(fl), front-right(fr), and back-right(br).
#layout_QUAD = bl=-135, fl=-45, fr=45, br=135
capture = /dev/dsp # Sets the device name for OSS capture. Default is /dev/dsp
## layout_51CHN:
# Sets the speaker layout when using 5.1 output. Available speakers are back-
# left(bl), front-left(fl), front-center(fc), front-right(fr), and back-
# right(br).
#layout_51CHN = bl=-110, fl=-30, fc=0, fr=30, br=110
[dsound] # DirectSound backend stuff
# Nothing yet...
## layout_61CHN:
# Sets the speaker layout when using 6.1 output. Available speakers are side-
# left(sl), front-left(fl), front-center(fc), front-right(fr), side-right(sr),
# and back-center(bc).
#layout_61CHN = sl=-90, fl=-30, fc=0, fr=30, sr=90, bc=180
[winmm] # Windows Multimedia backend stuff
# Nothing yet...
## layout_71CHN:
# Sets the speaker layout when using 7.1 output. Available speakers are back-
# left(bl), side-left(sl), front-left(fl), front-center(fc), front-right(fr),
# side-right(sr), and back-right(br).
#layout_71CHN = bl=-150, sl=-90, fl=-30, fc=0, fr=30, sr=90, br=150
[wave] # Wave File Writer stuff
file = # 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!
# Default is empty
##
## ALSA backend stuff
##
[alsa]
## device:
# Sets the device name for the default playback device.
#device = default
## capture:
# Sets the device name for the default capture device.
#capture = default
## 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
##
## OSS backend stuff
##
[oss]
## device:
# Sets the device name for OSS output.
#device = /dev/dsp
## capture:
# Sets the device name for OSS capture.
#capture = /dev/dsp
##
## Solaris backend stuff
##
[solaris]
## device:
# Sets the device name for Solaris output.
#device = /dev/audio
##
## DirectSound backend stuff
##
[dsound]
##
## Windows Multimedia backend stuff
##
[winmm]
##
## PortAudio backend stuff
##
[port]
## device:
# Sets the device index for output. Negative values will use the default as
# given by PortAudio itself.
#device = -1
##
## PulseAudio backend stuff
##
[pulse]
##
## Wave File Writer stuff
##
[wave]
## file:
# 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 =
View File
+30
View File
@@ -1,18 +1,30 @@
#ifndef CONFIG_H
#define CONFIG_H
/* Define to the library version */
#define ALSOFT_VERSION "${LIB_VERSION}"
/* Define if we have the ALSA backend */
#cmakedefine HAVE_ALSA
/* Define if we have the OSS backend */
#cmakedefine HAVE_OSS
/* Define if we have the Solaris backend */
#cmakedefine HAVE_SOLARIS
/* Define if we have the DSound backend */
#cmakedefine HAVE_DSOUND
/* Define if we have the Windows Multimedia backend */
#cmakedefine HAVE_WINMM
/* Define if we have the PortAudio backend */
#cmakedefine HAVE_PORTAUDIO
/* Define if we have the PulseAudio backend */
#cmakedefine HAVE_PULSEAUDIO
/* Define if we have dlfcn.h */
#cmakedefine HAVE_DLFCN_H
@@ -22,6 +34,12 @@
/* Define if we have the acosf function */
#cmakedefine HAVE_ACOSF
/* Define if we have the atanf function */
#cmakedefine HAVE_ATANF
/* Define if we have the fabsf function */
#cmakedefine HAVE_FABSF
/* Define if we have the strtof function */
#cmakedefine HAVE_STRTOF
@@ -49,4 +67,16 @@
/* Define if we have pthread_np.h */
#cmakedefine HAVE_PTHREAD_NP_H
/* Define if we have float.h */
#cmakedefine HAVE_FLOAT_H
/* Define if we have fenv.h */
#cmakedefine HAVE_FENV_H
/* Define if we have fesetround() */
#cmakedefine HAVE_FESETROUND
/* Define if we have _controlfp() */
#cmakedefine HAVE__CONTROLFP
#endif
+124 -1
View File
@@ -19,6 +19,37 @@
#include "AL/al.h"
#include "AL/alext.h"
#ifndef ALC_EXT_EFX
#define AL_FILTER_TYPE 0x8001
#define AL_EFFECT_TYPE 0x8001
#define AL_FILTER_NULL 0x0000
#define AL_FILTER_LOWPASS 0x0001
#define AL_FILTER_HIGHPASS 0x0002
#define AL_FILTER_BANDPASS 0x0003
#define AL_EFFECT_NULL 0x0000
#define AL_EFFECT_EAXREVERB 0x8000
#define AL_EFFECT_REVERB 0x0001
#define AL_EFFECT_CHORUS 0x0002
#define AL_EFFECT_DISTORTION 0x0003
#define AL_EFFECT_ECHO 0x0004
#define AL_EFFECT_FLANGER 0x0005
#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006
#define AL_EFFECT_VOCAL_MORPHER 0x0007
#define AL_EFFECT_PITCH_SHIFTER 0x0008
#define AL_EFFECT_RING_MODULATOR 0x0009
#define AL_EFFECT_AUTOWAH 0x000A
#define AL_EFFECT_COMPRESSOR 0x000B
#define AL_EFFECT_EQUALIZER 0x000C
#define ALC_EFX_MAJOR_VERSION 0x20001
#define ALC_EFX_MINOR_VERSION 0x20002
#define ALC_MAX_AUXILIARY_SENDS 0x20003
#endif
ALvoid (AL_APIENTRY *p_alGenFilters)(ALsizei,ALuint*);
ALvoid (AL_APIENTRY *p_alDeleteFilters)(ALsizei,ALuint*);
ALvoid (AL_APIENTRY *p_alFilteri)(ALuint,ALenum,ALint);
ALvoid (AL_APIENTRY *p_alGenEffects)(ALsizei,ALuint*);
ALvoid (AL_APIENTRY *p_alDeleteEffects)(ALsizei,ALuint*);
ALvoid (AL_APIENTRY *p_alEffecti)(ALuint,ALenum,ALint);
static const int indentation = 4;
static const int maxmimumWidth = 79;
@@ -134,7 +165,7 @@ static void printALCInfo (void)
alcGetString(device, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor);
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
checkForErrors();
printf("ALC version: %d.%d\n", (int)major, (int)minor);
@@ -152,6 +183,97 @@ static void printALInfo(void)
checkForErrors();
}
static void printEFXInfo(void)
{
ALCint major, minor, sends;
ALCdevice *device;
ALuint obj;
int i;
const struct {
ALenum type;
const char *name;
} effects[] = {
{ AL_EFFECT_EAXREVERB, "EAX Reverb" },
{ AL_EFFECT_REVERB, "Reverb" },
{ AL_EFFECT_CHORUS, "Chorus" },
{ AL_EFFECT_DISTORTION, "Distortion" },
{ AL_EFFECT_ECHO, "Echo" },
{ AL_EFFECT_FLANGER, "Flanger" },
{ AL_EFFECT_FREQUENCY_SHIFTER, "Frequency Shifter" },
{ AL_EFFECT_VOCAL_MORPHER, "Vocal Morpher" },
{ AL_EFFECT_PITCH_SHIFTER, "Pitch Shifter" },
{ AL_EFFECT_RING_MODULATOR, "Ring Modulator" },
{ AL_EFFECT_AUTOWAH, "Autowah" },
{ AL_EFFECT_COMPRESSOR, "Compressor" },
{ AL_EFFECT_EQUALIZER, "Equalizer" },
{ AL_EFFECT_NULL, NULL }
};
const struct {
ALenum type;
const char *name;
} filters[] = {
{ AL_FILTER_LOWPASS, "Low-pass" },
{ AL_FILTER_HIGHPASS, "High-pass" },
{ AL_FILTER_BANDPASS, "Band-pass" },
{ AL_FILTER_NULL, NULL }
};
device = alcGetContextsDevice(alcGetCurrentContext());
if(alcIsExtensionPresent(device, (const ALCchar*)"ALC_EXT_EFX") == AL_FALSE)
{
printf("EFX not available\n");
return;
}
alcGetIntegerv(device, ALC_EFX_MAJOR_VERSION, 1, &major);
alcGetIntegerv(device, ALC_EFX_MINOR_VERSION, 1, &minor);
checkForErrors();
printf("EFX version: %d.%d\n", (int)major, (int)minor);
alcGetIntegerv(device, ALC_MAX_AUXILIARY_SENDS, 1, &sends);
checkForErrors();
printf("Max auxiliary sends: %d\n", (int)sends);
p_alGenFilters = alGetProcAddress("alGenFilters");
p_alDeleteFilters = alGetProcAddress("alDeleteFilters");
p_alFilteri = alGetProcAddress("alFilteri");
p_alGenEffects = alGetProcAddress("alGenEffects");
p_alDeleteEffects = alGetProcAddress("alDeleteEffects");
p_alEffecti = alGetProcAddress("alEffecti");
checkForErrors();
if(!p_alGenEffects || !p_alDeleteEffects || !p_alEffecti ||
!p_alGenFilters || !p_alDeleteFilters || !p_alFilteri)
{
printf("Missing EFX functions!\n");
return;
}
p_alGenFilters(1, &obj);
checkForErrors();
printf("Available filters:\n");
for(i = 0;filters[i].type != AL_FILTER_NULL;i++)
{
p_alFilteri(obj, AL_FILTER_TYPE, filters[i].type);
if(alGetError() == AL_NO_ERROR)
printf(" %s\n", filters[i].name);
}
p_alDeleteFilters(1, &obj);
checkForErrors();
p_alGenEffects(1, &obj);
checkForErrors();
printf("Available effects:\n");
for(i = 0;effects[i].type != AL_EFFECT_NULL;i++)
{
p_alEffecti(obj, AL_EFFECT_TYPE, effects[i].type);
if(alGetError() == AL_NO_ERROR)
printf(" %s\n", effects[i].name);
}
p_alDeleteEffects(1, &obj);
checkForErrors();
}
int main()
{
ALCdevice *device = alcOpenDevice(NULL);
@@ -161,6 +283,7 @@ int main()
printALCInfo();
printALInfo();
printEFXInfo();
checkForErrors();
alcMakeContextCurrent(NULL);
+59
View File
@@ -91,6 +91,65 @@ extern "C" {
#define AL_FORMAT_STEREO_IMA4 0x1301
#endif
#ifndef AL_EXT_buffer_sub_data
#define AL_EXT_buffer_sub_data 1
#define AL_BYTE_RW_OFFSETS_EXT 0x1031
#define AL_SAMPLE_RW_OFFSETS_EXT 0x1032
#define AL_SEC_RW_OFFSETS_EXT 0x1033
typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATAEXTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei);
#endif
#ifndef AL_EXT_BUFFER_DATA_STATIC
#define AL_EXT_BUFFER_DATA_STATIC 1
typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei);
#endif
#ifndef AL_EXT_sample_buffer_object
#define AL_EXT_sample_buffer_object 1
#define AL_SAMPLE_SOURCE_EXT 0x1040
#define AL_SAMPLE_SINK_EXT 0x1041
#define AL_READ_ONLY_EXT 0x1042
#define AL_WRITE_ONLY_EXT 0x1043
#define AL_READ_WRITE_EXT 0x1044
#define AL_STREAM_WRITE_EXT 0x1045
#define AL_STREAM_READ_EXT 0x1046
#define AL_STREAM_COPY_EXT 0x1047
#define AL_STATIC_WRITE_EXT 0x1048
#define AL_STATIC_READ_EXT 0x1049
#define AL_STATIC_COPY_EXT 0x104A
#define AL_DYNAMIC_WRITE_EXT 0x104B
#define AL_DYNAMIC_READ_EXT 0x104C
#define AL_DYNAMIC_COPY_EXT 0x104D
typedef ALvoid (AL_APIENTRY*PFNALGENDATABUFFERSEXTPROC)(ALsizei n,ALuint *puiBuffers);
typedef ALvoid (AL_APIENTRY*PFNALDELETEDATABUFFERSEXTPROC)(ALsizei n, const ALuint *puiBuffers);
typedef ALboolean (AL_APIENTRY*PFNALISDATABUFFEREXTPROC)(ALuint uiBuffer);
typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERDATAEXTPROC)(ALuint buffer,const ALvoid *data,ALsizei size,ALenum usage);
typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERSUBDATAEXTPROC)(ALuint buffer, ALuint start, ALsizei length, const ALvoid *);
typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERSUBDATAEXTPROC)(ALuint buffer, ALuint start, ALsizei length, ALvoid *);
typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERFEXTPROC)(ALuint buffer, ALenum eParam, ALfloat flValue);
typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERFVEXTPROC)(ALuint buffer, ALenum eParam, const ALfloat* flValues);
typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERIEXTPROC)(ALuint buffer, ALenum eParam, ALint lValue);
typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERIVEXTPROC)(ALuint buffer, ALenum eParam, const ALint* plValues);
typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERFEXTPROC)(ALuint buffer, ALenum eParam, ALfloat *pflValue);
typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERFVEXTPROC)(ALuint buffer, ALenum eParam, ALfloat* pflValues);
typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERIEXTPROC)(ALuint buffer, ALenum eParam, ALint *plValue);
typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERIVEXTPROC)(ALuint buffer, ALenum eParam, ALint* plValues);
typedef ALvoid (AL_APIENTRY*PFNALSELECTDATABUFFEREXTPROC)(ALenum target, ALuint uiBuffer);
typedef ALvoid* (AL_APIENTRY*PFNALMAPDATABUFFEREXTPROC)(ALuint uiBuffer, ALuint start, ALsizei length, ALenum access);
typedef ALvoid (AL_APIENTRY*PFNALUNMAPDATABUFFEREXTPROC)(ALuint uiBuffer);
#endif
#ifndef ALC_EXT_disconnect
#define ALC_EXT_disconnect 1
#define ALC_CONNECTED 0x313
#endif
#ifndef ALC_EXT_thread_local_context
#define ALC_EXT_thread_local_context 1
typedef ALCboolean (ALCAPIENTRY*PFNALCMAKECURRENTPROC)(ALCcontext *context);
typedef ALCcontext* (ALCAPIENTRY*PFNALCGETTHREADCONTEXTPROC)(void);
#endif
#ifdef __cplusplus
}
#endif