Compare commits

..

428 Commits

Author SHA1 Message Date
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
Chris Robinson f1414c650e Release 1.5.304 2008-07-27 19:58:32 -07:00
Chris Robinson 869b041f2f Reduce the default buffer size to 4096
Should help with latency issues some people have and not put too much extra
burden on the mixer, hopefully
2008-07-26 21:07:08 -07:00
Chris Robinson 8621fbb015 Improve getting and setting EFX filter parameters 2008-07-26 18:32:45 -07:00
Chris Robinson 597e01153e Use arrays instead of pointer-to-arrays for the low-pass filter 2008-07-26 17:13:50 -07:00
Chris Robinson d3e5fcd13e Fix some calculations for the reverb buffer 2008-07-26 01:57:04 -07:00
Chris Robinson 3e0f9cc716 Make the filter processing function inline 2008-07-26 00:58:54 -07:00
Chris Robinson c7e49c9f57 Implement yet another low-pass filter
This one using the Butterworth IIR filter design
2008-07-25 19:31:12 -07:00
Chris Robinson e2ed8ff2bf Use a temp pointer when realloc()ing
So the original data isn't lost on out-of-memory conditions
2008-07-24 13:44:26 -07:00
Chris Robinson 559c786d0c Specify padding per buffer, and make sure it's large enough for the filter step 2008-07-24 00:41:25 -07:00
Chris Robinson c3a7480961 Don't advertise extra samples for mixing 2008-07-23 23:27:38 -07:00
Chris Robinson a75e75aef5 Implement an alternative low-pass filter
This method samples from the buffer so that it gets a time-correct 5khz stream,
which is subtracted from the original sample and has the high-frequency gain
applied, then added back.
A better method may be to average all the samples from the current one to the
one freq/5000 away, instead of bilinear filtering the two nearest freq/5000
apart. Processing cost will need to determine its viability
2008-07-23 22:29:53 -07:00
Chris Robinson d45b1207d0 Make sure the correct libname is used for pkg-config 2008-07-23 11:58:36 -07:00
Chris Robinson 5a9e24dea1 Add a warning when building on Windows with the DSound backend disabled 2008-07-23 00:51:55 -07:00
Chris Robinson dc8132e965 Add a pkg-config file to install on the system 2008-07-22 18:42:53 -07:00
Chris Robinson 20bcdc1ef6 Add AL_LOKI_IMA_ADPCM_format and AL_EXT_vorbis tokens to alext.h 2008-07-22 14:45:31 -07:00
Chris Robinson 93c0f61050 Clarify implicit destruction warnings 2008-07-22 14:29:27 -07:00
Chris Robinson 3a8c543f8b Move ALC_ENUMERATE_ALL_EXT tokens to alext.h 2008-07-22 13:50:08 -07:00
Chris Robinson 9e96156451 Add AL_LOKI_WAVE_format tokens to alext.h 2008-07-22 13:45:26 -07:00
Chris Robinson 19aabd6d02 Add ALC_LOKI_audio_channel tokens to alext.h 2008-07-22 13:16:58 -07:00
Chris Robinson 87b5d7bc7b Store extension list with a pointer, not a per-context array 2008-07-22 12:39:10 -07:00
Chris Robinson 646714b585 Set the new linking policy for CMake 2.6 to avoid warnings 2008-07-22 11:26:56 -07:00
Chris Robinson eba60c30c5 Don't force initialization when shutting down
Thanks to Michael Simms
2008-07-17 18:45:21 -07:00
Chris Robinson e66bb09156 Move (de)initialization into ALc.c and remove unneeded file 2008-07-17 18:38:07 -07:00
Chris Robinson 0042b1f80d Implement doppler factor source property 2008-07-15 02:33:05 -07:00
Chris Robinson 6d416ee734 Add the reverb room rolloff to the source room rolloff, not override 2008-07-15 02:23:53 -07:00
Chris Robinson 97d3a45aff Don't check the number of objects being deleted with the number currently allocated
Since apps can validly delete buffer 0, and delete the same source/buffer multiple times in a single call
2008-07-11 09:12:11 -07:00
Chris Robinson 9e9ff44b17 Use volatile for member variables that are changed in a different thread 2008-07-10 20:36:28 -07:00
Chris Robinson f369be148f Reduce the mix buffer sizes by half
Nearly 3MB is a bit much. Could reduce it further, but this is good enough for now.
2008-07-08 19:37:14 -07:00
Chris Robinson 3a09e446b3 Leave SourceToListener untransformed for use with untransformed velocities
Distance is also left untransformed so cone calculations with SoundToListener
are correct
2008-07-03 03:13:43 -07:00
Chris Robinson 2d0b12e49e Store thread return value in the struct to avoid void*-to-uint casting 2008-06-17 19:46:37 -07:00
Chris Robinson 55e2f294ac Allow for overriding the default lib destination with LIB_INSTALL_DIR
So 64-bit builds can be optionally redirected to lib64
2008-06-06 18:39:18 -07:00
Chris Robinson 2a4b467f08 Make the project explicitly C
So it doesn't search for an unneeded C++ compiler
2008-06-06 18:33:13 -07:00
Chris Robinson 2ae9da696a Release 1.4.272 2008-06-04 20:47:20 -07:00
Chris Robinson 376997c3ef Fix config value check 2008-06-04 20:44:51 -07:00
Chris Robinson e963782b8c Release 1.4.270 2008-06-04 19:46:31 -07:00
Chris Robinson 86c01aa62c Install openal-info if it is built 2008-06-04 19:40:52 -07:00
Chris Robinson 15783d25e7 Don't override the format config option in DSound 2008-06-04 18:33:02 -07:00
Chris Robinson 3243f69f21 Use %AppData%\alsoft.ini for the config file in Windows 2008-06-04 18:09:21 -07:00
Chris Robinson 10a87f510c Protect RingBufferSize calculation with the mutex 2008-06-04 17:01:44 -07:00
Chris Robinson ca6feeda29 Make sure the lib is initialized when shutting down
Pretty ugly, but the destructor sequence relies in the mutex being initialized
2008-05-18 20:17:31 -07:00
Chris Robinson cecf778de3 Add addiitonal copyright line 2008-05-18 18:44:17 -07:00
Chris Robinson fe79ab351a Add a simple example that prints out some OpenAL info 2008-05-18 18:40:53 -07:00
Chris Robinson dc0a3a6653 Remove -fno-strict-aliasing as the code should be safe, now 2008-05-18 17:46:45 -07:00
Chris Robinson fed346c285 Fix source calculations for AL_SOURCE_RELATIVE mode
Make sure the source position and direction are properly put into listener-
space before working with them, and don't calculate the listener velocity for
relative coordinates
2008-05-18 16:52:38 -07:00
Chris Robinson cad9b367a5 Use pthread_mutexattr_setkind_np as a fallback to set a recursive mutex type
Some systems (FreeBSD) don't like setting it through pthread_mutexattr_settype
2008-05-15 21:35:51 -07:00
Chris Robinson 6e86146a25 Prepare the ALSA PCM handle before starting capture
Thanks to Jason Daly for pointing it out
2008-05-06 16:05:36 -07:00
Chris Robinson 49d9695ad9 Check the right struct member for the filter type 2008-04-12 07:25:18 -07:00
Chris Robinson e15bc6b9ba Fill the correct capture device list 2008-04-05 20:33:19 -07:00
Chris Robinson 28093a6dcb constify the pointer that holds the filename 2008-03-22 19:05:00 -07:00
Chris Robinson 2af5498804 Define _WIN32_WINNT to 0x0500 when including windows.h
VC7 appears to require that value, or higher, set and fails otherwise
2008-03-01 01:39:42 -08:00
Chris Robinson 2b42d7fdb8 Don't start the DSound playback thread is startup failed 2008-03-01 00:57:37 -08:00
Chris Robinson 9b3c4faa34 Release 1.3.253 2008-02-21 01:28:18 -08:00
Chris Robinson 847b3e8b61 Preserve data and position when reallocating the reverb effect
Still not perfect, but better for when the size doesn't change
2008-02-18 21:58:58 -08:00
Chris Robinson b1bdd7c89f Add the first card after making sure there's a useable device on it 2008-02-15 21:48:00 -08:00
Chris Robinson ffe7a11866 Avoid a static variable for enumerating 2008-02-15 21:09:19 -08:00
Chris Robinson 8c3188bc7d Remove FrameSize struct member 2008-02-14 22:05:56 -08:00
Chris Robinson 880196e5a8 Remove unneeded headers 2008-02-13 19:42:47 -08:00
Chris Robinson d523b440e3 Wait for a PCM handle to be ready for more data instead of polling every 1ms or so 2008-02-13 19:34:47 -08:00
Chris Robinson f2875d5d13 Read in chunks of the fragment size, not expected buffer size 2008-02-12 21:19:09 -08:00
Chris Robinson b0720333cc UpdateSize is not used for capture devices 2008-02-12 19:50:49 -08:00
Chris Robinson c3446a10fa Rename UpdateFreq device field to UpdateSize 2008-02-12 19:38:27 -08:00
Chris Robinson fbc869eed7 Pretend DSound buffer fragment size is 1/4th the total buffer size 2008-02-12 19:24:08 -08:00
Chris Robinson e3e4dbbccf Make the backend list static 2008-02-11 17:24:04 -08:00
Chris Robinson 7fda645b16 Call InitAL at the start of some more ALC functions 2008-02-11 17:23:31 -08:00
Chris Robinson ec7f20644d Fast float-to-int function is no longer needed 2008-02-08 21:03:48 -08:00
Chris Robinson 3d5fa91703 Remove unnecessary casting 2008-02-08 21:01:05 -08:00
Chris Robinson e8acfb069c Remove explicit dependancy on ole32 and unused dxguid 2008-02-08 20:56:45 -08:00
Chris Robinson 4c38ed272d Enumerate DirectSound devices 2008-02-08 20:46:34 -08:00
Chris Robinson acbb4f8e6c Include alext.h instead of redefining some enums 2008-02-08 19:55:51 -08:00
Chris Robinson 13a3fe8a7a Remove unneeded device struct member 2008-02-08 19:41:47 -08:00
Chris Robinson 3dd3cd4ceb Prevent overflow of the device lists 2008-02-08 15:33:26 -08:00
Chris Robinson 80fcbc8adc Use all capture devices listed by ALSA, not just the first on each card 2008-02-08 15:22:17 -08:00
Chris Robinson 33680accea Don't remove the devices from the device list on unexpected shutdown
The close functions will remove it for us
2008-02-08 14:44:05 -08:00
Chris Robinson 081e593e2b Set the done flag immediately when entering the initialization
To prevent two threads from initializing at the same time (not that it's
likely to happen at this point).
2008-02-06 22:22:29 -08:00
Chris Robinson b4ffdfab81 Add an option for duplicating stereo sources on the back speakers 2008-02-06 22:18:50 -08:00
Chris Robinson 1ea4aac799 Add an alext.h header 2008-02-06 20:53:00 -08:00
Chris Robinson 4d6c292757 Fix race condition when starting winmm message poll thread 2008-02-03 00:28:00 -08:00
Chris Robinson 655a83c5c5 Use WAVEFORMATEXTENSIBLE for multichannel dsound output, and don't create a primary buffer 2008-02-01 08:17:57 -08:00
Chris Robinson e8b576bc25 Use the correct channel ordering for Windows 2008-01-27 07:04:13 -08:00
Chris Robinson 01404ed7af Fix output channel order for 6.1 and 7.1 2008-01-27 06:49:48 -08:00
Chris Robinson ad6237f6f7 Fix availibility amount calculation 2008-01-26 21:10:55 -08:00
Chris Robinson d06c64e1c4 aluBytesFromFormat returns bytes, not bits 2008-01-26 21:09:08 -08:00
Chris Robinson b4ad3186dd Update frame size after detecting the directsound output format 2008-01-25 17:05:14 -08:00
Chris Robinson 5f1c0450b3 Remove unnecessary Channels field 2008-01-25 16:38:37 -08:00
Chris Robinson 04b62f77e3 Set the output format according to the speaker setup reported by directsound 2008-01-25 05:02:00 -08:00
Chris Robinson 029dff3f40 Use both write pointers from the directsound buffer lock 2008-01-25 04:42:44 -08:00
Chris Robinson 342f639771 Release 1.2.218 2008-01-21 18:43:14 -08:00
Chris Robinson b5a2baafe5 Remove effect slot thunk entry when deallocated forcefully 2008-01-21 15:34:38 -08:00
Chris Robinson 781e4e5be4 Remove an unneceesary pointer check and decrease indentation 2008-01-21 14:54:15 -08:00
Chris Robinson f3dddb5e99 Remove unnecessary duplicate thunk lookups 2008-01-21 14:33:42 -08:00
Chris Robinson 9a5e892cad Small formatting updates 2008-01-20 22:16:28 -08:00
Chris Robinson 0317362662 Remove duplicate function 2008-01-20 19:22:39 -08:00
Chris Robinson 6b403a76e8 Don't access ALSource for every sample mix 2008-01-20 19:20:24 -08:00
Chris Robinson 6bf6c6fb7b More overflow protection 2008-01-20 13:27:54 -08:00
Chris Robinson 29618bee10 Prevent float samples from overflowing when converting to 16-bit 2008-01-20 00:43:02 -08:00
Chris Robinson db80f682c9 Clean a couple debug messages 2008-01-19 21:41:09 -08:00
Chris Robinson e1cdbac5a0 Close ALC first when exiting since devices might've been running when deleting stuff 2008-01-19 20:58:50 -08:00
Chris Robinson 543eb9d217 Don't use a multiple lists for extensions 2008-01-19 20:02:40 -08:00
Chris Robinson bc963463f3 Add an option for setting the max number of sources 2008-01-19 19:38:06 -08:00
Chris Robinson 86b7b3d54b Remove duplication of setting the max source count 2008-01-19 19:28:34 -08:00
Chris Robinson 799ba1f954 Use less ambiguous config file names 2008-01-19 18:18:14 -08:00
Chris Robinson 1a3e39e452 Remove some unnecessary duplicate math, which was making long lines 2008-01-19 00:49:05 -08:00
Chris Robinson 7dc73815ae Remove some branches 2008-01-18 21:39:09 -08:00
Chris Robinson 4caf2c7edd Implement AL_EFFECT_REVERB
Here is a quick description of how the reverb effect works:

 +--->---+*(4)
 |       V       new sample
 +-----+---+---+    |
 |extra|ltr|ref| <- +*(1)
 +-----+---+---+
   (3,5)*|   |*(2)
         +-->|
             V
         out sample

 1) Apply master reverb gain to incoming sample and place it at the head of the
    buffer. The master reverb gainhf was already applied when the source was
    initially mixed.
 2) Copy the delayed reflection sample to an output sample and apply the
    reflection gain.
 3) Apply the late reverb gain to the late reverb sample
 4) Copy the end of the buffer, applying a decay gain and the decay hf ratio,
    and add to the late reverb.
 5) Copy the late reverb sample, adding to the output sample.

 Then the head and sampling points are shifted forward, and done again for each
 new sample. The extra buffer length is determined by the Reverb Density
 property. A value of 0 gives a length of 0.1 seconds (long, with fairly
 distinct echos) , and 1 gives 0.075 seconds (short, indistinct echos).
 The decay gain is calculated such that after a number of loops to satisfy the
 Decay Time, a sample will be 1/32768th as powerful (virtually insignificant to
 the resulting output, and only getting further reduced). It is calculated as:

 DecayGain = pow(1.0f/32768.0f, 1.0/(DecayTime/ExtraLength));

 Things to note: Reverb Diffusion is not currently handled, nor is Decay HF
 Limit. Decay HF Ratios above 1 probably give incorrect results. Also, this
 method likely sucks, but it's the best I can come up with before release. :)
