diff options
Diffstat (limited to 'src/devices/sound/k007232.cpp')
-rw-r--r-- | src/devices/sound/k007232.cpp | 519 |
1 files changed, 193 insertions, 326 deletions
diff --git a/src/devices/sound/k007232.cpp b/src/devices/sound/k007232.cpp index 96f89ff628f..03f6f16eea0 100644 --- a/src/devices/sound/k007232.cpp +++ b/src/devices/sound/k007232.cpp @@ -6,153 +6,44 @@ /* Changelog, Hiromitsu Shioya 02/05/2002 - fix start address decode timing. (sample loop bug.) + fixed start address decode timing. (sample loop bug.) - Changelog, Mish, August 1999: - Removed interface support for different memory regions per channel. - Removed interface support for differing channel volume. + Changelog, Mish, August 1999: + Removed interface support for different memory regions per channel. + Removed interface support for differing channel volume. - Added bankswitching. - Added support for multiple chips. + Added bankswitching. + Added support for multiple chips. - (Nb: Should different memory regions per channel be needed - the bankswitching function can set this up). - -NS990821 -support for the k007232_VOL() macro. -added external port callback, and functions to set the volume of the channels + (NB: Should different memory regions per channel be needed, the bankswitching function can set this up). + Chanelog, Nicola, August 1999: + Added Support for the k007232_VOL() macro. + Added external port callback, and functions to set the volume of the channels */ #include "emu.h" #include "k007232.h" +#include "wavwrite.h" +#include <algorithm> -#define BASE_SHIFT (12) - - -#if 0 -static const int kdac_note[] = { - 261.63/8, 277.18/8, - 293.67/8, 311.13/8, - 329.63/8, - 349.23/8, 369.99/8, - 392.00/8, 415.31/8, - 440.00/8, 466.16/8, - 493.88/8, - - 523.25/8, -}; - -static const float kdaca_fn[][2] = { - /* B */ - { 0x03f, 493.88/8 }, /* ?? */ - { 0x11f, 493.88/4 }, /* ?? */ - { 0x18f, 493.88/2 }, /* ?? */ - { 0x1c7, 493.88 }, - { 0x1e3, 493.88*2 }, - { 0x1f1, 493.88*4 }, /* ?? */ - { 0x1f8, 493.88*8 }, /* ?? */ - /* A+ */ - { 0x020, 466.16/8 }, /* ?? */ - { 0x110, 466.16/4 }, /* ?? */ - { 0x188, 466.16/2 }, - { 0x1c4, 466.16 }, - { 0x1e2, 466.16*2 }, - { 0x1f1, 466.16*4 }, /* ?? */ - { 0x1f8, 466.16*8 }, /* ?? */ - /* A */ - { 0x000, 440.00/8 }, /* ?? */ - { 0x100, 440.00/4 }, /* ?? */ - { 0x180, 440.00/2 }, - { 0x1c0, 440.00 }, - { 0x1e0, 440.00*2 }, - { 0x1f0, 440.00*4 }, /* ?? */ - { 0x1f8, 440.00*8 }, /* ?? */ - { 0x1fc, 440.00*16}, /* ?? */ - { 0x1fe, 440.00*32}, /* ?? */ - { 0x1ff, 440.00*64}, /* ?? */ - /* G+ */ - { 0x0f2, 415.31/4 }, - { 0x179, 415.31/2 }, - { 0x1bc, 415.31 }, - { 0x1de, 415.31*2 }, - { 0x1ef, 415.31*4 }, /* ?? */ - { 0x1f7, 415.31*8 }, /* ?? */ - /* G */ - { 0x0e2, 392.00/4 }, - { 0x171, 392.00/2 }, - { 0x1b8, 392.00 }, - { 0x1dc, 392.00*2 }, - { 0x1ee, 392.00*4 }, /* ?? */ - { 0x1f7, 392.00*8 }, /* ?? */ - /* F+ */ - { 0x0d0, 369.99/4 }, /* ?? */ - { 0x168, 369.99/2 }, - { 0x1b4, 369.99 }, - { 0x1da, 369.99*2 }, - { 0x1ed, 369.99*4 }, /* ?? */ - { 0x1f6, 369.99*8 }, /* ?? */ - /* F */ - { 0x0bf, 349.23/4 }, /* ?? */ - { 0x15f, 349.23/2 }, - { 0x1af, 349.23 }, - { 0x1d7, 349.23*2 }, - { 0x1eb, 349.23*4 }, /* ?? */ - { 0x1f5, 349.23*8 }, /* ?? */ - /* E */ - { 0x0ac, 329.63/4 }, - { 0x155, 329.63/2 }, /* ?? */ - { 0x1ab, 329.63 }, - { 0x1d5, 329.63*2 }, - { 0x1ea, 329.63*4 }, /* ?? */ - { 0x1f4, 329.63*8 }, /* ?? */ - /* D+ */ - { 0x098, 311.13/4 }, /* ?? */ - { 0x14c, 311.13/2 }, - { 0x1a6, 311.13 }, - { 0x1d3, 311.13*2 }, - { 0x1e9, 311.13*4 }, /* ?? */ - { 0x1f4, 311.13*8 }, /* ?? */ - /* D */ - { 0x080, 293.67/4 }, /* ?? */ - { 0x140, 293.67/2 }, /* ?? */ - { 0x1a0, 293.67 }, - { 0x1d0, 293.67*2 }, - { 0x1e8, 293.67*4 }, /* ?? */ - { 0x1f4, 293.67*8 }, /* ?? */ - { 0x1fa, 293.67*16}, /* ?? */ - { 0x1fd, 293.67*32}, /* ?? */ - /* C+ */ - { 0x06d, 277.18/4 }, /* ?? */ - { 0x135, 277.18/2 }, /* ?? */ - { 0x19b, 277.18 }, - { 0x1cd, 277.18*2 }, - { 0x1e6, 277.18*4 }, /* ?? */ - { 0x1f2, 277.18*8 }, /* ?? */ - /* C */ - { 0x054, 261.63/4 }, - { 0x12a, 261.63/2 }, - { 0x195, 261.63 }, - { 0x1ca, 261.63*2 }, - { 0x1e5, 261.63*4 }, - { 0x1f2, 261.63*8 }, /* ?? */ - - { -1, -1 }, -}; -#endif - -/*************************************************************/ - +#define K007232_LOG_PCM (0) DEFINE_DEVICE_TYPE(K007232, k007232_device, "k007232", "K007232 PCM Controller") -k007232_device::k007232_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +k007232_device::k007232_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, K007232, tag, owner, clock) , device_sound_interface(mconfig, *this) + , device_memory_interface(mconfig, *this) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 17) // 17 bit address, 8 bit data, can be bankswitched per each voices , m_rom(*this, DEVICE_SELF) + , m_pcmlimit(~0) + , m_bank(0) + , m_stream(nullptr) , m_port_write_handler(*this) { + std::fill(std::begin(m_wreg), std::end(m_wreg), 0); } //------------------------------------------------- @@ -161,187 +52,159 @@ k007232_device::k007232_device(const machine_config &mconfig, const char *tag, d void k007232_device::device_start() { - /* Set up the chips */ - m_pcmlimit = m_rom.bytes(); + // assumes it can make an address mask with m_rom.length() - 1 + assert (!m_rom.found() || !(m_rom.length() & (m_rom.length() - 1))); - m_port_write_handler.resolve(); + m_pcmlimit = 1 << 17; + // default mapping (bankswitched ROM) + if (m_rom.found() && !has_configured_map(0)) + { + if (m_rom.bytes() > 0x20000) + space(0).install_read_handler(0x00000, std::min<offs_t>(0x1ffff, m_rom.bytes() - 1), read8sm_delegate(*this, FUNC(k007232_device::read_rom_default))); + else + { + space(0).install_rom(0x00000, m_rom.length() - 1, m_rom.target()); + m_pcmlimit = m_rom.bytes(); + } + } + space(0).cache(m_cache); - for (int i = 0; i < KDAC_A_PCM_MAX; i++) + /* Set up the chips */ + for (int i = 0; i < PCM_MAX; i++) { - m_addr[i] = 0; - m_start[i] = 0; - m_step[i] = 0; - m_play[i] = 0; - m_bank[i] = 0; + m_channel[i].addr = 0; + m_channel[i].start = 0; + m_channel[i].counter = 0x1000; + m_channel[i].step = 0; + m_channel[i].play = 0; + m_channel[i].bank = 0; } - m_vol[0][0] = 255; /* channel A output to output A */ - m_vol[0][1] = 0; - m_vol[1][0] = 0; - m_vol[1][1] = 255; /* channel B output to output B */ + m_channel[0].vol[0] = 255; /* channel A output to output A */ + m_channel[0].vol[1] = 0; + m_channel[1].vol[0] = 0; + m_channel[1].vol[1] = 255; /* channel B output to output B */ for (auto & elem : m_wreg) elem = 0; - m_stream = machine().sound().stream_alloc(*this, 0 , 2, clock()/128); + m_stream = stream_alloc(0, 2, clock() / 128); - KDAC_A_make_fncode(); - - save_item(NAME(m_vol)); - save_item(NAME(m_addr)); - save_item(NAME(m_start)); - save_item(NAME(m_step)); - save_item(NAME(m_bank)); - save_item(NAME(m_play)); + save_item(STRUCT_MEMBER(m_channel, vol)); + save_item(STRUCT_MEMBER(m_channel, addr)); + save_item(STRUCT_MEMBER(m_channel, counter)); + save_item(STRUCT_MEMBER(m_channel, start)); + save_item(STRUCT_MEMBER(m_channel, step)); + save_item(STRUCT_MEMBER(m_channel, bank)); + save_item(STRUCT_MEMBER(m_channel, play)); save_item(NAME(m_wreg)); } -void k007232_device::KDAC_A_make_fncode() +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +void k007232_device::device_clock_changed() { -#if 0 - int i, j, k; - float fn; - for( i = 0; i < 0x200; i++ ) fncode[i] = 0; - - i = 0; - while( (int)kdaca_fn[i][0] != -1 ){ - fncode[(int)kdaca_fn[i][0]] = kdaca_fn[i][1]; - i++; - } + m_stream->set_sample_rate(clock() / 128); +} - i = j = 0; - while( i < 0x200 ){ - if( fncode[i] != 0 ){ - if( i != j ){ - fn = (fncode[i] - fncode[j]) / (i - j); - for( k = 1; k < (i-j); k++ ) - fncode[k+j] = fncode[j] + fn*k; - j = i; - } - } - i++; - } -#if 0 - for( i = 0; i < 0x200; i++ ) - logerror("fncode[%04x] = %.2f\n", i, fncode[i] ); -#endif - -#else - int i; - for( i = 0; i < 0x200; i++ ) - { - //fncode[i] = (0x200 * 55) / (0x200 - i); - m_fncode[i] = (32 << BASE_SHIFT) / (0x200 - i); -// m_fncode[i] = ((0x200 * 55.2 / 880) / (0x200 - i)); - // = 512 * 55.2 / 220 / (512 - i) = 128 / (512 - i) - // logerror("2 : fncode[%04x] = %.2f\n", i, fncode[i] ); - } +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- -#endif +device_memory_interface::space_config_vector k007232_device::memory_space_config() const +{ + return space_config_vector{ std::make_pair(0, &m_data_config) }; } - /************************************************/ /* Konami PCM write register */ /************************************************/ -WRITE8_MEMBER( k007232_device::write ) -{ - int r = offset; - int v = data; +void k007232_device::write(offs_t offset, u8 data) +{ m_stream->update(); - m_wreg[r] = v; /* stock write data */ - - if (r == 0x0c){ - /* external port, usually volume control */ - if (!m_port_write_handler.isnull()) m_port_write_handler(0, v, mem_mask); - return; - } - else if( r == 0x0d ){ - /* loopflag. */ - return; - } - else{ - int reg_port; + m_wreg[offset] = data; // standard data write - reg_port = 0; - if (r >= 0x06){ - reg_port = 1; - r -= 0x06; + if (offset == 12) + { + // external port, usually volume control + m_port_write_handler(0, data); } - - switch (r){ - case 0x00: - case 0x01: + else if (offset == 13) { - /**** address step ****/ - int idx = (((((unsigned int)m_wreg[reg_port*0x06 + 0x01])<<8)&0x0100) | (((unsigned int)m_wreg[reg_port*0x06 + 0x00])&0x00ff)); -#if 0 - if( !reg_port && r == 1 ) - logerror("%04x\n" ,idx ); -#endif - - m_step[reg_port] = m_fncode[idx]; - break; + // loop flag, handled by standard data write } - case 0x02: - case 0x03: - case 0x04: - break; - case 0x05: - /**** start address ****/ - m_start[reg_port] = - ((((unsigned int)m_wreg[reg_port*0x06 + 0x04]<<16)&0x00010000) | - (((unsigned int)m_wreg[reg_port*0x06 + 0x03]<< 8)&0x0000ff00) | - (((unsigned int)m_wreg[reg_port*0x06 + 0x02] )&0x000000ff) | - m_bank[reg_port]); - if (m_start[reg_port] < m_pcmlimit ){ - m_play[reg_port] = 1; - m_addr[reg_port] = 0; + else + { + channel_t &channel = m_channel[(offset >= 6 ? 1 : 0)]; + int const reg_index = (offset >= 6 ? 6 : 0); + if (offset >= 6) + offset -= 6; + + switch (offset) + { + case 0: // address step, LSB + case 1: // address step, MSB + channel.step = (BIT(m_wreg[reg_index + 1], 0, 4) << 8) | m_wreg[reg_index]; + // TODO: Bit 4-5 is frequency divider, but not implemented now + break; + case 2: + case 3: + case 4: + // working data for start address + channel.start = (BIT(m_wreg[reg_index + 4], 0) << 16) | (m_wreg[reg_index + 3] << 8) | m_wreg[reg_index + 2]; + break; + case 5: // start address + if (channel.start < m_pcmlimit) + { + channel.play = true; + channel.addr = channel.start; + channel.counter = 0x1000; + } + break; } - break; - } } } /************************************************/ /* Konami PCM read register */ /************************************************/ -READ8_MEMBER( k007232_device::read ) + +u8 k007232_device::read(offs_t offset) { - int r = offset; - int ch; - - if( r == 0x0005 || r == 0x000b ){ - ch = r/0x0006; - r = ch * 0x0006; - - m_start[ch] = - ((((unsigned int)m_wreg[r + 0x04]<<16)&0x00010000) | - (((unsigned int)m_wreg[r + 0x03]<< 8)&0x0000ff00) | - (((unsigned int)m_wreg[r + 0x02] )&0x000000ff) | - m_bank[ch]); - - if (m_start[ch] < m_pcmlimit ){ - m_play[ch] = 1; - m_addr[ch] = 0; - } + if (!machine().side_effects_disabled()) + { + if (offset == 5 || offset == 11) + { + channel_t &channel = m_channel[(offset == 11) ? 1 : 0]; + + if (channel.start < m_pcmlimit) + { + channel.play = true; + channel.addr = channel.start; + channel.counter = 0x1000; + } + } } return 0; } /*****************************************************************************/ -void k007232_device::set_volume(int channel,int volumeA,int volumeB) +void k007232_device::set_volume(int channel, int vol_a, int vol_b) { - m_vol[channel][0] = volumeA; - m_vol[channel][1] = volumeB; + m_channel[channel].vol[0] = vol_a; + m_channel[channel].vol[1] = vol_b; } -void k007232_device::set_bank(int chABank, int chBBank ) +void k007232_device::set_bank(int chan_a_bank, int chan_b_bank) { - m_bank[0] = chABank<<17; - m_bank[1] = chBBank<<17; + m_channel[0].bank = chan_a_bank << 17; + m_channel[1].bank = chan_b_bank << 17; } /*****************************************************************************/ @@ -351,74 +214,78 @@ void k007232_device::set_bank(int chABank, int chBBank ) // sound_stream_update - handle a stream update //------------------------------------------------- -void k007232_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +void k007232_device::sound_stream_update(sound_stream &stream) { - int i; - - memset(outputs[0],0,samples * sizeof(*outputs[0])); - memset(outputs[1],0,samples * sizeof(*outputs[1])); - - for( i = 0; i < KDAC_A_PCM_MAX; i++ ) + if (K007232_LOG_PCM) { - if (m_play[i]) - { - int volA,volB,j,out; - unsigned int addr, old_addr; - //int cen; - - /**** PCM setup ****/ - addr = m_start[i] + ((m_addr[i]>>BASE_SHIFT)&0x000fffff); - volA = m_vol[i][0] * 2; - volB = m_vol[i][1] * 2; -#if 0 - cen = (volA + volB) / 2; - volA = (volA + cen) < 0x1fe ? (volA + cen) : 0x1fe; - volB = (volB + cen) < 0x1fe ? (volB + cen) : 0x1fe; -#endif - - for( j = 0; j < samples; j++ ) - { - old_addr = addr; - addr = m_start[i] + ((m_addr[i]>>BASE_SHIFT)&0x000fffff); - while (old_addr <= addr) + for (int i = 0; i < PCM_MAX; i++) { - if( (m_rom[old_addr] & 0x80) || old_addr >= m_pcmlimit ) + channel_t &channel = m_channel[i]; + if (channel.play) { - /* end of sample */ - - if( m_wreg[0x0d]&(1<<i) ) - { - /* loop to the beginning */ - m_start[i] = - ((((unsigned int)m_wreg[i*0x06 + 0x04]<<16)&0x00010000) | - (((unsigned int)m_wreg[i*0x06 + 0x03]<< 8)&0x0000ff00) | - (((unsigned int)m_wreg[i*0x06 + 0x02] )&0x000000ff) | - m_bank[i]); - addr = m_start[i]; - m_addr[i] = 0; - old_addr = addr; /* skip loop */ - } - else - { - /* stop sample */ - m_play[i] = 0; + char filebuf[256]; + snprintf(filebuf, 256, "pcm%08x.wav", channel.start); + util::wav_file_ptr file = util::wav_open(filebuf, stream.sample_rate(), 1); + if (file) + { + u32 addr = channel.start; + while (!BIT(read_sample(i, addr), 7) && addr < m_pcmlimit) + { + int16_t out = ((read_sample(i, addr) & 0x7f) - 0x40) << 7; + util::wav_add_data_16(*file, &out, 1); + addr++; + } + } } - break; - } - - old_addr++; } + } - if (m_play[i] == 0) - break; - - m_addr[i] += m_step[i]; - - out = (m_rom[addr] & 0x7f) - 0x40; - - outputs[0][j] += out * volA; - outputs[1][j] += out * volB; + for (int j = 0; j < stream.samples(); j++) + { + s32 lsum = 0, rsum = 0; + for (int i = 0; i < PCM_MAX; i++) + { + channel_t &channel = m_channel[i]; + if (channel.play) + { + /**** PCM setup ****/ + int const vol_a = channel.vol[0] * 2; + int const vol_b = channel.vol[1] * 2; + + u32 addr = channel.addr & 0x1ffff; + while (channel.counter <= channel.step) // result : clock / (4 * (4096 - frequency)) + { + if (BIT(read_sample(i, addr++), 7) || addr >= m_pcmlimit) + { + // end of sample + if (BIT(m_wreg[13], i)) + { + /* loop to the beginning */ + addr = channel.start; + } + else + { + /* stop sample */ + channel.play = false; + break; + } + } + channel.counter += (0x1000 - channel.step); + } + channel.addr = addr; + + if (!channel.play) + break; + + channel.counter -= 32; + + int const out = (read_sample(i, addr) & 0x7f) - 0x40; + + lsum += out * vol_a; + rsum += out * vol_b; + } } - } + stream.put_int(0, j, lsum, 32768); + stream.put_int(1, j, rsum, 32768); } } |