Merge remote-tracking branch 'origin/master' into 1.6

# Conflicts:
#	Source/Editor/Scripting/CodeEditors/VisualStudioCodeEditor.cpp
#	Source/Tools/Flax.Build/Deps/Dependencies/OpenAL.cs
This commit is contained in:
Wojtek Figat
2023-04-22 18:59:41 +02:00
51 changed files with 1397 additions and 673 deletions

View File

@@ -278,6 +278,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=heightfield/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Heightmap/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=HLSL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=HRTF/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Inlines/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Inscattering/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Interpolants/@EntryIndexedValue">True</s:Boolean>
@@ -334,6 +335,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Skybox/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Skyboxes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=slerp/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Spatialization/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=splatmap/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=splatmaps/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=SRGB/@EntryIndexedValue">True</s:Boolean>

View File

@@ -0,0 +1,69 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Dedicated
{
/// <summary>
/// Custom editor for <see cref="AudioSource"/>.
/// </summary>
[CustomEditor(typeof(AudioSource)), DefaultEditor]
public class AudioSourceEditor : ActorEditor
{
private Label _infoLabel;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
base.Initialize(layout);
// Show playback options during simulation
if (Editor.IsPlayMode)
{
var playbackGroup = layout.Group("Playback");
playbackGroup.Panel.Open();
_infoLabel = playbackGroup.Label(string.Empty).Label;
_infoLabel.AutoHeight = true;
var grid = playbackGroup.CustomContainer<UniformGridPanel>();
var gridControl = grid.CustomControl;
gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight;
gridControl.SlotsHorizontally = 3;
gridControl.SlotsVertically = 1;
grid.Button("Play").Button.Clicked += () => Foreach(x => x.Play());
grid.Button("Pause").Button.Clicked += () => Foreach(x => x.Pause());
grid.Button("Stop").Button.Clicked += () => Foreach(x => x.Stop());
}
}
/// <inheritdoc />
public override void Refresh()
{
base.Refresh();
if (_infoLabel != null)
{
var text = string.Empty;
foreach (var value in Values)
{
if (value is AudioSource audioSource && audioSource.Clip)
text += $"Time: {audioSource.Time:##0.0}s / {audioSource.Clip.Length:##0.0}s\n";
}
_infoLabel.Text = text;
}
}
private void Foreach(Action<AudioSource> func)
{
foreach (var value in Values)
{
if (value is AudioSource audioSource)
func(audioSource);
}
}
}
}

View File

@@ -0,0 +1,69 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Dedicated
{
/// <summary>
/// Custom editor for <see cref="SceneAnimationPlayer"/>.
/// </summary>
[CustomEditor(typeof(SceneAnimationPlayer)), DefaultEditor]
public class SceneAnimationPlayerEditor : ActorEditor
{
private Label _infoLabel;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
base.Initialize(layout);
// Show playback options during simulation
if (Editor.IsPlayMode)
{
var playbackGroup = layout.Group("Playback");
playbackGroup.Panel.Open();
_infoLabel = playbackGroup.Label(string.Empty).Label;
_infoLabel.AutoHeight = true;
var grid = playbackGroup.CustomContainer<UniformGridPanel>();
var gridControl = grid.CustomControl;
gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight;
gridControl.SlotsHorizontally = 3;
gridControl.SlotsVertically = 1;
grid.Button("Play").Button.Clicked += () => Foreach(x => x.Play());
grid.Button("Pause").Button.Clicked += () => Foreach(x => x.Pause());
grid.Button("Stop").Button.Clicked += () => Foreach(x => x.Stop());
}
}
/// <inheritdoc />
public override void Refresh()
{
base.Refresh();
if (_infoLabel != null)
{
var text = string.Empty;
foreach (var value in Values)
{
if (value is SceneAnimationPlayer player && player.Animation)
text += $"Time: {player.Time:##0.0}s / {player.Animation.Duration:##0.0}s\n";
}
_infoLabel.Text = text;
}
}
private void Foreach(Action<SceneAnimationPlayer> func)
{
foreach (var value in Values)
{
if (value is SceneAnimationPlayer player)
func(player);
}
}
}
}

View File

@@ -84,7 +84,7 @@ namespace FlaxEditor.GUI.Input
var range = _max - _min;
if (Mathf.IsOne(_slideSpeed) && range > Mathf.Epsilon * 200.0f && range < 1000000.0f)
{
_slideSpeed = range * 0.01f;
_slideSpeed = range * 0.001f;
}
}

View File

@@ -196,7 +196,7 @@ namespace FlaxEditor.GUI.Input
{
// Update sliding
var slidePosition = location + Root.TrackingMouseOffset;
Value = Mathf.Map(slidePosition.X, 4, TrackSize - 4, Minimum, Maximum);
Value = Mathf.Remap(slidePosition.X, 4, TrackSize - 4, Minimum, Maximum);
}
else
{
@@ -380,7 +380,7 @@ namespace FlaxEditor.GUI.Input
if (_valueIsChanging)
return;
Value = Mathf.Map(_slider.Value, Slider.Minimum, Slider.Maximum, MinValue, MaxValue);
Value = Mathf.Remap(_slider.Value, Slider.Minimum, Slider.Maximum, MinValue, MaxValue);
}
private void OnTextBoxEditEnd()
@@ -434,7 +434,7 @@ namespace FlaxEditor.GUI.Input
/// </summary>
protected virtual void UpdateSlider()
{
_slider.Value = Mathf.Map(_value, MinValue, MaxValue, Slider.Minimum, Slider.Maximum);
_slider.Value = Mathf.Remap(_value, MinValue, MaxValue, Slider.Minimum, Slider.Maximum);
}
/// <summary>

View File

@@ -90,7 +90,7 @@ namespace FlaxEditor.Modules
PrefabCreating?.Invoke(actor);
var proxy = Editor.ContentDatabase.GetProxy<Prefab>();
Editor.Windows.ContentWin.NewItem(proxy, actor, OnPrefabCreated);
Editor.Windows.ContentWin.NewItem(proxy, actor, OnPrefabCreated, actor.Name);
}
private void OnPrefabCreated(ContentItem contentItem)

View File

@@ -612,22 +612,26 @@ namespace FlaxEditor.SceneGraph.GUI
script.SetParent(newParent, true);
}
}
Select();
result = DragDropEffect.Move;
}
// Drag assets
else if (_dragAssets != null && _dragAssets.HasValidDrag)
{
var spawnParent = myActor;
if (DragOverMode == DragItemPositioning.Above || DragOverMode == DragItemPositioning.Below)
spawnParent = newParent;
for (int i = 0; i < _dragAssets.Objects.Count; i++)
{
var item = _dragAssets.Objects[i];
var actor = item.OnEditorDrop(this);
actor.StaticFlags = Actor.StaticFlags;
actor.StaticFlags = spawnParent.StaticFlags;
actor.Name = item.ShortName;
actor.Transform = Actor.Transform;
ActorNode.Root.Spawn(actor, Actor);
actor.Transform = spawnParent.Transform;
Editor.Instance.SceneEditing.Spawn(actor, spawnParent, false);
actor.OrderInParent = newOrder;
}
result = DragDropEffect.Move;
}
// Drag actor type

View File

@@ -144,7 +144,7 @@ void VisualStudioCodeEditor::OpenFile(const String& path, int32 line)
line = line > 0 ? line : 1;
CreateProcessSettings procSettings;
procSettings.FileName = _execPath;
procSettings.Arguments = String::Format(TEXT("\"{0}\" -g \"{1}\":{2}"), _workspacePath, path, line);
procSettings.Arguments = String::Format(TEXT("\"{0}\" -g \"{1}:{2}\""), _workspacePath, path, line);
procSettings.HiddenWindow = false;
procSettings.WaitForEnd = false;
procSettings.LogOutput = false;

View File

@@ -206,14 +206,14 @@ namespace FlaxEditor.Surface.Archetypes
if (_is2D)
{
pos = new Float2(
Mathf.Map(pos.X, pointsArea.Left, pointsArea.Right, _rangeX.X, _rangeX.Y),
Mathf.Map(pos.Y, pointsArea.Bottom, pointsArea.Top, _rangeY.X, _rangeY.Y)
Mathf.Remap(pos.X, pointsArea.Left, pointsArea.Right, _rangeX.X, _rangeX.Y),
Mathf.Remap(pos.Y, pointsArea.Bottom, pointsArea.Top, _rangeY.X, _rangeY.Y)
);
}
else
{
pos = new Float2(
Mathf.Map(pos.X, pointsArea.Left, pointsArea.Right, _rangeX.X, _rangeX.Y),
Mathf.Remap(pos.X, pointsArea.Left, pointsArea.Right, _rangeX.X, _rangeX.Y),
0
);
}
@@ -231,14 +231,14 @@ namespace FlaxEditor.Surface.Archetypes
if (_is2D)
{
pos = new Float2(
Mathf.Map(pos.X, _rangeX.X, _rangeX.Y, pointsArea.Left, pointsArea.Right),
Mathf.Map(pos.Y, _rangeY.X, _rangeY.Y, pointsArea.Bottom, pointsArea.Top)
Mathf.Remap(pos.X, _rangeX.X, _rangeX.Y, pointsArea.Left, pointsArea.Right),
Mathf.Remap(pos.Y, _rangeY.X, _rangeY.Y, pointsArea.Bottom, pointsArea.Top)
);
}
else
{
pos = new Float2(
Mathf.Map(pos.X, _rangeX.X, _rangeX.Y, pointsArea.Left, pointsArea.Right),
Mathf.Remap(pos.X, _rangeX.X, _rangeX.Y, pointsArea.Left, pointsArea.Right),
pointsArea.Center.Y
);
}

View File

@@ -12,7 +12,7 @@ class Actor;
/// <summary>
/// Editor viewports icons rendering service.
/// </summary>
API_CLASS(Static, Namespace="FlaxEditor") class ViewportIconsRenderer
API_CLASS(Static, Namespace="FlaxEditor") class FLAXENGINE_API ViewportIconsRenderer
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(ViewportIconsRenderer);

View File

@@ -37,6 +37,7 @@ namespace FlaxEditor.Viewport.Previews
private readonly object _locker = new object();
private AudioClip _asset;
private int _pcmSequence = 0;
private float[] _pcmData;
private AudioDataInfo _pcmInfo;
@@ -79,6 +80,20 @@ namespace FlaxEditor.Viewport.Previews
}
}
/// <summary>
/// Gets the cached audio data info.
/// </summary>
public AudioDataInfo DataInfo
{
get
{
lock (_locker)
{
return _pcmInfo;
}
}
}
/// <summary>
/// The draw mode.
/// </summary>
@@ -104,6 +119,28 @@ namespace FlaxEditor.Viewport.Previews
/// </summary>
public static readonly float UnitsPerSecond = 100.0f;
/// <summary>
/// Invalidates the cached audio PCM data and fetches it again from the asset.
/// </summary>
public void RefreshPreview()
{
lock (_locker)
{
if (_asset != null)
{
// Release any cached data
_pcmData = null;
// Invalidate any in-flight data download to reject cached data due to refresh
if (_pcmSequence != 0)
_pcmSequence++;
// Use async task to gather PCM data (engine loads it from the asset)
Task.Run(DownloadData);
}
}
}
/// <inheritdoc />
public override void Draw()
{
@@ -220,7 +257,13 @@ namespace FlaxEditor.Viewport.Previews
/// </summary>
private void DownloadData()
{
var asset = _asset;
AudioClip asset;
int sequence;
lock (_locker)
{
asset = _asset;
sequence = _pcmSequence;
}
if (!asset)
return;
@@ -245,8 +288,9 @@ namespace FlaxEditor.Viewport.Previews
lock (_locker)
{
// If asset has been modified during data fetching, ignore it
if (_asset == asset)
if (_asset == asset && _pcmSequence == sequence)
{
_pcmSequence++;
_pcmData = data;
_pcmInfo = dataInfo;
}

View File

@@ -19,6 +19,48 @@ namespace FlaxEditor.Windows.Assets
/// <seealso cref="FlaxEditor.Windows.Assets.AssetEditorWindow" />
public sealed class AudioClipWindow : AssetEditorWindowBase<AudioClip>
{
private sealed class Preview : AudioClipPreview
{
public AudioSource Source;
public override void Draw()
{
base.Draw();
if (!Source || Source.State == AudioSource.States.Stopped)
return;
var info = DataInfo;
if (!HasData || info.NumSamples == 0)
return;
var height = Height;
var width = Width;
// Draw current time
var playPosition = Source.Time / info.Length * width;
Render2D.DrawLine(new Float2(playPosition, 0), new Float2(playPosition, height), Color.White);
// Draw current mouse pointer
var mousePos = PointFromScreen(Input.MouseScreenPosition);
if (mousePos.X > 0 && mousePos.Y > 0 && mousePos.X < width && mousePos.Y < height)
{
Render2D.DrawLine(new Float2(mousePos.X, 0), new Float2(mousePos.X, height), Color.White.AlphaMultiplied(0.3f));
}
}
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (base.OnMouseDown(location, button))
return true;
if (button == MouseButton.Left && Source && Source.State != AudioSource.States.Stopped)
{
var info = DataInfo;
Source.Time = location.X / Width * info.Length;
}
return false;
}
}
/// <summary>
/// The AudioClip properties proxy object.
/// </summary>
@@ -113,7 +155,7 @@ namespace FlaxEditor.Windows.Assets
}
private readonly SplitPanel _split;
private readonly AudioClipPreview _preview;
private readonly Preview _preview;
private readonly CustomEditorPresenter _propertiesEditor;
private readonly ToolStripButton _playButton;
private readonly ToolStripButton _pauseButton;
@@ -137,7 +179,7 @@ namespace FlaxEditor.Windows.Assets
};
// Preview
_preview = new AudioClipPreview
_preview = new Preview
{
DrawMode = AudioClipPreview.DrawModes.Fill,
AnchorPreset = AnchorPresets.StretchAll,
@@ -154,10 +196,13 @@ namespace FlaxEditor.Windows.Assets
// Toolstrip
_toolstrip.AddButton(Editor.Icons.Import64, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
_toolstrip.AddSeparator();
_playButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Play64, OnPlay).LinkTooltip("Play/stop audio");
_pauseButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Pause64, OnPause).LinkTooltip("Pause audio");
_playButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Play64, OnPlay).LinkTooltip("Play/stop audio (F5)");
_pauseButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Pause64, OnPause).LinkTooltip("Pause audio (F6)");
_toolstrip.AddSeparator();
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/audio/audio-clip.html")).LinkTooltip("See documentation to learn more");
InputActions.Add(options => options.Play, OnPlay);
InputActions.Add(options => options.Pause, OnPause);
}
private void OnPlay()
@@ -171,8 +216,10 @@ namespace FlaxEditor.Windows.Assets
_previewSource = new AudioSource
{
Parent = _previewScene,
AllowSpatialization = false,
Clip = _asset,
};
_preview.Source = _previewSource;
}
if (_previewSource.State == AudioSource.States.Playing)
_previewSource.Stop();
@@ -184,7 +231,12 @@ namespace FlaxEditor.Windows.Assets
private void OnPause()
{
if (_previewSource)
_previewSource.Pause();
{
if (_previewSource.State == AudioSource.States.Playing)
_previewSource.Pause();
else
_previewSource.Play();
}
UpdateToolstrip();
}
@@ -230,6 +282,7 @@ namespace FlaxEditor.Windows.Assets
{
if (_previewSource)
{
_preview.Source = null;
_previewSource.Stop();
FlaxEngine.Object.Destroy(_previewSource);
_previewSource = null;
@@ -263,6 +316,7 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.BuildLayout();
if (_previewSource)
_previewSource.Stop();
_preview.RefreshPreview();
// Setup
ClearEditedFlag();

View File

@@ -164,6 +164,7 @@ namespace FlaxEditor.Windows
// Check if clear filters
if (_itemsSearchBox.TextLength == 0 && !_viewDropdown.HasSelection)
{
_view.IsSearching = false;
RefreshView();
return;
}

View File

@@ -815,7 +815,10 @@ namespace FlaxEditor.Windows
/// </summary>
public void RefreshView()
{
RefreshView(SelectedNode);
if (_view.IsSearching)
UpdateItemsSearch();
else
RefreshView(SelectedNode);
}
/// <summary>

View File

@@ -31,17 +31,9 @@
#include "XAudio2/AudioBackendXAudio2.h"
#endif
const Char* ToString(AudioFormat value)
float AudioDataInfo::GetLength() const
{
switch (value)
{
case AudioFormat::Raw:
return TEXT("Raw");
case AudioFormat::Vorbis:
return TEXT("Vorbis");
default:
return TEXT("");
}
return (float)NumSamples / (float)Math::Max(1U, SampleRate * NumChannels);
}
Array<AudioListener*> Audio::Listeners;
@@ -57,6 +49,7 @@ namespace
float Volume = 1.0f;
int32 ActiveDeviceIndex = -1;
bool MuteOnFocusLoss = true;
bool EnableHRTF = true;
}
class AudioService : public EngineService
@@ -94,6 +87,7 @@ void AudioSettings::Apply()
if (AudioBackend::Instance != nullptr)
{
Audio::SetDopplerFactor(DopplerFactor);
Audio::SetEnableHRTF(EnableHRTF);
}
}
@@ -141,6 +135,19 @@ void Audio::SetDopplerFactor(float value)
AudioBackend::SetDopplerFactor(value);
}
bool Audio::GetEnableHRTF()
{
return EnableHRTF;
}
void Audio::SetEnableHRTF(bool value)
{
if (EnableHRTF == value)
return;
EnableHRTF = value;
AudioBackend::Listener::ReinitializeAll();
}
void Audio::OnAddListener(AudioListener* listener)
{
ASSERT(!Listeners.Contains(listener));

View File

@@ -0,0 +1,12 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
namespace FlaxEngine
{
partial struct AudioDataInfo
{
/// <summary>
/// Gets the length of the audio data (in seconds).
/// </summary>
public float Length => (float)NumSamples / (float)Mathf.Max(1U, SampleRate * NumChannels);
}
}

View File

@@ -13,12 +13,11 @@
/// </summary>
API_CLASS(Static) class FLAXENGINE_API Audio
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Audio);
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Audio);
friend class AudioStreamingHandler;
friend class AudioClip;
public:
/// <summary>
/// The audio listeners collection registered by the service.
/// </summary>
@@ -45,7 +44,6 @@ public:
API_EVENT() static Action ActiveDeviceChanged;
public:
/// <summary>
/// Gets the active device.
/// </summary>
@@ -65,7 +63,6 @@ public:
API_PROPERTY() static void SetActiveDeviceIndex(int32 index);
public:
/// <summary>
/// Gets the master volume applied to all the audio sources (normalized to range 0-1).
/// </summary>
@@ -90,8 +87,18 @@ public:
/// <param name="value">The value.</param>
API_PROPERTY() static void SetDopplerFactor(float value);
public:
/// <summary>
/// Gets the preference to use HRTF audio (when available on platform). Default is true.
/// </summary>
API_PROPERTY() static bool GetEnableHRTF();
/// <summary>
/// Sets the preference to use HRTF audio (when available on platform). Default is true.
/// </summary>
/// <param name="value">The value.</param>
API_PROPERTY() static void SetEnableHRTF(bool value);
public:
static void OnAddListener(AudioListener* listener);
static void OnRemoveListener(AudioListener* listener);

