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