تدفق موجة الصوت
لاكتشاف نشاط الصوت (VAD)، راجع هذه الصفحة.
موجة الصوت المتدفقة هي نوع من موجات الصوت المستوردة التي تدعم إضافة بيانات الصوت ديناميكيًا، حتى أثناء التشغيل. توفر نفس الوظائف مثل موجة الصوت المستوردة، مثل إعادة التشغيل، ويمكن استخدامها في SoundCues، إلخ.
إنشاء موجة صوت متدفقة
أولاً يجب عليك إنشاء موجة صوت متدفقة. يرجى ملاحظة أنه يجب التعامل معها كمرجع قوي لمنع التدمير المبكر (على سبيل المثال عن طريق تعيينها لمتغير منفصل في Blueprints أو استخدام UPROPERTY()
في C++).
- Blueprint
- C++
UStreamingSoundWave* StreamingSoundWave = UStreamingSoundWave::CreateStreamingSoundWave();
تشغيل موجة الصوت
يمكنك بعد ذلك تشغيل موجة الصوت تلك. ومع ذلك، ليس من الضروري القيام بذلك الآن، يمكنك بدء تشغيل موجة الصوت لاحقًا.
تخصيص بيانات الصوت مسبقًا
اختياريًا، يمكنك تخصيص بيانات الصوت (بايت) مسبقًا لتجنب إعادة تخصيص مخزن PCM بالكامل في كل مرة يتم فيها إلحاق بيانات صوتية جديدة.
- Blueprint
- C++
// Assuming StreamingSoundWave is a UE reference to a UStreamingSoundWave object (or its derived type, such as UCapturableSoundWave)
StreamingSoundWave->PreAllocateAudioData(12582912, FOnPreAllocateAudioDataResultNative::CreateWeakLambda(this, [StreamingSoundWave](bool bSucceeded)
{
// Handle the result
}));
إلحاق بيانات الصوت
لإضافة بيانات الصوت إلى نهاية المخزن المؤقت الحالي، استخدم الدوال المناسبة للإلحاق الديناميكي لبيانات الصوت. سيتابع التشغيل تسلسل الطابور لهذه الإلحاقات.
- Blueprint
- C++
// Assuming StreamingSoundWave is a UE reference to a UStreamingSoundWave object (or its derived type, such as UCapturableSoundWave)
// Example of appending encoded audio data
TArray<uint8> AudioData = ...; // Fill with audio data
StreamingSoundWave->AppendAudioDataFromEncoded(AudioData, ERuntimeAudioFormat::Auto);
// Or, if you have raw audio data
TArray<uint8> RawAudioData = ...; // Fill with raw audio data
StreamingSoundWave->AppendAudioDataFromRAW(RawAudioData, ERuntimeRAWAudioFormat::Float32, 44100, 2);
تجنب تشغيل الصوت المسرع أو المشوه
عند بث بيانات الصوت أثناء تشغيل الموجة الصوتية، قد تواجه تشغيلًا صوتيًا مسرعًا أو مشوهًا في سيناريوهات محددة. تحدث هذه المشكلة عادةً عندما:
- يكون تشغيل الموجة الصوتية قريبًا/في نهاية المخزن المؤقت الحالي
- يتم إضافة بيانات صوتية جديدة باستمرار إلى موجة الصوت المتدفقة
- يلحق التشغيل بتيار البيانات الواردة
يمكنك إيقاف تعبئة بيانات الصوت في أي وقت دون مشاكل. ومع ذلك، بالنسبة للسيناريوهات التي تحتاج فيها إلى تدفق مستمر (مثل بث الصوت في الو قت الفعلي)، هناك طريقتان اعتمادًا على موثوقية تدفق بيانات الصوت لديك:
لتدفق موثوق ومتسق: استخدم مندوب OnPopulateAudioState لبدء التشغيل فورًا بعد استلام القطعة الأولى.
لتدفق غير موثوق (مشاكل الشبكة، بيانات متقطعة): أضف تأخيرًا إضافيًا حتى بعد تشغيل OnPopulateAudioState لبناء مخزن مؤقت أكبر قبل بدء التشغيل.
- Blueprint
- C++
// Approach 1: For reliable streaming - start immediately after first chunk
bool bHasStartedPlayback = false;
StreamingSoundWave->OnPopulateAudioStateNative.AddWeakLambda(this, [this, &bHasStartedPlayback]()
{
if (!bHasStartedPlayback)
{
UGameplayStatics::PlaySound2D(GetWorld(), StreamingSoundWave);
bHasStartedPlayback = true;
}
});
// Approach 2: For unreliable streaming - add delay after first chunk
bool bHasStartedPlayback = false;
StreamingSoundWave->OnPopulateAudioStateNative.AddWeakLambda(this, [this, &bHasStartedPlayback]()
{
if (!bHasStartedPlayback)
{
// Add delay to build up buffer for unreliable streaming
GetWorld()->GetTimerManager().SetTimer(PlaybackDelayTimer, [this]()
{
UGameplayStatics::PlaySound2D(GetWorld(), StreamingSoundWave);
}, 0.5f, false); // Half-second delay
bHasStartedPlayback = true;
}
});
ملاحظة: يمكنك إيقاف تعبئة بيانات الصوت في أي وقت دون التسبب في مشاكل تشغيل. يعتمد الأسلوب الدقيق على موثوقية تدفق بيانات الصوت لديك - استخدم التشغيل الفوري للتدفقات المتسقة، أو أضف تأخير تخزين مؤقت إضافي للتدفقات غير الموثوقة (مثل مشاكل اتصال الشبكة).
مثال للاستخدام
أخيرًا، قد يبدو تنفيذك كما يلي:
- Blueprint
- C++
هذا مثال أساسي للكود لإلحاق بيانات الصوت بموجة صوتية متدفقة.
يستخدم المثال دالة AppendAudioExample
الموجودة في صنف UAppendAudioClassExample
داخل وحدة EXAMPLEMODULE
.
ملاحظة: للتشغيل الناجح للمثال، تأكد من إضافة وحدة RuntimeAudioImporter
إما إلى PublicDependencyModuleNames
أو PrivateDependencyModuleNames
في ملف .Build.cs، وكذلك إلى ملف .uproject الخاص بمشروعك.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "AppendAudioClassExample.generated.h"
UCLASS(BlueprintType)
class EXAMPLEMODULE_API UAppendAudioClassExample : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void AppendAudioExample();
private:
// Please pay attention to making the StreamingSoundWave a hard reference, such as using UPROPERTY(), to prevent it from being prematurely garbage collected
UPROPERTY()
class UStreamingSoundWave* StreamingSoundWave;
};
#include "AppendAudioClassExample.h"
#include "Sound/StreamingSoundWave.h"
void UAppendAudioClassExample::AppendAudioExample()
{
// Create a streaming sound wave
StreamingSoundWave = UStreamingSoundWave::CreateStreamingSoundWave();
// Append audio data
TArray<uint8> StreamedAudioDataToAdd = ...; // Fill with audio data
StreamingSoundWave->AppendAudioDataFromEncoded(StreamedAudioDataToAdd, ERuntimeAudioFormat::Auto);
// Play the sound wave
UGameplayStatics::PlaySound2D(GetWorld(), StreamingSoundWave);
}
عند ملء حالة الصوت
تعمل المفوضة OnPopulateAudioState بشكل مشابه لـ OnPopulateAudioData ولكنها لا تبث بيانات الصوت المملوءة. يمكن أن يكون هذا مفيدًا عندما تريد تتبع وقت ملء بيانات الصوت دون تمرير مصفوفة لبيانات الصوت المملوءة، مما قد يحسن الأداء.
- Blueprint
- C++
// Assuming StreamingSoundWave is a UE reference to a UStreamingSoundWave object (or its derived type, such as UCapturableSoundWave)
StreamingSoundWave->OnPopulateAudioStateNative.AddWeakLambda(this, [this]()
{
// Handle the result
});
العمل مع بيانات PCM
للوصول إلى بيانات PCM في الوقت الفعلي أثناء التشغيل، راجع معالجة بيانات PCM.