trunk/src/emu/sound/msm5232.c
| r23881 | r23882 | |
| 9 | 9 | 8 channel tone generator |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | | struct VOICE { |
| 13 | | UINT8 mode; |
| 12 | const device_type MSM5232 = &device_creator<msm5232_device>; |
| 14 | 13 | |
| 15 | | int TG_count_period; |
| 16 | | int TG_count; |
| 14 | msm5232_device::msm5232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 15 | : device_t(mconfig, MSM5232, "MSM5232", tag, owner, clock, "msm5232", __FILE__), |
| 16 | device_sound_interface(mconfig, *this) |
| 17 | { |
| 18 | } |
| 17 | 19 | |
| 18 | | UINT8 TG_cnt; /* 7 bits binary counter (frequency output) */ |
| 19 | | UINT8 TG_out16; /* bit number (of TG_cnt) for 16' output */ |
| 20 | | UINT8 TG_out8; /* bit number (of TG_cnt) for 8' output */ |
| 21 | | UINT8 TG_out4; /* bit number (of TG_cnt) for 4' output */ |
| 22 | | UINT8 TG_out2; /* bit number (of TG_cnt) for 2' output */ |
| 20 | //------------------------------------------------- |
| 21 | // device_config_complete - perform any |
| 22 | // operations now that the configuration is |
| 23 | // complete |
| 24 | //------------------------------------------------- |
| 23 | 25 | |
| 24 | | int egvol; |
| 25 | | int eg_sect; |
| 26 | | int counter; |
| 27 | | int eg; |
| 26 | void msm5232_device::device_config_complete() |
| 27 | { |
| 28 | // inherit a copy of the static data |
| 29 | const msm5232_interface *intf = reinterpret_cast<const msm5232_interface *>(static_config()); |
| 30 | if (intf != NULL) |
| 31 | *static_cast<msm5232_interface *>(this) = *intf; |
| 32 | |
| 33 | // or initialize to defaults if none provided |
| 34 | else |
| 35 | { |
| 36 | memset(&m_gate_handler_cb, 0, sizeof(m_gate_handler_cb)); |
| 37 | } |
| 38 | } |
| 28 | 39 | |
| 29 | | UINT8 eg_arm; /* attack/release mode */ |
| 40 | //------------------------------------------------- |
| 41 | // device_start - device-specific startup |
| 42 | //------------------------------------------------- |
| 30 | 43 | |
| 31 | | double ar_rate; |
| 32 | | double dr_rate; |
| 33 | | double rr_rate; |
| 44 | void msm5232_device::device_start() |
| 45 | { |
| 46 | int rate = clock()/CLOCK_RATE_DIVIDER; |
| 47 | int voicenum; |
| 34 | 48 | |
| 35 | | int pitch; /* current pitch data */ |
| 49 | init(clock(), rate); |
| 36 | 50 | |
| 37 | | int GF; |
| 38 | | }; |
| 51 | m_stream = machine().sound().stream_alloc(*this, 0, 11, rate, this); |
| 39 | 52 | |
| 53 | /* register with the save state system */ |
| 54 | machine().save().register_postload(save_prepost_delegate(FUNC(msm5232_device::postload), this)); |
| 55 | save_item(NAME(m_EN_out16)); |
| 56 | save_item(NAME(m_EN_out8)); |
| 57 | save_item(NAME(m_EN_out4)); |
| 58 | save_item(NAME(m_EN_out2)); |
| 59 | save_item(NAME(m_noise_cnt)); |
| 60 | save_item(NAME(m_noise_rng)); |
| 61 | save_item(NAME(m_noise_clocks)); |
| 62 | save_item(NAME(m_control1)); |
| 63 | save_item(NAME(m_control2)); |
| 64 | save_item(NAME(m_gate)); |
| 65 | save_item(NAME(m_chip_clock)); |
| 66 | save_item(NAME(m_rate)); |
| 40 | 67 | |
| 41 | | struct msm5232_state { |
| 42 | | sound_stream *stream; |
| 68 | /* register voice-specific data for save states */ |
| 69 | for (voicenum = 0; voicenum < 8; voicenum++) |
| 70 | { |
| 71 | VOICE *voice = &m_voi[voicenum]; |
| 43 | 72 | |
| 44 | | VOICE voi[8]; |
| 73 | save_item(NAME(voice->mode), voicenum); |
| 74 | save_item(NAME(voice->TG_count_period), voicenum); |
| 75 | save_item(NAME(voice->TG_cnt), voicenum); |
| 76 | save_item(NAME(voice->TG_out16), voicenum); |
| 77 | save_item(NAME(voice->TG_out8), voicenum); |
| 78 | save_item(NAME(voice->TG_out4), voicenum); |
| 79 | save_item(NAME(voice->TG_out2), voicenum); |
| 80 | save_item(NAME(voice->egvol), voicenum); |
| 81 | save_item(NAME(voice->eg_sect), voicenum); |
| 82 | save_item(NAME(voice->counter), voicenum); |
| 83 | save_item(NAME(voice->eg), voicenum); |
| 84 | save_item(NAME(voice->eg_arm), voicenum); |
| 85 | save_item(NAME(voice->ar_rate), voicenum); |
| 86 | save_item(NAME(voice->dr_rate), voicenum); |
| 87 | save_item(NAME(voice->pitch), voicenum); |
| 88 | save_item(NAME(voice->GF), voicenum); |
| 89 | } |
| 90 | } |
| 45 | 91 | |
| 46 | | UINT32 EN_out16[2]; /* enable 16' output masks for both groups (0-disabled ; ~0 -enabled) */ |
| 47 | | UINT32 EN_out8[2]; /* enable 8' output masks */ |
| 48 | | UINT32 EN_out4[2]; /* enable 4' output masks */ |
| 49 | | UINT32 EN_out2[2]; /* enable 2' output masks */ |
| 92 | //------------------------------------------------- |
| 93 | // device_reset - device-specific reset |
| 94 | //------------------------------------------------- |
| 50 | 95 | |
| 51 | | int noise_cnt; |
| 52 | | int noise_step; |
| 53 | | int noise_rng; |
| 54 | | int noise_clocks; /* number of the noise_rng (output) level changes */ |
| 96 | void msm5232_device::device_reset() |
| 97 | { |
| 98 | int i; |
| 55 | 99 | |
| 56 | | unsigned int UpdateStep; |
| 100 | for (i=0; i<8; i++) |
| 101 | { |
| 102 | write(machine().driver_data()->generic_space(),i,0x80); |
| 103 | write(machine().driver_data()->generic_space(),i,0x00); |
| 104 | } |
| 105 | m_noise_cnt = 0; |
| 106 | m_noise_rng = 1; |
| 107 | m_noise_clocks = 0; |
| 57 | 108 | |
| 58 | | /* rate tables */ |
| 59 | | double ar_tbl[8]; |
| 60 | | double dr_tbl[16]; |
| 109 | m_control1 = 0; |
| 110 | m_EN_out16[0] = 0; |
| 111 | m_EN_out8[0] = 0; |
| 112 | m_EN_out4[0] = 0; |
| 113 | m_EN_out2[0] = 0; |
| 61 | 114 | |
| 62 | | UINT8 control1; |
| 63 | | UINT8 control2; |
| 115 | m_control2 = 0; |
| 116 | m_EN_out16[1] = 0; |
| 117 | m_EN_out8[1] = 0; |
| 118 | m_EN_out4[1] = 0; |
| 119 | m_EN_out2[1] = 0; |
| 64 | 120 | |
| 65 | | int gate; /* current state of the GATE output */ |
| 121 | gate_update(); |
| 122 | } |
| 66 | 123 | |
| 67 | | int clock; /* chip clock in Hz */ |
| 68 | | int rate; /* sample rate in Hz */ |
| 124 | //------------------------------------------------- |
| 125 | // device_stop - device-specific stop |
| 126 | //------------------------------------------------- |
| 69 | 127 | |
| 70 | | double external_capacity[8]; /* in Farads, eg 0.39e-6 = 0.36 uF (microFarads) */ |
| 71 | | device_t *device; |
| 72 | | devcb_resolved_write_line gate_handler;/* callback called when the GATE output pin changes state */ |
| 73 | | |
| 74 | | }; |
| 75 | | |
| 76 | | |
| 77 | | INLINE msm5232_state *get_safe_token(device_t *device) |
| 128 | void msm5232_device::device_stop() |
| 78 | 129 | { |
| 79 | | assert(device != NULL); |
| 80 | | assert(device->type() == MSM5232); |
| 81 | | return (msm5232_state *)downcast<msm5232_device *>(device)->token(); |
| 130 | #ifdef SAVE_SAMPLE |
| 131 | fclose(sample[8]); |
| 132 | #endif |
| 133 | #ifdef SAVE_SEPARATE_CHANNELS |
| 134 | fclose(sample[0]); |
| 135 | fclose(sample[1]); |
| 136 | fclose(sample[2]); |
| 137 | fclose(sample[3]); |
| 138 | fclose(sample[4]); |
| 139 | fclose(sample[5]); |
| 140 | fclose(sample[6]); |
| 141 | fclose(sample[7]); |
| 142 | #endif |
| 82 | 143 | } |
| 83 | 144 | |
| 84 | 145 | |
| r23881 | r23882 | |
| 171 | 232 | |
| 172 | 233 | |
| 173 | 234 | |
| 174 | | static void msm5232_init_tables( msm5232_state *chip ) |
| 235 | void msm5232_device::init_tables() |
| 175 | 236 | { |
| 176 | 237 | int i; |
| 177 | 238 | double scale; |
| r23881 | r23882 | |
| 180 | 241 | /* highest possible frequency is chipclock/13/16 (pitch data=0x57) */ |
| 181 | 242 | /* at 2MHz : 2000000/13/16 = 9615 Hz */ |
| 182 | 243 | |
| 183 | | i = ((double)(1<<STEP_SH) * (double)chip->rate) / (double)chip->clock; |
| 184 | | chip->UpdateStep = i; |
| 244 | i = ((double)(1<<STEP_SH) * (double)m_rate) / (double)m_chip_clock; |
| 245 | m_UpdateStep = i; |
| 185 | 246 | /* logerror("clock=%i Hz rate=%i Hz, UpdateStep=%i\n", |
| 186 | | chip->clock, chip->rate, chip->UpdateStep); */ |
| 247 | m_chip_clock, m_rate, m_UpdateStep); */ |
| 187 | 248 | |
| 188 | | scale = ((double)chip->clock) / (double)chip->rate; |
| 189 | | chip->noise_step = ((1<<STEP_SH)/128.0) * scale; /* step of the rng reg in 16.16 format */ |
| 190 | | /* logerror("noise step=%8x\n", chip->noise_step); */ |
| 249 | scale = ((double)m_chip_clock) / (double)m_rate; |
| 250 | m_noise_step = ((1<<STEP_SH)/128.0) * scale; /* step of the rng reg in 16.16 format */ |
| 251 | /* logerror("noise step=%8x\n", m_noise_step); */ |
| 191 | 252 | |
| 192 | 253 | #if 0 |
| 193 | 254 | { |
| r23881 | r23882 | |
| 197 | 258 | 333,500,1000,2000, 4000,8000, 4000,8000}; |
| 198 | 259 | for (i=0; i<8; i++) |
| 199 | 260 | { |
| 200 | | double clockscale = (double)chip->clock / 2119040.0; |
| 261 | double clockscale = (double)m_chip_clock / 2119040.0; |
| 201 | 262 | double time = (ATBL[i] / 1000.0) / clockscale; /* attack time in seconds */ |
| 202 | | chip->ar_tbl[i] = 0.50 * ( (1.0/time) / (double)chip->rate ); |
| 203 | | /* logerror("ATBL[%i] = %20.16f time = %f s\n",i, chip->ar_tbl[i], time); */ |
| 263 | m_ar_tbl[i] = 0.50 * ( (1.0/time) / (double)m_rate ); |
| 264 | /* logerror("ATBL[%i] = %20.16f time = %f s\n",i, m_ar_tbl[i], time); */ |
| 204 | 265 | } |
| 205 | 266 | |
| 206 | 267 | for (i=0; i<16; i++) |
| 207 | 268 | { |
| 208 | | double clockscale = (double)chip->clock / 2119040.0; |
| 269 | double clockscale = (double)m_chip_clock / 2119040.0; |
| 209 | 270 | double time = (DTBL[i] / 1000.0) / clockscale; /* decay time in seconds */ |
| 210 | | chip->dr_tbl[i] = 0.50 * ( (1.0/time) / (double)chip->rate ); |
| 211 | | /* logerror("DTBL[%i] = %20.16f time = %f s\n",i, chip->dr_tbl[i], time); */ |
| 271 | m_dr_tbl[i] = 0.50 * ( (1.0/time) / (double)m_rate ); |
| 272 | /* logerror("DTBL[%i] = %20.16f time = %f s\n",i, m_dr_tbl[i], time); */ |
| 212 | 273 | } |
| 213 | 274 | } |
| 214 | 275 | #endif |
| r23881 | r23882 | |
| 216 | 277 | |
| 217 | 278 | for (i=0; i<8; i++) |
| 218 | 279 | { |
| 219 | | double clockscale = (double)chip->clock / 2119040.0; |
| 220 | | chip->ar_tbl[i] = ((1<<i) / clockscale) * (double)R51; |
| 280 | double clockscale = (double)m_chip_clock / 2119040.0; |
| 281 | m_ar_tbl[i] = ((1<<i) / clockscale) * (double)R51; |
| 221 | 282 | } |
| 222 | 283 | |
| 223 | 284 | for (i=0; i<8; i++) |
| 224 | 285 | { |
| 225 | | double clockscale = (double)chip->clock / 2119040.0; |
| 226 | | chip->dr_tbl[i] = ( (1<<i) / clockscale) * (double)R52; |
| 227 | | chip->dr_tbl[i+8] = (6.25*(1<<i) / clockscale) * (double)R52; |
| 286 | double clockscale = (double)m_chip_clock / 2119040.0; |
| 287 | m_dr_tbl[i] = ( (1<<i) / clockscale) * (double)R52; |
| 288 | m_dr_tbl[i+8] = (6.25*(1<<i) / clockscale) * (double)R52; |
| 228 | 289 | } |
| 229 | 290 | |
| 230 | 291 | |
| r23881 | r23882 | |
| 244 | 305 | } |
| 245 | 306 | |
| 246 | 307 | |
| 247 | | static void msm5232_init_voice(msm5232_state *chip, int i) |
| 308 | void msm5232_device::init_voice(int i) |
| 248 | 309 | { |
| 249 | | chip->voi[i].ar_rate= chip->ar_tbl[0] * chip->external_capacity[i]; |
| 250 | | chip->voi[i].dr_rate= chip->dr_tbl[0] * chip->external_capacity[i]; |
| 251 | | chip->voi[i].rr_rate= chip->dr_tbl[0] * chip->external_capacity[i]; /* this is constant value */ |
| 252 | | chip->voi[i].eg_sect= -1; |
| 253 | | chip->voi[i].eg = 0.0; |
| 254 | | chip->voi[i].eg_arm = 0; |
| 255 | | chip->voi[i].pitch = -1.0; |
| 310 | m_voi[i].ar_rate= m_ar_tbl[0] * m_external_capacity[i]; |
| 311 | m_voi[i].dr_rate= m_dr_tbl[0] * m_external_capacity[i]; |
| 312 | m_voi[i].rr_rate= m_dr_tbl[0] * m_external_capacity[i]; /* this is constant value */ |
| 313 | m_voi[i].eg_sect= -1; |
| 314 | m_voi[i].eg = 0.0; |
| 315 | m_voi[i].eg_arm = 0; |
| 316 | m_voi[i].pitch = -1.0; |
| 256 | 317 | } |
| 257 | 318 | |
| 258 | 319 | |
| 259 | | static void msm5232_gate_update(msm5232_state *chip) |
| 320 | void msm5232_device::gate_update() |
| 260 | 321 | { |
| 261 | | int new_state = (chip->control2 & 0x20) ? chip->voi[7].GF : 0; |
| 322 | int new_state = (m_control2 & 0x20) ? m_voi[7].GF : 0; |
| 262 | 323 | |
| 263 | | if (chip->gate != new_state && !chip->gate_handler.isnull()) |
| 324 | if (m_gate != new_state && !m_gate_handler_func.isnull()) |
| 264 | 325 | { |
| 265 | | chip->gate = new_state; |
| 266 | | chip->gate_handler(new_state); |
| 326 | m_gate = new_state; |
| 327 | m_gate_handler_func(new_state); |
| 267 | 328 | } |
| 268 | 329 | } |
| 269 | 330 | |
| 270 | | |
| 271 | | static DEVICE_RESET( msm5232 ) |
| 331 | void msm5232_device::init(int clock, int rate) |
| 272 | 332 | { |
| 273 | | msm5232_state *chip = get_safe_token(device); |
| 274 | | int i; |
| 275 | | |
| 276 | | for (i=0; i<8; i++) |
| 277 | | { |
| 278 | | msm5232_w(device,device->machine().driver_data()->generic_space(),i,0x80); |
| 279 | | msm5232_w(device,device->machine().driver_data()->generic_space(),i,0x00); |
| 280 | | } |
| 281 | | chip->noise_cnt = 0; |
| 282 | | chip->noise_rng = 1; |
| 283 | | chip->noise_clocks = 0; |
| 284 | | |
| 285 | | chip->control1 = 0; |
| 286 | | chip->EN_out16[0] = 0; |
| 287 | | chip->EN_out8[0] = 0; |
| 288 | | chip->EN_out4[0] = 0; |
| 289 | | chip->EN_out2[0] = 0; |
| 290 | | |
| 291 | | chip->control2 = 0; |
| 292 | | chip->EN_out16[1] = 0; |
| 293 | | chip->EN_out8[1] = 0; |
| 294 | | chip->EN_out4[1] = 0; |
| 295 | | chip->EN_out2[1] = 0; |
| 296 | | |
| 297 | | msm5232_gate_update(chip); |
| 298 | | } |
| 299 | | |
| 300 | | static void msm5232_init(msm5232_state *chip, const msm5232_interface *intf, int clock, int rate) |
| 301 | | { |
| 302 | 333 | int j; |
| 303 | 334 | |
| 304 | | chip->clock = clock; |
| 305 | | chip->rate = rate ? rate : 44100; /* avoid division by 0 */ |
| 335 | m_chip_clock = clock; |
| 336 | m_rate = rate ? rate : 44100; /* avoid division by 0 */ |
| 306 | 337 | |
| 307 | 338 | for (j=0; j<8; j++) |
| 308 | 339 | { |
| 309 | | chip->external_capacity[j] = intf->capacity[j]; |
| 340 | m_external_capacity[j] = m_capacity[j]; |
| 310 | 341 | } |
| 311 | 342 | |
| 312 | | chip->gate_handler.resolve(intf->gate_handler_cb, *chip->device); |
| 343 | m_gate_handler_func.resolve(m_gate_handler_cb, *this); |
| 313 | 344 | |
| 314 | | msm5232_init_tables( chip ); |
| 345 | init_tables(); |
| 315 | 346 | |
| 316 | 347 | for (j=0; j<8; j++) |
| 317 | 348 | { |
| 318 | | memset(&chip->voi[j],0,sizeof(VOICE)); |
| 319 | | msm5232_init_voice(chip,j); |
| 349 | memset(&m_voi[j],0,sizeof(VOICE)); |
| 350 | init_voice(j); |
| 320 | 351 | } |
| 321 | 352 | } |
| 322 | 353 | |
| 323 | | static DEVICE_STOP( msm5232 ) |
| 324 | | { |
| 325 | | #ifdef SAVE_SAMPLE |
| 326 | | fclose(sample[8]); |
| 327 | | #endif |
| 328 | | #ifdef SAVE_SEPARATE_CHANNELS |
| 329 | | fclose(sample[0]); |
| 330 | | fclose(sample[1]); |
| 331 | | fclose(sample[2]); |
| 332 | | fclose(sample[3]); |
| 333 | | fclose(sample[4]); |
| 334 | | fclose(sample[5]); |
| 335 | | fclose(sample[6]); |
| 336 | | fclose(sample[7]); |
| 337 | | #endif |
| 338 | | } |
| 339 | 354 | |
| 340 | | WRITE8_DEVICE_HANDLER( msm5232_w ) |
| 355 | WRITE8_MEMBER( msm5232_device::write ) |
| 341 | 356 | { |
| 342 | | msm5232_state *chip = get_safe_token(device); |
| 343 | | |
| 344 | 357 | if (offset > 0x0d) |
| 345 | 358 | return; |
| 346 | 359 | |
| 347 | | chip->stream->update (); |
| 360 | m_stream->update (); |
| 348 | 361 | |
| 349 | 362 | if (offset < 0x08) /* pitch */ |
| 350 | 363 | { |
| 351 | 364 | int ch = offset&7; |
| 352 | 365 | |
| 353 | | chip->voi[ch].GF = ((data&0x80)>>7); |
| 366 | m_voi[ch].GF = ((data&0x80)>>7); |
| 354 | 367 | if (ch == 7) |
| 355 | | msm5232_gate_update(chip); |
| 368 | gate_update(); |
| 356 | 369 | |
| 357 | 370 | if(data&0x80) |
| 358 | 371 | { |
| 359 | 372 | if(data >= 0xd8) |
| 360 | 373 | { |
| 361 | 374 | /*if ((data&0x7f) != 0x5f) logerror("MSM5232: WRONG PITCH CODE = %2x\n",data&0x7f);*/ |
| 362 | | chip->voi[ch].mode = 1; /* noise mode */ |
| 363 | | chip->voi[ch].eg_sect = 0; /* Key On */ |
| 375 | m_voi[ch].mode = 1; /* noise mode */ |
| 376 | m_voi[ch].eg_sect = 0; /* Key On */ |
| 364 | 377 | } |
| 365 | 378 | else |
| 366 | 379 | { |
| 367 | | if ( chip->voi[ch].pitch != (data&0x7f) ) |
| 380 | if ( m_voi[ch].pitch != (data&0x7f) ) |
| 368 | 381 | { |
| 369 | 382 | int n; |
| 370 | 383 | UINT16 pg; |
| 371 | 384 | |
| 372 | | chip->voi[ch].pitch = data&0x7f; |
| 385 | m_voi[ch].pitch = data&0x7f; |
| 373 | 386 | |
| 374 | 387 | pg = MSM5232_ROM[ data&0x7f ]; |
| 375 | 388 | |
| 376 | | chip->voi[ch].TG_count_period = (pg & 0x1ff) * chip->UpdateStep / 2; |
| 389 | m_voi[ch].TG_count_period = (pg & 0x1ff) * m_UpdateStep / 2; |
| 377 | 390 | |
| 378 | 391 | n = (pg>>9) & 7; /* n = bit number for 16' output */ |
| 379 | | chip->voi[ch].TG_out16 = 1<<n; |
| 392 | m_voi[ch].TG_out16 = 1<<n; |
| 380 | 393 | /* for 8' it is bit n-1 (bit 0 if n-1<0) */ |
| 381 | 394 | /* for 4' it is bit n-2 (bit 0 if n-2<0) */ |
| 382 | 395 | /* for 2' it is bit n-3 (bit 0 if n-3<0) */ |
| 383 | 396 | n = (n>0)? n-1: 0; |
| 384 | | chip->voi[ch].TG_out8 = 1<<n; |
| 397 | m_voi[ch].TG_out8 = 1<<n; |
| 385 | 398 | |
| 386 | 399 | n = (n>0)? n-1: 0; |
| 387 | | chip->voi[ch].TG_out4 = 1<<n; |
| 400 | m_voi[ch].TG_out4 = 1<<n; |
| 388 | 401 | |
| 389 | 402 | n = (n>0)? n-1: 0; |
| 390 | | chip->voi[ch].TG_out2 = 1<<n; |
| 403 | m_voi[ch].TG_out2 = 1<<n; |
| 391 | 404 | } |
| 392 | | chip->voi[ch].mode = 0; /* tone mode */ |
| 393 | | chip->voi[ch].eg_sect = 0; /* Key On */ |
| 405 | m_voi[ch].mode = 0; /* tone mode */ |
| 406 | m_voi[ch].eg_sect = 0; /* Key On */ |
| 394 | 407 | } |
| 395 | 408 | } |
| 396 | 409 | else |
| 397 | 410 | { |
| 398 | | if ( !chip->voi[ch].eg_arm ) /* arm = 0 */ |
| 399 | | chip->voi[ch].eg_sect = 2; /* Key Off -> go to release */ |
| 411 | if ( !m_voi[ch].eg_arm ) /* arm = 0 */ |
| 412 | m_voi[ch].eg_sect = 2; /* Key Off -> go to release */ |
| 400 | 413 | else /* arm = 1 */ |
| 401 | | chip->voi[ch].eg_sect = 1; /* Key Off -> go to decay */ |
| 414 | m_voi[ch].eg_sect = 1; /* Key Off -> go to decay */ |
| 402 | 415 | } |
| 403 | 416 | } |
| 404 | 417 | else |
| r23881 | r23882 | |
| 408 | 421 | { |
| 409 | 422 | case 0x08: /* group1 attack */ |
| 410 | 423 | for (i=0; i<4; i++) |
| 411 | | chip->voi[i].ar_rate = chip->ar_tbl[data&0x7] * chip->external_capacity[i]; |
| 424 | m_voi[i].ar_rate = m_ar_tbl[data&0x7] * m_external_capacity[i]; |
| 412 | 425 | break; |
| 413 | 426 | |
| 414 | 427 | case 0x09: /* group2 attack */ |
| 415 | 428 | for (i=0; i<4; i++) |
| 416 | | chip->voi[i+4].ar_rate = chip->ar_tbl[data&0x7] * chip->external_capacity[i+4]; |
| 429 | m_voi[i+4].ar_rate = m_ar_tbl[data&0x7] * m_external_capacity[i+4]; |
| 417 | 430 | break; |
| 418 | 431 | |
| 419 | 432 | case 0x0a: /* group1 decay */ |
| 420 | 433 | for (i=0; i<4; i++) |
| 421 | | chip->voi[i].dr_rate = chip->dr_tbl[data&0xf] * chip->external_capacity[i]; |
| 434 | m_voi[i].dr_rate = m_dr_tbl[data&0xf] * m_external_capacity[i]; |
| 422 | 435 | break; |
| 423 | 436 | |
| 424 | 437 | case 0x0b: /* group2 decay */ |
| 425 | 438 | for (i=0; i<4; i++) |
| 426 | | chip->voi[i+4].dr_rate = chip->dr_tbl[data&0xf] * chip->external_capacity[i+4]; |
| 439 | m_voi[i+4].dr_rate = m_dr_tbl[data&0xf] * m_external_capacity[i+4]; |
| 427 | 440 | break; |
| 428 | 441 | |
| 429 | 442 | case 0x0c: /* group1 control */ |
| 430 | 443 | |
| 431 | | /*if (chip->control1 != data) |
| 444 | /*if (m_control1 != data) |
| 432 | 445 | logerror("msm5232: control1 ctrl=%x OE=%x\n", data&0xf0, data&0x0f);*/ |
| 433 | 446 | |
| 434 | 447 | /*if (data & 0x10) |
| 435 | 448 | popmessage("msm5232: control1 ctrl=%2x\n", data);*/ |
| 436 | 449 | |
| 437 | | chip->control1 = data; |
| 450 | m_control1 = data; |
| 438 | 451 | |
| 439 | 452 | for (i=0; i<4; i++) |
| 440 | | chip->voi[i].eg_arm = data&0x10; |
| 453 | m_voi[i].eg_arm = data&0x10; |
| 441 | 454 | |
| 442 | | chip->EN_out16[0] = (data&1) ? ~0:0; |
| 443 | | chip->EN_out8[0] = (data&2) ? ~0:0; |
| 444 | | chip->EN_out4[0] = (data&4) ? ~0:0; |
| 445 | | chip->EN_out2[0] = (data&8) ? ~0:0; |
| 455 | m_EN_out16[0] = (data&1) ? ~0:0; |
| 456 | m_EN_out8[0] = (data&2) ? ~0:0; |
| 457 | m_EN_out4[0] = (data&4) ? ~0:0; |
| 458 | m_EN_out2[0] = (data&8) ? ~0:0; |
| 446 | 459 | |
| 447 | 460 | break; |
| 448 | 461 | |
| 449 | 462 | case 0x0d: /* group2 control */ |
| 450 | 463 | |
| 451 | | /*if (chip->control2 != data) |
| 464 | /*if (m_control2 != data) |
| 452 | 465 | logerror("msm5232: control2 ctrl=%x OE=%x\n", data&0xf0, data&0x0f);*/ |
| 453 | 466 | |
| 454 | 467 | /*if (data & 0x10) |
| 455 | 468 | popmessage("msm5232: control2 ctrl=%2x\n", data);*/ |
| 456 | 469 | |
| 457 | | chip->control2 = data; |
| 458 | | msm5232_gate_update(chip); |
| 470 | m_control2 = data; |
| 471 | gate_update(); |
| 459 | 472 | |
| 460 | 473 | for (i=0; i<4; i++) |
| 461 | | chip->voi[i+4].eg_arm = data&0x10; |
| 474 | m_voi[i+4].eg_arm = data&0x10; |
| 462 | 475 | |
| 463 | | chip->EN_out16[1] = (data&1) ? ~0:0; |
| 464 | | chip->EN_out8[1] = (data&2) ? ~0:0; |
| 465 | | chip->EN_out4[1] = (data&4) ? ~0:0; |
| 466 | | chip->EN_out2[1] = (data&8) ? ~0:0; |
| 476 | m_EN_out16[1] = (data&1) ? ~0:0; |
| 477 | m_EN_out8[1] = (data&2) ? ~0:0; |
| 478 | m_EN_out4[1] = (data&4) ? ~0:0; |
| 479 | m_EN_out2[1] = (data&8) ? ~0:0; |
| 467 | 480 | |
| 468 | 481 | break; |
| 469 | 482 | } |
| r23881 | r23882 | |
| 476 | 489 | #define VMAX 32768 |
| 477 | 490 | |
| 478 | 491 | |
| 479 | | INLINE void EG_voices_advance(msm5232_state *chip) |
| 492 | void msm5232_device::EG_voices_advance() |
| 480 | 493 | { |
| 481 | | VOICE *voi = &chip->voi[0]; |
| 482 | | int samplerate = chip->rate; |
| 494 | VOICE *voi = &m_voi[0]; |
| 495 | int samplerate = m_rate; |
| 483 | 496 | int i; |
| 484 | 497 | |
| 485 | 498 | i = 8; |
| r23881 | r23882 | |
| 578 | 591 | |
| 579 | 592 | static int o2,o4,o8,o16,solo8,solo16; |
| 580 | 593 | |
| 581 | | INLINE void TG_group_advance(msm5232_state *chip, int groupidx) |
| 594 | void msm5232_device::TG_group_advance(int groupidx) |
| 582 | 595 | { |
| 583 | | VOICE *voi = &chip->voi[groupidx*4]; |
| 596 | VOICE *voi = &m_voi[groupidx*4]; |
| 584 | 597 | int i; |
| 585 | 598 | |
| 586 | 599 | o2 = o4 = o8 = o16 = solo8 = solo16 = 0; |
| r23881 | r23882 | |
| 636 | 649 | } |
| 637 | 650 | else /* generate noise */ |
| 638 | 651 | { |
| 639 | | if (chip->noise_clocks&8) out16+=(1<<STEP_SH); |
| 640 | | if (chip->noise_clocks&4) out8 +=(1<<STEP_SH); |
| 641 | | if (chip->noise_clocks&2) out4 +=(1<<STEP_SH); |
| 642 | | if (chip->noise_clocks&1) out2 +=(1<<STEP_SH); |
| 652 | if (m_noise_clocks&8) out16+=(1<<STEP_SH); |
| 653 | if (m_noise_clocks&4) out8 +=(1<<STEP_SH); |
| 654 | if (m_noise_clocks&2) out4 +=(1<<STEP_SH); |
| 655 | if (m_noise_clocks&1) out2 +=(1<<STEP_SH); |
| 643 | 656 | } |
| 644 | 657 | |
| 645 | 658 | /* calculate signed output */ |
| r23881 | r23882 | |
| 659 | 672 | }while (i>0); |
| 660 | 673 | |
| 661 | 674 | /* cut off disabled output lines */ |
| 662 | | o16 &= chip->EN_out16[groupidx]; |
| 663 | | o8 &= chip->EN_out8 [groupidx]; |
| 664 | | o4 &= chip->EN_out4 [groupidx]; |
| 665 | | o2 &= chip->EN_out2 [groupidx]; |
| 675 | o16 &= m_EN_out16[groupidx]; |
| 676 | o8 &= m_EN_out8 [groupidx]; |
| 677 | o4 &= m_EN_out4 [groupidx]; |
| 678 | o2 &= m_EN_out2 [groupidx]; |
| 666 | 679 | } |
| 667 | 680 | |
| 668 | 681 | |
| r23881 | r23882 | |
| 705 | 718 | #endif |
| 706 | 719 | |
| 707 | 720 | |
| 708 | | static STREAM_UPDATE( MSM5232_update_one ) |
| 721 | /* MAME Interface */ |
| 722 | void msm5232_device::postload() |
| 709 | 723 | { |
| 710 | | msm5232_state * chip = (msm5232_state *)param; |
| 724 | init_tables(); |
| 725 | } |
| 726 | |
| 727 | void msm5232_device::set_clock(int clock) |
| 728 | { |
| 729 | if (m_chip_clock != clock) |
| 730 | { |
| 731 | m_stream->update (); |
| 732 | m_chip_clock = clock; |
| 733 | m_rate = clock/CLOCK_RATE_DIVIDER; |
| 734 | init_tables(); |
| 735 | m_stream->set_sample_rate(m_rate); |
| 736 | } |
| 737 | } |
| 738 | |
| 739 | |
| 740 | //------------------------------------------------- |
| 741 | // sound_stream_update - handle a stream update |
| 742 | //------------------------------------------------- |
| 743 | |
| 744 | void msm5232_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 745 | { |
| 711 | 746 | stream_sample_t *buf1 = outputs[0]; |
| 712 | 747 | stream_sample_t *buf2 = outputs[1]; |
| 713 | 748 | stream_sample_t *buf3 = outputs[2]; |
| r23881 | r23882 | |
| 724 | 759 | for (i=0; i<samples; i++) |
| 725 | 760 | { |
| 726 | 761 | /* calculate all voices' envelopes */ |
| 727 | | EG_voices_advance(chip); |
| 762 | EG_voices_advance(); |
| 728 | 763 | |
| 729 | | TG_group_advance(chip,0); /* calculate tones group 1 */ |
| 764 | TG_group_advance(0); /* calculate tones group 1 */ |
| 730 | 765 | buf1[i] = o2; |
| 731 | 766 | buf2[i] = o4; |
| 732 | 767 | buf3[i] = o8; |
| r23881 | r23882 | |
| 737 | 772 | SAVE_SINGLE_CHANNEL(2,o8) |
| 738 | 773 | SAVE_SINGLE_CHANNEL(3,o16) |
| 739 | 774 | |
| 740 | | TG_group_advance(chip,1); /* calculate tones group 2 */ |
| 775 | TG_group_advance(1); /* calculate tones group 2 */ |
| 741 | 776 | buf5[i] = o2; |
| 742 | 777 | buf6[i] = o4; |
| 743 | 778 | buf7[i] = o8; |
| r23881 | r23882 | |
| 755 | 790 | |
| 756 | 791 | /* update noise generator */ |
| 757 | 792 | { |
| 758 | | int cnt = (chip->noise_cnt+=chip->noise_step) >> STEP_SH; |
| 759 | | chip->noise_cnt &= ((1<<STEP_SH)-1); |
| 793 | int cnt = (m_noise_cnt+=m_noise_step) >> STEP_SH; |
| 794 | m_noise_cnt &= ((1<<STEP_SH)-1); |
| 760 | 795 | while (cnt > 0) |
| 761 | 796 | { |
| 762 | | int tmp = chip->noise_rng & (1<<16); /* store current level */ |
| 797 | int tmp = m_noise_rng & (1<<16); /* store current level */ |
| 763 | 798 | |
| 764 | | if (chip->noise_rng&1) |
| 765 | | chip->noise_rng ^= 0x24000; |
| 766 | | chip->noise_rng>>=1; |
| 799 | if (m_noise_rng&1) |
| 800 | m_noise_rng ^= 0x24000; |
| 801 | m_noise_rng>>=1; |
| 767 | 802 | |
| 768 | | if ( (chip->noise_rng & (1<<16)) != tmp ) /* level change detect */ |
| 769 | | chip->noise_clocks++; |
| 803 | if ( (m_noise_rng & (1<<16)) != tmp ) /* level change detect */ |
| 804 | m_noise_clocks++; |
| 770 | 805 | |
| 771 | 806 | cnt--; |
| 772 | 807 | } |
| 773 | 808 | } |
| 774 | 809 | |
| 775 | | bufnoise[i] = (chip->noise_rng & (1<<16)) ? 32767 : 0; |
| 810 | bufnoise[i] = (m_noise_rng & (1<<16)) ? 32767 : 0; |
| 776 | 811 | } |
| 777 | 812 | } |
| 778 | | |
| 779 | | |
| 780 | | |
| 781 | | /* MAME Interface */ |
| 782 | | static void msm5232_postload(msm5232_state *chip) |
| 783 | | { |
| 784 | | msm5232_init_tables(chip); |
| 785 | | } |
| 786 | | |
| 787 | | static DEVICE_START( msm5232 ) |
| 788 | | { |
| 789 | | const msm5232_interface *intf = (const msm5232_interface *)device->static_config(); |
| 790 | | int rate = device->clock()/CLOCK_RATE_DIVIDER; |
| 791 | | msm5232_state *chip = get_safe_token(device); |
| 792 | | int voicenum; |
| 793 | | |
| 794 | | chip->device = device; |
| 795 | | |
| 796 | | msm5232_init(chip, intf, device->clock(), rate); |
| 797 | | |
| 798 | | chip->stream = device->machine().sound().stream_alloc(*device, 0, 11, rate, chip, MSM5232_update_one); |
| 799 | | |
| 800 | | /* register with the save state system */ |
| 801 | | device->machine().save().register_postload(save_prepost_delegate(FUNC(msm5232_postload), chip)); |
| 802 | | device->save_item(NAME(chip->EN_out16)); |
| 803 | | device->save_item(NAME(chip->EN_out8)); |
| 804 | | device->save_item(NAME(chip->EN_out4)); |
| 805 | | device->save_item(NAME(chip->EN_out2)); |
| 806 | | device->save_item(NAME(chip->noise_cnt)); |
| 807 | | device->save_item(NAME(chip->noise_rng)); |
| 808 | | device->save_item(NAME(chip->noise_clocks)); |
| 809 | | device->save_item(NAME(chip->control1)); |
| 810 | | device->save_item(NAME(chip->control2)); |
| 811 | | device->save_item(NAME(chip->gate)); |
| 812 | | device->save_item(NAME(chip->clock)); |
| 813 | | device->save_item(NAME(chip->rate)); |
| 814 | | |
| 815 | | /* register voice-specific data for save states */ |
| 816 | | for (voicenum = 0; voicenum < 8; voicenum++) |
| 817 | | { |
| 818 | | VOICE *voice = &chip->voi[voicenum]; |
| 819 | | |
| 820 | | device->save_item(NAME(voice->mode), voicenum); |
| 821 | | device->save_item(NAME(voice->TG_count_period), voicenum); |
| 822 | | device->save_item(NAME(voice->TG_cnt), voicenum); |
| 823 | | device->save_item(NAME(voice->TG_out16), voicenum); |
| 824 | | device->save_item(NAME(voice->TG_out8), voicenum); |
| 825 | | device->save_item(NAME(voice->TG_out4), voicenum); |
| 826 | | device->save_item(NAME(voice->TG_out2), voicenum); |
| 827 | | device->save_item(NAME(voice->egvol), voicenum); |
| 828 | | device->save_item(NAME(voice->eg_sect), voicenum); |
| 829 | | device->save_item(NAME(voice->counter), voicenum); |
| 830 | | device->save_item(NAME(voice->eg), voicenum); |
| 831 | | device->save_item(NAME(voice->eg_arm), voicenum); |
| 832 | | device->save_item(NAME(voice->ar_rate), voicenum); |
| 833 | | device->save_item(NAME(voice->dr_rate), voicenum); |
| 834 | | device->save_item(NAME(voice->pitch), voicenum); |
| 835 | | device->save_item(NAME(voice->GF), voicenum); |
| 836 | | } |
| 837 | | } |
| 838 | | |
| 839 | | void msm5232_set_clock(device_t *device, int clock) |
| 840 | | { |
| 841 | | msm5232_state *chip = get_safe_token(device); |
| 842 | | |
| 843 | | if (chip->clock != clock) |
| 844 | | { |
| 845 | | chip->stream->update (); |
| 846 | | chip->clock = clock; |
| 847 | | chip->rate = clock/CLOCK_RATE_DIVIDER; |
| 848 | | msm5232_init_tables( chip ); |
| 849 | | chip->stream->set_sample_rate(chip->rate); |
| 850 | | } |
| 851 | | } |
| 852 | | |
| 853 | | const device_type MSM5232 = &device_creator<msm5232_device>; |
| 854 | | |
| 855 | | msm5232_device::msm5232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 856 | | : device_t(mconfig, MSM5232, "MSM5232", tag, owner, clock, "msm5232", __FILE__), |
| 857 | | device_sound_interface(mconfig, *this) |
| 858 | | { |
| 859 | | m_token = global_alloc_clear(msm5232_state); |
| 860 | | } |
| 861 | | |
| 862 | | //------------------------------------------------- |
| 863 | | // device_config_complete - perform any |
| 864 | | // operations now that the configuration is |
| 865 | | // complete |
| 866 | | //------------------------------------------------- |
| 867 | | |
| 868 | | void msm5232_device::device_config_complete() |
| 869 | | { |
| 870 | | } |
| 871 | | |
| 872 | | //------------------------------------------------- |
| 873 | | // device_start - device-specific startup |
| 874 | | //------------------------------------------------- |
| 875 | | |
| 876 | | void msm5232_device::device_start() |
| 877 | | { |
| 878 | | DEVICE_START_NAME( msm5232 )(this); |
| 879 | | } |
| 880 | | |
| 881 | | //------------------------------------------------- |
| 882 | | // device_reset - device-specific reset |
| 883 | | //------------------------------------------------- |
| 884 | | |
| 885 | | void msm5232_device::device_reset() |
| 886 | | { |
| 887 | | DEVICE_RESET_NAME( msm5232 )(this); |
| 888 | | } |
| 889 | | |
| 890 | | //------------------------------------------------- |
| 891 | | // device_stop - device-specific stop |
| 892 | | //------------------------------------------------- |
| 893 | | |
| 894 | | void msm5232_device::device_stop() |
| 895 | | { |
| 896 | | DEVICE_STOP_NAME( msm5232 )(this); |
| 897 | | } |
| 898 | | |
| 899 | | //------------------------------------------------- |
| 900 | | // sound_stream_update - handle a stream update |
| 901 | | //------------------------------------------------- |
| 902 | | |
| 903 | | void msm5232_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 904 | | { |
| 905 | | // should never get here |
| 906 | | fatalerror("sound_stream_update called; not applicable to legacy sound devices\n"); |
| 907 | | } |