マルチバッファリングを用いてリアルタイムで音源を加工するサウンドノードを作っているのですが・・・

大学の研究でUE4を使用している者です.

サウンドキュー内のwaveplayer音源をバッファリングして,将来的には各バッファをリアルタイムで加工するサウンドノードをC++で作成しているのですが,コンパイルは成功したものの,
音源自体は加工されていないようでてこずっています.

UE4,C++共に初心者ながら以下二つのサイトを参考にソースを作らせていただきました.

http://mozpaca.hatenablog.com/entry/20171017/1508236384

以下に.hと.cppファイルを添付します.どうかお力添えお願いしたく存じます.

Buffering_sound.h

#pragma once
#include "windows.h"
#include "CoreMinimal.h"
#include "Sound/SoundNode.h"
#include "Buffering_sound.generated.h"

UCLASS(hidecategories = Object, editinlinenew, meta = (DisplayName = "Buffering"))
class SOUNDS_API UBuffering_sound : public USoundNode
{
	GENERATED_UCLASS_BODY()


	void closeWave();

	void initWave(TArray<FWaveInstance*>& WaveInstances);
	int32 oepnWaveFile(WAVEFORMATEX *wfe, TArray<FWaveInstance*>& WaveInstances);
	void wmWomDone();

	int32 readWaveData(HMMIO hmmio, short *buf, int bufferSize, int bufferLenght);
	

	virtual void ParseNodes(FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances) override;
	
//バッファ数(2以上にすること)	
#define BUFFER_COUNT 2


	//再生時の周波数	
	int32 srate;

  //バッファ関連情報
	int32 bufferSize;
	int32 bufferLenght;

  //バッファセレクター
	int32 bufferSelect;

  //再生予定のWAVEデータサイズ
	int32 waveDataSize;
  //再生済のWAVEデータのサイズ
	int32 readDataSize;

};

Buffering_sound.cpp

#include "Buffering_sound.h"
#include "ActiveSound.h"
#include "windows.h"

//ライブラリをくっつける
#pragma comment(lib, "winmm.lib")

//バッファ
static short  *(wWave[BUFFER_COUNT]);

//チャンネル数(2固定)
static const int32 channel = 2;

//出力のため構造体
static HWAVEOUT hWave;
static WAVEHDR whdr[BUFFER_COUNT];

//WAVEファイルを読み込むための構造体
static HMMIO hmmio;

//フォーマットチャンクのための構造体
static MMCKINFO ckRiff;

//音源
USoundWave * WaveData;


/** コンストラクタ */
UBuffering_sound::UBuffering_sound(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer){
	//HWND hWndMain;

	TestVolume = 1.f;
	TestIsMute = false;

}


void UBuffering_sound::ParseNodes(FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances)
{
	FSoundParseParameters UpdateParameters = ParseParams;
	Super::ParseNodes(AudioDevice, NodeWaveInstanceHash, ActiveSound, UpdateParameters, WaveInstances);
	initWave(WaveInstances);

	wmWomDone();
	closeWave();
	
	
}

/*Wave系の初期化全部*/
void UBuffering_sound::initWave(TArray<FWaveInstance*>& WaveInstances)
{
	int32 i;
	WAVEFORMATEX wfe;

   //WAVEデータ読み込みのための設定をする
	if (oepnWaveFile(&wfe, WaveInstances) == FALSE) {
		return ;
	}

        //バッファの長さを計算
	bufferLenght = srate * channel;
	bufferSize = bufferLenght * sizeof(short);

        //バッファのための領域確保
	for (i = 0; i<BUFFER_COUNT; i++) {
		wWave[i] = (short *)malloc(bufferSize);
	}

     //出力デバイスの設定  
	wfe.wFormatTag = WAVE_FORMAT_PCM;
	wfe.nSamplesPerSec = srate;
	wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8;
	wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nBlockAlign;

     //出力デバイスを開く
	waveOutOpen(&hWave, WAVE_MAPPER, &wfe,
		0, 0, CALLBACK_NULL);

	for (i = 0; i<BUFFER_COUNT; i++) {

		 //再生バッファにデータを送るための設定
		whdr[i].lpData = (LPSTR)wWave[i];
		whdr[i].dwBufferLength = 0;
		whdr[i].dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
		whdr[i].dwLoops = 1;

		waveOutPrepareHeader(hWave, &(whdr[i]), sizeof(WAVEHDR));
	}

     //マルチバッファリングをするために空データを書き込み
	waveOutWrite(hWave, &(whdr[0]), sizeof(WAVEHDR));
	waveOutWrite(hWave, &(whdr[1]), sizeof(WAVEHDR));

	 //セレクタの設定
	bufferSelect = 2 % BUFFER_COUNT;
	return ;
}

