mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-17 16:00:26 +02:00
Pan stereo sounds towards where they are
A sound with a position plays on a 3D channel, but those are mono: a stereo one (a Custom Edition map's gunfire, a bullet's impact) fell back to a stereo channel, which the Xbox never panned, so it was only faded with distance and came from nowhere. update_channels now gives a stereo channel's sound in the world a pan towards it, as the mixer pans a 3D voice; the mixer pans the channels' middle and keeps their difference as wide as the far ear's gain. Unpositioned stereo plays as before, and no channel pools change.
This commit is contained in:
1 parent
71bf206bd0
commit
a14401ac7d
3 files changed
+94
No files matched your search
@@ -91,6 +91,10 @@ struct sdl_stream
|
||||
/* 2D gains */
|
||||
float volume; /* SetVolume */
|
||||
float mix_left, mix_right;
|
||||
/* a stereo voice of a sound in the world: panned towards it, -1 left
|
||||
to 1 right (dsound_sdl_stream_set_stereo_pan) */
|
||||
BOOL stereo_positioned;
|
||||
float stereo_pan;
|
||||
float headroom;
|
||||
|
||||
/* 3D */
|
||||
@@ -399,6 +403,15 @@ static void voice_gains(const struct sdl_stream *stream, float *left, float *rig
|
||||
*room_lowpass = lowpass_coefficient(gain_from_millibels(high_level - level), cosine);
|
||||
}
|
||||
}
|
||||
else if (stream->channels == 2 && stream->stereo_positioned)
|
||||
{
|
||||
/* the equal power pan of a 3D voice, at the gains of a 2D one when
|
||||
centred (the game fades it with distance) */
|
||||
float angle = (stream->stereo_pan + 1.0f) * 0.25f * 3.14159265f;
|
||||
|
||||
*left = cosf(angle) * 1.41421356f * stream->mix_left;
|
||||
*right = sinf(angle) * 1.41421356f * stream->mix_right;
|
||||
}
|
||||
else
|
||||
{
|
||||
*left = stream->mix_left;
|
||||
@@ -554,6 +567,8 @@ static void mix_voice(struct sdl_stream *stream, float *output, float *send, uns
|
||||
float ramp_direct_lowpass, ramp_room_lowpass;
|
||||
long width;
|
||||
unsigned long frame;
|
||||
/* (a stereo voice panned towards its sound: voice_gains) */
|
||||
BOOL positioned = stream->channels == 2 && stream->stereo_positioned;
|
||||
|
||||
if (stream->paused || !stream->packet_count || !stream->sample_rate)
|
||||
return;
|
||||
@@ -665,6 +680,18 @@ static void mix_voice(struct sdl_stream *stream, float *output, float *send, uns
|
||||
output[frame * 2] += sample_left * left;
|
||||
output[frame * 2 + 1] += sample_left * right;
|
||||
}
|
||||
else if (positioned)
|
||||
{
|
||||
/* the channels' middle panned, and their difference kept as
|
||||
wide as the far ear's gain: the sound comes from where it is,
|
||||
still stereo */
|
||||
float middle = 0.5f * (sample_left + sample_right);
|
||||
float side = 0.5f * (sample_left - sample_right);
|
||||
float far_gain = left < right ? left : right;
|
||||
|
||||
output[frame * 2] += middle * left + side * far_gain;
|
||||
output[frame * 2 + 1] += middle * right - side * far_gain;
|
||||
}
|
||||
else
|
||||
{
|
||||
output[frame * 2] += sample_left * left;
|
||||
@@ -1362,10 +1389,26 @@ static HRESULT STDMETHODCALLTYPE stream_flush(IDirectSoundStream *object)
|
||||
}
|
||||
stream->cursor = 0;
|
||||
resampler_reset(stream);
|
||||
/* (the next sound on the channel says where it is) */
|
||||
stream->stereo_positioned = FALSE;
|
||||
pthread_mutex_unlock(&mixer_lock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* A stereo voice of a sound in the world (`positioned`) is panned towards
|
||||
it, `pan` from -1 (left) to 1 (right); not positioned, it plays as the Xbox
|
||||
played every stereo sound, unpanned. The game fades it with distance itself
|
||||
(sound_manager.c, update_channels: sound_dsound_xbox.c calls this). */
|
||||
void dsound_sdl_stream_set_stereo_pan(IDirectSoundStream *object, BOOL positioned, float pan)
|
||||
{
|
||||
struct sdl_stream *stream = stream_from_interface(object);
|
||||
|
||||
pthread_mutex_lock(&mixer_lock);
|
||||
stream->stereo_positioned = positioned && stream->channels == 2;
|
||||
stream->stereo_pan = pan < -1.0f ? -1.0f : (pan > 1.0f ? 1.0f : pan);
|
||||
pthread_mutex_unlock(&mixer_lock);
|
||||
}
|
||||
|
||||
static IDirectSoundStreamVtbl stream_vtable =
|
||||
{
|
||||
stream_add_reference,
|
||||
|
||||
@@ -1929,6 +1929,30 @@ static void dsound_virtual_set_location(
|
||||
return;
|
||||
}
|
||||
|
||||
/* port: a stereo channel's sound in the world is panned towards it, which
|
||||
the Xbox's stereo channels were not (sound_manager.c, update_channels;
|
||||
port/linux/src/dsound_sdl.c) */
|
||||
void dsound_port_set_channel_stereo_pan(
|
||||
short virtual_channel_index,
|
||||
boolean positioned,
|
||||
real pan)
|
||||
{
|
||||
extern void dsound_sdl_stream_set_stereo_pan(IDirectSoundStream *stream, BOOL positioned, float pan);
|
||||
short channel_index= dsound_virtual_touch(virtual_channel_index);
|
||||
|
||||
if (channel_index!=NONE)
|
||||
{
|
||||
struct sound_channel *channel= channel_get(channel_index);
|
||||
|
||||
if (channel->stream && TEST_FLAG(channel->type_flags, _sound_channel_stereo_bit))
|
||||
{
|
||||
dsound_sdl_stream_set_stereo_pan(channel->stream, positioned, pan);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void dsound_virtual_set_properties(
|
||||
short virtual_channel_index,
|
||||
struct platform_sound_channel_properties const *properties,
|
||||
|
||||
@@ -244,6 +244,10 @@ symbols in this file:
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* port: a stereo channel's sound in the world panned towards it
|
||||
(sound_dsound_xbox.c; update_channels) */
|
||||
void dsound_port_set_channel_stereo_pan(short virtual_channel_index, boolean positioned, real pan);
|
||||
|
||||
/* ---------- constants */
|
||||
|
||||
enum
|
||||
@@ -3495,6 +3499,11 @@ static void update_channels(
|
||||
switch (sound->source.spatialization_mode)
|
||||
{
|
||||
case _sound_spatialization_mode_none:
|
||||
/* port: (unpanned: dsound_port_set_channel_stereo_pan) */
|
||||
if (TEST_FLAG(channel->type_flags, _sound_channel_stereo_bit))
|
||||
{
|
||||
dsound_port_set_channel_stereo_pan(channel_index, FALSE, 0.f);
|
||||
}
|
||||
break;
|
||||
|
||||
case _sound_spatialization_mode_absolute:
|
||||
@@ -3530,6 +3539,24 @@ static void update_channels(
|
||||
(maximum_distance - minimum_distance);
|
||||
|
||||
fade *= PIN(attenuation, 0.f, 1.f);
|
||||
/* port: and a stereo sound is panned towards where it
|
||||
is, as the mixer pans a 3D one (port/linux/src/dsound_sdl.c,
|
||||
spatialize: ahead is x, right -y; centred when close),
|
||||
which the Xbox's stereo channels never were: a Custom
|
||||
Edition map's stereo gunfire came from nowhere */
|
||||
if (TEST_FLAG(channel->type_flags, _sound_channel_stereo_bit))
|
||||
{
|
||||
real horizontal = square_root(
|
||||
relative_position.x * relative_position.x +
|
||||
relative_position.y * relative_position.y);
|
||||
real pan = horizontal > 1.0e-4f ? -relative_position.y / horizontal : 0.f;
|
||||
|
||||
if (distance < minimum_distance && minimum_distance > 0.f)
|
||||
{
|
||||
pan *= distance / minimum_distance;
|
||||
}
|
||||
dsound_port_set_channel_stereo_pan(channel_index, TRUE, 0.75f * pan);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
Reference in new issue
Block a user