View File

@@ -16,6 +16,13 @@ class AudioBackend
public:
enum class FeatureFlags
{
None = 0,
// Supports multi-channel (incl. stereo) audio playback for spatial sources (3D), otherwise 3d audio needs to be in mono format.
SpatialMultiChannel = 1,
};
static AudioBackend* Instance;
private:
@@ -25,6 +32,7 @@ private:
virtual void Listener_OnRemove(AudioListener* listener) = 0;
virtual void Listener_VelocityChanged(AudioListener* listener) = 0;
virtual void Listener_TransformChanged(AudioListener* listener) = 0;
virtual void Listener_ReinitializeAll() = 0;
// Source
virtual void Source_OnAdd(AudioSource* source) = 0;
@@ -33,9 +41,9 @@ private:
virtual void Source_TransformChanged(AudioSource* source) = 0;
virtual void Source_VolumeChanged(AudioSource* source) = 0;
virtual void Source_PitchChanged(AudioSource* source) = 0;
virtual void Source_PanChanged(AudioSource* source) = 0;
virtual void Source_IsLoopingChanged(AudioSource* source) = 0;
virtual void Source_MinDistanceChanged(AudioSource* source) = 0;
virtual void Source_AttenuationChanged(AudioSource* source) = 0;
virtual void Source_SpatialSetupChanged(AudioSource* source) = 0;
virtual void Source_ClipLoaded(AudioSource* source) = 0;
virtual void Source_Cleanup(AudioSource* source) = 0;
virtual void Source_Play(AudioSource* source) = 0;
@@ -50,12 +58,13 @@ private:
virtual void Source_DequeueProcessedBuffers(AudioSource* source) = 0;
// Buffer
virtual void Buffer_Create(uint32& bufferId) = 0;
virtual void Buffer_Delete(uint32& bufferId) = 0;
virtual uint32 Buffer_Create() = 0;
virtual void Buffer_Delete(uint32 bufferId) = 0;
virtual void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) = 0;
// Base
virtual const Char* Base_Name() = 0;
virtual FeatureFlags Base_Features() = 0;
virtual void Base_OnActiveDeviceChanged() = 0;
virtual void Base_SetDopplerFactor(float value) = 0;
virtual void Base_SetVolume(float value) = 0;
@@ -94,6 +103,11 @@ public:
{
Instance->Listener_TransformChanged(listener);
}
FORCE_INLINE static void ReinitializeAll()
{
Instance->Listener_ReinitializeAll();
}
};
class Source
@@ -130,19 +144,19 @@ public:
Instance->Source_PitchChanged(source);
}
FORCE_INLINE static void PanChanged(AudioSource* source)
{
Instance->Source_PanChanged(source);
}
FORCE_INLINE static void IsLoopingChanged(AudioSource* source)
{
Instance->Source_IsLoopingChanged(source);
}
FORCE_INLINE static void MinDistanceChanged(AudioSource* source)
FORCE_INLINE static void SpatialSetupChanged(AudioSource* source)
{
Instance->Source_MinDistanceChanged(source);
}
FORCE_INLINE static void AttenuationChanged(AudioSource* source)
{
Instance->Source_AttenuationChanged(source);
Instance->Source_SpatialSetupChanged(source);
}
FORCE_INLINE static void ClipLoaded(AudioSource* source)
@@ -210,15 +224,14 @@ public:
{
public:
FORCE_INLINE static void Create(uint32& bufferId)
FORCE_INLINE static uint32 Create()
{
Instance->Buffer_Create(bufferId);
return Instance->Buffer_Create();
}
FORCE_INLINE static void Delete(uint32& bufferId)
FORCE_INLINE static void Delete(uint32 bufferId)
{
if (Instance)
Instance->Buffer_Delete(bufferId);
Instance->Buffer_Delete(bufferId);
}
FORCE_INLINE static void Write(uint32 bufferId, byte* samples, const AudioDataInfo& info)
@@ -232,6 +245,11 @@ public:
return Instance->Base_Name();
}
FORCE_INLINE static FeatureFlags Features()
{
return Instance->Base_Features();
}
FORCE_INLINE static void OnActiveDeviceChanged()
{
Instance->Base_OnActiveDeviceChanged();

View File

@@ -19,7 +19,7 @@ REGISTER_BINARY_ASSET_WITH_UPGRADER(AudioClip, "FlaxEngine.AudioClip", AudioClip
bool AudioClip::StreamingTask::Run()
{
AssetReference<AudioClip> ref = _asset.Get();
if (ref == nullptr)
if (ref == nullptr || AudioBackend::Instance == nullptr)
return true;
ScopeLock lock(ref->Locker);
const auto& queue = ref->StreamingQueue;
@@ -32,77 +32,25 @@ bool AudioClip::StreamingTask::Run()
{
const auto idx = queue[i];
uint32& bufferId = clip->Buffers[idx];
if (bufferId == AUDIO_BUFFER_ID_INVALID)
{
AudioBackend::Buffer::Create(bufferId);
bufferId = AudioBackend::Buffer::Create();
}
else
{
// Release unused data
AudioBackend::Buffer::Delete(bufferId);
bufferId = 0;
bufferId = AUDIO_BUFFER_ID_INVALID;
}
}
// Load missing buffers data
const auto format = clip->Format();
AudioDataInfo info = clip->AudioHeader.Info;
const uint32 bytesPerSample = info.BitDepth / 8;
// Load missing buffers data (from asset chunks)
for (int32 i = 0; i < queue.Count(); i++)
{
const auto idx = queue[i];
const uint32 bufferId = clip->Buffers[idx];
if (bufferId == AUDIO_BUFFER_ID_INVALID)
continue;
byte* data;
uint32 dataSize;
Array<byte> outTmp;
const auto chunk = clip->GetChunk(idx);
if (chunk == nullptr || chunk->IsMissing())
if (clip->WriteBuffer(queue[i]))
{
LOG(Warning, "Missing audio streaming data chunk.");
return true;
}
// Get raw data or decompress it
switch (format)
{
case AudioFormat::Vorbis:
{
#if COMPILE_WITH_OGG_VORBIS
OggVorbisDecoder decoder;
MemoryReadStream stream(chunk->Get(), chunk->Size());
AudioDataInfo outInfo;
if (decoder.Convert(&stream, outInfo, outTmp))
{
LOG(Warning, "Audio data decode failed (OggVorbisDecoder).");
return true;
}
// TODO: validate decompressed data header info?
data = outTmp.Get();
dataSize = outTmp.Count();
#else
LOG(Warning, "OggVorbisDecoder is disabled.");
return true;
#endif
}
break;
case AudioFormat::Raw:
{
data = chunk->Get();
dataSize = chunk->Size();
}
break;
default:
return true;
}
// Write samples to the audio buffer
info.NumSamples = dataSize / bytesPerSample;
AudioBackend::Buffer::Write(bufferId, data, info);
}
// Update the sources
@@ -150,11 +98,6 @@ AudioClip::~AudioClip()
ASSERT(_streamingTask == nullptr);
}
float AudioClip::GetLength() const
{
return AudioHeader.Info.NumSamples / static_cast<float>(Math::Max(1U, AudioHeader.Info.SampleRate * AudioHeader.Info.NumChannels));
}
float AudioClip::GetBufferStartTime(int32 bufferIndex) const
{
ASSERT(IsLoaded());
@@ -164,7 +107,7 @@ float AudioClip::GetBufferStartTime(int32 bufferIndex) const
int32 AudioClip::GetFirstBufferIndex(float time, float& offset) const
{
ASSERT(IsLoaded());
ASSERT(time >= 0 && time <= GetLength());
time = Math::Clamp(time, 0.0f, GetLength());
for (int32 i = 0; i < _totalChunks; i++)
{
@@ -205,6 +148,8 @@ bool AudioClip::ExtractData(Array<byte>& resultData, AudioDataInfo& resultDataIn
ASSERT(!IsVirtual());
if (WaitForLoaded())
return true;
ScopeLock lock(Locker);
auto storageLock = Storage->LockSafe();
// Allocate memory
ASSERT(_totalChunksSize > 0);
@@ -250,6 +195,7 @@ bool AudioClip::ExtractDataRaw(Array<byte>& resultData, AudioDataInfo& resultDat
{
if (WaitForLoaded())
return true;
ScopeLock lock(Locker);
switch (Format())
{
case AudioFormat::Raw:
@@ -362,7 +308,7 @@ bool AudioClip::init(AssetInitData& initData)
}
if (initData.CustomData.Length() != sizeof(AudioHeader))
{
LOG(Warning, "Missing audio clip header.");
LOG(Warning, "Missing audio data.");
return true;
}
@@ -422,64 +368,114 @@ Asset::LoadResult AudioClip::load()
// Load the whole audio at once
if (LoadChunk(0))
return LoadResult::CannotLoadData;
auto chunk0 = GetChunk(0);
if (chunk0 == nullptr || chunk0->IsMissing())
return LoadResult::MissingDataChunk;
// Create single buffer
if (!AudioBackend::Instance)
return LoadResult::Failed;
uint32 bufferId;
AudioBackend::Buffer::Create(bufferId);
Buffers[0] = bufferId;
Buffers[0] = AudioBackend::Buffer::Create();
// Write samples to the audio buffer
switch (AudioHeader.Format)
{
case AudioFormat::Vorbis:
{
#if COMPILE_WITH_OGG_VORBIS
OggVorbisDecoder decoder;
MemoryReadStream stream(chunk0->Get(), chunk0->Size());
AudioDataInfo outInfo;
Array<byte> outTmp;
if (decoder.Convert(&stream, outInfo, outTmp))
{
LOG(Warning, "Audio data decode failed (OggVorbisDecoder).");
return LoadResult::InvalidData;
}
AudioBackend::Buffer::Write(bufferId, outTmp.Get(), outInfo);
#endif
break;
}
case AudioFormat::Raw:
{
AudioBackend::Buffer::Write(bufferId, chunk0->Get(), AudioHeader.Info);
break;
}
default:
return LoadResult::InvalidData;
}
// Write data to audio buffer
if (WriteBuffer(0))
return LoadResult::Failed;
return LoadResult::Ok;
}
void AudioClip::unload(bool isReloading)
{
bool hasAnyBuffer = false;
for (const AUDIO_BUFFER_ID_TYPE bufferId : Buffers)
hasAnyBuffer |= bufferId != AUDIO_BUFFER_ID_INVALID;
// Stop any audio sources that are using this clip right now
// TODO: find better way to collect audio sources using audio clip and impl it for AudioStreamingHandler too
for (int32 sourceIndex = 0; sourceIndex < Audio::Sources.Count(); sourceIndex++)
{
const auto src = Audio::Sources[sourceIndex];
if (src->Clip == this)
src->Stop();
}
StopStreaming();
StreamingQueue.Clear();
if (Buffers.HasItems())
if (hasAnyBuffer && AudioBackend::Instance)
{
for (int32 i = 0; i < Buffers.Count(); i++)
for (AUDIO_BUFFER_ID_TYPE bufferId : Buffers)
{
auto bufferId = Buffers[i];
if (bufferId != AUDIO_BUFFER_ID_INVALID)
{
AudioBackend::Buffer::Delete(bufferId);
}
}
Buffers.Clear();
}
Buffers.Clear();
_totalChunks = 0;
Platform::MemoryClear(&AudioHeader, sizeof(AudioHeader));
}
bool AudioClip::WriteBuffer(int32 chunkIndex)
{
// Ignore if buffer is not created
const uint32 bufferId = Buffers[chunkIndex];
if (bufferId == AUDIO_BUFFER_ID_INVALID)
return false;
// Ensure audio backend exists
if (AudioBackend::Instance == nullptr)
return true;
const auto chunk = GetChunk(chunkIndex);
if (chunk == nullptr || chunk->IsMissing())
{
LOG(Warning, "Missing audio data.");
return true;
}
Span<byte> data;
Array<byte> tmp1, tmp2;
AudioDataInfo info = AudioHeader.Info;
const uint32 bytesPerSample = info.BitDepth / 8;
// Get raw data or decompress it
switch (Format())
{
case AudioFormat::Vorbis:
{
#if COMPILE_WITH_OGG_VORBIS
OggVorbisDecoder decoder;
MemoryReadStream stream(chunk->Get(), chunk->Size());
AudioDataInfo tmpInfo;
if (decoder.Convert(&stream, tmpInfo, tmp1))
{
LOG(Warning, "Audio data decode failed (OggVorbisDecoder).");
return true;
}
// TODO: validate decompressed data header info?
data = Span<byte>(tmp1.Get(), tmp1.Count());
#else
LOG(Warning, "OggVorbisDecoder is disabled.");
return true;
#endif
}
break;
case AudioFormat::Raw:
{
data = Span<byte>(chunk->Get(), chunk->Size());
}
break;
default:
return true;
}
info.NumSamples = data.Length() / bytesPerSample;
// Convert to Mono if used as 3D source and backend doesn't support it
if (Is3D() && info.NumChannels > 1 && EnumHasNoneFlags(AudioBackend::Features(), AudioBackend::FeatureFlags::SpatialMultiChannel))
{
const uint32 samplesPerChannel = info.NumSamples / info.NumChannels;
const uint32 monoBufferSize = samplesPerChannel * bytesPerSample;
tmp2.Resize(monoBufferSize);
AudioTool::ConvertToMono(data.Get(), tmp2.Get(), info.BitDepth, samplesPerChannel, info.NumChannels);
info.NumChannels = 1;
info.NumSamples = samplesPerChannel;
data = Span<byte>(tmp2.Get(), tmp2.Count());
}
// Write samples to the audio buffer
AudioBackend::Buffer::Write(bufferId, data.Get(), info);
return false;
}

View File

@@ -17,9 +17,9 @@ class AudioSource;
/// <seealso cref="BinaryAsset" />
API_CLASS(NoSpawn) class FLAXENGINE_API AudioClip : public BinaryAsset, public StreamableResource
{
DECLARE_BINARY_ASSET_HEADER(AudioClip, 2);
public:
DECLARE_BINARY_ASSET_HEADER(AudioClip, 2);
public:
/// <summary>
/// Audio Clip resource header structure, version 2. Added on 08.08.2019.
/// </summary>
@@ -40,12 +40,10 @@ public:
class StreamingTask : public ThreadPoolTask
{
private:
WeakAssetReference<AudioClip> _asset;
FlaxStorage::LockData _dataLock;
public:
/// <summary>
/// Init
/// </summary>
@@ -57,7 +55,6 @@ public:
}
public:
// [ThreadPoolTask]
bool HasReference(Object* resource) const override
{
@@ -65,28 +62,24 @@ public:
}
protected:
// [ThreadPoolTask]
bool Run() override;
void OnEnd() override;
};
private:
int32 _totalChunks;
int32 _totalChunksSize;
StreamingTask* _streamingTask;
float _buffersStartTimes[ASSET_FILE_DATA_CHUNKS + 1];
public:
/// <summary>
/// Finalizes an instance of the <see cref="AudioClip"/> class.
/// </summary>
~AudioClip();
public:
/// <summary>
/// The audio clip header data.
/// </summary>
@@ -103,11 +96,9 @@ public:
Array<int32, FixedAllocation<ASSET_FILE_DATA_CHUNKS>> StreamingQueue;
public:
/// <summary>
/// Gets the audio data format.
/// </summary>
/// <returns>The value.</returns>
API_PROPERTY() FORCE_INLINE AudioFormat Format() const
{
return AudioHeader.Format;
@@ -116,7 +107,6 @@ public:
/// <summary>
/// Gets the audio data info metadata.
/// </summary>
/// <returns>The value.</returns>
API_PROPERTY() FORCE_INLINE const AudioDataInfo& Info() const
{
return AudioHeader.Info;
@@ -125,7 +115,6 @@ public:
/// <summary>
/// Returns true if the sound source is three dimensional (volume and pitch varies based on listener distance and velocity).
/// </summary>
/// <returns>The value.</returns>
API_PROPERTY() FORCE_INLINE bool Is3D() const
{
return AudioHeader.Is3D;
@@ -134,7 +123,6 @@ public:
/// <summary>
/// Returns true if the sound is using data streaming.
/// </summary>
/// <returns>The value.</returns>
API_PROPERTY() FORCE_INLINE bool IsStreamable() const
{
return AudioHeader.Streamable;
@@ -143,7 +131,6 @@ public:
/// <summary>
/// Returns true if the sound data is during streaming by an async task.
/// </summary>
/// <returns>The streaming task existence value flag.</returns>
API_PROPERTY() FORCE_INLINE bool IsStreamingTaskActive() const
{
return _streamingTask != nullptr;
@@ -152,11 +139,12 @@ public:
/// <summary>
/// Gets the length of the audio clip (in seconds).
/// </summary>
/// <returns>The value.</returns>
API_PROPERTY() float GetLength() const;
API_PROPERTY() float GetLength() const
{
return AudioHeader.Info.GetLength();
}
public:
/// <summary>
/// Gets the buffer start time (in seconds).
/// </summary>
@@ -173,7 +161,6 @@ public:
int32 GetFirstBufferIndex(float time, float& offset) const;
public:
/// <summary>
/// Extracts the source audio data from the asset storage. Loads the whole asset. The result data is in an asset format.
/// </summary>
@@ -199,10 +186,9 @@ public:
API_FUNCTION() bool ExtractDataRaw(API_PARAM(Out) Array<byte>& resultData, API_PARAM(Out) AudioDataInfo& resultDataInfo);
public:
// [BinaryAsset]
void CancelStreaming() override;
// [StreamableResource]
int32 GetMaxResidency() const override;
int32 GetCurrentResidency() const override;
@@ -213,9 +199,12 @@ public:
void CancelStreamingTasks() override;
protected:
// [BinaryAsset]
bool init(AssetInitData& initData) override;
LoadResult load() override;
void unload(bool isReloading) override;
private:
// Writes audio samples into Audio Backend buffer and handles automatic decompression or format conversion for runtime playback.
bool WriteBuffer(int32 chunkIndex);
};

View File

@@ -10,9 +10,9 @@
/// </summary>
API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API AudioSettings : public SettingsBase
{
DECLARE_SCRIPTING_TYPE_MINIMAL(AudioSettings);
public:
DECLARE_SCRIPTING_TYPE_MINIMAL(AudioSettings);
public:
/// <summary>
/// If checked, audio playback will be disabled in build game. Can be used if game uses custom audio playback engine.
/// </summary>
@@ -31,8 +31,14 @@ public:
API_FIELD(Attributes="EditorOrder(200), DefaultValue(true), EditorDisplay(\"General\", \"Mute On Focus Loss\")")
bool MuteOnFocusLoss = true;
public:
/// <summary>
/// Enables or disables HRTF audio for in-engine processing of 3D audio (if supported by platform).
/// If enabled, the user should be using two-channel/headphones audio output and have all other surround virtualization disabled (Atmos, DTS:X, vendor specific, etc.)
/// </summary>
API_FIELD(Attributes="EditorOrder(300), DefaultValue(true), EditorDisplay(\"Spatial Audio\")")
bool EnableHRTF = true;
public:
/// <summary>
/// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use.
/// </summary>
@@ -46,5 +52,6 @@ public:
DESERIALIZE(DisableAudio);
DESERIALIZE(DopplerFactor);
DESERIALIZE(MuteOnFocusLoss);
DESERIALIZE(EnableHRTF);
}
};

View File

@@ -16,10 +16,10 @@ AudioSource::AudioSource(const SpawnParams& params)
, _velocity(Vector3::Zero)
, _volume(1.0f)
, _pitch(1.0f)
, _minDistance(1.0f)
, _attenuation(1.0f)
, _minDistance(1000.0f)
, _loop(false)
, _playOnStart(false)
, _allowSpatialization(true)
{
Clip.Changed.Bind<AudioSource, &AudioSource::OnClipChanged>(this);
Clip.Loaded.Bind<AudioSource, &AudioSource::OnClipLoaded>(this);
@@ -30,13 +30,9 @@ void AudioSource::SetVolume(float value)
value = Math::Saturate(value);
if (Math::NearEqual(_volume, value))
return;
_volume = value;
if (SourceIDs.HasItems())
{
AudioBackend::Source::VolumeChanged(this);
}
}
void AudioSource::SetPitch(float value)
@@ -44,27 +40,30 @@ void AudioSource::SetPitch(float value)
value = Math::Clamp(value, 0.5f, 2.0f);
if (Math::NearEqual(_pitch, value))
return;
_pitch = value;
if (SourceIDs.HasItems())
{
AudioBackend::Source::PitchChanged(this);
}
}
void AudioSource::SetPan(float value)
{
value = Math::Clamp(value, -1.0f, 1.0f);
if (Math::NearEqual(_pan, value))
return;
_pan = value;
if (SourceIDs.HasItems())
AudioBackend::Source::PanChanged(this);
}
void AudioSource::SetIsLooping(bool value)
{
if (_loop == value)
return;
_loop = value;
// When streaming we handle looping manually by the proper buffers submission
if (SourceIDs.HasItems() && !UseStreaming())
{
AudioBackend::Source::IsLoopingChanged(this);
}
}
void AudioSource::SetPlayOnStart(bool value)
@@ -77,13 +76,9 @@ void AudioSource::SetMinDistance(float value)
value = Math::Max(0.0f, value);
if (Math::NearEqual(_minDistance, value))
return;
_minDistance = value;
if (SourceIDs.HasItems())
{
AudioBackend::Source::MinDistanceChanged(this);
}
AudioBackend::Source::SpatialSetupChanged(this);
}
void AudioSource::SetAttenuation(float value)
@@ -91,13 +86,28 @@ void AudioSource::SetAttenuation(float value)
value = Math::Max(0.0f, value);
if (Math::NearEqual(_attenuation, value))
return;
_attenuation = value;
if (SourceIDs.HasItems())
{
AudioBackend::Source::AttenuationChanged(this);
}
AudioBackend::Source::SpatialSetupChanged(this);
}
void AudioSource::SetDopplerFactor(float value)
{
value = Math::Max(0.0f, value);
if (Math::NearEqual(_dopplerFactor, value))
return;
_dopplerFactor = value;
if (SourceIDs.HasItems())
AudioBackend::Source::SpatialSetupChanged(this);
}
void AudioSource::SetAllowSpatialization(bool value)
{
if (_allowSpatialization == value)
return;
_allowSpatialization = value;
if (SourceIDs.HasItems())
AudioBackend::Source::SpatialSetupChanged(this);
}
void AudioSource::Play()
@@ -231,7 +241,7 @@ bool AudioSource::Is3D() const
{
if (Clip == nullptr || Clip->WaitForLoaded())
return false;
return Clip->Is3D();
return _allowSpatialization && Clip->Is3D();
}
void AudioSource::RequestStreamingBuffersUpdate()
@@ -313,6 +323,22 @@ void AudioSource::PlayInternal()
_isActuallyPlayingSth = true;
}
#if USE_EDITOR
#include "Engine/Debug/DebugDraw.h"
void AudioSource::OnDebugDrawSelected()
{
// Draw influence range
if (_allowSpatialization)
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(_transform.Translation, _minDistance), Color::CornflowerBlue, 0, true);
// Base
Actor::OnDebugDrawSelected();
}
#endif
void AudioSource::Serialize(SerializeStream& stream, const void* otherObj)
{
// Base
@@ -323,10 +349,13 @@ void AudioSource::Serialize(SerializeStream& stream, const void* otherObj)
SERIALIZE(Clip);
SERIALIZE_MEMBER(Volume, _volume);
SERIALIZE_MEMBER(Pitch, _pitch);
SERIALIZE_MEMBER(Pan, _pan);
SERIALIZE_MEMBER(MinDistance, _minDistance);
SERIALIZE_MEMBER(Attenuation, _attenuation);
SERIALIZE_MEMBER(DopplerFactor, _dopplerFactor);
SERIALIZE_MEMBER(Loop, _loop);
SERIALIZE_MEMBER(PlayOnStart, _playOnStart);
SERIALIZE_MEMBER(AllowSpatialization, _allowSpatialization);
}
void AudioSource::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
@@ -334,13 +363,16 @@ void AudioSource::Deserialize(DeserializeStream& stream, ISerializeModifier* mod
// Base
Actor::Deserialize(stream, modifier);
DESERIALIZE(Clip);
DESERIALIZE_MEMBER(Volume, _volume);
DESERIALIZE_MEMBER(Pitch, _pitch);
DESERIALIZE_MEMBER(Pan, _pan);
DESERIALIZE_MEMBER(MinDistance, _minDistance);
DESERIALIZE_MEMBER(Attenuation, _attenuation);
DESERIALIZE_MEMBER(DopplerFactor, _dopplerFactor);
DESERIALIZE_MEMBER(Loop, _loop);
DESERIALIZE_MEMBER(PlayOnStart, _playOnStart);
DESERIALIZE_MEMBER(AllowSpatialization, _allowSpatialization);
DESERIALIZE(Clip);
}
bool AudioSource::HasContentLoaded() const

View File

@@ -46,10 +46,13 @@ private:
Vector3 _prevPos;
float _volume;
float _pitch;
float _pan = 0.0f;
float _minDistance;
float _attenuation;
float _attenuation = 1.0f;
float _dopplerFactor = 1.0f;
bool _loop;
bool _playOnStart;
bool _allowSpatialization;
bool _isActuallyPlayingSth = false;
bool _needToUpdateStreamingBuffers = false;
@@ -107,6 +110,20 @@ public:
/// </summary>
API_PROPERTY() void SetPitch(float value);
/// <summary>
/// Gets the stereo pan of the played audio (-1 is left speaker, 1 is right speaker, 0 is balanced). The default is 1. Used by non-spatial audio only.
/// </summary>
API_PROPERTY(Attributes="EditorOrder(30), DefaultValue(0.0f), Limit(-1.0f, 1.0f), EditorDisplay(\"Audio Source\")")
FORCE_INLINE float GetPan() const
{
return _pan;
}
/// <summary>
/// Sets the stereo pan of the played audio (-1 is left speaker, 1 is right speaker, 0 is balanced). The default is 0. Used by non-spatial audio only.
/// </summary>
API_PROPERTY() void SetPan(float value);
/// <summary>
/// Determines whether the audio clip should loop when it finishes playing.
/// </summary>
@@ -138,8 +155,7 @@ public:
/// <summary>
/// Gets the minimum distance at which audio attenuation starts. When the listener is closer to the source than this value, audio is heard at full volume. Once farther away the audio starts attenuating.
/// </summary>
/// <returns>The value.</returns>
API_PROPERTY(Attributes="EditorOrder(60), DefaultValue(1.0f), Limit(0, float.MaxValue, 0.1f), EditorDisplay(\"Audio Source\")")
API_PROPERTY(Attributes="EditorOrder(60), DefaultValue(1000.0f), Limit(0, float.MaxValue, 0.1f), EditorDisplay(\"Audio Source\")")
FORCE_INLINE float GetMinDistance() const
{
return _minDistance;
@@ -160,10 +176,38 @@ public:
}
/// <summary>
/// Sets the attenuation that controls how quickly does audio volume drop off as the listener moves further from the source.
/// Sets the attenuation that controls how quickly does audio volume drop off as the listener moves further from the source. At 0, no distance attenuation ever occurs.
/// </summary>
API_PROPERTY() void SetAttenuation(float value);
/// <summary>
/// Gets the doppler effect factor. Scale for source velocity. Default is 1.
/// </summary>
API_PROPERTY(Attributes="EditorOrder(75), DefaultValue(1.0f), Limit(0, float.MaxValue, 0.1f), EditorDisplay(\"Audio Source\")")
FORCE_INLINE float GetDopplerFactor() const
{
return _dopplerFactor;
}
/// <summary>
/// Sets the doppler effect factor. Scale for source velocity. Default is 1.
/// </summary>
API_PROPERTY() void SetDopplerFactor(float value);
/// <summary>
/// If checked, source can play spatial 3d audio (when audio clip supports it), otherwise will always play as 2d sound. At 0, no distance attenuation ever occurs.
/// </summary>
API_PROPERTY(Attributes="EditorOrder(80), DefaultValue(true), EditorDisplay(\"Audio Source\")")
FORCE_INLINE bool GetAllowSpatialization() const
{
return _allowSpatialization;
}
/// <summary>
/// If checked, source can play spatial 3d audio (when audio clip supports it), otherwise will always play as 2d sound.
/// </summary>
API_PROPERTY() void SetAllowSpatialization(bool value);
public:
/// <summary>
/// Starts playing the currently assigned audio clip.
@@ -257,6 +301,9 @@ public:
const Vector3 size(50);
return BoundingBox(_transform.Translation - size, _transform.Translation + size);
}
#endif
#if USE_EDITOR
void OnDebugDrawSelected() override;
#endif
void Serialize(SerializeStream& stream, const void* otherObj) override;
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;

View File

@@ -22,6 +22,10 @@ void AudioBackendNone::Listener_TransformChanged(AudioListener* listener)
{
}
void AudioBackendNone::Listener_ReinitializeAll()
{
}
void AudioBackendNone::Source_OnAdd(AudioSource* source)
{
source->Restore();
@@ -48,15 +52,15 @@ void AudioBackendNone::Source_PitchChanged(AudioSource* source)
{
}
void AudioBackendNone::Source_PanChanged(AudioSource* source)
{
}
void AudioBackendNone::Source_IsLoopingChanged(AudioSource* source)
{
}
void AudioBackendNone::Source_MinDistanceChanged(AudioSource* source)
{
}
void AudioBackendNone::Source_AttenuationChanged(AudioSource* source)
void AudioBackendNone::Source_SpatialSetupChanged(AudioSource* source)
{
}
@@ -110,12 +114,12 @@ void AudioBackendNone::Source_DequeueProcessedBuffers(AudioSource* source)
{
}
void AudioBackendNone::Buffer_Create(uint32& bufferId)
uint32 AudioBackendNone::Buffer_Create()
{
bufferId = 1;
return 1;
}
void AudioBackendNone::Buffer_Delete(uint32& bufferId)
void AudioBackendNone::Buffer_Delete(uint32 bufferId)
{
}
@@ -128,6 +132,11 @@ const Char* AudioBackendNone::Base_Name()
return TEXT("None");
}
AudioBackend::FeatureFlags AudioBackendNone::Base_Features()
{
return FeatureFlags::None;
}
void AudioBackendNone::Base_OnActiveDeviceChanged()
{
}

View File

@@ -18,15 +18,16 @@ public:
void Listener_OnRemove(AudioListener* listener) override;
void Listener_VelocityChanged(AudioListener* listener) override;
void Listener_TransformChanged(AudioListener* listener) override;
void Listener_ReinitializeAll() override;
void Source_OnAdd(AudioSource* source) override;
void Source_OnRemove(AudioSource* source) override;
void Source_VelocityChanged(AudioSource* source) override;
void Source_TransformChanged(AudioSource* source) override;
void Source_VolumeChanged(AudioSource* source) override;
void Source_PitchChanged(AudioSource* source) override;
void Source_PanChanged(AudioSource* source) override;
void Source_IsLoopingChanged(AudioSource* source) override;
void Source_MinDistanceChanged(AudioSource* source) override;
void Source_AttenuationChanged(AudioSource* source) override;
void Source_SpatialSetupChanged(AudioSource* source) override;
void Source_ClipLoaded(AudioSource* source) override;
void Source_Cleanup(AudioSource* source) override;
void Source_Play(AudioSource* source) override;
@@ -39,10 +40,11 @@ public:
void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) override;
void Source_QueueBuffer(AudioSource* source, uint32 bufferId) override;
void Source_DequeueProcessedBuffers(AudioSource* source) override;
void Buffer_Create(uint32& bufferId) override;
void Buffer_Delete(uint32& bufferId) override;
uint32 Buffer_Create() override;
void Buffer_Delete(uint32 bufferId) override;
void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) override;
const Char* Base_Name() override;
FeatureFlags Base_Features() override;
void Base_OnActiveDeviceChanged() override;
void Base_SetDopplerFactor(float value) override;
void Base_SetVolume(float value) override;

View File

@@ -17,10 +17,14 @@
//#define AL_LIBTYPE_STATIC
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#include <OpenAL/alext.h>
#define ALC_MULTIPLE_LISTENERS 0
#define FLAX_POS_TO_OAL(vec) ((ALfloat)vec.X * -0.01f), ((ALfloat)vec.Y * 0.01f), ((ALfloat)vec.Z * -0.01f)
#define FLAX_COORD_SCALE 0.01f // units are meters
#define FLAX_DST_TO_OAL(x) x * FLAX_COORD_SCALE
#define FLAX_POS_TO_OAL(vec) ((ALfloat)vec.X * -FLAX_COORD_SCALE), ((ALfloat)vec.Y * FLAX_COORD_SCALE), ((ALfloat)vec.Z * FLAX_COORD_SCALE)
#define FLAX_VEL_TO_OAL(vec) ((ALfloat)vec.X * -(FLAX_COORD_SCALE*FLAX_COORD_SCALE)), ((ALfloat)vec.Y * (FLAX_COORD_SCALE*FLAX_COORD_SCALE)), ((ALfloat)vec.Z * (FLAX_COORD_SCALE*FLAX_COORD_SCALE))
#if BUILD_RELEASE
#define ALC_CHECK_ERROR(method)
#else
@@ -55,8 +59,8 @@
namespace ALC
{
ALCdevice* Device = nullptr;
bool AL_EXT_float32 = false;
Array<ALCcontext*, FixedAllocation<AUDIO_MAX_LISTENERS>> Contexts;
AudioBackend::FeatureFlags Features = AudioBackend::FeatureFlags::None;
bool IsExtensionSupported(const char* extension)
{
@@ -100,7 +104,7 @@ namespace ALC
{
alcMakeContextCurrent(nullptr);
for (auto& context : Contexts)
for (ALCcontext* context : Contexts)
alcDestroyContext(context);
Contexts.Clear();
}
@@ -111,8 +115,8 @@ namespace ALC
{
AudioBackend::Listener::TransformChanged(listener);
const auto& velocity = listener->GetVelocity();
alListener3f(AL_VELOCITY, FLAX_POS_TO_OAL(velocity));
const Vector3 velocity = listener->GetVelocity();
alListener3f(AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
alListenerf(AL_GAIN, Audio::GetVolume());
}
}
@@ -124,8 +128,6 @@ namespace ALC
ASSERT(source->SourceIDs.IsEmpty());
const bool is3D = source->Is3D();
const bool loop = source->GetIsLooping() && !source->UseStreaming();
const Vector3 position = is3D ? source->GetPosition() : Vector3::Zero;
const Vector3 velocity = is3D ? source->GetVelocity() : Vector3::Zero;
ALC_FOR_EACH_CONTEXT()
uint32 sourceID = 0;
@@ -140,13 +142,33 @@ namespace ALC
alSourcef(sourceID, AL_GAIN, source->GetVolume());
alSourcef(sourceID, AL_PITCH, source->GetPitch());
alSourcef(sourceID, AL_SEC_OFFSET, 0.0f);
alSourcef(sourceID, AL_REFERENCE_DISTANCE, source->GetMinDistance());
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
alSourcei(sourceID, AL_LOOPING, loop);
alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D);
alSourcei(sourceID, AL_BUFFER, 0);
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
alSource3f(sourceID, AL_VELOCITY, FLAX_POS_TO_OAL(velocity));
if (is3D)
{
#ifdef AL_SOFT_source_spatialize
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE);
#endif
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
alSourcef(sourceID, AL_DOPPLER_FACTOR, source->GetDopplerFactor());
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(source->GetMinDistance()));
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(source->GetPosition()));
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(source->GetVelocity()));
}
else
{
alSourcef(sourceID, AL_ROLLOFF_FACTOR, 0.0f);
alSourcef(sourceID, AL_DOPPLER_FACTOR, 1.0f);
alSourcef(sourceID, AL_REFERENCE_DISTANCE, 0.0f);
alSource3f(sourceID, AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(sourceID, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
}
#ifdef AL_EXT_STEREO_ANGLES
const float panAngle = source->GetPan() * PI_HALF;
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
#endif
}
// Restore state after Cleanup
@@ -156,11 +178,11 @@ namespace ALC
void RebuildContexts(bool isChangingDevice)
{
LOG(Info, "Rebuild audio contexts");
LOG(Info, "Rebuilding audio contexts");
if (!isChangingDevice)
{
for (auto& source : Audio::Sources)
for (AudioSource* source : Audio::Sources)
source->Cleanup();
}
@@ -169,28 +191,36 @@ namespace ALC
if (Device == nullptr)
return;
ALCint attrsHrtf[] = { ALC_HRTF_SOFT, ALC_TRUE };
const ALCint* attrList = nullptr;
if (Audio::GetEnableHRTF())
{
LOG(Info, "Enabling OpenAL HRTF");
attrList = attrsHrtf;
}
#if ALC_MULTIPLE_LISTENERS
const int32 numListeners = Audio::Listeners.Count();
const int32 numContexts = numListeners > 1 ? numListeners : 1;
Contexts.Resize(numContexts);
ALC_FOR_EACH_CONTEXT()
ALCcontext* context = alcCreateContext(Device, nullptr);
ALCcontext* context = alcCreateContext(Device, attrList);
Contexts[i] = context;
}
#else
Contexts.Resize(1);
Contexts[0] = alcCreateContext(Device, nullptr);
Contexts[0] = alcCreateContext(Device, attrList);
#endif
// If only one context is available keep it active as an optimization.
// Audio listeners and sources will avoid excessive context switching in such case.
alcMakeContextCurrent(Contexts[0]);
for (auto& listener : Audio::Listeners)
for (AudioListener* listener : Audio::Listeners)
Listener::Rebuild(listener);
for (auto& source : Audio::Sources)
for (AudioSource* source : Audio::Sources)
Source::Rebuild(source);
}
}
@@ -276,8 +306,8 @@ void AudioBackendOAL::Listener_OnAdd(AudioListener* listener)
ALC::RebuildContexts(false);
#else
AudioBackend::Listener::TransformChanged(listener);
const auto& velocity = listener->GetVelocity();
alListener3f(AL_VELOCITY, FLAX_POS_TO_OAL(velocity));
const Vector3 velocity = listener->GetVelocity();
alListener3f(AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
alListenerf(AL_GAIN, Audio::GetVolume());
#endif
}
@@ -293,28 +323,34 @@ void AudioBackendOAL::Listener_VelocityChanged(AudioListener* listener)
{
ALC_GET_LISTENER_CONTEXT(listener)
const auto& velocity = listener->GetVelocity();
alListener3f(AL_VELOCITY, FLAX_POS_TO_OAL(velocity));
const Vector3 velocity = listener->GetVelocity();
alListener3f(AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
}
void AudioBackendOAL::Listener_TransformChanged(AudioListener* listener)
{
ALC_GET_LISTENER_CONTEXT(listener)
const Vector3& position = listener->GetPosition();
const Quaternion& orientation = listener->GetOrientation();
Vector3 alOrientation[2] =
const Vector3 position = listener->GetPosition();
const Quaternion orientation = listener->GetOrientation();
const Vector3 flipX(-1, 1, 1);
const Vector3 alOrientation[2] =
{
// Forward
orientation * Vector3::Forward,
orientation * Vector3::Forward * flipX,
// Up
orientation * Vector3::Up
orientation * Vector3::Up * flipX
};
alListenerfv(AL_ORIENTATION, (float*)alOrientation);
alListener3f(AL_POSITION, FLAX_POS_TO_OAL(position));
}
void AudioBackendOAL::Listener_ReinitializeAll()
{
ALC::RebuildContexts(false);
}
void AudioBackendOAL::Source_OnAdd(AudioSource* source)
{
ALC::Source::Rebuild(source);
@@ -327,25 +363,21 @@ void AudioBackendOAL::Source_OnRemove(AudioSource* source)
void AudioBackendOAL::Source_VelocityChanged(AudioSource* source)
{
const bool is3D = source->Is3D();
const Vector3 velocity = is3D ? source->GetVelocity() : Vector3::Zero;
if (!source->Is3D())
return;
ALC_FOR_EACH_CONTEXT()
const uint32 sourceID = source->SourceIDs[i];
alSource3f(sourceID, AL_VELOCITY, FLAX_POS_TO_OAL(velocity));
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(source->GetVelocity()));
}
}
void AudioBackendOAL::Source_TransformChanged(AudioSource* source)
{
const bool is3D = source->Is3D();
const Vector3 position = is3D ? source->GetPosition() : Vector3::Zero;
if (!source->Is3D())
return;
ALC_FOR_EACH_CONTEXT()
const uint32 sourceID = source->SourceIDs[i];
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(source->GetPosition()));
}
}
@@ -353,7 +385,6 @@ void AudioBackendOAL::Source_VolumeChanged(AudioSource* source)
{
ALC_FOR_EACH_CONTEXT()
const uint32 sourceID = source->SourceIDs[i];
alSourcef(sourceID, AL_GAIN, source->GetVolume());
}
}
@@ -362,36 +393,52 @@ void AudioBackendOAL::Source_PitchChanged(AudioSource* source)
{
ALC_FOR_EACH_CONTEXT()
const uint32 sourceID = source->SourceIDs[i];
alSourcef(sourceID, AL_PITCH, source->GetPitch());
}
}
void AudioBackendOAL::Source_PanChanged(AudioSource* source)
{
#ifdef AL_EXT_STEREO_ANGLES
const float panAngle = source->GetPan() * PI_HALF;
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
ALC_FOR_EACH_CONTEXT()
const uint32 sourceID = source->SourceIDs[i];
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
}
#endif
}
void AudioBackendOAL::Source_IsLoopingChanged(AudioSource* source)
{
const bool loop = source->GetIsLooping() && !source->UseStreaming();
ALC_FOR_EACH_CONTEXT()
const uint32 sourceID = source->SourceIDs[i];
alSourcei(sourceID, AL_LOOPING, loop);
}
}
void AudioBackendOAL::Source_MinDistanceChanged(AudioSource* source)
void AudioBackendOAL::Source_SpatialSetupChanged(AudioSource* source)
{
const bool is3D = source->Is3D();
ALC_FOR_EACH_CONTEXT()
const uint32 sourceID = source->SourceIDs[i];
alSourcef(sourceID, AL_REFERENCE_DISTANCE, source->GetMinDistance());
}
}
void AudioBackendOAL::Source_AttenuationChanged(AudioSource* source)
{
ALC_FOR_EACH_CONTEXT()
const uint32 sourceID = source->SourceIDs[i];
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D);
if (is3D)
{
#ifdef AL_SOFT_source_spatialize
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE);
#endif
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
alSourcef(sourceID, AL_DOPPLER_FACTOR, source->GetDopplerFactor());
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(source->GetMinDistance()));
}
else
{
alSourcef(sourceID, AL_ROLLOFF_FACTOR, 0.0f);
alSourcef(sourceID, AL_DOPPLER_FACTOR, 1.0f);
alSourcef(sourceID, AL_REFERENCE_DISTANCE, 0.0f);
}
}
}
@@ -405,7 +452,6 @@ void AudioBackendOAL::Source_ClipLoaded(AudioSource* source)
ALC_FOR_EACH_CONTEXT()
const uint32 sourceID = source->SourceIDs[i];
alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D);
alSourcei(sourceID, AL_LOOPING, loop);
}
@@ -415,7 +461,6 @@ void AudioBackendOAL::Source_Cleanup(AudioSource* source)
{
ALC_FOR_EACH_CONTEXT()
const uint32 sourceID = source->SourceIDs[i];
alSourcei(sourceID, AL_BUFFER, 0);
ALC_CHECK_ERROR(alSourcei);
alDeleteSources(1, &sourceID);
@@ -479,7 +524,7 @@ float AudioBackendOAL::Source_GetCurrentBufferTime(const AudioSource* source)
alGetSourcef(source->SourceIDs[0], AL_SEC_OFFSET, &time);
#else
ASSERT(source->Clip && source->Clip->IsLoaded());
const auto& clipInfo = source->Clip->AudioHeader.Info;
const AudioDataInfo& clipInfo = source->Clip->AudioHeader.Info;
ALint samplesPlayed;
alGetSourcei(source->SourceIDs[0], AL_SAMPLE_OFFSET, &samplesPlayed);
const uint32 totalSamples = clipInfo.NumSamples / clipInfo.NumChannels;
@@ -544,13 +589,15 @@ void AudioBackendOAL::Source_DequeueProcessedBuffers(AudioSource* source)
}
}
void AudioBackendOAL::Buffer_Create(uint32& bufferId)
uint32 AudioBackendOAL::Buffer_Create()
{
uint32 bufferId;
alGenBuffers(1, &bufferId);
ALC_CHECK_ERROR(alGenBuffers);
return bufferId;
}
void AudioBackendOAL::Buffer_Delete(uint32& bufferId)
void AudioBackendOAL::Buffer_Delete(uint32 bufferId)
{
alDeleteBuffers(1, &bufferId);
ALC_CHECK_ERROR(alDeleteBuffers);
@@ -567,7 +614,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
{
if (info.BitDepth > 16)
{
if (ALC::AL_EXT_float32)
if (ALC::IsExtensionSupported("AL_EXT_float32"))
{
const uint32 bufferSize = info.NumSamples * sizeof(float);
float* sampleBufferFloat = (float*)Allocator::Allocate(bufferSize);
@@ -666,10 +713,15 @@ const Char* AudioBackendOAL::Base_Name()
return TEXT("OpenAL");
}
AudioBackend::FeatureFlags AudioBackendOAL::Base_Features()
{
return ALC::Features;
}
void AudioBackendOAL::Base_OnActiveDeviceChanged()
{
// Cleanup
for (auto& source : Audio::Sources)
for (AudioSource* source : Audio::Sources)
source->Cleanup();
ALC::ClearContexts();
if (ALC::Device != nullptr)
@@ -679,7 +731,7 @@ void AudioBackendOAL::Base_OnActiveDeviceChanged()
}
// Open device
const auto& name = Audio::GetActiveDevice()->InternalName;
const StringAnsi& name = Audio::GetActiveDevice()->InternalName;
ALC::Device = alcOpenDevice(name.Get());
if (ALC::Device == nullptr)
{
@@ -688,7 +740,6 @@ void AudioBackendOAL::Base_OnActiveDeviceChanged()
}
// Setup
ALC::AL_EXT_float32 = ALC::IsExtensionSupported("AL_EXT_float32");
ALC::RebuildContexts(true);
}
@@ -800,10 +851,14 @@ bool AudioBackendOAL::Base_Init()
}
// Init
ALC::AL_EXT_float32 = ALC::IsExtensionSupported("AL_EXT_float32");
SetDopplerFactor(AudioSettings::Get()->DopplerFactor);
Base_SetDopplerFactor(AudioSettings::Get()->DopplerFactor);
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); // Default attenuation model
ALC::RebuildContexts(true);
Audio::SetActiveDeviceIndex(activeDeviceIndex);
#ifdef AL_SOFT_source_spatialize
if (ALC::IsExtensionSupported("AL_SOFT_source_spatialize"))
ALC::Features = EnumAddFlags(ALC::Features, FeatureFlags::SpatialMultiChannel);
#endif
// Log service info
LOG(Info, "{0} ({1})", String(alGetString(AL_RENDERER)), String(alGetString(AL_VERSION)));

