/[svn]/linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceCoreAudio.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceCoreAudio.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1829 - (show annotations) (download)
Fri Jan 30 19:22:36 2009 UTC (15 years, 2 months ago) by iliev
File size: 17228 byte(s)
* added (experimental) CoreAudio driver

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2009 Grigor Iliev *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include "AudioOutputDeviceCoreAudio.h"
24
25 #include "../../common/global_private.h"
26
27 namespace LinuxSampler {
28
29 void AudioOutputDeviceCoreAudio::HandleOutputBuffer (
30 void *aqData,
31 AudioQueueRef inAQ,
32 AudioQueueBufferRef inBuffer
33 ) {
34 AQPlayerState* pAqData = (AQPlayerState*) aqData;
35 if (atomic_read(&(pAqData->mIsRunning)) == 0) {
36 AudioQueueFlush(pAqData->mQueue);
37 AudioQueueStop (pAqData->mQueue, true);
38 return;
39 }
40 uint bufferSize = pAqData->pDevice->uiBufferSize;
41
42 // let all connected engines render 'fragmentSize' sample points
43 pAqData->pDevice->RenderAudio(bufferSize);
44
45 int16_t* pDataBuf = (int16_t*)(inBuffer->mAudioData);
46
47 uint uiCoreAudioChannels = pAqData->pDevice->uiCoreAudioChannels;
48 // convert from DSP value range (-1.0..+1.0) to 16 bit integer value
49 // range (-32768..+32767), check clipping and copy to Alsa output buffer
50 for (int c = 0; c < uiCoreAudioChannels; c++) {
51 float* in = pAqData->pDevice->Channels[c]->Buffer();
52 for (int i = 0, o = c; i < bufferSize; i++ , o += uiCoreAudioChannels) {
53 float sample_point = in[i] * 32768.0f;
54 if (sample_point < -32768.0) sample_point = -32768.0;
55 if (sample_point > 32767.0) sample_point = 32767.0;
56 pDataBuf[o] = (int16_t) sample_point;
57 }
58 }
59
60 inBuffer->mAudioDataByteSize = (uiCoreAudioChannels * 2) * bufferSize;
61
62 OSStatus res = AudioQueueEnqueueBuffer(pAqData->mQueue, inBuffer, 0, NULL);
63 if(res) std::cerr << "AudioQueueEnqueueBuffer: Error " << res << std::endl;
64 }
65
66 AudioOutputDeviceCoreAudio::DeviceInfo* AudioOutputDeviceCoreAudio::pDeviceInfo = NULL;
67
68 AudioOutputDeviceCoreAudio::DeviceInfo* AudioOutputDeviceCoreAudio::GetDeviceInfo() {
69 if(pDeviceInfo == NULL) {
70 pDeviceInfo = new DeviceInfo;
71
72 pDeviceInfo->uiSamplerate = 44100;
73 pDeviceInfo->uiChannelNumber = 2;
74
75 AudioStreamBasicDescription dataFormat;
76 SetAudioDataFormat(&dataFormat);
77 AudioQueueRef pQueue = NULL;
78
79 OSStatus res = AudioQueueNewOutput (
80 &dataFormat, NULL, NULL, NULL, NULL, 0, &pQueue
81 );
82
83 if(res) {
84 std::cerr << "Failed to retrieve device info: " << res << std::endl;
85 return pDeviceInfo;
86 }
87
88 UInt32 chns = pDeviceInfo->uiChannelNumber;
89 UInt32 size = sizeof(chns);
90 res = AudioQueueGetProperty (
91 pQueue,
92 kAudioQueueDeviceProperty_NumberChannels,
93 &chns, &size
94 );
95
96 if(res) std::cerr << "Failed to retrieve channel number: " << res << std::endl;
97 else pDeviceInfo->uiChannelNumber = chns;
98
99 Float64 sRate = pDeviceInfo->uiSamplerate;
100 size = sizeof(sRate);
101 res = AudioQueueGetProperty (
102 pQueue,
103 kAudioQueueDeviceProperty_SampleRate,
104 &sRate, &size
105 );
106
107 if(res) std::cerr << "Failed to retrieve samplerate: " << res << std::endl;
108 else pDeviceInfo->uiSamplerate = (uint)sRate;
109
110 AudioQueueDispose(pQueue, true);
111 }
112
113 return pDeviceInfo;
114 }
115
116 AudioOutputDeviceCoreAudio::AudioOutputDeviceCoreAudio (
117 std::map<String,DeviceCreationParameter*> Parameters
118 ) : AudioOutputDevice(Parameters), Thread(true, true, 1, 0) {
119
120 dmsg(2,("AudioOutputDeviceCoreAudio::AudioOutputDeviceCoreAudio()\n"));
121 atomic_set(&pausedNew, 0);
122 pausedOld = 0;
123
124 uiCoreAudioChannels = ((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt();
125 uint samplerate = ((DeviceCreationParameterInt*)Parameters["SAMPLERATE"])->ValueAsInt();
126 uiBufferNumber = ((DeviceCreationParameterInt*)Parameters["BUFFERS"])->ValueAsInt();
127 uiBufferSize = ((DeviceCreationParameterInt*)Parameters["BUFFERSIZE"])->ValueAsInt();
128
129 aqPlayerState.mDataFormat.mSampleRate = samplerate;
130 aqPlayerState.mDataFormat.mFormatID = kAudioFormatLinearPCM;
131
132 aqPlayerState.mDataFormat.mFormatFlags =
133 kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
134
135 aqPlayerState.mDataFormat.mBytesPerPacket = uiCoreAudioChannels * 2;
136 aqPlayerState.mDataFormat.mFramesPerPacket = 1;
137 aqPlayerState.mDataFormat.mBytesPerFrame = uiCoreAudioChannels * 2;
138 aqPlayerState.mDataFormat.mChannelsPerFrame = uiCoreAudioChannels;
139 aqPlayerState.mDataFormat.mBitsPerChannel = 16;
140
141 aqPlayerState.mBuffers = new AudioQueueBufferRef[uiBufferNumber];
142
143 aqPlayerState.bufferByteSize =
144 MaxSamplesPerCycle() * aqPlayerState.mDataFormat.mBytesPerFrame;
145
146 aqPlayerState.mNumPacketsToRead = MaxSamplesPerCycle();
147
148 aqPlayerState.pDevice = this;
149 aqPlayerState.mQueue = NULL;
150
151 uint fragmentSize = MaxSamplesPerCycle();
152 // create audio channels for this audio device to which the sampler engines can write to
153 for (int i = 0; i < uiCoreAudioChannels; i++) {
154 this->Channels.push_back(new AudioChannel(i, fragmentSize));
155 }
156
157 StartThread();
158
159 if (!((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
160 Stop();
161 }
162 }
163
164 AudioOutputDeviceCoreAudio::~AudioOutputDevice() {
165 atomic_set(&(aqPlayerState.mIsRunning), 0);
166 destroyMutex.Lock();
167 AudioQueueDispose(aqPlayerState.mQueue, true);
168 destroyMutex.Unlock();
169 delete [] aqPlayerState.mBuffers;
170 }
171
172 void AudioOutputDeviceCoreAudio::SetAudioDataFormat(AudioStreamBasicDescription* pDataFormat) {
173 pDataFormat->mSampleRate = 44100;
174 pDataFormat->mFormatID = kAudioFormatLinearPCM;
175
176 pDataFormat->mFormatFlags =
177 kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
178
179 pDataFormat->mBytesPerPacket = 4;
180 pDataFormat->mFramesPerPacket = 1;
181 pDataFormat->mBytesPerFrame = 4;
182 pDataFormat->mChannelsPerFrame = 2;
183 pDataFormat->mBitsPerChannel = 16;
184 }
185
186 String AudioOutputDeviceCoreAudio::Name() {
187 return "COREAUDIO";
188 }
189
190 String AudioOutputDeviceCoreAudio::Description() {
191 return "Apple CoreAudio";
192 }
193
194 String AudioOutputDeviceCoreAudio::Version() {
195 String s = "$Revision: 1.1 $";
196 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
197 }
198
199 void AudioOutputDeviceCoreAudio::Play() {
200 atomic_set(&pausedNew, 0);
201 }
202
203 bool AudioOutputDeviceCoreAudio::IsPlaying() {
204 return !atomic_read(&pausedNew);
205 }
206
207 void AudioOutputDeviceCoreAudio::Stop() {
208 atomic_set(&pausedNew, 1);
209 }
210
211 uint AudioOutputDeviceCoreAudio::MaxSamplesPerCycle() {
212 return uiBufferSize;
213 }
214
215 uint AudioOutputDeviceCoreAudio::SampleRate() {
216 return aqPlayerState.mDataFormat.mSampleRate;
217 }
218
219 String AudioOutputDeviceCoreAudio::Driver() {
220 return Name();
221 }
222
223 AudioChannel* AudioOutputDeviceCoreAudio::CreateChannel(uint ChannelNr) {
224 // just create a mix channel
225 return new AudioChannel(ChannelNr, Channel(ChannelNr % uiCoreAudioChannels));
226 }
227
228 /**
229 * Entry point for the thread.
230 */
231 int AudioOutputDeviceCoreAudio::Main() {
232 dmsg(2,("CoreAudio thread started\n"));
233
234 bool initialized = aqPlayerState.mQueue != NULL;
235 if(!initialized) {
236 /*
237 * Initializing the audio queue
238 * Need to be run from this thread because of CFRunLoopGetCurrent()
239 * which returns the CFRunLoop object for the current thread.
240 */
241 OSStatus res = AudioQueueNewOutput (
242 &aqPlayerState.mDataFormat,
243 HandleOutputBuffer,
244 &aqPlayerState,
245 CFRunLoopGetCurrent(),
246 kCFRunLoopCommonModes,
247 0,
248 &aqPlayerState.mQueue
249 );
250
251 if(res) {
252 String s = String("AudioQueueNewOutput: Error ") + ToString(res);
253 throw Exception(s);
254 }
255
256 for (int i = 0; i < uiBufferNumber; ++i) {
257 OSStatus res = AudioQueueAllocateBuffer (
258 aqPlayerState.mQueue,
259 aqPlayerState.bufferByteSize,
260 &aqPlayerState.mBuffers[i]
261 );
262
263 if(res) {
264 String s = String("AudioQueueAllocateBuffer: Error ");
265 throw Exception(s + ToString(res));
266 }
267 }
268 }
269
270 for (int i = 0; i < uiBufferNumber; ++i) {
271 HandleOutputBuffer (
272 &aqPlayerState,
273 aqPlayerState.mQueue,
274 aqPlayerState.mBuffers[i]
275 );
276 }
277
278 Float32 gain = 1.0;
279
280 OSStatus res = AudioQueueSetParameter (
281 aqPlayerState.mQueue,
282 kAudioQueueParam_Volume,
283 gain
284 );
285
286 if(res) std::cerr << "AudioQueueSetParameter: Error " << res << std::endl;
287
288 atomic_set(&(aqPlayerState.mIsRunning), 1);
289
290 if(!initialized) {
291 res = AudioQueuePrime(aqPlayerState.mQueue, 0, NULL);
292 if(res) {
293 String s = String("AudioQueuePrime: Error ") + ToString(res);
294 throw Exception(s);
295 }
296 }
297
298 res = AudioQueueStart(aqPlayerState.mQueue, NULL);
299 if(res) {
300 String s = String("AudioQueueStart: Error ") + ToString(res);
301 throw Exception(s);
302 }
303
304 destroyMutex.Lock();
305 do {
306 if(atomic_read(&pausedNew) != pausedOld) {
307 pausedOld = atomic_read(&pausedNew);
308
309 if(pausedOld) {
310 res = AudioQueuePause(aqPlayerState.mQueue);
311 if(res) std::cerr << "AudioQueuePause: Error " << res << std::endl;
312 } else {
313 res = AudioQueuePrime(aqPlayerState.mQueue, 0, NULL);
314 if(res) std::cerr << "AudioQueuePrime: Error " << res << std::endl;
315 res = AudioQueueStart(aqPlayerState.mQueue, NULL);
316 if(res) std::cerr << "AudioQueueStart: Error " << res << std::endl;
317 }
318 }
319
320 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.2, false);
321 } while (atomic_read(&(aqPlayerState.mIsRunning)));
322 destroyMutex.Unlock();
323
324 dmsg(2,("CoreAudio thread stopped\n"));
325
326 return 0;
327 }
328
329
330 // *************** ParameterSampleRate ***************
331 // *
332
333 AudioOutputDeviceCoreAudio::ParameterSampleRate::ParameterSampleRate() :
334 AudioOutputDevice::ParameterSampleRate::ParameterSampleRate() {
335
336 }
337
338 AudioOutputDeviceCoreAudio::ParameterSampleRate::ParameterSampleRate(String s) :
339 AudioOutputDevice::ParameterSampleRate::ParameterSampleRate(s) {
340
341 }
342
343 optional<int>
344 AudioOutputDeviceCoreAudio::ParameterSampleRate::DefaultAsInt(std::map<String,String> Parameters) {
345 dmsg(2,("AudioOutputDeviceCoreAudio::ParameterSampleRate::DefaultAsInt()\n"));
346 return GetDeviceInfo()->uiSamplerate;
347 }
348
349
350 // *************** ParameterChannels ***************
351 // *
352
353 AudioOutputDeviceCoreAudio::ParameterChannels::ParameterChannels() :
354 AudioOutputDevice::ParameterChannels::ParameterChannels() {
355
356 }
357
358 AudioOutputDeviceCoreAudio::ParameterChannels::ParameterChannels(String s) :
359 AudioOutputDevice::ParameterChannels::ParameterChannels(s) {
360
361 }
362
363 optional<int>
364 AudioOutputDeviceCoreAudio::ParameterChannels::DefaultAsInt(std::map<String,String> Parameters) {
365 dmsg(2,("AudioOutputDeviceCoreAudio::ParameterChannels::DefaultAsInt()\n"));
366 return GetDeviceInfo()->uiChannelNumber;
367 }
368
369 // *************** ParameterBuffers ***************
370 // *
371
372 AudioOutputDeviceCoreAudio::ParameterBuffers::ParameterBuffers() : DeviceCreationParameterInt() {
373 InitWithDefault();
374 }
375
376 AudioOutputDeviceCoreAudio::ParameterBuffers::ParameterBuffers(String s)
377 throw (Exception) : DeviceCreationParameterInt(s) {
378 }
379
380 String AudioOutputDeviceCoreAudio::ParameterBuffers::Description() {
381 return "Number of audio buffer";
382 }
383
384 bool AudioOutputDeviceCoreAudio::ParameterBuffers::Fix() {
385 return true;
386 }
387
388 bool AudioOutputDeviceCoreAudio::ParameterBuffers::Mandatory() {
389 return false;
390 }
391
392 std::map<String,DeviceCreationParameter*>
393 AudioOutputDeviceCoreAudio::ParameterBuffers::DependsAsParameters() {
394 return std::map<String,DeviceCreationParameter*>();
395 }
396
397 optional<int>
398 AudioOutputDeviceCoreAudio::ParameterBuffers::DefaultAsInt(std::map<String,String> Parameters) {
399 return 3;
400 }
401
402 optional<int>
403 AudioOutputDeviceCoreAudio::ParameterBuffers::RangeMinAsInt(std::map<String,String> Parameters) {
404 return 2;
405 }
406
407 optional<int>
408 AudioOutputDeviceCoreAudio::ParameterBuffers::RangeMaxAsInt(std::map<String,String> Parameters) {
409 return 16;
410 }
411
412 std::vector<int>
413 AudioOutputDeviceCoreAudio::ParameterBuffers::PossibilitiesAsInt(std::map<String,String> Parameters) {
414 return std::vector<int>();
415 }
416
417 void AudioOutputDeviceCoreAudio::ParameterBuffers::OnSetValue(int i) throw (Exception) {
418 // not posssible, as parameter is fix
419 }
420
421 String AudioOutputDeviceCoreAudio::ParameterBuffers::Name() {
422 return "BUFFERS";
423 }
424
425 // *************** ParameterBufferSize ***************
426 // *
427
428 AudioOutputDeviceCoreAudio::ParameterBufferSize::ParameterBufferSize() : DeviceCreationParameterInt() {
429 InitWithDefault();
430 }
431
432 AudioOutputDeviceCoreAudio::ParameterBufferSize::ParameterBufferSize(String s)
433 throw (Exception) : DeviceCreationParameterInt(s) {
434 }
435
436 String AudioOutputDeviceCoreAudio::ParameterBufferSize::Description() {
437 return "Size of the audio buffer in sample frames";
438 }
439
440 bool AudioOutputDeviceCoreAudio::ParameterBufferSize::Fix() {
441 return true;
442 }
443
444 bool AudioOutputDeviceCoreAudio::ParameterBufferSize::Mandatory() {
445 return false;
446 }
447
448 std::map<String,DeviceCreationParameter*>
449 AudioOutputDeviceCoreAudio::ParameterBufferSize::DependsAsParameters() {
450 return std::map<String,DeviceCreationParameter*>();
451 }
452
453 optional<int>
454 AudioOutputDeviceCoreAudio::ParameterBufferSize::DefaultAsInt(std::map<String,String> Parameters) {
455 return 128;
456 }
457
458 optional<int>
459 AudioOutputDeviceCoreAudio::ParameterBufferSize::RangeMinAsInt(std::map<String,String> Parameters) {
460 return 32;
461 }
462
463 optional<int>
464 AudioOutputDeviceCoreAudio::ParameterBufferSize::RangeMaxAsInt(std::map<String,String> Parameters) {
465 return 4096;
466 }
467
468 std::vector<int>
469 AudioOutputDeviceCoreAudio::ParameterBufferSize::PossibilitiesAsInt(std::map<String,String> Parameters) {
470 return std::vector<int>();
471 }
472
473 void AudioOutputDeviceCoreAudio::ParameterBufferSize::OnSetValue(int i) throw (Exception) {
474 // not posssible, as parameter is fix
475 }
476
477 String AudioOutputDeviceCoreAudio::ParameterBufferSize::Name() {
478 return "BUFFERSIZE";
479 }
480 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC