diff --git a/src/dosbox.cpp b/src/dosbox.cpp index 7308d8c5..d9a81612 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -558,7 +558,7 @@ void DOSBOX_Init(void) { Pstring->Set_values(oplmodes); Pstring->Set_help("Type of OPL emulation. On 'auto' the mode is determined by sblaster type. All OPL modes are Adlib-compatible, except for 'cms'."); - const char* oplemus[]={ "default", "compat", "fast", 0}; + const char* oplemus[]={ "default", "compat", "fast", "mame", 0}; Pstring = secprop->Add_string("oplemu",Property::Changeable::WhenIdle,"default"); Pstring->Set_values(oplemus); Pstring->Set_help("Provider for the OPL emulation. compat might provide better quality (see oplrate as well)."); diff --git a/src/hardware/adlib.cpp b/src/hardware/adlib.cpp index 836a3e21..de56dcc6 100644 --- a/src/hardware/adlib.cpp +++ b/src/hardware/adlib.cpp @@ -28,6 +28,13 @@ #include "mem.h" #include "dbopl.h" +#include "mame/emu.h" +#include "mame/fmopl.h" +#include "mame/ymf262.h" + +#define OPL2_INTERNAL_FREQ 3600000 // The OPL2 operates at 3.6MHz +#define OPL3_INTERNAL_FREQ 14400000 // The OPL3 operates at 14.4MHz + namespace OPL2 { #include "opl.cpp" @@ -85,6 +92,80 @@ namespace OPL3 { }; } +namespace MAMEOPL2 { + +struct Handler : public Adlib::Handler { + void* chip; + + virtual void WriteReg(Bit32u reg, Bit8u val) { + ym3812_write(chip, 0, reg); + ym3812_write(chip, 1, val); + } + virtual Bit32u WriteAddr(Bit32u port, Bit8u val) { + return val; + } + virtual void Generate(MixerChannel* chan, Bitu samples) { + Bit16s buf[1024 * 2]; + while (samples > 0) { + Bitu todo = samples > 1024 ? 1024 : samples; + samples -= todo; + ym3812_update_one(chip, buf, todo); + chan->AddSamples_m16(todo, buf); + } + } + virtual void Init(Bitu rate) { + chip = ym3812_init(0, OPL2_INTERNAL_FREQ, rate); + } + ~Handler() { + ym3812_shutdown(chip); + } +}; + +} + + +namespace MAMEOPL3 { + +struct Handler : public Adlib::Handler { + void* chip; + + virtual void WriteReg(Bit32u reg, Bit8u val) { + ymf262_write(chip, 0, reg); + ymf262_write(chip, 1, val); + } + virtual Bit32u WriteAddr(Bit32u port, Bit8u val) { + return val; + } + virtual void Generate(MixerChannel* chan, Bitu samples) { + //We generate data for 4 channels, but only the first 2 are connected on a pc + Bit16s buf[4][1024]; + Bit16s result[1024][2]; + Bit16s* buffers[4] = { buf[0], buf[1], buf[2], buf[3] }; + + while (samples > 0) { + Bitu todo = samples > 1024 ? 1024 : samples; + samples -= todo; + ymf262_update_one(chip, buffers, todo); + //Interleave the samples before mixing + for (Bitu i = 0; i < todo; i++) { + result[i][0] = buf[0][i]; + result[i][1] = buf[1][i]; + } + chan->AddSamples_s16(todo, result[0]); + } + } + virtual void Init(Bitu rate) { + chip = ymf262_init(0, OPL3_INTERNAL_FREQ, rate); + } + ~Handler() { + ymf262_shutdown(chip); + } +}; + +} + + + #define RAW_SIZE 1024 @@ -717,6 +798,14 @@ Module::Module( Section* configuration ) : Module_base(configuration) { } else { handler = new OPL3::Handler(); } + } + else if (oplemu == "mame") { + if (oplmode == OPL_opl2) { + handler = new MAMEOPL2::Handler(); + } + else { + handler = new MAMEOPL3::Handler(); + } } else { handler = new DBOPL::Handler(); } diff --git a/src/hardware/gameblaster.cpp b/src/hardware/gameblaster.cpp index a3906054..dbe3b093 100644 --- a/src/hardware/gameblaster.cpp +++ b/src/hardware/gameblaster.cpp @@ -27,408 +27,75 @@ #include #include +#include "mame/emu.h" +#include "mame/saa1099.h" -#define LEFT 0x00 -#define RIGHT 0x01 -#define CMS_BUFFER_SIZE 128 -#define CMS_RATE 22050 -/*#define MASTER_CLOCK 14318180/2 */ #define MASTER_CLOCK 7159090 - -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 const 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 const 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]; +//My mixer channel 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 Bitu base_port; - - -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 = MASTER_CLOCK/256 * 2; break; - case 1: saa->noise[ch].freq = MASTER_CLOCK/512 * 2; break; - case 2: saa->noise[ch].freq = MASTER_CLOCK/1024 * 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 * MASTER_CLOCK/512) << 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 * MASTER_CLOCK/512) << 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]; - if(offset == 1) { - // address port - saa->selected_reg = data & 0x1f; - if (saa->selected_reg == 0x18 || saa->selected_reg == 0x19) { - /* clock the envelope channels */ - if (saa->env_clock[0]) saa1099_envelope(chip,0); - if (saa->env_clock[1]) saa1099_envelope(chip,1); - } - return; - } - 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); - } -} +//Timer to disable the channel after a while +static Bit32u lastWriteTicks; +static Bit32u cmsBase; +static saa1099_device* device[2]; static void write_cms(Bitu port, Bitu val, Bitu /* iolen */) { if(cms_chan && (!cms_chan->enabled)) cms_chan->Enable(true); - last_command = PIC_Ticks; - switch (port-base_port) { - case 0: - saa1099_write_port_w(0,0,val); - break; + lastWriteTicks = PIC_Ticks; + switch ( port - cmsBase ) { case 1: - saa1099_write_port_w(0,1,val); + device[0]->control_w(0, 0, val); break; - case 2: - saa1099_write_port_w(1,0,val); + case 0: + device[0]->data_w(0, 0, val); break; case 3: - saa1099_write_port_w(1,1,val); + device[1]->control_w(0, 0, val); + break; + case 2: + device[1]->data_w(0, 0, val); break; } } static void CMS_CallBack(Bitu len) { - if (len > CMS_BUFFER_SIZE) return; + enum { + BUFFER_SIZE = 2048 + }; - saa1099_update(0, &cms_buf_point[0], (int)len); - saa1099_update(1, &cms_buf_point[2], (int)len); + if ( len > BUFFER_SIZE ) + return; - Bit16s * stream=(Bit16s *) MixTemp; - /* Mix chip outputs */ - for (Bitu l=0;lMAX_AUDIO) *stream=MAX_AUDIO; - else if (leftMAX_AUDIO) *stream=MAX_AUDIO; - else if (rightEnable( false ); + return; + } + Bit32s result[BUFFER_SIZE][2]; + Bit16s work[2][BUFFER_SIZE]; + Bit16s* buffers[2] = { work[0], work[1] }; + device_sound_interface::sound_stream stream; + device[0]->sound_stream_update(stream, 0, buffers, len); + for (Bitu i = 0; i < len; i++) { + result[i][0] = work[0][i]; + result[i][1] = work[1][i]; + } + device[1]->sound_stream_update(stream, 0, buffers, len); + for (Bitu i = 0; i < len; i++) { + result[i][0] += work[0][i]; + result[i][1] += work[1][i]; + } + cms_chan->AddSamples_s32( len, result[0] ); } - if(cms_chan) cms_chan->AddSamples_s16(len,(Bit16s *)MixTemp); - if (last_command + 10000 < PIC_Ticks) if(cms_chan) cms_chan->Enable(false); } // The Gameblaster detection static Bit8u cms_detect_register = 0xff; static void write_cms_detect(Bitu port, Bitu val, Bitu /* iolen */) { - switch(port-base_port) { + switch ( port - cmsBase ) { case 0x6: case 0x7: cms_detect_register = val; @@ -438,7 +105,7 @@ static void write_cms_detect(Bitu port, Bitu val, Bitu /* iolen */) { static Bitu read_cms_detect(Bitu port, Bitu /* iolen */) { Bit8u retval = 0xff; - switch(port-base_port) { + switch ( port - cmsBase ) { case 0x4: retval = 0x7f; break; @@ -461,31 +128,37 @@ private: public: CMS(Section* configuration):Module_base(configuration) { Section_prop * section = static_cast(configuration); - Bitu sample_rate_temp = section->Get_int("oplrate"); - sample_rate = static_cast(sample_rate_temp); - base_port = section->Get_hex("sbbase"); - WriteHandler.Install(base_port, write_cms, IO_MB,4); + Bitu sampleRate = section->Get_int( "oplrate" ); + cmsBase = section->Get_hex("sbbase"); + WriteHandler.Install( cmsBase, write_cms, IO_MB, 4 ); // A standalone Gameblaster has a magic chip on it which is // sometimes used for detection. const char * sbtype=section->Get_string("sbtype"); if (!strcasecmp(sbtype,"gb")) { - DetWriteHandler.Install(base_port+4,write_cms_detect,IO_MB,12); - DetReadHandler.Install(base_port,read_cms_detect,IO_MB,16); + DetWriteHandler.Install( cmsBase + 4, write_cms_detect, IO_MB, 12 ); + DetReadHandler.Install(cmsBase,read_cms_detect,IO_MB,16); } /* Register the Mixer CallBack */ - cms_chan = MixerChan.Install(CMS_CallBack,sample_rate_temp,"CMS"); + cms_chan = MixerChan.Install(CMS_CallBack,sampleRate,"CMS"); - last_command = PIC_Ticks; - - for (int s=0;s<2;s++) { - struct SAA1099 *saa = &saa1099[s]; - memset(saa, 0, sizeof(struct SAA1099)); - } + lastWriteTicks = PIC_Ticks; + + Bit32u freq = 7159000; //14318180 isa clock / 2 + + machine_config config; + device[0] = new saa1099_device(config, "", 0, 7159090); + device[1] = new saa1099_device(config, "", 0, 7159090); + + device[0]->device_start(); + device[1]->device_start(); } + ~CMS() { cms_chan = 0; + delete device[0]; + delete device[1]; } }; diff --git a/src/hardware/tandy_sound.cpp b/src/hardware/tandy_sound.cpp index 5d3ef2ea..3aef0ba7 100644 --- a/src/hardware/tandy_sound.cpp +++ b/src/hardware/tandy_sound.cpp @@ -30,47 +30,11 @@ #include "hardware.h" #include #include - -#define MAX_OUTPUT 0x7fff -#define STEP 0x10000 - -/* Formulas for noise generator */ -/* bit0 = output */ - -/* noise feedback for white noise mode (verified on real SN76489 by John Kortink) */ -#define FB_WNOISE 0x14002 /* (16bits) bit16 = bit0(out) ^ bit2 ^ bit15 */ - -/* noise feedback for periodic noise mode */ -//#define FB_PNOISE 0x10000 /* 16bit rorate */ -#define FB_PNOISE 0x08000 /* JH 981127 - fixes Do Run Run */ - -/* -0x08000 is definitely wrong. The Master System conversion of Marble Madness -uses periodic noise as a baseline. With a 15-bit rotate, the bassline is -out of tune. -The 16-bit rotate has been confirmed against a real PAL Sega Master System 2. -Hope that helps the System E stuff, more news on the PSG as and when! -*/ - -/* noise generator start preset (for periodic noise) */ -#define NG_PRESET 0x0f35 +#include "mame/emu.h" +#include "mame/sn76496.h" -struct SN76496 { - int SampleRate; - unsigned int UpdateStep; - int VolTable[16]; /* volume table */ - int Register[8]; /* registers */ - int LastRegister; /* last register written */ - int Volume[4]; /* volume of voice 0-2 and noise */ - unsigned int RNG; /* noise generator */ - int NoiseFB; /* noise feedback mask */ - int Period[4]; - int Count[4]; - int Output[4]; -}; - -static struct SN76496 sn; +#define SOUND_CLOCK (14318180 / 4) #define TDAC_DMA_BUFSIZE 1024 @@ -99,221 +63,36 @@ static struct { } dac; } tandy; +static sn76496_device device(machine_config(), 0, 0, SOUND_CLOCK ); + static void SN76496Write(Bitu /*port*/,Bitu data,Bitu /*iolen*/) { - struct SN76496 *R = &sn; - tandy.last_write=PIC_Ticks; if (!tandy.enabled) { tandy.chan->Enable(true); tandy.enabled=true; } - - /* update the output buffer before changing the registers */ - - if (data & 0x80) - { - int r = (data & 0x70) >> 4; - int c = r/2; - - R->LastRegister = r; - R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f); - switch (r) - { - case 0: /* tone 0 : frequency */ - case 2: /* tone 1 : frequency */ - case 4: /* tone 2 : frequency */ - R->Period[c] = R->UpdateStep * R->Register[r]; - if (R->Period[c] == 0) R->Period[c] = 0x3fe; - if (r == 4) - { - /* update noise shift frequency */ - if ((R->Register[6] & 0x03) == 0x03) - R->Period[3] = 2 * R->Period[2]; - } - break; - case 1: /* tone 0 : volume */ - case 3: /* tone 1 : volume */ - case 5: /* tone 2 : volume */ - case 7: /* noise : volume */ - R->Volume[c] = R->VolTable[data & 0x0f]; - break; - case 6: /* noise : frequency, mode */ - { - int n = R->Register[6]; - R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE; - n &= 3; - /* N/512,N/1024,N/2048,Tone #3 output */ - R->Period[3] = (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+n)); - - /* reset noise shifter */ -// R->RNG = NG_PRESET; -// R->Output[3] = R->RNG & 1; - } - break; - } - } - else - { - int r = R->LastRegister; - int c = r/2; - - switch (r) - { - case 0: /* tone 0 : frequency */ - case 2: /* tone 1 : frequency */ - case 4: /* tone 2 : frequency */ - R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4); - R->Period[c] = R->UpdateStep * R->Register[r]; - if (R->Period[c] == 0) R->Period[c] = 0x3fe; - if (r == 4) - { - /* update noise shift frequency */ - if ((R->Register[6] & 0x03) == 0x03) - R->Period[3] = 2 * R->Period[2]; - } - break; - } - } + device.write(data); } static void SN76496Update(Bitu length) { + //Disable the channel if it's been quiet for a while if ((tandy.last_write+5000)Enable(false); + return; } - int i; - struct SN76496 *R = &sn; - Bit16s * buffer=(Bit16s *)MixTemp; + const Bitu MAX_SAMPLES = 2048; + if (length > MAX_SAMPLES) + return; + Bit16s buffer[MAX_SAMPLES]; + Bit16s* outputs = buffer; - /* If the volume is 0, increase the counter */ - for (i = 0;i < 4;i++) - { - if (R->Volume[i] == 0) - { - /* note that I do count += length, NOT count = length + 1. You might think */ - /* it's the same since the volume is 0, but doing the latter could cause */ - /* interferencies when the program is rapidly modulating the volume. */ - if (R->Count[i] <= (int)length*STEP) R->Count[i] += length*STEP; - } - } - - Bitu count=length; - while (count) - { - int vol[4]; - unsigned int out; - int left; - - - /* vol[] keeps track of how long each square wave stays */ - /* in the 1 position during the sample period. */ - vol[0] = vol[1] = vol[2] = vol[3] = 0; - - for (i = 0;i < 3;i++) - { - if (R->Output[i]) vol[i] += R->Count[i]; - R->Count[i] -= STEP; - /* Period[i] is the half period of the square wave. Here, in each */ - /* loop I add Period[i] twice, so that at the end of the loop the */ - /* square wave is in the same status (0 or 1) it was at the start. */ - /* vol[i] is also incremented by Period[i], since the wave has been 1 */ - /* exactly half of the time, regardless of the initial position. */ - /* If we exit the loop in the middle, Output[i] has to be inverted */ - /* and vol[i] incremented only if the exit status of the square */ - /* wave is 1. */ - while (R->Count[i] <= 0) - { - R->Count[i] += R->Period[i]; - if (R->Count[i] > 0) - { - R->Output[i] ^= 1; - if (R->Output[i]) vol[i] += R->Period[i]; - break; - } - R->Count[i] += R->Period[i]; - vol[i] += R->Period[i]; - } - if (R->Output[i]) vol[i] -= R->Count[i]; - } - - left = STEP; - do - { - int nextevent; - - - if (R->Count[3] < left) nextevent = R->Count[3]; - else nextevent = left; - - if (R->Output[3]) vol[3] += R->Count[3]; - R->Count[3] -= nextevent; - if (R->Count[3] <= 0) - { - if (R->RNG & 1) R->RNG ^= R->NoiseFB; - R->RNG >>= 1; - R->Output[3] = R->RNG & 1; - R->Count[3] += R->Period[3]; - if (R->Output[3]) vol[3] += R->Period[3]; - } - if (R->Output[3]) vol[3] -= R->Count[3]; - - left -= nextevent; - } while (left > 0); - - out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] + - vol[2] * R->Volume[2] + vol[3] * R->Volume[3]; - - if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP; - - *(buffer++) = (Bit16s)(out / STEP); - - count--; - } - tandy.chan->AddSamples_m16(length,(Bit16s *)MixTemp); + device_sound_interface::sound_stream stream; + static_cast(device).sound_stream_update(stream, 0, &outputs, length); + tandy.chan->AddSamples_m16(length, buffer); } - - -static void SN76496_set_clock(int clock) { - struct SN76496 *R = &sn; - - /* the base clock for the tone generators is the chip clock divided by 16; */ - /* for the noise generator, it is clock / 256. */ - /* Here we calculate the number of steps which happen during one sample */ - /* at the given sample rate. No. of events = sample rate / (clock/16). */ - /* STEP is a multiplier used to turn the fraction into a fixed point */ - /* number. */ - R->UpdateStep = (unsigned int)(((double)STEP * R->SampleRate * 16) / clock); -} - - -static void SN76496_set_gain(int gain) { - struct SN76496 *R = &sn; - int i; - double out; - - gain &= 0xff; - - /* increase max output basing on gain (0.2 dB per step) */ - out = MAX_OUTPUT / 3; - while (gain-- > 0) - out *= 1.023292992; /* = (10 ^ (0.2/20)) */ - - /* build volume table (2dB per step) */ - for (i = 0;i < 15;i++) - { - /* limit volume to avoid clipping */ - if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3; - else R->VolTable[i] = (int)out; - - out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */ - } - R->VolTable[15] = 0; -} - - - bool TS_Get_Address(Bitu& tsaddr, Bitu& tsirq, Bitu& tsdma) { tsaddr=0; tsirq =0; @@ -548,26 +327,9 @@ public: tandy.enabled=false; real_writeb(0x40,0xd4,0xff); /* BIOS Tandy DAC initialization value */ - Bitu i; - struct SN76496 *R = &sn; - R->SampleRate = sample_rate; - SN76496_set_clock(3579545); - for (i = 0;i < 4;i++) R->Volume[i] = 0; - R->LastRegister = 0; - for (i = 0;i < 8;i+=2) - { - R->Register[i] = 0; - R->Register[i + 1] = 0x0f; /* volume = 0 */ - } - - for (i = 0;i < 4;i++) - { - R->Output[i] = 0; - R->Period[i] = R->Count[i] = R->UpdateStep; - } - R->RNG = NG_PRESET; - R->Output[3] = R->RNG & 1; - SN76496_set_gain(0x1); + ((device_t&)device).device_start(); + device.convert_samplerate(sample_rate); + } ~TANDYSOUND(){ } };