Added a new sound device: Oki MSM9810. Emulation is not yet perfect.

[out of whatsnew]
It sounds ~60% correct, and appears to play the right stuff, but there is still much to do.
I'm not respecting the volume command.
I'm not taking sample rate into account.
I'm not doing anything with stereo yet (though funcube doesn't tickle that functionality).
The ADPCM(2?) decoding clearly isn't perfect (I've made a local copy of the oki_adpcm class to mess around with).
The way i set the clock in the seta2 driver should show I don't know what I'm doing :).
None of the channel flags are being interpreted yet.
I haven't hooked up Luca's sigma98 games yet.
This commit is contained in:
Andrew Gardner 2011-02-10 15:52:50 +00:00
parent 297d177dc0
commit 545f57a04c
6 changed files with 689 additions and 9 deletions

2
.gitattributes vendored
View File

@ -1049,6 +1049,8 @@ src/emu/sound/okim6295.c svneol=native#text/plain
src/emu/sound/okim6295.h svneol=native#text/plain
src/emu/sound/okim6376.c svneol=native#text/plain
src/emu/sound/okim6376.h svneol=native#text/plain
src/emu/sound/okim9810.c svneol=native#text/plain
src/emu/sound/okim9810.h svneol=native#text/plain
src/emu/sound/pokey.c svneol=native#text/plain
src/emu/sound/pokey.h svneol=native#text/plain
src/emu/sound/pokey.txt svneol=native#text/plain

478
src/emu/sound/okim9810.c Normal file
View File

