kcat / alure

Alure is a utility library for OpenAL, providing a C++ API and managing common tasks that include file loading, caching, and streaming
zlib License
70 stars 20 forks source link

set3DSpatialize #46

Open serge4691a opened 4 years ago

serge4691a commented 4 years ago

I use in my program Open AL and in particular the flag AL_DIRECT_CHANNELS_SOFT = true. Moreover, this flag for some reason does not have an effect for the configuration 5.1 of my sound card, but it works great for 7.1 (SB Audigy 5/Rx). Am I correct in understanding that if I need a similar capability when using Alure, then I can use set3DSpatialize ()? Thank you.

kcat commented 4 years ago

Moreover, this flag for some reason does not have an effect for the configuration 5.1 of my sound card, but it works great for 7.1 (SB Audigy 5/Rx).

Is OpenAL Soft being used in both of these cases? The device name should have OpenAL Soft on Windows, and alIsExtensionPresent("AL_SOFT_direct_channels") should be true.

Am I correct in understanding that if I need a similar capability when using Alure, then I can use set3DSpatialize ()?

set3DSpatialize relates to AL_SOURCE_SPATIALIZE_SOFT in pure OpenAL Soft. Currently, Alure doesn't handle AL_DIRECT_CHANNELS_SOFT yet.

serge4691a commented 4 years ago

OpenAL uses in both of cases. Device name has OpenAL Soft on . . alIsExtension ("AL_SOFT_direct_channels") gives false, thus the AL_DIRECT_CHANNELS_SOFT flag should not work. Actually only the 7.1 configuration works as I would like. Each channel has a loudness according to its own coefficient which I specify when recalculating the buffer. (I load stereo 16 bit and then recalculate the buffer for the AL_FORMAT_71CHN16 format) Moreover it works regardless of the value of AL_DIRECT_CHANNELS_SOFT. In the 5.1 sound card configuration with the AL_DIRECT_CHANNELS_SOFT flag set the program works similarly but the volume across the channels does not exactly match the coefficients. If the flag is 0, then the rear channels are sent to the front and the signal is present only on the front channels and sub. For the x64 platform, all signals are sent to the front. Thus the signal is present only on the front connectors with increased volume, while there is no signal at all on the rear speakers connectors and the sub.

kcat commented 4 years ago

Device name has OpenAL Soft on . . alIsExtension ("AL_SOFT_direct_channels") gives false

That doesn't make much sense. What OpenAL Soft version are you using? What does alGetString(AL_RENDERER) and alGetString(AL_VERSION) report?

Moreover it works regardless of the value of AL_DIRECT_CHANNELS_SOFT.

AL_DIRECT_CHANNELS_SOFT specifies if each channel of a multi-channel buffer is mixed directly to the corresponding output channel, rather than being positioned with the normal panning algorithm. With it off on a surround sound system, each input channel should be focused on its output channel, but may sound a bit more diffuse (other speakers may play a little bit of the channel as well). So altering the input channel will affect the corresponding output channel, and maybe a little bit of the others. With it on, each input channel will play only on its matching output channel.

The results should be fairly similar when the buffer format matches the output format.

In the 5.1 sound card configuration with the AL_DIRECT_CHANNELS_SOFT flag set the program works similarly but the volume across the channels does not exactly match the coefficients. If the flag is 0, then the rear channels are sent to the front and the signal is present only on the front channels and sub.

If you're playing a 7.1 buffer with the device configured for 5.1 and connected to a 7.1 speaker setup, there can be a number of transforms at play. With AL_DIRECT_CHANNELS_SOFT on, each input buffer channel will mix to the corresponding output device channel, but the device may duplicate or remix the surround channels for the separate side and rear speakers. With it off, OpenAL Soft will generate a 5.1 mix of a virtual 7.1 layout, accounting for the missing output channels and differences in speaker positions for a 5.1 setup vs a 7.1 setup.

