【问题标题】:Execute 2 methods c++ and c# at same time Unity同时执行2个方法c++和c# Unity
【发布时间】:2017-03-28 08:08:24
【问题描述】:

我已将 c++ 中的本机代码导出到 dll 中,并将其统一导入到 c# 脚本中。 C++ 代码从 wav 文件中再现音乐。在统一的场景中,我有一个可以按箭头键旋转的人头。我想要做的是同步这两种方法。我想在旋转头部的同时再现音乐,因为将来音乐会根据头部旋转而改变。

目前,当我运行 Unity 游戏时,音乐开始播放,一旦播放完毕,我就可以开始旋转人类头部了。以前没有。

这是我的代码:

音频.h:

#pragma once
#include <iostream>
#define EXPORT __declspec(dllexport)

extern "C" {    
    EXPORT void initialize(std::string soundFilePaths[]);
    EXPORT void setSourcePosition(std::string soundFilePath, float x, float y, float z);
    EXPORT void play();
    EXPORT void stop();
    EXPORT void setListenerRotation(float x, float y, float z);
}

class Audio {

public:

static Audio& instance() {  // Singleton
    static Audio INSTANCE;
    return INSTANCE;
}

void initialize(std::string soundFilePaths[]);
void setSourcePosition(std::string soundFilePath, float x, float y, float z);
void play();
void stop();
void setListenerRotation(float x, float y, float z);
~Audio();

private:    
    Audio();
};

音频.cpp:

#include "Buffer.h"
#include "MonoSample.h"
#include "AudioDevice.h"
#include "Audio.h"
#include <windows.h>
#include <mmsystem.h>

#include <thread>

#include <stdio.h>
#include <conio.h>

#define NUMCHANNELS    2
#define OUTBUFSIZE  1024    
#define CREATEWAVFILE true


extern "C" {    

    void initialize(const char *soundFilePaths[], bool continuous) {    
        Audio::instance().initialize(soundFilePaths,continuous);        
    }

    void setSourcePosition(const char *soundFilePath, float x, float y, float z) {
        Audio::instance().setSourcePosition(soundFilePath, x, y, z);
    }

    void play() {
        Audio::instance().play();
    }

    void stop() {
        Audio::instance().stop();
    }

    void setListenerRotation(float x, float y, float z) {
        Audio::instance().setListenerRotation(x, y, z);
    }
}

float degree;
int numCanals;

Buffer channel[NUMCHANNELS];                            // Input buffer
unsigned char buffer[OUTBUFSIZE];                       // Ouput buffer
wavHdr header, *pheader;
FILE* outFile;                                          // Create output ( wave format) file
AudioDevice ad;


Audio::Audio()
{
}

Audio::~Audio()
{
}

void Audio::initialize(const char *soundFilePaths[], bool continuous)
{   
    char nom[20];

    for (int i = 0; i < NUMCHANNELS; i++)
    {
        sprintf(nom, "%02d.wav", i + 1);
        string fitxer(nom);
        string path = WAVBASEPATH + fitxer;
        if (!channel[i].openFile(path, i))      //obre i llegeix bytes (fread)
        {
            /*cout << "ERROR [" << i + 1 << "]";*/
            ExitProcess(1);
        }
    }

    int inSampleRate = channel[0].getHeader().samplesPerSec;        
    int inSampleLen = channel[0].getHeader().bitsPerSample;
    int inNumberOfCn = channel[0].getHeader().numOfChan;            

    ad.iniAudioDevice(inSampleRate, inSampleLen, 2);                
    ad.setVolume50p();                                              

}

void Audio::setSourcePosition(const char *soundFilePath, float x, float y, float z)
{

}

void Audio::play()
{       
        while (1)
        {
            long readBytes;
            readBytes = channel[0].ReadInputBufferBlock(buffer, OUTBUFSIZE, channel, NUMCHANNELS, 1, false);            

            if (readBytes > 0)
            {
                ad.writeAudio((LPSTR)buffer, sizeof(buffer));           
            }
            else
                break;
        }
}

void Audio::stop()
{
    while (ad.waveFreeBlockCount < BLOCK_COUNT)                     
        Sleep(10);

    ad.closeAudioDevice();
}

