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