2021.10.15

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()

生成临时的对象路径

然后下面几个功能类似的,就不翻译了,一起贴出来。

CreateVirtualAsset(Type)

CreateVirtualAsset<T>()

DeleteAsset(Asset)

DeleteAsset(String)

GetAllAssetsByType(Type)

GetAsset(Guid)

然后是获取对象信息,输出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 对象重载时发生。总会由主线程调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值