🔊

USoundWaveにツール等で生成した音データを入れて再生する

2023/08/10に公開

表題の通り、USoundWaveにツール等で生成した音データを入れて再生するやり方です。

無料で使える中品質なテキスト読み上げソフトウェア『VOICEVOX』から生成した音データをUSoundWaveに組み込んで再生させる、ということをしようとして想像以上に苦労したので記載しました。

↓苦労した自作プラグイン
Voicevox Engine For UEプラグイン

参考になれば幸いです。

サンプルコード

今回は単純に作成したUSoundWaveをPlaySound2Dを利用して再生します。

Sample.cpp

// AActorを継承

//何かしらのライブラリorツールで声データを取得済、と仮定
TArray<uint8> PCMData;

FString ErrorMessage = "";
// 音声データから必要な情報をロード
if (FWaveModInfo WaveInfo; WaveInfo.ReadWaveInfo(PCMData.GetData(), PCMData.Num(), &ErrorMessage))
{
	// USoundWaveを作成
	USoundWave* Sound = NewObject<USoundWave>(USoundWave::StaticClass());
	
	// フォーラムとエンジンソースコードを参考
	const int32 ChannelCount = *WaveInfo.pChannels;
	const int32 SizeOfSample = *WaveInfo.pBitsPerSample / 8;
	const int32 NumSamples = WaveInfo.SampleDataSize / SizeOfSample;
	const int32 NumFrames = NumSamples / ChannelCount;
		
	// 音声データを直接入れるのではなく、WaveInfoからロードしたデータを格納する
	Sound->RawPCMDataSize = WaveInfo.SampleDataSize;
	Sound->RawPCMData = static_cast<uint8*>(FMemory::Malloc(WaveInfo.SampleDataSize));
	FMemory::Memmove(Sound->RawPCMData, WaveInfo.SampleDataStart, WaveInfo.SampleDataSize);
		
	// 最低限必要な情報をセット
	Sound->Duration = static_cast<float>(NumFrames) / *WaveInfo.pSamplesPerSec;
	Sound->SetSampleRate(*WaveInfo.pSamplesPerSec);
	Sound->NumChannels = ChannelCount;
	Sound->TotalSamples = *WaveInfo.pSamplesPerSec * Sound->Duration;
	
	// 音再生
	UGameplayStatics::PlaySound2D(GetWorld(), Sound);
}

USoundWaveに音データを入れる際の注意点

重要なのはただ一点、RawPCMData、RawPCMDataSizeに 生成した音データ を入れないことです。
生成した音データを入れてしまうと、再生開始時にポップノイズが高確率で発生します

ポップノイズを防ぐために生成した音データをReadWaveInfoで読み込ませ、WaveInfo.SampleDataStart、WaveInfo.SampleDataSizeを必ず使用するようにしてください。


// NGパターン

// 音データを直接入れることは可能だが、高確率でポップノイズが発生
Sound->RawPCMDataSize = PCMData.Num();
Sound->RawPCMData = static_cast<uint8*>(FMemory::Malloc(PCMData.Num()));
FMemory::Memmove(Sound->RawPCMData, PCMData.GetData(), PCMData.Num());

// ネイティブの音再生APIを利用すれば、ポップノイズは発生しない
#if PLATFORM_WINDOWS
PlaySound(reinterpret_cast<LPCTSTR>(PCMData.GetData()), nullptr, SND_MEMORY);
#endif

// OKパターン

// WavInfoに格納された音データはポップノイズが発生しない!
Sound->RawPCMDataSize = WaveInfo.SampleDataSize;
Sound->RawPCMData = static_cast<uint8*>(FMemory::Malloc(WaveInfo.SampleDataSize));
FMemory::Memmove(Sound->RawPCMData, WaveInfo.SampleDataStart, WaveInfo.SampleDataSize);

これが出来ると自作のサウンドエンジンやオリジナルの音声チャットシステム、音声読み上げソフトをプロジェクトに組み込んで楽しいことができる、かもしれません。

参考資料

https://forums.unrealengine.com/t/ue5-1-how-to-access-soundwaves-resourcedata-in-packaged-build/719408/2

https://forums.unrealengine.com/t/how-to-play-a-soundcue-in-c/339969

https://github.com/getnamo/TensorFlow-Unreal/issues/27

Discussion