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 !! */
160 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;
171 /* update when signal changed */
172 if( m_signal != new_signal)
174 // m_stream->update();
175 m_signal = new_signal;
183 * Handle an update of the vclk status of a chip (1 is reset ON, 0 is reset OFF)
184 * This function can use selector = MSM5205_SEX only
186 void MSM5205::vclk_w(int vclk)
188 if (m_prescaler != 0)
190 out_debug_log(_T("ERROR: msm5205_vclk_w() called, but VCLK selected master mode\n"));
194 bool val = (vclk == 0) ? false : true;
199 event_callback(EVENT_TIMER, 0);
205 * Handle an update of the reset status of a chip (1 is reset ON, 0 is reset OFF)
208 void MSM5205::reset_w(int reset)
211 m_reset = (reset != 0);
212 set_realtime_render(this, (!m_reset)); // ?? 20181124 K.O
216 * Handle an update of the data to the chip
219 void MSM5205::data_w(int data)
223 m_data = data & 0x0f;
225 m_data = (data & 0x07) << 1; /* unknown */
229 * Handle a change of the selector
232 void MSM5205::playmode_w(int select)
234 static const int prescaler_table[2][4] =
239 int prescaler = prescaler_table[(select >> 3) & 1][select & 3];
240 int bitwidth = (select & 4) ? 4 : 3;
242 if (m_prescaler != prescaler)
246 m_prescaler = prescaler;
251 // attotime period = attotime::from_hz(m_mod_clock) * prescaler;
252 // m_timer->adjust(period, 0, period);
253 double period = ((1000000.0 / m_mod_clock) * prescaler) / 2.0;
255 cancel_event(this, m_timer);
257 register_event(this, EVENT_TIMER, period, true, &m_timer);
261 // m_timer->adjust(attotime::never);
263 cancel_event(this, m_timer);
269 if (m_bitwidth != bitwidth)
272 // m_stream->update();
273 m_bitwidth = bitwidth;
278 void MSM5205::set_volume(int volume)
281 volume_m = (int)(1024.0 * (max(0, min(100, volume)) / 100.0));
284 void MSM5205::change_clock_w(int32_t clock)
288 if (m_prescaler != 0) {
290 double period = ((1000000.0 / m_mod_clock) * m_prescaler) / 2.0;
292 cancel_event(this, m_timer);
294 register_event(this, EVENT_TIMER, period, true, &m_timer);
298 cancel_event(this, m_timer);
305 //-------------------------------------------------
306 // sound_stream_update - handle a stream update
307 //-------------------------------------------------
309 void MSM5205::mix(int32_t* buffer, int cnt)
311 /* if this voice is active */
314 int32_t val = apply_volume((int32_t)(m_signal) * 16, volume_m);
315 int32_t val_l = apply_volume(val, volume_l);
316 int32_t val_r = apply_volume(val, volume_r);
318 for(int i = 0; i < cnt; i++)
320 *buffer++ += val_l; // L
321 *buffer++ += val_r; // R
326 void MSM5205::set_volume(int ch, int decibel_l, int decibel_r)
328 volume_l = decibel_to_volume(decibel_l + 6.0);
329 volume_r = decibel_to_volume(decibel_r + 6.0);
332 #define STATE_VERSION 2
334 bool MSM5205::process_state(FILEIO* state_fio, bool loading)
336 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
339 if(!state_fio->StateCheckInt32(this_device_id)) {
342 state_fio->StateValue(m_mod_clock);
343 state_fio->StateValue(m_timer);
344 state_fio->StateValue(m_data);
345 state_fio->StateValue(m_vclk);
346 state_fio->StateValue(m_reset);
347 state_fio->StateValue(m_prescaler);
348 state_fio->StateValue(m_bitwidth);
349 state_fio->StateValue(m_signal);
350 state_fio->StateValue(m_step);
351 state_fio->StateValue(m_select);
352 state_fio->StateValue(volume_m);