大学の研究で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;
}