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