DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/mixer.cpp
00001 /*
00002  *  Copyright (C) 2002-2015  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 Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 
00061 #define MIXER_SSIZE 4
00062 #define MIXER_VOLSHIFT 13
00063 
00064 static INLINE Bit16s MIXER_CLIP(Bits SAMP) {
00065     if (SAMP < MAX_AUDIO) {
00066         if (SAMP > MIN_AUDIO)
00067             return SAMP;
00068         else
00069             return MIN_AUDIO;
00070     } else {
00071         return MAX_AUDIO;
00072     }
00073 }
00074 
00075 struct mixedFraction {
00076     unsigned int        w;
00077     unsigned int        fn,fd;
00078 };
00079 
00080 static struct {
00081     Bit32s          work[MIXER_BUFSIZE][2];
00082     Bitu            work_in,work_out,work_wrap;
00083     Bitu            pos,done;
00084     float           mastervol[2];
00085     float           recordvol[2];
00086     MixerChannel*       channels;
00087     Bit32u          freq;
00088     Bit32u          blocksize;
00089     struct mixedFraction samples_per_ms;
00090     struct mixedFraction samples_this_ms;
00091     struct mixedFraction samples_rendered_ms;
00092     bool            nosound;
00093     bool            swapstereo;
00094     bool            sampleaccurate;
00095     bool            prebuffer_wait;
00096     Bitu            prebuffer_samples;
00097     bool            mute;
00098 } mixer;
00099 
00100 bool Mixer_SampleAccurate() {
00101     return mixer.sampleaccurate;
00102 }
00103 
00104 Bit8u MixTemp[MIXER_BUFSIZE];
00105 
00106 inline void MixerChannel::updateSlew(void) {
00107     /* "slew" affects the linear interpolation ramp.
00108      * but, our implementation can only shorten the linear interpolation
00109      * period, it cannot extend it beyond one sample period */
00110     freq_nslew = freq_nslew_want;
00111     if (freq_nslew < freq_n) freq_nslew = freq_n;
00112 
00113     if (freq_nslew_want > 0 && freq_nslew_want < freq_n)
00114         max_change = ((Bit64u)freq_nslew_want * (Bit64u)0x8000) / (Bit64u)freq_n;
00115     else
00116         max_change = 0x7FFFFFFFUL;
00117 }
00118 
00119 MixerChannel * MIXER_AddChannel(MIXER_Handler handler,Bitu freq,const char * name) {
00120     MixerChannel * chan=new MixerChannel();
00121     chan->scale = 1.0;
00122     chan->freq_fslew = 0;
00123     chan->freq_nslew_want = 0;
00124     chan->freq_nslew = 0;
00125     chan->last_sample_write = 0;
00126     chan->current_loaded = false;
00127     chan->handler=handler;
00128     chan->name=name;
00129     chan->msbuffer_i = 0;
00130     chan->msbuffer_o = 0;
00131     chan->freq_n = chan->freq_d = 1;
00132     chan->lowpass_freq = 0;
00133     chan->lowpass_alpha = 0;
00134 
00135     for (unsigned int i=0;i < LOWPASS_ORDER;i++) {
00136         for (unsigned int j=0;j < 2;j++)
00137             chan->lowpass[i][j] = 0;
00138     }
00139 
00140     chan->lowpass_on_load = false;
00141     chan->lowpass_on_out = false;
00142     chan->freq_d_orig = 1;
00143     chan->freq_f = 0;
00144     chan->SetFreq(freq);
00145     chan->next=mixer.channels;
00146     chan->SetVolume(1,1);
00147     chan->enabled=false;
00148     chan->last[0] = chan->last[1] = 0;
00149     chan->delta[0] = chan->delta[1] = 0;
00150     chan->current[0] = chan->current[1] = 0;
00151 
00152     mixer.channels=chan;
00153     return chan;
00154 }
00155 
00156 MixerChannel * MIXER_FirstChannel(void) {
00157     return mixer.channels;
00158 }
00159 
00160 MixerChannel * MIXER_FindChannel(const char * name) {
00161     MixerChannel * chan=mixer.channels;
00162     while (chan) {
00163         if (!strcasecmp(chan->name,name)) break;
00164         chan=chan->next;
00165     }
00166     return chan;
00167 }
00168 
00169 void MIXER_DelChannel(MixerChannel* delchan) {
00170     MixerChannel * chan=mixer.channels;
00171     MixerChannel * * where=&mixer.channels;
00172     while (chan) {
00173         if (chan==delchan) {
00174             *where=chan->next;
00175             delete delchan;
00176             return;
00177         }
00178         where=&chan->next;
00179         chan=chan->next;
00180     }
00181 }
00182 
00183 void MixerChannel::UpdateVolume(void) {
00184     volmul[0]=(Bits)((1 << MIXER_VOLSHIFT)*scale*volmain[0]);
00185     volmul[1]=(Bits)((1 << MIXER_VOLSHIFT)*scale*volmain[1]);
00186 }
00187 
00188 void MixerChannel::SetVolume(float _left,float _right) {
00189     volmain[0]=_left;
00190     volmain[1]=_right;
00191     UpdateVolume();
00192 }
00193 
00194 void MixerChannel::SetScale( float f ) {
00195     scale = f;
00196     UpdateVolume();
00197 }
00198 
00199 static void MIXER_FillUp(void);
00200 
00201 void MixerChannel::Enable(bool _yesno) {
00202     if (_yesno==enabled) return;
00203     enabled=_yesno;
00204     if (!enabled) freq_f=0;
00205 }
00206 
00207 void MixerChannel::lowpassUpdate() {
00208     if (lowpass_freq != 0) {
00209         double timeInterval;
00210         double tau,talpha;
00211 
00212         if (freq_n > freq_d) { // source -> dest mixer rate ratio is > 100%
00213             timeInterval = (double)freq_d_orig / freq_n; // will filter on sample load at source rate
00214             lowpass_on_load = true;
00215             lowpass_on_out = false;
00216         }
00217         else {
00218             timeInterval = (double)1.0 / mixer.freq; // will filter mixer output at mixer rate
00219             lowpass_on_load = false;
00220             lowpass_on_out = true;
00221         }
00222 
00223         tau = 1.0 / (lowpass_freq * 2 * M_PI);
00224         talpha = timeInterval / (tau + timeInterval);
00225         lowpass_alpha = (Bitu)(talpha * 0x10000); // double -> 16.16 fixed point
00226 
00227 //      LOG_MSG("Lowpass freq_n=%u freq_d=%u timeInterval=%.12f tau=%.12f alpha=%.6f onload=%u onout=%u",
00228 //          freq_n,freq_d_orig,timeInterval,tau,talpha,lowpass_on_load,lowpass_on_out);
00229     }
00230     else {
00231         lowpass_on_load = false;
00232         lowpass_on_out = false;
00233     }
00234 }
00235 
00236 inline Bit32s MixerChannel::lowpassStep(Bit32s in,const unsigned int iteration,const unsigned int channel) {
00237     const Bit64s m1 = (Bit64s)in * (Bit64s)lowpass_alpha;
00238     const Bit64s m2 = ((Bit64s)lowpass[iteration][channel] << ((Bit64s)16)) - ((Bit64s)lowpass[iteration][channel] * (Bit64s)lowpass_alpha);
00239     const Bit32s ns = (Bit32s)((m1 + m2) >> (Bit64s)16);
00240     lowpass[iteration][channel] = ns;
00241     return ns;
00242 }
00243 
00244 inline void MixerChannel::lowpassProc(Bit32s ch[2]) {
00245     for (unsigned int i=0;i < lowpass_order;i++) {
00246         for (unsigned int c=0;c < 2;c++)
00247             ch[c] = lowpassStep(ch[c],i,c);
00248     }
00249 }
00250 
00251 void MixerChannel::SetLowpassFreq(Bitu _freq,unsigned int order) {
00252     if (order > LOWPASS_ORDER) order = LOWPASS_ORDER;
00253     if (_freq == lowpass_freq && lowpass_order == order) return;
00254     lowpass_order = order;
00255     lowpass_freq = _freq;
00256     lowpassUpdate();
00257 }
00258 
00259 void MixerChannel::SetSlewFreq(Bitu _freq) {
00260     freq_nslew_want = _freq;
00261     updateSlew();
00262 }
00263 
00264 void MixerChannel::SetFreq(Bitu _freq,Bitu _den) {
00265     if (freq_n == _freq && freq_d == freq_d_orig)
00266         return;
00267 
00268     if (freq_d_orig != _den) {
00269         Bit64u tmp = (Bit64u)freq_f * (Bit64u)_den * (Bit64u)mixer.freq;
00270         freq_f = freq_fslew = (unsigned int)(tmp / (Bit64u)freq_d_orig);
00271     }
00272 
00273     freq_n = _freq;
00274     freq_d = _den * mixer.freq;
00275     freq_d_orig = _den;
00276     updateSlew();
00277     lowpassUpdate();
00278 }
00279 
00280 void CAPTURE_MultiTrackAddWave(Bit32u freq, Bit32u len, Bit16s * data,const char *name);
00281 
00282 void MixerChannel::EndFrame(Bitu samples) {
00283     if (CaptureState & CAPTURE_MULTITRACK_WAVE) {// TODO: should be a separate call!
00284         Bit16s convert[1024][2];
00285         Bitu cnv = msbuffer_o;
00286         Bitu padding = 0;
00287 
00288         if (cnv > samples)
00289             cnv = samples;
00290         else
00291             padding = samples - cnv;
00292 
00293         if (cnv > 0) {
00294             Bit32s volscale1 = (Bit32s)(mixer.recordvol[0] * (1 << MIXER_VOLSHIFT));
00295             Bit32s volscale2 = (Bit32s)(mixer.recordvol[1] * (1 << MIXER_VOLSHIFT));
00296 
00297             if (cnv > 1024) cnv = 1024;
00298             for (Bitu i=0;i<cnv;i++) {
00299                 convert[i][0]=MIXER_CLIP(((Bit64s)msbuffer[i][0] * (Bit64s)volscale1) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT));
00300                 convert[i][1]=MIXER_CLIP(((Bit64s)msbuffer[i][1] * (Bit64s)volscale2) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT));
00301             }
00302             CAPTURE_MultiTrackAddWave(mixer.freq,cnv,(Bit16s*)convert,name);
00303         }
00304 
00305         if (padding > 0) {
00306             if (padding > 1024) padding = 1024;
00307             memset(&convert[0][0],0,padding*sizeof(Bit16s)*2);
00308             CAPTURE_MultiTrackAddWave(mixer.freq,padding,(Bit16s*)convert,name);
00309         }
00310     }
00311 
00312     rend_n = rend_d = 0;
00313     if (msbuffer_o <= samples) {
00314         msbuffer_o = 0;
00315         msbuffer_i = 0;
00316     }
00317     else {
00318         msbuffer_o -= samples;
00319         if (msbuffer_i >= samples) msbuffer_i -= samples;
00320         else msbuffer_i = 0;
00321         memmove(&msbuffer[0][0],&msbuffer[samples][0],msbuffer_o*sizeof(Bit32s)*2/*stereo*/);
00322     }
00323 
00324     last_sample_write -= (unsigned int)samples;
00325 }
00326 
00327 void MixerChannel::Mix(Bitu whole,Bitu frac) {
00328     unsigned int patience = 2;
00329     Bitu upto;
00330 
00331     if (whole <= rend_n) return;
00332     assert(whole <= mixer.samples_this_ms.w);
00333     assert(rend_n < mixer.samples_this_ms.w);
00334     Bit32s *outptr = &mixer.work[mixer.work_in+rend_n][0];
00335 
00336     if (!enabled) {
00337         rend_n = whole;
00338         rend_d = frac;
00339         return;
00340     }
00341 
00342     // HACK: We iterate twice only because of the Sound Blaster emulation. No other emulation seems to need this.
00343     rendering_to_n = whole;
00344     rendering_to_d = frac;
00345     while (msbuffer_o < whole) {
00346         Bit64u todo = (Bit64u)(whole - msbuffer_o) * (Bit64u)freq_n;
00347         todo += (Bit64u)freq_f;
00348         todo += (Bit64u)freq_d - (Bit64u)1;
00349         todo /= (Bit64u)freq_d;
00350         if (!current_loaded) todo++;
00351         handler(todo);
00352 
00353         if (--patience == 0) break;
00354     }
00355 
00356     if (msbuffer_o < whole)
00357         padFillSampleInterpolation(whole);
00358 
00359     upto = whole;
00360     if (upto > msbuffer_o) upto = msbuffer_o;
00361 
00362     if (lowpass_on_out) { /* before rendering out to mixer, process samples with lowpass filter */
00363         Bitu t_rend_n = rend_n;
00364         Bitu t_msbuffer_i = msbuffer_i;
00365 
00366         while (t_rend_n < whole && t_msbuffer_i < upto) {
00367             lowpassProc(msbuffer[t_msbuffer_i]);
00368             t_msbuffer_i++;
00369             t_rend_n++;
00370         }
00371     }
00372 
00373     if (mixer.swapstereo) {
00374         while (rend_n < whole && msbuffer_i < upto) {
00375             *outptr++ += msbuffer[msbuffer_i][1];
00376             *outptr++ += msbuffer[msbuffer_i][0];
00377             msbuffer_i++;
00378             rend_n++;
00379         }
00380     }
00381     else {
00382         while (rend_n < whole && msbuffer_i < upto) {
00383             *outptr++ += msbuffer[msbuffer_i][0];
00384             *outptr++ += msbuffer[msbuffer_i][1];
00385             msbuffer_i++;
00386             rend_n++;
00387         }
00388     }
00389 
00390     rend_n = whole;
00391     rend_d = frac;
00392 }
00393 
00394 void MixerChannel::AddSilence(void) {
00395 }
00396 
00397 template<class Type,bool stereo,bool signeddata,bool nativeorder,bool T_lowpass>
00398 inline void MixerChannel::loadCurrentSample(Bitu &len, const Type* &data) {
00399     last[0] = current[0];
00400     last[1] = current[1];
00401 
00402     if (sizeof(Type) == 1) {
00403         const uint8_t xr = signeddata ? 0x00 : 0x80;
00404 
00405         len--;
00406         current[0] = ((Bit8s)((*data++) ^ xr)) << 8;
00407         if (stereo)
00408             current[1] = ((Bit8s)((*data++) ^ xr)) << 8;
00409         else
00410             current[1] = current[0];
00411     }
00412     else if (sizeof(Type) == 2) {
00413         const uint16_t xr = signeddata ? 0x0000 : 0x8000;
00414         uint16_t d;
00415 
00416         len--;
00417         if (nativeorder) d = ((Bit16u)((*data++) ^ xr));
00418         else d = host_readw((HostPt)(data++)) ^ xr;
00419         current[0] = (Bit16s)d;
00420         if (stereo) {
00421             if (nativeorder) d = ((Bit16u)((*data++) ^ xr));
00422             else d = host_readw((HostPt)(data++)) ^ xr;
00423             current[1] = (Bit16s)d;
00424         }
00425         else {
00426             current[1] = current[0];
00427         }
00428     }
00429     else if (sizeof(Type) == 4) {
00430         const uint32_t xr = signeddata ? 0x00000000UL : 0x80000000UL;
00431         uint32_t d;
00432 
00433         len--;
00434         if (nativeorder) d = ((Bit32u)((*data++) ^ xr));
00435         else d = host_readd((HostPt)(data++)) ^ xr;
00436         current[0] = (Bit32s)d;
00437         if (stereo) {
00438             if (nativeorder) d = ((Bit32u)((*data++) ^ xr));
00439             else d = host_readd((HostPt)(data++)) ^ xr;
00440             current[1] = (Bit32s)d;
00441         }
00442         else {
00443             current[1] = current[0];
00444         }
00445     }
00446     else {
00447         current[0] = current[1] = 0;
00448         len = 0;
00449     }
00450 
00451     if (T_lowpass && lowpass_on_load)
00452         lowpassProc(current);
00453 
00454     if (stereo) {
00455         delta[0] = current[0] - last[0];
00456         delta[1] = current[1] - last[1];
00457     }
00458     else {
00459         delta[1] = delta[0] = current[0] - last[0];
00460     }
00461 
00462     if (freq_nslew_want != 0) {
00463         if (delta[0] < -max_change) delta[0] = -max_change;
00464         else if (delta[0] > max_change) delta[0] = max_change;
00465 
00466         if (stereo) {
00467             if (delta[1] < -max_change) delta[1] = -max_change;
00468             else if (delta[1] > max_change) delta[1] = max_change;
00469         }
00470         else {
00471             delta[1] = delta[0];
00472         }
00473     }
00474 
00475     current_loaded = true;
00476 }
00477 
00478 inline void MixerChannel::padFillSampleInterpolation(const Bitu upto) {
00479     finishSampleInterpolation(upto);
00480     if (msbuffer_o < upto) {
00481         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
00482 
00483         while (msbuffer_o < upto) {
00484             msbuffer[msbuffer_o][0] = current[0];
00485             msbuffer[msbuffer_o][1] = current[1];
00486             msbuffer_o++;
00487         }
00488     }
00489 }
00490 
00491 void MixerChannel::finishSampleInterpolation(const Bitu upto) {
00492     if (!current_loaded) return;
00493     runSampleInterpolation(upto);
00494 }
00495 
00496 double MixerChannel::timeSinceLastSample(void) {
00497     Bits delta = (Bits)mixer.samples_rendered_ms.w - (Bits)last_sample_write;
00498     return ((double)delta) / mixer.freq;
00499 }
00500 
00501 inline bool MixerChannel::runSampleInterpolation(const Bitu upto) {
00502     int sample;
00503 
00504     if (msbuffer_o >= upto)
00505         return false;
00506 
00507     while (freq_fslew < freq_d) {
00508         sample = last[0] + (int)(((int64_t)delta[0] * (int64_t)freq_fslew) / (int64_t)freq_d);
00509         msbuffer[msbuffer_o][0] = sample * volmul[0];
00510         sample = last[1] + (int)(((int64_t)delta[1] * (int64_t)freq_fslew) / (int64_t)freq_d);
00511         msbuffer[msbuffer_o][1] = sample * volmul[1];
00512 
00513         freq_f += freq_n;
00514         freq_fslew += freq_nslew;
00515         if ((++msbuffer_o) >= upto)
00516             return false;
00517     }
00518 
00519     current[0] = last[0] + delta[0];
00520     current[1] = last[1] + delta[1];
00521     while (freq_f < freq_d) {
00522         msbuffer[msbuffer_o][0] = current[0] * volmul[0];
00523         msbuffer[msbuffer_o][1] = current[1] * volmul[1];
00524 
00525         freq_f += freq_n;
00526         if ((++msbuffer_o) >= upto)
00527             return false;
00528     }
00529 
00530     return true;
00531 }
00532 
00533 template<class Type,bool stereo,bool signeddata,bool nativeorder>
00534 inline void MixerChannel::AddSamples(Bitu len, const Type* data) {
00535     last_sample_write = mixer.samples_rendered_ms.w;
00536 
00537     if (msbuffer_o >= 2048) {
00538         fprintf(stderr,"WARNING: addSample overrun (immediate)\n");
00539         return;
00540     }
00541 
00542     if (!current_loaded) {
00543         if (len == 0) return;
00544 
00545         loadCurrentSample<Type,stereo,signeddata,nativeorder,false>(len,data);
00546         if (len == 0) {
00547             freq_f = freq_fslew = freq_d; /* encourage loading next round */
00548             return;
00549         }
00550 
00551         loadCurrentSample<Type,stereo,signeddata,nativeorder,false>(len,data);
00552         freq_f = freq_fslew = 0; /* interpolate now from what we just loaded */
00553     }
00554 
00555     if (lowpass_on_load) {
00556         for (;;) {
00557             if (freq_f >= freq_d) {
00558                 if (len == 0) break;
00559                 loadCurrentSample<Type,stereo,signeddata,nativeorder,true>(len,data);
00560                 freq_f -= freq_d;
00561                 freq_fslew = freq_f;
00562             }
00563             if (!runSampleInterpolation(2048))
00564                 break;
00565         }
00566     }
00567     else {
00568         for (;;) {
00569             if (freq_f >= freq_d) {
00570                 if (len == 0) break;
00571                 loadCurrentSample<Type,stereo,signeddata,nativeorder,false>(len,data);
00572                 freq_f -= freq_d;
00573                 freq_fslew = freq_f;
00574             }
00575             if (!runSampleInterpolation(2048))
00576                 break;
00577         }
00578     }
00579 }
00580 
00581 void MixerChannel::AddSamples_m8(Bitu len, const Bit8u * data) {
00582     AddSamples<Bit8u,false,false,true>(len,data);
00583 }
00584 void MixerChannel::AddSamples_s8(Bitu len,const Bit8u * data) {
00585     AddSamples<Bit8u,true,false,true>(len,data);
00586 }
00587 void MixerChannel::AddSamples_m8s(Bitu len,const Bit8s * data) {
00588     AddSamples<Bit8s,false,true,true>(len,data);
00589 }
00590 void MixerChannel::AddSamples_s8s(Bitu len,const Bit8s * data) {
00591     AddSamples<Bit8s,true,true,true>(len,data);
00592 }
00593 void MixerChannel::AddSamples_m16(Bitu len,const Bit16s * data) {
00594     AddSamples<Bit16s,false,true,true>(len,data);
00595 }
00596 void MixerChannel::AddSamples_s16(Bitu len,const Bit16s * data) {
00597     AddSamples<Bit16s,true,true,true>(len,data);
00598 }
00599 void MixerChannel::AddSamples_m16u(Bitu len,const Bit16u * data) {
00600     AddSamples<Bit16u,false,false,true>(len,data);
00601 }
00602 void MixerChannel::AddSamples_s16u(Bitu len,const Bit16u * data) {
00603     AddSamples<Bit16u,true,false,true>(len,data);
00604 }
00605 void MixerChannel::AddSamples_m32(Bitu len,const Bit32s * data) {
00606     AddSamples<Bit32s,false,true,true>(len,data);
00607 }
00608 void MixerChannel::AddSamples_s32(Bitu len,const Bit32s * data) {
00609     AddSamples<Bit32s,true,true,true>(len,data);
00610 }
00611 void MixerChannel::AddSamples_m16_nonnative(Bitu len,const Bit16s * data) {
00612     AddSamples<Bit16s,false,true,false>(len,data);
00613 }
00614 void MixerChannel::AddSamples_s16_nonnative(Bitu len,const Bit16s * data) {
00615     AddSamples<Bit16s,true,true,false>(len,data);
00616 }
00617 void MixerChannel::AddSamples_m16u_nonnative(Bitu len,const Bit16u * data) {
00618     AddSamples<Bit16u,false,false,false>(len,data);
00619 }
00620 void MixerChannel::AddSamples_s16u_nonnative(Bitu len,const Bit16u * data) {
00621     AddSamples<Bit16u,true,false,false>(len,data);
00622 }
00623 void MixerChannel::AddSamples_m32_nonnative(Bitu len,const Bit32s * data) {
00624     AddSamples<Bit32s,false,true,false>(len,data);
00625 }
00626 void MixerChannel::AddSamples_s32_nonnative(Bitu len,const Bit32s * data) {
00627     AddSamples<Bit32s,true,true,false>(len,data);
00628 }
00629 
00630 extern bool ticksLocked;
00631 
00632 #if 0//unused
00633 static inline bool Mixer_irq_important(void) {
00634     /* In some states correct timing of the irqs is more important then 
00635      * non stuttering audo */
00636     return (ticksLocked || (CaptureState & (CAPTURE_WAVE|CAPTURE_VIDEO|CAPTURE_MULTITRACK_WAVE)));
00637 }
00638 #endif
00639 
00640 unsigned long long mixer_sample_counter = 0;
00641 double mixer_start_pic_time = 0;
00642 
00643 /* once a millisecond, render 1ms of audio, up to whole samples */
00644 static void MIXER_MixData(Bitu fracs/*render up to*/) {
00645     unsigned int prev_rendered = mixer.samples_rendered_ms.w;
00646     MixerChannel *chan = mixer.channels;
00647     unsigned int whole,frac;
00648     bool endframe = false;
00649 
00650     if (fracs >= (Bitu)(mixer.samples_this_ms.w * mixer.samples_this_ms.fd)) {
00651         fracs = (Bitu)(mixer.samples_this_ms.w * mixer.samples_this_ms.fd);
00652         endframe = true;
00653     }
00654 
00655     whole = (unsigned int)(fracs / mixer.samples_this_ms.fd);
00656     frac = (unsigned int)(fracs % mixer.samples_this_ms.fd);
00657     if (whole <= mixer.samples_rendered_ms.w) return;
00658 
00659     while (chan) {
00660         chan->Mix(whole,fracs);
00661         if (endframe) chan->EndFrame(mixer.samples_this_ms.w);
00662         chan=chan->next;
00663     }
00664 
00665     if (CaptureState & (CAPTURE_WAVE|CAPTURE_VIDEO)) {
00666         Bit32s volscale1 = (Bit32s)(mixer.recordvol[0] * (1 << MIXER_VOLSHIFT));
00667         Bit32s volscale2 = (Bit32s)(mixer.recordvol[1] * (1 << MIXER_VOLSHIFT));
00668         Bit16s convert[1024][2];
00669         Bitu added = whole - prev_rendered;
00670         if (added>1024) added=1024;
00671         Bitu readpos = mixer.work_in + prev_rendered;
00672         for (Bitu i=0;i<added;i++) {
00673             convert[i][0]=MIXER_CLIP(((Bit64s)mixer.work[readpos][0] * (Bit64s)volscale1) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT));
00674             convert[i][1]=MIXER_CLIP(((Bit64s)mixer.work[readpos][1] * (Bit64s)volscale2) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT));
00675             readpos++;
00676         }
00677         assert(readpos <= MIXER_BUFSIZE);
00678         CAPTURE_AddWave( mixer.freq, added, (Bit16s*)convert );
00679     }
00680 
00681     mixer.samples_rendered_ms.w = whole;
00682     mixer.samples_rendered_ms.fd = frac;
00683     mixer_sample_counter += mixer.samples_rendered_ms.w - prev_rendered;
00684 }
00685 
00686 static void MIXER_FillUp(void) {
00687     SDL_LockAudio();
00688     float index = PIC_TickIndex();
00689     if (index < 0) index = 0;
00690     MIXER_MixData((Bitu)(index * ((Bitu)mixer.samples_this_ms.w * (Bitu)mixer.samples_this_ms.fd)));
00691     SDL_UnlockAudio();
00692 }
00693 
00694 void MixerChannel::FillUp(void) {
00695     MIXER_FillUp();
00696 }
00697 
00698 static void MIXER_Mix(void) {
00699     Bitu thr;
00700 
00701     SDL_LockAudio();
00702 
00703     /* render */
00704     assert((mixer.work_in+mixer.samples_per_ms.w) <= MIXER_BUFSIZE);
00705     MIXER_MixData((Bitu)mixer.samples_this_ms.w * (Bitu)mixer.samples_this_ms.fd);
00706     mixer.work_in += mixer.samples_this_ms.w;
00707 
00708     /* how many samples for the next ms? */
00709     mixer.samples_this_ms.w = mixer.samples_per_ms.w;
00710     mixer.samples_this_ms.fn += mixer.samples_per_ms.fn;
00711     if (mixer.samples_this_ms.fn >= mixer.samples_this_ms.fd) {
00712         mixer.samples_this_ms.fn -= mixer.samples_this_ms.fd;
00713         mixer.samples_this_ms.w++;
00714     }
00715 
00716     /* advance. we use in/out & wrap pointers to make sure the rendering code
00717      * doesn't have to worry about circular buffer wraparound. */
00718     thr = mixer.blocksize;
00719     if (thr < mixer.samples_this_ms.w) thr = mixer.samples_this_ms.w;
00720     if ((mixer.work_in+thr) > MIXER_BUFSIZE) {
00721         mixer.work_wrap = mixer.work_in;
00722         mixer.work_in = 0;
00723     }
00724     assert((mixer.work_in+thr) <= MIXER_BUFSIZE);
00725     assert((mixer.work_in+mixer.samples_this_ms.w) <= MIXER_BUFSIZE);
00726     memset(&mixer.work[mixer.work_in][0],0,sizeof(Bit32s)*2*mixer.samples_this_ms.w);
00727     mixer.samples_rendered_ms.fn = 0;
00728     mixer.samples_rendered_ms.w = 0;
00729     SDL_UnlockAudio();
00730     MIXER_FillUp();
00731 }
00732 
00733 static void MIXER_CallBack(void * userdata, Uint8 *stream, int len) {
00734     (void)userdata;//UNUSED
00735     Bit32s volscale1 = (Bit32s)(mixer.mastervol[0] * (1 << MIXER_VOLSHIFT));
00736     Bit32s volscale2 = (Bit32s)(mixer.mastervol[1] * (1 << MIXER_VOLSHIFT));
00737     Bitu need = (Bitu)len/MIXER_SSIZE;
00738     Bit16s *output = (Bit16s*)stream;
00739     int remains;
00740     Bit32s *in;
00741 
00742     if (mixer.mute)
00743         mixer.work_in = mixer.work_out = 0;
00744 
00745     if (mixer.prebuffer_wait) {
00746         remains = (int)mixer.work_in - (int)mixer.work_out;
00747         if (remains < 0) remains += (int)mixer.work_wrap;
00748         if (remains < 0) remains = 0;
00749 
00750         if ((unsigned int)remains >= mixer.prebuffer_samples)
00751             mixer.prebuffer_wait = false;
00752     }
00753 
00754     if (!mixer.prebuffer_wait) {
00755         in = &mixer.work[mixer.work_out][0];
00756         while (need > 0) {
00757             if (mixer.work_out == mixer.work_in) break;
00758             *output++ = MIXER_CLIP((((Bit64s)(*in++)) * (Bit64s)volscale1) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT));
00759             *output++ = MIXER_CLIP((((Bit64s)(*in++)) * (Bit64s)volscale2) >> (MIXER_VOLSHIFT + MIXER_VOLSHIFT));
00760             mixer.work_out++;
00761             if (mixer.work_out >= mixer.work_wrap) {
00762                 mixer.work_out = 0;
00763                 in = &mixer.work[mixer.work_out][0];
00764             }
00765             need--;
00766         }
00767     }
00768 
00769     if (need > 0)
00770         mixer.prebuffer_wait = true;
00771 
00772     while (need > 0) {
00773         *output++ = 0;
00774         *output++ = 0;
00775         need--;
00776     }
00777 
00778     remains = (int)mixer.work_in - (int)mixer.work_out;
00779     if (remains < 0) remains += (int)mixer.work_wrap;
00780 
00781     if ((unsigned long)remains >= (mixer.blocksize*2UL)) {
00782         /* drop some samples to keep time */
00783         unsigned int drop;
00784 
00785         if ((unsigned long)remains >= (mixer.blocksize*3UL)) // hard drop
00786             drop = ((unsigned int)remains - (unsigned int)(mixer.blocksize));
00787         else // subtle drop
00788             drop = (((unsigned int)remains - (unsigned int)(mixer.blocksize*2)) / 50U) + 1;
00789 
00790         while (drop > 0) {
00791             mixer.work_out++;
00792             if (mixer.work_out >= mixer.work_wrap) mixer.work_out = 0;
00793             drop--;
00794         }
00795     }
00796 }
00797 
00798 static void MIXER_Stop(Section* sec) {
00799     (void)sec;//UNUSED
00800 }
00801 
00802 class MIXER : public Program {
00803 public:
00804     void MakeVolume(char * scan,float & vol0,float & vol1) {
00805         Bitu w=0;
00806         bool db=(toupper(*scan)=='D');
00807         if (db) scan++;
00808         while (*scan) {
00809             if (*scan==':') {
00810                 ++scan;w=1;
00811             }
00812             char * before=scan;
00813             float val=(float)strtod(scan,&scan);
00814             if (before==scan) {
00815                 ++scan;continue;
00816             }
00817             if (!db) val/=100;
00818             else val=powf(10.0f,(float)val/20.0f);
00819             if (val<0) val=1.0f;
00820             if (!w) {
00821                 vol0=val;
00822             } else {
00823                 vol1=val;
00824             }
00825         }
00826         if (!w) vol1=vol0;
00827     }
00828 
00829     void Run(void) {
00830         if(cmd->FindExist("/LISTMIDI")) {
00831             ListMidi();
00832             return;
00833         }
00834         if (cmd->FindString("MASTER",temp_line,false)) {
00835             MakeVolume((char *)temp_line.c_str(),mixer.mastervol[0],mixer.mastervol[1]);
00836         }
00837         if (cmd->FindString("RECORD",temp_line,false)) {
00838             MakeVolume((char *)temp_line.c_str(),mixer.recordvol[0],mixer.recordvol[1]);
00839         }
00840         MixerChannel * chan=mixer.channels;
00841         while (chan) {
00842             if (cmd->FindString(chan->name,temp_line,false)) {
00843                 MakeVolume((char *)temp_line.c_str(),chan->volmain[0],chan->volmain[1]);
00844             }
00845             chan->UpdateVolume();
00846             chan=chan->next;
00847         }
00848         if (cmd->FindExist("/NOSHOW")) return;
00849         chan=mixer.channels;
00850         WriteOut("Channel  Main    Main(dB)\n");
00851         ShowVolume("MASTER",mixer.mastervol[0],mixer.mastervol[1]);
00852         ShowVolume("RECORD",mixer.recordvol[0],mixer.recordvol[1]);
00853         for (chan=mixer.channels;chan;chan=chan->next) 
00854             ShowVolume(chan->name,chan->volmain[0],chan->volmain[1]);
00855     }
00856 private:
00857     void ShowVolume(const char * name,float vol0,float vol1) {
00858         WriteOut("%-8s %3.0f:%-3.0f  %+3.2f:%-+3.2f \n",name,
00859             vol0*100,vol1*100,
00860             20*log(vol0)/log(10.0f),20*log(vol1)/log(10.0f)
00861         );
00862     }
00863 
00864     void ListMidi(){
00865 #if defined (WIN32)
00866         unsigned int total = midiOutGetNumDevs();   
00867         for(unsigned int i=0;i<total;i++) {
00868             MIDIOUTCAPS mididev;
00869             midiOutGetDevCaps(i, &mididev, sizeof(MIDIOUTCAPS));
00870             WriteOut("%2d\t \"%s\"\n",i,mididev.szPname);
00871         }
00872 #endif
00873     return;
00874     };
00875 
00876 };
00877 
00878 static void MIXER_ProgramStart(Program * * make) {
00879     *make=new MIXER;
00880 }
00881 
00882 MixerChannel* MixerObject::Install(MIXER_Handler handler,Bitu freq,const char * name){
00883     if(!installed) {
00884         if(strlen(name) > 31) E_Exit("Too long mixer channel name");
00885         safe_strncpy(m_name,name,32);
00886         installed = true;
00887         return MIXER_AddChannel(handler,freq,name);
00888     } else {
00889         E_Exit("already added mixer channel.");
00890         return 0; //Compiler happy
00891     }
00892 }
00893 
00894 MixerObject::~MixerObject(){
00895     if(!installed) return;
00896     MIXER_DelChannel(MIXER_FindChannel(m_name));
00897 }
00898 
00899 void MENU_mute(bool enabled) {
00900     mixer.mute=enabled;
00901     mainMenu.get_item("mixer_mute").check(mixer.mute).refresh_item(mainMenu);
00902 }
00903 
00904 bool MENU_get_mute(void) {
00905     return mixer.mute;
00906 }
00907 
00908 void MENU_swapstereo(bool enabled) {
00909     mixer.swapstereo=enabled;
00910     mainMenu.get_item("mixer_swapstereo").check(mixer.swapstereo).refresh_item(mainMenu);
00911 }
00912 
00913 bool MENU_get_swapstereo(void) {
00914     return mixer.swapstereo;
00915 }
00916 
00917 void MAPPER_VolumeUp(bool pressed) {
00918     if (!pressed) return;
00919 
00920     double newvol = ((mixer.mastervol[0] + mixer.mastervol[1]) / 0.7) * 0.5;
00921 
00922     if (newvol > 1) newvol = 1;
00923 
00924     mixer.mastervol[0] = mixer.mastervol[1] = newvol;
00925 
00926     LOG(LOG_MISC,LOG_NORMAL)("Master volume UP to %.3f%%",newvol * 100);
00927 }
00928 
00929 void MAPPER_VolumeDown(bool pressed) {
00930     if (!pressed) return;
00931 
00932     double newvol = (mixer.mastervol[0] + mixer.mastervol[1]) * 0.7 * 0.5;
00933 
00934     if (fabs(newvol - 1.0) < 0.25)
00935         newvol = 1;
00936 
00937     mixer.mastervol[0] = mixer.mastervol[1] = newvol;
00938 
00939     LOG(LOG_MISC,LOG_NORMAL)("Master volume DOWN to %.3f%%",newvol * 100);
00940 }
00941 
00942 void MAPPER_RecVolumeUp(bool pressed) {
00943     if (!pressed) return;
00944 
00945     double newvol = ((mixer.recordvol[0] + mixer.recordvol[1]) / 0.7) * 0.5;
00946 
00947     if (newvol > 1) newvol = 1;
00948 
00949     mixer.recordvol[0] = mixer.recordvol[1] = newvol;
00950 
00951     LOG(LOG_MISC,LOG_NORMAL)("Recording volume UP to %.3f%%",newvol * 100);
00952 }
00953 
00954 void MAPPER_RecVolumeDown(bool pressed) {
00955     if (!pressed) return;
00956 
00957     double newvol = (mixer.recordvol[0] + mixer.recordvol[1]) * 0.7 * 0.5;
00958 
00959     if (fabs(newvol - 1.0) < 0.25)
00960         newvol = 1;
00961 
00962     mixer.recordvol[0] = mixer.recordvol[1] = newvol;
00963 
00964     LOG(LOG_MISC,LOG_NORMAL)("Recording volume DOWN to %.3f%%",newvol * 100);
00965 }
00966 
00967 void MIXER_Controls_Init() {
00968     DOSBoxMenu::item *item;
00969 
00970     MAPPER_AddHandler(MAPPER_VolumeUp  ,MK_kpplus, MMODHOST,"volup","VolUp",&item);
00971     item->set_text("Increase volume");
00972     
00973     MAPPER_AddHandler(MAPPER_VolumeDown,MK_kpminus,MMODHOST,"voldown","VolDown",&item);
00974     item->set_text("Decrease volume");
00975 
00976     MAPPER_AddHandler(MAPPER_RecVolumeUp  ,MK_nothing, 0,"recvolup","RecVolUp",&item);
00977     item->set_text("Increase recording volume");
00978 
00979     MAPPER_AddHandler(MAPPER_RecVolumeDown,MK_nothing, 0,"recvoldown","RecVolDn",&item);
00980     item->set_text("Decrease recording volume");
00981 }
00982 
00983 void MIXER_Init() {
00984     AddExitFunction(AddExitFunctionFuncPair(MIXER_Stop));
00985 
00986     LOG(LOG_MISC,LOG_DEBUG)("Initializing DOSBox audio mixer");
00987 
00988     Section_prop * section=static_cast<Section_prop *>(control->GetSection("mixer"));
00989     /* Read out config section */
00990     mixer.freq=(unsigned int)section->Get_int("rate");
00991     mixer.nosound=section->Get_bool("nosound");
00992     mixer.blocksize=(unsigned int)section->Get_int("blocksize");
00993     mixer.swapstereo=section->Get_bool("swapstereo");
00994     mixer.sampleaccurate=section->Get_bool("sample accurate");//FIXME: Make this bool mean something again!
00995     mixer.mute=false;
00996 
00997     /* Initialize the internal stuff */
00998     mixer.prebuffer_samples=0;
00999     mixer.prebuffer_wait=true;
01000     mixer.channels=0;
01001     mixer.pos=0;
01002     mixer.done=0;
01003     memset(mixer.work,0,sizeof(mixer.work));
01004     mixer.mastervol[0]=1.0f;
01005     mixer.mastervol[1]=1.0f;
01006     mixer.recordvol[0]=1.0f;
01007     mixer.recordvol[1]=1.0f;
01008 
01009     /* Start the Mixer using SDL Sound at 22 khz */
01010     SDL_AudioSpec spec;
01011     SDL_AudioSpec obtained;
01012 
01013     spec.freq=(int)mixer.freq;
01014     spec.format=AUDIO_S16SYS;
01015     spec.channels=2;
01016     spec.callback=MIXER_CallBack;
01017     spec.userdata=NULL;
01018     spec.samples=(Uint16)mixer.blocksize;
01019 
01020     if (mixer.nosound) {
01021         LOG(LOG_MISC,LOG_DEBUG)("MIXER:No Sound Mode Selected.");
01022         TIMER_AddTickHandler(MIXER_Mix);
01023     } else if (SDL_OpenAudio(&spec, &obtained) <0 ) {
01024         mixer.nosound = true;
01025         LOG(LOG_MISC,LOG_DEBUG)("MIXER:Can't open audio: %s , running in nosound mode.",SDL_GetError());
01026         TIMER_AddTickHandler(MIXER_Mix);
01027     } else {
01028         if(((Bitu)mixer.freq != (Bitu)obtained.freq) || ((Bitu)mixer.blocksize != (Bitu)obtained.samples))
01029             LOG(LOG_MISC,LOG_DEBUG)("MIXER:Got different values from SDL: freq %d, blocksize %d",(int)obtained.freq,(int)obtained.samples);
01030 
01031         mixer.freq=(unsigned int)obtained.freq;
01032         mixer.blocksize=obtained.samples;
01033         TIMER_AddTickHandler(MIXER_Mix);
01034         SDL_PauseAudio(0);
01035     }
01036     mixer_start_pic_time = PIC_FullIndex();
01037     mixer_sample_counter = 0;
01038     mixer.work_in = mixer.work_out = 0;
01039     mixer.work_wrap = MIXER_BUFSIZE;
01040     if (mixer.work_wrap <= mixer.blocksize) E_Exit("blocksize too large");
01041 
01042     {
01043         int ms = section->Get_int("prebuffer");
01044 
01045         if (ms < 0) ms = 20;
01046 
01047         mixer.prebuffer_samples = ((unsigned int)ms * (unsigned int)mixer.freq) / 1000u;
01048         if (mixer.prebuffer_samples > (mixer.work_wrap / 2))
01049             mixer.prebuffer_samples = (mixer.work_wrap / 2);
01050     }
01051 
01052     // how many samples per millisecond? compute as improper fraction (sample rate / 1000)
01053     mixer.samples_per_ms.w = mixer.freq / 1000U;
01054     mixer.samples_per_ms.fn = mixer.freq % 1000U;
01055     mixer.samples_per_ms.fd = 1000U;
01056     mixer.samples_this_ms.w = mixer.samples_per_ms.w;
01057     mixer.samples_this_ms.fn = 0;
01058     mixer.samples_this_ms.fd = mixer.samples_per_ms.fd;
01059     mixer.samples_rendered_ms.w = 0;
01060     mixer.samples_rendered_ms.fn = 0;
01061     mixer.samples_rendered_ms.fd = mixer.samples_per_ms.fd;
01062 
01063     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",
01064         (unsigned int)mixer.sampleaccurate,
01065         (unsigned int)mixer.blocksize,
01066         (unsigned int)obtained.freq,
01067         (unsigned int)mixer.freq,
01068         (unsigned int)obtained.channels,
01069         (unsigned int)obtained.samples,
01070         (unsigned int)0,
01071         (unsigned int)0,
01072         (unsigned int)0,
01073         (unsigned int)mixer.samples_per_ms.w,
01074         (unsigned int)mixer.samples_per_ms.fn,
01075         (unsigned int)mixer.samples_per_ms.fd,
01076         (unsigned int)mixer.prebuffer_samples);
01077 
01078     PROGRAMS_MakeFile("MIXER.COM",MIXER_ProgramStart);
01079 
01080     MIXER_Controls_Init();
01081 }
01082