comparison src/Output/CoreAudio/audio.c @ 0:13389e613d67 trunk

[svn] - initial import of audacious-plugins tree (lots to do)
author nenolod
date Mon, 18 Sep 2006 01:11:49 -0700
parents
children 088092a52fea
comparison
equal deleted inserted replaced
-1:000000000000 0:13389e613d67
1 /* XMMS - Cross-platform multimedia player
2 * Copyright (C) 1998-2001 Peter Alm, Mikael Alm, Olle Hallnas,
3 * Thomas Nilsson and 4Front Technologies
4 * Copyright (C) 1999-2001 Haavard Kvaalen
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20 #include "coreaudio.h"
21 #include "libaudacious/util.h"
22 #include <errno.h>
23 #include <CoreAudio/CoreAudio.h>
24
25 AudioDeviceID device_id;
26 AudioStreamBasicDescription device_format;
27 AudioStreamBasicDescription streamDesc;
28
29 //static gint fd = 0;
30 static float *buffer;
31 gboolean playing_flag;
32 static gboolean prebuffer, unpause, do_pause, remove_prebuffer;
33 static gint device_buffer_size;
34 static gint buffer_size, prebuffer_size;//, blk_size;
35 static gint buffer_index = 0;
36 static gint output_time_offset = 0;
37 static guint64 written = 0, output_total = 0;
38 static gint flush;
39 static gchar *device_name;
40
41 gint sample_multiplier, sample_size;
42
43 gboolean paused;
44
45
46 float left_volume, right_volume;
47 float base_pitch = 0.0;
48 float user_pitch = 0.0;
49 int output_buf_length; // length of data in output buffer
50 short output_buf[OUTPUT_BUFSIZE]; /* buffer used to hold main output to dbfsd */
51 short cue_buf[OUTPUT_BUFSIZE]; /* buffer used to hold cue output to dbfsd */
52 short conv_buf[OUTPUT_BUFSIZE]; /* buffer used to hold format converted input */
53
54 /*
55 * The format of the data from the input plugin
56 * This will never change during a song.
57 */
58 struct format_info input;
59
60
61 /*
62 * The format we get from the effect plugin.
63 * This will be different from input if the effect plugin does
64 * some kind of format conversion.
65 */
66 struct format_info effect;
67
68
69 /*
70 * The format of the data we actually send to the soundcard.
71 * This might be different from effect if we need to resample or do
72 * some other format conversion.
73 */
74 struct format_info output;
75
76
77 static int osx_calc_bitrate(int osx_fmt, int rate, int channels)
78 {
79 int bitrate = rate * channels;
80
81 // for now we know output is stereo
82 // fix this later
83
84 if (osx_fmt == FMT_U16_BE || osx_fmt == FMT_U16_LE ||
85 osx_fmt == FMT_S16_BE || osx_fmt == FMT_S16_LE)
86 {
87 bitrate *= 2;
88 }
89
90 //printf("osx_calc_bitrate(): %d\n",bitrate);
91
92 return bitrate;
93 }
94
95
96 static int osx_get_format(AFormat fmt)
97 {
98 int format = 0;
99
100 switch (fmt)
101 {
102 case FMT_U16_NE:
103 #ifdef WORDS_BIGENDIAN
104 format = FMT_U16_BE;
105 #else
106 format = FMT_U16_LE;
107 #endif
108 break;
109 case FMT_S16_NE:
110 #ifdef WORDS_BIGENDIAN
111 format = FMT_S16_BE;
112 #else
113 format = FMT_S16_LE;
114 #endif
115 break;
116 default:
117 format = fmt;
118 break;
119 }
120
121 return format;
122 }
123
124
125 OSStatus play_callback(AudioDeviceID inDevice, const AudioTimeStamp * inNow, const AudioBufferList * inInputData, const AudioTimeStamp * inInputTime, AudioBufferList * outOutputData, const AudioTimeStamp * inOutputTime, void * inClientData)
126 {
127 int i;
128 long m, n, o;
129 float * dest, tempfloat;
130 float * src;
131 int src_size_bytes;
132 int src_size_float;
133 int num_output_samples;
134 int used_samples;
135
136 src_size_bytes = outOutputData->mBuffers[0].mDataByteSize;
137 src_size_float = src_size_bytes / sizeof(float);
138
139 num_output_samples = MIN(buffer_index,src_size_float);
140
141 //printf("play_callback(): num_output_samples %d, index %d\n",num_output_samples,buffer_index);
142
143 // if we are prebuffering, zero the buffer
144 if (prebuffer && (buffer_index < prebuffer_size))
145 {
146 //printf("prebuffering... %d samples left\n",prebuffer_size-buffer_index);
147 num_output_samples = 0;
148 }
149 else
150 {
151 prebuffer = FALSE;
152 }
153
154 src = buffer;
155 dest = outOutputData->mBuffers[0].mData;
156
157 // copy available data to buffer and apply volume to each channel
158 for (i = 0; i < num_output_samples/2; i++)
159 {
160 //tempfloat = *src;
161 *dest = (*src) * left_volume;
162 src++;
163 dest++;
164
165 *dest = (*src) * right_volume;
166 src++;
167 dest++;
168 }
169
170 // if less than a buffer's worth of data is ready, zero remainder of output buffer
171 if (num_output_samples != src_size_float)
172 {
173 //printf("zeroing %d samples",(src_size_float - num_output_samples));
174
175 dest = (float*)outOutputData->mBuffers[0].mData + num_output_samples;
176
177 memset(dest,0,(src_size_float - num_output_samples) * sizeof(float));
178 }
179
180 // move unwritten data to beginning of buffer
181 {
182 dest = buffer;
183
184 for (i = num_output_samples; i < buffer_index; i++)
185 {
186 *dest = *src;
187 dest++;
188 src++;
189 }
190
191 output_total += num_output_samples;
192 buffer_index -= num_output_samples;
193 }
194
195
196 if (flush != -1)
197 {
198 osx_set_audio_params();
199 output_time_offset = flush;
200 written = ((guint64)flush * input.bps) / (1000 * sample_size);
201 buffer_index = 0;
202 output_total = 0;
203
204 flush = -1;
205 prebuffer = TRUE;
206 }
207
208 //printf("\n");
209
210 return 0;
211 }
212
213
214 static void osx_setup_format(AFormat fmt, int rate, int nch)
215 {
216 //printf("osx_setup_format(): fmt %d, rate %d, nch %d\n",fmt,rate,nch);
217
218 effect.format.xmms = osx_get_format(fmt);
219 effect.frequency = rate;
220 effect.channels = nch;
221 effect.bps = osx_calc_bitrate(fmt, rate, nch);
222
223 output.format.osx = osx_get_format(fmt);
224 output.frequency = rate;
225 output.channels = nch;
226
227 osx_set_audio_params();
228
229 output.bps = osx_calc_bitrate(output.format.osx, output.frequency,output.channels);
230 }
231
232
233 gint osx_get_written_time(void)
234 {
235 gint retval;
236
237 if (!playing_flag)
238 {
239 retval = 0;
240 }
241 else
242 {
243 retval = (written * sample_size * 1000) / effect.bps;
244 retval = (int)((float)retval / user_pitch);
245 }
246
247 //printf("osx_get_written_time(): written time is %d\n",retval);
248
249 return retval;
250 }
251
252
253 gint osx_get_output_time(void)
254 {
255 gint retval;
256
257 retval = output_time_offset + ((output_total * sample_size * 1000) / output.bps);
258 retval = (int)((float)retval / user_pitch);
259
260 //printf("osx_get_output_time(): time is %d\n",retval);
261
262 return retval;
263 }
264
265
266 gint osx_playing(void)
267 {
268 gint retval;
269
270 retval = 0;
271
272 if (!playing_flag)
273 {
274 retval = 0;
275 }
276 else
277 {
278 if (buffer_index == 0)
279 {
280 retval = FALSE;
281 }
282 else
283 {
284 retval = TRUE;
285 }
286 }
287
288 //printf("osx_playing(): playing is now %d\n",playing_flag);
289
290 return retval;
291 }
292
293
294 gint osx_free(void)
295 {
296 gint bytes_free;
297
298 if (remove_prebuffer && prebuffer)
299 {
300 prebuffer = FALSE;
301 remove_prebuffer = FALSE;
302 }
303
304 if (prebuffer)
305 {
306 remove_prebuffer = TRUE;
307 }
308
309 // get number of free samples
310 bytes_free = buffer_size - buffer_index;
311
312 // adjust for mono
313 if (input.channels == 1)
314 {
315 bytes_free /= 2;
316 }
317
318 // adjust by pitch conversion;
319 bytes_free = (int)((float)bytes_free * base_pitch * user_pitch);
320
321 // convert from number of samples to number of bytes
322 bytes_free *= sample_size;
323
324 return bytes_free;
325 }
326
327
328 void osx_write(gpointer ptr, int length)
329 {
330 int count, offset = 0;
331 int error;
332 float tempfloat;
333 float * dest;
334 short * src, * tempbuf;
335 int i;
336 int num_samples;
337
338 //printf("oss_write(): lenght: %d \n",length);
339
340 remove_prebuffer = FALSE;
341
342 // //printf("written is now %d\n",(gint)written);
343
344 // get number of samples
345 num_samples = length / sample_size;
346
347 // update amount of samples received
348 written += num_samples;
349
350 // step through audio
351 while (num_samples > 0)
352 {
353 // get # of samples to write to the buffer
354 count = MIN(num_samples, osx_free()/sample_size);
355
356 src = ptr+offset;
357
358 if (dbconvert((char*)src,count * sample_size) == -1)
359 {
360 //printf("dbconvert error %d\n",errno);
361 }
362 else
363 {
364 src = output_buf;
365 dest = (float*)(buffer + buffer_index);
366
367 //printf("output_buf_length is %d\n",output_buf_length);
368
369 for (i = 0; i < output_buf_length; i++)
370 {
371 tempfloat = ((float)*src)/32768.0;
372 *dest = tempfloat;
373 dest++;
374 src++;
375 }
376
377 buffer_index += output_buf_length;
378 }
379
380 if (buffer_index > buffer_size)
381 {
382 //printf("BUFFER_INDEX > BUFFER_SIZE!!!!\n");
383 exit(0);
384 }
385
386 num_samples -= count;
387 offset += count;
388 }
389
390 //printf("buffer_index is now %d\n\n",buffer_index);
391 }
392
393
394 void osx_close(void)
395 {
396 //printf("osx_close(): playing_flag is %d\n",playing_flag);
397
398 if (!playing_flag)
399 {
400 return;
401 }
402
403 playing_flag = 0;
404
405 // close audio device
406 AudioDeviceStop(device_id, play_callback);
407 AudioDeviceRemoveIOProc(device_id, play_callback);
408
409 g_free(device_name);
410
411 //printf("osx_close(): playing_flag is now %d\n",playing_flag);
412 }
413
414
415 void osx_flush(gint time)
416 {
417 //printf("osx_flush(): %d\n",time);
418
419 flush = time;
420
421 while (flush != -1)
422 {
423 xmms_usleep(10000);
424 }
425 }
426
427
428 void osx_pause(short p)
429 {
430 //printf("osx_pause(): %d\n",p);
431
432 if (p == TRUE)
433 {
434 if (AudioDeviceStop(device_id, play_callback))
435 {
436 //printf("failed to stop audio device.\n");
437 }
438
439 //printf("PAUSED!\n");
440 }
441 else
442 {
443 if (AudioDeviceStart(device_id, play_callback))
444 {
445 //printf("failed to start audio device.\n");
446 }
447
448 //printf("UNPAUSED!\n");
449 }
450
451 paused = p;
452 }
453
454
455 void osx_set_audio_params(void)
456 {
457 int stereo_multiplier, format_multiplier;
458 int frag, stereo, ret;
459 struct timeval tv;
460 fd_set set;
461
462 //printf("osx_set_audio_params(): fmt %d, freq %d, nch %d\n",output.format.osx,output.frequency,output.channels);
463
464 // set audio format
465
466 // set num channels
467
468 switch (input.channels)
469 {
470 case 1: stereo_multiplier = 2; break;
471 case 2: stereo_multiplier = 1; break;
472 default: stereo_multiplier = 1; break;
473 }
474
475 switch (input.format.xmms)
476 {
477 case FMT_U8:
478 case FMT_S8:
479 format_multiplier = 2;
480 sample_size = 1;
481 break;
482 case FMT_S16_LE:
483 case FMT_S16_BE:
484 case FMT_S16_NE:
485 format_multiplier = 1;
486 sample_size = 2;
487 break;
488 default: format_multiplier = 1; break;
489 }
490
491 sample_multiplier = stereo_multiplier * format_multiplier;
492
493 base_pitch = input.frequency / device_format.mSampleRate;
494
495 //printf("sample multiplier is now %d, base pitch %.2f\n",sample_multiplier,base_pitch);
496 }
497
498
499 gint osx_open(AFormat fmt, gint rate, gint nch)
500 {
501 char s[32];
502 long m;
503 long size;
504 char device_name[128];
505
506 //printf("\nosx_open(): fmt %d, rate %d, nch %d\n",fmt,rate,nch);
507
508 // init conversion variables
509 base_pitch = 1.0;
510 user_pitch = 1.0;
511
512 // open audio device
513
514 size = sizeof(device_id);
515
516 if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device_id))
517 {
518 //printf("failed to open default audio device");
519 return -1;
520 }
521
522 //printf("opened audio device\n");
523
524 size = 128;
525
526 if (AudioDeviceGetProperty(device_id,1,0,kAudioDevicePropertyDeviceName,&size,device_name))
527 {
528 //printf("could not get device name\n");
529 return -1;
530 }
531
532 //printf("device name is: \"%s\"\n",device_name);
533
534 size = sizeof(device_format);
535
536 if (AudioDeviceGetProperty(device_id, 0, 0, kAudioDevicePropertyStreamFormat, &size, &device_format))
537 {
538 //printf("failed to get audio format!\n");
539 return -1;
540 }
541
542 //fprintf(stderr, "got format: sample rate %f, %ld channels and %ld-bit sample\n",
543 // device_format.mSampleRate,device_format.mChannelsPerFrame,device_format.mBitsPerChannel);
544
545 if (device_format.mFormatID != kAudioFormatLinearPCM)
546 {
547 //printf("audio format isn't PCM\n");
548 return -1;
549 }
550
551 //printf("format is PCM\n");
552
553 input.format.xmms = fmt;
554 input.frequency = rate;
555 input.channels = nch;
556 input.bps = osx_calc_bitrate(osx_get_format(fmt),rate,nch);
557
558 osx_setup_format(osx_get_format(fmt),device_format.mSampleRate,device_format.mChannelsPerFrame);
559
560 //set audio buffer size
561 {
562 device_buffer_size = 4096 * sizeof(float);
563 size = sizeof(gint);
564
565 if (AudioDeviceSetProperty(device_id,0,0,0,kAudioDevicePropertyBufferSize,size,&device_buffer_size))
566 {
567 //printf("failed to set device buffer size\n");
568 }
569
570 //printf("buffer size set to %d\n",device_buffer_size);
571 }
572
573 buffer_size = 11 * 4096;
574 prebuffer_size = 4096;
575
576 buffer = (float *) g_malloc0(buffer_size*sizeof(float));
577
578 //printf("created buffer of size %d, prebuffer is %d\n",buffer_size,prebuffer_size);
579
580 flush = -1;
581 prebuffer = TRUE;
582
583 buffer_index = output_time_offset = written = output_total = 0;
584
585 paused = FALSE;
586
587 do_pause = FALSE;
588 unpause = FALSE;
589 remove_prebuffer = FALSE;
590
591 playing_flag = 1;
592
593 if (AudioDeviceAddIOProc(device_id, play_callback, NULL))
594 {
595 //printf("failed to add IO Proc callback\n");
596 osx_close();
597 return -1;
598 }
599
600 //printf("added callback\n");
601
602 if (AudioDeviceStart(device_id,play_callback))
603 {
604 osx_close();
605 //printf("failed to start audio device.\n");
606 exit(0);
607 }
608
609 //printf("started audio device\n");
610
611 return 1;
612 }