这是 Unity 中的 C# 脚本:

using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

public class AudioPlugin : MonoBehaviour
{
    public AudioContainer[] audioContainers;
    public Transform headGeometry;
    public float rotationSpeed = 50;
    public float maxYRotation = 90;
    public float minYRotation = -90;

    float _currentYRotation;


    void Start()
    {
        _currentYRotation = headGeometry.transform.rotation.eulerAngles.y;
        string[] filePaths = GetAllFilePathsFromClips();
        AudioPluginConnection.Initialize(filePaths);
        AudioPluginConnection.Play();
    }

    void Update()
    {
        TurnHeadWithInput();
        UpdateListenerRotation();
        UpdateSoundPositions();
    }

    void OnDestroy()
    {
        AudioPluginConnection.Stop();
    }

    void TurnHeadWithInput()
    {
        float horizontal = Input.GetAxis("Horizontal");
        horizontal *= Time.deltaTime * rotationSpeed;
        _currentYRotation = Mathf.Clamp(_currentYRotation + horizontal, minYRotation, maxYRotation);
        Vector3 eulerAngles = headGeometry.rotation.eulerAngles;
        eulerAngles.y = _currentYRotation;
        headGeometry.rotation = Quaternion.Euler(eulerAngles);
    }

    void UpdateListenerRotation()
    {
        Vector3 eulerAngles = headGeometry.rotation.eulerAngles;
        AudioPluginConnection.SetListenerRotation(eulerAngles.x, eulerAngles.y, eulerAngles.y);
    }

    void UpdateSoundPositions()
    {
        foreach (AudioContainer container in audioContainers)
        {
            Vector3 position = container.source.position;
            AudioPluginConnection.SetSourcePosition(container.filePath, position.x, position.y, position.z);
        }
    }

    string[] GetAllFilePathsFromClips()
    {
        List<string> audioFilePaths = new List<string>();
        foreach (AudioContainer container in audioContainers)
        {
            audioFilePaths.Add(container.filePath);
        }
        return audioFilePaths.ToArray();
    }    
}

[System.Serializable]
public class AudioContainer
{
    public AudioClip clip;
    public Transform source;
    //Dont forget, that you have to copy the Audio Folder in the 
    //Unity Editor to the *_Data Folder in your builded Project!!! Quan construim projecte
    public string filePath { get { return Application.dataPath + "/Audio/" + clip.name + ".wav"; } }
}

public class AudioPluginConnection
{
    [DllImport("AudioPlugin", EntryPoint = "test")]
    public static extern int Test();
    [DllImport("AudioPlugin", EntryPoint = "initialize")]
    public static extern void Initialize(string[] soundFilePaths);
    [DllImport("AudioPlugin", EntryPoint = "setSourcePosition")]
    public static extern void SetSourcePosition(string soundFilePath, float x, float y, float z);
    [DllImport("AudioPlugin", EntryPoint = "play")]
    public static extern void Play();
    [DllImport("AudioPlugin", EntryPoint = "stop")]
    public static extern void Stop();
    [DllImport("AudioPlugin", EntryPoint = "setListenerRotation")]
    public static extern void SetListenerRotation(float x, float y, float z);
}

我认为我需要创建一个与主线程并行的线程,以便能够同时执行这两个操作,但我不确定,也不知道如何操作。

AudioPluginConnection.play() 函数是再现声音的函数,TurnHeadWithInput() 函数是旋转头部的函数。

我的目标是能够在按下旋转头部的按钮时,音乐也能响起。以后,我会根据头部的旋转,对wav文件的样本应用一种算法并重现它。

提前谢谢你

【问题讨论】:

    标签: c# c++ multithreading unity3d


    【解决方案1】:

    您是对的,您确实需要创建一个单独的线程并从该线程运行您的 c++ 函数。我会推荐一些资源来学习线程: Unity Answers 的 Bunny83 回复了 here 关于 Unity 线程的一些重要事项。

    线程不是在 Unity 中实现的,而是在 C# 中实现的,所以我建议阅读有关线程的 MSDN 教程here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-12
      • 2021-04-14
      • 2020-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多