DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 /* 00021 Remove the sdl code from here and have it handeld in the sdlmain. 00022 That should call the mixer start from there or something. 00023 */ 00024 00025 #include <string.h> 00026 #include <sys/types.h> 00027 #define _USE_MATH_DEFINES // needed for M_PI in Visual Studio as documented [https://msdn.microsoft.com/en-us/library/4hwaceh6.aspx] 00028 #include <math.h> 00029 00030 #if defined(_MSC_VER) 00031 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */ 00032 #endif 00033 00034 #if defined (WIN32) 00035 //Midi listing 00036 #ifndef WIN32_LEAN_AND_MEAN 00037 #define WIN32_LEAN_AND_MEAN 00038 #endif 00039 #include <windows.h> 00040 #include <mmsystem.h> 00041 #endif 00042 00043 #if !defined(M_PI) 00044 # define M_PI (3.141592654) 00045 #endif 00046 00047 #include "SDL.h" 00048 #include "mem.h" 00049 #include "pic.h" 00050 #include "dosbox.h" 00051 #include "mixer.h" 00052 #include "timer.h" 00053 #include "setup.h" 00054 #include "cross.h" 00055 #include "support.h" 00056 #include "control.h" 00057 #include "mapper.h" 00058 #include "hardware.h" 00059 #include "programs.h" 00060 #include "midi.h" 00061 00062 #define MIXER_SSIZE 4 00063 #define MIXER_VOLSHIFT 13 00064 00065 static INLINE Bit16s MIXER_CLIP(Bits SAMP) { 00066 if (SAMP < MAX_AUDIO) { 00067 if (SAMP > MIN_AUDIO) 00068 return SAMP; 00069 else 00070 return MIN_AUDIO; 00071 } else { 00072 return MAX_AUDIO; 00073 } 00074 } 00075 00076 struct mixedFraction { 00077 unsigned int w; 00078 unsigned int fn,fd; 00079 }; 00080 00081 static struct { 00082 Bit32s work[MIXER_BUFSIZE][2]; 00083 Bitu work_in,work_out,work_wrap; 00084 Bitu pos,done; 00085 float mastervol[2]; 00086 float recordvol[2]; 00087 MixerChannel* channels; 00088 Bit32u freq; 00089 Bit32u blocksize; 00090 struct mixedFraction samples_per_ms; 00091 struct mixedFraction samples_this_ms; 00092 struct mixedFraction samples_rendered_ms; 00093 bool nosound; 00094 bool swapstereo; 00095 bool sampleaccurate; 00096 bool prebuffer_wait; 00097 Bitu prebuffer_samples; 00098 bool mute; 00099 } mixer; 00100 00101 uint32_t Mixer_MIXQ(void) { 00102 return ((uint32_t)mixer.freq) | 00103 ((uint32_t)2u/*channels*/ << (uint32_t)20u) | 00104 (mixer.swapstereo ? ((uint32_t)1u << (uint32_t)29u) : 0u) | 00105 (mixer.mute ? ((uint32_t)1u << (uint32_t)30u) : 0u) | 00106 (mixer.nosound ? 0u : ((uint32_t)1u << (uint32_t)31u)); 00107 } 00108 00109 PhysPt mixer_capture_write = 0; 00110 PhysPt mixer_capture_write_begin = 0; 00111 PhysPt mixer_capture_write_end = 0; 00112 uint32_t mixer_control = 0; 00113 00114 // mixer capture source bits [23:16] 00115 enum { 00116 MIXER_SRC_MIXDOWN=0 00117 }; 00118 00119 unsigned int Mixer_MIXC_Source(void) { 00120 return (unsigned int)((mixer_control >> 16ul) & 0xFFul); 00121 } 00122 00123 bool Mixer_MIXC_Active(void) { 00124 return ((mixer_control & 3u) == 3u)/*capture interface enable|write to memory*/; 00125 } 00126 00127 bool Mixer_MIXC_Error(void) { 00128 return ((mixer_control & 8u) == 8u); 00129 } 00130 00131 bool Mixer_MIXC_ShouldLoop(void) { 00132 return ((mixer_control & 4u) == 4u); 00133 } 00134 00135 void Mixer_MIXC_Stop(void) { 00136 mixer_control &= ~1u; // clear enable 00137 } 00138 00139 void Mixer_MIXC_LoopAround(void) { 00140 mixer_capture_write = mixer_capture_write_begin; 00141 } 00142 00143 // NTS: Check AFTER writing sample 00144 bool Mixer_MIXC_AtEnd(void) { 00145 return (mixer_capture_write >= mixer_capture_write_end); 00146 } 00147 00148 void Mixer_MIXC_MarkError(void) { 00149 mixer_control &= ~1u; // clear enable 00150 mixer_control |= 8u; // set error 00151 } 00152 00153 PhysPt Mixer_MIXWritePos(void) { 00154 return mixer_capture_write; 00155 } 00156 00157 void Mixer_MIXWritePos_Write(PhysPt np) { 00158 if (!Mixer_MIXC_Active()) 00159 mixer_capture_write = np; 00160 } 00161 00162 void Mixer_MIXWriteBegin_Write(PhysPt np) { 00163 if (!Mixer_MIXC_Active()) 00164 mixer_capture_write_begin = np; 00165 } 00166 00167 void Mixer_MIXWriteEnd_Write(PhysPt np) { 00168 if (!Mixer_MIXC_Active()) 00169 mixer_capture_write_end = np; 00170 } 00171 00172 void Mixer_MIXC_Validate(void) { 00173 if (Mixer_MIXC_Active()) { 00174 // NTS: phys_writew() will cause a segfault if the address is beyond the end of memory, 00175 // because it computes MemBase+addr 00176 PhysPt MemMax = (PhysPt)MEM_TotalPages() * (PhysPt)4096ul; 00177 00178 if (Mixer_MIXC_Error() || 00179 Mixer_MIXC_Source() != 0x00 || 00180 mixer_capture_write == 0 || mixer_capture_write_begin == 0 || mixer_capture_write_end == 0 || 00181 mixer_capture_write < mixer_capture_write_begin || 00182 mixer_capture_write > mixer_capture_write_end || 00183 mixer_capture_write_begin > mixer_capture_write_end || 00184 mixer_capture_write >= MemMax || 00185 mixer_capture_write_end >= MemMax || 00186 mixer_capture_write_begin >= MemMax) 00187 Mixer_MIXC_MarkError(); 00188 } 00189 } 00190 00191 uint32_t Mixer_MIXC(void) { 00192 return mixer_control; 00193 } 00194 00195 void Mixer_MIXC_Write(uint32_t v) { 00196 /* bit [0:0] = enable capture interface 00197 * bit [1:1] = enable writing to memory 00198 * bit [2:2] = enable loop around, when write == write_end, set write == write_begin 00199 * bit [3:3] = 1=error condition 0=no error 00200 * bit [23:16] = source selection (see list) */ 00201 if (mixer_control != v) { 00202 mixer_control = (v & 0x00FF00FFUL); 00203 Mixer_MIXC_Validate(); 00204 } 00205 } 00206 00207 bool Mixer_SampleAccurate() { 00208 return mixer.sampleaccurate; 00209 } 00210 00211 Bit8u MixTemp[MIXER_BUFSIZE]; 00212 00213 inline void MixerChannel::updateSlew(void) { 00214 /* "slew" affects the linear interpolation ramp. 00215 * but, our implementation can only shorten the linear interpolation 00216 * period, it cannot extend it beyond one sample period */ 00217 freq_nslew = freq_nslew_want; 00218 if (freq_nslew < freq_n) freq_nslew = freq_n; 00219 00220 if (freq_nslew_want > 0 && freq_nslew_want < freq_n) 00221 max_change = ((Bit64u)freq_nslew_want * (Bit64u)0x8000) / (Bit64u)freq_n; 00222 else 00223 max_change = 0x7FFFFFFFUL; 00224 } 00225 00226 MixerChannel * MIXER_AddChannel(MIXER_Handler handler,Bitu freq,const char * name) { 00227 MixerChannel * chan=new MixerChannel(); 00228 chan->freq_fslew = 0; 00229 chan->freq_nslew_want = 0; 00230 chan->freq_nslew = 0; 00231 chan->last_sample_write = 0; 00232 chan->current_loaded = false; 00233 chan->handler=handler; 00234 chan->name=name; 00235 chan->msbuffer_i = 0; 00236 chan->msbuffer_o = 0; 00237 chan->freq_n = chan->freq_d = 1; 00238 chan->lowpass_freq = 0; 00239 chan->lowpass_alpha = 0; 00240 00241 for (unsigned int i=0;i < LOWPASS_ORDER;i++) { 00242 for (unsigned int j=0;j < 2;j++) 00243 chan->lowpass[i][j] = 0; 00244 } 00245 00246 chan->lowpass_on_load = false; 00247 chan->lowpass_on_out = false; 00248 chan->freq_d_orig = 1; 00249 chan->freq_f = 0; 00250 chan->SetFreq(freq); 00251 chan->next=mixer.channels; 00252 chan->SetScale(1.0); 00253 chan->SetVolume(1,1); 00254 chan->enabled=false; 00255 chan->last[0] = chan->last[1] = 0; 00256 chan->delta[0] = chan->delta[1] = 0; 00257 chan->current[0] = chan->current[1] = 0; 00258 00259 mixer.channels=chan; 00260 return chan; 00261 } 00262 00263 MixerChannel * MIXER_FirstChannel(void) { 00264 return mixer.channels; 00265 } 00266 00267 MixerChannel * MIXER_FindChannel(const char * name) { 00268 MixerChannel * chan=mixer.channels; 00269 while (chan) { 00270 if (!strcasecmp(chan->name,name)) break; 00271 chan=chan->next; 00272 } 00273 return chan; 00274 } 00275 00276 void MIXER_DelChannel(MixerChannel* delchan) { 00277 MixerChannel * chan=mixer.channels; 00278 MixerChannel * * where=&mixer.channels; 00279 while (chan) { 00280 if (chan==delchan) { 00281 *where=chan->next; 00282 delete delchan; 00283 return; 00284 } 00285 where=&chan->next; 00286 chan=chan->next; 00287 } 00288 } 00289 00290 void MixerChannel::UpdateVolume(void) { 00291 volmul[0]=(Bits)((1 << MIXER_VOLSHIFT)*scale[0]*volmain[0]); 00292 volmul[1]=(Bits)((1 << MIXER_VOLSHIFT)*scale[1]*volmain[1]); 00293 } 00294 00295 void MixerChannel::SetVolume(float _left,float _right) { 00296 volmain[0]=_left; 00297 volmain[1]=_right; 00298 UpdateVolume(); 00299 } 00300 00301 void MixerChannel::SetScale( float f ) { 00302 SetScale(f, f); 00303 } 00304 00305 void MixerChannel::SetScale(float _left, float _right) { 00306 // Constrain application-defined volume between 0% and 100% 00307 const float min_volume(0.0); 00308 const float max_volume(1.0); 00309 _left = clamp(_left, min_volume, max_volume); 00310 _right = clamp(_right, min_volume, max_volume); 00311 if (scale[0] != _left || scale[1] != _right) { 00312 scale[0] = _left; 00313 scale[1] = _right; 00314 UpdateVolume(); 00315 } 00316 } 00317 00318 static void MIXER_FillUp(void); 00319 00320 void MixerChannel::Enable(bool _yesno) { 00321 if (_yesno==enabled) return; 00322 enabled=_yesno; 00323 if (!enabled) freq_f=0; 00324 } 00325 00326 void MixerChannel::lowpassUpdate() { 00327 if (lowpass_freq != 0) { 00328 double timeInterval; 00329 double tau,talpha; 00330 00331 if (freq_n > freq_d) { // source -> dest mixer rate ratio is > 100% 00332 timeInterval = (double)freq_d_orig / freq_n; // will filter on sample load at source rate 00333 lowpass_on_load = true; 00334 lowpass_on_out = false; 00335 } 00336 else { 00337 timeInterval = (double)1.0 / mixer.freq; // will filter mixer output at mixer rate 00338 lowpass_on_load = false; 00339 lowpass_on_out = true; 00340 } 00341 00342 tau = 1.0 / (lowpass_freq * 2 * M_PI); 00343 talpha = timeInterval / (tau + timeInterval); 00344 lowpass_alpha = (Bit32s)(talpha * 0x10000); // double -> 16.16 fixed point 00345 00346 // LOG_MSG("Lowpass freq_n=%u freq_d=%u timeInterval=%.12f tau=%.12f alpha=%.6f onload=%u onout=%u", 00347 // freq_n,freq_d_orig,timeInterval,tau,talpha,lowpass_on_load,lowpass_on_out); 00348 } 00349 else { 00350 lowpass_on_load = false; 00351 lowpass_on_out = false; 00352 } 00353 } 00354 00355 inline Bit32s MixerChannel::lowpassStep(Bit32s in,const unsigned int iteration,const unsigned int channel) { 00356 const Bit64s m1 = (Bit64s)in * (Bit64s)lowpass_alpha; 00357 const Bit64s m2 = ((Bit64s)lowpass[iteration][channel] << ((Bit64s)16)) - ((Bit64s)lowpass[iteration][channel] * (Bit64s)lowpass_alpha); 00358 const Bit32s ns = (Bit32s)((m1 + m2) >> (Bit64s)16); 00359 lowpass[iteration][channel] = ns; 00360 return ns; 00361 } 00362 00363 inline void MixerChannel::lowpassProc(Bit32s ch[2]) { 00364 for (unsigned int i=0;i < lowpass_order;i++) { 00365 for (unsigned int c=0;c < 2;c++) 00366 ch[c] = lowpassStep(ch[c],i,c); 00367 } 00368 } 00369 00370 void MixerChannel::SetLowpassFreq(Bitu _freq,unsigned int order) { 00371 if (order > LOWPASS_ORDER) order = LOWPASS_ORDER; 00372 if (_freq == lowpass_freq && lowpass_order == order) return; 00373 lowpass_order = order; 00374 lowpass_freq = _freq; 00375 lowpassUpdate(); 00376 } 00377 00378 void MixerChannel::SetSlewFreq(Bitu _freq) { 00379 freq_nslew_want = _freq; 00380 updateSlew(); 00381 } 00382 00383 void MixerChannel::SetFreq(Bitu _freq,Bitu _den) { 00384 if (freq_n == _freq && freq_d == freq_d_orig) 00385 return; 00386 00387 if (freq_d_orig != _den) { 00388 Bit64u tmp = (Bit64u)freq_f * (Bit64u)_den * (Bit64u)mixer.freq; 00389 freq_f = freq_fslew = (unsigned int)(tmp / (Bit64u)freq_d_orig); 00390 } 00391 00392 freq_n = _freq; 00393 freq_d = _den * mixer.freq; 00394 freq_d_orig = _den; 00395 updateSlew(); 00396 lowpassUpdate(); 00397 } 00398 00399 void CAPTURE_MultiTrackAddWave(Bit32u freq, Bit32u len, Bit16s * data,const char *name); 00400 00401 void MixerChannel::EndFrame(Bitu samples) { 00402 if (CaptureState & CAPTURE_MULTITRACK_WAVE) {// TODO: should be a separate call! 00403 Bit16s convert[1024][2]; 00404 Bitu cnv = msbuffer_o; 00405 Bitu padding = 0; 00406 00407 if (cnv > samples) 00408 cnv = samples; 00409 else 00410 padding = samples - cnv; 00411 00412 if (cnv > 0) { 00413 Bit32s volscale1 = (Bit32s)(mixer.recordvol[0] * (1 << MIXER_VOLSHIFT)); 00414 Bit32s volscale2 = (Bit32s)(mixer.recordvol[1] * (1 << MIXER_VOLSHIFT)); 00415 00416 if (cnv > 1024) cnv = 1024; 00417 for (Bitu i=0;i<cnv;i++) { 00418 convert[i][0]=MIXER_CLIP(((Bit64s)msbuffer[i][0] * (Bit64s)volscale1) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT)); 00419 convert[i][1]=MIXER_CLIP(((Bit64s)msbuffer[i][1] * (Bit64s)volscale2) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT)); 00420 } 00421 CAPTURE_MultiTrackAddWave(mixer.freq,cnv,(Bit16s*)convert,name); 00422 } 00423 00424 if (padding > 0) { 00425 if (padding > 1024) padding = 1024; 00426 memset(&convert[0][0],0,padding*sizeof(Bit16s)*2); 00427 CAPTURE_MultiTrackAddWave(mixer.freq,padding,(Bit16s*)convert,name); 00428 } 00429 } 00430 00431 rend_n = rend_d = 0; 00432 if (msbuffer_o <= samples) { 00433 msbuffer_o = 0; 00434 msbuffer_i = 0; 00435 } 00436 else { 00437 msbuffer_o -= samples; 00438 if (msbuffer_i >= samples) msbuffer_i -= samples; 00439 else msbuffer_i = 0; 00440 memmove(&msbuffer[0][0],&msbuffer[samples][0],msbuffer_o*sizeof(Bit32s)*2/*stereo*/); 00441 } 00442 00443 last_sample_write -= (int)samples; 00444 } 00445 00446 void MixerChannel::Mix(Bitu whole,Bitu frac) { 00447 unsigned int patience = 2; 00448 Bitu upto; 00449 00450 if (whole <= rend_n) return; 00451 assert(whole <= mixer.samples_this_ms.w); 00452 assert(rend_n < mixer.samples_this_ms.w); 00453 Bit32s *outptr = &mixer.work[mixer.work_in+rend_n][0]; 00454 00455 if (!enabled) { 00456 rend_n = whole; 00457 rend_d = frac; 00458 return; 00459 } 00460 00461 // HACK: We iterate twice only because of the Sound Blaster emulation. No other emulation seems to need this. 00462 rendering_to_n = whole; 00463 rendering_to_d = frac; 00464 while (msbuffer_o < whole) { 00465 Bit64u todo = (Bit64u)(whole - msbuffer_o) * (Bit64u)freq_n; 00466 todo += (Bit64u)freq_f; 00467 todo += (Bit64u)freq_d - (Bit64u)1; 00468 todo /= (Bit64u)freq_d; 00469 if (!current_loaded) todo++; 00470 handler(todo); 00471 00472 if (--patience == 0) break; 00473 } 00474 00475 if (msbuffer_o < whole) 00476 padFillSampleInterpolation(whole); 00477 00478 upto = whole; 00479 if (upto > msbuffer_o) upto = msbuffer_o; 00480 00481 if (lowpass_on_out) { /* before rendering out to mixer, process samples with lowpass filter */ 00482 Bitu t_rend_n = rend_n; 00483 Bitu t_msbuffer_i = msbuffer_i; 00484 00485 while (t_rend_n < whole && t_msbuffer_i < upto) { 00486 lowpassProc(msbuffer[t_msbuffer_i]); 00487 t_msbuffer_i++; 00488 t_rend_n++; 00489 } 00490 } 00491 00492 if (mixer.swapstereo) { 00493 while (rend_n < whole && msbuffer_i < upto) { 00494 *outptr++ += msbuffer[msbuffer_i][1]; 00495 *outptr++ += msbuffer[msbuffer_i][0]; 00496 msbuffer_i++; 00497 rend_n++; 00498 } 00499 } 00500 else { 00501 while (rend_n < whole && msbuffer_i < upto) { 00502 *outptr++ += msbuffer[msbuffer_i][0]; 00503 *outptr++ += msbuffer[msbuffer_i][1]; 00504 msbuffer_i++; 00505 rend_n++; 00506 } 00507 } 00508 00509 rend_n = whole; 00510 rend_d = frac; 00511 } 00512 00513 void MixerChannel::AddSilence(void) { 00514 } 00515 00516 template<class Type,bool stereo,bool signeddata,bool nativeorder,bool T_lowpass> 00517 inline void MixerChannel::loadCurrentSample(Bitu &len, const Type* &data) { 00518 last[0] = current[0]; 00519 last[1] = current[1]; 00520 00521 if (sizeof(Type) == 1) { 00522 const uint8_t xr = signeddata ? 0x00 : 0x80; 00523 00524 len--; 00525 current[0] = ((Bit8s)((*data++) ^ xr)) << 8; 00526 if (stereo) 00527 current[1] = ((Bit8s)((*data++) ^ xr)) << 8; 00528 else 00529 current[1] = current[0]; 00530 } 00531 else if (sizeof(Type) == 2) { 00532 const uint16_t xr = signeddata ? 0x0000 : 0x8000; 00533 uint16_t d; 00534 00535 len--; 00536 if (nativeorder) d = ((Bit16u)((*data++) ^ xr)); 00537 else d = host_readw((HostPt)(data++)) ^ xr; 00538 current[0] = (Bit16s)d; 00539 if (stereo) { 00540 if (nativeorder) d = ((Bit16u)((*data++) ^ xr)); 00541 else d = host_readw((HostPt)(data++)) ^ xr; 00542 current[1] = (Bit16s)d; 00543 } 00544 else { 00545 current[1] = current[0]; 00546 } 00547 } 00548 else if (sizeof(Type) == 4) { 00549 const uint32_t xr = signeddata ? 0x00000000UL : 0x80000000UL; 00550 uint32_t d; 00551 00552 len--; 00553 if (nativeorder) d = ((Bit32u)((*data++) ^ xr)); 00554 else d = host_readd((HostPt)(data++)) ^ xr; 00555 current[0] = (Bit32s)d; 00556 if (stereo) { 00557 if (nativeorder) d = ((Bit32u)((*data++) ^ xr)); 00558 else d = host_readd((HostPt)(data++)) ^ xr; 00559 current[1] = (Bit32s)d; 00560 } 00561 else { 00562 current[1] = current[0]; 00563 } 00564 } 00565 else { 00566 current[0] = current[1] = 0; 00567 len = 0; 00568 } 00569 00570 if (T_lowpass && lowpass_on_load) 00571 lowpassProc(current); 00572 00573 if (stereo) { 00574 delta[0] = current[0] - last[0]; 00575 delta[1] = current[1] - last[1]; 00576 } 00577 else { 00578 delta[1] = delta[0] = current[0] - last[0]; 00579 } 00580 00581 if (freq_nslew_want != 0) { 00582 if (delta[0] < -max_change) delta[0] = -max_change; 00583 else if (delta[0] > max_change) delta[0] = max_change; 00584 00585 if (stereo) { 00586 if (delta[1] < -max_change) delta[1] = -max_change; 00587 else if (delta[1] > max_change) delta[1] = max_change; 00588 } 00589 else { 00590 delta[1] = delta[0]; 00591 } 00592 } 00593 00594 current_loaded = true; 00595 } 00596 00597 inline void MixerChannel::padFillSampleInterpolation(const Bitu upto) { 00598 finishSampleInterpolation(upto); 00599 if (msbuffer_o < upto) { 00600 if (freq_f > freq_d) freq_f = freq_d; // this is an abrupt stop, so interpolation must not carry over, to help avoid popping artifacts 00601 00602 while (msbuffer_o < upto) { 00603 msbuffer[msbuffer_o][0] = current[0]; 00604 msbuffer[msbuffer_o][1] = current[1]; 00605 msbuffer_o++; 00606 } 00607 } 00608 } 00609 00610 void MixerChannel::finishSampleInterpolation(const Bitu upto) { 00611 if (!current_loaded) return; 00612 runSampleInterpolation(upto); 00613 } 00614 00615 double MixerChannel::timeSinceLastSample(void) { 00616 Bits delta = (Bits)mixer.samples_rendered_ms.w - (Bits)last_sample_write; 00617 return ((double)delta) / mixer.freq; 00618 } 00619 00620 inline bool MixerChannel::runSampleInterpolation(const Bitu upto) { 00621 if (msbuffer_o >= upto) 00622 return false; 00623 00624 while (freq_fslew < freq_d) { 00625 int sample = last[0] + (int)(((int64_t)delta[0] * (int64_t)freq_fslew) / (int64_t)freq_d); 00626 msbuffer[msbuffer_o][0] = sample * volmul[0]; 00627 sample = last[1] + (int)(((int64_t)delta[1] * (int64_t)freq_fslew) / (int64_t)freq_d); 00628 msbuffer[msbuffer_o][1] = sample * volmul[1]; 00629 00630 freq_f += freq_n; 00631 freq_fslew += freq_nslew; 00632 if ((++msbuffer_o) >= upto) 00633 return false; 00634 } 00635 00636 current[0] = last[0] + delta[0]; 00637 current[1] = last[1] + delta[1]; 00638 while (freq_f < freq_d) { 00639 msbuffer[msbuffer_o][0] = current[0] * volmul[0]; 00640 msbuffer[msbuffer_o][1] = current[1] * volmul[1]; 00641 00642 freq_f += freq_n; 00643 if ((++msbuffer_o) >= upto) 00644 return false; 00645 } 00646 00647 return true; 00648 } 00649 00650 template<class Type,bool stereo,bool signeddata,bool nativeorder> 00651 inline void MixerChannel::AddSamples(Bitu len, const Type* data) { 00652 last_sample_write = (Bits)mixer.samples_rendered_ms.w; 00653 00654 if (msbuffer_o >= 2048) { 00655 fprintf(stderr,"WARNING: addSample overrun (immediate)\n"); 00656 return; 00657 } 00658 00659 if (!current_loaded) { 00660 if (len == 0) return; 00661 00662 loadCurrentSample<Type,stereo,signeddata,nativeorder,false>(len,data); 00663 if (len == 0) { 00664 freq_f = freq_fslew = freq_d; /* encourage loading next round */ 00665 return; 00666 } 00667 00668 loadCurrentSample<Type,stereo,signeddata,nativeorder,false>(len,data); 00669 freq_f = freq_fslew = 0; /* interpolate now from what we just loaded */ 00670 } 00671 00672 if (lowpass_on_load) { 00673 for (;;) { 00674 if (freq_f >= freq_d) { 00675 if (len == 0) break; 00676 loadCurrentSample<Type,stereo,signeddata,nativeorder,true>(len,data); 00677 freq_f -= freq_d; 00678 freq_fslew = freq_f; 00679 } 00680 if (!runSampleInterpolation(2048)) 00681 break; 00682 } 00683 } 00684 else { 00685 for (;;) { 00686 if (freq_f >= freq_d) { 00687 if (len == 0) break; 00688 loadCurrentSample<Type,stereo,signeddata,nativeorder,false>(len,data); 00689 freq_f -= freq_d; 00690 freq_fslew = freq_f; 00691 } 00692 if (!runSampleInterpolation(2048)) 00693 break; 00694 } 00695 } 00696 } 00697 00698 void MixerChannel::AddSamples_m8(Bitu len, const Bit8u * data) { 00699 AddSamples<Bit8u,false,false,true>(len,data); 00700 } 00701 void MixerChannel::AddSamples_s8(Bitu len,const Bit8u * data) { 00702 AddSamples<Bit8u,true,false,true>(len,data); 00703 } 00704 void MixerChannel::AddSamples_m8s(Bitu len,const Bit8s * data) { 00705 AddSamples<Bit8s,false,true,true>(len,data); 00706 } 00707 void MixerChannel::AddSamples_s8s(Bitu len,const Bit8s * data) { 00708 AddSamples<Bit8s,true,true,true>(len,data); 00709 } 00710 void MixerChannel::AddSamples_m16(Bitu len,const Bit16s * data) { 00711 AddSamples<Bit16s,false,true,true>(len,data); 00712 } 00713 void MixerChannel::AddSamples_s16(Bitu len,const Bit16s * data) { 00714 AddSamples<Bit16s,true,true,true>(len,data); 00715 } 00716 void MixerChannel::AddSamples_m16u(Bitu len,const Bit16u * data) { 00717 AddSamples<Bit16u,false,false,true>(len,data); 00718 } 00719 void MixerChannel::AddSamples_s16u(Bitu len,const Bit16u * data) { 00720 AddSamples<Bit16u,true,false,true>(len,data); 00721 } 00722 void MixerChannel::AddSamples_m32(Bitu len,const Bit32s * data) { 00723 AddSamples<Bit32s,false,true,true>(len,data); 00724 } 00725 void MixerChannel::AddSamples_s32(Bitu len,const Bit32s * data) { 00726 AddSamples<Bit32s,true,true,true>(len,data); 00727 } 00728 void MixerChannel::AddSamples_m16_nonnative(Bitu len,const Bit16s * data) { 00729 AddSamples<Bit16s,false,true,false>(len,data); 00730 } 00731 void MixerChannel::AddSamples_s16_nonnative(Bitu len,const Bit16s * data) { 00732 AddSamples<Bit16s,true,true,false>(len,data); 00733 } 00734 void MixerChannel::AddSamples_m16u_nonnative(Bitu len,const Bit16u * data) { 00735 AddSamples<Bit16u,false,false,false>(len,data); 00736 } 00737 void MixerChannel::AddSamples_s16u_nonnative(Bitu len,const Bit16u * data) { 00738 AddSamples<Bit16u,true,false,false>(len,data); 00739 } 00740 void MixerChannel::AddSamples_m32_nonnative(Bitu len,const Bit32s * data) { 00741 AddSamples<Bit32s,false,true,false>(len,data); 00742 } 00743 void MixerChannel::AddSamples_s32_nonnative(Bitu len,const Bit32s * data) { 00744 AddSamples<Bit32s,true,true,false>(len,data); 00745 } 00746 00747 extern bool ticksLocked; 00748 00749 #if 0//unused 00750 static inline bool Mixer_irq_important(void) { 00751 /* In some states correct timing of the irqs is more important then 00752 * non stuttering audo */ 00753 return (ticksLocked || (CaptureState & (CAPTURE_WAVE|CAPTURE_VIDEO|CAPTURE_MULTITRACK_WAVE))); 00754 } 00755 #endif 00756 00757 unsigned long long mixer_sample_counter = 0; 00758 double mixer_start_pic_time = 0; 00759 00760 /* once a millisecond, render 1ms of audio, up to whole samples */ 00761 static void MIXER_MixData(Bitu fracs/*render up to*/) { 00762 unsigned int prev_rendered = mixer.samples_rendered_ms.w; 00763 MixerChannel *chan = mixer.channels; 00764 unsigned int whole,frac; 00765 bool endframe = false; 00766 00767 if (fracs >= ((Bitu)mixer.samples_this_ms.w * mixer.samples_this_ms.fd)) { 00768 fracs = ((Bitu)mixer.samples_this_ms.w * mixer.samples_this_ms.fd); 00769 endframe = true; 00770 } 00771 00772 whole = (unsigned int)(fracs / mixer.samples_this_ms.fd); 00773 frac = (unsigned int)(fracs % mixer.samples_this_ms.fd); 00774 if (whole <= mixer.samples_rendered_ms.w) return; 00775 00776 while (chan) { 00777 chan->Mix(whole,fracs); 00778 if (endframe) chan->EndFrame(mixer.samples_this_ms.w); 00779 chan=chan->next; 00780 } 00781 00782 if (CaptureState & (CAPTURE_WAVE|CAPTURE_VIDEO)) { 00783 Bit32s volscale1 = (Bit32s)(mixer.recordvol[0] * (1 << MIXER_VOLSHIFT)); 00784 Bit32s volscale2 = (Bit32s)(mixer.recordvol[1] * (1 << MIXER_VOLSHIFT)); 00785 Bit16s convert[1024][2]; 00786 Bitu added = whole - prev_rendered; 00787 if (added>1024) added=1024; 00788 Bitu readpos = mixer.work_in + prev_rendered; 00789 for (Bitu i=0;i<added;i++) { 00790 convert[i][0]=MIXER_CLIP(((Bit64s)mixer.work[readpos][0] * (Bit64s)volscale1) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT)); 00791 convert[i][1]=MIXER_CLIP(((Bit64s)mixer.work[readpos][1] * (Bit64s)volscale2) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT)); 00792 readpos++; 00793 } 00794 assert(readpos <= MIXER_BUFSIZE); 00795 CAPTURE_AddWave( mixer.freq, added, (Bit16s*)convert ); 00796 } 00797 00798 if (Mixer_MIXC_Active() && prev_rendered < whole) { 00799 Bitu readpos = mixer.work_in + prev_rendered; 00800 Bitu added = whole - prev_rendered; 00801 Bitu cando = (mixer_capture_write_end - mixer_capture_write) / 2/*bytes/sample*/ / 2/*channels*/; 00802 if (cando > added) cando = added; 00803 00804 if (cando == 0 && !Mixer_MIXC_AtEnd()) { 00805 Mixer_MIXC_MarkError(); 00806 } 00807 else if (cando != 0) { 00808 for (Bitu i=0;i < cando;i++) { 00809 phys_writew(mixer_capture_write,(Bit16u)MIXER_CLIP(((Bit64s)mixer.work[readpos][0]) >> (MIXER_VOLSHIFT))); 00810 mixer_capture_write += 2; 00811 00812 phys_writew(mixer_capture_write,(Bit16u)MIXER_CLIP(((Bit64s)mixer.work[readpos][1]) >> (MIXER_VOLSHIFT))); 00813 mixer_capture_write += 2; 00814 00815 readpos++; 00816 } 00817 00818 if (Mixer_MIXC_AtEnd()) { 00819 if (Mixer_MIXC_ShouldLoop()) 00820 Mixer_MIXC_LoopAround(); 00821 else 00822 Mixer_MIXC_Stop(); 00823 } 00824 } 00825 } 00826 00827 mixer.samples_rendered_ms.w = whole; 00828 mixer.samples_rendered_ms.fd = frac; 00829 mixer_sample_counter += mixer.samples_rendered_ms.w - prev_rendered; 00830 } 00831 00832 static void MIXER_FillUp(void) { 00833 SDL_LockAudio(); 00834 float index = PIC_TickIndex(); 00835 if (index < 0) index = 0; 00836 MIXER_MixData((Bitu)((double)index * ((Bitu)mixer.samples_this_ms.w * mixer.samples_this_ms.fd))); 00837 SDL_UnlockAudio(); 00838 } 00839 00840 void MixerChannel::FillUp(void) { 00841 MIXER_FillUp(); 00842 } 00843 00844 void MIXER_MixSingle(Bitu /*val*/) { 00845 MIXER_FillUp(); 00846 PIC_AddEvent(MIXER_MixSingle,1000.0 / mixer.freq); 00847 } 00848 00849 static void MIXER_Mix(void) { 00850 Bitu thr; 00851 00852 SDL_LockAudio(); 00853 00854 /* render */ 00855 assert((mixer.work_in+mixer.samples_per_ms.w) <= MIXER_BUFSIZE); 00856 MIXER_MixData((Bitu)mixer.samples_this_ms.w * (Bitu)mixer.samples_this_ms.fd); 00857 mixer.work_in += mixer.samples_this_ms.w; 00858 00859 /* how many samples for the next ms? */ 00860 mixer.samples_this_ms.w = mixer.samples_per_ms.w; 00861 mixer.samples_this_ms.fn += mixer.samples_per_ms.fn; 00862 if (mixer.samples_this_ms.fn >= mixer.samples_this_ms.fd) { 00863 mixer.samples_this_ms.fn -= mixer.samples_this_ms.fd; 00864 mixer.samples_this_ms.w++; 00865 } 00866 00867 /* advance. we use in/out & wrap pointers to make sure the rendering code 00868 * doesn't have to worry about circular buffer wraparound. */ 00869 thr = mixer.blocksize; 00870 if (thr < mixer.samples_this_ms.w) thr = mixer.samples_this_ms.w; 00871 if ((mixer.work_in+thr) > MIXER_BUFSIZE) { 00872 mixer.work_wrap = mixer.work_in; 00873 mixer.work_in = 0; 00874 } 00875 assert((mixer.work_in+thr) <= MIXER_BUFSIZE); 00876 assert((mixer.work_in+mixer.samples_this_ms.w) <= MIXER_BUFSIZE); 00877 memset(&mixer.work[mixer.work_in][0],0,sizeof(Bit32s)*2*mixer.samples_this_ms.w); 00878 mixer.samples_rendered_ms.fn = 0; 00879 mixer.samples_rendered_ms.w = 0; 00880 SDL_UnlockAudio(); 00881 MIXER_FillUp(); 00882 } 00883 00884 static void SDLCALL MIXER_CallBack(void * userdata, Uint8 *stream, int len) { 00885 (void)userdata;//UNUSED 00886 Bit32s volscale1 = (Bit32s)(mixer.mastervol[0] * (1 << MIXER_VOLSHIFT)); 00887 Bit32s volscale2 = (Bit32s)(mixer.mastervol[1] * (1 << MIXER_VOLSHIFT)); 00888 Bitu need = (Bitu)len/MIXER_SSIZE; 00889 Bit16s *output = (Bit16s*)stream; 00890 int remains; 00891 00892 if (mixer.mute) { 00893 if ((CaptureState & (CAPTURE_WAVE|CAPTURE_VIDEO|CAPTURE_MULTITRACK_WAVE)) != 0) 00894 mixer.work_out = mixer.work_in; 00895 else 00896 mixer.work_out = mixer.work_in = 0; 00897 } 00898 00899 if (mixer.prebuffer_wait) { 00900 remains = (int)mixer.work_in - (int)mixer.work_out; 00901 if (remains < 0) remains += (int)mixer.work_wrap; 00902 if (remains < 0) remains = 0; 00903 00904 if ((unsigned int)remains >= mixer.prebuffer_samples) 00905 mixer.prebuffer_wait = false; 00906 } 00907 00908 if (!mixer.prebuffer_wait && !mixer.mute) { 00909 Bit32s *in = &mixer.work[mixer.work_out][0]; 00910 while (need > 0) { 00911 if (mixer.work_out == mixer.work_in) break; 00912 *output++ = MIXER_CLIP((((Bit64s)(*in++)) * (Bit64s)volscale1) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT)); 00913 *output++ = MIXER_CLIP((((Bit64s)(*in++)) * (Bit64s)volscale2) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT)); 00914 mixer.work_out++; 00915 if (mixer.work_out >= mixer.work_wrap) { 00916 mixer.work_out = 0; 00917 in = &mixer.work[mixer.work_out][0]; 00918 } 00919 need--; 00920 } 00921 } 00922 00923 if (need > 0) 00924 mixer.prebuffer_wait = true; 00925 00926 while (need > 0) { 00927 *output++ = 0; 00928 *output++ = 0; 00929 need--; 00930 } 00931 00932 remains = (int)mixer.work_in - (int)mixer.work_out; 00933 if (remains < 0) remains += (int)mixer.work_wrap; 00934 00935 if ((unsigned long)remains >= (mixer.blocksize*2UL)) { 00936 /* drop some samples to keep time */ 00937 unsigned int drop; 00938 00939 if ((unsigned long)remains >= (mixer.blocksize*3UL)) // hard drop 00940 drop = ((unsigned int)remains - (unsigned int)(mixer.blocksize)); 00941 else // subtle drop 00942 drop = (((unsigned int)remains - (unsigned int)(mixer.blocksize*2)) / 50U) + 1; 00943 00944 while (drop > 0) { 00945 mixer.work_out++; 00946 if (mixer.work_out >= mixer.work_wrap) mixer.work_out = 0; 00947 drop--; 00948 } 00949 } 00950 } 00951 00952 static void MIXER_Stop(Section* sec) { 00953 (void)sec;//UNUSED 00954 } 00955 00956 class MIXER : public Program { 00957 public: 00958 void MakeVolume(char * scan,float & vol0,float & vol1) { 00959 Bitu w=0; 00960 bool db=(toupper(*scan)=='D'); 00961 if (db) scan++; 00962 while (*scan) { 00963 if (*scan==':') { 00964 ++scan;w=1; 00965 } 00966 char * before=scan; 00967 float val=(float)strtod(scan,&scan); 00968 if (before==scan) { 00969 ++scan;continue; 00970 } 00971 if (!db) val/=100; 00972 else val=powf(10.0f,(float)val/20.0f); 00973 if (val<0) val=1.0f; 00974 if (!w) { 00975 vol0=val; 00976 } else { 00977 vol1=val; 00978 } 00979 } 00980 if (!w) vol1=vol0; 00981 } 00982 00983 void Run(void) { 00984 if (cmd->FindExist("-?", false) || cmd->FindExist("/?", false)) { 00985 WriteOut("Displays or changes the current sound levels.\n\nMIXER [option]\n"); 00986 return; 00987 } 00988 if(cmd->FindExist("/LISTMIDI")) { 00989 ListMidi(); 00990 return; 00991 } 00992 if (cmd->FindString("MASTER",temp_line,false)) { 00993 MakeVolume((char *)temp_line.c_str(),mixer.mastervol[0],mixer.mastervol[1]); 00994 } 00995 if (cmd->FindString("RECORD",temp_line,false)) { 00996 MakeVolume((char *)temp_line.c_str(),mixer.recordvol[0],mixer.recordvol[1]); 00997 } 00998 MixerChannel * chan=mixer.channels; 00999 while (chan) { 01000 if (cmd->FindString(chan->name,temp_line,false)) { 01001 MakeVolume((char *)temp_line.c_str(),chan->volmain[0],chan->volmain[1]); 01002 } 01003 chan->UpdateVolume(); 01004 chan=chan->next; 01005 } 01006 if (cmd->FindExist("/NOSHOW")) return; 01007 WriteOut("Channel Main Main(dB)\n"); 01008 ShowVolume("MASTER",mixer.mastervol[0],mixer.mastervol[1]); 01009 ShowVolume("RECORD",mixer.recordvol[0],mixer.recordvol[1]); 01010 for (chan=mixer.channels;chan;chan=chan->next) 01011 ShowVolume(chan->name,chan->volmain[0],chan->volmain[1]); 01012 } 01013 private: 01014 void ShowVolume(const char * name,float vol0,float vol1) { 01015 WriteOut("%-8s %3.0f:%-3.0f %+3.2f:%-+3.2f \n",name, 01016 (double)vol0*100,(double)vol1*100, 01017 20*log(vol0)/log(10.0f),20*log(vol1)/log(10.0f) 01018 ); 01019 } 01020 01021 void ListMidi(){ 01022 if(midi.handler) midi.handler->ListAll(this); 01023 }; 01024 }; 01025 01026 static void MIXER_ProgramStart(Program * * make) { 01027 *make=new MIXER; 01028 } 01029 01030 MixerChannel* MixerObject::Install(MIXER_Handler handler,Bitu freq,const char * name){ 01031 if(!installed) { 01032 if(strlen(name) > 31) E_Exit("Too long mixer channel name"); 01033 safe_strncpy(m_name,name,32); 01034 installed = true; 01035 return MIXER_AddChannel(handler,freq,name); 01036 } else { 01037 E_Exit("already added mixer channel."); 01038 return 0; //Compiler happy 01039 } 01040 } 01041 01042 MixerObject::~MixerObject(){ 01043 if(!installed) return; 01044 MIXER_DelChannel(MIXER_FindChannel(m_name)); 01045 } 01046 01047 void MENU_mute(bool enabled) { 01048 mixer.mute=enabled; 01049 mainMenu.get_item("mixer_mute").check(mixer.mute).refresh_item(mainMenu); 01050 } 01051 01052 bool MENU_get_mute(void) { 01053 return mixer.mute; 01054 } 01055 01056 void MENU_swapstereo(bool enabled) { 01057 mixer.swapstereo=enabled; 01058 mainMenu.get_item("mixer_swapstereo").check(mixer.swapstereo).refresh_item(mainMenu); 01059 } 01060 01061 bool MENU_get_swapstereo(void) { 01062 return mixer.swapstereo; 01063 } 01064 01065 void MAPPER_VolumeUp(bool pressed) { 01066 if (!pressed) return; 01067 01068 double newvol = (((double)mixer.mastervol[0] + mixer.mastervol[1]) / 0.7) * 0.5; 01069 01070 if (newvol > 1) newvol = 1; 01071 01072 mixer.mastervol[0] = mixer.mastervol[1] = newvol; 01073 01074 LOG(LOG_MISC,LOG_NORMAL)("Master volume UP to %.3f%%",newvol * 100); 01075 } 01076 01077 void MAPPER_VolumeDown(bool pressed) { 01078 if (!pressed) return; 01079 01080 double newvol = ((double)mixer.mastervol[0] + mixer.mastervol[1]) * 0.7 * 0.5; 01081 01082 if (fabs(newvol - 1.0) < 0.25) 01083 newvol = 1; 01084 01085 mixer.mastervol[0] = mixer.mastervol[1] = newvol; 01086 01087 LOG(LOG_MISC,LOG_NORMAL)("Master volume DOWN to %.3f%%",newvol * 100); 01088 } 01089 01090 void MAPPER_RecVolumeUp(bool pressed) { 01091 if (!pressed) return; 01092 01093 double newvol = (((double)mixer.recordvol[0] + mixer.recordvol[1]) / 0.7) * 0.5; 01094 01095 if (newvol > 1) newvol = 1; 01096 01097 mixer.recordvol[0] = mixer.recordvol[1] = newvol; 01098 01099 LOG(LOG_MISC,LOG_NORMAL)("Recording volume UP to %.3f%%",newvol * 100); 01100 } 01101 01102 void MAPPER_RecVolumeDown(bool pressed) { 01103 if (!pressed) return; 01104 01105 double newvol = ((double)mixer.recordvol[0] + mixer.recordvol[1]) * 0.7 * 0.5; 01106 01107 if (fabs(newvol - 1.0) < 0.25) 01108 newvol = 1; 01109 01110 mixer.recordvol[0] = mixer.recordvol[1] = newvol; 01111 01112 LOG(LOG_MISC,LOG_NORMAL)("Recording volume DOWN to %.3f%%",newvol * 100); 01113 } 01114 01115 void MIXER_Controls_Init() { 01116 DOSBoxMenu::item *item; 01117 01118 MAPPER_AddHandler(MAPPER_VolumeUp ,MK_kpplus, MMODHOST,"volup","VolUp",&item); 01119 item->set_text("Increase volume"); 01120 01121 MAPPER_AddHandler(MAPPER_VolumeDown,MK_kpminus,MMODHOST,"voldown","VolDown",&item); 01122 item->set_text("Decrease volume"); 01123 01124 MAPPER_AddHandler(MAPPER_RecVolumeUp ,MK_nothing, 0,"recvolup","RecVolUp",&item); 01125 item->set_text("Increase recording volume"); 01126 01127 MAPPER_AddHandler(MAPPER_RecVolumeDown,MK_nothing, 0,"recvoldown","RecVolDn",&item); 01128 item->set_text("Decrease recording volume"); 01129 } 01130 01131 void MIXER_DOS_Boot(Section *) { 01132 PROGRAMS_MakeFile("MIXER.COM",MIXER_ProgramStart); 01133 } 01134 01135 void MIXER_Init() { 01136 AddExitFunction(AddExitFunctionFuncPair(MIXER_Stop)); 01137 01138 LOG(LOG_MISC,LOG_DEBUG)("Initializing DOSBox audio mixer"); 01139 01140 Section_prop * section=static_cast<Section_prop *>(control->GetSection("mixer")); 01141 /* Read out config section */ 01142 mixer.freq=(unsigned int)section->Get_int("rate"); 01143 mixer.nosound=section->Get_bool("nosound"); 01144 mixer.blocksize=(unsigned int)section->Get_int("blocksize"); 01145 mixer.swapstereo=section->Get_bool("swapstereo"); 01146 mixer.sampleaccurate=section->Get_bool("sample accurate"); 01147 mixer.mute=false; 01148 01149 /* Initialize the internal stuff */ 01150 mixer.prebuffer_samples=0; 01151 mixer.prebuffer_wait=true; 01152 mixer.channels=0; 01153 mixer.pos=0; 01154 mixer.done=0; 01155 memset(mixer.work,0,sizeof(mixer.work)); 01156 mixer.mastervol[0]=1.0f; 01157 mixer.mastervol[1]=1.0f; 01158 mixer.recordvol[0]=1.0f; 01159 mixer.recordvol[1]=1.0f; 01160 01161 /* Start the Mixer using SDL Sound at 22 khz */ 01162 SDL_AudioSpec spec; 01163 SDL_AudioSpec obtained; 01164 01165 spec.freq=(int)mixer.freq; 01166 spec.format=AUDIO_S16SYS; 01167 spec.channels=2; 01168 spec.callback=MIXER_CallBack; 01169 spec.userdata=NULL; 01170 spec.samples=(Uint16)mixer.blocksize; 01171 01172 if (mixer.nosound) { 01173 LOG(LOG_MISC,LOG_DEBUG)("MIXER:No Sound Mode Selected."); 01174 TIMER_AddTickHandler(MIXER_Mix); 01175 } else if (SDL_OpenAudio(&spec, &obtained) <0 ) { 01176 mixer.nosound = true; 01177 LOG(LOG_MISC,LOG_DEBUG)("MIXER:Can't open audio: %s , running in nosound mode.",SDL_GetError()); 01178 TIMER_AddTickHandler(MIXER_Mix); 01179 } else { 01180 if(((Bitu)mixer.freq != (Bitu)obtained.freq) || ((Bitu)mixer.blocksize != (Bitu)obtained.samples)) 01181 LOG(LOG_MISC,LOG_DEBUG)("MIXER:Got different values from SDL: freq %d, blocksize %d",(int)obtained.freq,(int)obtained.samples); 01182 01183 mixer.freq=(unsigned int)obtained.freq; 01184 mixer.blocksize=obtained.samples; 01185 TIMER_AddTickHandler(MIXER_Mix); 01186 if (mixer.sampleaccurate) PIC_AddEvent(MIXER_MixSingle,1000.0 / mixer.freq); 01187 SDL_PauseAudio(0); 01188 } 01189 mixer_start_pic_time = PIC_FullIndex(); 01190 mixer_sample_counter = 0; 01191 mixer.work_in = mixer.work_out = 0; 01192 mixer.work_wrap = MIXER_BUFSIZE; 01193 if (mixer.work_wrap <= mixer.blocksize) E_Exit("blocksize too large"); 01194 01195 { 01196 int ms = section->Get_int("prebuffer"); 01197 01198 if (ms < 0) ms = 20; 01199 01200 mixer.prebuffer_samples = ((unsigned int)ms * (unsigned int)mixer.freq) / 1000u; 01201 if (mixer.prebuffer_samples > (mixer.work_wrap / 2)) 01202 mixer.prebuffer_samples = (mixer.work_wrap / 2); 01203 } 01204 01205 // how many samples per millisecond? compute as improper fraction (sample rate / 1000) 01206 mixer.samples_per_ms.w = mixer.freq / 1000U; 01207 mixer.samples_per_ms.fn = mixer.freq % 1000U; 01208 mixer.samples_per_ms.fd = 1000U; 01209 mixer.samples_this_ms.w = mixer.samples_per_ms.w; 01210 mixer.samples_this_ms.fn = 0; 01211 mixer.samples_this_ms.fd = mixer.samples_per_ms.fd; 01212 mixer.samples_rendered_ms.w = 0; 01213 mixer.samples_rendered_ms.fn = 0; 01214 mixer.samples_rendered_ms.fd = mixer.samples_per_ms.fd; 01215 01216 LOG(LOG_MISC,LOG_DEBUG)("Mixer: sample_accurate=%u blocksize=%u sdl_rate=%uHz mixer_rate=%uHz channels=%u samples=%u min/max/need=%u/%u/%u per_ms=%u %u/%u samples prebuffer=%u", 01217 (unsigned int)mixer.sampleaccurate, 01218 (unsigned int)mixer.blocksize, 01219 (unsigned int)obtained.freq, 01220 (unsigned int)mixer.freq, 01221 (unsigned int)obtained.channels, 01222 (unsigned int)obtained.samples, 01223 (unsigned int)0, 01224 (unsigned int)0, 01225 (unsigned int)0, 01226 (unsigned int)mixer.samples_per_ms.w, 01227 (unsigned int)mixer.samples_per_ms.fn, 01228 (unsigned int)mixer.samples_per_ms.fd, 01229 (unsigned int)mixer.prebuffer_samples); 01230 01231 AddVMEventFunction(VM_EVENT_DOS_INIT_KERNEL_READY,AddVMEventFunctionFuncPair(MIXER_DOS_Boot)); 01232 01233 MIXER_Controls_Init(); 01234 } 01235 01236 // save state support 01237 //void *MIXER_Mix_NoSound_PIC_Timer = (void*)MIXER_Mix_NoSound; 01238 void *MIXER_Mix_PIC_Timer = (void*)((uintptr_t)MIXER_Mix); 01239 01240 01241 void MixerChannel::SaveState( std::ostream& stream ) 01242 { 01243 // - pure data 01244 WRITE_POD( &volmain, volmain ); 01245 WRITE_POD( &scale, scale ); 01246 WRITE_POD( &volmul, volmul ); 01247 //WRITE_POD( &freq_add, freq_add ); 01248 WRITE_POD( &enabled, enabled ); 01249 } 01250 01251 01252 void MixerChannel::LoadState( std::istream& stream ) 01253 { 01254 // - pure data 01255 READ_POD( &volmain, volmain ); 01256 READ_POD( &scale, scale ); 01257 READ_POD( &volmul, volmul ); 01258 //READ_POD( &freq_add, freq_add ); 01259 READ_POD( &enabled, enabled ); 01260 01261 //******************************************** 01262 //******************************************** 01263 //******************************************** 01264 01265 // reset mixer channel (system data) 01266 mixer.pos = 0; 01267 mixer.done = 0; 01268 } 01269 01270 extern void POD_Save_Adlib(std::ostream& stream); 01271 extern void POD_Save_Disney(std::ostream& stream); 01272 extern void POD_Save_Gameblaster(std::ostream& stream); 01273 extern void POD_Save_GUS(std::ostream& stream); 01274 extern void POD_Save_MPU401(std::ostream& stream); 01275 extern void POD_Save_PCSpeaker(std::ostream& stream); 01276 extern void POD_Save_Sblaster(std::ostream& stream); 01277 extern void POD_Save_Tandy_Sound(std::ostream& stream); 01278 extern void POD_Load_Adlib(std::istream& stream); 01279 extern void POD_Load_Disney(std::istream& stream); 01280 extern void POD_Load_Gameblaster(std::istream& stream); 01281 extern void POD_Load_GUS(std::istream& stream); 01282 extern void POD_Load_MPU401(std::istream& stream); 01283 extern void POD_Load_PCSpeaker(std::istream& stream); 01284 extern void POD_Load_Sblaster(std::istream& stream); 01285 extern void POD_Load_Tandy_Sound(std::istream& stream); 01286 01287 namespace 01288 { 01289 class SerializeMixer : public SerializeGlobalPOD 01290 { 01291 public: 01292 SerializeMixer() : SerializeGlobalPOD("Mixer") 01293 {} 01294 01295 private: 01296 virtual void getBytes(std::ostream& stream) 01297 { 01298 01299 //************************************************* 01300 //************************************************* 01301 01302 SerializeGlobalPOD::getBytes(stream); 01303 01304 01305 POD_Save_Adlib(stream); 01306 POD_Save_Disney(stream); 01307 POD_Save_Gameblaster(stream); 01308 POD_Save_GUS(stream); 01309 POD_Save_MPU401(stream); 01310 POD_Save_PCSpeaker(stream); 01311 POD_Save_Sblaster(stream); 01312 POD_Save_Tandy_Sound(stream); 01313 } 01314 01315 virtual void setBytes(std::istream& stream) 01316 { 01317 01318 //************************************************* 01319 //************************************************* 01320 01321 SerializeGlobalPOD::setBytes(stream); 01322 01323 01324 POD_Load_Adlib(stream); 01325 POD_Load_Disney(stream); 01326 POD_Load_Gameblaster(stream); 01327 POD_Load_GUS(stream); 01328 POD_Load_MPU401(stream); 01329 POD_Load_PCSpeaker(stream); 01330 POD_Load_Sblaster(stream); 01331 POD_Load_Tandy_Sound(stream); 01332 01333 // reset mixer channel (system data) 01334 mixer.pos = 0; 01335 mixer.done = 0; 01336 } 01337 01338 } dummy; 01339 }