2nd attempt at updated Waves audio backend, with added -fms-extensions as previously...
[ardour.git] / libs / backends / wavesaudio / wavesapi / devicemanager / WCMRNativeAudio.cpp
1 //----------------------------------------------------------------------------------
2 //
3 // Copyright (c) 2008 Waves Audio Ltd. All rights reserved.
4 //
5 //! \file       WCMRNativeAudio.cpp
6 //!
7 //! WCMRNativeAudioConnection and related class defienitions
8 //!
9 //---------------------------------------------------------------------------------*/
10 #if defined(__MACOS__)
11 #include <CoreAudio/CoreAudio.h>
12 #endif
13
14 #include "WCMRNativeAudio.h"
15 #include "MiscUtils/safe_delete.h"
16 #include <sstream>
17 #include <boost/assign/list_of.hpp>
18
19 #define NONE_DEVICE_NAME "None"
20 #define NONE_DEVICE_INPUT_NAMES "Input "
21 #define NONE_DEVICE_OUTPUT_NAMES "Output "
22
23 //**********************************************************************************************
24 // WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice
25 //
26 //! Constructor for the dummy "None" device. This constructor simply adds supported SRs,
27 //!             buffer sizes, and channels, so that it may look like a real native device to
28 //!             the applications.
29 //!
30 //! \param pManager : The managing device manager - simply passed on to the base class.
31 //! 
32 //! 
33 //**********************************************************************************************
34 WCMRNativeAudioNoneDevice::WCMRNativeAudioNoneDevice (WCMRAudioDeviceManager *pManager)
35         : WCMRNativeAudioDevice (pManager, false /*useMultiThreading*/)
36         , m_SilenceThread(0)
37 #if defined (_WINDOWS)
38     , _waitableTimerForUsleep (CreateWaitableTimer(NULL, TRUE, NULL))
39 #endif
40 {
41         m_DeviceName = NONE_DEVICE_NAME;
42
43         m_SamplingRates = boost::assign::list_of (m_CurrentSamplingRate=44100)(48000)(88200)(96000);
44
45         m_BufferSizes = boost::assign::list_of (32)(64)(128)(m_CurrentBufferSize=256)(512)(1024);
46
47         for (int channel = 0; channel < __m_NumInputChannels; channel++)
48         {
49         std::stringstream name;
50         name << NONE_DEVICE_INPUT_NAMES;
51                 name << (channel + 1);
52                 m_InputChannels.push_back(name.str());
53         }
54
55         for (int channel = 0; channel < __m_NumOutputChannels; channel++)
56         {
57         std::stringstream name;
58         name << NONE_DEVICE_INPUT_NAMES;
59                 name << (channel + 1);
60                 m_OutputChannels.push_back(name.str());
61         }
62         _m_inputBuffer = new float[__m_NumInputChannels * m_BufferSizes.back()];
63         _m_outputBuffer = new float[__m_NumOutputChannels * m_BufferSizes.back()];
64 }
65
66
67 WCMRNativeAudioNoneDevice::~WCMRNativeAudioNoneDevice ()
68 {
69 #if defined (_WINDOWS)
70     if(_waitableTimerForUsleep) {
71         CloseHandle(_waitableTimerForUsleep);
72     }
73 #endif
74 }
75
76 WTErr WCMRNativeAudioNoneDevice::SetActive (bool newState)
77 {
78         //This will most likely be overridden, the base class simply
79         //changes the member.
80         if (Active() == newState)
81         {
82                 return (eNoErr);
83         }
84
85         if (Active() && Streaming())
86         {
87                 SetStreaming(false);
88         }
89         return WCMRAudioDevice::SetActive(newState);
90 }
91
92 WTErr WCMRNativeAudioNoneDevice::SetCurrentBufferSize (int newSize)
93 {
94
95         //changes the status.
96         int oldSize = CurrentBufferSize();
97         bool oldActive = Active();
98
99         //same size, nothing to do.
100         if (oldSize == newSize)
101                 return eNoErr;
102         
103         //see if this is one of our supported rates...
104         std::vector<int>::iterator intIter = find(m_BufferSizes.begin(), m_BufferSizes.end(), newSize);
105         if (intIter == m_BufferSizes.end())
106         {
107                 //Can't change, perhaps use an "invalid param" type of error
108                 return eCommandLineParameter;
109         }
110         
111         if (Streaming())
112         {
113                 //Can't change, perhaps use an "in use" type of error
114                 return eGenericErr;
115         }
116
117         
118         return WCMRAudioDevice::SetCurrentBufferSize(newSize);
119 }
120
121
122 WTErr WCMRNativeAudioNoneDevice::UpdateDeviceInfo ()
123 {
124         return eNoErr;
125 }
126
127
128 WTErr WCMRNativeAudioNoneDevice::SetStreaming (bool newState)
129 {
130         if (Streaming() == newState)
131         {
132                 return (eNoErr);
133         }
134
135         WCMRAudioDevice::SetStreaming(newState);
136
137         if (Streaming())
138         {
139                 if (m_SilenceThread)
140                         std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the inactive NONE-DEVICE was streaming!" << std::endl;
141
142                 pthread_attr_t attributes;
143                 size_t stack_size = 100000;
144 #ifdef __MACOS__
145             stack_size = (((stack_size - 1) / PTHREAD_STACK_MIN) + 1) * PTHREAD_STACK_MIN;
146 #endif
147                 if (pthread_attr_init (&attributes)) {
148                         std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_init () failed!" << std::endl;
149                         return eGenericErr;
150                 }
151    
152                 if (pthread_attr_setstacksize (&attributes, stack_size)) {
153                         std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_attr_setstacksize () failed!" << std::endl;
154                         return eGenericErr;
155                 }
156
157                 if (pthread_create (&m_SilenceThread, &attributes, __SilenceThread, this)) {
158                         m_SilenceThread = 0;
159                         std::cerr << "WCMRNativeAudioNoneDevice::SetStreaming (): pthread_create () failed!" << std::endl;
160                         return eGenericErr;
161                 }
162         }
163         else
164         {
165                 if (!m_SilenceThread)
166                 {
167                         std::cerr << "\t\t\t\t\t !!!!!!!!!!!!!!! Warning: the active NONE-DEVICE was NOT streaming!" << std::endl;
168                 }
169
170                 while (m_SilenceThread)
171                 {
172                         _usleep(1); //now wait for ended  thread;
173                 }
174         }
175
176         return eNoErr;
177 }
178
179 void WCMRNativeAudioNoneDevice::_SilenceThread()
180 {
181 #if defined(_WINDOWS)
182         float* theInpBuffers[__m_NumInputChannels];
183         for(int i = 0; i < __m_NumInputChannels; ++i)
184         {
185                 theInpBuffers[i] = _m_inputBuffer + m_BufferSizes.back() * i;
186         }
187 #else
188         float* theInpBuffers = _m_inputBuffer;
189 #endif
190
191     uint32_t currentSampleTime = 0;    
192         const size_t buffer_size = CurrentBufferSize();
193     const uint64_t cyclePeriodNanos = (1000000000.0 * buffer_size) / CurrentSamplingRate();
194
195         struct WCMRAudioDeviceManagerClient::AudioCallbackData audioCallbackData =
196         {
197                 (const float*)theInpBuffers,
198                 _m_outputBuffer,
199                 buffer_size,
200                 0, 
201                 0
202         };
203
204         audioCallbackData.acdCycleStartTimeNanos =__get_time_nanos();
205
206     // VERY ROUGH IMPLEMENTATION: 
207     while(Streaming()) {
208         
209         uint64_t cycleEndTimeNanos = audioCallbackData.acdCycleStartTimeNanos + cyclePeriodNanos;
210
211                 m_pMyManager->NotifyClient (WCMRAudioDeviceManagerClient::AudioCallback, (void *)&audioCallbackData);
212                 
213         currentSampleTime += buffer_size;
214                 
215                 int64_t timeToSleepUsecs = ((int64_t)cycleEndTimeNanos - (int64_t)__get_time_nanos())/1000;
216                 
217         if (timeToSleepUsecs > 0) {
218             _usleep (timeToSleepUsecs);
219         }
220                 audioCallbackData.acdCycleStartTimeNanos = cycleEndTimeNanos+1;
221     }
222         m_SilenceThread = 0;
223 }
224
225 void* WCMRNativeAudioNoneDevice::__SilenceThread(void *This)
226 {
227         ((WCMRNativeAudioNoneDevice*)This)->_SilenceThread();
228         return 0;
229 }
230
231 #if defined(_WINDOWS)
232 void WCMRNativeAudioNoneDevice::_usleep(uint64_t duration_usec)
233
234     LARGE_INTEGER ft; 
235
236     ft.QuadPart = -(10*duration_usec); // Convert to 100 nanosecond interval, negative value indicates relative time
237
238     SetWaitableTimer(_waitableTimerForUsleep, &ft, 0, NULL, NULL, 0);
239     WaitForSingleObject(_waitableTimerForUsleep, INFINITE); 
240 }
241 #endif
242
243 uint64_t
244 WCMRNativeAudioNoneDevice::__get_time_nanos ()
245 {
246 #ifdef __MACOS__
247     // here we exploit the time counting API which is used by the WCMRCoreAudioDeviceManager. However,
248     // the API should be a part of WCMRCoreAudioDeviceManager to give a chance of being tied to the
249     // audio device transport time�.
250     return AudioConvertHostTimeToNanos (AudioGetCurrentHostTime ());
251     
252 #elif _WINDOWS
253     
254     LARGE_INTEGER Frequency, Count ;
255
256     QueryPerformanceFrequency (&Frequency) ;
257     QueryPerformanceCounter (&Count);
258     return uint64_t ((Count.QuadPart * 1000000000.0 / Frequency.QuadPart));
259 #endif
260 }