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