1 /*
2 * MOC - music on console
3 * Copyright (C) 2004-2008 Damian Pietras <daper@daper.net>
4 *
5 * Softmixer-extension Copyright (C) 2007-2008 Hendrik Iben <hiben@tzi.de>
6 * Provides a software-mixer to regulate volume independent from
7 * hardware.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 */
15
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <stdint.h>
24
25 #include "common.h"
26 #include "audio.h"
27 #include "audio_conversion.h"
28 #include "softmixer.h"
29 #include "options.h"
30 #include "files.h"
31 #include "log.h"
32
33 /* #define DEBUG */
34
35 static int active;
36 static int mix_mono;
37 static int mixer_val, mixer_amp, mixer_real;
38 static float mixer_realf;
39
40 static void softmixer_read_config();
41 static void softmixer_write_config();
42
43 /* public code */
44
softmixer_name()45 char *softmixer_name()
46 {
47 return xstrdup((active)?SOFTMIXER_NAME:SOFTMIXER_NAME_OFF);
48 }
49
softmixer_init()50 void softmixer_init()
51 {
52 active = 0;
53 mix_mono = 0;
54 mixer_amp = 100;
55 softmixer_set_value(100);
56 softmixer_read_config();
57 logit ("Softmixer initialized");
58 }
59
softmixer_shutdown()60 void softmixer_shutdown()
61 {
62 if(options_get_int(SOFTMIXER_SAVE_OPTION))
63 softmixer_write_config();
64 logit ("Softmixer stopped");
65 }
66
softmixer_set_value(const int val)67 void softmixer_set_value(const int val)
68 {
69 mixer_val = CLAMP(0, val, 100);
70 mixer_real = (mixer_val * mixer_amp) / 100;
71 mixer_real = CLAMP(SOFTMIXER_MIN, mixer_real, SOFTMIXER_MAX);
72 mixer_realf = ((float)mixer_real)/100.0f;
73 }
74
softmixer_get_value()75 int softmixer_get_value()
76 {
77 return mixer_val;
78 }
79
softmixer_set_active(int act)80 void softmixer_set_active(int act)
81 {
82 if(act)
83 active = 1;
84 else
85 active = 0;
86 }
87
softmixer_is_active()88 int softmixer_is_active()
89 {
90 return active;
91 }
92
softmixer_set_mono(int mono)93 void softmixer_set_mono(int mono)
94 {
95 if(mono)
96 mix_mono = 1;
97 else
98 mix_mono = 0;
99 }
100
softmixer_is_mono()101 int softmixer_is_mono()
102 {
103 return mix_mono;
104 }
105
106 /* private code */
107
108 static void process_buffer_u8(uint8_t *buf, size_t size);
109 static void process_buffer_s8(int8_t *buf, size_t size);
110 static void process_buffer_u16(uint16_t *buf, size_t size);
111 static void process_buffer_s16(int16_t *buf, size_t size);
112 static void process_buffer_u32(uint32_t *buf, size_t size);
113 static void process_buffer_s32(int32_t *buf, size_t size);
114 static void process_buffer_float(float *buf, size_t size);
115 static void mix_mono_u8(uint8_t *buf, int channels, size_t size);
116 static void mix_mono_s8(int8_t *buf, int channels, size_t size);
117 static void mix_mono_u16(uint16_t *buf, int channels, size_t size);
118 static void mix_mono_s16(int16_t *buf, int channels, size_t size);
119 static void mix_mono_u32(uint32_t *buf, int channels, size_t size);
120 static void mix_mono_s32(int32_t *buf, int channels, size_t size);
121 static void mix_mono_float(float *buf, int channels, size_t size);
122
softmixer_read_config()123 static void softmixer_read_config()
124 {
125 char *cfname = create_file_name(SOFTMIXER_SAVE_FILE);
126
127 FILE *cf = fopen(cfname, "r");
128
129 if(cf==NULL)
130 {
131 logit ("Unable to read softmixer configuration");
132 return;
133 }
134
135 char *linebuffer=NULL;
136
137 int tmp;
138
139 while((linebuffer=read_line(cf)))
140 {
141 if(
142 strncasecmp
143 (
144 linebuffer
145 , SOFTMIXER_CFG_ACTIVE
146 , strlen(SOFTMIXER_CFG_ACTIVE)
147 ) == 0
148 )
149 {
150 if(sscanf(linebuffer, "%*s %i", &tmp)>0)
151 {
152 if(tmp>0)
153 {
154 active = 1;
155 }
156 else
157 {
158 active = 0;
159 }
160 }
161 }
162 if(
163 strncasecmp
164 (
165 linebuffer
166 , SOFTMIXER_CFG_AMP
167 , strlen(SOFTMIXER_CFG_AMP)
168 ) == 0
169 )
170 {
171 if(sscanf(linebuffer, "%*s %i", &tmp)>0)
172 {
173 if(RANGE(SOFTMIXER_MIN, tmp, SOFTMIXER_MAX))
174 {
175 mixer_amp = tmp;
176 }
177 else
178 {
179 logit ("Tried to set softmixer amplification out of range.");
180 }
181 }
182 }
183 if(
184 strncasecmp
185 (
186 linebuffer
187 , SOFTMIXER_CFG_VALUE
188 , strlen(SOFTMIXER_CFG_VALUE)
189 ) == 0
190 )
191 {
192 if(sscanf(linebuffer, "%*s %i", &tmp)>0)
193 {
194 if(RANGE(0, tmp, 100))
195 {
196 softmixer_set_value(tmp);
197 }
198 else
199 {
200 logit ("Tried to set softmixer value out of range.");
201 }
202 }
203 }
204 if(
205 strncasecmp
206 (
207 linebuffer
208 , SOFTMIXER_CFG_MONO
209 , strlen(SOFTMIXER_CFG_MONO)
210 ) == 0
211 )
212 {
213 if(sscanf(linebuffer, "%*s %i", &tmp)>0)
214 {
215 if(tmp>0)
216 {
217 mix_mono = 1;
218 }
219 else
220 {
221 mix_mono = 0;
222 }
223 }
224 }
225
226 free(linebuffer);
227 }
228
229
230 fclose(cf);
231 }
232
softmixer_write_config()233 static void softmixer_write_config()
234 {
235 char *cfname = create_file_name(SOFTMIXER_SAVE_FILE);
236
237 FILE *cf = fopen(cfname, "w");
238
239 if(cf==NULL)
240 {
241 logit ("Unable to write softmixer configuration");
242 return;
243 }
244
245 fprintf(cf, "%s %i\n", SOFTMIXER_CFG_ACTIVE, active);
246 fprintf(cf, "%s %i\n", SOFTMIXER_CFG_AMP, mixer_amp);
247 fprintf(cf, "%s %i\n", SOFTMIXER_CFG_VALUE, mixer_val);
248 fprintf(cf, "%s %i\n", SOFTMIXER_CFG_MONO, mix_mono);
249
250 fclose(cf);
251
252 logit ("Softmixer configuration written");
253 }
254
softmixer_process_buffer(char * buf,size_t size,const struct sound_params * sound_params)255 void softmixer_process_buffer(char *buf, size_t size, const struct sound_params *sound_params)
256 {
257 debug ("Processing %zu bytes...", size);
258
259 if(mixer_real==100 && !mix_mono)
260 return;
261
262 int do_softmix = mixer_real != 100;
263
264 long sound_endianness = sound_params->fmt & SFMT_MASK_ENDIANNESS;
265 long sound_format = sound_params->fmt & SFMT_MASK_FORMAT;
266
267 int samplesize = sfmt_Bps(sound_format);
268 int is_float = (sound_params->fmt & SFMT_MASK_FORMAT) == SFMT_FLOAT;
269
270 int need_endianness_swap = 0;
271
272 if((sound_endianness != SFMT_NE) && (samplesize > 1) && (!is_float))
273 {
274 need_endianness_swap = 1;
275 }
276
277 assert (size % (samplesize * sound_params->channels) == 0);
278
279 /* setup samples to perform arithmetic */
280 if(need_endianness_swap)
281 {
282 debug ("Converting endianness before mixing");
283
284 if(samplesize == 4)
285 audio_conv_bswap_32((int32_t *)buf, size / sizeof(int32_t));
286 else
287 audio_conv_bswap_16((int16_t *)buf, size / sizeof(int16_t));
288 }
289
290 switch(sound_format)
291 {
292 case SFMT_U8:
293 if(do_softmix)
294 process_buffer_u8((uint8_t *)buf, size);
295 if(mix_mono)
296 mix_mono_u8((uint8_t *)buf, sound_params->channels, size);
297 break;
298 case SFMT_S8:
299 if(do_softmix)
300 process_buffer_s8((int8_t *)buf, size);
301 if(mix_mono)
302 mix_mono_s8((int8_t *)buf, sound_params->channels, size);
303 break;
304 case SFMT_U16:
305 if(do_softmix)
306 process_buffer_u16((uint16_t *)buf, size / sizeof(uint16_t));
307 if(mix_mono)
308 mix_mono_u16((uint16_t *)buf, sound_params->channels, size / sizeof(uint16_t));
309 break;
310 case SFMT_S16:
311 if(do_softmix)
312 process_buffer_s16((int16_t *)buf, size / sizeof(int16_t));
313 if(mix_mono)
314 mix_mono_s16((int16_t *)buf, sound_params->channels, size / sizeof(int16_t));
315 break;
316 case SFMT_U32:
317 if(do_softmix)
318 process_buffer_u32((uint32_t *)buf, size / sizeof(uint32_t));
319 if(mix_mono)
320 mix_mono_u32((uint32_t *)buf, sound_params->channels, size / sizeof(uint32_t));
321 break;
322 case SFMT_S32:
323 if(do_softmix)
324 process_buffer_s32((int32_t *)buf, size / sizeof(int32_t));
325 if(mix_mono)
326 mix_mono_s32((int32_t *)buf, sound_params->channels, size / sizeof(int32_t));
327 break;
328 case SFMT_FLOAT:
329 if(do_softmix)
330 process_buffer_float((float *)buf, size / sizeof(float));
331 if(mix_mono)
332 mix_mono_float((float *)buf, sound_params->channels, size / sizeof(float));
333 break;
334 }
335
336 /* restore sample-endianness */
337 if(need_endianness_swap)
338 {
339 debug ("Restoring endianness after mixing");
340
341 if(samplesize == 4)
342 audio_conv_bswap_32((int32_t *)buf, size / sizeof(int32_t));
343 else
344 audio_conv_bswap_16((int16_t *)buf, size / sizeof(int16_t));
345 }
346 }
347
process_buffer_u8(uint8_t * buf,size_t size)348 static void process_buffer_u8(uint8_t *buf, size_t size)
349 {
350 size_t i;
351
352 debug ("mixing");
353
354 for(i=0; i<size; i++)
355 {
356 int16_t tmp = buf[i];
357 tmp -= (UINT8_MAX>>1);
358 tmp *= mixer_real;
359 tmp /= 100;
360 tmp += (UINT8_MAX>>1);
361 tmp = CLAMP(0, tmp, UINT8_MAX);
362 buf[i] = (uint8_t)tmp;
363 }
364 }
365
process_buffer_s8(int8_t * buf,size_t size)366 static void process_buffer_s8(int8_t *buf, size_t size)
367 {
368 size_t i;
369
370 debug ("mixing");
371
372 for(i=0; i<size; i++)
373 {
374 int16_t tmp = buf[i];
375 tmp *= mixer_real;
376 tmp /= 100;
377 tmp = CLAMP(INT8_MIN, tmp, INT8_MAX);
378 buf[i] = (int8_t)tmp;
379 }
380 }
381
process_buffer_u16(uint16_t * buf,size_t size)382 static void process_buffer_u16(uint16_t *buf, size_t size)
383 {
384 size_t i;
385
386 debug ("mixing");
387
388 for(i=0; i<size; i++)
389 {
390 int32_t tmp = buf[i];
391 tmp -= (UINT16_MAX>>1);
392 tmp *= mixer_real;
393 tmp /= 100;
394 tmp += (UINT16_MAX>>1);
395 tmp = CLAMP(0, tmp, UINT16_MAX);
396 buf[i] = (uint16_t)tmp;
397 }
398 }
399
process_buffer_s16(int16_t * buf,size_t size)400 static void process_buffer_s16(int16_t *buf, size_t size)
401 {
402 size_t i;
403
404 debug ("mixing");
405
406 for(i=0; i<size; i++)
407 {
408 int32_t tmp = buf[i];
409 tmp *= mixer_real;
410 tmp /= 100;
411 tmp = CLAMP(INT16_MIN, tmp, INT16_MAX);
412 buf[i] = (int16_t)tmp;
413 }
414 }
415
process_buffer_u32(uint32_t * buf,size_t size)416 static void process_buffer_u32(uint32_t *buf, size_t size)
417 {
418 size_t i;
419
420 debug ("mixing");
421
422 for(i=0; i<size; i++)
423 {
424 int64_t tmp = buf[i];
425 tmp -= (UINT32_MAX>>1);
426 tmp *= mixer_real;
427 tmp /= 100;
428 tmp += (UINT32_MAX>>1);
429 tmp = CLAMP(0, tmp, UINT32_MAX);
430 buf[i] = (uint32_t)tmp;
431 }
432 }
433
process_buffer_s32(int32_t * buf,size_t size)434 static void process_buffer_s32(int32_t *buf, size_t size)
435 {
436 size_t i;
437
438 debug ("mixing");
439
440 for(i=0; i<size; i++)
441 {
442 int64_t tmp = buf[i];
443 tmp *= mixer_real;
444 tmp /= 100;
445 tmp = CLAMP(INT32_MIN, tmp, INT32_MAX);
446 buf[i] = (int32_t)tmp;
447 }
448 }
449
process_buffer_float(float * buf,size_t size)450 static void process_buffer_float(float *buf, size_t size)
451 {
452 size_t i;
453
454 debug ("mixing");
455
456 for(i=0; i<size; i++)
457 {
458 float tmp = buf[i];
459 tmp *= mixer_realf;
460 tmp = CLAMP(-1.0f, tmp, 1.0f);
461 buf[i] = tmp;
462 }
463 }
464
465 // Mono-Mixing
mix_mono_u8(uint8_t * buf,int channels,size_t size)466 static void mix_mono_u8(uint8_t *buf, int channels, size_t size)
467 {
468 int c;
469 size_t i = 0;
470
471 debug ("making mono");
472
473 if(channels < 2)
474 return;
475
476 while(i < size)
477 {
478 int16_t mono = 0;
479
480 for(c=0; c<channels; c++)
481 mono += *buf++;
482
483 buf-=channels;
484
485 mono /= channels;
486 mono = MIN(mono, UINT8_MAX); // can't be negative
487
488 for(c=0; c<channels; c++)
489 *buf++ = (uint8_t)mono;
490
491 i+=channels;
492 }
493 }
494
mix_mono_s8(int8_t * buf,int channels,size_t size)495 static void mix_mono_s8(int8_t *buf, int channels, size_t size)
496 {
497 int c;
498 size_t i = 0;
499
500 debug ("making mono");
501
502 if(channels < 2)
503 return;
504
505 while(i < size)
506 {
507 int16_t mono = 0;
508
509 for(c=0; c<channels; c++)
510 mono += *buf++;
511
512 buf-=channels;
513
514 mono /= channels;
515 mono = CLAMP(INT8_MIN, mono, INT8_MAX);
516
517 for(c=0; c<channels; c++)
518 *buf++ = (int8_t)mono;
519
520 i+=channels;
521 }
522 }
523
mix_mono_u16(uint16_t * buf,int channels,size_t size)524 static void mix_mono_u16(uint16_t *buf, int channels, size_t size)
525 {
526 int c;
527 size_t i = 0;
528
529 debug ("making mono");
530
531 if(channels < 2)
532 return;
533
534 while(i < size)
535 {
536 int32_t mono = 0;
537
538 for(c=0; c<channels; c++)
539 mono += *buf++;
540
541 buf-=channels;
542
543 mono /= channels;
544 mono = MIN(mono, UINT16_MAX); // can't be negative
545
546 for(c=0; c<channels; c++)
547 *buf++ = (uint16_t)mono;
548
549 i+=channels;
550 }
551 }
552
mix_mono_s16(int16_t * buf,int channels,size_t size)553 static void mix_mono_s16(int16_t *buf, int channels, size_t size)
554 {
555 int c;
556 size_t i = 0;
557
558 debug ("making mono");
559
560 if(channels < 2)
561 return;
562
563 while(i < size)
564 {
565 int32_t mono = 0;
566
567 for(c=0; c<channels; c++)
568 mono += *buf++;
569
570 buf-=channels;
571
572 mono /= channels;
573 mono = CLAMP(INT16_MIN, mono, INT16_MAX);
574
575 for(c=0; c<channels; c++)
576 *buf++ = (int16_t)mono;
577
578 i+=channels;
579 }
580 }
581
mix_mono_u32(uint32_t * buf,int channels,size_t size)582 static void mix_mono_u32(uint32_t *buf, int channels, size_t size)
583 {
584 int c;
585 size_t i = 0;
586
587 debug ("making mono");
588
589 if(channels < 2)
590 return;
591
592 while(i < size)
593 {
594 int64_t mono = 0;
595
596 for(c=0; c<channels; c++)
597 mono += *buf++;
598
599 buf-=channels;
600
601 mono /= channels;
602 mono = MIN(mono, UINT32_MAX); // can't be negative
603
604 for(c=0; c<channels; c++)
605 *buf++ = (uint32_t)mono;
606
607 i+=channels;
608 }
609 }
610
mix_mono_s32(int32_t * buf,int channels,size_t size)611 static void mix_mono_s32(int32_t *buf, int channels, size_t size)
612 {
613 int c;
614 size_t i = 0;
615
616 debug ("making mono");
617
618 if(channels < 2)
619 return;
620
621 while(i < size)
622 {
623 int64_t mono = 0;
624
625 for(c=0; c<channels; c++)
626 mono += *buf++;
627
628 buf-=channels;
629
630 mono /= channels;
631 mono = CLAMP(INT32_MIN, mono, INT32_MAX);
632
633 for(c=0; c<channels; c++)
634 *buf++ = (int32_t)mono;
635
636 i+=channels;
637 }
638 }
639
mix_mono_float(float * buf,int channels,size_t size)640 static void mix_mono_float(float *buf, int channels, size_t size)
641 {
642 int c;
643 size_t i = 0;
644
645 debug ("making mono");
646
647 if(channels < 2)
648 return;
649
650 while(i < size)
651 {
652 float mono = 0.0f;
653
654 for(c=0; c<channels; c++)
655 mono += *buf++;
656
657 buf-=channels;
658
659 mono /= channels;
660 mono = CLAMP(-1.0f, mono, 1.0f);
661
662 for(c=0; c<channels; c++)
663 *buf++ = mono;
664
665 i+=channels;
666 }
667 }
668