View File

@@ -18,15 +18,16 @@ public:
void Listener_OnRemove(AudioListener* listener) override;
void Listener_VelocityChanged(AudioListener* listener) override;
void Listener_TransformChanged(AudioListener* listener) override;
void Listener_ReinitializeAll() override;
void Source_OnAdd(AudioSource* source) override;
void Source_OnRemove(AudioSource* source) override;
void Source_VelocityChanged(AudioSource* source) override;
void Source_TransformChanged(AudioSource* source) override;
void Source_VolumeChanged(AudioSource* source) override;
void Source_PitchChanged(AudioSource* source) override;
void Source_PanChanged(AudioSource* source) override;
void Source_IsLoopingChanged(AudioSource* source) override;
void Source_MinDistanceChanged(AudioSource* source) override;
void Source_AttenuationChanged(AudioSource* source) override;
void Source_SpatialSetupChanged(AudioSource* source) override;
void Source_ClipLoaded(AudioSource* source) override;
void Source_Cleanup(AudioSource* source) override;
void Source_Play(AudioSource* source) override;
@@ -39,10 +40,11 @@ public:
void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) override;
void Source_QueueBuffer(AudioSource* source, uint32 bufferId) override;
void Source_DequeueProcessedBuffers(AudioSource* source) override;
void Buffer_Create(uint32& bufferId) override;
void Buffer_Delete(uint32& bufferId) override;
uint32 Buffer_Create() override;
void Buffer_Delete(uint32 bufferId) override;
void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) override;
const Char* Base_Name() override;
FeatureFlags Base_Features() override;
void Base_OnActiveDeviceChanged() override;
void Base_SetDopplerFactor(float value) override;
void Base_SetVolume(float value) override;

