Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by augusthemback · Oct 25, 2018 at 07:49 AM · audiodllnative pluginc++threads

Native Plugin works in editor but not in build

I'm building a virtual synthesizer in Unity by creating sounds using a c++ DLL. The DLL is being run at a custom thread declared in C# inside of Unity. My problem is that the DLL runs perfectly inside the Editor. No crashes or anything. However, when I try to build and run the standalone windows application it just terminates when reaching

waveOutWrite(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR));

at the end of the code.

This is the full header file inside the DLL where the crash occurs:

 #pragma once
 
 #pragma comment(lib, "winmm.lib")
 
 #include <cmath>
 #include <fstream>
 #include <vector>
 #include <string>
 #include <thread>
 #include <atomic>
 #include <condition_variable>
 #include <Windows.h>
 #define T short
 using namespace std;
 
 class SoundEngine
 {
 public:
 
     SoundEngine() {}
     SoundEngine(wstring sOutputDevice, unsigned int nSampleRate = 44100, unsigned int nChannels = 1, unsigned int nBlocks = 8, unsigned int nBlockSamples = 512)
     {
         Create(sOutputDevice, nSampleRate, nChannels, nBlocks, nBlockSamples);
     }
 
     ~SoundEngine()
     {
         Destroy();
     }
 
     bool Create(wstring sOutputDevice, unsigned int nSampleRate = 44100, unsigned int nChannels = 1, unsigned int nBlocks = 8, unsigned int nBlockSamples = 512)
     {
         m_bReady = false;
         m_nSampleRate = nSampleRate;
         m_nChannels = nChannels;
         m_nBlockCount = nBlocks;
         m_nBlockSamples = nBlockSamples;
         m_nBlockFree = m_nBlockCount;
         m_nBlockCurrent = 0;
         m_pBlockMemory = nullptr;
         m_pWaveHeaders = nullptr;
 
         // Validate device
         vector<wstring> devices = Enumerate();
         auto d = std::find(devices.begin(), devices.end(), sOutputDevice);
         if (d != devices.end())
         {
             // Device is available
             int nDeviceID = distance(devices.begin(), d);
             WAVEFORMATEX waveFormat;
             waveFormat.wFormatTag = WAVE_FORMAT_PCM;
             waveFormat.nSamplesPerSec = m_nSampleRate;
             waveFormat.wBitsPerSample = sizeof(T) * 8;
             waveFormat.nChannels = m_nChannels;
             waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
             waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
             waveFormat.cbSize = 0;
 
             // Open Device if valid
             if (waveOutOpen(&m_hwDevice, nDeviceID, &waveFormat, (DWORD_PTR)waveOutProcWrap, (DWORD_PTR)this, CALLBACK_FUNCTION) != S_OK)
                 return Destroy();
         }
 
         // Allocate Wave|Block Memory
         m_pBlockMemory = new T[m_nBlockCount * m_nBlockSamples];
         if (m_pBlockMemory == nullptr)
             return Destroy();
         ZeroMemory(m_pBlockMemory, sizeof(T) * m_nBlockCount * m_nBlockSamples);
 
         m_pWaveHeaders = new WAVEHDR[m_nBlockCount];
         if (m_pWaveHeaders == nullptr)
             return Destroy();
         ZeroMemory(m_pWaveHeaders, sizeof(WAVEHDR) * m_nBlockCount);
 
         // Link headers to block memory
         for (unsigned int n = 0; n < m_nBlockCount; n++)
         {
             m_pWaveHeaders[n].dwBufferLength = m_nBlockSamples * sizeof(T);
             m_pWaveHeaders[n].lpData = (LPSTR)(m_pBlockMemory + (n * m_nBlockSamples));
         }
 
         m_bReady = true;
 
         m_thread = thread(&SoundEngine::MainThread, this);
 
         // Start the ball rolling
         unique_lock<mutex> lm(m_muxBlockNotZero);
         m_cvBlockNotZero.notify_one();
 
         return true;
     }
 
     bool Destroy()
     {
         return false;
     }
 
     void Stop()
     {
         m_bReady = false;
         m_thread.join();
     }
 
     // Override to process current sample
     virtual double UserProcess(int nChannel, double dTime)
     {
         return 0.0;
     }
 
     double GetTime()
     {
         return m_dGlobalTime;
     }
 
 
 
 public:
     static vector<wstring> Enumerate()
     {
         int nDeviceCount = waveOutGetNumDevs();
         vector<wstring> sDevices;
         WAVEOUTCAPS woc;
         for (int n = 0; n < nDeviceCount; n++)
             if (waveOutGetDevCaps(n, &woc, sizeof(WAVEOUTCAPS)) == S_OK)
                 sDevices.push_back(woc.szPname);
         return sDevices;
     }
 
     double clip(double dSample, double dMax)
     {
         if (dSample >= 0.0)
             return fmin(dSample, dMax);
         else
             return fmax(dSample, -dMax);
     }
 
 
 private:
 
     unsigned int m_nSampleRate;
     unsigned int m_nChannels;
     unsigned int m_nBlockCount;
     unsigned int m_nBlockSamples;
     unsigned int m_nBlockCurrent;
 
     T* m_pBlockMemory;
     WAVEHDR *m_pWaveHeaders;
     HWAVEOUT m_hwDevice;
 
     thread m_thread;
     atomic<bool> m_bReady;
     atomic<unsigned int> m_nBlockFree;
     condition_variable m_cvBlockNotZero;
     mutex m_muxBlockNotZero;
 
     atomic<double> m_dGlobalTime;
 
     // Handler for soundcard request for more data
     void waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
     {
         if (uMsg != WOM_DONE) return;
 
         m_nBlockFree++;
         unique_lock<mutex> lm(m_muxBlockNotZero);
         m_cvBlockNotZero.notify_one();
     }
 
     // Static wrapper for sound card handler
     static void CALLBACK waveOutProcWrap(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
     {
         ((SoundEngine*)dwInstance)->waveOutProc(hWaveOut, uMsg, dwParam1, dwParam2);
     }
 
     // Main thread. This loop responds to requests from the soundcard to fill 'blocks'
     // with audio data. If no requests are available it goes dormant until the sound
     // card is ready for more data. The block is fille by the "user" in some manner
     // and then issued to the soundcard.
     void MainThread()
     {
         m_dGlobalTime = 0.0;
         double dTimeStep = 1.0 / (double)m_nSampleRate;
 
         // Goofy hack to get maximum integer for a type at run-time
         T nMaxSample = (T)pow(2, (sizeof(T) * 8) - 1) - 1;
         double dMaxSample = (double)nMaxSample;
         T nPreviousSample = 0;
 
         while (m_bReady)
         {
             // Wait for block to become available
             if (m_nBlockFree == 0)
             {
                 unique_lock<mutex> lm(m_muxBlockNotZero);
                 while (m_nBlockFree == 0) // sometimes, Windows signals incorrectly
                     m_cvBlockNotZero.wait(lm);
             }
 
             // Block is here, so use it
             m_nBlockFree--;
 
             // Prepare block for processing
             if (m_pWaveHeaders[m_nBlockCurrent].dwFlags & WHDR_PREPARED)
                 waveOutUnprepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR));
 
             T nNewSample = 0;
             int nCurrentBlock = m_nBlockCurrent * m_nBlockSamples;
 
             for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels)
             {
                 // User Process
                 for (unsigned int c = 0; c < m_nChannels; c++)
                 {
                     nNewSample = (T)(clip(MakeNoise(c, m_dGlobalTime), 1.0) * dMaxSample);
 
                     m_pBlockMemory[nCurrentBlock + n + c] = nNewSample;
                     nPreviousSample = nNewSample;
                 }
 
                 m_dGlobalTime = m_dGlobalTime + dTimeStep;
             }
 
             // Send block to sound device
             waveOutPrepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR));
             waveOutWrite(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR)); // THIS MAKES EVERYTHING CRASH!!!        
             m_nBlockCurrent++;
             m_nBlockCurrent %= m_nBlockCount;
         
         }
     }
 
     virtual double MakeNoise(int a, double b) = 0;
 };

Please tell me if I need to clarify anything. Thanks in advance!

Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image MechEthan · Jan 04, 2019 at 07:17 PM 1
Share

I looked around because I was curious, and found this: https://stackoverflow.com/questions/195696/why-would-waveoutwrite-cause-an-exception-in-the-debug-heap

Sorry, not much of a help!

avatar image augusthemback MechEthan · Jan 04, 2019 at 09:24 PM 0
Share

Thank you! $$anonymous$$ight've given me some answers. Not the complete picture of what's wrong though.

0 Replies

· Add your reply
  • Sort: 

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

123 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Using Native C++ dll in Unity 1 Answer

Need help compiling Unity Native Audio Plugins for Linux, got "multiple definition of" errors. 0 Answers

What is the correct location for a native (C++) plugin's DLL dependencies 1 Answer

Using a fixed size pointer in Unity C# with a C++ external function 0 Answers

How to step into a native C++ dll in Visual Studio? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges