Logo Search packages:      
Sourcecode: dosbox version File versions  Download package

gameblaster.cpp

/*
 *  Copyright (C) 2002-2004  The DOSBox Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <math.h>
#include "dosbox.h"
#include "inout.h"
#include "mixer.h"
#include "mem.h"
#include "hardware.h"
#include "setup.h"
#include "pic.h"

#define LEFT      0x00
#define RIGHT     0x01
#define CMS_BUFFER_SIZE 128
#define CMS_RATE 22050


typedef Bit8u UINT8;
typedef Bit16s INT16;

/* this structure defines a channel */
struct saa1099_channel
{
      int frequency;                /* frequency (0x00..0xff) */
      int freq_enable;        /* frequency enable */
      int noise_enable;       /* noise enable */
      int octave;                   /* octave (0x00..0x07) */
      int amplitude[2];       /* amplitude (0x00..0x0f) */
      int envelope[2];        /* envelope (0x00..0x0f or 0x10 == off) */

      /* vars to simulate the square wave */
      double counter;
      double freq;
      int level;
};

/* this structure defines a noise channel */
struct saa1099_noise
{
      /* vars to simulate the noise generator output */
      double counter;
      double freq;
      int level;                                /* noise polynomal shifter */
};

/* this structure defines a SAA1099 chip */
struct SAA1099
{
      int stream;                               /* our stream */
      int noise_params[2];                /* noise generators parameters */
      int env_enable[2];                        /* envelope generators enable */
      int env_reverse_right[2];           /* envelope reversed for right channel */
      int env_mode[2];                    /* envelope generators mode */
      int env_bits[2];                    /* non zero = 3 bits resolution */
      int env_clock[2];                   /* envelope clock mode (non-zero external) */
    int env_step[2];                /* current envelope step */
      int all_ch_enable;                        /* all channels enable */
      int sync_state;                           /* sync all channels */
      int selected_reg;                   /* selected register */
      struct saa1099_channel channels[6];    /* channels */
      struct saa1099_noise noise[2];      /* noise generators */
};

static UINT8 envelope[8][64] = {
      /* zero amplitude */
      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
      /* maximum amplitude */
    {15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
       15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
       15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
     15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, },
      /* single decay */
      {15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
      /* repetitive decay */
      {15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
       15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
       15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
       15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
      /* single triangular */
      { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
       15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
      /* repetitive triangular */
      { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
       15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
       15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
      /* single attack */
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
      /* repetitive attack */
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
      0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 }
};


static int amplitude_lookup[16] = {
       0*32767/16,  1*32767/16,  2*32767/16,    3*32767/16,
       4*32767/16,  5*32767/16,  6*32767/16,    7*32767/16,
       8*32767/16,  9*32767/16, 10*32767/16, 11*32767/16,
      12*32767/16, 13*32767/16, 14*32767/16, 15*32767/16
};

/* global parameters */
static double sample_rate;
static SAA1099 saa1099[2];
static MixerChannel * cms_chan;
static Bit16s cms_buffer[2][2][CMS_BUFFER_SIZE];
static Bit16s * cms_buf_point[4] = {
      cms_buffer[0][0],cms_buffer[0][1],cms_buffer[1][0],cms_buffer[1][1] };

static Bitu last_command;


static void saa1099_envelope(int chip, int ch)
{
      struct SAA1099 *saa = &saa1099[chip];
      if (saa->env_enable[ch])
      {
            int step, mode, mask;
        mode = saa->env_mode[ch];
            /* step from 0..63 and then loop in steps 32..63 */
            step = saa->env_step[ch] =
                  ((saa->env_step[ch] + 1) & 0x3f) | (saa->env_step[ch] & 0x20);

            mask = 15;
        if (saa->env_bits[ch])
                  mask &= ~1;       /* 3 bit resolution, mask LSB */

        saa->channels[ch*3+0].envelope[ LEFT] =
            saa->channels[ch*3+1].envelope[ LEFT] =
            saa->channels[ch*3+2].envelope[ LEFT] = envelope[mode][step] & mask;
            if (saa->env_reverse_right[ch] & 0x01)
            {
                  saa->channels[ch*3+0].envelope[RIGHT] =
                  saa->channels[ch*3+1].envelope[RIGHT] =
                  saa->channels[ch*3+2].envelope[RIGHT] = (15 - envelope[mode][step]) & mask;
            }
            else
            {
                  saa->channels[ch*3+0].envelope[RIGHT] =
                  saa->channels[ch*3+1].envelope[RIGHT] =
                  saa->channels[ch*3+2].envelope[RIGHT] = envelope[mode][step] & mask;
        }
      }
      else
      {
            /* envelope mode off, set all envelope factors to 16 */
            saa->channels[ch*3+0].envelope[ LEFT] =
            saa->channels[ch*3+1].envelope[ LEFT] =
            saa->channels[ch*3+2].envelope[ LEFT] =
            saa->channels[ch*3+0].envelope[RIGHT] =
            saa->channels[ch*3+1].envelope[RIGHT] =
            saa->channels[ch*3+2].envelope[RIGHT] = 16;
    }
}


static void saa1099_update(int chip, INT16 **buffer, int length)
{
      struct SAA1099 *saa = &saa1099[chip];
    int j, ch;

      /* if the channels are disabled we're done */
      if (!saa->all_ch_enable)
      {
            /* init output data */
            memset(buffer[LEFT],0,length*sizeof(INT16));
            memset(buffer[RIGHT],0,length*sizeof(INT16));
        return;
      }

    for (ch = 0; ch < 2; ch++)
    {
            switch (saa->noise_params[ch])
            {
            case 0: saa->noise[ch].freq = 31250.0 * 2; break;
            case 1: saa->noise[ch].freq = 15625.0 * 2; break;
            case 2: saa->noise[ch].freq =  7812.5 * 2; break;
            case 3: saa->noise[ch].freq = saa->channels[ch * 3].freq; break;
            }
      }

    /* fill all data needed */
      for( j = 0; j < length; j++ )
      {
            int output_l = 0, output_r = 0;

            /* for each channel */
            for (ch = 0; ch < 6; ch++)
            {
            if (saa->channels[ch].freq == 0.0)
                saa->channels[ch].freq = (double)((2 * 15625) << saa->channels[ch].octave) /
                    (511.0 - (double)saa->channels[ch].frequency);

            /* check the actual position in the square wave */
            saa->channels[ch].counter -= saa->channels[ch].freq;
                  while (saa->channels[ch].counter < 0)
                  {
                        /* calculate new frequency now after the half wave is updated */
                        saa->channels[ch].freq = (double)((2 * 15625) << saa->channels[ch].octave) /
                              (511.0 - (double)saa->channels[ch].frequency);

                        saa->channels[ch].counter += sample_rate;
                        saa->channels[ch].level ^= 1;

                        /* eventually clock the envelope counters */
                        if (ch == 1 && saa->env_clock[0] == 0)
                              saa1099_envelope(chip, 0);
                        if (ch == 4 && saa->env_clock[1] == 0)
                              saa1099_envelope(chip, 1);
                  }

                  /* if the noise is enabled */
                  if (saa->channels[ch].noise_enable)
                  {
                        /* if the noise level is high (noise 0: chan 0-2, noise 1: chan 3-5) */
                        if (saa->noise[ch/3].level & 1)
                        {
                              /* subtract to avoid overflows, also use only half amplitude */
                              output_l -= saa->channels[ch].amplitude[ LEFT] * saa->channels[ch].envelope[ LEFT] / 16 / 2;
                              output_r -= saa->channels[ch].amplitude[RIGHT] * saa->channels[ch].envelope[RIGHT] / 16 / 2;
                        }
                  }

                  /* if the square wave is enabled */
                  if (saa->channels[ch].freq_enable)
                  {
                        /* if the channel level is high */
                        if (saa->channels[ch].level & 1)
                        {
                              output_l += saa->channels[ch].amplitude[ LEFT] * saa->channels[ch].envelope[ LEFT] / 16;
                              output_r += saa->channels[ch].amplitude[RIGHT] * saa->channels[ch].envelope[RIGHT] / 16;
                        }
                  }
            }

            for (ch = 0; ch < 2; ch++)
            {
                  /* check the actual position in noise generator */
                  saa->noise[ch].counter -= saa->noise[ch].freq;
                  while (saa->noise[ch].counter < 0)
                  {
                        saa->noise[ch].counter += sample_rate;
                        if( ((saa->noise[ch].level & 0x4000) == 0) == ((saa->noise[ch].level & 0x0040) == 0) )
                              saa->noise[ch].level = (saa->noise[ch].level << 1) | 1;
                        else
                              saa->noise[ch].level <<= 1;
                  }
            }
        /* write sound data to the buffer */
            buffer[LEFT][j] = output_l / 6;
            buffer[RIGHT][j] = output_r / 6;
      }
}

static void saa1099_write_port_w( int chip, int offset, int data )
{
      struct SAA1099 *saa = &saa1099[chip];
      int reg = saa->selected_reg;
      int ch;

      switch (reg)
      {
      /* channel i amplitude */
      case 0x00:  case 0x01:  case 0x02:  case 0x03:  case 0x04:  case 0x05:
            ch = reg & 7;
            saa->channels[ch].amplitude[LEFT] = amplitude_lookup[data & 0x0f];
            saa->channels[ch].amplitude[RIGHT] = amplitude_lookup[(data >> 4) & 0x0f];
            break;
      /* channel i frequency */
      case 0x08:  case 0x09:  case 0x0a:  case 0x0b:  case 0x0c:  case 0x0d:
            ch = reg & 7;
            saa->channels[ch].frequency = data & 0xff;
            break;
      /* channel i octave */
      case 0x10:  case 0x11:  case 0x12:
            ch = (reg - 0x10) << 1;
            saa->channels[ch + 0].octave = data & 0x07;
            saa->channels[ch + 1].octave = (data >> 4) & 0x07;
            break;
      /* channel i frequency enable */
      case 0x14:
            saa->channels[0].freq_enable = data & 0x01;
            saa->channels[1].freq_enable = data & 0x02;
            saa->channels[2].freq_enable = data & 0x04;
            saa->channels[3].freq_enable = data & 0x08;
            saa->channels[4].freq_enable = data & 0x10;
            saa->channels[5].freq_enable = data & 0x20;
            break;
      /* channel i noise enable */
      case 0x15:
            saa->channels[0].noise_enable = data & 0x01;
            saa->channels[1].noise_enable = data & 0x02;
            saa->channels[2].noise_enable = data & 0x04;
            saa->channels[3].noise_enable = data & 0x08;
            saa->channels[4].noise_enable = data & 0x10;
            saa->channels[5].noise_enable = data & 0x20;
            break;
      /* noise generators parameters */
      case 0x16:
            saa->noise_params[0] = data & 0x03;
            saa->noise_params[1] = (data >> 4) & 0x03;
            break;
      /* envelope generators parameters */
      case 0x18:  case 0x19:
            ch = reg - 0x18;
            saa->env_reverse_right[ch] = data & 0x01;
            saa->env_mode[ch] = (data >> 1) & 0x07;
            saa->env_bits[ch] = data & 0x10;
            saa->env_clock[ch] = data & 0x20;
            saa->env_enable[ch] = data & 0x80;
            /* reset the envelope */
            saa->env_step[ch] = 0;
            break;
      /* channels enable & reset generators */
      case 0x1c:
            saa->all_ch_enable = data & 0x01;
            saa->sync_state = data & 0x02;
            if (data & 0x02)
            {
                  int i;
//                logerror("%04x: (SAA1099 #%d) -reg 0x1c- Chip reset\n",activecpu_get_pc(), chip);
                  /* Synch & Reset generators */
                  for (i = 0; i < 6; i++)
                  {
                saa->channels[i].level = 0;
                        saa->channels[i].counter = 0.0;
                  }
            }
            break;
      default:    /* Error! */
//          logerror("%04x: (SAA1099 #%d) Unknown operation (reg:%02x, data:%02x)\n",activecpu_get_pc(), chip, reg, data);
            LOG(LOG_MISC,LOG_ERROR)("CMS Unkown write to reg %x with %x",reg, data);
      }
}


static void write_cms(Bitu port,Bitu val,Bitu iolen) {
      if (last_command + 1000 < PIC_Ticks) cms_chan->Enable(true); 
      last_command = PIC_Ticks;
      switch (port) {
      case 0x0220:
            saa1099_write_port_w(0,1,val);
            break;
      case 0x221:
            saa1099[0].selected_reg = val & 0x1f;
            if (saa1099[0].selected_reg == 0x18 || saa1099[0].selected_reg == 0x19) {
                  /* clock the envelope channels */
                  if (saa1099[0].env_clock[0]) saa1099_envelope(0,0);
                  if (saa1099[0].env_clock[1]) saa1099_envelope(0,1);
            }
            break;
      case 0x0222:
            saa1099_write_port_w(1,1,val);
            break;
      case 0x223:
            saa1099[1].selected_reg = val & 0x1f;
            if (saa1099[1].selected_reg == 0x18 || saa1099[1].selected_reg == 0x19) {
                  /* clock the envelope channels */
                  if (saa1099[1].env_clock[0]) saa1099_envelope(1,0);
                  if (saa1099[1].env_clock[1]) saa1099_envelope(1,1);
            }
            break;
      }
}

 static void CMS_CallBack(Bitu len) {
      if (len > CMS_BUFFER_SIZE) return;

      saa1099_update(0, &cms_buf_point[0], (int)len);
      saa1099_update(1, &cms_buf_point[2], (int)len);

       Bit16s * stream=(Bit16s *) MixTemp;
      /* Mix chip outputs */
      for (Bitu l=0;l<len;l++) {
            register Bits left, right;
            left = cms_buffer[0][LEFT][l] + cms_buffer[1][LEFT][l];
            right = cms_buffer[0][RIGHT][l] + cms_buffer[1][RIGHT][l];

            if (left>MAX_AUDIO) *stream=MAX_AUDIO;
            else if (left<MIN_AUDIO) *stream=MIN_AUDIO;
            else *stream=(Bit16s)left;
            stream++;

            if (right>MAX_AUDIO) *stream=MAX_AUDIO;
            else if (right<MIN_AUDIO) *stream=MIN_AUDIO;
            else *stream=(Bit16s)right;
            stream++;
      }
      cms_chan->AddSamples_s16(len,(Bit16s *)MixTemp);
      if (last_command + 10000 < PIC_Ticks) cms_chan->Enable(false);
}


 void CMS_Init(Section* sec,Bitu base,Bitu rate) {
      Section_prop * section=static_cast<Section_prop *>(sec);
      sample_rate=rate;

      IO_RegisterWriteHandler(base,write_cms,IO_MB,4);
      
/* Register the Mixer CallBack */

      cms_chan=MIXER_AddChannel(CMS_CallBack,rate,"CMS");
      last_command=PIC_Ticks;
      
      for (int s=0;s<2;s++) {
            struct SAA1099 *saa = &saa1099[s];
            memset(saa, 0, sizeof(struct SAA1099));
      }
}


Generated by  Doxygen 1.6.0   Back to index