comparison src/Output/CoreAudio/dbconvert.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
comparison
equal deleted inserted replaced
-1:000000000000 0:13389e613d67
1 /*
2
3 Author: Bob Dean
4 Copyright (c) 1999 - 2004
5
6 The functionality in this file is modified from DBAudio_Write.c.
7 part of the DBMix project which is also released under the GPL.
8 It is used here both as licensed under the GPL and additionally
9 by permission of the original author (which is me).
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public Licensse as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25 */
26
27 #ifdef __cplusplus
28 extern "C"
29 {
30 #endif
31
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <limits.h>
38 #include <fcntl.h>
39 #include <signal.h>
40 #include <stdarg.h>
41 #include <sys/shm.h>
42 #include <glib.h>
43 #include <math.h>
44 #include <string.h>
45
46 #include "coreaudio.h"
47 #include "dbaudiolib.h"
48
49 extern int errno;
50
51 extern gboolean paused;
52 extern float left_volume, right_volume;
53
54 extern float base_pitch;
55 extern float user_pitch;
56
57
58 float local_pitch;
59 float sample1, sample2;
60 float float_index;
61
62 extern signed short output_buf[]; /* buffer used to hold main output to dbfsd */
63 extern signed short cue_buf[]; /* buffer used to hold cue output to dbfsd */
64 extern signed short conv_buf[]; /* buffer used to hold format converted input */
65 extern int output_buf_length;
66
67 int outlen;
68 int sampleindex;
69 int num_channels;
70 int format;
71
72
73 extern struct format_info input;
74
75
76 /*
77 dbconvert - given a buf of length len, write the data to the
78 channel associated with this instance.
79
80 On success, the number of bytes written is returned. Otherwise
81 -1, or FAILURE, is returned, and errno is set accordingly.
82
83 Hopefully this function returns values in the same fashion
84 as other basic I/O functions such as read() and write()
85
86 Variables:
87 count is the number of bytes written during a loop iteration
88 totalcount is the total number of bytes written
89 left_gain and right_gain are percentages used to adjust the
90 output signal volume
91 tempbuf is a temporary pointer used in the volume operation
92 temp_chbuf is a pointer to the buffer to be written to during
93 shared memory mode.
94 */
95
96 int dbconvert(char* buf, int len)
97 {
98 int left_gain,right_gain;
99 int left_cue_gain, right_cue_gain;
100 signed short * tempbuf, *tempbuf2, * tempoutbuf;
101 char * tempcharbuf;
102 int incr_flag, count;
103 int intindex;
104 float buflen, gain1, gain2;
105 int index1,index2, output_sample;
106 int i;
107 int stereo_multiplier,format_multiplier;
108 int tempsize;
109 int sampler_flag;
110 //enum sampler_state_e local_sampler_state;
111
112 /* check parameters */
113 if (buf == NULL) {errno = ERROR_BAD_PARAM; return FAILURE;}
114 //if (ch == NULL) {errno = ERROR_NOT_INITIALIZED; return FAILURE;}
115 if (len < 0) {errno = ERROR_BAD_PARAM; return FAILURE;}
116
117 //DBAudio_Handle_Message_Queue();
118
119 /* remember sampler state as it may change during
120 the course of the function */
121 #ifdef COMPILE_SAMPLER
122 local_sampler_state = ch->sampler_state;
123 #endif
124
125 if (paused)
126 {
127 //printf("convert: pauseed\n");
128 return 0;
129 }
130
131 /* get pitch */
132 local_pitch = base_pitch * user_pitch;
133
134 //printf("convert: local pitch is %.2f, base %.2f user %.2f\n",local_pitch,base_pitch,user_pitch);
135 buflen = len / 2.0;
136
137 //printf("convert: buflen %.2f len is %d\n",buflen,len);
138
139 /* calculate buffer space needed to convert the data to
140 44.1kHz 16bit stereo*/
141 switch (input.channels)
142 {
143 case 1: stereo_multiplier = 2; break;
144 case 2: stereo_multiplier = 1; break;
145 default: errno = ERROR_BAD_NUMCH; return FAILURE;
146 }
147
148 //printf("convert: format %d, %d %d %d %d\n",input.format.xmms,FMT_U8,FMT_S8,FMT_S16_LE,FMT_S16_BE);
149
150 switch (input.format.xmms)
151 {
152 case FMT_U8: format_multiplier = 2; break;
153 case FMT_S8: format_multiplier = 2; break;
154 case FMT_S16_LE: format_multiplier = 1; break;
155 case FMT_S16_BE: format_multiplier = 1; break;
156 case FMT_S16_NE: format_multiplier = 1; break;
157 default: errno = ERROR_BAD_FORMAT; return FAILURE;
158 }
159
160 /* return error if the needed output space is greater than the
161 output buffer */
162 if (ceil((buflen * (float)stereo_multiplier *
163 (float)format_multiplier) / local_pitch) > (float)(OUTPUT_BUFSIZE))
164 {
165 errno = ERROR_TOO_MUCH_DATA;
166 return FAILURE;
167 }
168
169 /* init local variables */
170 intindex = 0;
171 incr_flag = 0;
172 sampleindex = 0;
173 gain1 = gain2 = 0.0;
174 sample1 = sample2 = 0.0;
175 sampler_flag = 0;
176
177 left_gain = (int)(128.0 * left_volume);
178 right_gain = (int)(128.0 * right_volume);
179
180
181 #ifdef COMPILE_CUE
182 left_cue_gain = ch->cue_left_gain;
183 right_cue_gain = ch->cue_right_gain;
184
185 /* calculate gain percentages */
186 if (ch->mute == TRUE)
187 {
188 left_gain = right_gain = 0;
189 }
190 else
191 {
192 left_gain = ch->left_gain * sysdata->left_balance;
193 right_gain = ch->right_gain * sysdata->right_balance;
194
195 /* cut volume if mic is being used */
196 if (sysdata->talkover_enabled && !(MIC_ENABLED))
197 {
198 left_gain = left_gain >> DB_TALKOVER_DIVISOR_POWER;
199 right_gain = right_gain >> DB_TALKOVER_DIVISOR_POWER;
200 }
201 }
202 #endif
203
204 #ifdef COMPILE_SAMPLER
205 switch (local_sampler_state)
206 {
207 case SAMPLER_PLAY_SINGLE:
208 case SAMPLER_PLAY_LOOP:
209
210 if (ch->sampler_size == 0)
211 {
212 ch->sampler_state = SAMPLER_OFF;
213 len = 0;
214 goto done;
215 }
216
217 /* tempsize - amount of data available in buffer to read */
218 tempsize = (ch->sampler_endoffset - ch->sampler_readoffset);
219
220 sampler_flag = 1;
221
222 /* if we are in loop mode and loop over end of buffer,
223 get data from start of buffer */
224 if ((tempsize < len) && (local_sampler_state == SAMPLER_PLAY_LOOP))
225 {
226 /* copy portion at end of buffer */
227 memcpy(conv_buf,(ch->sampler_buf + ch->sampler_readoffset),tempsize);
228 /* copy portion at beginning of buffer */
229 memcpy(conv_buf+tempsize,ch->sampler_buf+ch->sampler_startoffset,(len - tempsize));
230 /* update variables */
231 /* read offset is now amount to write, minus the overflow, plus the startoffset */
232 ch->sampler_readoffset = len - tempsize + ch->sampler_startoffset;
233 tempsize = len;
234 }
235 else
236 {
237 /* if we are in simgle play mode and out of data, reset state
238 and exit */
239 if ((tempsize <= 0) && (local_sampler_state == SAMPLER_PLAY_SINGLE))
240 {
241 ch->sampler_state = SAMPLER_READY;
242 goto done;
243 }
244
245 /* get full buffers worth of data from somewhere in middle of
246 sampler buffer */
247 if (tempsize > len) tempsize = len;
248
249 memcpy(conv_buf,(ch->sampler_buf + ch->sampler_readoffset),tempsize);
250
251 ch->sampler_readoffset += tempsize;
252 }
253
254
255 /* update function state variables */
256 buflen = (tempsize / 2);
257 tempbuf = conv_buf;
258
259 break;
260 default:
261 #endif
262 {
263 /* convert input data into 44.1 KHz 16 bit stereo */
264 tempbuf = (signed short *) buf;
265
266 /* convert mono input to stereo */
267 if (input.channels == 1)
268 {
269 //printf("convert: data is mono\n");
270
271 tempbuf2 = conv_buf;
272
273 if ((input.format.xmms == FMT_U8) || (input.format.xmms == FMT_S8))
274 {
275 tempcharbuf = buf;
276
277 for (i = 0; i < buflen*2.0; i++)
278 {
279 *tempbuf2 = *tempcharbuf; tempbuf2++;
280 *tempbuf2 = *tempcharbuf; tempbuf2++; tempcharbuf++;
281 }
282 }
283 else
284 {
285 for (i = 0; i < buflen; i++)
286 {
287 *tempbuf2 = *tempbuf; tempbuf2++;
288 *tempbuf2 = *tempbuf; tempbuf2++; tempbuf++;
289 }
290 }
291
292 buflen *=2.0;
293 tempbuf = conv_buf;
294 }
295 else
296 {
297 //printf("convet: data is stereo\n");
298 }
299
300 //printf("convert: buflen %.2f\n",buflen);
301
302
303 /* convert 8 bit input to 16 bit input */
304 if ((input.format.xmms != FMT_S16_LE) && (input.format.xmms != FMT_S16_BE)
305 && (input.format.xmms != FMT_S16_NE))
306 {
307 switch (input.format.xmms)
308 {
309 case FMT_U8:
310 {
311 //printf("convert: converting unsigned 8 bit\n");
312
313 tempbuf2 = conv_buf;
314 buflen *= 2.0;
315
316 /* if data was mono, then it is already in conv_buf */
317 if (input.channels == 1)
318 {
319 for (i = 0; i < buflen; i++)
320 {
321 *tempbuf = (*tempbuf2 - 127) << 8;
322 tempbuf++; tempbuf2++;
323 }
324 }
325 else
326 { /* data is 8 bit stereo, and is in buf not conv_buf*/
327 tempcharbuf = buf;
328 for (i = 0; i < len; i++)
329 {
330 *tempbuf = (*tempcharbuf - 127) << 8;
331 tempbuf++; tempcharbuf++;
332 }
333 }
334
335 tempbuf = conv_buf;
336 break;
337 }
338 case FMT_S8:
339 {
340 //printf("convert: converting signed 8 bit\n");
341
342 tempbuf2 = conv_buf;
343 buflen *= 2.0;
344
345 /* if data was mono, then it is already in conv_buf */
346 if (input.channels == 1)
347 {
348 for (i = 0; i < buflen; i++)
349 {
350 *tempbuf = *tempbuf2 << 8;
351 tempbuf++; tempbuf2++;
352 }
353 }
354 else
355 { /* data is 8 bit stereo, and is in buf not conv_buf*/
356 tempcharbuf = buf;
357 for (i = 0; i < len; i++)
358 {
359 *tempbuf = *tempcharbuf << 8;
360 tempbuf++; tempcharbuf++;
361 }
362 }
363
364 tempbuf = conv_buf;
365 break;
366 }
367 default:
368 {
369 errno = ERROR_BAD_FORMAT;
370 //ch->writing = 0;
371 return FAILURE;
372 }
373 }
374 }
375 } /* end default case*/
376
377 //printf("convert: buflen %.2f\n",buflen);
378
379
380
381 #ifdef COMPILE_SAMPLER
382 } /* end switch sampler_state */
383
384 /* copy buffer to sample buffer if sampler state is record */
385 if (local_sampler_state == SAMPLER_RECORD)
386 {
387 tempsize = 0;
388
389 /* get amount of data to copy */
390 if ((ch->sampler_size + (buflen * 2)) > ch->sampler_bufsize)
391 {
392 tempsize = ch->sampler_bufsize - ch->sampler_size;
393 }
394 else
395 {
396 tempsize = (buflen * 2);
397 }
398
399 /* change state if buffer is full */
400 if (tempsize == 0)
401 {
402 ch->sampler_state = SAMPLER_READY;
403 }
404
405 /* copy data */
406 memcpy(((ch->sampler_buf) + (ch->sampler_size)),tempbuf,tempsize);
407
408 /* update sampler state variables */
409 ch->sampler_size += tempsize;
410 ch->sampler_endoffset = ch->sampler_size;
411 }
412 #endif
413
414 if (local_pitch == 1.0)
415 {
416 //printf("convert: pitch optimization buflen %.2f *2 %.2f\n",buflen,buflen*2);
417 //printf("tempbuf is 0x%x, output_buf is 0x%x\n",tempbuf,output_buf);
418 memcpy(output_buf,tempbuf,buflen*2);
419
420 outlen = buflen*2;
421 tempbuf = output_buf;
422 output_buf_length = buflen;
423
424 goto done;
425 }
426
427 /* calculate pitch shifted signal using basic linear interpolation
428 the theory is this:
429 you have two known samples, and want to calculate the value of a new sample
430 in between them. The new sample will contain a percentage of the first sample
431 and a percentage of the second sample. These percentages are porportional
432 to the distance between the new sample and each of the knwon samples.
433 The "position" of the new sample is determined by the float index */
434
435 tempoutbuf = output_buf;
436
437 while (intindex < buflen)
438 {
439 /* calculate sample percentages (amplitude) */
440 intindex = floor(float_index);
441 gain2 = float_index - intindex;
442 gain1 = 1.0 - gain2;
443
444 /* get index of first sample pair */
445 intindex = intindex << 1;
446
447 /* check incr_flag to see if we should be operatiing
448 on the left or right channel sample */
449 if (incr_flag)
450 {
451 float_index += local_pitch;
452 incr_flag = 0;
453 intindex++;
454 }
455 else
456 {
457 incr_flag = 1;
458 }
459
460 index1 = intindex;
461
462 /* get the first "known" sample*/
463 sample1 = tempbuf[index1];
464 index2 = index1 + 2;
465
466 /* get the second "known" sample */
467 if (index2 < (buflen))
468 {
469 sample2 = tempbuf[index2];
470 }
471 else
472 /* if index2 is beyond the length of the input buffer,
473 then cheat to prevent audio pops/snaps/etc */
474 {
475 *tempoutbuf = sample1;
476 sampleindex++;
477 break;
478 }
479
480 /* create the new sample */
481 output_sample = (((float)sample1 * gain1) + ((float)sample2 * gain2));
482
483 if (output_sample > 32767) {output_sample = 32767;}
484 if (output_sample < -32767) {output_sample = -32767;}
485
486 *tempoutbuf = output_sample;
487 tempoutbuf++;
488
489 sampleindex++;
490 }
491
492 /* update global variables */
493 outlen = (sampleindex-1) << 1;
494
495 float_index = float_index - floor(float_index);
496
497 tempbuf = output_buf;
498
499 output_buf_length = sampleindex - 1;
500
501 /* if (outlen < PIPE_BUF)
502 {errno = ERROR_TOO_LITTLE_DATA; return FAILURE;} */
503
504 apply_gain:
505
506
507 done:
508
509 //ch->writing = 0;
510
511 if (sampler_flag)
512 {
513 return 0;
514 }
515 else
516 {
517 return len;
518 }
519 }
520
521 #ifdef __cplusplus
522 }
523 #endif
524