2021SC@SDUSC
好。咱们继续。
Struct AudioDataInfo API
描述音频切片的元数据。
成员:
BitDepth 位深度。这个稍微懂一点计算机音频的都应该知道了,就不谈了。类型是Uint32.
NumChannels 通道数量。 类型同上,Uint32
NumSamples,音频数据中的采样总数。Uint32
Samplerate采样率。Uint32
这之后来看音频设备AudioDevice.h。
先看文档里面吧:
构造器AudioDevice()
成员:
Name 名称。字符串。
explicit AudioDevice()
: PersistentScriptingObject(SpawnParams(Guid::New(), TypeInitializer))
{
}
这里用到了显式指定explicit。禁止隐式转换调用这个构造器。
枚举类Enum AudioFormat
两个字段,raw和vorbis。Raw是rawPcmdata,vorbisvorbisData。再提一次,Vorbis是一种有损压缩格式。
监听器AudioListener。
先看文档。
监听器表示听到音频源的侦听器。对于空间音频,所播放的音频的音量和音调是由声源和听者之间的距离、方向和速度差决定的。
构造器AudioListener()
成员:
Velocity,监听器的速度。音调受监听器的位置影响。类型是Vector3。这个Vector3,我们紧接着就来看看。
跳转到这个Vector3.
Vector3,表示一个三维向量。
构造器Vector3(vector2,single)
两个参数,第一个顾名思义肯定是一个二维的向量,表示x和y;第二个参数表示Z的初始值。
构造器vector3(vector4)
一个包含有xyz轴的向量。
构造器Vector3(single)
一个single被赋给所有的组件(三个方向)
然后还有两个构造器,分别从三个参数和一个single数组中获取参数,不再赘述。
成员:
Backward
向量单位,表示左手坐标系中向后的单位(0,0,-1)。
同样的,还有Down和Forward。不再赘述。
Half 所有参量减半。
Maximum 一个vector3,所有参量都等于System.Single.MaxValue
同理还有一个Minimum
One 所有参量等于一
SizeInBytes
以字节返回Vector3的大小
UnitX Vector3单位向量(1,0,0)
同理还有Unity,unityz
此外有XYZ单位组件。
成员变量:
Absolute
返回绝对值
avgValue
平均值
Isnormalized
是否正则化。Bool型。
Abs(Vector3)
返回绝对值
Add(Vector3,Vector3)
两个三维向量相加。
然后还有一大堆向量向量、向量组件、组件组件相互四则运算的方法。不谈了。
还有几个重写操作符Operator。
就是向量和向量相加,向量和组件相四则运算、还有相等。
看一下文件里面Listener.cpp
void AudioListener::Update()
{
// Update the velocity
const Vector3 pos = GetPosition();
const float dt = Time::Update.UnscaledDeltaTime.GetTotalSeconds();
const auto prevVelocity = _velocity;
_velocity = (pos - _prevPos) / dt;
_prevPos = pos;
if (_velocity != prevVelocity)
{
AudioBackend::Listener::VelocityChanged(this);
}
}
更新监听器。
先获得当前位置,然后获取当前时间。
把前一个速度记下来,然后算现在的速度,距离相减除以时间;
如果现在的速度有变化,更新。
void AudioListener::OnEnable()
{
_prevPos = GetPosition();
_velocity = Vector3::Zero;
Audio::OnAddListener(this);
GetScene()->Ticking.Update.AddTick<AudioListener, &AudioListener::Update>(this);
#if USE_EDITOR
GetSceneRendering()->AddViewportIcon(this);
#endif
// Base
Actor::OnEnable();
}
void AudioListener::OnDisable()
{
#if USE_EDITOR
GetSceneRendering()->RemoveViewportIcon(this);
#endif
GetScene()->Ticking.Update.RemoveTick(this);
Audio::OnRemoveListener(this);
// Base
Actor::OnDisable();
}
一组启用和停用监听器的方法。
API_CLASS() class FLAXENGINE_API AudioListener : public Actor
{
DECLARE_SCENE_OBJECT(AudioListener);
private:
Vector3 _velocity;
Vector3 _prevPos;
监听器里面的actor,两个私有成员,速度、位置。
private:
void Update();
更新方法,上面说过了。
AudioSetting.h
bool DisableAudio = false;
/// <summary>
/// The doppler effect factor. Scale for source and listener velocities. Default is 1.
/// </summary>
API_FIELD(Attributes="EditorOrder(100), DefaultValue(1.0f), EditorDisplay(\"General\")")
float DopplerFactor = 1.0f;
一些默认设置。
随便看一下,比如默认是启用音频,然后多普勒因子1.0
Class AudioSource
音频源。音频可以在空间中播放(比如枪声) ,或正常播放下(背景音乐)。每个音频源必须由一个音频片段(就是上面的clip)来播放。如果是空间音频,那么他要有一个位置属性(当然了,不然在哪里放呢。)
然后音频源是否是空间的,由指定的音频clip控制。空间音频源的音量和音调由其位置和 AudioListener监听器的位置、方向、速度控制。
构造器AudioSource()没啥好说的。
Properties
Attenuation衰减值
获取或设置衰减值,该衰减值控制当侦听器远离源时音频音量下降的速度。类型是single
Clip片段 就是上面的那个clip
Is3D 就是上面的那个空间与否。Bool类型。
IsActrallyPlayingSTh确定此音频源是否通过音频后端开始播放音频。音频播放后,它可能等待音频剪辑数据被加载或流。有一说一这个没看懂啥意思。大概是源还可以直接绕过音频后端不做任何处理播放。
Islooping 循环与否。布尔值。
MinDistance 获取或设置音频衰减开始的最小距离。当侦听器距离源的距离比这个值更近时,就会以最大音量听到音频。一旦远离音频开始衰减。Single类型。
Pitch 音调。Get、set音调。默认是1.single类型。
Playonstart 是否自动开始播放。布尔值。
State set、get当前音频状态,就是暂停、播放、停止。类型是states。
Time 获取播放时间。形式是秒,必须在0和总长度之间。当然了。
UseStreaming如果音频剪辑有效、已加载并使用动态数据流,则返回 true。布尔值。
Velocity 源的速度。影响音调,当然这个只对空间音源有效。Vector3类型。
Volume single类型。音量。
方法:
Pause()
Play()
Stop()
没啥好说的。
AudioSource::AudioSource(const SpawnParams& params)
: Actor(params)
, _velocity(Vector3::Zero)
, _volume(1.0f)
, _pitch(1.0f)
, _minDistance(1.0f)
, _attenuation(1.0f)
, _loop(false)
, _playOnStart(false)
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)
{
value = Math::Clamp(value, 0.5f, 2.0f);
if (Math::NearEqual(_pitch, value))
return;
_pitch = value;
if (SourceIDs.HasItems())
{
AudioBackend::Source::PitchChanged(this);
}
}
设置音调。
下面还有很多相似的setget,就跳过吧。
void AudioSource::Play()
{
if (_state == States::Playing)
return;
if (Clip == nullptr)
{
LOG(Warning, "Cannot play audio source without a clip ({0})", GetNamePath());
return;
}
_state = States::Playing;
_isActuallyPlayingSth = false;
// Don't block scripting if audio is not loaded or has missing streaming data
if (!Clip->IsLoaded())
return;
// Audio clips with disabled streaming are controlled by audio source, otherwise streaming manager will play it
if (Clip->IsStreamable())
{
// Request faster streaming update
Clip->RequestStreamingUpdate();
}
else
{
// Play it right away
SetNonStreamingBuffer();
PlayInternal();
}
}
Types.h里面规定了变量的类型。
API_FIELD() uint32 NumSamples;
/// <summary>
/// The number of audio samples per second, per channel.
/// </summary>
API_FIELD() uint32 SampleRate;
/// <summary>
/// The number of channels. Each channel has its own set of samples.
/// </summary>
API_FIELD() uint32 NumChannels;
然后整个Audio大包就看完了。整体功能还是比较明确的,音频源-音频后端的路径,然后最终落实到播放音频上;播放音频包括两种,一种全局音乐,一种带一个位置和速度属性的空间音乐。然后在AudioClip里面可以自己把音频源剪成音频片段。
直接按顺序向下,Content大包。
Class Content 加载并管理所有的assets。这里应该叫做对象吗?
看一下Properties。
Assets 拿到已经加载的对象,或者通过加载方法拿到未加载对象。有点拗口。值是一个asset列表。
Stats 拿到内容的统计属性,类型是一个ContentStats。这个类型我们下面马上去看。
结构体:ContentStats
内容的统计数据容器。
字段:
AssetsCount 内存中的目标对象数量。Int32
LoadedAssetsCount已加载目标数量int32
LoadingAssetscount 正在加载的数量。若全部加载完成,为0.int32
VirtualAssetscount 虚对象数量。虚对象,指的是未在文件中拥有指代的对象 Int32
然后我们回到Content。
Methods
CreateTemporaryAssetsPath()
生成临时的对象路径
然后下面几个功能类似的,就不翻译了,一起贴出来。
然后是获取对象信息,输出AssetInfo类型,这个类型下面看。当然,也是分两个方法,按照id和string去get。
结构体:AssetInfo
描述简短信息的容器
字段:
ID guid类型
Path string
Type name string
很短,就这三个。
回到方法:
Load(guid,double)
将目标对象加载到内容池并保存它,直到它不被任何对象引用为止。如果目标丢失,返回 null。实际的数据加载在另一个线程上异步执行。目标被加载前阻塞。相当于 LoadAsync + WaitForLoaded。返回值:Asset instance if loaded, null otherwise。参数里面第一个是id,第二个是自定义的超时毫秒。
然后下面是一个对应的方法,不是从id加载而是从路径加载。
LoadAsync(id) 看来这个就是上一个Load函数提到过的组合函数之一。
然后下面是一大堆类似的加载函数,就是参数的排列组合,不再赘述。
重命名。RenameAsset()
卸载Asset。 UnloadAsset(Asset)
Events:
AssetDisposing 当对象被卸载时发生。将会清除所有指向该对象的引用。
AssetReloading 对象重载时发生。总会由主线程调用。