View File

@@ -25,12 +25,10 @@ API_ENUM() enum class AudioFormat
Vorbis,
};
const Char* ToString(AudioFormat value);
/// <summary>
/// Meta-data describing a chunk of audio.
/// </summary>
API_STRUCT() struct AudioDataInfo
API_STRUCT(NoDefault) struct AudioDataInfo
{
DECLARE_SCRIPTING_TYPE_MINIMAL(AudioDataInfo);
@@ -53,4 +51,9 @@ DECLARE_SCRIPTING_TYPE_MINIMAL(AudioDataInfo);
/// The number of bits per sample.
/// </summary>
API_FIELD() uint32 BitDepth;
/// <summary>
/// Gets the length of the audio data (in seconds).
/// </summary>
float GetLength() const;
};

View File

@@ -9,6 +9,7 @@
#include "Engine/Audio/Audio.h"
#include "Engine/Audio/AudioSource.h"
#include "Engine/Audio/AudioListener.h"
#include "Engine/Threading/Threading.h"
#if PLATFORM_WINDOWS
// Tweak Win ver
@@ -26,7 +27,10 @@
#define MAX_OUTPUT_CHANNELS 8
#define MAX_CHANNELS_MATRIX_SIZE (MAX_INPUT_CHANNELS*MAX_OUTPUT_CHANNELS)
#define FLAX_POS_TO_XAUDIO(vec) X3DAUDIO_VECTOR(vec.X * 0.01f, vec.Y * 0.01f, vec.Z * 0.01f)
#define FLAX_COORD_SCALE 0.01f // units are meters
#define FLAX_DST_TO_XAUDIO(x) x * FLAX_COORD_SCALE
#define FLAX_POS_TO_XAUDIO(vec) X3DAUDIO_VECTOR(vec.X * FLAX_COORD_SCALE, vec.Y * FLAX_COORD_SCALE, vec.Z * FLAX_COORD_SCALE)
#define FLAX_VEL_TO_XAUDIO(vec) X3DAUDIO_VECTOR(vec.X * (FLAX_COORD_SCALE*FLAX_COORD_SCALE), vec.Y * (FLAX_COORD_SCALE*FLAX_COORD_SCALE), vec.Z * (FLAX_COORD_SCALE*FLAX_COORD_SCALE))
#define FLAX_VEC_TO_XAUDIO(vec) (*((X3DAUDIO_VECTOR*)&vec))
namespace XAudio2
@@ -68,7 +72,7 @@ namespace XAudio2
{
const Vector3& velocity = AudioListener->GetVelocity();
Data.Velocity = FLAX_POS_TO_XAUDIO(velocity);
Data.Velocity = FLAX_VEL_TO_XAUDIO(velocity);
}
};
@@ -103,7 +107,6 @@ namespace XAudio2
}
public:
AudioSource* Source;
void PeekSamples();
@@ -116,12 +119,15 @@ namespace XAudio2
WAVEFORMATEX Format;
XAUDIO2_SEND_DESCRIPTOR Destination;
float Pitch;
float Pan;
float StartTime;
float DopplerFactor;
uint64 LastBufferStartSamplesPlayed;
int32 BuffersProcessed;
bool IsDirty;
bool Is3D;
bool IsPlaying;
bool IsForceMono3D;
VoiceCallback Callback;
Source()
@@ -137,6 +143,7 @@ namespace XAudio2
Destination.Flags = 0;
Destination.pOutputVoice = nullptr;
Pitch = 1.0f;
Pan = 0.0f;
StartTime = 0.0f;
IsDirty = false;
Is3D = false;
@@ -166,7 +173,7 @@ namespace XAudio2
{
const Vector3& velocity = source->GetVelocity();
Data.Velocity = FLAX_POS_TO_XAUDIO(velocity);
Data.Velocity = FLAX_VEL_TO_XAUDIO(velocity);
}
};
@@ -198,13 +205,12 @@ namespace XAudio2
DWORD ChannelMask;
UINT32 SampleRate;
UINT32 Channels;
bool UseRedirectToLFE;
bool ForceDirty = true;
Listener Listeners[AUDIO_MAX_LISTENERS];
CriticalSection Locker;
Array<Source> Sources(32); // TODO: use ChunkedArray for better performance
Array<Buffer*> Buffers(64); // TODO: use ChunkedArray for better performance or use buffers pool?
EngineCallback Callback;
float MatrixCoefficients[MAX_CHANNELS_MATRIX_SIZE];
Listener* GetListener()
{
@@ -302,7 +308,6 @@ void AudioBackendXAudio2::Listener_OnAdd(AudioListener* listener)
void AudioBackendXAudio2::Listener_OnRemove(AudioListener* listener)
{
// Free listener
XAudio2::Listener* aListener = XAudio2::GetListener(listener);
if (aListener)
{
@@ -331,12 +336,18 @@ void AudioBackendXAudio2::Listener_TransformChanged(AudioListener* listener)
}
}
void AudioBackendXAudio2::Listener_ReinitializeAll()
{
// TODO: Implement XAudio2 reinitialization; read HRTF audio value from Audio class
}
void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
{
// Skip if has no clip (needs audio data to create a source - needs data format information)
if (source->Clip == nullptr || !source->Clip->IsLoaded())
return;
auto clip = source->Clip.Get();
ScopeLock lock(XAudio2::Locker);
// Get first free source
XAudio2::Source* aSource = nullptr;
@@ -360,10 +371,10 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
}
// Initialize audio data format information (from clip)
auto& header = clip->AudioHeader;
const auto& header = clip->AudioHeader;
auto& format = aSource->Format;
format.wFormatTag = WAVE_FORMAT_PCM;
format.nChannels = header.Info.NumChannels;
format.nChannels = source->Is3D() ? 1 : header.Info.NumChannels; // 3d audio is always mono (AudioClip auto-converts before buffer write)
format.nSamplesPerSec = header.Info.SampleRate;
format.wBitsPerSample = header.Info.BitDepth;
format.nBlockAlign = (WORD)(format.nChannels * (format.wBitsPerSample / 8));
@@ -389,12 +400,16 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
// Prepare source state
aSource->Callback.Source = source;
aSource->IsDirty = true;
aSource->Data.ChannelCount = header.Info.NumChannels;
aSource->Data.ChannelCount = format.nChannels;
aSource->Data.InnerRadius = FLAX_DST_TO_XAUDIO(source->GetMinDistance());
aSource->Is3D = source->Is3D();
aSource->IsForceMono3D = header.Is3D && header.Info.NumChannels > 1;
aSource->Pitch = source->GetPitch();
aSource->Data.InnerRadius = source->GetMinDistance();
aSource->Pan = source->GetPan();
aSource->DopplerFactor = source->GetDopplerFactor();
aSource->UpdateTransform(source);
aSource->UpdateVelocity(source);
aSource->Voice->SetVolume(source->GetVolume());
// 0 is invalid ID so shift them
sourceID++;
@@ -406,6 +421,7 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
void AudioBackendXAudio2::Source_OnRemove(AudioSource* source)
{
ScopeLock lock(XAudio2::Locker);
source->Cleanup();
}
@@ -448,6 +464,16 @@ void AudioBackendXAudio2::Source_PitchChanged(AudioSource* source)
}
}
void AudioBackendXAudio2::Source_PanChanged(AudioSource* source)
{
auto aSource = XAudio2::GetSource(source);
if (aSource)
{
aSource->Pan = source->GetPan();
aSource->IsDirty = true;
}
}
void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
{
auto aSource = XAudio2::GetSource(source);
@@ -462,8 +488,10 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
// Looping is defined during buffer submission so reset source buffer (this is called only for non-streamable sources that ue single buffer)
XAudio2::Locker.Lock();
const uint32 bufferId = source->Clip->Buffers[0];
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
XAudio2::Locker.Unlock();
const bool isPlaying = source->IsActuallyPlayingSth();
if (isPlaying)
@@ -491,23 +519,29 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
aSource->Voice->Start();
}
void AudioBackendXAudio2::Source_MinDistanceChanged(AudioSource* source)
void AudioBackendXAudio2::Source_SpatialSetupChanged(AudioSource* source)
{
auto aSource = XAudio2::GetSource(source);
if (aSource)
{
aSource->Data.InnerRadius = source->GetMinDistance();
// TODO: implement attenuation settings for 3d audio
auto clip = source->Clip.Get();
if (clip && clip->IsLoaded())
{
const auto& header = clip->AudioHeader;
aSource->Data.ChannelCount = source->Is3D() ? 1 : header.Info.NumChannels; // 3d audio is always mono (AudioClip auto-converts before buffer write)
aSource->IsForceMono3D = header.Is3D && header.Info.NumChannels > 1;
}
aSource->Is3D = source->Is3D();
aSource->DopplerFactor = source->GetDopplerFactor();
aSource->Data.InnerRadius = FLAX_DST_TO_XAUDIO(source->GetMinDistance());
aSource->IsDirty = true;
}
}
void AudioBackendXAudio2::Source_AttenuationChanged(AudioSource* source)
{
// TODO: implement it
}
void AudioBackendXAudio2::Source_ClipLoaded(AudioSource* source)
{
ScopeLock lock(XAudio2::Locker);
auto aSource = XAudio2::GetSource(source);
if (!aSource)
{
@@ -518,6 +552,7 @@ void AudioBackendXAudio2::Source_ClipLoaded(AudioSource* source)
void AudioBackendXAudio2::Source_Cleanup(AudioSource* source)
{
ScopeLock lock(XAudio2::Locker);
auto aSource = XAudio2::GetSource(source);
if (!aSource)
return;
@@ -590,7 +625,8 @@ float AudioBackendXAudio2::Source_GetCurrentBufferTime(const AudioSource* source
const auto& clipInfo = source->Clip->AudioHeader.Info;
XAUDIO2_VOICE_STATE state;
aSource->Voice->GetState(&state);
const UINT32 totalSamples = clipInfo.NumSamples / clipInfo.NumChannels;
const uint32 numChannels = clipInfo.NumChannels;
const uint32 totalSamples = clipInfo.NumSamples / numChannels;
state.SamplesPlayed -= aSource->LastBufferStartSamplesPlayed % totalSamples; // Offset by the last buffer start to get time relative to its begin
time = aSource->StartTime + (state.SamplesPlayed % totalSamples) / static_cast<float>(Math::Max(1U, clipInfo.SampleRate));
}
@@ -603,8 +639,10 @@ void AudioBackendXAudio2::Source_SetNonStreamingBuffer(AudioSource* source)
if (!aSource)
return;
XAudio2::Locker.Lock();
const uint32 bufferId = source->Clip->Buffers[0];
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
XAudio2::Locker.Unlock();
XAUDIO2_BUFFER buffer = { 0 };
buffer.pContext = aBuffer;
@@ -666,8 +704,11 @@ void AudioBackendXAudio2::Source_DequeueProcessedBuffers(AudioSource* source)
}
}
void AudioBackendXAudio2::Buffer_Create(uint32& bufferId)
uint32 AudioBackendXAudio2::Buffer_Create()
{
uint32 bufferId;
ScopeLock lock(XAudio2::Locker);
// Get first free buffer slot
XAudio2::Buffer* aBuffer = nullptr;
for (int32 i = 0; i < XAudio2::Buffers.Count(); i++)
@@ -689,10 +730,12 @@ void AudioBackendXAudio2::Buffer_Create(uint32& bufferId)
}
aBuffer->Data.Resize(0);
return bufferId;
}
void AudioBackendXAudio2::Buffer_Delete(uint32& bufferId)
void AudioBackendXAudio2::Buffer_Delete(uint32 bufferId)
{
ScopeLock lock(XAudio2::Locker);
XAudio2::Buffer*& aBuffer = XAudio2::Buffers[bufferId - 1];
aBuffer->Data.Resize(0);
Delete(aBuffer);
@@ -701,7 +744,9 @@ void AudioBackendXAudio2::Buffer_Delete(uint32& bufferId)
void AudioBackendXAudio2::Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info)
{
XAudio2::Locker.Lock();
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
XAudio2::Locker.Unlock();
const uint32 bytesPerSample = info.BitDepth / 8;
const int32 samplesLength = info.NumSamples * bytesPerSample;
@@ -715,6 +760,11 @@ const Char* AudioBackendXAudio2::Base_Name()
return TEXT("XAudio2");
}
AudioBackend::FeatureFlags AudioBackendXAudio2::Base_Features()
{
return FeatureFlags::None;
}
void AudioBackendXAudio2::Base_OnActiveDeviceChanged()
{
}
@@ -762,7 +812,6 @@ bool AudioBackendXAudio2::Base_Init()
LOG(Error, "Failed to get XAudio2 mastering voice channel mask. Error: 0x{0:x}", hr);
return true;
}
XAudio2::UseRedirectToLFE = ((XAudio2::ChannelMask & SPEAKER_LOW_FREQUENCY) != 0);
// Initialize spatial audio subsystem
DWORD dwChannelMask;
@@ -787,19 +836,13 @@ bool AudioBackendXAudio2::Base_Init()
void AudioBackendXAudio2::Base_Update()
{
// Note: only one listener is supported for now
const auto listener = XAudio2::GetListener();
if (!listener)
{
// How can we play audio when no one is listening
return;
}
// Update dirty voices
const auto listener = XAudio2::GetListener();
const float dopplerFactor = AudioSettings::Get()->DopplerFactor;
float matrixCoefficients[MAX_CHANNELS_MATRIX_SIZE];
X3DAUDIO_DSP_SETTINGS dsp = { 0 };
dsp.DstChannelCount = XAudio2::Channels;
dsp.pMatrixCoefficients = XAudio2::MatrixCoefficients;
dsp.pMatrixCoefficients = matrixCoefficients;
for (int32 i = 0; i < XAudio2::Sources.Count(); i++)
{
auto& source = XAudio2::Sources[i];
@@ -807,15 +850,16 @@ void AudioBackendXAudio2::Base_Update()
continue;
dsp.SrcChannelCount = source.Data.ChannelCount;
if (source.Is3D)
if (source.Is3D && listener)
{
// 3D sound
X3DAudioCalculate(XAudio2::X3DInstance, &listener->Data, &source.Data, X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_DOPPLER, &dsp);
}
else
{
// Stereo
// 2D sound
dsp.DopplerFactor = 1.0f;
Platform::MemoryClear(dsp.pMatrixCoefficients, sizeof(XAudio2::MatrixCoefficients));
Platform::MemoryClear(dsp.pMatrixCoefficients, sizeof(matrixCoefficients));
dsp.pMatrixCoefficients[0] = 1.0f;
if (source.Format.nChannels == 1)
{
@@ -825,9 +869,20 @@ void AudioBackendXAudio2::Base_Update()
{
dsp.pMatrixCoefficients[3] = 1.0f;
}
const float panLeft = Math::Min(1.0f - source.Pan, 1.0f);
const float panRight = Math::Min(1.0f + source.Pan, 1.0f);
if (source.Format.nChannels >= 2)
{
dsp.pMatrixCoefficients[0] *= panLeft;
dsp.pMatrixCoefficients[3] *= panRight;
}
}
const float frequencyRatio = dopplerFactor * source.Pitch * dsp.DopplerFactor;
if (source.IsForceMono3D)
{
// Hack to fix playback speed for 3D clip that has auto-converted stereo to mono at runtime
dsp.DopplerFactor *= 0.5f;
}
const float frequencyRatio = dopplerFactor * source.Pitch * dsp.DopplerFactor * source.DopplerFactor;
source.Voice->SetFrequencyRatio(frequencyRatio);
source.Voice->SetOutputMatrix(XAudio2::MasteringVoice, dsp.SrcChannelCount, dsp.DstChannelCount, dsp.pMatrixCoefficients);

View File

@@ -18,15 +18,16 @@ public:
void Listener_OnRemove(AudioListener* listener) override;
void Listener_VelocityChanged(AudioListener* listener) override;
void Listener_TransformChanged(AudioListener* listener) override;
void Listener_ReinitializeAll() override;
void Source_OnAdd(AudioSource* source) override;
void Source_OnRemove(AudioSource* source) override;
void Source_VelocityChanged(AudioSource* source) override;
void Source_TransformChanged(AudioSource* source) override;
void Source_VolumeChanged(AudioSource* source) override;
void Source_PitchChanged(AudioSource* source) override;
void Source_PanChanged(AudioSource* source) override;
void Source_IsLoopingChanged(AudioSource* source) override;
void Source_MinDistanceChanged(AudioSource* source) override;
void Source_AttenuationChanged(AudioSource* source) override;
void Source_SpatialSetupChanged(AudioSource* source) override;
void Source_ClipLoaded(AudioSource* source) override;
void Source_Cleanup(AudioSource* source) override;
void Source_Play(AudioSource* source) override;
@@ -39,10 +40,11 @@ public:
void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) override;
void Source_QueueBuffer(AudioSource* source, uint32 bufferId) override;
void Source_DequeueProcessedBuffers(AudioSource* source) override;
void Buffer_Create(uint32& bufferId) override;
void Buffer_Delete(uint32& bufferId) override;
uint32 Buffer_Create() override;
void Buffer_Delete(uint32 bufferId) override;
void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) override;
const Char* Base_Name() override;
FeatureFlags Base_Features() override;
void Base_OnActiveDeviceChanged() override;
void Base_SetDopplerFactor(float value) override;
void Base_SetVolume(float value) override;

View File

@@ -18,25 +18,11 @@
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
#include "Engine/Tools/AudioTool/OggVorbisEncoder.h"
#include "Engine/Serialization/JsonWriters.h"
ImportAudio::Options::Options()
{
Format = AudioFormat::Vorbis;
DisableStreaming = false;
Is3D = false;
Quality = 0.4f;
BitDepth = 16;
}
#include "Engine/Scripting/Enums.h"
String ImportAudio::Options::ToString() const
{
return String::Format(TEXT("Format:{}, DisableStreaming:{}, Is3D:{}, Quality:{}, BitDepth:{}"),
::ToString(Format),
DisableStreaming,
Is3D,
Quality,
BitDepth
);
return String::Format(TEXT("Format:{}, DisableStreaming:{}, Is3D:{}, Quality:{}, BitDepth:{}"), ScriptingEnum::ToString(Format), DisableStreaming, Is3D, Quality, BitDepth);
}
void ImportAudio::Options::Serialize(SerializeStream& stream, const void* otherObj)
@@ -59,11 +45,9 @@ void ImportAudio::Options::Deserialize(DeserializeStream& stream, ISerializeModi
DESERIALIZE(BitDepth);
}
bool ImportAudio::TryGetImportOptions(String path, Options& options)
bool ImportAudio::TryGetImportOptions(const String& path, Options& options)
{
#if IMPORT_AUDIO_CACHE_OPTIONS
// Check if target asset file exists
if (FileSystem::FileExists(path))
{
// Try to load asset file and asset info
@@ -88,7 +72,6 @@ bool ImportAudio::TryGetImportOptions(String path, Options& options)
}
#endif
return false;
}
@@ -123,9 +106,7 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder&
Array<byte> audioData;
if (decoder.Convert(stream, info, audioData))
return CreateAssetResult::Error;
const float length = info.NumSamples / static_cast<float>(Math::Max(1U, info.SampleRate * info.NumChannels));
LOG(Info, "Audio: {0}kHz, channels: {1}, Bit depth: {2}, Length: {3}s", info.SampleRate / 1000.0f, info.NumChannels, info.BitDepth, length);
LOG(Info, "Audio: {0}kHz, channels: {1}, Bit depth: {2}, Length: {3}s", info.SampleRate / 1000.0f, info.NumChannels, info.BitDepth, info.GetLength());
// Load the whole audio data
uint32 bytesPerSample = info.BitDepth / 8;
@@ -133,22 +114,6 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder&
DataContainer<byte> sampleBuffer;
sampleBuffer.Link(audioData.Get());
// Convert to Mono if used as 3D source
if (options.Is3D && info.NumChannels > 1)
{
const uint32 numSamplesPerChannel = info.NumSamples / info.NumChannels;
const uint32 monoBufferSize = numSamplesPerChannel * bytesPerSample;
sampleBuffer.Allocate(monoBufferSize);
AudioTool::ConvertToMono(audioData.Get(), sampleBuffer.Get(), info.BitDepth, numSamplesPerChannel, info.NumChannels);
info.NumSamples = numSamplesPerChannel;
info.NumChannels = 1;
bufferSize = monoBufferSize;
}
// Convert bit depth if need to
if (options.BitDepth != static_cast<int32>(info.BitDepth))
{
@@ -222,7 +187,7 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder&
{
// Split audio data into a several chunks (uniform data spread)
const int32 MinChunkSize = 1 * 1024 * 1024; // 1 MB
const int32 chunkSize = Math::Max<int32>(MinChunkSize, Math::AlignUp<uint32>(bufferSize / ASSET_FILE_DATA_CHUNKS, 256));
const int32 chunkSize = Math::Max<int32>(MinChunkSize, (int32)Math::AlignUp<uint32>(bufferSize / ASSET_FILE_DATA_CHUNKS, 256));
const int32 chunksCount = Math::CeilToInt((float)bufferSize / chunkSize);
ASSERT(chunksCount > 0 && chunksCount <= ASSET_FILE_DATA_CHUNKS);

View File

@@ -25,24 +25,14 @@ public:
/// </summary>
struct Options : public ISerializable
{
AudioFormat Format;
bool DisableStreaming;
bool Is3D;
int32 BitDepth;
float Quality;
AudioFormat Format = AudioFormat::Vorbis;
bool DisableStreaming = false;
bool Is3D = false;
int32 BitDepth = 16;
float Quality = 0.4f;
/// <summary>
/// Initializes a new instance of the <see cref="Options"/> struct.
/// </summary>
Options();
/// <summary>
/// Gets string that contains information about options
/// </summary>
/// <returns>String</returns>
String ToString() const;
public:
// [ISerializable]
void Serialize(SerializeStream& stream, const void* otherObj) override;
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
@@ -55,7 +45,7 @@ public:
/// <param name="path">The asset path.</param>
/// <param name="options">The options.</param>
/// <returns>True if success, otherwise false.</returns>
static bool TryGetImportOptions(String path, Options& options);
static bool TryGetImportOptions(const String& path, Options& options);
/// <summary>
/// Imports the audio data (with given audio decoder).
@@ -80,14 +70,12 @@ public:
static CreateAssetResult ImportMp3(CreateAssetContext& context);
#if COMPILE_WITH_OGG_VORBIS
/// <summary>
/// Imports the .ogg audio file.
/// </summary>
/// <param name="context">The importing context.</param>
/// <returns>Result.</returns>
static CreateAssetResult ImportOgg(CreateAssetContext& context);
#endif
};

View File

@@ -386,6 +386,61 @@ namespace Math
return Min(Min(Min(a, b), c), d);
}
/// <summary>
/// Moves a value current towards target.
/// </summary>
/// <param name="current">The current value.</param>
/// <param name="target">The value to move towards.</param>
/// <param name="maxDelta">The maximum change that should be applied to the value.</param>
template<class T>
static T MoveTowards(const T current, const T target, const T maxDelta)
{
if (Abs(target - current) <= maxDelta)
return target;
return current + Sign(target - current) * maxDelta;
}
/// <summary>
/// Same as MoveTowards but makes sure the values interpolate correctly when they wrap around 360 degrees.
/// </summary>
/// <param name="current"></param>
/// <param name="target"></param>
/// <param name="maxDelta"></param>
template<class T>
static T MoveTowardsAngle(const T current, const T target, const T maxDelta)
{
T delta = DeltaAngle(current, target);
if ((-maxDelta < delta) && (delta < maxDelta))
return target;
T deltaTarget = current + delta;
return MoveTowards(current, deltaTarget, maxDelta);
}
/// <summary>
/// Calculates the shortest difference between two given angles given in degrees.
/// </summary>
/// <param name="current"></param>
/// <param name="target"></param>
template<class T>
static T DeltaAngle(const T current, const T target)
{
T t = Repeat(target - current, (T)360);
if (t > (T)180)
t -= (T)360;
return t;
}
/// <summary>
/// Loops the value t, so that it is never larger than length and never smaller than 0.
/// </summary>
/// <param name="t"></param>
/// <param name="length"></param>
template<class T>
static T Repeat(const T t, const T length)
{
return t - Floor(t / length) * length;
}
// Multiply value by itself
template<class T>
static T Square(const T a)

View File

@@ -395,7 +395,7 @@ namespace FlaxEngine
/// <param name="f"></param>
public static double Sign(double f)
{
return f < 0d ? -1d : 1d;
return f > 0.0d ? 1.0d : f < 0.0d ? -1.0d : 0.0d;
}
/// <summary>
@@ -652,6 +652,8 @@ namespace FlaxEngine
/// <param name="toMin">The destination range minimum value.</param>
/// <param name="toMax">The destination range maximum value.</param>
/// <returns>The mapped value in range [toMin; toMax].</returns>
// [Deprecated on 17.04.2023, expires on 17.04.2024]
[Obsolete("Please use Remap to upkeep the API consistency")]
public static double Map(double value, double fromMin, double fromMax, double toMin, double toMax)
{
double t = (value - fromMin) / (fromMax - fromMin);

View File

@@ -548,7 +548,7 @@ namespace FlaxEngine
/// <param name="f"></param>
public static float Sign(float f)
{
return f < 0f ? -1f : 1f;
return f > 0.0f ? 1.0f : f < 0.0f ? -1.0f : 0.0f;
}
/// <summary>
@@ -815,6 +815,8 @@ namespace FlaxEngine
/// <param name="toMin">The destination range minimum value.</param>
/// <param name="toMax">The destination range maximum value.</param>
/// <returns>The mapped value in range [toMin; toMax].</returns>
// [Deprecated on 17.04.2023, expires on 17.04.2024]
[Obsolete("Please use Remap to upkeep the API consistency")]
public static float Map(float value, float fromMin, float fromMax, float toMin, float toMax)
{
float t = (value - fromMin) / (fromMax - fromMin);

View File

@@ -171,5 +171,12 @@ constexpr bool EnumHasNoneFlags(T value, T flags)
return ((__underlying_type(T))value & (__underlying_type(T))flags) == 0;
}
// Returns enum value with additional enum flags set
template<typename T>
constexpr T EnumAddFlags(T value, T flags)
{
return (T)((__underlying_type(T))value | (__underlying_type(T))flags);
}
// Returns byte offset from the object pointer in vtable to the begin of the given inherited type implementation
#define VTABLE_OFFSET(type, baseType) (((intptr)static_cast<baseType*>((type*)1))-1)

View File

@@ -404,7 +404,7 @@ protected:
if (_streamingTexture)
{
// Stop streaming on fail
_streamingTexture->CancelStreaming();
_streamingTexture->ResetStreaming();
}
GPUUploadTextureMipTask::OnFail();

View File

@@ -176,9 +176,9 @@ void NetworkTransform::Serialize(NetworkStream* stream)
if (EnumHasAnyFlags(data.Components, ReplicationComponents::PositionX))
stream->Write(transform.Translation.X);
if (EnumHasAnyFlags(data.Components, ReplicationComponents::PositionY))
stream->Write(transform.Translation.X);
stream->Write(transform.Translation.Y);
if (EnumHasAnyFlags(data.Components, ReplicationComponents::PositionZ))
stream->Write(transform.Translation.X);
stream->Write(transform.Translation.Z);
}
if (EnumHasAllFlags(data.Components, ReplicationComponents::Scale))
{
@@ -189,9 +189,9 @@ void NetworkTransform::Serialize(NetworkStream* stream)
if (EnumHasAnyFlags(data.Components, ReplicationComponents::ScaleX))
stream->Write(transform.Scale.X);
if (EnumHasAnyFlags(data.Components, ReplicationComponents::ScaleY))
stream->Write(transform.Scale.X);
stream->Write(transform.Scale.Y);
if (EnumHasAnyFlags(data.Components, ReplicationComponents::ScaleZ))
stream->Write(transform.Scale.X);
stream->Write(transform.Scale.Z);
}
if (EnumHasAllFlags(data.Components, ReplicationComponents::Rotation))
{
@@ -241,9 +241,9 @@ void NetworkTransform::Deserialize(NetworkStream* stream)
if (EnumHasAnyFlags(data.Components, ReplicationComponents::PositionX))
stream->Read(transform.Translation.X);
if (EnumHasAnyFlags(data.Components, ReplicationComponents::PositionY))
stream->Read(transform.Translation.X);
stream->Read(transform.Translation.Y);
if (EnumHasAnyFlags(data.Components, ReplicationComponents::PositionZ))
stream->Read(transform.Translation.X);
stream->Read(transform.Translation.Z);
}
if (EnumHasAllFlags(data.Components, ReplicationComponents::Scale))
{
@@ -254,9 +254,9 @@ void NetworkTransform::Deserialize(NetworkStream* stream)
if (EnumHasAnyFlags(data.Components, ReplicationComponents::ScaleX))
stream->Read(transform.Scale.X);
if (EnumHasAnyFlags(data.Components, ReplicationComponents::ScaleY))
stream->Read(transform.Scale.X);
stream->Read(transform.Scale.Y);
if (EnumHasAnyFlags(data.Components, ReplicationComponents::ScaleZ))
stream->Read(transform.Scale.X);
stream->Read(transform.Scale.Z);
}
if (EnumHasAllFlags(data.Components, ReplicationComponents::Rotation))
{

View File

@@ -118,12 +118,7 @@ bool CollisionCooking::CookCollision(const Argument& arg, CollisionData::Seriali
indexCounts.Resize(needIndexBuffer ? meshesCount : 0);
vertexCounts.SetAll(0);
indexCounts.SetAll(0);
bool useCpuData = IsInMainThread() && !arg.Model->IsVirtual();
if (!useCpuData)
{
// If mesh data is already cached in memory then we could use it instead of GPU
useCpuData |= arg.Model->HasChunkLoaded(MODEL_LOD_TO_CHUNK_INDEX(lodIndex));
}
bool useCpuData = IsInMainThread() || !arg.Model->IsVirtual();
if (useCpuData)
{
// Read directly from the asset storage

View File

@@ -211,7 +211,7 @@ void Font::ProcessText(const StringView& text, Array<FontLineCache>& outputLines
{
cursorX = lastUpperX;
tmpLine.LastCharIndex = lastUpperIndex - 1;
currentIndex = lastUpperIndex;
currentIndex = lastUpperIndex + 1;
nextCharIndex = currentIndex;
}
else if (lastUnderscoreIndex != INVALID_INDEX)

View File

@@ -131,7 +131,7 @@ public:
/// <summary>
/// Stops the streaming (eg. on streaming fail).
/// </summary>
void CancelStreaming();
void ResetStreaming();
protected:

View File

@@ -84,7 +84,7 @@ void StreamableResource::RequestStreamingUpdate()
Streaming.LastUpdate = 0;
}
void StreamableResource::CancelStreaming()
void StreamableResource::ResetStreaming()
{
Streaming.TargetResidency = 0;
Streaming.LastUpdate = DateTime::MaxValue().Ticks;
@@ -169,7 +169,7 @@ void UpdateResource(StreamableResource* resource, DateTime now, double currentTi
else if (resource->GetAllocatedResidency() < targetResidency)
{
// Allocation failed (eg. texture format is not supported or run out of memory)
resource->CancelStreaming();
resource->ResetStreaming();
return;
}
}

View File

@@ -4,6 +4,11 @@
#include "Engine/Core/Core.h"
#include "Engine/Core/Memory/Allocation.h"
#define CONVERT_TO_MONO_AVG 1
#if !CONVERT_TO_MONO_AVG
#include "Engine/Core/Math/Math.h"
#endif
void ConvertToMono8(const int8* input, uint8* output, uint32 numSamples, uint32 numChannels)
{
for (uint32 i = 0; i < numSamples; i++)
@@ -15,7 +20,11 @@ void ConvertToMono8(const int8* input, uint8* output, uint32 numSamples, uint32
++input;
}
*output = sum / numChannels;
#if CONVERT_TO_MONO_AVG
*output = (uint8)(sum / numChannels);
#else
*output = (uint8)Math::Clamp<int16>(sum, 0, MAX_uint8);
#endif
++output;
}
}
@@ -31,7 +40,11 @@ void ConvertToMono16(const int16* input, int16* output, uint32 numSamples, uint3
++input;
}
*output = sum / numChannels;
#if CONVERT_TO_MONO_AVG
*output = (int16)(sum / numChannels);
#else
*output = (int16)Math::Clamp<int32>(sum, MIN_int16, MAX_int16);
#endif
++output;
}
}
@@ -55,8 +68,12 @@ void ConvertToMono24(const uint8* input, uint8* output, uint32 numSamples, uint3
input += 3;
}
const int32 avg = (int32)(sum / numChannels);
Convert32To24Bits(avg, output);
#if CONVERT_TO_MONO_AVG
const int32 val = (int32)(sum / numChannels);
#else
const int32 val = (int32)Math::Clamp<int64>(sum, MIN_int16, MAX_int16);
#endif
Convert32To24Bits(val, output);
output += 3;
}
}
@@ -72,7 +89,11 @@ void ConvertToMono32(const int32* input, int32* output, uint32 numSamples, uint3
++input;
}
#if CONVERT_TO_MONO_AVG
*output = (int32)(sum / numChannels);
#else
*output = (int32)Math::Clamp<int64>(sum, MIN_int16, MAX_int16);
#endif
++output;
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -1,7 +1,7 @@
#ifndef AL_AL_H
#define AL_AL_H
#if defined(__cplusplus)
#ifdef __cplusplus
extern "C" {
#endif
@@ -15,14 +15,14 @@ extern "C" {
#endif
#endif
#if defined(_WIN32)
#ifdef _WIN32
#define AL_APIENTRY __cdecl
#else
#define AL_APIENTRY
#endif
/** Deprecated macro. */
/* Deprecated macros. */
#define OPENAL
#define ALAPI AL_API
#define ALAPIENTRY AL_APIENTRY
@@ -30,7 +30,7 @@ extern "C" {
#define AL_ILLEGAL_ENUM AL_INVALID_ENUM
#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
/** Supported AL version. */
/* Supported AL versions. */
#define AL_VERSION_1_0
#define AL_VERSION_1_1
@@ -40,43 +40,43 @@ typedef char ALboolean;
/** character */
typedef char ALchar;
/** signed 8-bit 2's complement integer */
/** signed 8-bit integer */
typedef signed char ALbyte;
/** unsigned 8-bit integer */
typedef unsigned char ALubyte;
/** signed 16-bit 2's complement integer */
/** signed 16-bit integer */
typedef short ALshort;
/** unsigned 16-bit integer */
typedef unsigned short ALushort;
/** signed 32-bit 2's complement integer */
/** signed 32-bit integer */
typedef int ALint;
/** unsigned 32-bit integer */
typedef unsigned int ALuint;
/** non-negative 32-bit binary integer size */
/** non-negative 32-bit integer size */
typedef int ALsizei;
/** enumerated 32-bit value */
/** 32-bit enumeration value */
typedef int ALenum;
/** 32-bit IEEE754 floating-point */
/** 32-bit IEEE-754 floating-point */
typedef float ALfloat;
/** 64-bit IEEE754 floating-point */
/** 64-bit IEEE-754 floating-point */
typedef double ALdouble;
/** void type (for opaque pointers only) */
/** void type (opaque pointers only) */
typedef void ALvoid;
/* Enumerant values begin at column 50. No tabs. */
/* Enumeration values begin at column 50. Do not use tabs. */
/** "no distance model" or "no buffer" */
/** No distance model or no buffer */
#define AL_NONE 0
/** Boolean False. */
@@ -89,10 +89,10 @@ typedef void ALvoid;
/**
* Relative source.
* Type: ALboolean
* Range: [AL_TRUE, AL_FALSE]
* Range: [AL_FALSE, AL_TRUE]
* Default: AL_FALSE
*
* Specifies if the Source has relative coordinates.
* Specifies if the source uses relative coordinates.
*/
#define AL_SOURCE_RELATIVE 0x202
@@ -103,7 +103,8 @@ typedef void ALvoid;
* Range: [0 - 360]
* Default: 360
*
* The angle covered by the inner cone, where the source will not attenuate.
* The angle covered by the inner cone, the area within which the source will
* not be attenuated by direction.
*/
#define AL_CONE_INNER_ANGLE 0x1001
@@ -112,8 +113,8 @@ typedef void ALvoid;
* Range: [0 - 360]
* Default: 360
*
* The angle covered by the outer cone, where the source will be fully
* attenuated.
* The angle covered by the outer cone, the area outside of which the source
* will be fully attenuated by direction.
*/
#define AL_CONE_OUTER_ANGLE 0x1002
@@ -123,7 +124,7 @@ typedef void ALvoid;
* Range: [0.5 - 2.0]
* Default: 1.0
*
* A multiplier for the frequency (sample rate) of the source's buffer.
* A multiplier for the sample rate of the source's buffer.
*/
#define AL_PITCH 0x1003
@@ -134,12 +135,12 @@ typedef void ALvoid;
*
* The source or listener location in three dimensional space.
*
* OpenAL, like OpenGL, uses a right handed coordinate system, where in a
* frontal default view X (thumb) points right, Y points up (index finger), and
* Z points towards the viewer/camera (middle finger).
* OpenAL uses a right handed coordinate system, like OpenGL, where with a
* default view, X points right (thumb), Y points up (index finger), and Z
* points towards the viewer/camera (middle finger).
*
* To switch from a left handed coordinate system, flip the sign on the Z
* coordinate.
* To change from or to a left handed coordinate system, negate the Z
* component.
*/
#define AL_POSITION 0x1004
@@ -148,8 +149,11 @@ typedef void ALvoid;
* Type: ALfloat[3], ALint[3]
* Default: {0, 0, 0}
*
* Specifies the current direction in local space.
* A zero-length vector specifies an omni-directional source (cone is ignored).
* Specifies the current direction in local space. A zero-length vector
* specifies an omni-directional source (cone is ignored).
*
* To change from or to a left handed coordinate system, negate the Z
* component.
*/
#define AL_DIRECTION 0x1005
@@ -158,26 +162,30 @@ typedef void ALvoid;
* Type: ALfloat[3], ALint[3]
* Default: {0, 0, 0}
*
* Specifies the current velocity in local space.
* Specifies the current velocity, relative to the position.
*
* To change from or to a left handed coordinate system, negate the Z
* component.
*/
#define AL_VELOCITY 0x1006
/**
* Source looping.
* Type: ALboolean
* Range: [AL_TRUE, AL_FALSE]
* Range: [AL_FALSE, AL_TRUE]
* Default: AL_FALSE
*
* Specifies whether source is looping.
* Specifies whether source playback loops.
*/
#define AL_LOOPING 0x1007
/**
* Source buffer.
* Type: ALuint
* Range: any valid Buffer.
* Type: ALuint
* Range: any valid Buffer ID
* Default: AL_NONE
*
* Specifies the buffer to provide sound samples.
* Specifies the buffer to provide sound samples for a source.
*/
#define AL_BUFFER 0x1009
@@ -186,12 +194,12 @@ typedef void ALvoid;
* Type: ALfloat
* Range: [0.0 - ]
*
* A value of 1.0 means unattenuated. Each division by 2 equals an attenuation
* of about -6dB. Each multiplicaton by 2 equals an amplification of about
* +6dB.
* For sources, an initial linear gain value (before attenuation is applied).
* For the listener, an output linear gain adjustment.
*
* A value of 0.0 is meaningless with respect to a logarithmic scale; it is
* silent.
* A value of 1.0 means unattenuated. Each division by 2 equals an attenuation
* of about -6dB. Each multiplication by 2 equals an amplification of about
* +6dB.
*/
#define AL_GAIN 0x100A
@@ -200,8 +208,8 @@ typedef void ALvoid;
* Type: ALfloat
* Range: [0.0 - 1.0]
*
* The minimum gain allowed for a source, after distance and cone attenation is
* applied (if applicable).
* The minimum gain allowed for a source, after distance and cone attenuation
* are applied (if applicable).
*/
#define AL_MIN_GAIN 0x100D
@@ -210,31 +218,33 @@ typedef void ALvoid;
* Type: ALfloat
* Range: [0.0 - 1.0]
*
* The maximum gain allowed for a source, after distance and cone attenation is
* applied (if applicable).
* The maximum gain allowed for a source, after distance and cone attenuation
* are applied (if applicable).
*/
#define AL_MAX_GAIN 0x100E
/**
* Listener orientation.
* Type: ALfloat[6]
* Type: ALfloat[6]
* Default: {0.0, 0.0, -1.0, 0.0, 1.0, 0.0}
*
* Effectively two three dimensional vectors. The first vector is the front (or
* "at") and the second is the top (or "up").
* "at") and the second is the top (or "up"). Both vectors are relative to the
* listener position.
*
* Both vectors are in local space.
* To change from or to a left handed coordinate system, negate the Z
* component of both vectors.
*/
#define AL_ORIENTATION 0x100F
/**
* Source state (query only).
* Type: ALint
* Type: ALenum
* Range: [AL_INITIAL, AL_PLAYING, AL_PAUSED, AL_STOPPED]
*/
#define AL_SOURCE_STATE 0x1010
/** Source state value. */
/* Source state values. */
#define AL_INITIAL 0x1011
#define AL_PLAYING 0x1012
#define AL_PAUSED 0x1013
@@ -267,9 +277,9 @@ typedef void ALvoid;
* Range: [0.0 - ]
* Default: 1.0
*
* The distance in units that no attenuation occurs.
* The distance in units that no distance attenuation occurs.
*
* At 0.0, no distance attenuation ever occurs on non-linear attenuation models.
* At 0.0, no distance attenuation occurs with non-linear attenuation models.
*/
#define AL_REFERENCE_DISTANCE 0x1020
@@ -292,7 +302,7 @@ typedef void ALvoid;
* Default: 0.0
*
* The gain attenuation applied when the listener is outside of the source's
* outer cone.
* outer cone angle.
*/
#define AL_CONE_OUTER_GAIN 0x1022
@@ -300,7 +310,7 @@ typedef void ALvoid;
* Source maximum distance.
* Type: ALfloat
* Range: [0.0 - ]
* Default: +inf
* Default: FLT_MAX
*
* The distance above which the source is not attenuated any further with a
* clamped distance model, or where attenuation reaches 0.0 gain for linear
@@ -308,16 +318,16 @@ typedef void ALvoid;
*/
#define AL_MAX_DISTANCE 0x1023
/** Source buffer position, in seconds */
/** Source buffer offset, in seconds */
#define AL_SEC_OFFSET 0x1024
/** Source buffer position, in sample frames */
/** Source buffer offset, in sample frames */
#define AL_SAMPLE_OFFSET 0x1025
/** Source buffer position, in bytes */
/** Source buffer offset, in bytes */
#define AL_BYTE_OFFSET 0x1026
/**
* Source type (query only).
* Type: ALint
* Type: ALenum
* Range: [AL_STATIC, AL_STREAMING, AL_UNDETERMINED]
*
* A Source is Static if a Buffer has been attached using AL_BUFFER.
@@ -330,31 +340,30 @@ typedef void ALvoid;
*/
#define AL_SOURCE_TYPE 0x1027
/** Source type value. */
/* Source type values. */
#define AL_STATIC 0x1028
#define AL_STREAMING 0x1029
#define AL_UNDETERMINED 0x1030
/** Buffer format specifier. */
/** Unsigned 8-bit mono buffer format. */
#define AL_FORMAT_MONO8 0x1100
/** Signed 16-bit mono buffer format. */
#define AL_FORMAT_MONO16 0x1101
/** Unsigned 8-bit stereo buffer format. */
#define AL_FORMAT_STEREO8 0x1102
/** Signed 16-bit stereo buffer format. */
#define AL_FORMAT_STEREO16 0x1103
/** Buffer frequency (query only). */
/** Buffer frequency/sample rate (query only). */
#define AL_FREQUENCY 0x2001
/** Buffer bits per sample (query only). */
#define AL_BITS 0x2002
/** Buffer channel count (query only). */
#define AL_CHANNELS 0x2003
/** Buffer data size (query only). */
/** Buffer data size in bytes (query only). */
#define AL_SIZE 0x2004
/**
* Buffer state.
*
* Not for public use.
*/
/* Buffer state. Not for public use. */
#define AL_UNUSED 0x2010
#define AL_PENDING 0x2011
#define AL_PROCESSED 0x2012
@@ -363,32 +372,31 @@ typedef void ALvoid;
/** No error. */
#define AL_NO_ERROR 0
/** Invalid name paramater passed to AL call. */
/** Invalid name (ID) passed to an AL call. */
#define AL_INVALID_NAME 0xA001
/** Invalid enum parameter passed to AL call. */
/** Invalid enumeration passed to AL call. */
#define AL_INVALID_ENUM 0xA002
/** Invalid value parameter passed to AL call. */
/** Invalid value passed to AL call. */
#define AL_INVALID_VALUE 0xA003
/** Illegal AL call. */
#define AL_INVALID_OPERATION 0xA004
/** Not enough memory. */
/** Not enough memory to execute the AL call. */
#define AL_OUT_OF_MEMORY 0xA005
/** Context string: Vendor ID. */
/** Context string: Vendor name. */
#define AL_VENDOR 0xB001
/** Context string: Version. */
#define AL_VERSION 0xB002
/** Context string: Renderer ID. */
/** Context string: Renderer name. */
#define AL_RENDERER 0xB003
/** Context string: Space-separated extension list. */
#define AL_EXTENSIONS 0xB004
/**
* Doppler scale.
* Type: ALfloat
@@ -398,7 +406,6 @@ typedef void ALvoid;
* Scale for source and listener velocities.
*/
#define AL_DOPPLER_FACTOR 0xC000
AL_API void AL_APIENTRY alDopplerFactor(ALfloat value);
/**
* Doppler velocity (deprecated).
@@ -406,7 +413,6 @@ AL_API void AL_APIENTRY alDopplerFactor(ALfloat value);
* A multiplier applied to the Speed of Sound.
*/
#define AL_DOPPLER_VELOCITY 0xC001
AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value);
/**
* Speed of Sound, in units per second.
@@ -415,14 +421,13 @@ AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value);
* Default: 343.3
*
* The speed at which sound waves are assumed to travel, when calculating the
* doppler effect.
* doppler effect from source and listener velocities.
*/
#define AL_SPEED_OF_SOUND 0xC003
AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value);
/**
* Distance attenuation model.
* Type: ALint
* Type: ALenum
* Range: [AL_NONE, AL_INVERSE_DISTANCE, AL_INVERSE_DISTANCE_CLAMPED,
* AL_LINEAR_DISTANCE, AL_LINEAR_DISTANCE_CLAMPED,
* AL_EXPONENT_DISTANCE, AL_EXPONENT_DISTANCE_CLAMPED]
@@ -439,9 +444,8 @@ AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value);
* distance calculated is clamped between the reference and max distances.
*/
#define AL_DISTANCE_MODEL 0xD000
AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel);
/** Distance model value. */
/* Distance model values. */
#define AL_INVERSE_DISTANCE 0xD001
#define AL_INVERSE_DISTANCE_CLAMPED 0xD002
#define AL_LINEAR_DISTANCE 0xD003
@@ -449,12 +453,19 @@ AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel);
#define AL_EXPONENT_DISTANCE 0xD005
#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006
/** Renderer State management. */
#ifndef AL_NO_PROTOTYPES
/* Renderer State management. */
AL_API void AL_APIENTRY alEnable(ALenum capability);
AL_API void AL_APIENTRY alDisable(ALenum capability);
AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability);
/** State retrieval. */
/* Context state setting. */
AL_API void AL_APIENTRY alDopplerFactor(ALfloat value);
AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value);
AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value);
AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel);
/* Context state retrieval. */
AL_API const ALchar* AL_APIENTRY alGetString(ALenum param);
AL_API void AL_APIENTRY alGetBooleanv(ALenum param, ALboolean *values);
AL_API void AL_APIENTRY alGetIntegerv(ALenum param, ALint *values);
@@ -466,24 +477,25 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum param);
AL_API ALdouble AL_APIENTRY alGetDouble(ALenum param);
/**
* Error retrieval.
*
* Obtain the first error generated in the AL context since the last check.
* Obtain the first error generated in the AL context since the last call to
* this function.
*/
AL_API ALenum AL_APIENTRY alGetError(void);
/**
* Extension support.
*
* Query for the presence of an extension, and obtain any appropriate function
* pointers and enum values.
*/
/** Query for the presence of an extension on the AL context. */
AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extname);
/**
* Retrieve the address of a function. The returned function may be context-
* specific.
*/
AL_API void* AL_APIENTRY alGetProcAddress(const ALchar *fname);
/**
* Retrieve the value of an enum. The returned value may be context-specific.
*/
AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *ename);
/** Set Listener parameters */
/* Set listener parameters. */
AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value);
AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values);
@@ -491,7 +503,7 @@ AL_API void AL_APIENTRY alListeneri(ALenum param, ALint value);
AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3);
AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values);
/** Get Listener parameters */
/* Get listener parameters. */
AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value);
AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values);
@@ -500,14 +512,14 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint *values);
/** Create Source objects. */
/** Create source objects. */
AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources);
/** Delete Source objects. */
/** Delete source objects. */
AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources);
/** Verify a handle is a valid Source. */
/** Verify an ID is for a valid source. */
AL_API ALboolean AL_APIENTRY alIsSource(ALuint source);
/** Set Source parameters. */
/* Set source parameters. */
AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value);
AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values);
@@ -515,7 +527,7 @@ AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value);
AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values);
/** Get Source parameters. */
/* Get source parameters. */
AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value);
AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values);
@@ -524,41 +536,44 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1
AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values);
/** Play, replay, or resume (if paused) a list of Sources */
AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources);
/** Stop a list of Sources */
AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources);
/** Rewind a list of Sources */
AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources);
/** Pause a list of Sources */
AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources);
/** Play, replay, or resume a Source */
/** Play, restart, or resume a source, setting its state to AL_PLAYING. */
AL_API void AL_APIENTRY alSourcePlay(ALuint source);
/** Stop a Source */
/** Stop a source, setting its state to AL_STOPPED if playing or paused. */
AL_API void AL_APIENTRY alSourceStop(ALuint source);
/** Rewind a Source (set playback postiton to beginning) */
/** Rewind a source, setting its state to AL_INITIAL. */
AL_API void AL_APIENTRY alSourceRewind(ALuint source);
/** Pause a Source */
/** Pause a source, setting its state to AL_PAUSED if playing. */
AL_API void AL_APIENTRY alSourcePause(ALuint source);
/** Play, restart, or resume a list of sources atomically. */
AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources);
/** Stop a list of sources atomically. */
AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources);
/** Rewind a list of sources atomically. */
AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources);
/** Pause a list of sources atomically. */
AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources);
/** Queue buffers onto a source */
AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers);
/** Unqueue processed buffers from a source */
AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers);
/** Create Buffer objects */
/** Create buffer objects */
AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers);
/** Delete Buffer objects */
/** Delete buffer objects */
AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers);
/** Verify a handle is a valid Buffer */
/** Verify an ID is a valid buffer (including the NULL buffer) */
AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer);
/** Specifies the data to be copied into a buffer */
AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq);
/**
* Copies data into the buffer, interpreting it using the specified format and
* samplerate.
*/
AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei samplerate);
/** Set Buffer parameters, */
/* Set buffer parameters. */
AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value);
AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values);
@@ -566,15 +581,18 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value);
AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3);
AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values);
/** Get Buffer parameters. */
/* Get buffer parameters. */
AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value);
AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3);
AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values);
AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value);
AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3);
AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values);
#endif /* AL_NO_PROTOTYPES */
/** Pointer-to-function type, useful for dynamically getting AL entry points. */
/* Pointer-to-function types, useful for storing dynamically loaded AL entry
* points.
*/
typedef void (AL_APIENTRY *LPALENABLE)(ALenum capability);
typedef void (AL_APIENTRY *LPALDISABLE)(ALenum capability);
typedef ALboolean (AL_APIENTRY *LPALISENABLED)(ALenum capability);
@@ -631,7 +649,7 @@ typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALs
typedef void (AL_APIENTRY *LPALGENBUFFERS)(ALsizei n, ALuint *buffers);
typedef void (AL_APIENTRY *LPALDELETEBUFFERS)(ALsizei n, const ALuint *buffers);
typedef ALboolean (AL_APIENTRY *LPALISBUFFER)(ALuint buffer);
typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq);
typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei samplerate);
typedef void (AL_APIENTRY *LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value);
typedef void (AL_APIENTRY *LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3);
typedef void (AL_APIENTRY *LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values);
@@ -649,7 +667,7 @@ typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)(ALfloat value);
typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)(ALfloat value);
typedef void (AL_APIENTRY *LPALDISTANCEMODEL)(ALenum distanceModel);
#if defined(__cplusplus)
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@@ -1,7 +1,7 @@
#ifndef AL_ALC_H
#define AL_ALC_H
#if defined(__cplusplus)
#ifdef __cplusplus
extern "C" {
#endif
@@ -15,14 +15,14 @@ extern "C" {
#endif
#endif
#if defined(_WIN32)
#ifdef _WIN32
#define ALC_APIENTRY __cdecl
#else
#define ALC_APIENTRY
#endif
/** Deprecated macro. */
/* Deprecated macros. */
#define ALCAPI ALC_API
#define ALCAPIENTRY ALC_APIENTRY
#define ALC_INVALID 0
@@ -31,9 +31,9 @@ extern "C" {
#define ALC_VERSION_0_1 1
/** Opaque device handle */
typedef struct ALCdevice_struct ALCdevice;
typedef struct ALCdevice ALCdevice;
/** Opaque context handle */
typedef struct ALCcontext_struct ALCcontext;
typedef struct ALCcontext ALCcontext;
/** 8-bit boolean */
typedef char ALCboolean;
@@ -41,41 +41,41 @@ typedef char ALCboolean;
/** character */
typedef char ALCchar;
/** signed 8-bit 2's complement integer */
/** signed 8-bit integer */
typedef signed char ALCbyte;
/** unsigned 8-bit integer */
typedef unsigned char ALCubyte;
/** signed 16-bit 2's complement integer */
/** signed 16-bit integer */
typedef short ALCshort;
/** unsigned 16-bit integer */
typedef unsigned short ALCushort;
/** signed 32-bit 2's complement integer */
/** signed 32-bit integer */
typedef int ALCint;
/** unsigned 32-bit integer */
typedef unsigned int ALCuint;
/** non-negative 32-bit binary integer size */
/** non-negative 32-bit integer size */
typedef int ALCsizei;
/** enumerated 32-bit value */
/** 32-bit enumeration value */
typedef int ALCenum;
/** 32-bit IEEE754 floating-point */
/** 32-bit IEEE-754 floating-point */
typedef float ALCfloat;
/** 64-bit IEEE754 floating-point */
/** 64-bit IEEE-754 floating-point */
typedef double ALCdouble;
/** void type (for opaque pointers only) */
typedef void ALCvoid;
/* Enumerant values begin at column 50. No tabs. */
/* Enumeration values begin at column 50. Do not use tabs. */
/** Boolean False. */
#define ALC_FALSE 0
@@ -89,7 +89,7 @@ typedef void ALCvoid;
/** Context attribute: <int> Hz. */
#define ALC_REFRESH 0x1008
/** Context attribute: AL_TRUE or AL_FALSE. */
/** Context attribute: AL_TRUE or AL_FALSE synchronous context? */
#define ALC_SYNC 0x1009
/** Context attribute: <int> requested Mono (3D) Sources. */
@@ -107,30 +107,32 @@ typedef void ALCvoid;
/** Invalid context handle. */
#define ALC_INVALID_CONTEXT 0xA002
/** Invalid enum parameter passed to an ALC call. */
/** Invalid enumeration passed to an ALC call. */
#define ALC_INVALID_ENUM 0xA003
/** Invalid value parameter passed to an ALC call. */
/** Invalid value passed to an ALC call. */
#define ALC_INVALID_VALUE 0xA004
/** Out of memory. */
#define ALC_OUT_OF_MEMORY 0xA005
/** Runtime ALC version. */
/** Runtime ALC major version. */
#define ALC_MAJOR_VERSION 0x1000
/** Runtime ALC minor version. */
#define ALC_MINOR_VERSION 0x1001
/** Context attribute list properties. */
/** Context attribute list size. */
#define ALC_ATTRIBUTES_SIZE 0x1002
/** Context attribute list properties. */
#define ALC_ALL_ATTRIBUTES 0x1003
/** String for the default device specifier. */
#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004
/**
* String for the given device's specifier.
* Device specifier string.
*
* If device handle is NULL, it is instead a null-char separated list of
* If device handle is NULL, it is instead a null-character separated list of
* strings of known device specifiers (list ends with an empty string).
*/
#define ALC_DEVICE_SPECIFIER 0x1005
@@ -141,9 +143,9 @@ typedef void ALCvoid;
/** Capture extension */
#define ALC_EXT_CAPTURE 1
/**
* String for the given capture device's specifier.
* Capture device specifier string.
*
* If device handle is NULL, it is instead a null-char separated list of
* If device handle is NULL, it is instead a null-character separated list of
* strings of known capture device specifiers (list ends with an empty string).
*/
#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310
@@ -158,57 +160,92 @@ typedef void ALCvoid;
/** String for the default extended device specifier. */
#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
/**
* String for the given extended device's specifier.
* Device's extended specifier string.
*
* If device handle is NULL, it is instead a null-char separated list of
* If device handle is NULL, it is instead a null-character separated list of
* strings of known extended device specifiers (list ends with an empty string).
*/
#define ALC_ALL_DEVICES_SPECIFIER 0x1013
/** Context management. */
ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint* attrlist);
#ifndef ALC_NO_PROTOTYPES
/* Context management. */
/** Create and attach a context to the given device. */
ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist);
/**
* Makes the given context the active process-wide context. Passing NULL clears
* the active context.
*/
ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context);
/** Resumes processing updates for the given context. */
ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context);
/** Suspends updates for the given context. */
ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context);
/** Remove a context from its device and destroys it. */
ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context);
/** Returns the currently active context. */
ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void);
/** Returns the device that a particular context is attached to. */
ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context);
/** Device management. */
/* Device management. */
/** Opens the named playback device. */
ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename);
/** Closes the given playback device. */
ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device);
/* Error support. */
/**
* Error support.
*
* Obtain the most recent Device error.
*/
/** Obtain the most recent Device error. */
ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device);
/* Extension support. */
/**
* Extension support.
*
* Query for the presence of an extension, and obtain any appropriate
* function pointers and enum values.
* Query for the presence of an extension on the device. Pass a NULL device to
* query a device-inspecific extension.
*/
ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname);
ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname);
/**
* Retrieve the address of a function. Given a non-NULL device, the returned
* function may be device-specific.
*/
ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname);
/**
* Retrieve the value of an enum. Given a non-NULL device, the returned value
* may be device-specific.
*/
ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname);
/** Query function. */
/* Query functions. */
/** Returns information about the device, and error strings. */
ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param);
/** Returns information about the device and the version of OpenAL. */
ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values);
/** Capture function. */
ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device);
ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device);
ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device);
ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
/* Capture functions. */
/** Pointer-to-function type, useful for dynamically getting ALC entry points. */
/**
* Opens the named capture device with the given frequency, format, and buffer
* size.
*/
ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
/** Closes the given capture device. */
ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device);
/** Starts capturing samples into the device buffer. */
ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device);
/** Stops capturing samples. Samples in the device buffer remain available. */
ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device);
/** Reads samples from the device buffer. */
ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
#endif /* ALC_NO_PROTOTYPES */
/* Pointer-to-function types, useful for storing dynamically loaded ALC entry
* points.
*/
typedef ALCcontext* (ALC_APIENTRY *LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist);
typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)(ALCcontext *context);
typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)(ALCcontext *context);
@@ -220,7 +257,7 @@ typedef ALCdevice* (ALC_APIENTRY *LPALCOPENDEVICE)(const ALCchar *devicename
typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)(ALCdevice *device);
typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)(ALCdevice *device);
typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname);
typedef void* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname);
typedef ALCvoid* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname);
typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname);
typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)(ALCdevice *device, ALCenum param);
typedef void (ALC_APIENTRY *LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values);
@@ -230,8 +267,8 @@ typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device);
typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device);
typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
#if defined(__cplusplus)
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AL_ALC_H */

