UEのQuartzをC++から触ってみる

頑張ってBlueprintをC++変換する練習をしているので、
備忘録がてらQuartzのビートごとにイベントが呼ばれる簡単なサンプルをC++で書いてみました。

Blueprint版

C++

SandboxActor.cpp
#include "SandboxActor.h"

#include "Components/AudioComponent.h"
#include "Kismet/KismetSystemLibrary.h"

ASandboxActor::ASandboxActor()
{
	PrimaryActorTick.bCanEverTick = true;

	ClockHandleCpp = CreateDefaultSubobject<UQuartzClockHandle>(TEXT("ClockHandleCpp"));

	RootCpp = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
	AudioComponentCpp = CreateDefaultSubobject<UAudioComponent>(TEXT("AudioCpp"));

	SetRootComponent(RootCpp);
	AudioComponentCpp->SetupAttachment(RootCpp);
}

void ASandboxActor::BeginPlay()
{
	Super::BeginPlay();

	EnableInput(GetWorld()->GetFirstPlayerController());
	InputComponent->BindKey(EKeys::H, IE_Pressed, this, &ASandboxActor::PressedH);
}

void ASandboxActor::PressedH()
{
	FQuartzQuantizationBoundary QuantizationBoundary = FQuartzQuantizationBoundary(EQuartzCommandQuantization::Bar);
	AudioComponentCpp->PlayQuantized(
		this,
		ClockHandleCpp,
		QuantizationBoundary,
		FOnQuartzCommandEventBP(),
		0.0f,
		0.0f,
		1.0f,
		EAudioFaderCurve::Linear
	);

	FOnQuartzMetronomeEventBP OnQuantizationEvent;
	OnQuantizationEvent.BindDynamic(this, &ASandboxActor::MyQuantizationEvent);
	ClockHandleCpp->SubscribeToQuantizationEvent(
		this,
		EQuartzCommandQuantization::Bar,
		OnQuantizationEvent,
		ClockHandleCpp
	);

	ClockHandleCpp->ResumeClock(
		this,
		ClockHandleCpp
	);
}

void ASandboxActor::MyQuantizationEvent(FName ClockName, EQuartzCommandQuantization QuantizationType, int32 NumBars, int32 Beat, float BeatFraction)
{
	UKismetSystemLibrary::PrintString(this, "MyQuantizationEvent");
	TickCpp(NumBars); // こういう演出はBP側でできた方が嬉しいのかな〜と思ってあえてBPに残してる
}
SandboxActor.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Quartz/AudioMixerClockHandle.h"
#include "SandboxActor.generated.h"

UCLASS()
class SANDBOX_API ASandboxActor : public AActor
{
    GENERATED_BODY()
    
public:
    ASandboxActor();

protected:
    virtual void BeginPlay() override;

public:
    void PressedH();

    UFUNCTION(BlueprintCallable)
    void MyQuantizationEvent(FName ClockName, EQuartzCommandQuantization QuantizationType, int32 NumBars, int32 Beat, float BeatFraction);

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    UQuartzClockHandle* ClockHandleCpp;

    UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
    void TickCpp(int32 numBars);

protected:
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
    USceneComponent* RootCpp;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
    UAudioComponent* AudioComponentCpp;
};

ハマったところ

ASandboxActor::MyQuantizationEventはUFUNCTIONで定義しないとビルドが通るのに呼ばれない。
C++なんだからビルドが通るなら動いて欲しい・・・。

疑問点

ClockHandleCpp->ResumeClock(
    this,
    ClockHandleCpp
);

このへん、引数にClockHandleCpp(自分自身)を渡す意味何!?!?
たぶんBP用のinterfaceなんだろうけれど、C++からはどう呼ぶのが綺麗なんだろう
→ どうやらQuartzが特殊なだけで、他の機能はいい感じに呼べるっぽい。