summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/sound/vlm5030.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/sound/vlm5030.c')
-rw-r--r--trunk/src/emu/sound/vlm5030.c718
1 files changed, 718 insertions, 0 deletions
diff --git a/trunk/src/emu/sound/vlm5030.c b/trunk/src/emu/sound/vlm5030.c
new file mode 100644
index 00000000000..05d69fc22b9
--- /dev/null
+++ b/trunk/src/emu/sound/vlm5030.c
@@ -0,0 +1,718 @@
+/*
+ vlm5030.c
+
+ Sanyo VLM5030 emulator
+
+ Written by Tatsuyuki Satoh
+ Based on TMS5220 simulator (tms5220.c)
+
+ +-------,_,-------+
+ GND -- | 1 40 | <- RST
+ (gnd) TST1 -> | 2 39 | ?? TST4
+ OSC2 ck | 3 _ 38 | ?? TST3
+ OSC1 ck | 4 (_) 37 | ?? TST2
+ D0 -> | 5 36 | -> DAO
+ D1 -> | 6 35 | -- VREF (+5v through 5.6k resistor)
+ D2 -> | 7 34 | -> MTE
+ D3 -> | 8 V 33 | -> /ME
+ D4 -> | 9 L 32 | <- VCU
+ D5 -> | 10 M 31 | <- START
+ D6 -> | 11 5 30 | -> BSY
+ D7 -> | 12 0 29 | -- Vdd (+5v)
+ A0 <- | 13 3 28 | -> A15
+ A1 <- | 14 0 27 | -> A14
+ A2 <- | 15 26 | -> A13
+ A3 <- | 16 _ 25 | -> A12
+ A4 <- | 17 (_) 24 | -> A11
+ A5 <- | 18 23 | -> A10
+ A6 <- | 19 22 | -> A9
+ A7 <- | 20 21 | -> A8
+ +-----------------+
+
+TST1 is probably a test mode enable pin, must be grounded for normal operation.
+TST2-4 are some sort of test pins but can be left floating?
+VREF is probably the 0v ref for the output dac
+DAO is the output dac
+/ME is connected to the voice data rom /OE enable
+START strobes in a byte of data over the data bus from host cpu
+OSC1/2 are to both ends of a 3.579545MHz xtal with a 100pf cap from each end to gnd
+VCU makes the data bus select the upper 8 bits of the word register internally instead of the lower 8 bits. it is only useful if you need more than 256 phrases in rom? (recheck this)
+MTE is an output for roms which need to be clocked to latch address before use, or for a latch sitting in front of the voice rom address lines? (recheck this)
+RST not only resets the chip on its rising edge but grabs a byte of mode state data from the data bus on its falling edge? (recheck this)
+
+ note:
+ memory read cycle(==sampling rate) = 122.9u(440clock)
+ interpolator (LC8109 = 2.5ms) = 20 * samples(125us)
+ frame time (20ms) = 4 * interpolator
+ 9bit DAC is composed of 5bit Physical and 3bitPWM.
+
+ todo:
+ Noise Generator circuit without 'machine.rand()' function.
+
+----------- command format (Analytical result) ----------
+
+1)end of speech (8bit)
+:00000011:
+
+2)silent some frame (8bit)
+:????SS01:
+
+SS : number of silent frames
+ 00 = 2 frame
+ 01 = 4 frame
+ 10 = 6 frame
+ 11 = 8 frame
+
+3)-speech frame (48bit)
+function: 6th : 5th : 4th : 3rd : 2nd : 1st :
+end : --- : --- : --- : --- : --- :00000011:
+silent : --- : --- : --- : --- : --- :0000SS01:
+speech :11111122:22233334:44455566:67778889:99AAAEEE:EEPPPPP0:
+
+EEEEE : energy : volume 0=off,0x1f=max
+PPPPP : pitch : 0=noize , 1=fast,0x1f=slow
+111111 : K1 : 48=off
+22222 : K2 : 0=off,1=+min,0x0f=+max,0x10=off,0x11=+max,0x1f=-min
+ : 16 == special function??
+3333 : K3 : 0=off,1=+min,0x07=+max,0x08=-max,0x0f=-min
+4444 : K4 :
+555 : K5 : 0=off,1=+min,0x03=+max,0x04=-max,0x07=-min
+666 : K6 :
+777 : K7 :
+888 : K8 :
+999 : K9 :
+AAA : K10 :
+
+ ---------- chirp table information ----------
+
+DAC PWM cycle == 88system clock , (11clock x 8 pattern) = 40.6KHz
+one chirp == 5 x PWM cycle == 440systemclock(8,136Hz)
+
+chirp 0 : volume 10- 8 : with filter
+chirp 1 : volume 8- 6 : with filter
+chirp 2 : volume 6- 4 : with filter
+chirp 3 : volume 4 : no filter ??
+chirp 4- 5: volume 4- 2 : with filter
+chirp 6-11: volume 2- 0 : with filter
+chirp 12-..: vokume 0 : silent
+
+ ---------- digial output information ----------
+ when ME pin = high , some status output to A0..15 pins
+
+ A0..8 : DAC output value (abs)
+ A9 : DAC sign flag , L=minus,H=Plus
+ A10 : energy reload flag (pitch pulse)
+ A11..15 : unknown
+
+ [DAC output value(signed 6bit)] = A9 ? A0..8 : -(A0..8)
+
+*/
+#include "emu.h"
+#include "vlm5030.h"
+
+/* interpolator per frame */
+#define FR_SIZE 4
+/* samples per interpolator */
+#define IP_SIZE_SLOWER (240/FR_SIZE)
+#define IP_SIZE_SLOW (200/FR_SIZE)
+#define IP_SIZE_NORMAL (160/FR_SIZE)
+#define IP_SIZE_FAST (120/FR_SIZE)
+#define IP_SIZE_FASTER ( 80/FR_SIZE)
+
+typedef struct _vlm5030_state vlm5030_state;
+struct _vlm5030_state
+{
+ device_t *device;
+ const vlm5030_interface *intf;
+
+ sound_stream * channel;
+
+ /* coefficient tables */
+ const struct tms5100_coeffs *coeff;
+
+ /* need to save state */
+
+ UINT8 *rom;
+ int address_mask;
+ UINT16 address;
+ UINT8 pin_BSY;
+ UINT8 pin_ST;
+ UINT8 pin_VCU;
+ UINT8 pin_RST;
+ UINT8 latch_data;
+ UINT16 vcu_addr_h;
+ UINT8 parameter;
+ UINT8 phase;
+
+ /* state of option paramter */
+ int frame_size;
+ int pitch_offset;
+ UINT8 interp_step;
+
+ UINT8 interp_count; /* number of interp periods */
+ UINT8 sample_count; /* sample number within interp */
+ UINT8 pitch_count;
+
+ /* these contain data describing the current and previous voice frames */
+ UINT16 old_energy;
+ UINT8 old_pitch;
+ INT16 old_k[10];
+ UINT16 target_energy;
+ UINT8 target_pitch;
+ INT16 target_k[10];
+
+ UINT16 new_energy;
+ UINT8 new_pitch;
+ INT16 new_k[10];
+
+ /* these are all used to contain the current state of the sound generation */
+ unsigned int current_energy;
+ unsigned int current_pitch;
+ int current_k[10];
+
+ INT32 x[10];
+};
+
+/* phase value */
+enum {
+ PH_RESET,
+ PH_IDLE,
+ PH_SETUP,
+ PH_WAIT,
+ PH_RUN,
+ PH_STOP,
+ PH_END
+};
+
+/* Pull in the ROM tables */
+#include "tms5110r.c"
+
+/*
+ speed parameter
+SPC SPB SPA
+ 1 0 1 more slow (05h) : 42ms (150%) : 60sample
+ 1 1 x slow (06h,07h) : 34ms (125%) : 50sample
+ x 0 0 normal (00h,04h) : 25.6ms (100%) : 40samplme
+ 0 0 1 fast (01h) : 20.2ms (75%) : 30sample
+ 0 1 x more fast (02h,03h) : 12.2ms (50%) : 20sample
+*/
+static const int vlm5030_speed_table[8] =
+{
+ IP_SIZE_NORMAL,
+ IP_SIZE_FAST,
+ IP_SIZE_FASTER,
+ IP_SIZE_FASTER,
+ IP_SIZE_NORMAL,
+ IP_SIZE_SLOWER,
+ IP_SIZE_SLOW,
+ IP_SIZE_SLOW
+};
+
+static const char VLM_NAME[] = "VLM5030";
+
+INLINE vlm5030_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == VLM5030);
+ return (vlm5030_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+static int get_bits(vlm5030_state *chip, int sbit,int bits)
+{
+ int offset = chip->address + (sbit>>3);
+ int data;
+
+ data = chip->rom[offset&chip->address_mask] +
+ (((int)chip->rom[(offset+1)&chip->address_mask])*256);
+ data >>= (sbit&7);
+ data &= (0xff>>(8-bits));
+
+ return data;
+}
+
+/* get next frame */
+static int parse_frame (vlm5030_state *chip)
+{
+ unsigned char cmd;
+ int i;
+
+ /* remember previous frame */
+ chip->old_energy = chip->new_energy;
+ chip->old_pitch = chip->new_pitch;
+ for(i=0;i<=9;i++)
+ chip->old_k[i] = chip->new_k[i];
+
+ /* command byte check */
+ cmd = chip->rom[chip->address&chip->address_mask];
+ if( cmd & 0x01 )
+ { /* extend frame */
+ chip->new_energy = chip->new_pitch = 0;
+ for(i=0;i<=9;i++)
+ chip->new_k[i] = 0;
+ chip->address++;
+ if( cmd & 0x02 )
+ { /* end of speech */
+
+ /* logerror("VLM5030 %04X end \n",chip->address ); */
+ return 0;
+ }
+ else
+ { /* silent frame */
+ int nums = ( (cmd>>2)+1 )*2;
+ /* logerror("VLM5030 %04X silent %d frame\n",chip->address,nums ); */
+ return nums * FR_SIZE;
+ }
+ }
+ /* pitch */
+ chip->new_pitch = ( chip->coeff->pitchtable[get_bits(chip, 1,chip->coeff->pitch_bits)] + chip->pitch_offset )&0xff;
+ /* energy */
+ chip->new_energy = chip->coeff->energytable[get_bits(chip, 6,chip->coeff->energy_bits)];
+
+ /* 10 K's */
+ chip->new_k[9] = chip->coeff->ktable[9][get_bits(chip,11,chip->coeff->kbits[9])];
+ chip->new_k[8] = chip->coeff->ktable[8][get_bits(chip,14,chip->coeff->kbits[8])];
+ chip->new_k[7] = chip->coeff->ktable[7][get_bits(chip,17,chip->coeff->kbits[7])];
+ chip->new_k[6] = chip->coeff->ktable[6][get_bits(chip,20,chip->coeff->kbits[6])];
+ chip->new_k[5] = chip->coeff->ktable[5][get_bits(chip,23,chip->coeff->kbits[5])];
+ chip->new_k[4] = chip->coeff->ktable[4][get_bits(chip,26,chip->coeff->kbits[4])];
+ chip->new_k[3] = chip->coeff->ktable[3][get_bits(chip,29,chip->coeff->kbits[3])];
+ chip->new_k[2] = chip->coeff->ktable[2][get_bits(chip,33,chip->coeff->kbits[2])];
+ chip->new_k[1] = chip->coeff->ktable[1][get_bits(chip,37,chip->coeff->kbits[1])];
+ chip->new_k[0] = chip->coeff->ktable[0][get_bits(chip,42,chip->coeff->kbits[0])];
+
+ chip->address+=6;
+ logerror("VLM5030 %04X voice \n",chip->address );
+ //fprintf(stderr,"*** target Energy, Pitch, and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",chip->new_energy, chip->new_pitch, chip->new_k[0], chip->new_k[1], chip->new_k[2], chip->new_k[3], chip->new_k[4], chip->new_k[5], chip->new_k[6], chip->new_k[7], chip->new_k[8], chip->new_k[9]);
+ return FR_SIZE;
+}
+
+/* decode and buffering data */
+static STREAM_UPDATE( vlm5030_update_callback )
+{
+ vlm5030_state *chip = (vlm5030_state *)param;
+ int buf_count=0;
+ int interp_effect;
+ int i;
+ int u[11];
+ stream_sample_t *buffer = outputs[0];
+
+ /* running */
+ if( chip->phase == PH_RUN || chip->phase == PH_STOP )
+ {
+ /* playing speech */
+ while (samples > 0)
+ {
+ int current_val;
+
+ /* check new interpolator or new frame */
+ if( chip->sample_count == 0 )
+ {
+ if( chip->phase == PH_STOP )
+ {
+ chip->phase = PH_END;
+ chip->sample_count = 1;
+ goto phase_stop; /* continue to end phase */
+ }
+ chip->sample_count = chip->frame_size;
+ /* interpolator changes */
+ if ( chip->interp_count == 0 )
+ {
+ /* change to new frame */
+ chip->interp_count = parse_frame(chip); /* with change phase */
+ if ( chip->interp_count == 0 )
+ { /* end mark found */
+ chip->interp_count = FR_SIZE;
+ chip->sample_count = chip->frame_size; /* end -> stop time */
+ chip->phase = PH_STOP;
+ }
+ /* Set old target as new start of frame */
+ chip->current_energy = chip->old_energy;
+ chip->current_pitch = chip->old_pitch;
+ for(i=0;i<=9;i++)
+ chip->current_k[i] = chip->old_k[i];
+ /* is this a zero energy frame? */
+ if (chip->current_energy == 0)
+ {
+ /*mame_printf_debug("processing frame: zero energy\n");*/
+ chip->target_energy = 0;
+ chip->target_pitch = chip->current_pitch;
+ for(i=0;i<=9;i++)
+ chip->target_k[i] = chip->current_k[i];
+ }
+ else
+ {
+ /*mame_printf_debug("processing frame: Normal\n");*/
+ /*mame_printf_debug("*** Energy = %d\n",chip->current_energy);*/
+ /*mame_printf_debug("proc: %d %d\n",last_fbuf_head,fbuf_head);*/
+ chip->target_energy = chip->new_energy;
+ chip->target_pitch = chip->new_pitch;
+ for(i=0;i<=9;i++)
+ chip->target_k[i] = chip->new_k[i];
+ }
+ }
+ /* next interpolator */
+ /* Update values based on step values 25% , 50% , 75% , 100% */
+ chip->interp_count -= chip->interp_step;
+ /* 3,2,1,0 -> 1,2,3,4 */
+ interp_effect = FR_SIZE - (chip->interp_count%FR_SIZE);
+ chip->current_energy = chip->old_energy + (chip->target_energy - chip->old_energy) * interp_effect / FR_SIZE;
+ if (chip->old_pitch > 1)
+ chip->current_pitch = chip->old_pitch + (chip->target_pitch - chip->old_pitch) * interp_effect / FR_SIZE;
+ for (i = 0; i <= 9 ; i++)
+ chip->current_k[i] = chip->old_k[i] + (chip->target_k[i] - chip->old_k[i]) * interp_effect / FR_SIZE;
+ }
+ /* calcrate digital filter */
+ if (chip->old_energy == 0)
+ {
+ /* generate silent samples here */
+ current_val = 0x00;
+ }
+ else if (chip->old_pitch <= 1)
+ { /* generate unvoiced samples here */
+ current_val = (chip->device->machine().rand()&1) ? chip->current_energy : -chip->current_energy;
+ }
+ else
+ {
+ /* generate voiced samples here */
+ current_val = ( chip->pitch_count == 0) ? chip->current_energy : 0;
+ }
+
+ /* Lattice filter here */
+ u[10] = current_val;
+ for (i = 9; i >= 0; i--)
+ u[i] = u[i+1] - ((-chip->current_k[i] * chip->x[i]) / 512);
+ for (i = 9; i >= 1; i--)
+ chip->x[i] = chip->x[i-1] + ((-chip->current_k[i-1] * u[i-1]) / 512);
+ chip->x[0] = u[0];
+
+ /* clipping, buffering */
+ if (u[0] > 511)
+ buffer[buf_count] = 511<<6;
+ else if (u[0] < -511)
+ buffer[buf_count] = -511<<6;
+ else
+ buffer[buf_count] = (u[0] << 6);
+ buf_count++;
+
+ /* sample count */
+ chip->sample_count--;
+ /* pitch */
+ chip->pitch_count++;
+ if (chip->pitch_count >= chip->current_pitch )
+ chip->pitch_count = 0;
+ /* size */
+ samples--;
+ }
+/* return;*/
+ }
+ /* stop phase */
+phase_stop:
+ switch( chip->phase )
+ {
+ case PH_SETUP:
+ if( chip->sample_count <= samples)
+ {
+ chip->sample_count = 0;
+ /* logerror("VLM5030 BSY=H\n" ); */
+ /* pin_BSY = 1; */
+ chip->phase = PH_WAIT;
+ }
+ else
+ {
+ chip->sample_count -= samples;
+ }
+ break;
+ case PH_END:
+ if( chip->sample_count <= samples)
+ {
+ chip->sample_count = 0;
+ /* logerror("VLM5030 BSY=L\n" ); */
+ chip->pin_BSY = 0;
+ chip->phase = PH_IDLE;
+ }
+ else
+ {
+ chip->sample_count -= samples;
+ }
+ }
+ /* silent buffering */
+ while (samples > 0)
+ {
+ buffer[buf_count++] = 0x00;
+ samples--;
+ }
+}
+
+/* realtime update */
+static void vlm5030_update(vlm5030_state *chip)
+{
+ chip->channel->update();
+}
+
+/* setup parameteroption when RST=H */
+static void vlm5030_setup_parameter(vlm5030_state *chip, UINT8 param)
+{
+ /* latch parameter value */
+ chip->parameter = param;
+
+ /* bit 0,1 : 4800bps / 9600bps , interporator step */
+ if(param&2) /* bit 1 = 1 , 9600bps */
+ chip->interp_step = 4; /* 9600bps : no interporator */
+ else if(param&1) /* bit1 = 0 & bit0 = 1 , 4800bps */
+ chip->interp_step = 2; /* 4800bps : 2 interporator */
+ else /* bit1 = bit0 = 0 : 2400bps */
+ chip->interp_step = 1; /* 2400bps : 4 interporator */
+
+ /* bit 3,4,5 : speed (frame size) */
+ chip->frame_size = vlm5030_speed_table[(param>>3) &7];
+
+ /* bit 6,7 : low / high pitch */
+ if(param&0x80) /* bit7=1 , high pitch */
+ chip->pitch_offset = -8;
+ else if(param&0x40) /* bit6=1 , low pitch */
+ chip->pitch_offset = 8;
+ else
+ chip->pitch_offset = 0;
+}
+
+
+static void vlm5030_restore_state(vlm5030_state *chip)
+{
+ int i;
+
+ int interp_effect = FR_SIZE - (chip->interp_count%FR_SIZE);
+ /* restore parameter data */
+ vlm5030_setup_parameter(chip, chip->parameter);
+
+ /* restore current energy,pitch & filter */
+ chip->current_energy = chip->old_energy + (chip->target_energy - chip->old_energy) * interp_effect / FR_SIZE;
+ if (chip->old_pitch > 1)
+ chip->current_pitch = chip->old_pitch + (chip->target_pitch - chip->old_pitch) * interp_effect / FR_SIZE;
+ for (i = 0; i <= 9 ; i++)
+ chip->current_k[i] = chip->old_k[i] + (chip->target_k[i] - chip->old_k[i]) * interp_effect / FR_SIZE;
+}
+
+
+static void vlm5030_reset(vlm5030_state *chip)
+{
+ chip->phase = PH_RESET;
+ chip->address = 0;
+ chip->vcu_addr_h = 0;
+ chip->pin_BSY = 0;
+
+ chip->old_energy = chip->old_pitch = 0;
+ chip->new_energy = chip->new_pitch = 0;
+ chip->current_energy = chip->current_pitch = 0;
+ chip->target_energy = chip->target_pitch = 0;
+ memset(chip->old_k, 0, sizeof(chip->old_k));
+ memset(chip->new_k, 0, sizeof(chip->new_k));
+ memset(chip->current_k, 0, sizeof(chip->current_k));
+ memset(chip->target_k, 0, sizeof(chip->target_k));
+ chip->interp_count = chip->sample_count = chip->pitch_count = 0;
+ memset(chip->x, 0, sizeof(chip->x));
+ /* reset parameters */
+ vlm5030_setup_parameter(chip, 0x00);
+}
+
+static DEVICE_RESET( vlm5030 )
+{
+ vlm5030_reset(get_safe_token(device));
+}
+
+
+/* set speech rom address */
+void vlm5030_set_rom(device_t *device, void *speech_rom)
+{
+ vlm5030_state *chip = get_safe_token(device);
+ chip->rom = (UINT8 *)speech_rom;
+}
+
+/* get BSY pin level */
+int vlm5030_bsy(device_t *device)
+{
+ vlm5030_state *chip = get_safe_token(device);
+ vlm5030_update(chip);
+ return chip->pin_BSY;
+}
+
+/* latch contoll data */
+WRITE8_DEVICE_HANDLER( vlm5030_data_w )
+{
+ vlm5030_state *chip = get_safe_token(device);
+ chip->latch_data = (UINT8)data;
+}
+
+/* set RST pin level : reset / set table address A8-A15 */
+void vlm5030_rst (device_t *device, int pin )
+{
+ vlm5030_state *chip = get_safe_token(device);
+ if( chip->pin_RST )
+ {
+ if( !pin )
+ { /* H -> L : latch parameters */
+ chip->pin_RST = 0;
+ vlm5030_setup_parameter(chip, chip->latch_data);
+ }
+ }
+ else
+ {
+ if( pin )
+ { /* L -> H : reset chip */
+ chip->pin_RST = 1;
+ if( chip->pin_BSY )
+ {
+ vlm5030_reset(chip);
+ }
+ }
+ }
+}
+
+/* set VCU pin level : ?? unknown */
+void vlm5030_vcu(device_t *device, int pin)
+{
+ vlm5030_state *chip = get_safe_token(device);
+ /* direct mode / indirect mode */
+ chip->pin_VCU = pin;
+ return;
+}
+
+/* set ST pin level : set table address A0-A7 / start speech */
+void vlm5030_st(device_t *device, int pin )
+{
+ vlm5030_state *chip = get_safe_token(device);
+ int table;
+
+ if( chip->pin_ST != pin )
+ {
+ /* pin level is change */
+ if( !pin )
+ { /* H -> L */
+ chip->pin_ST = 0;
+
+ if( chip->pin_VCU )
+ { /* direct access mode & address High */
+ chip->vcu_addr_h = ((int)chip->latch_data<<8) + 0x01;
+ }
+ else
+ {
+ /* start speech */
+ /* check access mode */
+ if( chip->vcu_addr_h )
+ { /* direct access mode */
+ chip->address = (chip->vcu_addr_h&0xff00) + chip->latch_data;
+ chip->vcu_addr_h = 0;
+ }
+ else
+ { /* indirect accedd mode */
+ table = (chip->latch_data&0xfe) + (((int)chip->latch_data&1)<<8);
+ chip->address = (((int)chip->rom[table&chip->address_mask])<<8)
+ | chip->rom[(table+1)&chip->address_mask];
+#if 0
+/* show unsupported parameter message */
+if( chip->interp_step != 1)
+ popmessage("No %d %dBPS parameter",table/2,chip->interp_step*2400);
+#endif
+ }
+ vlm5030_update(chip);
+ /* logerror("VLM5030 %02X start adr=%04X\n",table/2,chip->address ); */
+ /* reset process status */
+ chip->sample_count = chip->frame_size;
+ chip->interp_count = FR_SIZE;
+ /* clear filter */
+ /* start after 3 sampling cycle */
+ chip->phase = PH_RUN;
+ }
+ }
+ else
+ { /* L -> H */
+ chip->pin_ST = 1;
+ /* setup speech , BSY on after 30ms? */
+ chip->phase = PH_SETUP;
+ chip->sample_count = 1; /* wait time for busy on */
+ chip->pin_BSY = 1; /* */
+ }
+ }
+}
+
+/* start VLM5030 with sound rom */
+/* speech_rom == 0 -> use sampling data mode */
+static DEVICE_START( vlm5030 )
+{
+ const vlm5030_interface defintrf = { 0 };
+ int emulation_rate;
+ vlm5030_state *chip = get_safe_token(device);
+
+ chip->device = device;
+ chip->coeff = &vlm5030_coeff;
+ chip->intf = (device->static_config() != NULL) ? (const vlm5030_interface *)device->static_config() : &defintrf;
+
+ emulation_rate = device->clock() / 440;
+
+ /* reset input pins */
+ chip->pin_RST = chip->pin_ST = chip->pin_VCU= 0;
+ chip->latch_data = 0;
+
+ vlm5030_reset(chip);
+ chip->phase = PH_IDLE;
+
+ chip->rom = *device->region();
+ /* memory size */
+ if( chip->intf->memory_size == 0)
+ chip->address_mask = device->region()->bytes()-1;
+ else
+ chip->address_mask = chip->intf->memory_size-1;
+
+ chip->channel = device->machine().sound().stream_alloc(*device, 0, 1, emulation_rate,chip,vlm5030_update_callback);
+
+ /* don't restore "UINT8 *chip->rom" when use vlm5030_set_rom() */
+
+ device->save_item(NAME(chip->address));
+ device->save_item(NAME(chip->pin_BSY));
+ device->save_item(NAME(chip->pin_ST));
+ device->save_item(NAME(chip->pin_VCU));
+ device->save_item(NAME(chip->pin_RST));
+ device->save_item(NAME(chip->latch_data));
+ device->save_item(NAME(chip->vcu_addr_h));
+ device->save_item(NAME(chip->parameter));
+ device->save_item(NAME(chip->phase));
+ device->save_item(NAME(chip->interp_count));
+ device->save_item(NAME(chip->sample_count));
+ device->save_item(NAME(chip->pitch_count));
+ device->save_item(NAME(chip->old_energy));
+ device->save_item(NAME(chip->old_pitch));
+ device->save_item(NAME(chip->old_k));
+ device->save_item(NAME(chip->target_energy));
+ device->save_item(NAME(chip->target_pitch));
+ device->save_item(NAME(chip->target_k));
+ device->save_item(NAME(chip->x));
+ device->machine().save().register_postload(save_prepost_delegate(FUNC(vlm5030_restore_state), chip));
+}
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+DEVICE_GET_INFO( vlm5030 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(vlm5030_state); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( vlm5030 ); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( vlm5030 ); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "VLM5030"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "VLM speech"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
+ }
+}
+
+
+DEFINE_LEGACY_SOUND_DEVICE(VLM5030, vlm5030);