1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
4 * streaming ADPCM driver
7 * Library to transcode from an ADPCM source to raw PCM.
8 * Written by Buffoni Mirko in 08/06/97
9 * References: various sources and documents.
12 * modified to use an automatically selected oversampling factor
13 * for the current sample rate
16 * separate MSM5205 emulator form adpcm.c and some fix
19 * added basic support for the MSM6585
31 Data is streamed from a CPU by means of a clock generated on the chip.
33 A reset signal is set high or low to determine whether playback (and interrupts) are occurring.
35 MSM6585: is an upgraded MSM5205 voice synth IC.
37 More precise internal DA converter
38 Built in low-pass filter
39 Expanded sampling frequency
41 Differences between MSM6585 & MSM5205:
44 Master clock frequency 640kHz 384kHz
45 Sampling frequency 4k/8k/16k/32kHz 4k/6k/8kHz
46 ADPCM bit length 4-bit 3-bit/4-bit
47 DA converter 12-bit 10-bit
48 Low-pass filter -40dB/oct N/A
49 Overflow prevent circuit Included N/A
51 Timer callback at VCLK low edge on MSM5205 (at rising edge on MSM6585)
54 - lowpass filter for MSM6585
58 void MSM5205::initialize()
61 // m_mod_clock = clock();
62 // m_vclk_cb.resolve();
64 /* compute the difference tables */
67 /* stream system initialize */
68 // m_stream = machine().sound().stream_alloc(*this, 0, 1, clock());
69 // m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(msm5205_device::vclk_callback), this));
73 //-------------------------------------------------
74 // device_reset - device-specific reset
75 //-------------------------------------------------
86 /* initialize clock */
87 change_clock_w(m_mod_clock);
89 /* timer and bitwidth set */
98 /* step size index shift table */
99 static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
102 * Compute the difference table
105 void MSM5205::compute_tables()
107 /* nibble to bit map */
108 static const int nbl2bit[16][4] =
110 { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
111 { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
112 {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
113 {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
118 /* loop over all possible steps */
119 for (step = 0; step <= 48; step++)
121 /* compute the step value */
122 int stepval = (int)floor (16.0 * pow (11.0 / 10.0, (double)step));
124 /* loop over all nibbles and compute the difference */
125 for (nib = 0; nib < 16; nib++)
127 m_diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
128 (stepval * nbl2bit[nib][1] +
129 stepval/2 * nbl2bit[nib][2] +
130 stepval/4 * nbl2bit[nib][3] +
136 /* timer callback at VCLK low edge on MSM5205 (at rising edge on MSM6585) */
137 // Change: Check edge value via m_vclk, to be half cycle.
138 void MSM5205::event_callback(int event_id, int err)
140 if(event_id == EVENT_TIMER)
143 int new_signal = m_signal;
145 /* callback user handler and latch next data */
147 write_signals(&m_vclk_cb, (m_vclk) ? 0xffffffff : 0x00000000);
149 /* reset check at last hiedge of VCLK */
156 if(m_vclk) return; // If MSM6585 Invert level.
158 /* !! MSM5205 has internal 12bit decoding, signal width is 0 to 8191 !! */
161 new_signal = m_signal + m_diff_lookup[m_step * 16 + (val & 15)];
162 if (new_signal > 2047) new_signal = 2047;
163 else if (new_signal < -2048) new_signal = -2048;
165 m_step += index_shift[val & 7];
167 if (m_step > 48) m_step = 48;
168 else if (m_step < 0) m_step = 0;
172 /* update when signal changed */
173 if( m_signal != new_signal)
175 // m_stream->update();
176 m_signal = new_signal;
184 * Handle an update of the vclk status of a chip (1 is reset ON, 0 is reset OFF)
185 * This function can use selector = MSM5205_SEX only
187 void MSM5205::vclk_w(int vclk)
189 if (m_prescaler != 0)
191 out_debug_log(_T("ERROR: msm5205_vclk_w() called, but VCLK selected master mode\n"));
195 bool val = (vclk == 0) ? false : true;
200 event_callback(EVENT_TIMER, 0);
206 * Handle an update of the reset status of a chip (1 is reset ON, 0 is reset OFF)
209 void MSM5205::reset_w(int reset)
212 m_reset = (reset != 0);
213 set_realtime_render(this, (!m_reset)); // ?? 20181124 K.O
217 * Handle an update of the data to the chip
220 void MSM5205::data_w(int data)
224 m_data = data & 0x0f;
226 m_data = (data & 0x07) << 1; /* unknown */
230 * Handle a change of the selector
233 void MSM5205::playmode_w(int select)
235 static const int prescaler_table[2][4] =
240 int prescaler = prescaler_table[(select >> 3) & 1][select & 3];
241 int bitwidth = (select & 4) ? 4 : 3;
243 if (m_prescaler != prescaler)
247 m_prescaler = prescaler;
252 // attotime period = attotime::from_hz(m_mod_clock) * prescaler;
253 // m_timer->adjust(period, 0, period);
254 double period = ((1000000.0 / m_mod_clock) * prescaler) / 2.0;
256 cancel_event(this, m_timer);
258 register_event(this, EVENT_TIMER, period, true, &m_timer);
262 // m_timer->adjust(attotime::never);
264 cancel_event(this, m_timer);
270 if (m_bitwidth != bitwidth)
273 // m_stream->update();
274 m_bitwidth = bitwidth;
279 * PAUSE playing (hack for PCE).
282 void MSM5205::pause_w(int data)
284 m_ignore = (data != 0) ? true : false;
287 void MSM5205::set_volume(int volume)
290 volume_m = (int)(1024.0 * (max(0, min(100, volume)) / 100.0));
293 void MSM5205::change_clock_w(int32_t clock)
297 if (m_prescaler != 0) {
299 double period = ((1000000.0 / m_mod_clock) * m_prescaler) / 2.0;
301 cancel_event(this, m_timer);
303 register_event(this, EVENT_TIMER, period, true, &m_timer);
307 cancel_event(this, m_timer);
314 //-------------------------------------------------
315 // sound_stream_update - handle a stream update
316 //-------------------------------------------------
318 void MSM5205::mix(int32_t* buffer, int cnt)
320 /* if this voice is active */
323 int32_t val = apply_volume((int32_t)(m_signal) * 32, volume_m); // Changed by 20190212 K.O
324 int32_t val_l = apply_volume(val, volume_l);
325 int32_t val_r = apply_volume(val, volume_r);
327 for(int i = 0; i < cnt; i++)
329 *buffer++ += val_l; // L
330 *buffer++ += val_r; // R
335 void MSM5205::set_volume(int ch, int decibel_l, int decibel_r)
337 volume_l = decibel_to_volume(decibel_l + 6.0);
338 volume_r = decibel_to_volume(decibel_r + 6.0);
341 #define STATE_VERSION 3
343 bool MSM5205::process_state(FILEIO* state_fio, bool loading)
345 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
348 if(!state_fio->StateCheckInt32(this_device_id)) {
351 state_fio->StateValue(m_mod_clock);
352 state_fio->StateValue(m_timer);
353 state_fio->StateValue(m_data);
354 state_fio->StateValue(m_vclk);
355 state_fio->StateValue(m_reset);
356 state_fio->StateValue(m_prescaler);
357 state_fio->StateValue(m_bitwidth);
358 state_fio->StateValue(m_signal);
359 state_fio->StateValue(m_step);
360 state_fio->StateValue(m_select);
361 state_fio->StateValue(m_ignore);
362 state_fio->StateValue(volume_m);