View File

@@ -1,38 +1,21 @@
/**
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#ifndef AL_ALEXT_H
#define AL_ALEXT_H
#include <stddef.h>
/* Define int64_t and uint64_t types */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#include <inttypes.h>
#elif defined(_WIN32) && defined(__GNUC__)
/* Define int64 and uint64 types */
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
(defined(__cplusplus) && __cplusplus >= 201103L)
#include <stdint.h>
typedef int64_t _alsoft_int64_t;
typedef uint64_t _alsoft_uint64_t;
#elif defined(_WIN32)
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef __int64 _alsoft_int64_t;
typedef unsigned __int64 _alsoft_uint64_t;
#else
/* Fallback if nothing above works */
#include <inttypes.h>
#include <stdint.h>
typedef int64_t _alsoft_int64_t;
typedef uint64_t _alsoft_uint64_t;
#endif
#include "alc.h"
@@ -158,9 +141,9 @@ extern "C" {
#ifndef AL_EXT_STATIC_BUFFER
#define AL_EXT_STATIC_BUFFER 1
typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei);
typedef void (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALuint,ALenum,ALvoid*,ALsizei,ALsizei);
#ifdef AL_ALEXT_PROTOTYPES
AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq);
void AL_APIENTRY alBufferDataStatic(const ALuint buffer, ALenum format, ALvoid *data, ALsizei size, ALsizei freq);
#endif
#endif
@@ -193,9 +176,9 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void);
#define AL_SOFT_buffer_sub_data 1
#define AL_BYTE_RW_OFFSETS_SOFT 0x1031
#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032
typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei);
typedef void (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei);
#ifdef AL_ALEXT_PROTOTYPES
AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length);
AL_API void AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length);
#endif
#endif
@@ -343,8 +326,8 @@ ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffe
#define AL_SOFT_source_latency 1
#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200
#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201
typedef int64_t ALint64SOFT;
typedef uint64_t ALuint64SOFT;
typedef _alsoft_int64_t ALint64SOFT;
typedef _alsoft_uint64_t ALuint64SOFT;
typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble);
typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble);
typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*);
@@ -381,11 +364,11 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64
#ifndef AL_SOFT_deferred_updates
#define AL_SOFT_deferred_updates 1
#define AL_DEFERRED_UPDATES_SOFT 0xC002
typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void);
typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void);
typedef void (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void);
typedef void (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void);
#ifdef AL_ALEXT_PROTOTYPES
AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void);
AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void);
AL_API void AL_APIENTRY alDeferUpdatesSOFT(void);
AL_API void AL_APIENTRY alProcessUpdatesSOFT(void);
#endif
#endif
@@ -408,6 +391,13 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void);
/*#define AL_SEC_LENGTH_SOFT 0x200B*/
#endif
#ifndef AL_SOFT_buffer_length_query
#define AL_SOFT_buffer_length_query 1
/*#define AL_BYTE_LENGTH_SOFT 0x2009*/
/*#define AL_SAMPLE_LENGTH_SOFT 0x200A*/
/*#define AL_SEC_LENGTH_SOFT 0x200B*/
#endif
#ifndef ALC_SOFT_pause_device
#define ALC_SOFT_pause_device 1
typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device);
@@ -496,8 +486,8 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index);
#ifndef ALC_SOFT_device_clock
#define ALC_SOFT_device_clock 1
typedef int64_t ALCint64SOFT;
typedef uint64_t ALCuint64SOFT;
typedef _alsoft_int64_t ALCint64SOFT;
typedef _alsoft_uint64_t ALCuint64SOFT;
#define ALC_DEVICE_CLOCK_SOFT 0x1600
#define ALC_DEVICE_LATENCY_SOFT 0x1601
#define ALC_DEVICE_CLOCK_LATENCY_SOFT 0x1602
@@ -509,6 +499,155 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
#endif
#endif
#ifndef AL_SOFT_direct_channels_remix
#define AL_SOFT_direct_channels_remix 1
#define AL_DROP_UNMATCHED_SOFT 0x0001
#define AL_REMIX_UNMATCHED_SOFT 0x0002
#endif
#ifndef AL_SOFT_bformat_ex
#define AL_SOFT_bformat_ex 1
#define AL_AMBISONIC_LAYOUT_SOFT 0x1997
#define AL_AMBISONIC_SCALING_SOFT 0x1998
/* Ambisonic layouts */
#define AL_FUMA_SOFT 0x0000
#define AL_ACN_SOFT 0x0001
/* Ambisonic scalings (normalization) */
/*#define AL_FUMA_SOFT*/
#define AL_SN3D_SOFT 0x0001
#define AL_N3D_SOFT 0x0002
#endif
#ifndef ALC_SOFT_loopback_bformat
#define ALC_SOFT_loopback_bformat 1
#define ALC_AMBISONIC_LAYOUT_SOFT 0x1997
#define ALC_AMBISONIC_SCALING_SOFT 0x1998
#define ALC_AMBISONIC_ORDER_SOFT 0x1999
#define ALC_MAX_AMBISONIC_ORDER_SOFT 0x199B
#define ALC_BFORMAT3D_SOFT 0x1507
/* Ambisonic layouts */
#define ALC_FUMA_SOFT 0x0000
#define ALC_ACN_SOFT 0x0001
/* Ambisonic scalings (normalization) */
/*#define ALC_FUMA_SOFT*/
#define ALC_SN3D_SOFT 0x0001
#define ALC_N3D_SOFT 0x0002
#endif
#ifndef AL_SOFT_effect_target
#define AL_SOFT_effect_target
#define AL_EFFECTSLOT_TARGET_SOFT 0x199C
#endif
#ifndef AL_SOFT_events
#define AL_SOFT_events 1
#define AL_EVENT_CALLBACK_FUNCTION_SOFT 0x19A2
#define AL_EVENT_CALLBACK_USER_PARAM_SOFT 0x19A3
#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT 0x19A4
#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0x19A5
#define AL_EVENT_TYPE_DISCONNECTED_SOFT 0x19A6
typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param,
ALsizei length, const ALchar *message,
void *userParam);
typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable);
typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam);
typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname);
typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values);
#ifdef AL_ALEXT_PROTOTYPES
AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable);
AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam);
AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname);
AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values);
#endif
#endif
#ifndef ALC_SOFT_reopen_device
#define ALC_SOFT_reopen_device
typedef ALCboolean (ALC_APIENTRY*LPALCREOPENDEVICESOFT)(ALCdevice *device,
const ALCchar *deviceName, const ALCint *attribs);
#ifdef AL_ALEXT_PROTOTYPES
ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device, const ALCchar *deviceName,
const ALCint *attribs);
#endif
#endif
#ifndef AL_SOFT_callback_buffer
#define AL_SOFT_callback_buffer
#define AL_BUFFER_CALLBACK_FUNCTION_SOFT 0x19A0
#define AL_BUFFER_CALLBACK_USER_PARAM_SOFT 0x19A1
typedef ALsizei (AL_APIENTRY*ALBUFFERCALLBACKTYPESOFT)(ALvoid *userptr, ALvoid *sampledata, ALsizei numbytes);
typedef void (AL_APIENTRY*LPALBUFFERCALLBACKSOFT)(ALuint buffer, ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr);
typedef void (AL_APIENTRY*LPALGETBUFFERPTRSOFT)(ALuint buffer, ALenum param, ALvoid **value);
typedef void (AL_APIENTRY*LPALGETBUFFER3PTRSOFT)(ALuint buffer, ALenum param, ALvoid **value1, ALvoid **value2, ALvoid **value3);
typedef void (AL_APIENTRY*LPALGETBUFFERPTRVSOFT)(ALuint buffer, ALenum param, ALvoid **values);
#ifdef AL_ALEXT_PROTOTYPES
AL_API void AL_APIENTRY alBufferCallbackSOFT(ALuint buffer, ALenum format, ALsizei freq, ALBUFFERCALLBACKTYPESOFT callback, ALvoid *userptr);
AL_API void AL_APIENTRY alGetBufferPtrSOFT(ALuint buffer, ALenum param, ALvoid **ptr);
AL_API void AL_APIENTRY alGetBuffer3PtrSOFT(ALuint buffer, ALenum param, ALvoid **ptr0, ALvoid **ptr1, ALvoid **ptr2);
AL_API void AL_APIENTRY alGetBufferPtrvSOFT(ALuint buffer, ALenum param, ALvoid **ptr);
#endif
#endif
#ifndef AL_SOFT_UHJ
#define AL_SOFT_UHJ
#define AL_FORMAT_UHJ2CHN8_SOFT 0x19A2
#define AL_FORMAT_UHJ2CHN16_SOFT 0x19A3
#define AL_FORMAT_UHJ2CHN_FLOAT32_SOFT 0x19A4
#define AL_FORMAT_UHJ3CHN8_SOFT 0x19A5
#define AL_FORMAT_UHJ3CHN16_SOFT 0x19A6
#define AL_FORMAT_UHJ3CHN_FLOAT32_SOFT 0x19A7
#define AL_FORMAT_UHJ4CHN8_SOFT 0x19A8
#define AL_FORMAT_UHJ4CHN16_SOFT 0x19A9
#define AL_FORMAT_UHJ4CHN_FLOAT32_SOFT 0x19AA
#define AL_STEREO_MODE_SOFT 0x19B0
#define AL_NORMAL_SOFT 0x0000
#define AL_SUPER_STEREO_SOFT 0x0001
#define AL_SUPER_STEREO_WIDTH_SOFT 0x19B1
#endif
#ifndef AL_SOFT_UHJ_ex
#define AL_SOFT_UHJ_ex
#define AL_FORMAT_UHJ2CHN_MULAW_SOFT 0x19B3
#define AL_FORMAT_UHJ2CHN_ALAW_SOFT 0x19B4
#define AL_FORMAT_UHJ2CHN_IMA4_SOFT 0x19B5
#define AL_FORMAT_UHJ2CHN_MSADPCM_SOFT 0x19B6
#define AL_FORMAT_UHJ3CHN_MULAW_SOFT 0x19B7
#define AL_FORMAT_UHJ3CHN_ALAW_SOFT 0x19B8
#define AL_FORMAT_UHJ4CHN_MULAW_SOFT 0x19B9
#define AL_FORMAT_UHJ4CHN_ALAW_SOFT 0x19BA
#endif
#ifndef ALC_SOFT_output_mode
#define ALC_SOFT_output_mode
#define ALC_OUTPUT_MODE_SOFT 0x19AC
#define ALC_ANY_SOFT 0x19AD
/*#define ALC_MONO_SOFT 0x1500*/
/*#define ALC_STEREO_SOFT 0x1501*/
#define ALC_STEREO_BASIC_SOFT 0x19AE
#define ALC_STEREO_UHJ_SOFT 0x19AF
#define ALC_STEREO_HRTF_SOFT 0x19B2
/*#define ALC_QUAD_SOFT 0x1503*/
#define ALC_SURROUND_5_1_SOFT 0x1504
#define ALC_SURROUND_6_1_SOFT 0x1505
#define ALC_SURROUND_7_1_SOFT 0x1506
#endif
#ifndef AL_SOFT_source_start_delay
#define AL_SOFT_source_start_delay
typedef void (AL_APIENTRY*LPALSOURCEPLAYATTIMESOFT)(ALuint source, ALint64SOFT start_time);
typedef void (AL_APIENTRY*LPALSOURCEPLAYATTIMEVSOFT)(ALsizei n, const ALuint *sources, ALint64SOFT start_time);
#ifdef AL_ALEXT_PROTOTYPES
void AL_APIENTRY alSourcePlayAtTimeSOFT(ALuint source, ALint64SOFT start_time);
void AL_APIENTRY alSourcePlayAtTimevSOFT(ALsizei n, const ALuint *sources, ALint64SOFT start_time);
#endif
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -1,6 +1,7 @@
#ifndef AL_EFX_H
#define AL_EFX_H
#include <float.h>
#include "alc.h"
#include "al.h"
@@ -242,41 +243,41 @@ typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*
typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);
#ifdef AL_ALEXT_PROTOTYPES
AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects);
AL_API void AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
AL_API void AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects);
AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect);
AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues);
AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
AL_API void AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
AL_API void AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues);
AL_API void AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
AL_API void AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues);
AL_API void AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
AL_API void AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
AL_API void AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
AL_API void AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters);
AL_API void AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
AL_API void AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters);
AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter);
AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues);
AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
AL_API void AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
AL_API void AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues);
AL_API void AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
AL_API void AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues);
AL_API void AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
AL_API void AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
AL_API void AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
AL_API void AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots);
AL_API void AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
AL_API void AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots);
AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
AL_API void AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
AL_API void AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues);
AL_API void AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
AL_API void AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues);
AL_API void AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
AL_API void AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
#endif
/* Filter ranges and defaults. */

View File

@@ -49,7 +49,7 @@ namespace Flax.Deps.Dependencies
public override void Build(BuildOptions options)
{
var root = options.IntermediateFolder;
var version = "1.23.0";
var version = "1.23.1";
var dstIncludePath = Path.Combine(options.ThirdPartyFolder, "OpenAL");
foreach (var platform in options.Platforms)

View File

@@ -42,18 +42,23 @@ namespace Flax.Build.Platforms
// Pick the newest compiler (overriden by specified in command line)
if (Which(Configuration.Compiler) != null)
Compiler = Configuration.Compiler;
else if (Which("clang++-10") != null)
Compiler = "clang++-10";
else if (Which("clang++-9") != null)
Compiler = "clang++-9";
else if (Which("clang++-8") != null)
Compiler = "clang++-8";
else if (Which("clang++-7") != null)
Compiler = "clang++-7";
else if (Which("clang++-6") != null)
Compiler = "clang++-6";
else if (Which("clang++") != null)
Compiler = "clang++";
else
{
for (int ver = 15; ver >= 6; ver--)
{
var compiler = "clang++-" + ver;
if (Which(compiler) != null)
{
Compiler = compiler;
break;
}
}
if (Compiler == null)
{
if (Which("clang++") != null)
Compiler = "clang++";
}
}
}
if (Compiler != null)
{