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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1644 - (show annotations) (download)
Sat Jan 19 16:55:03 2008 UTC (16 years, 3 months ago) by persson
File size: 39694 byte(s)
* fixed memory leaks that occurred when liblinuxsampler was unloaded
* fixed a memory leak that could happen when a channel was deleted
  while notes were playing
* fixed memory management bug in ASIO driver
* optimized the SynchronizedConfig class so it doesn't wait
  unnecessarily long after an update

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2008 Christian Schoenebeck *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #include "AudioOutputDeviceAsio.h"
25 #include "AudioOutputDeviceFactory.h"
26
27 #define kMaxInputChannels 32
28 #define kMaxOutputChannels 32
29 #define ASIO_MAX_DEVICE_INFO 32
30
31 #define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */
32 #define NUM_CUSTOMSAMPLINGRATES 9 /* must be the same number of elements as in the array below */
33 #define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES)
34
35 // internal data storage
36 typedef struct DriverInfo
37 {
38 // ASIOInit()
39 ASIODriverInfo driverInfo;
40
41 // ASIOGetChannels()
42 long numInputChannels;
43 long numOutputChannels;
44
45 // ASIOGetBufferSize()
46 long minBufSize;
47 long maxBufSize;
48 long preferredBufSize;
49 long bufGranularity;
50 long chosenBufSize;
51
52 // ASIOGetSampleRate()
53 ASIOSampleRate sampleRate;
54 int numSampleRates;
55 std::vector<int> sampleRates;
56
57 // ASIOOutputReady()
58 bool ASIOOutputReadySupported;
59
60 // ASIOGetLatencies ()
61 long inputLatency;
62 long outputLatency;
63
64 // ASIOCreateBuffers ()
65 long numInputBuffers; // becomes number of actual created input buffers
66 long numOutputBuffers; // becomes number of actual created output buffers
67 ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's
68
69 // ASIOGetChannelInfo()
70 ASIOChannelInfo channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's
71 // The above two arrays share the same indexing, as the data in them are linked together
72
73 // Information from ASIOGetSamplePosition()
74 // data is converted to double floats for easier use, however 64 bit integer can be used, too
75 double nanoSeconds;
76 double samples;
77 double tcSamples; // time code samples
78
79 // bufferSwitchTimeInfo()
80 ASIOTime tInfo; // time info state
81 unsigned long sysRefTime; // system reference time, when bufferSwitch() was called
82
83 // Signal the end of processing in this example
84 bool stopped;
85 } DriverInfo;
86
87 extern AsioDrivers* asioDrivers;
88 extern bool loadAsioDriver(char *name);
89 static ASIODriverInfo MyAsioDriverInfo;
90 static DriverInfo asioDriverInfo = {0};
91
92 static bool asioDriverOpened;
93 static bool AudioOutputDeviceAsioInstantiated = false;
94 static String currentAsioDriverName;
95 static std::vector<String> asioDriverList;
96 static bool asioDriverListLoaded = false;
97
98 namespace LinuxSampler {
99
100 // callback prototypes
101
102 ASIOCallbacks asioCallbacks;
103 ASIOBufferInfo bufferInfos[2];
104 AudioOutputDeviceAsio *GlobalAudioOutputDeviceAsioThisPtr;
105
106 void floatToASIOSTInt16LSB(float *in, void *dest, int numSamples) {
107 int16_t *out = (int16_t *)dest;
108 for(int i=0; i < numSamples ; i++) {
109 float sample_point = in[i] * 32768.0f;
110 if (sample_point < -32768.0) sample_point = -32768.0;
111 if (sample_point > 32767.0) sample_point = 32767.0;
112 out[i] = (int16_t)sample_point;
113 }
114 }
115
116 void floatToASIOSTInt32LSB(float *in, void *dest, int numSamples) {
117 int32_t *out = (int32_t *)dest;
118 for(int i=0; i < numSamples ; i++) {
119 double sample_point = in[i] * 2147483648.0;
120 if (sample_point < - 2147483648.0) sample_point = -2147483648.0;
121 if (sample_point > 2147483647.0) sample_point = 2147483647.0;
122 out[i] = (int32_t)(sample_point);
123 }
124 }
125
126 static bool ASIO_loadAsioDriver(char *name)
127 {
128 dmsg(1,("ASIO_loadAsioDriver: trying to load '%s'\n",name));
129 #ifdef WINDOWS
130 CoInitialize(0);
131 #endif
132 return loadAsioDriver(name);
133 }
134
135 int ASIO_OpenAndQueryDeviceInfo(char *driverName, DriverInfo *driverInfo, ASIODriverInfo *asioDriverInfo)
136 {
137 ASIOSampleRate possibleSampleRates[]
138 = {8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0};
139
140 ASIOChannelInfo channelInfos;
141 ASIOError asioError;
142
143 dmsg(1,("ASIO_OpenAndQueryDeviceInfo driverName='%s' current='%s'\n",driverName, currentAsioDriverName.c_str() ));
144 if(!strcmp(driverName, currentAsioDriverName.c_str() )) {
145 // if the given ASIO driver name == current ASIO driver name and the driver
146 // was already opened then do nothing
147 if(asioDriverOpened) {
148 dmsg(0,("asioDriver ALREADY OPENED, DOING NOTHING !\n"));
149 return 0;
150 }
151 }
152 else {
153 dmsg(1,("driverName != currentAsioDriverName , new asio driver specified, opening device ....\n"));
154 // if a new ASIO driver name was specified then first check if we need to close
155 // the old one
156 if(asioDriverOpened) {
157 dmsg(0,("different asioDriver ALREADY OPENED, closing old one !\n"));
158 asioDriverOpened = false;
159 ASIOExit(); // close the old ASIO driver
160 }
161 }
162 currentAsioDriverName = driverName;
163
164 memset((void *)asioDriverInfo,0,sizeof(ASIODriverInfo));
165 asioDriverInfo->asioVersion=1;
166 asioDriverInfo->sysRef = NULL;
167
168 /* MUST BE CHECKED : to force fragments loading on Mac */
169 //ASIO_loadAsioDriver("dummy");
170
171 dmsg(1,("Before ASIO_loadAsioDriver('%s')\n",driverName));
172 if ( !ASIO_loadAsioDriver(driverName) ) {
173 dmsg(1,("ASIO_OpenAndQueryDeviceInfo could not loadAsioDriver %s\n", driverName));
174 return -1;
175 }
176 dmsg(1,("Before ASIOInit()\n"));
177 if( (asioError = ASIOInit(asioDriverInfo)) != ASE_OK ) {
178 dmsg(1,("ASIO_OpenAndQueryDeviceInfo: ASIOInit returned %d for %s\n", asioError, driverName));
179 return asioError;
180 }
181 dmsg(1,("Before ASIOGetChannels()\n"));
182 if( (asioError = ASIOGetChannels(&driverInfo->numInputChannels, &driverInfo->numOutputChannels) != ASE_OK)) {
183 dmsg(1,("ASIO_OpenAndQueryDeviceInfo could not ASIOGetChannels for %s\n", driverName));
184 return asioError;
185 }
186
187 dmsg(1,("Before ASIOGetBufferSize()\n"));
188 if( (asioError = ASIOGetBufferSize(&driverInfo->minBufSize,&driverInfo->maxBufSize,&driverInfo->preferredBufSize,&driverInfo->bufGranularity) != ASE_OK)) {
189 dmsg(1,("ASIO_OpenAndQueryDeviceInfo could not ASIOGetBufferSize for %s\n", driverName));
190 return asioError;
191 }
192
193 dmsg(0,("ASIO_OpenAndQueryDeviceInfo: InputChannels = %d\n", driverInfo->numInputChannels ));
194 dmsg(0,("ASIO_OpenAndQueryDeviceInfo: OutputChannels = %d\n", driverInfo->numOutputChannels ));
195
196 /* Loop through the possible sampling rates and check each to see if the device supports it. */
197 driverInfo->numSampleRates = 0;
198 driverInfo->sampleRates.clear();
199 for (int index = 0; index < MAX_NUMSAMPLINGRATES; index++) {
200 if (ASIOCanSampleRate(possibleSampleRates[index]) != ASE_NoClock) {
201 dmsg(1,("ASIOCanSampleRate: possible sample rate = %d\n", (long)possibleSampleRates[index]));
202 driverInfo->sampleRates.push_back( (int)possibleSampleRates[index] );
203 driverInfo->numSampleRates++;
204 }
205 }
206
207 /* get the channel infos for each output channel (including sample format) */
208 for(int i=0 ; i < driverInfo->numOutputChannels ; i++) {
209 driverInfo->channelInfos[i].channel = i;
210 driverInfo->channelInfos[i].isInput = ASIOFalse;
211 ASIOGetChannelInfo(&driverInfo->channelInfos[i]);
212 dmsg(1,("channelInfos[%d].type (sampleformat) = %d\n", i, driverInfo->channelInfos[i].type));
213 }
214
215 dmsg(1,("ASIO_OpenAndQueryDeviceInfo: driver opened.\n"));
216 asioDriverOpened = true;
217 return ASE_OK;
218 }
219
220
221 std::vector<String> getAsioDriverNames() {
222
223 char* names[ASIO_MAX_DEVICE_INFO];
224 int numDrivers;
225
226 if(asioDriverListLoaded) {
227 dmsg(1,("getAsioDriverNames: ASIO driver list already loaded, doing returning cached list.\n"));
228 return asioDriverList;
229 }
230
231 /* MUST BE CHECKED : to force fragments loading on Mac */
232 ASIO_loadAsioDriver("dummy");
233
234 #if MAC
235 numDrivers = asioDrivers->getNumFragments();
236 #elif WINDOWS
237 numDrivers = asioDrivers->asioGetNumDev();
238 #endif
239
240 for (int i = 0 ; i < ASIO_MAX_DEVICE_INFO ; i++) {
241 names[i] = new char[32];
242 memset(names[i],0,32);
243 }
244
245 /* Get names of all available ASIO drivers */
246 asioDrivers->getDriverNames(names,ASIO_MAX_DEVICE_INFO);
247 dmsg(1,("getAsioDriverNames: numDrivers=%d\n",numDrivers));
248
249 for (int i = 0 ; i < numDrivers ; i++) {
250 dmsg(1,("ASIO DRIVERLIST: i=%d name='%s'\n",i,names[i]));
251
252 #if 1
253 asioDriverList.push_back(names[i]);
254 #else
255 int asioError;
256 // FIXME: we currently try what is the best methode to exclude not connected devices or not working drivers
257 // the code below is for testing only, it tried to load each ASIO driver and if it gives an error it is not included
258 // in the list of available drivers (asioDriverList)
259 if ( ASIO_loadAsioDriver(names[i]) ) {
260 if( (asioError = ASIOInit(&MyAsioDriverInfo)) == ASE_OK ) {
261 asioDriverList.push_back(names[i]);
262 }
263 else {
264 dmsg(0,("getDriverList: ASIOInit of driver %s gave Error %d ! ignoring it.\n", names[i],asioError));
265 }
266 }
267 else {
268 dmsg(0,("getDriverList: load driver %s failed! ignoring it.\n", names[i]));
269 }
270 // FIXME: we need to check this ASIOExit is needed (gave a crash on a ASIO ADSP24(WDM) card so we commented it out)
271 //ASIOExit();
272 #endif
273 currentAsioDriverName="";
274
275 }
276
277 for (int i = 0 ; i < ASIO_MAX_DEVICE_INFO ; i++) {
278 delete[] names[i];
279 }
280
281 dmsg(1,("getAsioDriverNames: returing from function. asioDriverList.size()=%d\n", asioDriverList.size() ));
282 asioDriverListLoaded = true;
283 return asioDriverList;
284 }
285
286 unsigned long get_sys_reference_time()
287 {
288 // get the system reference time
289 #if WINDOWS
290 return timeGetTime();
291 #elif MAC
292 static const double twoRaisedTo32 = 4294967296.;
293 UnsignedWide ys;
294 Microseconds(&ys);
295 double r = ((double)ys.hi * twoRaisedTo32 + (double)ys.lo);
296 return (unsigned long)(r / 1000.);
297 #endif
298 }
299
300
301 //----------------------------------------------------------------------------------
302 // conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
303 #if NATIVE_INT64
304 #define ASIO64toDouble(a) (a)
305 #else
306 const double twoRaisedTo32 = 4294967296.;
307 #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
308 #endif
309
310
311 ASIOTime* AudioOutputDeviceAsio::bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
312 {
313
314 static long processedSamples = 0;
315 // store the timeInfo for later use
316 asioDriverInfo.tInfo = *timeInfo;
317
318 // get the time stamp of the buffer, not necessary if no
319 // synchronization to other media is required
320 if (timeInfo->timeInfo.flags & kSystemTimeValid)
321 asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
322 else
323 asioDriverInfo.nanoSeconds = 0;
324
325 if (timeInfo->timeInfo.flags & kSamplePositionValid)
326 asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
327 else
328 asioDriverInfo.samples = 0;
329
330 if (timeInfo->timeCode.flags & kTcValid)
331 asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
332 else
333 asioDriverInfo.tcSamples = 0;
334
335 // get the system reference time
336 asioDriverInfo.sysRefTime = get_sys_reference_time();
337
338 // buffer size in samples
339 long buffSize = asioDriverInfo.chosenBufSize;
340 int32_t *p;
341
342 // tell LinuxSampler to render a fragment of buffSize samples
343 GlobalAudioOutputDeviceAsioThisPtr->RenderAudio(buffSize);
344
345 // now write and convert the samples to the ASIO buffer
346 for (int i = 0; i < asioDriverInfo.numOutputBuffers; i++)
347 {
348 // do processing for the outputs only
349 switch (asioDriverInfo.channelInfos[i].type)
350 {
351 case ASIOSTInt16LSB:
352 memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 2);
353 break;
354 case ASIOSTInt24LSB: // used for 20 bits as well
355 memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 3);
356 break;
357 case ASIOSTInt32LSB:
358 p = (int32_t *)asioDriverInfo.bufferInfos[i].buffers[index];
359 floatToASIOSTInt32LSB(GlobalAudioOutputDeviceAsioThisPtr->Channels[i]->Buffer(), p, buffSize);
360 break;
361 case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
362 throw AudioOutputException(String("ASIO Error: ASIOSTFloat32LSB not yet supported! report to LinuxSampler developers.") );
363 break;
364 case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
365 throw AudioOutputException(String("ASIO Error: ASIOSTFloat64LSB not yet supported! report to LinuxSampler developers.") );
366 break;
367
368 // these are used for 32 bit data buffer, with different alignment of the data inside
369 // 32 bit PCI bus systems can more easily used with these
370 case ASIOSTInt32LSB16: // 32 bit data with 18 bit alignment
371 throw AudioOutputException(String("ASIO Error: ASIOSTInt32LSB16 not yet supported! report to LinuxSampler developers.") );
372 break;
373 case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
374 throw AudioOutputException(String("ASIO Error: ASIOSTInt32LSB18 not yet supported! report to LinuxSampler developers.") );
375 break;
376 case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
377 throw AudioOutputException(String("ASIO Error: ASIOSTInt32LSB20 not yet supported! report to LinuxSampler developers.") );
378 break;
379 case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
380 throw AudioOutputException(String("ASIO Error: ASIOSTInt32LSB24 not yet supported! report to LinuxSampler developers.") );
381 break;
382 case ASIOSTInt16MSB:
383 throw AudioOutputException(String("ASIO Error: ASIOSTInt16MSB not yet supported! report to LinuxSampler developers.") );
384 break;
385 case ASIOSTInt24MSB: // used for 20 bits as well
386 throw AudioOutputException(String("ASIO Error: ASIOSTInt24MSB not yet supported! report to LinuxSampler developers.") );
387 break;
388 case ASIOSTInt32MSB:
389 throw AudioOutputException(String("ASIO Error: ASIOSTInt32MSB not yet supported! report to LinuxSampler developers.") );
390 break;
391 case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on bigendian architecture
392 throw AudioOutputException(String("ASIO Error: ASIOSTFloat32MSB not yet supported! report to LinuxSampler developers.") );
393 break;
394 case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on bigendian architecture
395 throw AudioOutputException(String("ASIO Error: ASIOSTFloat64MSB not yet supported! report to LinuxSampler developers.") );
396 break;
397
398 // these are used for 32 bit data buffer, with different alignment of the data inside
399 // 32 bit PCI bus systems can more easily used with these
400 case ASIOSTInt32MSB16: // 32 bit data with 18 bit alignment
401 throw AudioOutputException(String("ASIO Error: ASIOSTInt32MSB16 not yet supported! report to LinuxSampler developers.") );
402 break;
403 case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
404 throw AudioOutputException(String("ASIO Error: ASIOSTInt32MSB18 not yet supported! report to LinuxSampler developers.") );
405 break;
406 case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
407 throw AudioOutputException(String("ASIO Error: ASIOSTInt32MSB20 not yet supported! report to LinuxSampler developers.") );
408 break;
409 case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
410 throw AudioOutputException(String("ASIO Error: ASIOSTInt32MSB24 not yet supported! report to LinuxSampler developers.") );
411 break;
412 default:
413 throw AudioOutputException(String("ASIO Error: unknown ASIOST sample format. report error.") );
414 break;
415 }
416 }
417
418 // finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
419 if (asioDriverInfo.ASIOOutputReadySupported)
420 ASIOOutputReady();
421
422 processedSamples += buffSize;
423 return 0L;
424 }
425
426 void AudioOutputDeviceAsio::bufferSwitch(long index, ASIOBool processNow)
427 {
428 // the actual processing callback.
429 // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs to be created
430 // though it will only set the timeInfo.samplePosition and timeInfo.systemTime fields and the according flags
431 ASIOTime timeInfo;
432 memset (&timeInfo, 0, sizeof (timeInfo));
433
434 // get the time stamp of the buffer, not necessary if no
435 // synchronization to other media is required
436 if(ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
437 timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
438
439 bufferSwitchTimeInfo (&timeInfo, index, processNow);
440 }
441
442 void sampleRateChanged(ASIOSampleRate sRate)
443 {
444 // do whatever you need to do if the sample rate changed
445 // usually this only happens during external sync.
446 // Audio processing is not stopped by the driver, actual sample rate
447 // might not have even changed, maybe only the sample rate status of an
448 // AES/EBU or S/PDIF digital input at the audio device.
449 // You might have to update time/sample related conversion routines, etc.
450 }
451
452 long asioMessages(long selector, long value, void* message, double* opt)
453 {
454 dmsg(1,("asioMessages selector=%d value=%d\n",selector,value));
455 // currently the parameters "value", "message" and "opt" are not used.
456 long ret = 0;
457 switch(selector)
458 {
459 case kAsioSelectorSupported:
460 if(value == kAsioResetRequest
461 || value == kAsioEngineVersion
462 || value == kAsioResyncRequest
463 || value == kAsioLatenciesChanged
464 // the following three were added for ASIO 2.0, we don't necessarily have to support them
465 || value == kAsioSupportsTimeInfo
466 || value == kAsioSupportsTimeCode
467 || value == kAsioSupportsInputMonitor)
468 ret = 1L;
469 break;
470 case kAsioResetRequest:
471 // defer the task and perform the reset of the driver during the next "safe" situation
472 // You cannot reset the driver right now, as this code is called from the driver.
473 // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
474 // Afterwards you initialize the driver again.
475 //GlobalAudioOutputDeviceAsioThisPtr->asioDriverInfo.stopped; // In this sample the processing will just stop
476 ret = 1L;
477 break;
478 case kAsioResyncRequest:
479 // This informs the application, that the driver encountered some non fatal data loss.
480 // It is used for synchronization purposes of different media.
481 // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
482 // Windows Multimedia system, which could loose data because the Mutex was hold too long
483 // by another thread.
484 // However a driver can issue it in other situations, too.
485 ret = 1L;
486 break;
487 case kAsioLatenciesChanged:
488 // This will inform the host application that the drivers were latencies changed.
489 // Beware, it this does not mean that the buffer sizes have changed!
490 // You might need to update internal delay data.
491 ret = 1L;
492 break;
493 case kAsioEngineVersion:
494 // return the supported ASIO version of the host application
495 // If a host applications does not implement this selector, ASIO 1.0 is assumed
496 // by the driver
497 ret = 2L;
498 break;
499 case kAsioSupportsTimeInfo:
500 // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
501 // is supported.
502 // For compatibility with ASIO 1.0 drivers the host application should always support
503 // the "old" bufferSwitch method, too.
504 ret = 1;
505 break;
506 case kAsioSupportsTimeCode:
507 // informs the driver wether application is interested in time code info.
508 // If an application does not need to know about time code, the driver has less work
509 // to do.
510 ret = 0;
511 break;
512 }
513 return ret;
514 }
515
516
517 // *************** ParameterCard ***************
518 // *
519
520 AudioOutputDeviceAsio::ParameterCard::ParameterCard() : DeviceCreationParameterString() {
521 InitWithDefault(); // use default card
522 }
523
524 AudioOutputDeviceAsio::ParameterCard::ParameterCard(String s) throw (Exception) : DeviceCreationParameterString(s) {
525 }
526
527 String AudioOutputDeviceAsio::ParameterCard::Description() {
528 return "Sound card to be used";
529 }
530
531 bool AudioOutputDeviceAsio::ParameterCard::Fix() {
532 return true;
533 }
534
535 bool AudioOutputDeviceAsio::ParameterCard::Mandatory() {
536 return false;
537 }
538
539 std::map<String,DeviceCreationParameter*> AudioOutputDeviceAsio::ParameterCard::DependsAsParameters() {
540 return std::map<String,DeviceCreationParameter*>(); // no dependencies
541 }
542
543 optional<String> AudioOutputDeviceAsio::ParameterCard::DefaultAsString(std::map<String,String> Parameters) {
544
545 std::vector<String> cards = PossibilitiesAsString(Parameters);
546 if (cards.empty()) throw Exception("AudioOutputDeviceAsio: Can't find any card");
547 dmsg(1,("AudioOutputDeviceAsio::ParameterCard::DefaultAsString='%s'\n",cards[0].c_str() ));
548 return cards[0]; // first card by default
549 }
550
551 std::vector<String> AudioOutputDeviceAsio::ParameterCard::PossibilitiesAsString(std::map<String,String> Parameters) {
552 dmsg(1,("AudioOutputDeviceAsio::ParameterCard::PossibilitiesAsString:\n"));
553 return getAsioDriverNames();
554 }
555
556 void AudioOutputDeviceAsio::ParameterCard::OnSetValue(String s) throw (Exception) {
557 // not posssible, as parameter is fix
558 }
559
560 String AudioOutputDeviceAsio::ParameterCard::Name() {
561 return "CARD";
562 }
563
564
565
566 // *************** ParameterSampleRate ***************
567 // *
568
569 AudioOutputDeviceAsio::ParameterSampleRate::ParameterSampleRate() : AudioOutputDevice::ParameterSampleRate::ParameterSampleRate() {
570 }
571
572 AudioOutputDeviceAsio::ParameterSampleRate::ParameterSampleRate(String s) : AudioOutputDevice::ParameterSampleRate::ParameterSampleRate(s) {
573 }
574
575 std::map<String,DeviceCreationParameter*> AudioOutputDeviceAsio::ParameterSampleRate::DependsAsParameters() {
576 static ParameterCard card;
577 std::map<String,DeviceCreationParameter*> dependencies;
578 dependencies[card.Name()] = &card;
579 return dependencies;
580 }
581
582 optional<int> AudioOutputDeviceAsio::ParameterSampleRate::DefaultAsInt(std::map<String,String> Parameters) {
583 if (!Parameters.count("CARD")) {
584 dmsg(1,("AudioOutputDeviceAsio::ParameterSampleRate::DefaultAsInt returning optional<int>::nothing (parameter CARD not supplied)\n"));
585 return optional<int>::nothing;
586 }
587
588 // return the default samplerate. first try 44100 then 48000, then the first samplerate found in the list
589 ParameterCard card(Parameters["CARD"]);
590 if( ASIO_OpenAndQueryDeviceInfo((char *)card.ValueAsString().c_str(), &asioDriverInfo, &MyAsioDriverInfo) != ASE_OK) {
591 throw AudioOutputException(String("Error: ASIO Initalization Error") );
592 }
593 for(int i = 0 ; i < asioDriverInfo.sampleRates.size() ; i++) {
594 if(asioDriverInfo.sampleRates[i] == 44100) {
595 return 44100;
596 dmsg(1,("AudioOutputDeviceAsio::ParameterSampleRate::DefaultAsInt returning 44100\n"));
597 }
598 if(asioDriverInfo.sampleRates[i] == 48000) {
599 dmsg(1,("AudioOutputDeviceAsio::ParameterSampleRate::DefaultAsInt returning 48000\n"));
600 return 48000;
601 }
602 }
603 dmsg(1,("AudioOutputDeviceAsio::ParameterSampleRate::DefaultAsInt returning %d\n",asioDriverInfo.sampleRates[0]));
604 return asioDriverInfo.sampleRates[0];
605 }
606
607 std::vector<int> AudioOutputDeviceAsio::ParameterSampleRate::PossibilitiesAsInt(std::map<String,String> Parameters) {
608 dmsg(1,("AudioOutputDeviceAsio::ParameterSampleRate::PossibilitiesAsInt\n"));
609 if (!Parameters.count("CARD")) {
610 dmsg(1,("AudioOutputDeviceAsio::ParameterSampleRate::PossibilitiesAsInt returning empty vector (parameter CARD not supplied)\n"));
611 return std::vector<int>();
612 }
613
614 ParameterCard card(Parameters["CARD"]);
615 if( ASIO_OpenAndQueryDeviceInfo((char *)card.ValueAsString().c_str(), &asioDriverInfo, &MyAsioDriverInfo) != ASE_OK) {
616 throw AudioOutputException(String("Error: ASIO Initalization Error") );
617 }
618
619 for(int i=0;i<asioDriverInfo.sampleRates.size();i++) {
620 dmsg(1,("AudioOutputDeviceAsio::ParameterSampleRate::PossibilitiesAsInt samplerate[%d]=%d\n",i,asioDriverInfo.sampleRates[i]));
621 }
622
623 return asioDriverInfo.sampleRates;
624 }
625
626
627
628 // *************** ParameterChannels ***************
629 // *
630
631 AudioOutputDeviceAsio::ParameterChannels::ParameterChannels() : AudioOutputDevice::ParameterChannels::ParameterChannels() {
632 //InitWithDefault();
633 // could not determine default value? ...
634 //if (ValueAsInt() == 0) SetValue(2); // ... then (try) a common value
635 }
636
637 AudioOutputDeviceAsio::ParameterChannels::ParameterChannels(String s) : AudioOutputDevice::ParameterChannels::ParameterChannels(s) {
638 }
639
640 std::map<String,DeviceCreationParameter*> AudioOutputDeviceAsio::ParameterChannels::DependsAsParameters() {
641 static ParameterCard card;
642 std::map<String,DeviceCreationParameter*> dependencies;
643 dependencies[card.Name()] = &card;
644 return dependencies;
645 }
646
647 optional<int> AudioOutputDeviceAsio::ParameterChannels::DefaultAsInt(std::map<String,String> Parameters) {
648 dmsg(1,("AudioOutputDeviceAsio::ParameterChannels::DefaultAsInt\n"));
649 if (!Parameters.count("CARD")) {
650 dmsg(1,("AudioOutputDeviceAsio::ParameterChannels::DefaultAsInt returning optional<int>::nothing (CARD parameter not supplied)\n"));
651 return optional<int>::nothing;
652 }
653
654 ParameterCard card(Parameters["CARD"]);
655 if( ASIO_OpenAndQueryDeviceInfo((char *)card.ValueAsString().c_str(), &asioDriverInfo, &MyAsioDriverInfo) != ASE_OK) {
656 throw AudioOutputException(String("Error: ASIO Initialization Error") );
657 }
658 dmsg(1,("AudioOutputDeviceAsio::ParameterChannels::DefaultAsInt returning %d\n",asioDriverInfo.numOutputChannels));
659 return asioDriverInfo.numOutputChannels;
660 }
661
662 optional<int> AudioOutputDeviceAsio::ParameterChannels::RangeMinAsInt(std::map<String,String> Parameters) {
663 dmsg(1,("AudioOutputDeviceAsio::ParameterChannels::RangeMinAsInt!\n"));
664 if (!Parameters.count("CARD")) {
665 dmsg(1,("AudioOutputDeviceAsio::ParameterChannels::RangeMinAsInt returning optional<int>::nothing (CARD parameter not supplied)\n"));
666 return optional<int>::nothing;
667 }
668 dmsg(1,("AudioOutputDeviceAsio::ParameterChannels::RangeMinAsInt returning 1\n"));
669 return 1;
670 }
671
672 optional<int> AudioOutputDeviceAsio::ParameterChannels::RangeMaxAsInt(std::map<String,String> Parameters) {
673 dmsg(1,("AudioOutputDeviceAsio::ParameterChannels::RangeMaxAsInt!\n"));
674 if (!Parameters.count("CARD")) {
675 dmsg(1,("AudioOutputDeviceAsio::ParameterChannels::RangeMaxAsInt returning optional<int>::nothing (CARD parameter not supplied)\n"));
676 return optional<int>::nothing;
677 }
678
679 ParameterCard card(Parameters["CARD"]);
680 if( ASIO_OpenAndQueryDeviceInfo((char *)card.ValueAsString().c_str(), &asioDriverInfo, &MyAsioDriverInfo) != ASE_OK) {
681 throw AudioOutputException(String("Error: ASIO Init Error") );
682 }
683 dmsg(1,("AudioOutputDeviceAsio::ParameterChannels::RangeMaxAsInt returning %d\n",asioDriverInfo.numOutputChannels));
684 return asioDriverInfo.numOutputChannels;
685 }
686
687
688
689 // *************** ParameterFragmentSize ***************
690 // *
691
692 AudioOutputDeviceAsio::ParameterFragmentSize::ParameterFragmentSize() : DeviceCreationParameterInt() {
693 InitWithDefault();
694 }
695
696 AudioOutputDeviceAsio::ParameterFragmentSize::ParameterFragmentSize(String s) throw (Exception) : DeviceCreationParameterInt(s) {
697 }
698
699 String AudioOutputDeviceAsio::ParameterFragmentSize::Description() {
700 return "Size of each buffer fragment";
701 }
702
703 bool AudioOutputDeviceAsio::ParameterFragmentSize::Fix() {
704 return true;
705 }
706
707 bool AudioOutputDeviceAsio::ParameterFragmentSize::Mandatory() {
708 return false;
709 }
710
711 std::map<String,DeviceCreationParameter*> AudioOutputDeviceAsio::ParameterFragmentSize::DependsAsParameters() {
712 static ParameterCard card;
713 std::map<String,DeviceCreationParameter*> dependencies;
714 dependencies[card.Name()] = &card;
715 return dependencies;
716 }
717
718 optional<int> AudioOutputDeviceAsio::ParameterFragmentSize::DefaultAsInt(std::map<String,String> Parameters) {
719 dmsg(1,("AudioOutputDeviceAsio::ParameterFragmentSize::DefaultAsInt!\n"));
720 if (!Parameters.count("CARD")) {
721 dmsg(1,("AudioOutputDeviceAsio::ParameterFragmentSize::DefaultAsInt returning optional<int>::nothing (no CARD parameter supplied\n"));
722 return optional<int>::nothing;
723 }
724
725 ParameterCard card(Parameters["CARD"]);
726 if( ASIO_OpenAndQueryDeviceInfo((char *)card.ValueAsString().c_str(), &asioDriverInfo, &MyAsioDriverInfo) != ASE_OK) {
727 throw AudioOutputException(String("Error: ASIO Initialization Error") );
728 }
729 dmsg(1,("AudioOutputDeviceAsio::ParameterFragmentSize::DefaultAsInt returning %d\n",asioDriverInfo.preferredBufSize));
730 return asioDriverInfo.preferredBufSize;
731 }
732
733 optional<int> AudioOutputDeviceAsio::ParameterFragmentSize::RangeMinAsInt(std::map<String,String> Parameters) {
734 dmsg(1,("AudioOutputDeviceAsio::ParameterFragmentSize::RangeMinAsInt!\n"));
735 if (!Parameters.count("CARD")) {
736 dmsg(1,("AudioOutputDeviceAsio::ParameterFragmentSize::RangeMinAsInt returning optional<int>::nothing (no CARD parameter supplied\n"));
737 return optional<int>::nothing;
738 }
739
740 ParameterCard card(Parameters["CARD"]);
741 if( ASIO_OpenAndQueryDeviceInfo((char *)card.ValueAsString().c_str(), &asioDriverInfo, &MyAsioDriverInfo) != ASE_OK) {
742 throw AudioOutputException(String("Error: ASIO Initalization Error") );
743 }
744 dmsg(1,("AudioOutputDeviceAsio::ParameterFragmentSize::RangeMinAsInt returning %d\n",asioDriverInfo.minBufSize));
745 return asioDriverInfo.minBufSize;
746 }
747
748 optional<int> AudioOutputDeviceAsio::ParameterFragmentSize::RangeMaxAsInt(std::map<String,String> Parameters) {
749 dmsg(1,("AudioOutputDeviceAsio::ParameterFragmentSize::RangeMaxAsInt!\n"));
750 if (!Parameters.count("CARD")) {
751 dmsg(1,("AudioOutputDeviceAsio::ParameterFragmentSize::RangeMaxAsInt returning optional<int>::nothing (no CARD parameter supplied\n"));
752 return optional<int>::nothing;
753 }
754
755 ParameterCard card(Parameters["CARD"]);
756 if( ASIO_OpenAndQueryDeviceInfo((char *)card.ValueAsString().c_str(), &asioDriverInfo, &MyAsioDriverInfo) != ASE_OK) {
757 throw AudioOutputException(String("Error: ASIO Initialization Error") );
758 }
759 dmsg(1,("AudioOutputDeviceAsio::ParameterFragmentSize::RangeMaxAsInt returning %d\n",asioDriverInfo.maxBufSize));
760 return asioDriverInfo.maxBufSize;
761 }
762
763 std::vector<int> AudioOutputDeviceAsio::ParameterFragmentSize::PossibilitiesAsInt(std::map<String,String> Parameters) {
764 dmsg(1,("AudioOutputDeviceAsio::ParameterFragmentSize::PossibilitiesAsInt!\n"));
765 return std::vector<int>();
766 }
767
768 void AudioOutputDeviceAsio::ParameterFragmentSize::OnSetValue(int i) throw (Exception) {
769 // not posssible, as parameter is fix
770 }
771
772 String AudioOutputDeviceAsio::ParameterFragmentSize::Name() {
773 return "FRAGMENTSIZE";
774 }
775
776
777
778 // *************** AudioOutputDeviceAsio ***************
779 // *
780
781 /**
782 * Create and initialize Asio audio output device with given parameters.
783 *
784 * @param Parameters - optional parameters
785 * @throws AudioOutputException if output device cannot be opened
786 */
787 AudioOutputDeviceAsio::AudioOutputDeviceAsio(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
788 if(AudioOutputDeviceAsioInstantiated) throw Exception("AudioOutputDeviceAsio: Sorry, only one ASIO card at time can be opened");
789 AudioOutputDeviceAsioInstantiated = true;
790 asioDriverOpened = false;
791 this->uiAsioChannels = ((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt();
792 this->uiSamplerate = ((DeviceCreationParameterInt*)Parameters["SAMPLERATE"])->ValueAsInt();
793 this->FragmentSize = ((DeviceCreationParameterInt*)Parameters["FRAGMENTSIZE"])->ValueAsInt();
794 String Card = ((DeviceCreationParameterString*)Parameters["CARD"])->ValueAsString();
795
796
797 dmsg(1,("AudioOutputDeviceAsio::AudioOutputDeviceAsio constructor\n"));
798
799 asioIsPlaying = false;
800
801 ASIO_OpenAndQueryDeviceInfo((char *)Card.c_str(), &asioDriverInfo, &MyAsioDriverInfo);
802 dmsg(1,("AudioOutputDeviceAsio::AudioOutputDeviceAsio: after ASIO_OpenAndQueryDeviceInfo\n"));
803
804 if( ASIOSetSampleRate(uiSamplerate) != ASE_OK ) {
805 throw AudioOutputException(String("Error: ASIOSetSampleRate: cannot set samplerate. ") );
806 }
807 dmsg(1,("AudioOutputDeviceAsio::AudioOutputDeviceAsio: after ASIOSetSampleRate\n"));
808
809 if(ASIOOutputReady() == ASE_OK) asioDriverInfo.ASIOOutputReadySupported = true;
810 else asioDriverInfo.ASIOOutputReadySupported = false;
811 dmsg(1,("AudioOutputDeviceAsio::AudioOutputDeviceAsio: after ASIOOutputReady\n"));
812
813 asioDriverInfo.numInputBuffers = 0;
814 asioDriverInfo.numOutputBuffers = uiAsioChannels;
815 asioDriverInfo.chosenBufSize = FragmentSize;
816
817 for( int i = 0 ; i < uiAsioChannels ; i++) {
818 asioDriverInfo.bufferInfos[i].isInput = ASIOFalse;
819 asioDriverInfo.bufferInfos[i].channelNum = i;
820 }
821
822 asioCallbacks.bufferSwitch = &bufferSwitch;
823 asioCallbacks.sampleRateDidChange = &sampleRateChanged;
824 asioCallbacks.asioMessage = &asioMessages;
825 asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
826
827 if ( ASIOCreateBuffers(asioDriverInfo.bufferInfos, asioDriverInfo.numOutputBuffers, asioDriverInfo.chosenBufSize = FragmentSize, &asioCallbacks) != ASE_OK ){
828 throw AudioOutputException(String("AudioOutputDeviceAsio: Error: ASIOCreateBuffers failed.") );
829 }
830 dmsg(1,("AudioOutputDeviceAsio::AudioOutputDeviceAsio: after ASIOCreateBuffers\n"));
831
832 // create audio channels for this audio device to which the sampler engines can write to
833 for (int i = 0; i < uiAsioChannels; i++) this->Channels.push_back(new AudioChannel(i, FragmentSize));
834
835 // FIXME: temporary global variable used to store the this pointer for the ASIO callbacks wanting to access the AudioOutputDeviceAsio methods
836 GlobalAudioOutputDeviceAsioThisPtr = this;
837
838 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
839 Play();
840 }
841 }
842
843 AudioOutputDeviceAsio::~AudioOutputDeviceAsio() {
844 ASIOExit();
845 asioDriverOpened = false;
846 AudioOutputDeviceAsioInstantiated = false;
847 }
848
849 void AudioOutputDeviceAsio::Play() {
850 dmsg(1,("AudioOutputDeviceAsio::Play() !\n"));
851 if ( ASIOStart() != ASE_OK ){
852 asioIsPlaying = false;
853 throw AudioOutputException(String("AudioOutputDeviceAsio: Error: ASIOStart failed.") );
854 }
855 else asioIsPlaying = true;
856 }
857
858 bool AudioOutputDeviceAsio::IsPlaying() {
859 return asioIsPlaying;
860 }
861
862 void AudioOutputDeviceAsio::Stop() {
863 dmsg(1,("AudioOutputDeviceAsio::Stop() !\n"));
864 ASIOStop();
865 asioIsPlaying = false;
866 }
867
868 AudioChannel* AudioOutputDeviceAsio::CreateChannel(uint ChannelNr) {
869 dmsg(1,("AudioOutputDeviceAsio::CreateChannel value=%d uiAsioChannels=%d\n",ChannelNr,uiAsioChannels));
870 // just create a mix channel
871 return new AudioChannel(ChannelNr, Channel(ChannelNr % uiAsioChannels));
872 }
873
874 uint AudioOutputDeviceAsio::MaxSamplesPerCycle() {
875 dmsg(3,("AudioOutputDeviceAsio::MaxSamplesPerCycle value=%d\n",FragmentSize));
876 return FragmentSize;
877 }
878
879 uint AudioOutputDeviceAsio::SampleRate() {
880 dmsg(1,("AudioOutputDeviceAsio::SampleRate value=%d\n",uiSamplerate)); fflush(stdout);
881 return uiSamplerate;
882 }
883
884 String AudioOutputDeviceAsio::Name() {
885 return "ASIO";
886 }
887
888 String AudioOutputDeviceAsio::Driver() {
889 return Name();
890 }
891
892 String AudioOutputDeviceAsio::Description() {
893 return "Audio Streaming Input Output 2.2";
894 }
895
896 String AudioOutputDeviceAsio::Version() {
897 String s = "$Revision: 1.2 $";
898 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
899 }
900
901 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC