DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/gameblaster.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 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 #include "dosbox.h"
00020 #include "inout.h"
00021 #include "mixer.h"
00022 #include "mem.h"
00023 #include "hardware.h"
00024 #include "setup.h"
00025 #include "support.h"
00026 #include "pic.h"
00027 #include <cstring>
00028 #include <math.h>
00029 
00030 
00031 #define LEFT    0x00
00032 #define RIGHT   0x01
00033 #define CMS_BUFFER_SIZE 128
00034 #define CMS_RATE 22050
00035 /*#define MASTER_CLOCK 14318180/2 */
00036 #define MASTER_CLOCK 7159090
00037 
00038 
00039 typedef Bit8u UINT8;
00040 typedef Bit16s INT16;
00041 
00042 /* this structure defines a channel */
00043 struct saa1099_channel
00044 {
00045         int frequency;                  /* frequency (0x00..0xff) */
00046         int freq_enable;                /* frequency enable */
00047         int noise_enable;               /* noise enable */
00048         int octave;                     /* octave (0x00..0x07) */
00049         int amplitude[2];               /* amplitude (0x00..0x0f) */
00050         int envelope[2];                /* envelope (0x00..0x0f or 0x10 == off) */
00051 
00052         /* vars to simulate the square wave */
00053         double counter;
00054         double freq;
00055         int level;
00056 };
00057 
00058 /* this structure defines a noise channel */
00059 struct saa1099_noise
00060 {
00061         /* vars to simulate the noise generator output */
00062         double counter;
00063         double freq;
00064         int level;                                              /* noise polynomal shifter */
00065 };
00066 
00067 /* this structure defines a SAA1099 chip */
00068 struct SAA1099
00069 {
00070         int stream;                                             /* our stream */
00071         int noise_params[2];                    /* noise generators parameters */
00072         int env_enable[2];                              /* envelope generators enable */
00073         int env_reverse_right[2];               /* envelope reversed for right channel */
00074         int env_mode[2];                                /* envelope generators mode */
00075         int env_bits[2];                                /* non zero = 3 bits resolution */
00076         int env_clock[2];                               /* envelope clock mode (non-zero external) */
00077     int env_step[2];                /* current envelope step */
00078         int all_ch_enable;                              /* all channels enable */
00079         int sync_state;                                 /* sync all channels */
00080         int selected_reg;                               /* selected register */
00081         struct saa1099_channel channels[6];    /* channels */
00082         struct saa1099_noise noise[2];  /* noise generators */
00083 };
00084 
00085 static const UINT8 envelope[8][64] = {
00086         /* zero amplitude */
00087         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00088           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00089           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00090       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
00091         /* maximum amplitude */
00092     {15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
00093          15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
00094          15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
00095      15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, },
00096         /* single decay */
00097         {15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
00098           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00099       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00100           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
00101         /* repetitive decay */
00102         {15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
00103          15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
00104          15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
00105          15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
00106         /* single triangular */
00107         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
00108          15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
00109           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00110       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
00111         /* repetitive triangular */
00112         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
00113          15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
00114           0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
00115          15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
00116         /* single attack */
00117     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
00118           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00119       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00120       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
00121         /* repetitive attack */
00122     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
00123           0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
00124       0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
00125           0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 }
00126 };
00127 
00128 
00129 static const int amplitude_lookup[16] = {
00130          0*32767/16,  1*32767/16,  2*32767/16,  3*32767/16,
00131          4*32767/16,  5*32767/16,  6*32767/16,  7*32767/16,
00132          8*32767/16,  9*32767/16, 10*32767/16, 11*32767/16,
00133         12*32767/16, 13*32767/16, 14*32767/16, 15*32767/16
00134 };
00135 
00136 /* global parameters */
00137 static double sample_rate;
00138 static SAA1099 saa1099[2];
00139 static MixerChannel * cms_chan;
00140 static Bit16s cms_buffer[2][2][CMS_BUFFER_SIZE];
00141 static Bit16s * cms_buf_point[4] = {
00142         cms_buffer[0][0],cms_buffer[0][1],cms_buffer[1][0],cms_buffer[1][1] };
00143 
00144 static Bitu last_command;
00145 static Bitu base_port;
00146 
00147 
00148 static void saa1099_envelope(int chip, int ch)
00149 {
00150         struct SAA1099 *saa = &saa1099[chip];
00151         if (saa->env_enable[ch])
00152         {
00153                 int step, mode, mask;
00154         mode = saa->env_mode[ch];
00155                 /* step from 0..63 and then loop in steps 32..63 */
00156                 step = saa->env_step[ch] =
00157                         ((saa->env_step[ch] + 1) & 0x3f) | (saa->env_step[ch] & 0x20);
00158 
00159                 mask = 15;
00160         if (saa->env_bits[ch])
00161                         mask &= ~1;     /* 3 bit resolution, mask LSB */
00162 
00163         saa->channels[ch*3+0].envelope[ LEFT] =
00164                 saa->channels[ch*3+1].envelope[ LEFT] =
00165                 saa->channels[ch*3+2].envelope[ LEFT] = envelope[mode][step] & mask;
00166                 if (saa->env_reverse_right[ch] & 0x01)
00167                 {
00168                         saa->channels[ch*3+0].envelope[RIGHT] =
00169                         saa->channels[ch*3+1].envelope[RIGHT] =
00170                         saa->channels[ch*3+2].envelope[RIGHT] = (15 - envelope[mode][step]) & mask;
00171                 }
00172                 else
00173                 {
00174                         saa->channels[ch*3+0].envelope[RIGHT] =
00175                         saa->channels[ch*3+1].envelope[RIGHT] =
00176                         saa->channels[ch*3+2].envelope[RIGHT] = envelope[mode][step] & mask;
00177         }
00178         }
00179         else
00180         {
00181                 /* envelope mode off, set all envelope factors to 16 */
00182                 saa->channels[ch*3+0].envelope[ LEFT] =
00183                 saa->channels[ch*3+1].envelope[ LEFT] =
00184                 saa->channels[ch*3+2].envelope[ LEFT] =
00185                 saa->channels[ch*3+0].envelope[RIGHT] =
00186                 saa->channels[ch*3+1].envelope[RIGHT] =
00187                 saa->channels[ch*3+2].envelope[RIGHT] = 16;
00188     }
00189 }
00190 
00191 
00192 static void saa1099_update(int chip, INT16 **buffer, int length)
00193 {
00194         struct SAA1099 *saa = &saa1099[chip];
00195     int j, ch;
00196 
00197         /* if the channels are disabled we're done */
00198         if (!saa->all_ch_enable)
00199         {
00200                 /* init output data */
00201                 memset(buffer[LEFT],0,(unsigned int)length*sizeof(INT16));
00202                 memset(buffer[RIGHT],0,(unsigned int)length*sizeof(INT16));
00203         return;
00204         }
00205 
00206     for (ch = 0; ch < 2; ch++)
00207     {
00208                 switch (saa->noise_params[ch])
00209                 {
00210                 case 0: saa->noise[ch].freq = MASTER_CLOCK/256  * 2; break;
00211                 case 1: saa->noise[ch].freq = MASTER_CLOCK/512  * 2; break;
00212                 case 2: saa->noise[ch].freq = MASTER_CLOCK/1024 * 2; break;
00213                 case 3: saa->noise[ch].freq = saa->channels[ch * 3].freq; break;
00214                 }
00215         }
00216 
00217     /* fill all data needed */
00218         for( j = 0; j < length; j++ )
00219         {
00220                 int output_l = 0, output_r = 0;
00221 
00222                 /* for each channel */
00223                 for (ch = 0; ch < 6; ch++)
00224                 {
00225             if (saa->channels[ch].freq == 0.0)
00226                 saa->channels[ch].freq = (double)((2 * MASTER_CLOCK/512) << saa->channels[ch].octave) /
00227                     (511.0 - (double)saa->channels[ch].frequency);
00228 
00229             /* check the actual position in the square wave */
00230             saa->channels[ch].counter -= saa->channels[ch].freq;
00231                         while (saa->channels[ch].counter < 0)
00232                         {
00233                                 /* calculate new frequency now after the half wave is updated */
00234                                 saa->channels[ch].freq = (double)((2 * MASTER_CLOCK/512) << saa->channels[ch].octave) /
00235                                         (511.0 - (double)saa->channels[ch].frequency);
00236 
00237                                 saa->channels[ch].counter += sample_rate;
00238                                 saa->channels[ch].level ^= 1;
00239 
00240                                 /* eventually clock the envelope counters */
00241                                 if (ch == 1 && saa->env_clock[0] == 0)
00242                                         saa1099_envelope(chip, 0);
00243                                 if (ch == 4 && saa->env_clock[1] == 0)
00244                                         saa1099_envelope(chip, 1);
00245                         }
00246 
00247                         /* if the noise is enabled */
00248                         if (saa->channels[ch].noise_enable)
00249                         {
00250                                 /* if the noise level is high (noise 0: chan 0-2, noise 1: chan 3-5) */
00251                                 if (saa->noise[ch/3].level & 1)
00252                                 {
00253                                         /* subtract to avoid overflows, also use only half amplitude */
00254                                         output_l -= saa->channels[ch].amplitude[ LEFT] * saa->channels[ch].envelope[ LEFT] / 16 / 2;
00255                                         output_r -= saa->channels[ch].amplitude[RIGHT] * saa->channels[ch].envelope[RIGHT] / 16 / 2;
00256                                 }
00257                         }
00258 
00259                         /* if the square wave is enabled */
00260                         if (saa->channels[ch].freq_enable)
00261                         {
00262                                 /* if the channel level is high */
00263                                 if (saa->channels[ch].level & 1)
00264                                 {
00265                                         output_l += saa->channels[ch].amplitude[ LEFT] * saa->channels[ch].envelope[ LEFT] / 16;
00266                                         output_r += saa->channels[ch].amplitude[RIGHT] * saa->channels[ch].envelope[RIGHT] / 16;
00267                                 }
00268                         }
00269                 }
00270 
00271                 for (ch = 0; ch < 2; ch++)
00272                 {
00273                         /* check the actual position in noise generator */
00274                         saa->noise[ch].counter -= saa->noise[ch].freq;
00275                         while (saa->noise[ch].counter < 0)
00276                         {
00277                                 saa->noise[ch].counter += sample_rate;
00278                                 if( ((saa->noise[ch].level & 0x4000) == 0) == ((saa->noise[ch].level & 0x0040) == 0) )
00279                                         saa->noise[ch].level = (saa->noise[ch].level << 1) | 1;
00280                                 else
00281                                         saa->noise[ch].level <<= 1;
00282                         }
00283                 }
00284         /* write sound data to the buffer */
00285                 buffer[LEFT][j] = output_l / 6;
00286                 buffer[RIGHT][j] = output_r / 6;
00287         }
00288 }
00289 
00290 static void saa1099_write_port_w( int chip, int offset, int data )
00291 {
00292         struct SAA1099 *saa = &saa1099[chip];
00293         if(offset == 1) {
00294                 // address port
00295                 saa->selected_reg = data & 0x1f;
00296                 if (saa->selected_reg == 0x18 || saa->selected_reg == 0x19) {
00297                         /* clock the envelope channels */
00298                         if (saa->env_clock[0]) saa1099_envelope(chip,0);
00299                         if (saa->env_clock[1]) saa1099_envelope(chip,1);
00300                 }
00301                 return;
00302         }
00303         int reg = saa->selected_reg;
00304         int ch;
00305 
00306         switch (reg)
00307         {
00308         /* channel i amplitude */
00309         case 0x00:      case 0x01:      case 0x02:      case 0x03:      case 0x04:      case 0x05:
00310                 ch = reg & 7;
00311                 saa->channels[ch].amplitude[LEFT] = amplitude_lookup[data & 0x0f];
00312                 saa->channels[ch].amplitude[RIGHT] = amplitude_lookup[(data >> 4) & 0x0f];
00313                 break;
00314         /* channel i frequency */
00315         case 0x08:      case 0x09:      case 0x0a:      case 0x0b:      case 0x0c:      case 0x0d:
00316                 ch = reg & 7;
00317                 saa->channels[ch].frequency = data & 0xff;
00318                 break;
00319         /* channel i octave */
00320         case 0x10:      case 0x11:      case 0x12:
00321                 ch = (reg - 0x10) << 1;
00322                 saa->channels[ch + 0].octave = data & 0x07;
00323                 saa->channels[ch + 1].octave = (data >> 4) & 0x07;
00324                 break;
00325         /* channel i frequency enable */
00326         case 0x14:
00327                 saa->channels[0].freq_enable = data & 0x01;
00328                 saa->channels[1].freq_enable = data & 0x02;
00329                 saa->channels[2].freq_enable = data & 0x04;
00330                 saa->channels[3].freq_enable = data & 0x08;
00331                 saa->channels[4].freq_enable = data & 0x10;
00332                 saa->channels[5].freq_enable = data & 0x20;
00333                 break;
00334         /* channel i noise enable */
00335         case 0x15:
00336                 saa->channels[0].noise_enable = data & 0x01;
00337                 saa->channels[1].noise_enable = data & 0x02;
00338                 saa->channels[2].noise_enable = data & 0x04;
00339                 saa->channels[3].noise_enable = data & 0x08;
00340                 saa->channels[4].noise_enable = data & 0x10;
00341                 saa->channels[5].noise_enable = data & 0x20;
00342                 break;
00343         /* noise generators parameters */
00344         case 0x16:
00345                 saa->noise_params[0] = data & 0x03;
00346                 saa->noise_params[1] = (data >> 4) & 0x03;
00347                 break;
00348         /* envelope generators parameters */
00349         case 0x18:      case 0x19:
00350                 ch = reg - 0x18;
00351                 saa->env_reverse_right[ch] = data & 0x01;
00352                 saa->env_mode[ch] = (data >> 1) & 0x07;
00353                 saa->env_bits[ch] = data & 0x10;
00354                 saa->env_clock[ch] = data & 0x20;
00355                 saa->env_enable[ch] = data & 0x80;
00356                 /* reset the envelope */
00357                 saa->env_step[ch] = 0;
00358                 break;
00359         /* channels enable & reset generators */
00360         case 0x1c:
00361                 saa->all_ch_enable = data & 0x01;
00362                 saa->sync_state = data & 0x02;
00363                 if (data & 0x02)
00364                 {
00365                         int i;
00366 //                      logerror("%04x: (SAA1099 #%d) -reg 0x1c- Chip reset\n",activecpu_get_pc(), chip);
00367                         /* Synch & Reset generators */
00368                         for (i = 0; i < 6; i++)
00369                         {
00370                 saa->channels[i].level = 0;
00371                                 saa->channels[i].counter = 0.0;
00372                         }
00373                 }
00374                 break;
00375         default:        /* Error! */
00376 //              logerror("%04x: (SAA1099 #%d) Unknown operation (reg:%02x, data:%02x)\n",activecpu_get_pc(), chip, reg, data);
00377                 LOG(LOG_MISC,LOG_ERROR)("CMS Unkown write to reg %x with %x",reg, data);
00378         }
00379 }
00380 
00381 static void write_cms(Bitu port, Bitu val, Bitu /* iolen */) {
00382         if(cms_chan && (!cms_chan->enabled)) cms_chan->Enable(true);
00383         last_command = PIC_Ticks;
00384         switch (port-base_port) {
00385         case 0:
00386                 saa1099_write_port_w(0,0,val);
00387                 break;
00388         case 1:
00389                 saa1099_write_port_w(0,1,val);
00390                 break;
00391         case 2:
00392                 saa1099_write_port_w(1,0,val);
00393                 break;
00394         case 3:
00395                 saa1099_write_port_w(1,1,val);
00396                 break;
00397         }
00398 }
00399 
00400 static void CMS_CallBack(Bitu len) {
00401         if (len > CMS_BUFFER_SIZE) return;
00402 
00403         saa1099_update(0, &cms_buf_point[0], (int)len);
00404         saa1099_update(1, &cms_buf_point[2], (int)len);
00405 
00406          Bit16s * stream=(Bit16s *) MixTemp;
00407         /* Mix chip outputs */
00408         for (Bitu l=0;l<len;l++) {
00409                 Bits left, right;
00410 
00411                 left = cms_buffer[0][LEFT][l] + cms_buffer[1][LEFT][l];
00412                 right = cms_buffer[0][RIGHT][l] + cms_buffer[1][RIGHT][l];
00413 
00414                 if (left>MAX_AUDIO) *stream=MAX_AUDIO;
00415                 else if (left<MIN_AUDIO) *stream=MIN_AUDIO;
00416                 else *stream=(Bit16s)left;
00417                 stream++;
00418 
00419                 if (right>MAX_AUDIO) *stream=MAX_AUDIO;
00420                 else if (right<MIN_AUDIO) *stream=MIN_AUDIO;
00421                 else *stream=(Bit16s)right;
00422                 stream++;
00423         }
00424         if(cms_chan) cms_chan->AddSamples_s16(len,(Bit16s *)MixTemp);
00425         if (last_command + 10000 < PIC_Ticks) if(cms_chan) cms_chan->Enable(false);
00426 }
00427 
00428 // The Gameblaster detection
00429 static Bit8u cms_detect_register = 0xff;
00430 
00431 static void write_cms_detect(Bitu port, Bitu val, Bitu /* iolen */) {
00432         switch(port-base_port) {
00433         case 0x6:
00434         case 0x7:
00435                 cms_detect_register = val;
00436                 break;
00437         }
00438 }
00439 
00440 static Bitu read_cms_detect(Bitu port, Bitu /* iolen */) {
00441         Bit8u retval = 0xff;
00442         switch(port-base_port) {
00443         case 0x4:
00444                 retval = 0x7f;
00445                 break;
00446         case 0xa:
00447         case 0xb:
00448                 retval = cms_detect_register;
00449                 break;
00450         }
00451         return retval;
00452 }
00453 
00454 
00455 class CMS:public Module_base {
00456 private:
00457         IO_WriteHandleObject WriteHandler;
00458         IO_WriteHandleObject DetWriteHandler;
00459         IO_ReadHandleObject DetReadHandler;
00460         MixerObject MixerChan;
00461 
00462 public:
00463         CMS(Section* configuration):Module_base(configuration) {
00464                 Section_prop * section = static_cast<Section_prop *>(configuration);
00465                 Bitu sample_rate_temp = (Bitu)section->Get_int("oplrate");
00466                 sample_rate = static_cast<double>(sample_rate_temp);
00467                 base_port = (unsigned int)section->Get_hex("sbbase");
00468                 WriteHandler.Install(base_port, write_cms, IO_MB,4);
00469 
00470                 // A standalone Gameblaster has a magic chip on it which is
00471                 // sometimes used for detection.
00472                 const char * sbtype=section->Get_string("sbtype");
00473                 if (!strcasecmp(sbtype,"gb")) {
00474                         DetWriteHandler.Install(base_port+4,write_cms_detect,IO_MB,12);
00475                         DetReadHandler.Install(base_port,read_cms_detect,IO_MB,16);
00476                 }
00477 
00478                 /* Register the Mixer CallBack */
00479                 cms_chan = MixerChan.Install(CMS_CallBack,sample_rate_temp,"CMS");
00480         
00481                 last_command = PIC_Ticks;
00482         
00483                 for (int s=0;s<2;s++) {
00484                         struct SAA1099 *saa = &saa1099[s];
00485                         memset(saa, 0, sizeof(struct SAA1099));
00486                 }
00487         }
00488         ~CMS() {
00489                 cms_chan = 0;
00490         }
00491 };
00492 
00493 
00494 static CMS* test = NULL;
00495    
00496 void CMS_Init(Section* sec) {
00497     if (test == NULL)
00498         test = new CMS(sec);
00499 }
00500 void CMS_ShutDown(Section* sec) {
00501     (void)sec;//UNUSED
00502     if (test) {
00503         delete test;
00504         test = NULL;
00505     }
00506 }
00507