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 #include <string.h> 00021 #include <algorithm> 00022 #include "dosbox.h" 00023 #include "inout.h" 00024 #include "mixer.h" 00025 #include "pic.h" 00026 #include "setup.h" 00027 #include "bios.h" 00028 #include "mem.h" 00029 #include "control.h" 00030 00031 using namespace std; 00032 00033 unsigned int DISNEY_BASE = 0x0378; 00034 00035 #define DISNEY_SIZE 128 00036 00037 typedef struct _dac_channel { 00038 Bit8u buffer[DISNEY_SIZE]; // data buffer 00039 Bitu used; // current data buffer level 00040 double speedcheck_sum; 00041 double speedcheck_last; 00042 bool speedcheck_failed; 00043 bool speedcheck_init; 00044 } dac_channel; 00045 00046 static struct { 00047 // parallel port stuff 00048 Bit8u data; 00049 Bit8u status; 00050 Bit8u control; 00051 // the D/A channels 00052 dac_channel da[2]; 00053 00054 Bitu last_used; 00055 MixerObject * mo; 00056 MixerChannel * chan; 00057 bool stereo; 00058 // which channel do we use for mono output? 00059 // and the channel used for stereo 00060 dac_channel* leader; 00061 00062 Bitu state; 00063 Bitu interface_det; 00064 Bitu interface_det_ext; 00065 } disney; 00066 00067 #define DS_IDLE 0 00068 #define DS_RUNNING 1 00069 #define DS_FINISH 2 00070 #define DS_ANALYZING 3 00071 00072 static void DISNEY_CallBack(Bitu len); 00073 00074 static void DISNEY_disable(Bitu) { 00075 if(disney.mo) { 00076 disney.chan->AddSilence(); 00077 disney.chan->Enable(false); 00078 } 00079 disney.leader = 0; 00080 disney.last_used = 0; 00081 disney.state = DS_IDLE; 00082 disney.interface_det = 0; 00083 disney.interface_det_ext = 0; 00084 disney.stereo = false; 00085 } 00086 00087 static void DISNEY_enable(Bitu freq) { 00088 if(freq < 500 || freq > 100000) { 00089 // try again.. 00090 disney.state = DS_IDLE; 00091 #if 0 00092 LOG(LOG_MISC,LOG_NORMAL)("disney enable rejected, %ld Hz, stereo=%u",(long)freq,(int)disney.stereo); 00093 #endif 00094 return; 00095 } else { 00096 #if 0 00097 if(disney.stereo) LOG(LOG_MISC,LOG_NORMAL)("disney enable %d Hz, stereo",freq); 00098 else LOG(LOG_MISC,LOG_NORMAL)("disney enable %d Hz, mono",freq); 00099 #endif 00100 disney.chan->SetFreq(freq); 00101 disney.chan->Enable(true); 00102 disney.state = DS_RUNNING; 00103 } 00104 } 00105 00106 static void DISNEY_analyze(Bitu channel){ 00107 switch(disney.state) { 00108 case DS_RUNNING: // should not get here 00109 break; 00110 case DS_IDLE: 00111 // initialize channel data 00112 for(int i = 0; i < 2; i++) { 00113 disney.da[i].used = 0; 00114 disney.da[i].speedcheck_sum = 0; 00115 disney.da[i].speedcheck_failed = false; 00116 disney.da[i].speedcheck_init = false; 00117 } 00118 disney.da[channel].speedcheck_last = PIC_FullIndex(); 00119 disney.da[channel].speedcheck_init = true; 00120 00121 disney.state = DS_ANALYZING; 00122 break; 00123 00124 case DS_FINISH: 00125 { 00126 // detect stereo: if we have about the same data amount in both channels 00127 Bits st_diff = (Bits)disney.da[0].used - (Bits)disney.da[1].used; 00128 00129 // find leader channel (the one with higher rate) [this good for the stereo case?] 00130 if(disney.da[0].used > disney.da[1].used) { 00131 //disney.monochannel=0; 00132 disney.leader = &disney.da[0]; 00133 } else { 00134 //disney.monochannel=1; 00135 disney.leader = &disney.da[1]; 00136 } 00137 00138 if((st_diff < 5) && (st_diff > -5)) disney.stereo = true; 00139 else disney.stereo = false; 00140 00141 // calculate rate for both channels 00142 Bitu ch_speed[2]; 00143 00144 for(Bitu i = 0; i < 2; i++) { 00145 if (disney.da[i].used > 1/*avoid divide-by-zero!*/) { 00146 ch_speed[i] = (Bitu)(1.0/((disney.da[i].speedcheck_sum/1000.0) / 00147 (float)(((float)disney.da[i].used)-1.0))); // -1.75 00148 } 00149 else { 00150 ch_speed[i] = 0; 00151 } 00152 } 00153 00154 // choose the larger value 00155 DISNEY_enable(max(ch_speed[0],ch_speed[1])); 00156 break; 00157 } 00158 case DS_ANALYZING: 00159 { 00160 double current = PIC_FullIndex(); 00161 dac_channel* cch = &disney.da[channel]; 00162 00163 if(!cch->speedcheck_init) { 00164 cch->speedcheck_init = true; 00165 cch->speedcheck_last = current; 00166 break; 00167 } 00168 cch->speedcheck_sum += current - cch->speedcheck_last; 00169 //LOG_MSG("t=%f",current - cch->speedcheck_last); 00170 00171 // sanity checks (printer...) 00172 if((current - cch-> speedcheck_last) < 0.01 || 00173 (current - cch-> speedcheck_last) > 2) 00174 cch->speedcheck_failed = true; 00175 00176 // if both are failed we are back at start 00177 if(disney.da[0].speedcheck_failed && disney.da[1].speedcheck_failed) { 00178 disney.state=DS_IDLE; 00179 break; 00180 } 00181 00182 cch->speedcheck_last = current; 00183 00184 // analyze finish condition 00185 if(disney.da[0].used > 30 || disney.da[1].used > 30) 00186 disney.state = DS_FINISH; 00187 break; 00188 } 00189 } 00190 } 00191 00192 static void disney_write(Bitu port,Bitu val,Bitu iolen) { 00193 (void)iolen;//UNUSED 00194 //LOG_MSG("write disney time %f addr%x val %x",PIC_FullIndex(),port,val); 00195 disney.last_used=PIC_Ticks; 00196 switch (port-DISNEY_BASE) { 00197 case 0: /* Data Port */ 00198 { 00199 disney.data=(Bit8u)val; 00200 // if data is written here too often without using the stereo 00201 // mechanism we use the simple DAC machanism. 00202 if(disney.state != DS_RUNNING) { 00203 disney.interface_det++; 00204 if(disney.interface_det > 5) 00205 DISNEY_analyze(0); 00206 } 00207 if(disney.interface_det > 5) { 00208 if(disney.da[0].used < DISNEY_SIZE) { 00209 disney.da[0].buffer[disney.da[0].used] = disney.data; 00210 disney.da[0].used++; 00211 } //else LOG_MSG("disney overflow 0"); 00212 } 00213 break; 00214 } 00215 case 1: /* Status Port */ 00216 LOG(LOG_MISC,LOG_NORMAL)("DISNEY:Status write %x",(int)val); 00217 break; 00218 case 2: /* Control Port */ 00219 if((disney.control & 0x2) && !(val & 0x2)) { 00220 if(disney.state != DS_RUNNING) { 00221 disney.interface_det = 0; 00222 disney.interface_det_ext = 0; 00223 DISNEY_analyze(1); 00224 } 00225 00226 // stereo channel latch 00227 if(disney.da[1].used < DISNEY_SIZE) { 00228 disney.da[1].buffer[disney.da[1].used] = disney.data; 00229 disney.da[1].used++; 00230 } //else LOG_MSG("disney overflow 1"); 00231 } 00232 00233 if((disney.control & 0x1) && !(val & 0x1)) { 00234 if(disney.state != DS_RUNNING) { 00235 disney.interface_det = 0; 00236 disney.interface_det_ext = 0; 00237 DISNEY_analyze(0); 00238 } 00239 // stereo channel latch 00240 if(disney.da[0].used < DISNEY_SIZE) { 00241 disney.da[0].buffer[disney.da[0].used] = disney.data; 00242 disney.da[0].used++; 00243 } //else LOG_MSG("disney overflow 0"); 00244 } 00245 00246 if((disney.control & 0x8) && !(val & 0x8)) { 00247 // emulate a device with 16-byte sound FIFO 00248 if(disney.state != DS_RUNNING) { 00249 disney.interface_det_ext++; 00250 disney.interface_det = 0; 00251 if(disney.interface_det_ext > 5) { 00252 disney.leader = &disney.da[0]; 00253 DISNEY_enable(7000); 00254 } 00255 } 00256 if(disney.interface_det_ext > 5) { 00257 if(disney.da[0].used < DISNEY_SIZE) { 00258 disney.da[0].buffer[disney.da[0].used] = disney.data; 00259 disney.da[0].used++; 00260 } 00261 } 00262 } 00263 00264 // LOG_WARN("DISNEY:Control write %x",val); 00265 if (val&0x10) LOG(LOG_MISC,LOG_ERROR)("DISNEY:Parallel IRQ Enabled"); 00266 disney.control=(Bit8u)val; 00267 break; 00268 } 00269 } 00270 00271 static Bitu disney_read(Bitu port,Bitu iolen) { 00272 (void)iolen;//UNUSED 00273 Bitu retval; 00274 switch (port-DISNEY_BASE) { 00275 case 0: /* Data Port */ 00276 // LOG(LOG_MISC,LOG_NORMAL)("DISNEY:Read from data port"); 00277 return disney.data; 00278 break; 00279 case 1: /* Status Port */ 00280 // LOG(LOG_MISC,"DISNEY:Read from status port %X",disney.status); 00281 retval = 0x07;//0x40; // Stereo-on-1 and (or) New-Stereo DACs present 00282 if(disney.interface_det_ext > 5) { 00283 if (disney.leader && disney.leader->used >= 16){ 00284 retval |= 0x40u; // ack 00285 retval &= ~0x4u; // interrupt 00286 } 00287 } 00288 if(!(disney.data&0x80)) retval |= 0x80; // pin 9 is wired to pin 11 00289 return retval; 00290 break; 00291 case 2: /* Control Port */ 00292 LOG(LOG_MISC,LOG_NORMAL)("DISNEY:Read from control port"); 00293 return disney.control; 00294 break; 00295 } 00296 return 0xff; 00297 } 00298 00299 static void DISNEY_PlayStereo(Bitu len, Bit8u* l, Bit8u* r) { 00300 static Bit8u stereodata[DISNEY_SIZE*2]; 00301 for(Bitu i = 0; i < len; i++) { 00302 stereodata[i*2] = l[i]; 00303 stereodata[i*2+1] = r[i]; 00304 } 00305 disney.chan->AddSamples_s8(len,stereodata); 00306 } 00307 00308 static void DISNEY_CallBack(Bitu len) { 00309 if (!len) return; 00310 if (disney.leader == NULL) return; 00311 00312 // get the smaller used 00313 Bitu real_used; 00314 if(disney.stereo) { 00315 real_used = disney.da[0].used; 00316 if(disney.da[1].used < real_used) real_used = disney.da[1].used; 00317 } else 00318 real_used = disney.leader->used; 00319 00320 if (real_used >= len) { // enough data for now 00321 if(disney.stereo) DISNEY_PlayStereo(len, disney.da[0].buffer, disney.da[1].buffer); 00322 else disney.chan->AddSamples_m8(len,disney.leader->buffer); 00323 00324 // put the rest back to start 00325 for(int i = 0; i < 2; i++) { 00326 // TODO for mono only one 00327 memmove(disney.da[i].buffer,&disney.da[i].buffer[len],DISNEY_SIZE/*real_used*/-len); 00328 disney.da[i].used -= len; 00329 } 00330 // TODO: len > DISNEY 00331 } else { // not enough data 00332 if(disney.stereo) { 00333 Bit8u gapfiller0 = 128; 00334 Bit8u gapfiller1 = 128; 00335 if(real_used) { 00336 gapfiller0 = disney.da[0].buffer[real_used-1]; 00337 gapfiller1 = disney.da[1].buffer[real_used-1]; 00338 } 00339 00340 memset(disney.da[0].buffer+real_used, 00341 gapfiller0,len-real_used); 00342 memset(disney.da[1].buffer+real_used, 00343 gapfiller1,len-real_used); 00344 00345 DISNEY_PlayStereo(len, disney.da[0].buffer, disney.da[1].buffer); 00346 len -= real_used; 00347 00348 } else { // mono 00349 Bit8u gapfiller = 128; //Keep the middle 00350 if(real_used) { 00351 // fix for some stupid game; it outputs 0 at the end of the stream 00352 // causing a click. So if we have at least two bytes availible in the 00353 // buffer and the last one is a 0 then ignore that. 00354 if(disney.leader->buffer[real_used-1]==0) 00355 real_used--; 00356 } 00357 // do it this way because AddSilence sounds like a gnawing mouse 00358 if(real_used) 00359 gapfiller = disney.leader->buffer[real_used-1]; 00360 //LOG_MSG("gapfiller %x, fill len %d, realused %d",gapfiller,len-real_used,real_used); 00361 memset(disney.leader->buffer+real_used, gapfiller, len-real_used); 00362 disney.chan->AddSamples_m8(len, disney.leader->buffer); 00363 } 00364 disney.da[0].used =0; 00365 disney.da[1].used =0; 00366 00367 //LOG_MSG("disney underflow %d",len - real_used); 00368 } 00369 if (disney.last_used+100<PIC_Ticks) { 00370 // disable sound output 00371 PIC_AddEvent(DISNEY_disable,0.0001f); // I think we shouldn't delete the 00372 // mixer while we are inside it 00373 } 00374 } 00375 00376 void CPU_Snap_Back_To_Real_Mode(); 00377 void CPU_Snap_Back_Restore(); 00378 00379 class DISNEY: public Module_base { 00380 private: 00381 IO_ReadHandleObject ReadHandler; 00382 IO_WriteHandleObject WriteHandler; 00383 //FIXME: this conflicts with MPU-401, is this really needed? //IO_WriteHandleObject WriteHandler_cvm; 00384 //MixerObject MixerChan; 00385 public: 00386 DISNEY(Section* configuration):Module_base(configuration) { 00387 Section_prop * section=static_cast<Section_prop *>(configuration); 00388 if(!section->Get_bool("disney")) return; 00389 00390 for(int i = 0; i < 2; i++) { 00391 disney.da[i].used = 0; 00392 disney.da[i].speedcheck_sum = 0; 00393 disney.da[i].speedcheck_failed = false; 00394 disney.da[i].speedcheck_init = false; 00395 } 00396 00397 WriteHandler.Install(DISNEY_BASE,disney_write,IO_MB,3); 00398 ReadHandler.Install(DISNEY_BASE,disney_read,IO_MB,3); 00399 // see above //WriteHandler_cvm.Install(0x330,disney_write,IO_MB,1); 00400 00401 disney.status=0x84; 00402 disney.control=0; 00403 disney.last_used=0; 00404 00405 disney.mo = new MixerObject(); 00406 disney.chan=disney.mo->Install(&DISNEY_CallBack,10000,"DISNEY"); 00407 DISNEY_disable(0); 00408 } 00409 ~DISNEY(){ 00410 CPU_Snap_Back_To_Real_Mode(); 00411 00412 BIOS_SetLPTPort(0,0); 00413 DISNEY_disable(0); 00414 if (disney.mo) 00415 delete disney.mo; 00416 00417 CPU_Snap_Back_Restore(); 00418 } 00419 }; 00420 00421 static DISNEY* test = NULL; 00422 00423 static void DISNEY_ShutDown(Section* sec){ 00424 (void)sec;//UNUSED 00425 if (test) { 00426 delete test; 00427 test = NULL; 00428 } 00429 } 00430 00431 Bitu DISNEY_BasePort() { 00432 return DISNEY_BASE; 00433 } 00434 00435 bool DISNEY_ShouldInit() { 00436 Section_prop *sec = (Section_prop*)control->GetSection("speaker"); 00437 return sec->Get_bool("disney"); 00438 } 00439 00440 bool DISNEY_HasInit() { 00441 return (test != NULL); 00442 } 00443 00444 // parallel port init code will call this depending on port allocation and config. 00445 void DISNEY_Init(unsigned int base_port) { 00446 if (test == NULL) { 00447 DISNEY_BASE = base_port; 00448 LOG(LOG_MISC,LOG_DEBUG)("Allocating Disney Sound emulation on port %xh",DISNEY_BASE); 00449 test = new DISNEY(control->GetSection("speaker")); 00450 } 00451 } 00452 00453 void DISNEY_Init() { 00454 LOG(LOG_MISC,LOG_DEBUG)("Initializing Disney Sound Source emulation"); 00455 00456 AddExitFunction(AddExitFunctionFuncPair(DISNEY_ShutDown),true); 00457 } 00458 00459 // save state support 00460 void *DISNEY_disable_PIC_Event = (void*)((uintptr_t)DISNEY_disable); 00461 00462 void POD_Save_Disney( std::ostream& stream ) 00463 { 00464 const char pod_name[32] = "Disney"; 00465 00466 if( stream.fail() ) return; 00467 if( !test ) return; 00468 if( !disney.chan ) return; 00469 00470 WRITE_POD( &pod_name, pod_name ); 00471 00472 //************************************************ 00473 //************************************************ 00474 //************************************************ 00475 00476 Bit8u dac_leader_idx; 00477 00478 00479 dac_leader_idx = 0xff; 00480 for( int lcv=0; lcv<2; lcv++ ) { 00481 if( disney.leader == &disney.da[lcv] ) { dac_leader_idx = lcv; break; } 00482 } 00483 00484 // ******************************************* 00485 // ******************************************* 00486 // ******************************************* 00487 00488 // - near-pure struct data 00489 WRITE_POD( &disney, disney ); 00490 00491 00492 00493 00494 // - reloc ptr 00495 WRITE_POD( &dac_leader_idx, dac_leader_idx ); 00496 00497 //******************************************* 00498 //******************************************* 00499 //******************************************* 00500 00501 disney.chan->SaveState(stream); 00502 } 00503 00504 void POD_Load_Disney( std::istream& stream ) 00505 { 00506 char pod_name[32] = {0}; 00507 00508 if( stream.fail() ) return; 00509 if( !test ) return; 00510 if( !disney.chan ) return; 00511 00512 // error checking 00513 READ_POD( &pod_name, pod_name ); 00514 if( strcmp( pod_name, "Disney" ) ) { 00515 stream.clear( std::istream::failbit | std::istream::badbit ); 00516 return; 00517 } 00518 00519 //************************************************ 00520 //************************************************ 00521 //************************************************ 00522 00523 Bit8u dac_leader_idx; 00524 MixerObject *mo_old; 00525 MixerChannel *chan_old; 00526 00527 00528 // save old ptrs 00529 mo_old = disney.mo; 00530 chan_old = disney.chan; 00531 00532 //******************************************* 00533 //******************************************* 00534 //******************************************* 00535 00536 // - near-pure struct data 00537 READ_POD( &disney, disney ); 00538 00539 00540 00541 // - reloc ptr 00542 READ_POD( &dac_leader_idx, dac_leader_idx ); 00543 00544 //******************************************* 00545 //******************************************* 00546 //******************************************* 00547 00548 disney.leader = NULL; 00549 if( dac_leader_idx != 0xff ) disney.leader = &disney.da[dac_leader_idx]; 00550 00551 //******************************************* 00552 //******************************************* 00553 //******************************************* 00554 00555 // restore old ptrs 00556 disney.mo = mo_old; 00557 disney.chan = chan_old; 00558 00559 00560 disney.chan->LoadState(stream); 00561 }