x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

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

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

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

UE4,C++共に初心者ながら以下二つのサイトを参考にソースを作らせていただきました. https://codezine.jp/article/detail/368 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;
 }
 
Product Version: UE 4.18
Tags:
more ▼

asked Apr 14 '18 at 07:17 AM in Japanese

avatar image

masabo07
14 1 1 8

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

1 answer: sort voted first

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

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

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

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

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


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

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

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

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


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

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

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

more ▼

answered Apr 24 '18 at 06:59 AM

avatar image

MozPaca
266 2 4 5

avatar image masabo07 Apr 24 '18 at 04:27 PM

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

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

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

avatar image MozPaca Apr 25 '18 at 04:44 AM

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

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

是非頑張ってください。

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

Answerhubクイックスタート

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question