@ -0,0 +1,478 @@
/***************************************************************************
okim9810.h
OKI MSM9810 ADCPM(2) sound chip.
***************************************************************************/
#include "emu.h"
#include "okim9810.h"
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
// devices
const device_type OKIM9810 = okim9810_device_config::static_alloc_device_config;
// default address map
static ADDRESS_MAP_START( okim9810, 0, 8 )
AM_RANGE(0x000000, 0xffffff) AM_ROM
ADDRESS_MAP_END
//**************************************************************************
// DEVICE CONFIGURATION
//**************************************************************************
//-------------------------------------------------
// okim9810_device_config - constructor
//-------------------------------------------------
okim9810_device_config::okim9810_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
: device_config(mconfig, static_alloc_device_config, "OKI9810", tag, owner, clock),
device_config_sound_interface(mconfig, *this),
device_config_memory_interface(mconfig, *this),
m_space_config("samples", ENDIANNESS_BIG, 8, 24, 0, NULL, *ADDRESS_MAP_NAME(okim9810))
{
}
//-------------------------------------------------
// static_alloc_device_config - allocate a new
// configuration object
//-------------------------------------------------
device_config *okim9810_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
{
return global_alloc(okim9810_device_config(mconfig, tag, owner, clock));
}
//-------------------------------------------------
// alloc_device - allocate a new device object
//-------------------------------------------------
device_t *okim9810_device_config::alloc_device(running_machine &machine) const
{
return auto_alloc(&machine, okim9810_device(machine, *this));
}
//-------------------------------------------------
// memory_space_config - return a description of
// any address spaces owned by this device
//-------------------------------------------------
const address_space_config *okim9810_device_config::memory_space_config(int spacenum) const
{
return (spacenum == 0) ? &m_space_config : NULL;
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// okim9810_device - constructor
//-------------------------------------------------
okim9810_device::okim9810_device(running_machine &_machine, const okim9810_device_config &config)
: device_t(_machine, config),
device_sound_interface(_machine, config, *this),
device_memory_interface(_machine, config, *this),
m_config(config),
m_stream(NULL),
m_TMP_register(0x00)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void okim9810_device::device_start()
{
// find our direct access
m_direct = &space()->direct();
// create the stream
//int divisor = m_config.m_pin7 ? 132 : 165;
m_stream = m_machine.sound().stream_alloc(*this, 0, 1, clock());
// save state stuff
// m_TMP_register
// m_voice
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void okim9810_device::device_reset()
{
m_stream->update();
for (int voicenum = 0; voicenum < OKIM9810_VOICES; voicenum++)
m_voice[voicenum].m_playing = false;
}
//-------------------------------------------------
// device_post_load - device-specific post-load
//-------------------------------------------------
void okim9810_device::device_post_load()
{
}
//-------------------------------------------------
// device_clock_changed - called if the clock
// changes
//-------------------------------------------------
void okim9810_device::device_clock_changed()
{
}
//-------------------------------------------------
// stream_generate - handle update requests for
// our sound stream
//-------------------------------------------------
void okim9810_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
// reset the output stream
memset(outputs[0], 0, samples * sizeof(*outputs[0]));
// iterate over voices and accumulate sample data
for (int voicenum = 0; voicenum < OKIM9810_VOICES; voicenum++)
m_voice[voicenum].generate_adpcm(*m_direct, outputs[0], samples);
}
//-------------------------------------------------
// read_status - read the status register
//-------------------------------------------------
UINT8 okim9810_device::read_status()
{
UINT8 result = 0x00;
return result;
}
//-------------------------------------------------
// read - memory interface for read
//-------------------------------------------------
READ8_MEMBER( okim9810_device::read )
{
return read_status();
}
//-------------------------------------------------
// write - memory interface for write
//-------------------------------------------------
// The command is written when the CMD pin is low
void okim9810_device::write_command(UINT8 data)
{
const UINT8 cmd = (data & 0xf8) >> 3;
const UINT8 channel = (data & 0x07);
switch(cmd)
{
case 0x00: // START
{
mame_printf_verbose("START channel mask %02x\n", m_TMP_register);
UINT8 channelMask = 0x01;
for (int i = 0; i < OKIM9810_VOICES; i++, channelMask <<= 1)
{
if (channelMask & m_TMP_register)
{
m_voice[i].m_playing = true;
mame_printf_verbose("\t\tPlaying channel %d: type %02x @ %08x for %d samples (looping=%d).\n", i,
m_voice[i].m_startFlags,
m_voice[i].m_base_offset,
m_voice[i].m_count,
m_voice[i].m_looping);
}
}
break;
}
case 0x01: // STOP
{
mame_printf_verbose("STOP channel mask %02x\n", m_TMP_register);
UINT8 channelMask = 0x01;
for (int i = 0; i < OKIM9810_VOICES; i++, channelMask <<= 1)
{
if (channelMask & m_TMP_register)
{
m_voice[i].m_playing = false;
mame_printf_verbose("\tChannel %d stopping.\n", i);
}
}
break;
}
case 0x02: // LOOP
{
mame_printf_verbose("LOOP channel mask %02x\n", m_TMP_register);
UINT8 channelMask = 0x01;
for (int i = 0; i < OKIM9810_VOICES; i++, channelMask <<= 1)
{
if (channelMask & m_TMP_register)
{
m_voice[i].m_looping = true;
mame_printf_verbose("\tChannel %d looping.\n", i);
}
else
{
m_voice[i].m_looping = false;
mame_printf_verbose("\tChannel %d done looping.\n", i);
}
}
break;
}
case 0x03: // OPT (options)
{
mame_printf_warning("OPT complex data %02x\n", m_TMP_register);
mame_printf_warning("MSM9810: UNIMPLEMENTED COMMAND!\n");
break;
}
case 0x04: // MUON (silence)
{
mame_printf_warning("MUON channel %d length %02x\n", channel, m_TMP_register);
mame_printf_warning("MSM9810: UNIMPLEMENTED COMMAND!\n");
break;
}
case 0x05: // FADR (phrase address)
{
const offs_t base = m_TMP_register * 8;
offs_t startAddr;
const UINT8 startFlags = m_direct->read_raw_byte(base + 0);
startAddr = m_direct->read_raw_byte(base + 1) << 16;
startAddr |= m_direct->read_raw_byte(base + 2) << 8;
startAddr |= m_direct->read_raw_byte(base + 3) << 0;
offs_t endAddr;
const UINT8 endFlags = m_direct->read_raw_byte(base + 4);
endAddr = m_direct->read_raw_byte(base + 5) << 16;
endAddr |= m_direct->read_raw_byte(base + 6) << 8;
endAddr |= m_direct->read_raw_byte(base + 7) << 0;
// Note: flags might be (& 0x30 => voice synthesis algorithm) (& 0x0f => sampling frequency)
mame_printf_verbose("FADR channel %d phrase offset %02x => ", channel, m_TMP_register);
mame_printf_verbose("\tstartFlags(%02x) startAddr(%06x) endFlags(%02x) endAddr(%06x) bytes(%d)\n", startFlags, startAddr, endFlags, endAddr, endAddr-startAddr);
m_voice[channel].m_startFlags = startFlags;
m_voice[channel].m_base_offset = startAddr;
m_voice[channel].m_endFlags = endFlags;
m_voice[channel].m_sample = 0;
// TODO: Sample count (m_count) changes based on decoding mode
m_voice[channel].m_count = 2 * ((endAddr-startAddr) + 1); // TODO: Explain the +1
break;
}
case 0x06: // DADR (direct address playback)
{
mame_printf_warning("DADR channel %d complex data %02x\n", channel, m_TMP_register);
mame_printf_warning("MSM9810: UNIMPLEMENTED COMMAND!\n");
break;
}
case 0x07: // CVOL (channel volume)
{
mame_printf_verbose("CVOL channel %d volume level %02x\n", channel, m_TMP_register);
mame_printf_verbose("\tChannel %d -> volume %d.\n", channel, m_TMP_register);
// TODO: Use the proper volume table p37
m_voice[channel].m_volume = m_TMP_register;
break;
}
case 0x08: // PAN
{
mame_printf_warning("PAN channel %d volume level %02x\n", channel, m_TMP_register);
mame_printf_warning("MSM9810: UNIMPLEMENTED COMMAND!\n");
break;
}
default:
{
mame_printf_warning("MSM9810: UNKNOWN COMMAND!\n");
break;
}
}
}
WRITE8_MEMBER( okim9810_device::write )
{
write_command(data);
}
//-----------------------------------------------------------
// writeTMP - memory interface for writing the TMP register
//-----------------------------------------------------------
// TMP is written when the CMD pin is high
void okim9810_device::write_TMP_register(UINT8 data)
{
m_TMP_register = data;
}
WRITE8_MEMBER( okim9810_device::write_TMP_register )
{
write_TMP_register(data);
}
//**************************************************************************
// OKIM VOICE
//**************************************************************************
//-------------------------------------------------
// okim_voice - constructor
//-------------------------------------------------
okim9810_device::okim_voice::okim_voice()
: m_playing(false),
m_looping(false),
m_startFlags(0),
m_endFlags(0),
m_base_offset(0),
m_sample(0),
m_count(0),
m_volume(0)
{
}
//-------------------------------------------------
// generate_adpcm - generate ADPCM samples and
// add them to an output stream
//-------------------------------------------------
void okim9810_device::okim_voice::generate_adpcm(direct_read_data &direct, stream_sample_t *buffer, int samples)
{
// skip if not active
if (!m_playing)
return;
// loop while we still have samples to generate
while (samples-- != 0)
{
// fetch the next sample byte
int nibble = direct.read_raw_byte(m_base_offset + m_sample / 2) >> (((m_sample & 1) << 2) ^ 4);
// output to the buffer, scaling by the volume
// signal in range -2048..2047, volume in range 2..32 => signal * volume / 2 in range -32768..32767
*buffer++ += m_adpcm.clock(nibble); //TODO * m_volume / 2;
// next!
if (++m_sample >= m_count)
{
if (!m_looping)
m_playing = false;
else
m_sample = 0;
break;
}
}
}
//**************************************************************************
// ADPCM STATE HELPER
//**************************************************************************
// ADPCM state and tables
bool adpcm_stateCopy::s_tables_computed = false;
const INT8 adpcm_stateCopy::s_index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
int adpcm_stateCopy::s_diff_lookup[49*16];
//-------------------------------------------------
// reset - reset the ADPCM state
//-------------------------------------------------
void adpcm_stateCopy::reset()
{
// reset the signal/step
m_signal = -2;
m_step = 0;
}
//-------------------------------------------------
// device_clock_changed - called if the clock
// changes
//-------------------------------------------------
INT16 adpcm_stateCopy::clock(UINT8 nibble)
{
// update the signal
m_signal += s_diff_lookup[m_step * 16 + (nibble & 15)];
// clamp to the maximum
if (m_signal > 2047)
m_signal = 2047;
else if (m_signal < -2048)
m_signal = -2048;
// adjust the step size and clamp
m_step += s_index_shift[nibble & 7];
if (m_step > 48)
m_step = 48;
else if (m_step < 0)
m_step = 0;
// return the signal
return m_signal;
}
//-------------------------------------------------
// compute_tables - precompute tables for faster
// sound generation
//-------------------------------------------------
void adpcm_stateCopy::compute_tables()
{
// skip if we already did it
if (s_tables_computed)
return;
s_tables_computed = true;
// nibble to bit map
static const INT8 nbl2bit[16][4] =
{
{ 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
{ 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
{-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
{-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
};
// loop over all possible steps
for (int step = 0; step <= 48; step++)
{
// compute the step value
int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step));
// loop over all nibbles and compute the difference
for (int nib = 0; nib < 16; nib++)
{
s_diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
(stepval * nbl2bit[nib][1] +
stepval/2 * nbl2bit[nib][2] +
stepval/4 * nbl2bit[nib][3] +
stepval/8);
}
}
}

164
src/emu/sound/okim9810.h Normal file
View File

@ -0,0 +1,164 @@
/***************************************************************************
okim9810.h
OKI MSM9810 ADCPM(2) sound chip.
***************************************************************************/
#pragma once
#ifndef __OKIM9810_H__
#define __OKIM9810_H__
//**************************************************************************
// CONSTANTS
//**************************************************************************
enum
{
OKIM9810_SERIAL_PIN_LOW = 0,
OKIM9810_SERIAL_PIN_HIGH = 1,
// etc
};
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_OKIM9810_ADD(_tag, _clock) \
MCFG_DEVICE_ADD(_tag, OKIM9810, _clock)
#define MCFG_OKIM9810_REPLACE(_tag, _clock) \
MCFG_DEVICE_REPLACE(_tag, OKIM9810, _clock)
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> adpcm_stateCopy
// Internal ADPCM state, used by external ADPCM generators with compatible specs to the OKIM 6295.
class adpcm_stateCopy
{
public:
adpcm_stateCopy() { compute_tables(); reset(); }
void reset();
INT16 clock(UINT8 nibble);
INT32 m_signal;
INT32 m_step;
private:
static const INT8 s_index_shift[8];
static int s_diff_lookup[49*16];
static void compute_tables();
static bool s_tables_computed;
};
// ======================> okim9810_device_config
class okim9810_device_config : public device_config,
public device_config_sound_interface,
public device_config_memory_interface
{
friend class okim9810_device;
// construction/destruction
okim9810_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
public:
// allocators
static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
virtual device_t *alloc_device(running_machine &machine) const;
protected:
// device_config overrides
virtual const address_space_config *memory_space_config(int spacenum = 0) const;
// internal state
const address_space_config m_space_config;
};
// ======================> okim9810_device
class okim9810_device : public device_t,
public device_sound_interface,
public device_memory_interface
{
friend class okim9810_device_config;
// construction/destruction
okim9810_device(running_machine &_machine, const okim9810_device_config &config);
public:
UINT8 read_status();
void write_TMP_register(UINT8 command);
void write_command(UINT8 command);
DECLARE_READ8_MEMBER( read );
DECLARE_WRITE8_MEMBER( write );
DECLARE_WRITE8_MEMBER( write_TMP_register );
protected:
// device-level overrides
virtual void device_start();
virtual void device_reset();
virtual void device_post_load();
virtual void device_clock_changed();
// sound interface overrides
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
// a single voice
class okim_voice
{
public:
okim_voice();
void generate_adpcm(direct_read_data &direct, stream_sample_t *buffer, int samples);
adpcm_stateCopy m_adpcm; // current ADPCM state
bool m_playing;
bool m_looping;
UINT8 m_startFlags;
UINT8 m_endFlags;
offs_t m_base_offset; // pointer to the base memory location
UINT32 m_sample; // current sample number
UINT32 m_count; // total bytes to play
INT8 m_volume; // output volume
// TODO: m_volume_left; // stereo volume
// TODO: m_volume_right; // stereo volume
};
// internal state
const okim9810_device_config &m_config;
sound_stream* m_stream;
direct_read_data* m_direct;
UINT8 m_TMP_register;
static const int OKIM9810_VOICES = 8;
okim_voice m_voice[OKIM9810_VOICES];
};
// device type definition
extern const device_type OKIM9810;
#endif // __OKIM9810_H__

View File

@ -376,6 +376,10 @@ ifneq ($(filter OKIM6258,$(SOUNDS)),)
SOUNDOBJS += $(SOUNDOBJ)/okim6258.o
endif
ifneq ($(filter OKIM9810,$(SOUNDS)),)
SOUNDOBJS += $(SOUNDOBJ)/okim9810.o
endif
#-------------------------------------------------

View File

@ -535,6 +535,7 @@ The same H8/3007 code "FC21 IOPR-0" at U49 is used for FUNCUBE 2,3,4 & 5
#include "cpu/h83002/h8.h"
#include "machine/eeprom.h"
#include "sound/x1_010.h"
#include "sound/okim9810.h"
#include "includes/seta2.h"
#include "machine/nvram.h"
@ -959,6 +960,20 @@ static READ32_HANDLER( funcube_debug_r )
return ret;
}
static WRITE32_DEVICE_HANDLER( oki_write )
{
if (ACCESSING_BITS_0_7)
{
const UINT8 tmp = (data & 0x000000ff);
downcast<okim9810_device *>(device)->write_TMP_register(tmp);
}
else if (ACCESSING_BITS_16_23)
{
const UINT8 cmd = (data & 0x00ff0000) >> 16;
downcast<okim9810_device *>(device)->write_command(cmd);
}
}
static ADDRESS_MAP_START( funcube_map, ADDRESS_SPACE_PROGRAM, 32 )
AM_RANGE( 0x00000000, 0x0007ffff ) AM_ROM
@ -967,7 +982,7 @@ static ADDRESS_MAP_START( funcube_map, ADDRESS_SPACE_PROGRAM, 32 )
AM_RANGE( 0x00500000, 0x00500003 ) AM_READ( funcube_debug_r )
AM_RANGE( 0x00500004, 0x00500007 ) AM_READ( watchdog_reset32_r ) AM_WRITENOP
AM_RANGE( 0x00600000, 0x00600003 ) AM_WRITENOP // sound chip
AM_RANGE( 0x00600000, 0x00600003 ) AM_DEVWRITE("oki", oki_write)
AM_RANGE( 0x00800000, 0x0083ffff ) AM_READWRITE( spriteram32_dword_r, spriteram32_dword_w ) AM_BASE_SIZE_MEMBER(seta2_state, spriteram, spriteram_size)
AM_RANGE( 0x00840000, 0x0084ffff ) AM_READWRITE( paletteram32_dword_r, paletteram32_dword_w ) AM_BASE_GENERIC(paletteram)
@ -2494,9 +2509,11 @@ static MACHINE_CONFIG_START( funcube, seta2_state )
MCFG_VIDEO_EOF(seta2)
/* sound hardware */
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
// MSM9810B
MCFG_OKIM9810_ADD("oki", XTAL_14_7456MHz/10/10/10)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.80)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.80)
MACHINE_CONFIG_END
@ -2804,8 +2821,8 @@ ROM_START( funcube2 )
ROM_LOAD32_WORD( "fc21_obj-0.u43", 0x000000, 0x400000, CRC(08cfe6d9) SHA1(d10f362dcde01f7a9855d8f76af3084b5dd1573a) )
ROM_LOAD32_WORD( "fc21_obj-1.u42", 0x000002, 0x400000, CRC(4c1fbc20) SHA1(ff83691c19ce3600b31c494eaec26d2ac79e0028) )
ROM_REGION( 0x400000, "samples", 0 )
ROM_LOAD( "fc21_voi0.u47", 0x00000, 0x400000, CRC(25b5fc3f) SHA1(18b16a14e9ee62f3fea382e9d3fdcd43bdb165f5) )
ROM_REGION( 0x1000000, "oki", 0 )
ROM_LOAD( "fc21_voi0.u47", 0x000000, 0x400000, CRC(25b5fc3f) SHA1(18b16a14e9ee62f3fea382e9d3fdcd43bdb165f5) )
ROM_END
ROM_START( funcube4 )
@ -2822,8 +2839,8 @@ ROM_START( funcube4 )
ROM_LOAD32_WORD( "fc41_obj-0.u43", 0x000000, 0x400000, CRC(9ff029d5) SHA1(e057f4929aa745ecaf9d4ff7e39974c82e440146) )
ROM_LOAD32_WORD( "fc41_obj-1.u42", 0x000002, 0x400000, CRC(5ab7b087) SHA1(c600158b2358cdf947357170044dda2deacd4f37) )
ROM_REGION( 0x400000, "samples", 0 )
ROM_LOAD( "fc41_snd0.u47", 0x00000, 0x400000, CRC(48337257) SHA1(d1755024b824100070b489f48f6ae921765329e8) )
ROM_REGION( 0x1000000, "oki", 0 )
ROM_LOAD( "fc41_snd0.u47", 0x000000, 0x400000, CRC(48337257) SHA1(d1755024b824100070b489f48f6ae921765329e8) )
ROM_END
static DRIVER_INIT( funcube2 )
@ -2841,8 +2858,15 @@ static DRIVER_INIT( funcube2 )
main_cpu[0xa8c/4] = 0x4e7141f9;
// Sub CPU
sub_cpu[0x4d4/2] = 0x5470; // rte -> rts
// Audio
// The first half of the rom appears to be a dupe of the second half with 0xffs destructively interleaved
UINT8* oki = (UINT8*) machine->region("oki")->base();
for (int i = 0; i < 0x200000; i++)
{
oki[i] = oki[i+0x200000];
}
}
// Note: same as funcube2
@ -2861,8 +2885,15 @@ static DRIVER_INIT( funcube4 )
main_cpu[0xa8c/4] = 0x4e7141f9;
// Sub CPU
sub_cpu[0x4d4/2] = 0x5470; // rte -> rts
// Audio
// The first half of the rom appears to be a dupe of the second half with 0xffs destructively interleaved
UINT8* oki = (UINT8*) machine->region("oki")->base();
for (int i = 0; i < 0x200000; i++)
{
oki[i] = oki[i+0x200000];
}
}
GAME( 1994, gundamex, 0, gundamex, gundamex, 0, ROT0, "Banpresto", "Mobile Suit Gundam EX Revue", 0 )

View File

@ -177,6 +177,7 @@ SOUNDS += MSM5232
SOUNDS += OKIM6258
SOUNDS += OKIM6295
SOUNDS += OKIM6376
SOUNDS += OKIM9810
SOUNDS += UPD7759
SOUNDS += HC55516
SOUNDS += K005289