DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/mixer.cpp
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 }