Compare commits

...

279 Commits

Author SHA1 Message Date
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 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 9ed574b399 Merge branch 'master' into efx-experiment 2008-01-01 06:29:11 -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 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 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
40 changed files with 6386 additions and 1661 deletions
+311 -96
View File
@@ -26,12 +26,16 @@
#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"
#include "alThunk.h"
#include "alSource.h"
#include "alBuffer.h"
#include "alExtension.h"
#include "alAuxEffectSlot.h"
#include "bs2b.h"
///////////////////////////////////////////////////////
@@ -43,7 +47,7 @@ char _alDebug[256];
#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
struct {
static struct {
const char *name;
void (*Init)(BackendFuncs*);
BackendFuncs Funcs;
@@ -54,6 +58,9 @@ 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
@@ -61,35 +68,27 @@ struct {
{ "winmm", alcWinMMInit, EmptyFuncs },
#endif
{ "wave", alc_wave_init, EmptyFuncs },
{ NULL, NULL, EmptyFuncs }
};
#undef EmptyFuncs
///////////////////////////////////////////////////////
#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 },
@@ -136,9 +135,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 },
@@ -166,16 +170,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;
@@ -183,21 +195,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(&_alMutex);
init_done = AL_TRUE;
InitializeCriticalSection(&g_csMutex);
ALTHUNK_INIT();
ReadALConfig();
@@ -243,31 +303,82 @@ 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[] = {
{ "reverb", REVERB },
{ 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;
}
@@ -307,7 +418,7 @@ ALCvoid SetALCError(ALenum errorCode)
ALCvoid SuspendContext(ALCcontext *pContext)
{
(void)pContext;
EnterCriticalSection(&_alMutex);
EnterCriticalSection(&g_csMutex);
}
@@ -319,7 +430,7 @@ ALCvoid SuspendContext(ALCcontext *pContext)
ALCvoid ProcessContext(ALCcontext *pContext)
{
(void)pContext;
LeaveCriticalSection(&_alMutex);
LeaveCriticalSection(&g_csMutex);
}
@@ -334,6 +445,7 @@ static ALvoid InitContext(ALCcontext *pContext)
//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;
@@ -363,7 +475,7 @@ static ALvoid InitContext(ALCcontext *pContext)
pContext->lNumStereoSources = 1;
pContext->lNumMonoSources = pContext->Device->MaxNoOfSources - pContext->lNumStereoSources;
strcpy(pContext->ExtensionList, "AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET");
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_LOKI_quadriphonic";
level = GetConfigValueInt(NULL, "cf_level", 0);
if(level > 0 && level <= 6)
@@ -382,26 +494,6 @@ 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;
@@ -426,42 +518,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;
}
@@ -475,9 +571,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);
@@ -685,13 +793,34 @@ 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
*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:
@@ -707,19 +836,22 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize
data[i++] = device->Frequency;
data[i++] = ALC_REFRESH;
data[i++] = device->Frequency / 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++] = MAX_SENDS;
}
ProcessContext(NULL);
@@ -742,7 +874,7 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize
else if(!size)
SetALCError(ALC_INVALID_VALUE);
else
*data = device->Frequency / device->UpdateFreq;
*data = device->Frequency / device->UpdateSize;
break;
case ALC_SYNC:
@@ -754,6 +886,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;
@@ -775,18 +925,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);
@@ -926,6 +1089,8 @@ ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context)
{
ALCcontext **list;
InitAL();
// Lock context list
SuspendContext(NULL);
@@ -934,6 +1099,9 @@ ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context)
// Lock context
SuspendContext(context);
ReleaseALSources(context);
ReleaseALAuxiliaryEffectSlots(context);
context->Device->Context = NULL;
list = &g_pContextList;
@@ -968,6 +1136,8 @@ ALCAPI ALCcontext * ALCAPIENTRY alcGetCurrentContext(ALCvoid)
{
ALCcontext *pContext = NULL;
InitAL();
SuspendContext(NULL);
pContext = g_pContextList;
@@ -989,6 +1159,8 @@ ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext *pContext)
{
ALCdevice *pDevice = NULL;
InitAL();
SuspendContext(NULL);
if (IsContext(pContext))
pDevice = pContext->Device;
@@ -1010,6 +1182,8 @@ ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context)
ALCcontext *ALContext;
ALboolean bReturn = AL_TRUE;
InitAL();
SuspendContext(NULL);
// context must be a valid Context or NULL
@@ -1066,7 +1240,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
@@ -1078,20 +1251,16 @@ 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;
// Find a playback device to open
for(i = 0;BackendList[i].Init;i++)
@@ -1099,6 +1268,12 @@ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName)
device->Funcs = &BackendList[i].Funcs;
if(ALCdevice_OpenPlayback(device, deviceName))
{
SuspendContext(NULL);
device->next = g_pDeviceList;
g_pDeviceList = device;
g_ulDeviceCount++;
ProcessContext(NULL);
bDeviceFound = AL_TRUE;
break;
}
@@ -1107,10 +1282,13 @@ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName)
if (!bDeviceFound)
{
// No suitable output device found
SetALCError(ALC_INVALID_VALUE);
free(device);
device = NULL;
}
}
else
SetALCError(ALC_OUT_OF_MEMORY);
return device;
}
@@ -1124,9 +1302,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
@@ -1140,4 +1337,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);
}
}
///////////////////////////////////////////////////////
+805 -555
View File
File diff suppressed because it is too large Load Diff
+44 -2
View File
@@ -18,6 +18,8 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
@@ -25,6 +27,11 @@
#include "alMain.h"
#ifdef _WIN32
#define _WIN32_IE 0x400
#include <shlobj.h>
#endif
typedef struct ConfigEntry {
char *key;
char *value;
@@ -199,8 +206,26 @@ 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)
{
f = fopen("/etc/openal/config", "r");
if(f)
AL_PRINT("Reading /etc/openal/config; this file is deprecated\n"
"\tPlease rename it to /etc/openal/alsoft.conf\n");
}
if(f)
{
LoadConfigFromFile(f);
@@ -208,8 +233,16 @@ 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)
{
snprintf(buffer, sizeof(buffer), "%s/.openalrc", getenv("HOME"));
f = fopen(buffer, "r");
if(f)
AL_PRINT("Reading ~/.openalrc; this file is deprecated\n"
"\tPlease rename it to ~/.alsoftrc\n");
}
if(f)
{
LoadConfigFromFile(f);
@@ -217,6 +250,15 @@ void ReadALConfig(void)
}
}
#endif
if(getenv("ALSOFT_CONF"))
{
f = fopen(getenv("ALSOFT_CONF"), "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
}
void FreeALConfig(void)
+559
View File
@@ -0,0 +1,559 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2008 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 "alReverb.h"
#ifdef HAVE_SQRTF
#define aluSqrt(x) ((ALfloat)sqrtf((float)(x)))
#else
#define aluSqrt(x) ((ALfloat)sqrt((double)(x)))
#endif
// fixes for mingw32.
#if defined(max) && !defined(__max)
#define __max max
#endif
#if defined(min) && !defined(__min)
#define __min min
#endif
typedef struct DelayLine
{
// The delay lines use lengths that are powers of 2 to allow bitmasking
// instead of modulus wrapping.
ALuint Mask;
ALfloat *Line;
} DelayLine;
struct ALverbState
{
// All delay lines are allocated as a single buffer to reduce memory
// fragmentation and teardown code.
ALfloat *SampleBuffer;
// Master reverb gain.
ALfloat Gain;
// Initial reverb delay.
DelayLine Delay;
// The tap points for the initial delay. First tap goes to early
// reflections, the second to late reverb.
ALuint Tap[2];
struct {
// Gain for early reflections.
ALfloat Gain;
// Early reflections are done with 4 delay lines.
ALfloat Coeff[4];
DelayLine Delay[4];
ALuint Offset[4];
} Early;
struct {
// Gain for late reverb.
ALfloat Gain;
// Diffusion of late reverb.
ALfloat Diffusion;
// Late reverb is done with 8 delay lines.
ALfloat Coeff[8];
DelayLine Delay[8];
ALuint Offset[8];
// The input and last 4 delay lines are low-pass filtered.
ALfloat LpCoeff[5];
ALfloat LpSample[5];
} Late;
ALuint Offset;
};
// All delay line lengths are specified in seconds.
// The length of the initial delay line (a sum of the maximum delay before
// early reflections and late reverb; 0.3 + 0.1).
static const ALfloat MASTER_LINE_LENGTH = 0.4000f;
// 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 delay lines.
static const ALfloat LATE_LINE_LENGTH[8] =
{
0.0015f, 0.0037f, 0.0093f, 0.0234f,
0.0100f, 0.0150f, 0.0225f, 0.0337f
};
// The last 4 late delay lines have a variable length dependent on the effect
// density parameter and this multiplier.
static const ALfloat LATE_LINE_MULTIPLIER = 9.0f;
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 a decorrelated 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 FDN.
* N
* ---
* \
* v = 2/N / di
* ---
* 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]);
// To decorrelate the output for stereo separation, the two outputs are
// obtained from the inner delay lines.
// Output is instant by using the inputs to them instead of taking the
// result of the two delay lines directly (f[0] and f[3] instead of d[1]
// and d[2]).
out[0] = State->Early.Gain * f[0];
out[1] = State->Early.Gain * f[3];
}
// 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 an input sample, this function produces a decorrelated stereo output
// for late reverb.
static __inline ALvoid LateReverb(ALverbState *State, ALfloat in, ALfloat *out)
{
ALfloat din, d[8], v, dv, f[8];
// Since the input will be sent directly to the output as in the early
// reflections function, it needs to take into account some immediate
// absorption.
in = LateLowPassInOut(State, 0, in);
// When diffusion is full, no input is directly passed to the variable-
// length delay lines (the last 4).
din = (1.0f - State->Late.Diffusion) * in;
// Obtain the decayed results of the fixed-length delay lines.
d[0] = LateDelayLineOut(State, 0);
d[1] = LateDelayLineOut(State, 1);
d[2] = LateDelayLineOut(State, 2);
d[3] = LateDelayLineOut(State, 3);
// Obtain the decayed and low-pass filtered results of the variable-
// length delay lines.
d[4] = LateLowPassInOut(State, 1, LateDelayLineOut(State, 4));
d[5] = LateLowPassInOut(State, 2, LateDelayLineOut(State, 5));
d[6] = LateLowPassInOut(State, 3, LateDelayLineOut(State, 6));
d[7] = LateLowPassInOut(State, 4, LateDelayLineOut(State, 7));
// The waveguide formula used in the early reflections function works
// great for high diffusion, but it is not obviously paramerized to allow
// a variable diffusion. With only limited time and resources, what
// follows is the best variation of that formula I could come up with.
// First, there are 8 delay lines used. The first 4 are fixed-length and
// generate the highest density of the diffuse response. The last 4 are
// variable-length, and are used to smooth out the diffuse response. The
// density effect parameter alters their length. The inner two delay
// lines of each group have their signs reversed (more about this later).
v = (d[0] - d[1] - d[2] + d[3] +
d[4] - d[5] - d[6] + d[7]) * 0.25f;
// Diffusion is applied as a reduction of the junction pressure for all
// branches. This presents two problems. When the diffusion factor (0
// to 1) reaches 0.5, the average feed value is reduced (the junction
// becomes lossy). Thus, at 0.5 the signal decays almost twice as fast
// as it should. The second problem is the introduction of some
// resonant frequencies (coloration). The reversed signs above are used
// to help combat some of the coloration by adding variations along the
// feed cycle.
v *= State->Late.Diffusion;
// Load the junction with the input. To reduce the noticeable echo of
// the longer delay lines (the variable-length ones) the input is loaded
// with the inverse of the effect diffusion. So at full diffusion, the
// input is not applied to the last 4 delay lines. Input signs reversed
// to balance the equation.
dv = v + din;
v += in;
// As with the reversed signs above, to balance the equation the signs
// need to be reversed here, too.
f[0] = d[0] - v;
f[1] = d[1] + v;
f[2] = d[2] + v;
f[3] = d[3] - v;
f[4] = d[4] - dv;
f[5] = d[5] + dv;
f[6] = d[6] + dv;
f[7] = d[7] - dv;
// Feed the fixed-length delay lines with their own cycle (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]);
// Feed the variable-length delay lines with their cycle (4 -> 6 -> 7 ->
// 5 -> 4...).
DelayLineIn(&State->Late.Delay[4], State->Offset, f[5]);
DelayLineIn(&State->Late.Delay[5], State->Offset, f[7]);
DelayLineIn(&State->Late.Delay[6], State->Offset, f[4]);
DelayLineIn(&State->Late.Delay[7], State->Offset, f[6]);
// Output is derived from the values fed to the inner two variable-length
// delay lines (5 and 6).
out[0] = State->Late.Gain * f[7];
out[1] = State->Late.Gain * f[4];
}
// 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.
ALverbState *VerbCreate(ALCcontext *Context)
{
ALverbState *State = NULL;
ALuint length[13], totalLength, index;
State = malloc(sizeof(ALverbState));
if(!State)
return NULL;
// All line lengths are powers of 2, calculated from the line timings and
// the addition of an extra sample (for safety).
length[0] = NextPowerOf2((ALuint)(MASTER_LINE_LENGTH*Context->Frequency) + 1);
totalLength = length[0];
for(index = 0;index < 4;index++)
{
length[1+index] = NextPowerOf2((ALuint)(EARLY_LINE_LENGTH[index]*Context->Frequency) + 1);
totalLength += length[1+index];
}
for(index = 0;index < 4;index++)
{
length[5+index] = NextPowerOf2((ALuint)(LATE_LINE_LENGTH[index]*Context->Frequency) + 1);
totalLength += length[5+index];
}
for(index = 4;index < 8;index++)
{
length[5+index] = NextPowerOf2((ALuint)(LATE_LINE_LENGTH[index]*(1.0f + LATE_LINE_MULTIPLIER)*Context->Frequency) + 1);
totalLength += length[5+index];
}
// They all share a single sample buffer.
State->SampleBuffer = malloc(totalLength * sizeof(ALfloat));
if(!State->SampleBuffer)
{
free(State);
return NULL;
}
for(index = 0; index < totalLength;index++)
State->SampleBuffer[index] = 0.0f;
// Each one has its mask and start address calculated one time.
State->Gain = 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->Early.Gain = 0.0f;
// All fixed-length delay lines have their read-write offsets calculated
// one time.
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];
State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] * Context->Frequency);
}
State->Late.Gain = 0.0f;
State->Late.Diffusion = 0.0f;
for(index = 0;index < 8;index++)
{
State->Late.Coeff[index] = 0.0f;
State->Late.Delay[index].Mask = length[5 + index] - 1;
State->Late.Delay[index].Line = &State->SampleBuffer[totalLength];
totalLength += length[5 + index];
State->Late.Offset[index] = 0;
if(index < 4)
{
State->Late.Offset[index] = (ALuint)(LATE_LINE_LENGTH[index] * Context->Frequency);
State->Late.LpCoeff[index] = 0.0f;
State->Late.LpSample[index] = 0.0f;
}
else if(index == 4)
{
State->Late.LpCoeff[index] = 0.0f;
State->Late.LpSample[index] = 0.0f;
}
}
State->Offset = 0;
return State;
}
// 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(ALverbState *State)
{
if(State)
{
free(State->SampleBuffer);
State->SampleBuffer = NULL;
free(State);
}
}
// This updates the reverb state. This is called any time the reverb effect
// is loaded into a slot.
ALvoid VerbUpdate(ALCcontext *Context, ALeffectslot *Slot, ALeffect *Effect)
{
ALverbState *State = Slot->ReverbState;
ALuint index, index2;
ALfloat length, lpcoeff, cw, g;
ALfloat hfRatio = Effect->Reverb.DecayHFRatio;
// Calculate the master gain (from the slot and master reverb gain).
State->Gain = Slot->Gain * Effect->Reverb.Gain;
// Calculate the initial delay taps.
length = Effect->Reverb.ReflectionsDelay;
State->Tap[0] = (ALuint)(length * Context->Frequency);
length += Effect->Reverb.LateReverbDelay;
State->Tap[1] = (ALuint)(length * Context->Frequency);
// Calculate the early reflections gain. Right now this uses a gain of
// 0.75 to compensate for the increase in density. It should probably
// use a power (RMS) based measurement from the resulting distribution of
// early delay lines.
State->Early.Gain = Effect->Reverb.ReflectionsGain * 0.75f;
// 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 late reverb gain, adjusted by density, diffusion, and
// decay time. To be accurate, the adjustments should probably use power
// measurements for each contribution, but they are not too bad as they
// are.
State->Late.Gain = Effect->Reverb.LateReverbGain *
(0.45f + (0.55f * Effect->Reverb.Density)) *
(1.0f - (0.25f * Effect->Reverb.Diffusion)) *
(1.0f - (0.025f * Effect->Reverb.DecayTime));
State->Late.Diffusion = Effect->Reverb.Diffusion;
// The EFX specification does not make it clear whether the air
// absorption parameter should always take effect. Both Generic Software
// and Generic Hardware only apply it when HF limit is flagged, so that's
// what is done here.
// 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;
// The following is my best guess at how to limit the HF ratio by the
// air absorption parameter.
// For each of the last 4 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);
}
cw = cos(2.0f*3.141592654f * LOWPASSFREQCUTOFF / Context->Frequency);
for(index = 0;index < 8;index++)
{
// Calculate the length (in seconds) of each delay line.
length = LATE_LINE_LENGTH[index];
if(index >= 4)
{
// Calculate the delay offset for the variable-length delay
// lines.
length *= 1.0f + (Effect->Reverb.Density * LATE_LINE_MULTIPLIER);
State->Late.Offset[index] = (ALuint)(length * Context->Frequency);
}
// Calculate the gain (coefficient) for each line.
State->Late.Coeff[index] = pow(10.0f, length / Effect->Reverb.DecayTime *
-60.0f / 20.0f);
if(index >= 4)
{
index2 = index - 3;
// 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.
lpcoeff = 0.0f;
if(g < 0.9999f) // 1-epsilon
lpcoeff = (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.
State->Late.LpCoeff[index2] = __min(lpcoeff, 0.98f);
}
}
// This just calculates the coefficient for the late reverb input low-
// pass filter. It is calculated based the average (hence -30 instead
// of -60) length of the inner two variable-length delay lines.
length = LATE_LINE_LENGTH[5] * (1.0f + Effect->Reverb.Density * LATE_LINE_MULTIPLIER) +
LATE_LINE_LENGTH[6] * (1.0f + Effect->Reverb.Density * LATE_LINE_MULTIPLIER);
g = pow(10.0f, ((length / (Effect->Reverb.DecayTime * hfRatio))-
(length / Effect->Reverb.DecayTime)) * -30.0f / 20.0f);
g = __max(g, 0.1f);
g *= g;
lpcoeff = 0.0f;
if(g < 0.9999f) // 1-epsilon
lpcoeff = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
State->Late.LpCoeff[0] = __min(lpcoeff, 0.98f);
}
// This processes the reverb state, given the input samples and an output
// buffer.
ALvoid VerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
{
ALuint index;
ALfloat in, early[2], late[2], out[2];
for(index = 0;index < SamplesToDo;index++)
{
// Feed the initial delay line.
DelayLineIn(&State->Delay, State->Offset, SamplesIn[index]);
// 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 second delay tap.
in = DelayLineOut(&State->Delay, State->Offset - State->Tap[1]);
LateReverb(State, in, late);
// Mix early reflections and late reverb.
out[0] = State->Gain * (early[0] + late[0]);
out[1] = State->Gain * (early[1] + late[1]);
// Step all delays forward one sample.
State->Offset++;
// Output the results.
SamplesOut[index][FRONT_LEFT] += out[0];
SamplesOut[index][FRONT_RIGHT] += out[1];
SamplesOut[index][SIDE_LEFT] += out[0];
SamplesOut[index][SIDE_RIGHT] += out[1];
SamplesOut[index][BACK_LEFT] += out[0];
SamplesOut[index][BACK_RIGHT] += out[1];
}
}
+9 -4
View File
@@ -18,11 +18,11 @@
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include "config.h"
#include "alMain.h"
@@ -70,7 +70,13 @@ void DestroyRingBuffer(RingBuffer *ring)
ALsizei RingBufferSize(RingBuffer *ring)
{
return (ring->write_pos-ring->read_pos-1+ring->length) % ring->length;
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)
@@ -115,4 +121,3 @@ void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
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
+287 -112
View File
@@ -40,7 +40,10 @@ typedef struct {
ALvoid *buffer;
ALsizei size;
int killNow;
RingBuffer *ring;
int doCapture;
volatile int killNow;
ALvoid *thread;
} alsa_data;
@@ -67,16 +70,20 @@ 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_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);
@@ -101,27 +108,23 @@ MAKE_FUNC(snd_card_next);
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));
}
@@ -177,7 +180,19 @@ static ALuint ALSAProc(ALvoid *ptr)
// make sure there's frames to process
if(avail == 0)
{
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;
}
@@ -239,9 +254,8 @@ static ALuint ALSANoMMapProc(ALvoid *ptr)
case -EAGAIN:
continue;
case -ESTRPIPE:
do {
ret = psnd_pcm_resume(data->pcmHandle);
} while(ret == -EAGAIN);
while((ret=psnd_pcm_resume(data->pcmHandle)) == -EAGAIN)
Sleep(1);
break;
case -EPIPE:
break;
@@ -265,53 +279,40 @@ static ALuint ALSANoMMapProc(ALvoid *ptr)
return 0;
}
static void fill_silence(snd_pcm_t *pcmHandle, snd_pcm_format_t alsaFormat, int channels)
static ALuint ALSANoMMapCaptureProc(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;
avail = psnd_pcm_avail_update(pcmHandle);
if(avail < 0)
while(!data->killNow)
{
err = xrun_recovery(pcmHandle, avail);
if (err < 0)
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)
{
AL_PRINT("available update failed: %s\n", psnd_strerror(err));
return;
}
}
// 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)
{
err = xrun_recovery(pcmHandle, err);
if (err < 0)
{
AL_PRINT("mmap begin error: %s\n", psnd_strerror(err));
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;
}
continue;
}
psnd_pcm_areas_silence(areas, offset, channels, frames, alsaFormat);
commitres = psnd_pcm_mmap_commit(pcmHandle, offset, frames);
if (commitres < 0 || (commitres-frames) != 0)
if(avail < 0)
{
AL_PRINT("mmap commit error: %s\n",
psnd_strerror(commitres >= 0 ? -EPIPE : commitres));
break;
avail = psnd_pcm_prepare(data->pcmHandle);
if(avail < 0)
AL_PRINT("prepare error: %s\n", psnd_strerror(avail));
}
avail -= frames;
}
return 0;
}
static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
@@ -322,9 +323,14 @@ static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceNam
unsigned int periods;
alsa_data *data;
char driver[64];
const char *str;
int allowmmap;
char *err;
int i;
if(!alsa_handle)
return ALC_FALSE;
strncpy(driver, GetConfigValue("alsa", "device", "default"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(deviceName)
@@ -364,7 +370,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)
@@ -393,24 +399,28 @@ 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;
periods = GetConfigValueInt("alsa", "periods", 0);
bufferSizeInFrames = device->UpdateSize;
str = GetConfigValue("alsa", "mmap", "true");
allowmmap = (strcasecmp(str, "true") == 0 ||
strcasecmp(str, "yes") == 0 ||
strcasecmp(str, "on") == 0 ||
atoi(str) != 0);
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") ||
((allowmmap && ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED), "set access")) ||
ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_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") &&
ok(psnd_pcm_hw_params_set_channels(data->pcmHandle, p, aluChannelsFromFormat(device->Format)), "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") &&
(!periods || 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) */
@@ -435,12 +445,20 @@ open_alsa:
return ALC_FALSE;
}
if((i=psnd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0)
{
AL_PRINT("get_period_size failed: %s\n", psnd_strerror(i));
psnd_pcm_hw_params_free(p);
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
psnd_pcm_hw_params_free(p);
device->MaxNoOfSources = 256;
device->UpdateFreq = bufferSizeInFrames;
device->UpdateSize = bufferSizeInFrames;
data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateFreq);
data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize);
if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
{
data->buffer = malloc(data->size);
@@ -463,18 +481,6 @@ open_alsa:
free(data);
return ALC_FALSE;
}
fill_silence(data->pcmHandle, data->format, device->Channels);
i = psnd_pcm_start(data->pcmHandle);
if(i < 0)
{
AL_PRINT("start error: %s\n", psnd_strerror(i));
psnd_pcm_close(data->pcmHandle);
free(data->buffer);
free(data);
return ALC_FALSE;
}
}
device->ExtraData = data;
@@ -484,6 +490,7 @@ open_alsa:
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);
@@ -511,34 +518,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;
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));
@@ -546,7 +558,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)
@@ -575,20 +587,24 @@ open_alsa:
AL_PRINT("Unknown format?! %x\n", format);
}
bufferSizeInFrames = SampleSize / periods;
str = GetConfigValue("alsa", "mmap", "true");
allowmmap = (strcasecmp(str, "true") == 0 ||
strcasecmp(str, "yes") == 0 ||
strcasecmp(str, "on") == 0 ||
atoi(str) != 0);
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") &&
if(!(allowmmap &&
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") &&
ok(psnd_pcm_hw_params_set_channels(data->pcmHandle, p, aluChannelsFromFormat(pDevice->Format)), "set channels") &&
/* 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) */
@@ -596,31 +612,109 @@ open_alsa:
/* install and prepare hardware configuration */
ok(psnd_pcm_hw_params(data->pcmHandle, p), "set params")))
{
AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
if(i < 0)
AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
bufferSizeInFrames = SampleSize;
if(!(ok(psnd_pcm_hw_params_any(data->pcmHandle, p), "any") &&
ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED), "set access") &&
ok(psnd_pcm_hw_params_set_format(data->pcmHandle, p, alsaFormat), "set format") &&
ok(psnd_pcm_hw_params_set_channels(data->pcmHandle, p, aluChannelsFromFormat(pDevice->Format)), "set channels") &&
ok(psnd_pcm_hw_params_set_rate(data->pcmHandle, p, frequency, 0), "set rate") &&
ok(psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames), "set buffer size near") &&
ok(psnd_pcm_hw_params(data->pcmHandle, p), "set params")))
{
AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
psnd_pcm_hw_params_free(p);
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
}
#undef ok
if((i=psnd_pcm_hw_params_get_access(p, &access)) < 0)
{
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;
}
#undef ok
psnd_pcm_hw_params_free(p);
i = psnd_pcm_prepare(data->pcmHandle);
if(i < 0)
if((i=psnd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0)
{
AL_PRINT("prepare error: %s\n", psnd_strerror(i));
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);
@@ -630,13 +724,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)
@@ -645,8 +746,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)
{
@@ -682,7 +804,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;
@@ -702,16 +824,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);
}
@@ -758,7 +901,7 @@ void alc_alsa_init(BackendFuncs *func_list)
} while(0)
#else
str = NULL;
alsa_handle = NULL;
alsa_handle = 0xDEADBEEF;
#define LOAD_FUNC(f) p##f = f
#endif
@@ -778,16 +921,20 @@ 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_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);
@@ -822,6 +969,8 @@ LOAD_FUNC(snd_card_next);
}
while (card >= 0) {
int firstDev = 1;
sprintf(name, "hw:%d", card);
if ((err = psnd_ctl_open(&handle, name, 0)) < 0) {
AL_PRINT("control open (%i): %s\n", card, psnd_strerror(err));
@@ -832,11 +981,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) {
@@ -846,6 +990,14 @@ LOAD_FUNC(snd_card_next);
AL_PRINT("snd_ctl_pcm_next_device failed\n");
if (dev < 0)
break;
if(firstDev && card < MAX_DEVICES-1) {
firstDev = 0;
snprintf(name, sizeof(name), "ALSA Software on %s",
psnd_ctl_card_info_get_name(info));
alsaDeviceList[card+1] = AppendDeviceList(name);
}
psnd_pcm_info_set_device(pcminfo, dev);
psnd_pcm_info_set_subdevice(pcminfo, 0);
psnd_pcm_info_set_stream(pcminfo, stream);
@@ -883,7 +1035,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);
@@ -893,13 +1046,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]",
cname, dname);
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) {
+2
View File
@@ -21,6 +21,8 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <math.h>
#include "bs2b.h"
+235 -100
View File
@@ -18,122 +18,144 @@
* 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>
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
#ifndef DSSPEAKER_7POINT1
#define DSSPEAKER_7POINT1 7
#endif
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
// 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;
DWORD LastCursor = 0;
DWORD PlayCursor;
VOID *WritePtr1, *WritePtr2;
DWORD WriteCnt1, WriteCnt2;
DWORD BufferSize;
DWORD avail;
HRESULT err;
(void)uID;
(void)uReserved;
(void)dwReserved1;
(void)dwReserved2;
BufferSize = pDevice->UpdateSize * num_frags *
aluBytesFromFormat(pDevice->Format) *
aluChannelsFromFormat(pDevice->Format);
BufSize = pDevice->UpdateFreq * 2 * 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)
while(!pData->killNow)
{
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);
}
// Get current play and write cursors
IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
avail = (PlayCursor-LastCursor+BufferSize) % BufferSize;
// Successfully locked the output buffer
if (DSRes==DS_OK)
{
// If we have an active context, mix data directly into output buffer otherwise fill with silence
SuspendContext(NULL);
if (WritePtr1)
if(avail < BufferSize/num_frags)
{
Sleep(1);
continue;
}
// 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 %= BufferSize;
}
// 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;
DWORD speakers;
HRESULT hr;
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 = aluBytesFromFormat(device->Format) * 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 +166,142 @@ 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 = DirectSoundCreate(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)
device->Format = AL_FORMAT_MONO8;
else
device->Format = AL_FORMAT_MONO16;
}
else if(speakers == DSSPEAKER_STEREO)
{
if(aluBytesFromFormat(device->Format) == 1)
device->Format = AL_FORMAT_STEREO8;
else
device->Format = AL_FORMAT_STEREO16;
}
else if(speakers == DSSPEAKER_QUAD)
{
if(aluBytesFromFormat(device->Format) == 1)
device->Format = AL_FORMAT_QUAD8;
else
device->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)
device->Format = AL_FORMAT_51CHN8;
else
device->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)
device->Format = AL_FORMAT_71CHN8;
else
device->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;
}
frameSize = aluBytesFromFormat(device->Format) *
aluChannelsFromFormat(device->Format);
OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
OutputType.Format.nChannels = aluChannelsFromFormat(device->Format);
OutputType.Format.wBitsPerSample = aluBytesFromFormat(device->Format) * 8;
OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
OutputType.Format.nSamplesPerSec = device->Frequency;
OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
OutputType.Format.cbSize = 0;
device->UpdateSize /= num_frags;
}
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 * 2 * device->FrameSize;
DSBDescription.lpwfxFormat=&OutputType;
DSBDescription.dwBufferBytes=device->UpdateSize * 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 +315,6 @@ 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->ExtraData = pData;
return ALC_TRUE;
}
@@ -201,26 +322,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 +385,36 @@ 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]);
num_frags = GetConfigValueInt("dsound", "periods", 4);
if(num_frags < 2) num_frags = 2;
hr = DirectSoundEnumerate(DSoundEnumDevices, &iter);
if(FAILED(hr))
AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
}
+31 -64
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>
@@ -50,12 +52,11 @@ 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;
@@ -106,7 +107,7 @@ static ALuint OSSProc(ALvoid *ptr)
memmove(data->mix_data, data->mix_data+wrote, remaining);
}
else
usleep(1000);
Sleep(1);
}
return 0;
@@ -132,7 +133,7 @@ static ALuint OSSCaptureProc(ALvoid *ptr)
}
if(amt == 0)
{
usleep(1000);
Sleep(1);
continue;
}
if(data->doCapture)
@@ -148,6 +149,7 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
int log2FragmentSize;
unsigned int periods;
audio_buf_info info;
ALuint frameSize;
char driver[64];
int numChannels;
oss_data *data;
@@ -181,11 +183,9 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
switch(aluBytesFromFormat(device->Format))
{
case 1:
data->silence = 0x80;
ossFormat = AFMT_U8;
break;
case 2:
data->silence = 0;
ossFormat = AFMT_S16_NE;
break;
default:
@@ -196,9 +196,11 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
periods = GetConfigValueInt("oss", "periods", 4);
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)
@@ -221,9 +223,9 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
device->Frequency = ossSpeed;
if((int)device->Channels != numChannels)
if((int)aluChannelsFromFormat(device->Format) != numChannels)
{
AL_PRINT("Could not set %d channels, got %d instead\n", device->Channels, numChannels);
AL_PRINT("Could not set %d channels, got %d instead\n", aluChannelsFromFormat(device->Format), numChannels);
close(data->fd);
free(data);
return ALC_FALSE;
@@ -238,13 +240,11 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
return ALC_FALSE;
}
device->UpdateFreq = info.fragsize / device->FrameSize;
device->UpdateSize = info.fragsize / frameSize;
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)
@@ -278,6 +278,7 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName,
int log2FragmentSize;
unsigned int periods;
audio_buf_info info;
ALuint frameSize;
int numChannels;
char driver[64];
oss_data *data;
@@ -311,11 +312,9 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName,
switch(aluBytesFromFormat(format))
{
case 1:
data->silence = 0x80;
ossFormat = AFMT_U8;
break;
case 2:
data->silence = 0;
ossFormat = AFMT_S16_NE;
break;
default:
@@ -324,9 +323,10 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName,
}
periods = 4;
numChannels = device->Channels;
numChannels = aluChannelsFromFormat(device->Format);
frameSize = numChannels * aluBytesFromFormat(device->Format);
ossSpeed = frequency;
log2FragmentSize = log2i(device->UpdateFreq * device->FrameSize / periods);
log2FragmentSize = log2i(SampleSize * frameSize / periods);
/* according to the OSS spec, 16 bytes are the minimum */
if (log2FragmentSize < 4)
@@ -347,55 +347,24 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName,
}
#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;
}
data->ring = CreateRingBuffer(device->FrameSize, SampleSize);
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");
@@ -404,9 +373,7 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName,
return ALC_FALSE;
}
device->UpdateFreq = info.fragsize / device->FrameSize;
data->data_size = device->UpdateFreq * device->FrameSize * info.fragments;
data->data_size = info.fragsize;
data->mix_data = calloc(1, data->data_size);
device->ExtraData = data;
+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);
}
+334
View File
@@ -0,0 +1,334 @@
/**
* 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;
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
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));
}
+195 -91
View File
@@ -1,5 +1,11 @@
# 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)
@@ -9,28 +15,41 @@ 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(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(XCOMPILEWIN32 "Cross-compile to Win32" OFF)
IF(WIN32 OR XCOMPILEWIN32)
SET(LIBNAME openal32)
ADD_DEFINITIONS("-D_WIN32")
ELSE()
SET(LIBNAME openal)
ENDIF()
SET(LIB_MAJOR_VERSION "1")
SET(LIB_MINOR_VERSION "1")
SET(LIB_BUILD_VERSION "93")
SET(LIB_MINOR_VERSION "6")
SET(LIB_BUILD_VERSION "372")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_BUILD_VERSION}")
IF(NOT DEFINED LIB_INSTALL_DIR)
SET(LIB_INSTALL_DIR "lib")
ENDIF(NOT DEFINED LIB_INSTALL_DIR)
CHECK_TYPE_SIZE("long" SIZEOF_LONG)
@@ -42,8 +61,18 @@ CHECK_TYPE_SIZE("void*" SIZEOF_VOIDP)
# Add definitions, compiler switches, etc.
INCLUDE_DIRECTORIES(OpenAL32/Include include "${OpenAL_BINARY_DIR}")
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(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")
ELSE()
ADD_DEFINITIONS(-Wall)
CHECK_C_COMPILER_FLAG(-Wextra HAVE_W_EXTRA)
@@ -55,23 +84,21 @@ 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 AND NOT XCOMPILEWIN32)
CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor));
int main() {return 0;}" HAVE_GCC_DESTRUCTOR)
@@ -86,32 +113,44 @@ ELSE()
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)
IF("${HAVE_SQRTF}")
CHECK_LIBRARY_EXISTS(m acosf "" HAVE_ACOSF)
IF(HAVE_FENV_H)
CHECK_LIBRARY_EXISTS(m fesetround "" HAVE_FESETROUND)
ENDIF()
IF(HAVE_SQRTF OR HAVE_ACOSF 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}")
IF(NOT HAVE_SNPRINTF)
CHECK_FUNCTION_EXISTS(_snprintf HAVE__SNPRINTF)
IF(NOT "${HAVE__SNPRINTF}")
IF(NOT HAVE__SNPRINTF)
MESSAGE(FATAL_ERROR "No snprintf function found, please report!")
ENDIF()
@@ -121,43 +160,57 @@ 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()
@@ -165,21 +218,25 @@ 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/alcReverb.c
Alc/alcRing.c
Alc/alcThread.c
Alc/bs2b.c
Alc/wave.c
)
SET(BACKENDS "")
@@ -187,15 +244,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()
@@ -205,89 +262,136 @@ 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)
SET(HAVE_DSOUND 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/dsound.c)
SET(BACKENDS "${BACKENDS} DirectSound,")
IF(DSOUND)
CHECK_INCLUDE_FILE(dsound.h HAVE_DSOUND_H)
IF("${HAVE_DSOUND_H}")
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})
ENDIF()
SET(CMAKE_REQUIRED_LIBRARIES dsound)
CHECK_C_SOURCE_COMPILES("int main() {return 0;}" HAVE_LIBDSOUND)
SET(CMAKE_REQUIRED_LIBRARIES "")
# CHECK_LIBRARY_EXISTS(dsound DirectSoundCreate "" HAVE_LIBDSOUND)
IF(HAVE_LIBDSOUND)
SET(EXTRA_LIBS dsound ${EXTRA_LIBS})
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()
# 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
IF("${WIN32}")
SET(LIBNAME openal32)
ELSE()
SET(LIBNAME openal)
# Build a library
IF(NOT LIBTYPE)
SET(LIBTYPE SHARED)
ENDIF()
ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALC_OBJS})
ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION}
SOVERSION ${LIB_MAJOR_VERSION})
IF("${WIN32}")
IF(WIN32)
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "")
ENDIF()
IF(XCOMPILEWIN32)
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "" SUFFIX .dll)
IF(EXAMPLES)
SET(EXAMPLES OFF)
MESSAGE(STATUS "")
MESSAGE(STATUS "Building examples disabled when cross-compiling")
ENDIF()
ENDIF()
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES OUTPUT_NAME ${LIBNAME})
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/pkgconfig)
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 OR XCOMPILEWIN32)
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()
+56
View File
@@ -0,0 +1,56 @@
#ifndef _AL_AUXEFFECTSLOT_H_
#define _AL_AUXEFFECTSLOT_H_
#include "AL/al.h"
#include "alEffect.h"
#include "alFilter.h"
#include "alReverb.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 ALeffectslot
{
ALeffect effect;
ALfloat Gain;
ALboolean AuxSendAuto;
ALverbState *ReverbState;
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);
#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
+96
View File
@@ -0,0 +1,96 @@
#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_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
enum {
REVERB = 0,
MAX_EFFECTS
};
extern ALboolean DisabledEffects[MAX_EFFECTS];
typedef struct ALeffect_struct
{
// Effect type (AL_EFFECT_NULL, ...)
ALenum type;
struct {
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;
} Reverb;
// 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
+60
View File
@@ -0,0 +1,60 @@
#ifndef _AL_FILTER_H_
#define _AL_FILTER_H_
#include "AL/al.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
ALfloat history[4];
ALfloat coeff;
} FILTER;
#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
+70 -40
View File
@@ -2,17 +2,31 @@
#define AL_MAIN_H
#include <string.h>
#include <stdio.h>
#include "alu.h"
#ifdef HAVE_FENV_H
#include <fenv.h>
#endif
#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)
@@ -38,6 +52,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);
@@ -52,59 +70,65 @@ 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 "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "alListener.h"
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
extern CRITICAL_SECTION _alMutex;
extern char _alDebug[256];
#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; \
#define AL_PRINT(...) do { \
int _al_print_i; \
const char *_al_print_fn = strrchr(__FILE__, '/'); \
if(!_al_print_fn) _al_print_fn = __FILE__; \
else _al_print_fn += 1; \
_al_print_i = snprintf(_alDebug, sizeof(_alDebug), "AL lib: %s:%d: ", _al_print_fn, __LINE__); \
if(_al_print_i < (int)sizeof(_alDebug) && _al_print_i > 0) \
if(_al_print_i < (int)sizeof(_alDebug) && _al_print_i > 0) \
snprintf(_alDebug+_al_print_i, sizeof(_alDebug)-_al_print_i, __VA_ARGS__); \
_alDebug[sizeof(_alDebug)-1] = 0; \
fprintf(stderr, "%s", _alDebug); \
_alDebug[sizeof(_alDebug)-1] = 0; \
fprintf(stderr, "%s", _alDebug); \
} while(0)
#define AL_FORMAT_MONO_FLOAT32 0x10010
#define AL_FORMAT_STEREO_FLOAT32 0x10011
#define AL_FORMAT_MONO_IMA4 0x1300
#define AL_FORMAT_STEREO_IMA4 0x1301
#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
#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 SWMIXER_OUTPUT_RATE 44100
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINDBHF (-0.05f)
#define LOWPASSFREQCUTOFF (5000)
typedef struct {
ALCboolean (*OpenPlayback)(ALCdevice*, const ALCchar*);
@@ -120,19 +144,18 @@ 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_wave_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;
@@ -145,6 +168,8 @@ struct ALCdevice_struct
BackendFuncs *Funcs;
void *ExtraData; // For the backend's use
ALCdevice *next;
};
#define ALCdevice_OpenPlayback(a,b) ((a)->Funcs->OpenPlayback((a), (b)))
@@ -163,6 +188,9 @@ struct ALCcontext_struct
struct ALsource *Source;
ALuint SourceCount;
struct ALeffectslot *AuxiliaryEffectSlot;
ALuint AuxiliaryEffectSlotCount;
ALenum LastError;
ALboolean InUse;
@@ -178,13 +206,15 @@ struct ALCcontext_struct
ALint lNumStereoSources;
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);
+26
View File
@@ -0,0 +1,26 @@
#ifndef _AL_REVERB_H_
#define _AL_REVERB_H_
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alEffect.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ALverbState ALverbState;
ALverbState *VerbCreate(ALCcontext *Context);
ALvoid VerbDestroy(ALverbState *State);
ALvoid VerbUpdate(ALCcontext *Context, struct ALeffectslot *Slot, ALeffect *Effect);
ALvoid VerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]);
#ifdef __cplusplus
}
#endif
#endif
+43 -4
View File
@@ -3,8 +3,22 @@
#define AL_NUM_SOURCE_PARAMS 128
/* This cannot be changed without working on the code! */
#define MAX_SENDS 1
#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
@@ -42,28 +56,53 @@ typedef struct ALsource
ALenum state;
ALuint position;
ALuint position_fraction;
struct ALbufferlistitem *queue; // Linked list of buffers in queue
ALuint BuffersInQueue; // Number of buffers in queue
ALuint BuffersProcessed; // Number of buffers already processed (played)
ALuint TotalBufferDataSize; // Total amount of data contained in the buffers queued for this source
ALuint BuffersPlayed; // Number of buffers played on this loop
ALuint BufferPosition; // Read position in audio data of current buffer
ALfilter DirectFilter;
struct {
struct ALeffectslot *Slot;
ALfilter WetFilter;
FILTER iirFilter;
} Send[MAX_SENDS];
ALboolean DryGainHFAuto;
ALboolean WetGainAuto;
ALboolean WetGainHFAuto;
ALfloat OuterGainHF;
FILTER iirFilter;
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;
// Current gains, which are ramped while mixed
ALfloat DryGains[OUTPUTCHANNELS];
ALfloat WetGain;
ALboolean FirstStart;
struct ALsource *next;
} ALsource;
ALvoid ReleaseALSources(ALCcontext *Context);
#ifdef __cplusplus
}
#endif
+15
View File
@@ -8,6 +8,21 @@
extern "C" {
#endif
enum {
FRONT_LEFT = 0,
FRONT_RIGHT,
SIDE_LEFT,
SIDE_RIGHT,
BACK_LEFT,
BACK_RIGHT,
CENTER,
LFE,
OUTPUTCHANNELS
};
extern ALboolean DuplicateStereo;
__inline ALuint aluBytesFromFormat(ALenum format);
__inline ALuint aluChannelsFromFormat(ALenum format);
ALvoid aluMixData(ALCcontext *context,ALvoid *buffer,ALsizei size,ALenum format);
-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 _alMutex;
#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(&_alMutex);
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(&_alMutex);
}
#endif
#endif
+508
View File
@@ -0,0 +1,508 @@
/**
* 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"
#include "alReverb.h"
static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect);
ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCcontext *Context;
ALsizei i;
Context = alcGetCurrentContext();
if(!Context)
{
alSetError(AL_INVALID_OPERATION);
return;
}
SuspendContext(Context);
if (n > 0)
{
/* NOTE: We only support one slot currently */
if(n == 1 && Context->AuxiliaryEffectSlotCount == 0)
{
// 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;
(*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);
VerbDestroy(ALAuxiliaryEffectSlot->ReverbState);
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)
{
memset(&ALEffectSlot->effect, 0, sizeof(ALEffectSlot->effect));
VerbDestroy(ALEffectSlot->ReverbState);
ALEffectSlot->ReverbState = NULL;
return;
}
if(effect->type == AL_EFFECT_REVERB)
{
if(!ALEffectSlot->ReverbState)
ALEffectSlot->ReverbState = VerbCreate(Context);
VerbUpdate(Context, ALEffectSlot, effect);
}
memcpy(&ALEffectSlot->effect, effect, sizeof(*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
VerbDestroy(temp->ReverbState);
ALTHUNK_REMOVEENTRY(temp->effectslot);
memset(temp, 0, sizeof(ALeffectslot));
free(temp);
}
Context->AuxiliaryEffectSlotCount = 0;
}
+348 -347
View File
@@ -20,6 +20,8 @@
#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>
@@ -32,6 +34,9 @@
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
@@ -95,20 +100,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
{
@@ -140,63 +145,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);
@@ -257,14 +258,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);
@@ -296,102 +293,39 @@ ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *d
ALuint OrigBytes = ((format==AL_FORMAT_REAR8) ? 1 :
((format==AL_FORMAT_REAR16) ? 2 :
4));
ALsizei i;
assert(aluBytesFromFormat(NewFormat) == 2);
if ((size%(OrigBytes*2)) != 0)
if((size%(OrigBytes*2)) != 0)
{
alSetError(AL_INVALID_VALUE);
break;
}
switch(OrigBytes)
size /= OrigBytes;
size *= 2;
// Samples are converted to 16 bit here
temp = realloc(ALBuf->data, (padding*NewChannels + size) * sizeof(ALshort));
if(temp)
{
case 1:
size /= sizeof(ALubyte);
size *= 2;
ALBuf->data = temp;
ConvertDataRear(ALBuf->data, data, OrigBytes, size);
// 8bit Samples are converted to 16 bit here
// Allocate 8 extra samples
ALBuf->data = realloc(ALBuf->data, (8*NewChannels + size) * (1*sizeof(ALshort)));
if (ALBuf->data)
{
for (i = 0;i < size;i+=4)
{
ALBuf->data[i+0] = 0;
ALBuf->data[i+1] = 0;
ALBuf->data[i+2] = (ALshort)((((ALubyte*)data)[i/2+0]-128) << 8);
ALBuf->data[i+3] = (ALshort)((((ALubyte*)data)[i/2+1]-128) << 8);
}
memset(&(ALBuf->data[size]), 0, 16*NewChannels);
memset(&(ALBuf->data[size]), 0, padding*NewChannels*sizeof(ALshort));
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
case 2:
size /= sizeof(ALshort);
size *= 2;
// Allocate 8 extra samples
ALBuf->data = realloc(ALBuf->data, (8*NewChannels + size) * (1*sizeof(ALshort)));
if (ALBuf->data)
{
for (i = 0;i < size;i+=4)
{
ALBuf->data[i+0] = 0;
ALBuf->data[i+1] = 0;
ALBuf->data[i+2] = ((ALshort*)data)[i/2+0];
ALBuf->data[i+3] = ((ALshort*)data)[i/2+1];
}
memset(&(ALBuf->data[size]), 0, 16*NewChannels);
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
case 4:
size /= sizeof(ALfloat);
size *= 2;
// Allocate 8 extra samples
ALBuf->data = realloc(ALBuf->data, (8*NewChannels + size) * (1*sizeof(ALshort)));
if (ALBuf->data)
{
for (i = 0;i < size;i+=4)
{
ALBuf->data[i+0] = 0;
ALBuf->data[i+1] = 0;
ALBuf->data[i+2] = (ALshort)(((ALfloat*)data)[i/2+0] * 32767.5f - 0.5);
ALBuf->data[i+3] = (ALshort)(((ALfloat*)data)[i/2+1] * 32767.5f - 0.5);
}
memset(&(ALBuf->data[size]), 0, 16*NewChannels);
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
default:
assert(0);
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
} break;
case AL_FORMAT_QUAD8_LOKI:
case AL_FORMAT_QUAD16_LOKI:
case AL_FORMAT_QUAD8:
case AL_FORMAT_QUAD16:
case AL_FORMAT_QUAD32:
@@ -417,157 +351,39 @@ ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *d
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);
@@ -589,6 +405,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)
{
@@ -986,7 +906,8 @@ static void LoadData(ALbuffer *ALBuf, const ALubyte *data, ALsizei size, ALuint
ALuint NewChannels = aluChannelsFromFormat(NewFormat);
ALuint OrigBytes = aluBytesFromFormat(OrigFormat);
ALuint OrigChannels = aluChannelsFromFormat(OrigFormat);
ALsizei i;
ALsizei padding = 2;
ALvoid *temp;
assert(aluBytesFromFormat(NewFormat) == 2);
assert(NewChannels == OrigChannels);
@@ -997,73 +918,153 @@ static void LoadData(ALbuffer *ALBuf, const ALubyte *data, ALsizei size, ALuint
return;
}
switch(OrigBytes)
// Samples are converted to 16 bit here
size /= OrigBytes;
temp = realloc(ALBuf->data, (padding*NewChannels + size) * sizeof(ALshort));
if(temp)
{
case 1:
size /= sizeof(ALubyte);
ALBuf->data = temp;
ConvertData(ALBuf->data, data, OrigBytes, size);
// 8bit Samples are converted to 16 bit here
// Allocate 8 extra samples
ALBuf->data = realloc(ALBuf->data, (8*NewChannels + size) * (1*sizeof(ALshort)));
if (ALBuf->data)
{
for (i = 0;i < size;i++)
ALBuf->data[i] = (ALshort)((data[i]-128) << 8);
memset(&(ALBuf->data[size]), 0, 16*NewChannels);
memset(&(ALBuf->data[size]), 0, padding*NewChannels*sizeof(ALshort));
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
case 2:
size /= sizeof(ALshort);
static void ConvertData(ALshort *dst, const ALvoid *src, ALint origBytes, ALsizei len)
{
ALsizei i;
switch(origBytes)
{
case 1:
for(i = 0;i < len;i++)
dst[i] = ((ALshort)((ALubyte*)src)[i] - 128) << 8;
break;
// Allocate 8 extra samples
ALBuf->data = realloc(ALBuf->data, (8*NewChannels + size) * (1*sizeof(ALshort)));
if (ALBuf->data)
{
memcpy(ALBuf->data, data, size*1*sizeof(ALshort));
memset(&(ALBuf->data[size]), 0, 16*NewChannels);
case 2:
memcpy(dst, src, len*sizeof(ALshort));
break;
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
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;
case 4:
size /= sizeof(ALfloat);
// Allocate 8 extra samples
ALBuf->data = realloc(ALBuf->data, (8*NewChannels + size) * (1*sizeof(ALshort)));
if (ALBuf->data)
{
for (i = 0;i < size;i++)
ALBuf->data[i] = (ALshort)(((ALfloat*)data)[i] * 32767.5f - 0.5);
memset(&(ALBuf->data[size]), 0, 16*NewChannels);
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
default:
assert(0);
default:
assert(0);
}
}
static void ConvertDataRear(ALshort *dst, const ALvoid *src, ALint origBytes, ALsizei len)
{
ALsizei i;
switch(origBytes)
{
case 1:
for(i = 0;i < len;i+=4)
{
dst[i+0] = 0;
dst[i+1] = 0;
dst[i+2] = ((ALshort)((ALubyte*)src)[i/2+0] - 128) << 8;
dst[i+3] = ((ALshort)((ALubyte*)src)[i/2+1] - 128) << 8;
}
break;
case 2:
for(i = 0;i < len;i+=4)
{
dst[i+0] = 0;
dst[i+1] = 0;
dst[i+2] = ((ALshort*)src)[i/2+0];
dst[i+3] = ((ALshort*)src)[i/2+1];
}
break;
case 4:
for(i = 0;i < len;i+=4)
{
ALint smp;
dst[i+0] = 0;
dst[i+1] = 0;
smp = (((ALfloat*)src)[i/2+0] * 32767.5f - 0.5);
smp = min(smp, 32767);
smp = max(smp, -32768);
dst[i+2] = (ALshort)smp;
smp = (((ALfloat*)src)[i/2+1] * 32767.5f - 0.5);
smp = min(smp, 32767);
smp = max(smp, -32768);
dst[i+3] = (ALshort)smp;
}
break;
default:
assert(0);
}
}
static void ConvertDataIMA4(ALshort *dst, const ALvoid *src, ALint origChans, ALsizei len)
{
const ALuint *IMAData;
ALint Sample[2],Index[2];
ALuint IMACode[2];
ALsizei i,j,k,c;
assert(origChans <= 2);
IMAData = src;
for(i = 0;i < len/origChans;i++)
{
for(c = 0;c < origChans;c++)
{
Sample[c] = ((ALshort*)IMAData)[0];
Index[c] = ((ALshort*)IMAData)[1];
Index[c] = ((Index[c]<0) ? 0 : Index[c]);
Index[c] = ((Index[c]>88) ? 88 : Index[c]);
dst[i*65*origChans + c] = (ALshort)Sample[c];
IMAData++;
}
for(j = 1;j < 65;j += 8)
{
for(c = 0;c < origChans;c++)
IMACode[c] = *(IMAData++);
for(k = 0;k < 8;k++)
{
for(c = 0;c < origChans;c++)
{
Sample[c] += ((g_IMAStep_size[Index[c]]*g_IMACodeword_4[IMACode[c]&15])/8);
Index[c] += g_IMAIndex_adjust_4[IMACode[c]&15];
if(Sample[c] < -32768) Sample[c] = -32768;
else if(Sample[c] > 32767) Sample[c] = 32767;
if(Index[c]<0) Index[c] = 0;
else if(Index[c]>88) Index[c] = 88;
dst[(i*65+j+k)*origChans + c] = (ALshort)Sample[c];
IMACode[c] >>= 4;
}
}
}
}
}
/*
* ReleaseALBuffers()
@@ -1077,7 +1078,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;
+636
View File
@@ -0,0 +1,636 @@
/**
* 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 "alEffect.h"
#include "alThunk.h"
#include "alError.h"
ALboolean DisabledEffects[MAX_EFFECTS];
static ALeffect *g_EffectList;
static ALuint g_EffectCount;
static void InitEffectParams(ALeffect *effect, ALenum type);
ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
{
ALCcontext *Context;
ALsizei i;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (n > 0)
{
// Check that enough memory has been allocted in the 'effects' array for n Effects
if (!IsBadWritePtr((void*)effects, n * sizeof(ALuint)))
{
ALeffect **list = &g_EffectList;
while(*list)
list = &(*list)->next;
i = 0;
while(i < n)
{
*list = calloc(1, sizeof(ALeffect));
if(!(*list))
{
// We must have run out or memory
alDeleteEffects(i, effects);
alSetError(AL_OUT_OF_MEMORY);
break;
}
effects[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
(*list)->effect = effects[i];
InitEffectParams(*list, AL_EFFECT_NULL);
g_EffectCount++;
i++;
list = &(*list)->next;
}
}
}
ProcessContext(Context);
}
ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects)
{
ALCcontext *Context;
ALeffect *ALEffect;
ALsizei i;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (n >= 0)
{
// Check that all effects are valid
for (i = 0; i < n; i++)
{
if (!alIsEffect(effects[i]))
{
alSetError(AL_INVALID_NAME);
break;
}
}
if (i == n)
{
// All effects are valid
for (i = 0; i < n; i++)
{
// Recheck that the effect is valid, because there could be duplicated names
if (effects[i] && alIsEffect(effects[i]))
{
ALeffect **list;
ALEffect = ((ALeffect*)ALTHUNK_LOOKUPENTRY(effects[i]));
// Remove Source from list of Sources
list = &g_EffectList;
while(*list && *list != ALEffect)
list = &(*list)->next;
if(*list)
*list = (*list)->next;
ALTHUNK_REMOVEENTRY(ALEffect->effect);
memset(ALEffect, 0, sizeof(ALeffect));
free(ALEffect);
g_EffectCount--;
}
}
}
}
else
alSetError(AL_INVALID_VALUE);
ProcessContext(Context);
}
ALboolean AL_APIENTRY alIsEffect(ALuint effect)
{
ALCcontext *Context;
ALeffect **list;
Context = alcGetCurrentContext();
SuspendContext(Context);
list = &g_EffectList;
while(*list && (*list)->effect != effect)
list = &(*list)->next;
ProcessContext(Context);
return ((*list || !effect) ? AL_TRUE : AL_FALSE);
}
ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (effect && alIsEffect(effect))
{
ALeffect *ALEffect = (ALeffect*)ALTHUNK_LOOKUPENTRY(effect);
if(param == AL_EFFECT_TYPE)
{
ALboolean isOk = (iValue == AL_EFFECT_NULL ||
(iValue == AL_EFFECT_REVERB && !DisabledEffects[REVERB]));
if(isOk)
InitEffectParams(ALEffect, iValue);
else
alSetError(AL_INVALID_VALUE);
}
else if(ALEffect->type == AL_EFFECT_REVERB)
{
switch(param)
{
case AL_REVERB_DECAY_HFLIMIT:
if(iValue == AL_TRUE || iValue == AL_FALSE)
ALEffect->Reverb.DecayHFLimit = iValue;
else
alSetError(AL_INVALID_VALUE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_ENUM);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (effect && alIsEffect(effect))
{
ALeffect *ALEffect = (ALeffect*)ALTHUNK_LOOKUPENTRY(effect);
if(param == AL_EFFECT_TYPE)
{
alEffecti(effect, param, piValues[0]);
}
else if(ALEffect->type == AL_EFFECT_REVERB)
{
switch(param)
{
case AL_REVERB_DECAY_HFLIMIT:
alEffecti(effect, param, piValues[0]);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_ENUM);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (effect && alIsEffect(effect))
{
ALeffect *ALEffect = (ALeffect*)ALTHUNK_LOOKUPENTRY(effect);
if(ALEffect->type == AL_EFFECT_REVERB)
{
switch(param)
{
case AL_REVERB_DENSITY:
if(flValue >= 0.0f && flValue <= 1.0f)
ALEffect->Reverb.Density = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_DIFFUSION:
if(flValue >= 0.0f && flValue <= 1.0f)
ALEffect->Reverb.Diffusion = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_GAIN:
if(flValue >= 0.0f && flValue <= 1.0f)
ALEffect->Reverb.Gain = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_GAINHF:
if(flValue >= 0.0f && flValue <= 1.0f)
ALEffect->Reverb.GainHF = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_DECAY_TIME:
if(flValue >= 0.1f && flValue <= 20.0f)
ALEffect->Reverb.DecayTime = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_DECAY_HFRATIO:
if(flValue >= 0.1f && flValue <= 2.0f)
ALEffect->Reverb.DecayHFRatio = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_REFLECTIONS_GAIN:
if(flValue >= 0.0f && flValue <= 3.16f)
ALEffect->Reverb.ReflectionsGain = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_REFLECTIONS_DELAY:
if(flValue >= 0.0f && flValue <= 0.3f)
ALEffect->Reverb.ReflectionsDelay = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_LATE_REVERB_GAIN:
if(flValue >= 0.0f && flValue <= 10.0f)
ALEffect->Reverb.LateReverbGain = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_LATE_REVERB_DELAY:
if(flValue >= 0.0f && flValue <= 0.1f)
ALEffect->Reverb.LateReverbDelay = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_AIR_ABSORPTION_GAINHF:
if(flValue >= 0.892f && flValue <= 1.0f)
ALEffect->Reverb.AirAbsorptionGainHF = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_REVERB_ROOM_ROLLOFF_FACTOR:
if(flValue >= 0.0f && flValue <= 10.0f)
ALEffect->Reverb.RoomRolloffFactor = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_ENUM);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (effect && alIsEffect(effect))
{
ALeffect *ALEffect = (ALeffect*)ALTHUNK_LOOKUPENTRY(effect);
if(ALEffect->type == AL_EFFECT_REVERB)
{
switch(param)
{
case AL_REVERB_DENSITY:
case AL_REVERB_DIFFUSION:
case AL_REVERB_GAIN:
case AL_REVERB_GAINHF:
case AL_REVERB_DECAY_TIME:
case AL_REVERB_DECAY_HFRATIO:
case AL_REVERB_REFLECTIONS_GAIN:
case AL_REVERB_REFLECTIONS_DELAY:
case AL_REVERB_LATE_REVERB_GAIN:
case AL_REVERB_LATE_REVERB_DELAY:
case AL_REVERB_AIR_ABSORPTION_GAINHF:
case AL_REVERB_ROOM_ROLLOFF_FACTOR:
alEffectf(effect, param, pflValues[0]);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_ENUM);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (effect && alIsEffect(effect))
{
ALeffect *ALEffect = (ALeffect*)ALTHUNK_LOOKUPENTRY(effect);
if(param == AL_EFFECT_TYPE)
{
*piValue = ALEffect->type;
}
else if(ALEffect->type == AL_EFFECT_REVERB)
{
switch(param)
{
case AL_REVERB_DECAY_HFLIMIT:
*piValue = ALEffect->Reverb.DecayHFLimit;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_ENUM);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (effect && alIsEffect(effect))
{
ALeffect *ALEffect = (ALeffect*)ALTHUNK_LOOKUPENTRY(effect);
if(param == AL_EFFECT_TYPE)
{
alGetEffecti(effect, param, piValues);
}
else if(ALEffect->type == AL_EFFECT_REVERB)
{
switch(param)
{
case AL_REVERB_DECAY_HFLIMIT:
alGetEffecti(effect, param, piValues);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_ENUM);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (effect && alIsEffect(effect))
{
ALeffect *ALEffect = (ALeffect*)ALTHUNK_LOOKUPENTRY(effect);
if(ALEffect->type == AL_EFFECT_REVERB)
{
switch(param)
{
case AL_REVERB_DENSITY:
*pflValue = ALEffect->Reverb.Density;
break;
case AL_REVERB_DIFFUSION:
*pflValue = ALEffect->Reverb.Diffusion;
break;
case AL_REVERB_GAIN:
*pflValue = ALEffect->Reverb.Gain;
break;
case AL_REVERB_GAINHF:
*pflValue = ALEffect->Reverb.GainHF;
break;
case AL_REVERB_DECAY_TIME:
*pflValue = ALEffect->Reverb.DecayTime;
break;
case AL_REVERB_DECAY_HFRATIO:
*pflValue = ALEffect->Reverb.DecayHFRatio;
break;
case AL_REVERB_REFLECTIONS_GAIN:
*pflValue = ALEffect->Reverb.ReflectionsGain;
break;
case AL_REVERB_REFLECTIONS_DELAY:
*pflValue = ALEffect->Reverb.ReflectionsDelay;
break;
case AL_REVERB_LATE_REVERB_GAIN:
*pflValue = ALEffect->Reverb.LateReverbGain;
break;
case AL_REVERB_LATE_REVERB_DELAY:
*pflValue = ALEffect->Reverb.LateReverbDelay;
break;
case AL_REVERB_AIR_ABSORPTION_GAINHF:
*pflValue = ALEffect->Reverb.AirAbsorptionGainHF;
break;
case AL_REVERB_ROOM_ROLLOFF_FACTOR:
*pflValue = ALEffect->Reverb.RoomRolloffFactor;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_ENUM);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
Context = alcGetCurrentContext();
SuspendContext(Context);
if (effect && alIsEffect(effect))
{
ALeffect *ALEffect = (ALeffect*)ALTHUNK_LOOKUPENTRY(effect);
if(ALEffect->type == AL_EFFECT_REVERB)
{
switch(param)
{
case AL_REVERB_DENSITY:
case AL_REVERB_DIFFUSION:
case AL_REVERB_GAIN:
case AL_REVERB_GAINHF:
case AL_REVERB_DECAY_TIME:
case AL_REVERB_DECAY_HFRATIO:
case AL_REVERB_REFLECTIONS_GAIN:
case AL_REVERB_REFLECTIONS_DELAY:
case AL_REVERB_LATE_REVERB_GAIN:
case AL_REVERB_LATE_REVERB_DELAY:
case AL_REVERB_AIR_ABSORPTION_GAINHF:
case AL_REVERB_ROOM_ROLLOFF_FACTOR:
alGetEffectf(effect, param, pflValues);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
}
}
else
alSetError(AL_INVALID_ENUM);
}
else
alSetError(AL_INVALID_NAME);
ProcessContext(Context);
}
ALvoid ReleaseALEffects(ALvoid)
{
#ifdef _DEBUG
if(g_EffectCount > 0)
AL_PRINT("exit(): deleting %d Effect(s)\n", g_EffectCount);
#endif
while(g_EffectList)
{
ALeffect *temp = g_EffectList;
g_EffectList = g_EffectList->next;
// Release effect structure
memset(temp, 0, sizeof(ALeffect));
free(temp);
}
g_EffectCount = 0;
}
static void InitEffectParams(ALeffect *effect, ALenum type)
{
effect->type = type;
switch(type)
{
case AL_EFFECT_REVERB:
effect->Reverb.Density = 1.0f;
effect->Reverb.Diffusion = 1.0f;
effect->Reverb.Gain = 0.32f;
effect->Reverb.GainHF = 0.89f;
effect->Reverb.DecayTime = 1.49f;
effect->Reverb.DecayHFRatio = 0.83f;
effect->Reverb.ReflectionsGain = 0.05f;
effect->Reverb.ReflectionsDelay = 0.007f;
effect->Reverb.LateReverbGain = 1.26f;
effect->Reverb.LateReverbDelay = 0.011f;
effect->Reverb.AirAbsorptionGainHF = 0.994f;
effect->Reverb.RoomRolloffFactor = 0.0f;
effect->Reverb.DecayHFLimit = AL_TRUE;
break;
}
}
+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"
+119 -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 },
@@ -156,6 +214,8 @@ static ALenums enumeration[]={
{ (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 },
@@ -211,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 }
};
@@ -220,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)
{
@@ -235,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];
+343 -124
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>
@@ -28,9 +30,10 @@
#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 ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize);
static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
static ALint GetByteOffset(ALsource *pSource);
@@ -65,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(*list);
Context->SourceCount++;
i++;
list = &(*list)->next;
}
}
else
{
@@ -119,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;
@@ -134,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
@@ -343,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 <= 1.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:
@@ -463,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;
@@ -600,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;
}
@@ -638,6 +667,43 @@ 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;
default:
alSetError(AL_INVALID_ENUM);
break;
@@ -666,6 +732,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:
@@ -674,6 +742,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;
@@ -718,12 +815,17 @@ 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:
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;
@@ -751,7 +853,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflV
{
ALCcontext *pContext;
ALsource *pSource;
ALfloat flOffset;
ALfloat flOffset[2];
pContext = alcGetCurrentContext();
if (pContext)
@@ -794,11 +896,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;
@@ -815,6 +933,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;
@@ -915,6 +1045,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:
@@ -922,6 +1053,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;
@@ -967,7 +1101,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValu
{
ALCcontext *pContext;
ALsource *pSource;
ALfloat flOffset;
ALfloat flOffset[2];
pContext = alcGetCurrentContext();
if (pContext)
@@ -1030,7 +1164,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:
@@ -1040,12 +1174,44 @@ 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;
default:
alSetError(AL_INVALID_ENUM);
break;
@@ -1153,8 +1319,13 @@ 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:
alGetSourcei(source, eParam, plValues);
break;
@@ -1209,7 +1380,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)
@@ -1252,6 +1423,10 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
if (bPlay)
{
for(j = 0;j < OUTPUTCHANNELS;j++)
pSource->DryGains[j] = 0.0f;
pSource->WetGain = 0.0f;
if (pSource->state != AL_PAUSED)
{
pSource->state = AL_PLAYING;
@@ -1259,10 +1434,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;
@@ -1279,6 +1452,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
@@ -1295,7 +1469,7 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
ALBufferList = ALBufferList->next;
}
pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
pSource->BuffersPlayed = pSource->BuffersInQueue;
}
}
}
@@ -1419,7 +1593,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)
{
@@ -1491,7 +1665,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)
{
@@ -1764,7 +1938,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)
@@ -1778,10 +1951,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;
}
@@ -1831,6 +2001,14 @@ 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->state = AL_INITIAL;
pSource->lSourceType = AL_UNDETERMINED;
@@ -1845,12 +2023,13 @@ 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;
@@ -1864,15 +2043,20 @@ static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOf
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)
@@ -1884,64 +2068,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_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 = (ALfloat)(lBytesPlayed >> 2);
pflOffset[0] = (ALfloat)(readPos >> 2);
pflOffset[1] = (ALfloat)(writePos >> 2);
}
else if (eOriginalFormat == AL_FORMAT_REAR16)
{
*pflOffset = (ALfloat)(lBytesPlayed >> 1);
pflOffset[0] = (ALfloat)(readPos >> 1);
pflOffset[1] = (ALfloat)(writePos >> 1);
}
else if (aluBytesFromFormat(eOriginalFormat) == 1)
{
*pflOffset = (ALfloat)(lBytesPlayed >> 1);
pflOffset[0] = (ALfloat)(readPos >> 1);
pflOffset[1] = (ALfloat)(writePos >> 1);
}
else if (aluBytesFromFormat(eOriginalFormat) == 4)
{
*pflOffset = (ALfloat)(lBytesPlayed << 1);
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;
@@ -1971,7 +2179,6 @@ static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
pBufferList = pSource->queue;
lTotalBufferSize = 0;
pSource->BuffersPlayed = 0;
pSource->BuffersProcessed = 0;
while (pBufferList)
{
pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
@@ -1984,10 +2191,7 @@ static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
pSource->BuffersPlayed++;
if (!pSource->bLooping)
{
pBufferList->bufferstate = PROCESSED;
pSource->BuffersProcessed++;
}
}
else if (lTotalBufferSize <= lByteOffset)
{
@@ -1997,14 +2201,8 @@ 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 /
pSource->position = (lByteOffset - lTotalBufferSize) /
aluBytesFromFormat(pBuffer->format) /
aluChannelsFromFormat(pBuffer->format);
}
@@ -2133,3 +2331,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;
}
+3 -1
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"
#include "AL/alc.h"
@@ -25,7 +27,7 @@
#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
+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"
+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}
+46 -8
View File
@@ -1,8 +1,12 @@
# 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
# 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
@@ -36,25 +40,49 @@ cf_level = 0 # Sets the crossfeed level for stereo output. Valid values are:
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.
refresh = 4096 # Sets the buffer size, in frames. Default is 4096. Note that
# the actual granularity may or may not be less than this.
sources = 256 # Sets the maximum number of allocatable sources. Lower values
# may help for systems with apps that try to play more sounds
# than the CPU can handle. Default is 256
stereodup = # Sets whether to duplicate stereo sounds on the rear speakers for
# 4+ channel output. This can make stereo sources substantially
# louder than mono or even 4+ channel sources, but provides a
# "fuller" playback quality. True, yes, on, and non-0 values will
# duplicate stereo sources. 0 and anything else will cause stereo
# sounds to only play out the front speakers.
# Default is false
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,oss,solaris,dsound,winmm,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:
# reverb
# Default is empty (all available effects enabled)
[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
periods = 0 # Sets the number of update buffers for playback. A value of 0
# means auto-select. Default is 0
capture = default # Sets the device name for the default capture device.
# Default is default
mmap = true # Sets whether to try using mmap mode (helps reduce latencies and
# CPU consumption). If mmap isn't available, it will automatically
# fall back to non-mmap mode. True, yes, on, and non-0 values will
# attempt to use mmap. 0 and anything else will force mmap off.
# Default is true.
[oss] # OSS backend stuff
device = /dev/dsp # Sets the device name for OSS output. Default is /dev/dsp
@@ -62,8 +90,18 @@ periods = 4 # Sets the number of update buffers. Default is 4
capture = /dev/dsp # Sets the device name for OSS capture. Default is /dev/dsp
[solaris] # Solaris backend stuff
device = /dev/audio # Sets the device name for Solaris output. Default is
# /dev/audio
[dsound] # DirectSound backend stuff
# Nothing yet...
periods = 4 # Sets the number of updates for the output buffer. Default is 4
[winmm] # Windows Multimedia backend stuff
# Nothing yet...
[wave] # Wave File Writer stuff
file = # Sets the filename of the wave file to write to. An empty name
# prevents the backend from opening, even when explicitly requested.
# THIS WILL OVERWRITE EXISTING FILES WITHOUT QUESTION!
# Default is empty
+24
View File
@@ -1,12 +1,18 @@
#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
@@ -19,6 +25,9 @@
/* 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 strtof function */
#cmakedefine HAVE_STRTOF
@@ -43,4 +52,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, "Standard 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