1 /*
2  *  Copyright (C) 2002-2013  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU Library General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 
20 # include <stdlib.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <math.h>
24 
25 #if defined (WIN32)
26 //Midi listing
27 #ifndef WIN32_LEAN_AND_MEAN
28 #define WIN32_LEAN_AND_MEAN
29 #endif
30 #include <windows.h>
31 #include <mmsystem.h>
32 #endif
33 
34 #include "mem.h"
35 #include "pic.h"
36 #include "dosbox.h"
37 #include "mixer.h"
38 #include "timer.h"
39 #include "setup.h"
40 #include "cross.h"
41 #include "support.h"
42 #include "mapper.h"
43 #include "hardware.h"
44 #include "programs.h"
45 
46 #define MIXER_SSIZE 4
47 #define MIXER_SHIFT 14
48 #define MIXER_REMAIN ((1<<MIXER_SHIFT)-1)
49 #define MIXER_VOLSHIFT 13
50 
MIXER_CLIP(Bits SAMP)51 static INLINE Bit16s MIXER_CLIP(Bits SAMP)
52 {
53 	if (SAMP < MAX_AUDIO)
54    {
55       if (SAMP > MIN_AUDIO)
56          return SAMP;
57       return MIN_AUDIO;
58    }
59    return MAX_AUDIO;
60 }
61 
62 static struct {
63 	Bit32s work[MIXER_BUFSIZE][2];
64 	Bitu pos,done;
65 	Bitu needed, min_needed, max_needed;
66 	Bit32u tick_add,tick_remain;
67 	float mastervol[2];
68 	MixerChannel * channels;
69 	bool nosound;
70 	Bit32u freq;
71 	Bit32u blocksize;
72 } mixer;
73 
74 Bit8u MixTemp[MIXER_BUFSIZE];
75 
MIXER_AddChannel(MIXER_Handler handler,Bitu freq,const char * name)76 MixerChannel * MIXER_AddChannel(MIXER_Handler handler,Bitu freq,const char * name)
77 {
78 	MixerChannel * chan=new MixerChannel();
79 
80    if (!chan)
81       return NULL;
82 
83 	chan->scale = 1.0;
84 	chan->handler=handler;
85 	chan->name=name;
86 	chan->SetFreq(freq);
87 	chan->next=mixer.channels;
88 	chan->SetVolume(1,1);
89 	chan->enabled=false;
90 	mixer.channels=chan;
91 	return chan;
92 }
93 
MIXER_FindChannel(const char * name)94 MixerChannel * MIXER_FindChannel(const char * name)
95 {
96 	MixerChannel * chan=mixer.channels;
97 	while (chan)
98    {
99 		if (!strcasecmp(chan->name,name))
100          break;
101 		chan=chan->next;
102 	}
103 	return chan;
104 }
105 
MIXER_DelChannel(MixerChannel * delchan)106 void MIXER_DelChannel(MixerChannel* delchan)
107 {
108 	MixerChannel * chan=mixer.channels;
109 	MixerChannel * * where=&mixer.channels;
110 	while (chan)
111    {
112 		if (chan==delchan)
113       {
114 			*where=chan->next;
115 			delete delchan;
116 			return;
117 		}
118 		where=&chan->next;
119 		chan=chan->next;
120 	}
121 }
122 
UpdateVolume(void)123 void MixerChannel::UpdateVolume(void)
124 {
125 	volmul[0]=(Bits)((1 << MIXER_VOLSHIFT)*scale*volmain[0]*mixer.mastervol[0]);
126 	volmul[1]=(Bits)((1 << MIXER_VOLSHIFT)*scale*volmain[1]*mixer.mastervol[1]);
127 }
128 
SetVolume(float _left,float _right)129 void MixerChannel::SetVolume(float _left,float _right)
130 {
131 	volmain[0]=_left;
132 	volmain[1]=_right;
133 	UpdateVolume();
134 }
135 
SetScale(float f)136 void MixerChannel::SetScale( float f )
137 {
138 	scale = f;
139 	UpdateVolume();
140 }
141 
Enable(bool _yesno)142 void MixerChannel::Enable(bool _yesno)
143 {
144 	if (_yesno==enabled) return;
145 	enabled=_yesno;
146 	if (enabled)
147    {
148 		freq_index=MIXER_REMAIN;
149 		if (done<mixer.done)
150          done=mixer.done;
151 	}
152 }
153 
SetFreq(Bitu _freq)154 void MixerChannel::SetFreq(Bitu _freq)
155 {
156 	freq_add=(_freq<<MIXER_SHIFT)/mixer.freq;
157 }
158 
Mix(Bitu _needed)159 void MixerChannel::Mix(Bitu _needed)
160 {
161 	needed=_needed;
162 	while (enabled && needed>done)
163    {
164 		Bitu todo=needed-done;
165 		todo *= freq_add;
166 		todo  = (todo >> MIXER_SHIFT) + ((todo & MIXER_REMAIN)!=0);
167 		handler(todo);
168 	}
169 }
170 
AddSilence(void)171 void MixerChannel::AddSilence(void)
172 {
173 	if (done<needed)
174    {
175 		done=needed;
176 		last[0]=last[1]=0;
177 		freq_index=MIXER_REMAIN;
178 	}
179 }
180 
181 template<class Type,bool stereo,bool signeddata,bool nativeorder>
AddSamples(Bitu len,const Type * data)182 inline void MixerChannel::AddSamples(Bitu len, const Type* data)
183 {
184    Bits diff[2];
185    Bitu mixpos=mixer.pos+done;
186    freq_index&=MIXER_REMAIN;
187    Bitu pos=0;Bitu new_pos;
188 
189    goto thestart;
190    for (;;)
191    {
192       new_pos=freq_index >> MIXER_SHIFT;
193       if (pos<new_pos)
194       {
195          last[0]+=diff[0];
196          if (stereo) last[1]+=diff[1];
197          pos=new_pos;
198 thestart:
199          if (pos>=len)
200             return;
201 
202          if ( sizeof( Type) == 1)
203          {
204             if (!signeddata)
205             {
206                if (stereo)
207                {
208                   diff[0]=(((Bit8s)(data[pos*2+0] ^ 0x80)) << 8)-last[0];
209                   diff[1]=(((Bit8s)(data[pos*2+1] ^ 0x80)) << 8)-last[1];
210                }
211                else
212                   diff[0]=(((Bit8s)(data[pos] ^ 0x80)) << 8)-last[0];
213             }
214             else
215             {
216                if (stereo)
217                {
218                   diff[0]=(data[pos*2+0] << 8)-last[0];
219                   diff[1]=(data[pos*2+1] << 8)-last[1];
220                }
221                else
222                   diff[0]=(data[pos] << 8)-last[0];
223             }
224             //16bit and 32bit both contain 16bit data internally
225          }
226          else
227          {
228             if (signeddata)
229             {
230                if (stereo)
231                {
232                   if (nativeorder)
233                   {
234                      diff[0]=data[pos*2+0]-last[0];
235                      diff[1]=data[pos*2+1]-last[1];
236                   }
237                   else
238                   {
239                      if ( sizeof( Type) == 2)
240                      {
241                         diff[0]=(Bit16s)host_readw((HostPt)&data[pos*2+0])-last[0];
242                         diff[1]=(Bit16s)host_readw((HostPt)&data[pos*2+1])-last[1];
243                      }
244                      else
245                      {
246                         diff[0]=(Bit32s)host_readd((HostPt)&data[pos*2+0])-last[0];
247                         diff[1]=(Bit32s)host_readd((HostPt)&data[pos*2+1])-last[1];
248                      }
249                   }
250                } else {
251                   if (nativeorder)
252                      diff[0]=data[pos]-last[0];
253                   else
254                   {
255                      if ( sizeof( Type) == 2)
256                         diff[0]=(Bit16s)host_readw((HostPt)&data[pos])-last[0];
257                      else
258                         diff[0]=(Bit32s)host_readd((HostPt)&data[pos])-last[0];
259                   }
260                }
261             } else {
262                if (stereo)
263                {
264                   if (nativeorder)
265                   {
266                      diff[0]=(Bits)data[pos*2+0]-32768-last[0];
267                      diff[1]=(Bits)data[pos*2+1]-32768-last[1];
268                   }
269                   else
270                   {
271                      if ( sizeof( Type) == 2)
272                      {
273                         diff[0]=(Bits)host_readw((HostPt)&data[pos*2+0])-32768-last[0];
274                         diff[1]=(Bits)host_readw((HostPt)&data[pos*2+1])-32768-last[1];
275                      }
276                      else
277                      {
278                         diff[0]=(Bits)host_readd((HostPt)&data[pos*2+0])-32768-last[0];
279                         diff[1]=(Bits)host_readd((HostPt)&data[pos*2+1])-32768-last[1];
280                      }
281                   }
282                }
283                else
284                {
285                   if (nativeorder)
286                      diff[0]=(Bits)data[pos]-32768-last[0];
287                   else
288                   {
289                      if ( sizeof( Type) == 2)
290                         diff[0]=(Bits)host_readw((HostPt)&data[pos])-32768-last[0];
291                      else
292                         diff[0]=(Bits)host_readd((HostPt)&data[pos])-32768-last[0];
293                   }
294                }
295             }
296          }
297       }
298       Bits diff_mul=freq_index & MIXER_REMAIN;
299       freq_index+=freq_add;
300       mixpos&=MIXER_BUFMASK;
301       Bits sample=last[0]+((diff[0]*diff_mul) >> MIXER_SHIFT);
302       mixer.work[mixpos][0]+=sample*volmul[0];
303       if (stereo)
304          sample = last[1] + ((diff[1]*diff_mul) >> MIXER_SHIFT);
305       mixer.work[mixpos][1]+=sample*volmul[1];
306       mixpos++;done++;
307    }
308 }
309 
AddStretched(Bitu len,Bit16s * data)310 void MixerChannel::AddStretched(Bitu len,Bit16s * data)
311 {
312 	if (done>=needed)
313    {
314 		LOG_MSG("Can't add, buffer full");
315 		return;
316 	}
317 	Bitu outlen=needed-done;Bits diff;
318 	freq_index=0;
319 	Bitu temp_add=(len << MIXER_SHIFT)/outlen;
320 	Bitu mixpos=mixer.pos+done;done=needed;
321 	Bitu pos=0;
322 	diff=data[0]-last[0];
323 	while (outlen--)
324    {
325 		Bitu new_pos=freq_index >> MIXER_SHIFT;
326 		if (pos<new_pos)
327       {
328 			pos=new_pos;
329 			last[0]+=diff;
330 			diff=data[pos]-last[0];
331 		}
332 		Bits diff_mul=freq_index & MIXER_REMAIN;
333 		freq_index+=temp_add;
334 		mixpos&=MIXER_BUFMASK;
335 		Bits sample=last[0]+((diff*diff_mul) >> MIXER_SHIFT);
336 		mixer.work[mixpos][0]+=sample*volmul[0];
337 		mixer.work[mixpos][1]+=sample*volmul[1];
338 		mixpos++;
339 	}
340 }
341 
AddSamples_m8(Bitu len,const Bit8u * data)342 void MixerChannel::AddSamples_m8(Bitu len, const Bit8u * data) {
343 	AddSamples<Bit8u,false,false,true>(len,data);
344 }
AddSamples_s8(Bitu len,const Bit8u * data)345 void MixerChannel::AddSamples_s8(Bitu len,const Bit8u * data) {
346 	AddSamples<Bit8u,true,false,true>(len,data);
347 }
AddSamples_m8s(Bitu len,const Bit8s * data)348 void MixerChannel::AddSamples_m8s(Bitu len,const Bit8s * data) {
349 	AddSamples<Bit8s,false,true,true>(len,data);
350 }
AddSamples_s8s(Bitu len,const Bit8s * data)351 void MixerChannel::AddSamples_s8s(Bitu len,const Bit8s * data) {
352 	AddSamples<Bit8s,true,true,true>(len,data);
353 }
AddSamples_m16(Bitu len,const Bit16s * data)354 void MixerChannel::AddSamples_m16(Bitu len,const Bit16s * data) {
355 	AddSamples<Bit16s,false,true,true>(len,data);
356 }
AddSamples_s16(Bitu len,const Bit16s * data)357 void MixerChannel::AddSamples_s16(Bitu len,const Bit16s * data) {
358 	AddSamples<Bit16s,true,true,true>(len,data);
359 }
AddSamples_m16u(Bitu len,const Bit16u * data)360 void MixerChannel::AddSamples_m16u(Bitu len,const Bit16u * data) {
361 	AddSamples<Bit16u,false,false,true>(len,data);
362 }
AddSamples_s16u(Bitu len,const Bit16u * data)363 void MixerChannel::AddSamples_s16u(Bitu len,const Bit16u * data) {
364 	AddSamples<Bit16u,true,false,true>(len,data);
365 }
AddSamples_m32(Bitu len,const Bit32s * data)366 void MixerChannel::AddSamples_m32(Bitu len,const Bit32s * data) {
367 	AddSamples<Bit32s,false,true,true>(len,data);
368 }
AddSamples_s32(Bitu len,const Bit32s * data)369 void MixerChannel::AddSamples_s32(Bitu len,const Bit32s * data) {
370 	AddSamples<Bit32s,true,true,true>(len,data);
371 }
AddSamples_m16_nonnative(Bitu len,const Bit16s * data)372 void MixerChannel::AddSamples_m16_nonnative(Bitu len,const Bit16s * data) {
373 	AddSamples<Bit16s,false,true,false>(len,data);
374 }
AddSamples_s16_nonnative(Bitu len,const Bit16s * data)375 void MixerChannel::AddSamples_s16_nonnative(Bitu len,const Bit16s * data) {
376 	AddSamples<Bit16s,true,true,false>(len,data);
377 }
AddSamples_m16u_nonnative(Bitu len,const Bit16u * data)378 void MixerChannel::AddSamples_m16u_nonnative(Bitu len,const Bit16u * data) {
379 	AddSamples<Bit16u,false,false,false>(len,data);
380 }
AddSamples_s16u_nonnative(Bitu len,const Bit16u * data)381 void MixerChannel::AddSamples_s16u_nonnative(Bitu len,const Bit16u * data) {
382 	AddSamples<Bit16u,true,false,false>(len,data);
383 }
AddSamples_m32_nonnative(Bitu len,const Bit32s * data)384 void MixerChannel::AddSamples_m32_nonnative(Bitu len,const Bit32s * data) {
385 	AddSamples<Bit32s,false,true,false>(len,data);
386 }
AddSamples_s32_nonnative(Bitu len,const Bit32s * data)387 void MixerChannel::AddSamples_s32_nonnative(Bitu len,const Bit32s * data) {
388 	AddSamples<Bit32s,true,true,false>(len,data);
389 }
390 
FillUp(void)391 void MixerChannel::FillUp(void)
392 {
393 	if (!enabled || done<mixer.done)
394 		return;
395 	float index=PIC_TickIndex();
396 	Mix((Bitu)(index*mixer.needed));
397 }
398 
399 extern bool ticksLocked;
400 
401 /* In some states correct timing of the irqs is more important then
402  * non stuttering audo */
403 
Mixer_irq_important(void)404 static inline bool Mixer_irq_important(void)
405 {
406 	return ticksLocked;
407 }
408 
409 /* Mix a certain amount of new samples */
MIXER_MixData(Bitu needed)410 static void MIXER_MixData(Bitu needed)
411 {
412 	MixerChannel * chan=mixer.channels;
413 	while (chan)
414    {
415 		chan->Mix(needed);
416 		chan=chan->next;
417 	}
418 	//Reset the the tick_add for constant speed
419 	if( Mixer_irq_important() )
420 		mixer.tick_add = ((mixer.freq) << MIXER_SHIFT)/1000;
421 	mixer.done = needed;
422 }
423 
MIXER_Mix(void)424 static void MIXER_Mix(void)
425 {
426 	MIXER_MixData(mixer.needed);
427 	mixer.tick_remain+=mixer.tick_add;
428 	mixer.needed+=(mixer.tick_remain>>MIXER_SHIFT);
429 	mixer.tick_remain&=MIXER_REMAIN;
430 }
431 
MIXER_Mix_NoSound(void)432 static void MIXER_Mix_NoSound(void)
433 {
434 	MIXER_MixData(mixer.needed);
435 	/* Clear piece we've just generated */
436 	for (Bitu i=0;i<mixer.needed;i++)
437    {
438 		mixer.work[mixer.pos][0]=0;
439 		mixer.work[mixer.pos][1]=0;
440 		mixer.pos=(mixer.pos+1)&MIXER_BUFMASK;
441 	}
442 	/* Reduce count in channels */
443 	for (MixerChannel * chan=mixer.channels;chan;chan=chan->next)
444    {
445 		if (chan->done>mixer.needed)
446          chan->done-=mixer.needed;
447 		else
448          chan->done=0;
449 	}
450 	/* Set values for next tick */
451 	mixer.tick_remain+=mixer.tick_add;
452 	mixer.needed=mixer.tick_remain>>MIXER_SHIFT;
453 	mixer.tick_remain&=MIXER_REMAIN;
454 	mixer.done=0;
455 }
456 
MIXER_CallBack(void * userdata,Uint8 * stream,int len)457 void MIXER_CallBack(void * userdata, Uint8 *stream, int len)
458 {
459 	Bitu need=(Bitu)len/MIXER_SSIZE;
460 	Bit16s * output=(Bit16s *)stream;
461 	Bitu reduce;
462 	Bitu pos, index, index_add;
463 	Bits sample;
464 
465 	/* Enough room in the buffer ? */
466 	if (mixer.done < need)
467    {
468       //		LOG_MSG("Full underrun need %d, have %d, min %d", need, mixer.done, mixer.min_needed);
469       if((need - mixer.done) > (need >>7) ) //Max 1 procent stretch.
470          return;
471       reduce = mixer.done;
472       index_add = (reduce << MIXER_SHIFT) / need;
473       mixer.tick_add = ((mixer.freq+mixer.min_needed) << MIXER_SHIFT)/1000;
474    }
475    else if (mixer.done < mixer.max_needed)
476    {
477       Bitu left = mixer.done - need;
478       if (left < mixer.min_needed)
479       {
480          if( !Mixer_irq_important() )
481          {
482             Bitu needed = mixer.needed - need;
483             Bitu diff = (mixer.min_needed>needed?mixer.min_needed:needed) - left;
484             mixer.tick_add = ((mixer.freq+(diff*3)) << MIXER_SHIFT)/1000;
485             left = 0; //No stretching as we compensate with the tick_add value
486          }
487          else
488          {
489             left = (mixer.min_needed - left);
490             left = 1 + (2*left) / mixer.min_needed; //left=1,2,3
491          }
492          //			LOG_MSG("needed underrun need %d, have %d, min %d, left %d", need, mixer.done, mixer.min_needed, left);
493          reduce = need - left;
494          index_add = (reduce << MIXER_SHIFT) / need;
495       }
496       else
497       {
498          reduce = need;
499          index_add = (1 << MIXER_SHIFT);
500          //			LOG_MSG("regular run need %d, have %d, min %d, left %d", need, mixer.done, mixer.min_needed, left);
501 
502          /* Mixer tick value being updated:
503           * 3 cases:
504           * 1) A lot too high. >division by 5. but maxed by 2* min to prevent too fast drops.
505           * 2) A little too high > division by 8
506           * 3) A little to nothing above the min_needed buffer > go to default value
507           */
508          Bitu diff = left - mixer.min_needed;
509          if(diff > (mixer.min_needed<<1)) diff = mixer.min_needed<<1;
510          if(diff > (mixer.min_needed>>1))
511             mixer.tick_add = ((mixer.freq-(diff/5)) << MIXER_SHIFT)/1000;
512          else if (diff > (mixer.min_needed>>4))
513             mixer.tick_add = ((mixer.freq-(diff>>3)) << MIXER_SHIFT)/1000;
514          else
515             mixer.tick_add = (mixer.freq<< MIXER_SHIFT)/1000;
516       }
517    }
518    else
519    {
520       /* There is way too much data in the buffer */
521       //		LOG_MSG("overflow run need %d, have %d, min %d", need, mixer.done, mixer.min_needed);
522       if (mixer.done > MIXER_BUFSIZE)
523          index_add = MIXER_BUFSIZE - 2*mixer.min_needed;
524       else
525          index_add = mixer.done - 2*mixer.min_needed;
526       index_add = (index_add << MIXER_SHIFT) / need;
527       reduce = mixer.done - 2* mixer.min_needed;
528       mixer.tick_add = ((mixer.freq-(mixer.min_needed/5)) << MIXER_SHIFT)/1000;
529    }
530 
531 	/* Reduce done count in all channels */
532 	for (MixerChannel * chan=mixer.channels;chan;chan=chan->next)
533    {
534 		if (chan->done>reduce)
535          chan->done-=reduce;
536 		else chan->done=0;
537 	}
538 
539 	// Reset mixer.tick_add when irqs are important
540 	if( Mixer_irq_important() )
541 		mixer.tick_add=(mixer.freq<< MIXER_SHIFT)/1000;
542 
543 	mixer.done -= reduce;
544 	mixer.needed -= reduce;
545 	pos = mixer.pos;
546 	mixer.pos = (mixer.pos + reduce) & MIXER_BUFMASK;
547 	index = 0;
548 	if(need != reduce)
549    {
550       while (need--)
551       {
552          Bitu i = (pos + (index >> MIXER_SHIFT )) & MIXER_BUFMASK;
553          index += index_add;
554          sample=mixer.work[i][0]>>MIXER_VOLSHIFT;
555          *output++=MIXER_CLIP(sample);
556          sample=mixer.work[i][1]>>MIXER_VOLSHIFT;
557          *output++=MIXER_CLIP(sample);
558       }
559 
560       /* Clean the used buffer */
561       while (reduce--)
562       {
563          pos &= MIXER_BUFMASK;
564          mixer.work[pos][0]=0;
565          mixer.work[pos][1]=0;
566          pos++;
567       }
568    }
569    else
570    {
571 		while (reduce--)
572       {
573          pos &= MIXER_BUFMASK;
574          sample=mixer.work[pos][0]>>MIXER_VOLSHIFT;
575          *output++=MIXER_CLIP(sample);
576          sample=mixer.work[pos][1]>>MIXER_VOLSHIFT;
577          *output++=MIXER_CLIP(sample);
578          mixer.work[pos][0]=0;
579          mixer.work[pos][1]=0;
580          pos++;
581       }
582 	}
583 }
584 
MIXER_Stop(Section * sec)585 static void MIXER_Stop(Section* sec)
586 {
587 }
588 
589 class MIXER : public Program {
590 public:
MakeVolume(char * scan,float & vol0,float & vol1)591 	void MakeVolume(char * scan,float & vol0,float & vol1)
592    {
593       Bitu w=0;
594       bool db=(toupper(*scan)=='D');
595       if (db) scan++;
596       while (*scan)
597       {
598          if (*scan==':')
599             ++scan;w=1;
600          char * before=scan;
601          float val=(float)strtod(scan,&scan);
602          if (before==scan)
603          {
604             ++scan;
605             continue;
606          }
607          if (!db)
608             val/=100;
609          else
610             val=powf(10.0f,(float)val/20.0f);
611          if (val<0)
612             val=1.0f;
613          if (!w)
614             vol0=val;
615          else
616             vol1=val;
617       }
618       if (!w) vol1=vol0;
619    }
620 
Run(void)621 	void Run(void)
622    {
623       if(cmd->FindExist("/LISTMIDI"))
624       {
625          ListMidi();
626          return;
627       }
628       if (cmd->FindString("MASTER",temp_line,false))
629          MakeVolume((char *)temp_line.c_str(),mixer.mastervol[0],mixer.mastervol[1]);
630       MixerChannel * chan=mixer.channels;
631       while (chan)
632       {
633          if (cmd->FindString(chan->name,temp_line,false))
634             MakeVolume((char *)temp_line.c_str(),chan->volmain[0],chan->volmain[1]);
635          chan->UpdateVolume();
636          chan=chan->next;
637       }
638       if (cmd->FindExist("/NOSHOW"))
639          return;
640       chan=mixer.channels;
641       WriteOut("Channel  Main    Main(dB)\n");
642       ShowVolume("MASTER",mixer.mastervol[0],mixer.mastervol[1]);
643       for (chan=mixer.channels;chan;chan=chan->next)
644          ShowVolume(chan->name,chan->volmain[0],chan->volmain[1]);
645    }
646 private:
ShowVolume(const char * name,float vol0,float vol1)647 	void ShowVolume(const char * name,float vol0,float vol1)
648    {
649       WriteOut("%-8s %3.0f:%-3.0f  %+3.2f:%-+3.2f \n",name,
650             vol0*100,vol1*100,
651             20*log(vol0)/log(10.0f),20*log(vol1)/log(10.0f)
652             );
653    }
654 
ListMidi()655 	void ListMidi(){
656 #if defined (WIN32)
657 		unsigned int total = midiOutGetNumDevs();
658 		for(unsigned int i=0;i<total;i++)
659       {
660 			MIDIOUTCAPS mididev;
661 			midiOutGetDevCaps(i, &mididev, sizeof(MIDIOUTCAPS));
662 			WriteOut("%2d\t \"%s\"\n",i,mididev.szPname);
663 		}
664 #endif
665 	return;
666 	};
667 
668 };
669 
MIXER_ProgramStart(Program ** make)670 static void MIXER_ProgramStart(Program * * make)
671 {
672 	*make=new MIXER;
673 }
674 
Install(MIXER_Handler handler,Bitu freq,const char * name)675 MixerChannel* MixerObject::Install(MIXER_Handler handler,Bitu freq,const char * name){
676 	if(!installed)
677    {
678       if(strlen(name) > 31) E_Exit("Too long mixer channel name");
679       safe_strncpy(m_name,name,32);
680       installed = true;
681       return MIXER_AddChannel(handler,freq,name);
682    }
683    else
684    {
685 		E_Exit("already added mixer channel.");
686 		return 0; //Compiler happy
687 	}
688 }
689 
~MixerObject()690 MixerObject::~MixerObject()
691 {
692 	if(!installed)
693       return;
694 	MIXER_DelChannel(MIXER_FindChannel(m_name));
695 }
696 
697 
MIXER_Init(Section * sec)698 void MIXER_Init(Section* sec)
699 {
700    sec->AddDestroyFunction(&MIXER_Stop);
701 
702    Section_prop * section=static_cast<Section_prop *>(sec);
703    /* Read out config section */
704    mixer.freq=section->Get_int("rate");
705    mixer.nosound=section->Get_bool("nosound");
706    mixer.blocksize=section->Get_int("blocksize");
707 
708    /* Initialize the internal stuff */
709    mixer.channels=0;
710    mixer.pos=0;
711    mixer.done=0;
712    memset(mixer.work,0,sizeof(mixer.work));
713    mixer.mastervol[0]=1.0f;
714    mixer.mastervol[1]=1.0f;
715 
716    mixer.tick_remain=0;
717    if (mixer.nosound || mixer.freq > 49716)
718    {
719       LOG_MSG("MIXER:No Sound Mode Selected.");
720       mixer.tick_add=((mixer.freq) << MIXER_SHIFT)/1000;
721       TIMER_AddTickHandler(MIXER_Mix_NoSound);
722    }
723    else
724    {
725       mixer.tick_add=(mixer.freq << MIXER_SHIFT)/1000;
726       TIMER_AddTickHandler(MIXER_Mix);
727    }
728    mixer.min_needed=section->Get_int("prebuffer");
729    if (mixer.min_needed>100) mixer.min_needed=100;
730    mixer.min_needed=(mixer.freq*mixer.min_needed)/1000;
731    mixer.max_needed=mixer.blocksize * 2 + 2*mixer.min_needed;
732    mixer.needed=mixer.min_needed+1;
733    PROGRAMS_MakeFile("MIXER.COM",MIXER_ProgramStart);
734 }
735 
736 // Need to put it in the av_info struct
MIXER_RETRO_GetFrequency()737 Bit32u MIXER_RETRO_GetFrequency()
738 {
739     return mixer.freq;
740 }
741 
742