/*WAVEファイルの読み込み*/
int32 UBuffering_sound::oepnWaveFile(WAVEFORMATEX *wfe, TArray<FWaveInstance*>& WaveInstances)
{
  //WAVEファイルのオープン
	hmmio = mmioOpen((LPWSTR)WaveInstances.GetData(), NULL, MMIO_READ);
     

	if (!hmmio) {

		return FALSE;
	}
   //WAVEファイルかのチェック

	if (mmioDescend(hmmio, &ckRiff, NULL, 0) != MMSYSERR_NOERROR || ckRiff.ckid != FOURCC_RIFF || ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E'))
	{

		mmioClose(hmmio, 0);
		return FALSE;
	}

      // フォーマットチャンクの読み込み
	ckRiff.ckid = mmioFOURCC('f', 'm', 't', ' ');
     //フォーマットチャンクに侵入
	if (mmioDescend(hmmio, &ckRiff, NULL, MMIO_FINDCHUNK) != MMSYSERR_NOERROR) {

		mmioClose(hmmio, 0);
		return FALSE;
	}

     //フォーマットチャンクを読み込む
	ZeroMemory(wfe, sizeof(*wfe));
	if (mmioRead(hmmio, (HPSTR)wfe, (long)(ckRiff.cksize)) != (long)(ckRiff.cksize)) {

		mmioClose(hmmio, 0);
		return FALSE;
	}

      //フォーマットチャンクから抜け出す
	if (mmioAscend(hmmio, &ckRiff, 0) != MMSYSERR_NOERROR) {

		mmioClose(hmmio, 0);
		return FALSE;
	}

      // データチャンクの読み込み
	ckRiff.ckid = mmioFOURCC('d', 'a', 't', 'a');
     //データチャンクに侵入
	if (mmioDescend(hmmio, &ckRiff, NULL, MMIO_FINDCHUNK) != MMSYSERR_NOERROR) {

		mmioClose(hmmio, 0);
		return FALSE;
	}

	 //16Bitステレオかをチェック
	if (wfe->nChannels != 2 || wfe->wBitsPerSample != 16) {

		return FALSE;
	}

       //データのサイズ
	waveDataSize = ckRiff.cksize;

   //再生周波数を設定する。(自由に変えても良い。再生速度が変わる)
	srate = wfe->nSamplesPerSec;


	return TRUE;
}


/******************************************************************************
Wave系の後処理全般
******************************************************************************/
void UBuffering_sound::closeWave(void)
{
	int32 i;
	waveOutReset((HWAVEOUT)hWave);
	for (i = 0; i<BUFFER_COUNT; i++) {
		waveOutUnprepareHeader((HWAVEOUT)hWave, &(whdr[i]), sizeof(WAVEHDR));
		free(wWave[i]);
	}

        //クローズ
	waveOutClose(hWave);
     /データチャンクから抜け出す
	mmioAscend(hmmio, &ckRiff, 0);
	mmioClose(hmmio, 0);
}

/*****************************************************************************
バッファが切れたときに呼び出される
*****************************************************************************/
void UBuffering_sound::wmWomDone()
{
	int32 readsize;

    //最後まで再生した場合は最初にシークする。
	if (waveDataSize - readDataSize == 0) {
		mmioSeek(hmmio, -waveDataSize, SEEK_CUR);
		readDataSize = 0;

        //MM_WOM_DONEを起こすために「waveOutWrite」を呼ぶ
		whdr[bufferSelect].dwBufferLength = 0;
		waveOutWrite((HWAVEOUT)hWave, &(whdr[bufferSelect]), sizeof(WAVEHDR));

        //バッファセレクターのインクリメント
		bufferSelect = (bufferSelect + 1) % BUFFER_COUNT;
		return ;
	}
      //読み込むサイズを決定する。
	readsize = bufferSize;
	if (readsize > waveDataSize - readDataSize) {
		readsize = waveDataSize - readDataSize;
		readDataSize = waveDataSize;
	}
	else {
		readDataSize += readsize;
	}

      //読み込み
	readsize = readWaveData(hmmio, wWave[bufferSelect], readsize, bufferLenght);

      //再生バッファに書き込み
	whdr[bufferSelect].dwBufferLength = readsize;
	waveOutWrite((HWAVEOUT)hWave, &(whdr[bufferSelect]), sizeof(WAVEHDR));
      //バッファセレクターのインクリメント
	bufferSelect = (bufferSelect + 1) % BUFFER_COUNT;
	return ;
}

/*****************************************************************************
ファイルからデータを読みとり、加工する
*****************************************************************************/
int32 UBuffering_sound::readWaveData(HMMIO hmmio, short *buf, int bufferSize, int bufferLenght)
{
	 //読み込み
	int32 ret = mmioRead(hmmio, (HPSTR)buf, bufferSize);

       //手抜きボーカルキャンセラー&モノラル化
	if (1) {
		int32 i;
		for (i = 0; i<bufferLenght; i += 2) {
		        //モノラル化	
			//short t1 = (short)((((int)buf[i]) +((int)buf[i+1]))/2);

	
			short t1 = (short)(((int)buf[i]) - ((int)buf[i + 1]));
			
                        //真ん中の音を消す
			buf[i] = buf[i + 1] = t1;
		
		}
		
	}

	return ret;
}

この書き方では処理は通りません。

その処理がコンパイラに認識されていない可能性があります。

Sound NodeではSoundNode.hのParceNodes()に値を渡し、

作成したClassで変更した値を更新する必要があります。

WaveファイルのInstanceを触りたいのなら、ActiveSound.hを見るといいかもしれません。


Soundの処理は資料などが少ないため、かなり難しい部類に入ります。

初心者がSoundNodeの拡張を行いたいのであれば、

まずは他のSoundNode(MixerやDelayなど)を参考に

簡単なものから作成するのが望ましいでしょう。


またUE4でwindows.hの使用はおすすめしません。

Windowsに依存する処理を追加すると、

Macや他のOSで動作しない、もしくはバグの原因になります。

アドバイスありがとうございます.

ひとまずwindowのみで動作すればいいと考えていますので,windows.hは使いつつ,

ほかのサウンドノードを参考に組んでみようと思います.

個人的にはEnveloperノードやWave Playerノードが

参考になりそうな処理を書いてるかと思います。

是非頑張ってください。

また、下記手順に従い解決済みにチェックをお願いいたします。

Answerhubクイックスタート