2008-01-18 21:25:40 -08:00
Chris Robinson 1b9d740244 Remove duplicated source freeing code 2008-01-18 00:56:01 -08:00
Chris Robinson 497ada9c77 Buffer size fixes. Partially reverts the ALSA buffer size "fix" 2008-01-18 00:28:25 -08:00
Chris Robinson 73e386dc6f Release effect slots when deleting sources 2008-01-17 21:17:08 -08:00
Chris Robinson 43cfc097de Don't dereference ALContext if there's no context yet
Patch by Evgeny A. Marchenko
2008-01-17 12:57:22 -08:00
Chris Robinson 6735fc7911 Add missing config.h includes 2008-01-16 14:09:04 -08:00
Chris Robinson be34dbe608 Don't include alAuxEffectSlot.h in alSource.h 2008-01-16 14:01:24 -08:00
Chris Robinson 70102e7cd3 Fix debug comments 2008-01-16 13:58:10 -08:00
Chris Robinson 8ad16145f6 Make sure sources are deleted with the context 2008-01-16 13:27:15 -08:00
Chris Robinson bb7b18d4e1 Keep track of references to effect slots, so they aren't deleted while in use 2008-01-16 13:20:09 -08:00
Chris Robinson 4742dedb45 Don't clamp wet gain if there's no send slot, and move slot gain calculation
To remove an extra if check
2008-01-16 13:00:35 -08:00
Chris Robinson 10a9bc62bf Store a reference to the effect slot in a source's send, not a copy 2008-01-16 12:43:25 -08:00
Chris Robinson 8cbbf17519 Allow getting and setting reverb parameters, as well as setting reverb effects
Reverb is still not implemented. The parameters just no-op for now.
2008-01-15 23:32:28 -08:00
Chris Robinson 24f433b938 Remove unneeded variables 2008-01-15 21:57:50 -08:00
Chris Robinson abc69dd3d0 Use acosf when available 2008-01-15 21:23:14 -08:00
Chris Robinson bf87aed459 Add reverb parameters 2008-01-15 20:32:20 -08:00
Chris Robinson 42306f93b3 Set default room rolloff factor 2008-01-15 19:59:19 -08:00
Chris Robinson 03ca50fa70 Use the previous low-pass filter again, as it seems to match the intended output better 2008-01-15 18:29:21 -08:00
Chris Robinson 7b1b8bd741 Set the default outer cone gainhf 2008-01-15 17:40:37 -08:00
Chris Robinson a11f25e47b Fix source and buffer out-of-memory conditions 2008-01-15 16:30:43 -08:00
Chris Robinson a6213ebfc7 Fix allocation of multiple effect slots, effects, and filters 2008-01-15 16:24:12 -08:00
Chris Robinson b95fcf5da1 Store effect slots in the context 2008-01-15 16:22:39 -08:00
Chris Robinson 707e596811 Don't append _struct to the effect slot struct name 2008-01-15 16:01:27 -08:00
Chris Robinson 5678041b92 Remove errant line 2008-01-15 15:53:58 -08:00
Chris Robinson 7f850d8fb0 Make sure a valid context is set for effect slots 2008-01-15 15:53:06 -08:00
Chris Robinson 7edc576e9c Fix some copy/paste errors 2008-01-15 15:37:54 -08:00
Chris Robinson 0041a09576 Move include so win32 gets it too, and remove unnecessary line 2008-01-15 12:45:24 -08:00
Chris Robinson 0f06254ecf Use a string for the detected backends, instead of a list 2008-01-15 12:43:43 -08:00
Chris Robinson ff5245ca8a Reword the backend options' text 2008-01-15 12:30:20 -08:00
Chris Robinson fe925ada59 Fix use of variables in checks 2008-01-15 12:25:51 -08:00
Chris Robinson b6596f38b9 Use CMAKE_BUILD_TYPE instead of custom options for compile modes 2008-01-15 10:00:56 -08:00
Chris Robinson 16fb3f6db5 Check for strncasecmp or _strnicmp 2008-01-14 16:30:18 -08:00
Chris Robinson a2e2522612 Let alIsExtensionPresent work with mixed-case extension names 2008-01-14 16:26:22 -08:00
Chris Robinson df07e8a65b Add support for AL_LOKI_quadriphonic 2008-01-14 16:11:15 -08:00
Chris Robinson 729f076c3b Reduce indentation 2008-01-14 15:38:15 -08:00
Chris Robinson dfc0118b8b Add an option for disabling ALSA mmap 2008-01-14 15:30:52 -08:00
Chris Robinson d9ef062caf Avoid busy waiting when waiting for suspend to clear 2008-01-14 13:23:49 -08:00
Chris Robinson 2b8ce3b4cf Let the mmap thread start the pcm stream when it's full
Instead of filling it with silence and starting it before the thread is active
2008-01-14 13:07:41 -08:00
Chris Robinson a27b855a39 Make sure the stream is playing when it's full 2008-01-14 12:59:44 -08:00
Chris Robinson 1634b69faf Don't restart the stream right after preparing it
It needs to be filled, first
2008-01-14 12:51:36 -08:00
Chris Robinson 59fa1f90d5 Don't attempt to recover the ALSA stream when filling silence
Since it was just prepared, any error would likely mean bigger problems
2008-01-14 12:49:21 -08:00
Chris Robinson e519338a2b Add missing stdio include 2008-01-14 10:55:13 -08:00
Chris Robinson 7a4870bd97 Close dangling devices when exiting 2008-01-14 10:54:33 -08:00
Chris Robinson a552e32a9a Destroy context if closing a device with one 2008-01-14 10:42:11 -08:00
Chris Robinson 29c6238b52 Keep track of open devices 2008-01-14 10:39:54 -08:00
Chris Robinson 38db8eb64b Reorder setting of some variables 2008-01-12 07:36:22 -08:00
Chris Robinson 3bbbf8a025 Merge branch 'master' into efx-experiment 2008-01-11 17:19:08 -08:00
Chris Robinson 978764cb6b Don't limit output wave filename size 2008-01-11 15:27:56 -08:00
Chris Robinson 893ecf1af2 Fix the Wave Writer's reliance on ftell
So output can work on FIFOs
2008-01-11 15:18:26 -08:00
Chris Robinson aa453b4e9e Use Sleep instead of usleep 2008-01-11 14:55:35 -08:00
Chris Robinson f8089d2026 Don't double-close a handle on error 2008-01-11 13:23:37 -08:00
Chris Robinson 40241b4e97 Don't attempt to open ALSA playback/capture if it didn't load 2008-01-11 13:00:30 -08:00
Chris Robinson f10408739e Add a wave file writing backend 2008-01-11 09:32:22 -08:00
Chris Robinson e1d0ad749b Use nanosleep instead of usleep
So not to rely on the non-standard unistd.h header
2008-01-11 08:15:44 -08:00
Chris Robinson 2a5a5b5c1b Add Sleep wrapper 2008-01-11 06:54:09 -08:00
Chris Robinson a97ecb8690 Add a timing wrapper, using gettimeofday 2008-01-11 06:01:51 -08:00
Chris Robinson bc56c00a9a Allow querying of ALC_MONO_SOURCES and ALC_STEREO_SOURCES
Based on a patch by Xavier Bouchoux
2008-01-10 08:24:23 -08:00
Chris Robinson 1e3ad2f9ce Use a more reliable thread loop for DSound, instead of a Win32 timer
Also use a simpler method for calculating the read/write location
2008-01-08 07:09:25 -08:00
Chris Robinson 9c97f07ec9 Remove unneeded silence field 2008-01-07 00:26:10 -08:00
Chris Robinson f8acdc9497 Release 1.1.93 2008-01-06 04:35:53 -08:00
Chris Robinson 90d825e7f8 Fix lone ALC_REFRESH query case 2008-01-06 03:36:01 -08:00
Chris Robinson 1178e900eb Don't allow 0 periods 2008-01-06 01:27:26 -08:00
Chris Robinson 298f6f440a Add missing header include 2008-01-06 01:15:44 -08:00
Chris Robinson 8553fb9e30 ALC_REFRESH is the number of updates per second 2008-01-06 01:14:09 -08:00
Chris Robinson da3b270488 Make OSS's update size dynamic 2008-01-06 00:19:28 -08:00
Chris Robinson dd60366aec Fix the buffer size so ALSA doesn't multiply by the number of periods 2008-01-06 00:18:06 -08:00
Chris Robinson 017fc93307 Some non-mmap ALSA fixes 2008-01-05 05:33:54 -08:00
Chris Robinson 042ec206e7 Disable fast float-to-int hack.
Even with precautions, it's giving problems. Not worth it since I don't quite
understand how it works, or know if there's even a benefit.
2008-01-05 05:03:31 -08:00
Chris Robinson 312108a0d3 Try a different low-pass filter
Seems to be more correct, although it's not as powerful as the previous (which
may be a good thing)
2008-01-05 03:51:24 -08:00
Chris Robinson 5e48be27b8 Merge branch 'master' into efx-experiment 2008-01-04 14:40:38 -08:00
Chris Robinson b3badbf97d Use 6 point spatialization for 6.1 and 7.1 output 2008-01-04 14:15:55 -08:00
Chris Robinson 4d5885e27b Implement a crossfeed config option 2008-01-03 06:02:06 -08:00
Chris Robinson 8fe39042da Add the Bauer stereophonic-to-binaural DSP (bs2b) code and hooks 2008-01-03 05:36:51 -08:00
Chris Robinson 9ed574b399 Merge branch 'master' into efx-experiment 2008-01-01 06:29:11 -08:00
Chris Robinson 7ef623c71d Fail if OSS can't set the requested bit depth and channel count 2008-01-01 06:25:00 -08:00
Chris Robinson 733cd120b3 Fix channel ordering for multichannel buffers 2008-01-01 06:16:19 -08:00
Chris Robinson 4e2f8e305e Fix wet volumes for multichannel path 2007-12-31 19:40:24 -08:00
Chris Robinson 3d78d93b40 Merge branch 'master' into efx-experiment 2007-12-31 19:34:52 -08:00
Chris Robinson 5a2f509104 Zero out wet send params when calculating source params
Instead of using a check in the mix loop
2007-12-31 19:13:18 -08:00
Chris Robinson 9382956b0e Remove obsolete comment 2007-12-31 06:00:50 -08:00
Chris Robinson 42027a3f94 Advertise the AL_EXT_MCFORMATS extension 2007-12-31 05:52:22 -08:00
Chris Robinson 1397417fcd Handle AL_FORMAT_REAR* formats 2007-12-31 05:46:20 -08:00
Chris Robinson c9a539eade Allow loading of 4, 5.1, 6.1, and 7.1 sample data 2007-12-31 05:06:59 -08:00
Chris Robinson cb1d62f254 Add paths for 4 to 7.1 channel buffer mixing 2007-12-31 04:50:34 -08:00
Chris Robinson 1cbd625b4e Disable unnecessary calculations 2007-12-31 03:45:26 -08:00
Chris Robinson 73678f3b78 Allow psuedo 6.1 and 7.1 output
This only does spatial calculations on the 4 corner speakers, but it's
necessary groundwork for AL_EXT_MCFORMATS support. Spatial calculations for 6
speakers can be added later.
2007-12-31 03:29:14 -08:00
Chris Robinson 79b95da0a3 Check specific formats before general properties 2007-12-31 02:57:58 -08:00
Chris Robinson 1c85273662 Export float32 formats 2007-12-31 02:55:35 -08:00
Chris Robinson 76dd568971 Add some more formats 2007-12-31 02:53:56 -08:00
Chris Robinson a43868c32b Use an enum list for dealing with channels
This will make it easier to remap channels, especially the center and lfe channels
2007-12-31 01:47:10 -08:00
Chris Robinson 7a99b1fa32 Make some defines local to ALu.c 2007-12-31 01:16:13 -08:00
Chris Robinson e82c27ab04 Fix includes so alMain.h doesn't include so much by itself 2007-12-31 01:09:57 -08:00
Chris Robinson f32098e04d Don't append _struct to the source struct name 2007-12-31 01:09:21 -08:00
Chris Robinson 1e0fa58d79 Remove unused macros 2007-12-31 00:52:34 -08:00
Chris Robinson f7ef5c169b Don't default to AL_FORMAT_STEREO16 when writing to the output buffer 2007-12-31 00:08:07 -08:00
Chris Robinson 927763902f Loop per frame, not per sample, when writing the output buffer 2007-12-31 00:05:29 -08:00
Chris Robinson fcff17c567 Fallback to non-mmap access for ALSA if mmap isn't available 2007-12-30 02:09:39 -08:00
Chris Robinson 2e88a3d03b Check for the correct ALSA driver option name 2007-12-30 01:28:25 -08:00
Chris Robinson 1061108c61 Remove some duplication 2007-12-28 22:56:48 -08:00
Chris Robinson 5f8e65e099 Implement AL_EXT_FLOAT32 2007-12-28 22:41:14 -08:00
Chris Robinson d90b36cf11 Advertise AL_EXT_IMA4, since it's been supported all this time 2007-12-28 22:14:36 -08:00
Chris Robinson 87615fffc9 Consolidate buffer loading/conversion a bit 2007-12-28 20:25:18 -08:00
Chris Robinson 8343a98ec6 Avoid a couple explicit format checks for buffers 2007-12-28 19:21:21 -08:00
Chris Robinson d7bf7a8b0d Don't rely on the exact formats as much for sources 2007-12-28 18:53:46 -08:00
Chris Robinson 9eed1e8609 Add new output formats to sample config 2007-12-27 01:00:19 -08:00
Chris Robinson 8011ad97b5 Don't check explicitly against formats, but rather their byte/channel count 2007-12-26 23:29:32 -08:00
Chris Robinson ab8d342df0 Allow 5.1 channel output
This doesn't use the center or LFE channel in spatial calculations, however
2007-12-26 23:01:22 -08:00
Chris Robinson dcac0de44c Allow empty device specifiers when opening; treat them like NULL 2007-12-26 17:38:42 -08:00
Chris Robinson 2ee389044b Check for libm before including it 2007-12-23 16:28:09 -08:00
Chris Robinson a48201ed94 Fix target opts to remove prefix on the win32 dll
CMake didn't like the previous attempt
2007-12-23 16:27:05 -08:00
Chris Robinson e516b3c0d3 Prevent possible buffer overflow in AL_PRINT 2007-12-22 14:00:10 -08:00
Chris Robinson 51c5fa94aa Check for snprintf, and use _snprintf when needed 2007-12-22 13:35:52 -08:00
Chris Robinson d6288d63c6 Release the new stuff on exit for Windows, too 2007-12-22 13:18:05 -08:00
Chris Robinson 96bd020bd3 Use the right-channel sample... 2007-12-21 14:30:38 -08:00
Chris Robinson 8dc2aef058 Don't send stereo samples to the wet path without an auxiliary slot 2007-12-21 12:12:13 -08:00
Chris Robinson d43486f894 Fix extrenuous comment 2007-12-21 10:52:26 -08:00
Chris Robinson 229bc0d7e1 Merge branch 'master' into efx-experiment 2007-12-20 21:48:17 -08:00
Chris Robinson 5b0514a829 Do the channel pannings based on output channel count
This should make it a bit easier to extend in the future
2007-12-20 21:40:22 -08:00
Chris Robinson 0bef94cb48 Don't use the lib prefix for the Win32 DLL 2007-12-20 12:32:54 -08:00
Chris Robinson 44df5c3567 MacOSX doesn't like global szDebug and g_mutex symbol names 2007-12-19 14:14:26 -08:00
Chris Robinson 7bf9ebf545 Allow auxiliary effect slot 0 when (un)setting the source auxiliary send 2007-12-18 23:51:21 -08:00
Chris Robinson 1e9302f564 Don't assume only one max send when setting source properties 2007-12-18 19:47:42 -08:00
Chris Robinson a433ae0ff4 Use the AuxSendAuto property of the effect slot 2007-12-18 19:43:54 -08:00
Chris Robinson e5609279da Implement AL_AUXILIARY_SEND_FILTER_GAIN_AUTO property 2007-12-18 19:13:41 -08:00
Chris Robinson afd3b71849 Implement AL_ROOM_ROLLOFF_FACTOR property 2007-12-18 19:03:40 -08:00
Chris Robinson 4cc64fa9a8 Don't allow properties on effect and filter name 0 2007-12-18 18:39:08 -08:00
Chris Robinson 7f55372727 Implement AL_EFFECT_TYPE property
Only the null effect type is accepted, right now
2007-12-18 18:15:52 -08:00
Chris Robinson 919b8c5bd1 Report one max auxiliary send per source 2007-12-18 18:13:49 -08:00
Chris Robinson a281027876 Implement AL_AUXILIARY_SEND_FILTER source property 2007-12-18 17:59:28 -08:00
Chris Robinson 72ce653bcf Remove unneeded struct member 2007-12-18 17:46:49 -08:00
Chris Robinson 17c8881444 Add AL_EFFECTSLOT_AUXILIARY_SEND_AUTO property (still unimplemented) 2007-12-18 17:41:44 -08:00
Chris Robinson 6aabc837a9 Fix initial WetMix setup 2007-12-18 17:21:13 -08:00
Chris Robinson 233e6f1765 Implement AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO property 2007-12-18 16:54:22 -08:00
Chris Robinson 9adc20e4e7 Implement AL_EFFECTSLOT_GAIN property 2007-12-18 15:47:24 -08:00
Chris Robinson bdf16bf601 Add initial auxiliary send paths 2007-12-18 15:10:21 -08:00
Chris Robinson cf03bfa156 Implement AL_EFFECTSLOT_EFFECT property 2007-12-18 14:22:59 -08:00
Chris Robinson d4f556836a Only allow one auxiliary effect slot 2007-12-18 13:42:13 -08:00
Chris Robinson ebb30ec5b0 Implement AL_AIR_ABSORPTION_FACTOR source property 2007-12-18 13:37:07 -08:00
Chris Robinson 168d8e3bee Add AL_FILTER_LOWPASS support
Direct filters only, since auxiliary sends and slots aren't available yet
2007-12-17 22:42:38 -08:00
Chris Robinson 654788f2cf Implement AL_CONE_OUTER_GAINHF source property 2007-12-17 21:56:31 -08:00
Chris Robinson 06f2076f04 Implement AL_DIRECT_FILTER_GAINHF_AUTO source property 2007-12-17 21:33:05 -08:00
Chris Robinson fc43a13927 Implement basic lowpass filter path 2007-12-17 21:00:52 -08:00
Chris Robinson 28f80fa113 Add AL_METERS_PER_UNIT listener property 2007-12-17 19:40:43 -08:00
Chris Robinson 9ebf1c1431 Don't attempt to free null effects or filters 2007-12-17 19:12:49 -08:00
Chris Robinson 8795932420 0 is a valid filter and effect name 2007-12-17 19:10:22 -08:00
Chris Robinson be50a5f992 Export ALC_EXT_EFX extension
Preliminary testing can now begin. Almost nothing will work, but the bare
framework is laid out, and the functions can begin to be implemented.
2007-12-17 18:01:01 -08:00
Chris Robinson 7086f5f84c Add new listener property definition 2007-12-17 17:55:27 -08:00
Chris Robinson 670487b4dd Add effect type enums 2007-12-17 17:52:03 -08:00
Chris Robinson 0ac746df57 Add new functions to proc address table 2007-12-17 17:44:11 -08:00
Chris Robinson 7458273634 Add auxiliary effect slot function skeletons 2007-12-17 17:43:19 -08:00
Chris Robinson aa386041e7 Fix comment 2007-12-17 17:20:55 -08:00
Chris Robinson 44e0fa9325 Implement effect function skeletons 2007-12-17 17:20:11 -08:00
Chris Robinson 91d214d713 Release left over filters on close 2007-12-17 17:08:44 -08:00
Chris Robinson 635f673b95 Implement ALC properties 2007-12-17 16:55:07 -08:00
Chris Robinson 35a82970a3 Implement AL_DIRECT_FILTER source property
Only AL_FILTER_NULL filter types are currently supported, however
2007-12-17 16:28:16 -08:00
Chris Robinson ac9bef0b31 Add EFX source filter properties 2007-12-17 16:02:34 -08:00
Chris Robinson f6bb6cc891 Add AL_FILTER_TYPE enum 2007-12-17 15:49:26 -08:00
Chris Robinson 56ff747463 Implement filter function skeletons 2007-12-17 15:43:35 -08:00
Chris Robinson d14ea2965d The error code is in errno, not the return value 2007-12-16 19:45:32 -08:00
Chris Robinson e773887b4b Implement capture config option for OSS. 2007-12-16 19:37:20 -08:00
Chris Robinson 5b85067f9c Support capture for OSS 2007-12-16 19:34:52 -08:00
Chris Robinson 1fa1edf16b Fix ring buffer size and overrun detection 2007-12-16 19:30:57 -08:00
Chris Robinson 19156ab895 Add generic ring buffer methods 2007-12-16 18:36:06 -08:00
45 changed files with 10368 additions and 1593 deletions
+367 -107
View File
@@ -18,28 +18,28 @@
* 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 <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <ctype.h>
#include "alMain.h"
#include "alSource.h"
#include "AL/al.h"
#include "AL/alc.h"
///////////////////////////////////////////////////////
// DEBUG INFORMATION
char szDebug[256];
///////////////////////////////////////////////////////
#include "alThunk.h"
#include "alSource.h"
#include "alBuffer.h"
#include "alExtension.h"
#include "alAuxEffectSlot.h"
#include "bs2b.h"
#include "alu.h"
#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
struct {
static struct {
const char *name;
void (*Init)(BackendFuncs*);
BackendFuncs Funcs;
@@ -50,12 +50,23 @@ struct {
#ifdef HAVE_OSS
{ "oss", alc_oss_init, EmptyFuncs },
#endif
#ifdef HAVE_SOLARIS
{ "solaris", alc_solaris_init, EmptyFuncs },
#endif
#ifdef HAVE_DSOUND
{ "dsound", alcDSoundInit, EmptyFuncs },
#endif
#ifdef HAVE_WINMM
{ "winmm", alcWinMMInit, EmptyFuncs },
#endif
#ifdef HAVE_PORTAUDIO
{ "port", alc_pa_init, EmptyFuncs },
#endif
#ifdef HAVE_PULSEAUDIO
{ "pulse", alc_pulse_init, EmptyFuncs },
#endif
{ "wave", alc_wave_init, EmptyFuncs },
{ NULL, NULL, EmptyFuncs }
};
@@ -63,29 +74,19 @@ struct {
///////////////////////////////////////////////////////
#define ALC_EFX_MAJOR_VERSION 0x20001
#define ALC_EFX_MINOR_VERSION 0x20002
#define ALC_MAX_AUXILIARY_SENDS 0x20003
///////////////////////////////////////////////////////
// STRING and EXTENSIONS
typedef struct ALCextension_struct
{
ALCchar *extName;
ALvoid *address;
} ALCextension;
typedef struct ALCfunction_struct
{
ALCchar *funcName;
ALvoid *address;
} ALCfunction;
static ALCextension alcExtensions[] = {
{ "ALC_ENUMERATE_ALL_EXT", (ALvoid *) NULL },
{ "ALC_ENUMERATION_EXT", (ALvoid *) NULL },
{ "ALC_EXT_CAPTURE", (ALvoid *) NULL },
{ NULL, (ALvoid *) NULL }
};
static ALCfunction alcFunctions[] = {
{ "alcCreateContext", (ALvoid *) alcCreateContext },
{ "alcMakeContextCurrent", (ALvoid *) alcMakeContextCurrent },
@@ -132,9 +133,14 @@ static ALenums enumeration[]={
{ (ALchar *)"ALC_MONO_SOURCES", ALC_MONO_SOURCES },
{ (ALchar *)"ALC_STEREO_SOURCES", ALC_STEREO_SOURCES },
{ (ALchar *)"ALC_CAPTURE_DEVICE_SPECIFIER", ALC_CAPTURE_DEVICE_SPECIFIER },
{ (ALchar *)"ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER },
{ (ALchar *)"ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER},
{ (ALchar *)"ALC_CAPTURE_SAMPLES", ALC_CAPTURE_SAMPLES },
// EFX Properties
{ (ALchar *)"ALC_EFX_MAJOR_VERSION", ALC_EFX_MAJOR_VERSION },
{ (ALchar *)"ALC_EFX_MINOR_VERSION", ALC_EFX_MINOR_VERSION },
{ (ALchar *)"ALC_MAX_AUXILIARY_SENDS", ALC_MAX_AUXILIARY_SENDS },
// ALC Error Message
{ (ALchar *)"ALC_NO_ERROR", ALC_NO_ERROR },
{ (ALchar *)"ALC_INVALID_DEVICE", ALC_INVALID_DEVICE },
@@ -162,16 +168,24 @@ static ALCchar *alcDefaultAllDeviceSpecifier = alcAllDeviceList;
static ALCchar *alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList;
static ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE";
static ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE ALC_EXT_EFX";
static ALCint alcMajorVersion = 1;
static ALCint alcMinorVersion = 1;
static ALCint alcEFXMajorVersion = 1;
static ALCint alcEFXMinorVersion = 0;
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
// Global Variables
static ALCdevice *g_pDeviceList = NULL;
static ALCuint g_ulDeviceCount = 0;
static CRITICAL_SECTION g_csMutex;
// Context List
static ALCcontext *g_pContextList = NULL;
static ALCuint g_ulContextCount = 0;
@@ -179,21 +193,69 @@ static ALCuint g_ulContextCount = 0;
// Context Error
static ALCenum g_eLastContextError = ALC_NO_ERROR;
static ALboolean init_done = AL_FALSE;
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
// ALC Related helper functions
#ifdef _WIN32
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
(void)lpReserved;
// Perform actions based on the reason for calling.
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
break;
case DLL_PROCESS_DETACH:
if(!init_done)
break;
ReleaseALC();
ReleaseALBuffers();
ReleaseALEffects();
ReleaseALFilters();
FreeALConfig();
ALTHUNK_EXIT();
DeleteCriticalSection(&g_csMutex);
break;
}
return TRUE;
}
#else
#ifdef HAVE_GCC_DESTRUCTOR
static void my_deinit() __attribute__((destructor));
static void my_deinit()
{
static ALenum once = AL_FALSE;
if(once || !init_done) return;
once = AL_TRUE;
ReleaseALC();
ReleaseALBuffers();
ReleaseALEffects();
ReleaseALFilters();
FreeALConfig();
ALTHUNK_EXIT();
DeleteCriticalSection(&g_csMutex);
}
#endif
#endif
static void InitAL(void)
{
static int done = 0;
if(!done)
if(!init_done)
{
int i;
const char *devs;
const char *devs, *str;
InitializeCriticalSection(&g_mutex);
init_done = AL_TRUE;
InitializeCriticalSection(&g_csMutex);
ALTHUNK_INIT();
ReadALConfig();
@@ -239,31 +301,84 @@ static void InitAL(void)
for(i = 0;BackendList[i].Init;i++)
BackendList[i].Init(&BackendList[i].Funcs);
done = 1;
str = GetConfigValue(NULL, "stereodup", "false");
DuplicateStereo = (strcasecmp(str, "true") == 0 ||
strcasecmp(str, "yes") == 0 ||
strcasecmp(str, "on") == 0 ||
atoi(str) != 0);
str = GetConfigValue(NULL, "excludefx", "");
if(str[0])
{
const struct {
const char *name;
int type;
} EffectList[] = {
{ "eaxreverb", EAXREVERB },
{ "reverb", REVERB },
{ "echo", ECHO },
{ NULL, 0 }
};
int n;
size_t len;
const char *next = str;
do {
str = next;
next = strchr(str, ',');
if(!str[0] || next == str)
continue;
len = (next ? ((size_t)(next-str)) : strlen(str));
for(n = 0;EffectList[n].name;n++)
{
if(len == strlen(EffectList[n].name) &&
strncmp(EffectList[n].name, str, len) == 0)
DisabledEffects[EffectList[n].type] = AL_TRUE;
}
} while(next++);
}
}
}
ALCchar *AppendDeviceList(char *name)
{
static int pos;
static size_t pos;
ALCchar *ret = alcDeviceList+pos;
pos += snprintf(alcDeviceList+pos, sizeof(alcDeviceList)-pos, "%s", name) + 1;
if(pos >= sizeof(alcDeviceList))
{
AL_PRINT("Not enough room to add %s!\n", name);
return alcDeviceList + sizeof(alcDeviceList) - 1;
}
pos += snprintf(alcDeviceList+pos, sizeof(alcDeviceList)-pos-1, "%s", name) + 1;
return ret;
}
ALCchar *AppendAllDeviceList(char *name)
{
static int pos;
static size_t pos;
ALCchar *ret = alcAllDeviceList+pos;
pos += snprintf(alcAllDeviceList+pos, sizeof(alcAllDeviceList)-pos, "%s", name) + 1;
if(pos >= sizeof(alcAllDeviceList))
{
AL_PRINT("Not enough room to add %s!\n", name);
return alcAllDeviceList + sizeof(alcAllDeviceList) - 1;
}
pos += snprintf(alcAllDeviceList+pos, sizeof(alcAllDeviceList)-pos-1, "%s", name) + 1;
return ret;
}
ALCchar *AppendCaptureDeviceList(char *name)
{
static int pos;
static size_t pos;
ALCchar *ret = alcCaptureDeviceList+pos;
pos += snprintf(alcCaptureDeviceList+pos, sizeof(alcCaptureDeviceList)-pos, "%s", name) + 1;
if(pos >= sizeof(alcCaptureDeviceList))
{
AL_PRINT("Not enough room to add %s!\n", name);
return alcCaptureDeviceList + sizeof(alcCaptureDeviceList) - 1;
}
pos += snprintf(alcCaptureDeviceList+pos, sizeof(alcCaptureDeviceList)-pos-1, "%s", name) + 1;
return ret;
}
@@ -303,7 +418,7 @@ ALCvoid SetALCError(ALenum errorCode)
ALCvoid SuspendContext(ALCcontext *pContext)
{
(void)pContext;
EnterCriticalSection(&g_mutex);
EnterCriticalSection(&g_csMutex);
}
@@ -315,7 +430,7 @@ ALCvoid SuspendContext(ALCcontext *pContext)
ALCvoid ProcessContext(ALCcontext *pContext)
{
(void)pContext;
LeaveCriticalSection(&g_mutex);
LeaveCriticalSection(&g_csMutex);
}
@@ -326,8 +441,11 @@ ALCvoid ProcessContext(ALCcontext *pContext)
*/
static ALvoid InitContext(ALCcontext *pContext)
{
int level;
//Initialise listener
pContext->Listener.Gain = 1.0f;
pContext->Listener.MetersPerUnit = 1.0f;
pContext->Listener.Position[0] = 0.0f;
pContext->Listener.Position[1] = 0.0f;
pContext->Listener.Position[2] = 0.0f;
@@ -357,7 +475,21 @@ static ALvoid InitContext(ALCcontext *pContext)
pContext->lNumStereoSources = 1;
pContext->lNumMonoSources = pContext->Device->MaxNoOfSources - pContext->lNumStereoSources;
strcpy(pContext->ExtensionList, "AL_EXT_EXPONENT_DISTANCE AL_EXT_LINEAR_DISTANCE AL_EXT_OFFSET");
pContext->NumSends = GetConfigValueInt(NULL, "sends", MAX_SENDS);
if(pContext->NumSends > MAX_SENDS)
pContext->NumSends = MAX_SENDS;
pContext->ExtensionList = "AL_EXTX_buffer_sub_data AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET AL_EXTX_source_distance_model AL_LOKI_quadriphonic";
level = GetConfigValueInt(NULL, "cf_level", 0);
if(level > 0 && level <= 6)
{
pContext->bs2b = calloc(1, sizeof(*pContext->bs2b));
bs2b_set_srate(pContext->bs2b, pContext->Frequency);
bs2b_set_level(pContext->bs2b, level);
}
aluInitPanning(pContext);
}
@@ -368,29 +500,12 @@ static ALvoid InitContext(ALCcontext *pContext)
*/
static ALCvoid ExitContext(ALCcontext *pContext)
{
unsigned int i;
ALsource *ALSource;
ALsource *ALTempSource;
#ifdef _DEBUG
if (pContext->SourceCount>0)
AL_PRINT("alcDestroyContext() %d Source(s) NOT deleted\n", pContext->SourceCount);
#endif
// Free all the Sources still remaining
ALSource = pContext->Source;
for (i = 0; i < pContext->SourceCount; i++)
{
ALTempSource = ALSource->next;
ALTHUNK_REMOVEENTRY(ALSource->source);
memset(ALSource, 0, sizeof(ALsource));
free(ALSource);
ALSource = ALTempSource;
}
//Invalidate context
pContext->LastError = AL_NO_ERROR;
pContext->InUse = AL_FALSE;
free(pContext->bs2b);
pContext->bs2b = NULL;
}
///////////////////////////////////////////////////////
@@ -409,39 +524,46 @@ ALCAPI ALCdevice* ALCAPIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, AL
InitAL();
if(SampleSize <= 0)
{
SetALCError(ALC_INVALID_VALUE);
return NULL;
}
if(deviceName && !deviceName[0])
deviceName = NULL;
pDevice = malloc(sizeof(ALCdevice));
if (pDevice)
{
if (SampleSize > 0)
//Initialise device structure
memset(pDevice, 0, sizeof(ALCdevice));
//Validate device
pDevice->IsCaptureDevice = AL_TRUE;
pDevice->Frequency = frequency;
pDevice->Format = format;
for(i = 0;BackendList[i].Init;i++)
{
//Initialise device structure
memset(pDevice, 0, sizeof(ALCdevice));
//Validate device
pDevice->InUse = AL_TRUE;
pDevice->IsCaptureDevice = AL_TRUE;
pDevice->Frequency = frequency;
pDevice->Format = format;
pDevice->Channels = aluChannelsFromFormat(format);
pDevice->FrameSize = aluBytesFromFormat(format) *
pDevice->Channels;
for(i = 0;BackendList[i].Init;i++)
pDevice->Funcs = &BackendList[i].Funcs;
if(ALCdevice_OpenCapture(pDevice, deviceName, frequency, format, SampleSize))
{
pDevice->Funcs = &BackendList[i].Funcs;
if(ALCdevice_OpenCapture(pDevice, deviceName, frequency, format, SampleSize))
{
DeviceFound = ALC_TRUE;
break;
}
SuspendContext(NULL);
pDevice->next = g_pDeviceList;
g_pDeviceList = pDevice;
g_ulDeviceCount++;
ProcessContext(NULL);
DeviceFound = ALC_TRUE;
break;
}
}
else
SetALCError(ALC_INVALID_VALUE);
if(!DeviceFound)
{
SetALCError(ALC_INVALID_VALUE);
free(pDevice);
pDevice = NULL;
}
@@ -455,9 +577,21 @@ ALCAPI ALCdevice* ALCAPIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, AL
ALCAPI ALCboolean ALCAPIENTRY alcCaptureCloseDevice(ALCdevice *pDevice)
{
ALCboolean bReturn = ALC_FALSE;
ALCdevice **list;
if ((pDevice)&&(pDevice->IsCaptureDevice))
{
SuspendContext(NULL);
list = &g_pDeviceList;
while(*list != pDevice)
list = &(*list)->next;
*list = (*list)->next;
g_ulDeviceCount--;
ProcessContext(NULL);
ALCdevice_CloseCapture(pDevice);
free(pDevice);
@@ -665,13 +799,36 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize
*data = alcMinorVersion;
break;
case ALC_EFX_MAJOR_VERSION:
if(!size)
SetALCError(ALC_INVALID_VALUE);
else
*data = alcEFXMajorVersion;
break;
case ALC_EFX_MINOR_VERSION:
if(!size)
SetALCError(ALC_INVALID_VALUE);
else
*data = alcEFXMinorVersion;
break;
case ALC_MAX_AUXILIARY_SENDS:
if(!size)
SetALCError(ALC_INVALID_VALUE);
else if(device && device->Context)
*data = device->Context->NumSends;
else
*data = MAX_SENDS;
break;
case ALC_ATTRIBUTES_SIZE:
if(!device)
SetALCError(ALC_INVALID_DEVICE);
else if(!size)
SetALCError(ALC_INVALID_VALUE);
else
*data = 11;
*data = 12;
break;
case ALC_ALL_ATTRIBUTES:
@@ -687,19 +844,22 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize
data[i++] = device->Frequency;
data[i++] = ALC_REFRESH;
data[i++] = device->UpdateFreq;
data[i++] = device->Frequency / device->UpdateSize;
data[i++] = ALC_SYNC;
data[i++] = ALC_FALSE;
SuspendContext(NULL);
if(device->Context && size >= 11)
if(device->Context && size >= 12)
{
data[i++] = ALC_MONO_SOURCES;
data[i++] = device->Context->lNumMonoSources;
data[i++] = ALC_STEREO_SOURCES;
data[i++] = device->Context->lNumStereoSources;
data[i++] = ALC_MAX_AUXILIARY_SENDS;
data[i++] = device->Context->NumSends;
}
ProcessContext(NULL);
@@ -722,7 +882,7 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize
else if(!size)
SetALCError(ALC_INVALID_VALUE);
else
*data = device->UpdateFreq;
*data = device->Frequency / device->UpdateSize;
break;
case ALC_SYNC:
@@ -734,6 +894,24 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize
*data = ALC_FALSE;
break;
case ALC_MONO_SOURCES:
if(!device || !device->Context)
SetALCError(ALC_INVALID_DEVICE);
else if (size != 1)
SetALCError(ALC_INVALID_VALUE);
else
*data = device->Context->lNumMonoSources;
break;
case ALC_STEREO_SOURCES:
if(!device || !device->Context)
SetALCError(ALC_INVALID_DEVICE);
else if (size != 1)
SetALCError(ALC_INVALID_VALUE);
else
*data = device->Context->lNumStereoSources;
break;
default:
SetALCError(ALC_INVALID_ENUM);
break;
@@ -755,18 +933,31 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize
ALCAPI ALCboolean ALCAPIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName)
{
ALCboolean bResult = ALC_FALSE;
ALsizei i = 0;
(void)device;
if (extName)
{
while(alcExtensions[i].extName &&
strcasecmp(alcExtensions[i].extName,extName) != 0)
i++;
const char *ptr;
size_t len;
if (alcExtensions[i].extName)
bResult = ALC_TRUE;
len = strlen(extName);
ptr = alcExtensionList;
while(ptr && *ptr)
{
if(strncasecmp(ptr, extName, len) == 0 &&
(ptr[len] == '\0' || isspace(ptr[len])))
{
bResult = ALC_TRUE;
break;
}
if((ptr=strchr(ptr, ' ')) != NULL)
{
do {
++ptr;
} while(isspace(*ptr));
}
}
}
else
SetALCError(ALC_INVALID_VALUE);
@@ -833,6 +1024,7 @@ ALCAPI ALCcontext* ALCAPIENTRY alcCreateContext(ALCdevice *device, const ALCint
{
ALCcontext *ALContext = NULL;
ALuint ulAttributeIndex, ulRequestedStereoSources;
ALuint RequestedSends;
if ((device)&&(!device->IsCaptureDevice))
{
@@ -862,7 +1054,7 @@ ALCAPI ALCcontext* ALCAPIENTRY alcCreateContext(ALCdevice *device, const ALCint
ProcessContext(NULL);
// Check for Voice Count attributes
// Check for attributes
if (attrList)
{
ulAttributeIndex = 0;
@@ -877,7 +1069,16 @@ ALCAPI ALCcontext* ALCAPIENTRY alcCreateContext(ALCdevice *device, const ALCint
ALContext->lNumStereoSources = ulRequestedStereoSources;
ALContext->lNumMonoSources = ALContext->Device->MaxNoOfSources - ALContext->lNumStereoSources;
break;
}
if(attrList[ulAttributeIndex] == ALC_MAX_AUXILIARY_SENDS)
{
RequestedSends = attrList[ulAttributeIndex + 1];
if(RequestedSends > ALContext->NumSends)
RequestedSends = ALContext->NumSends;
ALContext->NumSends = RequestedSends;
}
ulAttributeIndex += 2;
@@ -906,6 +1107,8 @@ ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context)
{
ALCcontext **list;
InitAL();
// Lock context list
SuspendContext(NULL);
@@ -914,6 +1117,9 @@ ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context)
// Lock context
SuspendContext(context);
ReleaseALSources(context);
ReleaseALAuxiliaryEffectSlots(context);
context->Device->Context = NULL;
list = &g_pContextList;
@@ -948,6 +1154,8 @@ ALCAPI ALCcontext * ALCAPIENTRY alcGetCurrentContext(ALCvoid)
{
ALCcontext *pContext = NULL;
InitAL();
SuspendContext(NULL);
pContext = g_pContextList;
@@ -969,6 +1177,8 @@ ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext *pContext)
{
ALCdevice *pDevice = NULL;
InitAL();
SuspendContext(NULL);
if (IsContext(pContext))
pDevice = pContext->Device;
@@ -990,6 +1200,8 @@ ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context)
ALCcontext *ALContext;
ALboolean bReturn = AL_TRUE;
InitAL();
SuspendContext(NULL);
// context must be a valid Context or NULL
@@ -1034,6 +1246,9 @@ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName)
InitAL();
if(deviceName && !deviceName[0])
deviceName = NULL;
device = malloc(sizeof(ALCdevice));
if (device)
{
@@ -1043,7 +1258,6 @@ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName)
memset(device, 0, sizeof(ALCdevice));
//Validate device
device->InUse = AL_TRUE;
device->IsCaptureDevice = AL_FALSE;
//Set output format
@@ -1055,39 +1269,48 @@ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName)
if(fmt[0])
device->Format = alGetEnumValue(fmt);
device->Channels = aluChannelsFromFormat(device->Format);
if(!device->Channels)
{
if(!aluChannelsFromFormat(device->Format))
device->Format = AL_FORMAT_STEREO16;
device->Channels = 2;
device->FrameSize = 4;
}
else
device->FrameSize = aluBytesFromFormat(device->Format) *
device->Channels;
device->UpdateFreq = GetConfigValueInt(NULL, "refresh", 0);
if((ALint)device->UpdateFreq <= 0)
device->UpdateFreq = 8192 * device->Frequency / 22050;
device->UpdateSize = GetConfigValueInt(NULL, "refresh", 4096);
if((ALint)device->UpdateSize <= 0)
device->UpdateSize = 4096;
device->MaxNoOfSources = GetConfigValueInt(NULL, "sources", 256);
if((ALint)device->MaxNoOfSources <= 0)
device->MaxNoOfSources = 256;
device->AuxiliaryEffectSlotMax = GetConfigValueInt(NULL, "slots", 4);
if((ALint)device->AuxiliaryEffectSlotMax <= 0)
device->AuxiliaryEffectSlotMax = 4;
// Find a playback device to open
SuspendContext(NULL);
for(i = 0;BackendList[i].Init;i++)
{
device->Funcs = &BackendList[i].Funcs;
if(ALCdevice_OpenPlayback(device, deviceName))
{
device->next = g_pDeviceList;
g_pDeviceList = device;
g_ulDeviceCount++;
bDeviceFound = AL_TRUE;
break;
}
}
ProcessContext(NULL);
if (!bDeviceFound)
{
// No suitable output device found
SetALCError(ALC_INVALID_VALUE);
free(device);
device = NULL;
}
}
else
SetALCError(ALC_OUT_OF_MEMORY);
return device;
}
@@ -1101,9 +1324,28 @@ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName)
ALCAPI ALCboolean ALCAPIENTRY alcCloseDevice(ALCdevice *pDevice)
{
ALCboolean bReturn = ALC_FALSE;
ALCdevice **list;
if ((pDevice)&&(!pDevice->IsCaptureDevice))
{
SuspendContext(NULL);
list = &g_pDeviceList;
while(*list != pDevice)
list = &(*list)->next;
*list = (*list)->next;
g_ulDeviceCount--;
ProcessContext(NULL);
if(pDevice->Context)
{
#ifdef _DEBUG
AL_PRINT("alcCloseDevice(): destroying 1 Context\n");
#endif
alcDestroyContext(pDevice->Context);
}
ALCdevice_ClosePlayback(pDevice);
//Release device structure
@@ -1117,4 +1359,22 @@ ALCAPI ALCboolean ALCAPIENTRY alcCloseDevice(ALCdevice *pDevice)
return bReturn;
}
ALCvoid ReleaseALC(ALCvoid)
{
#ifdef _DEBUG
if(g_ulDeviceCount > 0)
AL_PRINT("exit(): closing %u Device%s\n", g_ulDeviceCount, (g_ulDeviceCount>1)?"s":"");
#endif
while(g_pDeviceList)
{
if(g_pDeviceList->IsCaptureDevice)
alcCaptureCloseDevice(g_pDeviceList);
else
alcCloseDevice(g_pDeviceList);
}
}
///////////////////////////////////////////////////////
+1177 -405
View File
File diff suppressed because it is too large Load Diff
+32 -2
View File
@@ -18,6 +18,12 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#ifdef _WIN32
#define _WIN32_IE 0x400
#endif
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
@@ -25,6 +31,10 @@
#include "alMain.h"
#ifdef _WIN32_IE
#include <shlobj.h>
#endif
typedef struct ConfigEntry {
char *key;
char *value;
@@ -199,8 +209,19 @@ void ReadALConfig(void)
cfgCount = 1;
#ifdef _WIN32
if(SHGetSpecialFolderPathA(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
{
int p = strlen(buffer);
snprintf(buffer+p, sizeof(buffer)-p, "\\alsoft.ini");
f = fopen(buffer, "rt");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
#else
f = fopen("/etc/openal/config", "r");
f = fopen("/etc/openal/alsoft.conf", "r");
if(f)
{
LoadConfigFromFile(f);
@@ -208,7 +229,7 @@ void ReadALConfig(void)
}
if(getenv("HOME") && *(getenv("HOME")))
{
snprintf(buffer, sizeof(buffer), "%s/.openalrc", getenv("HOME"));
snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", getenv("HOME"));
f = fopen(buffer, "r");
if(f)
{
@@ -217,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)
+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;
}
+125
View File
@@ -0,0 +1,125 @@
/**
* 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 <string.h>
#include <stdlib.h>
#include "alMain.h"
struct RingBuffer {
ALubyte *mem;
ALsizei frame_size;
ALsizei length;
ALint read_pos;
ALint write_pos;
CRITICAL_SECTION cs;
};
RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length)
{
RingBuffer *ring = calloc(1, sizeof(*ring));
if(ring)
{
ring->frame_size = frame_size;
ring->length = length+1;
ring->write_pos = 1;
ring->mem = malloc((length+1)*frame_size);
if(!ring->mem)
{
free(ring);
ring = NULL;
}
InitializeCriticalSection(&ring->cs);
}
return ring;
}
void DestroyRingBuffer(RingBuffer *ring)
{
if(ring)
{
DeleteCriticalSection(&ring->cs);
free(ring->mem);
free(ring);
}
}
ALsizei RingBufferSize(RingBuffer *ring)
{
ALsizei s;
EnterCriticalSection(&ring->cs);
s = (ring->write_pos-ring->read_pos-1+ring->length) % ring->length;
LeaveCriticalSection(&ring->cs);
return s;
}
void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
{
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;
if(remain < len)
{
memcpy(ring->mem+(ring->write_pos*ring->frame_size), data, remain*ring->frame_size);
memcpy(ring->mem, data+(remain*ring->frame_size), (len-remain)*ring->frame_size);
}
else
memcpy(ring->mem+(ring->write_pos*ring->frame_size), data, len*ring->frame_size);
ring->write_pos += len;
ring->write_pos %= ring->length;
LeaveCriticalSection(&ring->cs);
}
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
{
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);
memcpy(data+(remain*ring->frame_size), ring->mem, (len-remain)*ring->frame_size);
}
else
memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), len*ring->frame_size);
ring->read_pos += len;
ring->read_pos %= ring->length;
LeaveCriticalSection(&ring->cs);
}
+14 -11
View File
@@ -18,6 +18,8 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include "alMain.h"
@@ -26,8 +28,6 @@
#ifdef _WIN32
#include <windows.h>
typedef struct {
ALuint (*func)(ALvoid*);
ALvoid *ptr;
@@ -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);
@@ -83,22 +85,21 @@ ALuint StopThread(ALvoid *thread)
typedef struct {
ALuint (*func)(ALvoid*);
ALvoid *ptr;
ALuint ret;
pthread_t thread;
} ThreadInfo;
static void *StarterFunc(void *ptr)
{
ThreadInfo *inf = (ThreadInfo*)ptr;
ALint ret;
ret = inf->func(inf->ptr);
return (void*)ret;
inf->ret = inf->func(inf->ptr);
return NULL;
}
ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr)
{
ThreadInfo *inf = malloc(sizeof(ThreadInfo));
if(!inf) return 0;
if(!inf) return NULL;
inf->func = func;
inf->ptr = ptr;
@@ -114,12 +115,14 @@ ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr)
ALuint StopThread(ALvoid *thread)
{
ThreadInfo *inf = thread;
void *ret;
ALuint ret;
pthread_join(inf->thread, NULL);
ret = inf->ret;
pthread_join(inf->thread, &ret);
free(inf);
return (ALuint)ret;
return ret;
}
#endif
+468 -162
View File
@@ -36,7 +36,14 @@
typedef struct {
snd_pcm_t *pcmHandle;
snd_pcm_format_t format;
int killNow;
ALvoid *buffer;
ALsizei size;
RingBuffer *ring;
int doCapture;
volatile int killNow;
ALvoid *thread;
} alsa_data;
@@ -63,15 +70,26 @@ MAKE_FUNC(snd_pcm_hw_params_set_rate_near);
MAKE_FUNC(snd_pcm_hw_params_set_rate);
MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near);
MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
MAKE_FUNC(snd_pcm_hw_params_get_period_size);
MAKE_FUNC(snd_pcm_hw_params_get_access);
MAKE_FUNC(snd_pcm_hw_params);
MAKE_FUNC(snd_pcm_sw_params_malloc);
MAKE_FUNC(snd_pcm_sw_params_current);
MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
MAKE_FUNC(snd_pcm_sw_params);
MAKE_FUNC(snd_pcm_sw_params_free);
MAKE_FUNC(snd_pcm_prepare);
MAKE_FUNC(snd_pcm_start);
MAKE_FUNC(snd_pcm_resume);
MAKE_FUNC(snd_pcm_wait);
MAKE_FUNC(snd_pcm_state);
MAKE_FUNC(snd_pcm_avail_update);
MAKE_FUNC(snd_pcm_areas_silence);
MAKE_FUNC(snd_pcm_mmap_begin);
MAKE_FUNC(snd_pcm_mmap_commit);
MAKE_FUNC(snd_pcm_readi);
MAKE_FUNC(snd_pcm_writei);
MAKE_FUNC(snd_pcm_drain);
MAKE_FUNC(snd_pcm_info_malloc);
MAKE_FUNC(snd_pcm_info_free);
@@ -90,32 +108,27 @@ MAKE_FUNC(snd_ctl_card_info_get_name);
MAKE_FUNC(snd_card_next);
#undef MAKE_FUNC
#define MAX_DEVICES 16
#define MAX_ALL_DEVICES 32
static ALCchar *alsaDevice;
static DevMap allDevNameMap[MAX_ALL_DEVICES];
static ALCchar *alsaDeviceList[MAX_DEVICES];
static ALCchar *alsaCaptureDeviceList[MAX_DEVICES];
static DevMap allCaptureDevNameMap[MAX_ALL_DEVICES];
static int xrun_recovery(snd_pcm_t *handle, int err)
{
if (err == -EPIPE)
{ /* under-run */
err = psnd_pcm_prepare(handle);
if(err >= 0)
err = psnd_pcm_start(handle);
if (err < 0)
AL_PRINT("prepare failed: %s\n", psnd_strerror(err));
}
else if (err == -ESTRPIPE)
{
while ((err = psnd_pcm_resume(handle)) == -EAGAIN)
usleep(1); /* wait until the suspend flag is released */
Sleep(1); /* wait until the suspend flag is released */
if (err < 0)
{
err = psnd_pcm_prepare(handle);
if(err >= 0)
err = psnd_pcm_start(handle);
if (err < 0)
AL_PRINT("prepare failed: %s\n", psnd_strerror(err));
}
@@ -169,39 +182,54 @@ static ALuint ALSAProc(ALvoid *ptr)
}
// make sure there's frames to process
if(avail == 0)
if(avail >= 0 && avail < (snd_pcm_sframes_t)pDevice->UpdateSize)
{
usleep(1000);
if(state != SND_PCM_STATE_RUNNING)
{
err = psnd_pcm_start(data->pcmHandle);
if(err < 0)
err = xrun_recovery(data->pcmHandle, err);
if(err < 0)
{
AL_PRINT("start failed: %s\n", psnd_strerror(err));
break;
}
}
else if(psnd_pcm_wait(data->pcmHandle, 1000) == 0)
AL_PRINT("Wait timeout... buffer size too low?\n");
continue;
}
avail = pDevice->UpdateSize;
// it is possible that contiguous areas are smaller, thus we use a loop
while (avail > 0)
{
frames = avail;
SuspendContext(NULL);
err = psnd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
if (err < 0)
{
err = xrun_recovery(data->pcmHandle, err);
if (err < 0)
AL_PRINT("mmap begin error: %s\n", psnd_strerror(err));
ProcessContext(NULL);
break;
}
SuspendContext(NULL);
WritePtr = (char*)areas->addr + (offset * areas->step / 8);
WriteCnt = psnd_pcm_frames_to_bytes(data->pcmHandle, frames);
aluMixData(pDevice->Context, WritePtr, WriteCnt, pDevice->Format);
ProcessContext(NULL);
commitres = psnd_pcm_mmap_commit(data->pcmHandle, offset, frames);
if (commitres < 0 || (commitres-frames) != 0)
{
AL_PRINT("mmap commit error: %s\n",
psnd_strerror(commitres >= 0 ? -EPIPE : commitres));
ProcessContext(NULL);
break;
}
ProcessContext(NULL);
avail -= frames;
}
@@ -210,66 +238,109 @@ static ALuint ALSAProc(ALvoid *ptr)
return 0;
}
static void fill_silence(snd_pcm_t *pcmHandle, snd_pcm_format_t alsaFormat, int channels)
static ALuint ALSANoMMapProc(ALvoid *ptr)
{
const snd_pcm_channel_area_t *areas = NULL;
snd_pcm_sframes_t avail, commitres;
snd_pcm_uframes_t offset, frames;
int err;
ALCdevice *pDevice = (ALCdevice*)ptr;
alsa_data *data = (alsa_data*)pDevice->ExtraData;
snd_pcm_sframes_t avail;
char *WritePtr;
avail = psnd_pcm_avail_update(pcmHandle);
if(avail < 0)
while(!data->killNow)
{
err = xrun_recovery(pcmHandle, avail);
if (err < 0)
{
AL_PRINT("available update failed: %s\n", psnd_strerror(err));
return;
}
}
SuspendContext(NULL);
aluMixData(pDevice->Context, data->buffer, data->size, pDevice->Format);
ProcessContext(NULL);
// it is possible that contiguous areas are smaller, thus we use a loop
while (avail > 0)
{
frames = avail;
err = psnd_pcm_mmap_begin(pcmHandle, &areas, &offset, &frames);
if (err < 0)
WritePtr = data->buffer;
avail = (snd_pcm_uframes_t)data->size / psnd_pcm_frames_to_bytes(data->pcmHandle, 1);
while(avail > 0)
{
err = xrun_recovery(pcmHandle, err);
if (err < 0)
int ret = psnd_pcm_writei(data->pcmHandle, WritePtr, avail);
switch (ret)
{
AL_PRINT("mmap begin error: %s\n", psnd_strerror(err));
case -EAGAIN:
continue;
case -ESTRPIPE:
while((ret=psnd_pcm_resume(data->pcmHandle)) == -EAGAIN)
Sleep(1);
break;
case -EPIPE:
break;
default:
if (ret >= 0)
{
WritePtr += psnd_pcm_frames_to_bytes(data->pcmHandle, ret);
avail -= ret;
}
break;
}
continue;
if (ret < 0)
{
ret = psnd_pcm_prepare(data->pcmHandle);
if(ret < 0)
break;
}
}
psnd_pcm_areas_silence(areas, offset, channels, frames, alsaFormat);
commitres = psnd_pcm_mmap_commit(pcmHandle, offset, frames);
if (commitres < 0 || (commitres-frames) != 0)
{
AL_PRINT("mmap commit error: %s\n",
psnd_strerror(commitres >= 0 ? -EPIPE : commitres));
break;
}
avail -= frames;
}
return 0;
}
static ALuint ALSANoMMapCaptureProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
alsa_data *data = (alsa_data*)pDevice->ExtraData;
snd_pcm_sframes_t avail;
while(!data->killNow)
{
avail = (snd_pcm_uframes_t)data->size / psnd_pcm_frames_to_bytes(data->pcmHandle, 1);
avail = psnd_pcm_readi(data->pcmHandle, data->buffer, avail);
switch(avail)
{
case -EAGAIN:
continue;
case -ESTRPIPE:
while((avail=psnd_pcm_resume(data->pcmHandle)) == -EAGAIN)
Sleep(1);
break;
case -EPIPE:
break;
default:
if (avail >= 0 && data->doCapture)
WriteRingBuffer(data->ring, data->buffer, avail);
break;
}
if(avail < 0)
{
avail = psnd_pcm_prepare(data->pcmHandle);
if(avail < 0)
AL_PRINT("prepare error: %s\n", psnd_strerror(avail));
}
}
return 0;
}
static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
snd_pcm_uframes_t bufferSizeInFrames;
snd_pcm_sw_params_t *sp = NULL;
snd_pcm_hw_params_t *p = NULL;
snd_pcm_access_t access;
unsigned int periods;
unsigned int rate;
alsa_data *data;
char driver[64];
const char *str;
int allowmmap;
char *err;
int i;
strncpy(driver, GetConfigValue("alsa", "default", "default"), sizeof(driver)-1);
if(!alsa_handle)
return ALC_FALSE;
strncpy(driver, GetConfigValue("alsa", "device", "default"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(deviceName)
{
@@ -286,21 +357,15 @@ static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceNam
goto open_alsa;
}
}
for(idx = 0;idx < MAX_DEVICES;idx++)
if(strcmp(deviceName, alsaDevice) == 0)
{
if(alsaDeviceList[idx] &&
strcmp(deviceName, alsaDeviceList[idx]) == 0)
{
device->szDeviceName = alsaDeviceList[idx];
if(idx > 0)
sprintf(driver, "hw:%zd,0", idx-1);
goto open_alsa;
}
device->szDeviceName = alsaDevice;
goto open_alsa;
}
return ALC_FALSE;
}
else
device->szDeviceName = alsaDeviceList[0];
device->szDeviceName = alsaDevice;
open_alsa:
data = (alsa_data*)calloc(1, sizeof(alsa_data));
@@ -308,7 +373,7 @@ open_alsa:
i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if(i < 0)
{
usleep(200000);
Sleep(200);
i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
}
if(i >= 0)
@@ -324,16 +389,12 @@ open_alsa:
return ALC_FALSE;
}
switch(device->Format)
switch(aluBytesFromFormat(device->Format))
{
case AL_FORMAT_MONO8:
case AL_FORMAT_STEREO8:
case AL_FORMAT_QUAD8:
case 1:
data->format = SND_PCM_FORMAT_U8;
break;
case AL_FORMAT_MONO16:
case AL_FORMAT_STEREO16:
case AL_FORMAT_QUAD16:
case 2:
data->format = SND_PCM_FORMAT_S16;
break;
default:
@@ -341,29 +402,50 @@ open_alsa:
AL_PRINT("Unknown format?! %x\n", device->Format);
}
periods = GetConfigValueInt("alsa", "periods", 4);
if((int)periods <= 0)
periods = 4;
bufferSizeInFrames = device->UpdateFreq;
periods = GetConfigValueInt("alsa", "periods", 0);
bufferSizeInFrames = device->UpdateSize;
rate = device->Frequency;
str = GetConfigValue("alsa", "mmap", "true");
allowmmap = (strcasecmp(str, "true") == 0 ||
strcasecmp(str, "yes") == 0 ||
strcasecmp(str, "on") == 0 ||
atoi(str) != 0);
err = NULL;
psnd_pcm_hw_params_malloc(&p);
#define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1))
/* start with the largest configuration space possible */
if(!(ok(psnd_pcm_hw_params_any(data->pcmHandle, p), "any") &&
/* set interleaved access */
ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED), "set access") &&
/* set format (implicitly sets sample bits) */
ok(psnd_pcm_hw_params_set_format(data->pcmHandle, p, data->format), "set format") &&
/* set channels (implicitly sets frame bits) */
ok(psnd_pcm_hw_params_set_channels(data->pcmHandle, p, device->Channels), "set channels") &&
/* set periods (implicitly constrains period/buffer parameters) */
ok(psnd_pcm_hw_params_set_periods_near(data->pcmHandle, p, &periods, NULL), "set periods near") &&
/* set rate (implicitly constrains period/buffer parameters) */
ok(psnd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &device->Frequency, NULL), "set rate near") &&
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
ok(psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames), "set buffer size near") &&
/* install and prepare hardware configuration */
ok(psnd_pcm_hw_params(data->pcmHandle, p), "set params")))
if((i=psnd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
err = "any";
/* set interleaved access */
if(err == NULL && (!allowmmap || (i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0))
{
if((i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
err = "set access";
}
/* set format (implicitly sets sample bits) */
if(err == NULL && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, data->format)) < 0)
err = "set format";
/* set channels (implicitly sets frame bits) */
if(err == NULL && (i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, aluChannelsFromFormat(device->Format))) < 0)
err = "set channels";
/* set periods (implicitly constrains period/buffer parameters) */
if(err == NULL && periods && (i=psnd_pcm_hw_params_set_periods_near(data->pcmHandle, p, &periods, NULL)) < 0)
err = "set periods near";
/* set rate (implicitly constrains period/buffer parameters) */
if(err == NULL && (i=psnd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL)) < 0)
err = "set rate near";
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
if(err == NULL && (i=psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0)
err = "set buffer size near";
/* install and prepare hardware configuration */
if(err == NULL && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0)
err = "set params";
if(err == NULL && (i=psnd_pcm_hw_params_get_access(p, &access)) < 0)
err = "get access";
if(err == NULL && (i=psnd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0)
err = "get period size";
if(err != NULL)
{
AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
psnd_pcm_hw_params_free(p);
@@ -371,41 +453,72 @@ open_alsa:
free(data);
return ALC_FALSE;
}
#undef ok
psnd_pcm_hw_params_free(p);
device->MaxNoOfSources = 256;
device->UpdateFreq = bufferSizeInFrames;
err = NULL;
psnd_pcm_sw_params_malloc(&sp);
i = psnd_pcm_prepare(data->pcmHandle);
if(i < 0)
if((i=psnd_pcm_sw_params_current(data->pcmHandle, sp)) != 0)
err = "sw current";
if(err == NULL && (i=psnd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, bufferSizeInFrames)) != 0)
err = "sw set avail min";
if(err == NULL && (i=psnd_pcm_sw_params(data->pcmHandle, sp)) != 0)
err = "sw set params";
if(err != NULL)
{
AL_PRINT("prepare error: %s\n", psnd_strerror(i));
AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
psnd_pcm_sw_params_free(sp);
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
fill_silence(data->pcmHandle, data->format, device->Channels);
i = psnd_pcm_start(data->pcmHandle);
if(i < 0)
psnd_pcm_sw_params_free(sp);
data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames);
if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
{
AL_PRINT("start error: %s\n", psnd_strerror(i));
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
data->buffer = malloc(data->size);
if(!data->buffer)
{
AL_PRINT("buffer malloc failed\n");
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
}
else
{
i = psnd_pcm_prepare(data->pcmHandle);
if(i < 0)
{
AL_PRINT("prepare error: %s\n", psnd_strerror(i));
psnd_pcm_close(data->pcmHandle);
free(data->buffer);
free(data);
return ALC_FALSE;
}
}
device->ExtraData = data;
data->thread = StartThread(ALSAProc, device);
if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
data->thread = StartThread(ALSANoMMapProc, device);
else
data->thread = StartThread(ALSAProc, device);
if(data->thread == NULL)
{
AL_PRINT("Could not create playback thread\n");
psnd_pcm_close(data->pcmHandle);
device->ExtraData = NULL;
free(data->buffer);
free(data);
return ALC_FALSE;
}
device->UpdateSize = bufferSizeInFrames;
device->Frequency = rate;
return ALC_TRUE;
}
@@ -416,6 +529,7 @@ static void alsa_close_playback(ALCdevice *device)
StopThread(data->thread);
psnd_pcm_close(data->pcmHandle);
free(data->buffer);
free(data);
device->ExtraData = NULL;
}
@@ -425,34 +539,39 @@ static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceNam
{
snd_pcm_format_t alsaFormat;
snd_pcm_hw_params_t *p;
unsigned int periods = 4;
snd_pcm_uframes_t bufferSizeInFrames = SampleSize;
snd_pcm_uframes_t bufferSizeInFrames;
snd_pcm_access_t access;
const char *str;
alsa_data *data;
char driver[64];
int allowmmap;
char *err;
int i;
if(!alsa_handle)
return ALC_FALSE;
strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(deviceName)
{
size_t idx;
for(idx = 0;idx < MAX_DEVICES;idx++)
for(idx = 0;idx < MAX_ALL_DEVICES;idx++)
{
if(alsaCaptureDeviceList[idx] &&
strcmp(deviceName, alsaCaptureDeviceList[idx]) == 0)
if(allCaptureDevNameMap[idx].name &&
strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
{
pDevice->szDeviceName = alsaCaptureDeviceList[idx];
pDevice->szDeviceName = allCaptureDevNameMap[idx].name;
if(idx > 0)
sprintf(driver, "hw:%zd,0", idx-1);
sprintf(driver, "plughw:%d,%d", allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev);
goto open_alsa;
}
}
return ALC_FALSE;
}
else
pDevice->szDeviceName = alsaCaptureDeviceList[0];
pDevice->szDeviceName = allCaptureDevNameMap[0].name;
open_alsa:
data = (alsa_data*)calloc(1, sizeof(alsa_data));
@@ -460,7 +579,7 @@ open_alsa:
i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
if(i < 0)
{
usleep(200000);
Sleep(200);
i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
}
if(i >= 0)
@@ -489,24 +608,69 @@ open_alsa:
AL_PRINT("Unknown format?! %x\n", format);
}
str = GetConfigValue("alsa", "mmap", "true");
allowmmap = (strcasecmp(str, "true") == 0 ||
strcasecmp(str, "yes") == 0 ||
strcasecmp(str, "on") == 0 ||
atoi(str) != 0);
err = NULL;
bufferSizeInFrames = SampleSize;
psnd_pcm_hw_params_malloc(&p);
#define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1))
/* start with the largest configuration space possible */
if(!(ok(psnd_pcm_hw_params_any(data->pcmHandle, p), "any") &&
/* set interleaved access */
ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED), "set access") &&
/* set format (implicitly sets sample bits) */
ok(psnd_pcm_hw_params_set_format(data->pcmHandle, p, alsaFormat), "set format") &&
/* set channels (implicitly sets frame bits) */
ok(psnd_pcm_hw_params_set_channels(data->pcmHandle, p, pDevice->Channels), "set channels") &&
/* set periods (implicitly constrains period/buffer parameters) */
ok(psnd_pcm_hw_params_set_periods_near(data->pcmHandle, p, &periods, NULL), "set periods near") &&
/* set rate (implicitly constrains period/buffer parameters) */
ok(psnd_pcm_hw_params_set_rate(data->pcmHandle, p, frequency, 0), "set rate") &&
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
ok(psnd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, p, &bufferSizeInFrames), "set buffer size min") &&
/* install and prepare hardware configuration */
ok(psnd_pcm_hw_params(data->pcmHandle, p), "set params")))
if(!allowmmap)
err = "no mmap";
if((i=psnd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
err = "any";
/* set interleaved access */
if(err == NULL && (i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0)
{
err = "set access";
allowmmap = 0;
}
/* set format (implicitly sets sample bits) */
if(err == NULL && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, data->format)) < 0)
err = "set format";
/* set channels (implicitly sets frame bits) */
if(err == NULL && (i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, aluChannelsFromFormat(pDevice->Format))) < 0)
err = "set channels";
/* set rate (implicitly constrains period/buffer parameters) */
if(err == NULL && (i=psnd_pcm_hw_params_set_rate(data->pcmHandle, p, frequency, 0)) < 0)
err = "set rate near";
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
if(err == NULL && (i=psnd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, p, &bufferSizeInFrames)) < 0)
{
err = "set buffer size min";
allowmmap = 0;
}
/* install and prepare hardware configuration */
if(err == NULL && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0)
err = "set params";
if(!allowmmap)
{
err = NULL;
if((i=psnd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
err = "any";
/* set interleaved access */
if(err == NULL && (i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0)
err = "set access";
/* set format (implicitly sets sample bits) */
if(err == NULL && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, data->format)) < 0)
err = "set format";
/* set channels (implicitly sets frame bits) */
if(err == NULL && (i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, aluChannelsFromFormat(pDevice->Format))) < 0)
err = "set channels";
/* set rate (implicitly constrains period/buffer parameters) */
if(err == NULL && (i=psnd_pcm_hw_params_set_rate(data->pcmHandle, p, frequency, 0)) < 0)
err = "set rate near";
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
if(err == NULL && (i=psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0)
err = "set buffer size near";
/* install and prepare hardware configuration */
if(err == NULL && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0)
err = "set params";
}
if(err != NULL)
{
AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
psnd_pcm_hw_params_free(p);
@@ -514,25 +678,90 @@ open_alsa:
free(data);
return ALC_FALSE;
}
#undef ok
psnd_pcm_hw_params_free(p);
i = psnd_pcm_prepare(data->pcmHandle);
if(i < 0)
if((i=psnd_pcm_hw_params_get_access(p, &access)) < 0)
{
AL_PRINT("prepare error: %s\n", psnd_strerror(i));
AL_PRINT("get_access failed: %s\n", psnd_strerror(i));
psnd_pcm_hw_params_free(p);
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
if((i=psnd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0)
{
AL_PRINT("get size failed: %s\n", psnd_strerror(i));
psnd_pcm_hw_params_free(p);
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
pDevice->ExtraData = data;
psnd_pcm_hw_params_free(p);
if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
{
ALuint frameSize = aluChannelsFromFormat(pDevice->Format);
frameSize *= aluBytesFromFormat(pDevice->Format);
data->ring = CreateRingBuffer(frameSize, SampleSize);
if(!data->ring)
{
AL_PRINT("ring buffer create failed\n");
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames);
data->buffer = malloc(data->size);
if(!data->buffer)
{
AL_PRINT("buffer malloc failed\n");
psnd_pcm_close(data->pcmHandle);
DestroyRingBuffer(data->ring);
free(data);
return ALC_FALSE;
}
pDevice->ExtraData = data;
data->thread = StartThread(ALSANoMMapCaptureProc, pDevice);
if(data->thread == NULL)
{
AL_PRINT("Could not create capture thread\n");
pDevice->ExtraData = NULL;
psnd_pcm_close(data->pcmHandle);
DestroyRingBuffer(data->ring);
free(data->buffer);
free(data);
return ALC_FALSE;
}
}
else
{
i = psnd_pcm_prepare(data->pcmHandle);
if(i < 0)
{
AL_PRINT("prepare error: %s\n", psnd_strerror(i));
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
pDevice->ExtraData = data;
}
return ALC_TRUE;
}
static void alsa_close_capture(ALCdevice *pDevice)
{
alsa_data *data = (alsa_data*)pDevice->ExtraData;
if(data->thread)
{
data->killNow = 1;
StopThread(data->thread);
DestroyRingBuffer(data->ring);
}
psnd_pcm_close(data->pcmHandle);
free(data);
@@ -542,13 +771,20 @@ static void alsa_close_capture(ALCdevice *pDevice)
static void alsa_start_capture(ALCdevice *pDevice)
{
alsa_data *data = (alsa_data*)pDevice->ExtraData;
psnd_pcm_start(data->pcmHandle);
data->doCapture = 1;
if(!data->thread)
{
psnd_pcm_prepare(data->pcmHandle);
psnd_pcm_start(data->pcmHandle);
}
}
static void alsa_stop_capture(ALCdevice *pDevice)
{
alsa_data *data = (alsa_data*)pDevice->ExtraData;
psnd_pcm_drain(data->pcmHandle);
data->doCapture = 0;
if(!data->thread)
psnd_pcm_drain(data->pcmHandle);
}
static void alsa_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
@@ -557,8 +793,29 @@ static void alsa_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint l
const snd_pcm_channel_area_t *areas = NULL;
snd_pcm_sframes_t frames, commitres;
snd_pcm_uframes_t size, offset;
snd_pcm_state_t state;
int err;
if(data->thread)
{
if(lSamples <= (ALCuint)RingBufferSize(data->ring))
ReadRingBuffer(data->ring, pBuffer, lSamples);
else
SetALCError(ALC_INVALID_VALUE);
return;
}
state = psnd_pcm_state(data->pcmHandle);
if(state == SND_PCM_STATE_XRUN)
{
err = xrun_recovery(data->pcmHandle, -EPIPE);
if(err < 0)
{
AL_PRINT("XRUN recovery failed: %s\n", psnd_strerror(err));
return;
}
}
frames = psnd_pcm_avail_update(data->pcmHandle);
if(frames < 0)
{
@@ -594,7 +851,7 @@ static void alsa_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint l
}
Pointer = (char*)areas->addr + (offset * areas->step / 8);
Count = size * pDevice->FrameSize;
Count = psnd_pcm_frames_to_bytes(data->pcmHandle, size);
memcpy(pBuffer, Pointer, Count);
pBuffer = (char*)pBuffer + Count;
@@ -614,16 +871,37 @@ static void alsa_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint l
static ALCuint alsa_available_samples(ALCdevice *pDevice)
{
alsa_data *data = (alsa_data*)pDevice->ExtraData;
snd_pcm_sframes_t frames = psnd_pcm_avail_update(data->pcmHandle);
snd_pcm_sframes_t frames;
snd_pcm_state_t state;
int err;
if(data->thread)
return RingBufferSize(data->ring);
state = psnd_pcm_state(data->pcmHandle);
if(state == SND_PCM_STATE_XRUN)
{
err = xrun_recovery(data->pcmHandle, -EPIPE);
if(err >= 0)
{
if(data->doCapture)
err = psnd_pcm_start(data->pcmHandle);
}
if (err < 0)
{
AL_PRINT("XRUN recovery failed: %s\n", psnd_strerror(err));
return 0;
}
}
frames = psnd_pcm_avail_update(data->pcmHandle);
if(frames < 0)
{
int err = xrun_recovery(data->pcmHandle, frames);
err = xrun_recovery(data->pcmHandle, frames);
if (err < 0)
AL_PRINT("available update failed: %s\n", psnd_strerror(err));
else
frames = psnd_pcm_avail_update(data->pcmHandle);
if(frames < 0) /* ew.. */
SetALCError(ALC_INVALID_DEVICE);
}
return max(frames, 0);
}
@@ -670,7 +948,7 @@ void alc_alsa_init(BackendFuncs *func_list)
} while(0)
#else
str = NULL;
alsa_handle = NULL;
alsa_handle = (void*)0xDEADBEEF;
#define LOAD_FUNC(f) p##f = f
#endif
@@ -690,15 +968,26 @@ LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
LOAD_FUNC(snd_pcm_hw_params_set_rate);
LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
LOAD_FUNC(snd_pcm_hw_params_get_period_size);
LOAD_FUNC(snd_pcm_hw_params_get_access);
LOAD_FUNC(snd_pcm_hw_params);
LOAD_FUNC(snd_pcm_sw_params_malloc);
LOAD_FUNC(snd_pcm_sw_params_current);
LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
LOAD_FUNC(snd_pcm_sw_params);
LOAD_FUNC(snd_pcm_sw_params_free);
LOAD_FUNC(snd_pcm_prepare);
LOAD_FUNC(snd_pcm_start);
LOAD_FUNC(snd_pcm_resume);
LOAD_FUNC(snd_pcm_wait);
LOAD_FUNC(snd_pcm_state);
LOAD_FUNC(snd_pcm_avail_update);
LOAD_FUNC(snd_pcm_areas_silence);
LOAD_FUNC(snd_pcm_mmap_begin);
LOAD_FUNC(snd_pcm_mmap_commit);
LOAD_FUNC(snd_pcm_readi);
LOAD_FUNC(snd_pcm_writei);
LOAD_FUNC(snd_pcm_drain);
LOAD_FUNC(snd_pcm_info_malloc);
@@ -725,11 +1014,9 @@ LOAD_FUNC(snd_card_next);
card = -1;
if(psnd_card_next(&card) < 0 || card < 0)
AL_PRINT("no playback cards found...\n");
else
{
alsaDeviceList[0] = AppendDeviceList("ALSA Software on default");
allDevNameMap[0].name = AppendAllDeviceList("ALSA Software on default");
}
alsaDevice = AppendDeviceList("ALSA Software");
allDevNameMap[0].name = AppendAllDeviceList("ALSA Software on default");
while (card >= 0) {
sprintf(name, "hw:%d", card);
@@ -742,11 +1029,6 @@ LOAD_FUNC(snd_card_next);
psnd_ctl_close(handle);
goto next_card;
}
if(card < MAX_DEVICES-1) {
snprintf(name, sizeof(name), "ALSA Software on %s",
psnd_ctl_card_info_get_name(info));
alsaDeviceList[card+1] = AppendDeviceList(name);
}
dev = -1;
while (idx < MAX_ALL_DEVICES) {
@@ -756,6 +1038,7 @@ LOAD_FUNC(snd_card_next);
AL_PRINT("snd_ctl_pcm_next_device failed\n");
if (dev < 0)
break;
psnd_pcm_info_set_device(pcminfo, dev);
psnd_pcm_info_set_subdevice(pcminfo, 0);
psnd_pcm_info_set_stream(pcminfo, stream);
@@ -767,8 +1050,8 @@ LOAD_FUNC(snd_card_next);
cname = psnd_ctl_card_info_get_name(info);
dname = psnd_pcm_info_get_name(pcminfo);
snprintf(name, sizeof(name), "ALSA Software on %s [%s]",
cname, dname);
snprintf(name, sizeof(name), "ALSA Software on %s [%s] (hw:%d,%d)",
cname, dname, card, dev);
allDevNameMap[idx].name = AppendAllDeviceList(name);
allDevNameMap[idx].card = card;
allDevNameMap[idx].dev = dev;
@@ -793,7 +1076,8 @@ next_card:
return;
}
alsaCaptureDeviceList[0] = AppendCaptureDeviceList("ALSA Capture on default");
allCaptureDevNameMap[0].name = AppendCaptureDeviceList("ALSA Capture on default");
idx = 1;
while (card >= 0) {
sprintf(name, "hw:%d", card);
@@ -803,13 +1087,35 @@ next_card:
}
if (err >= 0 && (err = psnd_ctl_card_info(handle, info)) < 0) {
AL_PRINT("control hardware info (%i): %s\n", card, psnd_strerror(err));
psnd_ctl_close(handle);
}
else if (err >= 0 && card < MAX_DEVICES-1)
else if (err >= 0)
{
snprintf(name, sizeof(name), "ALSA Capture on %s",
psnd_ctl_card_info_get_name(info));
alsaCaptureDeviceList[card+1] = AppendCaptureDeviceList(name);
dev = -1;
while (idx < MAX_ALL_DEVICES) {
const char *cname, *dname;
if (psnd_ctl_pcm_next_device(handle, &dev)<0)
AL_PRINT("snd_ctl_pcm_next_device failed\n");
if (dev < 0)
break;
psnd_pcm_info_set_device(pcminfo, dev);
psnd_pcm_info_set_subdevice(pcminfo, 0);
psnd_pcm_info_set_stream(pcminfo, stream);
if ((err = psnd_ctl_pcm_info(handle, pcminfo)) < 0) {
if (err != -ENOENT)
AL_PRINT("control digital audio info (%i): %s\n", card, psnd_strerror(err));
continue;
}
cname = psnd_ctl_card_info_get_name(info);
dname = psnd_pcm_info_get_name(pcminfo);
snprintf(name, sizeof(name), "ALSA Capture on %s [%s] (hw:%d,%d)",
cname, dname, card, dev);
allCaptureDevNameMap[idx].name = AppendCaptureDeviceList(name);
allCaptureDevNameMap[idx].card = card;
allCaptureDevNameMap[idx].dev = dev;
idx++;
}
}
if(handle) psnd_ctl_close(handle);
if(psnd_card_next(&card) < 0) {
+203
View File
@@ -0,0 +1,203 @@
/*-
* Copyright (c) 2005 Boris Mikhaylov
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <math.h>
#include "bs2b.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* Single pole IIR filter.
* O[n] = a0*I[n] + a1*I[n-1] + b1*O[n-1]
*/
/* Lowpass filter */
#define lo_filter(in, out_1) (bs2b->a0_lo*(in) + bs2b->b1_lo*(out_1))
/* Highboost filter */
#define hi_filter(in, in_1, out_1) (bs2b->a0_hi*(in) + bs2b->a1_hi*(in_1) + bs2b->b1_hi*(out_1))
/* Set up all data. */
static void init(struct bs2b *bs2b)
{
double Fc_lo, Fc_hi;
double G_lo, G_hi;
double x;
if ((bs2b->srate > 192000) || (bs2b->srate < 2000))
bs2b->srate = BS2B_DEFAULT_SRATE;
switch(bs2b->level)
{
case BS2B_LOW_CLEVEL: /* Low crossfeed level */
Fc_lo = 360.0;
Fc_hi = 501.0;
G_lo = 0.398107170553497;
G_hi = 0.205671765275719;
break;
case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */
Fc_lo = 500.0;
Fc_hi = 711.0;
G_lo = 0.459726988530872;
G_hi = 0.228208484414988;
break;
case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */
Fc_lo = 700.0;
Fc_hi = 1021.0;
G_lo = 0.530884444230988;
G_hi = 0.250105790667544;
break;
case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */
Fc_lo = 360.0;
Fc_hi = 494.0;
G_lo = 0.316227766016838;
G_hi = 0.168236228897329;
break;
case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */
Fc_lo = 500.0;
Fc_hi = 689.0;
G_lo = 0.354813389233575;
G_hi = 0.187169483835901;
break;
default: /* High easy crossfeed level */
bs2b->level = BS2B_HIGH_ECLEVEL;
Fc_lo = 700.0;
Fc_hi = 975.0;
G_lo = 0.398107170553497;
G_hi = 0.205671765275719;
break;
} /* switch */
/* $fc = $Fc / $s;
* $d = 1 / 2 / pi / $fc;
* $x = exp(-1 / $d);
*/
x = exp(-2.0 * M_PI * Fc_lo / bs2b->srate);
bs2b->b1_lo = x;
bs2b->a0_lo = G_lo * (1.0 - x);
x = exp(-2.0 * M_PI * Fc_hi / bs2b->srate);
bs2b->b1_hi = x;
bs2b->a0_hi = 1.0 - G_hi * (1.0 - x);
bs2b->a1_hi = -x;
bs2b->gain = 1.0 / (1.0 - G_hi + G_lo);
bs2b_clear(bs2b);
} /* init */
/* Exported functions.
* See descriptions in "bs2b.h"
*/
void bs2b_set_level(struct bs2b *bs2b, int level)
{
if(level == bs2b->level)
return;
bs2b->level = level;
init(bs2b);
} /* bs2b_set_level */
int bs2b_get_level(struct bs2b *bs2b)
{
return bs2b->level;
} /* bs2b_get_level */
void bs2b_set_srate(struct bs2b *bs2b, int srate)
{
if (srate == bs2b->srate)
return;
bs2b->srate = srate;
init(bs2b);
} /* bs2b_set_srate */
int bs2b_get_srate(struct bs2b *bs2b)
{
return bs2b->srate;
} /* bs2b_get_srate */
void bs2b_clear(struct bs2b *bs2b)
{
int loopv = sizeof(bs2b->last_sample);
while (loopv)
{
((char *)&bs2b->last_sample)[--loopv] = 0;
}
} /* bs2b_clear */
int bs2b_is_clear(struct bs2b *bs2b)
{
int loopv = sizeof(bs2b->last_sample);
while (loopv)
{
if (((char *)&bs2b->last_sample)[--loopv] != 0)
return 0;
}
return 1;
} /* bs2b_is_clear */
void bs2b_cross_feed(struct bs2b *bs2b, float *sample)
{
/* Lowpass filter */
bs2b->last_sample.lo[0] = lo_filter(sample[0], bs2b->last_sample.lo[0]);
bs2b->last_sample.lo[1] = lo_filter(sample[1], bs2b->last_sample.lo[1]);
/* Highboost filter */
bs2b->last_sample.hi[0] = hi_filter(sample[0], bs2b->last_sample.asis[0], bs2b->last_sample.hi[0]);
bs2b->last_sample.hi[1] = hi_filter(sample[1], bs2b->last_sample.asis[1], bs2b->last_sample.hi[1]);
bs2b->last_sample.asis[0] = sample[0];
bs2b->last_sample.asis[1] = sample[1];
/* Crossfeed */
sample[0] = bs2b->last_sample.hi[0] + bs2b->last_sample.lo[1];
sample[1] = bs2b->last_sample.hi[1] + bs2b->last_sample.lo[0];
/* Bass boost cause allpass attenuation */
sample[0] *= bs2b->gain;
sample[1] *= bs2b->gain;
/* Clipping of overloaded samples */
#if 0
if (sample[0] > 1.0)
sample[0] = 1.0;
if (sample[0] < -1.0)
sample[0] = -1.0;
if (sample[1] > 1.0)
sample[1] = 1.0;
if (sample[1] < -1.0)
sample[1] = -1.0;
#endif
} /* bs2b_cross_feed */
+286 -98
View File
@@ -18,122 +18,168 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#define _WIN32_WINNT 0x0500
#define INITGUID
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <windows.h>
#include <mmsystem.h>
#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);
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, emulate it
static int num_frags;
typedef struct {
// DirectSound Playback Device
LPDIRECTSOUND lpDS;
LPDIRECTSOUNDBUFFER DSpbuffer;
LPDIRECTSOUNDBUFFER DSsbuffer;
MMRESULT ulDSTimerID;
DWORD OldWriteCursor;
volatile int killNow;
ALvoid *thread;
} DSoundData;
static ALCchar *DeviceList[16];
typedef struct {
ALCchar *name;
GUID guid;
} DevMap;
static DevMap DeviceList[16];
static void CALLBACK DirectSoundProc(UINT uID,UINT uReserved,DWORD_PTR dwUser,DWORD_PTR dwReserved1,DWORD_PTR dwReserved2)
static ALuint DSoundProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice *)dwUser;
DSoundData *pData = pDevice->ExtraData;
DWORD PlayCursor,WriteCursor;
BYTE *WritePtr1,*WritePtr2;
DWORD WriteCnt1,WriteCnt2;
WAVEFORMATEX OutputType;
DWORD BytesPlayed;
DWORD BufSize;
HRESULT DSRes;
ALCdevice *pDevice = (ALCdevice*)ptr;
DSoundData *pData = (DSoundData*)pDevice->ExtraData;
DSBCAPS DSBCaps;
DWORD LastCursor = 0;
DWORD PlayCursor;
VOID *WritePtr1, *WritePtr2;
DWORD WriteCnt1, WriteCnt2;
DWORD FragSize;
DWORD avail;
HRESULT err;
(void)uID;
(void)uReserved;
(void)dwReserved1;
(void)dwReserved2;
BufSize = pDevice->UpdateFreq * pDevice->FrameSize;
// Get current play and write cursors
IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer,&PlayCursor,&WriteCursor);
if (!pData->OldWriteCursor) pData->OldWriteCursor=WriteCursor-PlayCursor;
// Get the output format and figure the number of bytes played (block aligned)
IDirectSoundBuffer_GetFormat(pData->DSsbuffer,&OutputType,sizeof(WAVEFORMATEX),NULL);
BytesPlayed=((((WriteCursor<pData->OldWriteCursor)?(BufSize+WriteCursor-pData->OldWriteCursor):(WriteCursor-pData->OldWriteCursor))/OutputType.nBlockAlign)*OutputType.nBlockAlign);
// Lock output buffer started at 40msec in front of the old write cursor (15msec in front of the actual write cursor)
DSRes=IDirectSoundBuffer_Lock(pData->DSsbuffer,(pData->OldWriteCursor+(OutputType.nSamplesPerSec/25)*OutputType.nBlockAlign)%BufSize,BytesPlayed,(LPVOID*)&WritePtr1,&WriteCnt1,(LPVOID*)&WritePtr2,&WriteCnt2,0);
// If the buffer is lost, restore it, play and lock
if (DSRes==DSERR_BUFFERLOST)
memset(&DSBCaps, 0, sizeof(DSBCaps));
DSBCaps.dwSize = sizeof(DSBCaps);
err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps);
if(FAILED(err))
{
IDirectSoundBuffer_Restore(pData->DSsbuffer);
IDirectSoundBuffer_Play(pData->DSsbuffer,0,0,DSBPLAY_LOOPING);
DSRes=IDirectSoundBuffer_Lock(pData->DSsbuffer,(pData->OldWriteCursor+(OutputType.nSamplesPerSec/25)*OutputType.nBlockAlign)%BufSize,BytesPlayed,(LPVOID*)&WritePtr1,&WriteCnt1,(LPVOID*)&WritePtr2,&WriteCnt2,0);
AL_PRINT("Failed to get buffer caps: 0x%lx\n", err);
return 1;
}
FragSize = DSBCaps.dwBufferBytes / num_frags;
// Successfully locked the output buffer
if (DSRes==DS_OK)
IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL);
while(!pData->killNow)
{
// If we have an active context, mix data directly into output buffer otherwise fill with silence
SuspendContext(NULL);
if (WritePtr1)
// Get current play and write cursors
IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
if(avail < FragSize)
{
Sleep(1);
continue;
}
avail -= avail%FragSize;
// Lock output buffer
WriteCnt1 = 0;
WriteCnt2 = 0;
err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
// If the buffer is lost, restore it, play and lock
if(err == DSERR_BUFFERLOST)
{
err = IDirectSoundBuffer_Restore(pData->DSsbuffer);
if(SUCCEEDED(err))
err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
if(SUCCEEDED(err))
err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
}
// Successfully locked the output buffer
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);
if (WritePtr2)
aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format);
ProcessContext(NULL);
ProcessContext(NULL);
// Unlock output buffer only when successfully locked
IDirectSoundBuffer_Unlock(pData->DSsbuffer,WritePtr1,WriteCnt1,WritePtr2,WriteCnt2);
// Unlock output buffer only when successfully locked
IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
}
else
AL_PRINT("Buffer lock error: %#lx\n", err);
// Update old write cursor location
LastCursor += WriteCnt1+WriteCnt2;
LastCursor %= DSBCaps.dwBufferBytes;
}
// Update old write cursor location
pData->OldWriteCursor=((pData->OldWriteCursor+BytesPlayed)%BufSize);
return 0;
}
static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
{
DSBUFFERDESC DSBDescription;
DSoundData *pData = NULL;
WAVEFORMATEX OutputType;
WAVEFORMATEXTENSIBLE OutputType;
DWORD frameSize = 0;
LPGUID guid = NULL;
ALenum format = 0;
DWORD speakers;
HRESULT hr;
if(ds_handle == NULL)
return ALC_FALSE;
if(deviceName)
{
int i;
for(i = 0;DeviceList[i];i++)
for(i = 0;DeviceList[i].name;i++)
{
if(strcmp(deviceName, DeviceList[i]) == 0)
if(strcmp(deviceName, DeviceList[i].name) == 0)
{
device->szDeviceName = DeviceList[i];
device->szDeviceName = DeviceList[i].name;
if(i > 0)
guid = &DeviceList[i].guid;
break;
}
}
if(!DeviceList[i])
if(!DeviceList[i].name)
return ALC_FALSE;
}
else
device->szDeviceName = DeviceList[0];
device->szDeviceName = DeviceList[0].name;
//Platform specific
memset(&OutputType, 0, sizeof(WAVEFORMATEX));
OutputType.wFormatTag = WAVE_FORMAT_PCM;
OutputType.nChannels = device->Channels;
OutputType.wBitsPerSample = (((device->Format==AL_FORMAT_MONO16)||(device->Format==AL_FORMAT_STEREO16)||(device->Format==AL_FORMAT_QUAD16))?16:8);
OutputType.nBlockAlign = OutputType.nChannels*OutputType.wBitsPerSample/8;
OutputType.nSamplesPerSec = device->Frequency;
OutputType.nAvgBytesPerSec = OutputType.nSamplesPerSec*OutputType.nBlockAlign;
OutputType.cbSize = 0;
memset(&OutputType, 0, sizeof(OutputType));
//Initialise requested device
@@ -144,39 +190,141 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
return ALC_FALSE;
}
//Init COM
CoInitialize(NULL);
//DirectSound Init code
hr = CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSound, (LPVOID*)&pData->lpDS);
if(SUCCEEDED(hr))
hr = IDirectSound_Initialize(pData->lpDS, NULL);
hr = pDirectSoundCreate(guid, &pData->lpDS, NULL);
if(SUCCEEDED(hr))
hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
if(SUCCEEDED(hr))
{
memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
DSBDescription.dwSize=sizeof(DSBUFFERDESC);
DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL);
if(*(GetConfigValue(NULL, "format", "")) == 0)
hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
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);
}
}
if(SUCCEEDED(hr))
hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType);
{
speakers = DSSPEAKER_CONFIG(speakers);
if(speakers == DSSPEAKER_MONO)
{
if(aluBytesFromFormat(device->Format) == 1)
format = AL_FORMAT_MONO8;
else
format = AL_FORMAT_MONO16;
}
else if(speakers == DSSPEAKER_STEREO)
{
if(aluBytesFromFormat(device->Format) == 1)
format = AL_FORMAT_STEREO8;
else
format = AL_FORMAT_STEREO16;
}
else if(speakers == DSSPEAKER_QUAD)
{
if(aluBytesFromFormat(device->Format) == 1)
format = AL_FORMAT_QUAD8;
else
format = AL_FORMAT_QUAD16;
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
}
else if(speakers == DSSPEAKER_5POINT1)
{
if(aluBytesFromFormat(device->Format) == 1)
format = AL_FORMAT_51CHN8;
else
format = AL_FORMAT_51CHN16;
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
}
else if(speakers == DSSPEAKER_7POINT1)
{
if(aluBytesFromFormat(device->Format) == 1)
format = AL_FORMAT_71CHN8;
else
format = AL_FORMAT_71CHN16;
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
}
else
format = device->Format;
frameSize = aluBytesFromFormat(format) * aluChannelsFromFormat(format);
OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
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;
}
if(OutputType.Format.nChannels > 2)
{
OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
OutputType.Format.cbSize = 22;
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
}
else
{
if(SUCCEEDED(hr))
{
memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
DSBDescription.dwSize=sizeof(DSBUFFERDESC);
DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL);
}
if(SUCCEEDED(hr))
hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format);
}
if(SUCCEEDED(hr))
{
memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
DSBDescription.dwSize=sizeof(DSBUFFERDESC);
DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
DSBDescription.dwBufferBytes=device->UpdateFreq * device->FrameSize;
DSBDescription.lpwfxFormat=&OutputType;
DSBDescription.dwBufferBytes=(device->UpdateSize/num_frags) * num_frags * frameSize;
DSBDescription.lpwfxFormat=&OutputType.Format;
hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
}
if(SUCCEEDED(hr))
hr = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
if(SUCCEEDED(hr))
{
device->ExtraData = pData;
pData->thread = StartThread(DSoundProc, device);
if(!pData->thread)
hr = E_FAIL;
}
if(FAILED(hr))
{
if (pData->DSsbuffer)
@@ -190,10 +338,9 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
return ALC_FALSE;
}
pData->ulDSTimerID = timeSetEvent(25, 0, (LPTIMECALLBACK)DirectSoundProc, (DWORD)device, (UINT)TIME_CALLBACK_FUNCTION|TIME_PERIODIC);
device->MaxNoOfSources = 256;
device->Format = format;
device->UpdateSize /= num_frags;
device->ExtraData = pData;
return ALC_TRUE;
}
@@ -201,26 +348,14 @@ static void DSoundClosePlayback(ALCdevice *device)
{
DSoundData *pData = device->ExtraData;
// Stop and release the DS timer
if (pData->ulDSTimerID)
timeKillEvent(pData->ulDSTimerID);
pData->killNow = 1;
StopThread(pData->thread);
// Wait ... just in case any timer events happen
Sleep(100);
SuspendContext(NULL);
if (pData->DSsbuffer)
IDirectSoundBuffer_Release(pData->DSsbuffer);
IDirectSoundBuffer_Release(pData->DSsbuffer);
if (pData->DSpbuffer)
IDirectSoundBuffer_Release(pData->DSpbuffer);
IDirectSound_Release(pData->lpDS);
//Deinit COM
CoUninitialize();
ProcessContext(NULL);
free(pData);
device->ExtraData = NULL;
}
@@ -276,10 +411,63 @@ BackendFuncs DSoundFuncs = {
DSoundAvailableSamples
};
static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
{
size_t *iter = 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)++;
}
else
DeviceList[0].name = AppendDeviceList("DirectSound Software");
return TRUE;
}
void alcDSoundInit(BackendFuncs *FuncList)
{
size_t iter = 1;
HRESULT hr;
*FuncList = DSoundFuncs;
DeviceList[0] = AppendDeviceList("DirectSound Software");
AppendAllDeviceList(DeviceList[0]);
#ifdef _WIN32
ds_handle = LoadLibraryA("dsound.dll");
if(ds_handle == NULL)
{
AL_PRINT("Failed to load dsound.dll\n");
return;
}
#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
num_frags = GetConfigValueInt("dsound", "periods", 4);
if(num_frags < 2) num_frags = 2;
hr = pDirectSoundEnumerateA(DSoundEnumDevices, &iter);
if(FAILED(hr))
AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
}
+216 -89
View File
@@ -18,6 +18,8 @@
* 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>
@@ -46,15 +48,18 @@
#endif
static char *oss_device;
static char *oss_device_capture;
typedef struct {
int fd;
int killNow;
volatile int killNow;
ALvoid *thread;
ALubyte *mix_data;
int data_size;
int silence;
RingBuffer *ring;
int doCapture;
} oss_data;
@@ -74,42 +79,77 @@ static ALuint OSSProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
oss_data *data = (oss_data*)pDevice->ExtraData;
int remaining;
int wrote;
while(!data->killNow)
{
ALint len = data->data_size;
ALubyte *WritePtr = data->mix_data;
SuspendContext(NULL);
aluMixData(pDevice->Context,data->mix_data,data->data_size,pDevice->Format);
aluMixData(pDevice->Context, WritePtr, len, pDevice->Format);
ProcessContext(NULL);
remaining = data->data_size;
while(remaining > 0)
while(len > 0 && !data->killNow)
{
wrote = write(data->fd, data->mix_data+data->data_size-remaining, remaining);
wrote = write(data->fd, WritePtr, len);
if(wrote < 0)
{
AL_PRINT("write failed: %s\n", strerror(errno));
break;
}
if(wrote == 0)
{
usleep(1000);
if(errno != EAGAIN && errno != EWOULDBLOCK)
{
AL_PRINT("write failed: %s\n", strerror(errno));
len = 0;
}
else
Sleep(1);
continue;
}
remaining -= wrote;
len -= wrote;
WritePtr += wrote;
}
}
return 0;
}
static ALuint OSSCaptureProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
oss_data *data = (oss_data*)pDevice->ExtraData;
int frameSize;
int amt;
frameSize = aluBytesFromFormat(pDevice->Format);
frameSize *= aluChannelsFromFormat(pDevice->Format);
while(!data->killNow)
{
amt = read(data->fd, data->mix_data, data->data_size);
if(amt < 0)
{
AL_PRINT("read failed: %s\n", strerror(errno));
break;
}
if(amt == 0)
{
Sleep(1);
continue;
}
if(data->doCapture)
WriteRingBuffer(data->ring, data->mix_data, amt/frameSize);
}
return 0;
}
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;
@@ -140,18 +180,12 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
return ALC_FALSE;
}
switch(device->Format)
switch(aluBytesFromFormat(device->Format))
{
case AL_FORMAT_MONO8:
case AL_FORMAT_STEREO8:
case AL_FORMAT_QUAD8:
data->silence = 0x80;
case 1:
ossFormat = AFMT_U8;
break;
case AL_FORMAT_MONO16:
case AL_FORMAT_STEREO16:
case AL_FORMAT_QUAD16:
data->silence = 0;
case 2:
ossFormat = AFMT_S16_NE;
break;
default:
@@ -160,11 +194,13 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
}
periods = GetConfigValueInt("oss", "periods", 4);
if((int)periods < 0)
if((int)periods <= 0)
periods = 4;
numChannels = device->Channels;
numChannels = aluChannelsFromFormat(device->Format);
frameSize = numChannels * aluBytesFromFormat(device->Format);
ossSpeed = device->Frequency;
log2FragmentSize = log2i(device->UpdateFreq * device->FrameSize / periods);
log2FragmentSize = log2i(device->UpdateSize * frameSize / periods);
/* according to the OSS spec, 16 bytes are the minimum */
if (log2FragmentSize < 4)
@@ -178,68 +214,33 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
ok(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed), "set speed") &&
ok(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info), "get space")))
{
AL_PRINT("%s failed: %s\n", err, strerror(i));
AL_PRINT("%s failed: %s\n", err, strerror(errno));
close(data->fd);
free(data);
return ALC_FALSE;
}
#undef ok
device->Channels = numChannels;
device->Frequency = ossSpeed;
device->Format = 0;
if(ossFormat == AFMT_U8)
if((int)aluChannelsFromFormat(device->Format) != numChannels)
{
if(device->Channels == 1)
{
device->Format = AL_FORMAT_MONO8;
device->FrameSize = 1;
}
else if(device->Channels == 2)
{
device->Format = AL_FORMAT_STEREO8;
device->FrameSize = 2;
}
else if(device->Channels == 4)
{
device->Format = AL_FORMAT_QUAD8;
device->FrameSize = 4;
}
}
else if(ossFormat == AFMT_S16_NE)
{
if(device->Channels == 1)
{
device->Format = AL_FORMAT_MONO16;
device->FrameSize = 2;
}
else if(device->Channels == 2)
{
device->Format = AL_FORMAT_STEREO16;
device->FrameSize = 4;
}
else if(device->Channels == 4)
{
device->Format = AL_FORMAT_QUAD16;
device->FrameSize = 8;
}
}
if(!device->Format)
{
AL_PRINT("returned unknown format: %#x %d!\n", ossFormat, numChannels);
AL_PRINT("Could not set %d channels, got %d instead\n", aluChannelsFromFormat(device->Format), numChannels);
close(data->fd);
free(data);
return ALC_FALSE;
}
device->UpdateFreq = info.fragsize / device->FrameSize;
if(!((ossFormat == AFMT_U8 && aluBytesFromFormat(device->Format) == 1) ||
(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;
}
data->data_size = device->UpdateFreq * device->FrameSize;
data->data_size = device->UpdateSize * frameSize;
data->mix_data = calloc(1, data->data_size);
device->MaxNoOfSources = 256;
device->ExtraData = data;
data->thread = StartThread(OSSProc, device);
if(data->thread == NULL)
@@ -250,6 +251,9 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
return ALC_FALSE;
}
device->Frequency = ossSpeed;
device->UpdateSize = info.fragsize / frameSize;
return ALC_TRUE;
}
@@ -267,42 +271,163 @@ static void oss_close_playback(ALCdevice *device)
}
static ALCboolean oss_open_capture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
{
(void)pDevice;
(void)deviceName;
(void)frequency;
(void)format;
(void)SampleSize;
return ALC_FALSE;
int numFragmentsLogSize;
int log2FragmentSize;
unsigned int periods;
audio_buf_info info;
ALuint frameSize;
int numChannels;
char driver[64];
oss_data *data;
int ossFormat;
int ossSpeed;
char *err;
int i;
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;
data = (oss_data*)calloc(1, sizeof(oss_data));
data->killNow = 0;
data->fd = open(driver, O_RDONLY);
if(data->fd == -1)
{
free(data);
AL_PRINT("Could not open %s: %s\n", driver, strerror(errno));
return ALC_FALSE;
}
switch(aluBytesFromFormat(format))
{
case 1:
ossFormat = AFMT_U8;
break;
case 2:
ossFormat = AFMT_S16_NE;
break;
default:
ossFormat = -1;
AL_PRINT("Unknown format?! %x\n", device->Format);
}
periods = 4;
numChannels = aluChannelsFromFormat(device->Format);
frameSize = numChannels * aluBytesFromFormat(device->Format);
ossSpeed = frequency;
log2FragmentSize = log2i(SampleSize * frameSize / periods);
/* according to the OSS spec, 16 bytes are the minimum */
if (log2FragmentSize < 4)
log2FragmentSize = 4;
numFragmentsLogSize = (periods << 16) | log2FragmentSize;
#define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1))
if (!(ok(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize), "set fragment") &&
ok(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat), "set format") &&
ok(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels), "set channels") &&
ok(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed), "set speed") &&
ok(ioctl(data->fd, SNDCTL_DSP_GETISPACE, &info), "get space")))
{
AL_PRINT("%s failed: %s\n", err, strerror(errno));
close(data->fd);
free(data);
return ALC_FALSE;
}
#undef ok
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;
}
if(!((ossFormat == AFMT_U8 && aluBytesFromFormat(device->Format) == 1) ||
(ossFormat == AFMT_S16_NE && aluBytesFromFormat(device->Format) == 2)))
{
AL_PRINT("Could not set %d-bit input, got format %#x\n", aluBytesFromFormat(device->Format)*8, ossFormat);
close(data->fd);
free(data);
return ALC_FALSE;
}
data->ring = CreateRingBuffer(frameSize, SampleSize);
if(!data->ring)
{
AL_PRINT("ring buffer create failed\n");
close(data->fd);
free(data);
return ALC_FALSE;
}
data->data_size = info.fragsize;
data->mix_data = calloc(1, data->data_size);
device->ExtraData = data;
data->thread = StartThread(OSSCaptureProc, device);
if(data->thread == NULL)
{
device->ExtraData = NULL;
free(data->mix_data);
free(data);
return ALC_FALSE;
}
return ALC_TRUE;
}
static void oss_close_capture(ALCdevice *pDevice)
static void oss_close_capture(ALCdevice *device)
{
(void)pDevice;
oss_data *data = (oss_data*)device->ExtraData;
data->killNow = 1;
StopThread(data->thread);
close(data->fd);
DestroyRingBuffer(data->ring);
free(data->mix_data);
free(data);
device->ExtraData = NULL;
}
static void oss_start_capture(ALCdevice *pDevice)
{
(void)pDevice;
oss_data *data = (oss_data*)pDevice->ExtraData;
data->doCapture = 1;
}
static void oss_stop_capture(ALCdevice *pDevice)
{
(void)pDevice;
oss_data *data = (oss_data*)pDevice->ExtraData;
data->doCapture = 0;
}
static void oss_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
{
(void)pDevice;
(void)pBuffer;
(void)lSamples;
oss_data *data = (oss_data*)pDevice->ExtraData;
if(lSamples <= (ALCuint)RingBufferSize(data->ring))
ReadRingBuffer(data->ring, pBuffer, lSamples);
else
SetALCError(ALC_INVALID_VALUE);
}
static ALCuint oss_available_samples(ALCdevice *pDevice)
{
(void)pDevice;
return 0;
oss_data *data = (oss_data*)pDevice->ExtraData;
return RingBufferSize(data->ring);
}
@@ -323,4 +448,6 @@ void alc_oss_init(BackendFuncs *func_list)
oss_device = AppendDeviceList("OSS Software");
AppendAllDeviceList(oss_device);
oss_device_capture = AppendCaptureDeviceList("OSS Capture");
}
+239
View File
@@ -0,0 +1,239 @@
/**
* 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_GetErrorText);
MAKE_FUNC(Pa_StartStream);
MAKE_FUNC(Pa_StopStream);
MAKE_FUNC(Pa_OpenStream);
MAKE_FUNC(Pa_CloseStream);
MAKE_FUNC(Pa_GetDefaultOutputDevice);
#undef MAKE_FUNC
static char *pa_device;
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;
int frameSize;
(void)inputBuffer;
(void)timeInfo;
(void)statusFlags;
frameSize = aluBytesFromFormat(device->Format);
frameSize *= aluChannelsFromFormat(device->Format);
SuspendContext(NULL);
aluMixData(device->Context, outputBuffer, framesPerBuffer*frameSize, device->Format);
ProcessContext(NULL);
return 0;
}
static ALCboolean pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
PaStreamParameters outParams;
pa_data *data;
int periods;
PaError err;
if(pa_handle == NULL)
return ALC_FALSE;
if(deviceName)
{
if(strcmp(deviceName, pa_device) != 0)
return ALC_FALSE;
}
device->szDeviceName = pa_device;
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 = (float)device->UpdateSize /
(float)device->Frequency;
outParams.hostApiSpecificStreamInfo = NULL;
switch(aluBytesFromFormat(device->Format))
{
case 1:
outParams.sampleFormat = paUInt8;
break;
case 2:
outParams.sampleFormat = paInt16;
break;
default:
outParams.sampleFormat = -1;
AL_PRINT("Unknown format?! %x\n", device->Format);
}
periods = GetConfigValueInt("port", "periods", 4);
if((int)periods <= 0)
periods = 4;
outParams.channelCount = aluChannelsFromFormat(device->Format);
err = pPa_OpenStream(&data->stream, NULL, &outParams, device->Frequency,
device->UpdateSize/periods, 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;
}
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->UpdateSize /= periods;
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_open_capture(ALCdevice *device, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
{
return ALC_FALSE;
(void)device;
(void)deviceName;
(void)frequency;
(void)format;
(void)SampleSize;
}
static const BackendFuncs pa_funcs = {
pa_open_playback,
pa_close_playback,
pa_open_capture,
NULL,
NULL,
NULL,
NULL,
NULL
};
void alc_pa_init(BackendFuncs *func_list)
{
const char *str;
PaError err;
*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_GetErrorText);
LOAD_FUNC(Pa_StartStream);
LOAD_FUNC(Pa_StopStream);
LOAD_FUNC(Pa_OpenStream);
LOAD_FUNC(Pa_CloseStream);
LOAD_FUNC(Pa_GetDefaultOutputDevice);
#undef LOAD_FUNC
if((err=pPa_Initialize()) != paNoError)
{
AL_PRINT("Pa_Initialize() returned an error: %s\n", pPa_GetErrorText(err));
return;
}
pa_device = AppendDeviceList("PortAudio Software");
AppendAllDeviceList(pa_device);
}
+595
View File
@@ -0,0 +1,595 @@
/**
* 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_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
typedef struct {
ALCdevice *device;
ALCenum format;
ALCuint samples;
ALCuint frequency;
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 char *pulse_device;
static char *pulse_capture_device;
// PulseAudio Event Callbacks {{{
static void stream_state_callback(pa_stream *stream, void *pdata) //{{{
{
pulse_data *data = pdata;
switch(ppa_stream_get_state(stream))
{
case PA_STREAM_READY:
AL_PRINT("%s: %s ready!\n", data->context_name, data->stream_name);
break;
case PA_STREAM_FAILED:
AL_PRINT("%s: %s: Connection failed: %s\n", data->context_name,
data->stream_name, ppa_strerror(ppa_context_errno(data->context)));
break;
case PA_STREAM_TERMINATED:
AL_PRINT("%s: %s terminated!\n", data->context_name, data->stream_name);
break;
default:
break;
}
ppa_threaded_mainloop_signal(data->loop, 1);
} //}}}
static void context_state_callback(pa_context *context, void *pdata) //{{{
{
pulse_data *data = pdata;
switch(ppa_context_get_state(context))
{
case PA_CONTEXT_READY:
AL_PRINT("%s ready!\n", data->context_name);
break;
case PA_CONTEXT_FAILED:
AL_PRINT("%s: Connection failed: %s\n", data->context_name,
ppa_strerror(ppa_context_errno(context)));
break;
case PA_CONTEXT_TERMINATED:
AL_PRINT("%s terminated!\n", data->context_name);
break;
default:
break;
}
ppa_threaded_mainloop_signal(data->loop, 1);
} //}}}
//}}}
// PulseAudio I/O Callbacks //{{{
static void stream_write_callback(pa_stream *stream, size_t len, void *pdata) //{{{
{
ALCdevice *Device = pdata;
void *buf = ppa_xmalloc0(len);
SuspendContext(NULL);
aluMixData(Device->Context, buf, len, Device->Format);
ProcessContext(NULL);
ppa_stream_write(stream, buf, len, 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, ALCchar *device_name, ALCenum format, ALCuint samples, ALCuint frequency) //{{{
{
pulse_data *data = ppa_xmalloc0(sizeof(pulse_data));
data->device = device;
data->format = format;
data->samples = samples;
data->frequency = frequency;
data->frame_size = aluBytesFromFormat(format) * aluChannelsFromFormat(format);
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->ring = CreateRingBuffer(data->frame_size, data->samples)))
{
ppa_xfree(data);
return ALC_FALSE;
}
device->ExtraData = data;
device->szDeviceName = device_name;
data->attr.minreq = -1;
data->attr.prebuf = -1;
data->attr.maxlength = -1;
if(device->IsCaptureDevice)
{
data->attr.tlength = -1;
data->attr.fragsize = data->frame_size * data->samples / 2;
data->stream_name = "Capture Stream";
}
else
{
data->attr.tlength = data->frame_size * (device->UpdateSize&~3);
data->attr.fragsize = -1;
data->stream_name = "Playback Stream";
}
data->spec.rate = data->frequency;
data->spec.channels = aluChannelsFromFormat(data->format);
switch(aluBytesFromFormat(data->format))
{
case 1:
data->spec.format = PA_SAMPLE_U8;
break;
case 2:
data->spec.format = PA_SAMPLE_S16NE;
break;
default:
AL_PRINT("Unknown format: %x\n", data->format);
goto out2;
}
if(ppa_sample_spec_valid(&data->spec) == 0)
{
AL_PRINT("Invalid sample format\n");
goto out2;
}
if(!(data->loop = ppa_threaded_mainloop_new()))
{
AL_PRINT("pa_threaded_mainloop_new() failed!\n");
goto out2;
}
if(ppa_threaded_mainloop_start(data->loop) < 0)
{
AL_PRINT("pa_threaded_mainloop_start() failed\n");
goto out3;
}
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 out3;
}
ppa_context_set_state_callback(data->context, context_state_callback, data);
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);
ppa_threaded_mainloop_unlock(data->loop);
data->context = NULL;
goto out3;
}
while(ppa_context_get_state(data->context) != PA_CONTEXT_READY)
{
if(!PA_CONTEXT_IS_GOOD(ppa_context_get_state(data->context)))
{
ppa_context_unref(data->context);
ppa_threaded_mainloop_unlock(data->loop);
data->context = NULL;
goto out3;
}
ppa_threaded_mainloop_wait(data->loop);
ppa_threaded_mainloop_accept(data->loop);
}
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);
goto out4;
}
ppa_stream_set_state_callback(data->stream, stream_state_callback, data);
if(device->IsCaptureDevice)
{
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;
goto out4;
}
}
else
{
ppa_stream_set_write_callback(data->stream, stream_write_callback, device);
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);
ppa_threaded_mainloop_unlock(data->loop);
data->stream = NULL;
goto out4;
}
}
while(ppa_stream_get_state(data->stream) != PA_STREAM_READY)
{
if(!PA_STREAM_IS_GOOD(ppa_stream_get_state(data->stream)))
{
ppa_stream_unref(data->stream);
ppa_threaded_mainloop_unlock(data->loop);
data->stream = NULL;
goto out4;
}
ppa_threaded_mainloop_wait(data->loop);
ppa_threaded_mainloop_accept(data->loop);
}
device->UpdateSize /= 4;
ppa_threaded_mainloop_unlock(data->loop);
return ALC_TRUE;
out4:
ppa_threaded_mainloop_lock(data->loop);
ppa_context_disconnect(data->context);
ppa_context_unref(data->context);
ppa_threaded_mainloop_unlock(data->loop);
out3:
ppa_threaded_mainloop_stop(data->loop);
ppa_threaded_mainloop_free(data->loop);
out2:
device->ExtraData = NULL;
device->szDeviceName = NULL;
DestroyRingBuffer(data->ring);
ppa_xfree(data);
return ALC_FALSE;
} //}}}
static void pulse_close(ALCdevice *device) //{{{
{
pulse_data *data = device->ExtraData;
ppa_threaded_mainloop_lock(data->loop);
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;
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)
{
if(strcmp(device_name, pulse_device) != 0)
return ALC_FALSE;
}
return pulse_open(device, pulse_device, device->Format, 0, device->Frequency);
} //}}}
static void pulse_close_playback(ALCdevice *device) //{{{
{
pulse_close(device);
} //}}}
static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_name, ALCuint frequency, ALCenum format, ALCsizei samples) //{{{
{
if(!pa_handle)
return ALC_FALSE;
if(device_name)
{
if(strcmp(device_name, pulse_capture_device) != 0)
return ALC_FALSE;
}
return pulse_open(device, pulse_capture_device, format, samples, frequency);
} //}}}
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_open_capture,
pulse_close_capture,
pulse_start_capture,
pulse_stop_capture,
pulse_capture_samples,
pulse_available_samples
}; //}}}
void alc_pulse_init(BackendFuncs *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)) { \
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)) { \
dlclose(pa_handle); \
pa_handle = NULL; \
return; \
} \
} while(0)
#else
pa_handle = (void*)0xDEADBEEF;
#define LOAD_FUNC(x) p##x = (x)
#endif
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_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
pulse_device = AppendDeviceList("PulseAudio Software");
AppendAllDeviceList(pulse_device);
pulse_capture_device = AppendCaptureDeviceList("PulseAudio Capture");
} //}}}
//}}}
+258
View File
@@ -0,0 +1,258 @@
/**
* 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 char *solaris_device;
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;
int wrote;
while(!data->killNow)
{
int len = data->data_size - remaining;
if(len > 0)
{
SuspendContext(NULL);
aluMixData(pDevice->Context, data->mix_data+remaining, len, pDevice->Format);
ProcessContext(NULL);
}
remaining += len;
wrote = write(data->fd, data->mix_data, remaining);
if(wrote < 0)
{
AL_PRINT("write failed: %s\n", strerror(errno));
remaining = 0;
}
else if(wrote > 0)
{
remaining -= wrote;
if(remaining > 0)
memmove(data->mix_data, data->mix_data+wrote, remaining);
}
else
Sleep(1);
}
return 0;
}
static ALCboolean solaris_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
audio_info_t info;
ALuint frameSize;
char driver[64];
int numChannels;
solaris_data *data;
strncpy(driver, GetConfigValue("solaris", "device", "/dev/audio"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(deviceName)
{
if(strcmp(deviceName, solaris_device))
return ALC_FALSE;
device->szDeviceName = solaris_device;
}
else
device->szDeviceName = solaris_device;
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;
}
numChannels = aluChannelsFromFormat(device->Format);
AUDIO_INITINFO(&info);
info.play.sample_rate = device->Frequency;
info.play.channels = numChannels;
switch(aluBytesFromFormat(device->Format))
{
case 1:
info.play.precision = 8;
info.play.encoding = AUDIO_ENCODING_LINEAR8;
break;
case 2:
info.play.precision = 16;
info.play.encoding = AUDIO_ENCODING_LINEAR;
break;
default:
AL_PRINT("Unknown format?! %x\n", device->Format);
}
frameSize = numChannels * aluBytesFromFormat(device->Format);
info.play.buffer_size = device->UpdateSize * frameSize;
if(ioctl(data->fd, AUDIO_SETINFO, &info) < 0)
{
AL_PRINT("ioctl failed: %s\n", strerror(errno));
close(data->fd);
free(data);
return ALC_FALSE;
}
device->Frequency = info.play.sample_rate;
if(aluChannelsFromFormat(device->Format) != info.play.channels)
{
AL_PRINT("Could not set %d channels, got %d instead\n", aluChannelsFromFormat(device->Format), info.play.channels);
close(data->fd);
free(data);
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);
close(data->fd);
free(data);
return ALC_FALSE;
}
device->UpdateSize = info.play.buffer_size / 4;
data->data_size = device->UpdateSize * frameSize;
data->mix_data = calloc(1, data->data_size);
device->ExtraData = data;
data->thread = StartThread(SolarisProc, device);
if(data->thread == NULL)
{
device->ExtraData = NULL;
free(data->mix_data);
free(data);
return ALC_FALSE;
}
return ALC_TRUE;
}
static void solaris_close_playback(ALCdevice *device)
{
solaris_data *data = (solaris_data*)device->ExtraData;
data->killNow = 1;
StopThread(data->thread);
close(data->fd);
free(data->mix_data);
free(data);
device->ExtraData = 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_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;
solaris_device = AppendDeviceList("Solaris Software");
AppendAllDeviceList(solaris_device);
}
+335
View File
@@ -0,0 +1,335 @@
/**
* 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 <memory.h>
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
typedef struct {
FILE *f;
long DataStart;
ALvoid *buffer;
ALuint size;
volatile int killNow;
ALvoid *thread;
} wave_data;
static ALCchar *waveDevice;
static ALuint WaveProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
wave_data *data = (wave_data*)pDevice->ExtraData;
ALuint frameSize;
ALuint now, last;
size_t WriteCnt;
size_t fs;
ALuint avail;
union {
short s;
char b[sizeof(short)];
} uSB;
uSB.s = 1;
frameSize = aluBytesFromFormat(pDevice->Format) *
aluChannelsFromFormat(pDevice->Format);
last = timeGetTime();
while(!data->killNow)
{
now = timeGetTime();
avail = (now-last) * pDevice->Frequency / 1000;
if(avail < pDevice->UpdateSize/4)
{
Sleep(1);
continue;
}
while(avail > 0)
{
SuspendContext(NULL);
WriteCnt = min(data->size, avail);
aluMixData(pDevice->Context, data->buffer, WriteCnt * frameSize,
pDevice->Format);
ProcessContext(NULL);
if(uSB.b[0] != 1 && aluBytesFromFormat(pDevice->Format) > 1)
{
ALubyte *bytes = data->buffer;
ALuint i;
for(i = 0;i < WriteCnt*frameSize;i++)
fputc(bytes[i^1], data->f);
}
else
fs = fwrite(data->buffer, frameSize, WriteCnt, data->f);
if(ferror(data->f))
{
AL_PRINT("Error writing to file\n");
data->killNow = 1;
break;
}
avail -= WriteCnt;
}
last = now;
}
return 0;
}
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;
data = (wave_data*)calloc(1, sizeof(wave_data));
data->f = fopen(fname, "wb");
if(!data->f)
{
free(data);
AL_PRINT("Could not open file '%s': %s\n", fname, strerror(errno));
return ALC_FALSE;
}
bits = aluBytesFromFormat(device->Format) * 8;
channels = aluChannelsFromFormat(device->Format);
switch(bits)
{
case 8:
case 16:
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;
}
fprintf(data->f, "RIFF");
fputc(0, data->f); // 'RIFF' header len; filled in at close
fputc(0, data->f);
fputc(0, data->f);
fputc(0, data->f);
fprintf(data->f, "WAVE");
fprintf(data->f, "fmt ");
fputc(16, data->f); // 'fmt ' header len; 16 bytes for PCM
fputc(0, data->f);
fputc(0, data->f);
fputc(0, data->f);
// 16-bit val, format type id (PCM: 1)
fputc(1, data->f);
fputc(0, data->f);
// 16-bit val, channel count
fputc(channels&0xff, data->f);
fputc((channels>>8)&0xff, data->f);
// 32-bit val, frequency
fputc(device->Frequency&0xff, data->f);
fputc((device->Frequency>>8)&0xff, data->f);
fputc((device->Frequency>>16)&0xff, data->f);
fputc((device->Frequency>>24)&0xff, data->f);
// 32-bit val, bytes per second
i = device->Frequency * channels * bits / 8;
fputc(i&0xff, data->f);
fputc((i>>8)&0xff, data->f);
fputc((i>>16)&0xff, data->f);
fputc((i>>24)&0xff, data->f);
// 16-bit val, frame size
i = channels * bits / 8;
fputc(i&0xff, data->f);
fputc((i>>8)&0xff, data->f);
// 16-bit val, bits per sample
fputc(bits&0xff, data->f);
fputc((bits>>8)&0xff, data->f);
fprintf(data->f, "data");
fputc(0, data->f); // 'data' header len; filled in at close
fputc(0, data->f);
fputc(0, data->f);
fputc(0, data->f);
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);
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);
return ALC_FALSE;
}
return ALC_TRUE;
}
static void wave_close_playback(ALCdevice *device)
{
wave_data *data = (wave_data*)device->ExtraData;
ALuint dataLen;
long size;
data->killNow = 1;
StopThread(data->thread);
size = ftell(data->f);
if(size > 0)
{
dataLen = size - data->DataStart;
if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0)
{
fputc(dataLen&0xff, data->f); // 'data' header len
fputc((dataLen>>8)&0xff, data->f);
fputc((dataLen>>16)&0xff, data->f);
fputc((dataLen>>24)&0xff, data->f);
}
if(fseek(data->f, 4, SEEK_SET) == 0)
{
size -= 8;
fputc(size&0xff, data->f); // 'WAVE' header len
fputc((size>>8)&0xff, data->f);
fputc((size>>16)&0xff, data->f);
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)
{
(void)pDevice;
(void)deviceName;
(void)frequency;
(void)format;
(void)SampleSize;
return ALC_FALSE;
}
static void wave_close_capture(ALCdevice *pDevice)
{
(void)pDevice;
}
static void wave_start_capture(ALCdevice *pDevice)
{
(void)pDevice;
}
static void wave_stop_capture(ALCdevice *pDevice)
{
(void)pDevice;
}
static void wave_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
{
(void)pDevice;
(void)pBuffer;
(void)lSamples;
}
static ALCuint wave_available_samples(ALCdevice *pDevice)
{
(void)pDevice;
return 0;
}
BackendFuncs wave_funcs = {
wave_open_playback,
wave_close_playback,
wave_open_capture,
wave_close_capture,
wave_start_capture,
wave_stop_capture,
wave_capture_samples,
wave_available_samples
};
void alc_wave_init(BackendFuncs *func_list)
{
*func_list = wave_funcs;
waveDevice = AppendDeviceList("Wave File Writer");
AppendAllDeviceList(waveDevice);
}
+38 -16
View File
@@ -18,6 +18,9 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#define _WIN32_WINNT 0x0500
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
@@ -63,7 +66,7 @@ static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,D
(void)hDevice;
(void)dwParam2;
if ((uMsg==WIM_DATA) && (pDevice))
if ((uMsg==WIM_DATA))
{
// Decrement number of buffers in use
pData->lWaveInBuffersCommitted--;
@@ -207,12 +210,13 @@ static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName
memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX));
wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM;
wfexCaptureFormat.nChannels = pDevice->Channels;
wfexCaptureFormat.wBitsPerSample = pDevice->FrameSize / pDevice->Channels * 8;
wfexCaptureFormat.nBlockAlign = pDevice->FrameSize;
wfexCaptureFormat.nChannels = aluChannelsFromFormat(pDevice->Format);
wfexCaptureFormat.wBitsPerSample = aluBytesFromFormat(pDevice->Format) * 8;
wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *
wfexCaptureFormat.nChannels / 8;
wfexCaptureFormat.nSamplesPerSec = frequency;
wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *
pDevice->FrameSize;
wfexCaptureFormat.nBlockAlign;
wfexCaptureFormat.cbSize = 0;
if (waveInOpen(&pData->hWaveInHandle, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
@@ -226,10 +230,6 @@ static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName
if (pData->hWaveInThreadEvent == NULL)
goto failure;
pData->hWaveInThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveInThreadID);
if (pData->hWaveInThread == NULL)
goto failure;
// Allocate circular memory buffer for the captured audio
pData->ulCapturedDataSize = SampleSize * wfexCaptureFormat.nBlockAlign;
@@ -264,15 +264,32 @@ static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName
pData->ulWriteCapturedDataPos = 0;
pDevice->ExtraData = pData;
pData->hWaveInThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveInThreadID);
if (pData->hWaveInThread == NULL)
goto failure;
return ALC_TRUE;
failure:
if (pData->hWaveInThreadEvent)
CloseHandle(pData->hWaveInThreadEvent);
for (i=0;i<4;i++)
{
if(pData->WaveInBuffer[i].lpData)
{
waveInUnprepareHeader(pData->hWaveInHandle, &pData->WaveInBuffer[i], sizeof(WAVEHDR));
free(pData->WaveInBuffer[i].lpData);
}
}
free(pData->pCapturedSampleData);
if(pData->hWaveInHandle)
waveInClose(pData->hWaveInHandle);
if(pData->hWaveInThread)
CloseHandle(pData->hWaveInThread);
if (pData->hWaveInHdrEvent)
CloseHandle(pData->hWaveInHdrEvent);
if (pData->hWaveInHandle)
waveInClose(pData->hWaveInHandle);
if (pData->hWaveInThreadEvent)
CloseHandle(pData->hWaveInThreadEvent);
free(pData);
return ALC_FALSE;
@@ -346,16 +363,20 @@ static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lS
ALuint ulBytes, ulBytesToCopy;
ALuint ulCapturedSamples;
ALuint ulReadOffset;
ALuint frameSize = aluBytesFromFormat(pDevice->Format) *
aluChannelsFromFormat(pDevice->Format);
// Check that we have the requested numbers of Samples
ulCapturedSamples = (pData->ulWriteCapturedDataPos - pData->ulReadCapturedDataPos) / pDevice->FrameSize;
ulCapturedSamples = (pData->ulWriteCapturedDataPos -
pData->ulReadCapturedDataPos) /
frameSize;
if(ulSamples > ulCapturedSamples)
{
SetALCError(ALC_INVALID_VALUE);
return;
}
ulBytes = ulSamples * pDevice->FrameSize;
ulBytes = ulSamples * frameSize;
// Get Read Offset
ulReadOffset = (pData->ulReadCapturedDataPos % pData->ulCapturedDataSize);
@@ -384,7 +405,8 @@ static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
{
WinMMData *pData = (WinMMData*)pDevice->ExtraData;
ALCuint lCapturedBytes = (pData->ulWriteCapturedDataPos - pData->ulReadCapturedDataPos);
return lCapturedBytes / pDevice->FrameSize;
return lCapturedBytes / (aluBytesFromFormat(pDevice->Format) *
aluChannelsFromFormat(pDevice->Format));
}
+280 -90
View File
@@ -1,44 +1,59 @@
# CMake build file list for OpenAL
CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
IF(COMMAND CMAKE_POLICY)
CMAKE_POLICY(SET CMP0003 NEW)
ENDIF(COMMAND CMAKE_POLICY)
INCLUDE(CheckFunctionExists)
INCLUDE(CheckLibraryExists)
INCLUDE(CheckIncludeFile)
INCLUDE(CheckIncludeFiles)
INCLUDE(CheckSymbolExists)
INCLUDE(CheckCCompilerFlag)
INCLUDE(CheckCSourceCompiles)
INCLUDE(CheckTypeSize)
PROJECT(OpenAL)
PROJECT(OpenAL C)
SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE)
OPTION(ALSA "ALSA backend" ON)
OPTION(OSS "OSS backend" ON)
OPTION(DSOUND "DirectSound backend" ON)
OPTION(WINMM "Windows Multimedia backend" ON)
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 "Use the dlopen API for loading optional libs" ON)
OPTION(DLOPEN "Check for the dlopen API for loading optional libs" ON)
OPTION(DEBUG "Build lib in debug mode" OFF)
OPTION(NODEBUG "Disable all debug info for optimizations" OFF)
OPTION(WERROR "Treat compile warnings as errors" OFF)
OPTION(WERROR "Treat compile warnings as errors" OFF)
OPTION(EXAMPLES "Build example programs" ON)
OPTION(ALSOFT_CONFIG "Install alsoft.conf configuration file" OFF)
SET(LIB_MAJOR_VERSION "1")
SET(LIB_MINOR_VERSION "0")
SET(LIB_BUILD_VERSION "38")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_BUILD_VERSION}")
IF("${WIN32}")
SET(LIBNAME openal32)
IF(WIN32)
SET(LIBNAME OpenAL32)
ADD_DEFINITIONS("-D_WIN32")
ELSE()
SET(LIBNAME openal)
ENDIF()
SET(LIB_MAJOR_VERSION "1")
SET(LIB_MINOR_VERSION "8")
SET(LIB_BUILD_VERSION "466")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_BUILD_VERSION}")
IF(NOT DEFINED LIB_INSTALL_DIR)
SET(LIB_INSTALL_DIR "lib${LIB_SUFFIX}")
ENDIF(NOT DEFINED LIB_INSTALL_DIR)
CHECK_TYPE_SIZE("long" SIZEOF_LONG)
CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
@@ -48,14 +63,29 @@ CHECK_TYPE_SIZE("void*" SIZEOF_VOIDP)
# Add definitions, compiler switches, etc.
INCLUDE_DIRECTORIES(OpenAL32/Include include "${OpenAL_BINARY_DIR}")
SET(EXTRA_LIBS m ${EXTRA_LIBS})
IF("${MSVC}")
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
"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)
# ???
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -D_DEBUG")
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()
@@ -63,96 +93,156 @@ ELSE()
ADD_DEFINITIONS(-Werror)
ENDIF()
IF(DEBUG)
ADD_DEFINITIONS(-g3)
ELSEIF(NODEBUG)
ADD_DEFINITIONS(-O2 -funroll-loops -fomit-frame-pointer)
ELSE()
ADD_DEFINITIONS(-g -O2 -funroll-loops)
ENDIF()
# The mixer doesn't like GCC's strict aliasing optimizations. Make sure
# it's turned off
CHECK_C_COMPILER_FLAG(-fstrict-aliasing HAVE_STRICT_ALIASING)
IF("${HAVE_STRICT_ALIASING}")
ADD_DEFINITIONS(-fno-strict-aliasing)
ENDIF()
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O2 -funroll-loops -D_DEBUG" CACHE STRING
"Flags used by the compiler during Release with Debug Info builds."
FORCE)
SET(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" CACHE STRING
"Flags used by the compiler during release minsize builds."
FORCE)
SET(CMAKE_C_FLAGS_RELEASE "-O2 -funroll-loops -fomit-frame-pointer -DNDEBUG" CACHE STRING
"Flags used by the compiler during release builds"
FORCE)
SET(CMAKE_C_FLAGS_DEBUG "-g3 -D_DEBUG" CACHE STRING
"Flags used by the compiler during debug builds."
FORCE)
# Set visibility options if available
IF(NOT "${WIN32}")
IF(NOT WIN32)
CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor));
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()
IF(DEBUG)
ADD_DEFINITIONS(-D_DEBUG)
ELSEIF(NODEBUG)
ADD_DEFINITIONS(-DNDEBUG)
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)
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}")
IF(NOT HAVE_STRCASECMP)
CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP)
IF(NOT "${HAVE__STRICMP}")
IF(NOT HAVE__STRICMP)
MESSAGE(FATAL_ERROR "No case-insensitive compare function found, please report!")
ENDIF()
ADD_DEFINITIONS(-Dstrcasecmp=_stricmp)
ENDIF()
CHECK_FUNCTION_EXISTS(strncasecmp HAVE_STRNCASECMP)
IF(NOT HAVE_STRNCASECMP)
CHECK_FUNCTION_EXISTS(_strnicmp HAVE__STRNICMP)
IF(NOT HAVE__STRNICMP)
MESSAGE(FATAL_ERROR "No case-insensitive size-limitted compare function found, please report!")
ENDIF()
ADD_DEFINITIONS(-Dstrncasecmp=_strnicmp)
ENDIF()
CHECK_FUNCTION_EXISTS(snprintf HAVE_SNPRINTF)
IF(NOT HAVE_SNPRINTF)
CHECK_FUNCTION_EXISTS(_snprintf HAVE__SNPRINTF)
IF(NOT HAVE__SNPRINTF)
MESSAGE(FATAL_ERROR "No snprintf function found, please report!")
ENDIF()
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)
IF("${HAVE_DLFCN_H}")
IF(HAVE_DLFCN_H)
CHECK_LIBRARY_EXISTS(dl dlopen "" HAVE_LIBDL)
IF("${HAVE_LIBDL}")
IF(HAVE_LIBDL)
SET(EXTRA_LIBS dl ${EXTRA_LIBS})
ENDIF()
ENDIF()
ENDIF()
# Check if we have Windows headers
CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H)
IF(NOT "${HAVE_WINDOWS_H}")
CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H -D_WIN32_WINNT=0x0500)
IF(NOT HAVE_WINDOWS_H)
CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY)
IF(NOT HAVE_GETTIMEOFDAY)
MESSAGE(FATAL_ERROR "No timing function found!")
ENDIF()
CHECK_FUNCTION_EXISTS(nanosleep HAVE_NANOSLEEP)
IF(NOT HAVE_NANOSLEEP)
MESSAGE(FATAL_ERROR "No sleep function found!")
ENDIF()
# We need pthreads outside of Windows
CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
IF(NOT "${HAVE_PTHREAD_H}")
IF(NOT HAVE_PTHREAD_H)
MESSAGE(FATAL_ERROR "PThreads is required for non-Windows builds!")
ENDIF()
# Some systems need pthread_np.h to get recursive mutexes
CHECK_INCLUDE_FILES("pthread.h;pthread_np.h" HAVE_PTHREAD_NP_H)
# _GNU_SOURCE is needed on some systems for extra attributes, and
# _REENTRANT is needed for libc thread-safety
ADD_DEFINITIONS(-D_GNU_SOURCE=1 -D_REENTRANT)
CHECK_LIBRARY_EXISTS(pthread pthread_create "" HAVE_LIBPTHREAD)
IF("${HAVE_LIBPTHREAD}")
IF(HAVE_LIBPTHREAD)
SET(EXTRA_LIBS pthread ${EXTRA_LIBS})
ENDIF()
ENDIF()
# Check for a 64-bit type
CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H)
IF(NOT "${HAVE_STDINT_H}")
IF("${HAVE_WINDOWS_H}")
CHECK_C_SOURCE_COMPILES("\#include <windows.h>
IF(NOT HAVE_STDINT_H)
IF(HAVE_WINDOWS_H)
CHECK_C_SOURCE_COMPILES("\#define _WIN32_WINNT 0x0500
\#include <windows.h>
__int64 foo;
int main() {return 0;}" HAVE___INT64)
ENDIF()
IF(NOT "${HAVE___INT64}")
IF(NOT "${SIZEOF_LONG}" MATCHES "8")
IF(NOT "${SIZEOF_LONG_LONG}" MATCHES "8")
IF(NOT HAVE___INT64)
IF(NOT SIZEOF_LONG MATCHES "8")
IF(NOT SIZEOF_LONG_LONG MATCHES "8")
MESSAGE(FATAL_ERROR "No 64-bit types found, please report!")
ENDIF()
ENDIF()
@@ -160,19 +250,26 @@ IF(NOT "${HAVE_STDINT_H}")
ENDIF()
SET(OPENAL_OBJS OpenAL32/alBuffer.c
SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c
OpenAL32/alBuffer.c
OpenAL32/alEffect.c
OpenAL32/alError.c
OpenAL32/alExtension.c
OpenAL32/alFilter.c
OpenAL32/alListener.c
OpenAL32/alSource.c
OpenAL32/alState.c
OpenAL32/alThunk.c
OpenAL32/OpenAL32.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/wave.c
)
SET(BACKENDS "")
@@ -180,15 +277,15 @@ SET(BACKENDS "")
# Check ALSA backend
IF(ALSA)
CHECK_INCLUDE_FILE(alsa/asoundlib.h HAVE_ALSA_ASOUNDLIB_H)
IF("${HAVE_ALSA_ASOUNDLIB_H}")
IF(HAVE_ALSA_ASOUNDLIB_H)
CHECK_LIBRARY_EXISTS(asound snd_pcm_open "" HAVE_LIBASOUND)
IF("${HAVE_DLFCN_H}" OR "${HAVE_LIBASOUND}")
IF(HAVE_DLFCN_H OR HAVE_LIBASOUND)
SET(HAVE_ALSA 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/alsa.c)
IF("${HAVE_DLFCN_H}")
SET(BACKENDS ${BACKENDS} ALSA)
IF(HAVE_DLFCN_H)
SET(BACKENDS "${BACKENDS} ALSA,")
ELSE()
SET(BACKENDS ${BACKENDS} ALSA\(linked\))
SET(BACKENDS "${BACKENDS} ALSA \(linked\),")
SET(EXTRA_LIBS asound ${EXTRA_LIBS})
ENDIF()
ENDIF()
@@ -198,79 +295,172 @@ ENDIF()
# Check OSS backend
IF(OSS)
CHECK_INCLUDE_FILE(sys/soundcard.h HAVE_SYS_SOUNDCARD_H)
IF("${HAVE_SYS_SOUNDCARD_H}")
IF(HAVE_SYS_SOUNDCARD_H)
SET(HAVE_OSS 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/oss.c)
SET(BACKENDS ${BACKENDS} OSS)
SET(BACKENDS "${BACKENDS} 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}")
SET(CMAKE_REQUIRED_LIBRARIES ole32)
CHECK_C_SOURCE_COMPILES("int main() {return 0;}" HAVE_LIBOLE32)
SET(CMAKE_REQUIRED_LIBRARIES "")
# CHECK_LIBRARY_EXISTS(ole32 CoInitialize "" HAVE_LIBOLE32)
IF("${HAVE_LIBOLE32}")
SET(EXTRA_LIBS ole32 ${EXTRA_LIBS})
ENDIF()
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)
CHECK_LIBRARY_EXISTS(dxguid IID_IDirectSound "" HAVE_LIBDXGUID)
IF("${HAVE_LIBDXGUID}")
SET(EXTRA_LIBS dxguid ${EXTRA_LIBS})
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)
IF("${HAVE_MMSYSTEM_H}")
CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0500)
IF(HAVE_MMSYSTEM_H)
SET(HAVE_WINMM 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/winmm.c)
SET(BACKENDS ${BACKENDS} WinMM)
SET(BACKENDS "${BACKENDS} WinMM,")
SET(CMAKE_REQUIRED_LIBRARIES winmm)
CHECK_C_SOURCE_COMPILES("int main() {return 0;}" HAVE_LIBWINMM)
SET(CMAKE_REQUIRED_LIBRARIES "")
# CHECK_LIBRARY_EXISTS(winmm waveInOpen "" HAVE_LIBWINMM)
IF("${HAVE_LIBWINMM}")
IF(HAVE_LIBWINMM)
SET(EXTRA_LIBS winmm ${EXTRA_LIBS})
ENDIF()
ENDIF()
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")
# Needed for openal.pc.in
SET(prefix ${CMAKE_INSTALL_PREFIX})
SET(exec_prefix "\${prefix}")
SET(libdir "\${exec_prefix}/${LIB_INSTALL_DIR}")
SET(bindir "\${exec_prefix}/bin")
SET(includedir "\${prefix}/include")
SET(PACKAGE_VERSION "${LIB_VERSION}")
# End configuration
CONFIGURE_FILE(
"${OpenAL_SOURCE_DIR}/config.h.in"
"${OpenAL_BINARY_DIR}/config.h")
CONFIGURE_FILE(
"${OpenAL_SOURCE_DIR}/admin/pkgconfig/openal.pc.in"
"${OpenAL_BINARY_DIR}/admin/pkgconfig/openal.pc"
@ONLY)
ADD_DEFINITIONS(-DAL_BUILD_LIBRARY)
# Build a shared library
ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALC_OBJS})
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION} SOVERSION ${LIB_MAJOR_VERSION})
# 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)
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "")
ENDIF()
TARGET_LINK_LIBRARIES(${LIBNAME} ${EXTRA_LIBS})
# Add an install target here
INSTALL(TARGETS ${LIBNAME}
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
)
INSTALL(FILES include/AL/al.h
include/AL/alc.h
include/AL/alext.h
DESTINATION include/AL
)
INSTALL(FILES "${OpenAL_BINARY_DIR}/admin/pkgconfig/openal.pc"
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)
TARGET_LINK_LIBRARIES(openal-info ${LIBNAME})
INSTALL(TARGETS openal-info
RUNTIME DESTINATION bin
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
)
ENDIF()
MESSAGE(STATUS "")
MESSAGE(STATUS "Building OpenAL with support for the following backends:")
MESSAGE(STATUS " ${BACKENDS}")
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()
+75
View File
@@ -0,0 +1,75 @@
#ifndef _AL_AUXEFFECTSLOT_H_
#define _AL_AUXEFFECTSLOT_H_
#include "AL/al.h"
#include "alEffect.h"
#include "alFilter.h"
#ifdef __cplusplus
extern "C" {
#endif
#define AL_EFFECTSLOT_EFFECT 0x0001
#define AL_EFFECTSLOT_GAIN 0x0002
#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003
#define AL_EFFECTSLOT_NULL 0x0000
typedef struct ALeffectState ALeffectState;
typedef struct ALeffectslot
{
ALeffect effect;
ALfloat Gain;
ALboolean AuxSendAuto;
ALeffectState *EffectState;
ALfloat WetBuffer[BUFFERSIZE];
ALuint refcount;
// Index to itself
ALuint effectslot;
struct ALeffectslot *next;
} ALeffectslot;
ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
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);
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
#endif
+3
View File
@@ -18,11 +18,14 @@ typedef struct ALbuffer_struct
ALshort *data;
ALsizei size;
ALsizei frequency;
ALsizei padding;
ALenum state;
ALuint refcount; // Number of sources using this buffer (deletion can only occur when this is 0)
struct ALbuffer_struct *next;
} ALbuffer;
ALvoid ALAPIENTRY alBufferSubDataEXT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length);
ALvoid ReleaseALBuffers(ALvoid);
#ifdef __cplusplus
+274
View File
@@ -0,0 +1,274 @@
// 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_
#include "AL/al.h"
#ifdef __cplusplus
extern "C" {
#endif
#define AL_EFFECT_TYPE 0x8001
#define AL_EFFECT_NULL 0x0000
#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 AL_EFFECT_EAXREVERB 0x8000
#define AL_REVERB_DENSITY 0x0001
#define AL_REVERB_DIFFUSION 0x0002
#define AL_REVERB_GAIN 0x0003
#define AL_REVERB_GAINHF 0x0004
#define AL_REVERB_DECAY_TIME 0x0005
#define AL_REVERB_DECAY_HFRATIO 0x0006
#define AL_REVERB_REFLECTIONS_GAIN 0x0007
#define AL_REVERB_REFLECTIONS_DELAY 0x0008
#define AL_REVERB_LATE_REVERB_GAIN 0x0009
#define AL_REVERB_LATE_REVERB_DELAY 0x000A
#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B
#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)
#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_struct
{
// Effect type (AL_EFFECT_NULL, ...)
ALenum type;
struct {
// Shared Reverb Properties
ALfloat Density;
ALfloat Diffusion;
ALfloat Gain;
ALfloat GainHF;
ALfloat DecayTime;
ALfloat DecayHFRatio;
ALfloat ReflectionsGain;
ALfloat ReflectionsDelay;
ALfloat LateReverbGain;
ALfloat LateReverbDelay;
ALfloat AirAbsorptionGainHF;
ALfloat RoomRolloffFactor;
ALboolean DecayHFLimit;
// Additional EAX Reverb Properties
ALfloat GainLF;
ALfloat DecayLFRatio;
ALfloat ReflectionsPan[3];
ALfloat LateReverbPan[3];
ALfloat EchoTime;
ALfloat EchoDepth;
ALfloat ModulationTime;
ALfloat ModulationDepth;
ALfloat HFReference;
ALfloat LFReference;
} Reverb;
struct {
ALfloat Delay;
ALfloat LRDelay;
ALfloat Damping;
ALfloat Feedback;
ALfloat Spread;
} Echo;
// Index to itself
ALuint effect;
struct ALeffect_struct *next;
} ALeffect;
ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects);
ALboolean AL_APIENTRY alIsEffect(ALuint effect);
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);
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);
#ifdef __cplusplus
}
#endif
#endif
+98
View File
@@ -0,0 +1,98 @@
#ifndef _AL_FILTER_H_
#define _AL_FILTER_H_
#include "AL/al.h"
#include "alu.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
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
#define AL_FILTER_LOWPASS 0x0001
#define AL_FILTER_HIGHPASS 0x0002
#define AL_FILTER_BANDPASS 0x0003
#define AL_LOWPASS_GAIN 0x0001
#define AL_LOWPASS_GAINHF 0x0002
typedef struct ALfilter_struct
{
// Filter type (AL_FILTER_NULL, ...)
ALenum type;
ALfloat Gain;
ALfloat GainHF;
// Index to itself
ALuint filter;
struct ALfilter_struct *next;
} ALfilter;
ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters);
ALboolean AL_APIENTRY alIsFilter(ALuint filter);
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);
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);
#ifdef __cplusplus
}
#endif
#endif
+3
View File
@@ -7,6 +7,8 @@
extern "C" {
#endif
#define AL_METERS_PER_UNIT 0x20004
typedef struct ALlistener_struct
{
ALfloat Position[3];
@@ -14,6 +16,7 @@ typedef struct ALlistener_struct
ALfloat Forward[3];
ALfloat Up[3];
ALfloat Gain;
ALfloat MetersPerUnit;
} ALlistener;
#ifdef __cplusplus
+110 -38
View File
@@ -1,21 +1,35 @@
#ifndef AL_MAIN_H
#define AL_MAIN_H
#define AL_MAX_CHANNELS 4
#define AL_MAX_SOURCES 32
#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
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include <windows.h>
//#define strcasecmp _stricmp
#else
#include <assert.h>
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#define IsBadWritePtr(a,b) (0)
@@ -41,6 +55,10 @@ static inline void InitializeCriticalSection(CRITICAL_SECTION *cs)
assert(ret == 0);
ret = pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE);
#ifdef HAVE_PTHREAD_NP_H
if(ret != 0)
ret = pthread_mutexattr_setkind_np(&attrib, PTHREAD_MUTEX_RECURSIVE);
#endif
assert(ret == 0);
ret = pthread_mutex_init(cs, &attrib);
assert(ret == 0);
@@ -55,49 +73,77 @@ static inline void DeleteCriticalSection(CRITICAL_SECTION *cs)
assert(ret == 0);
}
/* NOTE: This wrapper isn't quite accurate as it returns an ALuint, as opposed
* to the expected DWORD. Both are defined as unsigned 32-bit types, however.
* Additionally, Win32 is supposed to measure the time since Windows started,
* as opposed to the actual time. */
static inline ALuint timeGetTime(void)
{
struct timeval tv;
int ret;
ret = gettimeofday(&tv, NULL);
assert(ret == 0);
return tv.tv_usec/1000 + tv.tv_sec*1000;
}
static inline void Sleep(ALuint t)
{
struct timespec tv, rem;
tv.tv_nsec = (t*1000000)%1000000000;
tv.tv_sec = t/1000;
while(nanosleep(&tv, &rem) == -1 && errno == EINTR)
tv = rem;
}
#define min(x,y) (((x)<(y))?(x):(y))
#define max(x,y) (((x)>(y))?(x):(y))
#endif
#include "alBuffer.h"
#include "alError.h"
#include "alExtension.h"
#include "alListener.h"
#include "alSource.h"
#include "alState.h"
#include "alThunk.h"
#include "alu.h"
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
extern CRITICAL_SECTION g_mutex;
static __inline void al_print(const char *fname, unsigned int line, const char *fmt, ...)
{
const char *fn;
char str[256];
int i;
extern char szDebug[256];
fn = strrchr(fname, '/');
if(!fn) fn = strrchr(fname, '\\');;
if(!fn) fn = fname;
else fn += 1;
#define AL_PRINT(...) do { \
int _al_print_i; \
char *_al_print_fn = strrchr(__FILE__, '/'); \
if(!_al_print_fn) _al_print_fn = __FILE__; \
else _al_print_fn += 1; \
_al_print_i = snprintf(szDebug, sizeof(szDebug), "AL lib: %s:%d: ", _al_print_fn, __LINE__); \
snprintf(szDebug+_al_print_i, sizeof(szDebug)-_al_print_i, __VA_ARGS__); \
fprintf(stderr, "%s", szDebug); \
} while(0)
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 AL_FORMAT_MONO_IMA4 0x1300
#define AL_FORMAT_STEREO_IMA4 0x1301
// These are from AL_EXT_MCFORMATS, which we don't support yet but the mixer
// can use 4-channel formats
#define AL_FORMAT_QUAD8 0x1204
#define AL_FORMAT_QUAD16 0x1205
#define SWMIXER_OUTPUT_RATE 44100
//#define OUTPUT_BUFFER_SIZE (32768*SWMIXER_OUTPUT_RATE/22050)
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINDBHF (-0.05f)
#define LOWPASSFREQCUTOFF (5000)
#define QUADRANT_NUM 128
#define LUT_NUM (4 * QUADRANT_NUM)
typedef struct {
ALCboolean (*OpenPlayback)(ALCdevice*, const ALCchar*);
@@ -113,31 +159,36 @@ typedef struct {
void alc_alsa_init(BackendFuncs *func_list);
void alc_oss_init(BackendFuncs *func_list);
void alc_solaris_init(BackendFuncs *func_list);
void alcDSoundInit(BackendFuncs *func_list);
void alcWinMMInit(BackendFuncs *FuncList);
void alc_pa_init(BackendFuncs *func_list);
void alc_wave_init(BackendFuncs *func_list);
void alc_pulse_init(BackendFuncs *func_list);
struct ALCdevice_struct
{
ALboolean InUse;
ALboolean IsCaptureDevice;
ALuint Frequency;
ALuint UpdateFreq;
ALuint FrameSize;
ALuint Channels;
ALuint UpdateSize;
ALenum Format;
ALCchar *szDeviceName;
// Maximum number of sources that can be created
ALuint MaxNoOfSources;
// Maximum number of slots that can be created
ALuint AuxiliaryEffectSlotMax;
// Context created on this device
ALCcontext *Context;
BackendFuncs *Funcs;
void *ExtraData; // For the backend's use
ALCdevice *next;
};
#define ALCdevice_OpenPlayback(a,b) ((a)->Funcs->OpenPlayback((a), (b)))
@@ -153,8 +204,11 @@ struct ALCcontext_struct
{
ALlistener Listener;
ALsource *Source;
ALuint SourceCount;
struct ALsource *Source;
ALuint SourceCount;
struct ALeffectslot *AuxiliaryEffectSlot;
ALuint AuxiliaryEffectSlotCount;
ALenum LastError;
ALboolean InUse;
@@ -170,12 +224,23 @@ struct ALCcontext_struct
ALint lNumMonoSources;
ALint lNumStereoSources;
ALuint NumSends;
ALfloat PanningLUT[OUTPUTCHANNELS * LUT_NUM];
ALint NumChan;
ALfloat ChannelMatrix[OUTPUTCHANNELS][OUTPUTCHANNELS];
ALCdevice *Device;
ALCchar ExtensionList[1024];
const ALCchar *ExtensionList;
struct bs2b *bs2b;
ALCcontext *next;
};
ALCvoid ReleaseALC(ALCvoid);
ALCchar *AppendDeviceList(char *name);
ALCchar *AppendAllDeviceList(char *name);
ALCchar *AppendCaptureDeviceList(char *name);
@@ -188,6 +253,13 @@ ALCvoid ProcessContext(ALCcontext *context);
ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr);
ALuint StopThread(ALvoid *thread);
typedef struct RingBuffer RingBuffer;
RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length);
void DestroyRingBuffer(RingBuffer *ring);
ALsizei RingBufferSize(RingBuffer *ring);
void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len);
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len);
void ReadALConfig(void);
void FreeALConfig(void);
const char *GetConfigValue(const char *blockName, const char *keyName, const char *def);
+47 -6
View File
@@ -3,8 +3,21 @@
#define AL_NUM_SOURCE_PARAMS 128
#define MAX_SENDS 2
#include "alFilter.h"
#include "alu.h"
#include "AL/al.h"
#define AL_DIRECT_FILTER 0x20005
#define AL_AUXILIARY_SEND_FILTER 0x20006
#define AL_AIR_ABSORPTION_FACTOR 0x20007
#define AL_ROOM_ROLLOFF_FACTOR 0x20008
#define AL_CONE_OUTER_GAINHF 0x20009
#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A
#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B
#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C
#ifdef __cplusplus
extern "C" {
#endif
@@ -17,7 +30,7 @@ typedef struct ALbufferlistitem
struct ALbufferlistitem *next;
} ALbufferlistitem;
typedef struct ALsource_struct
typedef struct ALsource
{
ALfloat flPitch;
ALfloat flGain;
@@ -34,6 +47,7 @@ typedef struct ALsource_struct
ALfloat vOrientation[3];
ALboolean bHeadRelative;
ALboolean bLooping;
ALenum DistanceModel;
ALuint ulBufferID;
@@ -42,28 +56,55 @@ typedef struct ALsource_struct
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
ALfilter DirectFilter;
struct {
struct ALeffectslot *Slot;
ALfilter WetFilter;
FILTER iirFilter;
ALfloat history[2];
} Send[MAX_SENDS];
ALboolean DryGainHFAuto;
ALboolean WetGainAuto;
ALboolean WetGainHFAuto;
ALfloat OuterGainHF;
FILTER iirFilter;
ALfloat history[OUTPUTCHANNELS*2];
ALfloat AirAbsorptionFactor;
ALfloat RoomRolloffFactor;
ALfloat DopplerFactor;
// Index to itself
ALuint source;
ALint lBytesPlayed;
ALint lOffset;
ALint lOffsetType;
// Source Type (Static, Streaming, or Undetermined)
ALint lSourceType;
struct ALsource_struct *next;
// Current gains, which are ramped while mixed
ALfloat DryGains[OUTPUTCHANNELS];
ALfloat WetGains[MAX_SENDS];
ALboolean FirstStart;
struct ALsource *next;
} ALsource;
ALvoid ReleaseALSources(ALCcontext *Context);
#ifdef __cplusplus
}
#endif
+138 -8
View File
@@ -1,21 +1,151 @@
#ifndef _ALU_H_
#define _ALU_H_
#define BUFFERSIZE 48000
#define FRACTIONBITS 14
#define FRACTIONMASK ((1L<<FRACTIONBITS)-1)
#define MAX_PITCH 4
#define OUTPUTCHANNELS 4
#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
__inline ALuint aluBytesFromFormat(ALenum format);
__inline ALuint aluChannelsFromFormat(ALenum format);
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;
/* 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(ALCcontext *context,ALvoid *buffer,ALsizei size,ALenum format);
#ifdef __cplusplus
+109
View File
@@ -0,0 +1,109 @@
/*-
* Copyright (c) 2005 Boris Mikhaylov
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef BS2B_H
#define BS2B_H
/* Number of crossfeed levels */
#define BS2B_CLEVELS 3
/* Normal crossfeed levels */
#define BS2B_HIGH_CLEVEL 3
#define BS2B_MIDDLE_CLEVEL 2
#define BS2B_LOW_CLEVEL 1
/* Easy crossfeed levels */
#define BS2B_HIGH_ECLEVEL BS2B_HIGH_CLEVEL + BS2B_CLEVELS
#define BS2B_MIDDLE_ECLEVEL BS2B_MIDDLE_CLEVEL + BS2B_CLEVELS
#define BS2B_LOW_ECLEVEL BS2B_LOW_CLEVEL + BS2B_CLEVELS
/* Default crossfeed levels */
#define BS2B_DEFAULT_CLEVEL BS2B_HIGH_ECLEVEL
/* Default sample rate (Hz) */
#define BS2B_DEFAULT_SRATE 44100
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct bs2b {
int level; /* Crossfeed level */
int srate; /* Sample rate (Hz) */
/* Lowpass IIR filter coefficients */
double a0_lo;
double b1_lo;
/* Highboost IIR filter coefficients */
double a0_hi;
double a1_hi;
double b1_hi;
/* Global gain against overloading */
double gain;
/* Buffer of last filtered sample.
* [0] - first channel, [1] - second channel
*/
struct t_last_sample {
double asis[2];
double lo[2];
double hi[2];
} last_sample;
};
/* Clear buffers and set new coefficients with new crossfeed level value.
* level - crossfeed level of *LEVEL values.
*/
void bs2b_set_level(struct bs2b *bs2b, int level);
/* Return current crossfeed level value */
int bs2b_get_level(struct bs2b *bs2b);
/* Clear buffers and set new coefficients with new sample rate value.
* srate - sample rate by Hz.
*/
void bs2b_set_srate(struct bs2b *bs2b, int srate);
/* Return current sample rate value */
int bs2b_get_srate(struct bs2b *bs2b);
/* Clear buffer */
void bs2b_clear(struct bs2b *bs2b);
/* Return 1 if buffer is clear */
int bs2b_is_clear(struct bs2b *bs2b);
/* Crossfeeds one stereo sample that are pointed by sample.
* [0] - first channel, [1] - second channel.
* Returns crossfided samle by sample pointer.
*/
/* sample poits to floats */
void bs2b_cross_feed(struct bs2b *bs2b, float *sample);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* BS2B_H */
-63
View File
@@ -1,63 +0,0 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "alMain.h"
#include "alBuffer.h"
#include "alThunk.h"
CRITICAL_SECTION g_mutex;
#ifdef _WIN32
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
(void)lpReserved;
// Perform actions based on the reason for calling.
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
break;
case DLL_PROCESS_DETACH:
ReleaseALBuffers();
FreeALConfig();
ALTHUNK_EXIT();
DeleteCriticalSection(&g_mutex);
break;
}
return TRUE;
}
#else
#ifdef HAVE_GCC_DESTRUCTOR
static void my_deinit() __attribute__((destructor));
static void my_deinit()
{
static ALenum once = AL_FALSE;
if(once) return;
once = AL_TRUE;
ReleaseALBuffers();
FreeALConfig();
ALTHUNK_EXIT();
DeleteCriticalSection(&g_mutex);
}
#endif
#endif
+524
View File
@@ -0,0 +1,524 @@
/**
* 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 <math.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alThunk.h"
#include "alError.h"
static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect);
ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCcontext *Context;
ALsizei i, j;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
if (n > 0)
{
ALCdevice *Device = alcGetContextsDevice(Context);
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)))
{
ALeffectslot **list = &Context->AuxiliaryEffectSlot;
while(*list)
list = &(*list)->next;
i = 0;
while(i < n)
{
*list = calloc(1, sizeof(ALeffectslot));
if(!(*list))
{
// We must have run out or memory
alDeleteAuxiliaryEffectSlots(i, effectslots);
alSetError(AL_OUT_OF_MEMORY);
break;
}
(*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);
(*list)->effectslot = effectslots[i];
Context->AuxiliaryEffectSlotCount++;
i++;
list = &(*list)->next;
}
}
}
else
alSetError(AL_INVALID_OPERATION);
}
ProcessContext(Context);
}
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);
if (n >= 0)
{
// Check that all effectslots are valid
for (i = 0; i < n; i++)
{
if (!alIsAuxiliaryEffectSlot(effectslots[i]))
{
alSetError(AL_INVALID_NAME);
break;
}
else
{
ALAuxiliaryEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslots[i]);
if(ALAuxiliaryEffectSlot->refcount > 0)
{
alSetError(AL_INVALID_NAME);
break;
}
}
}
if (i == n)
{
// All effectslots are valid
for (i = 0; i < n; i++)
{
// Recheck that the effectslot is valid, because there could be duplicated names
if (alIsAuxiliaryEffectSlot(effectslots[i]))
{
ALeffectslot **list;
ALAuxiliaryEffectSlot = ((ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslots[i]));
// Remove Source from list of Sources
list = &Context->AuxiliaryEffectSlot;
while(*list && *list != ALAuxiliaryEffectSlot)
list = &(*list)->next;
if(*list)
*list = (*list)->next;
ALTHUNK_REMOVEENTRY(ALAuxiliaryEffectSlot->effectslot);
if(ALAuxiliaryEffectSlot->EffectState)
ALEffect_Destroy(ALAuxiliaryEffectSlot->EffectState);
memset(ALAuxiliaryEffectSlot, 0, sizeof(ALeffectslot));
free(ALAuxiliaryEffectSlot);
Context->AuxiliaryEffectSlotCount--;
}
}
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(Context);
}
ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
{
ALCcontext *Context;
ALeffectslot **list;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return AL_FALSE;
}
SuspendContext(Context);
list = &Context->AuxiliaryEffectSlot;
while(*list && (*list)->effectslot != effectslot)
list = &(*list)->next;
ProcessContext(Context);
return (*list ? AL_TRUE : AL_FALSE);
}
ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
if (alIsAuxiliaryEffectSlot(effectslot))
{
ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslot);
switch(param)
{
case AL_EFFECTSLOT_EFFECT:
if(alIsEffect(iValue))
{
ALeffect *effect = (ALeffect*)ALTHUNK_LOOKUPENTRY(iValue);
InitializeEffect(Context, ALEffectSlot, effect);
}
else
alSetError(AL_INVALID_VALUE);
break;
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
if(iValue == AL_TRUE || iValue == AL_FALSE)
ALEffectSlot->AuxSendAuto = iValue;
else
alSetError(AL_INVALID_VALUE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
if (alIsAuxiliaryEffectSlot(effectslot))
{
switch(param)
{
case AL_EFFECTSLOT_EFFECT:
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
alAuxiliaryEffectSloti(effectslot, param, piValues[0]);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
if (alIsAuxiliaryEffectSlot(effectslot))
{
ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslot);
switch(param)
{
case AL_EFFECTSLOT_GAIN:
if(flValue >= 0.0f && flValue <= 1.0f)
ALEffectSlot->Gain = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
if (alIsAuxiliaryEffectSlot(effectslot))
{
switch(param)
{
case AL_EFFECTSLOT_GAIN:
alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
if (alIsAuxiliaryEffectSlot(effectslot))
{
ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslot);
switch(param)
{
case AL_EFFECTSLOT_EFFECT:
*piValue = ALEffectSlot->effect.effect;
break;
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
*piValue = ALEffectSlot->AuxSendAuto;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
if (alIsAuxiliaryEffectSlot(effectslot))
{
switch(param)
{
case AL_EFFECTSLOT_EFFECT:
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
alGetAuxiliaryEffectSloti(effectslot, param, piValues);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
if (alIsAuxiliaryEffectSlot(effectslot))
{
ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(effectslot);
switch(param)
{
case AL_EFFECTSLOT_GAIN:
*pflValue = ALEffectSlot->Gain;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
if (alIsAuxiliaryEffectSlot(effectslot))
{
switch(param)
{
case AL_EFFECTSLOT_GAIN:
alGetAuxiliaryEffectSlotf(effectslot, param, pflValues);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect)
{
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));
return;
}
memcpy(&ALEffectSlot->effect, effect, sizeof(*effect));
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
if(temp->EffectState)
ALEffect_Destroy(temp->EffectState);
ALTHUNK_REMOVEENTRY(temp->effectslot);
memset(temp, 0, sizeof(ALeffectslot));
free(temp);
}
Context->AuxiliaryEffectSlotCount = 0;
}
+432 -286
View File
@@ -18,17 +18,24 @@
* 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>
#include <stdio.h>
#include <assert.h>
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
#include "alError.h"
#include "alBuffer.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
*
@@ -91,20 +98,20 @@ ALAPI ALvoid ALAPIENTRY alGenBuffers(ALsizei n,ALuint *puiBuffers)
while(i < n)
{
*list = calloc(1, sizeof(ALbuffer));
if(*list)
if(!(*list))
{
puiBuffers[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
(*list)->state = UNUSED;
g_uiBufferCount++;
i++;
list = &(*list)->next;
alDeleteBuffers(i, puiBuffers);
alSetError(AL_OUT_OF_MEMORY);
break;
}
}
// If we didn't create all the Buffers, we must have run out of memory
if (i != n)
alSetError(AL_OUT_OF_MEMORY);
puiBuffers[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
(*list)->state = UNUSED;
g_uiBufferCount++;
i++;
list = &(*list)->next;
}
}
else
{
@@ -136,63 +143,59 @@ ALAPI ALvoid ALAPIENTRY alDeleteBuffers(ALsizei n, const ALuint *puiBuffers)
// Check we are actually Deleting some Buffers
if (n >= 0)
{
if ((ALuint)n <= g_uiBufferCount)
// Check that all the buffers are valid and can actually be deleted
for (i = 0; i < n; i++)
{
// Check that all the buffers are valid and can actually be deleted
for (i = 0; i < n; i++)
// Check for valid Buffer ID (can be NULL buffer)
if (alIsBuffer(puiBuffers[i]))
{
// Check for valid Buffer ID (can be NULL buffer)
if (alIsBuffer(puiBuffers[i]))
// If not the NULL buffer, check that the reference count is 0
ALBuf = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(puiBuffers[i]));
if (ALBuf)
{
// If not the NULL buffer, check that the reference count is 0
ALBuf = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(puiBuffers[i]));
if (ALBuf)
if (ALBuf->refcount != 0)
{
if (ALBuf->refcount != 0)
{
// Buffer still in use, cannot be deleted
alSetError(AL_INVALID_OPERATION);
bFailed = AL_TRUE;
}
// Buffer still in use, cannot be deleted
alSetError(AL_INVALID_OPERATION);
bFailed = AL_TRUE;
}
}
else
{
// Invalid Buffer
alSetError(AL_INVALID_NAME);
bFailed = AL_TRUE;
}
}
// If all the Buffers were valid (and have Reference Counts of 0), then we can delete them
if (!bFailed)
else
{
for (i = 0; i < n; i++)
// Invalid Buffer
alSetError(AL_INVALID_NAME);
bFailed = AL_TRUE;
}
}
// If all the Buffers were valid (and have Reference Counts of 0), then we can delete them
if (!bFailed)
{
for (i = 0; i < n; i++)
{
if (puiBuffers[i] && alIsBuffer(puiBuffers[i]))
{
ALbuffer **list = &g_pBuffers;
ALBuf=((ALbuffer *)ALTHUNK_LOOKUPENTRY(puiBuffers[i]));
if (ALBuf)
{
ALbuffer **list = &g_pBuffers;
while(*list && *list != ALBuf)
list = &(*list)->next;
while(*list && *list != ALBuf)
list = &(*list)->next;
if(*list)
*list = (*list)->next;
if(*list)
*list = (*list)->next;
// Release the memory used to store audio data
free(ALBuf->data);
// Release the memory used to store audio data
free(ALBuf->data);
// Release buffer structure
ALTHUNK_REMOVEENTRY(puiBuffers[i]);
memset(ALBuf, 0, sizeof(ALbuffer));
g_uiBufferCount--;
free(ALBuf);
}
// Release buffer structure
ALTHUNK_REMOVEENTRY(puiBuffers[i]);
memset(ALBuf, 0, sizeof(ALbuffer));
g_uiBufferCount--;
free(ALBuf);
}
}
}
else
alSetError(AL_INVALID_NAME);
}
else
alSetError(AL_INVALID_VALUE);
@@ -253,14 +256,10 @@ 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 i,j,k;
ALvoid *temp;
Context = alcGetCurrentContext();
SuspendContext(Context);
@@ -273,245 +272,116 @@ ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *d
switch(format)
{
case AL_FORMAT_MONO8:
if ((size%1) == 0)
{
// 8bit Samples are converted to 16 bit here
// Allocate 8 extra samples (16 bytes)
ALBuf->data=realloc(ALBuf->data,16+(size/sizeof(ALubyte))*(1*sizeof(ALshort)));
if (ALBuf->data)
{
ALBuf->format = AL_FORMAT_MONO16;
ALBuf->eOriginalFormat = AL_FORMAT_MONO8;
for (i=0;i<(ALsizei)(size/sizeof(ALubyte));i++)
ALBuf->data[i]=(ALshort)((((ALubyte *)data)[i]-128)<<8);
memset(&(ALBuf->data[size/sizeof(ALubyte)]), 0, 16);
ALBuf->size=size/sizeof(ALubyte)*1*sizeof(ALshort);
ALBuf->frequency=freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
else
alSetError(AL_INVALID_VALUE);
break;
case AL_FORMAT_MONO16:
if ((size%2) == 0)
{
// Allocate 8 extra samples (16 bytes)
ALBuf->data=realloc(ALBuf->data,16+(size/sizeof(ALshort))*(1*sizeof(ALshort)));
if (ALBuf->data)
{
ALBuf->format = AL_FORMAT_MONO16;
ALBuf->eOriginalFormat = AL_FORMAT_MONO16;
memcpy(ALBuf->data,data,size/sizeof(ALshort)*1*sizeof(ALshort));
memset(&(ALBuf->data[size/sizeof(ALshort)]), 0, 16);
ALBuf->size=size/sizeof(ALshort)*1*sizeof(ALshort);
ALBuf->frequency=freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
else
alSetError(AL_INVALID_VALUE);
case AL_FORMAT_MONO_FLOAT32:
LoadData(ALBuf, data, size, freq, format, AL_FORMAT_MONO16);
break;
case AL_FORMAT_STEREO8:
if ((size%2) == 0)
{
// 8bit Samples are converted to 16 bit here
// Allocate 8 extra samples (32 bytes)
ALBuf->data=realloc(ALBuf->data,32+(size/sizeof(ALubyte))*(1*sizeof(ALshort)));
if (ALBuf->data)
{
ALBuf->format = AL_FORMAT_STEREO16;
ALBuf->eOriginalFormat = AL_FORMAT_STEREO8;
for (i=0;i<(ALsizei)(size/sizeof(ALubyte));i++)
ALBuf->data[i]=(ALshort)((((ALubyte *)data)[i]-128)<<8);
memset(&(ALBuf->data[size/sizeof(ALubyte)]), 0, 32);
ALBuf->size=size/sizeof(ALubyte)*1*sizeof(ALshort);
ALBuf->frequency=freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
else
alSetError(AL_INVALID_VALUE);
case AL_FORMAT_STEREO16:
case AL_FORMAT_STEREO_FLOAT32:
LoadData(ALBuf, data, size, freq, format, AL_FORMAT_STEREO16);
break;
case AL_FORMAT_STEREO16:
if ((size%4) == 0)
case AL_FORMAT_REAR8:
case AL_FORMAT_REAR16:
case AL_FORMAT_REAR32: {
ALuint NewFormat = AL_FORMAT_QUAD16;
ALuint NewChannels = aluChannelsFromFormat(NewFormat);
ALuint OrigBytes = ((format==AL_FORMAT_REAR8) ? 1 :
((format==AL_FORMAT_REAR16) ? 2 :
4));
assert(aluBytesFromFormat(NewFormat) == 2);
if((size%(OrigBytes*2)) != 0)
{
// Allocate 8 extra samples (32 bytes)
ALBuf->data=realloc(ALBuf->data,32+(size/sizeof(ALshort))*(1*sizeof(ALshort)));
if (ALBuf->data)
{
ALBuf->format = AL_FORMAT_STEREO16;
ALBuf->eOriginalFormat = AL_FORMAT_STEREO16;
memcpy(ALBuf->data,data,size/sizeof(ALshort)*1*sizeof(ALshort));
memset(&(ALBuf->data[size/sizeof(ALshort)]), 0, 32);
ALBuf->size=size/sizeof(ALshort)*1*sizeof(ALshort);
ALBuf->frequency=freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
alSetError(AL_INVALID_VALUE);
break;
}
size /= OrigBytes;
size *= 2;
// Samples are converted to 16 bit here
temp = realloc(ALBuf->data, (padding*NewChannels + size) * sizeof(ALshort));
if(temp)
{
ALBuf->data = temp;
ConvertDataRear(ALBuf->data, data, OrigBytes, size);
memset(&(ALBuf->data[size]), 0, padding*NewChannels*sizeof(ALshort));
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_INVALID_VALUE);
alSetError(AL_OUT_OF_MEMORY);
} break;
case AL_FORMAT_QUAD8_LOKI:
case AL_FORMAT_QUAD16_LOKI:
case AL_FORMAT_QUAD8:
case AL_FORMAT_QUAD16:
case AL_FORMAT_QUAD32:
LoadData(ALBuf, data, size, freq, format, AL_FORMAT_QUAD16);
break;
case AL_FORMAT_51CHN8:
case AL_FORMAT_51CHN16:
case AL_FORMAT_51CHN32:
LoadData(ALBuf, data, size, freq, format, AL_FORMAT_51CHN16);
break;
case AL_FORMAT_61CHN8:
case AL_FORMAT_61CHN16:
case AL_FORMAT_61CHN32:
LoadData(ALBuf, data, size, freq, format, AL_FORMAT_61CHN16);
break;
case AL_FORMAT_71CHN8:
case AL_FORMAT_71CHN16:
case AL_FORMAT_71CHN32:
LoadData(ALBuf, data, size, freq, format, AL_FORMAT_71CHN16);
break;
case AL_FORMAT_MONO_IMA4:
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 8 extra samples (16 bytes)
ALBuf->data=realloc(ALBuf->data,16+(size/36)*(65*sizeof(ALshort)));
if (ALBuf->data)
{
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, 16);
ALBuf->size=size/36*65*sizeof(ALshort);
ALBuf->frequency=freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
else
alSetError(AL_INVALID_VALUE);
break;
case AL_FORMAT_STEREO_IMA4:
// 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 8 extra samples (32 bytes)
ALBuf->data=realloc(ALBuf->data,32+(size/72)*(2*65*sizeof(ALshort)));
if (ALBuf->data)
{
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, 32);
ALBuf->size=size/72*2*65*sizeof(ALshort);
ALBuf->frequency=freq;
}
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);
@@ -533,6 +403,110 @@ 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 = alcGetCurrentContext();
SuspendContext(Context);
if(alIsBuffer(buffer) && buffer != 0)
{
ALBuf = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffer);
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)
{
@@ -817,11 +791,11 @@ ALAPI ALvoid ALAPIENTRY alGetBufferi(ALuint buffer, ALenum eParam, ALint *plValu
break;
case AL_BITS:
*plValue= (((pBuffer->format==AL_FORMAT_MONO8)||(pBuffer->format==AL_FORMAT_STEREO8))?8:16);
*plValue = aluBytesFromFormat(pBuffer->format) * 8;
break;
case AL_CHANNELS:
*plValue = (((pBuffer->format==AL_FORMAT_MONO8)||(pBuffer->format==AL_FORMAT_MONO16))?1:2);
*plValue = aluChannelsFromFormat(pBuffer->format);
break;
case AL_SIZE:
@@ -917,6 +891,178 @@ ALAPI void ALAPIENTRY alGetBufferiv(ALuint buffer, ALenum eParam, ALint* plValue
ProcessContext(pContext);
}
/*
* LoadData
*
* Loads the specified data into the buffer, using the specified formats.
* Currently, the new format must be 16-bit, and must have the same channel
* configuration as the original format. This does NOT handle compressed
* formats (eg. IMA4).
*/
static void LoadData(ALbuffer *ALBuf, const ALubyte *data, ALsizei size, ALuint freq, ALenum OrigFormat, ALenum NewFormat)
{
ALuint NewChannels = aluChannelsFromFormat(NewFormat);
ALuint OrigBytes = aluBytesFromFormat(OrigFormat);
ALuint OrigChannels = aluChannelsFromFormat(OrigFormat);
ALsizei padding = 2;
ALvoid *temp;
assert(aluBytesFromFormat(NewFormat) == 2);
assert(NewChannels == OrigChannels);
if ((size%(OrigBytes*OrigChannels)) != 0)
{
alSetError(AL_INVALID_VALUE);
return;
}
// Samples are converted to 16 bit here
size /= OrigBytes;
temp = realloc(ALBuf->data, (padding*NewChannels + size) * sizeof(ALshort));
if(temp)
{
ALBuf->data = temp;
ConvertData(ALBuf->data, data, OrigBytes, size);
memset(&(ALBuf->data[size]), 0, padding*NewChannels*sizeof(ALshort));
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
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;
case 2:
memcpy(dst, src, len*sizeof(ALshort));
break;
case 4:
for(i = 0;i < len;i++)
{
ALint smp;
smp = (((ALfloat*)src)[i] * 32767.5f - 0.5f);
smp = min(smp, 32767);
smp = max(smp, -32768);
dst[i] = (ALshort)smp;
}
break;
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()
@@ -930,7 +1076,7 @@ ALvoid ReleaseALBuffers(ALvoid)
#ifdef _DEBUG
if(g_uiBufferCount > 0)
AL_PRINT("exit() %d Buffer(s) NOT deleted\n", g_uiBufferCount);
AL_PRINT("exit(): deleting %d Buffer(s)\n", g_uiBufferCount);
#endif
ALBuffer = g_pBuffers;
+1230
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -18,6 +18,8 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include "alMain.h"
#include "AL/alc.h"
#include "alError.h"
+134 -18
View File
@@ -18,12 +18,19 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "alExtension.h"
#include "alError.h"
#include "alMain.h"
#include "alFilter.h"
#include "alEffect.h"
#include "alAuxEffectSlot.h"
#include "alSource.h"
#include "alBuffer.h"
#include "AL/al.h"
#include "AL/alc.h"
@@ -101,6 +108,45 @@ static ALfunction function[]= {
{ "alDopplerVelocity", (ALvoid *) alDopplerVelocity },
{ "alSpeedOfSound", (ALvoid *) alSpeedOfSound },
{ "alDistanceModel", (ALvoid *) alDistanceModel },
{ "alGenFilters", (ALvoid *) alGenFilters },
{ "alDeleteFilters", (ALvoid *) alDeleteFilters },
{ "alIsFilter", (ALvoid *) alIsFilter },
{ "alFilteri", (ALvoid *) alFilteri },
{ "alFilteriv", (ALvoid *) alFilteriv },
{ "alFilterf", (ALvoid *) alFilterf },
{ "alFilterfv", (ALvoid *) alFilterfv },
{ "alGetFilteri", (ALvoid *) alGetFilteri },
{ "alGetFilteriv", (ALvoid *) alGetFilteriv },
{ "alGetFilterf", (ALvoid *) alGetFilterf },
{ "alGetFilterfv", (ALvoid *) alGetFilterfv },
{ "alGenEffects", (ALvoid *) alGenEffects },
{ "alDeleteEffects", (ALvoid *) alDeleteEffects },
{ "alIsEffect", (ALvoid *) alIsEffect },
{ "alEffecti", (ALvoid *) alEffecti },
{ "alEffectiv", (ALvoid *) alEffectiv },
{ "alEffectf", (ALvoid *) alEffectf },
{ "alEffectfv", (ALvoid *) alEffectfv },
{ "alGetEffecti", (ALvoid *) alGetEffecti },
{ "alGetEffectiv", (ALvoid *) alGetEffectiv },
{ "alGetEffectf", (ALvoid *) alGetEffectf },
{ "alGetEffectfv", (ALvoid *) alGetEffectfv },
{ "alGenAuxiliaryEffectSlots", (ALvoid *) alGenAuxiliaryEffectSlots },
{ "alDeleteAuxiliaryEffectSlots",(ALvoid *) alDeleteAuxiliaryEffectSlots},
{ "alIsAuxiliaryEffectSlot", (ALvoid *) alIsAuxiliaryEffectSlot },
{ "alAuxiliaryEffectSloti", (ALvoid *) alAuxiliaryEffectSloti },
{ "alAuxiliaryEffectSlotiv", (ALvoid *) alAuxiliaryEffectSlotiv },
{ "alAuxiliaryEffectSlotf", (ALvoid *) alAuxiliaryEffectSlotf },
{ "alAuxiliaryEffectSlotfv", (ALvoid *) alAuxiliaryEffectSlotfv },
{ "alGetAuxiliaryEffectSloti", (ALvoid *) alGetAuxiliaryEffectSloti },
{ "alGetAuxiliaryEffectSlotiv", (ALvoid *) alGetAuxiliaryEffectSlotiv},
{ "alGetAuxiliaryEffectSlotf", (ALvoid *) alGetAuxiliaryEffectSlotf },
{ "alGetAuxiliaryEffectSlotfv", (ALvoid *) alGetAuxiliaryEffectSlotfv},
{ "alBufferSubDataEXT", (ALvoid *) alBufferSubDataEXT },
{ NULL, (ALvoid *) NULL } };
static ALenums enumeration[]={
@@ -135,6 +181,18 @@ static ALenums enumeration[]={
{ (ALchar *)"AL_STATIC", AL_STATIC },
{ (ALchar *)"AL_STREAMING", AL_STREAMING },
{ (ALchar *)"AL_UNDETERMINED", AL_UNDETERMINED },
{ (ALchar *)"AL_METERS_PER_UNIT", AL_METERS_PER_UNIT },
// Source EFX Properties
{ (ALchar *)"AL_DIRECT_FILTER", AL_DIRECT_FILTER },
{ (ALchar *)"AL_AUXILIARY_SEND_FILTER", AL_AUXILIARY_SEND_FILTER },
{ (ALchar *)"AL_AIR_ABSORPTION_FACTOR", AL_AIR_ABSORPTION_FACTOR },
{ (ALchar *)"AL_ROOM_ROLLOFF_FACTOR", AL_ROOM_ROLLOFF_FACTOR },
{ (ALchar *)"AL_CONE_OUTER_GAINHF", AL_CONE_OUTER_GAINHF },
{ (ALchar *)"AL_DIRECT_FILTER_GAINHF_AUTO", AL_DIRECT_FILTER_GAINHF_AUTO },
{ (ALchar *)"AL_AUXILIARY_SEND_FILTER_GAIN_AUTO", AL_AUXILIARY_SEND_FILTER_GAIN_AUTO },
{ (ALchar *)"AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO", AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO},
// Source State information
{ (ALchar *)"AL_SOURCE_STATE", AL_SOURCE_STATE },
@@ -150,12 +208,29 @@ static ALenums enumeration[]={
// Buffer Formats
{ (ALchar *)"AL_FORMAT_MONO8", AL_FORMAT_MONO8 },
{ (ALchar *)"AL_FORMAT_MONO16", AL_FORMAT_MONO16 },
{ (ALchar *)"AL_FORMAT_MONO_FLOAT32", AL_FORMAT_MONO_FLOAT32 },
{ (ALchar *)"AL_FORMAT_STEREO8", AL_FORMAT_STEREO8 },
{ (ALchar *)"AL_FORMAT_STEREO16", AL_FORMAT_STEREO16 },
{ (ALchar *)"AL_FORMAT_STEREO_FLOAT32", AL_FORMAT_STEREO_FLOAT32 },
{ (ALchar *)"AL_FORMAT_MONO_IMA4", AL_FORMAT_MONO_IMA4 },
{ (ALchar *)"AL_FORMAT_STEREO_IMA4", AL_FORMAT_STEREO_IMA4 },
{ (ALchar *)"AL_FORMAT_QUAD8_LOKI", AL_FORMAT_QUAD8_LOKI },
{ (ALchar *)"AL_FORMAT_QUAD16_LOKI", AL_FORMAT_QUAD16_LOKI },
{ (ALchar *)"AL_FORMAT_QUAD8", AL_FORMAT_QUAD8 },
{ (ALchar *)"AL_FORMAT_QUAD16", AL_FORMAT_QUAD16 },
{ (ALchar *)"AL_FORMAT_QUAD32", AL_FORMAT_QUAD32 },
{ (ALchar *)"AL_FORMAT_51CHN8", AL_FORMAT_51CHN8 },
{ (ALchar *)"AL_FORMAT_51CHN16", AL_FORMAT_51CHN16 },
{ (ALchar *)"AL_FORMAT_51CHN32", AL_FORMAT_51CHN32 },
{ (ALchar *)"AL_FORMAT_61CHN8", AL_FORMAT_61CHN8 },
{ (ALchar *)"AL_FORMAT_61CHN16", AL_FORMAT_61CHN16 },
{ (ALchar *)"AL_FORMAT_61CHN32", AL_FORMAT_61CHN32 },
{ (ALchar *)"AL_FORMAT_71CHN8", AL_FORMAT_71CHN8 },
{ (ALchar *)"AL_FORMAT_71CHN16", AL_FORMAT_71CHN16 },
{ (ALchar *)"AL_FORMAT_71CHN32", AL_FORMAT_71CHN32 },
{ (ALchar *)"AL_FORMAT_REAR8", AL_FORMAT_REAR8 },
{ (ALchar *)"AL_FORMAT_REAR16", AL_FORMAT_REAR16 },
{ (ALchar *)"AL_FORMAT_REAR32", AL_FORMAT_REAR32 },
// Buffer attributes
{ (ALchar *)"AL_FREQUENCY", AL_FREQUENCY },
@@ -196,8 +271,52 @@ static ALenums enumeration[]={
{ (ALchar *)"AL_EXPONENT_DISTANCE", AL_EXPONENT_DISTANCE },
{ (ALchar *)"AL_EXPONENT_DISTANCE_CLAMPED", AL_EXPONENT_DISTANCE_CLAMPED },
// Filter types
{ (ALchar *)"AL_FILTER_TYPE", AL_FILTER_TYPE },
{ (ALchar *)"AL_FILTER_NULL", AL_FILTER_NULL },
{ (ALchar *)"AL_FILTER_LOWPASS", AL_FILTER_LOWPASS },
{ (ALchar *)"AL_FILTER_HIGHPASS", AL_FILTER_HIGHPASS },
{ (ALchar *)"AL_FILTER_BANDPASS", AL_FILTER_BANDPASS },
// Filter params
{ (ALchar *)"AL_LOWPASS_GAIN", AL_LOWPASS_GAIN },
{ (ALchar *)"AL_LOWPASS_GAINHF", AL_LOWPASS_GAINHF },
// Effect types
{ (ALchar *)"AL_EFFECT_TYPE", AL_EFFECT_TYPE },
{ (ALchar *)"AL_EFFECT_NULL", AL_EFFECT_NULL },
{ (ALchar *)"AL_EFFECT_REVERB", AL_EFFECT_REVERB },
{ (ALchar *)"AL_EFFECT_CHORUS", AL_EFFECT_CHORUS },
{ (ALchar *)"AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION },
{ (ALchar *)"AL_EFFECT_ECHO", AL_EFFECT_ECHO },
{ (ALchar *)"AL_EFFECT_FLANGER", AL_EFFECT_FLANGER },
{ (ALchar *)"AL_EFFECT_FREQUENCY_SHIFTER", AL_EFFECT_FREQUENCY_SHIFTER },
{ (ALchar *)"AL_EFFECT_VOCAL_MORPHER", AL_EFFECT_VOCAL_MORPHER },
{ (ALchar *)"AL_EFFECT_PITCH_SHIFTER", AL_EFFECT_PITCH_SHIFTER },
{ (ALchar *)"AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR },
{ (ALchar *)"AL_EFFECT_AUTOWAH", AL_EFFECT_AUTOWAH },
{ (ALchar *)"AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR },
{ (ALchar *)"AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER },
// Reverb params
{ (ALchar *)"AL_REVERB_DENSITY", AL_REVERB_DENSITY },
{ (ALchar *)"AL_REVERB_DIFFUSION", AL_REVERB_DIFFUSION },
{ (ALchar *)"AL_REVERB_GAIN", AL_REVERB_GAIN },
{ (ALchar *)"AL_REVERB_GAINHF", AL_REVERB_GAINHF },
{ (ALchar *)"AL_REVERB_DECAY_TIME", AL_REVERB_DECAY_TIME },
{ (ALchar *)"AL_REVERB_DECAY_HFRATIO", AL_REVERB_DECAY_HFRATIO },
{ (ALchar *)"AL_REVERB_REFLECTIONS_GAIN", AL_REVERB_REFLECTIONS_GAIN },
{ (ALchar *)"AL_REVERB_REFLECTIONS_DELAY", AL_REVERB_REFLECTIONS_DELAY },
{ (ALchar *)"AL_REVERB_LATE_REVERB_GAIN", AL_REVERB_LATE_REVERB_GAIN },
{ (ALchar *)"AL_REVERB_LATE_REVERB_DELAY", AL_REVERB_LATE_REVERB_DELAY },
{ (ALchar *)"AL_REVERB_AIR_ABSORPTION_GAINHF", AL_REVERB_AIR_ABSORPTION_GAINHF },
{ (ALchar *)"AL_REVERB_ROOM_ROLLOFF_FACTOR", AL_REVERB_ROOM_ROLLOFF_FACTOR },
{ (ALchar *)"AL_REVERB_DECAY_HFLIMIT", AL_REVERB_DECAY_HFLIMIT },
// Default
{ (ALchar *)NULL, (ALenum ) 0 } };
{ (ALchar *)NULL, (ALenum)0 }
};
@@ -205,7 +324,8 @@ ALAPI ALboolean ALAPIENTRY alIsExtensionPresent(const ALchar *extName)
{
ALboolean bIsSupported = AL_FALSE;
ALCcontext *pContext;
char *ptr, *ext;
const char *ptr;
size_t len;
if (!extName)
{
@@ -220,32 +340,28 @@ ALAPI ALboolean ALAPIENTRY alIsExtensionPresent(const ALchar *extName)
return AL_FALSE;
}
ext = strdup(extName);
ptr = ext;
do {
*ptr = (char)toupper(*ptr);
} while(*(ptr++));
SuspendContext(pContext);
len = strlen(extName);
ptr = pContext->ExtensionList;
while((ptr=strstr(ptr, ext)) != NULL)
while(ptr && *ptr)
{
if(ptr == pContext->ExtensionList || ptr[-1] == ' ')
if(strncasecmp(ptr, extName, len) == 0 &&
(ptr[len] == '\0' || isspace(ptr[len])))
{
char e = ptr[strlen(ext)];
if(e == ' ' || e == 0)
{
bIsSupported = AL_TRUE;
break;
}
bIsSupported = AL_TRUE;
break;
}
if((ptr=strchr(ptr, ' ')) != NULL)
{
do {
++ptr;
} while(isspace(*ptr));
}
ptr++;
}
ProcessContext(pContext);
free(ext);
return bIsSupported;
}
+426
View File
@@ -0,0 +1,426 @@
/**
* 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 "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alFilter.h"
#include "alThunk.h"
#include "alError.h"
static ALfilter *g_FilterList;
static ALuint g_FilterCount;
static void InitFilterParams(ALfilter *filter, ALenum type);
ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
{
ALCcontext *Context;
ALsizei i;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (n > 0)
{
// 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;
while(*list)
list = &(*list)->next;
i = 0;
while(i < n)
{
*list = calloc(1, sizeof(ALfilter));
if(!(*list))
{
// We must have run out or memory
alDeleteFilters(i, filters);
alSetError(AL_OUT_OF_MEMORY);
break;
}
filters[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
(*list)->filter = filters[i];
InitFilterParams(*list, AL_FILTER_NULL);
g_FilterCount++;
i++;
list = &(*list)->next;
}
}
}
ProcessContext(Context);
}
ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
{
ALCcontext *Context;
ALfilter *ALFilter;
ALsizei i;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (n >= 0)
{
// Check that all filters are valid
for (i = 0; i < n; i++)
{
if (!alIsFilter(filters[i]))
{
alSetError(AL_INVALID_NAME);
break;
}
}
if (i == n)
{
// All filters are valid
for (i = 0; i < n; i++)
{
// Recheck that the filter is valid, because there could be duplicated names
if (filters[i] && alIsFilter(filters[i]))
{
ALfilter **list;
ALFilter = ((ALfilter*)ALTHUNK_LOOKUPENTRY(filters[i]));
// Remove Source from list of Sources
list = &g_FilterList;
while(*list && *list != ALFilter)
list = &(*list)->next;
if(*list)
*list = (*list)->next;
ALTHUNK_REMOVEENTRY(ALFilter->filter);
memset(ALFilter, 0, sizeof(ALfilter));
free(ALFilter);
g_FilterCount--;
}
}
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(Context);
}
ALboolean AL_APIENTRY alIsFilter(ALuint filter)
{
ALCcontext *Context;
ALfilter **list;
Context = alcGetCurrentContext();
SuspendContext(Context);
list = &g_FilterList;
while(*list && (*list)->filter != filter)
list = &(*list)->next;
ProcessContext(Context);
return ((*list || !filter) ? AL_TRUE : AL_FALSE);
}
ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (filter && alIsFilter(filter))
{
ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(filter);
switch(param)
{
case AL_FILTER_TYPE:
if(iValue == AL_FILTER_NULL ||
iValue == AL_FILTER_LOWPASS)
InitFilterParams(ALFilter, iValue);
else
alSetError(AL_INVALID_VALUE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (filter && alIsFilter(filter))
{
switch(param)
{
case AL_FILTER_TYPE:
alFilteri(filter, param, piValues[0]);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (filter && alIsFilter(filter))
{
ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(filter);
switch(ALFilter->type)
{
case AL_FILTER_LOWPASS:
switch(param)
{
case AL_LOWPASS_GAIN:
if(flValue >= 0.0f && flValue <= 1.0f)
ALFilter->Gain = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_LOWPASS_GAINHF:
if(flValue >= 0.0f && flValue <= 1.0f)
ALFilter->GainHF = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (filter && alIsFilter(filter))
{
switch(param)
{
default:
alFilterf(filter, param, pflValues[0]);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (filter && alIsFilter(filter))
{
ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(filter);
switch(param)
{
case AL_FILTER_TYPE:
*piValue = ALFilter->type;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (filter && alIsFilter(filter))
{
switch(param)
{
case AL_FILTER_TYPE:
alGetFilteri(filter, param, piValues);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (filter && alIsFilter(filter))
{
ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(filter);
switch(ALFilter->type)
{
case AL_FILTER_LOWPASS:
switch(param)
{
case AL_LOWPASS_GAIN:
*pflValue = ALFilter->Gain;
break;
case AL_LOWPASS_GAINHF:
*pflValue = ALFilter->GainHF;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (filter && alIsFilter(filter))
{
switch(param)
{
default:
alGetFilterf(filter, param, pflValues);
break;
}
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid ReleaseALFilters(ALvoid)
{
#ifdef _DEBUG
if(g_FilterCount > 0)
AL_PRINT("exit(): deleting %d Filter(s)\n", g_FilterCount);
#endif
while(g_FilterList)
{
ALfilter *temp = g_FilterList;
g_FilterList = g_FilterList->next;
// Release filter structure
memset(temp, 0, sizeof(ALfilter));
free(temp);
}
g_FilterCount = 0;
}
static void InitFilterParams(ALfilter *filter, ALenum type)
{
filter->type = type;
filter->Gain = 1.0;
filter->GainHF = 1.0;
}
+24
View File
@@ -18,6 +18,8 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include "alMain.h"
#include "AL/alc.h"
#include "alError.h"
@@ -41,6 +43,13 @@ ALAPI ALvoid ALAPIENTRY alListenerf(ALenum eParam, ALfloat flValue)
alSetError(AL_INVALID_VALUE);
break;
case AL_METERS_PER_UNIT:
if (flValue > 0.0f)
pContext->Listener.MetersPerUnit = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
@@ -112,6 +121,13 @@ ALAPI ALvoid ALAPIENTRY alListenerfv(ALenum eParam, const ALfloat *pflValues)
alSetError(AL_INVALID_VALUE);
break;
case AL_METERS_PER_UNIT:
if (pflValues[0] > 0.0f)
pContext->Listener.MetersPerUnit = pflValues[0];
else
alSetError(AL_INVALID_VALUE);
break;
case AL_POSITION:
pContext->Listener.Position[0] = pflValues[0];
pContext->Listener.Position[1] = pflValues[1];
@@ -274,6 +290,10 @@ ALAPI ALvoid ALAPIENTRY alGetListenerf(ALenum eParam, ALfloat *pflValue)
*pflValue = pContext->Listener.Gain;
break;
case AL_METERS_PER_UNIT:
*pflValue = pContext->Listener.MetersPerUnit;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
@@ -350,6 +370,10 @@ ALAPI ALvoid ALAPIENTRY alGetListenerfv(ALenum eParam, ALfloat *pflValues)
pflValues[0] = pContext->Listener.Gain;
break;
case AL_METERS_PER_UNIT:
pflValues[0] = pContext->Listener.MetersPerUnit;
break;
case AL_POSITION:
pflValues[0] = pContext->Listener.Position[0];
pflValues[1] = pContext->Listener.Position[1];
+416 -138
View File
@@ -18,6 +18,8 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include <math.h>
#include <float.h>
@@ -26,9 +28,12 @@
#include "AL/alc.h"
#include "alError.h"
#include "alSource.h"
#include "alBuffer.h"
#include "alThunk.h"
#include "alAuxEffectSlot.h"
static ALvoid InitSourceParams(ALsource *pSource);
static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource);
static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize);
static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
static ALint GetByteOffset(ALsource *pSource);
@@ -63,22 +68,22 @@ ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
while(i < n)
{
*list = calloc(1, sizeof(ALsource));
if(*list)
if(!(*list))
{
sources[i]=(ALuint)ALTHUNK_ADDENTRY(*list);
(*list)->source = sources[i];
InitSourceParams(*list);
Context->SourceCount++;
i++;
list = &(*list)->next;
alDeleteSources(i, sources);
alSetError(AL_OUT_OF_MEMORY);
break;
}
}
// If we didn't create all the Sources, we must have run out or memory
if(i != n)
alSetError(AL_OUT_OF_MEMORY);
sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
(*list)->source = sources[i];
InitSourceParams(Context, *list);
Context->SourceCount++;
i++;
list = &(*list)->next;
}
}
else
{
@@ -117,7 +122,7 @@ ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
ALCdevice *Device;
ALsource *ALSource;
ALsource **list;
ALsizei i;
ALsizei i, j;
ALbufferlistitem *ALBufferList;
ALboolean bSourcesValid = AL_TRUE;
@@ -132,66 +137,64 @@ ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
if (Device)
{
if ((ALuint)n <= Context->SourceCount)
// Check that all Sources are valid (and can therefore be deleted)
for (i = 0; i < n; i++)
{
// Check that all Sources are valid (and can therefore be deleted)
for (i = 0; i < n; i++)
if (!alIsSource(sources[i]))
{
if (!alIsSource(sources[i]))
{
alSetError(AL_INVALID_NAME);
bSourcesValid = AL_FALSE;
break;
}
}
if (bSourcesValid)
{
// All Sources are valid, and can be deleted
for (i = 0; i < n; i++)
{
// Recheck that the Source is valid, because there could be duplicated Source names
if (alIsSource(sources[i]))
{
ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
alSourceStop((ALuint)ALSource->source);
// For each buffer in the source's queue, decrement its reference counter and remove it
while (ALSource->queue != NULL)
{
ALBufferList = ALSource->queue;
// Decrement buffer's reference counter
if (ALBufferList->buffer != 0)
((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
// Update queue to point to next element in list
ALSource->queue = ALBufferList->next;
// Release memory allocated for buffer list item
free(ALBufferList);
}
// Decrement Source count
Context->SourceCount--;
// Remove Source from list of Sources
list = &Context->Source;
while(*list && *list != ALSource)
list = &(*list)->next;
if(*list)
*list = (*list)->next;
ALTHUNK_REMOVEENTRY(ALSource->source);
memset(ALSource,0,sizeof(ALsource));
free(ALSource);
}
}
alSetError(AL_INVALID_NAME);
bSourcesValid = AL_FALSE;
break;
}
}
else
if (bSourcesValid)
{
// Trying to delete more Sources than have been generated
alSetError(AL_INVALID_NAME);
// All Sources are valid, and can be deleted
for (i = 0; i < n; i++)
{
// Recheck that the Source is valid, because there could be duplicated Source names
if (alIsSource(sources[i]))
{
ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i]));
alSourceStop((ALuint)ALSource->source);
// For each buffer in the source's queue, decrement its reference counter and remove it
while (ALSource->queue != NULL)
{
ALBufferList = ALSource->queue;
// Decrement buffer's reference counter
if (ALBufferList->buffer != 0)
((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--;
// Update queue to point to next element in list
ALSource->queue = ALBufferList->next;
// Release memory allocated for buffer list item
free(ALBufferList);
}
for(j = 0;j < MAX_SENDS;++j)
{
if(ALSource->Send[j].Slot)
ALSource->Send[j].Slot->refcount--;
ALSource->Send[j].Slot = NULL;
}
// Decrement Source count
Context->SourceCount--;
// Remove Source from list of Sources
list = &Context->Source;
while(*list && *list != ALSource)
list = &(*list)->next;
if(*list)
*list = (*list)->next;
ALTHUNK_REMOVEENTRY(ALSource->source);
memset(ALSource,0,sizeof(ALsource));
free(ALSource);
}
}
}
}
else
@@ -341,6 +344,34 @@ ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
alSetError(AL_INVALID_VALUE);
break;
case AL_CONE_OUTER_GAINHF:
if ((flValue >= 0.0f) && (flValue <= 1.0f))
pSource->OuterGainHF = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_AIR_ABSORPTION_FACTOR:
if (flValue >= 0.0f && flValue <= 10.0f)
pSource->AirAbsorptionFactor = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_ROOM_ROLLOFF_FACTOR:
if (flValue >= 0.0f && flValue <= 10.0f)
pSource->RoomRolloffFactor = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_DOPPLER_FACTOR:
if (flValue >= 0.0f && flValue <= 1.0f)
pSource->DopplerFactor = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
@@ -461,9 +492,12 @@ ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *
case AL_MIN_GAIN:
case AL_MAX_GAIN:
case AL_CONE_OUTER_GAIN:
case AL_CONE_OUTER_GAINHF:
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
case AL_AIR_ABSORPTION_FACTOR:
case AL_ROOM_ROLLOFF_FACTOR:
alSourcef(source, eParam, pflValues[0]);
break;
@@ -598,9 +632,6 @@ ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
pSource->lSourceType = AL_UNDETERMINED;
}
// Set Buffers Processed
pSource->BuffersProcessed = 0;
// Update AL_BUFFER parameter
pSource->ulBufferID = lValue;
}
@@ -636,6 +667,56 @@ ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
alSetError(AL_INVALID_VALUE);
break;
case AL_DIRECT_FILTER:
if(alIsFilter(lValue))
{
ALfilter *filter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue);
if(!filter)
{
pSource->DirectFilter.type = AL_FILTER_NULL;
pSource->DirectFilter.filter = 0;
}
else
memcpy(&pSource->DirectFilter, filter, sizeof(*filter));
}
else
alSetError(AL_INVALID_VALUE);
break;
case AL_DIRECT_FILTER_GAINHF_AUTO:
if(lValue == AL_TRUE || lValue == AL_FALSE)
pSource->DryGainHFAuto = lValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
if(lValue == AL_TRUE || lValue == AL_FALSE)
pSource->WetGainAuto = lValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
if(lValue == AL_TRUE || lValue == AL_FALSE)
pSource->WetGainHFAuto = lValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_DISTANCE_MODEL:
if(lValue == AL_NONE ||
lValue == AL_INVERSE_DISTANCE ||
lValue == AL_INVERSE_DISTANCE_CLAMPED ||
lValue == AL_LINEAR_DISTANCE ||
lValue == AL_LINEAR_DISTANCE_CLAMPED ||
lValue == AL_EXPONENT_DISTANCE ||
lValue == AL_EXPONENT_DISTANCE_CLAMPED)
pSource->DistanceModel = lValue;
else
alSetError(AL_INVALID_VALUE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
@@ -664,6 +745,8 @@ ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, AL
if (alIsSource(source))
{
ALsource *pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source));
switch (eParam)
{
case AL_POSITION:
@@ -672,6 +755,35 @@ ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, AL
alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
break;
case AL_AUXILIARY_SEND_FILTER:
if(lValue2 >= 0 && lValue2 < MAX_SENDS &&
(alIsAuxiliaryEffectSlot(lValue1) || lValue1 == 0) &&
alIsFilter(lValue3))
{
ALeffectslot *ALEffectSlot = (ALeffectslot*)ALTHUNK_LOOKUPENTRY(lValue1);
ALfilter *ALFilter = (ALfilter*)ALTHUNK_LOOKUPENTRY(lValue3);
/* Release refcount on the previous slot, and add one for
* the new slot */
if(pSource->Send[lValue2].Slot)
pSource->Send[lValue2].Slot->refcount--;
pSource->Send[lValue2].Slot = ALEffectSlot;
if(pSource->Send[lValue2].Slot)
pSource->Send[lValue2].Slot->refcount++;
if(!ALFilter)
{
/* Disable filter */
pSource->Send[lValue2].WetFilter.type = 0;
pSource->Send[lValue2].WetFilter.filter = 0;
}
else
memcpy(&pSource->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
}
else
alSetError(AL_INVALID_VALUE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
@@ -716,12 +828,18 @@ ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plVa
case AL_MAX_DISTANCE:
case AL_ROLLOFF_FACTOR:
case AL_REFERENCE_DISTANCE:
case AL_DIRECT_FILTER:
case AL_DIRECT_FILTER_GAINHF_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DISTANCE_MODEL:
alSourcei(source, eParam, plValues[0]);
break;
case AL_POSITION:
case AL_VELOCITY:
case AL_DIRECTION:
case AL_AUXILIARY_SEND_FILTER:
alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
break;
@@ -749,7 +867,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflV
{
ALCcontext *pContext;
ALsource *pSource;
ALfloat flOffset;
ALfloat flOffset[2];
pContext = alcGetCurrentContext();
if (pContext)
@@ -792,11 +910,27 @@ ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflV
*pflValue = pSource->flOuterGain;
break;
case AL_CONE_OUTER_GAINHF:
*pflValue = pSource->OuterGainHF;
break;
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
if (GetSourceOffset(pSource, eParam, &flOffset))
*pflValue = flOffset;
if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
*pflValue = flOffset[0];
else
alSetError(AL_INVALID_OPERATION);
break;
case AL_SEC_RW_OFFSETS_EXT:
case AL_SAMPLE_RW_OFFSETS_EXT:
case AL_BYTE_RW_OFFSETS_EXT:
if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
{
pflValue[0] = flOffset[0];
pflValue[1] = flOffset[1];
}
else
alSetError(AL_INVALID_OPERATION);
break;
@@ -813,6 +947,18 @@ ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflV
*pflValue = pSource->flRefDistance;
break;
case AL_AIR_ABSORPTION_FACTOR:
*pflValue = pSource->AirAbsorptionFactor;
break;
case AL_ROOM_ROLLOFF_FACTOR:
*pflValue = pSource->RoomRolloffFactor;
break;
case AL_DOPPLER_FACTOR:
*pflValue = pSource->DopplerFactor;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
@@ -913,6 +1059,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pfl
case AL_MAX_GAIN:
case AL_MAX_DISTANCE:
case AL_ROLLOFF_FACTOR:
case AL_DOPPLER_FACTOR:
case AL_CONE_OUTER_GAIN:
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
@@ -920,6 +1067,9 @@ ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pfl
case AL_CONE_INNER_ANGLE:
case AL_CONE_OUTER_ANGLE:
case AL_REFERENCE_DISTANCE:
case AL_CONE_OUTER_GAINHF:
case AL_AIR_ABSORPTION_FACTOR:
case AL_ROOM_ROLLOFF_FACTOR:
alGetSourcef(source, eParam, pflValues);
break;
@@ -965,7 +1115,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValu
{
ALCcontext *pContext;
ALsource *pSource;
ALfloat flOffset;
ALfloat flOffset[2];
pContext = alcGetCurrentContext();
if (pContext)
@@ -1028,7 +1178,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValu
*plValue = 0;
}
else
*plValue = pSource->BuffersProcessed;
*plValue = pSource->BuffersPlayed;
break;
case AL_SOURCE_TYPE:
@@ -1038,12 +1188,48 @@ ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValu
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
if (GetSourceOffset(pSource, eParam, &flOffset))
*plValue = (ALint)flOffset;
if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
*plValue = (ALint)flOffset[0];
else
alSetError(AL_INVALID_OPERATION);
break;
case AL_SEC_RW_OFFSETS_EXT:
case AL_SAMPLE_RW_OFFSETS_EXT:
case AL_BYTE_RW_OFFSETS_EXT:
if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
{
plValue[0] = (ALint)flOffset[0];
plValue[1] = (ALint)flOffset[1];
}
else
alSetError(AL_INVALID_OPERATION);
break;
case AL_DIRECT_FILTER:
*plValue = pSource->DirectFilter.filter;
break;
case AL_DIRECT_FILTER_GAINHF_AUTO:
*plValue = pSource->DryGainHFAuto;
break;
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
*plValue = pSource->WetGainAuto;
break;
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
*plValue = pSource->WetGainHFAuto;
break;
case AL_DOPPLER_FACTOR:
*plValue = (ALint)pSource->DopplerFactor;
break;
case AL_DISTANCE_MODEL:
*plValue = pSource->DistanceModel;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
@@ -1151,8 +1337,14 @@ ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValue
case AL_BYTE_OFFSET:
case AL_MAX_DISTANCE:
case AL_ROLLOFF_FACTOR:
case AL_DOPPLER_FACTOR:
case AL_REFERENCE_DISTANCE:
case AL_SOURCE_TYPE:
case AL_DIRECT_FILTER:
case AL_DIRECT_FILTER_GAINHF_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DISTANCE_MODEL:
alGetSourcei(source, eParam, plValues);
break;
@@ -1207,7 +1399,7 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
ALbufferlistitem *ALBufferList;
ALboolean bSourcesValid = AL_TRUE;
ALboolean bPlay;
ALsizei i;
ALsizei i, j;
pContext = alcGetCurrentContext();
if (pContext)
@@ -1250,6 +1442,11 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
if (bPlay)
{
for(j = 0;j < OUTPUTCHANNELS;j++)
pSource->DryGains[j] = 0.0f;
for(j = 0;j < MAX_SENDS;j++)
pSource->WetGains[j] = 0.0f;
if (pSource->state != AL_PAUSED)
{
pSource->state = AL_PLAYING;
@@ -1257,10 +1454,8 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
pSource->play = AL_TRUE;
pSource->position = 0;
pSource->position_fraction = 0;
pSource->BuffersProcessed = 0;
pSource->BuffersPlayed = 0;
pSource->BufferPosition = 0;
pSource->lBytesPlayed = 0;
pSource->FirstStart = AL_TRUE;
pSource->ulBufferID = pSource->queue->buffer;
@@ -1277,6 +1472,7 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
pSource->state = AL_PLAYING;
pSource->inuse = AL_TRUE;
pSource->play = AL_TRUE;
pSource->FirstStart = AL_FALSE;
}
// Check if an Offset has been set
@@ -1293,7 +1489,7 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
ALBufferList = ALBufferList->next;
}
pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
pSource->BuffersPlayed = pSource->BuffersInQueue;
}
}
}
@@ -1417,7 +1613,7 @@ ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
{
Source->state=AL_STOPPED;
Source->inuse=AL_FALSE;
Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
Source->BuffersPlayed = Source->BuffersInQueue;
ALBufferListItem= Source->queue;
while (ALBufferListItem != NULL)
{
@@ -1489,7 +1685,7 @@ ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
Source->inuse=AL_FALSE;
Source->position=0;
Source->position_fraction=0;
Source->BuffersProcessed = 0;
Source->BuffersPlayed = 0;
ALBufferListItem= Source->queue;
while (ALBufferListItem != NULL)
{
@@ -1762,7 +1958,6 @@ ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint
// Release memory for buffer list item
free(ALBufferList);
ALSource->BuffersInQueue--;
ALSource->BuffersProcessed--;
}
if (ALSource->state != AL_PLAYING)
@@ -1776,10 +1971,7 @@ ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint
}
if((ALuint)n > ALSource->BuffersPlayed)
{
ALSource->BuffersPlayed = 0;
ALSource->BufferPosition = 0;
}
else
ALSource->BuffersPlayed -= n;
}
@@ -1807,7 +1999,7 @@ ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint
}
static ALvoid InitSourceParams(ALsource *pSource)
static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource)
{
pSource->flInnerAngle = 360.0f;
pSource->flOuterAngle = 360.0f;
@@ -1829,6 +2021,16 @@ static ALvoid InitSourceParams(ALsource *pSource)
pSource->flMinGain = 0.0f;
pSource->flMaxGain = 1.0f;
pSource->flOuterGain = 0.0f;
pSource->OuterGainHF = 1.0f;
pSource->DryGainHFAuto = AL_TRUE;
pSource->WetGainAuto = AL_TRUE;
pSource->WetGainHFAuto = AL_TRUE;
pSource->AirAbsorptionFactor = 0.0f;
pSource->RoomRolloffFactor = 0.0f;
pSource->DopplerFactor = 1.0f;
pSource->DistanceModel = Context->DistanceModel;
pSource->state = AL_INITIAL;
pSource->lSourceType = AL_UNDETERMINED;
@@ -1843,32 +2045,40 @@ static ALvoid InitSourceParams(ALsource *pSource)
Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
The offset is relative to the start of the queue (not the start of the current buffer)
*/
static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
{
ALbufferlistitem *pBufferList;
ALbuffer *pBuffer;
ALfloat flBufferFreq;
ALint lBytesPlayed, lChannels;
ALint lChannels;
ALint readPos, writePos;
ALenum eOriginalFormat;
ALboolean bReturn = AL_TRUE;
ALint lTotalBufferDataSize;
if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID))
{
pBuffer = ALTHUNK_LOOKUPENTRY(pSource->ulBufferID);
// Get Current Buffer Size and frequency (in milliseconds)
flBufferFreq = (ALfloat)(((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->frequency);
eOriginalFormat = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->eOriginalFormat;
lChannels = ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->format == AL_FORMAT_MONO16)?1:2);
flBufferFreq = (ALfloat)pBuffer->frequency;
eOriginalFormat = pBuffer->eOriginalFormat;
lChannels = aluChannelsFromFormat(pBuffer->format);
// Get Current BytesPlayed
lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
// Add byte length of any processed buffers in the queue
pBufferList = pSource->queue;
while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
{
lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
readPos += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
pBufferList = pBufferList->next;
}
if(pSource->state == AL_PLAYING)
writePos = readPos + (updateSize * lChannels * 2);
else
writePos = readPos;
lTotalBufferDataSize = 0;
pBufferList = pSource->queue;
while (pBufferList)
@@ -1880,51 +2090,88 @@ static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOf
if (pSource->bLooping)
{
if (lBytesPlayed < 0)
lBytesPlayed = 0;
if(readPos < 0)
readPos = 0;
else
lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
readPos %= lTotalBufferDataSize;
if(writePos < 0)
writePos = 0;
else
writePos %= lTotalBufferDataSize;
}
else
{
// Clamp BytesPlayed to within 0 and lTotalBufferDataSize
if(lBytesPlayed < 0)
lBytesPlayed = 0;
if(lBytesPlayed > lTotalBufferDataSize)
lBytesPlayed = lTotalBufferDataSize;
if(readPos < 0)
readPos = 0;
else if(readPos > lTotalBufferDataSize)
readPos = lTotalBufferDataSize;
if(writePos < 0)
writePos = 0;
else if(writePos > lTotalBufferDataSize)
writePos = lTotalBufferDataSize;
}
switch (eName)
{
case AL_SEC_OFFSET:
*pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
case AL_SEC_RW_OFFSETS_EXT:
pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
break;
case AL_SAMPLE_OFFSET:
*pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
case AL_SAMPLE_RW_OFFSETS_EXT:
pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
break;
case AL_BYTE_OFFSET:
case AL_BYTE_RW_OFFSETS_EXT:
// Take into account the original format of the Buffer
if ((eOriginalFormat == AL_FORMAT_MONO8) || (eOriginalFormat == AL_FORMAT_STEREO8))
if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
(eOriginalFormat == AL_FORMAT_STEREO_IMA4))
{
*pflOffset = (ALfloat)(lBytesPlayed >> 1);
}
else if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) || (eOriginalFormat == AL_FORMAT_STEREO_IMA4))
{
// Compression rate of the ADPCM supported is 3.6111 to 1
lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
// Round down to nearest ADPCM block
*pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
pflOffset[0] = (ALfloat)((readPos / (65 * 2 * lChannels)) * 36 * lChannels);
if(pSource->state == AL_PLAYING)
{
// Round up to nearest ADPCM block
pflOffset[1] = (ALfloat)(((writePos + (65 * 2 * lChannels) - 1) / (65 * 2 * lChannels)) * 36 * lChannels);
}
else
pflOffset[1] = pflOffset[0];
}
else if (eOriginalFormat == AL_FORMAT_REAR8)
{
pflOffset[0] = (ALfloat)(readPos >> 2);
pflOffset[1] = (ALfloat)(writePos >> 2);
}
else if (eOriginalFormat == AL_FORMAT_REAR16)
{
pflOffset[0] = (ALfloat)(readPos >> 1);
pflOffset[1] = (ALfloat)(writePos >> 1);
}
else if (aluBytesFromFormat(eOriginalFormat) == 1)
{
pflOffset[0] = (ALfloat)(readPos >> 1);
pflOffset[1] = (ALfloat)(writePos >> 1);
}
else if (aluBytesFromFormat(eOriginalFormat) == 4)
{
pflOffset[0] = (ALfloat)(readPos << 1);
pflOffset[1] = (ALfloat)(writePos << 1);
}
else
{
*pflOffset = (ALfloat)lBytesPlayed;
pflOffset[0] = (ALfloat)readPos;
pflOffset[1] = (ALfloat)writePos;
}
break;
}
}
else
{
*pflOffset = 0.0f;
pflOffset[0] = 0.0f;
pflOffset[1] = 0.0f;
}
return bReturn;
@@ -1940,6 +2187,7 @@ static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOf
static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
{
ALbufferlistitem *pBufferList;
ALbuffer *pBuffer;
ALint lBufferSize, lTotalBufferSize;
ALint lByteOffset;
@@ -1953,10 +2201,10 @@ static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
pBufferList = pSource->queue;
lTotalBufferSize = 0;
pSource->BuffersPlayed = 0;
pSource->BuffersProcessed = 0;
while (pBufferList)
{
lBufferSize = pBufferList->buffer ? ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size : 0;
pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
lBufferSize = pBuffer ? pBuffer->size : 0;
if ((lTotalBufferSize + lBufferSize) <= lByteOffset)
{
@@ -1965,10 +2213,7 @@ static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
pSource->BuffersPlayed++;
if (!pSource->bLooping)
{
pBufferList->bufferstate = PROCESSED;
pSource->BuffersProcessed++;
}
}
else if (lTotalBufferSize <= lByteOffset)
{
@@ -1978,14 +2223,10 @@ static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
// Set Current Buffer ID
pSource->ulBufferID = pBufferList->buffer;
// Set current position in this buffer
pSource->BufferPosition = lByteOffset - lTotalBufferSize;
// Set Total Bytes Played to Offset
pSource->lBytesPlayed = lByteOffset;
// SW Mixer Positions are in Samples
pSource->position = pSource->BufferPosition / ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->format == AL_FORMAT_MONO16)?2:4);
pSource->position = (lByteOffset - lTotalBufferSize) /
aluBytesFromFormat(pBuffer->format) /
aluChannelsFromFormat(pBuffer->format);
}
else
{
@@ -2042,19 +2283,15 @@ static ALint GetByteOffset(ALsource *pSource)
if (pBuffer)
{
flBufferFreq = ((ALfloat)pBuffer->frequency);
lChannels = (pBuffer->format == AL_FORMAT_MONO16)?1:2;
lChannels = aluChannelsFromFormat(pBuffer->format);
// Determine the ByteOffset (and ensure it is block aligned)
switch (pSource->lOffsetType)
{
case AL_BYTE_OFFSET:
// Take into consideration the original format
if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO8) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO8))
{
lByteOffset = pSource->lOffset * 2;
lByteOffset -= (lByteOffset % (lChannels * 2));
}
else if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
(pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4))
{
// Round down to nearest ADPCM block
lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels;
@@ -2062,6 +2299,26 @@ static ALint GetByteOffset(ALsource *pSource)
lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset);
lByteOffset -= (lByteOffset % (lChannels * 2));
}
else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR8)
{
lByteOffset = pSource->lOffset * 4;
lByteOffset -= (lByteOffset % (lChannels * 2));
}
else if (pBuffer->eOriginalFormat == AL_FORMAT_REAR16)
{
lByteOffset = pSource->lOffset * 2;
lByteOffset -= (lByteOffset % (lChannels * 2));
}
else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 1)
{
lByteOffset = pSource->lOffset * 2;
lByteOffset -= (lByteOffset % (lChannels * 2));
}
else if (aluBytesFromFormat(pBuffer->eOriginalFormat) == 4)
{
lByteOffset = pSource->lOffset / 2;
lByteOffset -= (lByteOffset % (lChannels * 2));
}
else
{
lByteOffset = pSource->lOffset;
@@ -2096,3 +2353,24 @@ static ALint GetByteOffset(ALsource *pSource)
return lByteOffset;
}
ALvoid ReleaseALSources(ALCcontext *Context)
{
#ifdef _DEBUG
if(Context->SourceCount > 0)
AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", Context->SourceCount);
#endif
while(Context->Source)
{
ALsource *temp = Context->Source;
Context->Source = Context->Source->next;
// Release source structure
ALTHUNK_REMOVEENTRY(temp->source);
memset(temp, 0, sizeof(ALsource));
free(temp);
}
Context->SourceCount = 0;
}
+7 -1
View File
@@ -18,14 +18,17 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include "alMain.h"
#include "AL/alc.h"
#include "alError.h"
#include "alSource.h"
#include "alState.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
@@ -642,6 +645,7 @@ ALAPI ALvoid ALAPIENTRY alSpeedOfSound(ALfloat flSpeedOfSound)
ALAPI ALvoid ALAPIENTRY alDistanceModel(ALenum value)
{
ALCcontext *Context;
ALsource *Source;
Context=alcGetCurrentContext();
if (Context)
@@ -658,6 +662,8 @@ ALAPI ALvoid ALAPIENTRY alDistanceModel(ALenum value)
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;
default:
+2
View File
@@ -18,6 +18,8 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include "alMain.h"
+24
View File
@@ -0,0 +1,24 @@
# 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 CMakeConf/
# 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)
+11
View File
@@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: OpenAL
Description: OpenAL is a cross-platform 3D audio API
Requires: @PKG_CONFIG_REQUIRES@
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -l@LIBNAME@ @PKG_CONFIG_LIBS@
Cflags: -I${includedir}
+214
View File
@@ -0,0 +1,214 @@
# OpenAL config file. Options that are not under a block or are under the
# [general] block are for general, non-backend-specific options. Blocks may
# appear multiple times, and duplicated options will take the last value
# specified.
# 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:
## 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)
#format = AL_FORMAT_STEREO16
## 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:
# Sets the output frequency.
#frequency = 44100
## refresh:
# Sets the buffer size, in frames. Note that the actual granularity may or may
# not be less than this.
#refresh = 4096
## 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
## 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
## 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
## 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 =
## 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
## 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
## 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
## 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
## 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
## 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
## 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
##
## ALSA backend stuff
##
[alsa]
## device:
# Sets the device name for the default playback device.
#device = default
## periods:
# Sets the number of update buffers for playback. A value of 0 means auto-
# select.
#periods = 0
## 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
## periods:
# Sets the number of update buffers.
#periods = 4
## 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]
## periods:
# Sets the number of updates for the output buffer.
#periods = 4
##
## 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
## periods:
# Sets the number of update buffers.
#periods = 4
##
## 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 =
+36
View File
@@ -1,24 +1,45 @@
#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
/* Define if we have the sqrtf function */
#cmakedefine HAVE_SQRTF
/* 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
@@ -43,4 +64,19 @@
/* Define if we have GCC's destructor attribute */
#cmakedefine HAVE_GCC_DESTRUCTOR
/* 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
+294
View File
@@ -0,0 +1,294 @@
/*
* openal-info: Display information about ALC and AL.
*
* Idea based on glxinfo for OpenGL.
* Initial OpenAL version by Erik Hofman <erik@ehofman.com>.
* Further hacked by Sven Panne <sven.panne@aedion.de>.
* More work (clean up) by Chris Robinson <chris.kcat@gmail.com>.
*
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include "AL/alc.h"
#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;
static void printChar(int c, int *width)
{
putchar(c);
*width = ((c == '\n') ? 0 : ((*width) + 1));
}
static void indent(int *width)
{
int i;
for(i = 0; i < indentation; i++)
printChar(' ', width);
}
static void printExtensions(const char *header, char separator, const char *extensions)
{
int width = 0, start = 0, end = 0;
printf("%s:\n", header);
if(extensions == NULL || extensions[0] == '\0')
return;
indent(&width);
while (1)
{
if(extensions[end] == separator || extensions[end] == '\0')
{
if(width + end - start + 2 > maxmimumWidth)
{
printChar('\n', &width);
indent(&width);
}
while(start < end)
{
printChar(extensions[start], &width);
start++;
}
if(extensions[end] == '\0')
break;
start++;
end++;
if(extensions[end] == '\0')
break;
printChar(',', &width);
printChar(' ', &width);
}
end++;
}
printChar('\n', &width);
}
static void die(const char *kind, const char *description)
{
fprintf(stderr, "%s error %s occured\n", kind, description);
exit(EXIT_FAILURE);
}
static void checkForErrors(void)
{
{
ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext());
ALCenum error = alcGetError(device);
if(error != ALC_NO_ERROR)
die("ALC", (const char*)alcGetString(device, error));
}
{
ALenum error = alGetError();
if(error != AL_NO_ERROR)
die("AL", (const char*)alGetString(error));
}
}
static void printDevices(ALCenum which, const char *kind)
{
const char *s = alcGetString(NULL, which);
checkForErrors();
printf("Available %sdevices:\n", kind);
while(*s != '\0')
{
printf(" %s\n", s);
while(*s++ != '\0')
;
}
}
static void printALCInfo (void)
{
ALCint major, minor;
ALCdevice *device;
if(alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE)
{
if(alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATE_ALL_EXT") == AL_TRUE)
printDevices(ALC_ALL_DEVICES_SPECIFIER, "playback ");
else
printDevices(ALC_DEVICE_SPECIFIER, "playback ");
printDevices(ALC_CAPTURE_DEVICE_SPECIFIER, "capture ");
}
else
printf("No device enumeration available\n");
device = alcGetContextsDevice(alcGetCurrentContext());
checkForErrors();
printf("Default device: %s\n",
alcGetString(device, ALC_DEFAULT_DEVICE_SPECIFIER));
printf("Default capture device: %s\n",
alcGetString(device, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
checkForErrors();
printf("ALC version: %d.%d\n", (int)major, (int)minor);
printExtensions("ALC extensions", ' ',
alcGetString(device, ALC_EXTENSIONS));
checkForErrors();
}
static void printALInfo(void)
{
printf("OpenAL vendor string: %s\n", alGetString(AL_VENDOR));
printf("OpenAL renderer string: %s\n", alGetString(AL_RENDERER));
printf("OpenAL version string: %s\n", alGetString(AL_VERSION));
printExtensions("OpenAL extensions", ' ', alGetString(AL_EXTENSIONS));
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);
ALCcontext *context = alcCreateContext(device, NULL);
alcMakeContextCurrent(context);
checkForErrors();
printALCInfo();
printALInfo();
printEFXInfo();
checkForErrors();
alcMakeContextCurrent(NULL);
alcDestroyContext(context);
alcCloseDevice(device);
return EXIT_SUCCESS;
}
-5
View File
@@ -166,11 +166,6 @@ typedef void ALCvoid;
#define ALC_ATTRIBUTES_SIZE 0x1002
#define ALC_ALL_ATTRIBUTES 0x1003
/**
* ALC_ENUMERATE_ALL_EXT enums
*/
#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
#define ALC_ALL_DEVICES_SPECIFIER 0x1013
/**
* Capture extension
+106
View File
@@ -0,0 +1,106 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2008 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
*/
#ifndef AL_ALEXT_H
#define AL_ALEXT_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef AL_LOKI_IMA_ADPCM_format
#define AL_LOKI_IMA_ADPCM_format 1
#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000
#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001
#endif
#ifndef AL_LOKI_WAVE_format
#define AL_LOKI_WAVE_format 1
#define AL_FORMAT_WAVE_EXT 0x10002
#endif
#ifndef AL_EXT_vorbis
#define AL_EXT_vorbis 1
#define AL_FORMAT_VORBIS_EXT 0x10003
#endif
#ifndef AL_LOKI_quadriphonic
#define AL_LOKI_quadriphonic 1
#define AL_FORMAT_QUAD8_LOKI 0x10004
#define AL_FORMAT_QUAD16_LOKI 0x10005
#endif
#ifndef AL_EXT_float32
#define AL_EXT_float32 1
#define AL_FORMAT_MONO_FLOAT32 0x10010
#define AL_FORMAT_STEREO_FLOAT32 0x10011
#endif
#ifndef ALC_LOKI_audio_channel
#define ALC_LOKI_audio_channel 1
#define ALC_CHAN_MAIN_LOKI 0x500001
#define ALC_CHAN_PCM_LOKI 0x500002
#define ALC_CHAN_CD_LOKI 0x500003
#endif
#ifndef ALC_ENUMERATE_ALL_EXT
#define ALC_ENUMERATE_ALL_EXT 1
#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
#define ALC_ALL_DEVICES_SPECIFIER 0x1013
#endif
#ifndef AL_EXT_MCFORMATS
#define AL_EXT_MCFORMATS 1
#define AL_FORMAT_QUAD8 0x1204
#define AL_FORMAT_QUAD16 0x1205
#define AL_FORMAT_QUAD32 0x1206
#define AL_FORMAT_REAR8 0x1207
#define AL_FORMAT_REAR16 0x1208
#define AL_FORMAT_REAR32 0x1209
#define AL_FORMAT_51CHN8 0x120A
#define AL_FORMAT_51CHN16 0x120B
#define AL_FORMAT_51CHN32 0x120C
#define AL_FORMAT_61CHN8 0x120D
#define AL_FORMAT_61CHN16 0x120E
#define AL_FORMAT_61CHN32 0x120F
#define AL_FORMAT_71CHN8 0x1210
#define AL_FORMAT_71CHN16 0x1211
#define AL_FORMAT_71CHN32 0x1212
#endif
#ifndef AL_EXT_IMA4
#define AL_EXT_IMA4 1
#define AL_FORMAT_MONO_IMA4 0x1300
#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
#ifdef __cplusplus
}
#endif
#endif
-50
View File
@@ -1,50 +0,0 @@
# OpenAL config file. Options that are not under a block or are under the
# [general] block are for general, non-backend-specific options. Blocks may
# appear multiple times, and duplicated options will take the last value
# specified. The system-wide settings can be put in /etc/openal/config and
# user-specific override settings in ~/.openalrc
# 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:
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_MONO16 (16-bit mono)
# AL_FORMAT_STEREO16 (16-bit stereo)
# AL_FORMAT_QUAD16 (16-bit 4-channel)
# Default is AL_FORMAT_STEREO16
frequency = 44100 # Sets the output frequency. Default is 44100
refresh = 0 # Sets the number of frames-per-update. Default is calculated as
# 8192*frequency/22050. Note that the actual granularity may or
# may not be less than this.
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
[alsa] # ALSA backend stuff
device = default # Sets the device name for the default playback device.
# Default is default
periods = 4 # Sets the number of update buffers. Default is 4
capture = default # Sets the device name for the default capture device.
# Default is default
[oss] # OSS backend stuff
device = /dev/dsp # Sets the device name for OSS output. Default is /dev/dsp
periods = 4 # Sets the number of update buffers. Default is 4
[dsound] # DirectSound backend stuff
# Nothing yet...
[winmm] # Windows Multimedia backend stuff
# Nothing yet...