If there's no output on the surround channels when it's off, that could mean OpenAL Soft is just producing a stereo mix (though if it did that, I'd not expect the surround channels to be used at all when direct channels is on either), or the input 7.1 signal is such that it's managing to phase cancel on the surround channel mix, leaving the side and rear channels audible only on the front outputs.

serge4691a commented 4 years ago

Thaank you. I'll think it over and investigate on the sound card. I probably have some kind of misunderstanding. But if possible I will ask the question differently. What is the most direct way for a buffer prepared for example for a 5.1 or 7.1 channel configuration (AL_FORMAT_51CHN16/AL_FORMAT_71CHN!16), to sound at the output in its pure form as it is without any processing?

kcat commented 4 years ago

What is the most direct way for a buffer prepared for example for a 5.1 or 7.1 channel configuration (AL_FORMAT_51CHN16/AL_FORMAT_71CHN!16), to sound at the output in its pure form as it is without any processing?

With AL_DIRECT_CHANNELS_SOFT enabled on the source. If the newer AL_SOFT_direct_channels_remix is supported, calling

alSourcei(source, AL_DIRECT_CHANNELS_SOFT, AL_REMIX_UNMATCHED_SOFT);

will play each input channel on its matching output channel, and remix input channels that don't have a matching output to other "nearby" channels. Otherwise, if you don't want that remixing behavior, or if only AL_SOFT_direct_channels is supported, calling

alSourcei(source, AL_DIRECT_CHANNELS_SOFT, AL_DROP_UNMATCHED_SOFT);
// or equivalently
alSourcei(source, AL_DIRECT_CHANNELS_SOFT, AL_TRUE);

will play each input channel on its matching output channel, and drop/silence input channels that don't have a matching output channel.

serge4691a commented 4 years ago

In my program, I create about 100 - 150 static sound buffers. As soon as the volume of a sound becomes > 0 I create a source and associate it with the buffer that I want to play. With such a dynamic source selection in my case approximately 8 - 15 sources are simultaneously involved. In alure you declare that you can create a conditionally unlimited number of sources. Does it means that this number may exceed the ALC_MONO_SOURCES obtained by calling alcGetIntegerv (device, ALC_ALL_ATTRIBUTES, size, attrs)? My value is 256. Are alure's Context :: createSource, Source :: destroy methods similar to the OpenAL functions alGenSources / alDeleteSources or is there some algorithm that frees a non-playing source or a source with zero gain? Could you please explain how mAllSources and mFreeSources work?

kcat commented 4 years ago

Does it means that this number may exceed the ALC_MONO_SOURCES obtained by calling alcGetIntegerv (device, ALC_ALL_ATTRIBUTES, size, attrs)?

Yes.

Are alure's Context :: createSource, Source :: destroy methods similar to the OpenAL functions alGenSources / alDeleteSources or is there some algorithm that frees a non-playing source or a source with zero gain?

Alure virtualizes OpenAL sources. When you play an alure::Source, it gets an OpenAL source internally, applies the appropriate properties, then plays it. When the sound stops, the source gets placed in a free list (mSourceIds), which can be reused when another alure::Source wants to play. Consequently, the number of alure::Source objects you can allocate isn't influenced by the number of OpenAL sources, as only a playing sound will be using an OpenAL source.

A source with 0 gain still plays, in case the gain is increased while playing (so it'll be at the correct playback offset when it becomes audible). But a non-playing alure::Source won't have an OpenAL source.

Could you please explain how mAllSources and mFreeSources work?

mAllSources are all alure::Source objects that have been allocated. mFreeSources are alure::Source objects that have been "destroyed", and can be reused when another is needed (to avoid allocating/deallocating each one individually when the app creates/destroys the handle).

serge4691a commented 4 years ago

This means, if I understand correctly, at each moment in time all alure :: Source looping sources regardless of their volume and all alure :: Source unlooping sources that have not reached the end of its buffer regardless of their volume, will have internal OpenAL sources unless it were called Source :: destroy or Source::stop methods?

kcat commented 4 years ago

Or the alure::Source has been preempted. If you try to play an alure::Source when there are no more OpenAL sources available, Alure will search for a playing source with the lowest priority (as set by alure::Source::setPriority). If the alure::Source to play has a higher priority than that, the lowest priority alure::Source will be forced to stop regardless, so the higher priority source can use its OpenAL source.

serge4691a commented 4 years ago

With this everything is clear. I have come to the conclusion that my program logic is "struggling" with perhaps the most important feature of OpenAL: simulating the position of a sound source in a 3D sound system. I am trying to do the same but by calculating the volume of each channel in a multi-channel buffer. But for this I just need to make my buffer sound unchanged at the output. Perhaps I will achieve the result I want more efficiently if I leave the buffer alone and simulate the position of each of my sources by specifying properties such as position and orientation for them.