-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathCookFrameSequenceAsync.cpp
69 lines (55 loc) · 2.46 KB
/
CookFrameSequenceAsync.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// Fill out your copyright notice in the Description page of Project Settings.
#include "CookFrameSequenceAsync.h"
#include "Sound/SoundWave.h"
#include "Misc/ScopedSlowTask.h"
#include "Async/Async.h"
constexpr auto LipSyncSequenceUpateFrequency = 100;
constexpr auto LipSyncSequenceDuration = 1.0f / LipSyncSequenceUpateFrequency;
UCookFrameSequenceAsync* UCookFrameSequenceAsync::CookFrameSequence(const TArray<uint8>& RawSamples, bool UseOfflineModel)
{
UCookFrameSequenceAsync* BPNode = NewObject<UCookFrameSequenceAsync>();
BPNode->RawSamples = RawSamples;
BPNode->UseOfflineModel = UseOfflineModel;
return BPNode;
}
void UCookFrameSequenceAsync::Activate()
{
if (RawSamples.Num() <= 44)
{
onFrameSequenceCooked.Broadcast(nullptr, false);
return;
}
FWaveModInfo waveInfo;
uint8 *waveData = const_cast<uint8*>(RawSamples.GetData());
if (waveInfo.ReadWaveInfo(waveData, RawSamples.Num()))
{
int32 NumChannels = *waveInfo.pChannels;
int32 SampleRate = *waveInfo.pSamplesPerSec;
auto PCMDataSize = waveInfo.SampleDataSize / sizeof(int16_t);
int16_t* PCMData = reinterpret_cast<int16_t*>(waveData + 44);
int32 ChunkSizeSamples = static_cast<int32>(SampleRate * LipSyncSequenceDuration);
int32 ChunkSize = NumChannels * ChunkSizeSamples;
int BufferSize = 4096;
FString modelPath = UseOfflineModel ? FPaths::Combine(FPaths::ProjectPluginsDir(), TEXT("OVRLipSync"),
TEXT("OfflineModel"), TEXT("ovrlipsync_offline_model.pb"))
: FString();
Async(EAsyncExecution::Thread, [=]()
{
UOVRLipSyncFrameSequence* Sequence = NewObject<UOVRLipSyncFrameSequence>();
UOVRLipSyncContextWrapper context(ovrLipSyncContextProvider_Enhanced, SampleRate, BufferSize, modelPath);
float LaughterScore = 0.0f;
int32_t FrameDelayInMs = 0;
TArray<float> Visemes;
for (int offs = 0; offs + ChunkSize < PCMDataSize; offs += ChunkSize)
{
context.ProcessFrame(PCMData + offs, ChunkSizeSamples, Visemes, LaughterScore, FrameDelayInMs, NumChannels > 1);
Sequence->Add(Visemes, LaughterScore);
}
AsyncTask(ENamedThreads::GameThread, [Sequence, this]() {
onFrameSequenceCooked.Broadcast(Sequence, true);
});
});
}
else
onFrameSequenceCooked.Broadcast(nullptr, false);
}